From 4b3bc6ac114b7964fd073d4b2f7d3f7edce339e3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 11 Sep 2016 15:56:48 -0600 Subject: [PATCH 0001/1301] PCI driver WIP --- pcid/Cargo.toml | 6 ++++ pcid/src/main.rs | 73 ++++++++++++++++++++++++++++++++++++++++++ pcid/src/pci/bar.rs | 18 +++++++++++ pcid/src/pci/bus.rs | 46 ++++++++++++++++++++++++++ pcid/src/pci/class.rs | 50 +++++++++++++++++++++++++++++ pcid/src/pci/dev.rs | 46 ++++++++++++++++++++++++++ pcid/src/pci/func.rs | 30 +++++++++++++++++ pcid/src/pci/header.rs | 43 +++++++++++++++++++++++++ pcid/src/pci/mod.rs | 67 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 379 insertions(+) create mode 100644 pcid/Cargo.toml create mode 100644 pcid/src/main.rs create mode 100644 pcid/src/pci/bar.rs create mode 100644 pcid/src/pci/bus.rs create mode 100644 pcid/src/pci/class.rs create mode 100644 pcid/src/pci/dev.rs create mode 100644 pcid/src/pci/func.rs create mode 100644 pcid/src/pci/header.rs create mode 100644 pcid/src/pci/mod.rs diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml new file mode 100644 index 0000000000..e6b63183f3 --- /dev/null +++ b/pcid/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "pcid" +version = "0.1.0" + +[dependencies.syscall] +path = "../../syscall/" diff --git a/pcid/src/main.rs b/pcid/src/main.rs new file mode 100644 index 0000000000..e23df8da6b --- /dev/null +++ b/pcid/src/main.rs @@ -0,0 +1,73 @@ +#![feature(asm)] + +extern crate syscall; + +use syscall::iopl; + +use pci::{Pci, PciBar, PciClass}; + +mod pci; + +fn enumerate_pci() { + println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); + + let pci = Pci::new(); + for bus in pci.buses() { + for dev in bus.devs() { + for func in dev.funcs() { + if let Some(header) = func.header() { + println!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", + bus.num, dev.num, func.num, + header.vendor_id, header.device_id, + header.class, header.subclass, header.interface, header.revision, + PciClass::from(header.class)); + + for i in 0..header.bars.len() { + match PciBar::from(header.bars[i]) { + PciBar::None => (), + PciBar::Memory(address) => println!(" BAR {} {:>08X}", i, address), + PciBar::Port(address) => println!(" BAR {} {:>04X}", i, address) + } + } + + match PciClass::from(header.class) { + PciClass::Storage => match header.subclass { + 0x01 => { + println!(" + IDE"); + }, + 0x06 => { + println!(" + SATA"); + }, + _ => () + }, + PciClass::SerialBus => match header.subclass { + 0x03 => match header.interface { + 0x00 => { + println!(" + UHCI"); + }, + 0x10 => { + println!(" + OHCI"); + }, + 0x20 => { + println!(" + EHCI"); + }, + 0x30 => { + println!(" + XHCI"); + }, + _ => () + }, + _ => () + }, + _ => () + } + } + } + } + } +} + +fn main() { + unsafe { iopl(3).unwrap() }; + + enumerate_pci(); +} diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs new file mode 100644 index 0000000000..190fa05d2d --- /dev/null +++ b/pcid/src/pci/bar.rs @@ -0,0 +1,18 @@ +#[derive(Debug)] +pub enum PciBar { + None, + Memory(u32), + Port(u16) +} + +impl From for PciBar { + fn from(bar: u32) -> Self { + if bar & 0xFFFFFFFC == 0 { + PciBar::None + } else if bar & 1 == 0 { + PciBar::Memory(bar & 0xFFFFFFF0) + } else { + PciBar::Port((bar & 0xFFFC) as u16) + } + } +} diff --git a/pcid/src/pci/bus.rs b/pcid/src/pci/bus.rs new file mode 100644 index 0000000000..120fa458f9 --- /dev/null +++ b/pcid/src/pci/bus.rs @@ -0,0 +1,46 @@ +use super::{Pci, PciDev}; + +pub struct PciBus<'pci> { + pub pci: &'pci Pci, + pub num: u8 +} + +impl<'pci> PciBus<'pci> { + pub fn devs(&'pci self) -> PciBusIter<'pci> { + PciBusIter::new(self) + } + + pub unsafe fn read(&self, dev: u8, func: u8, offset: u8) -> u32 { + self.pci.read(self.num, dev, func, offset) + } +} + +pub struct PciBusIter<'pci> { + bus: &'pci PciBus<'pci>, + num: u32 +} + +impl<'pci> PciBusIter<'pci> { + pub fn new(bus: &'pci PciBus<'pci>) -> Self { + PciBusIter { + bus: bus, + num: 0 + } + } +} + +impl<'pci> Iterator for PciBusIter<'pci> { + type Item = PciDev<'pci>; + fn next(&mut self) -> Option { + if self.num < 32 { + let dev = PciDev { + bus: self.bus, + num: self.num as u8 + }; + self.num += 1; + Some(dev) + } else { + None + } + } +} diff --git a/pcid/src/pci/class.rs b/pcid/src/pci/class.rs new file mode 100644 index 0000000000..21f7f69bbe --- /dev/null +++ b/pcid/src/pci/class.rs @@ -0,0 +1,50 @@ +#[derive(Debug)] +pub enum PciClass { + Legacy, + Storage, + Network, + Display, + Multimedia, + Memory, + Bridge, + SimpleComms, + Peripheral, + Input, + Docking, + Processor, + SerialBus, + Wireless, + IntelligentIo, + SatelliteComms, + Cryptography, + SignalProc, + Reserved(u8), + Unknown +} + +impl From for PciClass { + fn from(class: u8) -> PciClass { + match class { + 0x00 => PciClass::Legacy, + 0x01 => PciClass::Storage, + 0x02 => PciClass::Network, + 0x03 => PciClass::Display, + 0x04 => PciClass::Multimedia, + 0x05 => PciClass::Memory, + 0x06 => PciClass::Bridge, + 0x07 => PciClass::SimpleComms, + 0x08 => PciClass::Peripheral, + 0x09 => PciClass::Input, + 0x0A => PciClass::Docking, + 0x0B => PciClass::Processor, + 0x0C => PciClass::SerialBus, + 0x0D => PciClass::Wireless, + 0x0E => PciClass::IntelligentIo, + 0x0F => PciClass::SatelliteComms, + 0x10 => PciClass::Cryptography, + 0x11 => PciClass::SignalProc, + 0xFF => PciClass::Unknown, + reserved => PciClass::Reserved(reserved) + } + } +} diff --git a/pcid/src/pci/dev.rs b/pcid/src/pci/dev.rs new file mode 100644 index 0000000000..05088886e8 --- /dev/null +++ b/pcid/src/pci/dev.rs @@ -0,0 +1,46 @@ +use super::{PciBus, PciFunc}; + +pub struct PciDev<'pci> { + pub bus: &'pci PciBus<'pci>, + pub num: u8 +} + +impl<'pci> PciDev<'pci> { + pub fn funcs(&'pci self) -> PciDevIter<'pci> { + PciDevIter::new(self) + } + + pub unsafe fn read(&self, func: u8, offset: u8) -> u32 { + self.bus.read(self.num, func, offset) + } +} + +pub struct PciDevIter<'pci> { + dev: &'pci PciDev<'pci>, + num: u32 +} + +impl<'pci> PciDevIter<'pci> { + pub fn new(dev: &'pci PciDev<'pci>) -> Self { + PciDevIter { + dev: dev, + num: 0 + } + } +} + +impl<'pci> Iterator for PciDevIter<'pci> { + type Item = PciFunc<'pci>; + fn next(&mut self) -> Option { + if self.num < 8 { + let func = PciFunc { + dev: self.dev, + num: self.num as u8 + }; + self.num += 1; + Some(func) + } else { + None + } + } +} diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs new file mode 100644 index 0000000000..578e5c61be --- /dev/null +++ b/pcid/src/pci/func.rs @@ -0,0 +1,30 @@ +use std::ops::DerefMut; + +use super::{PciDev, PciHeader}; + +pub struct PciFunc<'pci> { + pub dev: &'pci PciDev<'pci>, + pub num: u8 +} + +impl<'pci> PciFunc<'pci> { + pub fn header(&self) -> Option { + if unsafe { self.read(0) } != 0xFFFFFFFF { + let mut header = PciHeader::default(); + { + let dwords = header.deref_mut(); + dwords.iter_mut().fold(0usize, |offset, dword| { + *dword = unsafe { self.read(offset as u8) }; + offset + 4 + }); + } + Some(header) + } else { + None + } + } + + pub unsafe fn read(&self, offset: u8) -> u32 { + self.dev.read(self.num, offset) + } +} diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs new file mode 100644 index 0000000000..2cc335e388 --- /dev/null +++ b/pcid/src/pci/header.rs @@ -0,0 +1,43 @@ +use std::ops::{Deref, DerefMut}; +use std::{slice, mem}; + +#[derive(Debug, Default)] +#[repr(packed)] +pub struct PciHeader { + pub vendor_id: u16, + pub device_id: u16, + pub command: u16, + pub status: u16, + pub revision: u8, + pub interface: u8, + pub subclass: u8, + pub class: u8, + pub cache_line_size: u8, + pub latency_timer: u8, + pub header_type: u8, + pub bist: u8, + pub bars: [u32; 6], + pub cardbus_cis_ptr: u32, + pub subsystem_vendor_id: u16, + pub subsystem_id: u16, + pub expansion_rom_bar: u32, + pub capabilities: u8, + pub reserved: [u8; 7], + pub interrupt_line: u8, + pub interrupt_pin: u8, + pub min_grant: u8, + pub max_latency: u8 +} + +impl Deref for PciHeader { + type Target = [u32]; + fn deref(&self) -> &[u32] { + unsafe { slice::from_raw_parts(self as *const PciHeader as *const u32, mem::size_of::()/4) as &[u32] } + } +} + +impl DerefMut for PciHeader { + fn deref_mut(&mut self) -> &mut [u32] { + unsafe { slice::from_raw_parts_mut(self as *mut PciHeader as *mut u32, mem::size_of::()/4) as &mut [u32] } + } +} diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs new file mode 100644 index 0000000000..0d760ef446 --- /dev/null +++ b/pcid/src/pci/mod.rs @@ -0,0 +1,67 @@ +pub use self::bar::PciBar; +pub use self::bus::{PciBus, PciBusIter}; +pub use self::class::PciClass; +pub use self::dev::{PciDev, PciDevIter}; +pub use self::func::PciFunc; +pub use self::header::PciHeader; + +mod bar; +mod bus; +mod class; +mod dev; +mod func; +mod header; + +pub struct Pci; + +impl Pci { + pub fn new() -> Self { + Pci + } + + pub fn buses<'pci>(&'pci self) -> PciIter<'pci> { + PciIter::new(self) + } + + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 { + let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); + let value: u32; + asm!("mov dx, 0xCF8 + out dx, eax + mov dx, 0xCFC + in eax, dx" + : "={eax}"(value) : "{eax}"(address) : "dx" : "intel", "volatile"); + value + } +} + +pub struct PciIter<'pci> { + pci: &'pci Pci, + num: u32 +} + +impl<'pci> PciIter<'pci> { + pub fn new(pci: &'pci Pci) -> Self { + PciIter { + pci: pci, + num: 0 + } + } +} + +impl<'pci> Iterator for PciIter<'pci> { + type Item = PciBus<'pci>; + fn next(&mut self) -> Option { + if self.num < 256 { + let bus = PciBus { + pci: self.pci, + num: self.num as u8 + }; + self.num += 1; + Some(bus) + } else { + None + } + } +} From e306348e44d03b5ffe41eff1b90b66d8a5070bd9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 11 Sep 2016 16:24:43 -0600 Subject: [PATCH 0002/1301] More compact output --- pcid/src/main.rs | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index e23df8da6b..d904ee809f 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -16,43 +16,36 @@ fn enumerate_pci() { for dev in bus.devs() { for func in dev.funcs() { if let Some(header) = func.header() { - println!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", + print!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X}", bus.num, dev.num, func.num, header.vendor_id, header.device_id, - header.class, header.subclass, header.interface, header.revision, - PciClass::from(header.class)); + header.class, header.subclass, header.interface, header.revision); - for i in 0..header.bars.len() { - match PciBar::from(header.bars[i]) { - PciBar::None => (), - PciBar::Memory(address) => println!(" BAR {} {:>08X}", i, address), - PciBar::Port(address) => println!(" BAR {} {:>04X}", i, address) - } - } - - match PciClass::from(header.class) { + let pci_class = PciClass::from(header.class); + print!(" {:?}", pci_class); + match pci_class { PciClass::Storage => match header.subclass { 0x01 => { - println!(" + IDE"); + print!(" IDE"); }, 0x06 => { - println!(" + SATA"); + print!(" SATA"); }, _ => () }, PciClass::SerialBus => match header.subclass { 0x03 => match header.interface { 0x00 => { - println!(" + UHCI"); + print!(" UHCI"); }, 0x10 => { - println!(" + OHCI"); + print!(" OHCI"); }, 0x20 => { - println!(" + EHCI"); + print!(" EHCI"); }, 0x30 => { - println!(" + XHCI"); + print!(" XHCI"); }, _ => () }, @@ -60,6 +53,16 @@ fn enumerate_pci() { }, _ => () } + + for i in 0..header.bars.len() { + match PciBar::from(header.bars[i]) { + PciBar::None => (), + PciBar::Memory(address) => print!(" {}={:>08X}", i, address), + PciBar::Port(address) => print!(" {}={:>04X}", i, address) + } + } + + print!("\n"); } } } From a87ab74e8fff0b4ddd1ada4fe50179ca5dc72af5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 17 Sep 2016 08:09:32 -0600 Subject: [PATCH 0003/1301] Run pcid as a daemon --- pcid/src/main.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index d904ee809f..0886bef5a9 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -2,6 +2,7 @@ extern crate syscall; +use std::thread; use syscall::iopl; use pci::{Pci, PciBar, PciClass}; @@ -70,7 +71,9 @@ fn enumerate_pci() { } fn main() { - unsafe { iopl(3).unwrap() }; + thread::spawn(||{ + unsafe { iopl(3).unwrap() }; - enumerate_pci(); + enumerate_pci(); + }); } From 0feba280aacb1a26c3e7c1e93a09e493faf61aa1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 18 Sep 2016 20:17:08 -0600 Subject: [PATCH 0004/1301] Allow userspace to handle IRQs (WIP). Create basic keyboard handler --- ps2d/Cargo.toml | 6 +++++ ps2d/src/main.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 ps2d/Cargo.toml create mode 100644 ps2d/src/main.rs diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml new file mode 100644 index 0000000000..f49dee1313 --- /dev/null +++ b/ps2d/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "ps2d" +version = "0.1.0" + +[dependencies.syscall] +path = "../../syscall/" diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs new file mode 100644 index 0000000000..9f45412c2f --- /dev/null +++ b/ps2d/src/main.rs @@ -0,0 +1,59 @@ +#![feature(asm)] + +extern crate syscall; + +use std::fs::File; +use std::io::{Read, Write}; +use std::thread; + +use syscall::iopl; + +fn main() { + if true { + unsafe { + iopl(3).expect("pskbd: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + let mut file = File::open("irq:1").expect("pskbd: failed to open irq:1"); + + println!("pskbd: Reading keyboard IRQs"); + + loop { + let mut irqs = [0; 8]; + file.read(&mut irqs).expect("pskbd: failed to read irq:1"); + + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + println!("pskbd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); + + file.write(&irqs).expect("pskbd: failed to write irq:1"); + } + } else { + unsafe { + iopl(3).expect("psmsd: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + let mut file = File::open("irq:12").expect("psmsd: failed to open irq:12"); + + println!("psmsd: Reading mouse IRQs"); + + loop { + let mut count = [0; 8]; + file.read(&mut count).expect("psmsd: failed to read irq:12"); + + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + println!("psmsd: IRQ: {:X}", data); + + file.write(&count).expect("psmsd: failed to write irq:12"); + } + } +} From aeabb66d9a212587b316155f23e835a56d777239 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 19 Sep 2016 09:43:30 -0600 Subject: [PATCH 0005/1301] Seperate PS/2 keyboard and mouse driver --- ps2d/src/main.rs | 51 +++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 9f45412c2f..95345aeec5 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -4,12 +4,15 @@ extern crate syscall; use std::fs::File; use std::io::{Read, Write}; +use std::mem; use std::thread; use syscall::iopl; fn main() { - if true { + println!("PS/2 driver launching"); + + thread::spawn(|| { unsafe { iopl(3).expect("pskbd: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); @@ -21,18 +24,22 @@ fn main() { loop { let mut irqs = [0; 8]; - file.read(&mut irqs).expect("pskbd: failed to read irq:1"); + if file.read(&mut irqs).expect("pskbd: failed to read irq:1") >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + println!("pskbd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); + + file.write(&irqs).expect("pskbd: failed to write irq:1"); + } else { + thread::yield_now(); } - - println!("pskbd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); - - file.write(&irqs).expect("pskbd: failed to write irq:1"); } - } else { + }); + + thread::spawn(|| { unsafe { iopl(3).expect("psmsd: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); @@ -43,17 +50,21 @@ fn main() { println!("psmsd: Reading mouse IRQs"); loop { - let mut count = [0; 8]; - file.read(&mut count).expect("psmsd: failed to read irq:12"); + let mut irqs = [0; 8]; + if file.read(&mut irqs).expect("psmsd: failed to read irq:12") >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + println!("psmsd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); + + file.write(&irqs).expect("psmsd: failed to write irq:12"); + } else { + thread::yield_now(); } - - println!("psmsd: IRQ: {:X}", data); - - file.write(&count).expect("psmsd: failed to write irq:12"); } - } + }); + + println!("PS/2 driver running in background"); } From a60773c1c51c32829e64a0a1772fa768022414e6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 19 Sep 2016 10:24:19 -0600 Subject: [PATCH 0006/1301] PS/2 driver convert to char --- ps2d/src/keymap.rs | 68 ++++++++++++++++++++++++++++++++++ ps2d/src/main.rs | 91 +++++++++++++++++++++++++--------------------- 2 files changed, 117 insertions(+), 42 deletions(-) create mode 100644 ps2d/src/keymap.rs diff --git a/ps2d/src/keymap.rs b/ps2d/src/keymap.rs new file mode 100644 index 0000000000..699e3ad144 --- /dev/null +++ b/ps2d/src/keymap.rs @@ -0,0 +1,68 @@ +static ENGLISH: [[char; 3]; 58] = [ + ['\0', '\0', '\0'], + ['\x1B', '\x1B', '\x1B'], + ['1', '!', '1'], + ['2', '@', '2'], + ['3', '#', '3'], + ['4', '$', '4'], + ['5', '%', '5'], + ['6', '^', '6'], + ['7', '&', '7'], + ['8', '*', '8'], + ['9', '(', '9'], + ['0', ')', '0'], + ['-', '_', '-'], + ['=', '+', '='], + ['\0', '\0', '\0'], + ['\t', '\t', '\t'], + ['q', 'Q', 'q'], + ['w', 'W', 'w'], + ['e', 'E', 'e'], + ['r', 'R', 'r'], + ['t', 'T', 't'], + ['y', 'Y', 'y'], + ['u', 'U', 'u'], + ['i', 'I', 'i'], + ['o', 'O', 'o'], + ['p', 'P', 'p'], + ['[', '{', '['], + [']', '}', ']'], + ['\n', '\n', '\n'], + ['\0', '\0', '\0'], + ['a', 'A', 'a'], + ['s', 'S', 's'], + ['d', 'D', 'd'], + ['f', 'F', 'f'], + ['g', 'G', 'g'], + ['h', 'H', 'h'], + ['j', 'J', 'j'], + ['k', 'K', 'k'], + ['l', 'L', 'l'], + [';', ':', ';'], + ['\'', '"', '\''], + ['`', '~', '`'], + ['\0', '\0', '\0'], + ['\\', '|', '\\'], + ['z', 'Z', 'z'], + ['x', 'X', 'x'], + ['c', 'C', 'c'], + ['v', 'V', 'v'], + ['b', 'B', 'b'], + ['n', 'N', 'n'], + ['m', 'M', 'm'], + [',', '<', ','], + ['.', '>', '.'], + ['/', '?', '/'], + ['\0', '\0', '\0'], + ['\0', '\0', '\0'], + ['\0', '\0', '\0'], + [' ', ' ', ' '] +]; + +pub fn get_char(scancode: u8) -> char { + if let Some(c) = ENGLISH.get(scancode as usize) { + c[0] + } else { + '\0' + } +} diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 95345aeec5..f5818a6b7a 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -9,34 +9,61 @@ use std::thread; use syscall::iopl; -fn main() { - println!("PS/2 driver launching"); +mod keymap; +fn keyboard() { + let mut file = File::open("irq:1").expect("pskbd: failed to open irq:1"); + + loop { + let mut irqs = [0; 8]; + if file.read(&mut irqs).expect("pskbd: failed to read irq:1") >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + let (scancode, pressed) = if data >= 0x80 { + (data - 0x80, false) + } else { + (data, true) + }; + println!("pskbd: IRQ {}: {:X}: {:X}: {}: {}", unsafe { *(irqs.as_ptr() as *const usize) }, data, scancode, keymap::get_char(scancode), pressed); + + file.write(&irqs).expect("pskbd: failed to write irq:1"); + } else { + thread::yield_now(); + } + } +} + +fn mouse() { + let mut file = File::open("irq:12").expect("psmsd: failed to open irq:12"); + + loop { + let mut irqs = [0; 8]; + if file.read(&mut irqs).expect("psmsd: failed to read irq:12") >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + println!("psmsd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); + + file.write(&irqs).expect("psmsd: failed to write irq:12"); + } else { + thread::yield_now(); + } + } +} + +fn main() { thread::spawn(|| { unsafe { iopl(3).expect("pskbd: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); } - let mut file = File::open("irq:1").expect("pskbd: failed to open irq:1"); - - println!("pskbd: Reading keyboard IRQs"); - - loop { - let mut irqs = [0; 8]; - if file.read(&mut irqs).expect("pskbd: failed to read irq:1") >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - println!("pskbd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); - - file.write(&irqs).expect("pskbd: failed to write irq:1"); - } else { - thread::yield_now(); - } - } + keyboard(); }); thread::spawn(|| { @@ -45,26 +72,6 @@ fn main() { asm!("cli" :::: "intel", "volatile"); } - let mut file = File::open("irq:12").expect("psmsd: failed to open irq:12"); - - println!("psmsd: Reading mouse IRQs"); - - loop { - let mut irqs = [0; 8]; - if file.read(&mut irqs).expect("psmsd: failed to read irq:12") >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - println!("psmsd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); - - file.write(&irqs).expect("psmsd: failed to write irq:12"); - } else { - thread::yield_now(); - } - } + mouse(); }); - - println!("PS/2 driver running in background"); } From 1bbd71d7d8fa1847ba2ab43979bb942639905f61 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 19 Sep 2016 17:19:49 -0600 Subject: [PATCH 0007/1301] Move PS/2 driver to userspace --- io/Cargo.toml | 3 + io/src/io.rs | 67 ++++++++++++ io/src/lib.rs | 14 +++ io/src/mmio.rs | 31 ++++++ io/src/pio.rs | 89 ++++++++++++++++ ps2d/Cargo.toml | 7 +- ps2d/src/controller.rs | 237 +++++++++++++++++++++++++++++++++++++++++ ps2d/src/keyboard.rs | 34 ++++++ ps2d/src/main.rs | 71 ++++-------- ps2d/src/mouse.rs | 73 +++++++++++++ 10 files changed, 571 insertions(+), 55 deletions(-) create mode 100644 io/Cargo.toml create mode 100644 io/src/io.rs create mode 100644 io/src/lib.rs create mode 100644 io/src/mmio.rs create mode 100644 io/src/pio.rs create mode 100644 ps2d/src/controller.rs create mode 100644 ps2d/src/keyboard.rs create mode 100644 ps2d/src/mouse.rs diff --git a/io/Cargo.toml b/io/Cargo.toml new file mode 100644 index 0000000000..b0ee40b297 --- /dev/null +++ b/io/Cargo.toml @@ -0,0 +1,3 @@ +[package] +name = "io" +version = "0.1.0" diff --git a/io/src/io.rs b/io/src/io.rs new file mode 100644 index 0000000000..fb866b581b --- /dev/null +++ b/io/src/io.rs @@ -0,0 +1,67 @@ +use core::cmp::PartialEq; +use core::ops::{BitAnd, BitOr, Not}; + +pub trait Io { + type Value: Copy + PartialEq + BitAnd + BitOr + Not; + + fn read(&self) -> Self::Value; + fn write(&mut self, value: Self::Value); + + #[inline(always)] + fn readf(&self, flags: Self::Value) -> bool { + (self.read() & flags) as Self::Value == flags + } + + #[inline(always)] + fn writef(&mut self, flags: Self::Value, value: bool) { + let tmp: Self::Value = match value { + true => self.read() | flags, + false => self.read() & !flags, + }; + self.write(tmp); + } +} + +pub struct ReadOnly { + inner: I +} + +impl ReadOnly { + pub const fn new(inner: I) -> ReadOnly { + ReadOnly { + inner: inner + } + } + + #[inline(always)] + pub fn read(&self) -> I::Value { + self.inner.read() + } + + #[inline(always)] + pub fn readf(&self, flags: I::Value) -> bool { + self.inner.readf(flags) + } +} + +pub struct WriteOnly { + inner: I +} + +impl WriteOnly { + pub const fn new(inner: I) -> WriteOnly { + WriteOnly { + inner: inner + } + } + + #[inline(always)] + pub fn write(&mut self, value: I::Value) { + self.inner.write(value) + } + + #[inline(always)] + pub fn writef(&mut self, flags: I::Value, value: bool) { + self.inner.writef(flags, value) + } +} diff --git a/io/src/lib.rs b/io/src/lib.rs new file mode 100644 index 0000000000..22f8eb72c0 --- /dev/null +++ b/io/src/lib.rs @@ -0,0 +1,14 @@ +//! I/O functions + +#![feature(asm)] +#![feature(const_fn)] +#![feature(core_intrinsics)] +#![no_std] + +pub use self::io::*; +pub use self::mmio::*; +pub use self::pio::*; + +mod io; +mod mmio; +mod pio; diff --git a/io/src/mmio.rs b/io/src/mmio.rs new file mode 100644 index 0000000000..1a1d1996d1 --- /dev/null +++ b/io/src/mmio.rs @@ -0,0 +1,31 @@ +use core::intrinsics::{volatile_load, volatile_store}; +use core::mem::uninitialized; +use core::ops::{BitAnd, BitOr, Not}; + +use super::io::Io; + +#[repr(packed)] +pub struct Mmio { + value: T, +} + +impl Mmio { + /// Create a new Mmio without initializing + pub fn new() -> Self { + Mmio { + value: unsafe { uninitialized() } + } + } +} + +impl Io for Mmio where T: Copy + PartialEq + BitAnd + BitOr + Not { + type Value = T; + + fn read(&self) -> T { + unsafe { volatile_load(&self.value) } + } + + fn write(&mut self, value: T) { + unsafe { volatile_store(&mut self.value, value) }; + } +} diff --git a/io/src/pio.rs b/io/src/pio.rs new file mode 100644 index 0000000000..91ae310b62 --- /dev/null +++ b/io/src/pio.rs @@ -0,0 +1,89 @@ +use core::marker::PhantomData; + +use super::io::Io; + +/// Generic PIO +#[derive(Copy, Clone)] +pub struct Pio { + port: u16, + value: PhantomData, +} + +impl Pio { + /// Create a PIO from a given port + pub const fn new(port: u16) -> Self { + Pio:: { + port: port, + value: PhantomData, + } + } +} + +/// Read/Write for byte PIO +impl Io for Pio { + type Value = u8; + + /// Read + #[inline(always)] + fn read(&self) -> u8 { + let value: u8; + unsafe { + asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u8) { + unsafe { + asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + } +} + +/// Read/Write for word PIO +impl Io for Pio { + type Value = u16; + + /// Read + #[inline(always)] + fn read(&self) -> u16 { + let value: u16; + unsafe { + asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u16) { + unsafe { + asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + } +} + +/// Read/Write for doubleword PIO +impl Io for Pio { + type Value = u32; + + /// Read + #[inline(always)] + fn read(&self) -> u32 { + let value: u32; + unsafe { + asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u32) { + unsafe { + asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); + } + } +} diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index f49dee1313..665e3c19c8 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -2,5 +2,8 @@ name = "ps2d" version = "0.1.0" -[dependencies.syscall] -path = "../../syscall/" +[dependencies] +bitflags = "*" +io = { path = "../io/" } +spin = "*" +syscall = { path = "../../syscall/" } diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs new file mode 100644 index 0000000000..8355dba7bc --- /dev/null +++ b/ps2d/src/controller.rs @@ -0,0 +1,237 @@ +use io::{Io, Pio, ReadOnly, WriteOnly}; + +pub unsafe fn init() { + Ps2::new().init(); +} + +bitflags! { + flags StatusFlags: u8 { + const OUTPUT_FULL = 1, + const INPUT_FULL = 1 << 1, + const SYSTEM = 1 << 2, + const COMMAND = 1 << 3, + // Chipset specific + const KEYBOARD_LOCK = 1 << 4, + // Chipset specific + const SECOND_OUTPUT_FULL = 1 << 5, + const TIME_OUT = 1 << 6, + const PARITY = 1 << 7 + } +} + +bitflags! { + flags ConfigFlags: u8 { + const FIRST_INTERRUPT = 1, + const SECOND_INTERRUPT = 1 << 1, + const POST_PASSED = 1 << 2, + // 1 << 3 should be zero + const CONFIG_RESERVED_3 = 1 << 3, + const FIRST_DISABLED = 1 << 4, + const SECOND_DISABLED = 1 << 5, + const FIRST_TRANSLATE = 1 << 6, + // 1 << 7 should be zero + const CONFIG_RESERVED_7 = 1 << 7, + } +} + +#[repr(u8)] +#[allow(dead_code)] +enum Command { + ReadConfig = 0x20, + WriteConfig = 0x60, + DisableSecond = 0xA7, + EnableSecond = 0xA8, + TestSecond = 0xA9, + TestController = 0xAA, + TestFirst = 0xAB, + Diagnostic = 0xAC, + DisableFirst = 0xAD, + EnableFirst = 0xAE, + WriteSecond = 0xD4 +} + +#[repr(u8)] +#[allow(dead_code)] +enum KeyboardCommand { + EnableReporting = 0xF4, + SetDefaults = 0xF6, + Reset = 0xFF +} + +#[repr(u8)] +enum KeyboardCommandData { + ScancodeSet = 0xF0 +} + +#[repr(u8)] +#[allow(dead_code)] +enum MouseCommand { + GetDeviceId = 0xF2, + EnableReporting = 0xF4, + SetDefaults = 0xF6, + Reset = 0xFF +} + +#[repr(u8)] +enum MouseCommandData { + SetSampleRate = 0xF3, +} + +pub struct Ps2 { + data: Pio, + status: ReadOnly>, + command: WriteOnly> +} + +impl Ps2 { + pub fn new() -> Self { + Ps2 { + data: Pio::new(0x60), + status: ReadOnly::new(Pio::new(0x64)), + command: WriteOnly::new(Pio::new(0x64)), + } + } + + fn status(&mut self) -> StatusFlags { + StatusFlags::from_bits_truncate(self.status.read()) + } + + fn wait_write(&mut self) { + while self.status().contains(INPUT_FULL) {} + } + + fn wait_read(&mut self) { + while ! self.status().contains(OUTPUT_FULL) {} + } + + fn flush_read(&mut self) { + while self.status().contains(OUTPUT_FULL) { + print!("FLUSH: {:X}\n", self.data.read()); + } + } + + fn command(&mut self, command: Command) { + self.wait_write(); + self.command.write(command as u8); + } + + fn read(&mut self) -> u8 { + self.wait_read(); + self.data.read() + } + + fn write(&mut self, data: u8) { + self.wait_write(); + self.data.write(data); + } + + fn config(&mut self) -> ConfigFlags { + self.command(Command::ReadConfig); + ConfigFlags::from_bits_truncate(self.read()) + } + + fn set_config(&mut self, config: ConfigFlags) { + self.command(Command::WriteConfig); + self.write(config.bits()); + } + + fn keyboard_command(&mut self, command: KeyboardCommand) -> u8 { + self.write(command as u8); + self.read() + } + + fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> u8 { + self.write(command as u8); + assert_eq!(self.read(), 0xFA); + self.write(data as u8); + self.read() + } + + fn mouse_command(&mut self, command: MouseCommand) -> u8 { + self.command(Command::WriteSecond); + self.write(command as u8); + self.read() + } + + fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> u8 { + self.command(Command::WriteSecond); + self.write(command as u8); + assert_eq!(self.read(), 0xFA); + self.command(Command::WriteSecond); + self.write(data as u8); + self.read() + } + + pub fn init(&mut self) -> bool { + // Disable devices + self.command(Command::DisableFirst); + self.command(Command::DisableSecond); + + // Clear remaining data + self.flush_read(); + + // Disable clocks, disable interrupts, and disable translate + { + let mut config = self.config(); + config.insert(FIRST_DISABLED); + config.insert(SECOND_DISABLED); + config.remove(FIRST_TRANSLATE); + config.remove(FIRST_INTERRUPT); + config.remove(SECOND_INTERRUPT); + self.set_config(config); + } + + // Perform the self test + self.command(Command::TestController); + assert_eq!(self.read(), 0x55); + + // Enable devices + self.command(Command::EnableFirst); + self.command(Command::EnableSecond); + + // Reset keyboard + assert_eq!(self.keyboard_command(KeyboardCommand::Reset), 0xFA); + assert_eq!(self.read(), 0xAA); + self.flush_read(); + + // Set scancode set to 2 + assert_eq!(self.keyboard_command_data(KeyboardCommandData::ScancodeSet, 2), 0xFA); + + // Reset mouse and set up scroll + // TODO: Check for ack + assert_eq!(self.mouse_command(MouseCommand::Reset), 0xFA); + assert_eq!(self.read(), 0xAA); + assert_eq!(self.read(), 0x00); + self.flush_read(); + + // Enable extra packet on mouse + assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA); + assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 100), 0xFA); + assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 80), 0xFA); + assert_eq!(self.mouse_command(MouseCommand::GetDeviceId), 0xFA); + let mouse_id = self.read(); + let mouse_extra = mouse_id == 3; + + // Set sample rate to maximum + assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA); + + // Enable data reporting + assert_eq!(self.keyboard_command(KeyboardCommand::EnableReporting), 0xFA); + assert_eq!(self.mouse_command(MouseCommand::EnableReporting), 0xFA); + + // Enable clocks and interrupts + { + let mut config = self.config(); + config.remove(FIRST_DISABLED); + config.remove(SECOND_DISABLED); + config.insert(FIRST_TRANSLATE); + config.insert(FIRST_INTERRUPT); + config.insert(SECOND_INTERRUPT); + self.set_config(config); + } + + self.flush_read(); + + mouse_extra + } +} diff --git a/ps2d/src/keyboard.rs b/ps2d/src/keyboard.rs new file mode 100644 index 0000000000..109819a725 --- /dev/null +++ b/ps2d/src/keyboard.rs @@ -0,0 +1,34 @@ +use std::fs::File; +use std::io::{Read, Write}; +use std::mem; +use std::thread; + +use keymap; + +pub fn keyboard() { + let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1"); + + loop { + let mut irqs = [0; 8]; + if file.read(&mut irqs).expect("ps2d: failed to read irq:1") >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + let (scancode, pressed) = if data >= 0x80 { + (data - 0x80, false) + } else { + (data, true) + }; + + if pressed { + print!("{}", keymap::get_char(scancode)); + } + + file.write(&irqs).expect("ps2d: failed to write irq:1"); + } else { + thread::yield_now(); + } + } +} diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index f5818a6b7a..4a3888eab8 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -1,77 +1,42 @@ #![feature(asm)] +#[macro_use] +extern crate bitflags; +extern crate io; extern crate syscall; -use std::fs::File; -use std::io::{Read, Write}; -use std::mem; use std::thread; use syscall::iopl; +mod controller; +mod keyboard; mod keymap; - -fn keyboard() { - let mut file = File::open("irq:1").expect("pskbd: failed to open irq:1"); - - loop { - let mut irqs = [0; 8]; - if file.read(&mut irqs).expect("pskbd: failed to read irq:1") >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - let (scancode, pressed) = if data >= 0x80 { - (data - 0x80, false) - } else { - (data, true) - }; - println!("pskbd: IRQ {}: {:X}: {:X}: {}: {}", unsafe { *(irqs.as_ptr() as *const usize) }, data, scancode, keymap::get_char(scancode), pressed); - - file.write(&irqs).expect("pskbd: failed to write irq:1"); - } else { - thread::yield_now(); - } - } -} - -fn mouse() { - let mut file = File::open("irq:12").expect("psmsd: failed to open irq:12"); - - loop { - let mut irqs = [0; 8]; - if file.read(&mut irqs).expect("psmsd: failed to read irq:12") >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - println!("psmsd: IRQ {}: {:X}", unsafe { *(irqs.as_ptr() as *const usize) }, data); - - file.write(&irqs).expect("psmsd: failed to write irq:12"); - } else { - thread::yield_now(); - } - } -} +mod mouse; fn main() { + unsafe { + iopl(3).expect("ps2d: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + let extra_packet = controller::Ps2::new().init(); + thread::spawn(|| { unsafe { - iopl(3).expect("pskbd: failed to get I/O permission"); + iopl(3).expect("ps2d: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); } - keyboard(); + keyboard::keyboard(); }); - thread::spawn(|| { + thread::spawn(move || { unsafe { - iopl(3).expect("psmsd: failed to get I/O permission"); + iopl(3).expect("ps2d: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); } - mouse(); + mouse::mouse(extra_packet); }); } diff --git a/ps2d/src/mouse.rs b/ps2d/src/mouse.rs new file mode 100644 index 0000000000..f273de9670 --- /dev/null +++ b/ps2d/src/mouse.rs @@ -0,0 +1,73 @@ +use std::fs::File; +use std::io::{Read, Write}; +use std::mem; +use std::thread; + +bitflags! { + flags MousePacketFlags: u8 { + const LEFT_BUTTON = 1, + const RIGHT_BUTTON = 1 << 1, + const MIDDLE_BUTTON = 1 << 2, + const ALWAYS_ON = 1 << 3, + const X_SIGN = 1 << 4, + const Y_SIGN = 1 << 5, + const X_OVERFLOW = 1 << 6, + const Y_OVERFLOW = 1 << 7 + } +} + +pub fn mouse(extra_packet: bool) { + let mut file = File::open("irq:12").expect("ps2d: failed to open irq:12"); + + let mut packets = [0; 4]; + let mut packet_i = 0; + loop { + let mut irqs = [0; 8]; + if file.read(&mut irqs).expect("ps2d: failed to read irq:12") >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + packets[packet_i] = data; + packet_i += 1; + + let flags = MousePacketFlags::from_bits_truncate(packets[0]); + if ! flags.contains(ALWAYS_ON) { + println!("MOUSE MISALIGN {:X}", packets[0]); + + packets = [0; 4]; + packet_i = 0; + } else if packet_i >= packets.len() || (!extra_packet && packet_i >= 3) { + if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { + let mut dx = packets[1] as isize; + if flags.contains(X_SIGN) { + dx -= 0x100; + } + + let mut dy = packets[2] as isize; + if flags.contains(Y_SIGN) { + dy -= 0x100; + } + + let extra = if extra_packet { + packets[3] + } else { + 0 + }; + + print!("ps2d: IRQ {:?}, {}, {}, {}\n", flags, dx, dy, extra); + } else { + println!("ps2d: overflow {:X} {:X} {:X} {:X}", packets[0], packets[1], packets[2], packets[3]); + } + + packets = [0; 4]; + packet_i = 0; + } + + file.write(&irqs).expect("ps2d: failed to write irq:12"); + } else { + thread::yield_now(); + } + } +} From a737a712540dbfdb88470548002445715d6d9913 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 08:47:16 -0600 Subject: [PATCH 0008/1301] Implement user schemes. Example in pcid. Currently deadlocks in UserInner --- pcid/src/main.rs | 16 +++++++++++++++- ps2d/src/keyboard.rs | 2 +- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 0886bef5a9..52f90b190f 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -2,8 +2,10 @@ extern crate syscall; +use std::fs::File; +use std::io::{Read, Write}; use std::thread; -use syscall::iopl; +use syscall::{iopl, Packet}; use pci::{Pci, PciBar, PciClass}; @@ -75,5 +77,17 @@ fn main() { unsafe { iopl(3).unwrap() }; enumerate_pci(); + + let mut scheme = File::create(":pci").expect("pcid: failed to create pci scheme"); + loop { + let mut packet = Packet::default(); + scheme.read(&mut packet).expect("pcid: failed to read events from pci scheme"); + + println!("{:?}", packet); + + packet.a = 0; + + scheme.write(&packet).expect("pcid: failed to write responses to pci scheme"); + } }); } diff --git a/ps2d/src/keyboard.rs b/ps2d/src/keyboard.rs index 109819a725..b0090a3ad0 100644 --- a/ps2d/src/keyboard.rs +++ b/ps2d/src/keyboard.rs @@ -5,7 +5,7 @@ use std::thread; use keymap; -pub fn keyboard() { +pub fn keyboard() { let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1"); loop { From 3e4544c4de06c5c752fc6f8533e1d377dec3c260 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 14:50:04 -0600 Subject: [PATCH 0009/1301] Grant to allow passing data to scheme handler --- pcid/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 52f90b190f..976d02a683 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -84,6 +84,9 @@ fn main() { scheme.read(&mut packet).expect("pcid: failed to read events from pci scheme"); println!("{:?}", packet); + if packet.a == 5 { + println!("{}", unsafe { ::std::str::from_utf8_unchecked(::std::slice::from_raw_parts(packet.b as *const u8, packet.c)) }); + } packet.a = 0; From f0d65c068e94aea096a52e6cb17151bcda88b3c4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 16:23:28 -0600 Subject: [PATCH 0010/1301] Create example userspace scheme. Remove kernel duplication of syscalls, use syscall crate instead --- pcid/src/main.rs | 19 +------------------ ps2d/src/controller.rs | 4 ---- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 976d02a683..0886bef5a9 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -2,10 +2,8 @@ extern crate syscall; -use std::fs::File; -use std::io::{Read, Write}; use std::thread; -use syscall::{iopl, Packet}; +use syscall::iopl; use pci::{Pci, PciBar, PciClass}; @@ -77,20 +75,5 @@ fn main() { unsafe { iopl(3).unwrap() }; enumerate_pci(); - - let mut scheme = File::create(":pci").expect("pcid: failed to create pci scheme"); - loop { - let mut packet = Packet::default(); - scheme.read(&mut packet).expect("pcid: failed to read events from pci scheme"); - - println!("{:?}", packet); - if packet.a == 5 { - println!("{}", unsafe { ::std::str::from_utf8_unchecked(::std::slice::from_raw_parts(packet.b as *const u8, packet.c)) }); - } - - packet.a = 0; - - scheme.write(&packet).expect("pcid: failed to write responses to pci scheme"); - } }); } diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 8355dba7bc..e68d4f13ec 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -1,9 +1,5 @@ use io::{Io, Pio, ReadOnly, WriteOnly}; -pub unsafe fn init() { - Ps2::new().init(); -} - bitflags! { flags StatusFlags: u8 { const OUTPUT_FULL = 1, From 492437bb9c0dcdf0d0a8fd72e8662c42ed09a37c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 21:52:45 -0600 Subject: [PATCH 0011/1301] WIP: VESA driver. Make initfs generated by code --- vesad/Cargo.toml | 6 +++ vesad/src/display.rs | 112 +++++++++++++++++++++++++++++++++++++++++ vesad/src/main.rs | 54 ++++++++++++++++++++ vesad/src/mode_info.rs | 37 ++++++++++++++ vesad/src/primitive.rs | 38 ++++++++++++++ 5 files changed, 247 insertions(+) create mode 100644 vesad/Cargo.toml create mode 100644 vesad/src/display.rs create mode 100644 vesad/src/main.rs create mode 100644 vesad/src/mode_info.rs create mode 100644 vesad/src/primitive.rs diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml new file mode 100644 index 0000000000..eb9335bef5 --- /dev/null +++ b/vesad/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "vesad" +version = "0.1.0" + +[dependencies] +syscall = { path = "../../syscall/" } diff --git a/vesad/src/display.rs b/vesad/src/display.rs new file mode 100644 index 0000000000..f1befd36db --- /dev/null +++ b/vesad/src/display.rs @@ -0,0 +1,112 @@ +use std::cmp; + +use primitive::{fast_set, fast_set64, fast_copy64}; + +static FONT: &'static [u8] = include_bytes!("../../../res/unifont.font"); + +/// A display +pub struct Display { + pub width: usize, + pub height: usize, + pub onscreen: &'static mut [u32], + pub offscreen: &'static mut [u32], +} + +impl Display { + pub fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display { + Display { + width: width, + height: height, + onscreen: onscreen, + offscreen: offscreen, + } + } + + /// Draw a rectangle + pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) { + let start_y = cmp::min(self.height - 1, y); + let end_y = cmp::min(self.height, y + h); + + let start_x = cmp::min(self.width - 1, x); + let len = cmp::min(self.width, x + w) - start_x; + + let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; + let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize; + + let stride = self.width * 4; + + let offset = y * stride + start_x * 4; + offscreen_ptr += offset; + onscreen_ptr += offset; + + let mut rows = end_y - start_y; + while rows > 0 { + unsafe { + fast_set(offscreen_ptr as *mut u32, color, len); + fast_set(onscreen_ptr as *mut u32, color, len); + } + offscreen_ptr += stride; + onscreen_ptr += stride; + rows -= 1; + } + } + + /// Draw a character + fn char(&mut self, x: usize, y: usize, character: char, color: u32) { + if x + 8 <= self.width && y + 16 <= self.height { + let mut font_i = 16 * (character as usize); + let font_end = font_i + 16; + if font_end <= FONT.len() { + let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; + let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize; + + let stride = self.width * 4; + + let offset = y * stride + x * 4; + offscreen_ptr += offset; + onscreen_ptr += offset; + + while font_i < font_end { + let mut row_data = FONT[font_i]; + let mut col = 8; + while col > 0 { + col -= 1; + if row_data & 1 == 1 { + unsafe { + *((offscreen_ptr + col * 4) as *mut u32) = color; + } + } + row_data = row_data >> 1; + } + + unsafe { + fast_copy64(onscreen_ptr as *mut u64, offscreen_ptr as *const u64, 4); + } + + offscreen_ptr += stride; + onscreen_ptr += stride; + font_i += 1; + } + } + } + } + + /// Scroll display + pub fn scroll(&mut self, rows: usize, color: u32) { + let data = (color as u64) << 32 | color as u64; + + let width = self.width/2; + let height = self.height; + if rows > 0 && rows < height { + let off1 = rows * width; + let off2 = height * width - off1; + unsafe { + let data_ptr = self.offscreen.as_mut_ptr() as *mut u64; + fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2); + fast_set64(data_ptr.offset(off2 as isize), data, off1); + + fast_copy64(self.onscreen.as_mut_ptr() as *mut u64, data_ptr, off1 + off2); + } + } + } +} diff --git a/vesad/src/main.rs b/vesad/src/main.rs new file mode 100644 index 0000000000..c85b3df466 --- /dev/null +++ b/vesad/src/main.rs @@ -0,0 +1,54 @@ +#![feature(alloc)] +#![feature(asm)] +#![feature(heap_api)] + +extern crate alloc; +extern crate syscall; + +use std::fs::File; +use std::{slice, thread}; +use syscall::{physmap, physunmap, MAP_WRITE, MAP_WRITE_COMBINE}; + +use display::Display; +use mode_info::VBEModeInfo; +use primitive::fast_set64; + +pub mod display; +pub mod mode_info; +pub mod primitive; + +fn main() { + let width; + let height; + let physbaseptr; + + { + let mode_info = unsafe { &*(physmap(0x5200, 4096, 0).expect("vesad: failed to map VBE info") as *const VBEModeInfo) }; + + width = mode_info.xresolution as usize; + height = mode_info.yresolution as usize; + physbaseptr = mode_info.physbaseptr as usize; + + unsafe { let _ = physunmap(mode_info as *const _ as usize); } + } + + if physbaseptr > 0 { + let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); + thread::spawn(move || { + let size = width * height; + + let onscreen = unsafe { physmap(physbaseptr as usize, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; + unsafe { fast_set64(onscreen as *mut u64, 0, size/2) }; + + let offscreen = unsafe { alloc::heap::allocate(size * 4, 4096) }; + unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; + + let mut display = Display::new(width, height, + unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, + unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } + ); + + display.rect(100, 100, 100, 100, 0xFF0000); + }); + } +} diff --git a/vesad/src/mode_info.rs b/vesad/src/mode_info.rs new file mode 100644 index 0000000000..7d59af6452 --- /dev/null +++ b/vesad/src/mode_info.rs @@ -0,0 +1,37 @@ +/// The info of the VBE mode +#[derive(Copy, Clone, Default, Debug)] +#[repr(packed)] +pub struct VBEModeInfo { + attributes: u16, + win_a: u8, + win_b: u8, + granularity: u16, + winsize: u16, + segment_a: u16, + segment_b: u16, + winfuncptr: u32, + bytesperscanline: u16, + pub xresolution: u16, + pub yresolution: u16, + xcharsize: u8, + ycharsize: u8, + numberofplanes: u8, + bitsperpixel: u8, + numberofbanks: u8, + memorymodel: u8, + banksize: u8, + numberofimagepages: u8, + unused: u8, + redmasksize: u8, + redfieldposition: u8, + greenmasksize: u8, + greenfieldposition: u8, + bluemasksize: u8, + bluefieldposition: u8, + rsvdmasksize: u8, + rsvdfieldposition: u8, + directcolormodeinfo: u8, + pub physbaseptr: u32, + offscreenmemoryoffset: u32, + offscreenmemsize: u16, +} diff --git a/vesad/src/primitive.rs b/vesad/src/primitive.rs new file mode 100644 index 0000000000..e3bdc25258 --- /dev/null +++ b/vesad/src/primitive.rs @@ -0,0 +1,38 @@ +#[cfg(target_arch = "x86_64")] +#[allow(unused_assignments)] +#[inline(always)] +#[cold] +pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) { + asm!("cld + rep movsq" + : + : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len) + : "cc", "memory" + : "intel", "volatile"); +} + +#[cfg(target_arch = "x86_64")] +#[allow(unused_assignments)] +#[inline(always)] +#[cold] +pub unsafe fn fast_set(dst: *mut u32, src: u32, len: usize) { + asm!("cld + rep stosd" + : + : "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len) + : "cc", "memory" + : "intel", "volatile"); +} + +#[cfg(target_arch = "x86_64")] +#[allow(unused_assignments)] +#[inline(always)] +#[cold] +pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) { + asm!("cld + rep stosq" + : + : "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len) + : "cc", "memory" + : "intel", "volatile"); +} From 6d8a75ff9bf35c40fd39484d8295140ef0c6050d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 20 Sep 2016 21:56:40 -0600 Subject: [PATCH 0012/1301] Launch ion --- vesad/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index c85b3df466..1cd185a322 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -33,8 +33,9 @@ fn main() { } if physbaseptr > 0 { - let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); thread::spawn(move || { + let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); + let size = width * height; let onscreen = unsafe { physmap(physbaseptr as usize, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; From a77bc89a9f9fc27bbac476ad73606c2b6287ad2e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 21 Sep 2016 12:18:48 -0600 Subject: [PATCH 0013/1301] WIP: Userspace console --- vesad/Cargo.toml | 1 + vesad/src/display.rs | 8 +-- vesad/src/main.rs | 115 +++++++++++++++++++++++++++++++++++++---- vesad/src/primitive.rs | 15 +++++- 4 files changed, 125 insertions(+), 14 deletions(-) diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index eb9335bef5..f8482a4847 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -3,4 +3,5 @@ name = "vesad" version = "0.1.0" [dependencies] +ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" } syscall = { path = "../../syscall/" } diff --git a/vesad/src/display.rs b/vesad/src/display.rs index f1befd36db..9975c8d3d5 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -1,6 +1,6 @@ use std::cmp; -use primitive::{fast_set, fast_set64, fast_copy64}; +use primitive::{fast_set32, fast_set64, fast_copy64}; static FONT: &'static [u8] = include_bytes!("../../../res/unifont.font"); @@ -42,8 +42,8 @@ impl Display { let mut rows = end_y - start_y; while rows > 0 { unsafe { - fast_set(offscreen_ptr as *mut u32, color, len); - fast_set(onscreen_ptr as *mut u32, color, len); + fast_set32(offscreen_ptr as *mut u32, color, len); + fast_set32(onscreen_ptr as *mut u32, color, len); } offscreen_ptr += stride; onscreen_ptr += stride; @@ -52,7 +52,7 @@ impl Display { } /// Draw a character - fn char(&mut self, x: usize, y: usize, character: char, color: u32) { + pub fn char(&mut self, x: usize, y: usize, character: char, color: u32) { if x + 8 <= self.width && y + 16 <= self.height { let mut font_i = 16 * (character as usize); let font_end = font_i + 16; diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 1cd185a322..a0022d5dc9 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -1,22 +1,108 @@ #![feature(alloc)] #![feature(asm)] #![feature(heap_api)] +#![feature(question_mark)] extern crate alloc; +extern crate ransid; extern crate syscall; +use std::cell::RefCell; +use std::collections::BTreeMap; use std::fs::File; -use std::{slice, thread}; -use syscall::{physmap, physunmap, MAP_WRITE, MAP_WRITE_COMBINE}; +use std::io::{Read, Write}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::{cmp, slice, thread}; +use ransid::{Console, Event}; +use syscall::{physmap, physunmap, Error, EINVAL, EBADF, Packet, Result, Scheme, SEEK_SET, SEEK_CUR, SEEK_END, MAP_WRITE, MAP_WRITE_COMBINE}; use display::Display; use mode_info::VBEModeInfo; -use primitive::fast_set64; +use primitive::{fast_copy, fast_set64}; pub mod display; pub mod mode_info; pub mod primitive; +struct DisplayScheme { + console: RefCell, + display: RefCell, + next_id: AtomicUsize, + handles: RefCell> +} + +impl Scheme for DisplayScheme { + fn open(&self, _path: &[u8], _flags: usize) -> Result { + Ok(0) + } + + fn dup(&self, _id: usize) -> Result { + Ok(0) + } + + fn write(&self, _id: usize, buf: &[u8]) -> Result { + let mut display = self.display.borrow_mut(); + self.console.borrow_mut().write(buf, |event| { + match event { + Event::Char { x, y, c, color, .. } => display.char(x * 8, y * 16, c, color.data), + Event::Rect { x, y, w, h, color } => display.rect(x * 8, y * 16, w * 8, h * 16, color.data), + Event::Scroll { rows, color } => display.scroll(rows * 16, color.data) + } + }); + Ok(buf.len()) + } + + fn close(&self, id: usize) -> Result { + Ok(0) + } +} + +/* +struct DisplayScheme { + display: RefCell, + next_id: AtomicUsize, + handles: RefCell> +} + +impl Scheme for DisplayScheme { + fn open(&self, _path: &[u8], _flags: usize) -> Result { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.borrow_mut().insert(id, 0); + Ok(id) + } + + fn write(&self, id: usize, buf: &[u8]) -> Result { + let mut handles = self.handles.borrow_mut(); + let mut seek = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + let mut display = self.display.borrow_mut(); + let len = cmp::min(buf.len(), display.offscreen.len() * 4 - *seek); + unsafe { + fast_copy((display.offscreen.as_mut_ptr() as usize + *seek) as *mut u8, buf.as_ptr(), len); + fast_copy((display.onscreen.as_mut_ptr() as usize + *seek) as *mut u8, buf.as_ptr(), len); + } + *seek += len; + Ok(len) + } + + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { + let mut handles = self.handles.borrow_mut(); + let mut seek = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + let len = self.display.borrow().offscreen.len() * 4; + *seek = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *seek as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + Ok(*seek) + } + + fn close(&self, id: usize) -> Result { + self.handles.borrow_mut().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) + } +} +*/ + fn main() { let width; let height; @@ -35,7 +121,7 @@ fn main() { if physbaseptr > 0 { thread::spawn(move || { let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); - + let size = width * height; let onscreen = unsafe { physmap(physbaseptr as usize, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; @@ -44,12 +130,23 @@ fn main() { let offscreen = unsafe { alloc::heap::allocate(size * 4, 4096) }; unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; - let mut display = Display::new(width, height, - unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, - unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } - ); + let scheme = DisplayScheme { + console: RefCell::new(Console::new(width/8, height/16)), + display: RefCell::new(Display::new(width, height, + unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, + unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } + )), + next_id: AtomicUsize::new(0), + handles: RefCell::new(BTreeMap::new()) + }; - display.rect(100, 100, 100, 100, 0xFF0000); + loop { + let mut packet = Packet::default(); + socket.read(&mut packet); + //println!("vesad: {:?}", packet); + scheme.handle(&mut packet); + socket.write(&packet); + } }); } } diff --git a/vesad/src/primitive.rs b/vesad/src/primitive.rs index e3bdc25258..8427745485 100644 --- a/vesad/src/primitive.rs +++ b/vesad/src/primitive.rs @@ -1,3 +1,16 @@ +#[cfg(target_arch = "x86_64")] +#[allow(unused_assignments)] +#[inline(always)] +#[cold] +pub unsafe fn fast_copy(dst: *mut u8, src: *const u8, len: usize) { + asm!("cld + rep movsb" + : + : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len) + : "cc", "memory" + : "intel", "volatile"); +} + #[cfg(target_arch = "x86_64")] #[allow(unused_assignments)] #[inline(always)] @@ -15,7 +28,7 @@ pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) { #[allow(unused_assignments)] #[inline(always)] #[cold] -pub unsafe fn fast_set(dst: *mut u32, src: u32, len: usize) { +pub unsafe fn fast_set32(dst: *mut u32, src: u32, len: usize) { asm!("cld rep stosd" : From dbb554f8857a5ebb5ff27d6ef304ee4f2f578cd2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 21 Sep 2016 16:46:16 -0600 Subject: [PATCH 0014/1301] Increase optimization, fix clobbers in vesad --- vesad/src/primitive.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/vesad/src/primitive.rs b/vesad/src/primitive.rs index 8427745485..16c2536a24 100644 --- a/vesad/src/primitive.rs +++ b/vesad/src/primitive.rs @@ -1,5 +1,4 @@ #[cfg(target_arch = "x86_64")] -#[allow(unused_assignments)] #[inline(always)] #[cold] pub unsafe fn fast_copy(dst: *mut u8, src: *const u8, len: usize) { @@ -7,12 +6,11 @@ pub unsafe fn fast_copy(dst: *mut u8, src: *const u8, len: usize) { rep movsb" : : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len) - : "cc", "memory" + : "cc", "memory", "rdi", "rsi", "rcx" : "intel", "volatile"); } #[cfg(target_arch = "x86_64")] -#[allow(unused_assignments)] #[inline(always)] #[cold] pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) { @@ -20,12 +18,11 @@ pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) { rep movsq" : : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len) - : "cc", "memory" + : "cc", "memory", "rdi", "rsi", "rcx" : "intel", "volatile"); } #[cfg(target_arch = "x86_64")] -#[allow(unused_assignments)] #[inline(always)] #[cold] pub unsafe fn fast_set32(dst: *mut u32, src: u32, len: usize) { @@ -33,12 +30,11 @@ pub unsafe fn fast_set32(dst: *mut u32, src: u32, len: usize) { rep stosd" : : "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len) - : "cc", "memory" + : "cc", "memory", "rdi", "rcx" : "intel", "volatile"); } #[cfg(target_arch = "x86_64")] -#[allow(unused_assignments)] #[inline(always)] #[cold] pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) { @@ -46,6 +42,6 @@ pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) { rep stosq" : : "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len) - : "cc", "memory" + : "cc", "memory", "rdi", "rcx" : "intel", "volatile"); } From b9a255443212f11ff0e3adefcfcefabc242a5d81 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 22 Sep 2016 08:43:22 -0600 Subject: [PATCH 0015/1301] Add login process. Remove debugging. Fix order of arguments --- vesad/src/main.rs | 72 ++++++++--------------------------------------- 1 file changed, 12 insertions(+), 60 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index a0022d5dc9..7cbed6ecc8 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -8,17 +8,15 @@ extern crate ransid; extern crate syscall; use std::cell::RefCell; -use std::collections::BTreeMap; use std::fs::File; use std::io::{Read, Write}; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::{cmp, slice, thread}; +use std::{slice, thread}; use ransid::{Console, Event}; -use syscall::{physmap, physunmap, Error, EINVAL, EBADF, Packet, Result, Scheme, SEEK_SET, SEEK_CUR, SEEK_END, MAP_WRITE, MAP_WRITE_COMBINE}; +use syscall::{physmap, physunmap, Packet, Result, Scheme, MAP_WRITE, MAP_WRITE_COMBINE}; use display::Display; use mode_info::VBEModeInfo; -use primitive::{fast_copy, fast_set64}; +use primitive::fast_set64; pub mod display; pub mod mode_info; @@ -26,9 +24,7 @@ pub mod primitive; struct DisplayScheme { console: RefCell, - display: RefCell, - next_id: AtomicUsize, - handles: RefCell> + display: RefCell } impl Scheme for DisplayScheme { @@ -40,6 +36,10 @@ impl Scheme for DisplayScheme { Ok(0) } + fn fsync(&self, _id: usize) -> Result { + Ok(0) + } + fn write(&self, _id: usize, buf: &[u8]) -> Result { let mut display = self.display.borrow_mut(); self.console.borrow_mut().write(buf, |event| { @@ -52,57 +52,11 @@ impl Scheme for DisplayScheme { Ok(buf.len()) } - fn close(&self, id: usize) -> Result { + fn close(&self, _id: usize) -> Result { Ok(0) } } -/* -struct DisplayScheme { - display: RefCell, - next_id: AtomicUsize, - handles: RefCell> -} - -impl Scheme for DisplayScheme { - fn open(&self, _path: &[u8], _flags: usize) -> Result { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.borrow_mut().insert(id, 0); - Ok(id) - } - - fn write(&self, id: usize, buf: &[u8]) -> Result { - let mut handles = self.handles.borrow_mut(); - let mut seek = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let mut display = self.display.borrow_mut(); - let len = cmp::min(buf.len(), display.offscreen.len() * 4 - *seek); - unsafe { - fast_copy((display.offscreen.as_mut_ptr() as usize + *seek) as *mut u8, buf.as_ptr(), len); - fast_copy((display.onscreen.as_mut_ptr() as usize + *seek) as *mut u8, buf.as_ptr(), len); - } - *seek += len; - Ok(len) - } - - fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { - let mut handles = self.handles.borrow_mut(); - let mut seek = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let len = self.display.borrow().offscreen.len() * 4; - *seek = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *seek as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - Ok(*seek) - } - - fn close(&self, id: usize) -> Result { - self.handles.borrow_mut().remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) - } -} -*/ - fn main() { let width; let height; @@ -135,17 +89,15 @@ fn main() { display: RefCell::new(Display::new(width, height, unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } - )), - next_id: AtomicUsize::new(0), - handles: RefCell::new(BTreeMap::new()) + )) }; loop { let mut packet = Packet::default(); - socket.read(&mut packet); + socket.read(&mut packet).expect("vesad: failed to read display scheme"); //println!("vesad: {:?}", packet); scheme.handle(&mut packet); - socket.write(&packet); + socket.write(&packet).expect("vesad: failed to write display scheme"); } }); } From 0cbc3eacf7b86bfb4e73e95b69e47b116b54f14d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 22 Sep 2016 10:10:27 -0600 Subject: [PATCH 0016/1301] Add wnohang, make PS/2 driver write input to display scheme, which then passes it to the shell --- ps2d/src/keyboard.rs | 21 ++++++-- ps2d/src/keymap.rs | 126 ++++++++++++++++++++++--------------------- vesad/src/main.rs | 70 ++++++++++++++++++------ 3 files changed, 134 insertions(+), 83 deletions(-) diff --git a/ps2d/src/keyboard.rs b/ps2d/src/keyboard.rs index b0090a3ad0..ec470306b8 100644 --- a/ps2d/src/keyboard.rs +++ b/ps2d/src/keyboard.rs @@ -5,9 +5,12 @@ use std::thread; use keymap; -pub fn keyboard() { +pub fn keyboard() { let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1"); + let mut input = File::open("display:input").expect("ps2d: failed to open display:input"); + let mut lshift = false; + let mut rshift = false; loop { let mut irqs = [0; 8]; if file.read(&mut irqs).expect("ps2d: failed to read irq:1") >= mem::size_of::() { @@ -16,17 +19,25 @@ pub fn keyboard() { asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); } + file.write(&irqs).expect("ps2d: failed to write irq:1"); + let (scancode, pressed) = if data >= 0x80 { (data - 0x80, false) } else { (data, true) }; - if pressed { - print!("{}", keymap::get_char(scancode)); + if scancode == 0x2A { + lshift = pressed; + } else if scancode == 0x36 { + rshift = pressed; + } else if pressed { + let c = keymap::get_char(scancode, lshift || rshift); + if c != '\0' { + print!("{}", c); + input.write(&[c as u8]).expect("ps2d: failed to write input"); + } } - - file.write(&irqs).expect("ps2d: failed to write irq:1"); } else { thread::yield_now(); } diff --git a/ps2d/src/keymap.rs b/ps2d/src/keymap.rs index 699e3ad144..0f7f6341a9 100644 --- a/ps2d/src/keymap.rs +++ b/ps2d/src/keymap.rs @@ -1,67 +1,71 @@ -static ENGLISH: [[char; 3]; 58] = [ - ['\0', '\0', '\0'], - ['\x1B', '\x1B', '\x1B'], - ['1', '!', '1'], - ['2', '@', '2'], - ['3', '#', '3'], - ['4', '$', '4'], - ['5', '%', '5'], - ['6', '^', '6'], - ['7', '&', '7'], - ['8', '*', '8'], - ['9', '(', '9'], - ['0', ')', '0'], - ['-', '_', '-'], - ['=', '+', '='], - ['\0', '\0', '\0'], - ['\t', '\t', '\t'], - ['q', 'Q', 'q'], - ['w', 'W', 'w'], - ['e', 'E', 'e'], - ['r', 'R', 'r'], - ['t', 'T', 't'], - ['y', 'Y', 'y'], - ['u', 'U', 'u'], - ['i', 'I', 'i'], - ['o', 'O', 'o'], - ['p', 'P', 'p'], - ['[', '{', '['], - [']', '}', ']'], - ['\n', '\n', '\n'], - ['\0', '\0', '\0'], - ['a', 'A', 'a'], - ['s', 'S', 's'], - ['d', 'D', 'd'], - ['f', 'F', 'f'], - ['g', 'G', 'g'], - ['h', 'H', 'h'], - ['j', 'J', 'j'], - ['k', 'K', 'k'], - ['l', 'L', 'l'], - [';', ':', ';'], - ['\'', '"', '\''], - ['`', '~', '`'], - ['\0', '\0', '\0'], - ['\\', '|', '\\'], - ['z', 'Z', 'z'], - ['x', 'X', 'x'], - ['c', 'C', 'c'], - ['v', 'V', 'v'], - ['b', 'B', 'b'], - ['n', 'N', 'n'], - ['m', 'M', 'm'], - [',', '<', ','], - ['.', '>', '.'], - ['/', '?', '/'], - ['\0', '\0', '\0'], - ['\0', '\0', '\0'], - ['\0', '\0', '\0'], - [' ', ' ', ' '] +static ENGLISH: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['1', '!'], + ['2', '@'], + ['3', '#'], + ['4', '$'], + ['5', '%'], + ['6', '^'], + ['7', '&'], + ['8', '*'], + ['9', '('], + ['0', ')'], + ['-', '_'], + ['=', '+'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['q', 'Q'], + ['w', 'W'], + ['e', 'E'], + ['r', 'R'], + ['t', 'T'], + ['y', 'Y'], + ['u', 'U'], + ['i', 'I'], + ['o', 'O'], + ['p', 'P'], + ['[', '{'], + [']', '}'], + ['\n', '\n'], + ['\0', '\0'], + ['a', 'A'], + ['s', 'S'], + ['d', 'D'], + ['f', 'F'], + ['g', 'G'], + ['h', 'H'], + ['j', 'J'], + ['k', 'K'], + ['l', 'L'], + [';', ':'], + ['\'', '"'], + ['`', '~'], + ['\0', '\0'], + ['\\', '|'], + ['z', 'Z'], + ['x', 'X'], + ['c', 'C'], + ['v', 'V'], + ['b', 'B'], + ['n', 'N'], + ['m', 'M'], + [',', '<'], + ['.', '>'], + ['/', '?'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] ]; -pub fn get_char(scancode: u8) -> char { +pub fn get_char(scancode: u8, shift: bool) -> char { if let Some(c) = ENGLISH.get(scancode as usize) { - c[0] + if shift { + c[1] + } else { + c[0] + } } else { '\0' } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 7cbed6ecc8..9e0aef9a99 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -8,6 +8,7 @@ extern crate ransid; extern crate syscall; use std::cell::RefCell; +use std::collections::VecDeque; use std::fs::File; use std::io::{Read, Write}; use std::{slice, thread}; @@ -24,32 +25,55 @@ pub mod primitive; struct DisplayScheme { console: RefCell, - display: RefCell + display: RefCell, + input: RefCell> } impl Scheme for DisplayScheme { - fn open(&self, _path: &[u8], _flags: usize) -> Result { - Ok(0) + fn open(&self, path: &[u8], _flags: usize) -> Result { + if path == b"input" { + Ok(1) + } else { + Ok(0) + } } - fn dup(&self, _id: usize) -> Result { - Ok(0) + fn dup(&self, id: usize) -> Result { + Ok(id) } fn fsync(&self, _id: usize) -> Result { Ok(0) } - fn write(&self, _id: usize, buf: &[u8]) -> Result { - let mut display = self.display.borrow_mut(); - self.console.borrow_mut().write(buf, |event| { - match event { - Event::Char { x, y, c, color, .. } => display.char(x * 8, y * 16, c, color.data), - Event::Rect { x, y, w, h, color } => display.rect(x * 8, y * 16, w * 8, h * 16, color.data), - Event::Scroll { rows, color } => display.scroll(rows * 16, color.data) + fn read(&self, _id: usize, buf: &mut [u8]) -> Result { + let mut i = 0; + let mut input = self.input.borrow_mut(); + while i < buf.len() && ! input.is_empty() { + buf[i] = input.pop_front().unwrap(); + i += 1; + } + Ok(i) + } + + fn write(&self, id: usize, buf: &[u8]) -> Result { + if id == 1 { + let mut input = self.input.borrow_mut(); + for &b in buf.iter() { + input.push_back(b); } - }); - Ok(buf.len()) + Ok(buf.len()) + } else { + let mut display = self.display.borrow_mut(); + self.console.borrow_mut().write(buf, |event| { + match event { + Event::Char { x, y, c, color, .. } => display.char(x * 8, y * 16, c, color.data), + Event::Rect { x, y, w, h, color } => display.rect(x * 8, y * 16, w * 8, h * 16, color.data), + Event::Scroll { rows, color } => display.scroll(rows * 16, color.data) + } + }); + Ok(buf.len()) + } } fn close(&self, _id: usize) -> Result { @@ -89,15 +113,27 @@ fn main() { display: RefCell::new(Display::new(width, height, unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } - )) + )), + input: RefCell::new(VecDeque::new()) }; + let mut blocked = VecDeque::new(); loop { let mut packet = Packet::default(); socket.read(&mut packet).expect("vesad: failed to read display scheme"); //println!("vesad: {:?}", packet); - scheme.handle(&mut packet); - socket.write(&packet).expect("vesad: failed to write display scheme"); + if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.input.borrow().is_empty() { + blocked.push_back(packet); + } else { + scheme.handle(&mut packet); + socket.write(&packet).expect("vesad: failed to write display scheme"); + } + while ! scheme.input.borrow().is_empty() { + if let Some(mut packet) = blocked.pop_front() { + scheme.handle(&mut packet); + socket.write(&packet).expect("vesad: failed to write display scheme"); + } + } } }); } From 7253270bd8a783972fb7c5397d8ba2b6442e3487 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 22 Sep 2016 10:23:00 -0600 Subject: [PATCH 0017/1301] Do not write ps2d keyboard to serial --- ps2d/src/keyboard.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ps2d/src/keyboard.rs b/ps2d/src/keyboard.rs index ec470306b8..e192bd29ed 100644 --- a/ps2d/src/keyboard.rs +++ b/ps2d/src/keyboard.rs @@ -34,7 +34,6 @@ pub fn keyboard() { } else if pressed { let c = keymap::get_char(scancode, lshift || rshift); if c != '\0' { - print!("{}", c); input.write(&[c as u8]).expect("ps2d: failed to write input"); } } From 690a4334214cda6f914a8cc3d1167fed52a67db3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 22 Sep 2016 16:15:38 -0600 Subject: [PATCH 0018/1301] Switch to using rusttype --- vesad/Cargo.toml | 1 + vesad/src/display.rs | 81 ++++++++++++++++++++++++++------------------ vesad/src/main.rs | 2 +- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index f8482a4847..cf0c2fa04b 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -4,4 +4,5 @@ version = "0.1.0" [dependencies] ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" } +rusttype = { git = "https://github.com/dylanede/rusttype.git" } syscall = { path = "../../syscall/" } diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 9975c8d3d5..2f849dd0fb 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -1,8 +1,15 @@ +extern crate rusttype; + use std::cmp; use primitive::{fast_set32, fast_set64, fast_copy64}; -static FONT: &'static [u8] = include_bytes!("../../../res/unifont.font"); +use self::rusttype::{Font, FontCollection, Scale, point}; + +static FONT: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono.ttf"); +static FONT_BOLD: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Bold.ttf"); +static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-BoldOblique.ttf"); +static FONT_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf"); /// A display pub struct Display { @@ -10,6 +17,10 @@ pub struct Display { pub height: usize, pub onscreen: &'static mut [u32], pub offscreen: &'static mut [u32], + pub font: Font<'static>, + pub font_bold: Font<'static>, + pub font_bold_italic: Font<'static>, + pub font_italic: Font<'static> } impl Display { @@ -19,6 +30,10 @@ impl Display { height: height, onscreen: onscreen, offscreen: offscreen, + font: FontCollection::from_bytes(FONT).into_font().unwrap(), + font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(), + font_bold_italic: FontCollection::from_bytes(FONT_BOLD_ITALIC).into_font().unwrap(), + font_italic: FontCollection::from_bytes(FONT_ITALIC).into_font().unwrap() } } @@ -52,42 +67,42 @@ impl Display { } /// Draw a character - pub fn char(&mut self, x: usize, y: usize, character: char, color: u32) { - if x + 8 <= self.width && y + 16 <= self.height { - let mut font_i = 16 * (character as usize); - let font_end = font_i + 16; - if font_end <= FONT.len() { - let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; - let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize; + pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, bold: bool, italic: bool) { + let width = self.width; + let height = self.height; + let offscreen = self.offscreen.as_mut_ptr(); + let onscreen = self.onscreen.as_mut_ptr(); - let stride = self.width * 4; + let font = if bold && italic { + &self.font_bold_italic + } else if bold { + &self.font_bold + } else if italic { + &self.font_italic + } else { + &self.font + }; - let offset = y * stride + x * 4; - offscreen_ptr += offset; - onscreen_ptr += offset; + if let Some(glyph) = font.glyph(character){ + let scale = Scale::uniform(16.0); + let v_metrics = font.v_metrics(scale); + let point = point(0.0, v_metrics.ascent); + glyph.scaled(scale).positioned(point).draw(|off_x, off_y, v| { + let off_x = x + off_x as usize; + let off_y = y + off_y as usize; + // There's still a possibility that the glyph clips the boundaries of the bitmap + if off_x < width && off_y < height { + let v_u = (v * 255.0) as u32; + let r = ((color >> 16) & 0xFF * v_u)/255; + let g = ((color >> 8) & 0xFF * v_u)/255; + let b = (color & 0xFF * v_u)/255; + let c = (r << 16) | (g << 8) | b; - while font_i < font_end { - let mut row_data = FONT[font_i]; - let mut col = 8; - while col > 0 { - col -= 1; - if row_data & 1 == 1 { - unsafe { - *((offscreen_ptr + col * 4) as *mut u32) = color; - } - } - row_data = row_data >> 1; - } - - unsafe { - fast_copy64(onscreen_ptr as *mut u64, offscreen_ptr as *const u64, 4); - } - - offscreen_ptr += stride; - onscreen_ptr += stride; - font_i += 1; + let index = (off_y * width + off_x) as isize; + unsafe { *offscreen.offset(index) = c; } + unsafe { *onscreen.offset(index) = c; } } - } + }); } } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 9e0aef9a99..207ad788ec 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -67,7 +67,7 @@ impl Scheme for DisplayScheme { let mut display = self.display.borrow_mut(); self.console.borrow_mut().write(buf, |event| { match event { - Event::Char { x, y, c, color, .. } => display.char(x * 8, y * 16, c, color.data), + Event::Char { x, y, c, color, bold, .. } => display.char(x * 8, y * 16, c, color.data, bold, false), Event::Rect { x, y, w, h, color } => display.rect(x * 8, y * 16, w * 8, h * 16, color.data), Event::Scroll { rows, color } => display.scroll(rows * 16, color.data) } From a6d5d23d96e562f183b94a3b6b8aa98b9ae7ef68 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 22 Sep 2016 16:57:26 -0600 Subject: [PATCH 0019/1301] Fix openlibm --- vesad/src/display.rs | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 2f849dd0fb..35640634ae 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -87,22 +87,27 @@ impl Display { let scale = Scale::uniform(16.0); let v_metrics = font.v_metrics(scale); let point = point(0.0, v_metrics.ascent); - glyph.scaled(scale).positioned(point).draw(|off_x, off_y, v| { - let off_x = x + off_x as usize; - let off_y = y + off_y as usize; - // There's still a possibility that the glyph clips the boundaries of the bitmap - if off_x < width && off_y < height { - let v_u = (v * 255.0) as u32; - let r = ((color >> 16) & 0xFF * v_u)/255; - let g = ((color >> 8) & 0xFF * v_u)/255; - let b = (color & 0xFF * v_u)/255; - let c = (r << 16) | (g << 8) | b; + let glyph = glyph.scaled(scale).positioned(point); + if let Some(bb) = glyph.pixel_bounding_box() { + glyph.draw(|off_x, off_y, v| { + let off_x = x + (off_x as i32 + bb.min.x) as usize; + let off_y = y + (off_y as i32 + bb.min.y) as usize; + // There's still a possibility that the glyph clips the boundaries of the bitmap + if off_x < width && off_y < height { + let v_u = (v * 255.0) as u32; + if v_u > 0 { + let r = (((color >> 16) & 0xFF) * v_u)/255; + let g = (((color >> 8) & 0xFF) * v_u)/255; + let b = ((color & 0xFF) * v_u)/255; + let c = (r << 16) | (g << 8) | b; - let index = (off_y * width + off_x) as isize; - unsafe { *offscreen.offset(index) = c; } - unsafe { *onscreen.offset(index) = c; } - } - }); + let index = (off_y * width + off_x) as isize; + unsafe { *offscreen.offset(index) = c; } + unsafe { *onscreen.offset(index) = c; } + } + } + }); + } } } From 2a5ff38f8d0c4a8ce149b8b40f3e253d543f5110 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 22 Sep 2016 17:11:42 -0600 Subject: [PATCH 0020/1301] Add cursor --- vesad/src/main.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 207ad788ec..f022a74204 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -65,13 +65,20 @@ impl Scheme for DisplayScheme { Ok(buf.len()) } else { let mut display = self.display.borrow_mut(); - self.console.borrow_mut().write(buf, |event| { + let mut console = self.console.borrow_mut(); + if console.x < console.w && console.y < console.h { + display.rect(console.x * 8, console.y * 16, 8, 16, 0); + } + console.write(buf, |event| { match event { Event::Char { x, y, c, color, bold, .. } => display.char(x * 8, y * 16, c, color.data, bold, false), Event::Rect { x, y, w, h, color } => display.rect(x * 8, y * 16, w * 8, h * 16, color.data), Event::Scroll { rows, color } => display.scroll(rows * 16, color.data) } }); + if console.x < console.w && console.y < console.h { + display.rect(console.x * 8, console.y * 16, 8, 16, 0xFFFFFF); + } Ok(buf.len()) } } From ffaf2160ca4e681ad337b72cda0f7b7dc44125e4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 23 Sep 2016 15:47:53 -0600 Subject: [PATCH 0021/1301] WIP: Kevent --- vesad/src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index f022a74204..41c01ba59f 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -42,6 +42,11 @@ impl Scheme for DisplayScheme { Ok(id) } + fn fevent(&self, _id: usize, flags: usize) -> Result { + println!("fevent {:X}", flags); + Ok(0) + } + fn fsync(&self, _id: usize) -> Result { Ok(0) } From 7ca0bcede855feb854d655d2829992025911d43d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 23 Sep 2016 17:54:39 -0600 Subject: [PATCH 0022/1301] Event support - demonstration in example scheme --- vesad/src/main.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 41c01ba59f..cb45f39bdd 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -13,7 +13,7 @@ use std::fs::File; use std::io::{Read, Write}; use std::{slice, thread}; use ransid::{Console, Event}; -use syscall::{physmap, physunmap, Packet, Result, Scheme, MAP_WRITE, MAP_WRITE_COMBINE}; +use syscall::{physmap, physunmap, Packet, Result, Scheme, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE}; use display::Display; use mode_info::VBEModeInfo; @@ -26,7 +26,8 @@ pub mod primitive; struct DisplayScheme { console: RefCell, display: RefCell, - input: RefCell> + input: RefCell>, + requested: RefCell } impl Scheme for DisplayScheme { @@ -43,6 +44,7 @@ impl Scheme for DisplayScheme { } fn fevent(&self, _id: usize, flags: usize) -> Result { + *self.requested.borrow_mut() = flags; println!("fevent {:X}", flags); Ok(0) } @@ -126,7 +128,8 @@ fn main() { unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } )), - input: RefCell::new(VecDeque::new()) + input: RefCell::new(VecDeque::new()), + requested: RefCell::new(0) }; let mut blocked = VecDeque::new(); @@ -134,18 +137,36 @@ fn main() { let mut packet = Packet::default(); socket.read(&mut packet).expect("vesad: failed to read display scheme"); //println!("vesad: {:?}", packet); + + // If it is a read packet, and there is no data, block it. Otherwise, handle packet if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.input.borrow().is_empty() { blocked.push_back(packet); } else { scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); } + + // If there are blocked readers, and data is available, handle them while ! scheme.input.borrow().is_empty() { if let Some(mut packet) = blocked.pop_front() { scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); + } else { + break; } } + + // If there are requested events, and data is available, send a notification + if ! scheme.input.borrow().is_empty() && *scheme.requested.borrow() & EVENT_READ == EVENT_READ { + let event_packet = Packet { + id: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: EVENT_READ, + d: scheme.input.borrow().len() + }; + socket.write(&event_packet).expect("vesad: failed to write display scheme"); + } } }); } From f79f80e5951377a4936c5369cc96ff2c0461a603 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 25 Sep 2016 16:59:25 -0600 Subject: [PATCH 0023/1301] Launch commands for each device found if specified --- pcid/Cargo.toml | 7 ++ pcid/src/config.rs | 14 ++++ pcid/src/main.rs | 171 +++++++++++++++++++++++++++++++-------------- 3 files changed, 139 insertions(+), 53 deletions(-) create mode 100644 pcid/src/config.rs diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index e6b63183f3..222032c14b 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -2,5 +2,12 @@ name = "pcid" version = "0.1.0" +[dependencies] +rustc-serialize = { git = "https://github.com/redox-os/rustc-serialize.git" } +toml = "*" + [dependencies.syscall] path = "../../syscall/" + +[replace] +"rustc-serialize:0.3.19" = { git = "https://github.com/redox-os/rustc-serialize.git" } diff --git a/pcid/src/config.rs b/pcid/src/config.rs new file mode 100644 index 0000000000..3bc4dba8df --- /dev/null +++ b/pcid/src/config.rs @@ -0,0 +1,14 @@ +#[derive(Debug, Default, RustcDecodable)] +pub struct Config { + pub drivers: Vec +} + +#[derive(Debug, Default, RustcDecodable)] +pub struct DriverConfig { + pub name: Option, + pub class: Option, + pub subclass: Option, + pub vendor: Option, + pub device: Option, + pub command: Option> +} diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 0886bef5a9..9eb0889c76 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,79 +1,144 @@ #![feature(asm)] +extern crate rustc_serialize; extern crate syscall; +extern crate toml; +use std::env; +use std::fs::File; +use std::io::Read; +use std::process::Command; use std::thread; use syscall::iopl; +use config::Config; use pci::{Pci, PciBar, PciClass}; +mod config; mod pci; -fn enumerate_pci() { - println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); +fn main() { + thread::spawn(|| { + let mut config = Config::default(); - let pci = Pci::new(); - for bus in pci.buses() { - for dev in bus.devs() { - for func in dev.funcs() { - if let Some(header) = func.header() { - print!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X}", - bus.num, dev.num, func.num, - header.vendor_id, header.device_id, - header.class, header.subclass, header.interface, header.revision); + let mut args = env::args().skip(1); + if let Some(config_path) = args.next() { + if let Ok(mut config_file) = File::open(&config_path) { + let mut config_data = String::new(); + if let Ok(_) = config_file.read_to_string(&mut config_data) { + config = toml::decode_str(&config_data).unwrap_or(Config::default()); + } + } + } - let pci_class = PciClass::from(header.class); - print!(" {:?}", pci_class); - match pci_class { - PciClass::Storage => match header.subclass { - 0x01 => { - print!(" IDE"); + println!("{:?}", config); + + unsafe { iopl(3).unwrap() }; + + println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); + + let pci = Pci::new(); + for bus in pci.buses() { + for dev in bus.devs() { + for func in dev.funcs() { + if let Some(header) = func.header() { + print!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X}", + bus.num, dev.num, func.num, + header.vendor_id, header.device_id, + header.class, header.subclass, header.interface, header.revision); + + let pci_class = PciClass::from(header.class); + print!(" {:?}", pci_class); + match pci_class { + PciClass::Storage => match header.subclass { + 0x01 => { + print!(" IDE"); + }, + 0x06 => { + print!(" SATA"); + }, + _ => () }, - 0x06 => { - print!(" SATA"); - }, - _ => () - }, - PciClass::SerialBus => match header.subclass { - 0x03 => match header.interface { - 0x00 => { - print!(" UHCI"); - }, - 0x10 => { - print!(" OHCI"); - }, - 0x20 => { - print!(" EHCI"); - }, - 0x30 => { - print!(" XHCI"); + PciClass::SerialBus => match header.subclass { + 0x03 => match header.interface { + 0x00 => { + print!(" UHCI"); + }, + 0x10 => { + print!(" OHCI"); + }, + 0x20 => { + print!(" EHCI"); + }, + 0x30 => { + print!(" XHCI"); + }, + _ => () }, _ => () }, _ => () - }, - _ => () - } + } - for i in 0..header.bars.len() { - match PciBar::from(header.bars[i]) { - PciBar::None => (), - PciBar::Memory(address) => print!(" {}={:>08X}", i, address), - PciBar::Port(address) => print!(" {}={:>04X}", i, address) + for i in 0..header.bars.len() { + match PciBar::from(header.bars[i]) { + PciBar::None => (), + PciBar::Memory(address) => print!(" {}={:>08X}", i, address), + PciBar::Port(address) => print!(" {}={:>04X}", i, address) + } + } + + print!("\n"); + + for driver in config.drivers.iter() { + if let Some(class) = driver.class { + if class != header.class { continue; } + } + + if let Some(subclass) = driver.subclass { + if subclass != header.subclass { continue; } + } + + if let Some(vendor) = driver.vendor { + if vendor != header.vendor_id { continue; } + } + + if let Some(device) = driver.device { + if device != header.device_id { continue; } + } + + if let Some(ref args) = driver.command { + let mut args = args.iter(); + if let Some(program) = args.next() { + let mut command = Command::new(program); + for arg in args { + let bar_arg = |i| -> String { + match PciBar::from(header.bars[i]) { + PciBar::None => String::new(), + PciBar::Memory(address) => format!("{:>08X}", address), + PciBar::Port(address) => format!("{:>04X}", address) + } + }; + let arg = match arg.as_str() { + "$0" => bar_arg(0), + "$1" => bar_arg(1), + "$2" => bar_arg(2), + "$3" => bar_arg(3), + "$4" => bar_arg(4), + "$5" => bar_arg(5), + _ => arg.clone() + }; + command.arg(&arg); + } + println!("{:?}", command); + } + } + + println!("Driver: {:?}", driver); } } - - print!("\n"); } } } - } -} - -fn main() { - thread::spawn(||{ - unsafe { iopl(3).unwrap() }; - - enumerate_pci(); }); } From 7bee7c6a8264cc496a7b8b81e0bec008ea99c17c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 26 Sep 2016 17:00:06 -0600 Subject: [PATCH 0024/1301] WIP: AHCI drivers and more memory syscalls --- ahcid/Cargo.toml | 9 + ahcid/src/ahci/fis.rs | 155 +++++++++++++++++ ahcid/src/ahci/hba.rs | 393 ++++++++++++++++++++++++++++++++++++++++++ ahcid/src/ahci/mod.rs | 83 +++++++++ ahcid/src/main.rs | 35 ++++ pcid/src/main.rs | 22 ++- 6 files changed, 690 insertions(+), 7 deletions(-) create mode 100644 ahcid/Cargo.toml create mode 100644 ahcid/src/ahci/fis.rs create mode 100644 ahcid/src/ahci/hba.rs create mode 100644 ahcid/src/ahci/mod.rs create mode 100644 ahcid/src/main.rs diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml new file mode 100644 index 0000000000..2bc8fa89f1 --- /dev/null +++ b/ahcid/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ahcid" +version = "0.1.0" + +[dependencies] +bitflags = "*" +io = { path = "../io/" } +spin = "*" +syscall = { path = "../../syscall/" } diff --git a/ahcid/src/ahci/fis.rs b/ahcid/src/ahci/fis.rs new file mode 100644 index 0000000000..7dbe33c179 --- /dev/null +++ b/ahcid/src/ahci/fis.rs @@ -0,0 +1,155 @@ +use io::Mmio; + +#[repr(u8)] +pub enum FisType { + /// Register FIS - host to device + RegH2D = 0x27, + /// Register FIS - device to host + RegD2H = 0x34, + /// DMA activate FIS - device to host + DmaAct = 0x39, + /// DMA setup FIS - bidirectional + DmaSetup = 0x41, + /// Data FIS - bidirectional + Data = 0x46, + /// BIST activate FIS - bidirectional + Bist = 0x58, + /// PIO setup FIS - device to host + PioSetup = 0x5F, + /// Set device bits FIS - device to host + DevBits = 0xA1 +} + +#[repr(packed)] +pub struct FisRegH2D { + // DWORD 0 + pub fis_type: Mmio, // FIS_TYPE_REG_H2D + + pub pm: Mmio, // Port multiplier, 1: Command, 0: Control + + pub command: Mmio, // Command register + pub featurel: Mmio, // Feature register, 7:0 + + // DWORD 1 + pub lba0: Mmio, // LBA low register, 7:0 + pub lba1: Mmio, // LBA mid register, 15:8 + pub lba2: Mmio, // LBA high register, 23:16 + pub device: Mmio, // Device register + + // DWORD 2 + pub lba3: Mmio, // LBA register, 31:24 + pub lba4: Mmio, // LBA register, 39:32 + pub lba5: Mmio, // LBA register, 47:40 + pub featureh: Mmio, // Feature register, 15:8 + + // DWORD 3 + pub countl: Mmio, // Count register, 7:0 + pub counth: Mmio, // Count register, 15:8 + pub icc: Mmio, // Isochronous command completion + pub control: Mmio, // Control register + + // DWORD 4 + pub rsv1: [Mmio; 4], // Reserved +} + +#[repr(packed)] +pub struct FisRegD2H { + // DWORD 0 + pub fis_type: Mmio, // FIS_TYPE_REG_D2H + + pub pm: Mmio, // Port multiplier, Interrupt bit: 2 + + pub status: Mmio, // Status register + pub error: Mmio, // Error register + + // DWORD 1 + pub lba0: Mmio, // LBA low register, 7:0 + pub lba1: Mmio, // LBA mid register, 15:8 + pub lba2: Mmio, // LBA high register, 23:16 + pub device: Mmio, // Device register + + // DWORD 2 + pub lba3: Mmio, // LBA register, 31:24 + pub lba4: Mmio, // LBA register, 39:32 + pub lba5: Mmio, // LBA register, 47:40 + pub rsv2: Mmio, // Reserved + + // DWORD 3 + pub countl: Mmio, // Count register, 7:0 + pub counth: Mmio, // Count register, 15:8 + pub rsv3: [Mmio; 2], // Reserved + + // DWORD 4 + pub rsv4: [Mmio; 4], // Reserved +} + +#[repr(packed)] +pub struct FisData { + // DWORD 0 + pub fis_type: Mmio, // FIS_TYPE_DATA + + pub pm: Mmio, // Port multiplier + + pub rsv1: [Mmio; 2], // Reserved + + // DWORD 1 ~ N + pub data: [Mmio; 252], // Payload +} + +#[repr(packed)] +pub struct FisPioSetup { + // DWORD 0 + pub fis_type: Mmio, // FIS_TYPE_PIO_SETUP + + pub pm: Mmio, // Port multiplier, direction: 4 - device to host, interrupt: 2 + + pub status: Mmio, // Status register + pub error: Mmio, // Error register + + // DWORD 1 + pub lba0: Mmio, // LBA low register, 7:0 + pub lba1: Mmio, // LBA mid register, 15:8 + pub lba2: Mmio, // LBA high register, 23:16 + pub device: Mmio, // Device register + + // DWORD 2 + pub lba3: Mmio, // LBA register, 31:24 + pub lba4: Mmio, // LBA register, 39:32 + pub lba5: Mmio, // LBA register, 47:40 + pub rsv2: Mmio, // Reserved + + // DWORD 3 + pub countl: Mmio, // Count register, 7:0 + pub counth: Mmio, // Count register, 15:8 + pub rsv3: Mmio, // Reserved + pub e_status: Mmio, // New value of status register + + // DWORD 4 + pub tc: Mmio, // Transfer count + pub rsv4: [Mmio; 2], // Reserved +} + +#[repr(packed)] +pub struct FisDmaSetup { + // DWORD 0 + pub fis_type: Mmio, // FIS_TYPE_DMA_SETUP + + pub pm: Mmio, // Port multiplier, direction: 4 - device to host, interrupt: 2, auto-activate: 1 + + pub rsv1: [Mmio; 2], // Reserved + + // DWORD 1&2 + pub dma_buffer_id: Mmio, /* DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work. */ + + // DWORD 3 + pub rsv3: Mmio, // More reserved + + // DWORD 4 + pub dma_buffer_offset: Mmio, // Byte offset into buffer. First 2 bits must be 0 + + // DWORD 5 + pub transfer_count: Mmio, // Number of bytes to transfer. Bit 0 must be 0 + + // DWORD 6 + pub rsv6: Mmio, // Reserved +} diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs new file mode 100644 index 0000000000..f7ca720975 --- /dev/null +++ b/ahcid/src/ahci/hba.rs @@ -0,0 +1,393 @@ +use io::{Io, Mmio}; + +use std::mem::size_of; +use std::{ptr, u32}; + +use syscall::{physalloc, physmap, physunmap, virttophys, MAP_WRITE}; +use syscall::error::{Error, Result, EIO}; + +use super::fis::{FisType, FisRegH2D}; + +const ATA_CMD_READ_DMA_EXT: u8 = 0x25; +const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35; +const ATA_CMD_IDENTIFY: u8 = 0xEC; +const ATA_DEV_BUSY: u8 = 0x80; +const ATA_DEV_DRQ: u8 = 0x08; + +const HBA_PORT_CMD_CR: u32 = 1 << 15; +const HBA_PORT_CMD_FR: u32 = 1 << 14; +const HBA_PORT_CMD_FRE: u32 = 1 << 4; +const HBA_PORT_CMD_ST: u32 = 1; +const HBA_PORT_IS_TFES: u32 = 1 << 30; +const HBA_SSTS_PRESENT: u32 = 0x3; +const HBA_SIG_ATA: u32 = 0x00000101; +const HBA_SIG_ATAPI: u32 = 0xEB140101; +const HBA_SIG_PM: u32 = 0x96690101; +const HBA_SIG_SEMB: u32 = 0xC33C0101; + +#[derive(Debug)] +pub enum HbaPortType { + None, + Unknown(u32), + SATA, + SATAPI, + PM, + SEMB, +} + +#[repr(packed)] +pub struct HbaPort { + pub clb: Mmio, // 0x00, command list base address, 1K-byte aligned + pub fb: Mmio, // 0x08, FIS base address, 256-byte aligned + pub is: Mmio, // 0x10, interrupt status + pub ie: Mmio, // 0x14, interrupt enable + pub cmd: Mmio, // 0x18, command and status + pub rsv0: Mmio, // 0x1C, Reserved + pub tfd: Mmio, // 0x20, task file data + pub sig: Mmio, // 0x24, signature + pub ssts: Mmio, // 0x28, SATA status (SCR0:SStatus) + pub sctl: Mmio, // 0x2C, SATA control (SCR2:SControl) + pub serr: Mmio, // 0x30, SATA error (SCR1:SError) + pub sact: Mmio, // 0x34, SATA active (SCR3:SActive) + pub ci: Mmio, // 0x38, command issue + pub sntf: Mmio, // 0x3C, SATA notification (SCR4:SNotification) + pub fbs: Mmio, // 0x40, FIS-based switch control + pub rsv1: [Mmio; 11], // 0x44 ~ 0x6F, Reserved + pub vendor: [Mmio; 4], // 0x70 ~ 0x7F, vendor specific +} + +impl HbaPort { + pub fn probe(&self) -> HbaPortType { + if self.ssts.readf(HBA_SSTS_PRESENT) { + let sig = self.sig.read(); + match sig { + HBA_SIG_ATA => HbaPortType::SATA, + HBA_SIG_ATAPI => HbaPortType::SATAPI, + HBA_SIG_PM => HbaPortType::PM, + HBA_SIG_SEMB => HbaPortType::SEMB, + _ => HbaPortType::Unknown(sig), + } + } else { + HbaPortType::None + } + } + + pub fn init(&mut self) { + self.stop(); + + let clb_phys = unsafe { physalloc(size_of::()).unwrap() }; + self.clb.write(clb_phys as u64); + + let fb = unsafe { physalloc(256).unwrap() }; + self.fb.write(fb as u64); + + let clb = unsafe { physmap(clb_phys, size_of::(), MAP_WRITE).unwrap() } as *mut HbaCmdHeader; + for i in 0..32 { + let cmdheader = unsafe { &mut *clb.offset(i) }; + let ctba = unsafe { physalloc(size_of::()).unwrap() }; + cmdheader.ctba.write(ctba as u64); + cmdheader.prdtl.write(0); + } + unsafe { physunmap(clb as usize).unwrap(); } + + self.start(); + } + + pub unsafe fn identify(&mut self, port: usize) -> Option { + self.is.write(u32::MAX); + + let dest_phys = physalloc(256).unwrap(); + let dest = physmap(dest_phys, 256, MAP_WRITE).unwrap() as *mut u16; + + if let Some(slot) = self.slot() { + { + let clb = unsafe { physmap(self.clb.read() as usize, size_of::(), MAP_WRITE).unwrap() } as *mut HbaCmdHeader; + let cmdheader = &mut *clb.offset(slot as isize); + cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); + cmdheader.prdtl.write(1); + + let ctba = unsafe { physmap(cmdheader.ctba.read() as usize, size_of::(), MAP_WRITE).unwrap() } as *mut HbaCmdTable; + ptr::write_bytes(ctba as *mut u8, 0, size_of::()); + let cmdtbl = &mut *(ctba); + + let prdt_entry = &mut cmdtbl.prdt_entry[0]; + prdt_entry.dba.write(dest_phys as u64); + prdt_entry.dbc.write(512 | 1); + + let cmdfis = &mut *(cmdtbl.cfis.as_ptr() as *mut FisRegH2D); + + cmdfis.fis_type.write(FisType::RegH2D as u8); + cmdfis.pm.write(1 << 7); + cmdfis.command.write(ATA_CMD_IDENTIFY); + cmdfis.device.write(0); + cmdfis.countl.write(1); + cmdfis.counth.write(0); + + unsafe { physunmap(ctba as usize).unwrap(); } + unsafe { physunmap(clb as usize).unwrap(); } + } + + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} + + self.ci.writef(1 << slot, true); + + while self.ci.readf(1 << slot) { + if self.is.readf(HBA_PORT_IS_TFES) { + return None; + } + } + + if self.is.readf(HBA_PORT_IS_TFES) { + return None; + } + + let mut serial = String::new(); + for word in 10..20 { + let d = *dest.offset(word); + let a = ((d >> 8) as u8) as char; + if a != '\0' { + serial.push(a); + } + let b = (d as u8) as char; + if b != '\0' { + serial.push(b); + } + } + + let mut firmware = String::new(); + for word in 23..27 { + let d = *dest.offset(word); + let a = ((d >> 8) as u8) as char; + if a != '\0' { + firmware.push(a); + } + let b = (d as u8) as char; + if b != '\0' { + firmware.push(b); + } + } + + let mut model = String::new(); + for word in 27..47 { + let d = *dest.offset(word); + let a = ((d >> 8) as u8) as char; + if a != '\0' { + model.push(a); + } + let b = (d as u8) as char; + if b != '\0' { + model.push(b); + } + } + + let mut sectors = (*dest.offset(100) as u64) | + ((*dest.offset(101) as u64) << 16) | + ((*dest.offset(102) as u64) << 32) | + ((*dest.offset(103) as u64) << 48); + + let lba_bits = if sectors == 0 { + sectors = (*dest.offset(60) as u64) | ((*dest.offset(61) as u64) << 16); + 28 + } else { + 48 + }; + + println!(" + Port {}: Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", + port, serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048); + + Some(sectors * 512) + } else { + None + } + } + + pub fn start(&mut self) { + while self.cmd.readf(HBA_PORT_CMD_CR) {} + + self.cmd.writef(HBA_PORT_CMD_FRE, true); + self.cmd.writef(HBA_PORT_CMD_ST, true); + } + + pub fn stop(&mut self) { + self.cmd.writef(HBA_PORT_CMD_ST, false); + + while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) {} + + self.cmd.writef(HBA_PORT_CMD_FRE, false); + } + + pub fn slot(&self) -> Option { + let slots = self.sact.read() | self.ci.read(); + for i in 0..32 { + if slots & 1 << i == 0 { + return Some(i); + } + } + None + } + + pub fn ata_dma_small(&mut self, block: u64, sectors: usize, mut buf: usize, write: bool) -> Result { + if buf >= 0x80000000 { + buf -= 0x80000000; + } + + // TODO: PRDTL for files larger than 4MB + let entries = 1; + + if buf > 0 && sectors > 0 { + self.is.write(u32::MAX); + + if let Some(slot) = self.slot() { + println!("Slot {}", slot); + + let clb = self.clb.read() as usize; + let cmdheader = unsafe { &mut *(clb as *mut HbaCmdHeader).offset(slot as isize) }; + + cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); + cmdheader.cfl.writef(1 << 6, write); + + cmdheader.prdtl.write(entries); + + let ctba = cmdheader.ctba.read() as usize; + unsafe { ptr::write_bytes(ctba as *mut u8, 0, size_of::()) }; + let cmdtbl = unsafe { &mut *(ctba as *mut HbaCmdTable) }; + + let prdt_entry = &mut cmdtbl.prdt_entry[0]; + prdt_entry.dba.write(buf as u64); + prdt_entry.dbc.write(((sectors * 512) as u32) | 1); + + let cmdfis = unsafe { &mut *(cmdtbl.cfis.as_ptr() as *mut FisRegH2D) }; + + cmdfis.fis_type.write(FisType::RegH2D as u8); + cmdfis.pm.write(1 << 7); + if write { + cmdfis.command.write(ATA_CMD_WRITE_DMA_EXT); + } else { + cmdfis.command.write(ATA_CMD_READ_DMA_EXT); + } + + cmdfis.lba0.write(block as u8); + cmdfis.lba1.write((block >> 8) as u8); + cmdfis.lba2.write((block >> 16) as u8); + + cmdfis.device.write(1 << 6); + + cmdfis.lba3.write((block >> 24) as u8); + cmdfis.lba4.write((block >> 32) as u8); + cmdfis.lba5.write((block >> 40) as u8); + + cmdfis.countl.write(sectors as u8); + cmdfis.counth.write((sectors >> 8) as u8); + + println!("Busy Wait"); + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} + + self.ci.writef(1 << slot, true); + + println!("Completion Wait"); + while self.ci.readf(1 << slot) { + if self.is.readf(HBA_PORT_IS_TFES) { + return Err(Error::new(EIO)); + } + } + + if self.is.readf(HBA_PORT_IS_TFES) { + return Err(Error::new(EIO)); + } + + Ok(sectors * 512) + } else { + println!("No Command Slots"); + Err(Error::new(EIO)) + } + } else { + println!("Invalid request"); + Err(Error::new(EIO)) + } + } + + pub fn ata_dma(&mut self, block: u64, sectors: usize, buf: usize, write: bool) -> Result { + println!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} BUF: {:X} WRITE: {}", (self as *mut HbaPort) as usize, block, sectors, buf, write); + + if sectors > 0 { + let physical_address = try!(unsafe { virttophys(buf) }); + + let mut sector: usize = 0; + while sectors - sector >= 255 { + if let Err(err) = self.ata_dma_small(block + sector as u64, 255, physical_address + sector * 512, write) { + return Err(err); + } + + sector += 255; + } + if sector < sectors { + if let Err(err) = self.ata_dma_small(block + sector as u64, sectors - sector, physical_address + sector * 512, write) { + return Err(err); + } + } + + Ok(sectors * 512) + } else { + println!("Invalid request"); + Err(Error::new(EIO)) + } + } +} + +#[repr(packed)] +pub struct HbaMem { + pub cap: Mmio, // 0x00, Host capability + pub ghc: Mmio, // 0x04, Global host control + pub is: Mmio, // 0x08, Interrupt status + pub pi: Mmio, // 0x0C, Port implemented + pub vs: Mmio, // 0x10, Version + pub ccc_ctl: Mmio, // 0x14, Command completion coalescing control + pub ccc_pts: Mmio, // 0x18, Command completion coalescing ports + pub em_loc: Mmio, // 0x1C, Enclosure management location + pub em_ctl: Mmio, // 0x20, Enclosure management control + pub cap2: Mmio, // 0x24, Host capabilities extended + pub bohc: Mmio, // 0x28, BIOS/OS handoff control and status + pub rsv: [Mmio; 116], // 0x2C - 0x9F, Reserved + pub vendor: [Mmio; 96], // 0xA0 - 0xFF, Vendor specific registers + pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers +} + +#[repr(packed)] +struct HbaPrdtEntry { + dba: Mmio, // Data base address + rsv0: Mmio, // Reserved + dbc: Mmio, // Byte count, 4M max, interrupt = 1 +} + +#[repr(packed)] +struct HbaCmdTable { + // 0x00 + cfis: [Mmio; 64], // Command FIS + + // 0x40 + acmd: [Mmio; 16], // ATAPI command, 12 or 16 bytes + + // 0x50 + rsv: [Mmio; 48], // Reserved + + // 0x80 + prdt_entry: [HbaPrdtEntry; 65536], // Physical region descriptor table entries, 0 ~ 65535 +} + +#[repr(packed)] +struct HbaCmdHeader { + // DW0 + cfl: Mmio, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */ + pm: Mmio, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier + + prdtl: Mmio, // Physical region descriptor table length in entries + + // DW1 + prdbc: Mmio, // Physical region descriptor byte count transferred + + // DW2, 3 + ctba: Mmio, // Command table descriptor base address + + // DW4 - 7 + rsv1: [Mmio; 4], // Reserved +} diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs new file mode 100644 index 0000000000..cdf54ca8ee --- /dev/null +++ b/ahcid/src/ahci/mod.rs @@ -0,0 +1,83 @@ +use io::Io; + +use syscall::error::Result; + +use self::hba::{HbaMem, HbaPort, HbaPortType}; + +pub mod fis; +pub mod hba; + +pub struct Ahci; + +impl Ahci { + pub fn disks(base: usize, irq: u8) -> Vec { + println!(" + AHCI on: {:X} IRQ: {:X}", base as usize, irq); + + let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); + let ret: Vec = (0..32) + .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) + .filter_map(|i| { + let mut disk = AhciDisk::new(base, i, irq); + let port_type = disk.port.probe(); + println!("{}: {:?}", i, port_type); + match port_type { + HbaPortType::SATA => { + /* + disk.port.init(); + if let Some(size) = unsafe { disk.port.identify(i) } { + disk.size = size; + Some(disk) + } else { + None + } + */ + None + } + _ => None, + } + }) + .collect(); + + ret + } +} + +pub struct AhciDisk { + port: &'static mut HbaPort, + port_index: usize, + irq: u8, + size: u64, +} + +impl AhciDisk { + fn new(base: usize, port_index: usize, irq: u8) -> Self { + AhciDisk { + port: &mut unsafe { &mut *(base as *mut HbaMem) }.ports[port_index], + port_index: port_index, + irq: irq, + size: 0 + } + } + + fn name(&self) -> String { + format!("AHCI Port {}", self.port_index) + } + + fn on_irq(&mut self, irq: u8) { + if irq == self.irq { + //debugln!("AHCI IRQ"); + } + } + + fn size(&self) -> u64 { + self.size + } + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { + self.port.ata_dma(block, buffer.len() / 512, buffer.as_ptr() as usize, false) + } + + fn write(&mut self, block: u64, buffer: &[u8]) -> Result { + self.port.ata_dma(block, buffer.len() / 512, buffer.as_ptr() as usize, true) + } +} diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs new file mode 100644 index 0000000000..5f7b1a11fb --- /dev/null +++ b/ahcid/src/main.rs @@ -0,0 +1,35 @@ +#![feature(asm)] + +#[macro_use] +extern crate bitflags; +extern crate io; +extern crate syscall; + +use std::{env, thread, usize}; + +use syscall::{iopl, physmap, physunmap, MAP_WRITE}; + +pub mod ahci; + +fn main() { + let mut args = env::args().skip(1); + + let bar_str = args.next().expect("ahcid: no address provided"); + let bar = usize::from_str_radix(&bar_str, 16).expect("ahcid: failed to parse address"); + + let irq_str = args.next().expect("ahcid: no irq provided"); + let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); + + thread::spawn(move || { + unsafe { + iopl(3).expect("ahcid: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; + { + ahci::Ahci::disks(address, irq); + } + unsafe { physunmap(address).expect("ahcid: failed to unmap address") }; + }); +} diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 9eb0889c76..a34ff17ab2 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -120,17 +120,25 @@ fn main() { } }; let arg = match arg.as_str() { - "$0" => bar_arg(0), - "$1" => bar_arg(1), - "$2" => bar_arg(2), - "$3" => bar_arg(3), - "$4" => bar_arg(4), - "$5" => bar_arg(5), + "$BAR0" => bar_arg(0), + "$BAR1" => bar_arg(1), + "$BAR2" => bar_arg(2), + "$BAR3" => bar_arg(3), + "$BAR4" => bar_arg(4), + "$BAR5" => bar_arg(5), + "$IRQ" => format!("{}", header.interrupt_line), _ => arg.clone() }; command.arg(&arg); } - println!("{:?}", command); + + match command.spawn() { + Ok(mut child) => match child.wait() { + Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()), + Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err) + }, + Err(err) => println!("pcid: failed to execute {:?}: {}", command, err) + } } } From 8e553d619de5ef2fdcc8ce6282aa8f369397331f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 26 Sep 2016 17:13:35 -0600 Subject: [PATCH 0025/1301] Fix allocate_frames --- ahcid/src/ahci/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index cdf54ca8ee..6cc266fd1f 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -22,7 +22,6 @@ impl Ahci { println!("{}: {:?}", i, port_type); match port_type { HbaPortType::SATA => { - /* disk.port.init(); if let Some(size) = unsafe { disk.port.identify(i) } { disk.size = size; @@ -30,8 +29,6 @@ impl Ahci { } else { None } - */ - None } _ => None, } From 0218393e92ba547ce650f376917b568cc0e6ccb7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 26 Sep 2016 17:39:58 -0600 Subject: [PATCH 0026/1301] Remove unnecessary slash --- ahcid/src/ahci/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index 6cc266fd1f..c3b4219f93 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -11,7 +11,7 @@ pub struct Ahci; impl Ahci { pub fn disks(base: usize, irq: u8) -> Vec { - println!(" + AHCI on: {:X} IRQ: {:X}", base as usize, irq); + println!(" + AHCI on: {:X} IRQ: {}", base as usize, irq); let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); let ret: Vec = (0..32) From 64d949fc620239b0451bd11a343ff9f956fe9078 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 27 Sep 2016 11:14:27 -0600 Subject: [PATCH 0027/1301] Abstractions for better Ahci driver --- ahcid/src/ahci/dma.rs | 76 +++++++++++++++++++++++++++++++++++++++++++ ahcid/src/ahci/hba.rs | 74 +++++++++++++++++++---------------------- ahcid/src/ahci/mod.rs | 63 ++++++++++++++++++++--------------- ahcid/src/main.rs | 7 ++-- 4 files changed, 150 insertions(+), 70 deletions(-) create mode 100644 ahcid/src/ahci/dma.rs diff --git a/ahcid/src/ahci/dma.rs b/ahcid/src/ahci/dma.rs new file mode 100644 index 0000000000..91258b8be9 --- /dev/null +++ b/ahcid/src/ahci/dma.rs @@ -0,0 +1,76 @@ +use std::{mem, ptr}; +use std::ops::{Deref, DerefMut}; + +use syscall::{self, Result}; + +struct PhysBox { + address: usize, + size: usize +} + +impl PhysBox { + fn new(size: usize) -> Result { + let address = unsafe { syscall::physalloc(size)? }; + Ok(PhysBox { + address: address, + size: size + }) + } +} + +impl Drop for PhysBox { + fn drop(&mut self) { + let _ = unsafe { syscall::physfree(self.address, self.size) }; + } +} + +pub struct Dma { + phys: PhysBox, + virt: *mut T +} + +impl Dma { + pub fn new(value: T) -> Result> { + let phys = PhysBox::new(mem::size_of::())?; + let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T; + unsafe { ptr::write(virt, value); } + Ok(Dma { + phys: phys, + virt: virt + }) + } + + pub fn zeroed() -> Result> { + let phys = PhysBox::new(mem::size_of::())?; + let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T; + unsafe { ptr::write_bytes(virt as *mut u8, 0, phys.size); } + Ok(Dma { + phys: phys, + virt: virt + }) + } + + pub fn physical(&self) -> usize { + self.phys.address + } +} + +impl Deref for Dma { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.virt } + } +} + +impl DerefMut for Dma { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.virt } + } +} + +impl Drop for Dma { + fn drop(&mut self) { + unsafe { drop(ptr::read(self.virt)); } + let _ = unsafe { syscall::physunmap(self.virt as usize) }; + } +} diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index f7ca720975..a76b4b4f9d 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -1,11 +1,13 @@ use io::{Io, Mmio}; use std::mem::size_of; +use std::ops::DerefMut; use std::{ptr, u32}; -use syscall::{physalloc, physmap, physunmap, virttophys, MAP_WRITE}; +use syscall::{virttophys, MAP_WRITE}; use syscall::error::{Error, Result, EIO}; +use super::dma::Dma; use super::fis::{FisType, FisRegH2D}; const ATA_CMD_READ_DMA_EXT: u8 = 0x25; @@ -72,49 +74,42 @@ impl HbaPort { } } - pub fn init(&mut self) { + pub fn init(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], fb: &mut Dma<[u8; 256]>) { self.stop(); - let clb_phys = unsafe { physalloc(size_of::()).unwrap() }; - self.clb.write(clb_phys as u64); + self.clb.write(clb.physical() as u64); + self.fb.write(fb.physical() as u64); - let fb = unsafe { physalloc(256).unwrap() }; - self.fb.write(fb as u64); - - let clb = unsafe { physmap(clb_phys, size_of::(), MAP_WRITE).unwrap() } as *mut HbaCmdHeader; for i in 0..32 { - let cmdheader = unsafe { &mut *clb.offset(i) }; - let ctba = unsafe { physalloc(size_of::()).unwrap() }; - cmdheader.ctba.write(ctba as u64); + let cmdheader = &mut clb[i]; + cmdheader.ctba.write(ctbas[i].physical() as u64); cmdheader.prdtl.write(0); } - unsafe { physunmap(clb as usize).unwrap(); } self.start(); } - pub unsafe fn identify(&mut self, port: usize) -> Option { + pub unsafe fn identify(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { self.is.write(u32::MAX); - let dest_phys = physalloc(256).unwrap(); - let dest = physmap(dest_phys, 256, MAP_WRITE).unwrap() as *mut u16; + let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); if let Some(slot) = self.slot() { - { - let clb = unsafe { physmap(self.clb.read() as usize, size_of::(), MAP_WRITE).unwrap() } as *mut HbaCmdHeader; - let cmdheader = &mut *clb.offset(slot as isize); - cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); - cmdheader.prdtl.write(1); + let cmdheader = &mut clb[slot as usize]; + cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); + cmdheader.prdtl.write(1); - let ctba = unsafe { physmap(cmdheader.ctba.read() as usize, size_of::(), MAP_WRITE).unwrap() } as *mut HbaCmdTable; - ptr::write_bytes(ctba as *mut u8, 0, size_of::()); - let cmdtbl = &mut *(ctba); + { + let cmdtbl = &mut ctbas[slot as usize]; + ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()); let prdt_entry = &mut cmdtbl.prdt_entry[0]; - prdt_entry.dba.write(dest_phys as u64); + prdt_entry.dba.write(dest.physical() as u64); prdt_entry.dbc.write(512 | 1); + } - let cmdfis = &mut *(cmdtbl.cfis.as_ptr() as *mut FisRegH2D); + { + let cmdfis = &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D); cmdfis.fis_type.write(FisType::RegH2D as u8); cmdfis.pm.write(1 << 7); @@ -122,9 +117,6 @@ impl HbaPort { cmdfis.device.write(0); cmdfis.countl.write(1); cmdfis.counth.write(0); - - unsafe { physunmap(ctba as usize).unwrap(); } - unsafe { physunmap(clb as usize).unwrap(); } } while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} @@ -143,7 +135,7 @@ impl HbaPort { let mut serial = String::new(); for word in 10..20 { - let d = *dest.offset(word); + let d = dest[word]; let a = ((d >> 8) as u8) as char; if a != '\0' { serial.push(a); @@ -156,7 +148,7 @@ impl HbaPort { let mut firmware = String::new(); for word in 23..27 { - let d = *dest.offset(word); + let d = dest[word]; let a = ((d >> 8) as u8) as char; if a != '\0' { firmware.push(a); @@ -169,7 +161,7 @@ impl HbaPort { let mut model = String::new(); for word in 27..47 { - let d = *dest.offset(word); + let d = dest[word]; let a = ((d >> 8) as u8) as char; if a != '\0' { model.push(a); @@ -180,20 +172,20 @@ impl HbaPort { } } - let mut sectors = (*dest.offset(100) as u64) | - ((*dest.offset(101) as u64) << 16) | - ((*dest.offset(102) as u64) << 32) | - ((*dest.offset(103) as u64) << 48); + let mut sectors = (dest[100] as u64) | + ((dest[101] as u64) << 16) | + ((dest[102] as u64) << 32) | + ((dest[103] as u64) << 48); let lba_bits = if sectors == 0 { - sectors = (*dest.offset(60) as u64) | ((*dest.offset(61) as u64) << 16); + sectors = (dest[60] as u64) | ((dest[61] as u64) << 16); 28 } else { 48 }; - println!(" + Port {}: Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", - port, serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048); + println!(" + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", + serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048); Some(sectors * 512) } else { @@ -353,14 +345,14 @@ pub struct HbaMem { } #[repr(packed)] -struct HbaPrdtEntry { +pub struct HbaPrdtEntry { dba: Mmio, // Data base address rsv0: Mmio, // Reserved dbc: Mmio, // Byte count, 4M max, interrupt = 1 } #[repr(packed)] -struct HbaCmdTable { +pub struct HbaCmdTable { // 0x00 cfis: [Mmio; 64], // Command FIS @@ -375,7 +367,7 @@ struct HbaCmdTable { } #[repr(packed)] -struct HbaCmdHeader { +pub struct HbaCmdHeader { // DW0 cfl: Mmio, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */ pm: Mmio, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index c3b4219f93..52e8c30c00 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -2,8 +2,10 @@ use io::Io; use syscall::error::Result; -use self::hba::{HbaMem, HbaPort, HbaPortType}; +use self::dma::Dma; +use self::hba::{HbaMem, HbaCmdTable, HbaCmdHeader, HbaPort, HbaPortType}; +pub mod dma; pub mod fis; pub mod hba; @@ -17,17 +19,17 @@ impl Ahci { let ret: Vec = (0..32) .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) .filter_map(|i| { - let mut disk = AhciDisk::new(base, i, irq); - let port_type = disk.port.probe(); + let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i]; + let port_type = port.probe(); println!("{}: {:?}", i, port_type); match port_type { HbaPortType::SATA => { - disk.port.init(); - if let Some(size) = unsafe { disk.port.identify(i) } { - disk.size = size; - Some(disk) - } else { - None + match AhciDisk::new(port) { + Ok(disk) => Some(disk), + Err(err) => { + println!("{}: {}", i, err); + None + } } } _ => None, @@ -41,29 +43,38 @@ impl Ahci { pub struct AhciDisk { port: &'static mut HbaPort, - port_index: usize, - irq: u8, size: u64, + clb: Dma<[HbaCmdHeader; 32]>, + ctbas: [Dma; 32], + fb: Dma<[u8; 256]> } impl AhciDisk { - fn new(base: usize, port_index: usize, irq: u8) -> Self { - AhciDisk { - port: &mut unsafe { &mut *(base as *mut HbaMem) }.ports[port_index], - port_index: port_index, - irq: irq, - size: 0 - } - } + fn new(port: &'static mut HbaPort) -> Result { + let mut clb = Dma::zeroed()?; + let mut ctbas = [ + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + ]; + let mut fb = Dma::zeroed()?; - fn name(&self) -> String { - format!("AHCI Port {}", self.port_index) - } + port.init(&mut clb, &mut ctbas, &mut fb); - fn on_irq(&mut self, irq: u8) { - if irq == self.irq { - //debugln!("AHCI IRQ"); - } + let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) }; + + Ok(AhciDisk { + port: port, + size: size, + clb: clb, + ctbas: ctbas, + fb: fb + }) } fn size(&self) -> u64 { diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 5f7b1a11fb..7a919aed8e 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -1,4 +1,5 @@ #![feature(asm)] +#![feature(question_mark)] #[macro_use] extern crate bitflags; @@ -27,9 +28,9 @@ fn main() { } let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; - { - ahci::Ahci::disks(address, irq); + ahci::Ahci::disks(address, irq); + loop { + let _ = syscall::sched_yield(); } - unsafe { physunmap(address).expect("ahcid: failed to unmap address") }; }); } From 8727861301157e32a62a516755f5065ee3991b08 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 27 Sep 2016 20:26:54 -0600 Subject: [PATCH 0028/1301] Make AHCI driver read bytes --- ahcid/src/ahci/disk.rs | 116 +++++++++++++++++++++++++++++++++++++++++ ahcid/src/ahci/hba.rs | 86 +++++++++--------------------- ahcid/src/ahci/mod.rs | 102 +++++++++--------------------------- ahcid/src/main.rs | 25 +++++++-- 4 files changed, 188 insertions(+), 141 deletions(-) create mode 100644 ahcid/src/ahci/disk.rs diff --git a/ahcid/src/ahci/disk.rs b/ahcid/src/ahci/disk.rs new file mode 100644 index 0000000000..fbef726151 --- /dev/null +++ b/ahcid/src/ahci/disk.rs @@ -0,0 +1,116 @@ +use std::ptr; + +use syscall::error::{Error, EIO, Result}; + +use super::dma::Dma; +use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; + +pub struct Disk { + id: usize, + port: &'static mut HbaPort, + size: u64, + clb: Dma<[HbaCmdHeader; 32]>, + ctbas: [Dma; 32], + fb: Dma<[u8; 256]>, + buf: Dma<[u8; 256 * 512]> +} + +impl Disk { + pub fn new(id: usize, port: &'static mut HbaPort) -> Result { + let mut clb = Dma::zeroed()?; + let mut ctbas = [ + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + ]; + let mut fb = Dma::zeroed()?; + let buf = Dma::zeroed()?; + + port.init(&mut clb, &mut ctbas, &mut fb); + + let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) }; + + Ok(Disk { + id: id, + port: port, + size: size, + clb: clb, + ctbas: ctbas, + fb: fb, + buf: buf + }) + } + + pub fn id(&self) -> usize { + self.id + } + + pub fn size(&self) -> u64 { + self.size + } + + pub fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { + let sectors = buffer.len()/512; + if sectors > 0 { + let mut sector: usize = 0; + while sectors - sector >= 255 { + if let Err(err) = self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); + } + + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); } + + sector += 255; + } + if sector < sectors { + if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); + } + + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); } + + sector += sectors - sector; + } + + Ok(sector * 512) + } else { + println!("Invalid request"); + Err(Error::new(EIO)) + } + } + + pub fn write(&mut self, block: u64, buffer: &[u8]) -> Result { + let sectors = (buffer.len() + 511)/512; + if sectors > 0 { + let mut sector: usize = 0; + while sectors - sector >= 255 { + unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), 255 * 512); } + + if let Err(err) = self.port.ata_dma(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); + } + + sector += 255; + } + if sector < sectors { + unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), (sectors - sector) * 512); } + + if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); + } + + sector += sectors - sector; + } + + Ok(sector * 512) + } else { + println!("Invalid request"); + Err(Error::new(EIO)) + } + } +} diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index a76b4b4f9d..015b733ae3 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -4,7 +4,6 @@ use std::mem::size_of; use std::ops::DerefMut; use std::{ptr, u32}; -use syscall::{virttophys, MAP_WRITE}; use syscall::error::{Error, Result, EIO}; use super::dma::Dma; @@ -218,37 +217,34 @@ impl HbaPort { None } - pub fn ata_dma_small(&mut self, block: u64, sectors: usize, mut buf: usize, write: bool) -> Result { - if buf >= 0x80000000 { - buf -= 0x80000000; - } + pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result { + println!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}", (self as *mut HbaPort) as usize, block, sectors, write); - // TODO: PRDTL for files larger than 4MB - let entries = 1; + assert!(sectors > 0 && sectors < 256); - if buf > 0 && sectors > 0 { - self.is.write(u32::MAX); + self.is.write(u32::MAX); - if let Some(slot) = self.slot() { - println!("Slot {}", slot); + if let Some(slot) = self.slot() { + println!("Slot {}", slot); - let clb = self.clb.read() as usize; - let cmdheader = unsafe { &mut *(clb as *mut HbaCmdHeader).offset(slot as isize) }; + let cmdheader = &mut clb[slot as usize]; - cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); - cmdheader.cfl.writef(1 << 6, write); + cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); + cmdheader.cfl.writef(1 << 6, write); - cmdheader.prdtl.write(entries); + cmdheader.prdtl.write(1); - let ctba = cmdheader.ctba.read() as usize; - unsafe { ptr::write_bytes(ctba as *mut u8, 0, size_of::()) }; - let cmdtbl = unsafe { &mut *(ctba as *mut HbaCmdTable) }; + { + let cmdtbl = &mut ctbas[slot as usize]; + unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()) }; let prdt_entry = &mut cmdtbl.prdt_entry[0]; - prdt_entry.dba.write(buf as u64); + prdt_entry.dba.write(buf.physical() as u64); prdt_entry.dbc.write(((sectors * 512) as u32) | 1); + } - let cmdfis = unsafe { &mut *(cmdtbl.cfis.as_ptr() as *mut FisRegH2D) }; + { + let cmdfis = unsafe { &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D) }; cmdfis.fis_type.write(FisType::RegH2D as u8); cmdfis.pm.write(1 << 7); @@ -270,57 +266,27 @@ impl HbaPort { cmdfis.countl.write(sectors as u8); cmdfis.counth.write((sectors >> 8) as u8); + } - println!("Busy Wait"); - while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} + println!("Busy Wait"); + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} - self.ci.writef(1 << slot, true); - - println!("Completion Wait"); - while self.ci.readf(1 << slot) { - if self.is.readf(HBA_PORT_IS_TFES) { - return Err(Error::new(EIO)); - } - } + self.ci.writef(1 << slot, true); + println!("Completion Wait"); + while self.ci.readf(1 << slot) { if self.is.readf(HBA_PORT_IS_TFES) { return Err(Error::new(EIO)); } - - Ok(sectors * 512) - } else { - println!("No Command Slots"); - Err(Error::new(EIO)) } - } else { - println!("Invalid request"); - Err(Error::new(EIO)) - } - } - pub fn ata_dma(&mut self, block: u64, sectors: usize, buf: usize, write: bool) -> Result { - println!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} BUF: {:X} WRITE: {}", (self as *mut HbaPort) as usize, block, sectors, buf, write); - - if sectors > 0 { - let physical_address = try!(unsafe { virttophys(buf) }); - - let mut sector: usize = 0; - while sectors - sector >= 255 { - if let Err(err) = self.ata_dma_small(block + sector as u64, 255, physical_address + sector * 512, write) { - return Err(err); - } - - sector += 255; - } - if sector < sectors { - if let Err(err) = self.ata_dma_small(block + sector as u64, sectors - sector, physical_address + sector * 512, write) { - return Err(err); - } + if self.is.readf(HBA_PORT_IS_TFES) { + return Err(Error::new(EIO)); } Ok(sectors * 512) } else { - println!("Invalid request"); + println!("No Command Slots"); Err(Error::new(EIO)) } } diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index 52e8c30c00..9d594ded2e 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -1,91 +1,37 @@ use io::Io; -use syscall::error::Result; - -use self::dma::Dma; -use self::hba::{HbaMem, HbaCmdTable, HbaCmdHeader, HbaPort, HbaPortType}; +use self::disk::Disk; +use self::hba::{HbaMem, HbaPortType}; +pub mod disk; pub mod dma; pub mod fis; pub mod hba; -pub struct Ahci; +pub fn disks(base: usize, irq: u8) -> Vec { + println!(" + AHCI on: {:X} IRQ: {}", base as usize, irq); -impl Ahci { - pub fn disks(base: usize, irq: u8) -> Vec { - println!(" + AHCI on: {:X} IRQ: {}", base as usize, irq); - - let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); - let ret: Vec = (0..32) - .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) - .filter_map(|i| { - let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i]; - let port_type = port.probe(); - println!("{}: {:?}", i, port_type); - match port_type { - HbaPortType::SATA => { - match AhciDisk::new(port) { - Ok(disk) => Some(disk), - Err(err) => { - println!("{}: {}", i, err); - None - } + let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); + let ret: Vec = (0..32) + .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) + .filter_map(|i| { + let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i]; + let port_type = port.probe(); + println!("{}: {:?}", i, port_type); + match port_type { + HbaPortType::SATA => { + match Disk::new(i, port) { + Ok(disk) => Some(disk), + Err(err) => { + println!("{}: {}", i, err); + None } } - _ => None, } - }) - .collect(); + _ => None, + } + }) + .collect(); - ret - } -} - -pub struct AhciDisk { - port: &'static mut HbaPort, - size: u64, - clb: Dma<[HbaCmdHeader; 32]>, - ctbas: [Dma; 32], - fb: Dma<[u8; 256]> -} - -impl AhciDisk { - fn new(port: &'static mut HbaPort) -> Result { - let mut clb = Dma::zeroed()?; - let mut ctbas = [ - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - ]; - let mut fb = Dma::zeroed()?; - - port.init(&mut clb, &mut ctbas, &mut fb); - - let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) }; - - Ok(AhciDisk { - port: port, - size: size, - clb: clb, - ctbas: ctbas, - fb: fb - }) - } - - fn size(&self) -> u64 { - self.size - } - - fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { - self.port.ata_dma(block, buffer.len() / 512, buffer.as_ptr() as usize, false) - } - - fn write(&mut self, block: u64, buffer: &[u8]) -> Result { - self.port.ata_dma(block, buffer.len() / 512, buffer.as_ptr() as usize, true) - } + ret } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 7a919aed8e..4eff7cd928 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -28,9 +28,28 @@ fn main() { } let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; - ahci::Ahci::disks(address, irq); - loop { - let _ = syscall::sched_yield(); + { + let mut disks = ahci::disks(address, irq); + for mut disk in disks.iter_mut() { + let mut sector = [0; 512]; + println!("Read disk {} size {} MB", disk.id(), disk.size()/1024/1024); + match disk.read(0, &mut sector) { + Ok(count) => { + println!("{}", count); + for i in 0..512 { + print!("{:X} ", sector[i]); + } + println!(""); + }, + Err(err) => { + println!("{}", err); + } + } + } + loop { + let _ = syscall::sched_yield(); + } } + unsafe { let _ = physunmap(address); } }); } From e6737c591faf00bc505691675acc4715177ec990 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 27 Sep 2016 20:52:26 -0600 Subject: [PATCH 0029/1301] Add disk scheme (mostly finished) --- ahcid/src/main.rs | 31 +++++++---------- ahcid/src/scheme.rs | 85 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 19 deletions(-) create mode 100644 ahcid/src/scheme.rs diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 4eff7cd928..07ca38e1b7 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -4,13 +4,18 @@ #[macro_use] extern crate bitflags; extern crate io; +extern crate spin; extern crate syscall; +use std::fs::File; +use std::io::{Read, Write}; use std::{env, thread, usize}; +use syscall::{iopl, physmap, physunmap, MAP_WRITE, Packet, Scheme}; -use syscall::{iopl, physmap, physunmap, MAP_WRITE}; +use scheme::DiskScheme; pub mod ahci; +pub mod scheme; fn main() { let mut args = env::args().skip(1); @@ -29,25 +34,13 @@ fn main() { let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; { - let mut disks = ahci::disks(address, irq); - for mut disk in disks.iter_mut() { - let mut sector = [0; 512]; - println!("Read disk {} size {} MB", disk.id(), disk.size()/1024/1024); - match disk.read(0, &mut sector) { - Ok(count) => { - println!("{}", count); - for i in 0..512 { - print!("{:X} ", sector[i]); - } - println!(""); - }, - Err(err) => { - println!("{}", err); - } - } - } + let mut socket = File::create(":disk").expect("ahcid: failed to create disk scheme"); + let scheme = DiskScheme::new(ahci::disks(address, irq)); loop { - let _ = syscall::sched_yield(); + let mut packet = Packet::default(); + socket.read(&mut packet).expect("ahcid: failed to read disk scheme"); + scheme.handle(&mut packet); + socket.write(&mut packet).expect("ahcid: failed to read disk scheme"); } } unsafe { let _ = physunmap(address); } diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs new file mode 100644 index 0000000000..76b8b8a2bf --- /dev/null +++ b/ahcid/src/scheme.rs @@ -0,0 +1,85 @@ +use std::collections::BTreeMap; +use std::{cmp, str}; +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering}; +use spin::Mutex; +use syscall::{Error, EBADF, EINVAL, ENOENT, Result, Scheme, SEEK_CUR, SEEK_END, SEEK_SET}; + +use ahci::disk::Disk; + +pub struct DiskScheme { + disks: Box<[Arc>]>, + handles: Mutex>, usize)>>, + next_id: AtomicUsize +} + +impl DiskScheme { + pub fn new(disks: Vec) -> DiskScheme { + let mut disk_arcs = vec![]; + for disk in disks { + disk_arcs.push(Arc::new(Mutex::new(disk))); + } + + DiskScheme { + disks: disk_arcs.into_boxed_slice(), + handles: Mutex::new(BTreeMap::new()), + next_id: AtomicUsize::new(0) + } + } +} + +impl Scheme for DiskScheme { + fn open(&self, path: &[u8], _flags: usize) -> Result { + let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; + + let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; + + if let Some(disk) = self.disks.get(i) { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, (disk.clone(), 0)); + Ok(id) + } else { + Err(Error::new(ENOENT)) + } + } + + fn read(&self, id: usize, buf: &mut [u8]) -> Result { + let mut handles = self.handles.lock(); + let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let mut disk = handle.0.lock(); + let count = disk.read((handle.1 as u64)/512, buf)?; + handle.1 += count; + Ok(count) + } + + fn write(&self, id: usize, buf: &[u8]) -> Result { + let mut handles = self.handles.lock(); + let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let mut disk = handle.0.lock(); + let count = disk.write((handle.1 as u64)/512, buf)?; + handle.1 += count; + Ok(count) + } + + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { + let mut handles = self.handles.lock(); + let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let len = handle.0.lock().size() as usize; + handle.1 = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(handle.1) + } + + fn close(&self, id: usize) -> Result { + let mut handles = self.handles.lock(); + handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) + } +} From 9f5353453a1f3d8c95116747852cf0164d5c385e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 27 Sep 2016 21:27:32 -0600 Subject: [PATCH 0030/1301] Remove debugging --- ahcid/src/ahci/hba.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 015b733ae3..a5b3a13260 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -218,15 +218,13 @@ impl HbaPort { } pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result { - println!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}", (self as *mut HbaPort) as usize, block, sectors, write); + //println!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}", (self as *mut HbaPort) as usize, block, sectors, write); assert!(sectors > 0 && sectors < 256); self.is.write(u32::MAX); if let Some(slot) = self.slot() { - println!("Slot {}", slot); - let cmdheader = &mut clb[slot as usize]; cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); @@ -268,12 +266,10 @@ impl HbaPort { cmdfis.counth.write((sectors >> 8) as u8); } - println!("Busy Wait"); while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} self.ci.writef(1 << slot, true); - println!("Completion Wait"); while self.ci.readf(1 << slot) { if self.is.readf(HBA_PORT_IS_TFES) { return Err(Error::new(EIO)); From 0a4b617eac82abdbbda5012b10cfd010fcb798d3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 28 Sep 2016 12:19:30 -0600 Subject: [PATCH 0031/1301] Cleaner blending of fonts. Do not draw cursor when disabled --- vesad/src/display.rs | 21 +++++++++++++++------ vesad/src/main.rs | 4 ++-- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 35640634ae..13c72f9865 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -94,14 +94,23 @@ impl Display { let off_y = y + (off_y as i32 + bb.min.y) as usize; // There's still a possibility that the glyph clips the boundaries of the bitmap if off_x < width && off_y < height { - let v_u = (v * 255.0) as u32; - if v_u > 0 { - let r = (((color >> 16) & 0xFF) * v_u)/255; - let g = (((color >> 8) & 0xFF) * v_u)/255; - let b = ((color & 0xFF) * v_u)/255; - let c = (r << 16) | (g << 8) | b; + if v > 0.0 { + let f_a = (v * 255.0) as u32; + let f_r = (((color >> 16) & 0xFF) * f_a)/255; + let f_g = (((color >> 8) & 0xFF) * f_a)/255; + let f_b = ((color & 0xFF) * f_a)/255; let index = (off_y * width + off_x) as isize; + + let bg = unsafe { *offscreen.offset(index) }; + + let b_a = 255 - f_a; + let b_r = (((bg >> 16) & 0xFF) * b_a)/255; + let b_g = (((bg >> 8) & 0xFF) * b_a)/255; + let b_b = ((bg & 0xFF) * b_a)/255; + + let c = ((f_r + b_r) << 16) | ((f_g + b_g) << 8) | (f_b + b_b); + unsafe { *offscreen.offset(index) = c; } unsafe { *onscreen.offset(index) = c; } } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index cb45f39bdd..f173bc47c9 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -73,7 +73,7 @@ impl Scheme for DisplayScheme { } else { let mut display = self.display.borrow_mut(); let mut console = self.console.borrow_mut(); - if console.x < console.w && console.y < console.h { + if console.cursor && console.x < console.w && console.y < console.h { display.rect(console.x * 8, console.y * 16, 8, 16, 0); } console.write(buf, |event| { @@ -83,7 +83,7 @@ impl Scheme for DisplayScheme { Event::Scroll { rows, color } => display.scroll(rows * 16, color.data) } }); - if console.x < console.w && console.y < console.h { + if console.cursor && console.x < console.w && console.y < console.h { display.rect(console.x * 8, console.y * 16, 8, 16, 0xFFFFFF); } Ok(buf.len()) From 3d714f1c3bf57fbc72186b4cb2b90c553ce6b0bd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 28 Sep 2016 15:04:15 -0600 Subject: [PATCH 0032/1301] Some fixes for cooked mode --- vesad/src/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index f173bc47c9..88eafcfb19 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -65,9 +65,15 @@ impl Scheme for DisplayScheme { fn write(&self, id: usize, buf: &[u8]) -> Result { if id == 1 { - let mut input = self.input.borrow_mut(); for &b in buf.iter() { - input.push_back(b); + self.input.borrow_mut().push_back(b); + if ! self.console.borrow().raw_mode { + if b == 0x7F { + self.write(0, b"\x08")?; + } else { + self.write(0, &[b])?; + } + } } Ok(buf.len()) } else { From 13b64da01a70c6053fb3a08ef49b7889a2f53939 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 28 Sep 2016 15:17:37 -0600 Subject: [PATCH 0033/1301] Improvements for cooked mode --- vesad/src/main.rs | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 88eafcfb19..31cb84c882 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -27,6 +27,7 @@ struct DisplayScheme { console: RefCell, display: RefCell, input: RefCell>, + cooked: RefCell>, requested: RefCell } @@ -65,13 +66,29 @@ impl Scheme for DisplayScheme { fn write(&self, id: usize, buf: &[u8]) -> Result { if id == 1 { - for &b in buf.iter() { - self.input.borrow_mut().push_back(b); - if ! self.console.borrow().raw_mode { - if b == 0x7F { - self.write(0, b"\x08")?; - } else { - self.write(0, &[b])?; + if self.console.borrow().raw_mode { + for &b in buf.iter() { + self.input.borrow_mut().push_back(b); + } + } else { + for &b in buf.iter() { + match b { + b'\x08' | b'\x7F' => { + if let Some(c) = self.cooked.borrow_mut().pop_back() { + self.write(0, b"\x08")?; + } + }, + b'\n' | b'\r' => { + self.cooked.borrow_mut().push_back(b); + while let Some(c) = self.cooked.borrow_mut().pop_front() { + self.input.borrow_mut().push_back(c); + } + self.write(0, b"\n")?; + }, + _ => { + self.cooked.borrow_mut().push_back(b); + self.write(0, &[b])?; + } } } } @@ -135,6 +152,7 @@ fn main() { unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } )), input: RefCell::new(VecDeque::new()), + cooked: RefCell::new(VecDeque::new()), requested: RefCell::new(0) }; From 1e519c75ac175a37d50f72eb07db7b9acb559392 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 28 Sep 2016 21:59:51 -0600 Subject: [PATCH 0034/1301] Implement control and navigation in ps2 driver --- ps2d/src/keyboard.rs | 47 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/ps2d/src/keyboard.rs b/ps2d/src/keyboard.rs index e192bd29ed..a726208319 100644 --- a/ps2d/src/keyboard.rs +++ b/ps2d/src/keyboard.rs @@ -9,6 +9,7 @@ pub fn keyboard() { let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1"); let mut input = File::open("display:input").expect("ps2d: failed to open display:input"); + let mut ctrl = false; let mut lshift = false; let mut rshift = false; loop { @@ -27,14 +28,52 @@ pub fn keyboard() { (data, true) }; - if scancode == 0x2A { + if scancode == 0x1D { + ctrl = pressed; + } else if scancode == 0x2A { lshift = pressed; } else if scancode == 0x36 { rshift = pressed; } else if pressed { - let c = keymap::get_char(scancode, lshift || rshift); - if c != '\0' { - input.write(&[c as u8]).expect("ps2d: failed to write input"); + match scancode { + 0x47 => { // Home + input.write(b"\x1B[H").unwrap(); + }, + 0x48 => { // Up + input.write(b"\x1B[A").unwrap(); + }, + 0x49 => { // Page up + input.write(b"\x1B[5~").unwrap(); + }, + 0x4B => { // Left + input.write(b"\x1B[D").unwrap(); + }, + 0x4D => { // Right + input.write(b"\x1B[C").unwrap(); + }, + 0x4F => { // End + input.write(b"\x1B[F").unwrap(); + }, + 0x50 => { // Down + input.write(b"\x1B[B").unwrap(); + }, + 0x51 => { // Page down + input.write(b"\x1B[6~").unwrap(); + }, + _ => { + let c = if ctrl { + match keymap::get_char(scancode, false) { + c @ 'a' ... 'z' => (c as u8 - b'a' + b'\x01') as char, + c => c + } + } else { + keymap::get_char(scancode, lshift || rshift) + }; + + if c != '\0' { + input.write(&[c as u8]).unwrap(); + } + } } } } else { From 31a059a9fd1affc9d339249a262e4eb5d460ab59 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 29 Sep 2016 12:25:43 -0600 Subject: [PATCH 0035/1301] Automatically get size of terminal --- vesad/src/main.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 31cb84c882..31f6e54f09 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -113,6 +113,25 @@ impl Scheme for DisplayScheme { } } + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { + let path_str = if id == 1 { + format!("display:input") + } else { + let console = self.console.borrow(); + format!("display:{}/{}", console.w, console.h) + }; + + let path = path_str.as_bytes(); + + let mut i = 0; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; + i += 1; + } + + Ok(i) + } + fn close(&self, _id: usize) -> Result { Ok(0) } From e542783402da91b362bac654abe1969eef16e1d5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 29 Sep 2016 13:17:19 -0600 Subject: [PATCH 0036/1301] Make rusttype optional for vesad --- vesad/src/display.rs | 109 ++++++++++++++++++++++++++++++++-------- vesad/src/main.rs | 115 ++++++++++++++++++++++++++++++++----------- 2 files changed, 173 insertions(+), 51 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 13c72f9865..ea1379dc63 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -1,39 +1,64 @@ +#[cfg(feature="rusttype")] extern crate rusttype; use std::cmp; -use primitive::{fast_set32, fast_set64, fast_copy64}; +use primitive::{fast_set32, fast_set64, fast_copy, fast_copy64}; +#[cfg(feature="rusttype")] use self::rusttype::{Font, FontCollection, Scale, point}; -static FONT: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono.ttf"); -static FONT_BOLD: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Bold.ttf"); -static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-BoldOblique.ttf"); -static FONT_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf"); +#[cfg(not(feature="rusttype"))] +static FONT: &'static [u8] = include_bytes!("../../../res/fonts/unifont.font"); /// A display +#[cfg(not(feature="rusttype"))] +pub struct Display { + pub width: usize, + pub height: usize, + pub onscreen: &'static mut [u32], + pub offscreen: &'static mut [u32] +} + +/// A display +#[cfg(feature="rusttype")] pub struct Display { pub width: usize, pub height: usize, pub onscreen: &'static mut [u32], pub offscreen: &'static mut [u32], + #[cfg(feature="rusttype")] pub font: Font<'static>, + #[cfg(feature="rusttype")] pub font_bold: Font<'static>, + #[cfg(feature="rusttype")] pub font_bold_italic: Font<'static>, + #[cfg(feature="rusttype")] pub font_italic: Font<'static> } impl Display { + #[cfg(not(feature="rusttype"))] + pub fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display { + Display { + width: width, + height: height, + onscreen: onscreen, + offscreen: offscreen + } + } + + #[cfg(feature="rusttype")] pub fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display { Display { width: width, height: height, onscreen: onscreen, offscreen: offscreen, - font: FontCollection::from_bytes(FONT).into_font().unwrap(), - font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(), - font_bold_italic: FontCollection::from_bytes(FONT_BOLD_ITALIC).into_font().unwrap(), - font_italic: FontCollection::from_bytes(FONT_ITALIC).into_font().unwrap() + font: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono.ttf")).into_font().unwrap(), + font_bold: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono-Bold.ttf")).into_font().unwrap(), + font_bold_italic: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono-BoldOblique.ttf")).into_font().unwrap(), + font_italic: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf")).into_font().unwrap() } } @@ -46,32 +71,49 @@ impl Display { let len = cmp::min(self.width, x + w) - start_x; let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; - let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize; let stride = self.width * 4; let offset = y * stride + start_x * 4; offscreen_ptr += offset; - onscreen_ptr += offset; let mut rows = end_y - start_y; while rows > 0 { unsafe { fast_set32(offscreen_ptr as *mut u32, color, len); - fast_set32(onscreen_ptr as *mut u32, color, len); } offscreen_ptr += stride; - onscreen_ptr += stride; rows -= 1; } } /// Draw a character + #[cfg(not(feature="rusttype"))] + pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) { + if x + 8 <= self.width && y + 16 <= self.height { + let mut dst = unsafe { self.offscreen.as_mut_ptr().offset((y * self.width + x) as isize) }; + + let font_i = 16 * (character as usize); + if font_i + 16 <= FONT.len() { + for row in 0..16 { + let row_data = FONT[font_i + row]; + for col in 0..8 { + if (row_data >> (7 - col)) & 1 == 1 { + unsafe { *dst.offset(col) = color; } + } + } + dst = unsafe { dst.offset(self.width as isize) }; + } + } + } + } + + /// Draw a character + #[cfg(feature="rusttype")] pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, bold: bool, italic: bool) { let width = self.width; let height = self.height; - let offscreen = self.offscreen.as_mut_ptr(); - let onscreen = self.onscreen.as_mut_ptr(); + let offscreen = self.offscreen.as_mut_ptr() as usize; let font = if bold && italic { &self.font_bold_italic @@ -100,9 +142,9 @@ impl Display { let f_g = (((color >> 8) & 0xFF) * f_a)/255; let f_b = ((color & 0xFF) * f_a)/255; - let index = (off_y * width + off_x) as isize; + let offscreen_ptr = (offscreen + (off_y * width + off_x) * 4) as *mut u32; - let bg = unsafe { *offscreen.offset(index) }; + let bg = unsafe { *offscreen_ptr }; let b_a = 255 - f_a; let b_r = (((bg >> 16) & 0xFF) * b_a)/255; @@ -111,8 +153,7 @@ impl Display { let c = ((f_r + b_r) << 16) | ((f_g + b_g) << 8) | (f_b + b_b); - unsafe { *offscreen.offset(index) = c; } - unsafe { *onscreen.offset(index) = c; } + unsafe { *offscreen_ptr = c; } } } }); @@ -133,9 +174,35 @@ impl Display { let data_ptr = self.offscreen.as_mut_ptr() as *mut u64; fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2); fast_set64(data_ptr.offset(off2 as isize), data, off1); - - fast_copy64(self.onscreen.as_mut_ptr() as *mut u64, data_ptr, off1 + off2); } } } + + /// Copy from offscreen to onscreen + pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize) { + let start_y = cmp::min(self.height - 1, y); + let end_y = cmp::min(self.height, y + h); + + let start_x = cmp::min(self.width - 1, x); + let len = (cmp::min(self.width, x + w) - start_x) * 4; + + let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; + let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize; + + let stride = self.width * 4; + + let offset = y * stride + start_x * 4; + offscreen_ptr += offset; + onscreen_ptr += offset; + + let mut rows = end_y - start_y; + while rows > 0 { + unsafe { + fast_copy(onscreen_ptr as *mut u8, offscreen_ptr as *const u8, len); + } + offscreen_ptr += stride; + onscreen_ptr += stride; + rows -= 1; + } + } } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 31f6e54f09..74c17f93f1 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -8,7 +8,7 @@ extern crate ransid; extern crate syscall; use std::cell::RefCell; -use std::collections::VecDeque; +use std::collections::{BTreeSet, VecDeque}; use std::fs::File; use std::io::{Read, Write}; use std::{slice, thread}; @@ -26,11 +26,49 @@ pub mod primitive; struct DisplayScheme { console: RefCell, display: RefCell, + changed: RefCell>, input: RefCell>, cooked: RefCell>, requested: RefCell } +impl DisplayScheme { + fn event(&self, event: Event) { + let mut display = self.display.borrow_mut(); + let mut changed = self.changed.borrow_mut(); + + match event { + Event::Char { x, y, c, color, bold, .. } => { + display.char(x * 8, y * 16, c, color.data, bold, false); + changed.insert(y); + }, + Event::Rect { x, y, w, h, color } => { + display.rect(x * 8, y * 16, w * 8, h * 16, color.data); + for y2 in y..y + h { + changed.insert(y2); + } + }, + Event::Scroll { rows, color } => { + display.scroll(rows * 16, color.data); + for y in 0..display.height/16 { + changed.insert(y); + } + } + } + } + + fn sync(&self) { + let mut display = self.display.borrow_mut(); + let mut changed = self.changed.borrow_mut(); + + let width = display.width; + for change in changed.iter() { + display.sync(0, change * 16, width, 16); + } + changed.clear(); + } +} + impl Scheme for DisplayScheme { fn open(&self, path: &[u8], _flags: usize) -> Result { if path == b"input" { @@ -50,7 +88,32 @@ impl Scheme for DisplayScheme { Ok(0) } - fn fsync(&self, _id: usize) -> Result { + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { + let path_str = if id == 1 { + format!("display:input") + } else { + let console = self.console.borrow(); + format!("display:{}/{}", console.w, console.h) + }; + + let path = path_str.as_bytes(); + + let mut i = 0; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; + i += 1; + } + + Ok(i) + } + + fn fsync(&self, id: usize) -> Result { + if id == 1 { + + } else { + self.sync(); + } + Ok(0) } @@ -74,7 +137,7 @@ impl Scheme for DisplayScheme { for &b in buf.iter() { match b { b'\x08' | b'\x7F' => { - if let Some(c) = self.cooked.borrow_mut().pop_back() { + if let Some(_c) = self.cooked.borrow_mut().pop_back() { self.write(0, b"\x08")?; } }, @@ -94,44 +157,35 @@ impl Scheme for DisplayScheme { } Ok(buf.len()) } else { - let mut display = self.display.borrow_mut(); let mut console = self.console.borrow_mut(); if console.cursor && console.x < console.w && console.y < console.h { - display.rect(console.x * 8, console.y * 16, 8, 16, 0); + self.event(Event::Rect { + x: console.x, + y: console.y, + w: 1, + h: 1, + color: console.background + }); } console.write(buf, |event| { - match event { - Event::Char { x, y, c, color, bold, .. } => display.char(x * 8, y * 16, c, color.data, bold, false), - Event::Rect { x, y, w, h, color } => display.rect(x * 8, y * 16, w * 8, h * 16, color.data), - Event::Scroll { rows, color } => display.scroll(rows * 16, color.data) - } + self.event(event); }); if console.cursor && console.x < console.w && console.y < console.h { - display.rect(console.x * 8, console.y * 16, 8, 16, 0xFFFFFF); + self.event(Event::Rect { + x: console.x, + y: console.y, + w: 1, + h: 1, + color: console.foreground + }); + } + if ! console.raw_mode { + self.sync(); } Ok(buf.len()) } } - fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let path_str = if id == 1 { - format!("display:input") - } else { - let console = self.console.borrow(); - format!("display:{}/{}", console.w, console.h) - }; - - let path = path_str.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) - } - fn close(&self, _id: usize) -> Result { Ok(0) } @@ -170,6 +224,7 @@ fn main() { unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } )), + changed: RefCell::new(BTreeSet::new()), input: RefCell::new(VecDeque::new()), cooked: RefCell::new(VecDeque::new()), requested: RefCell::new(0) From 71990b7c5457355cc62835ce12a92511e9e111a0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 29 Sep 2016 13:44:34 -0600 Subject: [PATCH 0037/1301] Update extrautils, more efficient font drawing --- vesad/src/display.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index ea1379dc63..064321fba1 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -91,7 +91,7 @@ impl Display { #[cfg(not(feature="rusttype"))] pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) { if x + 8 <= self.width && y + 16 <= self.height { - let mut dst = unsafe { self.offscreen.as_mut_ptr().offset((y * self.width + x) as isize) }; + let mut dst = self.offscreen.as_mut_ptr() as usize + (y * self.width + x) * 4; let font_i = 16 * (character as usize); if font_i + 16 <= FONT.len() { @@ -99,10 +99,10 @@ impl Display { let row_data = FONT[font_i + row]; for col in 0..8 { if (row_data >> (7 - col)) & 1 == 1 { - unsafe { *dst.offset(col) = color; } + unsafe { *((dst + col * 4) as *mut u32) = color; } } } - dst = unsafe { dst.offset(self.width as isize) }; + dst += self.width * 4; } } } From e4005d0503e9443d556d5cc05d98594ca7261a61 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 29 Sep 2016 17:45:01 -0600 Subject: [PATCH 0038/1301] Add dup to ahci disk scheme --- ahcid/src/scheme.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 76b8b8a2bf..4b39ae37e3 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -43,6 +43,15 @@ impl Scheme for DiskScheme { } } + fn dup(&self, id: usize) -> Result { + let mut handles = self.handles.lock(); + let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let new_id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(new_id, handle.clone()); + Ok(new_id) + } + fn read(&self, id: usize, buf: &mut [u8]) -> Result { let mut handles = self.handles.lock(); let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; From c1a1de1a0d8fade1129d7972d8eb2f165d329ab0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 29 Sep 2016 18:34:58 -0600 Subject: [PATCH 0039/1301] Fix dup deadlock, add stat --- ahcid/src/scheme.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 4b39ae37e3..73d46fcbf5 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -3,7 +3,7 @@ use std::{cmp, str}; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use spin::Mutex; -use syscall::{Error, EBADF, EINVAL, ENOENT, Result, Scheme, SEEK_CUR, SEEK_END, SEEK_SET}; +use syscall::{Error, EBADF, EINVAL, ENOENT, Result, Scheme, Stat, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET}; use ahci::disk::Disk; @@ -45,13 +45,25 @@ impl Scheme for DiskScheme { fn dup(&self, id: usize) -> Result { let mut handles = self.handles.lock(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + let new_handle = { + let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + handle.clone() + }; let new_id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(new_id, handle.clone()); + handles.insert(new_id, new_handle); Ok(new_id) } + fn fstat(&self, id: usize, stat: &mut Stat) -> Result { + let handles = self.handles.lock(); + let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + + stat.st_mode = MODE_FILE; + stat.st_size = handle.0.lock().size(); + Ok(0) + } + fn read(&self, id: usize, buf: &mut [u8]) -> Result { let mut handles = self.handles.lock(); let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; From 758dfb5fe67e735a5b1c02111942a8c545ff8271 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 30 Sep 2016 10:27:12 -0600 Subject: [PATCH 0040/1301] Do not emit I/O error in the case that a small buffer is passed - just return 0 --- ahcid/src/ahci/disk.rs | 82 +++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 45 deletions(-) diff --git a/ahcid/src/ahci/disk.rs b/ahcid/src/ahci/disk.rs index fbef726151..5f37c013af 100644 --- a/ahcid/src/ahci/disk.rs +++ b/ahcid/src/ahci/disk.rs @@ -1,6 +1,6 @@ use std::ptr; -use syscall::error::{Error, EIO, Result}; +use syscall::error::Result; use super::dma::Dma; use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; @@ -56,61 +56,53 @@ impl Disk { pub fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { let sectors = buffer.len()/512; - if sectors > 0 { - let mut sector: usize = 0; - while sectors - sector >= 255 { - if let Err(err) = self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } - unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); } - - sector += 255; - } - if sector < sectors { - if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } - - unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); } - - sector += sectors - sector; + let mut sector: usize = 0; + while sectors - sector >= 255 { + if let Err(err) = self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); } - Ok(sector * 512) - } else { - println!("Invalid request"); - Err(Error::new(EIO)) + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); } + + sector += 255; } + if sector < sectors { + if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); + } + + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); } + + sector += sectors - sector; + } + + Ok(sector * 512) } pub fn write(&mut self, block: u64, buffer: &[u8]) -> Result { - let sectors = (buffer.len() + 511)/512; - if sectors > 0 { - let mut sector: usize = 0; - while sectors - sector >= 255 { - unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), 255 * 512); } + let sectors = buffer.len()/512; - if let Err(err) = self.port.ata_dma(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } + let mut sector: usize = 0; + while sectors - sector >= 255 { + unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), 255 * 512); } - sector += 255; - } - if sector < sectors { - unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), (sectors - sector) * 512); } - - if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } - - sector += sectors - sector; + if let Err(err) = self.port.ata_dma(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); } - Ok(sector * 512) - } else { - println!("Invalid request"); - Err(Error::new(EIO)) + sector += 255; } + if sector < sectors { + unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), (sectors - sector) * 512); } + + if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return Err(err); + } + + sector += sectors - sector; + } + + Ok(sector * 512) } } From 9027443bf743337ff25a51384b1fe73f506fe206 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 30 Sep 2016 10:34:44 -0600 Subject: [PATCH 0041/1301] Add delete and insert to ps2d --- ps2d/src/keyboard.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ps2d/src/keyboard.rs b/ps2d/src/keyboard.rs index a726208319..d50557ed54 100644 --- a/ps2d/src/keyboard.rs +++ b/ps2d/src/keyboard.rs @@ -60,6 +60,12 @@ pub fn keyboard() { 0x51 => { // Page down input.write(b"\x1B[6~").unwrap(); }, + 0x52 => { // Insert + input.write(b"\x1B[2~").unwrap(); + }, + 0x53 => { // Delete + input.write(b"\x1B[3~").unwrap(); + }, _ => { let c = if ctrl { match keymap::get_char(scancode, false) { From 1983def7f4743cfd600d6f3ab0cda15cfd00206a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 30 Sep 2016 12:06:50 -0600 Subject: [PATCH 0042/1301] More detailed print on ahci error --- ahcid/src/ahci/hba.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index a5b3a13260..3f6748c371 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -78,6 +78,8 @@ impl HbaPort { self.clb.write(clb.physical() as u64); self.fb.write(fb.physical() as u64); + let is = self.is.read(); + self.is.write(is); for i in 0..32 { let cmdheader = &mut clb[i]; @@ -272,11 +274,13 @@ impl HbaPort { while self.ci.readf(1 << slot) { if self.is.readf(HBA_PORT_IS_TFES) { + println!("IS_TFES set in CI loop TFS {:X} SERR {:X}", self.tfd.read(), self.serr.read()); return Err(Error::new(EIO)); } } if self.is.readf(HBA_PORT_IS_TFES) { + println!("IS_TFES set after CI loop TFS {:X} SERR {:X}", self.tfd.read(), self.serr.read()); return Err(Error::new(EIO)); } @@ -306,6 +310,13 @@ pub struct HbaMem { pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers } +impl HbaMem { + pub fn reset(&mut self) { + self.ghc.writef(1, true); + while self.ghc.readf(1) {} + } +} + #[repr(packed)] pub struct HbaPrdtEntry { dba: Mmio, // Data base address From 7eb3a5f23ad6cdfbf3bbd10ccf28d209b03855ff Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 5 Oct 2016 14:24:08 -0600 Subject: [PATCH 0043/1301] Add permissions to the filesystem, preliminary permissions to the syscalls --- vesad/src/main.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 74c17f93f1..5deb03e231 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -258,6 +258,9 @@ fn main() { if ! scheme.input.borrow().is_empty() && *scheme.requested.borrow() & EVENT_READ == EVENT_READ { let event_packet = Packet { id: 0, + pid: 0, + uid: 0, + gid: 0, a: syscall::number::SYS_FEVENT, b: 0, c: EVENT_READ, From 00a9a1284070de1f94b80ecb55d25ab1e111beeb Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 5 Oct 2016 18:01:05 -0600 Subject: [PATCH 0044/1301] Implement unix permissions --- ahcid/src/scheme.rs | 2 +- vesad/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 73d46fcbf5..eb2ec12a12 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -29,7 +29,7 @@ impl DiskScheme { } impl Scheme for DiskScheme { - fn open(&self, path: &[u8], _flags: usize) -> Result { + fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 5deb03e231..1da58dd3c6 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -70,7 +70,7 @@ impl DisplayScheme { } impl Scheme for DisplayScheme { - fn open(&self, path: &[u8], _flags: usize) -> Result { + fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { if path == b"input" { Ok(1) } else { From da74f55e06569f9df050e1edbb7c9dc513767515 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 6 Oct 2016 19:21:48 -0600 Subject: [PATCH 0045/1301] Correct ctrl-c behavior --- vesad/src/main.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 1da58dd3c6..c6247a26fe 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -28,6 +28,7 @@ struct DisplayScheme { display: RefCell, changed: RefCell>, input: RefCell>, + end_of_input: RefCell, cooked: RefCell>, requested: RefCell } @@ -124,6 +125,9 @@ impl Scheme for DisplayScheme { buf[i] = input.pop_front().unwrap(); i += 1; } + if i == 0 { + *self.end_of_input.borrow_mut() = false; + } Ok(i) } @@ -136,6 +140,10 @@ impl Scheme for DisplayScheme { } else { for &b in buf.iter() { match b { + b'\x03' => { + *self.end_of_input.borrow_mut() = true; + self.write(0, b"^C\n")?; + }, b'\x08' | b'\x7F' => { if let Some(_c) = self.cooked.borrow_mut().pop_back() { self.write(0, b"\x08")?; @@ -226,6 +234,7 @@ fn main() { )), changed: RefCell::new(BTreeSet::new()), input: RefCell::new(VecDeque::new()), + end_of_input: RefCell::new(false), cooked: RefCell::new(VecDeque::new()), requested: RefCell::new(0) }; @@ -237,7 +246,14 @@ fn main() { //println!("vesad: {:?}", packet); // If it is a read packet, and there is no data, block it. Otherwise, handle packet + let mut block = false; if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.input.borrow().is_empty() { + if ! *scheme.end_of_input.borrow() { + block = true; + } + } + + if block { blocked.push_back(packet); } else { scheme.handle(&mut packet); @@ -245,7 +261,7 @@ fn main() { } // If there are blocked readers, and data is available, handle them - while ! scheme.input.borrow().is_empty() { + while ! scheme.input.borrow().is_empty() || *scheme.end_of_input.borrow() { if let Some(mut packet) = blocked.pop_front() { scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); @@ -255,7 +271,7 @@ fn main() { } // If there are requested events, and data is available, send a notification - if ! scheme.input.borrow().is_empty() && *scheme.requested.borrow() & EVENT_READ == EVENT_READ { + if (! scheme.input.borrow().is_empty() || *scheme.end_of_input.borrow()) && *scheme.requested.borrow() & EVENT_READ == EVENT_READ { let event_packet = Packet { id: 0, pid: 0, From 2cadfb8691773c626e1ebcb08f2698ce5715556c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 7 Oct 2016 20:18:05 -0600 Subject: [PATCH 0046/1301] Graphics (#13) Virtual Terminals --- ahcid/Cargo.toml | 1 + ahcid/src/ahci/disk.rs | 2 +- ahcid/src/ahci/hba.rs | 5 +- ahcid/src/ahci/mod.rs | 1 - ahcid/src/main.rs | 1 + dma/Cargo.toml | 6 + ahcid/src/ahci/dma.rs => dma/src/lib.rs | 6 +- e1000d/Cargo.toml | 10 + e1000d/src/main.rs | 41 ++++ ps2d/src/keyboard.rs | 11 +- vesad/Cargo.toml | 5 +- vesad/src/console.rs | 3 + vesad/src/display.rs | 38 ++-- vesad/src/main.rs | 241 +++--------------------- vesad/src/scheme.rs | 143 ++++++++++++++ vesad/src/screen/graphic.rs | 1 + vesad/src/screen/mod.rs | 10 + vesad/src/screen/text.rs | 149 +++++++++++++++ 18 files changed, 438 insertions(+), 236 deletions(-) create mode 100644 dma/Cargo.toml rename ahcid/src/ahci/dma.rs => dma/src/lib.rs (95%) create mode 100644 e1000d/Cargo.toml create mode 100644 e1000d/src/main.rs create mode 100644 vesad/src/console.rs create mode 100644 vesad/src/scheme.rs create mode 100644 vesad/src/screen/graphic.rs create mode 100644 vesad/src/screen/mod.rs create mode 100644 vesad/src/screen/text.rs diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index 2bc8fa89f1..80725d7b71 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" [dependencies] bitflags = "*" +dma = { path = "../dma/" } io = { path = "../io/" } spin = "*" syscall = { path = "../../syscall/" } diff --git a/ahcid/src/ahci/disk.rs b/ahcid/src/ahci/disk.rs index 5f37c013af..f28d5e83a8 100644 --- a/ahcid/src/ahci/disk.rs +++ b/ahcid/src/ahci/disk.rs @@ -1,8 +1,8 @@ use std::ptr; +use dma::Dma; use syscall::error::Result; -use super::dma::Dma; use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; pub struct Disk { diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 3f6748c371..43d29e1f1b 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -1,12 +1,11 @@ -use io::{Io, Mmio}; - use std::mem::size_of; use std::ops::DerefMut; use std::{ptr, u32}; +use dma::Dma; +use io::{Io, Mmio}; use syscall::error::{Error, Result, EIO}; -use super::dma::Dma; use super::fis::{FisType, FisRegH2D}; const ATA_CMD_READ_DMA_EXT: u8 = 0x25; diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index 9d594ded2e..b4e146588b 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -4,7 +4,6 @@ use self::disk::Disk; use self::hba::{HbaMem, HbaPortType}; pub mod disk; -pub mod dma; pub mod fis; pub mod hba; diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 07ca38e1b7..7f5ccdad25 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -3,6 +3,7 @@ #[macro_use] extern crate bitflags; +extern crate dma; extern crate io; extern crate spin; extern crate syscall; diff --git a/dma/Cargo.toml b/dma/Cargo.toml new file mode 100644 index 0000000000..e05c929079 --- /dev/null +++ b/dma/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "dma" +version = "0.1.0" + +[dependencies] +syscall = { path = "../../syscall/" } diff --git a/ahcid/src/ahci/dma.rs b/dma/src/lib.rs similarity index 95% rename from ahcid/src/ahci/dma.rs rename to dma/src/lib.rs index 91258b8be9..fa8e3d12da 100644 --- a/ahcid/src/ahci/dma.rs +++ b/dma/src/lib.rs @@ -1,7 +1,11 @@ +#![feature(question_mark)] + +extern crate syscall; + use std::{mem, ptr}; use std::ops::{Deref, DerefMut}; -use syscall::{self, Result}; +use syscall::Result; struct PhysBox { address: usize, diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml new file mode 100644 index 0000000000..eacd0d12d8 --- /dev/null +++ b/e1000d/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "rtl8139d" +version = "0.1.0" + +[dependencies] +bitflags = "*" +dma = { path = "../dma/" } +io = { path = "../io/" } +spin = "*" +syscall = { path = "../../syscall/" } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs new file mode 100644 index 0000000000..9ae8b04398 --- /dev/null +++ b/e1000d/src/main.rs @@ -0,0 +1,41 @@ +#![feature(asm)] + +extern crate dma; +extern crate syscall; + +use std::{env, thread}; +use std::fs::File; +use std::io::{Read, Write}; + +use syscall::{iopl, physmap, physunmap, Packet, MAP_WRITE}; + +fn main() { + let mut args = env::args().skip(1); + + let bar_str = args.next().expect("e1000d: no address provided"); + let bar = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address"); + + let irq_str = args.next().expect("e1000d: no irq provided"); + let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); + + thread::spawn(move || { + unsafe { + iopl(3).expect("e1000d: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("e1000d: failed to map address") }; + { + println!("e1000d {:X}", bar); + let mut socket = File::create(":network").expect("e1000d: failed to create network scheme"); + //let scheme = DiskScheme::new(ahci::disks(address, irq)); + loop { + let mut packet = Packet::default(); + socket.read(&mut packet).expect("e1000d: failed to read network scheme"); + //scheme.handle(&mut packet); + socket.write(&mut packet).expect("e1000d: failed to read network scheme"); + } + } + unsafe { let _ = physunmap(address); } + }); +} diff --git a/ps2d/src/keyboard.rs b/ps2d/src/keyboard.rs index d50557ed54..8eb28583f3 100644 --- a/ps2d/src/keyboard.rs +++ b/ps2d/src/keyboard.rs @@ -36,6 +36,15 @@ pub fn keyboard() { rshift = pressed; } else if pressed { match scancode { + f @ 0x3B ... 0x44 => { // F1 through F10 + input.write(&[(f - 0x3B) + 0xF4]).unwrap(); + }, + 0x57 => { // F11 + input.write(&[0xFE]).unwrap(); + }, + 0x58 => { // F12 + input.write(&[0xFF]).unwrap(); + }, 0x47 => { // Home input.write(b"\x1B[H").unwrap(); }, @@ -69,7 +78,7 @@ pub fn keyboard() { _ => { let c = if ctrl { match keymap::get_char(scancode, false) { - c @ 'a' ... 'z' => (c as u8 - b'a' + b'\x01') as char, + c @ 'a' ... 'z' => ((c as u8 - b'a') + b'\x01') as char, c => c } } else { diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index cf0c2fa04b..ebfdf0bba1 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -4,5 +4,8 @@ version = "0.1.0" [dependencies] ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" } -rusttype = { git = "https://github.com/dylanede/rusttype.git" } +rusttype = { git = "https://github.com/dylanede/rusttype.git", optional = true } syscall = { path = "../../syscall/" } + +[features] +default = [] diff --git a/vesad/src/console.rs b/vesad/src/console.rs new file mode 100644 index 0000000000..ea3546d5e7 --- /dev/null +++ b/vesad/src/console.rs @@ -0,0 +1,3 @@ +pub struct Text { + +} diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 064321fba1..a21be24ab0 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -1,7 +1,8 @@ #[cfg(feature="rusttype")] extern crate rusttype; -use std::cmp; +use alloc::heap; +use std::{cmp, slice}; use primitive::{fast_set32, fast_set64, fast_copy, fast_copy64}; @@ -11,6 +12,15 @@ use self::rusttype::{Font, FontCollection, Scale, point}; #[cfg(not(feature="rusttype"))] static FONT: &'static [u8] = include_bytes!("../../../res/fonts/unifont.font"); +#[cfg(feature="rusttype")] +static FONT: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono.ttf"); +#[cfg(feature="rusttype")] +static FONT_BOLD: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Bold.ttf"); +#[cfg(feature="rusttype")] +static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-BoldOblique.ttf"); +#[cfg(feature="rusttype")] +static FONT_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf"); + /// A display #[cfg(not(feature="rusttype"))] pub struct Display { @@ -39,26 +49,32 @@ pub struct Display { impl Display { #[cfg(not(feature="rusttype"))] - pub fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display { + pub fn new(width: usize, height: usize, onscreen: usize) -> Display { + let size = width * height; + let offscreen = unsafe { heap::allocate(size * 4, 4096) }; + unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; Display { width: width, height: height, - onscreen: onscreen, - offscreen: offscreen + onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, + offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } } } #[cfg(feature="rusttype")] - pub fn new(width: usize, height: usize, onscreen: &'static mut [u32], offscreen: &'static mut [u32]) -> Display { + pub fn new(width: usize, height: usize, onscreen: usize) -> Display { + let size = width * height; + let offscreen = unsafe { heap::allocate(size * 4, 4096) }; + unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; Display { width: width, height: height, - onscreen: onscreen, - offscreen: offscreen, - font: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono.ttf")).into_font().unwrap(), - font_bold: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono-Bold.ttf")).into_font().unwrap(), - font_bold_italic: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono-BoldOblique.ttf")).into_font().unwrap(), - font_italic: FontCollection::from_bytes(include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf")).into_font().unwrap() + onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, + offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }, + font: FontCollection::from_bytes(FONT).into_font().unwrap(), + font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(), + font_bold_italic: FontCollection::from_bytes(FONT_BOLD_ITALIC).into_font().unwrap(), + font_italic: FontCollection::from_bytes(FONT_ITALIC).into_font().unwrap() } } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index c6247a26fe..57a13b3ca1 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -4,200 +4,22 @@ #![feature(question_mark)] extern crate alloc; -extern crate ransid; extern crate syscall; -use std::cell::RefCell; -use std::collections::{BTreeSet, VecDeque}; use std::fs::File; use std::io::{Read, Write}; -use std::{slice, thread}; -use ransid::{Console, Event}; -use syscall::{physmap, physunmap, Packet, Result, Scheme, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE}; +use std::thread; +use syscall::{physmap, physunmap, Packet, Scheme, MAP_WRITE, MAP_WRITE_COMBINE}; -use display::Display; use mode_info::VBEModeInfo; use primitive::fast_set64; +use scheme::DisplayScheme; pub mod display; pub mod mode_info; pub mod primitive; - -struct DisplayScheme { - console: RefCell, - display: RefCell, - changed: RefCell>, - input: RefCell>, - end_of_input: RefCell, - cooked: RefCell>, - requested: RefCell -} - -impl DisplayScheme { - fn event(&self, event: Event) { - let mut display = self.display.borrow_mut(); - let mut changed = self.changed.borrow_mut(); - - match event { - Event::Char { x, y, c, color, bold, .. } => { - display.char(x * 8, y * 16, c, color.data, bold, false); - changed.insert(y); - }, - Event::Rect { x, y, w, h, color } => { - display.rect(x * 8, y * 16, w * 8, h * 16, color.data); - for y2 in y..y + h { - changed.insert(y2); - } - }, - Event::Scroll { rows, color } => { - display.scroll(rows * 16, color.data); - for y in 0..display.height/16 { - changed.insert(y); - } - } - } - } - - fn sync(&self) { - let mut display = self.display.borrow_mut(); - let mut changed = self.changed.borrow_mut(); - - let width = display.width; - for change in changed.iter() { - display.sync(0, change * 16, width, 16); - } - changed.clear(); - } -} - -impl Scheme for DisplayScheme { - fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - if path == b"input" { - Ok(1) - } else { - Ok(0) - } - } - - fn dup(&self, id: usize) -> Result { - Ok(id) - } - - fn fevent(&self, _id: usize, flags: usize) -> Result { - *self.requested.borrow_mut() = flags; - println!("fevent {:X}", flags); - Ok(0) - } - - fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let path_str = if id == 1 { - format!("display:input") - } else { - let console = self.console.borrow(); - format!("display:{}/{}", console.w, console.h) - }; - - let path = path_str.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) - } - - fn fsync(&self, id: usize) -> Result { - if id == 1 { - - } else { - self.sync(); - } - - Ok(0) - } - - fn read(&self, _id: usize, buf: &mut [u8]) -> Result { - let mut i = 0; - let mut input = self.input.borrow_mut(); - while i < buf.len() && ! input.is_empty() { - buf[i] = input.pop_front().unwrap(); - i += 1; - } - if i == 0 { - *self.end_of_input.borrow_mut() = false; - } - Ok(i) - } - - fn write(&self, id: usize, buf: &[u8]) -> Result { - if id == 1 { - if self.console.borrow().raw_mode { - for &b in buf.iter() { - self.input.borrow_mut().push_back(b); - } - } else { - for &b in buf.iter() { - match b { - b'\x03' => { - *self.end_of_input.borrow_mut() = true; - self.write(0, b"^C\n")?; - }, - b'\x08' | b'\x7F' => { - if let Some(_c) = self.cooked.borrow_mut().pop_back() { - self.write(0, b"\x08")?; - } - }, - b'\n' | b'\r' => { - self.cooked.borrow_mut().push_back(b); - while let Some(c) = self.cooked.borrow_mut().pop_front() { - self.input.borrow_mut().push_back(c); - } - self.write(0, b"\n")?; - }, - _ => { - self.cooked.borrow_mut().push_back(b); - self.write(0, &[b])?; - } - } - } - } - Ok(buf.len()) - } else { - let mut console = self.console.borrow_mut(); - if console.cursor && console.x < console.w && console.y < console.h { - self.event(Event::Rect { - x: console.x, - y: console.y, - w: 1, - h: 1, - color: console.background - }); - } - console.write(buf, |event| { - self.event(event); - }); - if console.cursor && console.x < console.w && console.y < console.h { - self.event(Event::Rect { - x: console.x, - y: console.y, - w: 1, - h: 1, - color: console.foreground - }); - } - if ! console.raw_mode { - self.sync(); - } - Ok(buf.len()) - } - } - - fn close(&self, _id: usize) -> Result { - Ok(0) - } -} +pub mod scheme; +pub mod screen; fn main() { let width; @@ -220,58 +42,42 @@ fn main() { let size = width * height; - let onscreen = unsafe { physmap(physbaseptr as usize, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; + let onscreen = unsafe { physmap(physbaseptr, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; unsafe { fast_set64(onscreen as *mut u64, 0, size/2) }; - let offscreen = unsafe { alloc::heap::allocate(size * 4, 4096) }; - unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; + let scheme = DisplayScheme::new(width, height, onscreen); - let scheme = DisplayScheme { - console: RefCell::new(Console::new(width/8, height/16)), - display: RefCell::new(Display::new(width, height, - unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, - unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } - )), - changed: RefCell::new(BTreeSet::new()), - input: RefCell::new(VecDeque::new()), - end_of_input: RefCell::new(false), - cooked: RefCell::new(VecDeque::new()), - requested: RefCell::new(0) - }; - - let mut blocked = VecDeque::new(); + let mut blocked = Vec::new(); loop { let mut packet = Packet::default(); socket.read(&mut packet).expect("vesad: failed to read display scheme"); //println!("vesad: {:?}", packet); // If it is a read packet, and there is no data, block it. Otherwise, handle packet - let mut block = false; - if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.input.borrow().is_empty() { - if ! *scheme.end_of_input.borrow() { - block = true; - } - } - - if block { - blocked.push_back(packet); + if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.will_block(packet.b) { + blocked.push(packet); } else { scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); } // If there are blocked readers, and data is available, handle them - while ! scheme.input.borrow().is_empty() || *scheme.end_of_input.borrow() { - if let Some(mut packet) = blocked.pop_front() { - scheme.handle(&mut packet); - socket.write(&packet).expect("vesad: failed to write display scheme"); - } else { - break; + { + let mut i = 0; + while i < blocked.len() { + if ! scheme.will_block(blocked[i].b) { + let mut packet = blocked.remove(i); + scheme.handle(&mut packet); + socket.write(&packet).expect("vesad: failed to write display scheme"); + } else { + i += 1; + } } } // If there are requested events, and data is available, send a notification - if (! scheme.input.borrow().is_empty() || *scheme.end_of_input.borrow()) && *scheme.requested.borrow() & EVENT_READ == EVENT_READ { + /* TODO + if (! scheme.screen.borrow().input.is_empty() || scheme.screen.borrow().end_of_input) && scheme.screen.borrow().requested & EVENT_READ == EVENT_READ { let event_packet = Packet { id: 0, pid: 0, @@ -280,10 +86,11 @@ fn main() { a: syscall::number::SYS_FEVENT, b: 0, c: EVENT_READ, - d: scheme.input.borrow().len() + d: scheme.screen.borrow().input.len() }; socket.write(&event_packet).expect("vesad: failed to write display scheme"); } + */ } }); } diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs new file mode 100644 index 0000000000..4c9155d038 --- /dev/null +++ b/vesad/src/scheme.rs @@ -0,0 +1,143 @@ +use std::cell::{Cell, RefCell}; +use std::collections::BTreeMap; +use std::str; + +use syscall::{Result, Error, EBADF, ENOENT, Scheme}; + +use display::Display; +use screen::TextScreen; + +pub struct DisplayScheme { + width: usize, + height: usize, + onscreen: usize, + active: Cell, + screens: RefCell> +} + +impl DisplayScheme { + pub fn new(width: usize, height: usize, onscreen: usize) -> DisplayScheme { + let mut screens = BTreeMap::new(); + for i in 1..7 { + screens.insert(i, TextScreen::new(Display::new(width, height, onscreen))); + } + + DisplayScheme { + width: width, + height: height, + onscreen: onscreen, + active: Cell::new(1), + screens: RefCell::new(screens) + } + } + + pub fn will_block(&self, id: usize) -> bool { + let screens = self.screens.borrow(); + if let Some(screen) = screens.get(&id) { + screen.will_block() + } else { + false + } + } +} + +impl Scheme for DisplayScheme { + fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { + if path == b"input" { + Ok(0) + } else { + let path_str = str::from_utf8(path).unwrap_or(""); + let id = path_str.parse::().unwrap_or(0); + if self.screens.borrow().contains_key(&id) { + Ok(id) + } else { + Err(Error::new(ENOENT)) + } + } + } + + fn dup(&self, id: usize) -> Result { + Ok(id) + } + + fn fevent(&self, id: usize, flags: usize) -> Result { + let mut screens = self.screens.borrow_mut(); + if let Some(mut screen) = screens.get_mut(&id) { + println!("fevent {:X}", flags); + screen.requested = flags; + Ok(0) + } else { + Err(Error::new(EBADF)) + } + } + + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { + let screens = self.screens.borrow(); + let path_str = if id == 0 { + format!("display:input") + } else if let Some(screen) = screens.get(&id) { + format!("display:{}/{}/{}", id, screen.console.w, screen.console.h) + } else { + return Err(Error::new(EBADF)); + }; + + let path = path_str.as_bytes(); + + let mut i = 0; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; + i += 1; + } + + Ok(i) + } + + fn fsync(&self, id: usize) -> Result { + let mut screens = self.screens.borrow_mut(); + if let Some(mut screen) = screens.get_mut(&id) { + if id == self.active.get() { + screen.sync(); + } + Ok(0) + } else { + Err(Error::new(EBADF)) + } + } + + fn read(&self, id: usize, buf: &mut [u8]) -> Result { + let mut screens = self.screens.borrow_mut(); + if let Some(mut screen) = screens.get_mut(&id) { + screen.read(buf) + } else { + Err(Error::new(EBADF)) + } + } + + fn write(&self, id: usize, buf: &[u8]) -> Result { + let mut screens = self.screens.borrow_mut(); + if id == 0 { + if buf.len() == 1 && buf[0] >= 0xF4 { + let new_active = (buf[0] - 0xF4) as usize + 1; + if let Some(mut screen) = screens.get_mut(&new_active) { + self.active.set(new_active); + screen.redraw(); + } + Ok(1) + } else { + if let Some(mut screen) = screens.get_mut(&self.active.get()) { + screen.input(buf) + } else { + Err(Error::new(EBADF)) + } + } + } else if let Some(mut screen) = screens.get_mut(&id) { + screen.write(buf, id == self.active.get()) + } else { + Err(Error::new(EBADF)) + } + } + + fn close(&self, _id: usize) -> Result { + Ok(0) + } +} diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs new file mode 100644 index 0000000000..9e6b71aa08 --- /dev/null +++ b/vesad/src/screen/graphic.rs @@ -0,0 +1 @@ +pub struct GraphicScreen; diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs new file mode 100644 index 0000000000..01e1583213 --- /dev/null +++ b/vesad/src/screen/mod.rs @@ -0,0 +1,10 @@ +pub use self::graphic::GraphicScreen; +pub use self::text::TextScreen; + +mod graphic; +mod text; + +pub enum Screen { + Graphic(GraphicScreen), + Text(TextScreen) +} diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs new file mode 100644 index 0000000000..bf187b78d2 --- /dev/null +++ b/vesad/src/screen/text.rs @@ -0,0 +1,149 @@ +extern crate ransid; + +use std::collections::{BTreeSet, VecDeque}; + +use self::ransid::{Console, Event}; +use syscall::Result; + +use display::Display; + +pub struct TextScreen { + pub console: Console, + pub display: Display, + pub changed: BTreeSet, + pub input: VecDeque, + pub end_of_input: bool, + pub cooked: VecDeque, + pub requested: usize +} + +impl TextScreen { + pub fn new(display: Display) -> TextScreen { + TextScreen { + console: Console::new(display.width/8, display.height/16), + display: display, + changed: BTreeSet::new(), + input: VecDeque::new(), + end_of_input: false, + cooked: VecDeque::new(), + requested: 0 + } + } + + pub fn input(&mut self, buf: &[u8]) -> Result { + if self.console.raw_mode { + for &b in buf.iter() { + self.input.push_back(b); + } + } else { + for &b in buf.iter() { + match b { + b'\x03' => { + self.end_of_input = true; + self.write(b"^C\n", true)?; + }, + b'\x08' | b'\x7F' => { + if let Some(_c) = self.cooked.pop_back() { + self.write(b"\x08", true)?; + } + }, + b'\n' | b'\r' => { + self.cooked.push_back(b); + while let Some(c) = self.cooked.pop_front() { + self.input.push_back(c); + } + self.write(b"\n", true)?; + }, + _ => { + self.cooked.push_back(b); + self.write(&[b], true)?; + } + } + } + } + Ok(buf.len()) + } + + pub fn read(&mut self, buf: &mut [u8]) -> Result { + let mut i = 0; + + while i < buf.len() && ! self.input.is_empty() { + buf[i] = self.input.pop_front().unwrap(); + i += 1; + } + + if i == 0 { + self.end_of_input = false; + } + + Ok(i) + } + + pub fn will_block(&self) -> bool { + self.input.is_empty() && ! self.end_of_input + } + + pub fn write(&mut self, buf: &[u8], sync: bool) -> Result { + if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h { + let x = self.console.x; + let y = self.console.y; + let color = self.console.background; + self.display.rect(x * 8, y * 16, 8, 16, color.data); + self.changed.insert(y); + } + + { + let display = &mut self.display; + let changed = &mut self.changed; + self.console.write(buf, |event| { + match event { + Event::Char { x, y, c, color, bold, .. } => { + display.char(x * 8, y * 16, c, color.data, bold, false); + changed.insert(y); + }, + Event::Rect { x, y, w, h, color } => { + display.rect(x * 8, y * 16, w * 8, h * 16, color.data); + for y2 in y..y + h { + changed.insert(y2); + } + }, + Event::Scroll { rows, color } => { + display.scroll(rows * 16, color.data); + for y in 0..display.height/16 { + changed.insert(y); + } + } + } + }); + } + + if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h { + let x = self.console.x; + let y = self.console.y; + let color = self.console.foreground; + self.display.rect(x * 8, y * 16, 8, 16, color.data); + self.changed.insert(y); + } + + if ! self.console.raw_mode && sync { + self.sync(); + } + + Ok(buf.len()) + } + + pub fn sync(&mut self) { + let width = self.display.width; + for change in self.changed.iter() { + self.display.sync(0, change * 16, width, 16); + } + self.changed.clear(); + } + + pub fn redraw(&mut self) { + let width = self.display.width; + let height = self.display.height; + self.display.sync(0, 0, width, height); + self.changed.clear(); + } +} From a6304e690ea58d1205c34aa65ff73371fa8f61c0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 8 Oct 2016 20:36:21 -0600 Subject: [PATCH 0047/1301] Enable bus mastering --- pcid/src/main.rs | 6 ++++++ pcid/src/pci/mod.rs | 11 +++++++++++ 2 files changed, 17 insertions(+) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index a34ff17ab2..108e8303bb 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -108,6 +108,12 @@ fn main() { } if let Some(ref args) = driver.command { + // Enable bus mastering + unsafe { + let cmd = pci.read(bus.num, dev.num, func.num, 0x04); + pci.write(bus.num, dev.num, func.num, 0x04, cmd | 4); + } + let mut args = args.iter(); if let Some(program) = args.next() { let mut command = Command::new(program); diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 0d760ef446..d2a8e8906a 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -34,6 +34,17 @@ impl Pci { : "={eax}"(value) : "{eax}"(address) : "dx" : "intel", "volatile"); value } + + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) { + let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); + asm!("mov dx, 0xCF8 + out dx, eax" + : : "{eax}"(address) : "dx" : "intel", "volatile"); + asm!("mov dx, 0xCFC + out dx, eax" + : : "{eax}"(value) : "dx" : "intel", "volatile"); + } } pub struct PciIter<'pci> { From 936f177775026c6f283fe44c8709633d99a43d2a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 8 Oct 2016 20:36:51 -0600 Subject: [PATCH 0048/1301] Allow sending/receiving with e1000 driver --- e1000d/src/device.rs | 297 +++++++++++++++++++++++++++++++++++++++++++ e1000d/src/main.rs | 12 +- 2 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 e1000d/src/device.rs diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs new file mode 100644 index 0000000000..ffe87749da --- /dev/null +++ b/e1000d/src/device.rs @@ -0,0 +1,297 @@ +use std::{cmp, mem, ptr, slice}; + +use dma::Dma; +use syscall::error::Result; +use syscall::scheme::Scheme; + +const CTRL: u32 = 0x00; +const CTRL_LRST: u32 = 1 << 3; +const CTRL_ASDE: u32 = 1 << 5; +const CTRL_SLU: u32 = 1 << 6; +const CTRL_ILOS: u32 = 1 << 7; +const CTRL_VME: u32 = 1 << 30; +const CTRL_PHY_RST: u32 = 1 << 31; + +const STATUS: u32 = 0x08; + +const FCAL: u32 = 0x28; +const FCAH: u32 = 0x2C; +const FCT: u32 = 0x30; +const FCTTV: u32 = 0x170; + +const ICR: u32 = 0xC0; + +const IMS: u32 = 0xD0; +const IMS_TXDW: u32 = 1; +const IMS_TXQE: u32 = 1 << 1; +const IMS_LSC: u32 = 1 << 2; +const IMS_RXSEQ: u32 = 1 << 3; +const IMS_RXDMT: u32 = 1 << 4; +const IMS_RX: u32 = 1 << 6; +const IMS_RXT: u32 = 1 << 7; + +const RCTL: u32 = 0x100; +const RCTL_EN: u32 = 1 << 1; +const RCTL_UPE: u32 = 1 << 3; +const RCTL_MPE: u32 = 1 << 4; +const RCTL_LPE: u32 = 1 << 5; +const RCTL_LBM: u32 = 1 << 6 | 1 << 7; +const RCTL_BAM: u32 = 1 << 15; +const RCTL_BSIZE1: u32 = 1 << 16; +const RCTL_BSIZE2: u32 = 1 << 17; +const RCTL_BSEX: u32 = 1 << 25; +const RCTL_SECRC: u32 = 1 << 26; + +const RDBAL: u32 = 0x2800; +const RDBAH: u32 = 0x2804; +const RDLEN: u32 = 0x2808; +const RDH: u32 = 0x2810; +const RDT: u32 = 0x2818; + +const RAL0: u32 = 0x5400; +const RAH0: u32 = 0x5404; + +#[derive(Debug)] +#[repr(packed)] +struct Rd { + buffer: u64, + length: u16, + checksum: u16, + status: u8, + error: u8, + special: u16, +} +const RD_DD: u8 = 1; +const RD_EOP: u8 = 1 << 1; + +const TCTL: u32 = 0x400; +const TCTL_EN: u32 = 1 << 1; +const TCTL_PSP: u32 = 1 << 3; + +const TDBAL: u32 = 0x3800; +const TDBAH: u32 = 0x3804; +const TDLEN: u32 = 0x3808; +const TDH: u32 = 0x3810; +const TDT: u32 = 0x3818; + +#[derive(Debug)] +#[repr(packed)] +struct Td { + buffer: u64, + length: u16, + cso: u8, + command: u8, + status: u8, + css: u8, + special: u16, +} +const TD_CMD_EOP: u8 = 1; +const TD_CMD_IFCS: u8 = 1 << 1; +const TD_CMD_RS: u8 = 1 << 3; +const TD_DD: u8 = 1; + +pub struct Intel8254x { + base: usize, + irq: u8, + receive_buffer: [Dma<[u8; 16384]>; 16], + receive_ring: Dma<[Rd; 16]>, + transmit_buffer: [Dma<[u8; 16384]>; 16], + transmit_ring: Dma<[Td; 16]>, +} + +impl Scheme for Intel8254x { + fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { + Ok(0) + } + + fn dup(&self, id: usize) -> Result { + Ok(id) + } + + fn read(&self, _id: usize, buf: &mut [u8]) -> Result { + for tail in 0..self.receive_ring.len() { + let rd = unsafe { &mut * (self.receive_ring.as_ptr().offset(tail as isize) as *mut Rd) }; + if rd.status & RD_DD == RD_DD { + rd.status = 0; + + let data = &self.receive_buffer[tail as usize][.. rd.length as usize]; + + let mut i = 0; + while i < buf.len() && i < data.len() { + buf[i] = data[i]; + i += 1; + } + return Ok(i); + } + } + + Ok(0) + } + + fn write(&self, _id: usize, buf: &[u8]) -> Result { + loop { + let head = unsafe { self.read(TDH) }; + let mut tail = unsafe { self.read(TDT) }; + let old_tail = tail; + + tail += 1; + if tail >= self.transmit_ring.len() as u32 { + tail = 0; + } + + if tail != head { + let td = unsafe { &mut * (self.transmit_ring.as_ptr().offset(old_tail as isize) as *mut Td) }; + + td.cso = 0; + td.command = TD_CMD_EOP | TD_CMD_IFCS | TD_CMD_RS; + td.status = 0; + td.css = 0; + td.special = 0; + + td.length = (cmp::min(buf.len(), 0x3FFF)) as u16; + + let mut data = unsafe { slice::from_raw_parts_mut(self.transmit_buffer[old_tail as usize].as_ptr() as *mut u8, td.length as usize) }; + + let mut i = 0; + while i < buf.len() && i < data.len() { + data[i] = buf[i]; + i += 1; + } + + unsafe { self.write(TDT, tail) }; + + while td.status == 0 { + unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } + } + + return Ok(i); + } + } + + Ok(0) + } + + fn close(&self, _id: usize) -> Result { + Ok(0) + } +} + +impl Intel8254x { + pub unsafe fn new(base: usize, irq: u8) -> Result { + let mut module = Intel8254x { + base: base, + irq: irq, + receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], + receive_ring: Dma::zeroed()?, + transmit_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], + transmit_ring: Dma::zeroed()? + }; + + module.init(); + + Ok(module) + } + + pub unsafe fn read(&self, register: u32) -> u32 { + ptr::read_volatile((self.base + register as usize) as *mut u32) + } + + pub unsafe fn write(&self, register: u32, data: u32) -> u32 { + ptr::write_volatile((self.base + register as usize) as *mut u32, data); + ptr::read_volatile((self.base + register as usize) as *mut u32) + } + + pub unsafe fn flag(&self, register: u32, flag: u32, value: bool) { + if value { + self.write(register, self.read(register) | flag); + } else { + self.write(register, self.read(register) & (0xFFFFFFFF - flag)); + } + } + + pub unsafe fn init(&mut self) { + println!(" + Intel 8254x on: {:X}, IRQ: {}", self.base, self.irq); + + // Enable auto negotiate, link, clear reset, do not Invert Loss-Of Signal + self.flag(CTRL, CTRL_ASDE | CTRL_SLU, true); + self.flag(CTRL, CTRL_LRST, false); + self.flag(CTRL, CTRL_PHY_RST, false); + self.flag(CTRL, CTRL_ILOS, false); + + // No flow control + self.write(FCAH, 0); + self.write(FCAL, 0); + self.write(FCT, 0); + self.write(FCTTV, 0); + + // Do not use VLANs + self.flag(CTRL, CTRL_VME, false); + + // TODO: Clear statistical counters + + let mac_low = self.read(RAL0); + let mac_high = self.read(RAH0); + let mac = [mac_low as u8, + (mac_low >> 8) as u8, + (mac_low >> 16) as u8, + (mac_low >> 24) as u8, + mac_high as u8, + (mac_high >> 8) as u8]; + println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + // + // MTA => 0; + // + + // Receive Buffer + for i in 0..self.receive_ring.len() { + self.receive_ring[i].buffer = self.receive_buffer[i].physical() as u64; + } + + self.write(RDBAH, (self.receive_ring.physical() >> 32) as u32); + self.write(RDBAL, self.receive_ring.physical() as u32); + self.write(RDLEN, (self.receive_ring.len() * mem::size_of::()) as u32); + self.write(RDH, 0); + self.write(RDT, self.receive_ring.len() as u32 - 1); + + // Transmit Buffer + for i in 0..self.transmit_ring.len() { + self.transmit_ring[i].buffer = self.transmit_buffer[i].physical() as u64; + } + + self.write(TDBAH, (self.transmit_ring.physical() >> 32) as u32); + self.write(TDBAL, self.transmit_ring.physical() as u32); + self.write(TDLEN, (self.transmit_ring.len() * mem::size_of::()) as u32); + self.write(TDH, 0); + self.write(TDT, 0); + + //self.write(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ | IMS_LSC | IMS_TXQE | IMS_TXDW); + self.write(IMS, 0); + + self.flag(RCTL, RCTL_EN, true); + self.flag(RCTL, RCTL_UPE, true); + // self.flag(RCTL, RCTL_MPE, true); + self.flag(RCTL, RCTL_LPE, true); + self.flag(RCTL, RCTL_LBM, false); + // RCTL.RDMTS = Minimum threshold size ??? + // RCTL.MO = Multicast offset + self.flag(RCTL, RCTL_BAM, true); + self.flag(RCTL, RCTL_BSIZE1, true); + self.flag(RCTL, RCTL_BSIZE2, false); + self.flag(RCTL, RCTL_BSEX, true); + self.flag(RCTL, RCTL_SECRC, true); + + self.flag(TCTL, TCTL_EN, true); + self.flag(TCTL, TCTL_PSP, true); + // TCTL.CT = Collition threshold + // TCTL.COLD = Collision distance + // TIPG Packet Gap + // TODO ... + } +} diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 9ae8b04398..9156aab7ee 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -1,4 +1,5 @@ #![feature(asm)] +#![feature(question_mark)] extern crate dma; extern crate syscall; @@ -7,7 +8,9 @@ use std::{env, thread}; use std::fs::File; use std::io::{Read, Write}; -use syscall::{iopl, physmap, physunmap, Packet, MAP_WRITE}; +use syscall::{iopl, physmap, physunmap, Packet, Scheme, MAP_WRITE}; + +pub mod device; fn main() { let mut args = env::args().skip(1); @@ -24,15 +27,14 @@ fn main() { asm!("cli" :::: "intel", "volatile"); } - let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("e1000d: failed to map address") }; + let address = unsafe { physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") }; { - println!("e1000d {:X}", bar); + let mut device = unsafe { device::Intel8254x::new(address, irq).expect("e1000d: failed to allocate device") }; let mut socket = File::create(":network").expect("e1000d: failed to create network scheme"); - //let scheme = DiskScheme::new(ahci::disks(address, irq)); loop { let mut packet = Packet::default(); socket.read(&mut packet).expect("e1000d: failed to read network scheme"); - //scheme.handle(&mut packet); + device.handle(&mut packet); socket.write(&mut packet).expect("e1000d: failed to read network scheme"); } } From 815c471aed044d05060f19a182fad4da81b30e5a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 13 Oct 2016 17:21:42 -0600 Subject: [PATCH 0049/1301] Orbital (#16) * Port previous ethernet scheme * Add ipd * Fix initfs rebuilds, use QEMU user networking addresses in ipd * Add tcp/udp, netutils, dns, and network config * Add fsync to network driver * Add dns, router, subnet by default * Fix e1000 driver. Make ethernet and IP non-blocking to avoid deadlocks * Add orbital server, WIP * Add futex * Add orbutils and orbital * Update libstd, orbutils, and orbital Move ANSI key encoding to vesad * Add orbital assets * Update orbital * Update to add login manager * Add blocking primitives, block for most things except waitpid, update orbital * Wait in waitpid and IRQ, improvements for other waits * Fevent in root scheme * WIP: Switch to using fevent * Reorganize * Event based e1000d driver * Superuser-only access to some network schemes, display, and disk * Superuser root and irq schemes * Fix orbital --- ahcid/Cargo.toml | 4 +- ahcid/src/ahci/hba.rs | 26 ++++++-- ahcid/src/main.rs | 40 +++++++++--- ahcid/src/scheme.rs | 22 ++++--- dma/Cargo.toml | 6 -- dma/src/lib.rs | 80 ------------------------ e1000d/Cargo.toml | 5 +- e1000d/src/device.rs | 41 ++++++++++--- e1000d/src/main.rs | 73 ++++++++++++++++++---- io/Cargo.toml | 3 - io/src/io.rs | 67 -------------------- io/src/lib.rs | 14 ----- io/src/mmio.rs | 31 ---------- io/src/pio.rs | 89 --------------------------- ps2d/Cargo.toml | 4 +- ps2d/src/keyboard.rs | 72 +++------------------- ps2d/src/main.rs | 1 + ps2d/src/mouse.rs | 22 ++++--- vesad/Cargo.toml | 1 + vesad/src/main.rs | 1 + vesad/src/scheme.rs | 75 +++++++++++++++++------ vesad/src/screen/graphic.rs | 119 +++++++++++++++++++++++++++++++++++- vesad/src/screen/mod.rs | 26 +++++++- vesad/src/screen/text.rs | 110 +++++++++++++++++++++++++++------ 24 files changed, 483 insertions(+), 449 deletions(-) delete mode 100644 dma/Cargo.toml delete mode 100644 dma/src/lib.rs delete mode 100644 io/Cargo.toml delete mode 100644 io/src/io.rs delete mode 100644 io/src/lib.rs delete mode 100644 io/src/mmio.rs delete mode 100644 io/src/pio.rs diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index 80725d7b71..324ea857b2 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" [dependencies] bitflags = "*" -dma = { path = "../dma/" } -io = { path = "../io/" } +dma = { path = "../../crates/dma/" } +io = { path = "../../crates/io/" } spin = "*" syscall = { path = "../../syscall/" } diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 43d29e1f1b..e5ff7ca3d9 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -25,6 +25,10 @@ const HBA_SIG_ATAPI: u32 = 0xEB140101; const HBA_SIG_PM: u32 = 0x96690101; const HBA_SIG_SEMB: u32 = 0xC33C0101; +fn pause() { + unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } +} + #[derive(Debug)] pub enum HbaPortType { None, @@ -119,7 +123,9 @@ impl HbaPort { cmdfis.counth.write(0); } - while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { + pause(); + } self.ci.writef(1 << slot, true); @@ -127,6 +133,7 @@ impl HbaPort { if self.is.readf(HBA_PORT_IS_TFES) { return None; } + pause(); } if self.is.readf(HBA_PORT_IS_TFES) { @@ -194,7 +201,9 @@ impl HbaPort { } pub fn start(&mut self) { - while self.cmd.readf(HBA_PORT_CMD_CR) {} + while self.cmd.readf(HBA_PORT_CMD_CR) { + pause(); + } self.cmd.writef(HBA_PORT_CMD_FRE, true); self.cmd.writef(HBA_PORT_CMD_ST, true); @@ -203,7 +212,9 @@ impl HbaPort { pub fn stop(&mut self) { self.cmd.writef(HBA_PORT_CMD_ST, false); - while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) {} + while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { + pause(); + } self.cmd.writef(HBA_PORT_CMD_FRE, false); } @@ -267,7 +278,9 @@ impl HbaPort { cmdfis.counth.write((sectors >> 8) as u8); } - while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {} + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { + pause(); + } self.ci.writef(1 << slot, true); @@ -276,6 +289,7 @@ impl HbaPort { println!("IS_TFES set in CI loop TFS {:X} SERR {:X}", self.tfd.read(), self.serr.read()); return Err(Error::new(EIO)); } + pause(); } if self.is.readf(HBA_PORT_IS_TFES) { @@ -312,7 +326,9 @@ pub struct HbaMem { impl HbaMem { pub fn reset(&mut self) { self.ghc.writef(1, true); - while self.ghc.readf(1) {} + while self.ghc.readf(1) { + pause(); + } } } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 7f5ccdad25..880177b65b 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -8,10 +8,11 @@ extern crate io; extern crate spin; extern crate syscall; +use std::{env, thread, usize}; use std::fs::File; use std::io::{Read, Write}; -use std::{env, thread, usize}; -use syscall::{iopl, physmap, physunmap, MAP_WRITE, Packet, Scheme}; +use std::os::unix::io::AsRawFd; +use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme}; use scheme::DiskScheme; @@ -29,21 +30,42 @@ fn main() { thread::spawn(move || { unsafe { - iopl(3).expect("ahcid: failed to get I/O permission"); + syscall::iopl(3).expect("ahcid: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); } - let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; { let mut socket = File::create(":disk").expect("ahcid: failed to create disk scheme"); + let socket_fd = socket.as_raw_fd(); + syscall::fevent(socket_fd, EVENT_READ).expect("ahcid: failed to fevent disk scheme"); + + let mut irq_file = File::open(&format!("irq:{}", irq)).expect("ahcid: failed to open irq file"); + let irq_fd = irq_file.as_raw_fd(); + syscall::fevent(irq_fd, EVENT_READ).expect("ahcid: failed to fevent irq file"); + + let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); + let scheme = DiskScheme::new(ahci::disks(address, irq)); loop { - let mut packet = Packet::default(); - socket.read(&mut packet).expect("ahcid: failed to read disk scheme"); - scheme.handle(&mut packet); - socket.write(&mut packet).expect("ahcid: failed to read disk scheme"); + let mut event = Event::default(); + event_file.read(&mut event).expect("ahcid: failed to read event file"); + if event.id == socket_fd { + let mut packet = Packet::default(); + socket.read(&mut packet).expect("ahcid: failed to read disk scheme"); + scheme.handle(&mut packet); + socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + } else if event.id == irq_fd { + let mut irq = [0; 8]; + if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() { + println!("IRQ"); + irq_file.write(&irq).expect("ahcid: failed to write irq file"); + } + } else { + println!("Unknown event {}", event.id); + } } } - unsafe { let _ = physunmap(address); } + unsafe { let _ = syscall::physunmap(address); } }); } diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index eb2ec12a12..790e920197 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -3,7 +3,7 @@ use std::{cmp, str}; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use spin::Mutex; -use syscall::{Error, EBADF, EINVAL, ENOENT, Result, Scheme, Stat, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET}; +use syscall::{Error, EACCES, EBADF, EINVAL, ENOENT, Result, Scheme, Stat, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET}; use ahci::disk::Disk; @@ -29,17 +29,21 @@ impl DiskScheme { } impl Scheme for DiskScheme { - fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; + fn open(&self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { + if uid == 0 { + let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; - let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; + let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; - if let Some(disk) = self.disks.get(i) { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, (disk.clone(), 0)); - Ok(id) + if let Some(disk) = self.disks.get(i) { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, (disk.clone(), 0)); + Ok(id) + } else { + Err(Error::new(ENOENT)) + } } else { - Err(Error::new(ENOENT)) + Err(Error::new(EACCES)) } } diff --git a/dma/Cargo.toml b/dma/Cargo.toml deleted file mode 100644 index e05c929079..0000000000 --- a/dma/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "dma" -version = "0.1.0" - -[dependencies] -syscall = { path = "../../syscall/" } diff --git a/dma/src/lib.rs b/dma/src/lib.rs deleted file mode 100644 index fa8e3d12da..0000000000 --- a/dma/src/lib.rs +++ /dev/null @@ -1,80 +0,0 @@ -#![feature(question_mark)] - -extern crate syscall; - -use std::{mem, ptr}; -use std::ops::{Deref, DerefMut}; - -use syscall::Result; - -struct PhysBox { - address: usize, - size: usize -} - -impl PhysBox { - fn new(size: usize) -> Result { - let address = unsafe { syscall::physalloc(size)? }; - Ok(PhysBox { - address: address, - size: size - }) - } -} - -impl Drop for PhysBox { - fn drop(&mut self) { - let _ = unsafe { syscall::physfree(self.address, self.size) }; - } -} - -pub struct Dma { - phys: PhysBox, - virt: *mut T -} - -impl Dma { - pub fn new(value: T) -> Result> { - let phys = PhysBox::new(mem::size_of::())?; - let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T; - unsafe { ptr::write(virt, value); } - Ok(Dma { - phys: phys, - virt: virt - }) - } - - pub fn zeroed() -> Result> { - let phys = PhysBox::new(mem::size_of::())?; - let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T; - unsafe { ptr::write_bytes(virt as *mut u8, 0, phys.size); } - Ok(Dma { - phys: phys, - virt: virt - }) - } - - pub fn physical(&self) -> usize { - self.phys.address - } -} - -impl Deref for Dma { - type Target = T; - fn deref(&self) -> &T { - unsafe { &*self.virt } - } -} - -impl DerefMut for Dma { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.virt } - } -} - -impl Drop for Dma { - fn drop(&mut self) { - unsafe { drop(ptr::read(self.virt)); } - let _ = unsafe { syscall::physunmap(self.virt as usize) }; - } -} diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index eacd0d12d8..01413fe6a2 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -4,7 +4,8 @@ version = "0.1.0" [dependencies] bitflags = "*" -dma = { path = "../dma/" } -io = { path = "../io/" } +dma = { path = "../../crates/dma/" } +event = { path = "../../crates/event/" } +io = { path = "../../crates/io/" } spin = "*" syscall = { path = "../../syscall/" } diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index ffe87749da..6674c7c15b 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,7 +1,7 @@ use std::{cmp, mem, ptr, slice}; use dma::Dma; -use syscall::error::Result; +use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; use syscall::scheme::Scheme; const CTRL: u32 = 0x00; @@ -96,12 +96,16 @@ pub struct Intel8254x { receive_buffer: [Dma<[u8; 16384]>; 16], receive_ring: Dma<[Rd; 16]>, transmit_buffer: [Dma<[u8; 16384]>; 16], - transmit_ring: Dma<[Td; 16]>, + transmit_ring: Dma<[Td; 16]> } impl Scheme for Intel8254x { - fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { - Ok(0) + fn open(&self, _path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { + if uid == 0 { + Ok(0) + } else { + Err(Error::new(EACCES)) + } } fn dup(&self, id: usize) -> Result { @@ -109,7 +113,15 @@ impl Scheme for Intel8254x { } fn read(&self, _id: usize, buf: &mut [u8]) -> Result { - for tail in 0..self.receive_ring.len() { + let head = unsafe { self.read(RDH) }; + let mut tail = unsafe { self.read(RDT) }; + + tail += 1; + if tail >= self.receive_ring.len() as u32 { + tail = 0; + } + + if tail != head { let rd = unsafe { &mut * (self.receive_ring.as_ptr().offset(tail as isize) as *mut Rd) }; if rd.status & RD_DD == RD_DD { rd.status = 0; @@ -121,11 +133,14 @@ impl Scheme for Intel8254x { buf[i] = data[i]; i += 1; } + + unsafe { self.write(RDT, tail) }; + return Ok(i); } } - Ok(0) + Err(Error::new(EWOULDBLOCK)) } fn write(&self, _id: usize, buf: &[u8]) -> Result { @@ -166,8 +181,12 @@ impl Scheme for Intel8254x { return Ok(i); } - } + unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } + } + } + + fn fsync(&self, _id: usize) -> Result { Ok(0) } @@ -198,6 +217,11 @@ impl Intel8254x { Ok(module) } + pub unsafe fn irq(&self) -> bool { + let icr = self.read(ICR); + icr != 0 + } + pub unsafe fn read(&self, register: u32) -> u32 { ptr::read_volatile((self.base + register as usize) as *mut u32) } @@ -271,8 +295,7 @@ impl Intel8254x { self.write(TDH, 0); self.write(TDT, 0); - //self.write(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ | IMS_LSC | IMS_TXQE | IMS_TXDW); - self.write(IMS, 0); + self.write(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ); // | IMS_LSC | IMS_TXQE | IMS_TXDW self.flag(RCTL, RCTL_EN, true); self.flag(RCTL, RCTL_UPE, true); diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 9156aab7ee..3b097dfa96 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -2,13 +2,19 @@ #![feature(question_mark)] extern crate dma; +extern crate event; extern crate syscall; +use std::cell::RefCell; use std::{env, thread}; use std::fs::File; -use std::io::{Read, Write}; +use std::io::{Read, Write, Result}; +use std::os::unix::io::AsRawFd; +use std::sync::Arc; -use syscall::{iopl, physmap, physunmap, Packet, Scheme, MAP_WRITE}; +use event::EventQueue; +use syscall::{Packet, Scheme, MAP_WRITE}; +use syscall::error::EWOULDBLOCK; pub mod device; @@ -23,21 +29,66 @@ fn main() { thread::spawn(move || { unsafe { - iopl(3).expect("e1000d: failed to get I/O permission"); + syscall::iopl(3).expect("e1000d: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); } - let address = unsafe { physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") }; + let socket = Arc::new(RefCell::new(File::create(":network").expect("e1000d: failed to create network scheme"))); + + let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") }; { - let mut device = unsafe { device::Intel8254x::new(address, irq).expect("e1000d: failed to allocate device") }; - let mut socket = File::create(":network").expect("e1000d: failed to create network scheme"); - loop { + let device = Arc::new(unsafe { device::Intel8254x::new(address, irq).expect("e1000d: failed to allocate device") }); + + let mut event_queue = EventQueue::<()>::new().expect("e1000d: failed to create event queue"); + + let todo = Arc::new(RefCell::new(Vec::::new())); + + let device_irq = device.clone(); + let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); + event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + if unsafe { device_irq.irq() } { + irq_file.write(&mut irq)?; + + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + device_irq.handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; + } else { + socket_irq.borrow_mut().write(&mut todo[i])?; + todo.remove(i); + } + } + } + Ok(None) + }).expect("e1000d: failed to catch events on IRQ file"); + + let socket_fd = socket.borrow().as_raw_fd(); + event_queue.add(socket_fd, move |_count: usize| -> Result> { let mut packet = Packet::default(); - socket.read(&mut packet).expect("e1000d: failed to read network scheme"); + socket.borrow_mut().read(&mut packet)?; + + let a = packet.a; device.handle(&mut packet); - socket.write(&mut packet).expect("e1000d: failed to read network scheme"); - } + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket.borrow_mut().write(&mut packet)?; + } + + Ok(None) + }).expect("e1000d: failed to catch events on IRQ file"); + + event_queue.run().expect("e1000d: failed to handle events"); } - unsafe { let _ = physunmap(address); } + unsafe { let _ = syscall::physunmap(address); } }); } diff --git a/io/Cargo.toml b/io/Cargo.toml deleted file mode 100644 index b0ee40b297..0000000000 --- a/io/Cargo.toml +++ /dev/null @@ -1,3 +0,0 @@ -[package] -name = "io" -version = "0.1.0" diff --git a/io/src/io.rs b/io/src/io.rs deleted file mode 100644 index fb866b581b..0000000000 --- a/io/src/io.rs +++ /dev/null @@ -1,67 +0,0 @@ -use core::cmp::PartialEq; -use core::ops::{BitAnd, BitOr, Not}; - -pub trait Io { - type Value: Copy + PartialEq + BitAnd + BitOr + Not; - - fn read(&self) -> Self::Value; - fn write(&mut self, value: Self::Value); - - #[inline(always)] - fn readf(&self, flags: Self::Value) -> bool { - (self.read() & flags) as Self::Value == flags - } - - #[inline(always)] - fn writef(&mut self, flags: Self::Value, value: bool) { - let tmp: Self::Value = match value { - true => self.read() | flags, - false => self.read() & !flags, - }; - self.write(tmp); - } -} - -pub struct ReadOnly { - inner: I -} - -impl ReadOnly { - pub const fn new(inner: I) -> ReadOnly { - ReadOnly { - inner: inner - } - } - - #[inline(always)] - pub fn read(&self) -> I::Value { - self.inner.read() - } - - #[inline(always)] - pub fn readf(&self, flags: I::Value) -> bool { - self.inner.readf(flags) - } -} - -pub struct WriteOnly { - inner: I -} - -impl WriteOnly { - pub const fn new(inner: I) -> WriteOnly { - WriteOnly { - inner: inner - } - } - - #[inline(always)] - pub fn write(&mut self, value: I::Value) { - self.inner.write(value) - } - - #[inline(always)] - pub fn writef(&mut self, flags: I::Value, value: bool) { - self.inner.writef(flags, value) - } -} diff --git a/io/src/lib.rs b/io/src/lib.rs deleted file mode 100644 index 22f8eb72c0..0000000000 --- a/io/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! I/O functions - -#![feature(asm)] -#![feature(const_fn)] -#![feature(core_intrinsics)] -#![no_std] - -pub use self::io::*; -pub use self::mmio::*; -pub use self::pio::*; - -mod io; -mod mmio; -mod pio; diff --git a/io/src/mmio.rs b/io/src/mmio.rs deleted file mode 100644 index 1a1d1996d1..0000000000 --- a/io/src/mmio.rs +++ /dev/null @@ -1,31 +0,0 @@ -use core::intrinsics::{volatile_load, volatile_store}; -use core::mem::uninitialized; -use core::ops::{BitAnd, BitOr, Not}; - -use super::io::Io; - -#[repr(packed)] -pub struct Mmio { - value: T, -} - -impl Mmio { - /// Create a new Mmio without initializing - pub fn new() -> Self { - Mmio { - value: unsafe { uninitialized() } - } - } -} - -impl Io for Mmio where T: Copy + PartialEq + BitAnd + BitOr + Not { - type Value = T; - - fn read(&self) -> T { - unsafe { volatile_load(&self.value) } - } - - fn write(&mut self, value: T) { - unsafe { volatile_store(&mut self.value, value) }; - } -} diff --git a/io/src/pio.rs b/io/src/pio.rs deleted file mode 100644 index 91ae310b62..0000000000 --- a/io/src/pio.rs +++ /dev/null @@ -1,89 +0,0 @@ -use core::marker::PhantomData; - -use super::io::Io; - -/// Generic PIO -#[derive(Copy, Clone)] -pub struct Pio { - port: u16, - value: PhantomData, -} - -impl Pio { - /// Create a PIO from a given port - pub const fn new(port: u16) -> Self { - Pio:: { - port: port, - value: PhantomData, - } - } -} - -/// Read/Write for byte PIO -impl Io for Pio { - type Value = u8; - - /// Read - #[inline(always)] - fn read(&self) -> u8 { - let value: u8; - unsafe { - asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - value - } - - /// Write - #[inline(always)] - fn write(&mut self, value: u8) { - unsafe { - asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - } -} - -/// Read/Write for word PIO -impl Io for Pio { - type Value = u16; - - /// Read - #[inline(always)] - fn read(&self) -> u16 { - let value: u16; - unsafe { - asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - value - } - - /// Write - #[inline(always)] - fn write(&mut self, value: u16) { - unsafe { - asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - } -} - -/// Read/Write for doubleword PIO -impl Io for Pio { - type Value = u32; - - /// Read - #[inline(always)] - fn read(&self) -> u32 { - let value: u32; - unsafe { - asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - value - } - - /// Write - #[inline(always)] - fn write(&mut self, value: u32) { - unsafe { - asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile"); - } - } -} diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 665e3c19c8..31bb2526a5 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "*" -io = { path = "../io/" } -spin = "*" +io = { path = "../../crates/io/" } +orbclient = "0.1" syscall = { path = "../../syscall/" } diff --git a/ps2d/src/keyboard.rs b/ps2d/src/keyboard.rs index 8eb28583f3..5384d696b7 100644 --- a/ps2d/src/keyboard.rs +++ b/ps2d/src/keyboard.rs @@ -1,7 +1,8 @@ use std::fs::File; use std::io::{Read, Write}; use std::mem; -use std::thread; + +use orbclient::KeyEvent; use keymap; @@ -9,7 +10,6 @@ pub fn keyboard() { let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1"); let mut input = File::open("display:input").expect("ps2d: failed to open display:input"); - let mut ctrl = false; let mut lshift = false; let mut rshift = false; loop { @@ -28,71 +28,17 @@ pub fn keyboard() { (data, true) }; - if scancode == 0x1D { - ctrl = pressed; - } else if scancode == 0x2A { + if scancode == 0x2A { lshift = pressed; } else if scancode == 0x36 { rshift = pressed; - } else if pressed { - match scancode { - f @ 0x3B ... 0x44 => { // F1 through F10 - input.write(&[(f - 0x3B) + 0xF4]).unwrap(); - }, - 0x57 => { // F11 - input.write(&[0xFE]).unwrap(); - }, - 0x58 => { // F12 - input.write(&[0xFF]).unwrap(); - }, - 0x47 => { // Home - input.write(b"\x1B[H").unwrap(); - }, - 0x48 => { // Up - input.write(b"\x1B[A").unwrap(); - }, - 0x49 => { // Page up - input.write(b"\x1B[5~").unwrap(); - }, - 0x4B => { // Left - input.write(b"\x1B[D").unwrap(); - }, - 0x4D => { // Right - input.write(b"\x1B[C").unwrap(); - }, - 0x4F => { // End - input.write(b"\x1B[F").unwrap(); - }, - 0x50 => { // Down - input.write(b"\x1B[B").unwrap(); - }, - 0x51 => { // Page down - input.write(b"\x1B[6~").unwrap(); - }, - 0x52 => { // Insert - input.write(b"\x1B[2~").unwrap(); - }, - 0x53 => { // Delete - input.write(b"\x1B[3~").unwrap(); - }, - _ => { - let c = if ctrl { - match keymap::get_char(scancode, false) { - c @ 'a' ... 'z' => ((c as u8 - b'a') + b'\x01') as char, - c => c - } - } else { - keymap::get_char(scancode, lshift || rshift) - }; - - if c != '\0' { - input.write(&[c as u8]).unwrap(); - } - } - } } - } else { - thread::yield_now(); + + input.write(&KeyEvent { + character: keymap::get_char(scancode, lshift || rshift), + scancode: scancode, + pressed: pressed + }.to_event()).expect("ps2d: failed to write key event"); } } } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 4a3888eab8..60d1bfc3ba 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -3,6 +3,7 @@ #[macro_use] extern crate bitflags; extern crate io; +extern crate orbclient; extern crate syscall; use std::thread; diff --git a/ps2d/src/mouse.rs b/ps2d/src/mouse.rs index f273de9670..f16c9c7e26 100644 --- a/ps2d/src/mouse.rs +++ b/ps2d/src/mouse.rs @@ -1,7 +1,8 @@ use std::fs::File; use std::io::{Read, Write}; use std::mem; -use std::thread; + +use orbclient::MouseEvent; bitflags! { flags MousePacketFlags: u8 { @@ -18,6 +19,7 @@ bitflags! { pub fn mouse(extra_packet: bool) { let mut file = File::open("irq:12").expect("ps2d: failed to open irq:12"); + let mut input = File::open("display:input").expect("ps2d: failed to open display:input"); let mut packets = [0; 4]; let mut packet_i = 0; @@ -40,23 +42,29 @@ pub fn mouse(extra_packet: bool) { packet_i = 0; } else if packet_i >= packets.len() || (!extra_packet && packet_i >= 3) { if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { - let mut dx = packets[1] as isize; + let mut dx = packets[1] as i32; if flags.contains(X_SIGN) { dx -= 0x100; } - let mut dy = packets[2] as isize; + let mut dy = -(packets[2] as i32); if flags.contains(Y_SIGN) { - dy -= 0x100; + dy += 0x100; } - let extra = if extra_packet { + let _extra = if extra_packet { packets[3] } else { 0 }; - print!("ps2d: IRQ {:?}, {}, {}, {}\n", flags, dx, dy, extra); + input.write(&MouseEvent { + x: dx, + y: dy, + left_button: flags.contains(LEFT_BUTTON), + middle_button: flags.contains(MIDDLE_BUTTON), + right_button: flags.contains(RIGHT_BUTTON) + }.to_event()).expect("ps2d: failed to write mouse event"); } else { println!("ps2d: overflow {:X} {:X} {:X} {:X}", packets[0], packets[1], packets[2], packets[3]); } @@ -66,8 +74,6 @@ pub fn mouse(extra_packet: bool) { } file.write(&irqs).expect("ps2d: failed to write irq:12"); - } else { - thread::yield_now(); } } } diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index ebfdf0bba1..f0dcc23be5 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -3,6 +3,7 @@ name = "vesad" version = "0.1.0" [dependencies] +orbclient = "0.1" ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" } rusttype = { git = "https://github.com/dylanede/rusttype.git", optional = true } syscall = { path = "../../syscall/" } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 57a13b3ca1..167c111e7f 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -4,6 +4,7 @@ #![feature(question_mark)] extern crate alloc; +extern crate orbclient; extern crate syscall; use std::fs::File; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 4c9155d038..1e48cb211e 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,26 +1,26 @@ use std::cell::{Cell, RefCell}; use std::collections::BTreeMap; -use std::str; +use std::{mem, slice, str}; -use syscall::{Result, Error, EBADF, ENOENT, Scheme}; +use orbclient::{Event, EventOption}; +use syscall::{Result, Error, EACCES, EBADF, ENOENT, Scheme}; use display::Display; -use screen::TextScreen; +use screen::{Screen, GraphicScreen, TextScreen}; pub struct DisplayScheme { width: usize, height: usize, onscreen: usize, active: Cell, - screens: RefCell> + screens: RefCell>> } impl DisplayScheme { pub fn new(width: usize, height: usize, onscreen: usize) -> DisplayScheme { - let mut screens = BTreeMap::new(); - for i in 1..7 { - screens.insert(i, TextScreen::new(Display::new(width, height, onscreen))); - } + let mut screens: BTreeMap> = BTreeMap::new(); + screens.insert(1, Box::new(TextScreen::new(Display::new(width, height, onscreen)))); + screens.insert(2, Box::new(GraphicScreen::new(Display::new(width, height, onscreen)))); DisplayScheme { width: width, @@ -42,9 +42,13 @@ impl DisplayScheme { } impl Scheme for DisplayScheme { - fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result { + fn open(&self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { if path == b"input" { - Ok(0) + if uid == 0 { + Ok(0) + } else { + Err(Error::new(EACCES)) + } } else { let path_str = str::from_utf8(path).unwrap_or(""); let id = path_str.parse::().unwrap_or(0); @@ -63,9 +67,7 @@ impl Scheme for DisplayScheme { fn fevent(&self, id: usize, flags: usize) -> Result { let mut screens = self.screens.borrow_mut(); if let Some(mut screen) = screens.get_mut(&id) { - println!("fevent {:X}", flags); - screen.requested = flags; - Ok(0) + screen.event(flags) } else { Err(Error::new(EBADF)) } @@ -76,7 +78,7 @@ impl Scheme for DisplayScheme { let path_str = if id == 0 { format!("display:input") } else if let Some(screen) = screens.get(&id) { - format!("display:{}/{}/{}", id, screen.console.w, screen.console.h) + format!("display:{}/{}/{}", id, screen.width(), screen.height()) } else { return Err(Error::new(EBADF)); }; @@ -124,11 +126,39 @@ impl Scheme for DisplayScheme { } Ok(1) } else { - if let Some(mut screen) = screens.get_mut(&self.active.get()) { - screen.input(buf) - } else { - Err(Error::new(EBADF)) + let events = unsafe { slice::from_raw_parts(buf.as_ptr() as *const Event, buf.len()/mem::size_of::()) }; + + for event in events.iter() { + let new_active_opt = if let EventOption::Key(key_event) = event.to_option() { + match key_event.scancode { + f @ 0x3B ... 0x44 => { // F1 through F10 + Some((f - 0x3A) as usize) + }, + 0x57 => { // F11 + Some(11) + }, + 0x58 => { // F12 + Some(12) + }, + _ => None + } + } else { + None + }; + + if let Some(new_active) = new_active_opt { + if let Some(mut screen) = screens.get_mut(&new_active) { + self.active.set(new_active); + screen.redraw(); + } + } else { + if let Some(mut screen) = screens.get_mut(&self.active.get()) { + screen.input(event); + } + } } + + Ok(events.len() * mem::size_of::()) } } else if let Some(mut screen) = screens.get_mut(&id) { screen.write(buf, id == self.active.get()) @@ -137,6 +167,15 @@ impl Scheme for DisplayScheme { } } + fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { + let mut screens = self.screens.borrow_mut(); + if let Some(mut screen) = screens.get_mut(&id) { + screen.seek(pos, whence) + } else { + Err(Error::new(EBADF)) + } + } + fn close(&self, _id: usize) -> Result { Ok(0) } diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 9e6b71aa08..11a6e2e935 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -1 +1,118 @@ -pub struct GraphicScreen; +use std::collections::VecDeque; +use std::{cmp, mem, slice}; + +use orbclient::{Event, EventOption}; +use syscall::error::*; +use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; + +use display::Display; +use primitive::fast_copy; +use screen::Screen; + +pub struct GraphicScreen { + pub display: Display, + pub seek: usize, + pub mouse_x: i32, + pub mouse_y: i32, + pub input: VecDeque, + pub requested: usize +} + +impl GraphicScreen { + pub fn new(display: Display) -> GraphicScreen { + GraphicScreen { + display: display, + seek: 0, + mouse_x: 0, + mouse_y: 0, + input: VecDeque::new(), + requested: 0 + } + } +} + +impl Screen for GraphicScreen { + fn width(&self) -> usize { + self.display.width + } + + fn height(&self) -> usize { + self.display.height + } + + fn event(&mut self, flags: usize) -> Result { + self.requested = flags; + Ok(0) + } + + fn input(&mut self, event: &Event) { + if let EventOption::Mouse(mut mouse_event) = event.to_option() { + let x = cmp::max(0, cmp::min(self.display.width as i32, self.mouse_x + mouse_event.x)); + let y = cmp::max(0, cmp::min(self.display.height as i32, self.mouse_y + mouse_event.y)); + + mouse_event.x = x; + self.mouse_x = x; + mouse_event.y = y; + self.mouse_y = y; + + self.input.push_back(mouse_event.to_event()); + } else { + self.input.push_back(*event); + } + } + + fn read(&mut self, buf: &mut [u8]) -> Result { + let mut i = 0; + + let event_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Event, buf.len()/mem::size_of::()) }; + + while i < event_buf.len() && ! self.input.is_empty() { + event_buf[i] = self.input.pop_front().unwrap(); + i += 1; + } + + Ok(i * mem::size_of::()) + } + + fn will_block(&self) -> bool { + self.input.is_empty() + } + + fn write(&mut self, buf: &[u8], sync: bool) -> Result { + let size = cmp::max(0, cmp::min(self.display.offscreen.len() as isize - self.seek as isize, (buf.len()/4) as isize)) as usize; + + if size > 0 { + unsafe { + fast_copy(self.display.offscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4); + if sync { + fast_copy(self.display.onscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4); + } + } + } + + Ok(size * 4) + } + + fn seek(&mut self, pos: usize, whence: usize) -> Result { + let size = self.display.offscreen.len(); + + self.seek = match whence { + SEEK_SET => cmp::min(size, (pos/4)), + SEEK_CUR => cmp::max(0, cmp::min(size as isize, self.seek as isize + (pos/4) as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(size as isize, size as isize + (pos/4) as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(self.seek * 4) + } + + fn sync(&mut self) { + self.redraw(); + } + + fn redraw(&mut self) { + let width = self.display.width; + let height = self.display.height; + self.display.sync(0, 0, width, height); + } +} diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs index 01e1583213..6a0d5fdfad 100644 --- a/vesad/src/screen/mod.rs +++ b/vesad/src/screen/mod.rs @@ -1,10 +1,30 @@ pub use self::graphic::GraphicScreen; pub use self::text::TextScreen; +use orbclient::Event; +use syscall::Result; + mod graphic; mod text; -pub enum Screen { - Graphic(GraphicScreen), - Text(TextScreen) +pub trait Screen { + fn width(&self) -> usize; + + fn height(&self) -> usize; + + fn event(&mut self, flags: usize) -> Result; + + fn input(&mut self, event: &Event); + + fn read(&mut self, buf: &mut [u8]) -> Result; + + fn will_block(&self) -> bool; + + fn write(&mut self, buf: &[u8], sync: bool) -> Result; + + fn seek(&mut self, pos: usize, whence: usize) -> Result; + + fn sync(&mut self); + + fn redraw(&mut self); } diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index bf187b78d2..d61fe7ac5c 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -2,15 +2,17 @@ extern crate ransid; use std::collections::{BTreeSet, VecDeque}; -use self::ransid::{Console, Event}; +use orbclient::{Event, EventOption}; use syscall::Result; use display::Display; +use screen::Screen; pub struct TextScreen { - pub console: Console, + pub console: ransid::Console, pub display: Display, pub changed: BTreeSet, + pub ctrl: bool, pub input: VecDeque, pub end_of_input: bool, pub cooked: VecDeque, @@ -20,17 +22,88 @@ pub struct TextScreen { impl TextScreen { pub fn new(display: Display) -> TextScreen { TextScreen { - console: Console::new(display.width/8, display.height/16), + console: ransid::Console::new(display.width/8, display.height/16), display: display, changed: BTreeSet::new(), + ctrl: false, input: VecDeque::new(), end_of_input: false, cooked: VecDeque::new(), requested: 0 } } +} + +impl Screen for TextScreen { + fn width(&self) -> usize { + self.console.w + } + + fn height(&self) -> usize { + self.console.h + } + + fn event(&mut self, flags: usize) -> Result { + self.requested = flags; + Ok(0) + } + + fn input(&mut self, event: &Event) { + let mut buf = vec![]; + + match event.to_option() { + EventOption::Key(key_event) => { + if key_event.scancode == 0x1D { + self.ctrl = key_event.pressed; + } else if key_event.pressed { + match key_event.scancode { + 0x47 => { // Home + buf.extend_from_slice(b"\x1B[H"); + }, + 0x48 => { // Up + buf.extend_from_slice(b"\x1B[A"); + }, + 0x49 => { // Page up + buf.extend_from_slice(b"\x1B[5~"); + }, + 0x4B => { // Left + buf.extend_from_slice(b"\x1B[D"); + }, + 0x4D => { // Right + buf.extend_from_slice(b"\x1B[C"); + }, + 0x4F => { // End + buf.extend_from_slice(b"\x1B[F"); + }, + 0x50 => { // Down + buf.extend_from_slice(b"\x1B[B"); + }, + 0x51 => { // Page down + buf.extend_from_slice(b"\x1B[6~"); + }, + 0x52 => { // Insert + buf.extend_from_slice(b"\x1B[2~"); + }, + 0x53 => { // Delete + buf.extend_from_slice(b"\x1B[3~"); + }, + _ => { + let c = match key_event.character { + c @ 'A' ... 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char, + c @ 'a' ... 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char, + c => c + }; + + if c != '\0' { + buf.extend_from_slice(&[c as u8]); + } + } + } + } + }, + _ => () //TODO: Mouse in terminal + } - pub fn input(&mut self, buf: &[u8]) -> Result { if self.console.raw_mode { for &b in buf.iter() { self.input.push_back(b); @@ -40,11 +113,11 @@ impl TextScreen { match b { b'\x03' => { self.end_of_input = true; - self.write(b"^C\n", true)?; + let _ = self.write(b"^C\n", true); }, b'\x08' | b'\x7F' => { if let Some(_c) = self.cooked.pop_back() { - self.write(b"\x08", true)?; + let _ = self.write(b"\x08", true); } }, b'\n' | b'\r' => { @@ -52,19 +125,18 @@ impl TextScreen { while let Some(c) = self.cooked.pop_front() { self.input.push_back(c); } - self.write(b"\n", true)?; + let _ = self.write(b"\n", true); }, _ => { self.cooked.push_back(b); - self.write(&[b], true)?; + let _ = self.write(&[b], true); } } } } - Ok(buf.len()) } - pub fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> Result { let mut i = 0; while i < buf.len() && ! self.input.is_empty() { @@ -79,11 +151,11 @@ impl TextScreen { Ok(i) } - pub fn will_block(&self) -> bool { + fn will_block(&self) -> bool { self.input.is_empty() && ! self.end_of_input } - pub fn write(&mut self, buf: &[u8], sync: bool) -> Result { + fn write(&mut self, buf: &[u8], sync: bool) -> Result { if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h { let x = self.console.x; let y = self.console.y; @@ -97,17 +169,17 @@ impl TextScreen { let changed = &mut self.changed; self.console.write(buf, |event| { match event { - Event::Char { x, y, c, color, bold, .. } => { + ransid::Event::Char { x, y, c, color, bold, .. } => { display.char(x * 8, y * 16, c, color.data, bold, false); changed.insert(y); }, - Event::Rect { x, y, w, h, color } => { + ransid::Event::Rect { x, y, w, h, color } => { display.rect(x * 8, y * 16, w * 8, h * 16, color.data); for y2 in y..y + h { changed.insert(y2); } }, - Event::Scroll { rows, color } => { + ransid::Event::Scroll { rows, color } => { display.scroll(rows * 16, color.data); for y in 0..display.height/16 { changed.insert(y); @@ -132,7 +204,11 @@ impl TextScreen { Ok(buf.len()) } - pub fn sync(&mut self) { + fn seek(&mut self, pos: usize, whence: usize) -> Result { + Ok(0) + } + + fn sync(&mut self) { let width = self.display.width; for change in self.changed.iter() { self.display.sync(0, change * 16, width, 16); @@ -140,7 +216,7 @@ impl TextScreen { self.changed.clear(); } - pub fn redraw(&mut self) { + fn redraw(&mut self) { let width = self.display.width; let height = self.display.height; self.display.sync(0, 0, width, height); From d494576d5928fb48d8f76a84229b1c86b0151629 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 14 Oct 2016 12:42:02 -0600 Subject: [PATCH 0050/1301] Move IRQ ack higher in mouse driver --- ps2d/src/mouse.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ps2d/src/mouse.rs b/ps2d/src/mouse.rs index f16c9c7e26..0b96bf6f48 100644 --- a/ps2d/src/mouse.rs +++ b/ps2d/src/mouse.rs @@ -31,6 +31,8 @@ pub fn mouse(extra_packet: bool) { asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); } + file.write(&irqs).expect("ps2d: failed to write irq:12"); + packets[packet_i] = data; packet_i += 1; @@ -72,8 +74,6 @@ pub fn mouse(extra_packet: bool) { packets = [0; 4]; packet_i = 0; } - - file.write(&irqs).expect("ps2d: failed to write irq:12"); } } } From ea59208002567acd999b1cb050c5fbfb2c7bf85f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 14 Oct 2016 12:54:37 -0600 Subject: [PATCH 0051/1301] Use a single thread for ps/2 driver --- ps2d/Cargo.toml | 1 + ps2d/src/keyboard.rs | 44 ------------- ps2d/src/main.rs | 148 +++++++++++++++++++++++++++++++++++++------ ps2d/src/mouse.rs | 79 ----------------------- 4 files changed, 131 insertions(+), 141 deletions(-) delete mode 100644 ps2d/src/keyboard.rs delete mode 100644 ps2d/src/mouse.rs diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 31bb2526a5..0c10180c45 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" [dependencies] bitflags = "*" +event = { path = "../../crates/event/" } io = { path = "../../crates/io/" } orbclient = "0.1" syscall = { path = "../../syscall/" } diff --git a/ps2d/src/keyboard.rs b/ps2d/src/keyboard.rs deleted file mode 100644 index 5384d696b7..0000000000 --- a/ps2d/src/keyboard.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::fs::File; -use std::io::{Read, Write}; -use std::mem; - -use orbclient::KeyEvent; - -use keymap; - -pub fn keyboard() { - let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1"); - let mut input = File::open("display:input").expect("ps2d: failed to open display:input"); - - let mut lshift = false; - let mut rshift = false; - loop { - let mut irqs = [0; 8]; - if file.read(&mut irqs).expect("ps2d: failed to read irq:1") >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - file.write(&irqs).expect("ps2d: failed to write irq:1"); - - let (scancode, pressed) = if data >= 0x80 { - (data - 0x80, false) - } else { - (data, true) - }; - - if scancode == 0x2A { - lshift = pressed; - } else if scancode == 0x36 { - rshift = pressed; - } - - input.write(&KeyEvent { - character: keymap::get_char(scancode, lshift || rshift), - scancode: scancode, - pressed: pressed - }.to_event()).expect("ps2d: failed to write key event"); - } - } -} diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 60d1bfc3ba..d1f1bff5f8 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -2,42 +2,154 @@ #[macro_use] extern crate bitflags; +extern crate event; extern crate io; extern crate orbclient; extern crate syscall; -use std::thread; +use std::fs::File; +use std::io::{Read, Write, Result}; +use std::os::unix::io::AsRawFd; +use std::{mem, thread}; +use event::EventQueue; +use orbclient::{KeyEvent, MouseEvent}; use syscall::iopl; mod controller; -mod keyboard; mod keymap; -mod mouse; + +bitflags! { + flags MousePacketFlags: u8 { + const LEFT_BUTTON = 1, + const RIGHT_BUTTON = 1 << 1, + const MIDDLE_BUTTON = 1 << 2, + const ALWAYS_ON = 1 << 3, + const X_SIGN = 1 << 4, + const Y_SIGN = 1 << 5, + const X_OVERFLOW = 1 << 6, + const Y_OVERFLOW = 1 << 7 + } +} fn main() { - unsafe { - iopl(3).expect("ps2d: failed to get I/O permission"); - asm!("cli" :::: "intel", "volatile"); - } - - let extra_packet = controller::Ps2::new().init(); - thread::spawn(|| { unsafe { iopl(3).expect("ps2d: failed to get I/O permission"); asm!("cli" :::: "intel", "volatile"); } - keyboard::keyboard(); - }); + let extra_packet = controller::Ps2::new().init(); - thread::spawn(move || { - unsafe { - iopl(3).expect("ps2d: failed to get I/O permission"); - asm!("cli" :::: "intel", "volatile"); + let mut input = File::open("display:input").expect("ps2d: failed to open display:input"); + + let mut event_queue = EventQueue::<(bool, u8)>::new().expect("ps2d: failed to create event queue"); + + let mut key_irq = File::open("irq:1").expect("ps2d: failed to open irq:1"); + + event_queue.add(key_irq.as_raw_fd(), move |_count: usize| -> Result> { + let mut irq = [0; 8]; + if key_irq.read(&mut irq)? >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + key_irq.write(&irq)?; + + Ok(Some((true, data))) + } else { + Ok(None) + } + }).expect("ps2d: failed to poll irq:1"); + + let mut mouse_irq = File::open("irq:12").expect("ps2d: failed to open irq:12"); + + event_queue.add(mouse_irq.as_raw_fd(), move |_count: usize| -> Result> { + let mut irq = [0; 8]; + if mouse_irq.read(&mut irq)? >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + mouse_irq.write(&irq)?; + + Ok(Some((false, data))) + } else { + Ok(None) + } + }).expect("ps2d: failed to poll irq:12"); + + let mut lshift = false; + let mut rshift = false; + let mut packets = [0; 4]; + let mut packet_i = 0; + + loop { + let (keyboard, data) = event_queue.run().expect("ps2d: failed to handle events"); + + if keyboard { + let (scancode, pressed) = if data >= 0x80 { + (data - 0x80, false) + } else { + (data, true) + }; + + if scancode == 0x2A { + lshift = pressed; + } else if scancode == 0x36 { + rshift = pressed; + } + + input.write(&KeyEvent { + character: keymap::get_char(scancode, lshift || rshift), + scancode: scancode, + pressed: pressed + }.to_event()).expect("ps2d: failed to write key event"); + } else { + packets[packet_i] = data; + packet_i += 1; + + let flags = MousePacketFlags::from_bits_truncate(packets[0]); + if ! flags.contains(ALWAYS_ON) { + println!("MOUSE MISALIGN {:X}", packets[0]); + + packets = [0; 4]; + packet_i = 0; + } else if packet_i >= packets.len() || (!extra_packet && packet_i >= 3) { + if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { + let mut dx = packets[1] as i32; + if flags.contains(X_SIGN) { + dx -= 0x100; + } + + let mut dy = -(packets[2] as i32); + if flags.contains(Y_SIGN) { + dy += 0x100; + } + + let _extra = if extra_packet { + packets[3] + } else { + 0 + }; + + input.write(&MouseEvent { + x: dx, + y: dy, + left_button: flags.contains(LEFT_BUTTON), + middle_button: flags.contains(MIDDLE_BUTTON), + right_button: flags.contains(RIGHT_BUTTON) + }.to_event()).expect("ps2d: failed to write mouse event"); + } else { + println!("ps2d: overflow {:X} {:X} {:X} {:X}", packets[0], packets[1], packets[2], packets[3]); + } + + packets = [0; 4]; + packet_i = 0; + } + } } - - mouse::mouse(extra_packet); }); } diff --git a/ps2d/src/mouse.rs b/ps2d/src/mouse.rs deleted file mode 100644 index 0b96bf6f48..0000000000 --- a/ps2d/src/mouse.rs +++ /dev/null @@ -1,79 +0,0 @@ -use std::fs::File; -use std::io::{Read, Write}; -use std::mem; - -use orbclient::MouseEvent; - -bitflags! { - flags MousePacketFlags: u8 { - const LEFT_BUTTON = 1, - const RIGHT_BUTTON = 1 << 1, - const MIDDLE_BUTTON = 1 << 2, - const ALWAYS_ON = 1 << 3, - const X_SIGN = 1 << 4, - const Y_SIGN = 1 << 5, - const X_OVERFLOW = 1 << 6, - const Y_OVERFLOW = 1 << 7 - } -} - -pub fn mouse(extra_packet: bool) { - let mut file = File::open("irq:12").expect("ps2d: failed to open irq:12"); - let mut input = File::open("display:input").expect("ps2d: failed to open display:input"); - - let mut packets = [0; 4]; - let mut packet_i = 0; - loop { - let mut irqs = [0; 8]; - if file.read(&mut irqs).expect("ps2d: failed to read irq:12") >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - file.write(&irqs).expect("ps2d: failed to write irq:12"); - - packets[packet_i] = data; - packet_i += 1; - - let flags = MousePacketFlags::from_bits_truncate(packets[0]); - if ! flags.contains(ALWAYS_ON) { - println!("MOUSE MISALIGN {:X}", packets[0]); - - packets = [0; 4]; - packet_i = 0; - } else if packet_i >= packets.len() || (!extra_packet && packet_i >= 3) { - if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { - let mut dx = packets[1] as i32; - if flags.contains(X_SIGN) { - dx -= 0x100; - } - - let mut dy = -(packets[2] as i32); - if flags.contains(Y_SIGN) { - dy += 0x100; - } - - let _extra = if extra_packet { - packets[3] - } else { - 0 - }; - - input.write(&MouseEvent { - x: dx, - y: dy, - left_button: flags.contains(LEFT_BUTTON), - middle_button: flags.contains(MIDDLE_BUTTON), - right_button: flags.contains(RIGHT_BUTTON) - }.to_event()).expect("ps2d: failed to write mouse event"); - } else { - println!("ps2d: overflow {:X} {:X} {:X} {:X}", packets[0], packets[1], packets[2], packets[3]); - } - - packets = [0; 4]; - packet_i = 0; - } - } - } -} From e089cffc391835987b2d83b0947568d665b68b4f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 14 Oct 2016 18:22:57 -0600 Subject: [PATCH 0052/1301] Add specification to vesad Fix piping Fix bug where resources are not closed Add arpd Remove question_mark features --- vesad/src/main.rs | 17 ++++++++++++++--- vesad/src/scheme.rs | 16 +++++++++++++--- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 167c111e7f..f1e15194a7 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -1,15 +1,14 @@ #![feature(alloc)] #![feature(asm)] #![feature(heap_api)] -#![feature(question_mark)] extern crate alloc; extern crate orbclient; extern crate syscall; +use std::{env, thread}; use std::fs::File; use std::io::{Read, Write}; -use std::thread; use syscall::{physmap, physunmap, Packet, Scheme, MAP_WRITE, MAP_WRITE_COMBINE}; use mode_info::VBEModeInfo; @@ -23,6 +22,18 @@ pub mod scheme; pub mod screen; fn main() { + let mut spec = Vec::new(); + + for arg in env::args().skip(1) { + if arg == "T" { + spec.push(false); + } else if arg == "G" { + spec.push(true); + } else { + println!("vesad: unknown screen type: {}", arg); + } + } + let width; let height; let physbaseptr; @@ -46,7 +57,7 @@ fn main() { let onscreen = unsafe { physmap(physbaseptr, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; unsafe { fast_set64(onscreen as *mut u64, 0, size/2) }; - let scheme = DisplayScheme::new(width, height, onscreen); + let scheme = DisplayScheme::new(width, height, onscreen, &spec); let mut blocked = Vec::new(); loop { diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 1e48cb211e..91484a1ff4 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -13,20 +13,30 @@ pub struct DisplayScheme { height: usize, onscreen: usize, active: Cell, + next_screen: Cell, screens: RefCell>> } impl DisplayScheme { - pub fn new(width: usize, height: usize, onscreen: usize) -> DisplayScheme { + pub fn new(width: usize, height: usize, onscreen: usize, spec: &[bool]) -> DisplayScheme { let mut screens: BTreeMap> = BTreeMap::new(); - screens.insert(1, Box::new(TextScreen::new(Display::new(width, height, onscreen)))); - screens.insert(2, Box::new(GraphicScreen::new(Display::new(width, height, onscreen)))); + + let mut screen_i = 1; + for &screen_type in spec.iter() { + if screen_type { + screens.insert(screen_i, Box::new(GraphicScreen::new(Display::new(width, height, onscreen)))); + } else { + screens.insert(screen_i, Box::new(TextScreen::new(Display::new(width, height, onscreen)))); + } + screen_i += 1; + } DisplayScheme { width: width, height: height, onscreen: onscreen, active: Cell::new(1), + next_screen: Cell::new(screen_i), screens: RefCell::new(screens) } } From 9eb092a215f6e11afbf87fde7fe7dd7719651cf2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 14 Oct 2016 20:12:21 -0600 Subject: [PATCH 0053/1301] Significant improvements for events - switch to event queue in orbital --- vesad/src/main.rs | 34 +++++++++++++++++----------------- vesad/src/scheme.rs | 4 ++-- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index f1e15194a7..e1db357c44 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -6,10 +6,10 @@ extern crate alloc; extern crate orbclient; extern crate syscall; -use std::{env, thread}; +use std::{env, mem, thread}; use std::fs::File; use std::io::{Read, Write}; -use syscall::{physmap, physunmap, Packet, Scheme, MAP_WRITE, MAP_WRITE_COMBINE}; +use syscall::{physmap, physunmap, Packet, Scheme, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE}; use mode_info::VBEModeInfo; use primitive::fast_set64; @@ -87,22 +87,22 @@ fn main() { } } - // If there are requested events, and data is available, send a notification - /* TODO - if (! scheme.screen.borrow().input.is_empty() || scheme.screen.borrow().end_of_input) && scheme.screen.borrow().requested & EVENT_READ == EVENT_READ { - let event_packet = Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: EVENT_READ, - d: scheme.screen.borrow().input.len() - }; - socket.write(&event_packet).expect("vesad: failed to write display scheme"); + for (screen_id, screen) in scheme.screens.borrow().iter() { + if ! screen.will_block() { + let event_packet = Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *screen_id, + c: EVENT_READ, + d: mem::size_of::() + }; + + socket.write(&event_packet).expect("vesad: failed to write display event"); + } } - */ } }); } diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 91484a1ff4..8ce9034905 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -14,7 +14,7 @@ pub struct DisplayScheme { onscreen: usize, active: Cell, next_screen: Cell, - screens: RefCell>> + pub screens: RefCell>> } impl DisplayScheme { @@ -77,7 +77,7 @@ impl Scheme for DisplayScheme { fn fevent(&self, id: usize, flags: usize) -> Result { let mut screens = self.screens.borrow_mut(); if let Some(mut screen) = screens.get_mut(&id) { - screen.event(flags) + screen.event(flags).and(Ok(id)) } else { Err(Error::new(EBADF)) } From b69014a48a097393c8fbe022c629f934d426e612 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 14 Oct 2016 22:06:20 -0600 Subject: [PATCH 0054/1301] Correct size of data --- vesad/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index e1db357c44..3f04d7c738 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -97,7 +97,7 @@ fn main() { a: syscall::number::SYS_FEVENT, b: *screen_id, c: EVENT_READ, - d: mem::size_of::() + d: mem::size_of::() }; socket.write(&event_packet).expect("vesad: failed to write display event"); From f0664243c3d7be8535ccffcb19c0e039adc28175 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 15 Oct 2016 20:56:32 -0600 Subject: [PATCH 0055/1301] Remove question mark where not required --- ahcid/src/main.rs | 1 - e1000d/src/main.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 880177b65b..fba2503d81 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -1,5 +1,4 @@ #![feature(asm)] -#![feature(question_mark)] #[macro_use] extern crate bitflags; diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 3b097dfa96..00b31db241 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -1,5 +1,4 @@ #![feature(asm)] -#![feature(question_mark)] extern crate dma; extern crate event; From 571c5ac641e5e53f7b544614a558366b135164e2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 19 Oct 2016 13:19:37 -0600 Subject: [PATCH 0056/1301] Less output in pcid, fix e1000d crate name --- e1000d/Cargo.toml | 2 +- pcid/src/main.rs | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 01413fe6a2..6261f65df5 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rtl8139d" +name = "e1000d" version = "0.1.0" [dependencies] diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 108e8303bb..cfc3e6d161 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -31,8 +31,6 @@ fn main() { } } - println!("{:?}", config); - unsafe { iopl(3).unwrap() }; println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); @@ -147,8 +145,6 @@ fn main() { } } } - - println!("Driver: {:?}", driver); } } } From d78981ded61de2253234c5432eb1f9a7cb3c711f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Oct 2016 12:52:58 -0600 Subject: [PATCH 0057/1301] Add rtl8168 driver, make drivers use O_NONBLOCK --- ahcid/src/main.rs | 6 +- e1000d/src/main.rs | 6 +- rtl8168d/Cargo.toml | 11 ++ rtl8168d/src/device.rs | 276 +++++++++++++++++++++++++++++++++++++++++ rtl8168d/src/main.rs | 99 +++++++++++++++ 5 files changed, 392 insertions(+), 6 deletions(-) create mode 100644 rtl8168d/Cargo.toml create mode 100644 rtl8168d/src/device.rs create mode 100644 rtl8168d/src/main.rs diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index fba2503d81..d15aea9f23 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -10,7 +10,7 @@ extern crate syscall; use std::{env, thread, usize}; use std::fs::File; use std::io::{Read, Write}; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, FromRawFd}; use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme}; use scheme::DiskScheme; @@ -35,8 +35,8 @@ fn main() { let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; { - let mut socket = File::create(":disk").expect("ahcid: failed to create disk scheme"); - let socket_fd = socket.as_raw_fd(); + let socket_fd = syscall::open(":disk", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ahcid: failed to create disk scheme"); + let mut socket = unsafe { File::from_raw_fd(socket_fd) }; syscall::fevent(socket_fd, EVENT_READ).expect("ahcid: failed to fevent disk scheme"); let mut irq_file = File::open(&format!("irq:{}", irq)).expect("ahcid: failed to open irq file"); diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 00b31db241..fcc7d6b486 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -8,7 +8,7 @@ use std::cell::RefCell; use std::{env, thread}; use std::fs::File; use std::io::{Read, Write, Result}; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::Arc; use event::EventQueue; @@ -32,7 +32,8 @@ fn main() { asm!("cli" :::: "intel", "volatile"); } - let socket = Arc::new(RefCell::new(File::create(":network").expect("e1000d: failed to create network scheme"))); + let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("e1000d: failed to create network scheme"); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") }; { @@ -69,7 +70,6 @@ fn main() { Ok(None) }).expect("e1000d: failed to catch events on IRQ file"); - let socket_fd = socket.borrow().as_raw_fd(); event_queue.add(socket_fd, move |_count: usize| -> Result> { let mut packet = Packet::default(); socket.borrow_mut().read(&mut packet)?; diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml new file mode 100644 index 0000000000..394f156677 --- /dev/null +++ b/rtl8168d/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "rtl8168d" +version = "0.1.0" + +[dependencies] +bitflags = "*" +dma = { path = "../../crates/dma/" } +event = { path = "../../crates/event/" } +io = { path = "../../crates/io/" } +spin = "*" +syscall = { path = "../../syscall/" } diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs new file mode 100644 index 0000000000..13181760e0 --- /dev/null +++ b/rtl8168d/src/device.rs @@ -0,0 +1,276 @@ +use std::{cmp, mem, slice}; + +use dma::Dma; +use io::{Mmio, Io, ReadOnly, WriteOnly}; +use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; +use syscall::scheme::SchemeMut; + +#[repr(packed)] +struct Regs { + mac: [Mmio; 2], + mar: Mmio, + dtccr: Mmio, + _rsv0: Mmio, + tnpds: Mmio, + thpds: Mmio, + _rsv1: [Mmio; 7], + cmd: Mmio, + tppoll: WriteOnly>, + _rsv2: [Mmio; 3], + imr: Mmio, + isr: Mmio, + tcr: Mmio, + rcr: Mmio, + tctr: Mmio, + _rsv3: Mmio, + cmd_9346: Mmio, + config: [Mmio; 6], + _rsv4: Mmio, + timer_int: Mmio, + _rsv5: Mmio, + phys_ar: Mmio, + _rsv6: Mmio, + phys_sts: ReadOnly>, + _rsv7: [Mmio; 23], + wakeup: [Mmio; 8], + crc: [Mmio; 5], + _rsv8: [Mmio; 12], + rms: Mmio, + _rsv9: Mmio, + c_plus_cr: Mmio, + _rsv10: Mmio, + rdsar: Mmio, + mtps: Mmio, + _rsv11: [Mmio; 19], +} + +const OWN: u16 = 1 << 15; +const EOR: u16 = 1 << 14; + +#[repr(packed)] +struct Rd { + length: Mmio, + flags: Mmio, + vlan: Mmio, + buffer: Mmio +} + +#[repr(packed)] +struct Td { + length: Mmio, + flags: Mmio, + vlan: Mmio, + buffer: Mmio +} + +pub struct Rtl8168 { + regs: &'static mut Regs, + irq: u8, + receive_buffer: [Dma<[u8; 0x1FF8]>; 16], + receive_ring: Dma<[Rd; 16]>, + transmit_buffer: [Dma<[u8; 0x1FF8]>; 16], + transmit_ring: Dma<[Td; 16]>, + transmit_buffer_h: [Dma<[u8; 0x1FF8]>; 1], + transmit_ring_h: Dma<[Td; 1]> +} + +impl SchemeMut for Rtl8168 { + fn open(&mut self, _path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { + if uid == 0 { + Ok(0) + } else { + Err(Error::new(EACCES)) + } + } + + fn dup(&mut self, id: usize) -> Result { + Ok(id) + } + + fn read(&mut self, _id: usize, buf: &mut [u8]) -> Result { + println!("Try Receive {}", buf.len()); + for (rd_i, rd) in self.receive_ring.iter_mut().enumerate() { + if ! rd.flags.readf(OWN) { + println!("Receive {}: {}", rd_i, rd.length.read()); + + let data = &self.receive_buffer[rd_i as usize][.. rd.length.read() as usize]; + + let mut i = 0; + while i < buf.len() && i < data.len() { + buf[i] = data[i]; + i += 1; + } + + rd.flags.writef(OWN, true); + + return Ok(i); + } + } + + Err(Error::new(EWOULDBLOCK)) + } + + fn write(&mut self, _id: usize, buf: &[u8]) -> Result { + println!("Try Transmit {}", buf.len()); + loop { + for (td_i, td) in self.transmit_ring.iter_mut().enumerate() { + if ! td.flags.readf(OWN) { + println!("Transmit {}: Setup {}", td_i, buf.len()); + + let mut data = &mut self.transmit_buffer[td_i as usize]; + + let mut i = 0; + while i < buf.len() && i < data.len() { + data[i] = buf[i]; + i += 1; + } + + td.length.write(cmp::min(buf.len(), i) as u16); + + td.flags.writef(OWN | 1 << 13 | 1 << 12, true); + + self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet + + return Ok(i); + } + } + + unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } + } + } + + fn fsync(&mut self, _id: usize) -> Result { + Ok(0) + } + + fn close(&mut self, _id: usize) -> Result { + Ok(0) + } +} + +impl Rtl8168 { + pub unsafe fn new(base: usize, irq: u8) -> Result { + assert_eq!(mem::size_of::(), 256); + + let regs = &mut *(base as *mut Regs); + assert_eq!(®s.tnpds as *const _ as usize - base, 0x20); + assert_eq!(®s.cmd as *const _ as usize - base, 0x37); + assert_eq!(®s.tcr as *const _ as usize - base, 0x40); + assert_eq!(®s.rcr as *const _ as usize - base, 0x44); + assert_eq!(®s.cmd_9346 as *const _ as usize - base, 0x50); + assert_eq!(®s.phys_sts as *const _ as usize - base, 0x6C); + assert_eq!(®s.rms as *const _ as usize - base, 0xDA); + assert_eq!(®s.rdsar as *const _ as usize - base, 0xE4); + assert_eq!(®s.mtps as *const _ as usize - base, 0xEC); + + let mut module = Rtl8168 { + regs: regs, + irq: irq, + receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], + receive_ring: Dma::zeroed()?, + transmit_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], + transmit_ring: Dma::zeroed()?, + transmit_buffer_h: [Dma::zeroed()?], + transmit_ring_h: Dma::zeroed()? + }; + + module.init(); + + Ok(module) + } + + pub unsafe fn irq(&mut self) -> u16 { + // Read and then clear the ISR + let isr = self.regs.isr.read(); + self.regs.isr.write(isr); + isr + } + + pub unsafe fn init(&mut self) { + println!(" + RTL8168 on: {:X}, IRQ: {}", self.regs as *mut Regs as usize, self.irq); + + let mac_low = self.regs.mac[0].read(); + let mac_high = self.regs.mac[1].read(); + let mac = [mac_low as u8, + (mac_low >> 8) as u8, + (mac_low >> 16) as u8, + (mac_low >> 24) as u8, + mac_high as u8, + (mac_high >> 8) as u8]; + println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value + self.regs.cmd.writef(1 << 4, true); + while self.regs.cmd.readf(1 << 4) {} + + // Set up rx buffers + for i in 0..self.receive_ring.len() { + self.receive_ring[i].flags.writef(OWN, true); + self.receive_ring[i].length.write(self.receive_buffer[i].len() as u16); + self.receive_ring[i].buffer.write(self.receive_buffer[i].physical() as u64); + } + if let Some(mut rd) = self.receive_ring.last_mut() { + rd.flags.writef(OWN | EOR, true); + } + + // Set up normal priority tx buffers + for i in 0..self.transmit_ring.len() { + self.transmit_ring[i].buffer.write(self.transmit_buffer[i].physical() as u64); + } + if let Some(mut td) = self.transmit_ring.last_mut() { + td.flags.writef(EOR, true); + } + + // Set up high priority tx buffers + for i in 0..self.transmit_ring_h.len() { + self.transmit_ring_h[i].buffer.write(self.transmit_buffer_h[i].physical() as u64); + } + if let Some(mut td) = self.transmit_ring_h.last_mut() { + td.flags.writef(EOR, true); + } + + // Unlock config + self.regs.cmd_9346.write(1 << 7 | 1 << 6); + + // Accept broadcast (bit 3), multicast (bit 2), and unicast (bit 1) + self.regs.rcr.writef(0xE70F /*TODO: Not permiscuious*/, true); + + // Enable tx (bit 2) + self.regs.cmd.writef(1 << 2, true); + + // Set TX config + self.regs.tcr.write(0x03010700); + + // Max RX packet size + self.regs.rms.write(0x1FF8); + + // Max TX packet size + self.regs.mtps.write(0x3B); + + // Set tx low priority buffer address + self.regs.tnpds.write(self.transmit_ring.physical() as u64); + + // Set tx high priority buffer address + self.regs.thpds.write(self.transmit_ring_h.physical() as u64); + + // Set rx buffer address + self.regs.rdsar.write(self.receive_ring.physical() as u64); + + // Enable rx (bit 3) and tx (bit 2) + self.regs.cmd.writef(1 << 3 | 1 << 2, true); + + // Interrupt on tx error (bit 3), tx ok (bit 2), rx error(bit 1), and rx ok (bit 0) + self.regs.imr.write(1 << 15 | 1 << 14 | 1 << 7 | 1 << 6 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1); + + // Lock config + self.regs.cmd_9346.write(0); + + println!(" - Ready {:X}", self.regs.phys_sts.read()); + } +} diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs new file mode 100644 index 0000000000..bd4425cc44 --- /dev/null +++ b/rtl8168d/src/main.rs @@ -0,0 +1,99 @@ +#![feature(asm)] + +extern crate dma; +extern crate event; +extern crate io; +extern crate syscall; + +use std::cell::RefCell; +use std::{env, thread}; +use std::fs::File; +use std::io::{Read, Write, Result}; +use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::sync::Arc; + +use event::EventQueue; +use syscall::{Packet, SchemeMut, MAP_WRITE}; +use syscall::error::EWOULDBLOCK; + +pub mod device; + +fn main() { + let mut args = env::args().skip(1); + + let bar_str = args.next().expect("rtl8168d: no address provided"); + let bar = usize::from_str_radix(&bar_str, 16).expect("rtl8168d: failed to parse address"); + + let irq_str = args.next().expect("rtl8168d: no irq provided"); + let irq = irq_str.parse::().expect("rtl8168d: failed to parse irq"); + + thread::spawn(move || { + unsafe { + syscall::iopl(3).expect("rtl8168d: failed to get I/O permission"); + asm!("cli" :::: "intel", "volatile"); + } + + let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("rtl8168d: failed to create network scheme"); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + + let address = unsafe { syscall::physmap(bar, 256, MAP_WRITE).expect("rtl8168d: failed to map address") }; + { + let device = Arc::new(RefCell::new(unsafe { device::Rtl8168::new(address, irq).expect("rtl8168d: failed to allocate device") })); + + let mut event_queue = EventQueue::<()>::new().expect("rtl8168d: failed to create event queue"); + + let todo = Arc::new(RefCell::new(Vec::::new())); + + let device_irq = device.clone(); + let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + let mut irq_file = File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open IRQ file"); + event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + + let isr = unsafe { device_irq.borrow_mut().irq() }; + if isr != 0 { + irq_file.write(&mut irq)?; + + println!("RTL8168 Interrupt {:X}", isr); + + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + device_irq.borrow_mut().handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; + } else { + socket_irq.borrow_mut().write(&mut todo[i])?; + todo.remove(i); + } + } + } + Ok(None) + }).expect("rtl8168d: failed to catch events on IRQ file"); + + let socket_fd = socket.borrow().as_raw_fd(); + event_queue.add(socket_fd, move |_count: usize| -> Result> { + let mut packet = Packet::default(); + socket.borrow_mut().read(&mut packet)?; + + let a = packet.a; + device.borrow_mut().handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket.borrow_mut().write(&mut packet)?; + } + + Ok(None) + }).expect("rtl8168d: failed to catch events on IRQ file"); + + event_queue.run().expect("rtl8168d: failed to handle events"); + } + unsafe { let _ = syscall::physunmap(address); } + }); +} From 6b60fd6c5935492175a3d9dfd383690606ca31b1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Oct 2016 14:28:58 -0600 Subject: [PATCH 0058/1301] Fix buffers by using two 32-bit high and low parts --- rtl8168d/src/device.rs | 131 ++++++++++++++++++++++++----------------- rtl8168d/src/main.rs | 2 - 2 files changed, 76 insertions(+), 57 deletions(-) diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 13181760e0..0eb2ac911f 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -1,65 +1,65 @@ -use std::{cmp, mem, slice}; +use std::mem; use dma::Dma; -use io::{Mmio, Io, ReadOnly, WriteOnly}; +use io::{Mmio, Io, ReadOnly}; use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; use syscall::scheme::SchemeMut; #[repr(packed)] struct Regs { mac: [Mmio; 2], - mar: Mmio, - dtccr: Mmio, - _rsv0: Mmio, - tnpds: Mmio, - thpds: Mmio, + _mar: [Mmio; 2], + _dtccr: [Mmio; 2], + _rsv0: [Mmio; 2], + tnpds: [Mmio; 2], + thpds: [Mmio; 2], _rsv1: [Mmio; 7], cmd: Mmio, - tppoll: WriteOnly>, + tppoll: Mmio, _rsv2: [Mmio; 3], imr: Mmio, isr: Mmio, tcr: Mmio, rcr: Mmio, - tctr: Mmio, + _tctr: Mmio, _rsv3: Mmio, cmd_9346: Mmio, - config: [Mmio; 6], + _config: [Mmio; 6], _rsv4: Mmio, - timer_int: Mmio, + _timer_int: Mmio, _rsv5: Mmio, - phys_ar: Mmio, - _rsv6: Mmio, + _phys_ar: Mmio, + _rsv6: [Mmio; 2], phys_sts: ReadOnly>, _rsv7: [Mmio; 23], - wakeup: [Mmio; 8], - crc: [Mmio; 5], + _wakeup: [Mmio; 16], + _crc: [Mmio; 5], _rsv8: [Mmio; 12], rms: Mmio, _rsv9: Mmio, - c_plus_cr: Mmio, + _c_plus_cr: Mmio, _rsv10: Mmio, - rdsar: Mmio, + rdsar: [Mmio; 2], mtps: Mmio, _rsv11: [Mmio; 19], } -const OWN: u16 = 1 << 15; -const EOR: u16 = 1 << 14; +const OWN: u32 = 1 << 31; +const EOR: u32 = 1 << 30; +const FS: u32 = 1 << 29; +const LS: u32 = 1 << 28; #[repr(packed)] struct Rd { - length: Mmio, - flags: Mmio, - vlan: Mmio, + ctrl: Mmio, + _vlan: Mmio, buffer: Mmio } #[repr(packed)] struct Td { - length: Mmio, - flags: Mmio, - vlan: Mmio, + ctrl: Mmio, + _vlan: Mmio, buffer: Mmio } @@ -90,18 +90,21 @@ impl SchemeMut for Rtl8168 { fn read(&mut self, _id: usize, buf: &mut [u8]) -> Result { println!("Try Receive {}", buf.len()); for (rd_i, rd) in self.receive_ring.iter_mut().enumerate() { - if ! rd.flags.readf(OWN) { - println!("Receive {}: {}", rd_i, rd.length.read()); + if ! rd.ctrl.readf(OWN) { + let rd_len = rd.ctrl.read() & 0x3FFF; - let data = &self.receive_buffer[rd_i as usize][.. rd.length.read() as usize]; + println!("Receive {}: {}", rd_i, rd_len); + + let data = &self.receive_buffer[rd_i as usize]; let mut i = 0; - while i < buf.len() && i < data.len() { + while i < buf.len() && i < rd_len as usize { buf[i] = data[i]; i += 1; } - rd.flags.writef(OWN, true); + let eor = rd.ctrl.read() & EOR; + rd.ctrl.write(OWN | eor | data.len() as u32); return Ok(i); } @@ -114,7 +117,7 @@ impl SchemeMut for Rtl8168 { println!("Try Transmit {}", buf.len()); loop { for (td_i, td) in self.transmit_ring.iter_mut().enumerate() { - if ! td.flags.readf(OWN) { + if ! td.ctrl.readf(OWN) { println!("Transmit {}: Setup {}", td_i, buf.len()); let mut data = &mut self.transmit_buffer[td_i as usize]; @@ -125,12 +128,20 @@ impl SchemeMut for Rtl8168 { i += 1; } - td.length.write(cmp::min(buf.len(), i) as u16); + println!("Transmit {}: Before: Control {:X}: TPPoll: {:X}", td_i, td.ctrl.read(), self.regs.tppoll.read()); - td.flags.writef(OWN | 1 << 13 | 1 << 12, true); + let eor = td.ctrl.read() & EOR; + td.ctrl.write(OWN | eor | FS | LS | i as u32); self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet + for s in 0..10 { + println!("Transmit {}: {}: Control {:X}: TPPoll: {:X}", td_i, s, td.ctrl.read(), self.regs.tppoll.read()); + ::std::thread::sleep_ms(1000); + } + + println!("Transmit {}: After: Control {:X}: TPPoll: {:X}", td_i, td.ctrl.read(), self.regs.tppoll.read()); + return Ok(i); } } @@ -189,7 +200,16 @@ impl Rtl8168 { // Read and then clear the ISR let isr = self.regs.isr.read(); self.regs.isr.write(isr); - isr + let imr = self.regs.imr.read(); + + if isr & imr != 0 { + println!("RTL8168 ISR {:X} IMR {:X} ISR & IMR {:X}", isr, imr, isr & imr); + for (rd_i, rd) in self.receive_ring.iter_mut().enumerate() { + println!("RD {}: {:X}", rd_i, rd.ctrl.read()); + } + } + + isr & imr } pub unsafe fn init(&mut self) { @@ -211,12 +231,13 @@ impl Rtl8168 { // Set up rx buffers for i in 0..self.receive_ring.len() { - self.receive_ring[i].flags.writef(OWN, true); - self.receive_ring[i].length.write(self.receive_buffer[i].len() as u16); - self.receive_ring[i].buffer.write(self.receive_buffer[i].physical() as u64); + let rd = &mut self.receive_ring[i]; + let data = &mut self.receive_buffer[i]; + rd.ctrl.write(OWN | data.len() as u32); + rd.buffer.write(data.physical() as u64); } if let Some(mut rd) = self.receive_ring.last_mut() { - rd.flags.writef(OWN | EOR, true); + rd.ctrl.writef(EOR, true); } // Set up normal priority tx buffers @@ -224,7 +245,7 @@ impl Rtl8168 { self.transmit_ring[i].buffer.write(self.transmit_buffer[i].physical() as u64); } if let Some(mut td) = self.transmit_ring.last_mut() { - td.flags.writef(EOR, true); + td.ctrl.writef(EOR, true); } // Set up high priority tx buffers @@ -232,20 +253,14 @@ impl Rtl8168 { self.transmit_ring_h[i].buffer.write(self.transmit_buffer_h[i].physical() as u64); } if let Some(mut td) = self.transmit_ring_h.last_mut() { - td.flags.writef(EOR, true); + td.ctrl.writef(EOR, true); } // Unlock config self.regs.cmd_9346.write(1 << 7 | 1 << 6); - // Accept broadcast (bit 3), multicast (bit 2), and unicast (bit 1) - self.regs.rcr.writef(0xE70F /*TODO: Not permiscuious*/, true); - - // Enable tx (bit 2) - self.regs.cmd.writef(1 << 2, true); - - // Set TX config - self.regs.tcr.write(0x03010700); + // Enable rx (bit 3) and tx (bit 2) + self.regs.cmd.writef(1 << 3 | 1 << 2, true); // Max RX packet size self.regs.rms.write(0x1FF8); @@ -254,23 +269,29 @@ impl Rtl8168 { self.regs.mtps.write(0x3B); // Set tx low priority buffer address - self.regs.tnpds.write(self.transmit_ring.physical() as u64); + self.regs.tnpds[0].write(self.transmit_ring.physical() as u32); + self.regs.tnpds[1].write((self.transmit_ring.physical() >> 32) as u32); // Set tx high priority buffer address - self.regs.thpds.write(self.transmit_ring_h.physical() as u64); + self.regs.thpds[0].write(self.transmit_ring_h.physical() as u32); + self.regs.thpds[1].write((self.transmit_ring_h.physical() >> 32) as u32); // Set rx buffer address - self.regs.rdsar.write(self.receive_ring.physical() as u64); - - // Enable rx (bit 3) and tx (bit 2) - self.regs.cmd.writef(1 << 3 | 1 << 2, true); + self.regs.rdsar[0].write(self.receive_ring.physical() as u32); + self.regs.rdsar[1].write((self.receive_ring.physical() >> 32) as u32); // Interrupt on tx error (bit 3), tx ok (bit 2), rx error(bit 1), and rx ok (bit 0) self.regs.imr.write(1 << 15 | 1 << 14 | 1 << 7 | 1 << 6 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1); + // Set RX config - Accept broadcast (bit 3), multicast (bit 2), and unicast (bit 1) + self.regs.rcr.writef(0xE70E, true); + + // Set TX config + self.regs.tcr.write(0x03010700); + // Lock config self.regs.cmd_9346.write(0); - println!(" - Ready {:X}", self.regs.phys_sts.read()); + println!(" - Ready PHYS {:X} RDSAR {:X}", self.regs.phys_sts.read(), self.regs.rdsar[0].read()); } } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index bd4425cc44..3054a6fcfe 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -56,8 +56,6 @@ fn main() { if isr != 0 { irq_file.write(&mut irq)?; - println!("RTL8168 Interrupt {:X}", isr); - let mut todo = todo_irq.borrow_mut(); let mut i = 0; while i < todo.len() { From 71a9795139bbfb5d4a1e61e44ba177b95cf6f70c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Oct 2016 14:37:05 -0600 Subject: [PATCH 0059/1301] Do not ack IRQ in ahcid, as it does not enable IRQs --- ahcid/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index d15aea9f23..f14955c5d1 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -57,8 +57,8 @@ fn main() { } else if event.id == irq_fd { let mut irq = [0; 8]; if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() { - println!("IRQ"); - irq_file.write(&irq).expect("ahcid: failed to write irq file"); + //TODO : Test for IRQ + //irq_file.write(&irq).expect("ahcid: failed to write irq file"); } } else { println!("Unknown event {}", event.id); From 1f0ba2b94568931bbc58d897fb9ff54f674f3eb6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Oct 2016 15:49:17 -0600 Subject: [PATCH 0060/1301] Do not block on IRQ read, add more debugging to RTL8168/9 --- rtl8168d/src/device.rs | 33 +++++++++++++++++++++++++++------ rtl8168d/src/main.rs | 3 ++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 0eb2ac911f..1b03253c54 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -128,7 +128,7 @@ impl SchemeMut for Rtl8168 { i += 1; } - println!("Transmit {}: Before: Control {:X}: TPPoll: {:X}", td_i, td.ctrl.read(), self.regs.tppoll.read()); + println!("Transmit {}: Before: Control {:X}: Buffer {:X} TPPoll: {:X}", td_i, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read()); let eor = td.ctrl.read() & EOR; td.ctrl.write(OWN | eor | FS | LS | i as u32); @@ -136,11 +136,11 @@ impl SchemeMut for Rtl8168 { self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet for s in 0..10 { - println!("Transmit {}: {}: Control {:X}: TPPoll: {:X}", td_i, s, td.ctrl.read(), self.regs.tppoll.read()); + println!("Transmit {}: {}: Control {:X}: Buffer {:X} TPPoll: {:X}", td_i, s, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read()); ::std::thread::sleep_ms(1000); } - println!("Transmit {}: After: Control {:X}: TPPoll: {:X}", td_i, td.ctrl.read(), self.regs.tppoll.read()); + println!("Transmit {}: After: Control {:X}: Buffer {:X} TPPoll: {:X}", td_i, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read()); return Ok(i); } @@ -204,6 +204,16 @@ impl Rtl8168 { if isr & imr != 0 { println!("RTL8168 ISR {:X} IMR {:X} ISR & IMR {:X}", isr, imr, isr & imr); + println!("CMD {:X} PHYS {:X} RMS {:X} MTPS {:X} RCR {:X} TCR {:X} RDSAR {:X} TNPDS {:X} THPDS {:X}", + self.regs.cmd.read(), + self.regs.phys_sts.read(), + self.regs.rms.read(), + self.regs.mtps.read(), + self.regs.rcr.read(), + self.regs.tcr.read(), + self.regs.rdsar[0].read(), + self.regs.tnpds[0].read(), + self.regs.thpds[0].read()); for (rd_i, rd) in self.receive_ring.iter_mut().enumerate() { println!("RD {}: {:X}", rd_i, rd.ctrl.read()); } @@ -281,10 +291,10 @@ impl Rtl8168 { self.regs.rdsar[1].write((self.receive_ring.physical() >> 32) as u32); // Interrupt on tx error (bit 3), tx ok (bit 2), rx error(bit 1), and rx ok (bit 0) - self.regs.imr.write(1 << 15 | 1 << 14 | 1 << 7 | 1 << 6 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1); + self.regs.imr.write(1 << 15 | 1 << 14 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1); // Set RX config - Accept broadcast (bit 3), multicast (bit 2), and unicast (bit 1) - self.regs.rcr.writef(0xE70E, true); + self.regs.rcr.write(0xE70E); // Set TX config self.regs.tcr.write(0x03010700); @@ -292,6 +302,17 @@ impl Rtl8168 { // Lock config self.regs.cmd_9346.write(0); - println!(" - Ready PHYS {:X} RDSAR {:X}", self.regs.phys_sts.read(), self.regs.rdsar[0].read()); + println!(" - Ready CMD {:X} ISR {:X} IMR {:X} PHYS {:X} RMS {:X} MTPS {:X} RCR {:X} TCR {:X} RDSAR {:X} TNPDS {:X} THPDS {:X}", + self.regs.cmd.read(), + self.regs.isr.read(), + self.regs.imr.read(), + self.regs.phys_sts.read(), + self.regs.rms.read(), + self.regs.mtps.read(), + self.regs.rcr.read(), + self.regs.tcr.read(), + self.regs.rdsar[0].read(), + self.regs.tnpds[0].read(), + self.regs.thpds[0].read()); } } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 3054a6fcfe..df0114c52d 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -36,6 +36,8 @@ fn main() { let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("rtl8168d: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + let mut irq_file = File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open IRQ file"); + let address = unsafe { syscall::physmap(bar, 256, MAP_WRITE).expect("rtl8168d: failed to map address") }; { let device = Arc::new(RefCell::new(unsafe { device::Rtl8168::new(address, irq).expect("rtl8168d: failed to allocate device") })); @@ -47,7 +49,6 @@ fn main() { let device_irq = device.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open IRQ file"); event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; From 4d3580f0f2881c699cb1b489e13b8b78f8b6a84f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Oct 2016 16:48:09 -0600 Subject: [PATCH 0061/1301] Fix tx and rx --- rtl8168d/src/device.rs | 43 +++++++++++++++--------------------------- rtl8168d/src/main.rs | 2 ++ 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 1b03253c54..0c563a88ab 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -68,9 +68,9 @@ pub struct Rtl8168 { irq: u8, receive_buffer: [Dma<[u8; 0x1FF8]>; 16], receive_ring: Dma<[Rd; 16]>, - transmit_buffer: [Dma<[u8; 0x1FF8]>; 16], + transmit_buffer: [Dma<[u8; 7552]>; 16], transmit_ring: Dma<[Td; 16]>, - transmit_buffer_h: [Dma<[u8; 0x1FF8]>; 1], + transmit_buffer_h: [Dma<[u8; 7552]>; 1], transmit_ring_h: Dma<[Td; 1]> } @@ -128,19 +128,20 @@ impl SchemeMut for Rtl8168 { i += 1; } - println!("Transmit {}: Before: Control {:X}: Buffer {:X} TPPoll: {:X}", td_i, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read()); + println!("Transmit {}: Before: Control {:X}: Buffer {:X} TPPoll: {:X} ISR: {:X}", td_i, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read(), self.regs.isr.read()); let eor = td.ctrl.read() & EOR; td.ctrl.write(OWN | eor | FS | LS | i as u32); self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet - for s in 0..10 { - println!("Transmit {}: {}: Control {:X}: Buffer {:X} TPPoll: {:X}", td_i, s, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read()); - ::std::thread::sleep_ms(1000); + println!("Transmit {}: During: Control {:X}: Buffer {:X} TPPoll: {:X} ISR: {:X}", td_i, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read(), self.regs.isr.read()); + + while self.regs.tppoll.readf(1 << 6) { + unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } } - println!("Transmit {}: After: Control {:X}: Buffer {:X} TPPoll: {:X}", td_i, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read()); + println!("Transmit {}: After: Control {:X}: Buffer {:X} TPPoll: {:X} ISR: {:X}", td_i, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read(), self.regs.isr.read()); return Ok(i); } @@ -201,24 +202,6 @@ impl Rtl8168 { let isr = self.regs.isr.read(); self.regs.isr.write(isr); let imr = self.regs.imr.read(); - - if isr & imr != 0 { - println!("RTL8168 ISR {:X} IMR {:X} ISR & IMR {:X}", isr, imr, isr & imr); - println!("CMD {:X} PHYS {:X} RMS {:X} MTPS {:X} RCR {:X} TCR {:X} RDSAR {:X} TNPDS {:X} THPDS {:X}", - self.regs.cmd.read(), - self.regs.phys_sts.read(), - self.regs.rms.read(), - self.regs.mtps.read(), - self.regs.rcr.read(), - self.regs.tcr.read(), - self.regs.rdsar[0].read(), - self.regs.tnpds[0].read(), - self.regs.thpds[0].read()); - for (rd_i, rd) in self.receive_ring.iter_mut().enumerate() { - println!("RD {}: {:X}", rd_i, rd.ctrl.read()); - } - } - isr & imr } @@ -290,15 +273,19 @@ impl Rtl8168 { self.regs.rdsar[0].write(self.receive_ring.physical() as u32); self.regs.rdsar[1].write((self.receive_ring.physical() >> 32) as u32); + //Clear ISR + let isr = self.regs.isr.read(); + self.regs.isr.write(isr); + // Interrupt on tx error (bit 3), tx ok (bit 2), rx error(bit 1), and rx ok (bit 0) self.regs.imr.write(1 << 15 | 1 << 14 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1); + // Set TX config + self.regs.tcr.write(0b11 << 24 | 0b111 << 8); + // Set RX config - Accept broadcast (bit 3), multicast (bit 2), and unicast (bit 1) self.regs.rcr.write(0xE70E); - // Set TX config - self.regs.tcr.write(0x03010700); - // Lock config self.regs.cmd_9346.write(0); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index df0114c52d..41dd4f3469 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -55,6 +55,8 @@ fn main() { let isr = unsafe { device_irq.borrow_mut().irq() }; if isr != 0 { + println!("RTL8168 ISR {:X}", isr); + irq_file.write(&mut irq)?; let mut todo = todo_irq.borrow_mut(); From 8ee024b34f86b3d91802f92251386a9bb4db98b1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Oct 2016 14:54:13 -0600 Subject: [PATCH 0062/1301] Simplify vesad by using SchemeMut --- vesad/src/main.rs | 6 ++-- vesad/src/scheme.rs | 76 ++++++++++++++++------------------------ vesad/src/screen/text.rs | 2 +- 3 files changed, 34 insertions(+), 50 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 3f04d7c738..e1437e75f4 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -9,7 +9,7 @@ extern crate syscall; use std::{env, mem, thread}; use std::fs::File; use std::io::{Read, Write}; -use syscall::{physmap, physunmap, Packet, Scheme, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE}; +use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE}; use mode_info::VBEModeInfo; use primitive::fast_set64; @@ -57,7 +57,7 @@ fn main() { let onscreen = unsafe { physmap(physbaseptr, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; unsafe { fast_set64(onscreen as *mut u64, 0, size/2) }; - let scheme = DisplayScheme::new(width, height, onscreen, &spec); + let mut scheme = DisplayScheme::new(width, height, onscreen, &spec); let mut blocked = Vec::new(); loop { @@ -87,7 +87,7 @@ fn main() { } } - for (screen_id, screen) in scheme.screens.borrow().iter() { + for (screen_id, screen) in scheme.screens.iter() { if ! screen.will_block() { let event_packet = Packet { id: 0, diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 8ce9034905..dd26e6a2cb 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,20 +1,15 @@ -use std::cell::{Cell, RefCell}; use std::collections::BTreeMap; use std::{mem, slice, str}; use orbclient::{Event, EventOption}; -use syscall::{Result, Error, EACCES, EBADF, ENOENT, Scheme}; +use syscall::{Result, Error, EACCES, EBADF, ENOENT, SchemeMut}; use display::Display; use screen::{Screen, GraphicScreen, TextScreen}; pub struct DisplayScheme { - width: usize, - height: usize, - onscreen: usize, - active: Cell, - next_screen: Cell, - pub screens: RefCell>> + active: usize, + pub screens: BTreeMap> } impl DisplayScheme { @@ -32,18 +27,13 @@ impl DisplayScheme { } DisplayScheme { - width: width, - height: height, - onscreen: onscreen, - active: Cell::new(1), - next_screen: Cell::new(screen_i), - screens: RefCell::new(screens) + active: 1, + screens: screens } } pub fn will_block(&self, id: usize) -> bool { - let screens = self.screens.borrow(); - if let Some(screen) = screens.get(&id) { + if let Some(screen) = self.screens.get(&id) { screen.will_block() } else { false @@ -51,8 +41,8 @@ impl DisplayScheme { } } -impl Scheme for DisplayScheme { - fn open(&self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { +impl SchemeMut for DisplayScheme { + fn open(&mut self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { if path == b"input" { if uid == 0 { Ok(0) @@ -62,7 +52,7 @@ impl Scheme for DisplayScheme { } else { let path_str = str::from_utf8(path).unwrap_or(""); let id = path_str.parse::().unwrap_or(0); - if self.screens.borrow().contains_key(&id) { + if self.screens.contains_key(&id) { Ok(id) } else { Err(Error::new(ENOENT)) @@ -70,24 +60,22 @@ impl Scheme for DisplayScheme { } } - fn dup(&self, id: usize) -> Result { + fn dup(&mut self, id: usize) -> Result { Ok(id) } - fn fevent(&self, id: usize, flags: usize) -> Result { - let mut screens = self.screens.borrow_mut(); - if let Some(mut screen) = screens.get_mut(&id) { + fn fevent(&mut self, id: usize, flags: usize) -> Result { + if let Some(mut screen) = self.screens.get_mut(&id) { screen.event(flags).and(Ok(id)) } else { Err(Error::new(EBADF)) } } - fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let screens = self.screens.borrow(); + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { let path_str = if id == 0 { format!("display:input") - } else if let Some(screen) = screens.get(&id) { + } else if let Some(screen) = self.screens.get(&id) { format!("display:{}/{}/{}", id, screen.width(), screen.height()) } else { return Err(Error::new(EBADF)); @@ -104,10 +92,9 @@ impl Scheme for DisplayScheme { Ok(i) } - fn fsync(&self, id: usize) -> Result { - let mut screens = self.screens.borrow_mut(); - if let Some(mut screen) = screens.get_mut(&id) { - if id == self.active.get() { + fn fsync(&mut self, id: usize) -> Result { + if let Some(mut screen) = self.screens.get_mut(&id) { + if id == self.active { screen.sync(); } Ok(0) @@ -116,22 +103,20 @@ impl Scheme for DisplayScheme { } } - fn read(&self, id: usize, buf: &mut [u8]) -> Result { - let mut screens = self.screens.borrow_mut(); - if let Some(mut screen) = screens.get_mut(&id) { + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + if let Some(mut screen) = self.screens.get_mut(&id) { screen.read(buf) } else { Err(Error::new(EBADF)) } } - fn write(&self, id: usize, buf: &[u8]) -> Result { - let mut screens = self.screens.borrow_mut(); + fn write(&mut self, id: usize, buf: &[u8]) -> Result { if id == 0 { if buf.len() == 1 && buf[0] >= 0xF4 { let new_active = (buf[0] - 0xF4) as usize + 1; - if let Some(mut screen) = screens.get_mut(&new_active) { - self.active.set(new_active); + if let Some(mut screen) = self.screens.get_mut(&new_active) { + self.active = new_active; screen.redraw(); } Ok(1) @@ -157,12 +142,12 @@ impl Scheme for DisplayScheme { }; if let Some(new_active) = new_active_opt { - if let Some(mut screen) = screens.get_mut(&new_active) { - self.active.set(new_active); + if let Some(mut screen) = self.screens.get_mut(&new_active) { + self.active = new_active; screen.redraw(); } } else { - if let Some(mut screen) = screens.get_mut(&self.active.get()) { + if let Some(mut screen) = self.screens.get_mut(&self.active) { screen.input(event); } } @@ -170,23 +155,22 @@ impl Scheme for DisplayScheme { Ok(events.len() * mem::size_of::()) } - } else if let Some(mut screen) = screens.get_mut(&id) { - screen.write(buf, id == self.active.get()) + } else if let Some(mut screen) = self.screens.get_mut(&id) { + screen.write(buf, id == self.active) } else { Err(Error::new(EBADF)) } } - fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { - let mut screens = self.screens.borrow_mut(); - if let Some(mut screen) = screens.get_mut(&id) { + fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result { + if let Some(mut screen) = self.screens.get_mut(&id) { screen.seek(pos, whence) } else { Err(Error::new(EBADF)) } } - fn close(&self, _id: usize) -> Result { + fn close(&mut self, _id: usize) -> Result { Ok(0) } } diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index d61fe7ac5c..1fcb988fcd 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -204,7 +204,7 @@ impl Screen for TextScreen { Ok(buf.len()) } - fn seek(&mut self, pos: usize, whence: usize) -> Result { + fn seek(&mut self, _pos: usize, _whence: usize) -> Result { Ok(0) } From 04266d6438806bff399b5fc32432d613ca0c4f60 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Oct 2016 17:14:52 -0600 Subject: [PATCH 0063/1301] WIP: Make network drivers send fevent packets --- e1000d/src/device.rs | 4 ++++ e1000d/src/main.rs | 28 ++++++++++++++++++++++------ rtl8168d/src/device.rs | 4 ++++ rtl8168d/src/main.rs | 28 ++++++++++++++++++++++------ 4 files changed, 52 insertions(+), 12 deletions(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 6674c7c15b..257369c906 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -186,6 +186,10 @@ impl Scheme for Intel8254x { } } + fn fevent(&self, _id: usize, _flags: usize) -> Result { + Ok(0) + } + fn fsync(&self, _id: usize) -> Result { Ok(0) } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index fcc7d6b486..fbec102b3d 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -39,7 +39,7 @@ fn main() { { let device = Arc::new(unsafe { device::Intel8254x::new(address, irq).expect("e1000d: failed to allocate device") }); - let mut event_queue = EventQueue::<()>::new().expect("e1000d: failed to create event queue"); + let mut event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -47,7 +47,7 @@ fn main() { let socket_irq = socket.clone(); let todo_irq = todo.clone(); let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); - event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; if unsafe { device_irq.irq() } { @@ -70,9 +70,10 @@ fn main() { Ok(None) }).expect("e1000d: failed to catch events on IRQ file"); - event_queue.add(socket_fd, move |_count: usize| -> Result> { + let socket_packet = socket.clone(); + event_queue.add(socket_fd, move |_count: usize| -> Result> { let mut packet = Packet::default(); - socket.borrow_mut().read(&mut packet)?; + socket_packet.borrow_mut().read(&mut packet)?; let a = packet.a; device.handle(&mut packet); @@ -80,13 +81,28 @@ fn main() { packet.a = a; todo.borrow_mut().push(packet); } else { - socket.borrow_mut().write(&mut packet)?; + socket_packet.borrow_mut().write(&mut packet)?; } Ok(None) }).expect("e1000d: failed to catch events on IRQ file"); - event_queue.run().expect("e1000d: failed to handle events"); + loop { + let event_count = event_queue.run().expect("e1000d: failed to handle events"); + + let event_packet = Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ, + d: event_count + }; + + socket.borrow_mut().write(&event_packet).expect("vesad: failed to write display event"); + } } unsafe { let _ = syscall::physunmap(address); } }); diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 0c563a88ab..4e8f53ce74 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -151,6 +151,10 @@ impl SchemeMut for Rtl8168 { } } + fn fevent(&mut self, _id: usize, _flags: usize) -> Result { + Ok(0) + } + fn fsync(&mut self, _id: usize) -> Result { Ok(0) } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 41dd4f3469..44609030c0 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -42,14 +42,14 @@ fn main() { { let device = Arc::new(RefCell::new(unsafe { device::Rtl8168::new(address, irq).expect("rtl8168d: failed to allocate device") })); - let mut event_queue = EventQueue::<()>::new().expect("rtl8168d: failed to create event queue"); + let mut event_queue = EventQueue::::new().expect("rtl8168d: failed to create event queue"); let todo = Arc::new(RefCell::new(Vec::::new())); let device_irq = device.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; @@ -77,9 +77,10 @@ fn main() { }).expect("rtl8168d: failed to catch events on IRQ file"); let socket_fd = socket.borrow().as_raw_fd(); - event_queue.add(socket_fd, move |_count: usize| -> Result> { + let socket_packet = socket.clone(); + event_queue.add(socket_fd, move |_count: usize| -> Result> { let mut packet = Packet::default(); - socket.borrow_mut().read(&mut packet)?; + socket_packet.borrow_mut().read(&mut packet)?; let a = packet.a; device.borrow_mut().handle(&mut packet); @@ -87,13 +88,28 @@ fn main() { packet.a = a; todo.borrow_mut().push(packet); } else { - socket.borrow_mut().write(&mut packet)?; + socket_packet.borrow_mut().write(&mut packet)?; } Ok(None) }).expect("rtl8168d: failed to catch events on IRQ file"); - event_queue.run().expect("rtl8168d: failed to handle events"); + loop { + let event_count = event_queue.run().expect("rtl8168d: failed to handle events"); + + let event_packet = Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ, + d: event_count + }; + + socket.borrow_mut().write(&event_packet).expect("vesad: failed to write display event"); + } } unsafe { let _ = syscall::physunmap(address); } }); From cb5f38dfdca769f97c135d35b120ad2fc9cd5718 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Oct 2016 19:00:36 -0600 Subject: [PATCH 0064/1301] Do not throw pcid into background - this prevents ethernetd from exiting if it tries to open network: too early --- pcid/src/main.rs | 209 +++++++++++++++++++++++------------------------ 1 file changed, 103 insertions(+), 106 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index cfc3e6d161..7eca6d78e5 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -8,7 +8,6 @@ use std::env; use std::fs::File; use std::io::Read; use std::process::Command; -use std::thread; use syscall::iopl; use config::Config; @@ -18,131 +17,129 @@ mod config; mod pci; fn main() { - thread::spawn(|| { - let mut config = Config::default(); + let mut config = Config::default(); - let mut args = env::args().skip(1); - if let Some(config_path) = args.next() { - if let Ok(mut config_file) = File::open(&config_path) { - let mut config_data = String::new(); - if let Ok(_) = config_file.read_to_string(&mut config_data) { - config = toml::decode_str(&config_data).unwrap_or(Config::default()); - } + let mut args = env::args().skip(1); + if let Some(config_path) = args.next() { + if let Ok(mut config_file) = File::open(&config_path) { + let mut config_data = String::new(); + if let Ok(_) = config_file.read_to_string(&mut config_data) { + config = toml::decode_str(&config_data).unwrap_or(Config::default()); } } + } - unsafe { iopl(3).unwrap() }; + unsafe { iopl(3).unwrap() }; - println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); + println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); - let pci = Pci::new(); - for bus in pci.buses() { - for dev in bus.devs() { - for func in dev.funcs() { - if let Some(header) = func.header() { - print!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X}", - bus.num, dev.num, func.num, - header.vendor_id, header.device_id, - header.class, header.subclass, header.interface, header.revision); + let pci = Pci::new(); + for bus in pci.buses() { + for dev in bus.devs() { + for func in dev.funcs() { + if let Some(header) = func.header() { + print!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X}", + bus.num, dev.num, func.num, + header.vendor_id, header.device_id, + header.class, header.subclass, header.interface, header.revision); - let pci_class = PciClass::from(header.class); - print!(" {:?}", pci_class); - match pci_class { - PciClass::Storage => match header.subclass { - 0x01 => { - print!(" IDE"); - }, - 0x06 => { - print!(" SATA"); - }, - _ => () + let pci_class = PciClass::from(header.class); + print!(" {:?}", pci_class); + match pci_class { + PciClass::Storage => match header.subclass { + 0x01 => { + print!(" IDE"); }, - PciClass::SerialBus => match header.subclass { - 0x03 => match header.interface { - 0x00 => { - print!(" UHCI"); - }, - 0x10 => { - print!(" OHCI"); - }, - 0x20 => { - print!(" EHCI"); - }, - 0x30 => { - print!(" XHCI"); - }, - _ => () + 0x06 => { + print!(" SATA"); + }, + _ => () + }, + PciClass::SerialBus => match header.subclass { + 0x03 => match header.interface { + 0x00 => { + print!(" UHCI"); + }, + 0x10 => { + print!(" OHCI"); + }, + 0x20 => { + print!(" EHCI"); + }, + 0x30 => { + print!(" XHCI"); }, _ => () }, _ => () + }, + _ => () + } + + for i in 0..header.bars.len() { + match PciBar::from(header.bars[i]) { + PciBar::None => (), + PciBar::Memory(address) => print!(" {}={:>08X}", i, address), + PciBar::Port(address) => print!(" {}={:>04X}", i, address) + } + } + + print!("\n"); + + for driver in config.drivers.iter() { + if let Some(class) = driver.class { + if class != header.class { continue; } } - for i in 0..header.bars.len() { - match PciBar::from(header.bars[i]) { - PciBar::None => (), - PciBar::Memory(address) => print!(" {}={:>08X}", i, address), - PciBar::Port(address) => print!(" {}={:>04X}", i, address) - } + if let Some(subclass) = driver.subclass { + if subclass != header.subclass { continue; } } - print!("\n"); + if let Some(vendor) = driver.vendor { + if vendor != header.vendor_id { continue; } + } - for driver in config.drivers.iter() { - if let Some(class) = driver.class { - if class != header.class { continue; } + if let Some(device) = driver.device { + if device != header.device_id { continue; } + } + + if let Some(ref args) = driver.command { + // Enable bus mastering + unsafe { + let cmd = pci.read(bus.num, dev.num, func.num, 0x04); + pci.write(bus.num, dev.num, func.num, 0x04, cmd | 4); } - if let Some(subclass) = driver.subclass { - if subclass != header.subclass { continue; } - } - - if let Some(vendor) = driver.vendor { - if vendor != header.vendor_id { continue; } - } - - if let Some(device) = driver.device { - if device != header.device_id { continue; } - } - - if let Some(ref args) = driver.command { - // Enable bus mastering - unsafe { - let cmd = pci.read(bus.num, dev.num, func.num, 0x04); - pci.write(bus.num, dev.num, func.num, 0x04, cmd | 4); + let mut args = args.iter(); + if let Some(program) = args.next() { + let mut command = Command::new(program); + for arg in args { + let bar_arg = |i| -> String { + match PciBar::from(header.bars[i]) { + PciBar::None => String::new(), + PciBar::Memory(address) => format!("{:>08X}", address), + PciBar::Port(address) => format!("{:>04X}", address) + } + }; + let arg = match arg.as_str() { + "$BAR0" => bar_arg(0), + "$BAR1" => bar_arg(1), + "$BAR2" => bar_arg(2), + "$BAR3" => bar_arg(3), + "$BAR4" => bar_arg(4), + "$BAR5" => bar_arg(5), + "$IRQ" => format!("{}", header.interrupt_line), + _ => arg.clone() + }; + command.arg(&arg); } - let mut args = args.iter(); - if let Some(program) = args.next() { - let mut command = Command::new(program); - for arg in args { - let bar_arg = |i| -> String { - match PciBar::from(header.bars[i]) { - PciBar::None => String::new(), - PciBar::Memory(address) => format!("{:>08X}", address), - PciBar::Port(address) => format!("{:>04X}", address) - } - }; - let arg = match arg.as_str() { - "$BAR0" => bar_arg(0), - "$BAR1" => bar_arg(1), - "$BAR2" => bar_arg(2), - "$BAR3" => bar_arg(3), - "$BAR4" => bar_arg(4), - "$BAR5" => bar_arg(5), - "$IRQ" => format!("{}", header.interrupt_line), - _ => arg.clone() - }; - command.arg(&arg); - } - - match command.spawn() { - Ok(mut child) => match child.wait() { - Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()), - Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err) - }, - Err(err) => println!("pcid: failed to execute {:?}: {}", command, err) - } + match command.spawn() { + Ok(mut child) => match child.wait() { + Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()), + Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err) + }, + Err(err) => println!("pcid: failed to execute {:?}: {}", command, err) } } } @@ -150,5 +147,5 @@ fn main() { } } } - }); + } } From 5724bacd2b0c1c1f32f2d58671d25ae57dcaee1d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Oct 2016 19:13:57 -0600 Subject: [PATCH 0065/1301] Set mac address on boot --- e1000d/Cargo.toml | 2 +- e1000d/src/device.rs | 2 ++ e1000d/src/main.rs | 1 + rtl8168d/Cargo.toml | 2 +- rtl8168d/src/device.rs | 2 ++ rtl8168d/src/main.rs | 1 + 6 files changed, 8 insertions(+), 2 deletions(-) diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 6261f65df5..9a9f2ab0a9 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -7,5 +7,5 @@ bitflags = "*" dma = { path = "../../crates/dma/" } event = { path = "../../crates/event/" } io = { path = "../../crates/io/" } -spin = "*" +netutils = { path = "../../programs/netutils/" } syscall = { path = "../../syscall/" } diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 257369c906..d8c518b7a7 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,6 +1,7 @@ use std::{cmp, mem, ptr, slice}; use dma::Dma; +use netutils::setcfg; use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; use syscall::scheme::Scheme; @@ -272,6 +273,7 @@ impl Intel8254x { mac_high as u8, (mac_high >> 8) as u8]; println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); // // MTA => 0; diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index fbec102b3d..9dbcf790ed 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -2,6 +2,7 @@ extern crate dma; extern crate event; +extern crate netutils; extern crate syscall; use std::cell::RefCell; diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index 394f156677..a4243e736d 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -7,5 +7,5 @@ bitflags = "*" dma = { path = "../../crates/dma/" } event = { path = "../../crates/event/" } io = { path = "../../crates/io/" } -spin = "*" +netutils = { path = "../../programs/netutils/" } syscall = { path = "../../syscall/" } diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 4e8f53ce74..e0b8998aa9 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -2,6 +2,7 @@ use std::mem; use dma::Dma; use io::{Mmio, Io, ReadOnly}; +use netutils::setcfg; use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; use syscall::scheme::SchemeMut; @@ -221,6 +222,7 @@ impl Rtl8168 { mac_high as u8, (mac_high >> 8) as u8]; println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value self.regs.cmd.writef(1 << 4, true); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 44609030c0..ddfa9e0935 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -3,6 +3,7 @@ extern crate dma; extern crate event; extern crate io; +extern crate netutils; extern crate syscall; use std::cell::RefCell; From b18653c57d6a970df76cee1e16af7bf21c1dba23 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Oct 2016 19:35:23 -0600 Subject: [PATCH 0066/1301] Debug all driver activity to display:1, use format to avoid line splitting --- ahcid/src/ahci/hba.rs | 12 ++++++------ ahcid/src/ahci/mod.rs | 6 ++---- ahcid/src/main.rs | 2 ++ e1000d/src/device.rs | 8 ++------ e1000d/src/main.rs | 4 +++- pcid/src/main.rs | 31 +++++++++++++++++-------------- rtl8168d/src/device.rs | 32 ++------------------------------ rtl8168d/src/main.rs | 6 +++--- 8 files changed, 37 insertions(+), 64 deletions(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index e5ff7ca3d9..5180d3b195 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -191,8 +191,8 @@ impl HbaPort { 48 }; - println!(" + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", - serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048); + print!("{}", format!(" + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB\n", + serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048)); Some(sectors * 512) } else { @@ -230,7 +230,7 @@ impl HbaPort { } pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result { - //println!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}", (self as *mut HbaPort) as usize, block, sectors, write); + //print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write)); assert!(sectors > 0 && sectors < 256); @@ -286,20 +286,20 @@ impl HbaPort { while self.ci.readf(1 << slot) { if self.is.readf(HBA_PORT_IS_TFES) { - println!("IS_TFES set in CI loop TFS {:X} SERR {:X}", self.tfd.read(), self.serr.read()); + print!("{}", format!("IS_TFES set in CI loop TFS {:X} SERR {:X}\n", self.tfd.read(), self.serr.read())); return Err(Error::new(EIO)); } pause(); } if self.is.readf(HBA_PORT_IS_TFES) { - println!("IS_TFES set after CI loop TFS {:X} SERR {:X}", self.tfd.read(), self.serr.read()); + print!("{}", format!("IS_TFES set after CI loop TFS {:X} SERR {:X}\n", self.tfd.read(), self.serr.read())); return Err(Error::new(EIO)); } Ok(sectors * 512) } else { - println!("No Command Slots"); + print!("No Command Slots\n"); Err(Error::new(EIO)) } } diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index b4e146588b..36207f0d64 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -8,21 +8,19 @@ pub mod fis; pub mod hba; pub fn disks(base: usize, irq: u8) -> Vec { - println!(" + AHCI on: {:X} IRQ: {}", base as usize, irq); - let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); let ret: Vec = (0..32) .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) .filter_map(|i| { let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i]; let port_type = port.probe(); - println!("{}: {:?}", i, port_type); + print!("{}", format!("{}: {:?}\n", i, port_type)); match port_type { HbaPortType::SATA => { match Disk::new(i, port) { Ok(disk) => Some(disk), Err(err) => { - println!("{}: {}", i, err); + print!("{}", format!("{}: {}\n", i, err)); None } } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index f14955c5d1..1c806c91bf 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -27,6 +27,8 @@ fn main() { let irq_str = args.next().expect("ahcid: no irq provided"); let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); + print!("{}", format!(" + AHCI on: {:X} IRQ: {}\n", bar, irq)); + thread::spawn(move || { unsafe { syscall::iopl(3).expect("ahcid: failed to get I/O permission"); diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index d8c518b7a7..86047283d1 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -93,7 +93,6 @@ const TD_DD: u8 = 1; pub struct Intel8254x { base: usize, - irq: u8, receive_buffer: [Dma<[u8; 16384]>; 16], receive_ring: Dma<[Rd; 16]>, transmit_buffer: [Dma<[u8; 16384]>; 16], @@ -201,10 +200,9 @@ impl Scheme for Intel8254x { } impl Intel8254x { - pub unsafe fn new(base: usize, irq: u8) -> Result { + pub unsafe fn new(base: usize) -> Result { let mut module = Intel8254x { base: base, - irq: irq, receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, @@ -245,8 +243,6 @@ impl Intel8254x { } pub unsafe fn init(&mut self) { - println!(" + Intel 8254x on: {:X}, IRQ: {}", self.base, self.irq); - // Enable auto negotiate, link, clear reset, do not Invert Loss-Of Signal self.flag(CTRL, CTRL_ASDE | CTRL_SLU, true); self.flag(CTRL, CTRL_LRST, false); @@ -272,7 +268,7 @@ impl Intel8254x { (mac_low >> 24) as u8, mac_high as u8, (mac_high >> 8) as u8]; - println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); // diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 9dbcf790ed..a80303bc94 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -27,6 +27,8 @@ fn main() { let irq_str = args.next().expect("e1000d: no irq provided"); let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); + print!("{}", format!(" + E1000 on: {:X}, IRQ: {}\n", bar, irq)); + thread::spawn(move || { unsafe { syscall::iopl(3).expect("e1000d: failed to get I/O permission"); @@ -38,7 +40,7 @@ fn main() { let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") }; { - let device = Arc::new(unsafe { device::Intel8254x::new(address, irq).expect("e1000d: failed to allocate device") }); + let device = Arc::new(unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }); let mut event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 7eca6d78e5..b732277084 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -31,43 +31,44 @@ fn main() { unsafe { iopl(3).unwrap() }; - println!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); + print!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV\n"); let pci = Pci::new(); for bus in pci.buses() { for dev in bus.devs() { for func in dev.funcs() { if let Some(header) = func.header() { - print!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X}", + let pci_class = PciClass::from(header.class); + + let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", bus.num, dev.num, func.num, header.vendor_id, header.device_id, - header.class, header.subclass, header.interface, header.revision); + header.class, header.subclass, header.interface, header.revision, + pci_class); - let pci_class = PciClass::from(header.class); - print!(" {:?}", pci_class); match pci_class { PciClass::Storage => match header.subclass { 0x01 => { - print!(" IDE"); + string.push_str(" IDE"); }, 0x06 => { - print!(" SATA"); + string.push_str(" SATA"); }, _ => () }, PciClass::SerialBus => match header.subclass { 0x03 => match header.interface { 0x00 => { - print!(" UHCI"); + string.push_str(" UHCI"); }, 0x10 => { - print!(" OHCI"); + string.push_str(" OHCI"); }, 0x20 => { - print!(" EHCI"); + string.push_str(" EHCI"); }, 0x30 => { - print!(" XHCI"); + string.push_str(" XHCI"); }, _ => () }, @@ -79,12 +80,14 @@ fn main() { for i in 0..header.bars.len() { match PciBar::from(header.bars[i]) { PciBar::None => (), - PciBar::Memory(address) => print!(" {}={:>08X}", i, address), - PciBar::Port(address) => print!(" {}={:>04X}", i, address) + PciBar::Memory(address) => string.push_str(&format!(" {}={:>08X}", i, address)), + PciBar::Port(address) => string.push_str(&format!(" {}={:>04X}", i, address)) } } - print!("\n"); + string.push('\n'); + + print!("{}", string); for driver in config.drivers.iter() { if let Some(class) = driver.class { diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index e0b8998aa9..f270c1ac0f 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -66,7 +66,6 @@ struct Td { pub struct Rtl8168 { regs: &'static mut Regs, - irq: u8, receive_buffer: [Dma<[u8; 0x1FF8]>; 16], receive_ring: Dma<[Rd; 16]>, transmit_buffer: [Dma<[u8; 7552]>; 16], @@ -89,13 +88,10 @@ impl SchemeMut for Rtl8168 { } fn read(&mut self, _id: usize, buf: &mut [u8]) -> Result { - println!("Try Receive {}", buf.len()); for (rd_i, rd) in self.receive_ring.iter_mut().enumerate() { if ! rd.ctrl.readf(OWN) { let rd_len = rd.ctrl.read() & 0x3FFF; - println!("Receive {}: {}", rd_i, rd_len); - let data = &self.receive_buffer[rd_i as usize]; let mut i = 0; @@ -115,11 +111,9 @@ impl SchemeMut for Rtl8168 { } fn write(&mut self, _id: usize, buf: &[u8]) -> Result { - println!("Try Transmit {}", buf.len()); loop { for (td_i, td) in self.transmit_ring.iter_mut().enumerate() { if ! td.ctrl.readf(OWN) { - println!("Transmit {}: Setup {}", td_i, buf.len()); let mut data = &mut self.transmit_buffer[td_i as usize]; @@ -129,21 +123,15 @@ impl SchemeMut for Rtl8168 { i += 1; } - println!("Transmit {}: Before: Control {:X}: Buffer {:X} TPPoll: {:X} ISR: {:X}", td_i, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read(), self.regs.isr.read()); - let eor = td.ctrl.read() & EOR; td.ctrl.write(OWN | eor | FS | LS | i as u32); self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet - println!("Transmit {}: During: Control {:X}: Buffer {:X} TPPoll: {:X} ISR: {:X}", td_i, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read(), self.regs.isr.read()); - while self.regs.tppoll.readf(1 << 6) { unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } } - println!("Transmit {}: After: Control {:X}: Buffer {:X} TPPoll: {:X} ISR: {:X}", td_i, td.ctrl.read(), td.buffer.read(), self.regs.tppoll.read(), self.regs.isr.read()); - return Ok(i); } } @@ -166,7 +154,7 @@ impl SchemeMut for Rtl8168 { } impl Rtl8168 { - pub unsafe fn new(base: usize, irq: u8) -> Result { + pub unsafe fn new(base: usize) -> Result { assert_eq!(mem::size_of::(), 256); let regs = &mut *(base as *mut Regs); @@ -182,7 +170,6 @@ impl Rtl8168 { let mut module = Rtl8168 { regs: regs, - irq: irq, receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, @@ -211,8 +198,6 @@ impl Rtl8168 { } pub unsafe fn init(&mut self) { - println!(" + RTL8168 on: {:X}, IRQ: {}", self.regs as *mut Regs as usize, self.irq); - let mac_low = self.regs.mac[0].read(); let mac_high = self.regs.mac[1].read(); let mac = [mac_low as u8, @@ -221,7 +206,7 @@ impl Rtl8168 { (mac_low >> 24) as u8, mac_high as u8, (mac_high >> 8) as u8]; - println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value @@ -294,18 +279,5 @@ impl Rtl8168 { // Lock config self.regs.cmd_9346.write(0); - - println!(" - Ready CMD {:X} ISR {:X} IMR {:X} PHYS {:X} RMS {:X} MTPS {:X} RCR {:X} TCR {:X} RDSAR {:X} TNPDS {:X} THPDS {:X}", - self.regs.cmd.read(), - self.regs.isr.read(), - self.regs.imr.read(), - self.regs.phys_sts.read(), - self.regs.rms.read(), - self.regs.mtps.read(), - self.regs.rcr.read(), - self.regs.tcr.read(), - self.regs.rdsar[0].read(), - self.regs.tnpds[0].read(), - self.regs.thpds[0].read()); } } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index ddfa9e0935..5dbf7034c6 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -28,6 +28,8 @@ fn main() { let irq_str = args.next().expect("rtl8168d: no irq provided"); let irq = irq_str.parse::().expect("rtl8168d: failed to parse irq"); + print!("{}", format!(" + RTL8168 on: {:X}, IRQ: {}", bar, irq)); + thread::spawn(move || { unsafe { syscall::iopl(3).expect("rtl8168d: failed to get I/O permission"); @@ -41,7 +43,7 @@ fn main() { let address = unsafe { syscall::physmap(bar, 256, MAP_WRITE).expect("rtl8168d: failed to map address") }; { - let device = Arc::new(RefCell::new(unsafe { device::Rtl8168::new(address, irq).expect("rtl8168d: failed to allocate device") })); + let device = Arc::new(RefCell::new(unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") })); let mut event_queue = EventQueue::::new().expect("rtl8168d: failed to create event queue"); @@ -56,8 +58,6 @@ fn main() { let isr = unsafe { device_irq.borrow_mut().irq() }; if isr != 0 { - println!("RTL8168 ISR {:X}", isr); - irq_file.write(&mut irq)?; let mut todo = todo_irq.borrow_mut(); From a1acadd373a5ce17c55a8ee77aef83a832adebd2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Oct 2016 22:23:09 -0600 Subject: [PATCH 0067/1301] More debugging of writes in ahcid --- ahcid/src/ahci/hba.rs | 150 +++++++++++++++++++++++++---------------- ahcid/src/ahci/mod.rs | 3 +- ahcid/src/main.rs | 2 +- rtl8168d/src/device.rs | 2 +- rtl8168d/src/main.rs | 2 +- 5 files changed, 97 insertions(+), 62 deletions(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 5180d3b195..e64afa32e2 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -18,7 +18,7 @@ const HBA_PORT_CMD_CR: u32 = 1 << 15; const HBA_PORT_CMD_FR: u32 = 1 << 14; const HBA_PORT_CMD_FRE: u32 = 1 << 4; const HBA_PORT_CMD_ST: u32 = 1; -const HBA_PORT_IS_TFES: u32 = 1 << 30; +const HBA_PORT_IS_ERR: u32 = 1 << 30 | 1 << 29 | 1 << 28 | 1 << 27; const HBA_SSTS_PRESENT: u32 = 0x3; const HBA_SIG_ATA: u32 = 0x00000101; const HBA_SIG_ATAPI: u32 = 0xEB140101; @@ -41,12 +41,12 @@ pub enum HbaPortType { #[repr(packed)] pub struct HbaPort { - pub clb: Mmio, // 0x00, command list base address, 1K-byte aligned - pub fb: Mmio, // 0x08, FIS base address, 256-byte aligned + pub clb: [Mmio; 2], // 0x00, command list base address, 1K-byte aligned + pub fb: [Mmio; 2], // 0x08, FIS base address, 256-byte aligned pub is: Mmio, // 0x10, interrupt status pub ie: Mmio, // 0x14, interrupt enable pub cmd: Mmio, // 0x18, command and status - pub rsv0: Mmio, // 0x1C, Reserved + pub _rsv0: Mmio, // 0x1C, Reserved pub tfd: Mmio, // 0x20, task file data pub sig: Mmio, // 0x24, signature pub ssts: Mmio, // 0x28, SATA status (SCR0:SStatus) @@ -56,7 +56,7 @@ pub struct HbaPort { pub ci: Mmio, // 0x38, command issue pub sntf: Mmio, // 0x3C, SATA notification (SCR4:SNotification) pub fbs: Mmio, // 0x40, FIS-based switch control - pub rsv1: [Mmio; 11], // 0x44 ~ 0x6F, Reserved + pub _rsv1: [Mmio; 11], // 0x44 ~ 0x6F, Reserved pub vendor: [Mmio; 4], // 0x70 ~ 0x7F, vendor specific } @@ -76,21 +76,54 @@ impl HbaPort { } } + pub fn start(&mut self) { + while self.cmd.readf(HBA_PORT_CMD_CR) { + pause(); + } + + self.cmd.writef(HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST, true); + } + + pub fn stop(&mut self) { + self.cmd.writef(HBA_PORT_CMD_ST, false); + + while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { + pause(); + } + + self.cmd.writef(HBA_PORT_CMD_FRE, false); + } + + pub fn slot(&self) -> Option { + let slots = self.sact.read() | self.ci.read(); + for i in 0..32 { + if slots & 1 << i == 0 { + return Some(i); + } + } + None + } + pub fn init(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], fb: &mut Dma<[u8; 256]>) { self.stop(); - self.clb.write(clb.physical() as u64); - self.fb.write(fb.physical() as u64); - let is = self.is.read(); - self.is.write(is); - for i in 0..32 { let cmdheader = &mut clb[i]; cmdheader.ctba.write(ctbas[i].physical() as u64); cmdheader.prdtl.write(0); } - self.start(); + self.clb[0].write(clb.physical() as u32); + self.clb[1].write((clb.physical() >> 32) as u32); + self.fb[0].write(fb.physical() as u32); + self.fb[1].write((fb.physical() >> 32) as u32); + let is = self.is.read(); + self.is.write(is); + self.ie.write(0); + let serr = self.serr.read(); + self.serr.write(serr); + + print!("{}", format!(" - AHCI init {:X}\n", self.cmd.read())); } pub unsafe fn identify(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { @@ -129,14 +162,16 @@ impl HbaPort { self.ci.writef(1 << slot, true); - while self.ci.readf(1 << slot) { - if self.is.readf(HBA_PORT_IS_TFES) { - return None; - } + self.start(); + + while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { pause(); } - if self.is.readf(HBA_PORT_IS_TFES) { + self.stop(); + + if self.is.read() & HBA_PORT_IS_ERR != 0 { + print!("{}", format!("ERROR IS {:X} TFD {:X} SERR {:X}\n", self.is.read(), self.tfd.read(), self.serr.read())); return None; } @@ -200,43 +235,20 @@ impl HbaPort { } } - pub fn start(&mut self) { - while self.cmd.readf(HBA_PORT_CMD_CR) { - pause(); - } - - self.cmd.writef(HBA_PORT_CMD_FRE, true); - self.cmd.writef(HBA_PORT_CMD_ST, true); - } - - pub fn stop(&mut self) { - self.cmd.writef(HBA_PORT_CMD_ST, false); - - while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { - pause(); - } - - self.cmd.writef(HBA_PORT_CMD_FRE, false); - } - - pub fn slot(&self) -> Option { - let slots = self.sact.read() | self.ci.read(); - for i in 0..32 { - if slots & 1 << i == 0 { - return Some(i); - } - } - None - } - pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result { - //print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write)); + if write { + print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write)); + } assert!(sectors > 0 && sectors < 256); self.is.write(u32::MAX); if let Some(slot) = self.slot() { + if write { + print!("{}", format!("SLOT {}\n", slot)); + } + let cmdheader = &mut clb[slot as usize]; cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); @@ -278,25 +290,40 @@ impl HbaPort { cmdfis.counth.write((sectors >> 8) as u8); } + if write { + print!("WAIT ATA_DEV_BUSY | ATA_DEV_DRQ\n"); + } while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { pause(); } + if write { + print!("{}", format!("WRITE CI {:X} in {:X}\n", 1 << slot, self.ci.read())); + } self.ci.writef(1 << slot, true); - while self.ci.readf(1 << slot) { - if self.is.readf(HBA_PORT_IS_TFES) { - print!("{}", format!("IS_TFES set in CI loop TFS {:X} SERR {:X}\n", self.tfd.read(), self.serr.read())); - return Err(Error::new(EIO)); - } + self.start(); + + if write { + print!("{}", format!("WAIT CI {:X} in {:X}\n", 1 << slot, self.ci.read())); + } + while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { pause(); + if write { + print!("{}", format!("WAIT CI {:X} TFD {:X} IS {:X} CMD {:X} SERR {:X}\n", self.ci.read(), self.tfd.read(), self.is.read(), self.cmd.read(), self.serr.read())); + } } - if self.is.readf(HBA_PORT_IS_TFES) { - print!("{}", format!("IS_TFES set after CI loop TFS {:X} SERR {:X}\n", self.tfd.read(), self.serr.read())); + self.stop(); + + if self.is.read() & HBA_PORT_IS_ERR != 0 { + print!("{}", format!("ERROR IS {:X} TFD {:X} SERR {:X}\n", self.is.read(), self.tfd.read(), self.serr.read())); return Err(Error::new(EIO)); } + if write { + print!("{}", format!("SUCCESS {}\n", sectors)); + } Ok(sectors * 512) } else { print!("No Command Slots\n"); @@ -318,24 +345,31 @@ pub struct HbaMem { pub em_ctl: Mmio, // 0x20, Enclosure management control pub cap2: Mmio, // 0x24, Host capabilities extended pub bohc: Mmio, // 0x28, BIOS/OS handoff control and status - pub rsv: [Mmio; 116], // 0x2C - 0x9F, Reserved + pub _rsv: [Mmio; 116], // 0x2C - 0x9F, Reserved pub vendor: [Mmio; 96], // 0xA0 - 0xFF, Vendor specific registers pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers } impl HbaMem { - pub fn reset(&mut self) { + pub fn init(&mut self) { + /* self.ghc.writef(1, true); while self.ghc.readf(1) { pause(); } + */ + self.ghc.write(1 << 31 | 1 << 1); + + print!("{}", format!(" - AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}", + self.cap.read(), self.ghc.read(), self.is.read(), self.pi.read(), + self.vs.read(), self.cap2.read(), self.bohc.read())); } } #[repr(packed)] pub struct HbaPrdtEntry { dba: Mmio, // Data base address - rsv0: Mmio, // Reserved + _rsv0: Mmio, // Reserved dbc: Mmio, // Byte count, 4M max, interrupt = 1 } @@ -348,7 +382,7 @@ pub struct HbaCmdTable { acmd: [Mmio; 16], // ATAPI command, 12 or 16 bytes // 0x50 - rsv: [Mmio; 48], // Reserved + _rsv: [Mmio; 48], // Reserved // 0x80 prdt_entry: [HbaPrdtEntry; 65536], // Physical region descriptor table entries, 0 ~ 65535 @@ -369,5 +403,5 @@ pub struct HbaCmdHeader { ctba: Mmio, // Command table descriptor base address // DW4 - 7 - rsv1: [Mmio; 4], // Reserved + _rsv1: [Mmio; 4], // Reserved } diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index 36207f0d64..90f334a097 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -7,7 +7,8 @@ pub mod disk; pub mod fis; pub mod hba; -pub fn disks(base: usize, irq: u8) -> Vec { +pub fn disks(base: usize) -> Vec { + unsafe { &mut *(base as *mut HbaMem) }.init(); let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); let ret: Vec = (0..32) .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 1c806c91bf..e7aa816fc9 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -47,7 +47,7 @@ fn main() { let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); - let scheme = DiskScheme::new(ahci::disks(address, irq)); + let scheme = DiskScheme::new(ahci::disks(address)); loop { let mut event = Event::default(); event_file.read(&mut event).expect("ahcid: failed to read event file"); diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index f270c1ac0f..6bf36133a9 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -206,7 +206,7 @@ impl Rtl8168 { (mac_low >> 24) as u8, mac_high as u8, (mac_high >> 8) as u8]; - print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 5dbf7034c6..83a02e9c67 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -28,7 +28,7 @@ fn main() { let irq_str = args.next().expect("rtl8168d: no irq provided"); let irq = irq_str.parse::().expect("rtl8168d: failed to parse irq"); - print!("{}", format!(" + RTL8168 on: {:X}, IRQ: {}", bar, irq)); + print!("{}", format!(" + RTL8168 on: {:X}, IRQ: {}\n", bar, irq)); thread::spawn(move || { unsafe { From 9c94a5cd86aeafd1e05d610fc0e34196a840b5c0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Oct 2016 15:26:36 -0600 Subject: [PATCH 0068/1301] Event based ethernetd --- e1000d/src/device.rs | 22 +++++++++++++++++++++- e1000d/src/main.rs | 5 +++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 86047283d1..edadeb1aab 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -140,7 +140,8 @@ impl Scheme for Intel8254x { } } - Err(Error::new(EWOULDBLOCK)) + //Err(Error::new(EWOULDBLOCK)) + Ok(0) } fn write(&self, _id: usize, buf: &[u8]) -> Result { @@ -225,6 +226,25 @@ impl Intel8254x { icr != 0 } + pub fn next_read(&self) -> usize { + let head = unsafe { self.read(RDH) }; + let mut tail = unsafe { self.read(RDT) }; + + tail += 1; + if tail >= self.receive_ring.len() as u32 { + tail = 0; + } + + if tail != head { + let rd = unsafe { &* (self.receive_ring.as_ptr().offset(tail as isize) as *const Rd) }; + if rd.status & RD_DD == RD_DD { + return rd.length as usize; + } + } + + 0 + } + pub unsafe fn read(&self, register: u32) -> u32 { ptr::read_volatile((self.base + register as usize) as *mut u32) } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index a80303bc94..c6a98f277c 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -69,6 +69,11 @@ fn main() { todo.remove(i); } } + + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } } Ok(None) }).expect("e1000d: failed to catch events on IRQ file"); From 87a726178136bcc6ad6675ccfb1f9db3a606f0de Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Oct 2016 15:38:49 -0600 Subject: [PATCH 0069/1301] Add O_NONBLOCK --- e1000d/src/device.rs | 14 +++++++++----- e1000d/src/main.rs | 5 +++++ rtl8168d/src/device.rs | 22 ++++++++++++++++++---- rtl8168d/src/main.rs | 10 ++++++++++ 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index edadeb1aab..350198654b 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -3,6 +3,7 @@ use std::{cmp, mem, ptr, slice}; use dma::Dma; use netutils::setcfg; use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; +use syscall::flag::O_NONBLOCK; use syscall::scheme::Scheme; const CTRL: u32 = 0x00; @@ -100,9 +101,9 @@ pub struct Intel8254x { } impl Scheme for Intel8254x { - fn open(&self, _path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { + fn open(&self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if uid == 0 { - Ok(0) + Ok(flags) } else { Err(Error::new(EACCES)) } @@ -112,7 +113,7 @@ impl Scheme for Intel8254x { Ok(id) } - fn read(&self, _id: usize, buf: &mut [u8]) -> Result { + fn read(&self, id: usize, buf: &mut [u8]) -> Result { let head = unsafe { self.read(RDH) }; let mut tail = unsafe { self.read(RDT) }; @@ -140,8 +141,11 @@ impl Scheme for Intel8254x { } } - //Err(Error::new(EWOULDBLOCK)) - Ok(0) + if id & O_NONBLOCK == O_NONBLOCK { + Ok(0) + } else { + Err(Error::new(EWOULDBLOCK)) + } } fn write(&self, _id: usize, buf: &[u8]) -> Result { diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index c6a98f277c..ee721ee99e 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -92,6 +92,11 @@ fn main() { socket_packet.borrow_mut().write(&mut packet)?; } + let next_read = device.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + Ok(None) }).expect("e1000d: failed to catch events on IRQ file"); diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 6bf36133a9..da2b2ee174 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -4,6 +4,7 @@ use dma::Dma; use io::{Mmio, Io, ReadOnly}; use netutils::setcfg; use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; +use syscall::flag::O_NONBLOCK; use syscall::scheme::SchemeMut; #[repr(packed)] @@ -75,9 +76,9 @@ pub struct Rtl8168 { } impl SchemeMut for Rtl8168 { - fn open(&mut self, _path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { + fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if uid == 0 { - Ok(0) + Ok(flags) } else { Err(Error::new(EACCES)) } @@ -87,7 +88,7 @@ impl SchemeMut for Rtl8168 { Ok(id) } - fn read(&mut self, _id: usize, buf: &mut [u8]) -> Result { + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { for (rd_i, rd) in self.receive_ring.iter_mut().enumerate() { if ! rd.ctrl.readf(OWN) { let rd_len = rd.ctrl.read() & 0x3FFF; @@ -107,7 +108,11 @@ impl SchemeMut for Rtl8168 { } } - Err(Error::new(EWOULDBLOCK)) + if id & O_NONBLOCK == O_NONBLOCK { + Ok(0) + } else { + Err(Error::new(EWOULDBLOCK)) + } } fn write(&mut self, _id: usize, buf: &[u8]) -> Result { @@ -197,6 +202,15 @@ impl Rtl8168 { isr & imr } + pub fn next_read(&self) -> usize { + for rd in self.receive_ring.iter() { + if ! rd.ctrl.readf(OWN) { + return rd.ctrl.read() as usize & 0x3FFF; + } + } + 0 + } + pub unsafe fn init(&mut self) { let mac_low = self.regs.mac[0].read(); let mac_high = self.regs.mac[1].read(); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 83a02e9c67..e6d5b62fe1 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -73,6 +73,11 @@ fn main() { todo.remove(i); } } + + let next_read = device_irq.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } } Ok(None) }).expect("rtl8168d: failed to catch events on IRQ file"); @@ -92,6 +97,11 @@ fn main() { socket_packet.borrow_mut().write(&mut packet)?; } + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + Ok(None) }).expect("rtl8168d: failed to catch events on IRQ file"); From 891a8a85b334f341187a1bb2ca1c2804850d83f7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Oct 2016 19:01:30 -0600 Subject: [PATCH 0070/1301] Update submodules --- ahcid/src/ahci/hba.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index e64afa32e2..c27779e9ed 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -237,7 +237,7 @@ impl HbaPort { pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result { if write { - print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write)); + //print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write)); } assert!(sectors > 0 && sectors < 256); @@ -246,7 +246,7 @@ impl HbaPort { if let Some(slot) = self.slot() { if write { - print!("{}", format!("SLOT {}\n", slot)); + //print!("{}", format!("SLOT {}\n", slot)); } let cmdheader = &mut clb[slot as usize]; @@ -291,26 +291,26 @@ impl HbaPort { } if write { - print!("WAIT ATA_DEV_BUSY | ATA_DEV_DRQ\n"); + //print!("WAIT ATA_DEV_BUSY | ATA_DEV_DRQ\n"); } while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { pause(); } if write { - print!("{}", format!("WRITE CI {:X} in {:X}\n", 1 << slot, self.ci.read())); + //print!("{}", format!("WRITE CI {:X} in {:X}\n", 1 << slot, self.ci.read())); } self.ci.writef(1 << slot, true); self.start(); if write { - print!("{}", format!("WAIT CI {:X} in {:X}\n", 1 << slot, self.ci.read())); + //print!("{}", format!("WAIT CI {:X} in {:X}\n", 1 << slot, self.ci.read())); } while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { pause(); if write { - print!("{}", format!("WAIT CI {:X} TFD {:X} IS {:X} CMD {:X} SERR {:X}\n", self.ci.read(), self.tfd.read(), self.is.read(), self.cmd.read(), self.serr.read())); + //print!("{}", format!("WAIT CI {:X} TFD {:X} IS {:X} CMD {:X} SERR {:X}\n", self.ci.read(), self.tfd.read(), self.is.read(), self.cmd.read(), self.serr.read())); } } @@ -322,7 +322,7 @@ impl HbaPort { } if write { - print!("{}", format!("SUCCESS {}\n", sectors)); + //print!("{}", format!("SUCCESS {}\n", sectors)); } Ok(sectors * 512) } else { From fe339a936214ec0487268167c091b5e6eb6378f3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 26 Oct 2016 13:19:56 -0600 Subject: [PATCH 0071/1301] Redo networking (#22) * Rewriting network functions * Add buffer to dup Fix non-blocking handling by triggering once on enabling events to read to EOF * Modifications for UDP API * Implement TCP client side * Add active close * Add DMAR parser * Implement basic TCP listening. Need to improve the state machine * Reduce debugging * Fixes for close procedure * Updates to fix path processing in libstd --- ahcid/src/main.rs | 12 ++-- ahcid/src/scheme.rs | 2 +- e1000d/src/device.rs | 2 +- e1000d/src/main.rs | 45 ++++++++---- ps2d/src/main.rs | 160 ++++++++++++++++++++++++----------------- rtl8168d/src/device.rs | 2 +- rtl8168d/src/main.rs | 45 ++++++++---- vesad/src/main.rs | 1 - vesad/src/scheme.rs | 2 +- 9 files changed, 165 insertions(+), 106 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index e7aa816fc9..02a514589a 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -52,10 +52,14 @@ fn main() { let mut event = Event::default(); event_file.read(&mut event).expect("ahcid: failed to read event file"); if event.id == socket_fd { - let mut packet = Packet::default(); - socket.read(&mut packet).expect("ahcid: failed to read disk scheme"); - scheme.handle(&mut packet); - socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + loop { + let mut packet = Packet::default(); + if socket.read(&mut packet).expect("ahcid: failed to read disk scheme") == 0 { + break; + } + scheme.handle(&mut packet); + socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + } } else if event.id == irq_fd { let mut irq = [0; 8]; if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() { diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 790e920197..96a7c20732 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -47,7 +47,7 @@ impl Scheme for DiskScheme { } } - fn dup(&self, id: usize) -> Result { + fn dup(&self, id: usize, _buf: &[u8]) -> Result { let mut handles = self.handles.lock(); let new_handle = { let handle = handles.get(&id).ok_or(Error::new(EBADF))?; diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 350198654b..fe2df0164f 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -109,7 +109,7 @@ impl Scheme for Intel8254x { } } - fn dup(&self, id: usize) -> Result { + fn dup(&self, id: usize, _buf: &[u8]) -> Result { Ok(id) } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index ee721ee99e..90f2590c0f 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -80,16 +80,20 @@ fn main() { let socket_packet = socket.clone(); event_queue.add(socket_fd, move |_count: usize| -> Result> { - let mut packet = Packet::default(); - socket_packet.borrow_mut().read(&mut packet)?; + loop { + let mut packet = Packet::default(); + if socket_packet.borrow_mut().read(&mut packet)? == 0 { + break; + } - let a = packet.a; - device.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); - } else { - socket_packet.borrow_mut().write(&mut packet)?; + let a = packet.a; + device.handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket_packet.borrow_mut().write(&mut packet)?; + } } let next_read = device.next_read(); @@ -100,10 +104,8 @@ fn main() { Ok(None) }).expect("e1000d: failed to catch events on IRQ file"); - loop { - let event_count = event_queue.run().expect("e1000d: failed to handle events"); - - let event_packet = Packet { + for event_count in event_queue.trigger_all(0).expect("e1000d: failed to trigger events") { + socket.borrow_mut().write(&Packet { id: 0, pid: 0, uid: 0, @@ -112,9 +114,22 @@ fn main() { b: 0, c: syscall::flag::EVENT_READ, d: event_count - }; + }).expect("e1000d: failed to write event"); + } - socket.borrow_mut().write(&event_packet).expect("vesad: failed to write display event"); + loop { + let event_count = event_queue.run().expect("e1000d: failed to handle events"); + + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ, + d: event_count + }).expect("e1000d: failed to write event"); } } unsafe { let _ = syscall::physunmap(address); } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index d1f1bff5f8..ba5e330e2c 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -32,6 +32,92 @@ bitflags! { } } +struct Ps2d { + input: File, + lshift: bool, + rshift: bool, + packets: [u8; 4], + packet_i: usize, + extra_packet: bool +} + +impl Ps2d { + fn new(input: File, extra_packet: bool) -> Self { + Ps2d { + input: input, + lshift: false, + rshift: false, + packets: [0; 4], + packet_i: 0, + extra_packet: extra_packet + } + } + + fn handle(&mut self, keyboard: bool, data: u8) { + if keyboard { + let (scancode, pressed) = if data >= 0x80 { + (data - 0x80, false) + } else { + (data, true) + }; + + if scancode == 0x2A { + self.lshift = pressed; + } else if scancode == 0x36 { + self.rshift = pressed; + } + + self.input.write(&KeyEvent { + character: keymap::get_char(scancode, self.lshift || self.rshift), + scancode: scancode, + pressed: pressed + }.to_event()).expect("ps2d: failed to write key event"); + } else { + self.packets[self.packet_i] = data; + self.packet_i += 1; + + let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); + if ! flags.contains(ALWAYS_ON) { + println!("MOUSE MISALIGN {:X}", self.packets[0]); + + self.packets = [0; 4]; + self.packet_i = 0; + } else if self.packet_i >= self.packets.len() || (!self.extra_packet && self.packet_i >= 3) { + if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { + let mut dx = self.packets[1] as i32; + if flags.contains(X_SIGN) { + dx -= 0x100; + } + + let mut dy = -(self.packets[2] as i32); + if flags.contains(Y_SIGN) { + dy += 0x100; + } + + let _extra = if self.extra_packet { + self.packets[3] + } else { + 0 + }; + + self.input.write(&MouseEvent { + x: dx, + y: dy, + left_button: flags.contains(LEFT_BUTTON), + middle_button: flags.contains(MIDDLE_BUTTON), + right_button: flags.contains(RIGHT_BUTTON) + }.to_event()).expect("ps2d: failed to write mouse event"); + } else { + println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); + } + + self.packets = [0; 4]; + self.packet_i = 0; + } + } + } +} + fn main() { thread::spawn(|| { unsafe { @@ -39,9 +125,11 @@ fn main() { asm!("cli" :::: "intel", "volatile"); } + let input = File::open("display:input").expect("ps2d: failed to open display:input"); + let extra_packet = controller::Ps2::new().init(); - let mut input = File::open("display:input").expect("ps2d: failed to open display:input"); + let mut ps2d = Ps2d::new(input, extra_packet); let mut event_queue = EventQueue::<(bool, u8)>::new().expect("ps2d: failed to create event queue"); @@ -81,75 +169,13 @@ fn main() { } }).expect("ps2d: failed to poll irq:12"); - let mut lshift = false; - let mut rshift = false; - let mut packets = [0; 4]; - let mut packet_i = 0; + for (keyboard, data) in event_queue.trigger_all(0).expect("ps2d: failed to trigger events") { + ps2d.handle(keyboard, data); + } loop { let (keyboard, data) = event_queue.run().expect("ps2d: failed to handle events"); - - if keyboard { - let (scancode, pressed) = if data >= 0x80 { - (data - 0x80, false) - } else { - (data, true) - }; - - if scancode == 0x2A { - lshift = pressed; - } else if scancode == 0x36 { - rshift = pressed; - } - - input.write(&KeyEvent { - character: keymap::get_char(scancode, lshift || rshift), - scancode: scancode, - pressed: pressed - }.to_event()).expect("ps2d: failed to write key event"); - } else { - packets[packet_i] = data; - packet_i += 1; - - let flags = MousePacketFlags::from_bits_truncate(packets[0]); - if ! flags.contains(ALWAYS_ON) { - println!("MOUSE MISALIGN {:X}", packets[0]); - - packets = [0; 4]; - packet_i = 0; - } else if packet_i >= packets.len() || (!extra_packet && packet_i >= 3) { - if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { - let mut dx = packets[1] as i32; - if flags.contains(X_SIGN) { - dx -= 0x100; - } - - let mut dy = -(packets[2] as i32); - if flags.contains(Y_SIGN) { - dy += 0x100; - } - - let _extra = if extra_packet { - packets[3] - } else { - 0 - }; - - input.write(&MouseEvent { - x: dx, - y: dy, - left_button: flags.contains(LEFT_BUTTON), - middle_button: flags.contains(MIDDLE_BUTTON), - right_button: flags.contains(RIGHT_BUTTON) - }.to_event()).expect("ps2d: failed to write mouse event"); - } else { - println!("ps2d: overflow {:X} {:X} {:X} {:X}", packets[0], packets[1], packets[2], packets[3]); - } - - packets = [0; 4]; - packet_i = 0; - } - } + ps2d.handle(keyboard, data); } }); } diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index da2b2ee174..923d888a15 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -84,7 +84,7 @@ impl SchemeMut for Rtl8168 { } } - fn dup(&mut self, id: usize) -> Result { + fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { Ok(id) } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index e6d5b62fe1..ca441cd84e 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -85,16 +85,20 @@ fn main() { let socket_fd = socket.borrow().as_raw_fd(); let socket_packet = socket.clone(); event_queue.add(socket_fd, move |_count: usize| -> Result> { - let mut packet = Packet::default(); - socket_packet.borrow_mut().read(&mut packet)?; + loop { + let mut packet = Packet::default(); + if socket_packet.borrow_mut().read(&mut packet)? == 0 { + break; + } - let a = packet.a; - device.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); - } else { - socket_packet.borrow_mut().write(&mut packet)?; + let a = packet.a; + device.borrow_mut().handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket_packet.borrow_mut().write(&mut packet)?; + } } let next_read = device.borrow().next_read(); @@ -105,10 +109,8 @@ fn main() { Ok(None) }).expect("rtl8168d: failed to catch events on IRQ file"); - loop { - let event_count = event_queue.run().expect("rtl8168d: failed to handle events"); - - let event_packet = Packet { + for event_count in event_queue.trigger_all(0).expect("rtl8168d: failed to trigger events") { + socket.borrow_mut().write(&Packet { id: 0, pid: 0, uid: 0, @@ -117,9 +119,22 @@ fn main() { b: 0, c: syscall::flag::EVENT_READ, d: event_count - }; + }).expect("rtl8168d: failed to write event"); + } - socket.borrow_mut().write(&event_packet).expect("vesad: failed to write display event"); + loop { + let event_count = event_queue.run().expect("rtl8168d: failed to handle events"); + + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ, + d: event_count + }).expect("rtl8168d: failed to write event"); } } unsafe { let _ = syscall::physunmap(address); } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index e1437e75f4..b9defbf995 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -63,7 +63,6 @@ fn main() { loop { let mut packet = Packet::default(); socket.read(&mut packet).expect("vesad: failed to read display scheme"); - //println!("vesad: {:?}", packet); // If it is a read packet, and there is no data, block it. Otherwise, handle packet if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.will_block(packet.b) { diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index dd26e6a2cb..c81f558c99 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -60,7 +60,7 @@ impl SchemeMut for DisplayScheme { } } - fn dup(&mut self, id: usize) -> Result { + fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { Ok(id) } From e71e27a3c698c0961118efd3dd5a8a0de540998f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 26 Oct 2016 14:17:57 -0600 Subject: [PATCH 0072/1301] Update vesad ransid branch --- vesad/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index f0dcc23be5..8045332cc5 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" [dependencies] orbclient = "0.1" -ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" } +ransid = { git = "https://github.com/redox-os/ransid.git" } rusttype = { git = "https://github.com/dylanede/rusttype.git", optional = true } syscall = { path = "../../syscall/" } From 81c4b8c99847ed9bdb6db87b14cd073fdecb127d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 31 Oct 2016 10:49:00 -0600 Subject: [PATCH 0073/1301] Smp (#23) * Fire up multiple processors * Use IPIs to wake up secondary processors * Much better exception information * Modifications to show more information on fault * WIP: Use real libstd * Add TLS (not complete) * Add random function, export getpid, cleanup * Do not spin APs until new context * Update rust * Update rust * Use rd/wrfsbase * Implement TLS * Implement compiler builtins and update rust * Update rust * Back to Redox libstd * Update rust --- ahcid/src/main.rs | 7 +------ e1000d/src/main.rs | 5 ----- ps2d/src/main.rs | 2 +- rtl8168d/src/main.rs | 5 ----- 4 files changed, 2 insertions(+), 17 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 02a514589a..3bc17ebcbf 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -30,11 +30,6 @@ fn main() { print!("{}", format!(" + AHCI on: {:X} IRQ: {}\n", bar, irq)); thread::spawn(move || { - unsafe { - syscall::iopl(3).expect("ahcid: failed to get I/O permission"); - asm!("cli" :::: "intel", "volatile"); - } - let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; { let socket_fd = syscall::open(":disk", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ahcid: failed to create disk scheme"); @@ -56,7 +51,7 @@ fn main() { let mut packet = Packet::default(); if socket.read(&mut packet).expect("ahcid: failed to read disk scheme") == 0 { break; - } + } scheme.handle(&mut packet); socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 90f2590c0f..f3baf1bbaf 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -30,11 +30,6 @@ fn main() { print!("{}", format!(" + E1000 on: {:X}, IRQ: {}\n", bar, irq)); thread::spawn(move || { - unsafe { - syscall::iopl(3).expect("e1000d: failed to get I/O permission"); - asm!("cli" :::: "intel", "volatile"); - } - let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("e1000d: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index ba5e330e2c..3a0615c5dd 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -122,7 +122,7 @@ fn main() { thread::spawn(|| { unsafe { iopl(3).expect("ps2d: failed to get I/O permission"); - asm!("cli" :::: "intel", "volatile"); + asm!("cli" : : : : "intel", "volatile"); } let input = File::open("display:input").expect("ps2d: failed to open display:input"); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index ca441cd84e..00d6f33678 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -31,11 +31,6 @@ fn main() { print!("{}", format!(" + RTL8168 on: {:X}, IRQ: {}\n", bar, irq)); thread::spawn(move || { - unsafe { - syscall::iopl(3).expect("rtl8168d: failed to get I/O permission"); - asm!("cli" :::: "intel", "volatile"); - } - let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("rtl8168d: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); From e4b4eb5a8384faf0d58a22dd8907013754164a2a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 2 Nov 2016 14:17:11 -0600 Subject: [PATCH 0074/1301] Update terminal emulator --- vesad/src/console.rs | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 vesad/src/console.rs diff --git a/vesad/src/console.rs b/vesad/src/console.rs deleted file mode 100644 index ea3546d5e7..0000000000 --- a/vesad/src/console.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub struct Text { - -} From 621e5571741cfb174a120538dc3dc5251933147d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 2 Nov 2016 19:48:25 -0600 Subject: [PATCH 0075/1301] Remove resource_sceme, Fix syscall crate name, add fmap --- ahcid/Cargo.toml | 2 +- e1000d/Cargo.toml | 2 +- pcid/Cargo.toml | 4 +--- ps2d/Cargo.toml | 2 +- rtl8168d/Cargo.toml | 2 +- vesad/Cargo.toml | 4 ++-- vesad/src/scheme.rs | 8 ++++++++ vesad/src/screen/graphic.rs | 8 ++++++++ vesad/src/screen/mod.rs | 2 ++ vesad/src/screen/text.rs | 6 +++++- 10 files changed, 30 insertions(+), 10 deletions(-) diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index 324ea857b2..f7183317cb 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -7,4 +7,4 @@ bitflags = "*" dma = { path = "../../crates/dma/" } io = { path = "../../crates/io/" } spin = "*" -syscall = { path = "../../syscall/" } +redox_syscall = { path = "../../syscall/" } diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 9a9f2ab0a9..ec8c45e1ab 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -8,4 +8,4 @@ dma = { path = "../../crates/dma/" } event = { path = "../../crates/event/" } io = { path = "../../crates/io/" } netutils = { path = "../../programs/netutils/" } -syscall = { path = "../../syscall/" } +redox_syscall = { path = "../../syscall/" } diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 222032c14b..a64211d070 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -3,11 +3,9 @@ name = "pcid" version = "0.1.0" [dependencies] +redox_syscall = { path = "../../syscall/" } rustc-serialize = { git = "https://github.com/redox-os/rustc-serialize.git" } toml = "*" -[dependencies.syscall] -path = "../../syscall/" - [replace] "rustc-serialize:0.3.19" = { git = "https://github.com/redox-os/rustc-serialize.git" } diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 0c10180c45..98ebbf218f 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -7,4 +7,4 @@ bitflags = "*" event = { path = "../../crates/event/" } io = { path = "../../crates/io/" } orbclient = "0.1" -syscall = { path = "../../syscall/" } +redox_syscall = { path = "../../syscall/" } diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index a4243e736d..e72a130458 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -8,4 +8,4 @@ dma = { path = "../../crates/dma/" } event = { path = "../../crates/event/" } io = { path = "../../crates/io/" } netutils = { path = "../../programs/netutils/" } -syscall = { path = "../../syscall/" } +redox_syscall = { path = "../../syscall/" } diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 8045332cc5..db87c0d1f9 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -4,9 +4,9 @@ version = "0.1.0" [dependencies] orbclient = "0.1" -ransid = { git = "https://github.com/redox-os/ransid.git" } +ransid = "0.2" rusttype = { git = "https://github.com/dylanede/rusttype.git", optional = true } -syscall = { path = "../../syscall/" } +redox_syscall = "0.1" [features] default = [] diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index c81f558c99..a58e7fd112 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -72,6 +72,14 @@ impl SchemeMut for DisplayScheme { } } + fn fmap(&mut self, id: usize, offset: usize, size: usize) -> Result { + if let Some(screen) = self.screens.get(&id) { + screen.map(offset, size) + } else { + Err(Error::new(EBADF)) + } + } + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { let path_str = if id == 0 { format!("display:input") diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 11a6e2e935..b91192267a 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -45,6 +45,14 @@ impl Screen for GraphicScreen { Ok(0) } + fn map(&self, offset: usize, size: usize) -> Result { + if offset + size <= self.display.offscreen.len() * 4 { + Ok(self.display.offscreen.as_ptr() as usize + offset) + } else { + Err(Error::new(EINVAL)) + } + } + fn input(&mut self, event: &Event) { if let EventOption::Mouse(mut mouse_event) = event.to_option() { let x = cmp::max(0, cmp::min(self.display.width as i32, self.mouse_x + mouse_event.x)); diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs index 6a0d5fdfad..9909694a99 100644 --- a/vesad/src/screen/mod.rs +++ b/vesad/src/screen/mod.rs @@ -14,6 +14,8 @@ pub trait Screen { fn event(&mut self, flags: usize) -> Result; + fn map(&self, offset: usize, size: usize) -> Result; + fn input(&mut self, event: &Event); fn read(&mut self, buf: &mut [u8]) -> Result; diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 1fcb988fcd..6d267d7e24 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -3,7 +3,7 @@ extern crate ransid; use std::collections::{BTreeSet, VecDeque}; use orbclient::{Event, EventOption}; -use syscall::Result; +use syscall::error::*; use display::Display; use screen::Screen; @@ -48,6 +48,10 @@ impl Screen for TextScreen { Ok(0) } + fn map(&self, offset: usize, size: usize) -> Result { + Err(Error::new(EBADF)) + } + fn input(&mut self, event: &Event) { let mut buf = vec![]; From 0fdebfd4a100535742e8be89ce05d179808d510c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 3 Nov 2016 15:10:32 -0600 Subject: [PATCH 0076/1301] Update syscall lib, update submodules and dependencies --- pcid/Cargo.toml | 5 +---- vesad/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index a64211d070..a2def71048 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -4,8 +4,5 @@ version = "0.1.0" [dependencies] redox_syscall = { path = "../../syscall/" } -rustc-serialize = { git = "https://github.com/redox-os/rustc-serialize.git" } +rustc-serialize = "0.3.19" toml = "*" - -[replace] -"rustc-serialize:0.3.19" = { git = "https://github.com/redox-os/rustc-serialize.git" } diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index db87c0d1f9..9041edb43b 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" orbclient = "0.1" ransid = "0.2" rusttype = { git = "https://github.com/dylanede/rusttype.git", optional = true } -redox_syscall = "0.1" +redox_syscall = { path = "../../syscall" } [features] default = [] From 9064550f6a350480ea3735d52f879a593321f2b7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 3 Nov 2016 15:47:54 -0600 Subject: [PATCH 0077/1301] Fix rustc-serialize --- pcid/Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index a2def71048..67588f21b6 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -4,5 +4,8 @@ version = "0.1.0" [dependencies] redox_syscall = { path = "../../syscall/" } -rustc-serialize = "0.3.19" +rustc-serialize = { git ="https://github.com/rust-lang-nursery/rustc-serialize.git" } toml = "*" + +[replace] +"rustc-serialize:0.3.19" = { git = "https://github.com/rust-lang-nursery/rustc-serialize.git" } From 8daf977c58f25958668970045d1780d54007b6d3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 3 Nov 2016 16:02:44 -0600 Subject: [PATCH 0078/1301] Fix eventing in kernel --- ahcid/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 3bc17ebcbf..0bad32239a 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -45,7 +45,9 @@ fn main() { let scheme = DiskScheme::new(ahci::disks(address)); loop { let mut event = Event::default(); - event_file.read(&mut event).expect("ahcid: failed to read event file"); + if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 { + break; + } if event.id == socket_fd { loop { let mut packet = Packet::default(); From 428e34f77d31d2a5a3232ca854e385b26e948f88 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 7 Nov 2016 20:46:34 -0700 Subject: [PATCH 0079/1301] Disable power management --- ahcid/src/ahci/hba.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index c27779e9ed..1981847e28 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -123,6 +123,13 @@ impl HbaPort { let serr = self.serr.read(); self.serr.write(serr); + // Disable power management + let sctl = self.sctl.read() ; + self.sctl.write(sctl | 7 << 8); + + // Power on and spin up device + self.cmd.writef(1 << 2 | 1 << 1, true); + print!("{}", format!(" - AHCI init {:X}\n", self.cmd.read())); } @@ -251,8 +258,7 @@ impl HbaPort { let cmdheader = &mut clb[slot as usize]; - cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); - cmdheader.cfl.writef(1 << 6, write); + cmdheader.cfl.write(((size_of::() / size_of::()) as u8) | if write { 1 << 7 | 1 << 6 } else { 0 }); cmdheader.prdtl.write(1); @@ -317,7 +323,11 @@ impl HbaPort { self.stop(); if self.is.read() & HBA_PORT_IS_ERR != 0 { - print!("{}", format!("ERROR IS {:X} TFD {:X} SERR {:X}\n", self.is.read(), self.tfd.read(), self.serr.read())); + print!("{}", format!("ERROR IS {:X} IE {:X} CMD {:X} TFD {:X}\nSSTS {:X} SCTL {:X} SERR {:X} SACT {:X}\nCI {:X} SNTF {:X} FBS {:X}\n", + self.is.read(), self.ie.read(), self.cmd.read(), self.tfd.read(), + self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(), + self.ci.read(), self.sntf.read(), self.fbs.read())); + self.is.write(u32::MAX); return Err(Error::new(EIO)); } From db37769a8b960c4b8ed8fe4bc046a108d52afef1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 9 Nov 2016 10:43:05 -0700 Subject: [PATCH 0080/1301] Update to use upstream libc and rand --- pcid/Cargo.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 67588f21b6..e1f0f78930 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -4,8 +4,5 @@ version = "0.1.0" [dependencies] redox_syscall = { path = "../../syscall/" } -rustc-serialize = { git ="https://github.com/rust-lang-nursery/rustc-serialize.git" } +rustc-serialize = "0.3" toml = "*" - -[replace] -"rustc-serialize:0.3.19" = { git = "https://github.com/rust-lang-nursery/rustc-serialize.git" } From 08557a7c133012376dc6dc578ae09aa94ed0ebef Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 9 Nov 2016 17:00:48 -0700 Subject: [PATCH 0081/1301] Fix build, remove cfg(redox) --- pcid/Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index e1f0f78930..132fc55039 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -4,5 +4,8 @@ version = "0.1.0" [dependencies] redox_syscall = { path = "../../syscall/" } -rustc-serialize = "0.3" +rustc-serialize = { git = "https://github.com/jackpot51/rustc-serialize.git" } toml = "*" + +[replace] +"rustc-serialize:0.3.20" = { git = "https://github.com/jackpot51/rustc-serialize.git" } From febfbfedb3bd64cbd5dc76a3c2409904af24b5f1 Mon Sep 17 00:00:00 2001 From: Waylon Cude Date: Thu, 10 Nov 2016 07:56:38 -0800 Subject: [PATCH 0082/1301] Added dvorak keymap (#752) Keymaps are passed as arguments to ps2d. To select the dvorak keymap use `ps2d dvorak`, otherwise the kymap will default to english. --- ps2d/src/keymap.rs | 210 ++++++++++++++++++++++++++++++--------------- ps2d/src/main.rs | 27 ++++-- 2 files changed, 162 insertions(+), 75 deletions(-) diff --git a/ps2d/src/keymap.rs b/ps2d/src/keymap.rs index 0f7f6341a9..5697e52543 100644 --- a/ps2d/src/keymap.rs +++ b/ps2d/src/keymap.rs @@ -1,72 +1,148 @@ -static ENGLISH: [[char; 2]; 58] = [ - ['\0', '\0'], - ['\x1B', '\x1B'], - ['1', '!'], - ['2', '@'], - ['3', '#'], - ['4', '$'], - ['5', '%'], - ['6', '^'], - ['7', '&'], - ['8', '*'], - ['9', '('], - ['0', ')'], - ['-', '_'], - ['=', '+'], - ['\x7F', '\x7F'], - ['\t', '\t'], - ['q', 'Q'], - ['w', 'W'], - ['e', 'E'], - ['r', 'R'], - ['t', 'T'], - ['y', 'Y'], - ['u', 'U'], - ['i', 'I'], - ['o', 'O'], - ['p', 'P'], - ['[', '{'], - [']', '}'], - ['\n', '\n'], - ['\0', '\0'], - ['a', 'A'], - ['s', 'S'], - ['d', 'D'], - ['f', 'F'], - ['g', 'G'], - ['h', 'H'], - ['j', 'J'], - ['k', 'K'], - ['l', 'L'], - [';', ':'], - ['\'', '"'], - ['`', '~'], - ['\0', '\0'], - ['\\', '|'], - ['z', 'Z'], - ['x', 'X'], - ['c', 'C'], - ['v', 'V'], - ['b', 'B'], - ['n', 'N'], - ['m', 'M'], - [',', '<'], - ['.', '>'], - ['/', '?'], - ['\0', '\0'], - ['\0', '\0'], - ['\0', '\0'], - [' ', ' '] -]; +pub mod english { + static ENGLISH: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['1', '!'], + ['2', '@'], + ['3', '#'], + ['4', '$'], + ['5', '%'], + ['6', '^'], + ['7', '&'], + ['8', '*'], + ['9', '('], + ['0', ')'], + ['-', '_'], + ['=', '+'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['q', 'Q'], + ['w', 'W'], + ['e', 'E'], + ['r', 'R'], + ['t', 'T'], + ['y', 'Y'], + ['u', 'U'], + ['i', 'I'], + ['o', 'O'], + ['p', 'P'], + ['[', '{'], + [']', '}'], + ['\n', '\n'], + ['\0', '\0'], + ['a', 'A'], + ['s', 'S'], + ['d', 'D'], + ['f', 'F'], + ['g', 'G'], + ['h', 'H'], + ['j', 'J'], + ['k', 'K'], + ['l', 'L'], + [';', ':'], + ['\'', '"'], + ['`', '~'], + ['\0', '\0'], + ['\\', '|'], + ['z', 'Z'], + ['x', 'X'], + ['c', 'C'], + ['v', 'V'], + ['b', 'B'], + ['n', 'N'], + ['m', 'M'], + [',', '<'], + ['.', '>'], + ['/', '?'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] + ]; -pub fn get_char(scancode: u8, shift: bool) -> char { - if let Some(c) = ENGLISH.get(scancode as usize) { - if shift { - c[1] + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = ENGLISH.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } } else { - c[0] + '\0' + } + } +} +pub mod dvorak { + static DVORAK: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['1', '!'], + ['2', '@'], + ['3', '#'], + ['4', '$'], + ['5', '%'], + ['6', '^'], + ['7', '&'], + ['8', '*'], + ['9', '('], + ['0', ')'], + ['[', '{'], + [']', '}'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['\'', '"'], + [',', '<'], + ['.', '>'], + ['p', 'P'], + ['y', 'Y'], + ['f', 'F'], + ['g', 'G'], + ['c', 'C'], + ['r', 'R'], + ['l', 'L'], + ['/', '?'], + ['=', '+'], + ['\n', '\n'], + ['\0', '\0'], + ['a', 'A'], + ['o', 'O'], + ['e', 'E'], + ['u', 'U'], + ['i', 'I'], + ['d', 'D'], + ['h', 'H'], + ['t', 'T'], + ['n', 'N'], + ['s', 'S'], + ['-', '_'], + ['`', '~'], + ['\0', '\0'], + ['\\', '|'], + [';', ':'], + ['q', 'Q'], + ['j', 'J'], + ['k', 'K'], + ['x', 'X'], + ['b', 'B'], + ['m', 'M'], + ['w', 'W'], + ['v', 'V'], + ['z', 'Z'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] + ]; + + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = DVORAK.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } + } else { + '\0' } - } else { - '\0' } } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 3a0615c5dd..8ff07331a6 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -7,6 +7,7 @@ extern crate io; extern crate orbclient; extern crate syscall; +use std::env; use std::fs::File; use std::io::{Read, Write, Result}; use std::os::unix::io::AsRawFd; @@ -32,24 +33,27 @@ bitflags! { } } -struct Ps2d { +struct Ps2d<'a> { input: File, lshift: bool, rshift: bool, packets: [u8; 4], packet_i: usize, - extra_packet: bool + extra_packet: bool, + //Keymap function + get_char: &'a Fn(u8,bool) -> char } -impl Ps2d { - fn new(input: File, extra_packet: bool) -> Self { +impl<'a> Ps2d<'a> { + fn new(input: File, extra_packet: bool, keymap: &'a Fn(u8,bool) -> char) -> Self { Ps2d { input: input, lshift: false, rshift: false, packets: [0; 4], packet_i: 0, - extra_packet: extra_packet + extra_packet: extra_packet, + get_char: keymap } } @@ -68,7 +72,7 @@ impl Ps2d { } self.input.write(&KeyEvent { - character: keymap::get_char(scancode, self.lshift || self.rshift), + character: (self.get_char)(scancode, self.lshift || self.rshift), scancode: scancode, pressed: pressed }.to_event()).expect("ps2d: failed to write key event"); @@ -128,8 +132,15 @@ fn main() { let input = File::open("display:input").expect("ps2d: failed to open display:input"); let extra_packet = controller::Ps2::new().init(); - - let mut ps2d = Ps2d::new(input, extra_packet); + let keymap = match env::args().skip(1).next() { + Some(k) => match k.to_lowercase().as_ref() { + "dvorak" => (keymap::dvorak::get_char), + "english" => (keymap::english::get_char), + &_ => (keymap::english::get_char) + }, + None => (keymap::english::get_char) + }; + let mut ps2d = Ps2d::new(input, extra_packet,&keymap); let mut event_queue = EventQueue::<(bool, u8)>::new().expect("ps2d: failed to create event queue"); From 60f880817f1903b968837e61969d869831ab1ba2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 10 Nov 2016 10:35:43 -0700 Subject: [PATCH 0083/1301] Invert on cursor --- vesad/src/display.rs | 32 ++++++++++++++++++++++++++++++++ vesad/src/screen/text.rs | 6 ++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index a21be24ab0..2d5f24e3c7 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -103,6 +103,38 @@ impl Display { } } + /// Invert a rectangle + pub fn invert(&mut self, x: usize, y: usize, w: usize, h: usize) { + let start_y = cmp::min(self.height - 1, y); + let end_y = cmp::min(self.height, y + h); + + let start_x = cmp::min(self.width - 1, x); + let len = cmp::min(self.width, x + w) - start_x; + + let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; + + let stride = self.width * 4; + + let offset = y * stride + start_x * 4; + offscreen_ptr += offset; + + let mut rows = end_y - start_y; + while rows > 0 { + let mut row_ptr = offscreen_ptr; + let mut cols = len; + while cols > 0 { + unsafe { + let color = *(row_ptr as *mut u32); + *(row_ptr as *mut u32) = !color; + } + row_ptr += 4; + cols -= 1; + } + offscreen_ptr += stride; + rows -= 1; + } + } + /// Draw a character #[cfg(not(feature="rusttype"))] pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) { diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 6d267d7e24..dbf79271eb 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -163,8 +163,7 @@ impl Screen for TextScreen { if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h { let x = self.console.x; let y = self.console.y; - let color = self.console.background; - self.display.rect(x * 8, y * 16, 8, 16, color.data); + self.display.invert(x * 8, y * 16, 8, 16); self.changed.insert(y); } @@ -196,8 +195,7 @@ impl Screen for TextScreen { if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h { let x = self.console.x; let y = self.console.y; - let color = self.console.foreground; - self.display.rect(x * 8, y * 16, 8, 16, color.data); + self.display.invert(x * 8, y * 16, 8, 16); self.changed.insert(y); } From 03abcd0e0ee46fea16e091fee93644a0f13d2870 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 10 Nov 2016 11:28:43 -0700 Subject: [PATCH 0084/1301] Update for new rustc-serialize --- pcid/Cargo.toml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 132fc55039..f09b85a3a5 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -4,8 +4,5 @@ version = "0.1.0" [dependencies] redox_syscall = { path = "../../syscall/" } -rustc-serialize = { git = "https://github.com/jackpot51/rustc-serialize.git" } -toml = "*" - -[replace] -"rustc-serialize:0.3.20" = { git = "https://github.com/jackpot51/rustc-serialize.git" } +rustc-serialize = "0.3" +toml = "0.2" From bac443482a390fba60c908fb1b0b46258058abf3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 10 Nov 2016 20:02:51 -0700 Subject: [PATCH 0085/1301] Switch to real standard, fix daemonization on real standard --- ahcid/src/main.rs | 7 ++++--- e1000d/src/main.rs | 7 ++++--- ps2d/src/main.rs | 7 ++++--- rtl8168d/src/main.rs | 7 ++++--- vesad/src/main.rs | 7 ++++--- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 0bad32239a..bd8f699a1a 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -7,7 +7,7 @@ extern crate io; extern crate spin; extern crate syscall; -use std::{env, thread, usize}; +use std::{env, usize}; use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd}; @@ -29,7 +29,8 @@ fn main() { print!("{}", format!(" + AHCI on: {:X} IRQ: {}\n", bar, irq)); - thread::spawn(move || { + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; { let socket_fd = syscall::open(":disk", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ahcid: failed to create disk scheme"); @@ -69,5 +70,5 @@ fn main() { } } unsafe { let _ = syscall::physunmap(address); } - }); + } } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index f3baf1bbaf..d199ff97a8 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -6,7 +6,7 @@ extern crate netutils; extern crate syscall; use std::cell::RefCell; -use std::{env, thread}; +use std::env; use std::fs::File; use std::io::{Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd}; @@ -29,7 +29,8 @@ fn main() { print!("{}", format!(" + E1000 on: {:X}, IRQ: {}\n", bar, irq)); - thread::spawn(move || { + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("e1000d: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); @@ -128,5 +129,5 @@ fn main() { } } unsafe { let _ = syscall::physunmap(address); } - }); + } } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 8ff07331a6..7c67bd3a2c 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -11,7 +11,7 @@ use std::env; use std::fs::File; use std::io::{Read, Write, Result}; use std::os::unix::io::AsRawFd; -use std::{mem, thread}; +use std::mem; use event::EventQueue; use orbclient::{KeyEvent, MouseEvent}; @@ -123,7 +123,8 @@ impl<'a> Ps2d<'a> { } fn main() { - thread::spawn(|| { + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { unsafe { iopl(3).expect("ps2d: failed to get I/O permission"); asm!("cli" : : : : "intel", "volatile"); @@ -188,5 +189,5 @@ fn main() { let (keyboard, data) = event_queue.run().expect("ps2d: failed to handle events"); ps2d.handle(keyboard, data); } - }); + } } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 00d6f33678..1198286124 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -7,7 +7,7 @@ extern crate netutils; extern crate syscall; use std::cell::RefCell; -use std::{env, thread}; +use std::env; use std::fs::File; use std::io::{Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd}; @@ -30,7 +30,8 @@ fn main() { print!("{}", format!(" + RTL8168 on: {:X}, IRQ: {}\n", bar, irq)); - thread::spawn(move || { + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("rtl8168d: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); @@ -133,5 +134,5 @@ fn main() { } } unsafe { let _ = syscall::physunmap(address); } - }); + } } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index b9defbf995..7f4347a1e1 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -6,7 +6,7 @@ extern crate alloc; extern crate orbclient; extern crate syscall; -use std::{env, mem, thread}; +use std::{env, mem}; use std::fs::File; use std::io::{Read, Write}; use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE}; @@ -49,7 +49,8 @@ fn main() { } if physbaseptr > 0 { - thread::spawn(move || { + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); let size = width * height; @@ -103,6 +104,6 @@ fn main() { } } } - }); + } } } From ccaf9636cff1f2dd74a1b89ca2ff923b79e7b160 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 15 Nov 2016 16:12:51 -0700 Subject: [PATCH 0086/1301] Update syscall and rust, add fcntl for permissions --- e1000d/Cargo.toml | 4 ++++ rtl8168d/Cargo.toml | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index ec8c45e1ab..dc0120893f 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -9,3 +9,7 @@ event = { path = "../../crates/event/" } io = { path = "../../crates/io/" } netutils = { path = "../../programs/netutils/" } redox_syscall = { path = "../../syscall/" } + +[replace] +"libc:0.2.17" = { git = "https://github.com/rust-lang/libc.git" } +"rand:0.3.14" = { git = "https://github.com/rust-lang-nursery/rand.git" } diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index e72a130458..dbc13b98d7 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -9,3 +9,7 @@ event = { path = "../../crates/event/" } io = { path = "../../crates/io/" } netutils = { path = "../../programs/netutils/" } redox_syscall = { path = "../../syscall/" } + +[replace] +"libc:0.2.17" = { git = "https://github.com/rust-lang/libc.git" } +"rand:0.3.14" = { git = "https://github.com/rust-lang-nursery/rand.git" } From aa5f12c3028827a7f8c9844764cabb6a4355e0c4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 20 Nov 2016 11:51:37 -0700 Subject: [PATCH 0087/1301] Fix printing of escape codes --- vesad/src/screen/text.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index dbf79271eb..704197a75f 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -124,6 +124,9 @@ impl Screen for TextScreen { let _ = self.write(b"\x08", true); } }, + b'\x1B' => { + let _ = self.write(b"^[", true); + }, b'\n' | b'\r' => { self.cooked.push_back(b); while let Some(c) = self.cooked.pop_front() { From 68a2fe57bcaaf4d75a65f9499a15cd198d1e844c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Nov 2016 12:23:17 -0700 Subject: [PATCH 0088/1301] WIP: Predictable naming --- ahcid/src/ahci/mod.rs | 4 ++-- ahcid/src/main.rs | 7 +++++-- e1000d/src/main.rs | 5 ++++- pcid/src/main.rs | 6 ++++++ rtl8168d/src/main.rs | 5 ++++- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index 90f334a097..fec9e0065f 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -7,7 +7,7 @@ pub mod disk; pub mod fis; pub mod hba; -pub fn disks(base: usize) -> Vec { +pub fn disks(base: usize, name: &str) -> Vec { unsafe { &mut *(base as *mut HbaMem) }.init(); let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); let ret: Vec = (0..32) @@ -15,7 +15,7 @@ pub fn disks(base: usize) -> Vec { .filter_map(|i| { let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i]; let port_type = port.probe(); - print!("{}", format!("{}: {:?}\n", i, port_type)); + print!("{}", format!("{}-{}: {:?}\n", name, i, port_type)); match port_type { HbaPortType::SATA => { match Disk::new(i, port) { diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index bd8f699a1a..1cd417c4b9 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -21,13 +21,16 @@ pub mod scheme; fn main() { let mut args = env::args().skip(1); + let mut name = args.next().expect("ahcid: no name provided"); + name.push_str("_ahci"); + let bar_str = args.next().expect("ahcid: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("ahcid: failed to parse address"); let irq_str = args.next().expect("ahcid: no irq provided"); let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); - print!("{}", format!(" + AHCI on: {:X} IRQ: {}\n", bar, irq)); + print!("{}", format!(" + AHCI {} on: {:X} IRQ: {}\n", name, bar, irq)); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { @@ -43,7 +46,7 @@ fn main() { let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); - let scheme = DiskScheme::new(ahci::disks(address)); + let scheme = DiskScheme::new(ahci::disks(address, &name)); loop { let mut event = Event::default(); if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 { diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index d199ff97a8..b690029c31 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -21,13 +21,16 @@ pub mod device; fn main() { let mut args = env::args().skip(1); + let mut name = args.next().expect("e1000d: no name provided"); + name.push_str("_e1000"); + let bar_str = args.next().expect("e1000d: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address"); let irq_str = args.next().expect("e1000d: no irq provided"); let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); - print!("{}", format!(" + E1000 on: {:X}, IRQ: {}\n", bar, irq)); + print!("{}", format!(" + E1000 {} on: {:X}, IRQ: {}\n", name, bar, irq)); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { diff --git a/pcid/src/main.rs b/pcid/src/main.rs index b732277084..8202d6fae8 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -125,6 +125,10 @@ fn main() { } }; let arg = match arg.as_str() { + "$BUS" => format!("{:>02X}", bus.num), + "$DEV" => format!("{:>02X}", dev.num), + "$FUNC" => format!("{:>02X}", func.num), + "$NAME" => format!("pci-{:>02X}.{:>02X}.{:>02X}", bus.num, dev.num, func.num), "$BAR0" => bar_arg(0), "$BAR1" => bar_arg(1), "$BAR2" => bar_arg(2), @@ -137,6 +141,8 @@ fn main() { command.arg(&arg); } + println!("PCID SPAWN {:?}", command); + match command.spawn() { Ok(mut child) => match child.wait() { Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()), diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 1198286124..46a1b86d6d 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -22,13 +22,16 @@ pub mod device; fn main() { let mut args = env::args().skip(1); + let mut name = args.next().expect("rtl8168d: no name provided"); + name.push_str("_rtl8168"); + let bar_str = args.next().expect("rtl8168d: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("rtl8168d: failed to parse address"); let irq_str = args.next().expect("rtl8168d: no irq provided"); let irq = irq_str.parse::().expect("rtl8168d: failed to parse irq"); - print!("{}", format!(" + RTL8168 on: {:X}, IRQ: {}\n", bar, irq)); + print!("{}", format!(" + RTL8168 {} on: {:X}, IRQ: {}\n", name, bar, irq)); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { From 3667c0ffd91fcee12214e3d048d43e4463223e83 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 22 Nov 2016 17:05:23 -0700 Subject: [PATCH 0089/1301] Use mmio, disable timer interrupt --- rtl8168d/src/device.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 923d888a15..7ed7d59521 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -28,7 +28,7 @@ struct Regs { cmd_9346: Mmio, _config: [Mmio; 6], _rsv4: Mmio, - _timer_int: Mmio, + timer_int: Mmio, _rsv5: Mmio, _phys_ar: Mmio, _rsv6: [Mmio; 2], @@ -67,11 +67,11 @@ struct Td { pub struct Rtl8168 { regs: &'static mut Regs, - receive_buffer: [Dma<[u8; 0x1FF8]>; 16], + receive_buffer: [Dma<[Mmio; 0x1FF8]>; 16], receive_ring: Dma<[Rd; 16]>, - transmit_buffer: [Dma<[u8; 7552]>; 16], + transmit_buffer: [Dma<[Mmio; 7552]>; 16], transmit_ring: Dma<[Td; 16]>, - transmit_buffer_h: [Dma<[u8; 7552]>; 1], + transmit_buffer_h: [Dma<[Mmio; 7552]>; 1], transmit_ring_h: Dma<[Td; 1]> } @@ -97,7 +97,7 @@ impl SchemeMut for Rtl8168 { let mut i = 0; while i < buf.len() && i < rd_len as usize { - buf[i] = data[i]; + buf[i] = data[i].read(); i += 1; } @@ -124,7 +124,7 @@ impl SchemeMut for Rtl8168 { let mut i = 0; while i < buf.len() && i < data.len() { - data[i] = buf[i]; + data[i].write(buf[i]); i += 1; } @@ -231,8 +231,8 @@ impl Rtl8168 { for i in 0..self.receive_ring.len() { let rd = &mut self.receive_ring[i]; let data = &mut self.receive_buffer[i]; - rd.ctrl.write(OWN | data.len() as u32); rd.buffer.write(data.physical() as u64); + rd.ctrl.write(OWN | data.len() as u32); } if let Some(mut rd) = self.receive_ring.last_mut() { rd.ctrl.writef(EOR, true); @@ -278,6 +278,9 @@ impl Rtl8168 { self.regs.rdsar[0].write(self.receive_ring.physical() as u32); self.regs.rdsar[1].write((self.receive_ring.physical() >> 32) as u32); + // Disable timer interrupt + self.regs.timer_int.write(0); + //Clear ISR let isr = self.regs.isr.read(); self.regs.isr.write(isr); From 159fdd0e7d55459dd79a86ce15aed50ff5e8cde0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 25 Nov 2016 17:01:19 -0700 Subject: [PATCH 0090/1301] Clean up cfg rusttype --- vesad/src/display.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 2d5f24e3c7..829d6ba98e 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -22,16 +22,6 @@ static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/Deja static FONT_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf"); /// A display -#[cfg(not(feature="rusttype"))] -pub struct Display { - pub width: usize, - pub height: usize, - pub onscreen: &'static mut [u32], - pub offscreen: &'static mut [u32] -} - -/// A display -#[cfg(feature="rusttype")] pub struct Display { pub width: usize, pub height: usize, From 4efc72b0a8143bda87957d4cae11d5a9c94cd748 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 27 Nov 2016 16:49:29 -0700 Subject: [PATCH 0091/1301] Remove rand replace --- e1000d/Cargo.toml | 1 - rtl8168d/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index dc0120893f..1c8431a89c 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -12,4 +12,3 @@ redox_syscall = { path = "../../syscall/" } [replace] "libc:0.2.17" = { git = "https://github.com/rust-lang/libc.git" } -"rand:0.3.14" = { git = "https://github.com/rust-lang-nursery/rand.git" } diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index dbc13b98d7..2672a5c2ec 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -12,4 +12,3 @@ redox_syscall = { path = "../../syscall/" } [replace] "libc:0.2.17" = { git = "https://github.com/rust-lang/libc.git" } -"rand:0.3.14" = { git = "https://github.com/rust-lang-nursery/rand.git" } From b7b861de84f8812331ab4c3e471aefa4b41af739 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 29 Nov 2016 21:25:45 -0700 Subject: [PATCH 0092/1301] Activate orbital screen on load --- vesad/src/scheme.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index a58e7fd112..e376bf7ad0 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -50,9 +50,15 @@ impl SchemeMut for DisplayScheme { Err(Error::new(EACCES)) } } else { - let path_str = str::from_utf8(path).unwrap_or(""); - let id = path_str.parse::().unwrap_or(0); + let path_str = str::from_utf8(path).unwrap_or("").trim_matches('/'); + let mut parts = path_str.split('/'); + let id = parts.next().unwrap_or("").parse::().unwrap_or(0); if self.screens.contains_key(&id) { + for cmd in parts { + if cmd == "activate" { + self.active = id; + } + } Ok(id) } else { Err(Error::new(ENOENT)) From a876a2925f7857a525eafff639a002da13260ef8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 6 Dec 2016 15:15:08 -0700 Subject: [PATCH 0093/1301] Remove replacement for libc --- e1000d/Cargo.toml | 3 --- rtl8168d/Cargo.toml | 3 --- 2 files changed, 6 deletions(-) diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 1c8431a89c..ec8c45e1ab 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -9,6 +9,3 @@ event = { path = "../../crates/event/" } io = { path = "../../crates/io/" } netutils = { path = "../../programs/netutils/" } redox_syscall = { path = "../../syscall/" } - -[replace] -"libc:0.2.17" = { git = "https://github.com/rust-lang/libc.git" } diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index 2672a5c2ec..e72a130458 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -9,6 +9,3 @@ event = { path = "../../crates/event/" } io = { path = "../../crates/io/" } netutils = { path = "../../programs/netutils/" } redox_syscall = { path = "../../syscall/" } - -[replace] -"libc:0.2.17" = { git = "https://github.com/rust-lang/libc.git" } From f3fa07ded971b001f25686098cf1d0afea1bf14c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 14 Dec 2016 08:34:45 -0700 Subject: [PATCH 0094/1301] Add BGA driver stub --- bgad/Cargo.toml | 3 +++ bgad/src/main.rs | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 bgad/Cargo.toml create mode 100644 bgad/src/main.rs diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml new file mode 100644 index 0000000000..cc9ce26988 --- /dev/null +++ b/bgad/Cargo.toml @@ -0,0 +1,3 @@ +[package] +name = "rtl8168d" +version = "0.1.0" diff --git a/bgad/src/main.rs b/bgad/src/main.rs new file mode 100644 index 0000000000..48d75d763d --- /dev/null +++ b/bgad/src/main.rs @@ -0,0 +1,13 @@ +use std::env; + +fn main() { + let mut args = env::args().skip(1); + + let mut name = args.next().expect("bgad: no name provided"); + name.push_str("_bga"); + + let bar_str = args.next().expect("bgad: no address provided"); + let bar = usize::from_str_radix(&bar_str, 16).expect("bgad: failed to parse address"); + + print!("{}", format!(" + BGA {} on: {:X}\n", name, bar)); +} From 04813e3e6eb01f98fb61bd35b715d1bca8412dc9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 17 Dec 2016 15:05:07 -0700 Subject: [PATCH 0095/1301] Update orbutils --- vesad/src/screen/text.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 704197a75f..ccc259d464 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -61,6 +61,9 @@ impl Screen for TextScreen { self.ctrl = key_event.pressed; } else if key_event.pressed { match key_event.scancode { + 0x0E => { // Backspace + buf.extend_from_slice(b"\x7F"); + }, 0x47 => { // Home buf.extend_from_slice(b"\x1B[H"); }, From 34708d4290144d7dd4c14ed826c62fa56c0e3dc3 Mon Sep 17 00:00:00 2001 From: xTibor Date: Wed, 28 Dec 2016 02:37:10 +0100 Subject: [PATCH 0096/1301] Fix vesad text rendering --- vesad/src/display.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 829d6ba98e..e9f29b559b 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -136,7 +136,7 @@ impl Display { for row in 0..16 { let row_data = FONT[font_i + row]; for col in 0..8 { - if (row_data >> (7 - col)) & 1 == 1 { + if (row_data >> (8 - col)) & 1 == 1 { unsafe { *((dst + col * 4) as *mut u32) = color; } } } From fd164153838a685119d79e6d377c912207a1af77 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 30 Dec 2016 21:30:24 -0700 Subject: [PATCH 0097/1301] Revert change that incorrectly overshifts char data --- vesad/src/display.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index e9f29b559b..829d6ba98e 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -136,7 +136,7 @@ impl Display { for row in 0..16 { let row_data = FONT[font_i + row]; for col in 0..8 { - if (row_data >> (8 - col)) & 1 == 1 { + if (row_data >> (7 - col)) & 1 == 1 { unsafe { *((dst + col * 4) as *mut u32) = color; } } } From cf46a3b5fca3f897c90eafff43aae45dd4495efd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 2 Jan 2017 08:53:50 -0700 Subject: [PATCH 0098/1301] Fallback in ahci driver when disk: not available, ability to list disk devices --- ahcid/src/ahci/disk.rs | 4 +- ahcid/src/ahci/hba.rs | 6 +- ahcid/src/main.rs | 15 ++++- ahcid/src/scheme.rs | 128 +++++++++++++++++++++++++++++------------ 4 files changed, 109 insertions(+), 44 deletions(-) diff --git a/ahcid/src/ahci/disk.rs b/ahcid/src/ahci/disk.rs index f28d5e83a8..4389425f5c 100644 --- a/ahcid/src/ahci/disk.rs +++ b/ahcid/src/ahci/disk.rs @@ -11,7 +11,7 @@ pub struct Disk { size: u64, clb: Dma<[HbaCmdHeader; 32]>, ctbas: [Dma; 32], - fb: Dma<[u8; 256]>, + _fb: Dma<[u8; 256]>, buf: Dma<[u8; 256 * 512]> } @@ -41,7 +41,7 @@ impl Disk { size: size, clb: clb, ctbas: ctbas, - fb: fb, + _fb: fb, buf: buf }) } diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 1981847e28..d22b7063a6 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -389,7 +389,7 @@ pub struct HbaCmdTable { cfis: [Mmio; 64], // Command FIS // 0x40 - acmd: [Mmio; 16], // ATAPI command, 12 or 16 bytes + _acmd: [Mmio; 16], // ATAPI command, 12 or 16 bytes // 0x50 _rsv: [Mmio; 48], // Reserved @@ -402,12 +402,12 @@ pub struct HbaCmdTable { pub struct HbaCmdHeader { // DW0 cfl: Mmio, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */ - pm: Mmio, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier + _pm: Mmio, // Reset - 0x80, bist: 0x40, clear busy on ok: 0x20, port multiplier prdtl: Mmio, // Physical region descriptor table length in entries // DW1 - prdbc: Mmio, // Physical region descriptor byte count transferred + _prdbc: Mmio, // Physical region descriptor byte count transferred // DW2, 3 ctba: Mmio, // Command table descriptor base address diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 1cd417c4b9..4e8cbc98bd 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -10,14 +10,23 @@ extern crate syscall; use std::{env, usize}; use std::fs::File; use std::io::{Read, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd}; -use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Result, Scheme}; use scheme::DiskScheme; pub mod ahci; pub mod scheme; +fn create_scheme_fallback<'a>(name: &'a str, fallback: &'a str) -> Result<(&'a str, RawFd)> { + if let Ok(fd) = syscall::open(&format!(":{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) { + Ok((name, fd)) + } else { + syscall::open(&format!(":{}", fallback), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) + .map(|fd| (fallback, fd)) + } +} + fn main() { let mut args = env::args().skip(1); @@ -36,7 +45,7 @@ fn main() { if unsafe { syscall::clone(0).unwrap() } == 0 { let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; { - let socket_fd = syscall::open(":disk", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ahcid: failed to create disk scheme"); + let (_scheme_name, socket_fd) = create_scheme_fallback("disk", &name).expect("ahcid: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd) }; syscall::fevent(socket_fd, EVENT_READ).expect("ahcid: failed to fevent disk scheme"); diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 96a7c20732..cd35d76dc8 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -1,15 +1,24 @@ use std::collections::BTreeMap; use std::{cmp, str}; +use std::fmt::Write; +use std::io::Read; use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering}; use spin::Mutex; -use syscall::{Error, EACCES, EBADF, EINVAL, ENOENT, Result, Scheme, Stat, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET}; +use syscall::{Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, Result, Scheme, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; use ahci::disk::Disk; +#[derive(Clone)] +enum Handle { + //TODO: Make these enum variants normal tuples (), not nested tuples (()) + List((Vec, usize)), + Disk((Arc>, usize)) +} + pub struct DiskScheme { disks: Box<[Arc>]>, - handles: Mutex>, usize)>>, + handles: Mutex>, next_id: AtomicUsize } @@ -29,18 +38,33 @@ impl DiskScheme { } impl Scheme for DiskScheme { - fn open(&self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { + fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if uid == 0 { - let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?; + let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_matches('/'); + if path_str.is_empty() { + if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { + let mut list = String::new(); - let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; + for i in 0..self.disks.len() { + write!(list, "{}\n", i).unwrap(); + } - if let Some(disk) = self.disks.get(i) { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, (disk.clone(), 0)); - Ok(id) + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, Handle::List((list.into_bytes(), 0))); + Ok(id) + } else { + Err(Error::new(EISDIR)) + } } else { - Err(Error::new(ENOENT)) + let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; + + if let Some(disk) = self.disks.get(i) { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, Handle::Disk((disk.clone(), 0))); + Ok(id) + } else { + Err(Error::new(ENOENT)) + } } } else { Err(Error::new(EACCES)) @@ -61,46 +85,78 @@ impl Scheme for DiskScheme { fn fstat(&self, id: usize, stat: &mut Stat) -> Result { let handles = self.handles.lock(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; - - stat.st_mode = MODE_FILE; - stat.st_size = handle.0.lock().size(); - Ok(0) + match *handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref handle) => { + stat.st_mode = MODE_DIR; + stat.st_size = handle.0.len() as u64; + Ok(0) + }, + Handle::Disk(ref handle) => { + stat.st_mode = MODE_FILE; + stat.st_size = handle.0.lock().size(); + Ok(0) + } + } } fn read(&self, id: usize, buf: &mut [u8]) -> Result { let mut handles = self.handles.lock(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let mut disk = handle.0.lock(); - let count = disk.read((handle.1 as u64)/512, buf)?; - handle.1 += count; - Ok(count) + match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref mut handle) => { + let count = (&handle.0[handle.1..]).read(buf).unwrap(); + handle.1 += count; + Ok(count) + }, + Handle::Disk(ref mut handle) => { + let mut disk = handle.0.lock(); + let count = disk.read((handle.1 as u64)/512, buf)?; + handle.1 += count; + Ok(count) + } + } } fn write(&self, id: usize, buf: &[u8]) -> Result { let mut handles = self.handles.lock(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let mut disk = handle.0.lock(); - let count = disk.write((handle.1 as u64)/512, buf)?; - handle.1 += count; - Ok(count) + match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(_) => { + Err(Error::new(EBADF)) + }, + Handle::Disk(ref mut handle) => { + let mut disk = handle.0.lock(); + let count = disk.write((handle.1 as u64)/512, buf)?; + handle.1 += count; + Ok(count) + } + } } fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { let mut handles = self.handles.lock(); - let mut handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref mut handle) => { + let len = handle.0.len() as usize; + handle.1 = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; - let len = handle.0.lock().size() as usize; - handle.1 = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; + Ok(handle.1) + }, + Handle::Disk(ref mut handle) => { + let len = handle.0.lock().size() as usize; + handle.1 = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; - Ok(handle.1) + Ok(handle.1) + } + } } fn close(&self, id: usize) -> Result { From 50d7e630f74f22a372597db33186a61f06e36a4b Mon Sep 17 00:00:00 2001 From: Martin Lindhe Date: Tue, 3 Jan 2017 13:14:37 +0100 Subject: [PATCH 0099/1301] fix some typos --- e1000d/src/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index fe2df0164f..8cb46f31d5 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -338,7 +338,7 @@ impl Intel8254x { self.flag(TCTL, TCTL_EN, true); self.flag(TCTL, TCTL_PSP, true); - // TCTL.CT = Collition threshold + // TCTL.CT = Collision threshold // TCTL.COLD = Collision distance // TIPG Packet Gap // TODO ... From 184539c133f9940fe197064197044ba8eefe2f0f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 4 Jan 2017 16:25:55 -0700 Subject: [PATCH 0100/1301] Fix name of bgad --- bgad/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml index cc9ce26988..c763e3206f 100644 --- a/bgad/Cargo.toml +++ b/bgad/Cargo.toml @@ -1,3 +1,3 @@ [package] -name = "rtl8168d" +name = "bgad" version = "0.1.0" From 9eeade88606095a03ee3c285972b45d1c499a971 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 4 Jan 2017 16:46:18 -0700 Subject: [PATCH 0101/1301] Cleanup dependencies --- ps2d/Cargo.toml | 2 +- vesad/Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 98ebbf218f..22863b9ea2 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -6,5 +6,5 @@ version = "0.1.0" bitflags = "*" event = { path = "../../crates/event/" } io = { path = "../../crates/io/" } -orbclient = "0.1" +orbclient = "0.2" redox_syscall = { path = "../../syscall/" } diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 9041edb43b..a70dbf0d76 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -3,9 +3,9 @@ name = "vesad" version = "0.1.0" [dependencies] -orbclient = "0.1" +orbclient = "0.2" ransid = "0.2" -rusttype = { git = "https://github.com/dylanede/rusttype.git", optional = true } +rusttype = { version = "0.2", optional = true } redox_syscall = { path = "../../syscall" } [features] From 608403765d1d290045ddc14d10c6f5442cb2452d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 9 Jan 2017 20:36:36 -0700 Subject: [PATCH 0102/1301] Refactor to move io into syscall, and use git for crate references --- ahcid/Cargo.toml | 4 +--- ahcid/src/ahci/disk.rs | 2 +- ahcid/src/ahci/fis.rs | 2 +- ahcid/src/ahci/hba.rs | 3 +-- ahcid/src/ahci/mod.rs | 2 +- ahcid/src/main.rs | 3 +-- bgad/src/main.rs | 2 ++ e1000d/Cargo.toml | 8 +++----- e1000d/src/device.rs | 2 +- e1000d/src/main.rs | 1 - pcid/Cargo.toml | 2 +- pcid/src/main.rs | 1 + ps2d/Cargo.toml | 5 ++--- ps2d/src/controller.rs | 2 +- ps2d/src/main.rs | 2 +- rtl8168d/Cargo.toml | 8 +++----- rtl8168d/src/device.rs | 3 +-- rtl8168d/src/main.rs | 2 -- vesad/Cargo.toml | 2 +- vesad/src/main.rs | 1 + vesad/src/screen/text.rs | 2 +- 21 files changed, 25 insertions(+), 34 deletions(-) diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index f7183317cb..ddd3fe1084 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -4,7 +4,5 @@ version = "0.1.0" [dependencies] bitflags = "*" -dma = { path = "../../crates/dma/" } -io = { path = "../../crates/io/" } spin = "*" -redox_syscall = { path = "../../syscall/" } +redox_syscall = { git = "https://github.com/redox-os/syscall.git" } diff --git a/ahcid/src/ahci/disk.rs b/ahcid/src/ahci/disk.rs index 4389425f5c..52170af710 100644 --- a/ahcid/src/ahci/disk.rs +++ b/ahcid/src/ahci/disk.rs @@ -1,6 +1,6 @@ use std::ptr; -use dma::Dma; +use syscall::io::Dma; use syscall::error::Result; use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; diff --git a/ahcid/src/ahci/fis.rs b/ahcid/src/ahci/fis.rs index 7dbe33c179..e91e4229e2 100644 --- a/ahcid/src/ahci/fis.rs +++ b/ahcid/src/ahci/fis.rs @@ -1,4 +1,4 @@ -use io::Mmio; +use syscall::io::Mmio; #[repr(u8)] pub enum FisType { diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index d22b7063a6..f294f14b0e 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -2,8 +2,7 @@ use std::mem::size_of; use std::ops::DerefMut; use std::{ptr, u32}; -use dma::Dma; -use io::{Io, Mmio}; +use syscall::io::{Dma, Io, Mmio}; use syscall::error::{Error, Result, EIO}; use super::fis::{FisType, FisRegH2D}; diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index fec9e0065f..072be72025 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -1,4 +1,4 @@ -use io::Io; +use syscall::io::Io; use self::disk::Disk; use self::hba::{HbaMem, HbaPortType}; diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 4e8cbc98bd..0c960a22b6 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -1,9 +1,8 @@ +#![deny(warnings)] #![feature(asm)] #[macro_use] extern crate bitflags; -extern crate dma; -extern crate io; extern crate spin; extern crate syscall; diff --git a/bgad/src/main.rs b/bgad/src/main.rs index 48d75d763d..7475aaac46 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -1,3 +1,5 @@ +#![deny(warnings)] + use std::env; fn main() { diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index ec8c45e1ab..088fda764e 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -4,8 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "*" -dma = { path = "../../crates/dma/" } -event = { path = "../../crates/event/" } -io = { path = "../../crates/io/" } -netutils = { path = "../../programs/netutils/" } -redox_syscall = { path = "../../syscall/" } +netutils = { git = "https://github.com/redox-os/netutils.git" } +redox_event = { git = "https://github.com/redox-os/event.git" } +redox_syscall = { git = "https://github.com/redox-os/syscall.git" } diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 8cb46f31d5..76884e5ae1 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,9 +1,9 @@ use std::{cmp, mem, ptr, slice}; -use dma::Dma; use netutils::setcfg; use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; use syscall::flag::O_NONBLOCK; +use syscall::io::Dma; use syscall::scheme::Scheme; const CTRL: u32 = 0x00; diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index b690029c31..0d59ed52b7 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -1,6 +1,5 @@ #![feature(asm)] -extern crate dma; extern crate event; extern crate netutils; extern crate syscall; diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index f09b85a3a5..9e1965ceff 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -3,6 +3,6 @@ name = "pcid" version = "0.1.0" [dependencies] -redox_syscall = { path = "../../syscall/" } +redox_syscall = { git = "https://github.com/redox-os/syscall.git" } rustc-serialize = "0.3" toml = "0.2" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 8202d6fae8..935a8f1c02 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,3 +1,4 @@ +#![deny(warnings)] #![feature(asm)] extern crate rustc_serialize; diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 22863b9ea2..3ccf4860be 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -4,7 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "*" -event = { path = "../../crates/event/" } -io = { path = "../../crates/io/" } orbclient = "0.2" -redox_syscall = { path = "../../syscall/" } +redox_event = { git = "https://github.com/redox-os/event.git" } +redox_syscall = { git = "https://github.com/redox-os/syscall.git" } diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index e68d4f13ec..29738b5a66 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -1,4 +1,4 @@ -use io::{Io, Pio, ReadOnly, WriteOnly}; +use syscall::io::{Io, Pio, ReadOnly, WriteOnly}; bitflags! { flags StatusFlags: u8 { diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 7c67bd3a2c..66e5d29754 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -1,9 +1,9 @@ +#![deny(warnings)] #![feature(asm)] #[macro_use] extern crate bitflags; extern crate event; -extern crate io; extern crate orbclient; extern crate syscall; diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index e72a130458..30846b0ba2 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -4,8 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "*" -dma = { path = "../../crates/dma/" } -event = { path = "../../crates/event/" } -io = { path = "../../crates/io/" } -netutils = { path = "../../programs/netutils/" } -redox_syscall = { path = "../../syscall/" } +netutils = { git = "https://github.com/redox-os/netutils.git" } +redox_event = { git = "https://github.com/redox-os/event.git" } +redox_syscall = { git = "https://github.com/redox-os/syscall.git" } diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 7ed7d59521..1f09f8372c 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -1,10 +1,9 @@ use std::mem; -use dma::Dma; -use io::{Mmio, Io, ReadOnly}; use netutils::setcfg; use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; use syscall::flag::O_NONBLOCK; +use syscall::io::{Dma, Mmio, Io, ReadOnly}; use syscall::scheme::SchemeMut; #[repr(packed)] diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 46a1b86d6d..27ba048aa7 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -1,8 +1,6 @@ #![feature(asm)] -extern crate dma; extern crate event; -extern crate io; extern crate netutils; extern crate syscall; diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index a70dbf0d76..88acd5b284 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" orbclient = "0.2" ransid = "0.2" rusttype = { version = "0.2", optional = true } -redox_syscall = { path = "../../syscall" } +redox_syscall = { git = "https://github.com/redox-os/syscall.git" } [features] default = [] diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 7f4347a1e1..337f6a560b 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -1,3 +1,4 @@ +#![deny(warnings)] #![feature(alloc)] #![feature(asm)] #![feature(heap_api)] diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index ccc259d464..1ede48ebc0 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -48,7 +48,7 @@ impl Screen for TextScreen { Ok(0) } - fn map(&self, offset: usize, size: usize) -> Result { + fn map(&self, _offset: usize, _size: usize) -> Result { Err(Error::new(EBADF)) } From cc299464fc11e01649ad8a09b127397e68901b77 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 9 Jan 2017 21:20:58 -0700 Subject: [PATCH 0103/1301] Use orbclient font --- vesad/src/display.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 829d6ba98e..e8b7eb0e84 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -10,7 +10,7 @@ use primitive::{fast_set32, fast_set64, fast_copy, fast_copy64}; use self::rusttype::{Font, FontCollection, Scale, point}; #[cfg(not(feature="rusttype"))] -static FONT: &'static [u8] = include_bytes!("../../../res/fonts/unifont.font"); +use orbclient::FONT; #[cfg(feature="rusttype")] static FONT: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono.ttf"); From 778852f92d835c17327819bde28c19db8096a4b1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 10 Jan 2017 20:48:59 -0700 Subject: [PATCH 0104/1301] WIP: XHCI --- xhcid/Cargo.toml | 8 +++++ xhcid/src/main.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 xhcid/Cargo.toml create mode 100644 xhcid/src/main.rs diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml new file mode 100644 index 0000000000..f411d57c42 --- /dev/null +++ b/xhcid/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "xhcid" +version = "0.1.0" + +[dependencies] +bitflags = "*" +spin = "*" +redox_syscall = { git = "https://github.com/redox-os/syscall.git" } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs new file mode 100644 index 0000000000..fb94771704 --- /dev/null +++ b/xhcid/src/main.rs @@ -0,0 +1,80 @@ +extern crate syscall; + +use std::{env, slice}; +use syscall::io::{Mmio, Io}; + +#[repr(packed)] +pub struct XhciCap { + len: Mmio, + _rsvd: Mmio, + hci_ver: Mmio, + hcs_params1: Mmio, + hcs_params2: Mmio, + hcs_params3: Mmio, + hcc_params1: Mmio, + db_offset: Mmio, + rts_offset: Mmio, + hcc_params2: Mmio +} + +#[repr(packed)] +pub struct XhciOp { + usb_cmd: Mmio, + usb_std: Mmio, + page_size: Mmio, + _rsvd: [Mmio; 2], + dn_ctrl: Mmio, + crcr: [Mmio; 2], + _rsvd2: [Mmio; 4], + dcbaap: [Mmio; 2], + config: Mmio, +} + +pub struct Xhci { + cap: &'static mut XhciCap, + op: &'static mut XhciOp, + ports: &'static mut [Mmio] +} + +impl Xhci { + pub fn new(address: usize) -> Xhci { + let cap = unsafe { &mut *(address as *mut XhciCap) }; + + let op_base = address + cap.len.read() as usize; + let op = unsafe { &mut *(op_base as *mut XhciOp) }; + + let port_base = op_base + 0x400; + let port_len = ((cap.hcs_params1.read() & 0xFF000000) >> 24) as usize; + let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut Mmio, port_len) }; + + Xhci { + cap: cap, + op: op, + ports: ports + } + } +} + +fn main() { + let mut args = env::args().skip(1); + + let mut name = args.next().expect("xhcid: no name provided"); + name.push_str("_xhci"); + + let bar_str = args.next().expect("xhcid: no address provided"); + let bar = usize::from_str_radix(&bar_str, 16).expect("xhcid: failed to parse address"); + + print!("{}", format!(" + XHCI {} on: {:X}\n", name, bar)); + + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + let address = unsafe { syscall::physmap(bar, 4096, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; + { + let mut xhci = Xhci::new(address); + for (i, port) in xhci.ports.iter().enumerate() { + println!("XHCI Port {}: {:X}", i, port.read()); + } + } + unsafe { let _ = syscall::physunmap(address); } + } +} From 4bb229959e7c662a0686c7986f5ad28c8fb4de12 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 13 Jan 2017 15:10:16 -0700 Subject: [PATCH 0105/1301] Specify crates.io versions --- ahcid/Cargo.toml | 6 +++--- e1000d/Cargo.toml | 4 ++-- pcid/Cargo.toml | 2 +- ps2d/Cargo.toml | 4 ++-- rtl8168d/Cargo.toml | 4 ++-- vesad/Cargo.toml | 2 +- xhcid/Cargo.toml | 6 +++--- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index ddd3fe1084..b881ce614b 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -3,6 +3,6 @@ name = "ahcid" version = "0.1.0" [dependencies] -bitflags = "*" -spin = "*" -redox_syscall = { git = "https://github.com/redox-os/syscall.git" } +bitflags = "0.7" +spin = "0.4" +redox_syscall = "0.1" diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 088fda764e..45f71f1576 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -3,7 +3,7 @@ name = "e1000d" version = "0.1.0" [dependencies] -bitflags = "*" +bitflags = "0.7" netutils = { git = "https://github.com/redox-os/netutils.git" } redox_event = { git = "https://github.com/redox-os/event.git" } -redox_syscall = { git = "https://github.com/redox-os/syscall.git" } +redox_syscall = "0.1" diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 9e1965ceff..9c0cf530c2 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -3,6 +3,6 @@ name = "pcid" version = "0.1.0" [dependencies] -redox_syscall = { git = "https://github.com/redox-os/syscall.git" } +redox_syscall = "0.1" rustc-serialize = "0.3" toml = "0.2" diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 3ccf4860be..8c534763b3 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -3,7 +3,7 @@ name = "ps2d" version = "0.1.0" [dependencies] -bitflags = "*" +bitflags = "0.7" orbclient = "0.2" redox_event = { git = "https://github.com/redox-os/event.git" } -redox_syscall = { git = "https://github.com/redox-os/syscall.git" } +redox_syscall = "0.1" diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index 30846b0ba2..13bb96f689 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -3,7 +3,7 @@ name = "rtl8168d" version = "0.1.0" [dependencies] -bitflags = "*" +bitflags = "0.7" netutils = { git = "https://github.com/redox-os/netutils.git" } redox_event = { git = "https://github.com/redox-os/event.git" } -redox_syscall = { git = "https://github.com/redox-os/syscall.git" } +redox_syscall = "0.1" diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 88acd5b284..c4a9cb7144 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -6,7 +6,7 @@ version = "0.1.0" orbclient = "0.2" ransid = "0.2" rusttype = { version = "0.2", optional = true } -redox_syscall = { git = "https://github.com/redox-os/syscall.git" } +redox_syscall = "0.1" [features] default = [] diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index f411d57c42..a5f5e61a27 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -3,6 +3,6 @@ name = "xhcid" version = "0.1.0" [dependencies] -bitflags = "*" -spin = "*" -redox_syscall = { git = "https://github.com/redox-os/syscall.git" } +bitflags = "0.7" +spin = "0.4" +redox_syscall = "0.1" From d8a35a9a08397421ed7ad588241fee94444465a9 Mon Sep 17 00:00:00 2001 From: Corentin Henry Date: Tue, 24 Jan 2017 11:04:52 -0800 Subject: [PATCH 0106/1301] remove unused #[macro_use] --- ahcid/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 0c960a22b6..19a37a8250 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -1,7 +1,6 @@ #![deny(warnings)] #![feature(asm)] -#[macro_use] extern crate bitflags; extern crate spin; extern crate syscall; From bd146da9bcc96ccdb94d61163de83f31b21c0b4e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 7 Feb 2017 20:53:41 -0700 Subject: [PATCH 0107/1301] Better errors when display not found --- ps2d/src/main.rs | 140 +++++++++++++++++++++++++---------------------- 1 file changed, 75 insertions(+), 65 deletions(-) diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 66e5d29754..46291b2f28 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -7,7 +7,7 @@ extern crate event; extern crate orbclient; extern crate syscall; -use std::env; +use std::{env, process}; use std::fs::File; use std::io::{Read, Write, Result}; use std::os::unix::io::AsRawFd; @@ -122,72 +122,82 @@ impl<'a> Ps2d<'a> { } } +fn daemon(input: File) { + unsafe { + iopl(3).expect("ps2d: failed to get I/O permission"); + asm!("cli" : : : : "intel", "volatile"); + } + + let extra_packet = controller::Ps2::new().init(); + let keymap = match env::args().skip(1).next() { + Some(k) => match k.to_lowercase().as_ref() { + "dvorak" => (keymap::dvorak::get_char), + "english" => (keymap::english::get_char), + &_ => (keymap::english::get_char) + }, + None => (keymap::english::get_char) + }; + let mut ps2d = Ps2d::new(input, extra_packet,&keymap); + + let mut event_queue = EventQueue::<(bool, u8)>::new().expect("ps2d: failed to create event queue"); + + let mut key_irq = File::open("irq:1").expect("ps2d: failed to open irq:1"); + + event_queue.add(key_irq.as_raw_fd(), move |_count: usize| -> Result> { + let mut irq = [0; 8]; + if key_irq.read(&mut irq)? >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + key_irq.write(&irq)?; + + Ok(Some((true, data))) + } else { + Ok(None) + } + }).expect("ps2d: failed to poll irq:1"); + + let mut mouse_irq = File::open("irq:12").expect("ps2d: failed to open irq:12"); + + event_queue.add(mouse_irq.as_raw_fd(), move |_count: usize| -> Result> { + let mut irq = [0; 8]; + if mouse_irq.read(&mut irq)? >= mem::size_of::() { + let data: u8; + unsafe { + asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); + } + + mouse_irq.write(&irq)?; + + Ok(Some((false, data))) + } else { + Ok(None) + } + }).expect("ps2d: failed to poll irq:12"); + + for (keyboard, data) in event_queue.trigger_all(0).expect("ps2d: failed to trigger events") { + ps2d.handle(keyboard, data); + } + + loop { + let (keyboard, data) = event_queue.run().expect("ps2d: failed to handle events"); + ps2d.handle(keyboard, data); + } +} + fn main() { - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - unsafe { - iopl(3).expect("ps2d: failed to get I/O permission"); - asm!("cli" : : : : "intel", "volatile"); - } - - let input = File::open("display:input").expect("ps2d: failed to open display:input"); - - let extra_packet = controller::Ps2::new().init(); - let keymap = match env::args().skip(1).next() { - Some(k) => match k.to_lowercase().as_ref() { - "dvorak" => (keymap::dvorak::get_char), - "english" => (keymap::english::get_char), - &_ => (keymap::english::get_char) - }, - None => (keymap::english::get_char) - }; - let mut ps2d = Ps2d::new(input, extra_packet,&keymap); - - let mut event_queue = EventQueue::<(bool, u8)>::new().expect("ps2d: failed to create event queue"); - - let mut key_irq = File::open("irq:1").expect("ps2d: failed to open irq:1"); - - event_queue.add(key_irq.as_raw_fd(), move |_count: usize| -> Result> { - let mut irq = [0; 8]; - if key_irq.read(&mut irq)? >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - key_irq.write(&irq)?; - - Ok(Some((true, data))) - } else { - Ok(None) + match File::open("display:input") { + Ok(input) => { + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + daemon(input); } - }).expect("ps2d: failed to poll irq:1"); - - let mut mouse_irq = File::open("irq:12").expect("ps2d: failed to open irq:12"); - - event_queue.add(mouse_irq.as_raw_fd(), move |_count: usize| -> Result> { - let mut irq = [0; 8]; - if mouse_irq.read(&mut irq)? >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - - mouse_irq.write(&irq)?; - - Ok(Some((false, data))) - } else { - Ok(None) - } - }).expect("ps2d: failed to poll irq:12"); - - for (keyboard, data) in event_queue.trigger_all(0).expect("ps2d: failed to trigger events") { - ps2d.handle(keyboard, data); - } - - loop { - let (keyboard, data) = event_queue.run().expect("ps2d: failed to handle events"); - ps2d.handle(keyboard, data); + }, + Err(err) => { + println!("ps2d: failed to open display: {}", err); + process::exit(1); } } } From 5b223c06d0bcd4c936bad3ad6ec8324fd0ba16a6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 13 Feb 2017 22:15:19 -0700 Subject: [PATCH 0108/1301] Improve XHCI driver --- pcid/src/main.rs | 2 +- xhcid/src/main.rs | 67 +++----------- xhcid/src/xhci.rs | 220 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+), 57 deletions(-) create mode 100644 xhcid/src/xhci.rs diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 935a8f1c02..0ef7c58666 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -142,7 +142,7 @@ fn main() { command.arg(&arg); } - println!("PCID SPAWN {:?}", command); + //println!("PCID SPAWN {:?}", command); match command.spawn() { Ok(mut child) => match child.wait() { diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index fb94771704..fe4a064962 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -1,59 +1,12 @@ +#[macro_use] +extern crate bitflags; extern crate syscall; -use std::{env, slice}; -use syscall::io::{Mmio, Io}; +use std::env; -#[repr(packed)] -pub struct XhciCap { - len: Mmio, - _rsvd: Mmio, - hci_ver: Mmio, - hcs_params1: Mmio, - hcs_params2: Mmio, - hcs_params3: Mmio, - hcc_params1: Mmio, - db_offset: Mmio, - rts_offset: Mmio, - hcc_params2: Mmio -} +use xhci::Xhci; -#[repr(packed)] -pub struct XhciOp { - usb_cmd: Mmio, - usb_std: Mmio, - page_size: Mmio, - _rsvd: [Mmio; 2], - dn_ctrl: Mmio, - crcr: [Mmio; 2], - _rsvd2: [Mmio; 4], - dcbaap: [Mmio; 2], - config: Mmio, -} - -pub struct Xhci { - cap: &'static mut XhciCap, - op: &'static mut XhciOp, - ports: &'static mut [Mmio] -} - -impl Xhci { - pub fn new(address: usize) -> Xhci { - let cap = unsafe { &mut *(address as *mut XhciCap) }; - - let op_base = address + cap.len.read() as usize; - let op = unsafe { &mut *(op_base as *mut XhciOp) }; - - let port_base = op_base + 0x400; - let port_len = ((cap.hcs_params1.read() & 0xFF000000) >> 24) as usize; - let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut Mmio, port_len) }; - - Xhci { - cap: cap, - op: op, - ports: ports - } - } -} +mod xhci; fn main() { let mut args = env::args().skip(1); @@ -69,10 +22,12 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { let address = unsafe { syscall::physmap(bar, 4096, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; - { - let mut xhci = Xhci::new(address); - for (i, port) in xhci.ports.iter().enumerate() { - println!("XHCI Port {}: {:X}", i, port.read()); + match Xhci::new(address) { + Ok(mut xhci) => { + xhci.init(); + }, + Err(err) => { + println!("xhcid: error: {}", err); } } unsafe { let _ = syscall::physunmap(address); } diff --git a/xhcid/src/xhci.rs b/xhcid/src/xhci.rs new file mode 100644 index 0000000000..afd78e5eaf --- /dev/null +++ b/xhcid/src/xhci.rs @@ -0,0 +1,220 @@ +use std::slice; +use syscall::error::Result; +use syscall::io::{Dma, Mmio, Io}; + +#[repr(packed)] +struct Trb { + pub data: u64, + pub status: u32, + pub control: u32, +} + +impl Trb { + pub fn from_type(trb_type: u32) -> Self { + Trb { + data: 0, + status: 0, + control: (trb_type & 0x3F) << 10, + } + } +} + +#[repr(packed)] +pub struct XhciCap { + len: Mmio, + _rsvd: Mmio, + hci_ver: Mmio, + hcs_params1: Mmio, + hcs_params2: Mmio, + hcs_params3: Mmio, + hcc_params1: Mmio, + db_offset: Mmio, + rts_offset: Mmio, + hcc_params2: Mmio +} + +#[repr(packed)] +pub struct XhciOp { + usb_cmd: Mmio, + usb_sts: Mmio, + page_size: Mmio, + _rsvd: [Mmio; 2], + dn_ctrl: Mmio, + crcr: Mmio, + _rsvd2: [Mmio; 4], + dcbaap: Mmio, + config: Mmio, +} + +bitflags! { + flags XhciPortFlags: u32 { + const PORT_CCS = 1 << 0, + const PORT_PED = 1 << 1, + const PORT_OCA = 1 << 3, + const PORT_PR = 1 << 4, + const PORT_PP = 1 << 9, + const PORT_PIC_AMB = 1 << 14, + const PORT_PIC_GRN = 1 << 15, + const PORT_LWS = 1 << 16, + const PORT_CSC = 1 << 17, + const PORT_PEC = 1 << 18, + const PORT_WRC = 1 << 19, + const PORT_OCC = 1 << 20, + const PORT_PRC = 1 << 21, + const PORT_PLC = 1 << 22, + const PORT_CEC = 1 << 23, + const PORT_CAS = 1 << 24, + const PORT_WCE = 1 << 25, + const PORT_WDE = 1 << 26, + const PORT_WOE = 1 << 27, + const PORT_DR = 1 << 30, + const PORT_WPR = 1 << 31, + } +} + +pub struct XhciPort(Mmio); + +impl XhciPort { + fn read(&self) -> u32 { + self.0.read() + } + + fn state(&self) -> u32 { + (self.read() & (0b111 << 5)) >> 5 + } + + fn speed(&self) -> u32 { + (self.read() & (0b1111 << 10)) >> 10 + } + + fn flags(&self) -> XhciPortFlags { + XhciPortFlags::from_bits_truncate(self.read()) + } +} + +pub struct XhciDoorbell(Mmio); + +impl XhciDoorbell { + fn read(&self) -> u32 { + self.0.read() + } + + fn write(&mut self, data: u32) { + self.0.write(data); + } +} + +#[repr(packed)] +pub struct XhciSlotContext { + inner: [u8; 32] +} + +#[repr(packed)] +pub struct XhciEndpointContext { + inner: [u8; 32] +} + +#[repr(packed)] +pub struct XhciDeviceContext { + slot: XhciSlotContext, + endpoints: [XhciEndpointContext; 15] +} + +pub struct Xhci { + cap: &'static mut XhciCap, + op: &'static mut XhciOp, + ports: &'static mut [XhciPort], + dbs: &'static mut [XhciDoorbell], + dev_baa: Dma<[u64; 256]>, + dev_ctxs: Vec>, + cmds: Dma<[Trb; 256]>, +} + +impl Xhci { + pub fn new(address: usize) -> Result { + let cap = unsafe { &mut *(address as *mut XhciCap) }; + + let op_base = address + cap.len.read() as usize; + let op = unsafe { &mut *(op_base as *mut XhciOp) }; + + let max_slots; + let max_ports; + + { + // Wait until controller is ready + while op.usb_sts.readf(1 << 11) { + println!(" - Waiting for XHCI ready"); + } + + // Set run/stop to 0 + op.usb_cmd.writef(1, false); + + // Wait until controller not running + while ! op.usb_sts.readf(1) { + println!(" - Waiting for XHCI stopped"); + } + + // Read maximum slots and ports + let hcs_params1 = cap.hcs_params1.read(); + max_slots = hcs_params1 & 0xFF; + max_ports = (hcs_params1 & 0xFF000000) >> 24; + + println!(" - Max Slots: {}, Max Ports {}", max_slots, max_ports); + + // Set enabled slots + op.config.write(max_slots); + println!(" - Enabled Slots: {}", op.config.read() & 0xFF); + } + + let port_base = op_base + 0x400; + let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut XhciPort, max_ports as usize) }; + + let db_base = op_base + cap.db_offset.read() as usize; + let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut XhciDoorbell, 256) }; + + let mut xhci = Xhci { + cap: cap, + op: op, + ports: ports, + dbs: dbs, + dev_baa: Dma::zeroed()?, + dev_ctxs: Vec::new(), + cmds: Dma::zeroed()?, + }; + + { + // Create device context buffers for each slot + for i in 0..max_slots as usize { + let dev_ctx: Dma = Dma::zeroed()?; + xhci.dev_baa[i] = dev_ctx.physical() as u64; + xhci.dev_ctxs.push(dev_ctx); + } + + // Set device context address array pointer + xhci.op.dcbaap.write(xhci.dev_baa.physical() as u64); + + // Set command ring control register + xhci.op.crcr.write(xhci.cmds.physical() as u64); + + // Set run/stop to 1 + xhci.op.usb_cmd.writef(1, true); + + // Wait until controller is running + while xhci.op.usb_sts.readf(1) { + println!(" - Waiting for XHCI running"); + } + } + + Ok(xhci) + } + + pub fn init(&mut self) { + for (i, port) in self.ports.iter().enumerate() { + let data = port.read(); + let state = port.state(); + let speed = port.speed(); + let flags = port.flags(); + println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags); + } + } +} From 28dbc45637364b6ac68d2d091b6c5fa2420f3546 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Feb 2017 14:05:04 -0700 Subject: [PATCH 0109/1301] WIP: NVME driver --- nvmed/Cargo.toml | 8 +++++ nvmed/src/main.rs | 83 +++++++++++++++++++++++++++++++++++++++++++++++ nvmed/src/nvme.rs | 31 ++++++++++++++++++ 3 files changed, 122 insertions(+) create mode 100644 nvmed/Cargo.toml create mode 100644 nvmed/src/main.rs create mode 100644 nvmed/src/nvme.rs diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml new file mode 100644 index 0000000000..fbdc36977d --- /dev/null +++ b/nvmed/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "nvmed" +version = "0.1.0" + +[dependencies] +bitflags = "0.7" +spin = "0.4" +redox_syscall = "0.1" diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs new file mode 100644 index 0000000000..ebf646b496 --- /dev/null +++ b/nvmed/src/main.rs @@ -0,0 +1,83 @@ +//#![deny(warnings)] +#![feature(asm)] + +extern crate bitflags; +extern crate spin; +extern crate syscall; + +use std::{env, usize}; +use std::fs::File; +use std::io::{Read, Write}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Result, Scheme}; + +mod nvme; + +fn create_scheme_fallback<'a>(name: &'a str, fallback: &'a str) -> Result<(&'a str, RawFd)> { + if let Ok(fd) = syscall::open(&format!(":{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) { + Ok((name, fd)) + } else { + syscall::open(&format!(":{}", fallback), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) + .map(|fd| (fallback, fd)) + } +} + +fn main() { + let mut args = env::args().skip(1); + + let mut name = args.next().expect("nvmed: no name provided"); + name.push_str("_nvme"); + + let bar_str = args.next().expect("nvmed: no address provided"); + let bar = usize::from_str_radix(&bar_str, 16).expect("nvmed: failed to parse address"); + + let irq_str = args.next().expect("nvmed: no irq provided"); + let irq = irq_str.parse::().expect("nvmed: failed to parse irq"); + + print!("{}", format!(" + NVME {} on: {:X} IRQ: {}\n", name, bar, irq)); + + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("nvmed: failed to map address") }; + { + /* + let (_scheme_name, socket_fd) = create_scheme_fallback("disk", &name).expect("nvmed: failed to create disk scheme"); + let mut socket = unsafe { File::from_raw_fd(socket_fd) }; + syscall::fevent(socket_fd, EVENT_READ).expect("nvmed: failed to fevent disk scheme"); + + let mut irq_file = File::open(&format!("irq:{}", irq)).expect("nvmed: failed to open irq file"); + let irq_fd = irq_file.as_raw_fd(); + syscall::fevent(irq_fd, EVENT_READ).expect("nvmed: failed to fevent irq file"); + + let mut event_file = File::open("event:").expect("nvmed: failed to open event file"); + + let scheme = DiskScheme::new(nvme::disks(address, &name)); + loop { + let mut event = Event::default(); + if event_file.read(&mut event).expect("nvmed: failed to read event file") == 0 { + break; + } + if event.id == socket_fd { + loop { + let mut packet = Packet::default(); + if socket.read(&mut packet).expect("nvmed: failed to read disk scheme") == 0 { + break; + } + scheme.handle(&mut packet); + socket.write(&mut packet).expect("nvmed: failed to write disk scheme"); + } + } else if event.id == irq_fd { + let mut irq = [0; 8]; + if irq_file.read(&mut irq).expect("nvmed: failed to read irq file") >= irq.len() { + //TODO : Test for IRQ + //irq_file.write(&irq).expect("nvmed: failed to write irq file"); + } + } else { + println!("Unknown event {}", event.id); + } + } + */ + } + unsafe { let _ = syscall::physunmap(address); } + } +} diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs new file mode 100644 index 0000000000..c6e022ac37 --- /dev/null +++ b/nvmed/src/nvme.rs @@ -0,0 +1,31 @@ +use syscall::io::{Io, Mmio}; + +#[repr(packed)] +pub struct NvmeRegs { + /// Controller Capabilities + cap: Mmio, + /// Version + vs: Mmio, + /// Interrupt mask set + intms: Mmio, + /// Interrupt mask clear + intmc: Mmio, + /// Controller configuration + cc: Mmio, + /// Reserved + _rsvd: Mmio, + /// Controller status + csts: Mmio, + /// NVM subsystem reset + nssr: Mmio, + /// Admin queue attributes + aqa: Mmio, + /// Admin submission queue base address + asq: Mmio, + /// Admin completion queue base address + acq: Mmio, + /// Controller memory buffer location + cmbloc: Mmio, + /// Controller memory buffer size + cmbsz: Mmio, +} \ No newline at end of file From 7be81d7837ee17d383402809ca4f904f4b5016a9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Feb 2017 15:00:14 -0700 Subject: [PATCH 0110/1301] Add read, write command structures --- nvmed/src/nvme.rs | 63 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index c6e022ac37..7a085b6a58 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -1,5 +1,64 @@ use syscall::io::{Io, Mmio}; +pub struct NvmeCmd { + /// Command dword 0 + cdw0: u32, + /// Namespace identifier + nsid: u32, + /// Reserved + _rsvd: u64, + /// Metadata pointer + mptr: u64, + /// Data pointer + dptr: [u64; 2], + /// Command dword 10 + cdw10: u32, + /// Command dword 11 + cdw11: u32, + /// Command dword 12 + cdw12: u32, + /// Command dword 13 + cdw13: u32, + /// Command dword 14 + cdw14: u32, + /// Command dword 15 + cdw15: u32, +} + +impl NvmeCmd { + pub fn read(cid: u16, lba: u64, count: u16, dst: u64) -> Self { + NvmeCmd { + cdw0: (cid as u32) << 16 | 1 << 14 | 2, + nsid: 0xFFFFFFFF, + _rsvd: 0, + mptr: 0, + dptr: [dst, (count as u64) << 9], + cdw10: lba as u32, + cdw11: (lba >> 32) as u32, + cdw12: count as u32, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + + pub fn write(cid: u16, lba: u64, count: u16, src: u64) -> Self { + NvmeCmd { + cdw0: (cid as u32) << 16 | 1 << 14 | 1, + nsid: 0xFFFFFFFF, + _rsvd: 0, + mptr: 0, + dptr: [src, (count as u64) << 9], + cdw10: lba as u32, + cdw11: (lba >> 32) as u32, + cdw12: count as u32, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } +} + #[repr(packed)] pub struct NvmeRegs { /// Controller Capabilities @@ -27,5 +86,5 @@ pub struct NvmeRegs { /// Controller memory buffer location cmbloc: Mmio, /// Controller memory buffer size - cmbsz: Mmio, -} \ No newline at end of file + cmbsz: Mmio, +} From 63dd2286fe99535fd7eaca9c99f3c1e951f69dda Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Feb 2017 19:07:11 -0700 Subject: [PATCH 0111/1301] nvmed: Verify correct memory space --- nvmed/src/main.rs | 4 ++++ nvmed/src/nvme.rs | 34 ++++++++++++++++++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index ebf646b496..14af0cf0f2 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -11,6 +11,8 @@ use std::io::{Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Result, Scheme}; +use self::nvme::Nvme; + mod nvme; fn create_scheme_fallback<'a>(name: &'a str, fallback: &'a str) -> Result<(&'a str, RawFd)> { @@ -40,6 +42,8 @@ fn main() { if unsafe { syscall::clone(0).unwrap() } == 0 { let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("nvmed: failed to map address") }; { + let mut nvme = Nvme::new(address); + nvme.init(); /* let (_scheme_name, socket_fd) = create_scheme_fallback("disk", &name).expect("nvmed: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd) }; diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index 7a085b6a58..63c6d78ec7 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -1,8 +1,13 @@ use syscall::io::{Io, Mmio}; +#[repr(packed)] pub struct NvmeCmd { - /// Command dword 0 - cdw0: u32, + /// Opcode + opcode: u8, + /// Flags + flags: u8, + /// Command ID + cid: u16, /// Namespace identifier nsid: u32, /// Reserved @@ -28,7 +33,9 @@ pub struct NvmeCmd { impl NvmeCmd { pub fn read(cid: u16, lba: u64, count: u16, dst: u64) -> Self { NvmeCmd { - cdw0: (cid as u32) << 16 | 1 << 14 | 2, + opcode: 2, + flags: 1 << 6, + cid: cid, nsid: 0xFFFFFFFF, _rsvd: 0, mptr: 0, @@ -44,7 +51,9 @@ impl NvmeCmd { pub fn write(cid: u16, lba: u64, count: u16, src: u64) -> Self { NvmeCmd { - cdw0: (cid as u32) << 16 | 1 << 14 | 1, + opcode: 1, + flags: 1 << 6, + cid: cid, nsid: 0xFFFFFFFF, _rsvd: 0, mptr: 0, @@ -88,3 +97,20 @@ pub struct NvmeRegs { /// Controller memory buffer size cmbsz: Mmio, } + +pub struct Nvme { + regs: &'static mut NvmeRegs +} + +impl Nvme { + pub fn new(address: usize) -> Self { + Nvme { + regs: unsafe { &mut *(address as *mut NvmeRegs) } + } + } + + pub fn init(&mut self) { + println!(" - CAPS: {:X}", self.regs.cap.read()); + println!(" - VS: {:X}", self.regs.vs.read()); + } +} From 975082c18abfc7c48ab24ba9a30da6a9ebad8717 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 24 Feb 2017 13:21:26 -0700 Subject: [PATCH 0112/1301] Disable XHCI driver to prevent deadlocks --- xhcid/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index fe4a064962..95beefd246 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -24,7 +24,7 @@ fn main() { let address = unsafe { syscall::physmap(bar, 4096, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; match Xhci::new(address) { Ok(mut xhci) => { - xhci.init(); + //xhci.init(); }, Err(err) => { println!("xhcid: error: {}", err); From 96fbf1658fcc45fa82c0eefd7c67dd7ac6b59dba Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 24 Feb 2017 13:25:57 -0700 Subject: [PATCH 0113/1301] More completely disable XHCI driver --- xhcid/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 95beefd246..741871db4b 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -22,14 +22,16 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { let address = unsafe { syscall::physmap(bar, 4096, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; + /* match Xhci::new(address) { Ok(mut xhci) => { - //xhci.init(); + xhci.init(); }, Err(err) => { println!("xhcid: error: {}", err); } } + */ unsafe { let _ = syscall::physunmap(address); } } } From f4d6fbb4a2db985947e421718147d1956d62767c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 27 Feb 2017 21:48:15 -0700 Subject: [PATCH 0114/1301] Update orbclient, add scroll events --- ps2d/Cargo.toml | 2 +- ps2d/src/main.rs | 24 +++++++++++++++++------- vesad/Cargo.toml | 2 +- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 8c534763b3..d1df438016 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "0.7" -orbclient = "0.2" +orbclient = "0.3" redox_event = { git = "https://github.com/redox-os/event.git" } redox_syscall = "0.1" diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 46291b2f28..1a09dab47b 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -14,7 +14,7 @@ use std::os::unix::io::AsRawFd; use std::mem; use event::EventQueue; -use orbclient::{KeyEvent, MouseEvent}; +use orbclient::{KeyEvent, MouseEvent, ScrollEvent}; use syscall::iopl; mod controller; @@ -98,11 +98,14 @@ impl<'a> Ps2d<'a> { dy += 0x100; } - let _extra = if self.extra_packet { - self.packets[3] - } else { - 0 - }; + let mut dz = 0; + if self.extra_packet { + let mut scroll = (self.packets[3] & 0xF) as i8; + if scroll & (1 << 3) == 1 << 3 { + scroll -= 16; + } + dz = -scroll as i32; + } self.input.write(&MouseEvent { x: dx, @@ -111,6 +114,13 @@ impl<'a> Ps2d<'a> { middle_button: flags.contains(MIDDLE_BUTTON), right_button: flags.contains(RIGHT_BUTTON) }.to_event()).expect("ps2d: failed to write mouse event"); + + if dz != 0 { + self.input.write(&ScrollEvent { + x: 0, + y: dz, + }.to_event()).expect("ps2d: failed to write scroll event"); + } } else { println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); } @@ -137,7 +147,7 @@ fn daemon(input: File) { }, None => (keymap::english::get_char) }; - let mut ps2d = Ps2d::new(input, extra_packet,&keymap); + let mut ps2d = Ps2d::new(input, extra_packet, &keymap); let mut event_queue = EventQueue::<(bool, u8)>::new().expect("ps2d: failed to create event queue"); diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index c4a9cb7144..a71776a129 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -3,7 +3,7 @@ name = "vesad" version = "0.1.0" [dependencies] -orbclient = "0.2" +orbclient = "0.3" ransid = "0.2" rusttype = { version = "0.2", optional = true } redox_syscall = "0.1" From ebc5f86e8c0eadb1a38ae72faf5f90089391416b Mon Sep 17 00:00:00 2001 From: Adrian Neumann Date: Sun, 5 Mar 2017 15:44:06 +0100 Subject: [PATCH 0115/1301] Make enum values List and Disk contain two values instead of a tuple of values. --- ahcid/src/scheme.rs | 61 ++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index cd35d76dc8..52df564f0a 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -11,9 +11,8 @@ use ahci::disk::Disk; #[derive(Clone)] enum Handle { - //TODO: Make these enum variants normal tuples (), not nested tuples (()) - List((Vec, usize)), - Disk((Arc>, usize)) + List(Vec, usize), + Disk(Arc>, usize) } pub struct DiskScheme { @@ -50,7 +49,7 @@ impl Scheme for DiskScheme { } let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, Handle::List((list.into_bytes(), 0))); + self.handles.lock().insert(id, Handle::List(list.into_bytes(), 0)); Ok(id) } else { Err(Error::new(EISDIR)) @@ -60,7 +59,7 @@ impl Scheme for DiskScheme { if let Some(disk) = self.disks.get(i) { let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, Handle::Disk((disk.clone(), 0))); + self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0)); Ok(id) } else { Err(Error::new(ENOENT)) @@ -86,14 +85,14 @@ impl Scheme for DiskScheme { fn fstat(&self, id: usize, stat: &mut Stat) -> Result { let handles = self.handles.lock(); match *handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => { + Handle::List(ref handle, _) => { stat.st_mode = MODE_DIR; - stat.st_size = handle.0.len() as u64; + stat.st_size = handle.len() as u64; Ok(0) }, - Handle::Disk(ref handle) => { + Handle::Disk(ref handle, _) => { stat.st_mode = MODE_FILE; - stat.st_size = handle.0.lock().size(); + stat.st_size = handle.lock().size(); Ok(0) } } @@ -102,15 +101,15 @@ impl Scheme for DiskScheme { fn read(&self, id: usize, buf: &mut [u8]) -> Result { let mut handles = self.handles.lock(); match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle) => { - let count = (&handle.0[handle.1..]).read(buf).unwrap(); - handle.1 += count; + Handle::List(ref mut handle, ref mut size) => { + let count = (&handle[*size..]).read(buf).unwrap(); + *size += count; Ok(count) }, - Handle::Disk(ref mut handle) => { - let mut disk = handle.0.lock(); - let count = disk.read((handle.1 as u64)/512, buf)?; - handle.1 += count; + Handle::Disk(ref mut handle, ref mut size) => { + let mut disk = handle.lock(); + let count = disk.read((*size as u64)/512, buf)?; + *size += count; Ok(count) } } @@ -119,13 +118,13 @@ impl Scheme for DiskScheme { fn write(&self, id: usize, buf: &[u8]) -> Result { let mut handles = self.handles.lock(); match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => { + Handle::List(_, _) => { Err(Error::new(EBADF)) }, - Handle::Disk(ref mut handle) => { - let mut disk = handle.0.lock(); - let count = disk.write((handle.1 as u64)/512, buf)?; - handle.1 += count; + Handle::Disk(ref mut handle, ref mut size) => { + let mut disk = handle.lock(); + let count = disk.write((*size as u64)/512, buf)?; + *size += count; Ok(count) } } @@ -134,27 +133,27 @@ impl Scheme for DiskScheme { fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { let mut handles = self.handles.lock(); match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle) => { - let len = handle.0.len() as usize; - handle.1 = match whence { + Handle::List(ref mut handle, ref mut size) => { + let len = handle.len() as usize; + *size = match whence { SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize, + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, _ => return Err(Error::new(EINVAL)) }; - Ok(handle.1) + Ok(*size) }, - Handle::Disk(ref mut handle) => { - let len = handle.0.lock().size() as usize; - handle.1 = match whence { + Handle::Disk(ref mut handle, ref mut size) => { + let len = handle.lock().size() as usize; + *size = match whence { SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, handle.1 as isize + pos as isize)) as usize, + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, _ => return Err(Error::new(EINVAL)) }; - Ok(handle.1) + Ok(*size) } } } From fe65978ac46cbfd33851f09c985a212d01084499 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 8 Mar 2017 15:00:53 -0700 Subject: [PATCH 0116/1301] Update to catch title event --- vesad/src/screen/text.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 1ede48ebc0..d7f226aaff 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -193,7 +193,8 @@ impl Screen for TextScreen { for y in 0..display.height/16 { changed.insert(y); } - } + }, + ransid::Event::Title { .. } => () } }); } From 2593c252123398a931f6563ba594822fed4d2020 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Mar 2017 21:47:38 -0600 Subject: [PATCH 0117/1301] Add support for BGA mode setting (WIP) --- bgad/Cargo.toml | 3 +++ bgad/src/bga.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ bgad/src/main.rs | 15 +++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 bgad/src/bga.rs diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml index c763e3206f..9a28ece41e 100644 --- a/bgad/Cargo.toml +++ b/bgad/Cargo.toml @@ -1,3 +1,6 @@ [package] name = "bgad" version = "0.1.0" + +[dependencies] +redox_syscall = "0.1" diff --git a/bgad/src/bga.rs b/bgad/src/bga.rs new file mode 100644 index 0000000000..ee196f7f95 --- /dev/null +++ b/bgad/src/bga.rs @@ -0,0 +1,47 @@ +use syscall::io::{Io, Pio}; + +const BGA_INDEX_XRES: u16 = 1; +const BGA_INDEX_YRES: u16 = 2; +const BGA_INDEX_BPP: u16 = 3; +const BGA_INDEX_ENABLE: u16 = 4; + +pub struct Bga { + index: Pio, + data: Pio, +} + +impl Bga { + pub fn new() -> Bga { + Bga { + index: Pio::new(0x1CE), + data: Pio::new(0x1CF), + } + } + + fn read(&mut self, index: u16) -> u16 { + self.index.write(index); + self.data.read() + } + + fn write(&mut self, index: u16, data: u16) { + self.index.write(index); + self.data.write(data); + } + + pub fn width(&mut self) -> u16 { + self.read(BGA_INDEX_XRES) + } + + pub fn height(&mut self) -> u16 { + self.read(BGA_INDEX_YRES) + } + + #[allow(dead_code)] + pub fn set_size(&mut self, width: u16, height: u16) { + self.write(BGA_INDEX_ENABLE, 0); + self.write(BGA_INDEX_XRES, width); + self.write(BGA_INDEX_YRES, height); + self.write(BGA_INDEX_BPP, 32); + self.write(BGA_INDEX_ENABLE, 0x41); + } +} diff --git a/bgad/src/main.rs b/bgad/src/main.rs index 7475aaac46..479f62f3ab 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -1,6 +1,13 @@ #![deny(warnings)] +extern crate syscall; + use std::env; +use syscall::iopl; + +use bga::Bga; + +mod bga; fn main() { let mut args = env::args().skip(1); @@ -12,4 +19,12 @@ fn main() { let bar = usize::from_str_radix(&bar_str, 16).expect("bgad: failed to parse address"); print!("{}", format!(" + BGA {} on: {:X}\n", name, bar)); + + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + unsafe { iopl(3).unwrap() }; + + let mut bga = Bga::new(); + print!("{}", format!(" - BGA {}x{}", bga.width(), bga.height())); + } } From 66d2aa8c0150420db530b33a7119403af6c091e1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Mar 2017 21:48:33 -0600 Subject: [PATCH 0118/1301] Add virtualbox guest driver (WIP) --- vboxd/Cargo.toml | 8 ++ vboxd/src/main.rs | 257 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 vboxd/Cargo.toml create mode 100644 vboxd/src/main.rs diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml new file mode 100644 index 0000000000..07c81b675a --- /dev/null +++ b/vboxd/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "vboxd" +version = "0.1.0" + +[dependencies] +orbclient = "0.3" +redox_event = { git = "https://github.com/redox-os/event.git" } +redox_syscall = "0.1" diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs new file mode 100644 index 0000000000..6633ca88f8 --- /dev/null +++ b/vboxd/src/main.rs @@ -0,0 +1,257 @@ +//#![deny(warnings)] + +extern crate event; +extern crate orbclient; +extern crate syscall; + +use event::EventQueue; +use std::{env, mem, slice}; +use std::os::unix::io::AsRawFd; +use std::fs::File; +use std::io::{Result, Read, Write}; +use syscall::flag::MAP_WRITE; +use syscall::io::{Dma, Io, Mmio, Pio}; +use syscall::iopl; + +const VBOX_REQUEST_HEADER_VERSION: u32 = 0x10001; +const VBOX_VMMDEV_VERSION: u32 = 0x00010003; + +const VBOX_EVENT_DISPLAY: u32 = 1 << 2; +const VBOX_EVENT_MOUSE: u32 = 1 << 9; + +/// VBox VMMDevMemory +#[repr(packed)] +struct VboxVmmDev { + size: Mmio, + version: Mmio, + host_events: Mmio, + guest_events: Mmio, +} + +/// VBox Guest packet header +#[repr(packed)] +struct VboxHeader { + /// Size of the entire packet (including this header) + size: Mmio, + /// Version; always VBOX_REQUEST_HEADER_VERSION + version: Mmio, + /// Request type + request: Mmio, + /// Return code + result: Mmio, + _reserved1: Mmio, + _reserved2: Mmio, +} + +/// VBox Get Mouse +#[repr(packed)] +struct VboxGetMouse { + header: VboxHeader, + features: Mmio, + x: Mmio, + y: Mmio, +} + +impl VboxGetMouse { + fn request() -> u32 { 1 } + + fn new() -> syscall::Result> { + let mut packet = Dma::::zeroed()?; + + packet.header.size.write(mem::size_of::() as u32); + packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); + packet.header.request.write(Self::request()); + + Ok(packet) + } +} + +/// VBox Set Mouse +#[repr(packed)] +struct VboxSetMouse { + header: VboxHeader, + features: Mmio, + x: Mmio, + y: Mmio, +} + +impl VboxSetMouse { + fn request() -> u32 { 2 } + + fn new() -> syscall::Result> { + let mut packet = Dma::::zeroed()?; + + packet.header.size.write(mem::size_of::() as u32); + packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); + packet.header.request.write(Self::request()); + + Ok(packet) + } +} + +/// VBox Acknowledge Events packet +#[repr(packed)] +struct VboxAckEvents { + header: VboxHeader, + events: Mmio, +} + +impl VboxAckEvents { + fn request() -> u32 { 41 } + + fn new() -> syscall::Result> { + let mut packet = Dma::::zeroed()?; + + packet.header.size.write(mem::size_of::() as u32); + packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); + packet.header.request.write(Self::request()); + + Ok(packet) + } +} + +/// VBox Guest Capabilities packet +#[repr(packed)] +struct VboxGuestCaps { + header: VboxHeader, + caps: Mmio, +} + +impl VboxGuestCaps { + fn request() -> u32 { 55 } + + fn new() -> syscall::Result> { + let mut packet = Dma::::zeroed()?; + + packet.header.size.write(mem::size_of::() as u32); + packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); + packet.header.request.write(Self::request()); + + Ok(packet) + } +} + +/* VBox GetDisplayChange packet */ +struct VboxDisplayChange { + header: VboxHeader, + xres: Mmio, + yres: Mmio, + bpp: Mmio, + eventack: Mmio, +} + +impl VboxDisplayChange { + fn request() -> u32 { 51 } + + fn new() -> syscall::Result> { + let mut packet = Dma::::zeroed()?; + + packet.header.size.write(mem::size_of::() as u32); + packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); + packet.header.request.write(Self::request()); + + Ok(packet) + } +} + +/// VBox Guest Info packet (legacy) +#[repr(packed)] +struct VboxGuestInfo { + header: VboxHeader, + version: Mmio, + ostype: Mmio, +} + +impl VboxGuestInfo { + fn request() -> u32 { 50 } + + fn new() -> syscall::Result> { + let mut packet = Dma::::zeroed()?; + + packet.header.size.write(mem::size_of::() as u32); + packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); + packet.header.request.write(Self::request()); + + Ok(packet) + } +} + +fn main() { + let mut args = env::args().skip(1); + + let mut name = args.next().expect("vboxd: no name provided"); + name.push_str("_vbox"); + + let bar0_str = args.next().expect("vboxd: no address provided"); + let bar0 = usize::from_str_radix(&bar0_str, 16).expect("vboxd: failed to parse address"); + + let bar1_str = args.next().expect("vboxd: no address provided"); + let bar1 = usize::from_str_radix(&bar1_str, 16).expect("vboxd: failed to parse address"); + + let irq_str = args.next().expect("vboxd: no irq provided"); + let irq = irq_str.parse::().expect("vboxd: failed to parse irq"); + + print!("{}", format!(" + VirtualBox {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1, irq)); + + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + unsafe { iopl(3).expect("vboxd: failed to get I/O permission"); }; + + let mut display = File::open("display:input").ok(); + + let mut irq_file = File::open(format!("irq:{}", irq)).expect("vboxd: failed to open IRQ file"); + + let mut port = Pio::::new(bar0 as u16); + let address = unsafe { syscall::physmap(bar1, 4096, MAP_WRITE).expect("vboxd: failed to map address") }; + { + let mut vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; + + let mut guest_info = VboxGuestInfo::new().expect("vboxd: failed to map GuestInfo"); + guest_info.version.write(VBOX_VMMDEV_VERSION); + guest_info.ostype.write(0x100); + port.write(guest_info.physical() as u32); + + let mut guest_caps = VboxGuestCaps::new().expect("vboxd: failed to map GuestCaps"); + guest_caps.caps.write(1 << 2); + port.write(guest_caps.physical() as u32); + + let mut set_mouse = VboxSetMouse::new().expect("vboxd: failed to map SetMouse"); + set_mouse.features.write(1 << 4 | 1); + port.write(set_mouse.physical() as u32); + + vmmdev.guest_events.write(VBOX_EVENT_DISPLAY | VBOX_EVENT_MOUSE); + + let mut event_queue = EventQueue::<()>::new().expect("vboxd: failed to create event queue"); + + let get_mouse = VboxGetMouse::new().expect("vboxd: failed to map GetMouse"); + let display_change = VboxDisplayChange::new().expect("vboxd: failed to map DisplayChange"); + let ack_events = VboxAckEvents::new().expect("vboxd: failed to map AckEvents"); + event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + let mut irq = [0; 8]; + if irq_file.read(&mut irq)? >= irq.len() { + let host_events = vmmdev.host_events.read(); + if host_events != 0 { + port.write(ack_events.physical() as u32); + irq_file.write(&irq)?; + + if host_events & VBOX_EVENT_DISPLAY == VBOX_EVENT_DISPLAY { + port.write(display_change.physical() as u32); + println!("Display {}, {}", display_change.xres.read(), display_change.yres.read()); + } + + if host_events & VBOX_EVENT_MOUSE == VBOX_EVENT_MOUSE { + port.write(get_mouse.physical() as u32); + println!("Mouse {}, {}", get_mouse.x.read(), get_mouse.y.read()); + } + } + } + Ok(None) + }).expect("vboxd: failed to poll irq"); + + event_queue.trigger_all(0).expect("vboxd: failed to trigger events"); + + event_queue.run().expect("vboxd: failed to run event loop"); + } + unsafe { let _ = syscall::physunmap(address); } + } +} From a294fe6d6f259dd44aeaf8d4a74bbddf01a605dd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 20 Mar 2017 21:38:30 -0600 Subject: [PATCH 0119/1301] Update to support absolute mouse events --- vesad/src/scheme.rs | 6 +++++- vesad/src/screen/graphic.rs | 20 ++------------------ 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index e376bf7ad0..495dc44810 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -8,6 +8,8 @@ use display::Display; use screen::{Screen, GraphicScreen, TextScreen}; pub struct DisplayScheme { + width: usize, + height: usize, active: usize, pub screens: BTreeMap> } @@ -27,6 +29,8 @@ impl DisplayScheme { } DisplayScheme { + width: width, + height: height, active: 1, screens: screens } @@ -88,7 +92,7 @@ impl SchemeMut for DisplayScheme { fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { let path_str = if id == 0 { - format!("display:input") + format!("display:input/{}/{}", self.width, self.height) } else if let Some(screen) = self.screens.get(&id) { format!("display:{}/{}/{}", id, screen.width(), screen.height()) } else { diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index b91192267a..12a26a0a52 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use std::{cmp, mem, slice}; -use orbclient::{Event, EventOption}; +use orbclient::Event; use syscall::error::*; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; @@ -12,8 +12,6 @@ use screen::Screen; pub struct GraphicScreen { pub display: Display, pub seek: usize, - pub mouse_x: i32, - pub mouse_y: i32, pub input: VecDeque, pub requested: usize } @@ -23,8 +21,6 @@ impl GraphicScreen { GraphicScreen { display: display, seek: 0, - mouse_x: 0, - mouse_y: 0, input: VecDeque::new(), requested: 0 } @@ -54,19 +50,7 @@ impl Screen for GraphicScreen { } fn input(&mut self, event: &Event) { - if let EventOption::Mouse(mut mouse_event) = event.to_option() { - let x = cmp::max(0, cmp::min(self.display.width as i32, self.mouse_x + mouse_event.x)); - let y = cmp::max(0, cmp::min(self.display.height as i32, self.mouse_y + mouse_event.y)); - - mouse_event.x = x; - self.mouse_x = x; - mouse_event.y = y; - self.mouse_y = y; - - self.input.push_back(mouse_event.to_event()); - } else { - self.input.push_back(*event); - } + self.input.push_back(*event); } fn read(&mut self, buf: &mut [u8]) -> Result { From bad856d7b435926d9713dff648c1921e205b16ef Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 20 Mar 2017 21:39:12 -0600 Subject: [PATCH 0120/1301] Support for mouse events in vbox driver --- vboxd/src/main.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 6633ca88f8..f1064ac56d 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -197,7 +197,18 @@ fn main() { if unsafe { syscall::clone(0).unwrap() } == 0 { unsafe { iopl(3).expect("vboxd: failed to get I/O permission"); }; - let mut display = File::open("display:input").ok(); + let mut width = 0; + let mut height = 0; + let mut display_opt = File::open("display:input").ok(); + if let Some(ref display) = display_opt { + let mut buf: [u8; 4096] = [0; 4096]; + if let Ok(count) = syscall::fpath(display.as_raw_fd() as usize, &mut buf) { + let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; + let res = path.split(":").nth(1).unwrap_or(""); + width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); + height = res.split("/").nth(2).unwrap_or("").parse::().unwrap_or(0); + } + } let mut irq_file = File::open(format!("irq:{}", irq)).expect("vboxd: failed to open IRQ file"); @@ -241,7 +252,15 @@ fn main() { if host_events & VBOX_EVENT_MOUSE == VBOX_EVENT_MOUSE { port.write(get_mouse.physical() as u32); - println!("Mouse {}, {}", get_mouse.x.read(), get_mouse.y.read()); + let x = get_mouse.x.read() * width / 0x10000; + let y = get_mouse.y.read() * height / 0x10000; + println!("Mouse {}, {} in {}, {} = {}, {}", get_mouse.x.read(), get_mouse.y.read(), width, height, x, y); + if let Some(ref mut display) = display_opt { + let _ = display.write(&orbclient::MouseEvent { + x: x as i32, + y: y as i32, + }.to_event()); + } } } } From 63df9fff38d58e3963962ca6da3966bbc29e102b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 20 Mar 2017 21:39:41 -0600 Subject: [PATCH 0121/1301] Fix interrupts in PS/2 driver, support for absolute mouse position and new orbclient event format --- ps2d/src/controller.rs | 11 ++++ ps2d/src/main.rs | 133 ++++++++++++++++++++++++++--------------- 2 files changed, 96 insertions(+), 48 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 29738b5a66..53f75cb951 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -158,6 +158,17 @@ impl Ps2 { self.read() } + pub fn next(&mut self) -> Option<(bool, u8)> { + let status = self.status(); + println!("{:?}", status); + if status.contains(OUTPUT_FULL) { + let data = self.data.read(); + Some((! status.contains(SECOND_OUTPUT_FULL), data)) + } else { + None + } + } + pub fn init(&mut self) -> bool { // Disable devices self.command(Command::DisableFirst); diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 1a09dab47b..87e6be3300 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -7,16 +7,19 @@ extern crate event; extern crate orbclient; extern crate syscall; -use std::{env, process}; +use std::{cmp, env, process}; +use std::cell::RefCell; use std::fs::File; use std::io::{Read, Write, Result}; use std::os::unix::io::AsRawFd; -use std::mem; +use std::sync::Arc; use event::EventQueue; -use orbclient::{KeyEvent, MouseEvent, ScrollEvent}; +use orbclient::{KeyEvent, MouseEvent, ButtonEvent, ScrollEvent}; use syscall::iopl; +use controller::Ps2; + mod controller; mod keymap; @@ -33,23 +36,54 @@ bitflags! { } } -struct Ps2d<'a> { +struct Ps2d char> { + ps2: Ps2, input: File, + width: u32, + height: u32, lshift: bool, rshift: bool, + mouse_x: i32, + mouse_y: i32, + mouse_left: bool, + mouse_middle: bool, + mouse_right: bool, packets: [u8; 4], packet_i: usize, extra_packet: bool, //Keymap function - get_char: &'a Fn(u8,bool) -> char + get_char: F } -impl<'a> Ps2d<'a> { - fn new(input: File, extra_packet: bool, keymap: &'a Fn(u8,bool) -> char) -> Self { +impl char> Ps2d { + fn new(input: File, keymap: F) -> Self { + let mut ps2 = Ps2::new(); + let extra_packet = ps2.init(); + + let mut width = 0; + let mut height = 0; + { + let mut buf: [u8; 4096] = [0; 4096]; + if let Ok(count) = syscall::fpath(input.as_raw_fd() as usize, &mut buf) { + let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; + let res = path.split(":").nth(1).unwrap_or(""); + width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); + height = res.split("/").nth(2).unwrap_or("").parse::().unwrap_or(0); + } + } + Ps2d { + ps2: ps2, input: input, + width: width, + height: height, lshift: false, rshift: false, + mouse_x: 0, + mouse_y: 0, + mouse_left: false, + mouse_middle: false, + mouse_right: false, packets: [0; 4], packet_i: 0, extra_packet: extra_packet, @@ -57,6 +91,12 @@ impl<'a> Ps2d<'a> { } } + fn irq(&mut self) { + while let Some((keyboard, data)) = self.ps2.next() { + self.handle(keyboard, data); + } + } + fn handle(&mut self, keyboard: bool, data: u8) { if keyboard { let (scancode, pressed) = if data >= 0x80 { @@ -107,13 +147,30 @@ impl<'a> Ps2d<'a> { dz = -scroll as i32; } - self.input.write(&MouseEvent { - x: dx, - y: dy, - left_button: flags.contains(LEFT_BUTTON), - middle_button: flags.contains(MIDDLE_BUTTON), - right_button: flags.contains(RIGHT_BUTTON) - }.to_event()).expect("ps2d: failed to write mouse event"); + let x = cmp::max(0, cmp::min(self.width as i32, self.mouse_x + dx)); + let y = cmp::max(0, cmp::min(self.height as i32, self.mouse_y + dy)); + if x != self.mouse_x || y != self.mouse_y { + self.mouse_x = x; + self.mouse_y = y; + self.input.write(&MouseEvent { + x: x, + y: y, + }.to_event()).expect("ps2d: failed to write mouse event"); + } + + let left = flags.contains(LEFT_BUTTON); + let middle = flags.contains(MIDDLE_BUTTON); + let right = flags.contains(RIGHT_BUTTON); + if left != self.mouse_left || middle != self.mouse_middle || right != self.mouse_right { + self.mouse_left = left; + self.mouse_middle = middle; + self.mouse_right = right; + self.input.write(&ButtonEvent { + left: left, + middle: middle, + right: right, + }.to_event()).expect("ps2d: failed to write button event"); + } if dz != 0 { self.input.write(&ScrollEvent { @@ -138,7 +195,6 @@ fn daemon(input: File) { asm!("cli" : : : : "intel", "volatile"); } - let extra_packet = controller::Ps2::new().init(); let keymap = match env::args().skip(1).next() { Some(k) => match k.to_lowercase().as_ref() { "dvorak" => (keymap::dvorak::get_char), @@ -147,54 +203,35 @@ fn daemon(input: File) { }, None => (keymap::english::get_char) }; - let mut ps2d = Ps2d::new(input, extra_packet, &keymap); + let ps2d = Arc::new(RefCell::new(Ps2d::new(input, keymap))); - let mut event_queue = EventQueue::<(bool, u8)>::new().expect("ps2d: failed to create event queue"); + let mut event_queue = EventQueue::<()>::new().expect("ps2d: failed to create event queue"); let mut key_irq = File::open("irq:1").expect("ps2d: failed to open irq:1"); - - event_queue.add(key_irq.as_raw_fd(), move |_count: usize| -> Result> { + let key_ps2d = ps2d.clone(); + event_queue.add(key_irq.as_raw_fd(), move |_count: usize| -> Result> { let mut irq = [0; 8]; - if key_irq.read(&mut irq)? >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - + if key_irq.read(&mut irq)? >= irq.len() { + key_ps2d.borrow_mut().irq(); key_irq.write(&irq)?; - - Ok(Some((true, data))) - } else { - Ok(None) } + Ok(None) }).expect("ps2d: failed to poll irq:1"); let mut mouse_irq = File::open("irq:12").expect("ps2d: failed to open irq:12"); - - event_queue.add(mouse_irq.as_raw_fd(), move |_count: usize| -> Result> { + let mouse_ps2d = ps2d; + event_queue.add(mouse_irq.as_raw_fd(), move |_count: usize| -> Result> { let mut irq = [0; 8]; - if mouse_irq.read(&mut irq)? >= mem::size_of::() { - let data: u8; - unsafe { - asm!("in al, dx" : "={al}"(data) : "{dx}"(0x60) : : "intel", "volatile"); - } - + if mouse_irq.read(&mut irq)? >= irq.len() { + mouse_ps2d.borrow_mut().irq(); mouse_irq.write(&irq)?; - - Ok(Some((false, data))) - } else { - Ok(None) } + Ok(None) }).expect("ps2d: failed to poll irq:12"); - for (keyboard, data) in event_queue.trigger_all(0).expect("ps2d: failed to trigger events") { - ps2d.handle(keyboard, data); - } + event_queue.trigger_all(0).expect("ps2d: failed to trigger events"); - loop { - let (keyboard, data) = event_queue.run().expect("ps2d: failed to handle events"); - ps2d.handle(keyboard, data); - } + event_queue.run().expect("ps2d: failed to handle events"); } fn main() { From f384376e194c65207473ca32b12f1e76a372570f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 20 Mar 2017 22:00:45 -0600 Subject: [PATCH 0122/1301] Remove debug statement --- ps2d/src/controller.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 53f75cb951..3dd159340f 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -160,7 +160,6 @@ impl Ps2 { pub fn next(&mut self) -> Option<(bool, u8)> { let status = self.status(); - println!("{:?}", status); if status.contains(OUTPUT_FULL) { let data = self.data.read(); Some((! status.contains(SECOND_OUTPUT_FULL), data)) From 060934a77df3850693778800deadcb5be1c3fb3b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 20 Mar 2017 22:23:56 -0600 Subject: [PATCH 0123/1301] Remove debug statement, again --- vboxd/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index f1064ac56d..5c2af742a3 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -254,7 +254,6 @@ fn main() { port.write(get_mouse.physical() as u32); let x = get_mouse.x.read() * width / 0x10000; let y = get_mouse.y.read() * height / 0x10000; - println!("Mouse {}, {} in {}, {} = {}, {}", get_mouse.x.read(), get_mouse.y.read(), width, height, x, y); if let Some(ref mut display) = display_opt { let _ = display.write(&orbclient::MouseEvent { x: x as i32, From c544b72c736ea8a6af7f2e8e386c5bd387b60b89 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 21 Mar 2017 16:56:26 -0600 Subject: [PATCH 0124/1301] Reset, wait for link up --- e1000d/src/device.rs | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 76884e5ae1..9f12fe124d 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,4 +1,4 @@ -use std::{cmp, mem, ptr, slice}; +use std::{cmp, mem, ptr, slice, thread, time}; use netutils::setcfg; use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; @@ -11,6 +11,7 @@ const CTRL_LRST: u32 = 1 << 3; const CTRL_ASDE: u32 = 1 << 5; const CTRL_SLU: u32 = 1 << 6; const CTRL_ILOS: u32 = 1 << 7; +const CTRL_RST: u32 = 1 << 26; const CTRL_VME: u32 = 1 << 30; const CTRL_PHY_RST: u32 = 1 << 31; @@ -267,11 +268,17 @@ impl Intel8254x { } pub unsafe fn init(&mut self) { + self.flag(CTRL, CTRL_RST, true); + loop { + thread::sleep(time::Duration::new(0, 1000)); + if self.read(CTRL) & CTRL_RST != CTRL_RST { + break; + } + } + // Enable auto negotiate, link, clear reset, do not Invert Loss-Of Signal self.flag(CTRL, CTRL_ASDE | CTRL_SLU, true); - self.flag(CTRL, CTRL_LRST, false); - self.flag(CTRL, CTRL_PHY_RST, false); - self.flag(CTRL, CTRL_ILOS, false); + self.flag(CTRL, CTRL_LRST | CTRL_PHY_RST | CTRL_ILOS, false); // No flow control self.write(FCAH, 0); @@ -342,5 +349,17 @@ impl Intel8254x { // TCTL.COLD = Collision distance // TIPG Packet Gap // TODO ... + + print!("{}", format!(" - CTRL: {:X}\n", self.read(CTRL))); + print!("{}", format!(" - STS: {:X}\n", self.read(STATUS))); + print!("{}", format!(" - RCTL: {:X}\n", self.read(RCTL))); + print!("{}", format!(" - TCTL: {:X}\n", self.read(TCTL))); + print!("{}", format!(" - IMS: {:X}\n", self.read(IMS))); + + + while self.read(STATUS) & 2 != 2 { + print!(" - Waiting for link up\n"); + thread::sleep(time::Duration::new(1, 0)); + } } } From 050abc1a7e8acf98bf35237abe819a3fb1246f10 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 21 Mar 2017 20:37:47 -0600 Subject: [PATCH 0125/1301] Do not cli in ps2d --- ps2d/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 87e6be3300..9f587c8818 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -192,7 +192,6 @@ impl char> Ps2d { fn daemon(input: File) { unsafe { iopl(3).expect("ps2d: failed to get I/O permission"); - asm!("cli" : : : : "intel", "volatile"); } let keymap = match env::args().skip(1).next() { From 3a8e40d78ca56273984a0ec18efd44af9a1c11f1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 21 Mar 2017 20:38:27 -0600 Subject: [PATCH 0126/1301] Yield unstead of spinning without interruption for loops in e1000d, add information about link speed --- e1000d/src/device.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 9f12fe124d..350857c558 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -182,7 +182,7 @@ impl Scheme for Intel8254x { unsafe { self.write(TDT, tail) }; while td.status == 0 { - unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } + thread::yield_now(); } return Ok(i); @@ -269,11 +269,9 @@ impl Intel8254x { pub unsafe fn init(&mut self) { self.flag(CTRL, CTRL_RST, true); - loop { - thread::sleep(time::Duration::new(0, 1000)); - if self.read(CTRL) & CTRL_RST != CTRL_RST { - break; - } + thread::sleep(time::Duration::new(0, 1000)); + while self.read(CTRL) & CTRL_RST == CTRL_RST { + thread::yield_now(); } // Enable auto negotiate, link, clear reset, do not Invert Loss-Of Signal @@ -357,9 +355,14 @@ impl Intel8254x { print!("{}", format!(" - IMS: {:X}\n", self.read(IMS))); + print!(" - Waiting for link up\n"); while self.read(STATUS) & 2 != 2 { - print!(" - Waiting for link up\n"); - thread::sleep(time::Duration::new(1, 0)); + thread::yield_now(); } + print!(" - Link is up with speed {}\n", match (self.read(STATUS) >> 6) & 0b11 { + 0b00 => "10 Mb/s", + 0b01 => "100 Mb/s", + _ => "1000 Mb/s", + }); } } From 898ec5acbddda7e7704873fc67b5ec7953127392 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 21 Mar 2017 20:38:57 -0600 Subject: [PATCH 0127/1301] Yield unstead of pause in loops in rtl8168d --- rtl8168d/src/device.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 1f09f8372c..9cb3205708 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -1,4 +1,4 @@ -use std::mem; +use std::{mem, thread}; use netutils::setcfg; use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; @@ -133,7 +133,7 @@ impl SchemeMut for Rtl8168 { self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet while self.regs.tppoll.readf(1 << 6) { - unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } + thread::yield_now(); } return Ok(i); @@ -224,7 +224,9 @@ impl Rtl8168 { // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value self.regs.cmd.writef(1 << 4, true); - while self.regs.cmd.readf(1 << 4) {} + while self.regs.cmd.readf(1 << 4) { + thread::yield_now(); + } // Set up rx buffers for i in 0..self.receive_ring.len() { From beef16096fb37b31b171f0f44b596c4a6019117d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 21 Mar 2017 20:52:39 -0600 Subject: [PATCH 0128/1301] Use thread::yield_now instead of pause in ahcid, e1000d, and rtl8168d Remove debugging from e1000d --- ahcid/src/ahci/hba.rs | 16 ++++++---------- e1000d/src/device.rs | 9 --------- rtl8168d/src/device.rs | 2 +- 3 files changed, 7 insertions(+), 20 deletions(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index f294f14b0e..4792cbb8d3 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -24,10 +24,6 @@ const HBA_SIG_ATAPI: u32 = 0xEB140101; const HBA_SIG_PM: u32 = 0x96690101; const HBA_SIG_SEMB: u32 = 0xC33C0101; -fn pause() { - unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } -} - #[derive(Debug)] pub enum HbaPortType { None, @@ -77,7 +73,7 @@ impl HbaPort { pub fn start(&mut self) { while self.cmd.readf(HBA_PORT_CMD_CR) { - pause(); + thread::yield_now(); } self.cmd.writef(HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST, true); @@ -87,7 +83,7 @@ impl HbaPort { self.cmd.writef(HBA_PORT_CMD_ST, false); while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { - pause(); + thread::yield_now(); } self.cmd.writef(HBA_PORT_CMD_FRE, false); @@ -163,7 +159,7 @@ impl HbaPort { } while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - pause(); + thread::yield_now(); } self.ci.writef(1 << slot, true); @@ -171,7 +167,7 @@ impl HbaPort { self.start(); while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { - pause(); + thread::yield_now(); } self.stop(); @@ -299,7 +295,7 @@ impl HbaPort { //print!("WAIT ATA_DEV_BUSY | ATA_DEV_DRQ\n"); } while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - pause(); + thread::yield_now(); } if write { @@ -313,7 +309,7 @@ impl HbaPort { //print!("{}", format!("WAIT CI {:X} in {:X}\n", 1 << slot, self.ci.read())); } while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { - pause(); + thread::yield_now(); if write { //print!("{}", format!("WAIT CI {:X} TFD {:X} IS {:X} CMD {:X} SERR {:X}\n", self.ci.read(), self.tfd.read(), self.is.read(), self.cmd.read(), self.serr.read())); } diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 350857c558..bfa6d51408 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -187,8 +187,6 @@ impl Scheme for Intel8254x { return Ok(i); } - - unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } } } @@ -348,13 +346,6 @@ impl Intel8254x { // TIPG Packet Gap // TODO ... - print!("{}", format!(" - CTRL: {:X}\n", self.read(CTRL))); - print!("{}", format!(" - STS: {:X}\n", self.read(STATUS))); - print!("{}", format!(" - RCTL: {:X}\n", self.read(RCTL))); - print!("{}", format!(" - TCTL: {:X}\n", self.read(TCTL))); - print!("{}", format!(" - IMS: {:X}\n", self.read(IMS))); - - print!(" - Waiting for link up\n"); while self.read(STATUS) & 2 != 2 { thread::yield_now(); diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 9cb3205708..bde150b626 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -140,7 +140,7 @@ impl SchemeMut for Rtl8168 { } } - unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); } + thread::yield_now(); } } From b6268ff95cfc7b3619902263eb9b57385ee2173c Mon Sep 17 00:00:00 2001 From: Ivan Chebykin Date: Wed, 22 Mar 2017 16:35:32 +0300 Subject: [PATCH 0129/1301] Fix missing use statement --- ahcid/src/ahci/hba.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 4792cbb8d3..5832042a5d 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -1,6 +1,7 @@ use std::mem::size_of; use std::ops::DerefMut; use std::{ptr, u32}; +use std::thread; use syscall::io::{Dma, Io, Mmio}; use syscall::error::{Error, Result, EIO}; From 4c93b53de0e0fbda46f115b8fe68ad73020f1eda Mon Sep 17 00:00:00 2001 From: Ivan Chebykin Date: Wed, 22 Mar 2017 17:01:49 +0300 Subject: [PATCH 0130/1301] Combine thread use statement with previous --- ahcid/src/ahci/hba.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 5832042a5d..53f54d77dc 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -1,7 +1,6 @@ use std::mem::size_of; use std::ops::DerefMut; -use std::{ptr, u32}; -use std::thread; +use std::{ptr, u32, thread}; use syscall::io::{Dma, Io, Mmio}; use syscall::error::{Error, Result, EIO}; From a0c5ab7911105649cb8c08fbf574e7dc0774f575 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 22 Mar 2017 15:59:53 -0600 Subject: [PATCH 0131/1301] WIP: VBox resize --- vboxd/src/bga.rs | 46 +++++++++++++++++++++++++++++++++++++ vboxd/src/main.rs | 24 ++++++++++++++++--- vesad/src/display.rs | 36 +++++++++++++++++++++++++++++ vesad/src/main.rs | 5 ++-- vesad/src/scheme.rs | 24 +++++++++++-------- vesad/src/screen/graphic.rs | 11 ++++++++- vesad/src/screen/mod.rs | 2 ++ vesad/src/screen/text.rs | 4 ++++ 8 files changed, 137 insertions(+), 15 deletions(-) create mode 100644 vboxd/src/bga.rs diff --git a/vboxd/src/bga.rs b/vboxd/src/bga.rs new file mode 100644 index 0000000000..21599f7fd0 --- /dev/null +++ b/vboxd/src/bga.rs @@ -0,0 +1,46 @@ +use syscall::io::{Io, Pio}; + +const BGA_INDEX_XRES: u16 = 1; +const BGA_INDEX_YRES: u16 = 2; +const BGA_INDEX_BPP: u16 = 3; +const BGA_INDEX_ENABLE: u16 = 4; + +pub struct Bga { + index: Pio, + data: Pio, +} + +impl Bga { + pub fn new() -> Bga { + Bga { + index: Pio::new(0x1CE), + data: Pio::new(0x1CF), + } + } + + fn read(&mut self, index: u16) -> u16 { + self.index.write(index); + self.data.read() + } + + fn write(&mut self, index: u16, data: u16) { + self.index.write(index); + self.data.write(data); + } + + pub fn width(&mut self) -> u16 { + self.read(BGA_INDEX_XRES) + } + + pub fn height(&mut self) -> u16 { + self.read(BGA_INDEX_YRES) + } + + pub fn set_size(&mut self, width: u16, height: u16) { + self.write(BGA_INDEX_ENABLE, 0); + self.write(BGA_INDEX_XRES, width); + self.write(BGA_INDEX_YRES, height); + self.write(BGA_INDEX_BPP, 32); + self.write(BGA_INDEX_ENABLE, 0x41); + } +} \ No newline at end of file diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 5c2af742a3..d84342a41c 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -13,6 +13,10 @@ use syscall::flag::MAP_WRITE; use syscall::io::{Dma, Io, Mmio, Pio}; use syscall::iopl; +use bga::Bga; + +mod bga; + const VBOX_REQUEST_HEADER_VERSION: u32 = 0x10001; const VBOX_VMMDEV_VERSION: u32 = 0x00010003; @@ -234,6 +238,7 @@ fn main() { let mut event_queue = EventQueue::<()>::new().expect("vboxd: failed to create event queue"); + let mut bga = Bga::new(); let get_mouse = VboxGetMouse::new().expect("vboxd: failed to map GetMouse"); let display_change = VboxDisplayChange::new().expect("vboxd: failed to map DisplayChange"); let ack_events = VboxAckEvents::new().expect("vboxd: failed to map AckEvents"); @@ -247,14 +252,27 @@ fn main() { if host_events & VBOX_EVENT_DISPLAY == VBOX_EVENT_DISPLAY { port.write(display_change.physical() as u32); - println!("Display {}, {}", display_change.xres.read(), display_change.yres.read()); + if let Some(ref mut display) = display_opt { + let new_width = display_change.xres.read(); + let new_height = display_change.yres.read(); + if width != new_width || height != new_height { + width = new_width; + height = new_height; + println!("Display {}, {}", width, height); + bga.set_size(width as u16, height as u16); + let _ = display.write(&orbclient::ResizeEvent { + width: width, + height: height, + }.to_event()); + } + } } if host_events & VBOX_EVENT_MOUSE == VBOX_EVENT_MOUSE { port.write(get_mouse.physical() as u32); - let x = get_mouse.x.read() * width / 0x10000; - let y = get_mouse.y.read() * height / 0x10000; if let Some(ref mut display) = display_opt { + let x = get_mouse.x.read() * width / 0x10000; + let y = get_mouse.y.read() * height / 0x10000; let _ = display.write(&orbclient::MouseEvent { x: x as i32, y: y as i32, diff --git a/vesad/src/display.rs b/vesad/src/display.rs index e8b7eb0e84..f6c37c417c 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -68,6 +68,36 @@ impl Display { } } + pub fn resize(&mut self, width: usize, height: usize) { + println!("Resize display to {}, {}", width, height); + + let size = width * height; + let offscreen = unsafe { heap::allocate(size * 4, 4096) }; + + { + let mut old_ptr = self.offscreen.as_ptr(); + let mut new_ptr = offscreen as *mut u32; + for _y in 0..cmp::min(height, self.height) { + unsafe { + fast_copy(new_ptr as *mut u8, old_ptr as *const u8, cmp::min(width, self.width) * 4); + old_ptr = old_ptr.offset(self.width as isize); + new_ptr = new_ptr.offset(width as isize); + } + } + } + + self.width = width; + self.height = height; + + let onscreen = self.onscreen.as_mut_ptr(); + self.onscreen = unsafe { slice::from_raw_parts_mut(onscreen, size) }; + + unsafe { heap::deallocate(self.offscreen.as_mut_ptr() as *mut u8, self.offscreen.len() * 4, 4096) }; + self.offscreen = unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }; + + self.sync(0, 0, width, height); + } + /// Draw a rectangle pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) { let start_y = cmp::min(self.height - 1, y); @@ -244,3 +274,9 @@ impl Display { } } } + +impl Drop for Display { + fn drop(&mut self) { + unsafe { heap::deallocate(self.offscreen.as_mut_ptr() as *mut u8, self.offscreen.len() * 4, 4096) }; + } +} diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 337f6a560b..211058cea5 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -55,8 +55,9 @@ fn main() { let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); let size = width * height; - - let onscreen = unsafe { physmap(physbaseptr, size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; + //TODO: Remap on resize + let largest_size = 8 * 1024 * 1024; + let onscreen = unsafe { physmap(physbaseptr, largest_size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; unsafe { fast_set64(onscreen as *mut u64, 0, size/2) }; let mut scheme = DisplayScheme::new(width, height, onscreen, &spec); diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 495dc44810..21fae86c2f 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -142,21 +142,27 @@ impl SchemeMut for DisplayScheme { let events = unsafe { slice::from_raw_parts(buf.as_ptr() as *const Event, buf.len()/mem::size_of::()) }; for event in events.iter() { - let new_active_opt = if let EventOption::Key(key_event) = event.to_option() { - match key_event.scancode { + let mut new_active_opt = None; + match event.to_option() { + EventOption::Key(key_event) => match key_event.scancode { f @ 0x3B ... 0x44 => { // F1 through F10 - Some((f - 0x3A) as usize) + new_active_opt = Some((f - 0x3A) as usize); }, 0x57 => { // F11 - Some(11) + new_active_opt = Some(11); }, 0x58 => { // F12 - Some(12) + new_active_opt = Some(12); }, - _ => None - } - } else { - None + _ => () + }, + EventOption::Resize(resize_event) => { + println!("Resizing to {}, {}", resize_event.width, resize_event.height); + for (_screen_id, screen) in self.screens.iter_mut() { + screen.resize(resize_event.width as usize, resize_event.height as usize); + } + }, + _ => () }; if let Some(new_active) = new_active_opt { diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 12a26a0a52..089787a81a 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use std::{cmp, mem, slice}; -use orbclient::Event; +use orbclient::{Event, ResizeEvent}; use syscall::error::*; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; @@ -36,6 +36,15 @@ impl Screen for GraphicScreen { self.display.height } + fn resize(&mut self, width: usize, height: usize) { + //TODO: Fix issue with mapped screens + self.display.resize(width, height); + self.input.push_back(ResizeEvent { + width: width as u32, + height: height as u32, + }.to_event()); + } + fn event(&mut self, flags: usize) -> Result { self.requested = flags; Ok(0) diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs index 9909694a99..4558546412 100644 --- a/vesad/src/screen/mod.rs +++ b/vesad/src/screen/mod.rs @@ -12,6 +12,8 @@ pub trait Screen { fn height(&self) -> usize; + fn resize(&mut self, width: usize, height: usize); + fn event(&mut self, flags: usize) -> Result; fn map(&self, offset: usize, size: usize) -> Result; diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index d7f226aaff..d9fd609219 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -43,6 +43,10 @@ impl Screen for TextScreen { self.console.h } + fn resize(&mut self, width: usize, height: usize) { + self.display.resize(width, height); + } + fn event(&mut self, flags: usize) -> Result { self.requested = flags; Ok(0) From b8aca0f5f0eff0a5357e8796e5775aa7871dfcad Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 22 Mar 2017 20:53:10 -0600 Subject: [PATCH 0132/1301] Fix bugs in resize in vesad --- bgad/src/main.rs | 2 +- vesad/src/display.rs | 71 +++++++++++++++++++++++++++----------------- vesad/src/scheme.rs | 5 +++- 3 files changed, 48 insertions(+), 30 deletions(-) diff --git a/bgad/src/main.rs b/bgad/src/main.rs index 479f62f3ab..eef1377e6e 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -25,6 +25,6 @@ fn main() { unsafe { iopl(3).unwrap() }; let mut bga = Bga::new(); - print!("{}", format!(" - BGA {}x{}", bga.width(), bga.height())); + print!("{}", format!(" - BGA {}x{}\n", bga.width(), bga.height())); } } diff --git a/vesad/src/display.rs b/vesad/src/display.rs index f6c37c417c..a697e406c8 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -69,41 +69,56 @@ impl Display { } pub fn resize(&mut self, width: usize, height: usize) { - println!("Resize display to {}, {}", width, height); + if width != self.width || height != self.height { + println!("Resize display to {}, {}", width, height); - let size = width * height; - let offscreen = unsafe { heap::allocate(size * 4, 4096) }; + let size = width * height; + let offscreen = unsafe { heap::allocate(size * 4, 4096) }; - { - let mut old_ptr = self.offscreen.as_ptr(); - let mut new_ptr = offscreen as *mut u32; - for _y in 0..cmp::min(height, self.height) { - unsafe { - fast_copy(new_ptr as *mut u8, old_ptr as *const u8, cmp::min(width, self.width) * 4); - old_ptr = old_ptr.offset(self.width as isize); - new_ptr = new_ptr.offset(width as isize); + { + let mut old_ptr = self.offscreen.as_ptr(); + let mut new_ptr = offscreen as *mut u32; + + for _y in 0..cmp::min(height, self.height) { + unsafe { + fast_copy(new_ptr as *mut u8, old_ptr as *const u8, cmp::min(width, self.width) * 4); + if width > self.width { + fast_set32(new_ptr.offset(self.width as isize), 0, width - self.width); + } + old_ptr = old_ptr.offset(self.width as isize); + new_ptr = new_ptr.offset(width as isize); + } + } + + if height > self.height { + for _y in self.height..height { + unsafe { + fast_set32(new_ptr, 0, width); + new_ptr = new_ptr.offset(width as isize); + } + } } } + + self.width = width; + self.height = height; + + let onscreen = self.onscreen.as_mut_ptr(); + self.onscreen = unsafe { slice::from_raw_parts_mut(onscreen, size) }; + + unsafe { heap::deallocate(self.offscreen.as_mut_ptr() as *mut u8, self.offscreen.len() * 4, 4096) }; + self.offscreen = unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }; + } else { + println!("Display is already {}, {}", width, height); } - - self.width = width; - self.height = height; - - let onscreen = self.onscreen.as_mut_ptr(); - self.onscreen = unsafe { slice::from_raw_parts_mut(onscreen, size) }; - - unsafe { heap::deallocate(self.offscreen.as_mut_ptr() as *mut u8, self.offscreen.len() * 4, 4096) }; - self.offscreen = unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }; - - self.sync(0, 0, width, height); } /// Draw a rectangle pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) { - let start_y = cmp::min(self.height - 1, y); + let start_y = cmp::min(self.height, y); let end_y = cmp::min(self.height, y + h); - let start_x = cmp::min(self.width - 1, x); + let start_x = cmp::min(self.width, x); let len = cmp::min(self.width, x + w) - start_x; let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; @@ -125,10 +140,10 @@ impl Display { /// Invert a rectangle pub fn invert(&mut self, x: usize, y: usize, w: usize, h: usize) { - let start_y = cmp::min(self.height - 1, y); + let start_y = cmp::min(self.height, y); let end_y = cmp::min(self.height, y + h); - let start_x = cmp::min(self.width - 1, x); + let start_x = cmp::min(self.width, x); let len = cmp::min(self.width, x + w) - start_x; let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; @@ -248,10 +263,10 @@ impl Display { /// Copy from offscreen to onscreen pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize) { - let start_y = cmp::min(self.height - 1, y); + let start_y = cmp::min(self.height, y); let end_y = cmp::min(self.height, y + h); - let start_x = cmp::min(self.width - 1, x); + let start_x = cmp::min(self.width, x); let len = (cmp::min(self.width, x + w) - start_x) * 4; let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 21fae86c2f..d34f74b67f 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -158,8 +158,11 @@ impl SchemeMut for DisplayScheme { }, EventOption::Resize(resize_event) => { println!("Resizing to {}, {}", resize_event.width, resize_event.height); - for (_screen_id, screen) in self.screens.iter_mut() { + for (screen_id, screen) in self.screens.iter_mut() { screen.resize(resize_event.width as usize, resize_event.height as usize); + if *screen_id == self.active { + screen.redraw(); + } } }, _ => () From 58246591c0bab69e1d9595ccf2e42a8b34b46e82 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 22 Mar 2017 22:15:58 -0600 Subject: [PATCH 0133/1301] Resize ransid --- vesad/src/screen/text.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index d9fd609219..ee9ee53026 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -45,6 +45,8 @@ impl Screen for TextScreen { fn resize(&mut self, width: usize, height: usize) { self.display.resize(width, height); + self.console.w = width / 8; + self.console.h = height / 16; } fn event(&mut self, flags: usize) -> Result { From ca262809dc795fef395db0c66156b14df4edc1e4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 23 Mar 2017 22:18:25 -0600 Subject: [PATCH 0134/1301] Fix issue with scroll on odd width display --- vesad/src/display.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index a697e406c8..8ab783f9b4 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -246,17 +246,15 @@ impl Display { /// Scroll display pub fn scroll(&mut self, rows: usize, color: u32) { - let data = (color as u64) << 32 | color as u64; - - let width = self.width/2; + let width = self.width; let height = self.height; if rows > 0 && rows < height { let off1 = rows * width; let off2 = height * width - off1; unsafe { - let data_ptr = self.offscreen.as_mut_ptr() as *mut u64; - fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2); - fast_set64(data_ptr.offset(off2 as isize), data, off1); + let data_ptr = self.offscreen.as_mut_ptr() as *mut u32; + fast_copy(data_ptr as *mut u8, data_ptr.offset(off1 as isize) as *const u8, off2 as usize * 4); + fast_set32(data_ptr.offset(off2 as isize), color, off1 as usize); } } } From 742bad2fd3b8ab51031f342c09aa6541486ec338 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 23 Mar 2017 22:19:38 -0600 Subject: [PATCH 0135/1301] Remove unused import --- vesad/src/display.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 8ab783f9b4..ec4afc90b7 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -4,7 +4,7 @@ extern crate rusttype; use alloc::heap; use std::{cmp, slice}; -use primitive::{fast_set32, fast_set64, fast_copy, fast_copy64}; +use primitive::{fast_set32, fast_set64, fast_copy}; #[cfg(feature="rusttype")] use self::rusttype::{Font, FontCollection, Scale, point}; From 8804e677025047fda545dd63d4e98a8a0973ed63 Mon Sep 17 00:00:00 2001 From: Meven Date: Sat, 25 Mar 2017 17:58:34 +0100 Subject: [PATCH 0136/1301] Add support for french azerty and bepo keymap --- ps2d/src/keymap.rs | 151 +++++++++++++++++++++++++++++++++++++++++++++ ps2d/src/main.rs | 2 + 2 files changed, 153 insertions(+) diff --git a/ps2d/src/keymap.rs b/ps2d/src/keymap.rs index 5697e52543..24c3ecda17 100644 --- a/ps2d/src/keymap.rs +++ b/ps2d/src/keymap.rs @@ -146,3 +146,154 @@ pub mod dvorak { } } } + +pub mod azerty { + static AZERTY: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['&', '1'], + ['é', '2'], + ['"', '3'], + ['\'', '4'], + ['(', '5'], + ['|', '6'], + ['è', '7'], + ['_', '8'], + ['ç', '9'], + ['à', '0'], + [')', '°'], + ['=', '+'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['a', 'A'], + ['z', 'Z'], + ['e', 'E'], + ['r', 'R'], + ['t', 'T'], + ['y', 'Y'], + ['u', 'U'], + ['i', 'I'], + ['o', 'O'], + ['p', 'P'], + ['^', '¨'], + ['$', '£'], + ['\n', '\n'], + ['\0', '\0'], + ['q', 'Q'], + ['s', 'S'], + ['d', 'D'], + ['f', 'F'], + ['g', 'G'], + ['h', 'H'], + ['j', 'J'], + ['k', 'K'], + ['l', 'L'], + ['m', 'M'], + ['ù', '%'], + ['*', 'µ'], + ['\0', '\0'], + ['ê', 'Ê'], + ['w', 'W'], + ['x', 'X'], + ['c', 'C'], + ['v', 'V'], + ['b', 'B'], + ['n', 'N'], + [',', '?'], + [';', '.'], + [':', '/'], + ['!', '§'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] + ]; + + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = AZERTY.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } + } else { + '\0' + } + } +} + +pub mod bepo { + static BEPO: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['"', '1'], + ['«', '2'], + ['»', '3'], + ['(', '4'], + [')', '5'], + ['@', '6'], + ['+', '7'], + ['-', '8'], + ['/', '9'], + ['*', '0'], + ['=', '°'], + ['%', '`'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['b', 'B'], + ['é', 'É'], + ['p', 'P'], + ['o', 'O'], + ['è', 'È'], + ['^', '!'], + ['v', 'V'], + ['d', 'D'], + ['l', 'L'], + ['j', 'J'], + ['z', 'Z'], + ['w', 'W'], + ['\n', '\n'], + ['\0', '\0'], + ['a', 'A'], + ['u', 'U'], + ['i', 'I'], + ['e', 'E'], + [',', ';'], + ['c', 'C'], + ['t', 'T'], + ['s', 'S'], + ['r', 'R'], + ['n', 'N'], + ['m', 'M'], + ['ç', 'Ç'], + ['\0', '\0'], + ['ê', 'Ê'], + ['à', 'À'], + ['y', 'Y'], + ['x', 'X'], + ['.', ':'], + ['k', 'K'], + ['\'', '?'], + ['q', 'Q'], + ['g', 'G'], + ['h', 'H'], + ['f', 'F'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] + ]; + + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = BEPO.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } + } else { + '\0' + } + } +} + diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 9f587c8818..a63405659b 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -198,6 +198,8 @@ fn daemon(input: File) { Some(k) => match k.to_lowercase().as_ref() { "dvorak" => (keymap::dvorak::get_char), "english" => (keymap::english::get_char), + "azerty" => (keymap::azerty::get_char), + "bepo" => (keymap::bepo::get_char), &_ => (keymap::english::get_char) }, None => (keymap::english::get_char) From 0b94ce28e4c7ba88e35efbd935e766ebe7edfdd5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 26 Mar 2017 15:24:25 -0600 Subject: [PATCH 0137/1301] WIP: ALX driver --- alxd/Cargo.toml | 9 + alxd/src/device/mod.rs | 1896 ++++++++++++++++++++++++++++++++ alxd/src/device/regs.rs | 2295 +++++++++++++++++++++++++++++++++++++++ alxd/src/main.rs | 138 +++ pcid/src/main.rs | 5 +- 5 files changed, 4341 insertions(+), 2 deletions(-) create mode 100644 alxd/Cargo.toml create mode 100644 alxd/src/device/mod.rs create mode 100644 alxd/src/device/regs.rs create mode 100644 alxd/src/main.rs diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml new file mode 100644 index 0000000000..ac2329863e --- /dev/null +++ b/alxd/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "alxd" +version = "0.1.0" + +[dependencies] +bitflags = "0.7" +netutils = { git = "https://github.com/redox-os/netutils.git" } +redox_event = { git = "https://github.com/redox-os/event.git" } +redox_syscall = "0.1" diff --git a/alxd/src/device/mod.rs b/alxd/src/device/mod.rs new file mode 100644 index 0000000000..ebdd04e42a --- /dev/null +++ b/alxd/src/device/mod.rs @@ -0,0 +1,1896 @@ +use std::{cmp, mem, ptr, slice, thread, time}; + +use netutils::setcfg; +use syscall::error::{Error, EACCES, EINVAL, EIO, EWOULDBLOCK, Result}; +use syscall::flag::O_NONBLOCK; +use syscall::io::{Dma, Io, Mmio}; +use syscall::scheme; + +use self::regs::*; + +mod regs; + +const ERR_ALOAD: usize = 1; +const ERR_RSTMAC: usize = 2; +const ERR_PARM: usize = 3; +const ERR_MIIBUSY: usize = 4; +const LINK_TIMEOUT: usize = 8; + +const FLAG_HALT: u32 = 0; +const FLAG_TASK_RESET: u32 = 1; +const FLAG_TASK_CHK_LINK: u32 = 2; +const FLAG_TASK_UPDATE_SMB: u32 = 3; + +const HALF_DUPLEX: u8 = 1; +const FULL_DUPLEX: u8 = 2; + +const SPEED_0: u16 = 0; +const SPEED_10: u16 = 10; +const SPEED_100: u16 = 100; +const SPEED_1000: u16 = 1000; + +const FC_RX: u8 = 0x01; +const FC_TX: u8 = 0x02; +const FC_ANEG: u8 = 0x04; + +const CAP_GIGA: u32 = 1 << 0; +const CAP_PTP: u32 = 1 << 1; +const CAP_AZ: u32 = 1 << 2; +const CAP_L0S: u32 = 1 << 3; +const CAP_L1: u32 = 1 << 4; +const CAP_SWOI: u32 = 1 << 5; +const CAP_RSS: u32 = 1 << 6; +const CAP_MSIX: u32 = 1 << 7; +/* support Multi-TX-Q */ +const CAP_MTQ: u32 = 1 << 8; +/* support Multi-RX-Q */ +const CAP_MRQ: u32 = 1 << 9; + +const ISR_MISC: u32 = + ISR_PCIE_LNKDOWN | + ISR_DMAW | + ISR_DMAR | + ISR_SMB | + ISR_MANU | + ISR_TIMER; + +const ISR_FATAL: u32 = + ISR_PCIE_LNKDOWN | + ISR_DMAW | + ISR_DMAR; + +const ISR_ALERT: u32 = + ISR_RXF_OV | + ISR_TXF_UR | + ISR_RFD_UR; + +const ISR_ALL_QUEUES: u32 = + ISR_TX_Q0 | + ISR_TX_Q1 | + ISR_TX_Q2 | + ISR_TX_Q3 | + ISR_RX_Q0 | + ISR_RX_Q1 | + ISR_RX_Q2 | + ISR_RX_Q3 | + ISR_RX_Q4 | + ISR_RX_Q5 | + ISR_RX_Q6 | + ISR_RX_Q7; + +const PCI_COMMAND_IO: u16 = 0x1; /* Enable response in I/O space */ +const PCI_COMMAND_MEMORY: u16 = 0x2; /* Enable response in Memory space */ +const PCI_COMMAND_MASTER: u16 = 0x4; /* Enable bus mastering */ +const PCI_COMMAND_SPECIAL: u16 = 0x8; /* Enable response to special cycles */ +const PCI_COMMAND_INVALIDATE: u16 = 0x10; /* Use memory write and invalidate */ +const PCI_COMMAND_VGA_PALETTE: u16 = 0x20; /* Enable palette snooping */ +const PCI_COMMAND_PARITY: u16 = 0x40; /* Enable parity checking */ +const PCI_COMMAND_WAIT: u16 = 0x80; /* Enable address/data stepping */ +const PCI_COMMAND_SERR: u16 = 0x100; /* Enable SERR */ +const PCI_COMMAND_FAST_BACK: u16 = 0x200; /* Enable back-to-back writes */ +const PCI_COMMAND_INTX_DISABLE: u16 = 0x400;/* INTx Emulation Disable */ + +/// MII basic mode control register +const MII_BMCR: u16 = 0x00; + const BMCR_FULLDPLX: u16 = 0x0100; + const BMCR_ANRESTART: u16 = 0x0200; + const BMCR_ANENABLE: u16 = 0x1000; + const BMCR_SPEED100: u16 = 0x2000; + const BMCR_RESET: u16 = 0x8000; + +/// MII basic mode status register +const MII_BMSR: u16 = 0x01; + const BMSR_LSTATUS: u16 = 0x0004; + +/// MII advertisement register +const MII_ADVERTISE: u16 = 0x04; + +/// MII 1000BASE-T control +const MII_CTRL1000: u16 = 0x09; + +const ETH_HLEN: u16 = 14; + +const ADVERTISED_10baseT_Half: u32 = 1 << 0; +const ADVERTISED_10baseT_Full: u32 = 1 << 1; +const ADVERTISED_100baseT_Half: u32 = 1 << 2; +const ADVERTISED_100baseT_Full: u32 = 1 << 3; +const ADVERTISED_1000baseT_Half: u32 = 1 << 4; +const ADVERTISED_1000baseT_Full: u32 = 1 << 5; +const ADVERTISED_Autoneg: u32 = 1 << 6; +const ADVERTISED_Pause: u32 = 1 << 13; +const ADVERTISED_Asym_Pause: u32 = 1 << 14; + +const ADVERTISE_CSMA: u32 = 0x0001; /* Only selector supported */ +const ADVERTISE_10HALF: u32 = 0x0020; /* Try for 10mbps half-duplex */ +const ADVERTISE_1000XFULL: u32 = 0x0020; /* Try for 1000BASE-X full-duplex */ +const ADVERTISE_10FULL: u32 = 0x0040; /* Try for 10mbps full-duplex */ +const ADVERTISE_1000XHALF: u32 = 0x0040; /* Try for 1000BASE-X half-duplex */ +const ADVERTISE_100HALF: u32 = 0x0080; /* Try for 100mbps half-duplex */ +const ADVERTISE_1000XPAUSE: u32 = 0x0080; /* Try for 1000BASE-X pause */ +const ADVERTISE_100FULL: u32 = 0x0100; /* Try for 100mbps full-duplex */ +const ADVERTISE_1000XPSE_ASYM: u32 = 0x0100; /* Try for 1000BASE-X asym pause */ +const ADVERTISE_100BASE4: u32 = 0x0200; /* Try for 100mbps 4k packets */ +const ADVERTISE_PAUSE_CAP: u32 = 0x0400; /* Try for pause */ +const ADVERTISE_PAUSE_ASYM: u32 = 0x0800; /* Try for asymetric pause */ + +const ADVERTISE_1000HALF: u32 = 0x0100; +const ADVERTISE_1000FULL: u32 = 0x0200; + +macro_rules! FIELD_GETX { + ($x:expr, $name:ident) => (( + ((($x) >> concat_idents!($name, _SHIFT)) & concat_idents!($name, _MASK)) + )) +} + +macro_rules! FIELDX { + ($name:ident, $v:expr) => (( + ((($v) as u32) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT) + )) +} + +macro_rules! FIELD_SETS { + ($x:expr, $name:ident, $v:expr) => {{ + ($x) = (($x) & !(concat_idents!($name, _MASK) << concat_idents!($name, _SHIFT))) + | (((($v) as u16) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT)) + }} +} + +macro_rules! FIELD_SET32 { + ($x:expr, $name:ident, $v:expr) => {{ + ($x) = (($x) & !(concat_idents!($name, _MASK) << concat_idents!($name, _SHIFT))) + | (((($v) as u32) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT)) + }} +} + +fn udelay(micros: u32) { + thread::sleep(time::Duration::new(0, micros * 1000)); +} + +fn ethtool_adv_to_mii_adv_t(ethadv: u32) -> u32 { + let mut result: u32 = 0; + + if (ethadv & ADVERTISED_10baseT_Half > 0) { + result |= ADVERTISE_10HALF; + } + if (ethadv & ADVERTISED_10baseT_Full > 0) { + result |= ADVERTISE_10FULL; + } + if (ethadv & ADVERTISED_100baseT_Half > 0) { + result |= ADVERTISE_100HALF; + } + if (ethadv & ADVERTISED_100baseT_Full > 0) { + result |= ADVERTISE_100FULL; + } + if (ethadv & ADVERTISED_Pause > 0) { + result |= ADVERTISE_PAUSE_CAP; + } + if (ethadv & ADVERTISED_Asym_Pause > 0) { + result |= ADVERTISE_PAUSE_ASYM; + } + + return result; +} + +fn ethtool_adv_to_mii_ctrl1000_t(ethadv: u32) -> u32 { + let mut result: u32 = 0; + + if (ethadv & ADVERTISED_1000baseT_Half > 0) { + result |= ADVERTISE_1000HALF; + } + if (ethadv & ADVERTISED_1000baseT_Full > 0) { + result |= ADVERTISE_1000FULL; + } + + return result; +} + +/// Transmit packet descriptor +#[repr(packed)] +struct Tpd { + blen: Mmio, + vlan: Mmio, + flags: Mmio, + addr: Mmio, +} + +/// Receive free descriptor +#[repr(packed)] +struct Rfd { + addr: Mmio, +} + +/// Receive return descriptor +#[repr(packed)] +struct Rrd { + checksum: Mmio, + rfd: Mmio, + rss: Mmio, + vlan: Mmio, + proto: Mmio, + rss_flags: Mmio, + len: Mmio, + flags: Mmio, +} + +pub struct Alx { + base: usize, + + vendor_id: u16, + device_id: u16, + subdev_id: u16, + subven_id: u16, + revision: u8, + + cap: u32, + flag: u32, + + mtu: u16, + imt: u16, + dma_chnl: u8, + ith_tpd: u32, + mc_hash: [u32; 2], + + wrr: [u32; 4], + wrr_ctrl: u32, + + imask: u32, + smb_timer: u32, + link_up: bool, + link_speed: u16, + link_duplex: u8, + + adv_cfg: u32, + flowctrl: u8, + + rx_ctrl: u32, + + lnk_patch: bool, + hib_patch: bool, + is_fpga: bool, + + rfd_buffer: [Dma<[u8; 16384]>; 16], + rfd_ring: Dma<[Rfd; 16]>, + rrd_ring: Dma<[Rrd; 16]>, + tpd_buffer: [Dma<[u8; 16384]>; 16], + tpd_ring: [Dma<[Tpd; 16]>; 4], +} + +impl Alx { + pub unsafe fn new(base: usize) -> Result { + let mut module = Alx { + base: base, + + vendor_id: 0, + device_id: 0, + subdev_id: 0, + subven_id: 0, + revision: 0, + + cap: 0, + flag: 0, + + mtu: 1500, /*TODO: Get from adapter?*/ + imt: 200, + dma_chnl: 0, + ith_tpd: 5, /* ~ size of tpd_ring / 3 */ + mc_hash: [0; 2], + + wrr: [4; 4], + wrr_ctrl: WRR_PRI_RESTRICT_NONE, + + imask: ISR_MISC, + smb_timer: 400, + link_up: false, + link_speed: 0, + link_duplex: 0, + + adv_cfg: ADVERTISED_Autoneg | + ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_1000baseT_Full, + flowctrl: FC_ANEG | FC_RX | FC_TX, + + rx_ctrl: MAC_CTRL_WOLSPED_SWEN | + MAC_CTRL_MHASH_ALG_HI5B | + MAC_CTRL_BRD_EN | + MAC_CTRL_PCRCE | + MAC_CTRL_CRCE | + MAC_CTRL_RXFC_EN | + MAC_CTRL_TXFC_EN | + FIELDX!(MAC_CTRL_PRMBLEN, 7), + + lnk_patch: false, + hib_patch: false, + is_fpga: false, + + rfd_buffer: [ + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()? + ], + rfd_ring: Dma::zeroed()?, + rrd_ring: Dma::zeroed()?, + tpd_buffer: [ + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()? + ], + tpd_ring: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?] + }; + + module.init()?; + + Ok(module) + } + + pub fn revid(&self) -> u8 { + self.revision >> PCI_REVID_SHIFT + } + + pub fn with_cr(&self) -> bool { + self.revision & 1 > 0 + } + + unsafe fn handle_intr_misc(&mut self, intr: u32) -> bool { + if (intr & ISR_FATAL > 0) { + println!("intr-fatal: {:X}", intr); + self.flag |= FLAG_TASK_RESET; + self.task(); + return true; + } + + if (intr & ISR_ALERT > 0) { + println!("interrupt alert: {:X}", intr); + } + + if (intr & ISR_SMB > 0) { + self.flag |= FLAG_TASK_UPDATE_SMB; + self.task(); + } + + if (intr & ISR_PHY > 0) { + /* suppress PHY interrupt, because the source + * is from PHY internal. only the internal status + * is cleared, the interrupt status could be cleared. + */ + self.imask &= !ISR_PHY; + let imask = self.imask; + self.write(IMR, imask); + self.flag |= FLAG_TASK_CHK_LINK; + self.task(); + } + + return false; + } + + unsafe fn intr_1(&mut self, mut intr: u32) -> bool { + /* ACK interrupt */ + println!("ACK interrupt: {:X}", intr | ISR_DIS); + self.write(ISR, intr | ISR_DIS); + intr &= self.imask; + + if (self.handle_intr_misc(intr)) { + return true; + } + + if (intr & (ISR_TX_Q0 | ISR_RX_Q0) > 0) { + println!("TX | RX"); + //TODO: napi_schedule(&adpt->qnapi[0]->napi); + /* mask rx/tx interrupt, enable them when napi complete */ + self.imask &= !ISR_ALL_QUEUES; + let imask = self.imask; + self.write(IMR, imask); + } + + self.write(ISR, 0); + + return true; + } + + pub unsafe fn intr_legacy(&mut self) -> bool { + /* read interrupt status */ + let intr = self.read(ISR); + if (intr & ISR_DIS > 0 || intr & self.imask == 0) { + let mask = self.read(IMR); + println!("seems a wild interrupt, intr={:X}, imask={:X}, mask={:X}", intr, self.imask, mask); + + return false; + } + + return self.intr_1(intr); + } + + pub fn next_read(&self) -> usize { + /* + let head = unsafe { self.read(RDH) }; + let mut tail = unsafe { self.read(RDT) }; + + tail += 1; + if tail >= self.receive_ring.len() as u32 { + tail = 0; + } + + if tail != head { + let rd = unsafe { &* (self.receive_ring.as_ptr().offset(tail as isize) as *const Rd) }; + if rd.status & RD_DD == RD_DD { + return rd.length as usize; + } + } + + 0 + */ + 0 + } + + unsafe fn read(&self, register: u32) -> u32 { + ptr::read_volatile((self.base + register as usize) as *mut u32) + } + + unsafe fn write(&self, register: u32, data: u32) -> u32 { + ptr::write_volatile((self.base + register as usize) as *mut u32, data); + ptr::read_volatile((self.base + register as usize) as *mut u32) + } + + unsafe fn wait_mdio_idle(&mut self) -> bool { + let mut val: u32; + let mut i: u32 = 0; + + while (i < MDIO_MAX_AC_TO) { + val = self.read(MDIO); + if (val & MDIO_BUSY == 0) { + break; + } + udelay(10); + i += 1; + } + return i != MDIO_MAX_AC_TO; + } + + unsafe fn stop_phy_polling(&mut self) { + if (!self.is_fpga) { + return; + } + + self.write(MDIO, 0); + self.wait_mdio_idle(); + } + + unsafe fn start_phy_polling(&mut self, clk_sel: u16) { + let mut val: u32; + + if (!self.is_fpga) { + return; + } + + val = MDIO_SPRES_PRMBL | + FIELDX!(MDIO_CLK_SEL, clk_sel) | + FIELDX!(MDIO_REG, 1) | + MDIO_START | + MDIO_OP_READ; + self.write(MDIO, val); + self.wait_mdio_idle(); + val |= MDIO_AUTO_POLLING; + val &= !MDIO_START; + self.write(MDIO, val); + udelay(30); + } + + unsafe fn read_phy_core(&mut self, ext: bool, dev: u8, reg: u16, phy_data: &mut u16) -> usize { + let mut val: u32; + let clk_sel: u16; + let err: usize; + + self.stop_phy_polling(); + + *phy_data = 0; + + /* use slow clock when it's in hibernation status */ + clk_sel = if !self.link_up { MDIO_CLK_SEL_25MD128 } else { MDIO_CLK_SEL_25MD4 }; + + if (ext) { + val = FIELDX!(MDIO_EXTN_DEVAD, dev) | + FIELDX!(MDIO_EXTN_REG, reg); + self.write(MDIO_EXTN, val); + + val = MDIO_SPRES_PRMBL | + FIELDX!(MDIO_CLK_SEL, clk_sel) | + MDIO_START | + MDIO_MODE_EXT | + MDIO_OP_READ; + } else { + val = MDIO_SPRES_PRMBL | + FIELDX!(MDIO_CLK_SEL, clk_sel) | + FIELDX!(MDIO_REG, reg) | + MDIO_START | + MDIO_OP_READ; + } + self.write(MDIO, val); + + if (! self.wait_mdio_idle()) { + err = ERR_MIIBUSY; + } else { + val = self.read(MDIO); + *phy_data = FIELD_GETX!(val, MDIO_DATA) as u16; + err = 0; + } + + self.start_phy_polling(clk_sel); + + return err; + } + + unsafe fn write_phy_core(&mut self, ext: bool, dev: u8, reg: u16, phy_data: u16) -> usize { + let mut val: u32; + let clk_sel: u16; + let mut err: usize = 0; + + self.stop_phy_polling(); + + /* use slow clock when it's in hibernation status */ + clk_sel = if ! self.link_up { MDIO_CLK_SEL_25MD128 } else { MDIO_CLK_SEL_25MD4 }; + + if (ext) { + val = FIELDX!(MDIO_EXTN_DEVAD, dev) | + FIELDX!(MDIO_EXTN_REG, reg); + self.write(MDIO_EXTN, val); + + val = MDIO_SPRES_PRMBL | + FIELDX!(MDIO_CLK_SEL, clk_sel) | + FIELDX!(MDIO_DATA, phy_data) | + MDIO_START | + MDIO_MODE_EXT; + } else { + val = MDIO_SPRES_PRMBL | + FIELDX!(MDIO_CLK_SEL, clk_sel) | + FIELDX!(MDIO_REG, reg) | + FIELDX!(MDIO_DATA, phy_data) | + MDIO_START; + } + self.write(MDIO, val); + + if ! self.wait_mdio_idle() { + err = ERR_MIIBUSY; + } + + self.start_phy_polling(clk_sel); + + return err; + } + + unsafe fn read_phy_reg(&mut self, reg: u16, phy_data: &mut u16) -> usize { + self.read_phy_core(false, 0, reg, phy_data) + } + + unsafe fn write_phy_reg(&mut self, reg: u16, phy_data: u16) -> usize { + self.write_phy_core(false, 0, reg, phy_data) + } + + unsafe fn read_phy_ext(&mut self, dev: u8, reg: u16, data: &mut u16) -> usize { + self.read_phy_core(true, dev, reg, data) + } + + unsafe fn write_phy_ext(&mut self, dev: u8, reg: u16, data: u16) -> usize { + self.write_phy_core(true, dev, reg, data) + } + + unsafe fn read_phy_dbg(&mut self, reg: u16, data: &mut u16) -> usize { + let err = self.write_phy_reg(MII_DBG_ADDR, reg); + if (err > 0) { + return err; + } + + self.read_phy_reg(MII_DBG_DATA, data) + } + + unsafe fn write_phy_dbg(&mut self, reg: u16, data: u16) -> usize { + let err = self.write_phy_reg(MII_DBG_ADDR, reg); + if (err > 0) { + return err; + } + + self.write_phy_reg(MII_DBG_DATA, data) + } + + unsafe fn enable_aspm(&mut self, l0s_en: bool, l1_en: bool) { + let mut pmctrl: u32; + let rev: u8 = self.revid(); + + pmctrl = self.read(PMCTRL); + + FIELD_SET32!(pmctrl, PMCTRL_LCKDET_TIMER, PMCTRL_LCKDET_TIMER_DEF); + pmctrl |= PMCTRL_RCVR_WT_1US | + PMCTRL_L1_CLKSW_EN | + PMCTRL_L1_SRDSRX_PWD ; + FIELD_SET32!(pmctrl, PMCTRL_L1REQ_TO, PMCTRL_L1REG_TO_DEF); + FIELD_SET32!(pmctrl, PMCTRL_L1_TIMER, PMCTRL_L1_TIMER_16US); + pmctrl &= !(PMCTRL_L1_SRDS_EN | + PMCTRL_L1_SRDSPLL_EN | + PMCTRL_L1_BUFSRX_EN | + PMCTRL_SADLY_EN | + PMCTRL_HOTRST_WTEN| + PMCTRL_L0S_EN | + PMCTRL_L1_EN | + PMCTRL_ASPM_FCEN | + PMCTRL_TXL1_AFTER_L0S | + PMCTRL_RXL1_AFTER_L0S + ); + if ((rev == REV_A0 || rev == REV_A1) && self.with_cr()) { + pmctrl |= PMCTRL_L1_SRDS_EN | PMCTRL_L1_SRDSPLL_EN; + } + + if (l0s_en) { + pmctrl |= (PMCTRL_L0S_EN | PMCTRL_ASPM_FCEN); + } + if (l1_en) { + pmctrl |= (PMCTRL_L1_EN | PMCTRL_ASPM_FCEN); + } + + self.write(PMCTRL, pmctrl); + } + + unsafe fn reset_pcie(&mut self) { + let mut val: u32; + let rev: u8 = self.revid(); + + /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */ + let mut val16 = ptr::read((self.base + 4) as *const u16); + if (val16 & (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO) == 0 + || val16 & PCI_COMMAND_INTX_DISABLE > 0) { + println!("Fix PCI_COMMAND_INTX_DISABLE"); + val16 = (val16 | (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) & !PCI_COMMAND_INTX_DISABLE; + ptr::write((self.base + 4) as *mut u16, val16); + } + + /* clear WoL setting/status */ + val = self.read(WOL0); + self.write(WOL0, 0); + + /* deflt val of PDLL D3PLLOFF */ + val = self.read(PDLL_TRNS1); + self.write(PDLL_TRNS1, val & !PDLL_TRNS1_D3PLLOFF_EN); + + /* mask some pcie error bits */ + val = self.read(UE_SVRT); + val &= !(UE_SVRT_DLPROTERR | UE_SVRT_FCPROTERR); + self.write(UE_SVRT, val); + + /* wol 25M & pclk */ + val = self.read(MASTER); + if ((rev == REV_A0 || rev == REV_A1) && self.with_cr()) { + if ((val & MASTER_WAKEN_25M) == 0 || + (val & MASTER_PCLKSEL_SRDS) == 0) { + self.write(MASTER, + val | MASTER_PCLKSEL_SRDS | + MASTER_WAKEN_25M); + } + } else { + if ((val & MASTER_WAKEN_25M) == 0 || + (val & MASTER_PCLKSEL_SRDS) != 0) { + self.write(MASTER, + (val & !MASTER_PCLKSEL_SRDS) | + MASTER_WAKEN_25M); + } + } + + /* ASPM setting */ + let l0s_en = self.cap & CAP_L0S > 0; + let l1_en = self.cap & CAP_L1 > 0; + self.enable_aspm(l0s_en, l1_en); + + udelay(10); + } + + unsafe fn reset_phy(&mut self) { + let mut i: u32; + let mut val: u32; + let mut phy_val: u16 = 0; + + /* (DSP)reset PHY core */ + val = self.read(PHY_CTRL); + val &= !(PHY_CTRL_DSPRST_OUT | PHY_CTRL_IDDQ | + PHY_CTRL_GATE_25M | PHY_CTRL_POWER_DOWN | + PHY_CTRL_CLS); + val |= PHY_CTRL_RST_ANALOG; + + if (! self.hib_patch) { + val |= (PHY_CTRL_HIB_PULSE | PHY_CTRL_HIB_EN); + } else { + val &= !(PHY_CTRL_HIB_PULSE | PHY_CTRL_HIB_EN); + } + self.write(PHY_CTRL, val); + udelay(10); + self.write(PHY_CTRL, val | PHY_CTRL_DSPRST_OUT); + + /* delay 800us */ + i = 0; + while (i < PHY_CTRL_DSPRST_TO) { + udelay(10); + i += 1; + } + + if ! self.is_fpga { + /* phy power saving & hib */ + if (! self.hib_patch) { + self.write_phy_dbg(MIIDBG_LEGCYPS, LEGCYPS_DEF); + self.write_phy_dbg(MIIDBG_SYSMODCTRL, + SYSMODCTRL_IECHOADJ_DEF); + self.write_phy_ext(MIIEXT_PCS, MIIEXT_VDRVBIAS, VDRVBIAS_DEF); + } else { + self.write_phy_dbg(MIIDBG_LEGCYPS, + LEGCYPS_DEF & !LEGCYPS_EN); + self.write_phy_dbg(MIIDBG_HIBNEG, HIBNEG_NOHIB); + self.write_phy_dbg(MIIDBG_GREENCFG, GREENCFG_DEF); + } + + /* EEE advertisement */ + if (self.cap & CAP_AZ > 0) { + let eeeadv = if self.cap & CAP_GIGA > 0 { + LOCAL_EEEADV_1000BT | LOCAL_EEEADV_100BT + } else { + LOCAL_EEEADV_100BT + }; + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_LOCAL_EEEADV, eeeadv); + /* half amplify */ + self.write_phy_dbg(MIIDBG_AZ_ANADECT, + AZ_ANADECT_DEF); + } else { + val = self.read(LPI_CTRL); + self.write(LPI_CTRL, val & (!LPI_CTRL_EN)); + self.write_phy_ext(MIIEXT_ANEG, + MIIEXT_LOCAL_EEEADV, 0); + } + + /* phy power saving */ + self.write_phy_dbg(MIIDBG_TST10BTCFG, TST10BTCFG_DEF); + self.write_phy_dbg(MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF); + self.write_phy_dbg(MIIDBG_TST100BTCFG, TST100BTCFG_DEF); + self.write_phy_dbg(MIIDBG_ANACTRL, ANACTRL_DEF); + self.read_phy_dbg(MIIDBG_GREENCFG2, &mut phy_val); + self.write_phy_dbg(MIIDBG_GREENCFG2, phy_val & (!GREENCFG2_GATE_DFSE_EN)); + /* rtl8139c, 120m issue */ + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_NLP78, MIIEXT_NLP78_120M_DEF); + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_S3DIG10, MIIEXT_S3DIG10_DEF); + + if (self.lnk_patch) { + /* Turn off half amplitude */ + self.read_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL3, &mut phy_val); + self.write_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL3, phy_val | CLDCTRL3_BP_CABLE1TH_DET_GT); + /* Turn off Green feature */ + self.read_phy_dbg(MIIDBG_GREENCFG2, &mut phy_val); + self.write_phy_dbg(MIIDBG_GREENCFG2, phy_val | GREENCFG2_BP_GREEN); + /* Turn off half Bias */ + self.read_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL5, &mut phy_val); + self.write_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL5, phy_val | CLDCTRL5_BP_VD_HLFBIAS); + } + } + + /* set phy interrupt mask */ + self.write_phy_reg(MII_IER, IER_LINK_UP | IER_LINK_DOWN); + } + + + unsafe fn stop_mac(&mut self) -> usize { + let txq: u32; + let rxq: u32; + let mut val: u32; + let mut i: u32; + + rxq = self.read(RXQ0); + self.write(RXQ0, rxq & (!RXQ0_EN)); + txq = self.read(TXQ0); + self.write(TXQ0, txq & (!TXQ0_EN)); + + udelay(40); + + self.rx_ctrl &= !(MAC_CTRL_RX_EN | MAC_CTRL_TX_EN); + self.write(MAC_CTRL, self.rx_ctrl); + + i = 0; + while i < DMA_MAC_RST_TO { + val = self.read(MAC_STS); + if (val & MAC_STS_IDLE == 0) { + break; + } + udelay(10); + i += 1; + } + + return if (DMA_MAC_RST_TO == i) { ERR_RSTMAC as usize } else { 0 }; + } + + unsafe fn start_mac(&mut self) { + let mut mac: u32; + let txq: u32; + let rxq: u32; + + rxq = self.read(RXQ0); + self.write(RXQ0, rxq | RXQ0_EN); + txq = self.read(TXQ0); + self.write(TXQ0, txq | TXQ0_EN); + + mac = self.rx_ctrl; + if (self.link_duplex == FULL_DUPLEX) { + mac |= MAC_CTRL_FULLD; + } else { + mac &= !MAC_CTRL_FULLD; + } + FIELD_SET32!(mac, MAC_CTRL_SPEED, if self.link_speed == 1000 { + MAC_CTRL_SPEED_1000 + } else { + MAC_CTRL_SPEED_10_100 + }); + mac |= MAC_CTRL_TX_EN | MAC_CTRL_RX_EN; + self.rx_ctrl = mac; + self.write(MAC_CTRL, mac); + } + + unsafe fn reset_osc(&mut self, rev: u8) { + let mut val: u32; + let mut val2: u32; + + /* clear Internal OSC settings, switching OSC by hw itself */ + val = self.read(MISC3); + self.write(MISC3, + (val & !MISC3_25M_BY_SW) | MISC3_25M_NOTO_INTNL); + + /* 25M clk from chipset may be unstable 1s after de-assert of + * PERST, driver need re-calibrate before enter Sleep for WoL + */ + val = self.read(MISC); + if (rev >= REV_B0) { + /* restore over current protection def-val, + * this val could be reset by MAC-RST + */ + FIELD_SET32!(val, MISC_PSW_OCP, MISC_PSW_OCP_DEF); + /* a 0->1 change will update the internal val of osc */ + val &= !MISC_INTNLOSC_OPEN; + self.write(MISC, val); + self.write(MISC, val | MISC_INTNLOSC_OPEN); + /* hw will automatically dis OSC after cab. */ + val2 = self.read(MSIC2); + val2 &= !MSIC2_CALB_START; + self.write(MSIC2, val2); + self.write(MSIC2, val2 | MSIC2_CALB_START); + } else { + val &= !MISC_INTNLOSC_OPEN; + /* disable isoloate for A0 */ + if ((rev == REV_A0 || rev == REV_A1)) { + val &= !MISC_ISO_EN; + } + + self.write(MISC, val | MISC_INTNLOSC_OPEN); + self.write(MISC, val); + } + + udelay(20); + } + + unsafe fn reset_mac(&mut self) -> usize { + let mut val: u32; + let mut pmctrl: u32; + let mut i: u32; + let ret: usize; + let rev: u8; + let a_cr: bool; + + pmctrl = 0; + rev = self.revid(); + a_cr = (rev == REV_A0 || rev == REV_A1) && self.with_cr(); + + /* disable all interrupts, RXQ/TXQ */ + self.write(MSIX_MASK, 0xFFFFFFFF); + self.write(IMR, 0); + self.write(ISR, ISR_DIS); + + ret = self.stop_mac(); + if (ret > 0) { + return ret; + } + + /* mac reset workaroud */ + self.write(RFD_PIDX, 1); + + /* dis l0s/l1 before mac reset */ + if (a_cr) { + pmctrl = self.read(PMCTRL); + if ((pmctrl & (PMCTRL_L1_EN | PMCTRL_L0S_EN)) != 0) { + self.write(PMCTRL, pmctrl & !(PMCTRL_L1_EN | PMCTRL_L0S_EN)); + } + } + + /* reset whole mac safely */ + val = self.read(MASTER); + self.write(MASTER, val | MASTER_DMA_MAC_RST | MASTER_OOB_DIS); + + /* make sure it's real idle */ + udelay(10); + i = 0; + while (i < DMA_MAC_RST_TO) { + val = self.read(RFD_PIDX); + if (val == 0) { + break; + } + udelay(10); + i += 1; + } + while (i < DMA_MAC_RST_TO) { + val = self.read(MASTER); + if ((val & MASTER_DMA_MAC_RST) == 0) { + break; + } + udelay(10); + i += 1; + } + if (i == DMA_MAC_RST_TO) { + return ERR_RSTMAC; + } + udelay(10); + + if (a_cr) { + /* set MASTER_PCLKSEL_SRDS (affect by soft-rst, PERST) */ + self.write(MASTER, val | MASTER_PCLKSEL_SRDS); + /* resoter l0s / l1 */ + if (pmctrl & (PMCTRL_L1_EN | PMCTRL_L0S_EN) > 0) { + self.write(PMCTRL, pmctrl); + } + } + + self.reset_osc(rev); + /* clear Internal OSC settings, switching OSC by hw itself, + * disable isoloate for A version + */ + val = self.read(MISC3); + self.write(MISC3, (val & !MISC3_25M_BY_SW) | MISC3_25M_NOTO_INTNL); + val = self.read(MISC); + val &= !MISC_INTNLOSC_OPEN; + if ((rev == REV_A0 || rev == REV_A1)) { + val &= !MISC_ISO_EN; + } + self.write(MISC, val); + udelay(20); + + /* driver control speed/duplex, hash-alg */ + self.write(MAC_CTRL, self.rx_ctrl); + + /* clk sw */ + val = self.read(SERDES); + self.write(SERDES, + val | SERDES_MACCLK_SLWDWN | SERDES_PHYCLK_SLWDWN); + + /* mac reset cause MDIO ctrl restore non-polling status */ + if (self.is_fpga) { + self.start_phy_polling(MDIO_CLK_SEL_25MD128); + } + + + return ret; + } + + unsafe fn ethadv_to_hw_cfg(&self, ethadv_cfg: u32) -> u32 { + let mut cfg: u32 = 0; + + if (ethadv_cfg & ADVERTISED_Autoneg > 0) { + cfg |= DRV_PHY_AUTO; + if (ethadv_cfg & ADVERTISED_10baseT_Half > 0) { + cfg |= DRV_PHY_10; + } + if (ethadv_cfg & ADVERTISED_10baseT_Full > 0) { + cfg |= DRV_PHY_10 | DRV_PHY_DUPLEX; + } + if (ethadv_cfg & ADVERTISED_100baseT_Half > 0) { + cfg |= DRV_PHY_100; + } + if (ethadv_cfg & ADVERTISED_100baseT_Full > 0) { + cfg |= DRV_PHY_100 | DRV_PHY_DUPLEX; + } + if (ethadv_cfg & ADVERTISED_1000baseT_Half > 0) { + cfg |= DRV_PHY_1000; + } + if (ethadv_cfg & ADVERTISED_1000baseT_Full > 0) { + cfg |= DRV_PHY_100 | DRV_PHY_DUPLEX; + } + if (ethadv_cfg & ADVERTISED_Pause > 0) { + cfg |= ADVERTISE_PAUSE_CAP; + } + if (ethadv_cfg & ADVERTISED_Asym_Pause > 0) { + cfg |= ADVERTISE_PAUSE_ASYM; + } + if (self.cap & CAP_AZ > 0) { + cfg |= DRV_PHY_EEE; + } + } else { + match (ethadv_cfg) { + ADVERTISED_10baseT_Half => { + cfg |= DRV_PHY_10; + }, + ADVERTISED_100baseT_Half => { + cfg |= DRV_PHY_100; + }, + ADVERTISED_10baseT_Full => { + cfg |= DRV_PHY_10 | DRV_PHY_DUPLEX; + }, + ADVERTISED_100baseT_Full => { + cfg |= DRV_PHY_100 | DRV_PHY_DUPLEX; + }, + _ => () + } + } + + return cfg; + } + + unsafe fn setup_speed_duplex(&mut self, ethadv: u32, flowctrl: u8) -> usize { + let mut adv: u32; + let mut giga: u16; + let mut cr: u16; + let mut val: u32; + let mut err: usize = 0; + + /* clear flag */ + self.write_phy_reg(MII_DBG_ADDR, 0); + val = self.read(DRV); + FIELD_SET32!(val, DRV_PHY, 0); + + if (ethadv & ADVERTISED_Autoneg > 0) { + adv = ADVERTISE_CSMA; + adv |= ethtool_adv_to_mii_adv_t(ethadv); + + if (flowctrl & FC_ANEG == FC_ANEG) { + if (flowctrl & FC_RX > 0) { + adv |= ADVERTISED_Pause; + if (flowctrl & FC_TX == 0) { + adv |= ADVERTISED_Asym_Pause; + } + } else if (flowctrl & FC_TX > 0) { + adv |= ADVERTISED_Asym_Pause; + } + } + giga = 0; + if (self.cap & CAP_GIGA > 0) { + giga = ethtool_adv_to_mii_ctrl1000_t(ethadv) as u16; + } + + cr = BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART; + + if (self.write_phy_reg(MII_ADVERTISE, adv as u16) > 0 || + self.write_phy_reg(MII_CTRL1000, giga) > 0 || + self.write_phy_reg(MII_BMCR, cr) > 0) { + err = ERR_MIIBUSY; + } + } else { + cr = BMCR_RESET; + if (ethadv == ADVERTISED_100baseT_Half || + ethadv == ADVERTISED_100baseT_Full) { + cr |= BMCR_SPEED100; + } + if (ethadv == ADVERTISED_10baseT_Full || + ethadv == ADVERTISED_100baseT_Full) { + cr |= BMCR_FULLDPLX; + } + + err = self.write_phy_reg(MII_BMCR, cr); + } + + if (err == 0) { + self.write_phy_reg(MII_DBG_ADDR, PHY_INITED); + /* save config to HW */ + val |= self.ethadv_to_hw_cfg(ethadv); + } + + self.write(DRV, val); + + return err; + } + + unsafe fn get_perm_macaddr(&mut self) -> [u8; 6] { + let mac_low = self.read(STAD0); + let mac_high = self.read(STAD1); + [ + mac_low as u8, + (mac_low >> 8) as u8, + (mac_low >> 16) as u8, + (mac_low >> 24) as u8, + mac_high as u8, + (mac_high >> 8) as u8 + ] + } + + unsafe fn get_phy_link(&mut self, link_up: &mut bool, speed: &mut u16) -> usize { + let mut bmsr: u16 = 0; + let mut giga: u16 = 0; + let mut err: usize; + + err = self.read_phy_reg(MII_BMSR, &mut bmsr); + err = self.read_phy_reg(MII_BMSR, &mut bmsr); + if (err > 0) { + return err; + } + + if (bmsr & BMSR_LSTATUS == 0) { + *link_up = false; + return err; + } + + *link_up = true; + + /* speed/duplex result is saved in PHY Specific Status Register */ + err = self.read_phy_reg(MII_GIGA_PSSR, &mut giga); + if (err > 0) { + return err; + } + + if (giga & GIGA_PSSR_SPD_DPLX_RESOLVED == 0) { + println!("PHY SPD/DPLX unresolved: {:X}", giga); + err = (-EINVAL) as usize; + } else { + match (giga & GIGA_PSSR_SPEED) { + GIGA_PSSR_1000MBS => *speed = SPEED_1000, + GIGA_PSSR_100MBS => *speed = SPEED_100, + GIGA_PSSR_10MBS => *speed = SPEED_10, + _ => { + println!("PHY SPD/DPLX unresolved: {:X}", giga); + err = (-EINVAL) as usize; + } + } + *speed += if (giga & GIGA_PSSR_DPLX > 0) { FULL_DUPLEX as u16 } else { HALF_DUPLEX as u16 }; + } + + return err; + } + + fn show_speed(&self, speed: u16) { + let desc = if speed == SPEED_1000 + FULL_DUPLEX as u16 { + "1 Gbps Full" + } else if speed == SPEED_100 + FULL_DUPLEX as u16 { + "100 Mbps Full" + } else if speed == SPEED_100 + HALF_DUPLEX as u16 { + "100 Mbps Half" + } else if speed == SPEED_10 + FULL_DUPLEX as u16 { + "10 Mbps Full" + } else if speed == SPEED_10 + HALF_DUPLEX as u16 { + "10 Mbps Half" + } else { + "Unknown speed" + }; + + println!("NIC Link Up: {}", desc); + } + + unsafe fn configure_basic(&mut self) { + let mut val: u32; + let raw_mtu: u32; + let max_payload: u32; + let val16: u16; + let chip_rev = self.revid(); + + /* mac address */ + //TODO alx_set_macaddr(hw, self.mac_addr); + + /* clk gating */ + self.write(CLK_GATE, CLK_GATE_ALL_A0); + + /* idle timeout to switch clk_125M */ + if (chip_rev >= REV_B0) { + self.write(IDLE_DECISN_TIMER, + IDLE_DECISN_TIMER_DEF); + } + + /* stats refresh timeout */ + self.write(SMB_TIMER, self.smb_timer * 500); + + /* intr moduration */ + val = self.read(MASTER); + val = val | MASTER_IRQMOD2_EN | + MASTER_IRQMOD1_EN | + MASTER_SYSALVTIMER_EN; + self.write(MASTER, val); + self.write(IRQ_MODU_TIMER, + FIELDX!(IRQ_MODU_TIMER1, self.imt >> 1)); + /* intr re-trig timeout */ + self.write(INT_RETRIG, INT_RETRIG_TO); + /* tpd threshold to trig int */ + self.write(TINT_TPD_THRSHLD, self.ith_tpd); + self.write(TINT_TIMER, self.imt as u32); + + /* mtu, 8:fcs+vlan */ + raw_mtu = (self.mtu + ETH_HLEN) as u32; + self.write(MTU, raw_mtu + 8); + if (raw_mtu > MTU_JUMBO_TH) { + self.rx_ctrl &= !MAC_CTRL_FAST_PAUSE; + } + + /* txq */ + if ((raw_mtu + 8) < TXQ1_JUMBO_TSO_TH) { + val = (raw_mtu + 8 + 7) >> 3; + } else { + val = TXQ1_JUMBO_TSO_TH >> 3; + } + self.write(TXQ1, val | TXQ1_ERRLGPKT_DROP_EN); + + /* TODO + max_payload = alx_get_readrq(hw) >> 8; + /* + * if BIOS had changed the default dma read max length, + * restore it to default value + */ + if (max_payload < DEV_CTRL_MAXRRS_MIN) + alx_set_readrq(hw, 128 << DEV_CTRL_MAXRRS_MIN); + */ + max_payload = 128 << DEV_CTRL_MAXRRS_MIN; + + val = FIELDX!(TXQ0_TPD_BURSTPREF, TXQ_TPD_BURSTPREF_DEF) | + TXQ0_MODE_ENHANCE | + TXQ0_LSO_8023_EN | + TXQ0_SUPT_IPOPT | + FIELDX!(TXQ0_TXF_BURST_PREF, TXQ_TXF_BURST_PREF_DEF); + self.write(TXQ0, val); + val = FIELDX!(HQTPD_Q1_NUMPREF, TXQ_TPD_BURSTPREF_DEF) | + FIELDX!(HQTPD_Q2_NUMPREF, TXQ_TPD_BURSTPREF_DEF) | + FIELDX!(HQTPD_Q3_NUMPREF, TXQ_TPD_BURSTPREF_DEF) | + HQTPD_BURST_EN; + self.write(HQTPD, val); + + /* rxq, flow control */ + val = self.read(SRAM5); + val = FIELD_GETX!(val, SRAM_RXF_LEN) << 3; + if (val > SRAM_RXF_LEN_8K) { + val16 = (MTU_STD_ALGN >> 3) as u16; + val = (val - RXQ2_RXF_FLOW_CTRL_RSVD) >> 3; + } else { + val16 = (MTU_STD_ALGN >> 3) as u16; + val = (val - MTU_STD_ALGN) >> 3; + } + self.write(RXQ2, + FIELDX!(RXQ2_RXF_XOFF_THRESH, val16) | + FIELDX!(RXQ2_RXF_XON_THRESH, val)); + val = FIELDX!(RXQ0_NUM_RFD_PREF, RXQ0_NUM_RFD_PREF_DEF) | + FIELDX!(RXQ0_RSS_MODE, RXQ0_RSS_MODE_DIS) | + FIELDX!(RXQ0_IDT_TBL_SIZE, RXQ0_IDT_TBL_SIZE_DEF) | + RXQ0_RSS_HSTYP_ALL | + RXQ0_RSS_HASH_EN | + RXQ0_IPV6_PARSE_EN; + if (self.cap & CAP_GIGA > 0) { + FIELD_SET32!(val, RXQ0_ASPM_THRESH, RXQ0_ASPM_THRESH_100M); + } + self.write(RXQ0, val); + + /* DMA */ + val = self.read(DMA); + val = FIELDX!(DMA_RORDER_MODE, DMA_RORDER_MODE_OUT) | + DMA_RREQ_PRI_DATA | + FIELDX!(DMA_RREQ_BLEN, max_payload) | + FIELDX!(DMA_WDLY_CNT, DMA_WDLY_CNT_DEF) | + FIELDX!(DMA_RDLY_CNT, DMA_RDLY_CNT_DEF) | + FIELDX!(DMA_RCHNL_SEL, self.dma_chnl - 1); + self.write(DMA, val); + + /* multi-tx-q weight */ + if (self.cap & CAP_MTQ > 0) { + val = FIELDX!(WRR_PRI, self.wrr_ctrl) | + FIELDX!(WRR_PRI0, self.wrr[0]) | + FIELDX!(WRR_PRI1, self.wrr[1]) | + FIELDX!(WRR_PRI2, self.wrr[2]) | + FIELDX!(WRR_PRI3, self.wrr[3]); + self.write(WRR, val); + } + } + + unsafe fn set_rx_mode(&mut self) { + /* TODO + struct alx_adapter *adpt = netdev_priv(netdev); + struct alx_hw *hw = &adpt->hw; + struct netdev_hw_addr *ha; + + + /* comoute mc addresses' hash value ,and put it into hash table */ + netdev_for_each_mc_addr(ha, netdev) + alx_add_mc_addr(hw, ha->addr); + */ + + self.write(HASH_TBL0, self.mc_hash[0]); + self.write(HASH_TBL1, self.mc_hash[1]); + + /* check for Promiscuous and All Multicast modes */ + self.rx_ctrl &= !(MAC_CTRL_MULTIALL_EN | MAC_CTRL_PROMISC_EN); + /* TODO + if (netdev->flags & IFF_PROMISC) { + self.rx_ctrl |= MAC_CTRL_PROMISC_EN; + } + if (netdev->flags & IFF_ALLMULTI) { + self.rx_ctrl |= MAC_CTRL_MULTIALL_EN; + } + */ + + self.write(MAC_CTRL, self.rx_ctrl); + } + + unsafe fn set_vlan_mode(&mut self, vlan_rx: bool) { + if (vlan_rx) { + self.rx_ctrl |= MAC_CTRL_VLANSTRIP; + } else { + self.rx_ctrl &= !MAC_CTRL_VLANSTRIP; + } + + self.write(MAC_CTRL, self.rx_ctrl); + } + + unsafe fn configure_rss(&mut self, en: bool) { + let mut ctrl: u32; + + ctrl = self.read(RXQ0); + + if (en) { + unimplemented!(); + /* + for (i = 0; i < sizeof(self.rss_key); i++) { + /* rss key should be saved in chip with + * reversed order. + */ + int j = sizeof(self.rss_key) - i - 1; + + MEM_W8(hw, RSS_KEY0 + j, self.rss_key[i]); + } + + for (i = 0; i < ARRAY_SIZE(self.rss_idt); i++) + self.write(RSS_IDT_TBL0 + i * 4, + self.rss_idt[i]); + + FIELD_SET32(ctrl, RXQ0_RSS_HSTYP, self.rss_hash_type); + FIELD_SET32(ctrl, RXQ0_RSS_MODE, RXQ0_RSS_MODE_MQMI); + FIELD_SET32(ctrl, RXQ0_IDT_TBL_SIZE, self.rss_idt_size); + ctrl |= RXQ0_RSS_HASH_EN; + */ + } else { + ctrl &= !RXQ0_RSS_HASH_EN; + } + + self.write(RXQ0, ctrl); + } + + unsafe fn configure(&mut self) { + self.configure_basic(); + self.configure_rss(false); + self.set_rx_mode(); + self.set_vlan_mode(false); + } + + unsafe fn irq_enable(&mut self) { + self.write(ISR, 0); + let imask = self.imask; + self.write(IMR, imask); + } + + unsafe fn irq_disable(&mut self) { + self.write(ISR, ISR_DIS); + self.write(IMR, 0); + } + + unsafe fn clear_phy_intr(&mut self) -> usize { + let mut isr: u16 = 0; + self.read_phy_reg(MII_ISR, &mut isr) + } + + unsafe fn post_phy_link(&mut self, speed: u16, az_en: bool) { + let mut phy_val: u16 = 0; + let len: u16; + let agc: u16; + let revid: u8 = self.revid(); + let adj_th: bool; + + if (revid != REV_B0 && + revid != REV_A1 && + revid != REV_A0) { + return; + } + adj_th = if (revid == REV_B0) { true } else { false }; + + /* 1000BT/AZ, wrong cable length */ + if (speed != SPEED_0) { + self.read_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL6, &mut phy_val); + len = FIELD_GETX!(phy_val, CLDCTRL6_CAB_LEN); + self.read_phy_dbg(MIIDBG_AGC, &mut phy_val); + agc = FIELD_GETX!(phy_val, AGC_2_VGA); + + if ((speed == SPEED_1000 && + (len > CLDCTRL6_CAB_LEN_SHORT1G || + (0 == len && agc > AGC_LONG1G_LIMT))) || + (speed == SPEED_100 && + (len > CLDCTRL6_CAB_LEN_SHORT100M || + (0 == len && agc > AGC_LONG100M_LIMT)))) { + self.write_phy_dbg(MIIDBG_AZ_ANADECT, AZ_ANADECT_LONG); + self.read_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, &mut phy_val); + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, phy_val | AFE_10BT_100M_TH); + } else { + self.write_phy_dbg(MIIDBG_AZ_ANADECT, AZ_ANADECT_DEF); + self.read_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, &mut phy_val); + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, phy_val & !AFE_10BT_100M_TH); + } + + /* threashold adjust */ + if (adj_th && self.lnk_patch) { + if (speed == SPEED_100) { + self.write_phy_dbg(MIIDBG_MSE16DB, MSE16DB_UP); + } else if (speed == SPEED_1000) { + /* + * Giga link threshold, raise the tolerance of + * noise 50% + */ + self.read_phy_dbg(MIIDBG_MSE20DB, &mut phy_val); + FIELD_SETS!(phy_val, MSE20DB_TH, MSE20DB_TH_HI); + self.write_phy_dbg(MIIDBG_MSE20DB, phy_val); + } + } + /* phy link-down in 1000BT/AZ mode */ + if (az_en && revid == REV_B0 && speed == SPEED_1000) { + self.write_phy_dbg(MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF & !SRDSYSMOD_DEEMP_EN); + } + } else { + self.read_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, &mut phy_val); + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, phy_val & !AFE_10BT_100M_TH); + + if (adj_th && self.lnk_patch) { + self.write_phy_dbg(MIIDBG_MSE16DB, MSE16DB_DOWN); + self.read_phy_dbg(MIIDBG_MSE20DB, &mut phy_val); + FIELD_SETS!(phy_val, MSE20DB_TH, MSE20DB_TH_DEF); + self.write_phy_dbg(MIIDBG_MSE20DB, phy_val); + } + if (az_en && revid == REV_B0) { + self.write_phy_dbg(MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF); + } + } + } + + unsafe fn task(&mut self) { + if self.flag & FLAG_HALT > 0 { + return; + } + + //TODO: RESET + if self.flag & FLAG_TASK_RESET > 0 { + self.flag &= !FLAG_TASK_RESET; + println!("reinit"); + self.reinit(); + } + + if self.flag & FLAG_TASK_CHK_LINK > 0 { + self.flag &= !FLAG_TASK_CHK_LINK; + self.check_link(); + } + } + + unsafe fn halt(&mut self) { + self.flag |= FLAG_HALT; + + //alx_netif_stop(adpt); + self.link_up = false; + self.link_speed = SPEED_0; + + self.reset_mac(); + + /* disable l0s/l1 */ + self.enable_aspm(false, false); + self.irq_disable(); + //self.free_all_rings_buf(); + } + + unsafe fn activate(&mut self) { + /* hardware setting lost, restore it */ + self.init_ring_ptrs(); + self.configure(); + + self.flag &= !FLAG_HALT; + /* clear old interrupts */ + self.write(ISR, !ISR_DIS); + + self.irq_enable(); + + self.flag |= FLAG_TASK_CHK_LINK; + self.task(); + } + + unsafe fn reinit(&mut self) { + if self.flag & FLAG_HALT > 0 { + return; + } + + self.halt(); + self.activate(); + } + + unsafe fn init_ring_ptrs(&mut self) { + // Write high addresses + self.write(RX_BASE_ADDR_HI, 0); + self.write(TX_BASE_ADDR_HI, 0); + + // RFD ring + for i in 0..self.rfd_ring.len() { + self.rfd_ring[i].addr.write(self.rfd_buffer[i].physical() as u64); + } + self.write(RFD_ADDR_LO, self.rfd_ring.physical() as u32); + self.write(RFD_RING_SZ, self.rfd_ring.len() as u32); + self.write(RFD_BUF_SZ, 16384); + + // RRD ring + self.write(RRD_ADDR_LO, self.rrd_ring.physical() as u32); + self.write(RRD_RING_SZ, self.rrd_ring.len() as u32); + + // TPD ring + self.write(TPD_PRI0_ADDR_LO, self.tpd_ring[0].physical() as u32); + self.write(TPD_PRI1_ADDR_LO, self.tpd_ring[1].physical() as u32); + self.write(TPD_PRI2_ADDR_LO, self.tpd_ring[2].physical() as u32); + self.write(TPD_PRI3_ADDR_LO, self.tpd_ring[3].physical() as u32); + self.write(TPD_RING_SZ, self.tpd_ring[0].len() as u32); + + // Write pointers into chip SRAM + self.write(SRAM9, SRAM_LOAD_PTR); + } + + unsafe fn check_link(&mut self) { + let mut speed: u16 = SPEED_0; + let old_speed: u16; + let mut link_up: bool = false; + let old_link_up: bool; + let mut err: usize; + + if (self.flag & FLAG_HALT > 0) { + return; + } + + macro_rules! goto_out { + () => { + if (err > 0) { + self.flag |= FLAG_TASK_RESET; + self.task(); + } + return; + } + } + + /* clear PHY internal interrupt status, + * otherwise the Main interrupt status will be asserted + * for ever. + */ + self.clear_phy_intr(); + + err = self.get_phy_link(&mut link_up, &mut speed); + if (err > 0) { + goto_out!(); + } + + /* open interrutp mask */ + self.imask |= ISR_PHY; + let imask = self.imask; + self.write(IMR, imask); + + if (!link_up && !self.link_up) { + goto_out!(); + } + + old_speed = self.link_speed + self.link_duplex as u16; + old_link_up = self.link_up; + + if (link_up) { + /* same speed ? */ + if (old_link_up && old_speed == speed) { + goto_out!(); + } + + self.show_speed(speed); + self.link_duplex = (speed % 10) as u8; + self.link_speed = speed - self.link_duplex as u16; + self.link_up = true; + let link_speed = self.link_speed; + let az_en = self.cap & CAP_AZ > 0; + self.post_phy_link(link_speed, az_en); + let l0s_en = self.cap & CAP_L0S > 0; + let l1_en = self.cap & CAP_L1 > 0; + self.enable_aspm(l0s_en, l1_en); + self.start_mac(); + + /* link kept, just speed changed */ + if (old_link_up) { + goto_out!(); + } + /* link changed from 'down' to 'up' */ + // TODO self.netif_start(); + goto_out!(); + } + + /* link changed from 'up' to 'down' */ + // TODO self.netif_stop(); + self.link_up = false; + self.link_speed = SPEED_0; + println!("NIC Link Down"); + err = self.reset_mac(); + if (err > 0) { + println!("linkdown:reset_mac fail {}", err); + err = (-EIO) as usize; + goto_out!(); + } + self.irq_disable(); + + /* reset-mac cause all settings on HW lost, + * following steps restore all of them and + * refresh whole RX/TX rings + */ + self.init_ring_ptrs(); + + self.configure(); + + let l1_en = self.cap & CAP_L1 > 0; + self.enable_aspm(false, l1_en); + + let cap_az = self.cap & CAP_AZ > 0; + self.post_phy_link(SPEED_0, cap_az); + + self.irq_enable(); + + goto_out!(); + } + + unsafe fn get_phy_info(&mut self) -> bool { + /* + let mut devs1: u16 = 0; + let mut devs2: u16 = 0; + + if (self.read_phy_reg(MII_PHYSID1, &mut self.phy_id[0]) > 0 || + self.read_phy_reg(MII_PHYSID2, &mut self.phy_id[1]) > 0) { + return false; + } + + /* since we haven't PMA/PMD status2 register, we can't + * use mdio45_probe function for prtad and mmds. + * use fixed MMD3 to get mmds. + */ + if (self.read_phy_ext(3, MDIO_DEVS1, &devs1) || + self.read_phy_ext(3, MDIO_DEVS2, &devs2)) { + return false; + } + self.mdio.mmds = devs1 | devs2 << 16; + + return true; + */ + return true; + } + + unsafe fn probe(&mut self) -> Result<()> { + println!(" - Reset PCIE"); + self.reset_pcie(); + + println!(" - Reset PHY"); + self.reset_phy(); + + println!(" - Reset MAC"); + let err = self.reset_mac(); + if err > 0 { + println!(" - MAC reset failed: {}", err); + return Err(Error::new(EIO)); + } + + println!(" - Setup speed duplex"); + let ethadv = self.adv_cfg; + let flowctrl = self.flowctrl; + let err = self.setup_speed_duplex(ethadv, flowctrl); + if err > 0 { + println!(" - PHY speed/duplex failed: {}", err); + return Err(Error::new(EIO)); + } + + let mac = self.get_perm_macaddr(); + print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + + if ! self.get_phy_info() { + println!(" - Identify PHY failed"); + return Err(Error::new(EIO)); + } + + Ok(()) + } + + unsafe fn free_all_ring_resources(&mut self) { + println!("free_all_ring_resources"); + } + + unsafe fn disable_advanced_intr(&mut self) { + println!("disable_advanced_intr"); + } + + unsafe fn open(&mut self) -> usize { + let mut err: usize = 0; + + macro_rules! goto_out { + () => {{ + self.free_all_ring_resources(); + self.disable_advanced_intr(); + return err; + }} + } + + /* allocate all memory resources */ + self.init_ring_ptrs(); + + /* make hardware ready before allocate interrupt */ + self.configure(); + + self.flag &= !FLAG_HALT; + + /* clear old interrupts */ + self.write(ISR, !ISR_DIS); + + self.irq_enable(); + + self.flag |= FLAG_TASK_CHK_LINK; + self.task(); + return 0; + } + + unsafe fn init(&mut self) -> Result<()> { + { + let pci_id = self.read(0); + self.vendor_id = pci_id as u16; + self.device_id = (pci_id >> 16) as u16; + } + + { + let pci_subid = self.read(0x2C); + self.subven_id = pci_subid as u16; + self.subdev_id = (pci_subid >> 16) as u16; + } + + { + let pci_rev = self.read(8); + self.revision = pci_rev as u8; + } + + { + self.dma_chnl = if self.revid() >= REV_B0 { 4 } else { 2 }; + } + + println!(" - ID: {:>04X}:{:>04X} SUB: {:>04X}:{:>04X} REV: {:>02X}", + self.vendor_id, self.device_id, + self.subven_id, self.subdev_id, + self.revision); + + self.probe()?; + + let err = self.open(); + if err > 0 { + println!(" - Failed to open: {}", err); + return Err(Error::new(EIO)); + } + + Ok(()) + } +} + +impl scheme::SchemeMut for Alx { + fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + if uid == 0 { + Ok(flags) + } else { + Err(Error::new(EACCES)) + } + } + + fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { + Ok(id) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + /* + let head = unsafe { self.read(RDH) }; + let mut tail = unsafe { self.read(RDT) }; + + tail += 1; + if tail >= self.receive_ring.len() as u32 { + tail = 0; + } + + if tail != head { + let rd = unsafe { &mut * (self.receive_ring.as_ptr().offset(tail as isize) as *mut Rd) }; + if rd.status & RD_DD == RD_DD { + rd.status = 0; + + let data = &self.receive_buffer[tail as usize][.. rd.length as usize]; + + let mut i = 0; + while i < buf.len() && i < data.len() { + buf[i] = data[i]; + i += 1; + } + + unsafe { self.write(RDT, tail) }; + + return Ok(i); + } + } + */ + + if id & O_NONBLOCK == O_NONBLOCK { + Ok(0) + } else { + Err(Error::new(EWOULDBLOCK)) + } + } + + fn write(&mut self, _id: usize, buf: &[u8]) -> Result { + /* + loop { + let head = unsafe { self.read(TDH) }; + let mut tail = unsafe { self.read(TDT) }; + let old_tail = tail; + + tail += 1; + if tail >= self.transmit_ring.len() as u32 { + tail = 0; + } + + if tail != head { + let td = unsafe { &mut * (self.transmit_ring.as_ptr().offset(old_tail as isize) as *mut Td) }; + + td.cso = 0; + td.command = TD_CMD_EOP | TD_CMD_IFCS | TD_CMD_RS; + td.status = 0; + td.css = 0; + td.special = 0; + + td.length = (cmp::min(buf.len(), 0x3FFF)) as u16; + + let mut data = unsafe { slice::from_raw_parts_mut(self.transmit_buffer[old_tail as usize].as_ptr() as *mut u8, td.length as usize) }; + + let mut i = 0; + while i < buf.len() && i < data.len() { + data[i] = buf[i]; + i += 1; + } + + unsafe { self.write(TDT, tail) }; + + while td.status == 0 { + thread::yield_now(); + } + + return Ok(i); + } + } + */ + Ok(0) + } + + fn fevent(&mut self, _id: usize, _flags: usize) -> Result { + Ok(0) + } + + fn fsync(&mut self, _id: usize) -> Result { + Ok(0) + } + + fn close(&mut self, _id: usize) -> Result { + Ok(0) + } +} diff --git a/alxd/src/device/regs.rs b/alxd/src/device/regs.rs new file mode 100644 index 0000000000..fed2169067 --- /dev/null +++ b/alxd/src/device/regs.rs @@ -0,0 +1,2295 @@ +/* + * Copyright (c) 2017 Jeremy Soller + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF; + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF; + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF; + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF; + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/**********************************************************************/ +/* following registers are mapped to both pci config and memory space */ +/**********************************************************************/ + +/* pci dev-ids */ +pub const DEV_ID_AR8161: u32 = 0x1091; +pub const DEV_ID_AR8162: u32 = 0x1090; +pub const DEV_ID_AR8171: u32 = 0x10A1; +pub const DEV_ID_AR8172: u32 = 0x10A0; + +/* rev definition, + * bit(0): with xD support + * bit(1): with Card Reader function + * bit(7:2): real revision + */ +pub const PCI_REVID_WTH_CR: u32 = 1 << 1; +pub const PCI_REVID_WTH_XD: u32 = 1 << 0; +pub const PCI_REVID_MASK: u32 = 0x1F; +pub const PCI_REVID_SHIFT: u32 = 3; +pub const REV_A0: u8 = 0; +pub const REV_A1: u8 = 1; +pub const REV_B0: u8 = 2; +pub const REV_C0: u8 = 3; + +pub const PM_CSR: u32 = 0x0044; +pub const PM_CSR_PME_STAT: u32 = 1 << 15; +pub const PM_CSR_DSCAL_MASK: u32 = 0x3; +pub const PM_CSR_DSCAL_SHIFT: u32 = 13; +pub const PM_CSR_DSEL_MASK: u32 = 0xF; +pub const PM_CSR_DSEL_SHIFT: u32 = 9; +pub const PM_CSR_PME_EN: u32 = 1 << 8; +pub const PM_CSR_PWST_MASK: u32 = 0x3; +pub const PM_CSR_PWST_SHIFT: u32 = 0; + +pub const DEV_CAP: u32 = 0x005C; +pub const DEV_CAP_SPLSL_MASK: u32 = 0x3; +pub const DEV_CAP_SPLSL_SHIFT: u32 = 26; +pub const DEV_CAP_SPLV_MASK: u32 = 0xFF; +pub const DEV_CAP_SPLV_SHIFT: u32 = 18; +pub const DEV_CAP_RBER: u32 = 1 << 15; +pub const DEV_CAP_PIPRS: u32 = 1 << 14; +pub const DEV_CAP_AIPRS: u32 = 1 << 13; +pub const DEV_CAP_ABPRS: u32 = 1 << 12; +pub const DEV_CAP_L1ACLAT_MASK: u32 = 0x7; +pub const DEV_CAP_L1ACLAT_SHIFT: u32 = 9; +pub const DEV_CAP_L0SACLAT_MASK: u32 = 0x7; +pub const DEV_CAP_L0SACLAT_SHIFT: u32 = 6; +pub const DEV_CAP_EXTAG: u32 = 1 << 5; +pub const DEV_CAP_PHANTOM: u32 = 1 << 4; +pub const DEV_CAP_MPL_MASK: u32 = 0x7; +pub const DEV_CAP_MPL_SHIFT: u32 = 0; +pub const DEV_CAP_MPL_128: u32 = 1; +pub const DEV_CAP_MPL_256: u32 = 2; +pub const DEV_CAP_MPL_512: u32 = 3; +pub const DEV_CAP_MPL_1024: u32 = 4; +pub const DEV_CAP_MPL_2048: u32 = 5; +pub const DEV_CAP_MPL_4096: u32 = 6; + +pub const DEV_CTRL: u32 = 0x0060; +pub const DEV_CTRL_MAXRRS_MASK: u32 = 0x7; +pub const DEV_CTRL_MAXRRS_SHIFT: u32 = 12; +pub const DEV_CTRL_MAXRRS_MIN: u32 = 2; +pub const DEV_CTRL_NOSNP_EN: u32 = 1 << 11; +pub const DEV_CTRL_AUXPWR_EN: u32 = 1 << 10; +pub const DEV_CTRL_PHANTOM_EN: u32 = 1 << 9; +pub const DEV_CTRL_EXTAG_EN: u32 = 1 << 8; +pub const DEV_CTRL_MPL_MASK: u32 = 0x7; +pub const DEV_CTRL_MPL_SHIFT: u32 = 5; +pub const DEV_CTRL_RELORD_EN: u32 = 1 << 4; +pub const DEV_CTRL_URR_EN: u32 = 1 << 3; +pub const DEV_CTRL_FERR_EN: u32 = 1 << 2; +pub const DEV_CTRL_NFERR_EN: u32 = 1 << 1; +pub const DEV_CTRL_CERR_EN: u32 = 1 << 0; + +pub const DEV_STAT: u32 = 0x0062; +pub const DEV_STAT_XS_PEND: u32 = 1 << 5; +pub const DEV_STAT_AUXPWR: u32 = 1 << 4; +pub const DEV_STAT_UR: u32 = 1 << 3; +pub const DEV_STAT_FERR: u32 = 1 << 2; +pub const DEV_STAT_NFERR: u32 = 1 << 1; +pub const DEV_STAT_CERR: u32 = 1 << 0; + +pub const LNK_CAP: u32 = 0x0064; +pub const LNK_CAP_PRTNUM_MASK: u32 = 0xFF; +pub const LNK_CAP_PRTNUM_SHIFT: u32 = 24; +pub const LNK_CAP_CLK_PM: u32 = 1 << 18; +pub const LNK_CAP_L1EXTLAT_MASK: u32 = 0x7; +pub const LNK_CAP_L1EXTLAT_SHIFT: u32 = 15; +pub const LNK_CAP_L0SEXTLAT_MASK: u32 = 0x7; +pub const LNK_CAP_L0SEXTLAT_SHIFT: u32 = 12; +pub const LNK_CAP_ASPM_SUP_MASK: u32 = 0x3; +pub const LNK_CAP_ASPM_SUP_SHIFT: u32 = 10; +pub const LNK_CAP_ASPM_SUP_L0S: u32 = 1; +pub const LNK_CAP_ASPM_SUP_L0SL1: u32 = 3; +pub const LNK_CAP_MAX_LWH_MASK: u32 = 0x3F; +pub const LNK_CAP_MAX_LWH_SHIFT: u32 = 4; +pub const LNK_CAP_MAX_LSPD_MASK: u32 = 0xF; +pub const LNK_CAP_MAX_LSPD_SHIFT: u32 = 0; + +pub const LNK_CTRL: u32 = 0x0068; +pub const LNK_CTRL_CLK_PM_EN: u32 = 1 << 8; +pub const LNK_CTRL_EXTSYNC: u32 = 1 << 7; +pub const LNK_CTRL_CMNCLK_CFG: u32 = 1 << 6; +pub const LNK_CTRL_RCB_128B: u32 = 1 << 3; +pub const LNK_CTRL_ASPM_MASK: u32 = 0x3; +pub const LNK_CTRL_ASPM_SHIFT: u32 = 0; +pub const LNK_CTRL_ASPM_DIS: u32 = 0; +pub const LNK_CTRL_ASPM_ENL0S: u32 = 1; +pub const LNK_CTRL_ASPM_ENL1: u32 = 2; +pub const LNK_CTRL_ASPM_ENL0SL1: u32 = 3; + +pub const LNK_STAT: u32 = 0x006A; +pub const LNK_STAT_SCLKCFG: u32 = 1 << 12; +pub const LNK_STAT_LNKTRAIN: u32 = 1 << 11; +pub const LNK_STAT_TRNERR: u32 = 1 << 10; +pub const LNK_STAT_LNKSPD_MASK: u32 = 0xF; +pub const LNK_STAT_LNKSPD_SHIFT: u32 = 0; +pub const LNK_STAT_NEGLW_MASK: u32 = 0x3F; +pub const LNK_STAT_NEGLW_SHIFT: u32 = 4; + +pub const MSIX_MASK: u32 = 0x0090; +pub const MSIX_PENDING: u32 = 0x0094; + +pub const UE_SVRT: u32 = 0x010C; +pub const UE_SVRT_UR: u32 = 1 << 20; +pub const UE_SVRT_ECRCERR: u32 = 1 << 19; +pub const UE_SVRT_MTLP: u32 = 1 << 18; +pub const UE_SVRT_RCVOVFL: u32 = 1 << 17; +pub const UE_SVRT_UNEXPCPL: u32 = 1 << 16; +pub const UE_SVRT_CPLABRT: u32 = 1 << 15; +pub const UE_SVRT_CPLTO: u32 = 1 << 14; +pub const UE_SVRT_FCPROTERR: u32 = 1 << 13; +pub const UE_SVRT_PTLP: u32 = 1 << 12; +pub const UE_SVRT_DLPROTERR: u32 = 1 << 4; +pub const UE_SVRT_TRNERR: u32 = 1 << 0; + +/* eeprom & flash load register */ +pub const EFLD: u32 = 0x0204; +pub const EFLD_F_ENDADDR_MASK: u32 = 0x3FF; +pub const EFLD_F_ENDADDR_SHIFT: u32 = 16; +pub const EFLD_F_EXIST: u32 = 1 << 10; +pub const EFLD_E_EXIST: u32 = 1 << 9; +pub const EFLD_EXIST: u32 = 1 << 8; +pub const EFLD_STAT: u32 = 1 << 5; +pub const EFLD_IDLE: u32 = 1 << 4; +pub const EFLD_START: u32 = 1 << 0; + +/* eFuse load register */ +pub const SLD: u32 = 0x0218; +pub const SLD_FREQ_MASK: u32 = 0x3; +pub const SLD_FREQ_SHIFT: u32 = 24; +pub const SLD_FREQ_100K: u32 = 0; +pub const SLD_FREQ_200K: u32 = 1; +pub const SLD_FREQ_300K: u32 = 2; +pub const SLD_FREQ_400K: u32 = 3; +pub const SLD_EXIST: u32 = 1 << 23; +pub const SLD_SLVADDR_MASK: u32 = 0x7F; +pub const SLD_SLVADDR_SHIFT: u32 = 16; +pub const SLD_IDLE: u32 = 1 << 13; +pub const SLD_STAT: u32 = 1 << 12; +pub const SLD_START: u32 = 1 << 11; +pub const SLD_STARTADDR_MASK: u32 = 0xFF; +pub const SLD_STARTADDR_SHIFT: u32 = 0; +pub const SLD_MAX_TO: u32 = 100; + +pub const PCIE_MSIC: u32 = 0x021C; +pub const PCIE_MSIC_MSIX_DIS: u32 = 1 << 22; +pub const PCIE_MSIC_MSI_DIS: u32 = 1 << 21; + +pub const PPHY_MISC1: u32 = 0x1000; +pub const PPHY_MISC1_RCVDET: u32 = 1 << 2; +pub const PPHY_MISC1_NFTS_MASK: u32 = 0xFF; +pub const PPHY_MISC1_NFTS_SHIFT: u32 = 16; +pub const PPHY_MISC1_NFTS_HIPERF: u32 = 0xA0; + +pub const PPHY_MISC2: u32 = 0x1004; +pub const PPHY_MISC2_L0S_TH_MASK: u32 = 0x3; +pub const PPHY_MISC2_L0S_TH_SHIFT: u32 = 18; +pub const PPHY_MISC2_CDR_BW_MASK: u32 = 0x3; +pub const PPHY_MISC2_CDR_BW_SHIFT: u32 = 16; + +pub const PDLL_TRNS1: u32 = 0x1104; +pub const PDLL_TRNS1_D3PLLOFF_EN: u32 = 1 << 11; +pub const PDLL_TRNS1_REGCLK_SEL_NORM: u32 = 1 << 10; +pub const PDLL_TRNS1_REPLY_TO_MASK: u32 = 0x3FF; +pub const PDLL_TRNS1_REPLY_TO_SHIFT: u32 = 0; + +pub const TLEXTN_STATS: u32 = 0x1208; +pub const TLEXTN_STATS_DEVNO_MASK: u32 = 0x1F; +pub const TLEXTN_STATS_DEVNO_SHIFT: u32 = 16; +pub const TLEXTN_STATS_BUSNO_MASK: u32 = 0xFF; +pub const TLEXTN_STATS_BUSNO_SHIFT: u32 = 8; + +pub const EFUSE_CTRL: u32 = 0x12C0; +pub const EFUSE_CTRL_FLAG: u32 = 1 << 31; +pub const EUFSE_CTRL_ACK: u32 = 1 << 30; +pub const EFUSE_CTRL_ADDR_MASK: u32 = 0x3FF; +pub const EFUSE_CTRL_ADDR_SHIFT: u32 = 16; + +pub const EFUSE_DATA: u32 = 0x12C4; + +pub const SPI_OP1: u32 = 0x12C8; +pub const SPI_OP1_RDID_MASK: u32 = 0xFF; +pub const SPI_OP1_RDID_SHIFT: u32 = 24; +pub const SPI_OP1_CE_MASK: u32 = 0xFF; +pub const SPI_OP1_CE_SHIFT: u32 = 16; +pub const SPI_OP1_SE_MASK: u32 = 0xFF; +pub const SPI_OP1_SE_SHIFT: u32 = 8; +pub const SPI_OP1_PRGRM_MASK: u32 = 0xFF; +pub const SPI_OP1_PRGRM_SHIFT: u32 = 0; + +pub const SPI_OP2: u32 = 0x12CC; +pub const SPI_OP2_READ_MASK: u32 = 0xFF; +pub const SPI_OP2_READ_SHIFT: u32 = 24; +pub const SPI_OP2_WRSR_MASK: u32 = 0xFF; +pub const SPI_OP2_WRSR_SHIFT: u32 = 16; +pub const SPI_OP2_RDSR_MASK: u32 = 0xFF; +pub const SPI_OP2_RDSR_SHIFT: u32 = 8; +pub const SPI_OP2_WREN_MASK: u32 = 0xFF; +pub const SPI_OP2_WREN_SHIFT: u32 = 0; + +pub const SPI_OP3: u32 = 0x12E4; +pub const SPI_OP3_WRDI_MASK: u32 = 0xFF; +pub const SPI_OP3_WRDI_SHIFT: u32 = 8; +pub const SPI_OP3_EWSR_MASK: u32 = 0xFF; +pub const SPI_OP3_EWSR_SHIFT: u32 = 0; + +pub const EF_CTRL: u32 = 0x12D0; +pub const EF_CTRL_FSTS_MASK: u32 = 0xFF; +pub const EF_CTRL_FSTS_SHIFT: u32 = 20; +pub const EF_CTRL_CLASS_MASK: u32 = 0x7; +pub const EF_CTRL_CLASS_SHIFT: u32 = 16; +pub const EF_CTRL_CLASS_F_UNKNOWN: u32 = 0; +pub const EF_CTRL_CLASS_F_STD: u32 = 1; +pub const EF_CTRL_CLASS_F_SST: u32 = 2; +pub const EF_CTRL_CLASS_E_UNKNOWN: u32 = 0; +pub const EF_CTRL_CLASS_E_1K: u32 = 1; +pub const EF_CTRL_CLASS_E_4K: u32 = 2; +pub const EF_CTRL_FRET: u32 = 1 << 15; +pub const EF_CTRL_TYP_MASK: u32 = 0x3; +pub const EF_CTRL_TYP_SHIFT: u32 = 12; +pub const EF_CTRL_TYP_NONE: u32 = 0; +pub const EF_CTRL_TYP_F: u32 = 1; +pub const EF_CTRL_TYP_E: u32 = 2; +pub const EF_CTRL_TYP_UNKNOWN: u32 = 3; +pub const EF_CTRL_ONE_CLK: u32 = 1 << 10; +pub const EF_CTRL_ECLK_MASK: u32 = 0x3; +pub const EF_CTRL_ECLK_SHIFT: u32 = 8; +pub const EF_CTRL_ECLK_125K: u32 = 0; +pub const EF_CTRL_ECLK_250K: u32 = 1; +pub const EF_CTRL_ECLK_500K: u32 = 2; +pub const EF_CTRL_ECLK_1M: u32 = 3; +pub const EF_CTRL_FBUSY: u32 = 1 << 7; +pub const EF_CTRL_ACTION: u32 = 1 << 6; +pub const EF_CTRL_AUTO_OP: u32 = 1 << 5; +pub const EF_CTRL_SST_MODE: u32 = 1 << 4; +pub const EF_CTRL_INST_MASK: u32 = 0xF; +pub const EF_CTRL_INST_SHIFT: u32 = 0; +pub const EF_CTRL_INST_NONE: u32 = 0; +pub const EF_CTRL_INST_READ: u32 = 1; +pub const EF_CTRL_INST_RDID: u32 = 2; +pub const EF_CTRL_INST_RDSR: u32 = 3; +pub const EF_CTRL_INST_WREN: u32 = 4; +pub const EF_CTRL_INST_PRGRM: u32 = 5; +pub const EF_CTRL_INST_SE: u32 = 6; +pub const EF_CTRL_INST_CE: u32 = 7; +pub const EF_CTRL_INST_WRSR: u32 = 10; +pub const EF_CTRL_INST_EWSR: u32 = 11; +pub const EF_CTRL_INST_WRDI: u32 = 12; +pub const EF_CTRL_INST_WRITE: u32 = 2; + +pub const EF_ADDR: u32 = 0x12D4; +pub const EF_DATA: u32 = 0x12D8; +pub const SPI_ID: u32 = 0x12DC; + +pub const SPI_CFG_START: u32 = 0x12E0; + +pub const PMCTRL: u32 = 0x12F8; +pub const PMCTRL_HOTRST_WTEN: u32 = 1 << 31; +/* bit30: L0s/L1 controlled by MAC based on throughput(setting in: u32 = 15A0) */ +pub const PMCTRL_ASPM_FCEN: u32 = 1 << 30; +pub const PMCTRL_SADLY_EN: u32 = 1 << 29; +pub const PMCTRL_L0S_BUFSRX_EN: u32 = 1 << 28; +pub const PMCTRL_LCKDET_TIMER_MASK: u32 = 0xF; +pub const PMCTRL_LCKDET_TIMER_SHIFT: u32 = 24; +pub const PMCTRL_LCKDET_TIMER_DEF: u32 = 0xC; +/* bit[23:20] if pm_request_l1 time > @, then enter L0s not L1 */ +pub const PMCTRL_L1REQ_TO_MASK: u32 = 0xF; +pub const PMCTRL_L1REQ_TO_SHIFT: u32 = 20; +pub const PMCTRL_L1REG_TO_DEF: u32 = 0xF; +pub const PMCTRL_TXL1_AFTER_L0S: u32 = 1 << 19; +pub const PMCTRL_L1_TIMER_MASK: u32 = 0x7; +pub const PMCTRL_L1_TIMER_SHIFT: u32 = 16; +pub const PMCTRL_L1_TIMER_DIS: u32 = 0; +pub const PMCTRL_L1_TIMER_2US: u32 = 1; +pub const PMCTRL_L1_TIMER_4US: u32 = 2; +pub const PMCTRL_L1_TIMER_8US: u32 = 3; +pub const PMCTRL_L1_TIMER_16US: u32 = 4; +pub const PMCTRL_L1_TIMER_24US: u32 = 5; +pub const PMCTRL_L1_TIMER_32US: u32 = 6; +pub const PMCTRL_L1_TIMER_63US: u32 = 7; +pub const PMCTRL_RCVR_WT_1US: u32 = 1 << 15; +pub const PMCTRL_PWM_VER_11: u32 = 1 << 14; +/* bit13: enable pcie clk switch in L1 state */ +pub const PMCTRL_L1_CLKSW_EN: u32 = 1 << 13; +pub const PMCTRL_L0S_EN: u32 = 1 << 12; +pub const PMCTRL_RXL1_AFTER_L0S: u32 = 1 << 11; +pub const PMCTRL_L0S_TIMER_MASK: u32 = 0x7; +pub const PMCTRL_L0S_TIMER_SHIFT: u32 = 8; +pub const PMCTRL_L1_BUFSRX_EN: u32 = 1 << 7; +/* bit6: power down serdes RX */ +pub const PMCTRL_L1_SRDSRX_PWD: u32 = 1 << 6; +pub const PMCTRL_L1_SRDSPLL_EN: u32 = 1 << 5; +pub const PMCTRL_L1_SRDS_EN: u32 = 1 << 4; +pub const PMCTRL_L1_EN: u32 = 1 << 3; +pub const PMCTRL_CLKREQ_EN: u32 = 1 << 2; +pub const PMCTRL_RBER_EN: u32 = 1 << 1; +pub const PMCTRL_SPRSDWER_EN: u32 = 1 << 0; + +pub const LTSSM_CTRL: u32 = 0x12FC; +pub const LTSSM_WRO_EN: u32 = 1 << 12; + +/*******************************************************/ +/* following registers are mapped only to memory space */ +/*******************************************************/ + +pub const MASTER: u32 = 0x1400; +pub const MASTER_OTP_FLG: u32 = 1 << 31; +pub const MASTER_DEV_NUM_MASK: u32 = 0x7F; +pub const MASTER_DEV_NUM_SHIFT: u32 = 24; +pub const MASTER_REV_NUM_MASK: u32 = 0xFF; +pub const MASTER_REV_NUM_SHIFT: u32 = 16; +pub const MASTER_DEASSRT: u32 = 1 << 15; +pub const MASTER_RDCLR_INT: u32 = 1 << 14; +pub const MASTER_DMA_RST: u32 = 1 << 13; +/* bit12:: u32 = 1:alwys select pclk from serdes, not sw to: u32 = 25M */ +pub const MASTER_PCLKSEL_SRDS: u32 = 1 << 12; +/* bit11: irq moduration for rx */ +pub const MASTER_IRQMOD2_EN: u32 = 1 << 11; +/* bit10: irq moduration for tx/rx */ +pub const MASTER_IRQMOD1_EN: u32 = 1 << 10; +pub const MASTER_MANU_INT: u32 = 1 << 9; +pub const MASTER_MANUTIMER_EN: u32 = 1 << 8; +pub const MASTER_SYSALVTIMER_EN: u32 = 1 << 7; +pub const MASTER_OOB_DIS: u32 = 1 << 6; +/* bit5: wakeup without pcie clk */ +pub const MASTER_WAKEN_25M: u32 = 1 << 5; +pub const MASTER_BERT_START: u32 = 1 << 4; +pub const MASTER_PCIE_TSTMOD_MASK: u32 = 0x3; +pub const MASTER_PCIE_TSTMOD_SHIFT: u32 = 2; +pub const MASTER_PCIE_RST: u32 = 1 << 1; +/* bit0: MAC & DMA reset */ +pub const MASTER_DMA_MAC_RST: u32 = 1 << 0; +pub const DMA_MAC_RST_TO: u32 = 50; + +pub const MANU_TIMER: u32 = 0x1404; + +pub const IRQ_MODU_TIMER: u32 = 0x1408; +/* hi-16bit is only for RX */ +pub const IRQ_MODU_TIMER2_MASK: u32 = 0xFFFF; +pub const IRQ_MODU_TIMER2_SHIFT: u32 = 16; +pub const IRQ_MODU_TIMER1_MASK: u32 = 0xFFFF; +pub const IRQ_MODU_TIMER1_SHIFT: u32 = 0; + +pub const PHY_CTRL: u32 = 0x140C; +pub const PHY_CTRL_ADDR_MASK: u32 = 0x1F; +pub const PHY_CTRL_ADDR_SHIFT: u32 = 19; +pub const PHY_CTRL_BP_VLTGSW: u32 = 1 << 18; +pub const PHY_CTRL_100AB_EN: u32 = 1 << 17; +pub const PHY_CTRL_10AB_EN: u32 = 1 << 16; +pub const PHY_CTRL_PLL_BYPASS: u32 = 1 << 15; +/* bit14: affect MAC & PHY, go to low power sts */ +pub const PHY_CTRL_POWER_DOWN: u32 = 1 << 14; +/* bit13:: u32 = 1:pll always ON,: u32 = 0:can switch in lpw */ +pub const PHY_CTRL_PLL_ON: u32 = 1 << 13; +pub const PHY_CTRL_RST_ANALOG: u32 = 1 << 12; +pub const PHY_CTRL_HIB_PULSE: u32 = 1 << 11; +pub const PHY_CTRL_HIB_EN: u32 = 1 << 10; +pub const PHY_CTRL_GIGA_DIS: u32 = 1 << 9; +/* bit8: poweron rst */ +pub const PHY_CTRL_IDDQ_DIS: u32 = 1 << 8; +/* bit7: while reboot, it affects bit8 */ +pub const PHY_CTRL_IDDQ: u32 = 1 << 7; +pub const PHY_CTRL_LPW_EXIT: u32 = 1 << 6; +pub const PHY_CTRL_GATE_25M: u32 = 1 << 5; +pub const PHY_CTRL_RVRS_ANEG: u32 = 1 << 4; +pub const PHY_CTRL_ANEG_NOW: u32 = 1 << 3; +pub const PHY_CTRL_LED_MODE: u32 = 1 << 2; +pub const PHY_CTRL_RTL_MODE: u32 = 1 << 1; +/* bit0: out of dsp RST state */ +pub const PHY_CTRL_DSPRST_OUT: u32 = 1 << 0; +pub const PHY_CTRL_DSPRST_TO: u32 = 80; +pub const PHY_CTRL_CLS: u32 = + PHY_CTRL_LED_MODE | + PHY_CTRL_100AB_EN | + PHY_CTRL_PLL_ON; + +pub const MAC_STS: u32 = 0x1410; +pub const MAC_STS_SFORCE_MASK: u32 = 0xF; +pub const MAC_STS_SFORCE_SHIFT: u32 = 14; +pub const MAC_STS_CALIB_DONE: u32 = 1 << 13; +pub const MAC_STS_CALIB_RES_MASK: u32 = 0x1F; +pub const MAC_STS_CALIB_RES_SHIFT: u32 = 8; +pub const MAC_STS_CALIBERR_MASK: u32 = 0xF; +pub const MAC_STS_CALIBERR_SHIFT: u32 = 4; +pub const MAC_STS_TXQ_BUSY: u32 = 1 << 3; +pub const MAC_STS_RXQ_BUSY: u32 = 1 << 2; +pub const MAC_STS_TXMAC_BUSY: u32 = 1 << 1; +pub const MAC_STS_RXMAC_BUSY: u32 = 1 << 0; +pub const MAC_STS_IDLE: u32 = + MAC_STS_TXQ_BUSY | + MAC_STS_RXQ_BUSY | + MAC_STS_TXMAC_BUSY | + MAC_STS_RXMAC_BUSY; + +pub const MDIO: u32 = 0x1414; +pub const MDIO_MODE_EXT: u32 = 1 << 30; +pub const MDIO_POST_READ: u32 = 1 << 29; +pub const MDIO_AUTO_POLLING: u32 = 1 << 28; +pub const MDIO_BUSY: u32 = 1 << 27; +pub const MDIO_CLK_SEL_MASK: u32 = 0x7; +pub const MDIO_CLK_SEL_SHIFT: u32 = 24; +pub const MDIO_CLK_SEL_25MD4: u16 = 0; +pub const MDIO_CLK_SEL_25MD6: u16 = 2; +pub const MDIO_CLK_SEL_25MD8: u16 = 3; +pub const MDIO_CLK_SEL_25MD10: u16 = 4; +pub const MDIO_CLK_SEL_25MD32: u16 = 5; +pub const MDIO_CLK_SEL_25MD64: u16 = 6; +pub const MDIO_CLK_SEL_25MD128: u16 = 7; +pub const MDIO_START: u32 = 1 << 23; +pub const MDIO_SPRES_PRMBL: u32 = 1 << 22; +/* bit21:: u32 = 1:read,0:write */ +pub const MDIO_OP_READ: u32 = 1 << 21; +pub const MDIO_REG_MASK: u32 = 0x1F; +pub const MDIO_REG_SHIFT: u32 = 16; +pub const MDIO_DATA_MASK: u32 = 0xFFFF; +pub const MDIO_DATA_SHIFT: u32 = 0; +pub const MDIO_MAX_AC_TO: u32 = 120; + +pub const MDIO_EXTN: u32 = 0x1448; +pub const MDIO_EXTN_PORTAD_MASK: u32 = 0x1F; +pub const MDIO_EXTN_PORTAD_SHIFT: u32 = 21; +pub const MDIO_EXTN_DEVAD_MASK: u32 = 0x1F; +pub const MDIO_EXTN_DEVAD_SHIFT: u32 = 16; +pub const MDIO_EXTN_REG_MASK: u32 = 0xFFFF; +pub const MDIO_EXTN_REG_SHIFT: u32 = 0; + +pub const PHY_STS: u32 = 0x1418; +pub const PHY_STS_LPW: u32 = 1 << 31; +pub const PHY_STS_LPI: u32 = 1 << 30; +pub const PHY_STS_PWON_STRIP_MASK: u32 = 0xFFF; +pub const PHY_STS_PWON_STRIP_SHIFT: u32 = 16; + +pub const PHY_STS_DUPLEX: u32 = 1 << 3; +pub const PHY_STS_LINKUP: u32 = 1 << 2; +pub const PHY_STS_SPEED_MASK: u32 = 0x3; +pub const PHY_STS_SPEED_SHIFT: u32 = 0; +pub const PHY_STS_SPEED_1000M: u32 = 2; +pub const PHY_STS_SPEED_100M: u32 = 1; +pub const PHY_STS_SPEED_10M: u32 = 0; + +pub const BIST0: u32 = 0x141C; +pub const BIST0_COL_MASK: u32 = 0x3F; +pub const BIST0_COL_SHIFT: u32 = 24; +pub const BIST0_ROW_MASK: u32 = 0xFFF; +pub const BIST0_ROW_SHIFT: u32 = 12; +pub const BIST0_STEP_MASK: u32 = 0xF; +pub const BIST0_STEP_SHIFT: u32 = 8; +pub const BIST0_PATTERN_MASK: u32 = 0x7; +pub const BIST0_PATTERN_SHIFT: u32 = 4; +pub const BIST0_CRIT: u32 = 1 << 3; +pub const BIST0_FIXED: u32 = 1 << 2; +pub const BIST0_FAIL: u32 = 1 << 1; +pub const BIST0_START: u32 = 1 << 0; + +pub const BIST1: u32 = 0x1420; +pub const BIST1_COL_MASK: u32 = 0x3F; +pub const BIST1_COL_SHIFT: u32 = 24; +pub const BIST1_ROW_MASK: u32 = 0xFFF; +pub const BIST1_ROW_SHIFT: u32 = 12; +pub const BIST1_STEP_MASK: u32 = 0xF; +pub const BIST1_STEP_SHIFT: u32 = 8; +pub const BIST1_PATTERN_MASK: u32 = 0x7; +pub const BIST1_PATTERN_SHIFT: u32 = 4; +pub const BIST1_CRIT: u32 = 1 << 3; +pub const BIST1_FIXED: u32 = 1 << 2; +pub const BIST1_FAIL: u32 = 1 << 1; +pub const BIST1_START: u32 = 1 << 0; + +pub const SERDES: u32 = 0x1424; +pub const SERDES_PHYCLK_SLWDWN: u32 = 1 << 18; +pub const SERDES_MACCLK_SLWDWN: u32 = 1 << 17; +pub const SERDES_SELFB_PLL_MASK: u32 = 0x3; +pub const SERDES_SELFB_PLL_SHIFT: u32 = 14; +/* bit13:: u32 = 1:gtx_clk,: u32 = 0:25M */ +pub const SERDES_PHYCLK_SEL_GTX: u32 = 1 << 13; +/* bit12:: u32 = 1:serdes,0:25M */ +pub const SERDES_PCIECLK_SEL_SRDS: u32 = 1 << 12; +pub const SERDES_BUFS_RX_EN: u32 = 1 << 11; +pub const SERDES_PD_RX: u32 = 1 << 10; +pub const SERDES_PLL_EN: u32 = 1 << 9; +pub const SERDES_EN: u32 = 1 << 8; +/* bit6:: u32 = 0:state-machine,1:csr */ +pub const SERDES_SELFB_PLL_SEL_CSR: u32 = 1 << 6; +pub const SERDES_SELFB_PLL_CSR_MASK: u32 = 0x3; +pub const SERDES_SELFB_PLL_CSR_SHIFT: u32 = 4; +/*: u32 = 4-12% OV-CLK */ +pub const SERDES_SELFB_PLL_CSR_4: u32 = 3; +/*: u32 = 0-4% OV-CLK */ +pub const SERDES_SELFB_PLL_CSR_0: u32 = 2; +/*: u32 = 12-18% OV-CLK */ +pub const SERDES_SELFB_PLL_CSR_12: u32 = 1; +/*: u32 = 18-25% OV-CLK */ +pub const SERDES_SELFB_PLL_CSR_18: u32 = 0; +pub const SERDES_VCO_SLOW: u32 = 1 << 3; +pub const SERDES_VCO_FAST: u32 = 1 << 2; +pub const SERDES_LOCKDCT_EN: u32 = 1 << 1; +pub const SERDES_LOCKDCTED: u32 = 1 << 0; + +pub const LED_CTRL: u32 = 0x1428; +pub const LED_CTRL_PATMAP2_MASK: u32 = 0x3; +pub const LED_CTRL_PATMAP2_SHIFT: u32 = 8; +pub const LED_CTRL_PATMAP1_MASK: u32 = 0x3; +pub const LED_CTRL_PATMAP1_SHIFT: u32 = 6; +pub const LED_CTRL_PATMAP0_MASK: u32 = 0x3; +pub const LED_CTRL_PATMAP0_SHIFT: u32 = 4; +pub const LED_CTRL_D3_MODE_MASK: u32 = 0x3; +pub const LED_CTRL_D3_MODE_SHIFT: u32 = 2; +pub const LED_CTRL_D3_MODE_NORMAL: u32 = 0; +pub const LED_CTRL_D3_MODE_WOL_DIS: u32 = 1; +pub const LED_CTRL_D3_MODE_WOL_ANY: u32 = 2; +pub const LED_CTRL_D3_MODE_WOL_EN: u32 = 3; +pub const LED_CTRL_DUTY_CYCL_MASK: u32 = 0x3; +pub const LED_CTRL_DUTY_CYCL_SHIFT: u32 = 0; +/*: u32 = 50% */ +pub const LED_CTRL_DUTY_CYCL_50: u32 = 0; +/*: u32 = 12.5% */ +pub const LED_CTRL_DUTY_CYCL_125: u32 = 1; +/*: u32 = 25% */ +pub const LED_CTRL_DUTY_CYCL_25: u32 = 2; +/*: u32 = 75% */ +pub const LED_CTRL_DUTY_CYCL_75: u32 = 3; + +pub const LED_PATN: u32 = 0x142C; +pub const LED_PATN1_MASK: u32 = 0xFFFF; +pub const LED_PATN1_SHIFT: u32 = 16; +pub const LED_PATN0_MASK: u32 = 0xFFFF; +pub const LED_PATN0_SHIFT: u32 = 0; + +pub const LED_PATN2: u32 = 0x1430; +pub const LED_PATN2_MASK: u32 = 0xFFFF; +pub const LED_PATN2_SHIFT: u32 = 0; + +pub const SYSALV: u32 = 0x1434; +pub const SYSALV_FLAG: u32 = 1 << 0; + +pub const PCIERR_INST: u32 = 0x1438; +pub const PCIERR_INST_TX_RATE_MASK: u32 = 0xF; +pub const PCIERR_INST_TX_RATE_SHIFT: u32 = 4; +pub const PCIERR_INST_RX_RATE_MASK: u32 = 0xF; +pub const PCIERR_INST_RX_RATE_SHIFT: u32 = 0; + +pub const LPI_DECISN_TIMER: u32 = 0x143C; + +pub const LPI_CTRL: u32 = 0x1440; +pub const LPI_CTRL_CHK_DA: u32 = 1 << 31; +pub const LPI_CTRL_ENH_TO_MASK: u32 = 0x1FFF; +pub const LPI_CTRL_ENH_TO_SHIFT: u32 = 12; +pub const LPI_CTRL_ENH_TH_MASK: u32 = 0x1F; +pub const LPI_CTRL_ENH_TH_SHIFT: u32 = 6; +pub const LPI_CTRL_ENH_EN: u32 = 1 << 5; +pub const LPI_CTRL_CHK_RX: u32 = 1 << 4; +pub const LPI_CTRL_CHK_STATE: u32 = 1 << 3; +pub const LPI_CTRL_GMII: u32 = 1 << 2; +pub const LPI_CTRL_TO_PHY: u32 = 1 << 1; +pub const LPI_CTRL_EN: u32 = 1 << 0; + +pub const LPI_WAIT: u32 = 0x1444; +pub const LPI_WAIT_TIMER_MASK: u32 = 0xFFFF; +pub const LPI_WAIT_TIMER_SHIFT: u32 = 0; + +/* heart-beat, for swoi/cifs */ +pub const HRTBT_VLAN: u32 = 0x1450; +pub const HRTBT_VLANID_MASK: u32 = 0xFFFF; +pub const HRRBT_VLANID_SHIFT: u32 = 0; + +pub const HRTBT_CTRL: u32 = 0x1454; +pub const HRTBT_CTRL_EN: u32 = 1 << 31; +pub const HRTBT_CTRL_PERIOD_MASK: u32 = 0x3F; +pub const HRTBT_CTRL_PERIOD_SHIFT: u32 = 25; +pub const HRTBT_CTRL_HASVLAN: u32 = 1 << 24; +pub const HRTBT_CTRL_HDRADDR_MASK: u32 = 0xFFF; +pub const HRTBT_CTRL_HDRADDR_SHIFT: u32 = 12; +pub const HRTBT_CTRL_HDRADDRB0_MASK: u32 = 0x7FF; +pub const HRTBT_CTRL_HDRADDRB0_SHIFT: u32 = 13; +pub const HRTBT_CTRL_PKT_FRAG: u32 = 1 << 12; +pub const HRTBT_CTRL_PKTLEN_MASK: u32 = 0xFFF; +pub const HRTBT_CTRL_PKTLEN_SHIFT: u32 = 0; + +/* for: u32 = B0+, bit[13..] for C0+ */ +pub const HRTBT_EXT_CTRL: u32 = 0x1AD0; +pub const L1F_HRTBT_EXT_CTRL_PERIOD_HIGH_MASK: u32 = 0x3F; +pub const L1F_HRTBT_EXT_CTRL_PERIOD_HIGH_SHIFT: u32 = 24; +pub const L1F_HRTBT_EXT_CTRL_SWOI_STARTUP_PKT_EN: u32 = 1 << 23; +pub const L1F_HRTBT_EXT_CTRL_IOAC_2_FRAGMENTED: u32 = 1 << 22; +pub const L1F_HRTBT_EXT_CTRL_IOAC_1_FRAGMENTED: u32 = 1 << 21; +pub const L1F_HRTBT_EXT_CTRL_IOAC_1_KEEPALIVE_EN: u32 = 1 << 20; +pub const L1F_HRTBT_EXT_CTRL_IOAC_1_HAS_VLAN: u32 = 1 << 19; +pub const L1F_HRTBT_EXT_CTRL_IOAC_1_IS_8023: u32 = 1 << 18; +pub const L1F_HRTBT_EXT_CTRL_IOAC_1_IS_IPV6: u32 = 1 << 17; +pub const L1F_HRTBT_EXT_CTRL_IOAC_2_KEEPALIVE_EN: u32 = 1 << 16; +pub const L1F_HRTBT_EXT_CTRL_IOAC_2_HAS_VLAN: u32 = 1 << 15; +pub const L1F_HRTBT_EXT_CTRL_IOAC_2_IS_8023: u32 = 1 << 14; +pub const L1F_HRTBT_EXT_CTRL_IOAC_2_IS_IPV6: u32 = 1 << 13; +pub const HRTBT_EXT_CTRL_NS_EN: u32 = 1 << 12; +pub const HRTBT_EXT_CTRL_FRAG_LEN_MASK: u32 = 0xFF; +pub const HRTBT_EXT_CTRL_FRAG_LEN_SHIFT: u32 = 4; +pub const HRTBT_EXT_CTRL_IS_8023: u32 = 1 << 3; +pub const HRTBT_EXT_CTRL_IS_IPV6: u32 = 1 << 2; +pub const HRTBT_EXT_CTRL_WAKEUP_EN: u32 = 1 << 1; +pub const HRTBT_EXT_CTRL_ARP_EN: u32 = 1 << 0; + +pub const HRTBT_REM_IPV4_ADDR: u32 = 0x1AD4; +pub const HRTBT_HOST_IPV4_ADDR: u32 = 0x1478; +pub const HRTBT_REM_IPV6_ADDR3: u32 = 0x1AD8; +pub const HRTBT_REM_IPV6_ADDR2: u32 = 0x1ADC; +pub const HRTBT_REM_IPV6_ADDR1: u32 = 0x1AE0; +pub const HRTBT_REM_IPV6_ADDR0: u32 = 0x1AE4; + +/*: u32 = 1B8C ~: u32 = 1B94 for C0+ */ +pub const SWOI_ACER_CTRL: u32 = 0x1B8C; +pub const SWOI_ORIG_ACK_NAK_EN: u32 = 1 << 20; +pub const SWOI_ORIG_ACK_NAK_PKT_LEN_MASK: u32 = 0xFF; +pub const SWOI_ORIG_ACK_NAK_PKT_LEN_SHIFT: u32 = 12; +pub const SWOI_ORIG_ACK_ADDR_MASK: u32 = 0xFFF; +pub const SWOI_ORIG_ACK_ADDR_SHIFT: u32 = 0; + +pub const SWOI_IOAC_CTRL_2: u32 = 0x1B90; +pub const SWOI_IOAC_CTRL_2_SWOI_1_FRAG_LEN_MASK: u32 = 0xFF; +pub const SWOI_IOAC_CTRL_2_SWOI_1_FRAG_LEN_SHIFT: u32 = 24; +pub const SWOI_IOAC_CTRL_2_SWOI_1_PKT_LEN_MASK: u32 = 0xFFF; +pub const SWOI_IOAC_CTRL_2_SWOI_1_PKT_LEN_SHIFT: u32 = 12; +pub const SWOI_IOAC_CTRL_2_SWOI_1_HDR_ADDR_MASK: u32 = 0xFFF; +pub const SWOI_IOAC_CTRL_2_SWOI_1_HDR_ADDR_SHIFT: u32 = 0; + +pub const SWOI_IOAC_CTRL_3: u32 = 0x1B94; +pub const SWOI_IOAC_CTRL_3_SWOI_2_FRAG_LEN_MASK: u32 = 0xFF; +pub const SWOI_IOAC_CTRL_3_SWOI_2_FRAG_LEN_SHIFT: u32 = 24; +pub const SWOI_IOAC_CTRL_3_SWOI_2_PKT_LEN_MASK: u32 = 0xFFF; +pub const SWOI_IOAC_CTRL_3_SWOI_2_PKT_LEN_SHIFT: u32 = 12; +pub const SWOI_IOAC_CTRL_3_SWOI_2_HDR_ADDR_MASK: u32 = 0xFFF; +pub const SWOI_IOAC_CTRL_3_SWOI_2_HDR_ADDR_SHIFT: u32 = 0; + +/*SWOI_HOST_IPV6_ADDR reuse reg1a60-1a6c,: u32 = 1a70-1a7c,: u32 = 1aa0-1aac,: u32 = 1ab0-1abc.*/ +pub const HRTBT_WAKEUP_PORT: u32 = 0x1AE8; +pub const HRTBT_WAKEUP_PORT_SRC_MASK: u32 = 0xFFFF; +pub const HRTBT_WAKEUP_PORT_SRC_SHIFT: u32 = 16; +pub const HRTBT_WAKEUP_PORT_DEST_MASK: u32 = 0xFFFF; +pub const HRTBT_WAKEUP_PORT_DEST_SHIFT: u32 = 0; + +pub const HRTBT_WAKEUP_DATA7: u32 = 0x1AEC; +pub const HRTBT_WAKEUP_DATA6: u32 = 0x1AF0; +pub const HRTBT_WAKEUP_DATA5: u32 = 0x1AF4; +pub const HRTBT_WAKEUP_DATA4: u32 = 0x1AF8; +pub const HRTBT_WAKEUP_DATA3: u32 = 0x1AFC; +pub const HRTBT_WAKEUP_DATA2: u32 = 0x1B80; +pub const HRTBT_WAKEUP_DATA1: u32 = 0x1B84; +pub const HRTBT_WAKEUP_DATA0: u32 = 0x1B88; + +pub const RXPARSE: u32 = 0x1458; +pub const RXPARSE_FLT6_L4_MASK: u32 = 0x3; +pub const RXPARSE_FLT6_L4_SHIFT: u32 = 30; +pub const RXPARSE_FLT6_L3_MASK: u32 = 0x3; +pub const RXPARSE_FLT6_L3_SHIFT: u32 = 28; +pub const RXPARSE_FLT5_L4_MASK: u32 = 0x3; +pub const RXPARSE_FLT5_L4_SHIFT: u32 = 26; +pub const RXPARSE_FLT5_L3_MASK: u32 = 0x3; +pub const RXPARSE_FLT5_L3_SHIFT: u32 = 24; +pub const RXPARSE_FLT4_L4_MASK: u32 = 0x3; +pub const RXPARSE_FLT4_L4_SHIFT: u32 = 22; +pub const RXPARSE_FLT4_L3_MASK: u32 = 0x3; +pub const RXPARSE_FLT4_L3_SHIFT: u32 = 20; +pub const RXPARSE_FLT3_L4_MASK: u32 = 0x3; +pub const RXPARSE_FLT3_L4_SHIFT: u32 = 18; +pub const RXPARSE_FLT3_L3_MASK: u32 = 0x3; +pub const RXPARSE_FLT3_L3_SHIFT: u32 = 16; +pub const RXPARSE_FLT2_L4_MASK: u32 = 0x3; +pub const RXPARSE_FLT2_L4_SHIFT: u32 = 14; +pub const RXPARSE_FLT2_L3_MASK: u32 = 0x3; +pub const RXPARSE_FLT2_L3_SHIFT: u32 = 12; +pub const RXPARSE_FLT1_L4_MASK: u32 = 0x3; +pub const RXPARSE_FLT1_L4_SHIFT: u32 = 10; +pub const RXPARSE_FLT1_L3_MASK: u32 = 0x3; +pub const RXPARSE_FLT1_L3_SHIFT: u32 = 8; +pub const RXPARSE_FLT6_EN: u32 = 1 << 5; +pub const RXPARSE_FLT5_EN: u32 = 1 << 4; +pub const RXPARSE_FLT4_EN: u32 = 1 << 3; +pub const RXPARSE_FLT3_EN: u32 = 1 << 2; +pub const RXPARSE_FLT2_EN: u32 = 1 << 1; +pub const RXPARSE_FLT1_EN: u32 = 1 << 0; +pub const RXPARSE_FLT_L4_UDP: u32 = 0; +pub const RXPARSE_FLT_L4_TCP: u32 = 1; +pub const RXPARSE_FLT_L4_BOTH: u32 = 2; +pub const RXPARSE_FLT_L4_NONE: u32 = 3; +pub const RXPARSE_FLT_L3_IPV6: u32 = 0; +pub const RXPARSE_FLT_L3_IPV4: u32 = 1; +pub const RXPARSE_FLT_L3_BOTH: u32 = 2; + +/* Terodo support */ +pub const TRD_CTRL: u32 = 0x145C; +pub const TRD_CTRL_EN: u32 = 1 << 31; +pub const TRD_CTRL_BUBBLE_WAKE_EN: u32 = 1 << 30; +pub const TRD_CTRL_PREFIX_CMP_HW: u32 = 1 << 28; +pub const TRD_CTRL_RSHDR_ADDR_MASK: u32 = 0xFFF; +pub const TRD_CTRL_RSHDR_ADDR_SHIFT: u32 = 16; +pub const TRD_CTRL_SINTV_MAX_MASK: u32 = 0xFF; +pub const TRD_CTRL_SINTV_MAX_SHIFT: u32 = 8; +pub const TRD_CTRL_SINTV_MIN_MASK: u32 = 0xFF; +pub const TRD_CTRL_SINTV_MIN_SHIFT: u32 = 0; + +pub const TRD_RS: u32 = 0x1460; +pub const TRD_RS_SZ_MASK: u32 = 0xFFF; +pub const TRD_RS_SZ_SHIFT: u32 = 20; +pub const TRD_RS_NONCE_OFS_MASK: u32 = 0xFFF; +pub const TRD_RS_NONCE_OFS_SHIFT: u32 = 8; +pub const TRD_RS_SEQ_OFS_MASK: u32 = 0xFF; +pub const TRD_RS_SEQ_OFS_SHIFT: u32 = 0; + +pub const TRD_SRV_IP4: u32 = 0x1464; + +pub const TRD_CLNT_EXTNL_IP4: u32 = 0x1468; + +pub const TRD_PORT: u32 = 0x146C; +pub const TRD_PORT_CLNT_EXTNL_MASK: u32 = 0xFFFF; +pub const TRD_PORT_CLNT_EXTNL_SHIFT: u32 = 16; +pub const TRD_PORT_SRV_MASK: u32 = 0xFFFF; +pub const TRD_PORT_SRV_SHIFT: u32 = 0; + +pub const TRD_PREFIX: u32 = 0x1470; + +pub const TRD_BUBBLE_DA_IP4: u32 = 0x1478; + +pub const TRD_BUBBLE_DA_PORT: u32 = 0x147C; + +/* for: u32 = B0 */ +pub const IDLE_DECISN_TIMER: u32 = 0x1474; +/*: u32 = 1ms */ +pub const IDLE_DECISN_TIMER_DEF: u32 = 0x400; + +pub const MAC_CTRL: u32 = 0x1480; +pub const MAC_CTRL_FAST_PAUSE: u32 = 1 << 31; +pub const MAC_CTRL_WOLSPED_SWEN: u32 = 1 << 30; +/* bit29:: u32 = 1:legacy(hi5b),: u32 = 0:marvl(lo5b)*/ +pub const MAC_CTRL_MHASH_ALG_HI5B: u32 = 1 << 29; +pub const MAC_CTRL_SPAUSE_EN: u32 = 1 << 28; +pub const MAC_CTRL_DBG_EN: u32 = 1 << 27; +pub const MAC_CTRL_BRD_EN: u32 = 1 << 26; +pub const MAC_CTRL_MULTIALL_EN: u32 = 1 << 25; +pub const MAC_CTRL_RX_XSUM_EN: u32 = 1 << 24; +pub const MAC_CTRL_THUGE: u32 = 1 << 23; +pub const MAC_CTRL_MBOF: u32 = 1 << 22; +pub const MAC_CTRL_SPEED_MASK: u32 = 0x3; +pub const MAC_CTRL_SPEED_SHIFT: u32 = 20; +pub const MAC_CTRL_SPEED_10_100: u32 = 1; +pub const MAC_CTRL_SPEED_1000: u32 = 2; +pub const MAC_CTRL_SIMR: u32 = 1 << 19; +pub const MAC_CTRL_SSTCT: u32 = 1 << 17; +pub const MAC_CTRL_TPAUSE: u32 = 1 << 16; +pub const MAC_CTRL_PROMISC_EN: u32 = 1 << 15; +pub const MAC_CTRL_VLANSTRIP: u32 = 1 << 14; +pub const MAC_CTRL_PRMBLEN_MASK: u32 = 0xF; +pub const MAC_CTRL_PRMBLEN_SHIFT: u32 = 10; +pub const MAC_CTRL_RHUGE_EN: u32 = 1 << 9; +pub const MAC_CTRL_FLCHK: u32 = 1 << 8; +pub const MAC_CTRL_PCRCE: u32 = 1 << 7; +pub const MAC_CTRL_CRCE: u32 = 1 << 6; +pub const MAC_CTRL_FULLD: u32 = 1 << 5; +pub const MAC_CTRL_LPBACK_EN: u32 = 1 << 4; +pub const MAC_CTRL_RXFC_EN: u32 = 1 << 3; +pub const MAC_CTRL_TXFC_EN: u32 = 1 << 2; +pub const MAC_CTRL_RX_EN: u32 = 1 << 1; +pub const MAC_CTRL_TX_EN: u32 = 1 << 0; + +pub const GAP: u32 = 0x1484; +pub const GAP_IPGR2_MASK: u32 = 0x7F; +pub const GAP_IPGR2_SHIFT: u32 = 24; +pub const GAP_IPGR1_MASK: u32 = 0x7F; +pub const GAP_IPGR1_SHIFT: u32 = 16; +pub const GAP_MIN_IFG_MASK: u32 = 0xFF; +pub const GAP_MIN_IFG_SHIFT: u32 = 8; +pub const GAP_IPGT_MASK: u32 = 0x7F; +pub const GAP_IPGT_SHIFT: u32 = 0; + +pub const STAD0: u32 = 0x1488; +pub const STAD1: u32 = 0x148C; + +pub const HASH_TBL0: u32 = 0x1490; +pub const HASH_TBL1: u32 = 0x1494; + +pub const HALFD: u32 = 0x1498; +pub const HALFD_JAM_IPG_MASK: u32 = 0xF; +pub const HALFD_JAM_IPG_SHIFT: u32 = 24; +pub const HALFD_ABEBT_MASK: u32 = 0xF; +pub const HALFD_ABEBT_SHIFT: u32 = 20; +pub const HALFD_ABEBE: u32 = 1 << 19; +pub const HALFD_BPNB: u32 = 1 << 18; +pub const HALFD_NOBO: u32 = 1 << 17; +pub const HALFD_EDXSDFR: u32 = 1 << 16; +pub const HALFD_RETRY_MASK: u32 = 0xF; +pub const HALFD_RETRY_SHIFT: u32 = 12; +pub const HALFD_LCOL_MASK: u32 = 0x3FF; +pub const HALFD_LCOL_SHIFT: u32 = 0; + +pub const MTU: u32 = 0x149C; +pub const MTU_JUMBO_TH: u32 = 1514; +pub const MTU_STD_ALGN: u32 = 1536; +pub const MTU_MIN: u32 = 64; + +pub const SRAM0: u32 = 0x1500; +pub const SRAM_RFD_TAIL_ADDR_MASK: u32 = 0xFFF; +pub const SRAM_RFD_TAIL_ADDR_SHIFT: u32 = 16; +pub const SRAM_RFD_HEAD_ADDR_MASK: u32 = 0xFFF; +pub const SRAM_RFD_HEAD_ADDR_SHIFT: u32 = 0; + +pub const SRAM1: u32 = 0x1510; +pub const SRAM_RFD_LEN_MASK: u32 = 0xFFF; +pub const SRAM_RFD_LEN_SHIFT: u32 = 0; + +pub const SRAM2: u32 = 0x1518; +pub const SRAM_TRD_TAIL_ADDR_MASK: u32 = 0xFFF; +pub const SRAM_TRD_TAIL_ADDR_SHIFT: u32 = 16; +pub const SRMA_TRD_HEAD_ADDR_MASK: u32 = 0xFFF; +pub const SRAM_TRD_HEAD_ADDR_SHIFT: u32 = 0; + +pub const SRAM3: u32 = 0x151C; +pub const SRAM_TRD_LEN_MASK: u32 = 0xFFF; +pub const SRAM_TRD_LEN_SHIFT: u32 = 0; + +pub const SRAM4: u32 = 0x1520; +pub const SRAM_RXF_TAIL_ADDR_MASK: u32 = 0xFFF; +pub const SRAM_RXF_TAIL_ADDR_SHIFT: u32 = 16; +pub const SRAM_RXF_HEAD_ADDR_MASK: u32 = 0xFFF; +pub const SRAM_RXF_HEAD_ADDR_SHIFT: u32 = 0; + +pub const SRAM5: u32 = 0x1524; +pub const SRAM_RXF_LEN_MASK: u32 = 0xFFF; +pub const SRAM_RXF_LEN_SHIFT: u32 = 0; +pub const SRAM_RXF_LEN_8K: u32 = (8*1024); + +pub const SRAM6: u32 = 0x1528; +pub const SRAM_TXF_TAIL_ADDR_MASK: u32 = 0xFFF; +pub const SRAM_TXF_TAIL_ADDR_SHIFT: u32 = 16; +pub const SRAM_TXF_HEAD_ADDR_MASK: u32 = 0xFFF; +pub const SRAM_TXF_HEAD_ADDR_SHIFT: u32 = 0; + +pub const SRAM7: u32 = 0x152C; +pub const SRAM_TXF_LEN_MASK: u32 = 0xFFF; +pub const SRAM_TXF_LEN_SHIFT: u32 = 0; + +pub const SRAM8: u32 = 0x1530; +pub const SRAM_PATTERN_ADDR_MASK: u32 = 0xFFF; +pub const SRAM_PATTERN_ADDR_SHIFT: u32 = 16; +pub const SRAM_TSO_ADDR_MASK: u32 = 0xFFF; +pub const SRAM_TSO_ADDR_SHIFT: u32 = 0; + +pub const SRAM9: u32 = 0x1534; +pub const SRAM_LOAD_PTR: u32 = 1 << 0; + +pub const RX_BASE_ADDR_HI: u32 = 0x1540; + +pub const TX_BASE_ADDR_HI: u32 = 0x1544; + +pub const RFD_ADDR_LO: u32 = 0x1550; +pub const RFD_RING_SZ: u32 = 0x1560; +pub const RFD_BUF_SZ: u32 = 0x1564; +pub const RFD_BUF_SZ_MASK: u32 = 0xFFFF; +pub const RFD_BUF_SZ_SHIFT: u32 = 0; + +pub const RRD_ADDR_LO: u32 = 0x1568; +pub const RRD_RING_SZ: u32 = 0x1578; +pub const RRD_RING_SZ_MASK: u32 = 0xFFF; +pub const RRD_RING_SZ_SHIFT: u32 = 0; + +/* pri3: highest, pri0: lowest */ +pub const TPD_PRI3_ADDR_LO: u32 = 0x14E4; +pub const TPD_PRI2_ADDR_LO: u32 = 0x14E0; +pub const TPD_PRI1_ADDR_LO: u32 = 0x157C; +pub const TPD_PRI0_ADDR_LO: u32 = 0x1580; + +/* producer index is: u32 = 16bit */ +pub const TPD_PRI3_PIDX: u32 = 0x1618; +pub const TPD_PRI2_PIDX: u32 = 0x161A; +pub const TPD_PRI1_PIDX: u32 = 0x15F0; +pub const TPD_PRI0_PIDX: u32 = 0x15F2; + +/* consumer index is: u32 = 16bit */ +pub const TPD_PRI3_CIDX: u32 = 0x161C; +pub const TPD_PRI2_CIDX: u32 = 0x161E; +pub const TPD_PRI1_CIDX: u32 = 0x15F4; +pub const TPD_PRI0_CIDX: u32 = 0x15F6; + +pub const TPD_RING_SZ: u32 = 0x1584; +pub const TPD_RING_SZ_MASK: u32 = 0xFFFF; +pub const TPD_RING_SZ_SHIFT: u32 = 0; + +pub const CMB_ADDR_LO: u32 = 0x1588; + +pub const TXQ0: u32 = 0x1590; +pub const TXQ0_TXF_BURST_PREF_MASK: u32 = 0xFFFF; +pub const TXQ0_TXF_BURST_PREF_SHIFT: u32 = 16; +pub const TXQ_TXF_BURST_PREF_DEF: u32 = 0x200; +pub const TXQ0_PEDING_CLR: u32 = 1 << 8; +pub const TXQ0_LSO_8023_EN: u32 = 1 << 7; +pub const TXQ0_MODE_ENHANCE: u32 = 1 << 6; +pub const TXQ0_EN: u32 = 1 << 5; +pub const TXQ0_SUPT_IPOPT: u32 = 1 << 4; +pub const TXQ0_TPD_BURSTPREF_MASK: u32 = 0xF; +pub const TXQ0_TPD_BURSTPREF_SHIFT: u32 = 0; +pub const TXQ_TPD_BURSTPREF_DEF: u32 = 5; + +pub const TXQ1: u32 = 0x1594; +/* bit11: drop large packet, len > (rfd buf) */ +pub const TXQ1_ERRLGPKT_DROP_EN: u32 = 1 << 11; +/* bit[9:0]:: u32 = 8bytes unit */ +pub const TXQ1_JUMBO_TSOTHR_MASK: u32 = 0x7FF; +pub const TXQ1_JUMBO_TSOTHR_SHIFT: u32 = 0; +pub const TXQ1_JUMBO_TSO_TH: u32 = (7*1024); + +/* L1 entrance control */ +pub const TXQ2: u32 = 0x1598; +pub const TXQ2_BURST_EN: u32 = 1 << 31; +pub const TXQ2_BURST_HI_WM_MASK: u32 = 0xFFF; +pub const TXQ2_BURST_HI_WM_SHIFT: u32 = 16; +pub const TXQ2_BURST_LO_WM_MASK: u32 = 0xFFF; +pub const TXQ2_BURST_LO_WM_SHIFT: u32 = 0; + +pub const RXQ0: u32 = 0x15A0; +pub const RXQ0_EN: u32 = 1 << 31; +pub const RXQ0_CUT_THRU_EN: u32 = 1 << 30; +pub const RXQ0_RSS_HASH_EN: u32 = 1 << 29; +/* bit28:: u32 = 0:goto Q0,: u32 = 1:as table */ +pub const RXQ0_NON_IP_QTBL: u32 = 1 << 28; +pub const RXQ0_RSS_MODE_MASK: u32 = 0x3; +pub const RXQ0_RSS_MODE_SHIFT: u32 = 26; +pub const RXQ0_RSS_MODE_DIS: u32 = 0; +pub const RXQ0_RSS_MODE_SQSI: u32 = 1; +pub const RXQ0_RSS_MODE_MQSI: u32 = 2; +pub const RXQ0_RSS_MODE_MQMI: u32 = 3; +pub const RXQ0_NUM_RFD_PREF_MASK: u32 = 0x3F; +pub const RXQ0_NUM_RFD_PREF_SHIFT: u32 = 20; +pub const RXQ0_NUM_RFD_PREF_DEF: u32 = 8; +pub const RXQ0_IDT_TBL_SIZE_MASK: u32 = 0x1FF; +pub const RXQ0_IDT_TBL_SIZE_SHIFT: u32 = 8; +pub const RXQ0_IDT_TBL_SIZE_DEF: u32 = 0x100; +pub const RXQ0_IPV6_PARSE_EN: u32 = 1 << 7; +pub const RXQ0_RSS_HSTYP_MASK: u32 = 0xF; +pub const RXQ0_RSS_HSTYP_SHIFT: u32 = 2; +pub const RXQ0_RSS_HSTYP_IPV6_TCP_EN: u32 = 1 << 5; +pub const RXQ0_RSS_HSTYP_IPV6_EN: u32 = 1 << 4; +pub const RXQ0_RSS_HSTYP_IPV4_TCP_EN: u32 = 1 << 3; +pub const RXQ0_RSS_HSTYP_IPV4_EN: u32 = 1 << 2; +pub const RXQ0_RSS_HSTYP_ALL: u32 = + RXQ0_RSS_HSTYP_IPV6_TCP_EN | + RXQ0_RSS_HSTYP_IPV4_TCP_EN | + RXQ0_RSS_HSTYP_IPV6_EN | + RXQ0_RSS_HSTYP_IPV4_EN; +pub const RXQ0_ASPM_THRESH_MASK: u32 = 0x3; +pub const RXQ0_ASPM_THRESH_SHIFT: u32 = 0; +pub const RXQ0_ASPM_THRESH_NO: u32 = 0; +pub const RXQ0_ASPM_THRESH_1M: u32 = 1; +pub const RXQ0_ASPM_THRESH_10M: u32 = 2; +pub const RXQ0_ASPM_THRESH_100M: u32 = 3; + +pub const RXQ1: u32 = 0x15A4; +/*: u32 = 32bytes unit */ +pub const RXQ1_JUMBO_LKAH_MASK: u32 = 0xF; +pub const RXQ1_JUMBO_LKAH_SHIFT: u32 = 12; +pub const RXQ1_RFD_PREF_DOWN_MASK: u32 = 0x3F; +pub const RXQ1_RFD_PREF_DOWN_SHIFT: u32 = 6; +pub const RXQ1_RFD_PREF_UP_MASK: u32 = 0x3F; +pub const RXQ1_RFD_PREF_UP_SHIFT: u32 = 0; + +pub const RXQ2: u32 = 0x15A8; +/* XOFF: USED SRAM LOWER THAN IT, THEN NOTIFY THE PEER TO SEND AGAIN */ +pub const RXQ2_RXF_XOFF_THRESH_MASK: u32 = 0xFFF; +pub const RXQ2_RXF_XOFF_THRESH_SHIFT: u32 = 16; +pub const RXQ2_RXF_XON_THRESH_MASK: u32 = 0xFFF; +pub const RXQ2_RXF_XON_THRESH_SHIFT: u32 = 0; +/* Size = tx-packet(1522) + IPG(12) + SOF(8) + 64(Pause) + IPG(12) + SOF(8) + + * rx-packet(1522) + delay-of-link(64) + * =: u32 = 3212. + */ +pub const RXQ2_RXF_FLOW_CTRL_RSVD: u32 = 3212; + +pub const RXQ3: u32 = 0x15AC; +pub const RXQ3_RXD_TIMER_MASK: u32 = 0x7FFF; +pub const RXQ3_RXD_TIMER_SHIFT: u32 = 16; +/*: u32 = 8bytes unit */ +pub const RXQ3_RXD_THRESH_MASK: u32 = 0xFFF; +pub const RXQ3_RXD_THRESH_SHIFT: u32 = 0; + +pub const DMA: u32 = 0x15C0; +pub const DMA_SMB_NOW: u32 = 1 << 31; +pub const DMA_WPEND_CLR: u32 = 1 << 30; +pub const DMA_RPEND_CLR: u32 = 1 << 29; +pub const DMA_WSRAM_RDCTRL: u32 = 1 << 28; +pub const DMA_RCHNL_SEL_MASK: u32 = 0x3; +pub const DMA_RCHNL_SEL_SHIFT: u32 = 26; +pub const DMA_RCHNL_SEL_1: u32 = 0; +pub const DMA_RCHNL_SEL_2: u32 = 1; +pub const DMA_RCHNL_SEL_3: u32 = 2; +pub const DMA_RCHNL_SEL_4: u32 = 3; +pub const DMA_SMB_EN: u32 = 1 << 21; +pub const DMA_WDLY_CNT_MASK: u32 = 0xF; +pub const DMA_WDLY_CNT_SHIFT: u32 = 16; +pub const DMA_WDLY_CNT_DEF: u32 = 4; +pub const DMA_RDLY_CNT_MASK: u32 = 0x1F; +pub const DMA_RDLY_CNT_SHIFT: u32 = 11; +pub const DMA_RDLY_CNT_DEF: u32 = 15; +/* bit10:: u32 = 0:tpd with pri,: u32 = 1: data */ +pub const DMA_RREQ_PRI_DATA: u32 = 1 << 10; +pub const DMA_WREQ_BLEN_MASK: u32 = 0x7; +pub const DMA_WREQ_BLEN_SHIFT: u32 = 7; +pub const DMA_RREQ_BLEN_MASK: u32 = 0x7; +pub const DMA_RREQ_BLEN_SHIFT: u32 = 4; +pub const DMA_PENDING_AUTO_RST: u32 = 1 << 3; +pub const DMA_RORDER_MODE_MASK: u32 = 0x7; +pub const DMA_RORDER_MODE_SHIFT: u32 = 0; +pub const DMA_RORDER_MODE_OUT: u32 = 4; +pub const DMA_RORDER_MODE_ENHANCE: u32 = 2; +pub const DMA_RORDER_MODE_IN: u32 = 1; + +pub const WOL0: u32 = 0x14A0; +pub const WOL0_PT7_MATCH: u32 = 1 << 31; +pub const WOL0_PT6_MATCH: u32 = 1 << 30; +pub const WOL0_PT5_MATCH: u32 = 1 << 29; +pub const WOL0_PT4_MATCH: u32 = 1 << 28; +pub const WOL0_PT3_MATCH: u32 = 1 << 27; +pub const WOL0_PT2_MATCH: u32 = 1 << 26; +pub const WOL0_PT1_MATCH: u32 = 1 << 25; +pub const WOL0_PT0_MATCH: u32 = 1 << 24; +pub const WOL0_PT7_EN: u32 = 1 << 23; +pub const WOL0_PT6_EN: u32 = 1 << 22; +pub const WOL0_PT5_EN: u32 = 1 << 21; +pub const WOL0_PT4_EN: u32 = 1 << 20; +pub const WOL0_PT3_EN: u32 = 1 << 19; +pub const WOL0_PT2_EN: u32 = 1 << 18; +pub const WOL0_PT1_EN: u32 = 1 << 17; +pub const WOL0_PT0_EN: u32 = 1 << 16; +pub const WOL0_IPV4_SYNC_EVT: u32 = 1 << 14; +pub const WOL0_IPV6_SYNC_EVT: u32 = 1 << 13; +pub const WOL0_LINK_EVT: u32 = 1 << 10; +pub const WOL0_MAGIC_EVT: u32 = 1 << 9; +pub const WOL0_PATTERN_EVT: u32 = 1 << 8; +pub const WOL0_SWOI_EVT: u32 = 1 << 7; +pub const WOL0_OOB_EN: u32 = 1 << 6; +pub const WOL0_PME_LINK: u32 = 1 << 5; +pub const WOL0_LINK_EN: u32 = 1 << 4; +pub const WOL0_PME_MAGIC_EN: u32 = 1 << 3; +pub const WOL0_MAGIC_EN: u32 = 1 << 2; +pub const WOL0_PME_PATTERN_EN: u32 = 1 << 1; +pub const WOL0_PATTERN_EN: u32 = 1 << 0; + +pub const WOL1: u32 = 0x14A4; +pub const WOL1_PT3_LEN_MASK: u32 = 0xFF; +pub const WOL1_PT3_LEN_SHIFT: u32 = 24; +pub const WOL1_PT2_LEN_MASK: u32 = 0xFF; +pub const WOL1_PT2_LEN_SHIFT: u32 = 16; +pub const WOL1_PT1_LEN_MASK: u32 = 0xFF; +pub const WOL1_PT1_LEN_SHIFT: u32 = 8; +pub const WOL1_PT0_LEN_MASK: u32 = 0xFF; +pub const WOL1_PT0_LEN_SHIFT: u32 = 0; + +pub const WOL2: u32 = 0x14A8; +pub const WOL2_PT7_LEN_MASK: u32 = 0xFF; +pub const WOL2_PT7_LEN_SHIFT: u32 = 24; +pub const WOL2_PT6_LEN_MASK: u32 = 0xFF; +pub const WOL2_PT6_LEN_SHIFT: u32 = 16; +pub const WOL2_PT5_LEN_MASK: u32 = 0xFF; +pub const WOL2_PT5_LEN_SHIFT: u32 = 8; +pub const WOL2_PT4_LEN_MASK: u32 = 0xFF; +pub const WOL2_PT4_LEN_SHIFT: u32 = 0; + +pub const RFD_PIDX: u32 = 0x15E0; +pub const RFD_PIDX_MASK: u32 = 0xFFF; +pub const RFD_PIDX_SHIFT: u32 = 0; + +pub const RFD_CIDX: u32 = 0x15F8; +pub const RFD_CIDX_MASK: u32 = 0xFFF; +pub const RFD_CIDX_SHIFT: u32 = 0; + +/* MIB */ +pub const MIB_BASE: u32 = 0x1700; +pub const MIB_RX_OK: u32 = (MIB_BASE + 0); +pub const MIB_RX_BC: u32 = (MIB_BASE + 4); +pub const MIB_RX_MC: u32 = (MIB_BASE + 8); +pub const MIB_RX_PAUSE: u32 = (MIB_BASE + 12); +pub const MIB_RX_CTRL: u32 = (MIB_BASE + 16); +pub const MIB_RX_FCS: u32 = (MIB_BASE + 20); +pub const MIB_RX_LENERR: u32 = (MIB_BASE + 24); +pub const MIB_RX_BYTCNT: u32 = (MIB_BASE + 28); +pub const MIB_RX_RUNT: u32 = (MIB_BASE + 32); +pub const MIB_RX_FRAGMENT: u32 = (MIB_BASE + 36); +pub const MIB_RX_64B: u32 = (MIB_BASE + 40); +pub const MIB_RX_127B: u32 = (MIB_BASE + 44); +pub const MIB_RX_255B: u32 = (MIB_BASE + 48); +pub const MIB_RX_511B: u32 = (MIB_BASE + 52); +pub const MIB_RX_1023B: u32 = (MIB_BASE + 56); +pub const MIB_RX_1518B: u32 = (MIB_BASE + 60); +pub const MIB_RX_SZMAX: u32 = (MIB_BASE + 64); +pub const MIB_RX_OVSZ: u32 = (MIB_BASE + 68); +pub const MIB_RXF_OV: u32 = (MIB_BASE + 72); +pub const MIB_RRD_OV: u32 = (MIB_BASE + 76); +pub const MIB_RX_ALIGN: u32 = (MIB_BASE + 80); +pub const MIB_RX_BCCNT: u32 = (MIB_BASE + 84); +pub const MIB_RX_MCCNT: u32 = (MIB_BASE + 88); +pub const MIB_RX_ERRADDR: u32 = (MIB_BASE + 92); +pub const MIB_TX_OK: u32 = (MIB_BASE + 96); +pub const MIB_TX_BC: u32 = (MIB_BASE + 100); +pub const MIB_TX_MC: u32 = (MIB_BASE + 104); +pub const MIB_TX_PAUSE: u32 = (MIB_BASE + 108); +pub const MIB_TX_EXCDEFER: u32 = (MIB_BASE + 112); +pub const MIB_TX_CTRL: u32 = (MIB_BASE + 116); +pub const MIB_TX_DEFER: u32 = (MIB_BASE + 120); +pub const MIB_TX_BYTCNT: u32 = (MIB_BASE + 124); +pub const MIB_TX_64B: u32 = (MIB_BASE + 128); +pub const MIB_TX_127B: u32 = (MIB_BASE + 132); +pub const MIB_TX_255B: u32 = (MIB_BASE + 136); +pub const MIB_TX_511B: u32 = (MIB_BASE + 140); +pub const MIB_TX_1023B: u32 = (MIB_BASE + 144); +pub const MIB_TX_1518B: u32 = (MIB_BASE + 148); +pub const MIB_TX_SZMAX: u32 = (MIB_BASE + 152); +pub const MIB_TX_1COL: u32 = (MIB_BASE + 156); +pub const MIB_TX_2COL: u32 = (MIB_BASE + 160); +pub const MIB_TX_LATCOL: u32 = (MIB_BASE + 164); +pub const MIB_TX_ABRTCOL: u32 = (MIB_BASE + 168); +pub const MIB_TX_UNDRUN: u32 = (MIB_BASE + 172); +pub const MIB_TX_TRDBEOP: u32 = (MIB_BASE + 176); +pub const MIB_TX_LENERR: u32 = (MIB_BASE + 180); +pub const MIB_TX_TRUNC: u32 = (MIB_BASE + 184); +pub const MIB_TX_BCCNT: u32 = (MIB_BASE + 188); +pub const MIB_TX_MCCNT: u32 = (MIB_BASE + 192); +pub const MIB_UPDATE: u32 = (MIB_BASE + 196); + +pub const ISR: u32 = 0x1600; +pub const ISR_DIS: u32 = 1 << 31; +pub const ISR_RX_Q7: u32 = 1 << 30; +pub const ISR_RX_Q6: u32 = 1 << 29; +pub const ISR_RX_Q5: u32 = 1 << 28; +pub const ISR_RX_Q4: u32 = 1 << 27; +pub const ISR_PCIE_LNKDOWN: u32 = 1 << 26; +pub const ISR_PCIE_CERR: u32 = 1 << 25; +pub const ISR_PCIE_NFERR: u32 = 1 << 24; +pub const ISR_PCIE_FERR: u32 = 1 << 23; +pub const ISR_PCIE_UR: u32 = 1 << 22; +pub const ISR_MAC_TX: u32 = 1 << 21; +pub const ISR_MAC_RX: u32 = 1 << 20; +pub const ISR_RX_Q3: u32 = 1 << 19; +pub const ISR_RX_Q2: u32 = 1 << 18; +pub const ISR_RX_Q1: u32 = 1 << 17; +pub const ISR_RX_Q0: u32 = 1 << 16; +pub const ISR_TX_Q0: u32 = 1 << 15; +pub const ISR_TXQ_TO: u32 = 1 << 14; +pub const ISR_PHY_LPW: u32 = 1 << 13; +pub const ISR_PHY: u32 = 1 << 12; +pub const ISR_TX_CREDIT: u32 = 1 << 11; +pub const ISR_DMAW: u32 = 1 << 10; +pub const ISR_DMAR: u32 = 1 << 9; +pub const ISR_TXF_UR: u32 = 1 << 8; +pub const ISR_TX_Q3: u32 = 1 << 7; +pub const ISR_TX_Q2: u32 = 1 << 6; +pub const ISR_TX_Q1: u32 = 1 << 5; +pub const ISR_RFD_UR: u32 = 1 << 4; +pub const ISR_RXF_OV: u32 = 1 << 3; +pub const ISR_MANU: u32 = 1 << 2; +pub const ISR_TIMER: u32 = 1 << 1; +pub const ISR_SMB: u32 = 1 << 0; + +pub const IMR: u32 = 0x1604; + +/* re-send assert msg if SW no response */ +pub const INT_RETRIG: u32 = 0x1608; +pub const INT_RETRIG_TIMER_MASK: u32 = 0xFFFF; +pub const INT_RETRIG_TIMER_SHIFT: u32 = 0; +/*: u32 = 40ms */ +pub const INT_RETRIG_TO: u32 = 20000; + +/* re-send deassert msg if SW no response */ +pub const INT_DEASST_TIMER: u32 = 0x1614; + +/* reg1620 used for sleep status */ +pub const PATTERN_MASK: u32 = 0x1620; +pub const PATTERN_MASK_LEN: u32 = 128; + + +pub const FLT1_SRC_IP0: u32 = 0x1A00; +pub const FLT1_SRC_IP1: u32 = 0x1A04; +pub const FLT1_SRC_IP2: u32 = 0x1A08; +pub const FLT1_SRC_IP3: u32 = 0x1A0C; +pub const FLT1_DST_IP0: u32 = 0x1A10; +pub const FLT1_DST_IP1: u32 = 0x1A14; +pub const FLT1_DST_IP2: u32 = 0x1A18; +pub const FLT1_DST_IP3: u32 = 0x1A1C; +pub const FLT1_PORT: u32 = 0x1A20; +pub const FLT1_PORT_DST_MASK: u32 = 0xFFFF; +pub const FLT1_PORT_DST_SHIFT: u32 = 16; +pub const FLT1_PORT_SRC_MASK: u32 = 0xFFFF; +pub const FLT1_PORT_SRC_SHIFT: u32 = 0; + +pub const FLT2_SRC_IP0: u32 = 0x1A24; +pub const FLT2_SRC_IP1: u32 = 0x1A28; +pub const FLT2_SRC_IP2: u32 = 0x1A2C; +pub const FLT2_SRC_IP3: u32 = 0x1A30; +pub const FLT2_DST_IP0: u32 = 0x1A34; +pub const FLT2_DST_IP1: u32 = 0x1A38; +pub const FLT2_DST_IP2: u32 = 0x1A40; +pub const FLT2_DST_IP3: u32 = 0x1A44; +pub const FLT2_PORT: u32 = 0x1A48; +pub const FLT2_PORT_DST_MASK: u32 = 0xFFFF; +pub const FLT2_PORT_DST_SHIFT: u32 = 16; +pub const FLT2_PORT_SRC_MASK: u32 = 0xFFFF; +pub const FLT2_PORT_SRC_SHIFT: u32 = 0; + +pub const FLT3_SRC_IP0: u32 = 0x1A4C; +pub const FLT3_SRC_IP1: u32 = 0x1A50; +pub const FLT3_SRC_IP2: u32 = 0x1A54; +pub const FLT3_SRC_IP3: u32 = 0x1A58; +pub const FLT3_DST_IP0: u32 = 0x1A5C; +pub const FLT3_DST_IP1: u32 = 0x1A60; +pub const FLT3_DST_IP2: u32 = 0x1A64; +pub const FLT3_DST_IP3: u32 = 0x1A68; +pub const FLT3_PORT: u32 = 0x1A6C; +pub const FLT3_PORT_DST_MASK: u32 = 0xFFFF; +pub const FLT3_PORT_DST_SHIFT: u32 = 16; +pub const FLT3_PORT_SRC_MASK: u32 = 0xFFFF; +pub const FLT3_PORT_SRC_SHIFT: u32 = 0; + +pub const FLT4_SRC_IP0: u32 = 0x1A70; +pub const FLT4_SRC_IP1: u32 = 0x1A74; +pub const FLT4_SRC_IP2: u32 = 0x1A78; +pub const FLT4_SRC_IP3: u32 = 0x1A7C; +pub const FLT4_DST_IP0: u32 = 0x1A80; +pub const FLT4_DST_IP1: u32 = 0x1A84; +pub const FLT4_DST_IP2: u32 = 0x1A88; +pub const FLT4_DST_IP3: u32 = 0x1A8C; +pub const FLT4_PORT: u32 = 0x1A90; +pub const FLT4_PORT_DST_MASK: u32 = 0xFFFF; +pub const FLT4_PORT_DST_SHIFT: u32 = 16; +pub const FLT4_PORT_SRC_MASK: u32 = 0xFFFF; +pub const FLT4_PORT_SRC_SHIFT: u32 = 0; + +pub const FLT5_SRC_IP0: u32 = 0x1A94; +pub const FLT5_SRC_IP1: u32 = 0x1A98; +pub const FLT5_SRC_IP2: u32 = 0x1A9C; +pub const FLT5_SRC_IP3: u32 = 0x1AA0; +pub const FLT5_DST_IP0: u32 = 0x1AA4; +pub const FLT5_DST_IP1: u32 = 0x1AA8; +pub const FLT5_DST_IP2: u32 = 0x1AAC; +pub const FLT5_DST_IP3: u32 = 0x1AB0; +pub const FLT5_PORT: u32 = 0x1AB4; +pub const FLT5_PORT_DST_MASK: u32 = 0xFFFF; +pub const FLT5_PORT_DST_SHIFT: u32 = 16; +pub const FLT5_PORT_SRC_MASK: u32 = 0xFFFF; +pub const FLT5_PORT_SRC_SHIFT: u32 = 0; + +pub const FLT6_SRC_IP0: u32 = 0x1AB8; +pub const FLT6_SRC_IP1: u32 = 0x1ABC; +pub const FLT6_SRC_IP2: u32 = 0x1AC0; +pub const FLT6_SRC_IP3: u32 = 0x1AC8; +pub const FLT6_DST_IP0: u32 = 0x1620; +pub const FLT6_DST_IP1: u32 = 0x1624; +pub const FLT6_DST_IP2: u32 = 0x1628; +pub const FLT6_DST_IP3: u32 = 0x162C; +pub const FLT6_PORT: u32 = 0x1630; +pub const FLT6_PORT_DST_MASK: u32 = 0xFFFF; +pub const FLT6_PORT_DST_SHIFT: u32 = 16; +pub const FLT6_PORT_SRC_MASK: u32 = 0xFFFF; +pub const FLT6_PORT_SRC_SHIFT: u32 = 0; + +pub const FLTCTRL: u32 = 0x1634; +pub const FLTCTRL_PSTHR_TIMER_MASK: u32 = 0xFF; +pub const FLTCTRL_PSTHR_TIMER_SHIFT: u32 = 24; +pub const FLTCTRL_CHK_DSTPRT6: u32 = 1 << 23; +pub const FLTCTRL_CHK_SRCPRT6: u32 = 1 << 22; +pub const FLTCTRL_CHK_DSTIP6: u32 = 1 << 21; +pub const FLTCTRL_CHK_SRCIP6: u32 = 1 << 20; +pub const FLTCTRL_CHK_DSTPRT5: u32 = 1 << 19; +pub const FLTCTRL_CHK_SRCPRT5: u32 = 1 << 18; +pub const FLTCTRL_CHK_DSTIP5: u32 = 1 << 17; +pub const FLTCTRL_CHK_SRCIP5: u32 = 1 << 16; +pub const FLTCTRL_CHK_DSTPRT4: u32 = 1 << 15; +pub const FLTCTRL_CHK_SRCPRT4: u32 = 1 << 14; +pub const FLTCTRL_CHK_DSTIP4: u32 = 1 << 13; +pub const FLTCTRL_CHK_SRCIP4: u32 = 1 << 12; +pub const FLTCTRL_CHK_DSTPRT3: u32 = 1 << 11; +pub const FLTCTRL_CHK_SRCPRT3: u32 = 1 << 10; +pub const FLTCTRL_CHK_DSTIP3: u32 = 1 << 9; +pub const FLTCTRL_CHK_SRCIP3: u32 = 1 << 8; +pub const FLTCTRL_CHK_DSTPRT2: u32 = 1 << 7; +pub const FLTCTRL_CHK_SRCPRT2: u32 = 1 << 6; +pub const FLTCTRL_CHK_DSTIP2: u32 = 1 << 5; +pub const FLTCTRL_CHK_SRCIP2: u32 = 1 << 4; +pub const FLTCTRL_CHK_DSTPRT1: u32 = 1 << 3; +pub const FLTCTRL_CHK_SRCPRT1: u32 = 1 << 2; +pub const FLTCTRL_CHK_DSTIP1: u32 = 1 << 1; +pub const FLTCTRL_CHK_SRCIP1: u32 = 1 << 0; + +pub const DROP_ALG1: u32 = 0x1638; +pub const DROP_ALG1_BWCHGVAL_MASK: u32 = 0xFFFFF; +pub const DROP_ALG1_BWCHGVAL_SHIFT: u32 = 12; +/* bit11:: u32 = 0:3.125%,: u32 = 1:6.25% */ +pub const DROP_ALG1_BWCHGSCL_6: u32 = 1 << 11; +pub const DROP_ALG1_ASUR_LWQ_EN: u32 = 1 << 10; +pub const DROP_ALG1_BWCHGVAL_EN: u32 = 1 << 9; +pub const DROP_ALG1_BWCHGSCL_EN: u32 = 1 << 8; +pub const DROP_ALG1_PSTHR_AUTO: u32 = 1 << 7; +pub const DROP_ALG1_MIN_PSTHR_MASK: u32 = 0x3; +pub const DROP_ALG1_MIN_PSTHR_SHIFT: u32 = 5; +pub const DROP_ALG1_MIN_PSTHR_1_16: u32 = 0; +pub const DROP_ALG1_MIN_PSTHR_1_8: u32 = 1; +pub const DROP_ALG1_MIN_PSTHR_1_4: u32 = 2; +pub const DROP_ALG1_MIN_PSTHR_1_2: u32 = 3; +pub const DROP_ALG1_PSCL_MASK: u32 = 0x3; +pub const DROP_ALG1_PSCL_SHIFT: u32 = 3; +pub const DROP_ALG1_PSCL_1_4: u32 = 0; +pub const DROP_ALG1_PSCL_1_8: u32 = 1; +pub const DROP_ALG1_PSCL_1_16: u32 = 2; +pub const DROP_ALG1_PSCL_1_32: u32 = 3; +pub const DROP_ALG1_TIMESLOT_MASK: u32 = 0x7; +pub const DROP_ALG1_TIMESLOT_SHIFT: u32 = 0; +pub const DROP_ALG1_TIMESLOT_4MS: u32 = 0; +pub const DROP_ALG1_TIMESLOT_8MS: u32 = 1; +pub const DROP_ALG1_TIMESLOT_16MS: u32 = 2; +pub const DROP_ALG1_TIMESLOT_32MS: u32 = 3; +pub const DROP_ALG1_TIMESLOT_64MS: u32 = 4; +pub const DROP_ALG1_TIMESLOT_128MS: u32 = 5; +pub const DROP_ALG1_TIMESLOT_256MS: u32 = 6; +pub const DROP_ALG1_TIMESLOT_512MS: u32 = 7; + +pub const DROP_ALG2: u32 = 0x163C; +pub const DROP_ALG2_SMPLTIME_MASK: u32 = 0xF; +pub const DROP_ALG2_SMPLTIME_SHIFT: u32 = 24; +pub const DROP_ALG2_LWQBW_MASK: u32 = 0xFFFFFF; +pub const DROP_ALG2_LWQBW_SHIFT: u32 = 0; + +pub const SMB_TIMER: u32 = 0x15C4; + +pub const TINT_TPD_THRSHLD: u32 = 0x15C8; + +pub const TINT_TIMER: u32 = 0x15CC; + +pub const CLK_GATE: u32 = 0x1814; +/* bit[8:6]: for: u32 = B0+ */ +pub const CLK_GATE_125M_SW_DIS_CR: u32 = 1 << 8; +pub const CLK_GATE_125M_SW_AZ: u32 = 1 << 7; +pub const CLK_GATE_125M_SW_IDLE: u32 = 1 << 6; +pub const CLK_GATE_RXMAC: u32 = 1 << 5; +pub const CLK_GATE_TXMAC: u32 = 1 << 4; +pub const CLK_GATE_RXQ: u32 = 1 << 3; +pub const CLK_GATE_TXQ: u32 = 1 << 2; +pub const CLK_GATE_DMAR: u32 = 1 << 1; +pub const CLK_GATE_DMAW: u32 = 1 << 0; +pub const CLK_GATE_ALL_A0: u32 = + CLK_GATE_RXMAC | + CLK_GATE_TXMAC | + CLK_GATE_RXQ | + CLK_GATE_TXQ | + CLK_GATE_DMAR | + CLK_GATE_DMAW; +pub const CLK_GATE_ALL_B0: u32 = CLK_GATE_ALL_A0; + +/* PORST affect */ +pub const BTROM_CFG: u32 = 0x1800; + +/* interop between drivers */ +pub const DRV: u32 = 0x1804; +pub const DRV_PHY_AUTO: u32 = 1 << 28; +pub const DRV_PHY_1000: u32 = 1 << 27; +pub const DRV_PHY_100: u32 = 1 << 26; +pub const DRV_PHY_10: u32 = 1 << 25; +pub const DRV_PHY_DUPLEX: u32 = 1 << 24; +/* bit23: adv Pause */ +pub const DRV_PHY_PAUSE: u32 = 1 << 23; +/* bit22: adv Asym Pause */ +pub const DRV_PHY_APAUSE: u32 = 1 << 22; +/* bit21:: u32 = 1:en AZ */ +pub const DRV_PHY_EEE: u32 = 1 << 21; +pub const DRV_PHY_MASK: u32 = 0xFF; +pub const DRV_PHY_SHIFT: u32 = 21; +pub const DRV_PHY_UNKNOWN: u32 = 0; +pub const DRV_DISABLE: u32 = 1 << 18; +pub const DRV_WOLS5_EN: u32 = 1 << 17; +pub const DRV_WOLS5_BIOS_EN: u32 = 1 << 16; +pub const DRV_AZ_EN: u32 = 1 << 12; +pub const DRV_WOLPATTERN_EN: u32 = 1 << 11; +pub const DRV_WOLLINKUP_EN: u32 = 1 << 10; +pub const DRV_WOLMAGIC_EN: u32 = 1 << 9; +pub const DRV_WOLCAP_BIOS_EN: u32 = 1 << 8; +pub const DRV_ASPM_SPD1000LMT_MASK: u32 = 0x3; +pub const DRV_ASPM_SPD1000LMT_SHIFT: u32 = 4; +pub const DRV_ASPM_SPD1000LMT_100M: u32 = 0; +pub const DRV_ASPM_SPD1000LMT_NO: u32 = 1; +pub const DRV_ASPM_SPD1000LMT_1M: u32 = 2; +pub const DRV_ASPM_SPD1000LMT_10M: u32 = 3; +pub const DRV_ASPM_SPD100LMT_MASK: u32 = 0x3; +pub const DRV_ASPM_SPD100LMT_SHIFT: u32 = 2; +pub const DRV_ASPM_SPD100LMT_1M: u32 = 0; +pub const DRV_ASPM_SPD100LMT_10M: u32 = 1; +pub const DRV_ASPM_SPD100LMT_100M: u32 = 2; +pub const DRV_ASPM_SPD100LMT_NO: u32 = 3; +pub const DRV_ASPM_SPD10LMT_MASK: u32 = 0x3; +pub const DRV_ASPM_SPD10LMT_SHIFT: u32 = 0; +pub const DRV_ASPM_SPD10LMT_1M: u32 = 0; +pub const DRV_ASPM_SPD10LMT_10M: u32 = 1; +pub const DRV_ASPM_SPD10LMT_100M: u32 = 2; +pub const DRV_ASPM_SPD10LMT_NO: u32 = 3; + +/* flag of phy inited */ +pub const PHY_INITED: u16 = 0x003F; + +/* PERST affect */ +pub const DRV_ERR1: u32 = 0x1808; +pub const DRV_ERR1_GEN: u32 = 1 << 31; +pub const DRV_ERR1_NOR: u32 = 1 << 30; +pub const DRV_ERR1_TRUNC: u32 = 1 << 29; +pub const DRV_ERR1_RES: u32 = 1 << 28; +pub const DRV_ERR1_INTFATAL: u32 = 1 << 27; +pub const DRV_ERR1_TXQPEND: u32 = 1 << 26; +pub const DRV_ERR1_DMAW: u32 = 1 << 25; +pub const DRV_ERR1_DMAR: u32 = 1 << 24; +pub const DRV_ERR1_PCIELNKDWN: u32 = 1 << 23; +pub const DRV_ERR1_PKTSIZE: u32 = 1 << 22; +pub const DRV_ERR1_FIFOFUL: u32 = 1 << 21; +pub const DRV_ERR1_RFDUR: u32 = 1 << 20; +pub const DRV_ERR1_RRDSI: u32 = 1 << 19; +pub const DRV_ERR1_UPDATE: u32 = 1 << 18; + +pub const DRV_ERR2: u32 = 0x180C; + +pub const DBG_ADDR: u32 = 0x1900; +pub const DBG_DATA: u32 = 0x1904; + +pub const SYNC_IPV4_SA: u32 = 0x1A00; +pub const SYNC_IPV4_DA: u32 = 0x1A04; + +pub const SYNC_V4PORT: u32 = 0x1A08; +pub const SYNC_V4PORT_DST_MASK: u32 = 0xFFFF; +pub const SYNC_V4PORT_DST_SHIFT: u32 = 16; +pub const SYNC_V4PORT_SRC_MASK: u32 = 0xFFFF; +pub const SYNC_V4PORT_SRC_SHIFT: u32 = 0; + +pub const SYNC_IPV6_SA0: u32 = 0x1A0C; +pub const SYNC_IPV6_SA1: u32 = 0x1A10; +pub const SYNC_IPV6_SA2: u32 = 0x1A14; +pub const SYNC_IPV6_SA3: u32 = 0x1A18; +pub const SYNC_IPV6_DA0: u32 = 0x1A1C; +pub const SYNC_IPV6_DA1: u32 = 0x1A20; +pub const SYNC_IPV6_DA2: u32 = 0x1A24; +pub const SYNC_IPV6_DA3: u32 = 0x1A28; + +pub const SYNC_V6PORT: u32 = 0x1A2C; +pub const SYNC_V6PORT_DST_MASK: u32 = 0xFFFF; +pub const SYNC_V6PORT_DST_SHIFT: u32 = 16; +pub const SYNC_V6PORT_SRC_MASK: u32 = 0xFFFF; +pub const SYNC_V6PORT_SRC_SHIFT: u32 = 0; + +pub const ARP_REMOTE_IPV4: u32 = 0x1A30; +pub const ARP_HOST_IPV4: u32 = 0x1A34; +pub const ARP_MAC0: u32 = 0x1A38; +pub const ARP_MAC1: u32 = 0x1A3C; + +pub const FIRST_REMOTE_IPV6_0: u32 = 0x1A40; +pub const FIRST_REMOTE_IPV6_1: u32 = 0x1A44; +pub const FIRST_REMOTE_IPV6_2: u32 = 0x1A48; +pub const FIRST_REMOTE_IPV6_3: u32 = 0x1A4C; + +pub const FIRST_SN_IPV6_0: u32 = 0x1A50; +pub const FIRST_SN_IPV6_1: u32 = 0x1A54; +pub const FIRST_SN_IPV6_2: u32 = 0x1A58; +pub const FIRST_SN_IPV6_3: u32 = 0x1A5C; + +pub const FIRST_TAR_IPV6_1_0: u32 = 0x1A60; +pub const FIRST_TAR_IPV6_1_1: u32 = 0x1A64; +pub const FIRST_TAR_IPV6_1_2: u32 = 0x1A68; +pub const FIRST_TAR_IPV6_1_3: u32 = 0x1A6C; +pub const FIRST_TAR_IPV6_2_0: u32 = 0x1A70; +pub const FIRST_TAR_IPV6_2_1: u32 = 0x1A74; +pub const FIRST_TAR_IPV6_2_2: u32 = 0x1A78; +pub const FIRST_TAR_IPV6_2_3: u32 = 0x1A7C; + +pub const SECOND_REMOTE_IPV6_0: u32 = 0x1A80; +pub const SECOND_REMOTE_IPV6_1: u32 = 0x1A84; +pub const SECOND_REMOTE_IPV6_2: u32 = 0x1A88; +pub const SECOND_REMOTE_IPV6_3: u32 = 0x1A8C; + +pub const SECOND_SN_IPV6_0: u32 = 0x1A90; +pub const SECOND_SN_IPV6_1: u32 = 0x1A94; +pub const SECOND_SN_IPV6_2: u32 = 0x1A98; +pub const SECOND_SN_IPV6_3: u32 = 0x1A9C; + +pub const SECOND_TAR_IPV6_1_0: u32 = 0x1AA0; +pub const SECOND_TAR_IPV6_1_1: u32 = 0x1AA4; +pub const SECOND_TAR_IPV6_1_2: u32 = 0x1AA8; +pub const SECOND_TAR_IPV6_1_3: u32 = 0x1AAC; +pub const SECOND_TAR_IPV6_2_0: u32 = 0x1AB0; +pub const SECOND_TAR_IPV6_2_1: u32 = 0x1AB4; +pub const SECOND_TAR_IPV6_2_2: u32 = 0x1AB8; +pub const SECOND_TAR_IPV6_2_3: u32 = 0x1ABC; + +pub const FIRST_NS_MAC0: u32 = 0x1AC0; +pub const FIRST_NS_MAC1: u32 = 0x1AC4; + +pub const SECOND_NS_MAC0: u32 = 0x1AC8; +pub const SECOND_NS_MAC1: u32 = 0x1ACC; + +pub const PMOFLD: u32 = 0x144C; +/* bit[11:10]: for: u32 = B0+ */ +pub const PMOFLD_ECMA_IGNR_FRG_SSSR: u32 = 1 << 11; +pub const PMOFLD_ARP_CNFLCT_WAKEUP: u32 = 1 << 10; +pub const PMOFLD_MULTI_SOLD: u32 = 1 << 9; +pub const PMOFLD_ICMP_XSUM: u32 = 1 << 8; +pub const PMOFLD_GARP_REPLY: u32 = 1 << 7; +pub const PMOFLD_SYNCV6_ANY: u32 = 1 << 6; +pub const PMOFLD_SYNCV4_ANY: u32 = 1 << 5; +pub const PMOFLD_BY_HW: u32 = 1 << 4; +pub const PMOFLD_NS_EN: u32 = 1 << 3; +pub const PMOFLD_ARP_EN: u32 = 1 << 2; +pub const PMOFLD_SYNCV6_EN: u32 = 1 << 1; +pub const PMOFLD_SYNCV4_EN: u32 = 1 << 0; + +/* reg: u32 = 1830 ~: u32 = 186C for C0+,: u32 = 16 bit map patterns and wake packet detection */ +pub const WOL_CTRL2: u32 = 0x1830; +pub const WOL_CTRL2_DATA_STORE: u32 = 1 << 3; +pub const WOL_CTRL2_PTRN_EVT: u32 = 1 << 2; +pub const WOL_CTRL2_PME_PTRN_EN: u32 = 1 << 1; +pub const WOL_CTRL2_PTRN_EN: u32 = 1 << 0; + +pub const WOL_CTRL3: u32 = 0x1834; +pub const WOL_CTRL3_PTRN_ADDR_MASK: u32 = 0xFFFFF; +pub const WOL_CTRL3_PTRN_ADDR_SHIFT: u32 = 0; + +pub const WOL_CTRL4: u32 = 0x1838; +pub const WOL_CTRL4_PT15_MATCH: u32 = 1 << 31; +pub const WOL_CTRL4_PT14_MATCH: u32 = 1 << 30; +pub const WOL_CTRL4_PT13_MATCH: u32 = 1 << 29; +pub const WOL_CTRL4_PT12_MATCH: u32 = 1 << 28; +pub const WOL_CTRL4_PT11_MATCH: u32 = 1 << 27; +pub const WOL_CTRL4_PT10_MATCH: u32 = 1 << 26; +pub const WOL_CTRL4_PT9_MATCH: u32 = 1 << 25; +pub const WOL_CTRL4_PT8_MATCH: u32 = 1 << 24; +pub const WOL_CTRL4_PT7_MATCH: u32 = 1 << 23; +pub const WOL_CTRL4_PT6_MATCH: u32 = 1 << 22; +pub const WOL_CTRL4_PT5_MATCH: u32 = 1 << 21; +pub const WOL_CTRL4_PT4_MATCH: u32 = 1 << 20; +pub const WOL_CTRL4_PT3_MATCH: u32 = 1 << 19; +pub const WOL_CTRL4_PT2_MATCH: u32 = 1 << 18; +pub const WOL_CTRL4_PT1_MATCH: u32 = 1 << 17; +pub const WOL_CTRL4_PT0_MATCH: u32 = 1 << 16; +pub const WOL_CTRL4_PT15_EN: u32 = 1 << 15; +pub const WOL_CTRL4_PT14_EN: u32 = 1 << 14; +pub const WOL_CTRL4_PT13_EN: u32 = 1 << 13; +pub const WOL_CTRL4_PT12_EN: u32 = 1 << 12; +pub const WOL_CTRL4_PT11_EN: u32 = 1 << 11; +pub const WOL_CTRL4_PT10_EN: u32 = 1 << 10; +pub const WOL_CTRL4_PT9_EN: u32 = 1 << 9; +pub const WOL_CTRL4_PT8_EN: u32 = 1 << 8; +pub const WOL_CTRL4_PT7_EN: u32 = 1 << 7; +pub const WOL_CTRL4_PT6_EN: u32 = 1 << 6; +pub const WOL_CTRL4_PT5_EN: u32 = 1 << 5; +pub const WOL_CTRL4_PT4_EN: u32 = 1 << 4; +pub const WOL_CTRL4_PT3_EN: u32 = 1 << 3; +pub const WOL_CTRL4_PT2_EN: u32 = 1 << 2; +pub const WOL_CTRL4_PT1_EN: u32 = 1 << 1; +pub const WOL_CTRL4_PT0_EN: u32 = 1 << 0; + +pub const WOL_CTRL5: u32 = 0x183C; +pub const WOL_CTRL5_PT3_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT3_LEN_SHIFT: u32 = 24; +pub const WOL_CTRL5_PT2_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT2_LEN_SHIFT: u32 = 16; +pub const WOL_CTRL5_PT1_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT1_LEN_SHIFT: u32 = 8; +pub const WOL_CTRL5_PT0_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT0_LEN_SHIFT: u32 = 0; + +pub const WOL_CTRL6: u32 = 0x1840; +pub const WOL_CTRL5_PT7_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT7_LEN_SHIFT: u32 = 24; +pub const WOL_CTRL5_PT6_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT6_LEN_SHIFT: u32 = 16; +pub const WOL_CTRL5_PT5_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT5_LEN_SHIFT: u32 = 8; +pub const WOL_CTRL5_PT4_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT4_LEN_SHIFT: u32 = 0; + +pub const WOL_CTRL7: u32 = 0x1844; +pub const WOL_CTRL5_PT11_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT11_LEN_SHIFT: u32 = 24; +pub const WOL_CTRL5_PT10_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT10_LEN_SHIFT: u32 = 16; +pub const WOL_CTRL5_PT9_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT9_LEN_SHIFT: u32 = 8; +pub const WOL_CTRL5_PT8_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT8_LEN_SHIFT: u32 = 0; + +pub const WOL_CTRL8: u32 = 0x1848; +pub const WOL_CTRL5_PT15_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT15_LEN_SHIFT: u32 = 24; +pub const WOL_CTRL5_PT14_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT14_LEN_SHIFT: u32 = 16; +pub const WOL_CTRL5_PT13_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT13_LEN_SHIFT: u32 = 8; +pub const WOL_CTRL5_PT12_LEN_MASK: u32 = 0xFF; +pub const WOL_CTRL5_PT12_LEN_SHIFT: u32 = 0; + +pub const ACER_FIXED_PTN0: u32 = 0x1850; +pub const ACER_FIXED_PTN0_MASK: u32 = 0xFFFFFFFF; +pub const ACER_FIXED_PTN0_SHIFT: u32 = 0; + +pub const ACER_FIXED_PTN1: u32 = 0x1854; +pub const ACER_FIXED_PTN1_MASK: u32 = 0xFFFF; +pub const ACER_FIXED_PTN1_SHIFT: u32 = 0; + +pub const ACER_RANDOM_NUM0: u32 = 0x1858; +pub const ACER_RANDOM_NUM0_MASK: u32 = 0xFFFFFFFF; +pub const ACER_RANDOM_NUM0_SHIFT: u32 = 0; + +pub const ACER_RANDOM_NUM1: u32 = 0x185C; +pub const ACER_RANDOM_NUM1_MASK: u32 = 0xFFFFFFFF; +pub const ACER_RANDOM_NUM1_SHIFT: u32 = 0; + +pub const ACER_RANDOM_NUM2: u32 = 0x1860; +pub const ACER_RANDOM_NUM2_MASK: u32 = 0xFFFFFFFF; +pub const ACER_RANDOM_NUM2_SHIFT: u32 = 0; + +pub const ACER_RANDOM_NUM3: u32 = 0x1864; +pub const ACER_RANDOM_NUM3_MASK: u32 = 0xFFFFFFFF; +pub const ACER_RANDOM_NUM3_SHIFT: u32 = 0; + +pub const ACER_MAGIC: u32 = 0x1868; +pub const ACER_MAGIC_EN: u32 = 1 << 31; +pub const ACER_MAGIC_PME_EN: u32 = 1 << 30; +pub const ACER_MAGIC_MATCH: u32 = 1 << 29; +pub const ACER_MAGIC_FF_CHECK: u32 = 1 << 10; +pub const ACER_MAGIC_RAN_LEN_MASK: u32 = 0x1F; +pub const ACER_MAGIC_RAN_LEN_SHIFT: u32 = 5; +pub const ACER_MAGIC_FIX_LEN_MASK: u32 = 0x1F; +pub const ACER_MAGIC_FIX_LEN_SHIFT: u32 = 0; + +pub const ACER_TIMER: u32 = 0x186C; +pub const ACER_TIMER_EN: u32 = 1 << 31; +pub const ACER_TIMER_PME_EN: u32 = 1 << 30; +pub const ACER_TIMER_MATCH: u32 = 1 << 29; +pub const ACER_TIMER_THRES_MASK: u32 = 0x1FFFF; +pub const ACER_TIMER_THRES_SHIFT: u32 = 0; +pub const ACER_TIMER_THRES_DEF: u32 = 1; + +/* RSS definitions */ +pub const RSS_KEY0: u32 = 0x14B0; +pub const RSS_KEY1: u32 = 0x14B4; +pub const RSS_KEY2: u32 = 0x14B8; +pub const RSS_KEY3: u32 = 0x14BC; +pub const RSS_KEY4: u32 = 0x14C0; +pub const RSS_KEY5: u32 = 0x14C4; +pub const RSS_KEY6: u32 = 0x14C8; +pub const RSS_KEY7: u32 = 0x14CC; +pub const RSS_KEY8: u32 = 0x14D0; +pub const RSS_KEY9: u32 = 0x14D4; + +pub const RSS_IDT_TBL0: u32 = 0x1B00; +pub const RSS_IDT_TBL1: u32 = 0x1B04; +pub const RSS_IDT_TBL2: u32 = 0x1B08; +pub const RSS_IDT_TBL3: u32 = 0x1B0C; +pub const RSS_IDT_TBL4: u32 = 0x1B10; +pub const RSS_IDT_TBL5: u32 = 0x1B14; +pub const RSS_IDT_TBL6: u32 = 0x1B18; +pub const RSS_IDT_TBL7: u32 = 0x1B1C; +pub const RSS_IDT_TBL8: u32 = 0x1B20; +pub const RSS_IDT_TBL9: u32 = 0x1B24; +pub const RSS_IDT_TBL10: u32 = 0x1B28; +pub const RSS_IDT_TBL11: u32 = 0x1B2C; +pub const RSS_IDT_TBL12: u32 = 0x1B30; +pub const RSS_IDT_TBL13: u32 = 0x1B34; +pub const RSS_IDT_TBL14: u32 = 0x1B38; +pub const RSS_IDT_TBL15: u32 = 0x1B3C; +pub const RSS_IDT_TBL16: u32 = 0x1B40; +pub const RSS_IDT_TBL17: u32 = 0x1B44; +pub const RSS_IDT_TBL18: u32 = 0x1B48; +pub const RSS_IDT_TBL19: u32 = 0x1B4C; +pub const RSS_IDT_TBL20: u32 = 0x1B50; +pub const RSS_IDT_TBL21: u32 = 0x1B54; +pub const RSS_IDT_TBL22: u32 = 0x1B58; +pub const RSS_IDT_TBL23: u32 = 0x1B5C; +pub const RSS_IDT_TBL24: u32 = 0x1B60; +pub const RSS_IDT_TBL25: u32 = 0x1B64; +pub const RSS_IDT_TBL26: u32 = 0x1B68; +pub const RSS_IDT_TBL27: u32 = 0x1B6C; +pub const RSS_IDT_TBL28: u32 = 0x1B70; +pub const RSS_IDT_TBL29: u32 = 0x1B74; +pub const RSS_IDT_TBL30: u32 = 0x1B78; +pub const RSS_IDT_TBL31: u32 = 0x1B7C; + +pub const RSS_HASH_VAL: u32 = 0x15B0; +pub const RSS_HASH_FLAG: u32 = 0x15B4; + +pub const RSS_BASE_CPU_NUM: u32 = 0x15B8; + +pub const MSI_MAP_TBL1: u32 = 0x15D0; +pub const MSI_MAP_TBL1_ALERT_MASK: u32 = 0xF; +pub const MSI_MAP_TBL1_ALERT_SHIFT: u32 = 28; +pub const MSI_MAP_TBL1_TIMER_MASK: u32 = 0xF; +pub const MSI_MAP_TBL1_TIMER_SHIFT: u32 = 24; +pub const MSI_MAP_TBL1_TXQ1_MASK: u32 = 0xF; +pub const MSI_MAP_TBL1_TXQ1_SHIFT: u32 = 20; +pub const MSI_MAP_TBL1_TXQ0_MASK: u32 = 0xF; +pub const MSI_MAP_TBL1_TXQ0_SHIFT: u32 = 16; +pub const MSI_MAP_TBL1_RXQ3_MASK: u32 = 0xF; +pub const MSI_MAP_TBL1_RXQ3_SHIFT: u32 = 12; +pub const MSI_MAP_TBL1_RXQ2_MASK: u32 = 0xF; +pub const MSI_MAP_TBL1_RXQ2_SHIFT: u32 = 8; +pub const MSI_MAP_TBL1_RXQ1_MASK: u32 = 0xF; +pub const MSI_MAP_TBL1_RXQ1_SHIFT: u32 = 4; +pub const MSI_MAP_TBL1_RXQ0_MASK: u32 = 0xF; +pub const MSI_MAP_TBL1_RXQ0_SHIFT: u32 = 0; + +pub const MSI_MAP_TBL2: u32 = 0x15D8; +pub const MSI_MAP_TBL2_PHY_MASK: u32 = 0xF; +pub const MSI_MAP_TBL2_PHY_SHIFT: u32 = 28; +pub const MSI_MAP_TBL2_SMB_MASK: u32 = 0xF; +pub const MSI_MAP_TBL2_SMB_SHIFT: u32 = 24; +pub const MSI_MAP_TBL2_TXQ3_MASK: u32 = 0xF; +pub const MSI_MAP_TBL2_TXQ3_SHIFT: u32 = 20; +pub const MSI_MAP_TBL2_TXQ2_MASK: u32 = 0xF; +pub const MSI_MAP_TBL2_TXQ2_SHIFT: u32 = 16; +pub const MSI_MAP_TBL2_RXQ7_MASK: u32 = 0xF; +pub const MSI_MAP_TBL2_RXQ7_SHIFT: u32 = 12; +pub const MSI_MAP_TBL2_RXQ6_MASK: u32 = 0xF; +pub const MSI_MAP_TBL2_RXQ6_SHIFT: u32 = 8; +pub const MSI_MAP_TBL2_RXQ5_MASK: u32 = 0xF; +pub const MSI_MAP_TBL2_RXQ5_SHIFT: u32 = 4; +pub const MSI_MAP_TBL2_RXQ4_MASK: u32 = 0xF; +pub const MSI_MAP_TBL2_RXQ4_SHIFT: u32 = 0; + +pub const MSI_ID_MAP: u32 = 0x15D4; +pub const MSI_ID_MAP_RXQ7: u32 = 1 << 30; +pub const MSI_ID_MAP_RXQ6: u32 = 1 << 29; +pub const MSI_ID_MAP_RXQ5: u32 = 1 << 28; +pub const MSI_ID_MAP_RXQ4: u32 = 1 << 27; +/* bit26:: u32 = 0:common,1:timer */ +pub const MSI_ID_MAP_PCIELNKDW: u32 = 1 << 26; +pub const MSI_ID_MAP_PCIECERR: u32 = 1 << 25; +pub const MSI_ID_MAP_PCIENFERR: u32 = 1 << 24; +pub const MSI_ID_MAP_PCIEFERR: u32 = 1 << 23; +pub const MSI_ID_MAP_PCIEUR: u32 = 1 << 22; +pub const MSI_ID_MAP_MACTX: u32 = 1 << 21; +pub const MSI_ID_MAP_MACRX: u32 = 1 << 20; +pub const MSI_ID_MAP_RXQ3: u32 = 1 << 19; +pub const MSI_ID_MAP_RXQ2: u32 = 1 << 18; +pub const MSI_ID_MAP_RXQ1: u32 = 1 << 17; +pub const MSI_ID_MAP_RXQ0: u32 = 1 << 16; +pub const MSI_ID_MAP_TXQ0: u32 = 1 << 15; +pub const MSI_ID_MAP_TXQTO: u32 = 1 << 14; +pub const MSI_ID_MAP_LPW: u32 = 1 << 13; +pub const MSI_ID_MAP_PHY: u32 = 1 << 12; +pub const MSI_ID_MAP_TXCREDIT: u32 = 1 << 11; +pub const MSI_ID_MAP_DMAW: u32 = 1 << 10; +pub const MSI_ID_MAP_DMAR: u32 = 1 << 9; +pub const MSI_ID_MAP_TXFUR: u32 = 1 << 8; +pub const MSI_ID_MAP_TXQ3: u32 = 1 << 7; +pub const MSI_ID_MAP_TXQ2: u32 = 1 << 6; +pub const MSI_ID_MAP_TXQ1: u32 = 1 << 5; +pub const MSI_ID_MAP_RFDUR: u32 = 1 << 4; +pub const MSI_ID_MAP_RXFOV: u32 = 1 << 3; +pub const MSI_ID_MAP_MANU: u32 = 1 << 2; +pub const MSI_ID_MAP_TIMER: u32 = 1 << 1; +pub const MSI_ID_MAP_SMB: u32 = 1 << 0; + +pub const MSI_RETRANS_TIMER: u32 = 0x1920; +/* bit16:: u32 = 1:line,0:standard */ +pub const MSI_MASK_SEL_LINE: u32 = 1 << 16; +pub const MSI_RETRANS_TM_MASK: u32 = 0xFFFF; +pub const MSI_RETRANS_TM_SHIFT: u32 = 0; + +pub const CR_DMA_CTRL: u32 = 0x1930; +pub const CR_DMA_CTRL_PRI: u32 = 1 << 22; +pub const CR_DMA_CTRL_RRDRXD_JOINT: u32 = 1 << 21; +pub const CR_DMA_CTRL_BWCREDIT_MASK: u32 = 0x3; +pub const CR_DMA_CTRL_BWCREDIT_SHIFT: u32 = 19; +pub const CR_DMA_CTRL_BWCREDIT_2KB: u32 = 0; +pub const CR_DMA_CTRL_BWCREDIT_1KB: u32 = 1; +pub const CR_DMA_CTRL_BWCREDIT_4KB: u32 = 2; +pub const CR_DMA_CTRL_BWCREDIT_8KB: u32 = 3; +pub const CR_DMA_CTRL_BW_EN: u32 = 1 << 18; +pub const CR_DMA_CTRL_BW_RATIO_MASK: u32 = 0x3; +pub const CR_DMA_CTRL_BW_RATIO_1_2: u32 = 0; +pub const CR_DMA_CTRL_BW_RATIO_1_4: u32 = 1; +pub const CR_DMA_CTRL_BW_RATIO_1_8: u32 = 2; +pub const CR_DMA_CTRL_BW_RATIO_2_1: u32 = 3; +pub const CR_DMA_CTRL_SOFT_RST: u32 = 1 << 11; +pub const CR_DMA_CTRL_TXEARLY_EN: u32 = 1 << 10; +pub const CR_DMA_CTRL_RXEARLY_EN: u32 = 1 << 9; +pub const CR_DMA_CTRL_WEARLY_EN: u32 = 1 << 8; +pub const CR_DMA_CTRL_RXTH_MASK: u32 = 0xF; +pub const CR_DMA_CTRL_WTH_MASK: u32 = 0xF; + + +pub const EFUSE_BIST: u32 = 0x1934; +pub const EFUSE_BIST_COL_MASK: u32 = 0x3F; +pub const EFUSE_BIST_COL_SHIFT: u32 = 24; +pub const EFUSE_BIST_ROW_MASK: u32 = 0x7F; +pub const EFUSE_BIST_ROW_SHIFT: u32 = 12; +pub const EFUSE_BIST_STEP_MASK: u32 = 0xF; +pub const EFUSE_BIST_STEP_SHIFT: u32 = 8; +pub const EFUSE_BIST_PAT_MASK: u32 = 0x7; +pub const EFUSE_BIST_PAT_SHIFT: u32 = 4; +pub const EFUSE_BIST_CRITICAL: u32 = 1 << 3; +pub const EFUSE_BIST_FIXED: u32 = 1 << 2; +pub const EFUSE_BIST_FAIL: u32 = 1 << 1; +pub const EFUSE_BIST_NOW: u32 = 1 << 0; + +/* CR DMA ctrl */ + +/* TX QoS */ +pub const WRR: u32 = 0x1938; +pub const WRR_PRI_MASK: u32 = 0x3; +pub const WRR_PRI_SHIFT: u32 = 29; +pub const WRR_PRI_RESTRICT_ALL: u32 = 0; +pub const WRR_PRI_RESTRICT_HI: u32 = 1; +pub const WRR_PRI_RESTRICT_HI2: u32 = 2; +pub const WRR_PRI_RESTRICT_NONE: u32 = 3; +pub const WRR_PRI3_MASK: u32 = 0x1F; +pub const WRR_PRI3_SHIFT: u32 = 24; +pub const WRR_PRI2_MASK: u32 = 0x1F; +pub const WRR_PRI2_SHIFT: u32 = 16; +pub const WRR_PRI1_MASK: u32 = 0x1F; +pub const WRR_PRI1_SHIFT: u32 = 8; +pub const WRR_PRI0_MASK: u32 = 0x1F; +pub const WRR_PRI0_SHIFT: u32 = 0; + +pub const HQTPD: u32 = 0x193C; +pub const HQTPD_BURST_EN: u32 = 1 << 31; +pub const HQTPD_Q3_NUMPREF_MASK: u32 = 0xF; +pub const HQTPD_Q3_NUMPREF_SHIFT: u32 = 8; +pub const HQTPD_Q2_NUMPREF_MASK: u32 = 0xF; +pub const HQTPD_Q2_NUMPREF_SHIFT: u32 = 4; +pub const HQTPD_Q1_NUMPREF_MASK: u32 = 0xF; +pub const HQTPD_Q1_NUMPREF_SHIFT: u32 = 0; + +pub const CPUMAP1: u32 = 0x19A0; +pub const CPUMAP1_VCT7_MASK: u32 = 0xF; +pub const CPUMAP1_VCT7_SHIFT: u32 = 28; +pub const CPUMAP1_VCT6_MASK: u32 = 0xF; +pub const CPUMAP1_VCT6_SHIFT: u32 = 24; +pub const CPUMAP1_VCT5_MASK: u32 = 0xF; +pub const CPUMAP1_VCT5_SHIFT: u32 = 20; +pub const CPUMAP1_VCT4_MASK: u32 = 0xF; +pub const CPUMAP1_VCT4_SHIFT: u32 = 16; +pub const CPUMAP1_VCT3_MASK: u32 = 0xF; +pub const CPUMAP1_VCT3_SHIFT: u32 = 12; +pub const CPUMAP1_VCT2_MASK: u32 = 0xF; +pub const CPUMAP1_VCT2_SHIFT: u32 = 8; +pub const CPUMAP1_VCT1_MASK: u32 = 0xF; +pub const CPUMAP1_VCT1_SHIFT: u32 = 4; +pub const CPUMAP1_VCT0_MASK: u32 = 0xF; +pub const CPUMAP1_VCT0_SHIFT: u32 = 0; + +pub const CPUMAP2: u32 = 0x19A4; +pub const CPUMAP2_VCT15_MASK: u32 = 0xF; +pub const CPUMAP2_VCT15_SHIFT: u32 = 28; +pub const CPUMAP2_VCT14_MASK: u32 = 0xF; +pub const CPUMAP2_VCT14_SHIFT: u32 = 24; +pub const CPUMAP2_VCT13_MASK: u32 = 0xF; +pub const CPUMAP2_VCT13_SHIFT: u32 = 20; +pub const CPUMAP2_VCT12_MASK: u32 = 0xF; +pub const CPUMAP2_VCT12_SHIFT: u32 = 16; +pub const CPUMAP2_VCT11_MASK: u32 = 0xF; +pub const CPUMAP2_VCT11_SHIFT: u32 = 12; +pub const CPUMAP2_VCT10_MASK: u32 = 0xF; +pub const CPUMAP2_VCT10_SHIFT: u32 = 8; +pub const CPUMAP2_VCT9_MASK: u32 = 0xF; +pub const CPUMAP2_VCT9_SHIFT: u32 = 4; +pub const CPUMAP2_VCT8_MASK: u32 = 0xF; +pub const CPUMAP2_VCT8_SHIFT: u32 = 0; + +pub const MISC: u32 = 0x19C0; +/* bit31:: u32 = 0:vector,1:cpu */ +pub const MISC_MODU: u32 = 1 << 31; +pub const MISC_OVERCUR: u32 = 1 << 29; +pub const MISC_PSWR_EN: u32 = 1 << 28; +pub const MISC_PSW_CTRL_MASK: u32 = 0xF; +pub const MISC_PSW_CTRL_SHIFT: u32 = 24; +pub const MISC_PSW_OCP_MASK: u32 = 0x7; +pub const MISC_PSW_OCP_SHIFT: u32 = 21; +pub const MISC_PSW_OCP_DEF: u32 = 0x7; +pub const MISC_V18_HIGH: u32 = 1 << 20; +pub const MISC_LPO_CTRL_MASK: u32 = 0xF; +pub const MISC_LPO_CTRL_SHIFT: u32 = 16; +pub const MISC_ISO_EN: u32 = 1 << 12; +pub const MISC_XSTANA_ALWAYS_ON: u32 = 1 << 11; +pub const MISC_SYS25M_SEL_ADAPTIVE: u32 = 1 << 10; +pub const MISC_SPEED_SIM: u32 = 1 << 9; +pub const MISC_S1_LWP_EN: u32 = 1 << 8; +/* bit7: pcie/mac do pwsaving as phy in lpw state */ +pub const MISC_MACLPW: u32 = 1 << 7; +pub const MISC_125M_SW: u32 = 1 << 6; +pub const MISC_INTNLOSC_OFF_EN: u32 = 1 << 5; +/* bit4:: u32 = 0:chipset,1:crystle */ +pub const MISC_EXTN25M_SEL: u32 = 1 << 4; +pub const MISC_INTNLOSC_OPEN: u32 = 1 << 3; +pub const MISC_SMBUS_AT_LED: u32 = 1 << 2; +pub const MISC_PPS_AT_LED_MASK: u32 = 0x3; +pub const MISC_PPS_AT_LED_SHIFT: u32 = 0; +pub const MISC_PPS_AT_LED_ACT: u32 = 1; +pub const MISC_PPS_AT_LED_10_100: u32 = 2; +pub const MISC_PPS_AT_LED_1000: u32 = 3; + +pub const MISC1: u32 = 0x19C4; +pub const MSC1_BLK_CRASPM_REQ: u32 = 1 << 15; + +pub const MSIC2: u32 = 0x19C8; +pub const MSIC2_CALB_START: u32 = 1 << 0; + +pub const MISC3: u32 = 0x19CC; +/* bit1:: u32 = 1:Software control: u32 = 25M */ +pub const MISC3_25M_BY_SW: u32 = 1 << 1; +/* bit0:: u32 = 25M switch to intnl OSC */ +pub const MISC3_25M_NOTO_INTNL: u32 = 1 << 0; + +/* MSIX tbl in memory space */ +pub const MSIX_ENTRY_BASE: u32 = 0x2000; + +/***************************** IO mapping registers ***************************/ +pub const IO_ADDR: u32 = 0x00; +pub const IO_DATA: u32 = 0x04; +/* same as reg1400 */ +pub const IO_MASTER: u32 = 0x08; +/* same as reg1480 */ +pub const IO_MAC_CTRL: u32 = 0x0C; +/* same as reg1600 */ +pub const IO_ISR: u32 = 0x10; +/* same as reg: u32 = 1604 */ +pub const IO_IMR: u32 = 0x14; +/* word, same as reg15F0 */ +pub const IO_TPD_PRI1_PIDX: u32 = 0x18; +/* word, same as reg15F2 */ +pub const IO_TPD_PRI0_PIDX: u32 = 0x1A; +/* word, same as reg15F4 */ +pub const IO_TPD_PRI1_CIDX: u32 = 0x1C; +/* word, same as reg15F6 */ +pub const IO_TPD_PRI0_CIDX: u32 = 0x1E; +/* word, same as reg15E0 */ +pub const IO_RFD_PIDX: u32 = 0x20; +/* word, same as reg15F8 */ +pub const IO_RFD_CIDX: u32 = 0x30; +/* same as reg1414 */ +pub const IO_MDIO: u32 = 0x38; +/* same as reg140C */ +pub const IO_PHY_CTRL: u32 = 0x3C; + + +/********************* PHY regs definition ***************************/ + +/* Autoneg Advertisement Register */ +pub const ADVERTISE_SPEED_MASK: u16 = 0x01E0; +pub const ADVERTISE_DEFAULT_CAP: u16 = 0x1DE0; + +/* 1000BASE-T Control Register (0x9) */ +pub const GIGA_CR_1000T_HD_CAPS: u16 = 0x0100; +pub const GIGA_CR_1000T_FD_CAPS: u16 = 0x0200; +pub const GIGA_CR_1000T_REPEATER_DTE: u16 = 0x0400; + +pub const GIGA_CR_1000T_MS_VALUE: u16 = 0x0800; + +pub const GIGA_CR_1000T_MS_ENABLE: u16 = 0x1000; + +pub const GIGA_CR_1000T_TEST_MODE_NORMAL: u16 = 0x0000; +pub const GIGA_CR_1000T_TEST_MODE_1: u16 = 0x2000; +pub const GIGA_CR_1000T_TEST_MODE_2: u16 = 0x4000; +pub const GIGA_CR_1000T_TEST_MODE_3: u16 = 0x6000; +pub const GIGA_CR_1000T_TEST_MODE_4: u16 = 0x8000; +pub const GIGA_CR_1000T_SPEED_MASK: u16 = 0x0300; +pub const GIGA_CR_1000T_DEFAULT_CAP: u16 = 0x0300; + +/* 1000BASE-T Status Register */ +pub const MII_GIGA_SR: u16 = 0x0A; + +/* PHY Specific Status Register */ +pub const MII_GIGA_PSSR: u16 = 0x11; +pub const GIGA_PSSR_FC_RXEN: u16 = 0x0004; +pub const GIGA_PSSR_FC_TXEN: u16 = 0x0008; +pub const GIGA_PSSR_SPD_DPLX_RESOLVED: u16 = 0x0800; +pub const GIGA_PSSR_DPLX: u16 = 0x2000; +pub const GIGA_PSSR_SPEED: u16 = 0xC000; +pub const GIGA_PSSR_10MBS: u16 = 0x0000; +pub const GIGA_PSSR_100MBS: u16 = 0x4000; +pub const GIGA_PSSR_1000MBS: u16 = 0x8000; + +/* PHY Interrupt Enable Register */ +pub const MII_IER: u16 = 0x12; +pub const IER_LINK_UP: u16 = 0x0400; +pub const IER_LINK_DOWN: u16 = 0x0800; + +/* PHY Interrupt Status Register */ +pub const MII_ISR: u16 = 0x13; +pub const ISR_LINK_UP: u16 = 0x0400; +pub const ISR_LINK_DOWN: u16 = 0x0800; + +/* Cable-Detect-Test Control Register */ +pub const MII_CDTC: u16 = 0x16; +/* self clear */ +pub const CDTC_EN: u16 = 1; +pub const CDTC_PAIR_MASK: u16 = 0x3; +pub const CDTC_PAIR_SHIFT: u16 = 8; + + +/* Cable-Detect-Test Status Register */ +pub const MII_CDTS: u16 = 0x1C; +pub const CDTS_STATUS_MASK: u16 = 0x3; +pub const CDTS_STATUS_SHIFT: u16 = 8; +pub const CDTS_STATUS_NORMAL: u16 = 0; +pub const CDTS_STATUS_SHORT: u16 = 1; +pub const CDTS_STATUS_OPEN: u16 = 2; +pub const CDTS_STATUS_INVALID: u16 = 3; + +pub const MII_DBG_ADDR: u16 = 0x1D; +pub const MII_DBG_DATA: u16 = 0x1E; + +/***************************** debug port *************************************/ + +pub const MIIDBG_ANACTRL: u16 = 0x00; +pub const ANACTRL_CLK125M_DELAY_EN: u16 = 0x8000; +pub const ANACTRL_VCO_FAST: u16 = 0x4000; +pub const ANACTRL_VCO_SLOW: u16 = 0x2000; +pub const ANACTRL_AFE_MODE_EN: u16 = 0x1000; +pub const ANACTRL_LCKDET_PHY: u16 = 0x0800; +pub const ANACTRL_LCKDET_EN: u16 = 0x0400; +pub const ANACTRL_OEN_125M: u16 = 0x0200; +pub const ANACTRL_HBIAS_EN: u16 = 0x0100; +pub const ANACTRL_HB_EN: u16 = 0x0080; +pub const ANACTRL_SEL_HSP: u16 = 0x0040; +pub const ANACTRL_CLASSA_EN: u16 = 0x0020; +pub const ANACTRL_MANUSWON_SWR_MASK: u16 = 0x3; +pub const ANACTRL_MANUSWON_SWR_SHIFT: u16 = 2; +pub const ANACTRL_MANUSWON_SWR_2V: u16 = 0; +pub const ANACTRL_MANUSWON_SWR_1P9V: u16 = 1; +pub const ANACTRL_MANUSWON_SWR_1P8V: u16 = 2; +pub const ANACTRL_MANUSWON_SWR_1P7V: u16 = 3; +pub const ANACTRL_MANUSWON_BW3_4M: u16 = 0x0002; +pub const ANACTRL_RESTART_CAL: u16 = 0x0001; +pub const ANACTRL_DEF: u16 = 0x02EF; + + +pub const MIIDBG_SYSMODCTRL: u16 = 0x04; +pub const SYSMODCTRL_IECHOADJ_PFMH_PHY: u16 = 0x8000; +pub const SYSMODCTRL_IECHOADJ_BIASGEN: u16 = 0x4000; +pub const SYSMODCTRL_IECHOADJ_PFML_PHY: u16 = 0x2000; +pub const SYSMODCTRL_IECHOADJ_PS_MASK: u16 = 0x3; +pub const SYSMODCTRL_IECHOADJ_PS_SHIFT: u16 = 10; +pub const SYSMODCTRL_IECHOADJ_PS_40: u16 = 3; +pub const SYSMODCTRL_IECHOADJ_PS_20: u16 = 2; +pub const SYSMODCTRL_IECHOADJ_PS_0: u16 = 1; +pub const SYSMODCTRL_IECHOADJ_10BT_100MV: u16 = 0x0040; +pub const SYSMODCTRL_IECHOADJ_HLFAP_MASK: u16 = 0x3; +pub const SYSMODCTRL_IECHOADJ_HLFAP_SHIFT: u16 = 4; +pub const SYSMODCTRL_IECHOADJ_VDFULBW: u16 = 0x0008; +pub const SYSMODCTRL_IECHOADJ_VDBIASHLF: u16 = 0x0004; +pub const SYSMODCTRL_IECHOADJ_VDAMPHLF: u16 = 0x0002; +pub const SYSMODCTRL_IECHOADJ_VDLANSW: u16 = 0x0001; +/* en half bias */ +pub const SYSMODCTRL_IECHOADJ_DEF: u16 = 0xBB8B; + + +pub const MIIDBG_SRDSYSMOD: u16 = 0x05; +pub const SRDSYSMOD_LCKDET_EN: u16 = 0x2000; +pub const SRDSYSMOD_PLL_EN: u16 = 0x0800; +pub const SRDSYSMOD_SEL_HSP: u16 = 0x0400; +pub const SRDSYSMOD_HLFTXDR: u16 = 0x0200; +pub const SRDSYSMOD_TXCLK_DELAY_EN: u16 = 0x0100; +pub const SRDSYSMOD_TXELECIDLE: u16 = 0x0080; +pub const SRDSYSMOD_DEEMP_EN: u16 = 0x0040; +pub const SRDSYSMOD_MS_PAD: u16 = 0x0004; +pub const SRDSYSMOD_CDR_ADC_VLTG: u16 = 0x0002; +pub const SRDSYSMOD_CDR_DAC_1MA: u16 = 0x0001; +pub const SRDSYSMOD_DEF: u16 = 0x2C46; + + +pub const MIIDBG_HIBNEG: u16 = 0x0B; +pub const HIBNEG_PSHIB_EN: u16 = 0x8000; +pub const HIBNEG_WAKE_BOTH: u16 = 0x4000; +pub const HIBNEG_ONOFF_ANACHG_SUDEN: u16 = 0x2000; +pub const HIBNEG_HIB_PULSE: u16 = 0x1000; +pub const HIBNEG_GATE_25M_EN: u16 = 0x0800; +pub const HIBNEG_RST_80U: u16 = 0x0400; +pub const HIBNEG_RST_TIMER_MASK: u16 = 0x3; +pub const HIBNEG_RST_TIMER_SHIFT: u16 = 8; +pub const HIBNEG_GTX_CLK_DELAY_MASK: u16 = 0x3; +pub const HIBNEG_GTX_CLK_DELAY_SHIFT: u16 = 5; +pub const HIBNEG_BYPSS_BRKTIMER: u16 = 0x0010; +pub const HIBNEG_DEF: u16 = 0xBC40; +pub const HIBNEG_NOHIB: u16 = HIBNEG_DEF & !(HIBNEG_PSHIB_EN | HIBNEG_HIB_PULSE); + +pub const MIIDBG_TST10BTCFG: u16 = 0x12; +pub const TST10BTCFG_INTV_TIMER_MASK: u16 = 0x3; +pub const TST10BTCFG_INTV_TIMER_SHIFT: u16 = 14; +pub const TST10BTCFG_TRIGER_TIMER_MASK: u16 = 0x3; +pub const TST10BTCFG_TRIGER_TIMER_SHIFT: u16 = 12; +pub const TST10BTCFG_DIV_MAN_MLT3_EN: u16 = 0x0800; +pub const TST10BTCFG_OFF_DAC_IDLE: u16 = 0x0400; +pub const TST10BTCFG_LPBK_DEEP: u16 = 0x0004; +pub const TST10BTCFG_DEF: u16 = 0x4C04; + +pub const MIIDBG_AZ_ANADECT: u16 = 0x15; +pub const AZ_ANADECT_10BTRX_TH: u16 = 0x8000; +pub const AZ_ANADECT_BOTH_01CHNL: u16 = 0x4000; +pub const AZ_ANADECT_INTV_MASK: u16 = 0x3F; +pub const AZ_ANADECT_INTV_SHIFT: u16 = 8; +pub const AZ_ANADECT_THRESH_MASK: u16 = 0xF; +pub const AZ_ANADECT_THRESH_SHIFT: u16 = 4; +pub const AZ_ANADECT_CHNL_MASK: u16 = 0xF; +pub const AZ_ANADECT_CHNL_SHIFT: u16 = 0; +pub const AZ_ANADECT_DEF: u16 = 0x3220; +pub const AZ_ANADECT_LONG: u16 = 0x3210; + +pub const MIIDBG_MSE16DB: u16 = 0x18; +pub const MSE16DB_UP: u16 = 0x05EA; +pub const MSE16DB_DOWN: u16 = 0x02EA; + +pub const MIIDBG_MSE20DB: u16 = 0x1C; +pub const MSE20DB_TH_MASK: u16 = 0x7F; +pub const MSE20DB_TH_SHIFT: u16 = 2; +pub const MSE20DB_TH_DEF: u16 = 0x2E; +pub const MSE20DB_TH_HI: u16 = 0x54; + +pub const MIIDBG_AGC: u16 = 0x23; +pub const AGC_2_VGA_MASK: u16 = 0x3F; +pub const AGC_2_VGA_SHIFT: u16 = 8; +pub const AGC_LONG1G_LIMT: u16 = 40; +pub const AGC_LONG100M_LIMT: u16 = 44; + +pub const MIIDBG_LEGCYPS: u16 = 0x29; +pub const LEGCYPS_EN: u16 = 0x8000; +pub const LEGCYPS_DAC_AMP1000_MASK: u16 = 0x7; +pub const LEGCYPS_DAC_AMP1000_SHIFT: u16 = 12; +pub const LEGCYPS_DAC_AMP100_MASK: u16 = 0x7; +pub const LEGCYPS_DAC_AMP100_SHIFT: u16 = 9; +pub const LEGCYPS_DAC_AMP10_MASK: u16 = 0x7; +pub const LEGCYPS_DAC_AMP10_SHIFT: u16 = 6; +pub const LEGCYPS_UNPLUG_TIMER_MASK: u16 = 0x7; +pub const LEGCYPS_UNPLUG_TIMER_SHIFT: u16 = 3; +pub const LEGCYPS_UNPLUG_DECT_EN: u16 = 0x0004; +pub const LEGCYPS_ECNC_PS_EN: u16 = 0x0001; +pub const LEGCYPS_DEF: u16 = 0x129D; + +pub const MIIDBG_TST100BTCFG: u16 = 0x36; +pub const TST100BTCFG_NORMAL_BW_EN: u16 = 0x8000; +pub const TST100BTCFG_BADLNK_BYPASS: u16 = 0x4000; +pub const TST100BTCFG_SHORTCABL_TH_MASK: u16 = 0x3F; +pub const TST100BTCFG_SHORTCABL_TH_SHIFT: u16 = 8; +pub const TST100BTCFG_LITCH_EN: u16 = 0x0080; +pub const TST100BTCFG_VLT_SW: u16 = 0x0040; +pub const TST100BTCFG_LONGCABL_TH_MASK: u16 = 0x3F; +pub const TST100BTCFG_LONGCABL_TH_SHIFT: u16 = 0; +pub const TST100BTCFG_DEF: u16 = 0xE12C; + +pub const MIIDBG_GREENCFG: u16 = 0x3B; +pub const GREENCFG_MSTPS_MSETH2_MASK: u16 = 0xFF; +pub const GREENCFG_MSTPS_MSETH2_SHIFT: u16 = 8; +pub const GREENCFG_MSTPS_MSETH1_MASK: u16 = 0xFF; +pub const GREENCFG_MSTPS_MSETH1_SHIFT: u16 = 0; +pub const GREENCFG_DEF: u16 = 0x7078; + +pub const MIIDBG_GREENCFG2: u16 = 0x3D; +pub const GREENCFG2_BP_GREEN: u16 = 0x8000; +pub const GREENCFG2_GATE_DFSE_EN: u16 = 0x0080; + + +/***************************** extension **************************************/ + +/******* dev 3 *********/ +pub const MIIEXT_PCS: u8 = 3; + +pub const MIIEXT_CLDCTRL3: u16 = 0x8003; +pub const CLDCTRL3_BP_CABLE1TH_DET_GT: u16 = 0x8000; +pub const CLDCTRL3_AZ_DISAMP: u16 = 0x1000; + +pub const MIIEXT_CLDCTRL5: u16 = 0x8005; +pub const CLDCTRL5_BP_VD_HLFBIAS: u16 = 0x4000; + +pub const MIIEXT_CLDCTRL6: u16 = 0x8006; +pub const CLDCTRL6_CAB_LEN_MASK: u16 = 0xFF; +pub const CLDCTRL6_CAB_LEN_SHIFT: u16 = 0; +pub const CLDCTRL6_CAB_LEN_SHORT1G: u16 = 116; +pub const CLDCTRL6_CAB_LEN_SHORT100M: u16 = 152; + +pub const MIIEXT_CLDCTRL7: u16 = 0x8007; +pub const CLDCTRL7_VDHLF_BIAS_TH_MASK: u16 = 0x7F; +pub const CLDCTRL7_VDHLF_BIAS_TH_SHIFT: u16 = 9; +pub const CLDCTRL7_AFE_AZ_MASK: u16 = 0x1F; +pub const CLDCTRL7_AFE_AZ_SHIFT: u16 = 4; +pub const CLDCTRL7_SIDE_PEAK_TH_MASK: u16 = 0xF; +pub const CLDCTRL7_SIDE_PEAK_TH_SHIFT: u16 = 0; +pub const CLDCTRL7_DEF: u16 = 0x6BF6; + +pub const MIIEXT_AZCTRL: u16 = 0x8008; +pub const AZCTRL_SHORT_TH_MASK: u16 = 0xFF; +pub const AZCTRL_SHORT_TH_SHIFT: u16 = 8; +pub const AZCTRL_LONG_TH_MASK: u16 = 0xFF; +pub const AZCTRL_LONG_TH_SHIFT: u16 = 0; +pub const AZCTRL_DEF: u16 = 0x1629; + +pub const MIIEXT_AZCTRL2: u16 = 0x8009; +pub const AZCTRL2_WAKETRNING_MASK: u16 = 0xFF; +pub const AZCTRL2_WAKETRNING_SHIFT: u16 = 8; +pub const AZCTRL2_QUIET_TIMER_MASK: u16 = 0x3; +pub const AZCTRL2_QUIET_TIMER_SHIFT: u16 = 6; +pub const AZCTRL2_PHAS_JMP2: u16 = 0x0010; +pub const AZCTRL2_CLKTRCV_125MD16: u16 = 0x0008; +pub const AZCTRL2_GATE1000_EN: u16 = 0x0004; +pub const AZCTRL2_AVRG_FREQ: u16 = 0x0002; +pub const AZCTRL2_PHAS_JMP4: u16 = 0x0001; +pub const AZCTRL2_DEF: u16 = 0x32C0; + +pub const MIIEXT_AZCTRL6: u16 = 0x800D; + +pub const MIIEXT_VDRVBIAS: u16 = 0x8062; +pub const VDRVBIAS_SEL_MASK: u16 = 0x3; +pub const VDRVBIAS_SEL_SHIFT: u16 = 0; +pub const VDRVBIAS_DEF: u16 = 0x3; + +/********* dev 7 **********/ +pub const MIIEXT_ANEG: u8 = 7; + +pub const MIIEXT_LOCAL_EEEADV: u16 = 0x3C; +pub const LOCAL_EEEADV_1000BT: u16 = 0x0004; +pub const LOCAL_EEEADV_100BT: u16 = 0x0002; + +pub const MIIEXT_REMOTE_EEEADV: u16 = 0x3D; +pub const REMOTE_EEEADV_1000BT: u16 = 0x0004; +pub const REMOTE_EEEADV_100BT: u16 = 0x0002; + +pub const MIIEXT_EEE_ANEG: u16 = 0x8000; +pub const EEE_ANEG_1000M: u16 = 0x0004; +pub const EEE_ANEG_100M: u16 = 0x0002; + +pub const MIIEXT_AFE: u16 = 0x801A; +pub const AFE_10BT_100M_TH: u16 = 0x0040; + +pub const MIIEXT_S3DIG10: u16 = 0x8023; +/* bit0:: u16 = 1:bypass: u16 = 10BT rx fifo,: u16 = 0:riginal: u16 = 10BT rx */ +pub const MIIEXT_S3DIG10_SL: u16 = 0x0001; +pub const MIIEXT_S3DIG10_DEF: u16 = 0; + +pub const MIIEXT_NLP34: u16 = 0x8025; +/* for: u16 = 160m */ +pub const MIIEXT_NLP34_DEF: u16 = 0x1010; + +pub const MIIEXT_NLP56: u16 = 0x8026; +/* for: u16 = 160m */ +pub const MIIEXT_NLP56_DEF: u16 = 0x1010; + +pub const MIIEXT_NLP78: u16 = 0x8027; +/* for: u16 = 160m */ +pub const MIIEXT_NLP78_160M_DEF: u16 = 0x8D05; +pub const MIIEXT_NLP78_120M_DEF : u16 = 0x8A05; diff --git a/alxd/src/main.rs b/alxd/src/main.rs new file mode 100644 index 0000000000..8fdca2719c --- /dev/null +++ b/alxd/src/main.rs @@ -0,0 +1,138 @@ +#![allow(unused_parens)] +#![feature(asm)] +#![feature(concat_idents)] + +extern crate event; +extern crate netutils; +extern crate syscall; + +use std::cell::RefCell; +use std::env; +use std::fs::File; +use std::io::{Read, Write, Result}; +use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::sync::Arc; + +use event::EventQueue; +use syscall::{Packet, SchemeMut, MAP_WRITE}; +use syscall::error::EWOULDBLOCK; + +pub mod device; + +fn main() { + let mut args = env::args().skip(1); + + let mut name = args.next().expect("alxd: no name provided"); + name.push_str("_alx"); + + let bar_str = args.next().expect("alxd: no address provided"); + let bar = usize::from_str_radix(&bar_str, 16).expect("alxd: failed to parse address"); + + let irq_str = args.next().expect("alxd: no irq provided"); + let irq = irq_str.parse::().expect("alxd: failed to parse irq"); + + print!("{}", format!(" + ALX {} on: {:X}, IRQ: {}\n", name, bar, irq)); + + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 + { + let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("alxd: failed to create network scheme"); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + + let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("alxd: failed to map address") }; + { + let device = Arc::new(RefCell::new(unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") })); + + let mut event_queue = EventQueue::::new().expect("alxd: failed to create event queue"); + + let todo = Arc::new(RefCell::new(Vec::::new())); + + let device_irq = device.clone(); + let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + let mut irq_file = File::open(format!("irq:{}", irq)).expect("alxd: failed to open IRQ file"); + event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + if unsafe { device_irq.borrow_mut().intr_legacy() } { + irq_file.write(&mut irq)?; + + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + device_irq.borrow_mut().handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; + } else { + socket_irq.borrow_mut().write(&mut todo[i])?; + todo.remove(i); + } + } + + let next_read = device_irq.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + } + Ok(None) + }).expect("alxd: failed to catch events on IRQ file"); + + let socket_packet = socket.clone(); + event_queue.add(socket_fd, move |_count: usize| -> Result> { + loop { + let mut packet = Packet::default(); + if socket_packet.borrow_mut().read(&mut packet)? == 0 { + break; + } + + let a = packet.a; + device.borrow_mut().handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket_packet.borrow_mut().write(&mut packet)?; + } + } + + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + + Ok(None) + }).expect("alxd: failed to catch events on IRQ file"); + + for event_count in event_queue.trigger_all(0).expect("alxd: failed to trigger events") { + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ, + d: event_count + }).expect("alxd: failed to write event"); + } + + loop { + let event_count = event_queue.run().expect("alxd: failed to handle events"); + + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ, + d: event_count + }).expect("alxd: failed to write event"); + } + } + unsafe { let _ = syscall::physunmap(address); } + } +} diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 0ef7c58666..469dec7d0e 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -108,10 +108,11 @@ fn main() { } if let Some(ref args) = driver.command { - // Enable bus mastering + // Enable bus mastering, memory space, and I/O space unsafe { let cmd = pci.read(bus.num, dev.num, func.num, 0x04); - pci.write(bus.num, dev.num, func.num, 0x04, cmd | 4); + println!("PCI CMD: {:>02X}", cmd); + pci.write(bus.num, dev.num, func.num, 0x04, cmd | 7); } let mut args = args.iter(); From 4d04f50b2a62f331009fa2a0ab43a34a923c6f64 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 26 Mar 2017 15:32:28 -0600 Subject: [PATCH 0138/1301] Handle input event from ransid --- vesad/src/screen/text.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index ee9ee53026..ffdc53094c 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -182,12 +182,16 @@ impl Screen for TextScreen { { let display = &mut self.display; let changed = &mut self.changed; + let input = &mut self.input; self.console.write(buf, |event| { match event { ransid::Event::Char { x, y, c, color, bold, .. } => { display.char(x * 8, y * 16, c, color.data, bold, false); changed.insert(y); }, + ransid::Event::Input { data } => { + input.extend(data); + }, ransid::Event::Rect { x, y, w, h, color } => { display.rect(x * 8, y * 16, w * 8, h * 16, color.data); for y2 in y..y + h { From 7957308f01a6c08440b81f27bdbdf51d515ea31a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 26 Mar 2017 21:20:09 -0600 Subject: [PATCH 0139/1301] Catch screenbuffer event --- vesad/src/screen/text.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index ffdc53094c..7436be5cbb 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -198,6 +198,7 @@ impl Screen for TextScreen { changed.insert(y2); } }, + ransid::Event::ScreenBuffer { .. } => (), ransid::Event::Scroll { rows, color } => { display.scroll(rows * 16, color.data); for y in 0..display.height/16 { From e712a352303dd55fbbb1d4795bf25c68e91ed639 Mon Sep 17 00:00:00 2001 From: Paul Davey Date: Tue, 11 Apr 2017 01:10:47 +1200 Subject: [PATCH 0140/1301] xhci: fix port detection. Ports are now correctly represented as 4 consecutive u32 registers. Port state now reads all 4 bits of the state value. --- xhcid/src/xhci.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/xhcid/src/xhci.rs b/xhcid/src/xhci.rs index afd78e5eaf..63b7b2d9ba 100644 --- a/xhcid/src/xhci.rs +++ b/xhcid/src/xhci.rs @@ -72,15 +72,21 @@ bitflags! { } } -pub struct XhciPort(Mmio); +#[repr(packed)] +pub struct XhciPort { + portsc : Mmio, + portpmsc : Mmio, + portli : Mmio, + porthlpmc : Mmio, +} impl XhciPort { fn read(&self) -> u32 { - self.0.read() + self.portsc.read() } fn state(&self) -> u32 { - (self.read() & (0b111 << 5)) >> 5 + (self.read() & (0b1111 << 5)) >> 5 } fn speed(&self) -> u32 { From 1e7013915b589531aec378df4cd51d615d8abb46 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 15 Apr 2017 09:57:37 -0600 Subject: [PATCH 0141/1301] Add path implementation for e1000d and ahcid --- ahcid/src/scheme.rs | 11 +++++++++++ e1000d/src/device.rs | 10 ++++++++++ 2 files changed, 21 insertions(+) diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 52df564f0a..f36ad7bb02 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -98,6 +98,17 @@ impl Scheme for DiskScheme { } } + fn fpath(&self, _id: usize, buf: &mut [u8]) -> Result { + //TODO: Get path + let mut i = 0; + let scheme_path = b"disk:"; + while i < buf.len() && i < scheme_path.len() { + buf[i] = scheme_path[i]; + i += 1; + } + Ok(i) + } + fn read(&self, id: usize, buf: &mut [u8]) -> Result { let mut handles = self.handles.lock(); match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index bfa6d51408..280c2d3197 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -194,6 +194,16 @@ impl Scheme for Intel8254x { Ok(0) } + fn fpath(&self, _id: usize, buf: &mut [u8]) -> Result { + let mut i = 0; + let scheme_path = b"network:"; + while i < buf.len() && i < scheme_path.len() { + buf[i] = scheme_path[i]; + i += 1; + } + Ok(i) + } + fn fsync(&self, _id: usize) -> Result { Ok(0) } From b3849ddf364c21fa2689a68b337bd61c099bc5f6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 18 Apr 2017 21:02:30 -0600 Subject: [PATCH 0142/1301] Convert vesad to be handle based, allow O_NONBLOCK --- vesad/src/main.rs | 10 +- vesad/src/scheme.rs | 182 ++++++++++++++++++++++++++---------- vesad/src/screen/graphic.rs | 8 +- vesad/src/screen/mod.rs | 2 +- vesad/src/screen/text.rs | 10 +- 5 files changed, 151 insertions(+), 61 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 211058cea5..5f072078cb 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -7,7 +7,7 @@ extern crate alloc; extern crate orbclient; extern crate syscall; -use std::{env, mem}; +use std::env; use std::fs::File; use std::io::{Read, Write}; use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE}; @@ -68,7 +68,7 @@ fn main() { socket.read(&mut packet).expect("vesad: failed to read display scheme"); // If it is a read packet, and there is no data, block it. Otherwise, handle packet - if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.will_block(packet.b) { + if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.can_read(packet.b).is_none() { blocked.push(packet); } else { scheme.handle(&mut packet); @@ -79,7 +79,7 @@ fn main() { { let mut i = 0; while i < blocked.len() { - if ! scheme.will_block(blocked[i].b) { + if scheme.can_read(blocked[i].b).is_some() { let mut packet = blocked.remove(i); scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); @@ -90,7 +90,7 @@ fn main() { } for (screen_id, screen) in scheme.screens.iter() { - if ! screen.will_block() { + if let Some(count) = screen.can_read() { let event_packet = Packet { id: 0, pid: 0, @@ -99,7 +99,7 @@ fn main() { a: syscall::number::SYS_FEVENT, b: *screen_id, c: EVENT_READ, - d: mem::size_of::() + d: count }; socket.write(&event_packet).expect("vesad: failed to write display event"); diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index d34f74b67f..bc933d7255 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -2,16 +2,30 @@ use std::collections::BTreeMap; use std::{mem, slice, str}; use orbclient::{Event, EventOption}; -use syscall::{Result, Error, EACCES, EBADF, ENOENT, SchemeMut}; +use syscall::{Result, Error, EACCES, EBADF, ENOENT, O_NONBLOCK, SchemeMut}; use display::Display; use screen::{Screen, GraphicScreen, TextScreen}; +#[derive(Clone)] +enum HandleKind { + Input, + Screen(usize), +} + +#[derive(Clone)] +struct Handle { + kind: HandleKind, + flags: usize, +} + pub struct DisplayScheme { width: usize, height: usize, active: usize, - pub screens: BTreeMap> + pub screens: BTreeMap>, + next_id: usize, + handles: BTreeMap, } impl DisplayScheme { @@ -32,37 +46,67 @@ impl DisplayScheme { width: width, height: height, active: 1, - screens: screens + screens: screens, + next_id: 0, + handles: BTreeMap::new(), } } - pub fn will_block(&self, id: usize) -> bool { - if let Some(screen) = self.screens.get(&id) { - screen.will_block() - } else { - false + pub fn can_read(&self, id: usize) -> Option { + if let Some(handle) = self.handles.get(&id) { + if let HandleKind::Screen(screen_i) = handle.kind { + if let Some(screen) = self.screens.get(&screen_i) { + match screen.can_read() { + Some(count) => return Some(count), + None => if handle.flags & O_NONBLOCK == O_NONBLOCK { + return Some(0); + } else { + return None; + } + } + } + } } + + Some(0) } } impl SchemeMut for DisplayScheme { - fn open(&mut self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { + fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if path == b"input" { if uid == 0 { - Ok(0) + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, Handle { + kind: HandleKind::Input, + flags: flags + }); + + Ok(id) } else { Err(Error::new(EACCES)) } } else { let path_str = str::from_utf8(path).unwrap_or("").trim_matches('/'); let mut parts = path_str.split('/'); - let id = parts.next().unwrap_or("").parse::().unwrap_or(0); - if self.screens.contains_key(&id) { + let screen_i = parts.next().unwrap_or("").parse::().unwrap_or(0); + if self.screens.contains_key(&screen_i) { for cmd in parts { if cmd == "activate" { - self.active = id; + self.active = screen_i; } } + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, Handle { + kind: HandleKind::Screen(screen_i), + flags: flags + }); + Ok(id) } else { Err(Error::new(ENOENT)) @@ -71,32 +115,52 @@ impl SchemeMut for DisplayScheme { } fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { - Ok(id) + let handle = self.handles.get(&id).map(|handle| handle.clone()).ok_or(Error::new(EBADF))?; + + let new_id = self.next_id; + self.next_id += 1; + + self.handles.insert(new_id, handle.clone()); + + Ok(new_id) } fn fevent(&mut self, id: usize, flags: usize) -> Result { - if let Some(mut screen) = self.screens.get_mut(&id) { - screen.event(flags).and(Ok(id)) - } else { - Err(Error::new(EBADF)) + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + if let HandleKind::Screen(screen_i) = handle.kind { + if let Some(mut screen) = self.screens.get_mut(&screen_i) { + return screen.event(flags).and(Ok(screen_i)); + } } + + Err(Error::new(EBADF)) } fn fmap(&mut self, id: usize, offset: usize, size: usize) -> Result { - if let Some(screen) = self.screens.get(&id) { - screen.map(offset, size) - } else { - Err(Error::new(EBADF)) + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + if let HandleKind::Screen(screen_i) = handle.kind { + if let Some(screen) = self.screens.get(&screen_i) { + return screen.map(offset, size); + } } + + Err(Error::new(EBADF)) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let path_str = if id == 0 { - format!("display:input/{}/{}", self.width, self.height) - } else if let Some(screen) = self.screens.get(&id) { - format!("display:{}/{}/{}", id, screen.width(), screen.height()) - } else { - return Err(Error::new(EBADF)); + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let path_str = match handle.kind { + HandleKind::Input => { + format!("display:input/{}/{}", self.width, self.height) + }, + HandleKind::Screen(screen_i) => if let Some(screen) = self.screens.get(&screen_i) { + format!("display:{}/{}/{}", screen_i, screen.width(), screen.height()) + } else { + return Err(Error::new(EBADF)); + } }; let path = path_str.as_bytes(); @@ -111,27 +175,37 @@ impl SchemeMut for DisplayScheme { } fn fsync(&mut self, id: usize) -> Result { - if let Some(mut screen) = self.screens.get_mut(&id) { - if id == self.active { - screen.sync(); + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + if let HandleKind::Screen(screen_i) = handle.kind { + if let Some(mut screen) = self.screens.get_mut(&screen_i) { + if screen_i == self.active { + screen.sync(); + } + return Ok(0); } - Ok(0) - } else { - Err(Error::new(EBADF)) } + + Err(Error::new(EBADF)) } fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { - if let Some(mut screen) = self.screens.get_mut(&id) { - screen.read(buf) - } else { - Err(Error::new(EBADF)) + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + if let HandleKind::Screen(screen_i) = handle.kind { + if let Some(mut screen) = self.screens.get_mut(&screen_i) { + return screen.read(buf); + } } + + Err(Error::new(EBADF)) } fn write(&mut self, id: usize, buf: &[u8]) -> Result { - if id == 0 { - if buf.len() == 1 && buf[0] >= 0xF4 { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + match handle.kind { + HandleKind::Input => if buf.len() == 1 && buf[0] >= 0xF4 { let new_active = (buf[0] - 0xF4) as usize + 1; if let Some(mut screen) = self.screens.get_mut(&new_active) { self.active = new_active; @@ -158,9 +232,9 @@ impl SchemeMut for DisplayScheme { }, EventOption::Resize(resize_event) => { println!("Resizing to {}, {}", resize_event.width, resize_event.height); - for (screen_id, screen) in self.screens.iter_mut() { + for (screen_i, screen) in self.screens.iter_mut() { screen.resize(resize_event.width as usize, resize_event.height as usize); - if *screen_id == self.active { + if *screen_i == self.active { screen.redraw(); } } @@ -181,23 +255,29 @@ impl SchemeMut for DisplayScheme { } Ok(events.len() * mem::size_of::()) + }, + HandleKind::Screen(screen_i) => if let Some(mut screen) = self.screens.get_mut(&screen_i) { + screen.write(buf, screen_i == self.active) + } else { + Err(Error::new(EBADF)) } - } else if let Some(mut screen) = self.screens.get_mut(&id) { - screen.write(buf, id == self.active) - } else { - Err(Error::new(EBADF)) } } fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result { - if let Some(mut screen) = self.screens.get_mut(&id) { - screen.seek(pos, whence) - } else { - Err(Error::new(EBADF)) + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + if let HandleKind::Screen(screen_i) = handle.kind { + if let Some(mut screen) = self.screens.get_mut(&screen_i) { + return screen.seek(pos, whence); + } } + + Err(Error::new(EBADF)) } - fn close(&mut self, _id: usize) -> Result { + fn close(&mut self, id: usize) -> Result { + self.handles.remove(&id).ok_or(Error::new(EBADF))?; Ok(0) } } diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 089787a81a..45d4f9fcd2 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -75,8 +75,12 @@ impl Screen for GraphicScreen { Ok(i * mem::size_of::()) } - fn will_block(&self) -> bool { - self.input.is_empty() + fn can_read(&self) -> Option { + if self.input.is_empty() { + None + } else { + Some(self.input.len() * mem::size_of::()) + } } fn write(&mut self, buf: &[u8], sync: bool) -> Result { diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs index 4558546412..5927cf4f50 100644 --- a/vesad/src/screen/mod.rs +++ b/vesad/src/screen/mod.rs @@ -22,7 +22,7 @@ pub trait Screen { fn read(&mut self, buf: &mut [u8]) -> Result; - fn will_block(&self) -> bool; + fn can_read(&self) -> Option; fn write(&mut self, buf: &[u8], sync: bool) -> Result; diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 7436be5cbb..49ba28e9c4 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -167,8 +167,14 @@ impl Screen for TextScreen { Ok(i) } - fn will_block(&self) -> bool { - self.input.is_empty() && ! self.end_of_input + fn can_read(&self) -> Option { + if self.end_of_input { + Some(0) + } else if self.input.is_empty() { + None + } else { + Some(self.input.len()) + } } fn write(&mut self, buf: &[u8], sync: bool) -> Result { From 520c140da848a6171950b1919ad40edec6c1d315 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Sun, 23 Apr 2017 15:29:48 +0100 Subject: [PATCH 0143/1301] Migrate to serde. Fixes #9 --- pcid/Cargo.toml | 5 +++-- pcid/src/config.rs | 4 ++-- pcid/src/main.rs | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 9c0cf530c2..bc28166532 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" [dependencies] redox_syscall = "0.1" -rustc-serialize = "0.3" -toml = "0.2" +serde = "1.0" +serde_derive = "1.0" +toml = "0.4" diff --git a/pcid/src/config.rs b/pcid/src/config.rs index 3bc4dba8df..efe88944a5 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -1,9 +1,9 @@ -#[derive(Debug, Default, RustcDecodable)] +#[derive(Debug, Default, Deserialize)] pub struct Config { pub drivers: Vec } -#[derive(Debug, Default, RustcDecodable)] +#[derive(Debug, Default, Deserialize)] pub struct DriverConfig { pub name: Option, pub class: Option, diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 469dec7d0e..cee6b15b3d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,7 +1,8 @@ #![deny(warnings)] #![feature(asm)] -extern crate rustc_serialize; +extern crate serde; +#[macro_use] extern crate serde_derive; extern crate syscall; extern crate toml; @@ -25,7 +26,7 @@ fn main() { if let Ok(mut config_file) = File::open(&config_path) { let mut config_data = String::new(); if let Ok(_) = config_file.read_to_string(&mut config_data) { - config = toml::decode_str(&config_data).unwrap_or(Config::default()); + config = toml::from_str(&config_data).unwrap_or(Config::default()); } } } From 77827f57b76fdf5d5cc7b3e0b05f2fb51a11fc01 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Sun, 23 Apr 2017 15:48:51 +0100 Subject: [PATCH 0144/1301] Rename 'english' keymap to 'us' This keyboard layout is only used in the United States, other english-speaking countries may have their own standard keyboard layouts. This commit changes the name of the 'english' layout to 'us' to match X11. --- ps2d/src/keymap.rs | 6 +++--- ps2d/src/main.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ps2d/src/keymap.rs b/ps2d/src/keymap.rs index 24c3ecda17..2d514156c9 100644 --- a/ps2d/src/keymap.rs +++ b/ps2d/src/keymap.rs @@ -1,5 +1,5 @@ -pub mod english { - static ENGLISH: [[char; 2]; 58] = [ +pub mod us { + static US: [[char; 2]; 58] = [ ['\0', '\0'], ['\x1B', '\x1B'], ['1', '!'], @@ -61,7 +61,7 @@ pub mod english { ]; pub fn get_char(scancode: u8, shift: bool) -> char { - if let Some(c) = ENGLISH.get(scancode as usize) { + if let Some(c) = US.get(scancode as usize) { if shift { c[1] } else { diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index a63405659b..fce59bb645 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -197,12 +197,12 @@ fn daemon(input: File) { let keymap = match env::args().skip(1).next() { Some(k) => match k.to_lowercase().as_ref() { "dvorak" => (keymap::dvorak::get_char), - "english" => (keymap::english::get_char), + "us" => (keymap::us::get_char), "azerty" => (keymap::azerty::get_char), "bepo" => (keymap::bepo::get_char), - &_ => (keymap::english::get_char) + &_ => (keymap::us::get_char) }, - None => (keymap::english::get_char) + None => (keymap::us::get_char) }; let ps2d = Arc::new(RefCell::new(Ps2d::new(input, keymap))); From bc1efaebf34a0967a995aace94d9b1e4debcef79 Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Sun, 23 Apr 2017 16:16:43 +0100 Subject: [PATCH 0145/1301] Added gb keymap --- ps2d/src/keymap.rs | 106 ++++++++++++++++++++++++++++++++++++++++++++- ps2d/src/main.rs | 1 + 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/ps2d/src/keymap.rs b/ps2d/src/keymap.rs index 2d514156c9..41ea1d2c74 100644 --- a/ps2d/src/keymap.rs +++ b/ps2d/src/keymap.rs @@ -72,6 +72,111 @@ pub mod us { } } } + +pub mod gb { + static GB: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['1', '!'], + ['2', '"'], + ['3', '£'], + ['4', '$'], + ['5', '%'], + ['6', '^'], + ['7', '&'], + ['8', '*'], + ['9', '('], + ['0', ')'], + ['-', '_'], + ['=', '+'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['q', 'Q'], + ['w', 'W'], + ['e', 'E'], + ['r', 'R'], + ['t', 'T'], + ['y', 'Y'], + ['u', 'U'], + ['i', 'I'], + ['o', 'O'], + ['p', 'P'], + ['[', '{'], + [']', '}'], + ['\n', '\n'], + ['\0', '\0'], + ['a', 'A'], + ['s', 'S'], + ['d', 'D'], + ['f', 'F'], + ['g', 'G'], + ['h', 'H'], + ['j', 'J'], + ['k', 'K'], + ['l', 'L'], + [';', ':'], + ['\'', '@'], + ['`', '¬'], + ['\0', '\0'], + ['#', '~'], + ['z', 'Z'], + ['x', 'X'], + ['c', 'C'], + ['v', 'V'], + ['b', 'B'], + ['n', 'N'], + ['m', 'M'], + [',', '<'], + ['.', '>'], + ['/', '?'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\\', '|'], + ]; + + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = GB.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } + } else { + '\0' + } + } +} + pub mod dvorak { static DVORAK: [[char; 2]; 58] = [ ['\0', '\0'], @@ -296,4 +401,3 @@ pub mod bepo { } } } - diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index fce59bb645..76ad116f95 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -198,6 +198,7 @@ fn daemon(input: File) { Some(k) => match k.to_lowercase().as_ref() { "dvorak" => (keymap::dvorak::get_char), "us" => (keymap::us::get_char), + "gb" => (keymap::gb::get_char), "azerty" => (keymap::azerty::get_char), "bepo" => (keymap::bepo::get_char), &_ => (keymap::us::get_char) From 60c3ed19c8827e72862ec081415fc5a32a15140e Mon Sep 17 00:00:00 2001 From: Karl Hobley Date: Sun, 23 Apr 2017 17:54:14 +0100 Subject: [PATCH 0146/1301] Fix a couple of syntax errors in keymap.rs My previous pull request that added a GB keyboard layout also added a couple of syntax errors. This PR fixes them. Apologies for that. --- ps2d/src/keymap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ps2d/src/keymap.rs b/ps2d/src/keymap.rs index 41ea1d2c74..34860c5d58 100644 --- a/ps2d/src/keymap.rs +++ b/ps2d/src/keymap.rs @@ -74,7 +74,7 @@ pub mod us { } pub mod gb { - static GB: [[char; 2]; 58] = [ + static GB: [[char; 2]; 87] = [ ['\0', '\0'], ['\x1B', '\x1B'], ['1', '!'], @@ -132,7 +132,7 @@ pub mod gb { ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], - [' ', ' '] + [' ', ' '], ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], From 15675ea9c3de8b552743f83ec2f9a7bbba538c15 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 26 Apr 2017 21:28:45 -0600 Subject: [PATCH 0147/1301] Allow retry of commands, allow failure of commands --- pcid/src/pci/mod.rs | 2 +- ps2d/src/controller.rs | 146 ++++++++++++++++++++++++++++++----------- 2 files changed, 109 insertions(+), 39 deletions(-) diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index d2a8e8906a..ef83986e60 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -64,7 +64,7 @@ impl<'pci> PciIter<'pci> { impl<'pci> Iterator for PciIter<'pci> { type Item = PciBus<'pci>; fn next(&mut self) -> Option { - if self.num < 256 { + if self.num < 255 { /* TODO: Do not ignore 0xFF bus */ let bus = PciBus { pci: self.pci, num: self.num as u8 diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 3dd159340f..1d758446be 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -50,6 +50,7 @@ enum Command { #[allow(dead_code)] enum KeyboardCommand { EnableReporting = 0xF4, + SetDefaultsDisable = 0xF5, SetDefaults = 0xF6, Reset = 0xFF } @@ -64,6 +65,7 @@ enum KeyboardCommandData { enum MouseCommand { GetDeviceId = 0xF2, EnableReporting = 0xF4, + SetDefaultsDisable = 0xF5, SetDefaults = 0xF6, Reset = 0xFF } @@ -100,9 +102,9 @@ impl Ps2 { while ! self.status().contains(OUTPUT_FULL) {} } - fn flush_read(&mut self) { + fn flush_read(&mut self, message: &str) { while self.status().contains(OUTPUT_FULL) { - print!("FLUSH: {:X}\n", self.data.read()); + print!("ps2d: flush {}: {:X}\n", message, self.data.read()); } } @@ -131,28 +133,57 @@ impl Ps2 { self.write(config.bits()); } + fn keyboard_command_inner(&mut self, command: u8) -> u8 { + let mut ret = 0xFE; + for i in 0..4 { + self.write(command as u8); + ret = self.read(); + if ret == 0xFE { + println!("ps2d: retry keyboard command {:X}: {}", command, i); + } else { + break; + } + } + ret + } + fn keyboard_command(&mut self, command: KeyboardCommand) -> u8 { - self.write(command as u8); - self.read() + self.keyboard_command_inner(command as u8) } fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> u8 { - self.write(command as u8); - assert_eq!(self.read(), 0xFA); + let res = self.keyboard_command_inner(command as u8); + if res != 0xFA { + return res; + } self.write(data as u8); self.read() } + fn mouse_command_inner(&mut self, command: u8) -> u8 { + let mut ret = 0xFE; + for i in 0..4 { + self.command(Command::WriteSecond); + self.write(command as u8); + ret = self.read(); + if ret == 0xFE { + println!("ps2d: retry mouse command {:X}: {}", command, i); + } else { + break; + } + } + ret + } + fn mouse_command(&mut self, command: MouseCommand) -> u8 { - self.command(Command::WriteSecond); - self.write(command as u8); - self.read() + self.mouse_command_inner(command as u8) } fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> u8 { - self.command(Command::WriteSecond); - self.write(command as u8); - assert_eq!(self.read(), 0xFA); + let res = self.mouse_command_inner(command as u8); + if res != 0xFA { + return res; + } self.command(Command::WriteSecond); self.write(data as u8); self.read() @@ -169,12 +200,15 @@ impl Ps2 { } pub fn init(&mut self) -> bool { + // Clear remaining data + self.flush_read("init start"); + // Disable devices self.command(Command::DisableFirst); self.command(Command::DisableSecond); // Clear remaining data - self.flush_read(); + self.flush_read("disable"); // Disable clocks, disable interrupts, and disable translate { @@ -195,35 +229,70 @@ impl Ps2 { self.command(Command::EnableFirst); self.command(Command::EnableSecond); + // Clear remaining data + self.flush_read("enable"); + // Reset keyboard - assert_eq!(self.keyboard_command(KeyboardCommand::Reset), 0xFA); - assert_eq!(self.read(), 0xAA); - self.flush_read(); + if self.keyboard_command(KeyboardCommand::Reset) == 0xFA { + if self.read() != 0xAA { + println!("ps2d: keyboard failed self test"); + } + } else { + println!("ps2d: keyboard failed to reset"); + } + + // Clear remaining data + self.flush_read("keyboard defaults"); // Set scancode set to 2 - assert_eq!(self.keyboard_command_data(KeyboardCommandData::ScancodeSet, 2), 0xFA); - - // Reset mouse and set up scroll - // TODO: Check for ack - assert_eq!(self.mouse_command(MouseCommand::Reset), 0xFA); - assert_eq!(self.read(), 0xAA); - assert_eq!(self.read(), 0x00); - self.flush_read(); - - // Enable extra packet on mouse - assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA); - assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 100), 0xFA); - assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 80), 0xFA); - assert_eq!(self.mouse_command(MouseCommand::GetDeviceId), 0xFA); - let mouse_id = self.read(); - let mouse_extra = mouse_id == 3; - - // Set sample rate to maximum - assert_eq!(self.mouse_command_data(MouseCommandData::SetSampleRate, 200), 0xFA); + let scancode_set = 2; + if self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set) != 0xFA { + println!("ps2d: keyboard failed to set scancode set {}", scancode_set); + } // Enable data reporting - assert_eq!(self.keyboard_command(KeyboardCommand::EnableReporting), 0xFA); - assert_eq!(self.mouse_command(MouseCommand::EnableReporting), 0xFA); + if self.keyboard_command(KeyboardCommand::EnableReporting) != 0xFA { + println!("ps2d: keyboard failed to enable reporting"); + } + + // Reset mouse and set up scroll + if self.mouse_command(MouseCommand::Reset) == 0xFA { + let a = self.read(); + let b = self.read(); + if a != 0xAA || b != 0x00 { + println!("ps2d: mouse failed self test"); + } + } else { + println!("ps2d: mouse failed to reset"); + } + + // Clear remaining data + self.flush_read("mouse defaults"); + + // Enable extra packet on mouse + if self.mouse_command_data(MouseCommandData::SetSampleRate, 200) != 0xFA + || self.mouse_command_data(MouseCommandData::SetSampleRate, 100) != 0xFA + || self.mouse_command_data(MouseCommandData::SetSampleRate, 80) != 0xFA { + println!("ps2d: mouse failed to enable extra packet"); + } + + let mouse_extra = if self.mouse_command(MouseCommand::GetDeviceId) == 0xFA { + self.read() == 3 + } else { + println!("ps2d: mouse failed to get device id"); + false + }; + + // Set sample rate to maximum + let sample_rate = 200; + if self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate) != 0xFA { + println!("ps2d: mouse failed to set sample rate to {}", sample_rate); + } + + // Enable data reporting + if self.mouse_command(MouseCommand::EnableReporting) != 0xFA { + println!("ps2d: mouse failed to enable reporting"); + } // Enable clocks and interrupts { @@ -236,7 +305,8 @@ impl Ps2 { self.set_config(config); } - self.flush_read(); + // Clear remaining data + self.flush_read("init finish"); mouse_extra } From 24f9dbccb089e362cdb93766883f8effa8aa2071 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 10 May 2017 21:46:59 -0600 Subject: [PATCH 0148/1301] Add pcid.toml, cargo workspace --- Cargo.toml | 14 +++++++++++ pcid.toml | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 Cargo.toml create mode 100644 pcid.toml diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000000..4b13eaf786 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[workspace] +members = [ + "ahcid", + "alxd", + "bgad", + "e1000d", + "nvmed", + "pcid", + "ps2d", + "rtl8168d", + "vboxd", + "vesad", + "xhcid" +] diff --git a/pcid.toml b/pcid.toml new file mode 100644 index 0000000000..7ba3e2e5ae --- /dev/null +++ b/pcid.toml @@ -0,0 +1,74 @@ +[[drivers]] +name = "AHCI storage" +class = 1 +subclass = 6 +command = ["ahcid", "$NAME", "$BAR5", "$IRQ"] + +[[drivers]] +name = "NVME storage" +class = 1 +subclass = 8 +command = ["nvmed", "$NAME", "$BAR0", "$IRQ"] + +[[drivers]] +name = "QEMU Graphics Array" +class = 3 +vendor = 4660 +device = 4369 +command = ["bgad", "$NAME", "$BAR0"] + +[[drivers]] +name = "VirtualBox Graphics Array" +class = 3 +vendor = 33006 +device = 48879 +command = ["bgad", "$NAME", "$BAR0"] + +[[drivers]] +name = "VirtualBox Guest Device" +class = 8 +vendor = 33006 +device = 51966 +command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] + +[[drivers]] +name = "82543GC NIC" +class = 2 +vendor = 32902 +device = 4100 +command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] + +[[drivers]] +name = "82540EM NIC" +class = 2 +vendor = 32902 +device = 4110 +command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] + +[[drivers]] +name = "82545EM NIC" +class = 2 +vendor = 32902 +device = 4111 +command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] + +[[drivers]] +name = "82579V NIC" +class = 2 +vendor = 32902 +device = 5379 +command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] + +[[drivers]] +name = "RTL8168 NIC" +class = 2 +vendor = 4332 +device = 33128 +command = ["rtl8168d", "$NAME", "$BAR2", "$IRQ"] + +[[drivers]] +name = "XHCI" +class = 12 +subclass = 3 +interface = 48 +command = ["xhcid", "$NAME", "$BAR0", "$IRQ"] From bb3073980438cf601f01ac667a121a76313e0760 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 10 May 2017 21:49:16 -0600 Subject: [PATCH 0149/1301] Organize pcid.toml --- pcid.toml | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/pcid.toml b/pcid.toml index 7ba3e2e5ae..aa320b72ca 100644 --- a/pcid.toml +++ b/pcid.toml @@ -1,15 +1,11 @@ +# ahcid [[drivers]] name = "AHCI storage" class = 1 subclass = 6 command = ["ahcid", "$NAME", "$BAR5", "$IRQ"] -[[drivers]] -name = "NVME storage" -class = 1 -subclass = 8 -command = ["nvmed", "$NAME", "$BAR0", "$IRQ"] - +# bgad [[drivers]] name = "QEMU Graphics Array" class = 3 @@ -24,13 +20,7 @@ vendor = 33006 device = 48879 command = ["bgad", "$NAME", "$BAR0"] -[[drivers]] -name = "VirtualBox Guest Device" -class = 8 -vendor = 33006 -device = 51966 -command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] - +# e1000d [[drivers]] name = "82543GC NIC" class = 2 @@ -59,6 +49,14 @@ vendor = 32902 device = 5379 command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] +# nvmed +[[drivers]] +name = "NVME storage" +class = 1 +subclass = 8 +command = ["nvmed", "$NAME", "$BAR0", "$IRQ"] + +# rtl8168d [[drivers]] name = "RTL8168 NIC" class = 2 @@ -66,6 +64,15 @@ vendor = 4332 device = 33128 command = ["rtl8168d", "$NAME", "$BAR2", "$IRQ"] +# vboxd +[[drivers]] +name = "VirtualBox Guest Device" +class = 8 +vendor = 33006 +device = 51966 +command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] + +# xhcid [[drivers]] name = "XHCI" class = 12 From e1f24810ba548c8710bcac978f6caae8b592a523 Mon Sep 17 00:00:00 2001 From: TheSchemm Date: Sat, 3 Jun 2017 13:45:52 -0500 Subject: [PATCH 0150/1301] Early Beta of the Intel HD Audio Driver --- ihdad/Cargo.toml | 10 + ihdad/src/HDA/CommandBuffer.rs | 146 ++++ ihdad/src/HDA/common.rs | 51 ++ ihdad/src/HDA/device.rs | 1248 ++++++++++++++++++++++++++++++++ ihdad/src/HDA/mod.rs | 19 + ihdad/src/HDA/node.rs | 112 +++ ihdad/src/HDA/stream.rs | 308 ++++++++ ihdad/src/main.rs | 164 +++++ pcid.toml | 8 + 9 files changed, 2066 insertions(+) create mode 100755 ihdad/Cargo.toml create mode 100644 ihdad/src/HDA/CommandBuffer.rs create mode 100644 ihdad/src/HDA/common.rs create mode 100755 ihdad/src/HDA/device.rs create mode 100644 ihdad/src/HDA/mod.rs create mode 100644 ihdad/src/HDA/node.rs create mode 100644 ihdad/src/HDA/stream.rs create mode 100755 ihdad/src/main.rs diff --git a/ihdad/Cargo.toml b/ihdad/Cargo.toml new file mode 100755 index 0000000000..e0e18f8906 --- /dev/null +++ b/ihdad/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "ihdad" +version = "0.1.0" + +[dependencies] +bitflags = "0.7" +spin = "0.4" +redox_event = { git = "https://github.com/redox-os/event.git" } +redox_syscall = "0.1" + diff --git a/ihdad/src/HDA/CommandBuffer.rs b/ihdad/src/HDA/CommandBuffer.rs new file mode 100644 index 0000000000..7d55f80e34 --- /dev/null +++ b/ihdad/src/HDA/CommandBuffer.rs @@ -0,0 +1,146 @@ +use std::{mem, thread, ptr, fmt}; +use syscall::io::{Dma, Mmio, Io, ReadOnly}; + + +// CORBCTL +const CMEIE: u8 = 1 << 0; // 1 bit +const CORBRUN: u8 = 1 << 1; // 1 bit + +// CORBSIZE +const CORBSZCAP: (u8,u8) = (4, 4); +const CORBSIZE: (u8,u8) = (0, 2); + +// CORBRP +const CORBRPRST: u16 = 1 << 15; + +// RIRBWP +const RIRBWPRST: u16 = 1 << 15; + +// RIRBCTL +const RINTCTL: u8 = 1 << 0; // 1 bit +const RIRBDMAEN: u8 = 1 << 1; // 1 bit + + +const CORB_OFFSET: usize = 0x00; +const RIRB_OFFSET: usize = 0x10; + + +const CORB_BUFF_MAX_SIZE: usize = 1024; + +struct CommandBufferRegs { + corblbase: Mmio, + corbubase: Mmio, + corbwp: Mmio, + corbrp: Mmio, + corbctl: Mmio, + corbsts: Mmio, + corbsize: Mmio, + rsvd5: Mmio, + + rirblbase: Mmio, + rirbubase: Mmio, + rirbwp: Mmio, + rintcnt: Mmio, + rirbctl: Mmio, + rirbsts: Mmio, + rirbsize: Mmio, + rsvd6: Mmio, +} + + +struct CorbRegs { + corblbase: Mmio, + corbubase: Mmio, + corbwp: Mmio, + corbrp: Mmio, + corbctl: Mmio, + corbsts: Mmio, + corbsize: Mmio, + rsvd5: Mmio, +} + +struct Corb { + regs: &'static mut CorbRegs, + corb_base: *mut u32, + corb_base_phys: usize, +} + +impl Corb { + + pub fn new(regs_addr:usize, corb_buff_phys:usize, corb_buff_virt:usize) -> Corb { + + + Corb { + regs: &mut *(regs_addr as *mut CorbRegs); + corb_base: (corb_buff_virt) as *mut u64, + + } + } + +} + +struct RirbRegs { + rirblbase: Mmio, + rirbubase: Mmio, + rirbwp: Mmio, + rintcnt: Mmio, + rirbctl: Mmio, + rirbsts: Mmio, + rirbsize: Mmio, + rsvd6: Mmio, +} + +struct Rirb { + regs: &'static mut RirbRegs, + rirb_base: *mut u64, + rirb_base_phys: usize, + rirb_rp: usize, +} + +impl Rirb { + + pub fn new(regs_addr:usize, rirb_buff_phys:usize, rirb_buff_virt:usize) -> Rirb { + + + Rirb { + regs: &mut *(regs_addr as *mut RirbRegs); + rirb_base: (rirb_buff_virt) as *mut u64, + rirb_rp: 0, + rirb_base_phys: rirb_buff_phys, + } + } + +} + + +struct CommandBuffer { + + // regs: &'static mut CommandBufferRegs, + + corb: Corb, + rirb: Rirb, + + + corb_rirb_base_phys: usize, + + + +} + +impl CommandBuffer { + pub fn new(regs_addr:usize, cmd_buff_frame_phys:usize, cmd_buff_frame:usize ) -> CommandBuffer { + + let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff_frame_phys, cmd_buff_frame); + let rirb = Rirb::new(regs_addr + RIRB_OFFSET, + cmd_buff_frame_phys + CORB_BUFF_MAX_SIZE, + cmd_buff_frame + CORB_BUFF_MAX_SIZE); + + CommandBuffer { + corb: corb, + rirb: rirb, + corb_rirb_base_phys: cmd_buff_frame_phys, + } + } + +} + diff --git a/ihdad/src/HDA/common.rs b/ihdad/src/HDA/common.rs new file mode 100644 index 0000000000..7a28902dfa --- /dev/null +++ b/ihdad/src/HDA/common.rs @@ -0,0 +1,51 @@ + + +use std::{mem, thread, ptr, fmt}; + +pub type HDANodeAddr = u16; +pub type HDACodecAddr = u16; + +#[derive(Debug, PartialEq)] +#[repr(u8)] +pub enum HDAWidgetType{ + AudioOutput = 0x0, + AudioInput = 0x1, + AudioMixer = 0x2, + AudioSelector = 0x3, + PinComplex = 0x4, + Power = 0x5, + VolumeKnob = 0x6, + BeepGenerator = 0x7, + + + VendorDefined = 0xf, +} + +impl fmt::Display for HDAWidgetType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + + +#[derive(Debug)] +#[repr(u8)] +pub enum HDADefaultDevice { + LineOut = 0x0, + Speaker = 0x1, + HPOut = 0x2, + CD = 0x3, + SPDIF = 0x4, + DigitalOtherOut = 0x5, + ModemLineSide = 0x6, + ModemHandsetSide = 0x7, + LineIn = 0x8, + AUX = 0x9, + MicIn = 0xA, + Telephony = 0xB, + SPDIFIn = 0xC, + DigitalOtherIn = 0xD, + Reserved = 0xE, + Other = 0xF, +} + diff --git a/ihdad/src/HDA/device.rs b/ihdad/src/HDA/device.rs new file mode 100755 index 0000000000..f136e91b1e --- /dev/null +++ b/ihdad/src/HDA/device.rs @@ -0,0 +1,1248 @@ +use std::{mem, thread, ptr, fmt}; +use std::cmp::{max, min}; + +use syscall::MAP_WRITE; +use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; +use syscall::flag::O_NONBLOCK; +use syscall::io::{Dma, Mmio, Io, ReadOnly}; +use syscall::scheme::SchemeMut; +use std::sync::Arc; +use std::cell::RefCell; + +extern crate syscall; + +use std::ptr::copy_nonoverlapping; + + +use super::BufferDescriptorListEntry; +use super::common::*; +use super::StreamDescriptorRegs; +use super::StreamBuffer; +use super::BitsPerSample; + +use super::HDANode; + + +// GCTL - Global Control +const CRST: u32 = 1 << 0; // 1 bit +const FNCTRL: u32 = 1 << 1; // 1 bit +const UNSOL: u32 = 1 << 8; // 1 bit + +// CORBCTL +const CMEIE: u8 = 1 << 0; // 1 bit +const CORBRUN: u8 = 1 << 1; // 1 bit + +// CORBSIZE +const CORBSZCAP: (u8,u8) = (4, 4); +const CORBSIZE: (u8,u8) = (0, 2); + +// CORBRP +const CORBRPRST: u16 = 1 << 15; + +// RIRBWP +const RIRBWPRST: u16 = 1 << 15; + +// RIRBCTL +const RINTCTL: u8 = 1 << 0; // 1 bit +const RIRBDMAEN: u8 = 1 << 1; // 1 bit + +// ICS +const ICB: u16 = 1 << 0; +const IRV: u16 = 1 << 1; + + +// CORB and RIRB offset + +const COMMAND_BUFFER_OFFSET: usize = 0x40; + + +const NUM_SUB_BUFFS: usize = 2; +const SUB_BUFF_SIZE: usize = 0x4000; + + + +#[repr(packed)] +struct Regs { + gcap: Mmio, + vmin: Mmio, + vmaj: Mmio, + outpay: Mmio, + inpay: Mmio, + gctl: Mmio, + wakeen: Mmio, + statests: Mmio, + gsts: Mmio, + rsvd0: [Mmio; 6], + outstrmpay: Mmio, + instrmpay: Mmio, + rsvd1: [Mmio; 4], + intctl: Mmio, + intsts: Mmio, + rsvd2: [Mmio; 8], + walclk: Mmio, + rsvd3: Mmio, + ssync: Mmio, + rsvd4: Mmio, + + corblbase: Mmio, + corbubase: Mmio, + corbwp: Mmio, + corbrp: Mmio, + corbctl: Mmio, + corbsts: Mmio, + corbsize: Mmio, + rsvd5: Mmio, + + rirblbase: Mmio, + rirbubase: Mmio, + rirbwp: Mmio, + rintcnt: Mmio, + rirbctl: Mmio, + rirbsts: Mmio, + rirbsize: Mmio, + rsvd6: Mmio, + + icoi: Mmio, + irii: Mmio, + ics: Mmio, + rsvd7: [Mmio; 6], + + dplbase: Mmio, // 0x70 + dpubase: Mmio, // 0x74 + +} + +pub struct IntelHDA { + base: usize, + regs: &'static mut Regs, + + + corb_rirb_base_phys: usize, + + corb_base: *mut u32, + rirb_base: *mut u64, + + corb_count: usize, + rirb_count: usize, + + rirb_rp: u16, + + codecs: Vec, + + nodes: Vec, + + + output_pins: Vec, + + input_pins: Vec, + + beep_addr: HDANodeAddr, + + + buff_desc: &'static mut [BufferDescriptorListEntry; 256], + buff_desc_phys: usize, + + + output_buff: usize, + output_buff_phys: usize, + output_buff_length: usize, + output_buff_wp: usize, + output_current_block: usize, + + buffs: Vec>, + + int_counter: usize, +} + + +impl IntelHDA { + pub unsafe fn new(base: usize) -> Result { + + let regs = &mut *(base as *mut Regs); + + let buff_desc_phys = unsafe { + syscall::physalloc(0x1000) + .expect("Could not allocate physical memory for buffer descriptor list.") + }; + + + let buff_desc_virt = unsafe { + syscall::physmap(buff_desc_phys, 0x1000, MAP_WRITE) + .expect("ihdad: failed to map address for buffer descriptor list.") + }; + + + let buff_desc = &mut *(buff_desc_virt as *mut [BufferDescriptorListEntry;256]); + + + let output_length = 0x8000; + + let output_phys = unsafe { + syscall::physalloc(output_length) + .expect("Could not allocate physical memory for buffer descriptor list.") + }; + + + let output_virt = unsafe { + syscall::physmap(output_phys, output_length, MAP_WRITE) + .expect("ihdad: failed to map address for buffer descriptor list.") + }; + + + let mut module = IntelHDA { + base: base, + regs: regs, + corb_base: ptr::null_mut(), + rirb_base: ptr::null_mut(), + corb_rirb_base_phys: 0, + + corb_count: 0, + rirb_count: 0, + rirb_rp: 0, + + beep_addr: 0, + + codecs: Vec::::new(), + nodes: Vec::::new(), + + output_pins: Vec::::new(), + input_pins: Vec::::new(), + + buff_desc: buff_desc, + buff_desc_phys: buff_desc_phys, + + output_buff: output_virt, + output_buff_phys: output_phys, + output_buff_length: output_length, + output_buff_wp: 0, + output_current_block: 0, + + buffs: Vec::>::new(), + + + int_counter: 0, + }; + module.init(); + //module.info(); + module.enumerate(); + module.vbox_speaker_test(); + print!("IHDA: Initialization finished.\n"); + Ok(module) + + } + + pub fn init(&mut self) -> bool { + + self.reset_controller(); + self.init_corb_and_rirb(); + + self.init_interrupts(); + //print!("Command 0xF0000: {:016X}\n", self.read_response()); + //print!("Command 0xF0004: {:016X}\n", self.send_immediate_command(0xF0004)); + + + true + + } + + pub fn init_interrupts(&mut self) { + // TODO: provide a function to enable certain interrupts + // This just enables the first output stream interupt and the global interrupt + + // TODO: No magic numbers! Bad Schemm. + self.regs.intctl.write((1 << 31) | (1 << 30) | (1 << 4)); + + + + } + + + + + pub fn irq(&mut self) -> bool { + self.int_counter += 1; + + self.handle_interrupts(); + + true + } + + pub fn int_count(&self) -> usize { + self.int_counter + } + + pub fn read_node(&mut self, addr: HDANodeAddr) -> HDANode { + let mut node = HDANode::new(); + let mut temp:u64; + + node.addr = addr; + + self.send_command(Self::node_command(0x00, addr, 0xF00, 0x04)); + temp = self.read_response(); + + node.subnode_count = (temp & 0xff) as u16; + node.subnode_start = ((temp >> 16) & 0xff) as u16; + + self.send_command(Self::node_command(0x00, addr, 0xF00, 0x05)); + temp = self.read_response(); + + node.function_group_type = (temp & 0xff) as u8; + + self.send_command(Self::node_command(0x00, addr, 0xF00, 0x09)); + temp = self.read_response(); + + node.capabilities = temp as u32; + + + self.send_command(Self::node_command(0x00, addr, 0xF00, 0x09)); + temp = self.read_response(); + + node.capabilities = temp as u32; + + self.send_command(Self::node_command(0x00, addr, 0xF00, 0x0E)); + temp = self.read_response(); + + node.conn_list_len = (temp & 0xFF) as u8; + + node.connections = self.node_get_connection_list(&node); + + self.send_command(Self::node_command(0x00, addr, 0xF1C, 0x00)); + node.config_default = self.read_response() as u32; + + node + + } + + pub fn node_get_connection_list(&mut self, node: &HDANode) -> Vec { + // get list length + self.send_command(Self::node_command(0x00, node.addr, 0xF00, 0x0E)); + let len_field: u8 = (self.read_response() & 0xFF) as u8; + + // Highest bit is if addresses are represented in longer notation + // lower 7 is actual count + + let count:u8 = len_field & 0x7F; + let use_long_addr: bool = (len_field >> 7) & 0x1 == 1; + + let mut current: u8 = 0; + + let mut list = Vec::::new(); + + while current < count { + self.send_command(Self::node_command(0x00, node.addr, 0xF02, current as u32)); + let response: u32 = (self.read_response() & 0xFFFFFFFF) as u32; + + if use_long_addr { + for i in 0..2 { + let addr_field = ((response >> (16 * i)) & 0xFFFF) as u16; + let addr = (addr_field & 0x7FFF); + + if addr == 0 { break; } + + if (addr_field >> 15) & 0x1 == 0x1 { + for i in (list.pop().unwrap() .. (addr + 1)) { + list.push(i); + } + } else { + list.push(addr); + } + } + + } else { + + for i in 0..4 { + let addr_field = ((response >> (8 * i)) & 0xff) as u16; + let addr = (addr_field & 0x7F); + + if addr == 0 { break; } + + if (addr_field >> 7) & 0x1 == 0x1 { + for i in (list.pop().unwrap() .. (addr + 1)) { + list.push(i); + } + } else { + list.push(addr); + } + } + + } + + current = list.len() as u8; + + } + list + + } + pub fn enumerate(&mut self) { + + self.nodes.clear(); + self.output_pins.clear(); + self.input_pins.clear(); + + + let root = self.read_node(0); + + // print!("{}\n", root); + + let root_count = root.subnode_count; + let root_start = root.subnode_start; + self.nodes.push(root); + + + //FIXME: So basically the way this is set up is to only support one codec and hopes the first one is an audio + for i in 0..root_count { + let afg = self.read_node((root_start + i) as HDANodeAddr); + // print!("{}\n", afg); + let afg_count = afg.subnode_count; + let afg_start = afg.subnode_start; + self.nodes.push(afg); + + for j in 0..afg_count { + let mut widget = self.read_node((afg_start + j) as HDANodeAddr); + widget.is_widget = true; + match widget.widget_type() { + HDAWidgetType::AudioOutput => {self.output_pins.push(widget.addr)}, + HDAWidgetType::AudioInput => {self.input_pins.push(widget.addr)}, + HDAWidgetType::BeepGenerator => {self.beep_addr = widget.addr }, + _ => {}, + } + // print!("{}\n", widget); + self.nodes.push(widget); + } + } + } + + pub fn get_node(&self, addr: HDANodeAddr) -> Option<&HDANode> { + + for ref node in &self.nodes { + if node.addr == addr { + return Some(node); + } + + } + None + } + pub fn find_shortest_path_to_speaker(&mut self) -> Vec { + let mut path = Vec::::new(); + + for addr in &self.output_pins { + //let node = self.get_node().unwrap(); + + + } + + path + } + + + pub fn create_sound_buffers(&mut self) { + + self.buffs.push(Vec::::new()); + // self.buffs[0].push(StreamBuffer::new(0x4000).unwrap()); + // self.buffs[0].push(StreamBuffer::new(0x4000).unwrap()); + + + } + + /* + Here we update the buffers and split them into 128 byte sub chunks + because each BufferDescriptorList needs to be 128 byte aligned, + this makes it so each of the streams can have up to 128/16 (8) buffer descriptors + */ + /* + Vec of a Vec was doing something weird and causing the driver to hang. + So now we have a set of variables instead. + */ + pub fn update_sound_buffers(&mut self) { + /* + for i in 0..self.buffs.len(){ + for j in 0.. min(self.buffs[i].len(), 128/16 ) { + self.buff_desc[i * 128/16 + j].set_address(self.buffs[i][j].phys()); + self.buff_desc[i * 128/16 + j].set_length(self.buffs[i][j].length() as u32); + self.buff_desc[i * 128/16 + j].set_interrupt_on_complete(true); + } + }*/ + + self.buff_desc[0].set_address(self.output_buff_phys); + self.buff_desc[0].set_length((self.output_buff_length/2) as u32); + self.buff_desc[0].set_interrupt_on_complete(true); + + self.buff_desc[1].set_address(self.output_buff_phys + self.output_buff_length/2); + self.buff_desc[1].set_length((self.output_buff_length/2) as u32); + self.buff_desc[1].set_interrupt_on_complete(true); + + + + } + + + /* + For testing in VBOX: + Create Ramp wave of 400hz to test the output of + the speakers to see sound can be played + */ + + pub fn test_buff_fill(&mut self) { + let n_samples = self.output_buff_length / (2 * 2); + let buf_ptr = unsafe { self.output_buff as * mut u16}; + + let freq:u16 = 440; + + let period:u16 = 44100 / 440; + + let step:u16 = 65535 / period; + + let mut j:u16 = 0; + let mut val:u16 = 0; + + for i in 0..n_samples { + unsafe { + *buf_ptr.offset((2*i) as isize) = val; + *buf_ptr.offset((2*i+1) as isize) = val; + } + val += step; + j += 1; + + if j >= period { + j = 0; + val = 0; + } + + } + print!("IHDA: Test buffer created.\n"); + } + + + pub fn vbox_speaker_test(&mut self) { + + + + + // Pin enable + self.send_command(Self::node_command(0x00, 0xC, 0x707, 0x40)); + let mut response: u32 = (self.read_response() & 0xFFFFFFFF) as u32; + + + // EAPD enable + self.send_command(Self::node_command(0x00, 0xC, 0x70C, 2)); + response = (self.read_response() & 0xFFFFFFFF) as u32; + + + self.set_stream_channel(0x3, 1, 0); + + // self.create_sound_buffers(); + self.update_sound_buffers(); + + + print!("Supported Formats: {:08X}\n", self.get_supported_formats(0x1)); + print!("Capabilities: {:08X}\n", self.get_capabilities(0x3)); + + let output = self.get_output_stream_descriptor(0).unwrap(); + + output.set_address(self.buff_desc_phys); + + output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); + output.set_cyclic_buffer_length(0x8000); // number of samples + output.set_stream_number(1); + output.set_last_valid_index(1); + output.set_interrupt_on_completion(true); + + + self.set_power_state(0x3, 0); // Power state 0 is fully on + self.set_converter_format(0x3, &super::SR_44_1, BitsPerSample::Bits16, 2); + + self.send_command(Self::node_command(0x00, 0x3, 0xA00, 0)); + response = (self.read_response() & 0xFFFFFFFF) as u32; + + print!("Format: {:04X}\n",response); + + // Unmute and set gain for pin complex and DAC + self.set_amplifier_gain_mute(0x3, true, true, true, true, 0, false, 0x7f); + self.set_amplifier_gain_mute(0xC, true, true, true, true, 0, false, 0x7f); + + + + + // self.test_buff_fill(); + + output.run(); + + print!("IHDA: Beep? \n"); + self.beep(1); + + } + + + // BEEP!! + pub fn beep(&mut self, div:u8) { + let addr = self.beep_addr; + if addr != 0 { + + self.send_command(Self::node_command(0x00, addr, 0xF0A, div as u32)); + let response = (self.read_response() & 0xFFFFFFFF) as u32; + } + + } + + pub fn read_beep(&mut self) -> u8 { + let addr = self.beep_addr; + if addr != 0 { + self.send_command(Self::node_command(0x00, addr, 0x70A, 0)); + (self.read_response() & 0xFF) as u8 + }else{ + 0 + } + + } + + pub fn enable_pin(&self, node: &HDANode) { + + + } + + pub fn reset_controller(&mut self) -> bool { + + self.regs.statests.write(0xFFFF); + + // 3.3.7 + self.regs.gctl.writef(CRST, false); + loop { + if ! self.regs.gctl.readf(CRST) { + break; + } + } + self.regs.gctl.writef(CRST, true); + loop { + if self.regs.gctl.readf(CRST) { + break; + } + } + + let mut ticks:u32 = 0; + while self.regs.statests.read() == 0 { + ticks += 1; + if ticks > 10000 { break;} + + } + + let statests = self.regs.statests.read(); + + + for i in 0..15 { + if (statests >> i) & 0x1 == 1 { + self.codecs.push(i as HDANodeAddr); + } + } + true + + } + + pub fn num_output_streams(&self) -> usize{ + let gcap = self.regs.gcap.read(); + ((gcap >> 12) & 0xF) as usize + } + + pub fn num_input_streams(&self) -> usize{ + let gcap = self.regs.gcap.read(); + ((gcap >> 8) & 0xF) as usize + } + + pub fn num_bidirectional_streams(&self) -> usize{ + let gcap = self.regs.gcap.read(); + ((gcap >> 3) & 0xF) as usize + } + + pub fn num_serial_data_out(&self) -> usize{ + let gcap = self.regs.gcap.read(); + ((gcap >> 1) & 0x3) as usize + } + + pub fn info(&self) { + print!("Intel HD Audio Version {}.{}\n", self.regs.vmaj.read(), self.regs.vmin.read()); + print!("IHDA: Input Streams: {}\n", self.num_input_streams()); + print!("IHDA: Output Streams: {}\n", self.num_output_streams()); + print!("IHDA: Bidirectional Streams: {}\n", self.num_bidirectional_streams()); + print!("IHDA: Serial Data Outputs: {}\n", self.num_serial_data_out()); + print!("IHDA: 64-Bit: {}\n", self.regs.gcap.read() & 1 == 1); + } + + pub fn node_command(codec_address: u32, node_index: HDANodeAddr, command: u32, data: u32) -> u32{ + let mut ncmd: u32 = 0; + let node_addr = node_index as u32; + + ncmd |= (codec_address & 0x00F) << 28; + ncmd |= (node_addr & 0x0FF) << 20; + ncmd |= (command & 0xFFF) << 8; + ncmd |= (data & 0x0FF) << 0; + ncmd + } + + + pub fn corb_start(&mut self) { + self.regs.corbctl.writef(CORBRUN,true); + } + + pub fn rirb_start(&mut self) { + self.regs.rirbctl.writef(RIRBDMAEN | RINTCTL,true); + } + + pub fn corb_stop(&mut self) { + + while self.regs.corbctl.readf(CORBRUN) { self.regs.corbctl.write(0); } + } + + pub fn rirb_stop(&mut self) { + let mut val = self.regs.rirbctl.read(); + val &= !(RIRBDMAEN); + self.regs.rirbctl.write(val); + } + + + + //Intel 4.4.1.3 + + pub fn init_corb_and_rirb(&mut self) -> Result<()> { + + + self.corb_stop(); + self.rirb_stop(); + + + //Determine CORB and RIRB size and allocate buffer + + + //3.3.24 + let corbsize_reg = self.regs.corbsize.read(); + let corbszcap = (corbsize_reg >> 4) & 0xF; + + let mut corbsize_bytes: usize = 0; + let mut corbsize: u8 = 0; + + if (corbszcap & 4) == 4 { + corbsize = 2; + corbsize_bytes = 1024; + + self.corb_count = 256; + } else if (corbszcap & 2) == 2 { + corbsize = 1; + corbsize_bytes = 64; + + self.corb_count = 16; + } else if (corbszcap & 1) == 1 { + corbsize = 0; + corbsize_bytes = 8; + + self.corb_count = 2; + } else { + //TODO: Error! + } + + //3.3.31 + + let rirbsize_reg = self.regs.rirbsize.read(); + let rirbszcap = (rirbsize_reg >> 4) & 0xF; + + let mut rirbsize_bytes: usize = 0; + let mut rirbsize: u8 = 0; + + if (rirbszcap & 4) == 4 { + rirbsize = 2; + rirbsize_bytes = 2048; + + self.rirb_count = 256; + } else if (rirbszcap & 2) == 2 { + rirbsize = 1; + rirbsize_bytes = 128; + + self.rirb_count = 8; + } else if (rirbszcap & 1) == 1 { + rirbsize = 0; + rirbsize_bytes = 16; + + self.rirb_count = 2; + } else { + //TODO: Error! + } + + //print!("CORB size: {} RIRB size: {}\n", corbsize_bytes, rirbsize_bytes); + + + // Allocate the physical memory, keeping in mind + // that the buffers need to be 128-byte aligned + + let buff_address = unsafe { + syscall::physalloc(max(rirbsize_bytes, 128) + max(corbsize_bytes, 128)) + .expect("Could not allocate physical memory for CORB and RIRB.") + }; + + + let virt_address = unsafe { syscall::physmap(buff_address, 0x1000, MAP_WRITE).expect("ihdad: failed to map address for CORB/RIRB buff") }; + + + self.corb_rirb_base_phys = buff_address; + + // Set the sizes and addresses of the buffers + self.regs.corbsize.write(corbsize); + + self.corb_set_address(buff_address); + + // make sure that the RIRB buffer is at least aligned to 128 bytes. + self.regs.rirbsize.write(rirbsize); + self.rirb_set_address(buff_address + max(128, corbsize_bytes)); + + + // set virtual addresses for the buffer so we can access it + + self.corb_base = (virt_address) as *mut u32; + self.rirb_base = (virt_address + max(128, corbsize_bytes)) as *mut u64; + + + //print!("IHDA State: {:04X}\n",self.regs.statests.read()); + self.regs.corbwp.write(0); + self.corb_reset_read_pointer(); + self.rirb_reset_write_pointer(); + self.rirb_rp = 0; + + self.regs.rintcnt.write(1); + + + self.corb_start(); + self.rirb_start(); + + Ok(()) + } + + fn corb_set_address(&mut self, addr: usize) { + + + + self.regs.corblbase.write((addr & 0xFFFFFFFF) as u32); + self.regs.corbubase.write((addr >> 32) as u32); + } + + fn rirb_set_address(&mut self, addr: usize) { + self.regs.rirblbase.write((addr & 0xFFFFFFFF) as u32); + self.regs.rirbubase.write((addr >> 32) as u32); + } + + fn rirb_reset_write_pointer(&mut self) { + self.regs.rirbwp.writef(RIRBWPRST, true); + + + } + + fn corb_reset_read_pointer(&mut self){ + + + /* + * FIRST ISSUE/PATCH + * This will loop forever in virtualbox + * So maybe just resetting the read pointer + * and leaving for the specific model? + */ + if true { + self.regs.corbrp.writef(CORBRPRST, true); + + } + else + { + // 3.3.21 + + self.corb_stop(); + // Set CORBRPRST to 1 + print!("CORBRP {:X}\n",self.regs.corbrp.read()); + self.regs.corbrp.writef(CORBRPRST, true); + print!("CORBRP {:X}\n",self.regs.corbrp.read()); + print!("Here!\n"); + + // Wait for it to become 1 + while ! self.regs.corbrp.readf(CORBRPRST) { + self.regs.corbrp.writef(CORBRPRST, true); + } + print!("Here!!\n"); + // Clear the bit again + self.regs.corbrp.write(0); + + // Read back the bit until zero to verify that it is cleared. + + loop { + + if !self.regs.corbrp.readf(CORBRPRST) { + break; + } + self.regs.corbrp.write(0); + } + } + } + + + fn send_command(&mut self, cmd: u32) { + + // wait for the commands to finish + while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {} + + let mut write_pos: usize = ( (self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count; + + unsafe { + *self.corb_base.offset(write_pos as isize) = cmd; + } + + self.regs.corbwp.write(write_pos as u16); + + + + } + + fn read_response(&mut self) -> u64 { + + // wait for response + while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) {} + + let mut read_pos: u16 = (self.rirb_rp + 1) % self.rirb_count as u16; + + let mut res: u64; + unsafe { + res = *self.rirb_base.offset(read_pos as isize); + } + + self.rirb_rp = read_pos; + + res + + } + + + // FIXME: Apparently vbox is picky about sending immediate commands. + // Hopefully this can be disregarded if the DMA works. + + + + fn send_immediate_command(&mut self, cmd: u32) -> u64 { + print!("Status: {:04X}\n",self.regs.ics.read()); + + // wait for ready + while self.regs.ics.readf(ICB) {} + + // write command + self.regs.icoi.write(cmd); + + + // set ICB bit to send command + self.regs.ics.writef(ICB, true); + + print!("Status: {:04X}\n",self.regs.ics.read()); + + // wait for IRV bit to be set to indicate a response is latched + while !self.regs.ics.readf(IRV) {} + + // read the result register twice, total of 8 bytes + // highest 4 will most likely be zeros (so I've heard) + let mut res:u64 = self.regs.irii.read() as u64; + res |= (self.regs.irii.read() as u64) << 32; + + + // clear the bit so we know when the next response comes + self.regs.ics.writef(IRV, false); + + res + + } + + fn get_input_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { + unsafe { + if index < self.num_input_streams() { + Some(&mut *((self.base + 0x80 + index * 0x20) as *mut StreamDescriptorRegs)) + }else{ + None + } + } + } + + fn get_output_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { + unsafe { + if index < self.num_output_streams() { + Some(&mut *((self.base + 0x80 + + self.num_input_streams() * 0x20 + + index * 0x20) as *mut StreamDescriptorRegs)) + }else{ + None + } + } + } + + + fn get_bidirectional_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { + unsafe { + if index < self.num_bidirectional_streams() { + Some(&mut *((self.base + 0x80 + + self.num_input_streams() * 0x20 + + self.num_output_streams() * 0x20 + + index * 0x20) as *mut StreamDescriptorRegs)) + }else{ + None + } + } + } + + fn set_dma_position_buff_addr(&mut self, addr: usize) { + let addr_val = addr & !0x7F; + self.regs.dplbase.write((addr_val & 0xFFFFFFFF) as u32); + self.regs.dpubase.write((addr_val >> 32) as u32); + } + + + fn set_stream_channel(&mut self, addr: HDANodeAddr, stream: u8, channel:u8) { + let val = ((stream & 0xF) << 4) | (channel & 0xF); + self.send_command(Self::node_command(0x00, addr, 0x706, val as u32)); + let temp = self.read_response(); + } + + fn set_power_state(&mut self, addr:HDANodeAddr, state:u8) { + self.send_command(Self::node_command(0x00, addr, 0x705, state as u32 & 0xF)); + let temp = self.read_response(); + } + + fn get_supported_formats(&mut self, addr: HDANodeAddr) -> u32 { + self.send_command(Self::node_command(0x00, addr, 0xF00, 0x0A)); + self.read_response() as u32 + } + + fn get_capabilities(&mut self, addr: HDANodeAddr) -> u32 { + self.send_command(Self::node_command(0x00, addr, 0xF00, 0x09)); + self.read_response() as u32 + } + + fn set_converter_format(&mut self, addr:HDANodeAddr, sr: &super::SampleRate, bps: BitsPerSample, channels:u8) { + let fmt = super::format_to_u16(sr, bps, channels); + let fmt_hi = (fmt >> 8) as u32; + let fmt_lo = (fmt & 0xFF) as u32; + print!("Format: {:04X}\n",fmt); + self.send_command(Self::node_command(0x00, addr, 0x200 | fmt_hi, fmt_lo)); + let temp = self.read_response(); + + } + + fn set_amplifier_gain_mute(&mut self, addr:HDANodeAddr, output:bool, input:bool, left:bool, right:bool, index:u8, mute:bool, gain: u8) { + + let mut payload: u16 = 0; + + if output { payload |= (1 << 15); } + if input { payload |= (1 << 14); } + if left { payload |= (1 << 13); } + if right { payload |= (1 << 12); } + if mute { payload |= (1 << 7); } + payload |= ((index as u16) & 0x0F) << 8; + payload |= ((gain as u16) & 0x7F); + + let payload_hi = (payload >> 8); + let payload_lo = (payload & 0xFF) as u8; + + self.send_command(Self::node_command(0x00, addr, 0x300 | payload_hi as u32, payload_lo as u32)); + let temp = self.read_response(); + } + + fn write_to_output(&mut self, out_index: usize, buf: &[u8]) -> Result { + + + // TODO: Better way of writing than just writing from the write pointer to the link position in buffer + + + + + let mut output = self.get_output_stream_descriptor(0).unwrap(); + + let sample_size:usize = output.sample_size(); + let sample_count:usize = buf.len() / sample_size; + let buff_len = output.cyclic_buffer_length() as usize; + + let mut samples_copied: usize = 0; + while samples_copied < sample_count { + + let samples_left = sample_count - samples_copied; + + // modular arithmetic to get the number of samples that we can write to + + let mut can_write = (output.link_position() as usize + buff_len) - self.output_buff_wp; + + if can_write >= buff_len { + can_write -= buff_len; + } + + let samples_to_write = min(can_write, samples_left); + let samples_until_end = buff_len - self.output_buff_wp; + + if samples_to_write > 0 { + + if samples_until_end >= samples_to_write { + unsafe { + copy_nonoverlapping(buf.as_ptr(), (self.output_buff + self.output_buff_wp * sample_size) as * mut u8, samples_to_write * sample_size); + } + + } else { + unsafe { + copy_nonoverlapping(buf.as_ptr(), (self.output_buff + self.output_buff_wp * sample_size) as * mut u8, samples_until_end * sample_size); + copy_nonoverlapping((buf.as_ptr() as usize + (samples_to_write * sample_size)) as * const u8, + (self.output_buff + self.output_buff_wp * sample_size) as * mut u8, + (samples_to_write - samples_until_end) * sample_size); + } + } + + self.output_buff_wp += samples_to_write; + + if self.output_buff_wp >= buff_len { + self.output_buff_wp -= buff_len; + } + + samples_copied += samples_to_write; + } + thread::yield_now(); + } + + Ok(samples_copied * sample_size) + + } + + + + pub fn write_to_output2(&mut self, index:u8, buf: &[u8]) -> Result { + + + let mut output = self.get_output_stream_descriptor(0).unwrap(); + let sample_size:usize = output.sample_size(); + let mut open_block = (output.link_position() as usize) / 0x4000; + + if open_block == 0 { + open_block = 1; + } else { + open_block = open_block - 1; + } + + + while open_block == self.output_current_block { + + open_block = (output.link_position() as usize) / 0x4000; + + if open_block == 0 { + open_block = 1; + } else { + open_block = open_block - 1; + } + + thread::yield_now(); + } + + self.output_current_block = open_block; + let len = min(0x4000, buf.len()); + + unsafe { + copy_nonoverlapping(buf.as_ptr(), (self.output_buff + self.output_current_block * 0x4000) as * mut u8, len); + } + + Ok(len) + } + + pub fn handle_interrupts(&mut self) { + + let intsts = self.regs.intsts.read(); + let sis = intsts & 0x3FFFFFFF; + print!("IHDA INTSTS: {:08X}\n", intsts); + if ((intsts >> 31) & 1) == 1 { // Global Interrupt Status + if ((intsts >> 30) & 1) == 1 { // Controller Interrupt Status + self.handle_controller_interrupt(); + } + + if sis != 0 { + self.handle_stream_interrupts(sis); + } + } + } + + pub fn handle_controller_interrupt(&mut self) { + + } + + pub fn handle_stream_interrupts(&mut self, sis: u32) { + let oss = self.num_output_streams(); + let iss = self.num_input_streams(); + let bss = self.num_bidirectional_streams(); + + + let sample_size = 4; // TODO: create method to get sample size + + for i in 0..iss { + if ((sis >> i) & 1 ) == 1 { + + + } + } + + for i in 0..oss { + if ((sis >> (i + iss)) & 1 ) == 1 { + + let mut output = self.get_output_stream_descriptor(i).unwrap(); + // TODO: No magic numbers! + let mut temp = output.link_position() as usize / 0x4000; + + if temp == 0 { + temp = self.output_buff_length - 0x4000; + } else { + temp = temp - 0x4000; + } + self.output_current_block = temp; + output.clear_interrupts(); + } + } + + for i in 0..bss { + if ((sis >> (i + iss + oss)) & 1 ) == 1 { + + + } + } + } + +} + + +impl Drop for IntelHDA { + fn drop(&mut self) { + let _ = unsafe {syscall::physfree(self.buff_desc_phys, 0x1000)}; + if self.output_buff_phys != 0 { + unsafe { + let _ = syscall::physfree(self.output_buff_phys, self.output_buff_length); + } + } + print!("IHDA: Deallocating IHDA driver.\n"); + + } + + +} + + +impl SchemeMut for IntelHDA { + fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + + // TODO: + + if uid == 0 { + Ok(flags) + } else { + Err(Error::new(EACCES)) + } + } + + fn write(&mut self, _id: usize, buf: &[u8]) -> Result { + + //print!("Int count: {}\n", self.int_counter); + + + self.write_to_output2(0, buf) + } + + fn close(&mut self, _id: usize) -> Result { + // TODO: + Ok(0) + } + +} diff --git a/ihdad/src/HDA/mod.rs b/ihdad/src/HDA/mod.rs new file mode 100644 index 0000000000..f3c06f06d0 --- /dev/null +++ b/ihdad/src/HDA/mod.rs @@ -0,0 +1,19 @@ + +pub mod device; +pub mod stream; +pub mod common; +pub mod node; + + +pub use self::stream::*; +pub use self::node::*; + + +pub use self::stream::StreamDescriptorRegs; +pub use self::stream::BufferDescriptorListEntry; +pub use self::stream::BitsPerSample; +pub use self::stream::StreamBuffer; +pub use self::device::IntelHDA; + + + diff --git a/ihdad/src/HDA/node.rs b/ihdad/src/HDA/node.rs new file mode 100644 index 0000000000..86e79eaa58 --- /dev/null +++ b/ihdad/src/HDA/node.rs @@ -0,0 +1,112 @@ + +use std::{mem, thread, ptr, fmt}; +use super::common::*; + +#[derive(Clone)] +pub struct HDANode { + pub addr: HDANodeAddr, + + + + // 0x4 + pub subnode_count: u16, + pub subnode_start: u16, + + // 0x5 + pub function_group_type: u8, + + + // 0x9 + pub capabilities: u32, + + // 0xC + pub pin_caps: u32, + + // 0xD + pub in_amp: u32, + + // 0xE + pub conn_list_len: u8, + + + // 0x12 + pub out_amp: u32, + + // 0x13 + pub vol_knob: u8, + + pub connections: Vec, + + pub is_widget: bool, + + pub config_default: u32, +} + + +impl HDANode { + + pub fn new() -> HDANode { + HDANode { + addr: 0, + subnode_count: 0, + subnode_start: 0, + function_group_type: 0, + capabilities: 0, + pin_caps: 0, + in_amp: 0, + out_amp: 0, + vol_knob: 0, + conn_list_len: 0, + + config_default: 0, + is_widget: false, + connections: Vec::::new(), + } + } + + pub fn widget_type(&self) -> HDAWidgetType { + unsafe { mem::transmute( ((self.capabilities >> 20) & 0xF) as u8 )} + + } + + pub fn getDeviceDefault(&self) -> Option { + if self.widget_type() != HDAWidgetType::PinComplex { + None + } else { + Some(unsafe { mem::transmute( ((self.config_default >> 20) & 0xF) as u8 )} ) + } + } + + pub fn addr(&self) -> HDANodeAddr { + self.addr + } +} + +impl fmt::Display for HDANode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.addr == 0 { + write!(f, "Addr: {:02X}, Root Node.", self.addr) + } else if self.is_widget { + match self.widget_type() { + + HDAWidgetType::PinComplex => { + write!(f, "Addr: {:02X}, Type: {:?}: {:?}, Inputs: {:X}: {:?}.", + self.addr, + self.widget_type(), + self.getDeviceDefault().unwrap(), + self.conn_list_len, + self.connections) + }, + + _ => { write!(f, "Addr: {:02X}, Type: {:?}, Inputs: {:X}: {:?}.", self.addr, self.widget_type(), self.conn_list_len, self.connections) }, + + } + } else { + write!(f, "Addr: {:02X}, AFG: {}, Widget count {}.", self.addr, self.function_group_type, self.subnode_count) + } + } +} + + + + diff --git a/ihdad/src/HDA/stream.rs b/ihdad/src/HDA/stream.rs new file mode 100644 index 0000000000..75034be732 --- /dev/null +++ b/ihdad/src/HDA/stream.rs @@ -0,0 +1,308 @@ +use std::{mem, thread, ptr, fmt}; +use std::cmp::max; + +use syscall::MAP_WRITE; +use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; +use syscall::flag::O_NONBLOCK; +use syscall::io::{Dma, Mmio, Io, ReadOnly}; +use syscall::scheme::SchemeMut; +use std::sync::Arc; +use std::cell::RefCell; +use std::result; + + +extern crate syscall; + +pub enum BaseRate { + BR44_1, + BR48, +} + + +pub struct SampleRate { + base: BaseRate, + mult: u16, + div: u16, +} + +use self::BaseRate::{BR44_1, BR48}; + +pub const SR_8: SampleRate = SampleRate {base: BR48 , mult: 1, div: 6}; +pub const SR_11_025: SampleRate = SampleRate {base: BR44_1, mult: 1, div: 4}; +pub const SR_16: SampleRate = SampleRate {base: BR48 , mult: 1, div: 3}; +pub const SR_22_05: SampleRate = SampleRate {base: BR44_1, mult: 1, div: 2}; +pub const SR_32: SampleRate = SampleRate {base: BR48 , mult: 2, div: 3}; + +pub const SR_44_1: SampleRate = SampleRate {base: BR44_1, mult: 1, div: 1}; +pub const SR_48: SampleRate = SampleRate {base: BR48 , mult: 1, div: 1}; +pub const SR_88_1: SampleRate = SampleRate {base: BR44_1, mult: 2, div: 1}; +pub const SR_96: SampleRate = SampleRate {base: BR48 , mult: 2, div: 1}; +pub const SR_176_4: SampleRate = SampleRate {base: BR44_1, mult: 4, div: 1}; +pub const SR_192: SampleRate = SampleRate {base: BR48 , mult: 4, div: 1}; + + + + + +#[repr(u8)] +pub enum BitsPerSample { + Bits8 = 0, + Bits16 = 1, + Bits20 = 2, + Bits24 = 3, + Bits32 = 4, +} + + + +pub fn format_to_u16(sr: &SampleRate, bps: BitsPerSample, channels:u8) -> u16{ + + + // 3.3.41 + + let base:u16 = match sr.base { + BaseRate::BR44_1 => { 1 << 14}, + BaseRate::BR48 => { 0 }, + }; + + let mult = ((sr.mult - 1) & 0x7) << 11; + + let div = ((sr.div - 1) & 0x7) << 8; + + let bits = (bps as u16) << 4; + + let chan = ((channels - 1) & 0xF) as u16; + + let val:u16 = base | mult | div | bits | chan; + + val + +} + + +#[repr(packed)] +pub struct StreamDescriptorRegs { + ctrl_lo: Mmio, + ctrl_hi: Mmio, + status: Mmio, + link_pos: Mmio, + buff_length: Mmio, + last_valid_index: Mmio, + resv1: Mmio, + fifo_size_: Mmio, + format: Mmio, + resv2: Mmio, + buff_desc_list_lo: Mmio, + buff_desc_list_hi: Mmio, + +} + + +impl StreamDescriptorRegs { + pub fn status(&self) -> u8 { + self.status.read() + } + + pub fn set_status(&mut self, status: u8){ + self.status.write(status); + } + + pub fn control(&self) -> u32 { + let mut ctrl = self.ctrl_lo.read() as u32; + ctrl |= (self.ctrl_hi.read() as u32) << 16; + ctrl + } + + pub fn set_control(&mut self, control:u32) { + self.ctrl_lo.write((control & 0xFFFF) as u16); + self.ctrl_hi.write(((control >> 16) & 0xFF) as u8); + } + + pub fn set_pcm_format(&mut self, sr: &SampleRate, bps: BitsPerSample, channels:u8) { + + + // 3.3.41 + + let val = format_to_u16(sr,bps,channels); + self.format.write(val); + + } + + pub fn fifo_size(&self) -> u16 { + self.fifo_size_.read() + } + + pub fn set_cyclic_buffer_length(&mut self, length: u32) { + self.buff_length.write(length); + } + + pub fn cyclic_buffer_length(&self) -> u32 { + self.buff_length.read() + } + + pub fn run(&mut self) { + let val = self.control() | (1 << 1); + self.set_control(val); + } + + pub fn stop(&mut self) { + let val = self.control() & !(1 << 1); + self.set_control(val); + } + + pub fn stream_number(&self) -> u8 { + ((self.control() >> 20) & 0xF) as u8 + } + + pub fn set_stream_number(&mut self, stream_number: u8) { + let val = (self.control() & 0x00FFFF ) | (((stream_number & 0xF ) as u32) << 20); + self.set_control(val); + } + + pub fn set_address(&mut self, addr: usize) { + self.buff_desc_list_lo.write( (addr & 0xFFFFFFFF) as u32); + self.buff_desc_list_hi.write( ( (addr >> 32) & 0xFFFFFFFF) as u32); + } + + pub fn set_last_valid_index(&mut self, index:u16) { + self.last_valid_index.write(index); + } + + pub fn link_position(&self) -> u32 { + self.link_pos.read() + } + + pub fn set_interrupt_on_completion(&mut self, enable:bool) { + let mut ctrl = self.control(); + if enable { + ctrl |= (1 << 2); + } else { + ctrl &= !(1 << 2); + } + self.set_control(ctrl); + } + + pub fn buffer_complete(&self) -> bool { + self.status.readf(1 << 2) + } + + pub fn clear_interrupts(&mut self) { + self.status.write(0x7 << 2); + } + + // get sample size in bytes + pub fn sample_size(&self) -> usize { + let format = self.format.read(); + let chan = (format & 0xF) as usize; + let bits = ((format >> 4) & 0xF) as usize; + match bits { + 0 => 1 * (chan + 1), + 1 => 2 * (chan + 1), + _ => 4 * (chan + 1), + } + } +} + +pub struct Stream { + buff: usize, + buff_phys: usize, + buff_length: usize, + output_current_block: usize, + block_length: usize, + block_count: usize, +} + + +#[repr(packed)] +pub struct BufferDescriptorListEntry { + addr: Mmio, + len: Mmio, + ioc_resv: Mmio, +} + +impl BufferDescriptorListEntry { + pub fn address(&self) -> usize { + self.addr.read() as usize + } + + pub fn set_address(&mut self, addr:usize) { + self.addr.write(addr as u64); + } + + pub fn length(&self) -> u32 { + self.len.read() + } + + pub fn set_length(&mut self, length: u32) { + self.len.write(length) + } + + pub fn interrupt_on_completion(&self) -> bool { + (self.ioc_resv.read() & 0x1) == 0x1 + } + + pub fn set_interrupt_on_complete(&mut self, ioc: bool) { + self.ioc_resv.writef(1, ioc); + } +} + + + +pub struct StreamBuffer { + phys: usize, + addr: usize, + + len: usize, +} + +impl StreamBuffer { + pub fn new(length: usize) -> result::Result { + let phys = unsafe { + syscall::physalloc(length) + }; + if !phys.is_ok() { + return Err("Could not allocate physical memory for buffer."); + } + + let phys_addr = phys.unwrap(); + + let addr = unsafe { + syscall::physmap(phys_addr, length, MAP_WRITE) + }; + + if !addr.is_ok() { + return Err("Could not map physical memory for buffer."); + } else { + unsafe {syscall::physfree(phys_addr, length);} + } + + Ok(StreamBuffer { + phys: phys_addr, + addr: addr.unwrap(), + len: length, + }) + } + + pub fn length(&self) -> usize { + self.len + } + + pub fn addr(&self) -> usize { + self.addr + } + + pub fn phys(&self) -> usize { + self.phys + } + +} +/* +impl Drop for StreamBuffer { + fn drop(&mut self) { + unsafe { + print!("IHDA: Deallocating buffer.\n"); + syscall::physunmap(self.addr); + syscall::physfree(self.phys, self.len); + } + } +}*/ diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs new file mode 100755 index 0000000000..5825ad7cd7 --- /dev/null +++ b/ihdad/src/main.rs @@ -0,0 +1,164 @@ +//#![deny(warnings)] +#![feature(asm)] + +extern crate bitflags; +extern crate spin; +extern crate syscall; +extern crate event; + +use std::{env, usize, thread}; +use std::fs::File; +use std::io::{Read, Write, Result}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme, SchemeMut}; +use std::cell::RefCell; +use std::sync::Arc; + +use event::EventQueue; +use syscall::error::EWOULDBLOCK; + +pub mod HDA; + + +use HDA::IntelHDA; + +fn main() { + let mut args = env::args().skip(1); + + let mut name = args.next().expect("ihda: no name provided"); + name.push_str("_ihda"); + + let bar_str = args.next().expect("ihda: no address provided"); + let bar = usize::from_str_radix(&bar_str, 16).expect("ihda: failed to parse address"); + + let irq_str = args.next().expect("ihda: no irq provided"); + let irq = irq_str.parse::().expect("ihda: failed to parse irq"); + + print!("{}", format!(" + ihda {} on: {:X} IRQ: {}\n", name, bar, irq)); + + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + + + let address = unsafe { syscall::physmap(bar, 0x4000, MAP_WRITE).expect("ihdad: failed to map address") }; + { + + let mut irq_file = File::open(format!("irq:{}", irq)).expect("IHDA: failed to open IRQ file"); + + + let device = Arc::new(RefCell::new(unsafe { HDA::IntelHDA::new(address).expect("ihdad: failed to allocate device") })); + let socket_fd = syscall::open(":audio", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create audio scheme"); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + + + + + + let mut event_queue = EventQueue::::new().expect("IHDA: Could not create event queue."); + + let todo = Arc::new(RefCell::new(Vec::::new())); + + + let todo_irq = todo.clone(); + let device_irq = device.clone(); + let socket_irq = socket.clone(); + let device_loop = device.clone(); + + + event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + + let _irq = unsafe { device_irq.borrow_mut().irq()}; + + if _irq { + irq_file.write(&mut irq)?; + + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + device_irq.borrow_mut().handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; + } else { + socket_irq.borrow_mut().write(&mut todo[i])?; + todo.remove(i); + } + } + /* + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + }*/ + } + Ok(Some(0)) + }).expect("IHDA: failed to catch events on IRQ file"); + + let socket_fd = socket.borrow().as_raw_fd(); + let socket_packet = socket.clone(); + event_queue.add(socket_fd, move |_count: usize| -> Result> { + loop { + let mut packet = Packet::default(); + if socket_packet.borrow_mut().read(&mut packet)? == 0 { + break; + } + + let a = packet.a; + device.borrow_mut().handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket_packet.borrow_mut().write(&mut packet)?; + } + } + /* + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + }*/ + + Ok(None) + }).expect("IHDA: failed to catch events on IRQ file"); + + for event_count in event_queue.trigger_all(0).expect("IHDA: failed to trigger events") { + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ, + d: event_count + }).expect("IHDA: failed to write event"); + } + + + + loop { + { + //device_loop.borrow_mut().handle_interrupts(); + } + let event_count = event_queue.run().expect("IHDA: failed to handle events"); + + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ, + d: event_count + }).expect("IHDA: failed to write event"); + } + } + + unsafe { let _ = syscall::physunmap(address); } + } +} + + diff --git a/pcid.toml b/pcid.toml index aa320b72ca..573276d4e6 100644 --- a/pcid.toml +++ b/pcid.toml @@ -49,6 +49,14 @@ vendor = 32902 device = 5379 command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] + +#ihdad +[[drivers]] +name = "Intel HD Audio" +vendor = 32902 +device = 9832 +command = ["/sbin/ihdad", "$NAME", "$BAR0", "$IRQ"] + # nvmed [[drivers]] name = "NVME storage" From a2fe86c72530f4afcfaabd276fc3cf2e230f03ae Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 3 Jun 2017 12:50:44 -0600 Subject: [PATCH 0151/1301] Update Cargo.toml --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 4b13eaf786..143e3a8b44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "alxd", "bgad", "e1000d", + "ihdad", "nvmed", "pcid", "ps2d", From 602ab29aba34fb968edadf2b35091b98dea7084b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 3 Jun 2017 14:13:51 -0600 Subject: [PATCH 0152/1301] Fix path of ihdad --- pcid.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcid.toml b/pcid.toml index 573276d4e6..b19bd30447 100644 --- a/pcid.toml +++ b/pcid.toml @@ -55,7 +55,7 @@ command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] name = "Intel HD Audio" vendor = 32902 device = 9832 -command = ["/sbin/ihdad", "$NAME", "$BAR0", "$IRQ"] +command = ["ihdad", "$NAME", "$BAR0", "$IRQ"] # nvmed [[drivers]] From beefc3e1e63a337eeda2311210d4ab2f72a5fe7f Mon Sep 17 00:00:00 2001 From: TheSchemm Date: Fri, 16 Jun 2017 22:16:50 -0500 Subject: [PATCH 0153/1301] Added and as arguments to pass to driver. --- pcid/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index cee6b15b3d..a4345608c6 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -139,6 +139,8 @@ fn main() { "$BAR4" => bar_arg(4), "$BAR5" => bar_arg(5), "$IRQ" => format!("{}", header.interrupt_line), + "$VENID" => format!("{:>04X}",header.vendor_id), + "$DEVID" => format!("{:>04X}",header.device_id), _ => arg.clone() }; command.arg(&arg); From 402b46561b3f5e4351ab45c599cee8acfb2c2b39 Mon Sep 17 00:00:00 2001 From: TheSchemm Date: Sat, 17 Jun 2017 17:07:19 -0500 Subject: [PATCH 0154/1301] Refactored ihdad and added Qemu support. --- ihdad/src/HDA/CommandBuffer.rs | 146 ----- ihdad/src/HDA/cmdbuff.rs | 469 ++++++++++++++ ihdad/src/HDA/common.rs | 150 ++++- ihdad/src/HDA/device.rs | 1052 +++++++++++++------------------- ihdad/src/HDA/mod.rs | 5 +- ihdad/src/HDA/node.rs | 31 +- ihdad/src/HDA/stream.rs | 117 +++- ihdad/src/main.rs | 34 +- 8 files changed, 1179 insertions(+), 825 deletions(-) delete mode 100644 ihdad/src/HDA/CommandBuffer.rs create mode 100644 ihdad/src/HDA/cmdbuff.rs diff --git a/ihdad/src/HDA/CommandBuffer.rs b/ihdad/src/HDA/CommandBuffer.rs deleted file mode 100644 index 7d55f80e34..0000000000 --- a/ihdad/src/HDA/CommandBuffer.rs +++ /dev/null @@ -1,146 +0,0 @@ -use std::{mem, thread, ptr, fmt}; -use syscall::io::{Dma, Mmio, Io, ReadOnly}; - - -// CORBCTL -const CMEIE: u8 = 1 << 0; // 1 bit -const CORBRUN: u8 = 1 << 1; // 1 bit - -// CORBSIZE -const CORBSZCAP: (u8,u8) = (4, 4); -const CORBSIZE: (u8,u8) = (0, 2); - -// CORBRP -const CORBRPRST: u16 = 1 << 15; - -// RIRBWP -const RIRBWPRST: u16 = 1 << 15; - -// RIRBCTL -const RINTCTL: u8 = 1 << 0; // 1 bit -const RIRBDMAEN: u8 = 1 << 1; // 1 bit - - -const CORB_OFFSET: usize = 0x00; -const RIRB_OFFSET: usize = 0x10; - - -const CORB_BUFF_MAX_SIZE: usize = 1024; - -struct CommandBufferRegs { - corblbase: Mmio, - corbubase: Mmio, - corbwp: Mmio, - corbrp: Mmio, - corbctl: Mmio, - corbsts: Mmio, - corbsize: Mmio, - rsvd5: Mmio, - - rirblbase: Mmio, - rirbubase: Mmio, - rirbwp: Mmio, - rintcnt: Mmio, - rirbctl: Mmio, - rirbsts: Mmio, - rirbsize: Mmio, - rsvd6: Mmio, -} - - -struct CorbRegs { - corblbase: Mmio, - corbubase: Mmio, - corbwp: Mmio, - corbrp: Mmio, - corbctl: Mmio, - corbsts: Mmio, - corbsize: Mmio, - rsvd5: Mmio, -} - -struct Corb { - regs: &'static mut CorbRegs, - corb_base: *mut u32, - corb_base_phys: usize, -} - -impl Corb { - - pub fn new(regs_addr:usize, corb_buff_phys:usize, corb_buff_virt:usize) -> Corb { - - - Corb { - regs: &mut *(regs_addr as *mut CorbRegs); - corb_base: (corb_buff_virt) as *mut u64, - - } - } - -} - -struct RirbRegs { - rirblbase: Mmio, - rirbubase: Mmio, - rirbwp: Mmio, - rintcnt: Mmio, - rirbctl: Mmio, - rirbsts: Mmio, - rirbsize: Mmio, - rsvd6: Mmio, -} - -struct Rirb { - regs: &'static mut RirbRegs, - rirb_base: *mut u64, - rirb_base_phys: usize, - rirb_rp: usize, -} - -impl Rirb { - - pub fn new(regs_addr:usize, rirb_buff_phys:usize, rirb_buff_virt:usize) -> Rirb { - - - Rirb { - regs: &mut *(regs_addr as *mut RirbRegs); - rirb_base: (rirb_buff_virt) as *mut u64, - rirb_rp: 0, - rirb_base_phys: rirb_buff_phys, - } - } - -} - - -struct CommandBuffer { - - // regs: &'static mut CommandBufferRegs, - - corb: Corb, - rirb: Rirb, - - - corb_rirb_base_phys: usize, - - - -} - -impl CommandBuffer { - pub fn new(regs_addr:usize, cmd_buff_frame_phys:usize, cmd_buff_frame:usize ) -> CommandBuffer { - - let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff_frame_phys, cmd_buff_frame); - let rirb = Rirb::new(regs_addr + RIRB_OFFSET, - cmd_buff_frame_phys + CORB_BUFF_MAX_SIZE, - cmd_buff_frame + CORB_BUFF_MAX_SIZE); - - CommandBuffer { - corb: corb, - rirb: rirb, - corb_rirb_base_phys: cmd_buff_frame_phys, - } - } - -} - diff --git a/ihdad/src/HDA/cmdbuff.rs b/ihdad/src/HDA/cmdbuff.rs new file mode 100644 index 0000000000..17efa8cdf7 --- /dev/null +++ b/ihdad/src/HDA/cmdbuff.rs @@ -0,0 +1,469 @@ +use std::{mem, thread, ptr, fmt}; +use syscall::io::{Dma, Mmio, Io, ReadOnly}; + +use super::common::*; + +// CORBCTL +const CMEIE: u8 = 1 << 0; // 1 bit +const CORBRUN: u8 = 1 << 1; // 1 bit + +// CORBSIZE +const CORBSZCAP: (u8,u8) = (4, 4); +const CORBSIZE: (u8,u8) = (0, 2); + +// CORBRP +const CORBRPRST: u16 = 1 << 15; + +// RIRBWP +const RIRBWPRST: u16 = 1 << 15; + +// RIRBCTL +const RINTCTL: u8 = 1 << 0; // 1 bit +const RIRBDMAEN: u8 = 1 << 1; // 1 bit + + +const CORB_OFFSET: usize = 0x00; +const RIRB_OFFSET: usize = 0x10; +const ICMD_OFFSET: usize = 0x20; + +// ICS +const ICB: u16 = 1 << 0; +const IRV: u16 = 1 << 1; + + +// CORB and RIRB offset + +const COMMAND_BUFFER_OFFSET: usize = 0x40; +const CORB_BUFF_MAX_SIZE: usize = 1024; + +struct CommandBufferRegs { + corblbase: Mmio, + corbubase: Mmio, + corbwp: Mmio, + corbrp: Mmio, + corbctl: Mmio, + corbsts: Mmio, + corbsize: Mmio, + rsvd5: Mmio, + + rirblbase: Mmio, + rirbubase: Mmio, + rirbwp: Mmio, + rintcnt: Mmio, + rirbctl: Mmio, + rirbsts: Mmio, + rirbsize: Mmio, + rsvd6: Mmio, +} + + +struct CorbRegs { + corblbase: Mmio, + corbubase: Mmio, + corbwp: Mmio, + corbrp: Mmio, + corbctl: Mmio, + corbsts: Mmio, + corbsize: Mmio, + rsvd5: Mmio, +} + +struct Corb { + regs: &'static mut CorbRegs, + corb_base: *mut u32, + corb_base_phys: usize, + corb_count: usize, +} + +impl Corb { + + pub fn new(regs_addr:usize, corb_buff_phys:usize, corb_buff_virt:usize) -> Corb { + + unsafe { + Corb { + regs: &mut *(regs_addr as *mut CorbRegs), + corb_base: (corb_buff_virt) as *mut u32, + corb_base_phys: corb_buff_phys, + corb_count: 0, + } + } + } + //Intel 4.4.1.3 + pub fn init(&mut self) { + self.stop(); + //Determine CORB and RIRB size and allocate buffer + + + //3.3.24 + let corbsize_reg = self.regs.corbsize.read(); + let corbszcap = (corbsize_reg >> 4) & 0xF; + + let mut corbsize_bytes: usize = 0; + let mut corbsize: u8 = 0; + + if (corbszcap & 4) == 4 { + corbsize = 2; + corbsize_bytes = 1024; + + self.corb_count = 256; + } else if (corbszcap & 2) == 2 { + corbsize = 1; + corbsize_bytes = 64; + + self.corb_count = 16; + } else if (corbszcap & 1) == 1 { + corbsize = 0; + corbsize_bytes = 8; + + self.corb_count = 2; + } + + assert!(self.corb_count != 0); + let addr = self.corb_base_phys; + self.set_address(addr); + self.regs.corbwp.write(0); + self.reset_read_pointer(); + + } + + + pub fn start(&mut self) { + self.regs.corbctl.writef(CORBRUN,true); + } + + + pub fn stop(&mut self) { + while self.regs.corbctl.readf(CORBRUN) { self.regs.corbctl.write(0); } + } + + pub fn set_address(&mut self, addr: usize) { + self.regs.corblbase.write((addr & 0xFFFFFFFF) as u32); + self.regs.corbubase.write((addr >> 32) as u32); + } + + pub fn reset_read_pointer(&mut self){ + + + /* + * FIRST ISSUE/PATCH + * This will loop forever in virtualbox + * So maybe just resetting the read pointer + * and leaving for the specific model? + */ + if true { + self.regs.corbrp.writef(CORBRPRST, true); + + } + else + { + // 3.3.21 + + self.stop(); + // Set CORBRPRST to 1 + print!("CORBRP {:X}\n",self.regs.corbrp.read()); + self.regs.corbrp.writef(CORBRPRST, true); + print!("CORBRP {:X}\n",self.regs.corbrp.read()); + print!("Here!\n"); + + // Wait for it to become 1 + while ! self.regs.corbrp.readf(CORBRPRST) { + self.regs.corbrp.writef(CORBRPRST, true); + } + print!("Here!!\n"); + // Clear the bit again + self.regs.corbrp.write(0); + + // Read back the bit until zero to verify that it is cleared. + + loop { + + if !self.regs.corbrp.readf(CORBRPRST) { + break; + } + self.regs.corbrp.write(0); + } + print!("Here!!!\n"); + } + } + + + fn send_command(&mut self, cmd: u32) { + + // wait for the commands to finish + while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {} + let mut write_pos: usize = ( (self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count; + unsafe { + *self.corb_base.offset(write_pos as isize) = cmd; + } + + self.regs.corbwp.write(write_pos as u16); + + print!("Corb: {:08X}\n", cmd); + } +} + +struct RirbRegs { + rirblbase: Mmio, + rirbubase: Mmio, + rirbwp: Mmio, + rintcnt: Mmio, + rirbctl: Mmio, + rirbsts: Mmio, + rirbsize: Mmio, + rsvd6: Mmio, +} + +struct Rirb { + regs: &'static mut RirbRegs, + rirb_base: *mut u64, + rirb_base_phys: usize, + rirb_rp: u16, + rirb_count: usize, +} + +impl Rirb { + + pub fn new(regs_addr:usize, rirb_buff_phys:usize, rirb_buff_virt:usize) -> Rirb { + + unsafe { + Rirb { + regs: &mut *(regs_addr as *mut RirbRegs), + rirb_base: (rirb_buff_virt) as *mut u64, + rirb_rp: 0, + rirb_base_phys: rirb_buff_phys, + rirb_count: 0, + } + } + } + //Intel 4.4.1.3 + pub fn init(&mut self) { + self.stop(); + + + let rirbsize_reg = self.regs.rirbsize.read(); + let rirbszcap = (rirbsize_reg >> 4) & 0xF; + + let mut rirbsize_bytes: usize = 0; + let mut rirbsize: u8 = 0; + + if (rirbszcap & 4) == 4 { + rirbsize = 2; + rirbsize_bytes = 2048; + + self.rirb_count = 256; + } else if (rirbszcap & 2) == 2 { + rirbsize = 1; + rirbsize_bytes = 128; + + self.rirb_count = 8; + } else if (rirbszcap & 1) == 1 { + rirbsize = 0; + rirbsize_bytes = 16; + + self.rirb_count = 2; + } + + assert!(self.rirb_count != 0); + + let addr = self.rirb_base_phys; + self.set_address(addr); + + self.reset_write_pointer(); + self.rirb_rp = 0; + + self.regs.rintcnt.write(1); + + } + + pub fn start(&mut self) { + self.regs.rirbctl.writef(RIRBDMAEN | RINTCTL,true); + } + + pub fn stop(&mut self) { + let mut val = self.regs.rirbctl.read(); + val &= !(RIRBDMAEN); + self.regs.rirbctl.write(val); + } + + + pub fn set_address(&mut self, addr: usize) { + self.regs.rirblbase.write((addr & 0xFFFFFFFF) as u32); + self.regs.rirbubase.write((addr >> 32) as u32); + } + + pub fn reset_write_pointer(&mut self) { + self.regs.rirbwp.writef(RIRBWPRST, true); + } + + fn read_response(&mut self) -> u64 { + // wait for response + while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) {} + let mut read_pos: u16 = (self.rirb_rp + 1) % self.rirb_count as u16; + + let mut res: u64; + unsafe { + res = *self.rirb_base.offset(read_pos as isize); + } + self.rirb_rp = read_pos; + print!("Rirb: {:08X}\n", res); + res + + } + +} + + +struct ImmediateCommandRegs { + icoi: Mmio, + irii: Mmio, + ics: Mmio, + rsvd7: [Mmio; 6], +} + +pub struct ImmediateCommand { + regs: &'static mut ImmediateCommandRegs, + +} + +impl ImmediateCommand { + + pub fn new(regs_addr:usize) -> ImmediateCommand { + + unsafe { + ImmediateCommand { + regs: &mut *(regs_addr as *mut ImmediateCommandRegs), + } + } + } + + pub fn cmd(&mut self, cmd:u32) -> u64 { + + // wait for ready + while self.regs.ics.readf(ICB) {} + + // write command + self.regs.icoi.write(cmd); + + + // set ICB bit to send command + self.regs.ics.writef(ICB, true); + + + // wait for IRV bit to be set to indicate a response is latched + while !self.regs.ics.readf(IRV) {} + + // read the result register twice, total of 8 bytes + // highest 4 will most likely be zeros (so I've heard) + let mut res:u64 = self.regs.irii.read() as u64; + res |= (self.regs.irii.read() as u64) << 32; + + + // clear the bit so we know when the next response comes + self.regs.ics.writef(IRV, false); + + res + + + } + +} + +pub struct CommandBuffer { + + // regs: &'static mut CommandBufferRegs, + + corb: Corb, + rirb: Rirb, + icmd: ImmediateCommand, + + corb_rirb_base_phys: usize, + + use_immediate_cmd: bool, +} + + + + +impl CommandBuffer { + pub fn new(regs_addr:usize, cmd_buff_frame_phys:usize, cmd_buff_frame:usize ) -> CommandBuffer { + + let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff_frame_phys, cmd_buff_frame); + let rirb = Rirb::new(regs_addr + RIRB_OFFSET, + cmd_buff_frame_phys + CORB_BUFF_MAX_SIZE, + cmd_buff_frame + CORB_BUFF_MAX_SIZE); + + let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET); + + let cmdbuff = CommandBuffer { + corb: corb, + rirb: rirb, + icmd: icmd, + + corb_rirb_base_phys: cmd_buff_frame_phys, + + use_immediate_cmd: false, + }; + + cmdbuff + } + + pub fn init(&mut self, use_imm_cmds: bool) { + self.corb.init(); + self.rirb.init(); + self.set_use_imm_cmds(use_imm_cmds); + + } + + pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> u64 { + let mut ncmd: u32 = 0; + + ncmd |= (addr.0 as u32 & 0x00F) << 28; + ncmd |= (addr.1 as u32 & 0x0FF) << 20; + ncmd |= (command & 0xFFF) << 8; + ncmd |= (data as u32 & 0x0FF) << 0; + self.cmd(ncmd) + + } + pub fn cmd4(&mut self, addr: WidgetAddr, command: u32, data: u16) -> u64 { + let mut ncmd: u32 = 0; + + ncmd |= (addr.0 as u32 & 0x000F) << 28; + ncmd |= (addr.1 as u32 & 0x00FF) << 20; + ncmd |= (command & 0x000F) << 16; + ncmd |= (data as u32 & 0xFFFF) << 0; + self.cmd(ncmd) + } + + pub fn cmd(&mut self, cmd:u32) -> u64 { + if self.use_immediate_cmd { + self.cmd_imm(cmd) + } else { + self.cmd_buff(cmd) + } + } + + pub fn cmd_imm(&mut self, cmd:u32) -> u64{ + self.icmd.cmd(cmd) + } + + pub fn cmd_buff(&mut self, cmd:u32) -> u64{ + self.corb.send_command(cmd); + self.rirb.read_response() + } + + pub fn set_use_imm_cmds(&mut self, use_imm: bool) { + self.use_immediate_cmd = use_imm; + + if self.use_immediate_cmd { + self.corb.stop(); + self.rirb.stop(); + } else { + self.corb.start(); + self.rirb.start(); + } + + } + + +} + diff --git a/ihdad/src/HDA/common.rs b/ihdad/src/HDA/common.rs index 7a28902dfa..67a35350a0 100644 --- a/ihdad/src/HDA/common.rs +++ b/ihdad/src/HDA/common.rs @@ -1,9 +1,20 @@ use std::{mem, thread, ptr, fmt}; - +use std::mem::transmute; pub type HDANodeAddr = u16; -pub type HDACodecAddr = u16; +pub type HDACodecAddr = u8; + +pub type NodeAddr = u16; +pub type CodecAddr = u8; + +pub type WidgetAddr = (CodecAddr, NodeAddr); +/* +impl fmt::Display for WidgetAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:01X}:{:02X}\n", self.0, self.1) + } +}*/ #[derive(Debug, PartialEq)] #[repr(u8)] @@ -28,9 +39,9 @@ impl fmt::Display for HDAWidgetType { } -#[derive(Debug)] +#[derive(Debug, PartialEq)] #[repr(u8)] -pub enum HDADefaultDevice { +pub enum DefaultDevice { LineOut = 0x0, Speaker = 0x1, HPOut = 0x2, @@ -49,3 +60,134 @@ pub enum HDADefaultDevice { Other = 0xF, } +#[derive(Debug)] +#[repr(u8)] +pub enum PortConnectivity { + ConnectedToJack = 0x0, + NoPhysicalConnection = 0x1, + FixedFunction = 0x2, + JackAndInternal = 0x3, +} + +#[derive(Debug)] +#[repr(u8)] +pub enum GrossLocation { + ExternalOnPrimary = 0x0, + Internal = 0x1, + SeperateChasis = 0x2, + Other = 0x3, +} + +#[derive(Debug)] +#[repr(u8)] +pub enum GeometricLocation { + NA = 0x0, + Rear = 0x1, + Front = 0x2, + Left = 0x3, + Right = 0x4, + Top = 0x5, + Bottom = 0x6, + Special1 = 0x7, + Special2 = 0x8, + Special3 = 0x9, + Resvd1 = 0xA, + Resvd2 = 0xB, + Resvd3 = 0xC, + Resvd4 = 0xD, + Resvd5 = 0xE, + Resvd6 = 0xF, +} + +#[derive(Debug)] +#[repr(u8)] +pub enum Color{ + Unknown = 0x0, + Black = 0x1, + Grey = 0x2, + Blue = 0x3, + Green = 0x4, + Red = 0x5, + Orange = 0x6, + Yellow = 0x7, + Purple = 0x8, + Pink = 0x9, + Resvd1 = 0xA, + Resvd2 = 0xB, + Resvd3 = 0xC, + Resvd4 = 0xD, + White = 0xE, + Other = 0xF, +} + +pub struct ConfigurationDefault { + value: u32, +} + +impl ConfigurationDefault { + pub fn from_u32(value:u32) -> ConfigurationDefault { + ConfigurationDefault { + value: value, + } + } + + pub fn color(&self) -> Color { + unsafe {transmute(((self.value >> 12) & 0xF) as u8)} + } + + pub fn default_device(&self) -> DefaultDevice { + unsafe {transmute(((self.value >> 20) & 0xF) as u8)} + } + + pub fn port_connectivity(&self) -> PortConnectivity { + unsafe {transmute(((self.value >> 30) & 0x3) as u8)} + } + + pub fn gross_location(&self) -> GrossLocation { + unsafe {transmute(((self.value >> 28) & 0x3) as u8)} + } + + pub fn geometric_location(&self) -> GeometricLocation { + unsafe {transmute(((self.value >> 24) & 0x7) as u8)} + } + + pub fn is_output(&self) -> bool { + match self.default_device() { + DefaultDevice::LineOut | + DefaultDevice::Speaker | + DefaultDevice::HPOut | + DefaultDevice::CD | + DefaultDevice::SPDIF | + DefaultDevice::DigitalOtherOut | + DefaultDevice::ModemLineSide => true, + _ => false, + } + } + + pub fn is_input(&self) -> bool { + match self.default_device() { + DefaultDevice::ModemHandsetSide | + DefaultDevice::LineIn | + DefaultDevice::AUX | + DefaultDevice::MicIn | + DefaultDevice::Telephony | + DefaultDevice::SPDIFIn | + DefaultDevice::DigitalOtherIn => true, + _ => false, + } + } + + pub fn sequence(&self) -> u8 { + (self.value & 0xF) as u8 + } + + pub fn default_association(&self) -> u8 { + ((self.value >> 4) & 0xF) as u8 + } +} + +impl fmt::Display for ConfigurationDefault { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?} {:?} {:?} {:?}", self.default_device(), self.color(), self.gross_location(), self.geometric_location()) + } +} \ No newline at end of file diff --git a/ihdad/src/HDA/device.rs b/ihdad/src/HDA/device.rs index f136e91b1e..3a35d0ff70 100755 --- a/ihdad/src/HDA/device.rs +++ b/ihdad/src/HDA/device.rs @@ -1,27 +1,34 @@ -use std::{mem, thread, ptr, fmt}; -use std::cmp::{max, min}; +#![allow(dead_code)] -use syscall::MAP_WRITE; -use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; -use syscall::flag::O_NONBLOCK; -use syscall::io::{Dma, Mmio, Io, ReadOnly}; -use syscall::scheme::SchemeMut; +use std::{mem, thread, ptr, fmt}; +use std::cmp; +use std::cmp::{max, min}; +use std::ptr::copy_nonoverlapping; use std::sync::Arc; use std::cell::RefCell; - +use std::collections::HashMap; +use std::str; +use std::string::String; +use std::collections::BTreeMap; +use std::sync::atomic::{AtomicUsize, Ordering}; extern crate syscall; -use std::ptr::copy_nonoverlapping; +use syscall::MAP_WRITE; +use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; +use syscall::io::{ Mmio, Io}; +use syscall::scheme::SchemeMut; + +use spin::Mutex; use super::BufferDescriptorListEntry; use super::common::*; use super::StreamDescriptorRegs; use super::StreamBuffer; use super::BitsPerSample; - +use super::CommandBuffer; use super::HDANode; - +use super::OutputStream; // GCTL - Global Control const CRST: u32 = 1 << 0; // 1 bit @@ -60,8 +67,16 @@ const NUM_SUB_BUFFS: usize = 2; const SUB_BUFF_SIZE: usize = 0x4000; +enum Handle { + Pcmout(usize, usize, usize), // Card, index, block_ptr + Pcmin(usize, usize, usize), // Card, index, block_ptr + StrBuf(Vec,usize), +} + + #[repr(packed)] +#[allow(dead_code)] struct Regs { gcap: Mmio, vmin: Mmio, @@ -113,53 +128,54 @@ struct Regs { } pub struct IntelHDA { + + vend_prod: u32, + base: usize, regs: &'static mut Regs, - corb_rirb_base_phys: usize, + //corb_rirb_base_phys: usize, - corb_base: *mut u32, - rirb_base: *mut u64, + + cmd: CommandBuffer, - corb_count: usize, - rirb_count: usize, + codecs: Vec, - rirb_rp: u16, - - codecs: Vec, - - nodes: Vec, - output_pins: Vec, + outputs: Vec, + inputs: Vec, - input_pins: Vec, + widget_map: HashMap, - beep_addr: HDANodeAddr, + output_pins: Vec, + input_pins: Vec, + + beep_addr: WidgetAddr, buff_desc: &'static mut [BufferDescriptorListEntry; 256], buff_desc_phys: usize, - output_buff: usize, - output_buff_phys: usize, - output_buff_length: usize, - output_buff_wp: usize, - output_current_block: usize, + output_streams: Vec, buffs: Vec>, int_counter: usize, + handles: Mutex>, + next_id: AtomicUsize, } impl IntelHDA { - pub unsafe fn new(base: usize) -> Result { + pub unsafe fn new(base: usize, vend_prod:u32) -> Result { let regs = &mut *(base as *mut Regs); + + let buff_desc_phys = unsafe { syscall::physalloc(0x1000) .expect("Could not allocate physical memory for buffer descriptor list.") @@ -170,79 +186,83 @@ impl IntelHDA { syscall::physmap(buff_desc_phys, 0x1000, MAP_WRITE) .expect("ihdad: failed to map address for buffer descriptor list.") }; + + print!("Virt: {:016X}, Phys: {:016X}\n", buff_desc_virt, buff_desc_phys); let buff_desc = &mut *(buff_desc_virt as *mut [BufferDescriptorListEntry;256]); - let output_length = 0x8000; - let output_phys = unsafe { - syscall::physalloc(output_length) - .expect("Could not allocate physical memory for buffer descriptor list.") + let cmd_buff_address = unsafe { + syscall::physalloc(0x1000) + .expect("Could not allocate physical memory for CORB and RIRB.") }; - let output_virt = unsafe { - syscall::physmap(output_phys, output_length, MAP_WRITE) - .expect("ihdad: failed to map address for buffer descriptor list.") - }; + let cmd_buff_virt = unsafe { syscall::physmap(cmd_buff_address, 0x1000, MAP_WRITE).expect("ihdad: failed to map address for CORB/RIRB buff") }; - + print!("Virt: {:016X}, Phys: {:016X}\n", cmd_buff_virt, cmd_buff_address); let mut module = IntelHDA { + vend_prod: vend_prod, base: base, regs: regs, - corb_base: ptr::null_mut(), - rirb_base: ptr::null_mut(), - corb_rirb_base_phys: 0, - - corb_count: 0, - rirb_count: 0, - rirb_rp: 0, - - beep_addr: 0, - codecs: Vec::::new(), - nodes: Vec::::new(), + cmd: CommandBuffer::new(base + COMMAND_BUFFER_OFFSET, cmd_buff_address, cmd_buff_virt), + + beep_addr: (0,0), - output_pins: Vec::::new(), - input_pins: Vec::::new(), + widget_map: HashMap::::new(), + + + codecs: Vec::::new(), + + outputs: Vec::::new(), + inputs: Vec::::new(), + + output_pins: Vec::::new(), + input_pins: Vec::::new(), buff_desc: buff_desc, buff_desc_phys: buff_desc_phys, - output_buff: output_virt, - output_buff_phys: output_phys, - output_buff_length: output_length, - output_buff_wp: 0, - output_current_block: 0, + + + output_streams: Vec::::new(), + buffs: Vec::>::new(), int_counter: 0, + handles: Mutex::new(BTreeMap::new()), + next_id: AtomicUsize::new(0), }; + module.init(); - //module.info(); + + // module.info(); module.enumerate(); - module.vbox_speaker_test(); + + module.configure(); print!("IHDA: Initialization finished.\n"); Ok(module) } pub fn init(&mut self) -> bool { - self.reset_controller(); - self.init_corb_and_rirb(); + let use_immediate_command_interface = match self.vend_prod { + + 0x8086_2668 => false, + _ => true, + }; + + self.cmd.init(use_immediate_command_interface); self.init_interrupts(); - //print!("Command 0xF0000: {:016X}\n", self.read_response()); - //print!("Command 0xF0004: {:016X}\n", self.send_immediate_command(0xF0004)); - true - } pub fn init_interrupts(&mut self) { @@ -250,10 +270,7 @@ impl IntelHDA { // This just enables the first output stream interupt and the global interrupt // TODO: No magic numbers! Bad Schemm. - self.regs.intctl.write((1 << 31) | (1 << 30) | (1 << 4)); - - - + self.regs.intctl.write((1 << 31) | /* (1 << 30) |*/ (1 << 4)); } @@ -271,52 +288,44 @@ impl IntelHDA { self.int_counter } - pub fn read_node(&mut self, addr: HDANodeAddr) -> HDANode { + pub fn read_node(&mut self, addr: WidgetAddr) -> HDANode { let mut node = HDANode::new(); let mut temp:u64; node.addr = addr; - - self.send_command(Self::node_command(0x00, addr, 0xF00, 0x04)); - temp = self.read_response(); + + temp = self.cmd.cmd12( addr, 0xF00, 0x04); node.subnode_count = (temp & 0xff) as u16; node.subnode_start = ((temp >> 16) & 0xff) as u16; - self.send_command(Self::node_command(0x00, addr, 0xF00, 0x05)); - temp = self.read_response(); + if addr == (0,0) { + return node; + } + temp = self.cmd.cmd12(addr, 0xF00, 0x04); node.function_group_type = (temp & 0xff) as u8; - self.send_command(Self::node_command(0x00, addr, 0xF00, 0x09)); - temp = self.read_response(); - + temp = self.cmd.cmd12(addr, 0xF00, 0x09); node.capabilities = temp as u32; - self.send_command(Self::node_command(0x00, addr, 0xF00, 0x09)); - temp = self.read_response(); + temp = self.cmd.cmd12(addr, 0xF00, 0x0E); - node.capabilities = temp as u32; - - self.send_command(Self::node_command(0x00, addr, 0xF00, 0x0E)); - temp = self.read_response(); - node.conn_list_len = (temp & 0xFF) as u8; node.connections = self.node_get_connection_list(&node); - - self.send_command(Self::node_command(0x00, addr, 0xF1C, 0x00)); - node.config_default = self.read_response() as u32; + + node.config_default = self.cmd.cmd12(addr, 0xF1C, 0x00) as u32; + node } - pub fn node_get_connection_list(&mut self, node: &HDANode) -> Vec { - // get list length - self.send_command(Self::node_command(0x00, node.addr, 0xF00, 0x0E)); - let len_field: u8 = (self.read_response() & 0xFF) as u8; + pub fn node_get_connection_list(&mut self, node: &HDANode) -> Vec { + + let len_field: u8 = (self.cmd.cmd12(node.addr, 0xF00, 0x0E) & 0xFF) as u8; // Highest bit is if addresses are represented in longer notation // lower 7 is actual count @@ -326,11 +335,11 @@ impl IntelHDA { let mut current: u8 = 0; - let mut list = Vec::::new(); + let mut list = Vec::::new(); while current < count { - self.send_command(Self::node_command(0x00, node.addr, 0xF02, current as u32)); - let response: u32 = (self.read_response() & 0xFFFFFFFF) as u32; + + let response: u32 = (self.cmd.cmd12(node.addr, 0xF02, current) & 0xFFFFFFFF) as u32; if use_long_addr { for i in 0..2 { @@ -340,11 +349,11 @@ impl IntelHDA { if addr == 0 { break; } if (addr_field >> 15) & 0x1 == 0x1 { - for i in (list.pop().unwrap() .. (addr + 1)) { - list.push(i); + for i in (list.pop().unwrap().1 .. (addr + 1)) { + list.push((node.addr.0, i)); } } else { - list.push(addr); + list.push((node.addr.0, addr)); } } @@ -357,11 +366,11 @@ impl IntelHDA { if addr == 0 { break; } if (addr_field >> 7) & 0x1 == 0x1 { - for i in (list.pop().unwrap() .. (addr + 1)) { - list.push(i); + for i in (list.pop().unwrap().1 .. (addr + 1)) { + list.push((node.addr.0, i)); } } else { - list.push(addr); + list.push((node.addr.0, addr)); } } @@ -375,75 +384,112 @@ impl IntelHDA { } pub fn enumerate(&mut self) { - self.nodes.clear(); + self.output_pins.clear(); self.input_pins.clear(); + + let codec:u8 = 0; - let root = self.read_node(0); + let root = self.read_node((codec,0)); // print!("{}\n", root); let root_count = root.subnode_count; let root_start = root.subnode_start; - self.nodes.push(root); //FIXME: So basically the way this is set up is to only support one codec and hopes the first one is an audio for i in 0..root_count { - let afg = self.read_node((root_start + i) as HDANodeAddr); + let afg = self.read_node((codec, root_start + i)); // print!("{}\n", afg); let afg_count = afg.subnode_count; let afg_start = afg.subnode_start; - self.nodes.push(afg); for j in 0..afg_count { - let mut widget = self.read_node((afg_start + j) as HDANodeAddr); + + let mut widget = self.read_node((codec, afg_start + j)); widget.is_widget = true; match widget.widget_type() { - HDAWidgetType::AudioOutput => {self.output_pins.push(widget.addr)}, - HDAWidgetType::AudioInput => {self.input_pins.push(widget.addr)}, + HDAWidgetType::AudioOutput => {self.outputs.push(widget.addr)}, + HDAWidgetType::AudioInput => {self.inputs.push(widget.addr)}, HDAWidgetType::BeepGenerator => {self.beep_addr = widget.addr }, + HDAWidgetType::PinComplex => { + let config = widget.configuration_default(); + if config.is_output() { + self.output_pins.push(widget.addr); + } else if (config.is_input()) { + self.input_pins.push(widget.addr); + } + + + print!("{:02X}{:02X} {}\n", widget.addr().0, widget.addr().1, config); + + }, _ => {}, } - // print!("{}\n", widget); - self.nodes.push(widget); + + print!("{}\n", widget); + self.widget_map.insert(widget.addr(), widget); } } } - pub fn get_node(&self, addr: HDANodeAddr) -> Option<&HDANode> { - - for ref node in &self.nodes { - if node.addr == addr { - return Some(node); + + + + pub fn find_best_output_pin(&self) -> Option{ + let outs = &self.output_pins; + if outs.len() == 0 { + None + } else if outs.len() == 1 { + Some(outs[0]) + } else { + // TODO: Somehow find the best. + // Slightly okay is find the speaker with the lowest sequence number. + + for &out in outs { + let widget = self.widget_map.get(&out).unwrap(); + + let cd = widget.configuration_default(); + if cd.sequence() == 0 && cd.default_device() == DefaultDevice::Speaker { + return Some(out); + } } - + + None } - None } - pub fn find_shortest_path_to_speaker(&mut self) -> Vec { - let mut path = Vec::::new(); - - for addr in &self.output_pins { - //let node = self.get_node().unwrap(); - + + + + pub fn find_path_to_dac(&self, addr: WidgetAddr) -> Option>{ + let widget = self.widget_map.get(&addr).unwrap(); + if widget.widget_type() == HDAWidgetType::AudioOutput { + return Some(vec![addr]); + }else{ + if widget.connections.len() == 0 { + return None; + }else{ + // TODO: do more than just first widget + + let mut res = self.find_path_to_dac(widget.connections[0]); + match res { + Some(p) => { + let mut ret = p.clone(); + ret.insert(0, addr); + Some(ret) + }, + None => {None}, + } + } } - - path - } + } - pub fn create_sound_buffers(&mut self) { - - self.buffs.push(Vec::::new()); - // self.buffs[0].push(StreamBuffer::new(0x4000).unwrap()); - // self.buffs[0].push(StreamBuffer::new(0x4000).unwrap()); - - - } - + + /* Here we update the buffers and split them into 128 byte sub chunks because each BufferDescriptorList needs to be 128 byte aligned, @@ -452,7 +498,11 @@ impl IntelHDA { /* Vec of a Vec was doing something weird and causing the driver to hang. So now we have a set of variables instead. + + + Fixed? */ + pub fn update_sound_buffers(&mut self) { /* for i in 0..self.buffs.len(){ @@ -462,144 +512,162 @@ impl IntelHDA { self.buff_desc[i * 128/16 + j].set_interrupt_on_complete(true); } }*/ - - self.buff_desc[0].set_address(self.output_buff_phys); - self.buff_desc[0].set_length((self.output_buff_length/2) as u32); - self.buff_desc[0].set_interrupt_on_complete(true); - self.buff_desc[1].set_address(self.output_buff_phys + self.output_buff_length/2); - self.buff_desc[1].set_length((self.output_buff_length/2) as u32); + let r = self.get_output_stream_descriptor(0).unwrap(); + + + self.output_streams.push(OutputStream::new(2, 0x4000, r)); + + let o = self.output_streams.get_mut(0).unwrap(); + + + self.buff_desc[0].set_address(o.phys()); + self.buff_desc[0].set_length(o.block_size() as u32); + self.buff_desc[0].set_interrupt_on_complete(true); + + + self.buff_desc[1].set_address(o.phys() + o.block_size()); + self.buff_desc[1].set_length(o.block_size() as u32); self.buff_desc[1].set_interrupt_on_complete(true); - } - /* - For testing in VBOX: - Create Ramp wave of 400hz to test the output of - the speakers to see sound can be played - */ - - pub fn test_buff_fill(&mut self) { - let n_samples = self.output_buff_length / (2 * 2); - let buf_ptr = unsafe { self.output_buff as * mut u16}; - - let freq:u16 = 440; - - let period:u16 = 44100 / 440; - - let step:u16 = 65535 / period; - - let mut j:u16 = 0; - let mut val:u16 = 0; - - for i in 0..n_samples { - unsafe { - *buf_ptr.offset((2*i) as isize) = val; - *buf_ptr.offset((2*i+1) as isize) = val; - } - val += step; - j += 1; - - if j >= period { - j = 0; - val = 0; - } - - } - print!("IHDA: Test buffer created.\n"); - } - pub fn vbox_speaker_test(&mut self) { - + pub fn configure(&mut self) { + let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); + + //print!("Best pin: {:01X}:{:02X}\n", outpin.0, outpin.1); + let path = self.find_path_to_dac(outpin).unwrap(); + + let dac = *path.last().unwrap(); + let pin = *path.first().unwrap(); + + //print!("Path to DAC: {:?}\n", path); // Pin enable - self.send_command(Self::node_command(0x00, 0xC, 0x707, 0x40)); - let mut response: u32 = (self.read_response() & 0xFFFFFFFF) as u32; - + self.cmd.cmd12(pin, 0x707, 0x40); + // EAPD enable - self.send_command(Self::node_command(0x00, 0xC, 0x70C, 2)); - response = (self.read_response() & 0xFFFFFFFF) as u32; + self.cmd.cmd12(pin, 0x70C, 2); + self.set_stream_channel(dac, 1, 0); - self.set_stream_channel(0x3, 1, 0); - - // self.create_sound_buffers(); self.update_sound_buffers(); - print!("Supported Formats: {:08X}\n", self.get_supported_formats(0x1)); - print!("Capabilities: {:08X}\n", self.get_capabilities(0x3)); + //print!("Supported Formats: {:08X}\n", self.get_supported_formats((0,0x1))); + //print!("Capabilities: {:08X}\n", self.get_capabilities(path[0])); + + let output = self.get_output_stream_descriptor(0).unwrap(); + + + + output.set_address(self.buff_desc_phys); + + + output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); + output.set_cyclic_buffer_length(0x8000); // number of bytes + output.set_stream_number(1); + output.set_last_valid_index(1); + output.set_interrupt_on_completion(true); + + + self.set_power_state(dac, 0); // Power state 0 is fully on + self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2); + + + self.cmd.cmd12(dac, 0xA00, 0); + + // Unmute and set gain for pin complex and DAC + self.set_amplifier_gain_mute(dac, true, true, true, true, 0, false, 0x7f); + self.set_amplifier_gain_mute(pin, true, true, true, true, 0, false, 0x7f); + + output.run(); + + } + /* + + pub fn configure_vbox(&mut self) { + + let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); + + print!("Best pin: {:01X}:{:02X}\n", outpin.0, outpin.1); + + let path = self.find_path_to_dac(outpin).unwrap(); + print!("Path to DAC: {:?}\n", path); + + // Pin enable + self.cmd.cmd12((0,0xC), 0x707, 0x40); + + + // EAPD enable + self.cmd.cmd12((0,0xC), 0x70C, 2); + + self.set_stream_channel((0,0x3), 1, 0); + + self.update_sound_buffers(); + + + print!("Supported Formats: {:08X}\n", self.get_supported_formats((0,0x1))); + print!("Capabilities: {:08X}\n", self.get_capabilities((0,0x1))); let output = self.get_output_stream_descriptor(0).unwrap(); output.set_address(self.buff_desc_phys); output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); - output.set_cyclic_buffer_length(0x8000); // number of samples + output.set_cyclic_buffer_length(0x8000); output.set_stream_number(1); output.set_last_valid_index(1); output.set_interrupt_on_completion(true); - self.set_power_state(0x3, 0); // Power state 0 is fully on - self.set_converter_format(0x3, &super::SR_44_1, BitsPerSample::Bits16, 2); + self.set_power_state((0,0x3), 0); // Power state 0 is fully on + self.set_converter_format((0,0x3), &super::SR_44_1, BitsPerSample::Bits16, 2); - self.send_command(Self::node_command(0x00, 0x3, 0xA00, 0)); - response = (self.read_response() & 0xFFFFFFFF) as u32; - print!("Format: {:04X}\n",response); + self.cmd.cmd12((0,0x3), 0xA00, 0); // Unmute and set gain for pin complex and DAC - self.set_amplifier_gain_mute(0x3, true, true, true, true, 0, false, 0x7f); - self.set_amplifier_gain_mute(0xC, true, true, true, true, 0, false, 0x7f); - - - - - // self.test_buff_fill(); + self.set_amplifier_gain_mute((0,0x3), true, true, true, true, 0, false, 0x7f); + self.set_amplifier_gain_mute((0,0xC), true, true, true, true, 0, false, 0x7f); output.run(); - print!("IHDA: Beep? \n"); self.beep(1); } - + + */ // BEEP!! pub fn beep(&mut self, div:u8) { let addr = self.beep_addr; - if addr != 0 { + if addr != (0,0) { + + let _ = self.cmd.cmd12(addr, 0xF0A, div); - self.send_command(Self::node_command(0x00, addr, 0xF0A, div as u32)); - let response = (self.read_response() & 0xFFFFFFFF) as u32; } } pub fn read_beep(&mut self) -> u8 { let addr = self.beep_addr; - if addr != 0 { - self.send_command(Self::node_command(0x00, addr, 0x70A, 0)); - (self.read_response() & 0xFF) as u8 + if addr != (0,0) { + + self.cmd.cmd12(addr, 0x70A, 0) as u8 }else{ 0 } } - pub fn enable_pin(&self, node: &HDANode) { - - - } - pub fn reset_controller(&mut self) -> bool { self.regs.statests.write(0xFFFF); @@ -626,11 +694,11 @@ impl IntelHDA { } let statests = self.regs.statests.read(); - + print!("Statests: {:04X}\n", statests); for i in 0..15 { if (statests >> i) & 0x1 == 1 { - self.codecs.push(i as HDANodeAddr); + self.codecs.push(i as CodecAddr); } } true @@ -666,289 +734,9 @@ impl IntelHDA { print!("IHDA: 64-Bit: {}\n", self.regs.gcap.read() & 1 == 1); } - pub fn node_command(codec_address: u32, node_index: HDANodeAddr, command: u32, data: u32) -> u32{ - let mut ncmd: u32 = 0; - let node_addr = node_index as u32; - - ncmd |= (codec_address & 0x00F) << 28; - ncmd |= (node_addr & 0x0FF) << 20; - ncmd |= (command & 0xFFF) << 8; - ncmd |= (data & 0x0FF) << 0; - ncmd - } - - - pub fn corb_start(&mut self) { - self.regs.corbctl.writef(CORBRUN,true); - } - - pub fn rirb_start(&mut self) { - self.regs.rirbctl.writef(RIRBDMAEN | RINTCTL,true); - } - - pub fn corb_stop(&mut self) { - - while self.regs.corbctl.readf(CORBRUN) { self.regs.corbctl.write(0); } - } - - pub fn rirb_stop(&mut self) { - let mut val = self.regs.rirbctl.read(); - val &= !(RIRBDMAEN); - self.regs.rirbctl.write(val); - } - - //Intel 4.4.1.3 - - pub fn init_corb_and_rirb(&mut self) -> Result<()> { - - - self.corb_stop(); - self.rirb_stop(); - - - //Determine CORB and RIRB size and allocate buffer - - - //3.3.24 - let corbsize_reg = self.regs.corbsize.read(); - let corbszcap = (corbsize_reg >> 4) & 0xF; - - let mut corbsize_bytes: usize = 0; - let mut corbsize: u8 = 0; - - if (corbszcap & 4) == 4 { - corbsize = 2; - corbsize_bytes = 1024; - - self.corb_count = 256; - } else if (corbszcap & 2) == 2 { - corbsize = 1; - corbsize_bytes = 64; - - self.corb_count = 16; - } else if (corbszcap & 1) == 1 { - corbsize = 0; - corbsize_bytes = 8; - - self.corb_count = 2; - } else { - //TODO: Error! - } - - //3.3.31 - - let rirbsize_reg = self.regs.rirbsize.read(); - let rirbszcap = (rirbsize_reg >> 4) & 0xF; - - let mut rirbsize_bytes: usize = 0; - let mut rirbsize: u8 = 0; - - if (rirbszcap & 4) == 4 { - rirbsize = 2; - rirbsize_bytes = 2048; - - self.rirb_count = 256; - } else if (rirbszcap & 2) == 2 { - rirbsize = 1; - rirbsize_bytes = 128; - - self.rirb_count = 8; - } else if (rirbszcap & 1) == 1 { - rirbsize = 0; - rirbsize_bytes = 16; - - self.rirb_count = 2; - } else { - //TODO: Error! - } - - //print!("CORB size: {} RIRB size: {}\n", corbsize_bytes, rirbsize_bytes); - - - // Allocate the physical memory, keeping in mind - // that the buffers need to be 128-byte aligned - - let buff_address = unsafe { - syscall::physalloc(max(rirbsize_bytes, 128) + max(corbsize_bytes, 128)) - .expect("Could not allocate physical memory for CORB and RIRB.") - }; - - - let virt_address = unsafe { syscall::physmap(buff_address, 0x1000, MAP_WRITE).expect("ihdad: failed to map address for CORB/RIRB buff") }; - - - self.corb_rirb_base_phys = buff_address; - - // Set the sizes and addresses of the buffers - self.regs.corbsize.write(corbsize); - - self.corb_set_address(buff_address); - - // make sure that the RIRB buffer is at least aligned to 128 bytes. - self.regs.rirbsize.write(rirbsize); - self.rirb_set_address(buff_address + max(128, corbsize_bytes)); - - - // set virtual addresses for the buffer so we can access it - - self.corb_base = (virt_address) as *mut u32; - self.rirb_base = (virt_address + max(128, corbsize_bytes)) as *mut u64; - - - //print!("IHDA State: {:04X}\n",self.regs.statests.read()); - self.regs.corbwp.write(0); - self.corb_reset_read_pointer(); - self.rirb_reset_write_pointer(); - self.rirb_rp = 0; - - self.regs.rintcnt.write(1); - - - self.corb_start(); - self.rirb_start(); - - Ok(()) - } - - fn corb_set_address(&mut self, addr: usize) { - - - - self.regs.corblbase.write((addr & 0xFFFFFFFF) as u32); - self.regs.corbubase.write((addr >> 32) as u32); - } - - fn rirb_set_address(&mut self, addr: usize) { - self.regs.rirblbase.write((addr & 0xFFFFFFFF) as u32); - self.regs.rirbubase.write((addr >> 32) as u32); - } - - fn rirb_reset_write_pointer(&mut self) { - self.regs.rirbwp.writef(RIRBWPRST, true); - - - } - - fn corb_reset_read_pointer(&mut self){ - - - /* - * FIRST ISSUE/PATCH - * This will loop forever in virtualbox - * So maybe just resetting the read pointer - * and leaving for the specific model? - */ - if true { - self.regs.corbrp.writef(CORBRPRST, true); - - } - else - { - // 3.3.21 - - self.corb_stop(); - // Set CORBRPRST to 1 - print!("CORBRP {:X}\n",self.regs.corbrp.read()); - self.regs.corbrp.writef(CORBRPRST, true); - print!("CORBRP {:X}\n",self.regs.corbrp.read()); - print!("Here!\n"); - - // Wait for it to become 1 - while ! self.regs.corbrp.readf(CORBRPRST) { - self.regs.corbrp.writef(CORBRPRST, true); - } - print!("Here!!\n"); - // Clear the bit again - self.regs.corbrp.write(0); - - // Read back the bit until zero to verify that it is cleared. - - loop { - - if !self.regs.corbrp.readf(CORBRPRST) { - break; - } - self.regs.corbrp.write(0); - } - } - } - - - fn send_command(&mut self, cmd: u32) { - - // wait for the commands to finish - while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {} - - let mut write_pos: usize = ( (self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count; - - unsafe { - *self.corb_base.offset(write_pos as isize) = cmd; - } - - self.regs.corbwp.write(write_pos as u16); - - - - } - - fn read_response(&mut self) -> u64 { - - // wait for response - while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) {} - - let mut read_pos: u16 = (self.rirb_rp + 1) % self.rirb_count as u16; - - let mut res: u64; - unsafe { - res = *self.rirb_base.offset(read_pos as isize); - } - - self.rirb_rp = read_pos; - - res - - } - - - // FIXME: Apparently vbox is picky about sending immediate commands. - // Hopefully this can be disregarded if the DMA works. - - - - fn send_immediate_command(&mut self, cmd: u32) -> u64 { - print!("Status: {:04X}\n",self.regs.ics.read()); - - // wait for ready - while self.regs.ics.readf(ICB) {} - - // write command - self.regs.icoi.write(cmd); - - - // set ICB bit to send command - self.regs.ics.writef(ICB, true); - - print!("Status: {:04X}\n",self.regs.ics.read()); - - // wait for IRV bit to be set to indicate a response is latched - while !self.regs.ics.readf(IRV) {} - - // read the result register twice, total of 8 bytes - // highest 4 will most likely be zeros (so I've heard) - let mut res:u64 = self.regs.irii.read() as u64; - res |= (self.regs.irii.read() as u64) << 32; - - - // clear the bit so we know when the next response comes - self.regs.ics.writef(IRV, false); - - res - - } - - fn get_input_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { + fn get_input_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { unsafe { if index < self.num_input_streams() { Some(&mut *((self.base + 0x80 + index * 0x20) as *mut StreamDescriptorRegs)) @@ -991,38 +779,31 @@ impl IntelHDA { } - fn set_stream_channel(&mut self, addr: HDANodeAddr, stream: u8, channel:u8) { + fn set_stream_channel(&mut self, addr: WidgetAddr, stream: u8, channel:u8) { let val = ((stream & 0xF) << 4) | (channel & 0xF); - self.send_command(Self::node_command(0x00, addr, 0x706, val as u32)); - let temp = self.read_response(); + self.cmd.cmd12(addr, 0x706, val); } - fn set_power_state(&mut self, addr:HDANodeAddr, state:u8) { - self.send_command(Self::node_command(0x00, addr, 0x705, state as u32 & 0xF)); - let temp = self.read_response(); + fn set_power_state(&mut self, addr:WidgetAddr, state:u8) { + self.cmd.cmd12(addr, 0x705, state & 0xF) as u32; } - fn get_supported_formats(&mut self, addr: HDANodeAddr) -> u32 { - self.send_command(Self::node_command(0x00, addr, 0xF00, 0x0A)); - self.read_response() as u32 + fn get_supported_formats(&mut self, addr: WidgetAddr) -> u32 { + self.cmd.cmd12(addr, 0xF00, 0x0A) as u32 } - fn get_capabilities(&mut self, addr: HDANodeAddr) -> u32 { - self.send_command(Self::node_command(0x00, addr, 0xF00, 0x09)); - self.read_response() as u32 + fn get_capabilities(&mut self, addr: WidgetAddr) -> u32 { + self.cmd.cmd12(addr, 0xF00, 0x09) as u32 } - fn set_converter_format(&mut self, addr:HDANodeAddr, sr: &super::SampleRate, bps: BitsPerSample, channels:u8) { + fn set_converter_format(&mut self, addr:WidgetAddr, sr: &super::SampleRate, bps: BitsPerSample, channels:u8) { let fmt = super::format_to_u16(sr, bps, channels); - let fmt_hi = (fmt >> 8) as u32; - let fmt_lo = (fmt & 0xFF) as u32; - print!("Format: {:04X}\n",fmt); - self.send_command(Self::node_command(0x00, addr, 0x200 | fmt_hi, fmt_lo)); - let temp = self.read_response(); - + self.cmd.cmd4(addr, 0x2, fmt); } - fn set_amplifier_gain_mute(&mut self, addr:HDANodeAddr, output:bool, input:bool, left:bool, right:bool, index:u8, mute:bool, gain: u8) { + + + fn set_amplifier_gain_mute(&mut self, addr: WidgetAddr, output:bool, input:bool, left:bool, right:bool, index:u8, mute:bool, gain: u8) { let mut payload: u16 = 0; @@ -1033,83 +814,24 @@ impl IntelHDA { if mute { payload |= (1 << 7); } payload |= ((index as u16) & 0x0F) << 8; payload |= ((gain as u16) & 0x7F); - - let payload_hi = (payload >> 8); - let payload_lo = (payload & 0xFF) as u8; - self.send_command(Self::node_command(0x00, addr, 0x300 | payload_hi as u32, payload_lo as u32)); - let temp = self.read_response(); - } + self.cmd.cmd4(addr, 0x3, payload); - fn write_to_output(&mut self, out_index: usize, buf: &[u8]) -> Result { - - - // TODO: Better way of writing than just writing from the write pointer to the link position in buffer - - - - - let mut output = self.get_output_stream_descriptor(0).unwrap(); - - let sample_size:usize = output.sample_size(); - let sample_count:usize = buf.len() / sample_size; - let buff_len = output.cyclic_buffer_length() as usize; - - let mut samples_copied: usize = 0; - while samples_copied < sample_count { - - let samples_left = sample_count - samples_copied; - - // modular arithmetic to get the number of samples that we can write to - - let mut can_write = (output.link_position() as usize + buff_len) - self.output_buff_wp; - - if can_write >= buff_len { - can_write -= buff_len; - } - - let samples_to_write = min(can_write, samples_left); - let samples_until_end = buff_len - self.output_buff_wp; - - if samples_to_write > 0 { - - if samples_until_end >= samples_to_write { - unsafe { - copy_nonoverlapping(buf.as_ptr(), (self.output_buff + self.output_buff_wp * sample_size) as * mut u8, samples_to_write * sample_size); - } - - } else { - unsafe { - copy_nonoverlapping(buf.as_ptr(), (self.output_buff + self.output_buff_wp * sample_size) as * mut u8, samples_until_end * sample_size); - copy_nonoverlapping((buf.as_ptr() as usize + (samples_to_write * sample_size)) as * const u8, - (self.output_buff + self.output_buff_wp * sample_size) as * mut u8, - (samples_to_write - samples_until_end) * sample_size); - } - } - - self.output_buff_wp += samples_to_write; - if self.output_buff_wp >= buff_len { - self.output_buff_wp -= buff_len; - } - - samples_copied += samples_to_write; - } - thread::yield_now(); - } - - Ok(samples_copied * sample_size) - } + pub fn write_to_output(&mut self, index:u8, buf: &[u8]) -> Result { - - pub fn write_to_output2(&mut self, index:u8, buf: &[u8]) -> Result { + let mut output = self.get_output_stream_descriptor(index as usize).unwrap(); + let mut os = self.output_streams.get_mut(index as usize).unwrap(); + - let mut output = self.get_output_stream_descriptor(0).unwrap(); let sample_size:usize = output.sample_size(); - let mut open_block = (output.link_position() as usize) / 0x4000; + let mut open_block = (output.link_position() as usize) / os.block_size(); + + + if open_block == 0 { open_block = 1; @@ -1117,35 +839,31 @@ impl IntelHDA { open_block = open_block - 1; } + //print!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}\n", output.status(), output.link_position(), output.control()); + while open_block == os.current_block() { - while open_block == self.output_current_block { - - open_block = (output.link_position() as usize) / 0x4000; + open_block = (output.link_position() as usize) / os.block_size(); if open_block == 0 { - open_block = 1; + open_block = os.block_count() - 1; } else { open_block = open_block - 1; } - + + thread::yield_now(); } - self.output_current_block = open_block; - let len = min(0x4000, buf.len()); - - unsafe { - copy_nonoverlapping(buf.as_ptr(), (self.output_buff + self.output_current_block * 0x4000) as * mut u8, len); - } + let len = min(os.block_size(), buf.len()); - Ok(len) + os.write_block(buf) } pub fn handle_interrupts(&mut self) { let intsts = self.regs.intsts.read(); let sis = intsts & 0x3FFFFFFF; - print!("IHDA INTSTS: {:08X}\n", intsts); + // print!("IHDA INTSTS: {:08X}\n", intsts); if ((intsts >> 31) & 1) == 1 { // Global Interrupt Status if ((intsts >> 30) & 1) == 1 { // Controller Interrupt Status self.handle_controller_interrupt(); @@ -1158,73 +876,120 @@ impl IntelHDA { } pub fn handle_controller_interrupt(&mut self) { - + } pub fn handle_stream_interrupts(&mut self, sis: u32) { let oss = self.num_output_streams(); let iss = self.num_input_streams(); let bss = self.num_bidirectional_streams(); - - - let sample_size = 4; // TODO: create method to get sample size for i in 0..iss { if ((sis >> i) & 1 ) == 1 { - - + let mut input = self.get_input_stream_descriptor(i).unwrap(); + input.clear_interrupts(); } } for i in 0..oss { if ((sis >> (i + iss)) & 1 ) == 1 { - let mut output = self.get_output_stream_descriptor(i).unwrap(); - // TODO: No magic numbers! - let mut temp = output.link_position() as usize / 0x4000; - - if temp == 0 { - temp = self.output_buff_length - 0x4000; - } else { - temp = temp - 0x4000; - } - self.output_current_block = temp; output.clear_interrupts(); } } for i in 0..bss { if ((sis >> (i + iss + oss)) & 1 ) == 1 { - - + let mut bid = self.get_bidirectional_stream_descriptor(i).unwrap(); + bid.clear_interrupts(); } } } + fn validate_path(&mut self, path: &Vec<&str>) -> bool { + + print!("Path: {:?}\n", path); + let mut it = path.iter(); + match it.next() { + Some(card_str) if (*card_str).starts_with("card") => { + match usize::from_str_radix(&(*card_str)[4..], 10) { + Ok(card_num) => { + print!("Card# {}\n", card_num); + match it.next() { + Some(codec_str) if (*codec_str).starts_with("codec#") => { + match usize::from_str_radix(&(*codec_str)[6..], 10) { + Ok(codec_num) => { + + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + //self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0)); + true + + }, + _ => false, + } + }, + Some(pcmout_str) if (*pcmout_str).starts_with("pcmout") => { + match usize::from_str_radix(&(*pcmout_str)[6..], 10) { + Ok(pcmout_num) => { + print!("pcmout {}\n", pcmout_num); + true + }, + _ => false, + } + }, + Some(pcmin_str) if (*pcmin_str).starts_with("pcmin") => { + match usize::from_str_radix(&(*pcmin_str)[6..], 10) { + Ok(pcmin_num) => { + print!("pcmin {}\n", pcmin_num); + true + }, + _ => false, + } + }, + _ => false, + } + }, + _ => false, + } + }, + Some(cards_str) if *cards_str == "cards" => { + true + }, + _ => false, + } + } } impl Drop for IntelHDA { fn drop(&mut self) { - let _ = unsafe {syscall::physfree(self.buff_desc_phys, 0x1000)}; - if self.output_buff_phys != 0 { - unsafe { - let _ = syscall::physfree(self.output_buff_phys, self.output_buff_length); - } - } print!("IHDA: Deallocating IHDA driver.\n"); } - - } impl SchemeMut for IntelHDA { - fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - - // TODO: + + + fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + let path: Vec<&str>; + /* + match str::from_utf8(_path) { + Ok(p) => { + path = p.split("/").collect(); + if !self.validate_path(&path) { + return Err(Error::new(EINVAL)); + + }, + Err(_) => {return Err(Error::new(EINVAL));}, + }*/ + + + + + // TODO: if uid == 0 { Ok(flags) } else { @@ -1237,12 +1002,31 @@ impl SchemeMut for IntelHDA { //print!("Int count: {}\n", self.int_counter); - self.write_to_output2(0, buf) + self.write_to_output(0, buf) } - fn close(&mut self, _id: usize) -> Result { - // TODO: - Ok(0) + fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result { + let mut handles = self.handles.lock(); + match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::StrBuf(ref mut strbuf, ref mut size) => { + let len = strbuf.len() as usize; + *size = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + Ok(*size) + }, + + _ => Err(Error::new(EINVAL)), + } } -} + + fn close(&mut self, _id: usize) -> Result { + let mut handles = self.handles.lock(); + handles.remove(&_id).ok_or(Error::new(EBADF)).and(Ok(0)) + } + +} \ No newline at end of file diff --git a/ihdad/src/HDA/mod.rs b/ihdad/src/HDA/mod.rs index f3c06f06d0..90330ee8d6 100644 --- a/ihdad/src/HDA/mod.rs +++ b/ihdad/src/HDA/mod.rs @@ -1,14 +1,15 @@ - +#![allow(dead_code)] pub mod device; pub mod stream; pub mod common; pub mod node; - +pub mod cmdbuff; pub use self::stream::*; pub use self::node::*; +pub use self::cmdbuff::*; pub use self::stream::StreamDescriptorRegs; pub use self::stream::BufferDescriptorListEntry; pub use self::stream::BitsPerSample; diff --git a/ihdad/src/HDA/node.rs b/ihdad/src/HDA/node.rs index 86e79eaa58..edbb3727e0 100644 --- a/ihdad/src/HDA/node.rs +++ b/ihdad/src/HDA/node.rs @@ -4,7 +4,7 @@ use super::common::*; #[derive(Clone)] pub struct HDANode { - pub addr: HDANodeAddr, + pub addr: WidgetAddr, @@ -35,7 +35,7 @@ pub struct HDANode { // 0x13 pub vol_knob: u8, - pub connections: Vec, + pub connections: Vec, pub is_widget: bool, @@ -47,7 +47,7 @@ impl HDANode { pub fn new() -> HDANode { HDANode { - addr: 0, + addr: (0,0), subnode_count: 0, subnode_start: 0, function_group_type: 0, @@ -60,7 +60,7 @@ impl HDANode { config_default: 0, is_widget: false, - connections: Vec::::new(), + connections: Vec::::new(), } } @@ -69,7 +69,7 @@ impl HDANode { } - pub fn getDeviceDefault(&self) -> Option { + pub fn device_default(&self) -> Option { if self.widget_type() != HDAWidgetType::PinComplex { None } else { @@ -77,32 +77,37 @@ impl HDANode { } } - pub fn addr(&self) -> HDANodeAddr { + pub fn configuration_default(&self) -> ConfigurationDefault { + ConfigurationDefault::from_u32(self.config_default) + } + + pub fn addr(&self) -> WidgetAddr { self.addr } } impl fmt::Display for HDANode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.addr == 0 { - write!(f, "Addr: {:02X}, Root Node.", self.addr) + if self.addr == (0,0) { + write!(f, "Addr: {:02X}:{:02X}, Root Node.", self.addr.0, self.addr.1) } else if self.is_widget { match self.widget_type() { HDAWidgetType::PinComplex => { - write!(f, "Addr: {:02X}, Type: {:?}: {:?}, Inputs: {:X}: {:?}.", - self.addr, + write!(f, "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {:X}: {:?}.", + self.addr.0, + self.addr.1, self.widget_type(), - self.getDeviceDefault().unwrap(), + self.device_default().unwrap(), self.conn_list_len, self.connections) }, - _ => { write!(f, "Addr: {:02X}, Type: {:?}, Inputs: {:X}: {:?}.", self.addr, self.widget_type(), self.conn_list_len, self.connections) }, + _ => { write!(f, "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {:X}: {:?}.", self.addr.0, self.addr.1, self.widget_type(), self.conn_list_len, self.connections) }, } } else { - write!(f, "Addr: {:02X}, AFG: {}, Widget count {}.", self.addr, self.function_group_type, self.subnode_count) + write!(f, "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", self.addr.0, self.addr.1, self.function_group_type, self.subnode_count) } } } diff --git a/ihdad/src/HDA/stream.rs b/ihdad/src/HDA/stream.rs index 75034be732..c87faf8690 100644 --- a/ihdad/src/HDA/stream.rs +++ b/ihdad/src/HDA/stream.rs @@ -1,15 +1,17 @@ -use std::{mem, thread, ptr, fmt}; -use std::cmp::max; + + use syscall::MAP_WRITE; -use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; +use syscall::error::{Error, EACCES, EWOULDBLOCK, EIO, Result}; use syscall::flag::O_NONBLOCK; use syscall::io::{Dma, Mmio, Io, ReadOnly}; use syscall::scheme::SchemeMut; use std::sync::Arc; use std::cell::RefCell; use std::result; - +use std::cmp::{max, min}; +use std::ptr::copy_nonoverlapping; +use std::{mem, thread, ptr, fmt}; extern crate syscall; @@ -201,18 +203,56 @@ impl StreamDescriptorRegs { _ => 4 * (chan + 1), } } + + } -pub struct Stream { - buff: usize, - buff_phys: usize, - buff_length: usize, - output_current_block: usize, - block_length: usize, - block_count: usize, +pub struct OutputStream { + buff: StreamBuffer, + + desc_regs: &'static mut StreamDescriptorRegs, } +impl OutputStream { + pub fn new(block_count: usize, block_length: usize, regs: &'static mut StreamDescriptorRegs) -> OutputStream { + unsafe { + OutputStream { + buff: StreamBuffer::new(block_length, block_count).unwrap(), + + desc_regs: regs, + } + } + } + + pub fn write_block(&mut self, buf: &[u8]) -> Result { + self.buff.write_block(buf) + } + + pub fn block_size(&self) -> usize { + self.buff.block_size() + } + + pub fn block_count(&self) -> usize { + self.buff.block_count() + } + + pub fn current_block(&self) -> usize { + self.buff.current_block() + } + + pub fn addr(&self) -> usize { + self.buff.addr() + } + + pub fn phys(&self) -> usize { + self.buff.phys() + } +} + + + + #[repr(packed)] pub struct BufferDescriptorListEntry { addr: Mmio, @@ -252,13 +292,16 @@ pub struct StreamBuffer { phys: usize, addr: usize, - len: usize, + block_cnt: usize, + block_len: usize, + + cur_pos: usize, } impl StreamBuffer { - pub fn new(length: usize) -> result::Result { + pub fn new(block_length: usize, block_count: usize) -> result::Result { let phys = unsafe { - syscall::physalloc(length) + syscall::physalloc(block_length * block_count) }; if !phys.is_ok() { return Err("Could not allocate physical memory for buffer."); @@ -267,24 +310,25 @@ impl StreamBuffer { let phys_addr = phys.unwrap(); let addr = unsafe { - syscall::physmap(phys_addr, length, MAP_WRITE) + syscall::physmap(phys_addr, block_length * block_count, MAP_WRITE) }; if !addr.is_ok() { + unsafe {syscall::physfree(phys_addr, block_length * block_count);} return Err("Could not map physical memory for buffer."); - } else { - unsafe {syscall::physfree(phys_addr, length);} } Ok(StreamBuffer { phys: phys_addr, addr: addr.unwrap(), - len: length, + block_len: block_length, + block_cnt: block_count, + cur_pos: 0, }) } pub fn length(&self) -> usize { - self.len + self.block_len * self.block_cnt } pub fn addr(&self) -> usize { @@ -295,14 +339,43 @@ impl StreamBuffer { self.phys } + pub fn block_size(&self) -> usize { + self.block_len + } + + pub fn block_count(&self) -> usize { + self.block_cnt + } + + pub fn current_block(&self) -> usize { + self.cur_pos + } + + pub fn write_block(&mut self, buf: &[u8]) -> Result { + if buf.len() != self.block_size() { + return Err(Error::new(EIO)) + } + let len = min(self.block_size(), buf.len()); + + + print!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}\n", self.phys(), self.addr(), self.current_block() * self.block_size(), len); + unsafe { + copy_nonoverlapping(buf.as_ptr(), (self.addr() + self.current_block() * self.block_size()) as * mut u8, len); + } + + self.cur_pos += 1; + self.cur_pos %= self.block_count(); + + Ok(len) + + } } -/* impl Drop for StreamBuffer { fn drop(&mut self) { unsafe { print!("IHDA: Deallocating buffer.\n"); syscall::physunmap(self.addr); - syscall::physfree(self.phys, self.len); + syscall::physfree(self.phys, self.block_len * self.block_cnt); } } -}*/ +} diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 5825ad7cd7..e914783d00 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -6,7 +6,7 @@ extern crate spin; extern crate syscall; extern crate event; -use std::{env, usize, thread}; +use std::{env, usize, u16, thread}; use std::fs::File; use std::io::{Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; @@ -14,14 +14,27 @@ use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme, SchemeMut}; use std::cell::RefCell; use std::sync::Arc; + use event::EventQueue; use syscall::error::EWOULDBLOCK; + pub mod HDA; - use HDA::IntelHDA; + + + + + +/* + VEND:PROD + Virtualbox 8086:2668 + QEMU ICH9 8086:293E + 82801H ICH8 8086:284B +*/ + fn main() { let mut args = env::args().skip(1); @@ -34,8 +47,17 @@ fn main() { let irq_str = args.next().expect("ihda: no irq provided"); let irq = irq_str.parse::().expect("ihda: failed to parse irq"); + + let vend_str = args.next().expect("ihda: no vendor id provided"); + let vend = usize::from_str_radix(&vend_str, 16).expect("ihda: failed to parse vendor id"); + + + let prod_str = args.next().expect("ihda: no product id provided"); + let prod = usize::from_str_radix(&prod_str, 16).expect("ihda: failed to parse product id"); + print!("{}", format!(" + ihda {} on: {:X} IRQ: {}\n", name, bar, irq)); + // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { @@ -45,8 +67,10 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("IHDA: failed to open IRQ file"); + let vend_prod:u32 = ((vend as u32) << 16) | (prod as u32); - let device = Arc::new(RefCell::new(unsafe { HDA::IntelHDA::new(address).expect("ihdad: failed to allocate device") })); + + let device = Arc::new(RefCell::new(unsafe { HDA::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); let socket_fd = syscall::open(":audio", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create audio scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); @@ -95,7 +119,6 @@ fn main() { } Ok(Some(0)) }).expect("IHDA: failed to catch events on IRQ file"); - let socket_fd = socket.borrow().as_raw_fd(); let socket_packet = socket.clone(); event_queue.add(socket_fd, move |_count: usize| -> Result> { @@ -114,6 +137,8 @@ fn main() { socket_packet.borrow_mut().write(&mut packet)?; } } + + /* let next_read = device.borrow().next_read(); if next_read > 0 { @@ -138,6 +163,7 @@ fn main() { + loop { { //device_loop.borrow_mut().handle_interrupts(); From 5ef20a47e7fd29c735182d55e3e08bb4ad4ff66a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 17 Jun 2017 17:03:18 -0600 Subject: [PATCH 0155/1301] Update pcid.toml to specify intel hd audio more broadly --- pcid.toml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pcid.toml b/pcid.toml index b19bd30447..db4383a0e8 100644 --- a/pcid.toml +++ b/pcid.toml @@ -49,13 +49,12 @@ vendor = 32902 device = 5379 command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] - #ihdad [[drivers]] name = "Intel HD Audio" -vendor = 32902 -device = 9832 -command = ["ihdad", "$NAME", "$BAR0", "$IRQ"] +class = 4 +subclass = 3 +command = ["ihdad", "$NAME", "$BAR0", "$IRQ", "$VENID", "$DEVID"] # nvmed [[drivers]] From d75e540fb70b66bdb96a05ebeaf2d7d29329c187 Mon Sep 17 00:00:00 2001 From: Tibor Nagy Date: Sun, 25 Jun 2017 00:44:25 +0200 Subject: [PATCH 0156/1301] ihdad: Fix seek flags --- ihdad/src/HDA/device.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ihdad/src/HDA/device.rs b/ihdad/src/HDA/device.rs index 3a35d0ff70..64774ea760 100755 --- a/ihdad/src/HDA/device.rs +++ b/ihdad/src/HDA/device.rs @@ -16,7 +16,8 @@ extern crate syscall; use syscall::MAP_WRITE; use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; -use syscall::io::{ Mmio, Io}; +use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; +use syscall::io::{Mmio, Io}; use syscall::scheme::SchemeMut; use spin::Mutex; @@ -1029,4 +1030,4 @@ impl SchemeMut for IntelHDA { handles.remove(&_id).ok_or(Error::new(EBADF)).and(Ok(0)) } -} \ No newline at end of file +} From cd782acf77d7d7fd00e843282b1f765ce6c13ab7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 8 Jul 2017 19:23:03 -0600 Subject: [PATCH 0157/1301] Add gitignore, update vesad --- .gitignore | 2 ++ vesad/src/display.rs | 13 +++++++------ vesad/src/main.rs | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..fa8d85ac52 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +Cargo.lock +target diff --git a/vesad/src/display.rs b/vesad/src/display.rs index ec4afc90b7..b3b5498626 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -1,7 +1,8 @@ #[cfg(feature="rusttype")] extern crate rusttype; -use alloc::heap; +use alloc::allocator::{Alloc, Layout}; +use alloc::heap::Heap; use std::{cmp, slice}; use primitive::{fast_set32, fast_set64, fast_copy}; @@ -41,7 +42,7 @@ impl Display { #[cfg(not(feature="rusttype"))] pub fn new(width: usize, height: usize, onscreen: usize) -> Display { let size = width * height; - let offscreen = unsafe { heap::allocate(size * 4, 4096) }; + let offscreen = unsafe { Heap.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap() }; unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; Display { width: width, @@ -54,7 +55,7 @@ impl Display { #[cfg(feature="rusttype")] pub fn new(width: usize, height: usize, onscreen: usize) -> Display { let size = width * height; - let offscreen = unsafe { heap::allocate(size * 4, 4096) }; + let offscreen = unsafe { Heap.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap() }; unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; Display { width: width, @@ -73,7 +74,7 @@ impl Display { println!("Resize display to {}, {}", width, height); let size = width * height; - let offscreen = unsafe { heap::allocate(size * 4, 4096) }; + let offscreen = unsafe { Heap.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap() }; { let mut old_ptr = self.offscreen.as_ptr(); @@ -106,7 +107,7 @@ impl Display { let onscreen = self.onscreen.as_mut_ptr(); self.onscreen = unsafe { slice::from_raw_parts_mut(onscreen, size) }; - unsafe { heap::deallocate(self.offscreen.as_mut_ptr() as *mut u8, self.offscreen.len() * 4, 4096) }; + unsafe { Heap.dealloc(self.offscreen.as_mut_ptr() as *mut u8, Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; self.offscreen = unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }; } else { println!("Display is already {}, {}", width, height); @@ -290,6 +291,6 @@ impl Display { impl Drop for Display { fn drop(&mut self) { - unsafe { heap::deallocate(self.offscreen.as_mut_ptr() as *mut u8, self.offscreen.len() * 4, 4096) }; + unsafe { Heap.dealloc(self.offscreen.as_mut_ptr() as *mut u8, Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; } } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 5f072078cb..5f9211bca1 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -1,7 +1,7 @@ #![deny(warnings)] #![feature(alloc)] +#![feature(allocator_api)] #![feature(asm)] -#![feature(heap_api)] extern crate alloc; extern crate orbclient; From c54aa03e54c10fdf1494891efb70b3ab90e85c32 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Jul 2017 19:02:50 -0600 Subject: [PATCH 0158/1301] Add newlines to network config --- alxd/src/device/mod.rs | 2 +- e1000d/src/device.rs | 2 +- rtl8168d/src/device.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/alxd/src/device/mod.rs b/alxd/src/device/mod.rs index ebdd04e42a..bf1f19a68f 100644 --- a/alxd/src/device/mod.rs +++ b/alxd/src/device/mod.rs @@ -1702,7 +1702,7 @@ impl Alx { let mac = self.get_perm_macaddr(); print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); if ! self.get_phy_info() { println!(" - Identify PHY failed"); diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 280c2d3197..077b8f4a80 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -306,7 +306,7 @@ impl Intel8254x { mac_high as u8, (mac_high >> 8) as u8]; print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); // // MTA => 0; diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index bde150b626..6873f37291 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -220,7 +220,7 @@ impl Rtl8168 { mac_high as u8, (mac_high >> 8) as u8]; print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value self.regs.cmd.writef(1 << 4, true); From 15f3f0ad0f3ad303207bb8809f380e68123851fb Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Jul 2017 19:37:35 -0600 Subject: [PATCH 0159/1301] Split pcid into initfs and fs parts --- pcid.toml => filesystem.toml | 37 +---------------------------------- initfs.toml | 38 ++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 36 deletions(-) rename pcid.toml => filesystem.toml (58%) create mode 100644 initfs.toml diff --git a/pcid.toml b/filesystem.toml similarity index 58% rename from pcid.toml rename to filesystem.toml index db4383a0e8..2124a24a6b 100644 --- a/pcid.toml +++ b/filesystem.toml @@ -1,24 +1,4 @@ -# ahcid -[[drivers]] -name = "AHCI storage" -class = 1 -subclass = 6 -command = ["ahcid", "$NAME", "$BAR5", "$IRQ"] - -# bgad -[[drivers]] -name = "QEMU Graphics Array" -class = 3 -vendor = 4660 -device = 4369 -command = ["bgad", "$NAME", "$BAR0"] - -[[drivers]] -name = "VirtualBox Graphics Array" -class = 3 -vendor = 33006 -device = 48879 -command = ["bgad", "$NAME", "$BAR0"] +## Drivers for FS ## # e1000d [[drivers]] @@ -56,13 +36,6 @@ class = 4 subclass = 3 command = ["ihdad", "$NAME", "$BAR0", "$IRQ", "$VENID", "$DEVID"] -# nvmed -[[drivers]] -name = "NVME storage" -class = 1 -subclass = 8 -command = ["nvmed", "$NAME", "$BAR0", "$IRQ"] - # rtl8168d [[drivers]] name = "RTL8168 NIC" @@ -71,14 +44,6 @@ vendor = 4332 device = 33128 command = ["rtl8168d", "$NAME", "$BAR2", "$IRQ"] -# vboxd -[[drivers]] -name = "VirtualBox Guest Device" -class = 8 -vendor = 33006 -device = 51966 -command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] - # xhcid [[drivers]] name = "XHCI" diff --git a/initfs.toml b/initfs.toml new file mode 100644 index 0000000000..4e68571eaa --- /dev/null +++ b/initfs.toml @@ -0,0 +1,38 @@ +## Drivers for InitFS ## + +# ahcid +[[drivers]] +name = "AHCI storage" +class = 1 +subclass = 6 +command = ["ahcid", "$NAME", "$BAR5", "$IRQ"] + +# bgad +[[drivers]] +name = "QEMU Graphics Array" +class = 3 +vendor = 4660 +device = 4369 +command = ["bgad", "$NAME", "$BAR0"] + +[[drivers]] +name = "VirtualBox Graphics Array" +class = 3 +vendor = 33006 +device = 48879 +command = ["bgad", "$NAME", "$BAR0"] + +# nvmed +[[drivers]] +name = "NVME storage" +class = 1 +subclass = 8 +command = ["nvmed", "$NAME", "$BAR0", "$IRQ"] + +# vboxd +[[drivers]] +name = "VirtualBox Guest Device" +class = 8 +vendor = 33006 +device = 51966 +command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] From ce78f9cf9e464b2543d7a4d2d61c02873be63bde Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Jul 2017 19:39:50 -0600 Subject: [PATCH 0160/1301] Use dashes for mac addresses --- alxd/src/device/mod.rs | 2 +- e1000d/src/device.rs | 2 +- rtl8168d/src/device.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/alxd/src/device/mod.rs b/alxd/src/device/mod.rs index bf1f19a68f..ba6219e6e5 100644 --- a/alxd/src/device/mod.rs +++ b/alxd/src/device/mod.rs @@ -1702,7 +1702,7 @@ impl Alx { let mac = self.get_perm_macaddr(); print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); if ! self.get_phy_info() { println!(" - Identify PHY failed"); diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 077b8f4a80..194dd4eef7 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -306,7 +306,7 @@ impl Intel8254x { mac_high as u8, (mac_high >> 8) as u8]; print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); // // MTA => 0; diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 6873f37291..a3c8ac476f 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -220,7 +220,7 @@ impl Rtl8168 { mac_high as u8, (mac_high >> 8) as u8]; print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - let _ = setcfg("mac", &format!("{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}.{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value self.regs.cmd.writef(1 << 4, true); From 473ac85faa32166697ea954c01e9227397c744b3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Jul 2017 13:17:48 -0600 Subject: [PATCH 0161/1301] Return error when dup buf is not empty --- ahcid/src/scheme.rs | 6 +++++- alxd/src/device/mod.rs | 6 +++++- e1000d/src/device.rs | 6 +++++- rtl8168d/src/device.rs | 6 +++++- vesad/src/scheme.rs | 6 +++++- 5 files changed, 25 insertions(+), 5 deletions(-) diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index f36ad7bb02..d76b046232 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -70,7 +70,11 @@ impl Scheme for DiskScheme { } } - fn dup(&self, id: usize, _buf: &[u8]) -> Result { + fn dup(&self, id: usize, buf: &[u8]) -> Result { + if ! buf.is_empty() { + return Err(Error::new(EINVAL)); + } + let mut handles = self.handles.lock(); let new_handle = { let handle = handles.get(&id).ok_or(Error::new(EBADF))?; diff --git a/alxd/src/device/mod.rs b/alxd/src/device/mod.rs index ba6219e6e5..9bfc9f0f08 100644 --- a/alxd/src/device/mod.rs +++ b/alxd/src/device/mod.rs @@ -1797,7 +1797,11 @@ impl scheme::SchemeMut for Alx { } } - fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { + fn dup(&mut self, id: usize, buf: &[u8]) -> Result { + if ! buf.is_empty() { + return Err(Error::new(EINVAL)); + } + Ok(id) } diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 194dd4eef7..bb926946a2 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -110,7 +110,11 @@ impl Scheme for Intel8254x { } } - fn dup(&self, id: usize, _buf: &[u8]) -> Result { + fn dup(&self, id: usize, buf: &[u8]) -> Result { + if ! buf.is_empty() { + return Err(Error::new(EINVAL)); + } + Ok(id) } diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index a3c8ac476f..0076fbe480 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -83,7 +83,11 @@ impl SchemeMut for Rtl8168 { } } - fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { + fn dup(&mut self, id: usize, buf: &[u8]) -> Result { + if ! buf.is_empty() { + return Err(Error::new(EINVAL)); + } + Ok(id) } diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index bc933d7255..34ea333d70 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -114,7 +114,11 @@ impl SchemeMut for DisplayScheme { } } - fn dup(&mut self, id: usize, _buf: &[u8]) -> Result { + fn dup(&mut self, id: usize, buf: &[u8]) -> Result { + if ! buf.is_empty() { + return Err(Error::new(EINVAL)); + } + let handle = self.handles.get(&id).map(|handle| handle.clone()).ok_or(Error::new(EBADF))?; let new_id = self.next_id; From 513ddd9eb5f3d1b32da1e795f97894a0666c4d12 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Jul 2017 13:44:21 -0600 Subject: [PATCH 0162/1301] Imports for EINVAL --- alxd/src/device/mod.rs | 2 +- alxd/src/main.rs | 2 ++ e1000d/src/device.rs | 2 +- rtl8168d/src/device.rs | 2 +- vesad/src/scheme.rs | 2 +- 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/alxd/src/device/mod.rs b/alxd/src/device/mod.rs index 9bfc9f0f08..2afdbdaf8a 100644 --- a/alxd/src/device/mod.rs +++ b/alxd/src/device/mod.rs @@ -1,4 +1,4 @@ -use std::{cmp, mem, ptr, slice, thread, time}; +use std::{ptr, thread, time}; use netutils::setcfg; use syscall::error::{Error, EACCES, EINVAL, EIO, EWOULDBLOCK, Result}; diff --git a/alxd/src/main.rs b/alxd/src/main.rs index 8fdca2719c..c38bb99682 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] +#![allow(non_upper_case_globals)] #![allow(unused_parens)] #![feature(asm)] #![feature(concat_idents)] diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index bb926946a2..95e6bf2990 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,7 +1,7 @@ use std::{cmp, mem, ptr, slice, thread, time}; use netutils::setcfg; -use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; +use syscall::error::{Error, EACCES, EINVAL, EWOULDBLOCK, Result}; use syscall::flag::O_NONBLOCK; use syscall::io::Dma; use syscall::scheme::Scheme; diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 0076fbe480..a85c0a8e25 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -1,7 +1,7 @@ use std::{mem, thread}; use netutils::setcfg; -use syscall::error::{Error, EACCES, EWOULDBLOCK, Result}; +use syscall::error::{Error, EACCES, EINVAL, EWOULDBLOCK, Result}; use syscall::flag::O_NONBLOCK; use syscall::io::{Dma, Mmio, Io, ReadOnly}; use syscall::scheme::SchemeMut; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 34ea333d70..7d9fede491 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::{mem, slice, str}; use orbclient::{Event, EventOption}; -use syscall::{Result, Error, EACCES, EBADF, ENOENT, O_NONBLOCK, SchemeMut}; +use syscall::{Result, Error, EACCES, EBADF, EINVAL, ENOENT, O_NONBLOCK, SchemeMut}; use display::Display; use screen::{Screen, GraphicScreen, TextScreen}; From 815b59b80bb74efb1ff93be02641c2e49cce3c8c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Jul 2017 20:22:19 -0600 Subject: [PATCH 0163/1301] Add runtime registers, testing for TLB to XHCI --- xhcid/src/main.rs | 6 +- xhcid/src/xhci/event.rs | 8 ++ xhcid/src/{xhci.rs => xhci/mod.rs} | 69 ++++++++++++---- xhcid/src/xhci/termios.rs | 102 ++++++++++++++++++++++++ xhcid/src/xhci/trb.rs | 123 +++++++++++++++++++++++++++++ 5 files changed, 289 insertions(+), 19 deletions(-) create mode 100644 xhcid/src/xhci/event.rs rename xhcid/src/{xhci.rs => xhci/mod.rs} (77%) create mode 100644 xhcid/src/xhci/termios.rs create mode 100644 xhcid/src/xhci/trb.rs diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 741871db4b..60dc85bd61 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -1,3 +1,5 @@ +#![feature(core_intrinsics)] + #[macro_use] extern crate bitflags; extern crate syscall; @@ -22,7 +24,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { let address = unsafe { syscall::physmap(bar, 4096, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; - /* + match Xhci::new(address) { Ok(mut xhci) => { xhci.init(); @@ -31,7 +33,7 @@ fn main() { println!("xhcid: error: {}", err); } } - */ + unsafe { let _ = syscall::physunmap(address); } } } diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs new file mode 100644 index 0000000000..e811442ad6 --- /dev/null +++ b/xhcid/src/xhci/event.rs @@ -0,0 +1,8 @@ +use syscall::io::Mmio; + +pub struct EventRingSte { + pub address: Mmio, + pub size: Mmio, + _rsvd: Mmio, + _rsvd2: Mmio, +} diff --git a/xhcid/src/xhci.rs b/xhcid/src/xhci/mod.rs similarity index 77% rename from xhcid/src/xhci.rs rename to xhcid/src/xhci/mod.rs index 63b7b2d9ba..96f23e9ebe 100644 --- a/xhcid/src/xhci.rs +++ b/xhcid/src/xhci/mod.rs @@ -2,22 +2,11 @@ use std::slice; use syscall::error::Result; use syscall::io::{Dma, Mmio, Io}; -#[repr(packed)] -struct Trb { - pub data: u64, - pub status: u32, - pub control: u32, -} +mod event; +mod trb; -impl Trb { - pub fn from_type(trb_type: u32) -> Self { - Trb { - data: 0, - status: 0, - control: (trb_type & 0x3F) << 10, - } - } -} +use self::event::*; +use self::trb::*; #[repr(packed)] pub struct XhciCap { @@ -46,6 +35,21 @@ pub struct XhciOp { config: Mmio, } +pub struct XhciInterrupter { + iman: Mmio, + imod: Mmio, + erstsz: Mmio, + _rsvd: Mmio, + erstba: Mmio, + erdp: Mmio, +} + +pub struct XhciRun { + mfindex: Mmio, + _rsvd: [Mmio; 7], + ints: [XhciInterrupter; 1024], +} + bitflags! { flags XhciPortFlags: u32 { const PORT_CCS = 1 << 0, @@ -131,9 +135,11 @@ pub struct Xhci { op: &'static mut XhciOp, ports: &'static mut [XhciPort], dbs: &'static mut [XhciDoorbell], + run: &'static mut XhciRun, dev_baa: Dma<[u64; 256]>, dev_ctxs: Vec>, cmds: Dma<[Trb; 256]>, + event_rings: Dma<[EventRingSte; 1]>, } impl Xhci { @@ -175,17 +181,22 @@ impl Xhci { let port_base = op_base + 0x400; let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut XhciPort, max_ports as usize) }; - let db_base = op_base + cap.db_offset.read() as usize; + let db_base = address + cap.db_offset.read() as usize; let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut XhciDoorbell, 256) }; + let run_base = address + cap.rts_offset.read() as usize; + let run = unsafe { &mut *(run_base as *mut XhciRun) }; + let mut xhci = Xhci { cap: cap, op: op, ports: ports, dbs: dbs, + run: run, dev_baa: Dma::zeroed()?, dev_ctxs: Vec::new(), cmds: Dma::zeroed()?, + event_rings: Dma::zeroed()?, }; { @@ -200,7 +211,10 @@ impl Xhci { xhci.op.dcbaap.write(xhci.dev_baa.physical() as u64); // Set command ring control register - xhci.op.crcr.write(xhci.cmds.physical() as u64); + xhci.op.crcr.write(xhci.cmds.physical() as u64 | 1); + + // Set event ring segment table registers + //TODO // Set run/stop to 1 xhci.op.usb_cmd.writef(1, true); @@ -209,6 +223,9 @@ impl Xhci { while xhci.op.usb_sts.readf(1) { println!(" - Waiting for XHCI running"); } + + // Ring command doorbell + xhci.dbs[0].write(0); } Ok(xhci) @@ -222,5 +239,23 @@ impl Xhci { let flags = port.flags(); println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags); } + + self.cmds[0].no_op_cmd(true); + + println!("Before"); + println!("USBSTS: {:X}", self.op.usb_sts.read()); + println!("CRCR: {:X}", self.op.crcr.read()); + println!("data: {:X}", self.cmds[0].data.read()); + println!("status: {:X}", self.cmds[0].status.read()); + println!("control: {:X}", self.cmds[0].control.read()); + + self.dbs[0].write(0); + + println!("After"); + println!("USBSTS: {:X}", self.op.usb_sts.read()); + println!("CRCR: {:X}", self.op.crcr.read()); + println!("data: {:X}", self.cmds[0].data.read()); + println!("status: {:X}", self.cmds[0].status.read()); + println!("control: {:X}", self.cmds[0].control.read()); } } diff --git a/xhcid/src/xhci/termios.rs b/xhcid/src/xhci/termios.rs new file mode 100644 index 0000000000..a9bac08040 --- /dev/null +++ b/xhcid/src/xhci/termios.rs @@ -0,0 +1,102 @@ +use std::cell::RefCell; +use std::ops::{Deref, DerefMut}; +use std::rc::Weak; + +use syscall::error::{Error, Result, EBADF, EINVAL, EPIPE}; +use syscall::flag::{F_GETFL, F_SETFL, O_ACCMODE}; + +use pty::Pty; +use resource::Resource; + +/// Read side of a pipe +#[derive(Clone)] +pub struct PtyTermios { + pty: Weak>, + flags: usize, +} + +impl PtyTermios { + pub fn new(pty: Weak>, flags: usize) -> Self { + PtyTermios { + pty: pty, + flags: flags, + } + } +} + +impl Resource for PtyTermios { + fn boxed_clone(&self) -> Box { + Box::new(self.clone()) + } + + fn pty(&self) -> Weak> { + self.pty.clone() + } + + fn flags(&self) -> usize { + self.flags + } + + fn path(&self, buf: &mut [u8]) -> Result { + if let Some(pty_lock) = self.pty.upgrade() { + pty_lock.borrow_mut().path(buf) + } else { + Err(Error::new(EPIPE)) + } + } + + fn read(&self, buf: &mut [u8]) -> Result { + if let Some(pty_lock) = self.pty.upgrade() { + let pty = pty_lock.borrow(); + let termios: &[u8] = pty.termios.deref(); + + let mut i = 0; + while i < buf.len() && i < termios.len() { + buf[i] = termios[i]; + i += 1; + } + Ok(i) + } else { + Ok(0) + } + } + + fn write(&self, buf: &[u8]) -> Result { + if let Some(pty_lock) = self.pty.upgrade() { + let mut pty = pty_lock.borrow_mut(); + let termios: &mut [u8] = pty.termios.deref_mut(); + + let mut i = 0; + while i < buf.len() && i < termios.len() { + termios[i] = buf[i]; + i += 1; + } + Ok(i) + } else { + Err(Error::new(EPIPE)) + } + } + + fn sync(&self) -> Result { + Ok(0) + } + + fn fcntl(&mut self, cmd: usize, arg: usize) -> Result { + match cmd { + F_GETFL => Ok(self.flags), + F_SETFL => { + self.flags = (self.flags & O_ACCMODE) | (arg & ! O_ACCMODE); + Ok(0) + }, + _ => Err(Error::new(EINVAL)) + } + } + + fn fevent(&self) -> Result<()> { + Err(Error::new(EBADF)) + } + + fn fevent_count(&self) -> Option { + None + } +} diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs new file mode 100644 index 0000000000..2e54fd3430 --- /dev/null +++ b/xhcid/src/xhci/trb.rs @@ -0,0 +1,123 @@ +use syscall::io::{Io, Mmio}; + +#[repr(u8)] +pub enum TrbType { + Reserved, + /* Transfer */ + Normal, + SetupStage, + DataStage, + StatusStage, + Isoch, + Link, + EventData, + NoOp, + /* Command */ + EnableSlot, + DisableSlot, + AddressDevice, + ConfigureEndpoint, + EvaluateContext, + ResetEndpoint, + StopEndpoint, + SetTrDequeuePointer, + ResetDevice, + ForceEvent, + NegotiateBandwidth, + SetLatencyToleranceValue, + GetPortBandwidth, + ForceHeader, + NoOpCmd, + /* Reserved */ + Rsv24, + Rsv25, + Rsv26, + Rsv27, + Rsv28, + Rsv29, + Rsv30, + Rsv31, + /* Events */ + Transfer, + CommandCompletion, + PortStatusChange, + BandwidthRequest, + Doorbell, + HostController, + DeviceNotification, + MfindexWrap, + /* Reserved from 40 to 47, vendor devined from 48 to 63 */ +} + +#[repr(u8)] +pub enum TrbCompletionCode { + Invalid, + Success, + DataBuffer, + BabbleDetected, + UsbTransaction, + Trb, + Stall, + Resource, + Bandwidth, + NoSlotsAvailable, + InvalidStreamType, + SlotNotEnabled, + EndpointNotEnabled, + ShortPacket, + RingUnderrun, + RingOverrun, + VfEventRingFull, + Parameter, + BandwidthOverrun, + ContextState, + NoPingResponse, + EventRingFull, + IncompatibleDevice, + MissedService, + CommandRingStopped, + CommandAborted, + Stopped, + StoppedLengthInvalid, + StoppedShortPacket, + MaxExitLatencyTooLarge, + Rsv30, + IsochBuffer, + EventLost, + Undefined, + InvalidStreamId, + SecondaryBandwidth, + SplitTransaction, + /* Values from 37 to 191 are reserved */ + /* 192 to 223 are vendor defined errors */ + /* 224 to 255 are vendor defined information */ +} + +#[repr(packed)] +pub struct Trb { + pub data: Mmio, + pub status: Mmio, + pub control: Mmio, +} + +impl Trb { + pub fn reset(&mut self, param: u64, status: u32, control: u16, trb_type: TrbType, evaluate_next: bool, cycle: bool) { + let full_control = + (control as u32) << 16 | + ((trb_type as u32) & 0x3F) << 10 | + if evaluate_next { 1 << 1 } else { 0 } | + if cycle { 1 << 0 } else { 0 }; + + self.data.write(param); + self.status.write(status); + self.control.write(full_control); + } + + pub fn no_op_cmd(&mut self, cycle: bool) { + self.reset(0, 0, 0, TrbType::NoOpCmd, false, cycle); + } + + pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) { + self.reset(0, 0, (slot_type as u16) & 0x1F, TrbType::EnableSlot, false, cycle); + } +} From 325b303c545d352f81c13a884dbf4e4595eb67aa Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Jul 2017 21:13:27 -0600 Subject: [PATCH 0164/1301] Fix mapping size of XHCI, add more debugging --- xhcid/src/main.rs | 2 +- xhcid/src/xhci/mod.rs | 42 +++++++++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 60dc85bd61..064d0fcddb 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -23,7 +23,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 4096, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 65536, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; match Xhci::new(address) { Ok(mut xhci) => { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 96f23e9ebe..7f7bd47a64 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -145,27 +145,33 @@ pub struct Xhci { impl Xhci { pub fn new(address: usize) -> Result { let cap = unsafe { &mut *(address as *mut XhciCap) }; + println!(" - CAP {:X}", address); let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut XhciOp) }; + println!(" - OP {:X}", op_base); let max_slots; let max_ports; { + println!(" - Wait for ready"); // Wait until controller is ready while op.usb_sts.readf(1 << 11) { println!(" - Waiting for XHCI ready"); } + println!(" - Stop"); // Set run/stop to 0 op.usb_cmd.writef(1, false); + println!(" - Wait for not running"); // Wait until controller not running while ! op.usb_sts.readf(1) { println!(" - Waiting for XHCI stopped"); } + println!(" - Read max slots"); // Read maximum slots and ports let hcs_params1 = cap.hcs_params1.read(); max_slots = hcs_params1 & 0xFF; @@ -173,6 +179,7 @@ impl Xhci { println!(" - Max Slots: {}, Max Ports {}", max_slots, max_ports); + println!(" - Set enabled slots"); // Set enabled slots op.config.write(max_slots); println!(" - Enabled Slots: {}", op.config.read() & 0xFF); @@ -180,12 +187,15 @@ impl Xhci { let port_base = op_base + 0x400; let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut XhciPort, max_ports as usize) }; + println!(" - PORT {:X}", port_base); let db_base = address + cap.db_offset.read() as usize; let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut XhciDoorbell, 256) }; + println!(" - DOORBELL {:X}", db_base); let run_base = address + cap.rts_offset.read() as usize; let run = unsafe { &mut *(run_base as *mut XhciRun) }; + println!(" - RUNTIME {:X}", run_base); let mut xhci = Xhci { cap: cap, @@ -202,30 +212,38 @@ impl Xhci { { // Create device context buffers for each slot for i in 0..max_slots as usize { + println!(" - Setup dev ctx {}", i); let dev_ctx: Dma = Dma::zeroed()?; xhci.dev_baa[i] = dev_ctx.physical() as u64; xhci.dev_ctxs.push(dev_ctx); } + println!(" - Write DCBAAP"); // Set device context address array pointer xhci.op.dcbaap.write(xhci.dev_baa.physical() as u64); + println!(" - Write CRCR"); // Set command ring control register xhci.op.crcr.write(xhci.cmds.physical() as u64 | 1); // Set event ring segment table registers //TODO + println!(" - Start"); // Set run/stop to 1 xhci.op.usb_cmd.writef(1, true); + println!(" - Wait for running"); // Wait until controller is running while xhci.op.usb_sts.readf(1) { println!(" - Waiting for XHCI running"); } + println!(" - Ring doorbell"); // Ring command doorbell xhci.dbs[0].write(0); + + println!(" - XHCI initialized"); } Ok(xhci) @@ -240,22 +258,20 @@ impl Xhci { println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags); } - self.cmds[0].no_op_cmd(true); + println!(" - Running Enable Slot command"); - println!("Before"); - println!("USBSTS: {:X}", self.op.usb_sts.read()); - println!("CRCR: {:X}", self.op.crcr.read()); - println!("data: {:X}", self.cmds[0].data.read()); - println!("status: {:X}", self.cmds[0].status.read()); - println!("control: {:X}", self.cmds[0].control.read()); + self.cmds[0].enable_slot(0, true); + + println!(" - Before"); + println!(" - data: {:X}", self.cmds[0].data.read()); + println!(" - status: {:X}", self.cmds[0].status.read()); + println!(" - control: {:X}", self.cmds[0].control.read()); self.dbs[0].write(0); - println!("After"); - println!("USBSTS: {:X}", self.op.usb_sts.read()); - println!("CRCR: {:X}", self.op.crcr.read()); - println!("data: {:X}", self.cmds[0].data.read()); - println!("status: {:X}", self.cmds[0].status.read()); - println!("control: {:X}", self.cmds[0].control.read()); + println!(" - After"); + println!(" - data: {:X}", self.cmds[0].data.read()); + println!(" - status: {:X}", self.cmds[0].status.read()); + println!(" - control: {:X}", self.cmds[0].control.read()); } } From 43c1d5b6b0ba6dfe0adc3237bfb679f98ecce116 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Jul 2017 21:36:51 -0600 Subject: [PATCH 0165/1301] Read events --- xhcid/src/xhci/event.rs | 24 +++++++++++++++++++++++- xhcid/src/xhci/mod.rs | 26 ++++++++++++++++++-------- 2 files changed, 41 insertions(+), 9 deletions(-) diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index e811442ad6..d59f27b2db 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -1,4 +1,7 @@ -use syscall::io::Mmio; +use syscall::error::Result; +use syscall::io::{Dma, Io, Mmio}; + +use super::trb::Trb; pub struct EventRingSte { pub address: Mmio, @@ -6,3 +9,22 @@ pub struct EventRingSte { _rsvd: Mmio, _rsvd2: Mmio, } + +pub struct EventRing { + pub ste: Dma, + pub trbs: Dma<[Trb; 256]> +} + +impl EventRing { + pub fn new() -> Result { + let mut ring = EventRing { + ste: Dma::zeroed()?, + trbs: Dma::zeroed()? + }; + + ring.ste.address.write(ring.trbs.physical() as u64); + ring.ste.size.write(ring.trbs.len() as u16); + + Ok(ring) + } +} diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 7f7bd47a64..41743c244d 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -139,7 +139,7 @@ pub struct Xhci { dev_baa: Dma<[u64; 256]>, dev_ctxs: Vec>, cmds: Dma<[Trb; 256]>, - event_rings: Dma<[EventRingSte; 1]>, + events: [EventRing; 1], } impl Xhci { @@ -206,7 +206,9 @@ impl Xhci { dev_baa: Dma::zeroed()?, dev_ctxs: Vec::new(), cmds: Dma::zeroed()?, - event_rings: Dma::zeroed()?, + events: [ + EventRing::new()? + ], }; { @@ -226,8 +228,11 @@ impl Xhci { // Set command ring control register xhci.op.crcr.write(xhci.cmds.physical() as u64 | 1); + println!(" - Write ERST"); // Set event ring segment table registers - //TODO + xhci.run.ints[0].erstsz.write(1); + xhci.run.ints[0].erstba.write(xhci.events[0].ste.physical() as u64); + xhci.run.ints[0].erdp.write(xhci.events[0].trbs.physical() as u64); println!(" - Start"); // Set run/stop to 1 @@ -262,16 +267,21 @@ impl Xhci { self.cmds[0].enable_slot(0, true); - println!(" - Before"); + println!(" - Command"); println!(" - data: {:X}", self.cmds[0].data.read()); println!(" - status: {:X}", self.cmds[0].status.read()); println!(" - control: {:X}", self.cmds[0].control.read()); self.dbs[0].write(0); - println!(" - After"); - println!(" - data: {:X}", self.cmds[0].data.read()); - println!(" - status: {:X}", self.cmds[0].status.read()); - println!(" - control: {:X}", self.cmds[0].control.read()); + println!(" - Wait for command completion"); + while self.op.crcr.readf(1 << 3) { + println!(" - Waiting for command completion"); + } + + println!(" - Response"); + println!(" - data: {:X}", self.events[0].trbs[0].data.read()); + println!(" - status: {:X}", self.events[0].trbs[0].status.read()); + println!(" - control: {:X}", self.events[0].trbs[0].control.read()); } } From 49cb1e3836d334d2929e16b2d058febabe5ec7c1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 26 Jul 2017 07:53:16 -0600 Subject: [PATCH 0166/1301] Add Cargo.lock --- .gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index fa8d85ac52..b83d22266a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1 @@ -Cargo.lock -target +/target/ From fc1a21c8eec1a989c760ef2f69019e33511989e7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 26 Jul 2017 08:02:08 -0600 Subject: [PATCH 0167/1301] Add Cargo.lock file --- Cargo.lock | 731 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 731 insertions(+) create mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000..796c1fe7d8 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,731 @@ +[root] +name = "xhcid" +version = "0.1.0" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ahcid" +version = "0.1.0" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "alxd" +version = "0.1.0" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", + "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "arrayvec" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bgad" +version = "0.1.0" +dependencies = [ + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "coco" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "e1000d" +version = "0.1.0" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", + "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "gcc" +version = "0.3.51" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "httparse" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hyper" +version = "0.10.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper-rustls" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)", + "rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "idna" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ihdad" +version = "0.1.0" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "language-tags" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.28" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "linked-hash-map" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "matches" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "mime" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "netutils" +version = "0.1.0" +source = "git+https://github.com/redox-os/netutils.git#9d3b8daeb9240fd8b761b8435cbb404bb2c1232b" +dependencies = [ + "hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", + "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nodrop" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ntpclient" +version = "0.0.1" +source = "git+https://github.com/willem66745/ntpclient-rust#7e3bdf60eb940825789a8da5181025320e3050b0" +dependencies = [ + "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-integer" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-iter" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num_cpus" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nvmed" +version = "0.1.0" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "odds" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "orbclient" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pcid" +version = "0.1.0" +dependencies = [ + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "percent-encoding" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "ps2d" +version = "0.1.0" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ransid" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rayon" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon-core" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_event" +version = "0.1.0" +source = "git+https://github.com/redox-os/event.git#42d552e4765efbfb4ec39ce174900d3f48548a70" +dependencies = [ + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ring" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rtl8168d" +version = "0.1.0" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", + "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustls" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rusttype" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "safemem" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "scopeguard" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "sdl2" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.27.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "sdl2-sys" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_derive" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive_internals" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spin" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "stb_truetype" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synom" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "toml" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "traitobject" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "typeable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicase" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "untrusted" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "url" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "vboxd" +version = "0.1.0" +dependencies = [ + "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "version_check" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vesad" +version = "0.1.0" +dependencies = [ + "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ransid 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "rusttype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "webpki" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "webpki-roots" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "699e63a93b79d717e8c3b5eb1b28b7780d0d6d9e59a72eb769291c83b0c8dc67" +"checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" +"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" +"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" +"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" +"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" +"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" +"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" +"checksum futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4b63a4792d4f8f686defe3b39b92127fea6344de5d38202b2ee5a11bbbf29d6a" +"checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" +"checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" +"checksum hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0f01e4a20f5dfa5278d7762b7bdb7cab96e24378b9eca3889fbd4b5e94dc7063" +"checksum hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04535774f79684c99528944ebdb89756c945c027e55ce52faa245879d836c8fb" +"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" +"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" +"checksum libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb7b49972ee23d8aa1026c365a5b440ba08e35075f18c459980c7395c221ec48" +"checksum linked-hash-map 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f26e961e0c884309cd527b1402a5409d35db612b36915d755e1a4f5c1547a31c" +"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" +"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" +"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" +"checksum netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)" = "" +"checksum nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "52cd74cd09beba596430cc6e3091b74007169a56246e1262f0ba451ea95117b2" +"checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" +"checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" +"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" +"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" +"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" +"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" +"checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" +"checksum orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9411f6bf9f60d65de1dcb601735ac0c904960f0f6ca03a13e6f02d25f842ea2c" +"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" +"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" +"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" +"checksum ransid 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e22373325a4a19d8350aae6ca20f43018fd2603b49a2721faa5c11273a7d4c41" +"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" +"checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" +"checksum redox_event 0.1.0 (git+https://github.com/redox-os/event.git)" = "" +"checksum redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "80dcf663dc552529b9bfc7bdb30ea12e5fa5d3545137d850a91ad410053f68e9" +"checksum redox_termios 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc495930de8d330f14856cface52561b7d79a072c76e438cf8f34d7233a35fa7" +"checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" +"checksum rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17727f4b991294da2c84d75a43c003151ff58072212768800f66c56ee46dca43" +"checksum rusttype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c64ffc93b0cc5a6f5e5e84da2a4082b0271e0a1dd76e821bdac570bda7797e" +"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" +"checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918" +"checksum sdl2 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c366cfa1f22d001774214ce2fb13f369af760b016bc79cc62d7f5ae15c00fea" +"checksum sdl2-sys 0.27.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d9f87e3d948f94f2d8688970422f49249c20e97f8f3aad76cb8729901d4eb10" +"checksum serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "433d7d9f8530d5a939ad5e0e72a6243d2e42a24804f70bf592c679363dcacb2f" +"checksum serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7b707cf0d4cab852084f573058def08879bb467fda89d99052485e7d00edd624" +"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" +"checksum spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1d16a26e2b789f86aabddbe91cb82ee2e822beb8a59840d631941b625ef77e53" +"checksum stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21b5c3b588a493a477e0d99769ee091b3627625f9ba4bdd882e6b4b0b0958805" +"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" +"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum termion 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8affd752d0f2c7127d6d5f1b98182a5471606b48b1a955165d39eb5e4887ceba" +"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" +"checksum toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b0601da6c97135c8d330c7a13a013ca6cd4143221b01de2f8d4edc50a9e551c7" +"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" +"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" +"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b65243989ef6aacd9c0d6bd2b822765c3361d8ed352185a6f3a41f3a718c673" +"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27" +"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" +"checksum webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e499345fc4c6b7c79a5b8756d4592c4305510a13512e79efafe00dfbd67bbac6" +"checksum webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb3f50499f21ad2317f442845e3b5805b007f1e728f59885c99e61b8c181a7" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" From 14e1b556ab424036cffc81bafbb24df8524357f7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 26 Jul 2017 08:17:39 -0600 Subject: [PATCH 0168/1301] Update Cargo.lock --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 796c1fe7d8..e6d440ebea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://github.com/redox-os/netutils.git#9d3b8daeb9240fd8b761b8435cbb404bb2c1232b" +source = "git+https://github.com/redox-os/netutils.git#f5ccf7232353107e46e3d9308a1631633ee0398a" dependencies = [ "hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", From b4209a6a9ca0527f2a0981e1eb4c6d73d25b2e26 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 27 Jul 2017 21:01:42 -0600 Subject: [PATCH 0169/1301] Refactor XHCI driver --- xhcid/src/main.rs | 4 +- xhcid/src/xhci/capability.rs | 15 ++ xhcid/src/xhci/command.rs | 23 +++ xhcid/src/xhci/device.rs | 56 +++++++ xhcid/src/xhci/doorbell.rs | 14 ++ xhcid/src/xhci/event.rs | 1 + xhcid/src/xhci/mod.rs | 276 ++++++++++------------------------ xhcid/src/xhci/operational.rs | 14 ++ xhcid/src/xhci/port.rs | 53 +++++++ xhcid/src/xhci/runtime.rs | 18 +++ xhcid/src/xhci/termios.rs | 102 ------------- 11 files changed, 272 insertions(+), 304 deletions(-) create mode 100644 xhcid/src/xhci/capability.rs create mode 100644 xhcid/src/xhci/command.rs create mode 100644 xhcid/src/xhci/device.rs create mode 100644 xhcid/src/xhci/doorbell.rs create mode 100644 xhcid/src/xhci/operational.rs create mode 100644 xhcid/src/xhci/port.rs create mode 100644 xhcid/src/xhci/runtime.rs delete mode 100644 xhcid/src/xhci/termios.rs diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 064d0fcddb..586c3be9b1 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -1,5 +1,3 @@ -#![feature(core_intrinsics)] - #[macro_use] extern crate bitflags; extern crate syscall; @@ -27,7 +25,7 @@ fn main() { match Xhci::new(address) { Ok(mut xhci) => { - xhci.init(); + xhci.probe(); }, Err(err) => { println!("xhcid: error: {}", err); diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs new file mode 100644 index 0000000000..4c0af02144 --- /dev/null +++ b/xhcid/src/xhci/capability.rs @@ -0,0 +1,15 @@ +use syscall::io::Mmio; + +#[repr(packed)] +pub struct CapabilityRegs { + pub len: Mmio, + _rsvd: Mmio, + pub hci_ver: Mmio, + pub hcs_params1: Mmio, + pub hcs_params2: Mmio, + pub hcs_params3: Mmio, + pub hcc_params1: Mmio, + pub db_offset: Mmio, + pub rts_offset: Mmio, + pub hcc_params2: Mmio +} diff --git a/xhcid/src/xhci/command.rs b/xhcid/src/xhci/command.rs new file mode 100644 index 0000000000..cbad816cff --- /dev/null +++ b/xhcid/src/xhci/command.rs @@ -0,0 +1,23 @@ +use syscall::error::Result; +use syscall::io::Dma; + +use super::event::EventRing; +use super::trb::Trb; + +pub struct CommandRing { + pub trbs: Dma<[Trb; 256]>, + pub events: EventRing, +} + +impl CommandRing { + pub fn new() -> Result { + Ok(CommandRing { + trbs: Dma::zeroed()?, + events: EventRing::new()?, + }) + } + + pub fn crcr(&self) -> u64 { + self.trbs.physical() as u64 | 1 + } +} diff --git a/xhcid/src/xhci/device.rs b/xhcid/src/xhci/device.rs new file mode 100644 index 0000000000..82f8608699 --- /dev/null +++ b/xhcid/src/xhci/device.rs @@ -0,0 +1,56 @@ +use syscall::error::Result; +use syscall::io::Dma; + +#[repr(packed)] +pub struct SlotContext { + inner: [u8; 32] +} + +#[repr(packed)] +pub struct EndpointContext { + inner: [u8; 32] +} + +#[repr(packed)] +pub struct DeviceContext { + pub slot: SlotContext, + pub endpoints: [EndpointContext; 15] +} + +#[repr(packed)] +pub struct InputContext { + pub drop_context: Mmio, + pub add_context: Mmio, + _rsvd: [Mmio; 5], + pub control: Mmio, + pub device: DeviceContext, +} + +pub struct DeviceList { + pub dcbaa: Dma<[u64; 256]>, + pub contexts: Vec>, +} + +impl DeviceList { + pub fn new(max_slots: u8) -> Result { + let mut dcbaa = Dma::<[u64; 256]>::zeroed()?; + let mut contexts = vec![]; + + // Create device context buffers for each slot + for i in 0..max_slots as usize { + println!(" - Setup dev ctx {}", i); + let context: Dma = Dma::zeroed()?; + dcbaa[i] = context.physical() as u64; + contexts.push(context); + } + + Ok(DeviceList { + dcbaa: dcbaa, + contexts: contexts + }) + } + + pub fn dcbaap(&self) -> u64 { + self.dcbaa.physical() as u64 + } +} diff --git a/xhcid/src/xhci/doorbell.rs b/xhcid/src/xhci/doorbell.rs new file mode 100644 index 0000000000..b464186b98 --- /dev/null +++ b/xhcid/src/xhci/doorbell.rs @@ -0,0 +1,14 @@ +use syscall::io::{Io, Mmio}; + +#[repr(packed)] +pub struct Doorbell(Mmio); + +impl Doorbell { + pub fn read(&self) -> u32 { + self.0.read() + } + + pub fn write(&mut self, data: u32) { + self.0.write(data); + } +} diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index d59f27b2db..309eed226b 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -3,6 +3,7 @@ use syscall::io::{Dma, Io, Mmio}; use super::trb::Trb; +#[repr(packed)] pub struct EventRingSte { pub address: Mmio, pub size: Mmio, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 41743c244d..6b4d4a215f 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,154 +1,42 @@ use std::slice; use syscall::error::Result; -use syscall::io::{Dma, Mmio, Io}; +use syscall::io::Io; +mod capability; +mod command; +mod device; +mod doorbell; mod event; +mod operational; +mod port; +mod runtime; mod trb; -use self::event::*; -use self::trb::*; - -#[repr(packed)] -pub struct XhciCap { - len: Mmio, - _rsvd: Mmio, - hci_ver: Mmio, - hcs_params1: Mmio, - hcs_params2: Mmio, - hcs_params3: Mmio, - hcc_params1: Mmio, - db_offset: Mmio, - rts_offset: Mmio, - hcc_params2: Mmio -} - -#[repr(packed)] -pub struct XhciOp { - usb_cmd: Mmio, - usb_sts: Mmio, - page_size: Mmio, - _rsvd: [Mmio; 2], - dn_ctrl: Mmio, - crcr: Mmio, - _rsvd2: [Mmio; 4], - dcbaap: Mmio, - config: Mmio, -} - -pub struct XhciInterrupter { - iman: Mmio, - imod: Mmio, - erstsz: Mmio, - _rsvd: Mmio, - erstba: Mmio, - erdp: Mmio, -} - -pub struct XhciRun { - mfindex: Mmio, - _rsvd: [Mmio; 7], - ints: [XhciInterrupter; 1024], -} - -bitflags! { - flags XhciPortFlags: u32 { - const PORT_CCS = 1 << 0, - const PORT_PED = 1 << 1, - const PORT_OCA = 1 << 3, - const PORT_PR = 1 << 4, - const PORT_PP = 1 << 9, - const PORT_PIC_AMB = 1 << 14, - const PORT_PIC_GRN = 1 << 15, - const PORT_LWS = 1 << 16, - const PORT_CSC = 1 << 17, - const PORT_PEC = 1 << 18, - const PORT_WRC = 1 << 19, - const PORT_OCC = 1 << 20, - const PORT_PRC = 1 << 21, - const PORT_PLC = 1 << 22, - const PORT_CEC = 1 << 23, - const PORT_CAS = 1 << 24, - const PORT_WCE = 1 << 25, - const PORT_WDE = 1 << 26, - const PORT_WOE = 1 << 27, - const PORT_DR = 1 << 30, - const PORT_WPR = 1 << 31, - } -} - -#[repr(packed)] -pub struct XhciPort { - portsc : Mmio, - portpmsc : Mmio, - portli : Mmio, - porthlpmc : Mmio, -} - -impl XhciPort { - fn read(&self) -> u32 { - self.portsc.read() - } - - fn state(&self) -> u32 { - (self.read() & (0b1111 << 5)) >> 5 - } - - fn speed(&self) -> u32 { - (self.read() & (0b1111 << 10)) >> 10 - } - - fn flags(&self) -> XhciPortFlags { - XhciPortFlags::from_bits_truncate(self.read()) - } -} - -pub struct XhciDoorbell(Mmio); - -impl XhciDoorbell { - fn read(&self) -> u32 { - self.0.read() - } - - fn write(&mut self, data: u32) { - self.0.write(data); - } -} - -#[repr(packed)] -pub struct XhciSlotContext { - inner: [u8; 32] -} - -#[repr(packed)] -pub struct XhciEndpointContext { - inner: [u8; 32] -} - -#[repr(packed)] -pub struct XhciDeviceContext { - slot: XhciSlotContext, - endpoints: [XhciEndpointContext; 15] -} +use self::capability::CapabilityRegs; +use self::command::CommandRing; +use self::device::DeviceList; +use self::doorbell::Doorbell; +use self::operational::OperationalRegs; +use self::port::Port; +use self::runtime::RuntimeRegs; pub struct Xhci { - cap: &'static mut XhciCap, - op: &'static mut XhciOp, - ports: &'static mut [XhciPort], - dbs: &'static mut [XhciDoorbell], - run: &'static mut XhciRun, - dev_baa: Dma<[u64; 256]>, - dev_ctxs: Vec>, - cmds: Dma<[Trb; 256]>, - events: [EventRing; 1], + cap: &'static mut CapabilityRegs, + op: &'static mut OperationalRegs, + ports: &'static mut [Port], + dbs: &'static mut [Doorbell], + run: &'static mut RuntimeRegs, + devices: DeviceList, + cmd: CommandRing, } impl Xhci { pub fn new(address: usize) -> Result { - let cap = unsafe { &mut *(address as *mut XhciCap) }; + let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; println!(" - CAP {:X}", address); let op_base = address + cap.len.read() as usize; - let op = unsafe { &mut *(op_base as *mut XhciOp) }; + let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; println!(" - OP {:X}", op_base); let max_slots; @@ -174,27 +62,22 @@ impl Xhci { println!(" - Read max slots"); // Read maximum slots and ports let hcs_params1 = cap.hcs_params1.read(); - max_slots = hcs_params1 & 0xFF; - max_ports = (hcs_params1 & 0xFF000000) >> 24; + max_slots = (hcs_params1 & 0xFF) as u8; + max_ports = ((hcs_params1 & 0xFF000000) >> 24) as u8; println!(" - Max Slots: {}, Max Ports {}", max_slots, max_ports); - - println!(" - Set enabled slots"); - // Set enabled slots - op.config.write(max_slots); - println!(" - Enabled Slots: {}", op.config.read() & 0xFF); } let port_base = op_base + 0x400; - let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut XhciPort, max_ports as usize) }; + let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut Port, max_ports as usize) }; println!(" - PORT {:X}", port_base); let db_base = address + cap.db_offset.read() as usize; - let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut XhciDoorbell, 256) }; + let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut Doorbell, 256) }; println!(" - DOORBELL {:X}", db_base); let run_base = address + cap.rts_offset.read() as usize; - let run = unsafe { &mut *(run_base as *mut XhciRun) }; + let run = unsafe { &mut *(run_base as *mut RuntimeRegs) }; println!(" - RUNTIME {:X}", run_base); let mut xhci = Xhci { @@ -203,58 +86,53 @@ impl Xhci { ports: ports, dbs: dbs, run: run, - dev_baa: Dma::zeroed()?, - dev_ctxs: Vec::new(), - cmds: Dma::zeroed()?, - events: [ - EventRing::new()? - ], + devices: DeviceList::new(max_slots)?, + cmd: CommandRing::new()?, }; - { - // Create device context buffers for each slot - for i in 0..max_slots as usize { - println!(" - Setup dev ctx {}", i); - let dev_ctx: Dma = Dma::zeroed()?; - xhci.dev_baa[i] = dev_ctx.physical() as u64; - xhci.dev_ctxs.push(dev_ctx); - } - - println!(" - Write DCBAAP"); - // Set device context address array pointer - xhci.op.dcbaap.write(xhci.dev_baa.physical() as u64); - - println!(" - Write CRCR"); - // Set command ring control register - xhci.op.crcr.write(xhci.cmds.physical() as u64 | 1); - - println!(" - Write ERST"); - // Set event ring segment table registers - xhci.run.ints[0].erstsz.write(1); - xhci.run.ints[0].erstba.write(xhci.events[0].ste.physical() as u64); - xhci.run.ints[0].erdp.write(xhci.events[0].trbs.physical() as u64); - - println!(" - Start"); - // Set run/stop to 1 - xhci.op.usb_cmd.writef(1, true); - - println!(" - Wait for running"); - // Wait until controller is running - while xhci.op.usb_sts.readf(1) { - println!(" - Waiting for XHCI running"); - } - - println!(" - Ring doorbell"); - // Ring command doorbell - xhci.dbs[0].write(0); - - println!(" - XHCI initialized"); - } + xhci.init(max_slots); Ok(xhci) } - pub fn init(&mut self) { + pub fn init(&mut self, max_slots: u8) { + println!(" - Set enabled slots"); + // Set enabled slots + self.op.config.write(max_slots as u32); + println!(" - Enabled Slots: {}", self.op.config.read() & 0xFF); + + println!(" - Write DCBAAP"); + // Set device context address array pointer + self.op.dcbaap.write(self.devices.dcbaap()); + + println!(" - Write CRCR"); + // Set command ring control register + self.op.crcr.write(self.cmd.crcr()); + + println!(" - Write ERST"); + // Set event ring segment table registers + self.run.ints[0].erstsz.write(1); + self.run.ints[0].erstba.write(self.cmd.events.ste.physical() as u64); + self.run.ints[0].erdp.write(self.cmd.events.trbs.physical() as u64); + + println!(" - Start"); + // Set run/stop to 1 + self.op.usb_cmd.writef(1, true); + + println!(" - Wait for running"); + // Wait until controller is running + while self.op.usb_sts.readf(1) { + println!(" - Waiting for XHCI running"); + } + + println!(" - Ring doorbell"); + // Ring command doorbell + self.dbs[0].write(0); + + println!(" - XHCI initialized"); + } + + pub fn probe(&mut self) { for (i, port) in self.ports.iter().enumerate() { let data = port.read(); let state = port.state(); @@ -265,12 +143,12 @@ impl Xhci { println!(" - Running Enable Slot command"); - self.cmds[0].enable_slot(0, true); + self.cmd.trbs[0].enable_slot(0, true); println!(" - Command"); - println!(" - data: {:X}", self.cmds[0].data.read()); - println!(" - status: {:X}", self.cmds[0].status.read()); - println!(" - control: {:X}", self.cmds[0].control.read()); + println!(" - data: {:X}", self.cmd.trbs[0].data.read()); + println!(" - status: {:X}", self.cmd.trbs[0].status.read()); + println!(" - control: {:X}", self.cmd.trbs[0].control.read()); self.dbs[0].write(0); @@ -280,8 +158,8 @@ impl Xhci { } println!(" - Response"); - println!(" - data: {:X}", self.events[0].trbs[0].data.read()); - println!(" - status: {:X}", self.events[0].trbs[0].status.read()); - println!(" - control: {:X}", self.events[0].trbs[0].control.read()); + println!(" - data: {:X}", self.cmd.events.trbs[0].data.read()); + println!(" - status: {:X}", self.cmd.events.trbs[0].status.read()); + println!(" - control: {:X}", self.cmd.events.trbs[0].control.read()); } } diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs new file mode 100644 index 0000000000..002be46506 --- /dev/null +++ b/xhcid/src/xhci/operational.rs @@ -0,0 +1,14 @@ +use syscall::io::Mmio; + +#[repr(packed)] +pub struct OperationalRegs { + pub usb_cmd: Mmio, + pub usb_sts: Mmio, + pub page_size: Mmio, + _rsvd: [Mmio; 2], + pub dn_ctrl: Mmio, + pub crcr: Mmio, + _rsvd2: [Mmio; 4], + pub dcbaap: Mmio, + pub config: Mmio, +} diff --git a/xhcid/src/xhci/port.rs b/xhcid/src/xhci/port.rs new file mode 100644 index 0000000000..50f23c9f18 --- /dev/null +++ b/xhcid/src/xhci/port.rs @@ -0,0 +1,53 @@ +use syscall::io::{Io, Mmio}; + +bitflags! { + pub flags PortFlags: u32 { + const PORT_CCS = 1 << 0, + const PORT_PED = 1 << 1, + const PORT_OCA = 1 << 3, + const PORT_PR = 1 << 4, + const PORT_PP = 1 << 9, + const PORT_PIC_AMB = 1 << 14, + const PORT_PIC_GRN = 1 << 15, + const PORT_LWS = 1 << 16, + const PORT_CSC = 1 << 17, + const PORT_PEC = 1 << 18, + const PORT_WRC = 1 << 19, + const PORT_OCC = 1 << 20, + const PORT_PRC = 1 << 21, + const PORT_PLC = 1 << 22, + const PORT_CEC = 1 << 23, + const PORT_CAS = 1 << 24, + const PORT_WCE = 1 << 25, + const PORT_WDE = 1 << 26, + const PORT_WOE = 1 << 27, + const PORT_DR = 1 << 30, + const PORT_WPR = 1 << 31, + } +} + +#[repr(packed)] +pub struct Port { + pub portsc : Mmio, + pub portpmsc : Mmio, + pub portli : Mmio, + pub porthlpmc : Mmio, +} + +impl Port { + pub fn read(&self) -> u32 { + self.portsc.read() + } + + pub fn state(&self) -> u32 { + (self.read() & (0b1111 << 5)) >> 5 + } + + pub fn speed(&self) -> u32 { + (self.read() & (0b1111 << 10)) >> 10 + } + + pub fn flags(&self) -> PortFlags { + PortFlags::from_bits_truncate(self.read()) + } +} diff --git a/xhcid/src/xhci/runtime.rs b/xhcid/src/xhci/runtime.rs new file mode 100644 index 0000000000..4dc4663ea4 --- /dev/null +++ b/xhcid/src/xhci/runtime.rs @@ -0,0 +1,18 @@ +use syscall::io::Mmio; + +#[repr(packed)] +pub struct Interrupter { + pub iman: Mmio, + pub imod: Mmio, + pub erstsz: Mmio, + _rsvd: Mmio, + pub erstba: Mmio, + pub erdp: Mmio, +} + +#[repr(packed)] +pub struct RuntimeRegs { + pub mfindex: Mmio, + _rsvd: [Mmio; 7], + pub ints: [Interrupter; 1024], +} diff --git a/xhcid/src/xhci/termios.rs b/xhcid/src/xhci/termios.rs deleted file mode 100644 index a9bac08040..0000000000 --- a/xhcid/src/xhci/termios.rs +++ /dev/null @@ -1,102 +0,0 @@ -use std::cell::RefCell; -use std::ops::{Deref, DerefMut}; -use std::rc::Weak; - -use syscall::error::{Error, Result, EBADF, EINVAL, EPIPE}; -use syscall::flag::{F_GETFL, F_SETFL, O_ACCMODE}; - -use pty::Pty; -use resource::Resource; - -/// Read side of a pipe -#[derive(Clone)] -pub struct PtyTermios { - pty: Weak>, - flags: usize, -} - -impl PtyTermios { - pub fn new(pty: Weak>, flags: usize) -> Self { - PtyTermios { - pty: pty, - flags: flags, - } - } -} - -impl Resource for PtyTermios { - fn boxed_clone(&self) -> Box { - Box::new(self.clone()) - } - - fn pty(&self) -> Weak> { - self.pty.clone() - } - - fn flags(&self) -> usize { - self.flags - } - - fn path(&self, buf: &mut [u8]) -> Result { - if let Some(pty_lock) = self.pty.upgrade() { - pty_lock.borrow_mut().path(buf) - } else { - Err(Error::new(EPIPE)) - } - } - - fn read(&self, buf: &mut [u8]) -> Result { - if let Some(pty_lock) = self.pty.upgrade() { - let pty = pty_lock.borrow(); - let termios: &[u8] = pty.termios.deref(); - - let mut i = 0; - while i < buf.len() && i < termios.len() { - buf[i] = termios[i]; - i += 1; - } - Ok(i) - } else { - Ok(0) - } - } - - fn write(&self, buf: &[u8]) -> Result { - if let Some(pty_lock) = self.pty.upgrade() { - let mut pty = pty_lock.borrow_mut(); - let termios: &mut [u8] = pty.termios.deref_mut(); - - let mut i = 0; - while i < buf.len() && i < termios.len() { - termios[i] = buf[i]; - i += 1; - } - Ok(i) - } else { - Err(Error::new(EPIPE)) - } - } - - fn sync(&self) -> Result { - Ok(0) - } - - fn fcntl(&mut self, cmd: usize, arg: usize) -> Result { - match cmd { - F_GETFL => Ok(self.flags), - F_SETFL => { - self.flags = (self.flags & O_ACCMODE) | (arg & ! O_ACCMODE); - Ok(0) - }, - _ => Err(Error::new(EINVAL)) - } - } - - fn fevent(&self) -> Result<()> { - Err(Error::new(EBADF)) - } - - fn fevent_count(&self) -> Option { - None - } -} From 84a8a6c0640325b2c545bbdfbb47a82d4a4a9774 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 27 Jul 2017 21:02:56 -0600 Subject: [PATCH 0170/1301] Add missing import --- xhcid/src/xhci/device.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xhcid/src/xhci/device.rs b/xhcid/src/xhci/device.rs index 82f8608699..362549468e 100644 --- a/xhcid/src/xhci/device.rs +++ b/xhcid/src/xhci/device.rs @@ -1,5 +1,5 @@ use syscall::error::Result; -use syscall::io::Dma; +use syscall::io::{Dma, Mmio}; #[repr(packed)] pub struct SlotContext { From 545ec4d21fa6b239cb7ee27f86a21baea9563f9b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 27 Jul 2017 21:28:16 -0600 Subject: [PATCH 0171/1301] Add more debugging --- xhcid/src/xhci/event.rs | 7 +++---- xhcid/src/xhci/mod.rs | 17 ++++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index 309eed226b..ae428281a4 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -6,9 +6,8 @@ use super::trb::Trb; #[repr(packed)] pub struct EventRingSte { pub address: Mmio, - pub size: Mmio, - _rsvd: Mmio, - _rsvd2: Mmio, + pub size: Mmio, + _rsvd: Mmio, } pub struct EventRing { @@ -24,7 +23,7 @@ impl EventRing { }; ring.ste.address.write(ring.trbs.physical() as u64); - ring.ste.size.write(ring.trbs.len() as u16); + ring.ste.size.write(ring.trbs.len() as u32); Ok(ring) } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 6b4d4a215f..a9c4b3f457 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -96,37 +96,40 @@ impl Xhci { } pub fn init(&mut self, max_slots: u8) { - println!(" - Set enabled slots"); // Set enabled slots + println!(" - Set enabled slots to {}", max_slots); self.op.config.write(max_slots as u32); println!(" - Enabled Slots: {}", self.op.config.read() & 0xFF); - println!(" - Write DCBAAP"); // Set device context address array pointer + println!(" - Write DCBAAP"); self.op.dcbaap.write(self.devices.dcbaap()); - println!(" - Write CRCR"); // Set command ring control register + println!(" - Write CRCR"); self.op.crcr.write(self.cmd.crcr()); - println!(" - Write ERST"); // Set event ring segment table registers + println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); + println!(" - Write ERSTZ"); self.run.ints[0].erstsz.write(1); + println!(" - Write ERSTBA: {:X}", self.cmd.events.ste.physical() as u64); self.run.ints[0].erstba.write(self.cmd.events.ste.physical() as u64); + println!(" - Write ERDP"); self.run.ints[0].erdp.write(self.cmd.events.trbs.physical() as u64); - println!(" - Start"); // Set run/stop to 1 + println!(" - Start"); self.op.usb_cmd.writef(1, true); - println!(" - Wait for running"); // Wait until controller is running + println!(" - Wait for running"); while self.op.usb_sts.readf(1) { println!(" - Waiting for XHCI running"); } - println!(" - Ring doorbell"); // Ring command doorbell + println!(" - Ring doorbell"); self.dbs[0].write(0); println!(" - XHCI initialized"); From e83471f53f83ab05b553c8989011cbad21215401 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 29 Jul 2017 08:24:33 -0600 Subject: [PATCH 0172/1301] Update Cargo.lock --- Cargo.lock | 103 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e6d440ebea..d94be338c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,7 @@ name = "xhcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -12,7 +12,7 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -23,7 +23,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -56,7 +56,7 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -88,6 +88,19 @@ dependencies = [ "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "conv" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "custom_derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "e1000d" version = "0.1.0" @@ -95,7 +108,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -162,7 +175,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -200,6 +213,23 @@ name = "log" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "magenta" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "magenta-sys" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "matches" version = "0.1.6" @@ -223,7 +253,7 @@ dependencies = [ "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -289,7 +319,7 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -303,7 +333,7 @@ name = "orbclient" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -311,10 +341,10 @@ dependencies = [ name = "pcid" version = "0.1.0" dependencies = [ - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -329,7 +359,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -339,10 +369,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -368,7 +399,7 @@ dependencies = [ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -376,12 +407,12 @@ name = "redox_event" version = "0.1.0" source = "git+https://github.com/redox-os/event.git#42d552e4765efbfb4ec39ce174900d3f48548a70" dependencies = [ - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -389,7 +420,7 @@ name = "redox_termios" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -411,7 +442,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -456,7 +487,7 @@ dependencies = [ "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.27.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -470,12 +501,12 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -529,7 +560,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -540,16 +571,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -609,7 +640,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -623,7 +654,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -665,6 +696,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" +"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" +"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" "checksum futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4b63a4792d4f8f686defe3b39b92127fea6344de5d38202b2ee5a11bbbf29d6a" "checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" @@ -678,6 +711,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb7b49972ee23d8aa1026c365a5b440ba08e35075f18c459980c7395c221ec48" "checksum linked-hash-map 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f26e961e0c884309cd527b1402a5409d35db612b36915d755e1a4f5c1547a31c" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" +"checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" +"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)" = "" @@ -692,12 +727,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9411f6bf9f60d65de1dcb601735ac0c904960f0f6ca03a13e6f02d25f842ea2c" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d" +"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" "checksum ransid 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e22373325a4a19d8350aae6ca20f43018fd2603b49a2721faa5c11273a7d4c41" "checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" "checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" "checksum redox_event 0.1.0 (git+https://github.com/redox-os/event.git)" = "" -"checksum redox_syscall 0.1.27 (registry+https://github.com/rust-lang/crates.io-index)" = "80dcf663dc552529b9bfc7bdb30ea12e5fa5d3545137d850a91ad410053f68e9" +"checksum redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "ddab7acd8e7bf3e49dfdf78ac1209b992329eb2f66e0bf672ab49c70a76d1d68" "checksum redox_termios 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc495930de8d330f14856cface52561b7d79a072c76e438cf8f34d7233a35fa7" "checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" "checksum rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17727f4b991294da2c84d75a43c003151ff58072212768800f66c56ee46dca43" @@ -706,8 +741,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918" "checksum sdl2 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c366cfa1f22d001774214ce2fb13f369af760b016bc79cc62d7f5ae15c00fea" "checksum sdl2-sys 0.27.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d9f87e3d948f94f2d8688970422f49249c20e97f8f3aad76cb8729901d4eb10" -"checksum serde 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "433d7d9f8530d5a939ad5e0e72a6243d2e42a24804f70bf592c679363dcacb2f" -"checksum serde_derive 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7b707cf0d4cab852084f573058def08879bb467fda89d99052485e7d00edd624" +"checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9" +"checksum serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cf823e706be268e73e7747b147aa31c8f633ab4ba31f115efb57e5047c3a76dd" "checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" "checksum spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1d16a26e2b789f86aabddbe91cb82ee2e822beb8a59840d631941b625ef77e53" "checksum stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21b5c3b588a493a477e0d99769ee091b3627625f9ba4bdd882e6b4b0b0958805" @@ -715,7 +750,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum termion 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8affd752d0f2c7127d6d5f1b98182a5471606b48b1a955165d39eb5e4887ceba" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" -"checksum toml 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b0601da6c97135c8d330c7a13a013ca6cd4143221b01de2f8d4edc50a9e551c7" +"checksum toml 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3e5e16033aacf7eead46cbcb62d06cf9d1c2aa1b12faa4039072f7ae5921103b" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" From 832f830cc4f0b77e493515cc227516cefa31f14e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 1 Aug 2017 19:40:25 -0600 Subject: [PATCH 0173/1301] Update EventSte structure --- xhcid/src/xhci/event.rs | 7 ++++--- xhcid/src/xhci/mod.rs | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index ae428281a4..309eed226b 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -6,8 +6,9 @@ use super::trb::Trb; #[repr(packed)] pub struct EventRingSte { pub address: Mmio, - pub size: Mmio, - _rsvd: Mmio, + pub size: Mmio, + _rsvd: Mmio, + _rsvd2: Mmio, } pub struct EventRing { @@ -23,7 +24,7 @@ impl EventRing { }; ring.ste.address.write(ring.trbs.physical() as u64); - ring.ste.size.write(ring.trbs.len() as u32); + ring.ste.size.write(ring.trbs.len() as u16); Ok(ring) } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index a9c4b3f457..30db7b9a83 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -111,12 +111,12 @@ impl Xhci { // Set event ring segment table registers println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); + println!(" - Write ERDP"); + self.run.ints[0].erdp.write(self.cmd.events.trbs.physical() as u64); println!(" - Write ERSTZ"); self.run.ints[0].erstsz.write(1); println!(" - Write ERSTBA: {:X}", self.cmd.events.ste.physical() as u64); self.run.ints[0].erstba.write(self.cmd.events.ste.physical() as u64); - println!(" - Write ERDP"); - self.run.ints[0].erdp.write(self.cmd.events.trbs.physical() as u64); // Set run/stop to 1 println!(" - Start"); From eb64f59d10d39a5373c2d1048c79e91841168a31 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 1 Aug 2017 19:43:55 -0600 Subject: [PATCH 0174/1301] Simplify vesad, use ptyd for control logic --- vesad/src/screen/text.rs | 46 +++------------------------------------- 1 file changed, 3 insertions(+), 43 deletions(-) diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 49ba28e9c4..eef26b1795 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -14,8 +14,6 @@ pub struct TextScreen { pub changed: BTreeSet, pub ctrl: bool, pub input: VecDeque, - pub end_of_input: bool, - pub cooked: VecDeque, pub requested: usize } @@ -27,8 +25,6 @@ impl TextScreen { changed: BTreeSet::new(), ctrl: false, input: VecDeque::new(), - end_of_input: false, - cooked: VecDeque::new(), requested: 0 } } @@ -117,38 +113,8 @@ impl Screen for TextScreen { _ => () //TODO: Mouse in terminal } - if self.console.raw_mode { - for &b in buf.iter() { - self.input.push_back(b); - } - } else { - for &b in buf.iter() { - match b { - b'\x03' => { - self.end_of_input = true; - let _ = self.write(b"^C\n", true); - }, - b'\x08' | b'\x7F' => { - if let Some(_c) = self.cooked.pop_back() { - let _ = self.write(b"\x08", true); - } - }, - b'\x1B' => { - let _ = self.write(b"^[", true); - }, - b'\n' | b'\r' => { - self.cooked.push_back(b); - while let Some(c) = self.cooked.pop_front() { - self.input.push_back(c); - } - let _ = self.write(b"\n", true); - }, - _ => { - self.cooked.push_back(b); - let _ = self.write(&[b], true); - } - } - } + for &b in buf.iter() { + self.input.push_back(b); } } @@ -160,17 +126,11 @@ impl Screen for TextScreen { i += 1; } - if i == 0 { - self.end_of_input = false; - } - Ok(i) } fn can_read(&self) -> Option { - if self.end_of_input { - Some(0) - } else if self.input.is_empty() { + if self.input.is_empty() { None } else { Some(self.input.len()) From a9d42d05fbd289ba55c803338e0d554d17f13927 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 2 Aug 2017 19:53:22 -0600 Subject: [PATCH 0175/1301] Update Cargo.lock --- Cargo.lock | 82 +++++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d94be338c0..9249bc501c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,7 @@ name = "xhcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -12,7 +12,7 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -23,7 +23,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -56,7 +56,7 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -108,7 +108,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -175,7 +175,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -200,7 +200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.28" +version = "0.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -246,15 +246,15 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://github.com/redox-os/netutils.git#f5ccf7232353107e46e3d9308a1631633ee0398a" +source = "git+https://github.com/redox-os/netutils.git#cdc0ebd10322ce0e9885da558a9d89d5c5d8abc4" dependencies = [ "hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.0 (git+https://github.com/redox-os/termion.git?branch=redox_termios)", ] [[package]] @@ -311,7 +311,7 @@ name = "num_cpus" version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -319,7 +319,7 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -333,7 +333,7 @@ name = "orbclient" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -341,7 +341,7 @@ dependencies = [ name = "pcid" version = "0.1.0" dependencies = [ - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -359,7 +359,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -372,13 +372,13 @@ name = "rand" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ransid" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -397,7 +397,7 @@ dependencies = [ "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -407,20 +407,20 @@ name = "redox_event" version = "0.1.0" source = "git+https://github.com/redox-os/event.git#42d552e4765efbfb4ec39ce174900d3f48548a70" dependencies = [ - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "redox_termios" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -430,7 +430,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -442,7 +442,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -485,7 +485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.27.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -496,7 +496,7 @@ name = "sdl2-sys" version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -557,11 +557,11 @@ dependencies = [ [[package]] name = "termion" version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/redox-os/termion.git?branch=redox_termios#cd455e835842831125df0ca23507384f5ae06c8b" dependencies = [ - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -570,8 +570,8 @@ version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -640,7 +640,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -653,8 +653,8 @@ name = "vesad" version = "0.1.0" dependencies = [ "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ransid 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "ransid 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -708,7 +708,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum libc 0.2.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb7b49972ee23d8aa1026c365a5b440ba08e35075f18c459980c7395c221ec48" +"checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264" "checksum linked-hash-map 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f26e961e0c884309cd527b1402a5409d35db612b36915d755e1a4f5c1547a31c" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" @@ -728,12 +728,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" -"checksum ransid 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e22373325a4a19d8350aae6ca20f43018fd2603b49a2721faa5c11273a7d4c41" +"checksum ransid 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "754ed82fc56508fc1353f0ab24affd4b055683a8ad4d53d39f7e4d8764c3efa4" "checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" "checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" "checksum redox_event 0.1.0 (git+https://github.com/redox-os/event.git)" = "" -"checksum redox_syscall 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "ddab7acd8e7bf3e49dfdf78ac1209b992329eb2f66e0bf672ab49c70a76d1d68" -"checksum redox_termios 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc495930de8d330f14856cface52561b7d79a072c76e438cf8f34d7233a35fa7" +"checksum redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9309631a35303bffb47e397198e3668cb544fe8834cd3da2a744441e70e524" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" "checksum rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17727f4b991294da2c84d75a43c003151ff58072212768800f66c56ee46dca43" "checksum rusttype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c64ffc93b0cc5a6f5e5e84da2a4082b0271e0a1dd76e821bdac570bda7797e" @@ -748,7 +748,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21b5c3b588a493a477e0d99769ee091b3627625f9ba4bdd882e6b4b0b0958805" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum termion 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8affd752d0f2c7127d6d5f1b98182a5471606b48b1a955165d39eb5e4887ceba" +"checksum termion 1.5.0 (git+https://github.com/redox-os/termion.git?branch=redox_termios)" = "" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" "checksum toml 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3e5e16033aacf7eead46cbcb62d06cf9d1c2aa1b12faa4039072f7ae5921103b" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" From 9a5a05b3b244b31e28827e1af27c77dfdf2f15bc Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 2 Aug 2017 20:02:30 -0600 Subject: [PATCH 0176/1301] Remove raw_mode usage from vesad --- vesad/src/screen/text.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index eef26b1795..06f450f1b2 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -183,7 +183,7 @@ impl Screen for TextScreen { self.changed.insert(y); } - if ! self.console.raw_mode && sync { + if sync { self.sync(); } From 1109da47fb481868755e09a1e61b334dbcebc506 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 2 Aug 2017 21:15:56 -0600 Subject: [PATCH 0177/1301] Update Cargo.lock --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9249bc501c..33e3407833 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://github.com/redox-os/netutils.git#cdc0ebd10322ce0e9885da558a9d89d5c5d8abc4" +source = "git+https://github.com/redox-os/netutils.git#47c0003ae18d23ff63cebe75e22bdc0bdbc069d7" dependencies = [ "hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -557,7 +557,7 @@ dependencies = [ [[package]] name = "termion" version = "1.5.0" -source = "git+https://github.com/redox-os/termion.git?branch=redox_termios#cd455e835842831125df0ca23507384f5ae06c8b" +source = "git+https://github.com/redox-os/termion.git?branch=redox_termios#18e589b9d92e8f93ae75475389e234bbe5deb109" dependencies = [ "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", From 646e8c9eac0fe62588b4aa2e595cb73f719d50dd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 3 Aug 2017 21:30:49 -0600 Subject: [PATCH 0178/1301] xhci: WIP grab device information --- xhcid/src/main.rs | 8 ++- xhcid/src/xhci/command.rs | 26 +++++++++- xhcid/src/xhci/device.rs | 13 ++++- xhcid/src/xhci/mod.rs | 102 +++++++++++++++++++++++++++++--------- xhcid/src/xhci/trb.rs | 30 +++++++++-- 5 files changed, 146 insertions(+), 33 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 586c3be9b1..2f09f8fe5a 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -25,13 +25,17 @@ fn main() { match Xhci::new(address) { Ok(mut xhci) => { - xhci.probe(); + if let Err(err) = xhci.probe() { + println!("xhcid: probe error: {}", err); + } }, Err(err) => { - println!("xhcid: error: {}", err); + println!("xhcid: open error: {}", err); } } unsafe { let _ = syscall::physunmap(address); } + + let _ = syscall::kill(1, syscall::SIGINT); } } diff --git a/xhcid/src/xhci/command.rs b/xhcid/src/xhci/command.rs index cbad816cff..3f0a5e8fe8 100644 --- a/xhcid/src/xhci/command.rs +++ b/xhcid/src/xhci/command.rs @@ -5,19 +5,43 @@ use super::event::EventRing; use super::trb::Trb; pub struct CommandRing { - pub trbs: Dma<[Trb; 256]>, + trbs: Dma<[Trb; 256]>, + cmd_i: usize, pub events: EventRing, + event_i: usize, } impl CommandRing { pub fn new() -> Result { Ok(CommandRing { trbs: Dma::zeroed()?, + cmd_i: 0, events: EventRing::new()?, + event_i: 0, }) } pub fn crcr(&self) -> u64 { self.trbs.physical() as u64 | 1 } + + pub fn next_cmd(&mut self) -> &mut Trb { + let i = self.cmd_i; + self.cmd_i += 1; + if self.cmd_i >= self.trbs.len() { + self.cmd_i = 0; + } + + &mut self.trbs[i] + } + + pub fn next_event(&mut self) -> &mut Trb { + let i = self.event_i; + self.event_i += 1; + if self.event_i >= self.events.trbs.len() { + self.event_i = 0; + } + + &mut self.events.trbs[i] + } } diff --git a/xhcid/src/xhci/device.rs b/xhcid/src/xhci/device.rs index 362549468e..d082f561ce 100644 --- a/xhcid/src/xhci/device.rs +++ b/xhcid/src/xhci/device.rs @@ -3,12 +3,21 @@ use syscall::io::{Dma, Mmio}; #[repr(packed)] pub struct SlotContext { - inner: [u8; 32] + pub a: Mmio, + pub b: Mmio, + pub c: Mmio, + pub d: Mmio, + _rsvd: [Mmio; 4], } #[repr(packed)] pub struct EndpointContext { - inner: [u8; 32] + pub a: Mmio, + pub b: Mmio, + pub trl: Mmio, + pub trh: Mmio, + pub c: Mmio, + _rsvd: [Mmio; 3], } #[repr(packed)] diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 30db7b9a83..5fced67c70 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,6 +1,6 @@ use std::slice; use syscall::error::Result; -use syscall::io::Io; +use syscall::io::{Dma, Io}; mod capability; mod command; @@ -59,6 +59,12 @@ impl Xhci { println!(" - Waiting for XHCI stopped"); } + println!(" - Reset"); + op.usb_cmd.writef(1 << 1, true); + while op.usb_sts.readf(1 << 1) { + println!(" - Waiting for XHCI reset"); + } + println!(" - Read max slots"); // Read maximum slots and ports let hcs_params1 = cap.hcs_params1.read(); @@ -111,10 +117,10 @@ impl Xhci { // Set event ring segment table registers println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); - println!(" - Write ERDP"); - self.run.ints[0].erdp.write(self.cmd.events.trbs.physical() as u64); println!(" - Write ERSTZ"); self.run.ints[0].erstsz.write(1); + println!(" - Write ERDP"); + self.run.ints[0].erdp.write(self.cmd.events.trbs.physical() as u64); println!(" - Write ERSTBA: {:X}", self.cmd.events.ste.physical() as u64); self.run.ints[0].erstba.write(self.cmd.events.ste.physical() as u64); @@ -135,34 +141,82 @@ impl Xhci { println!(" - XHCI initialized"); } - pub fn probe(&mut self) { + pub fn probe(&mut self) -> Result<()> { for (i, port) in self.ports.iter().enumerate() { let data = port.read(); let state = port.state(); let speed = port.speed(); let flags = port.flags(); println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags); + + if flags.contains(port::PORT_CCS) { + println!(" - Running Enable Slot command"); + + let db = &mut self.dbs[0]; + let crcr = &mut self.op.crcr; + let mut run = || { + db.write(0); + while crcr.readf(1 << 3) { + println!(" - Waiting for command completion"); + } + }; + + { + let cmd = self.cmd.next_cmd(); + cmd.enable_slot(0, true); + println!(" - Command: {}", cmd); + + run(); + + cmd.reserved(false); + } + + let slot; + { + let event = self.cmd.next_event(); + println!(" - Response: {}", event); + slot = (event.control.read() >> 24) as u8; + + event.reserved(false); + } + + println!(" Slot {}", slot); + + let mut trbs = Dma::<[trb::Trb; 256]>::zeroed()?; + let mut input = Dma::::zeroed()?; + { + input.add_context.write(1 << 1 | 1); + + input.device.slot.a.write(1 << 27); + input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16); + println!("{:>08X}", input.device.slot.b.read()); + + input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1); + input.device.endpoints[0].trh.write((trbs.physical() >> 32) as u32); + input.device.endpoints[0].trl.write(trbs.physical() as u32 | 1); + } + + { + let cmd = self.cmd.next_cmd(); + cmd.address_device(slot, input.physical(), true); + println!(" - Command: {}", cmd); + + run(); + + cmd.reserved(false); + } + + let address; + { + let event = self.cmd.next_event(); + println!(" - Response: {}", event); + address = (event.control.read() >> 24) as u8; + + event.reserved(false); + } + } } - println!(" - Running Enable Slot command"); - - self.cmd.trbs[0].enable_slot(0, true); - - println!(" - Command"); - println!(" - data: {:X}", self.cmd.trbs[0].data.read()); - println!(" - status: {:X}", self.cmd.trbs[0].status.read()); - println!(" - control: {:X}", self.cmd.trbs[0].control.read()); - - self.dbs[0].write(0); - - println!(" - Wait for command completion"); - while self.op.crcr.readf(1 << 3) { - println!(" - Waiting for command completion"); - } - - println!(" - Response"); - println!(" - data: {:X}", self.cmd.events.trbs[0].data.read()); - println!(" - status: {:X}", self.cmd.events.trbs[0].status.read()); - println!(" - control: {:X}", self.cmd.events.trbs[0].control.read()); + Ok(()) } } diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 2e54fd3430..b57f23dfbd 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -1,3 +1,4 @@ +use std::fmt; use syscall::io::{Io, Mmio}; #[repr(u8)] @@ -101,11 +102,10 @@ pub struct Trb { } impl Trb { - pub fn reset(&mut self, param: u64, status: u32, control: u16, trb_type: TrbType, evaluate_next: bool, cycle: bool) { + pub fn reset(&mut self, param: u64, status: u32, control: u16, trb_type: TrbType, cycle: bool) { let full_control = (control as u32) << 16 | ((trb_type as u32) & 0x3F) << 10 | - if evaluate_next { 1 << 1 } else { 0 } | if cycle { 1 << 0 } else { 0 }; self.data.write(param); @@ -113,11 +113,33 @@ impl Trb { self.control.write(full_control); } + pub fn reserved(&mut self, cycle: bool) { + self.reset(0, 0, 0, TrbType::Reserved, cycle); + } + pub fn no_op_cmd(&mut self, cycle: bool) { - self.reset(0, 0, 0, TrbType::NoOpCmd, false, cycle); + self.reset(0, 0, 0, TrbType::NoOpCmd, cycle); } pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) { - self.reset(0, 0, (slot_type as u16) & 0x1F, TrbType::EnableSlot, false, cycle); + self.reset(0, 0, (slot_type as u16) & 0x1F, TrbType::EnableSlot, cycle); + } + + pub fn address_device(&mut self, slot_id: u8, input: usize, cycle: bool) { + self.reset(input as u64, 0, (slot_id as u16) << 8, TrbType::AddressDevice, cycle); + } +} + +impl fmt::Debug for Trb { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Trb {{ data: {:>016X}, status: {:>08X}, control: {:>08X} }}", + self.data.read(), self.status.read(), self.control.read()) + } +} + +impl fmt::Display for Trb { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "({:>016X}, {:>08X}, {:>08X})", + self.data.read(), self.status.read(), self.control.read()) } } From dbceebbc09a8419358792743802e31b46bb056d5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 4 Aug 2017 08:54:16 -0600 Subject: [PATCH 0179/1301] Update main.rs --- xhcid/src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 2f09f8fe5a..4fc13e53c6 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -35,7 +35,5 @@ fn main() { } unsafe { let _ = syscall::physunmap(address); } - - let _ = syscall::kill(1, syscall::SIGINT); } } From 096a9a6e52d2d6db92220e40885a96a0f3e13816 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 5 Aug 2017 20:17:28 -0600 Subject: [PATCH 0180/1301] Read device, config, interface, and endpoint descriptions --- Cargo.lock | 7 ++ xhcid/Cargo.toml | 1 + xhcid/src/main.rs | 4 + xhcid/src/usb/config.rs | 12 +++ xhcid/src/usb/device.rs | 18 ++++ xhcid/src/usb/endpoint.rs | 14 +++ xhcid/src/usb/interface.rs | 17 ++++ xhcid/src/usb/mod.rs | 25 ++++++ xhcid/src/usb/setup.rs | 93 ++++++++++++++++++++ xhcid/src/xhci/command.rs | 16 ++++ xhcid/src/xhci/mod.rs | 175 ++++++++++++++++++++++++++++++------- xhcid/src/xhci/trb.rs | 84 ++++++++++++++---- 12 files changed, 420 insertions(+), 46 deletions(-) create mode 100644 xhcid/src/usb/config.rs create mode 100644 xhcid/src/usb/device.rs create mode 100644 xhcid/src/usb/endpoint.rs create mode 100644 xhcid/src/usb/interface.rs create mode 100644 xhcid/src/usb/mod.rs create mode 100644 xhcid/src/usb/setup.rs diff --git a/Cargo.lock b/Cargo.lock index 33e3407833..5d16f15d8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,6 +3,7 @@ name = "xhcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -352,6 +353,11 @@ name = "percent-encoding" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "plain" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ps2d" version = "0.1.0" @@ -726,6 +732,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" "checksum orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9411f6bf9f60d65de1dcb601735ac0c904960f0f6ca03a13e6f02d25f842ea2c" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" +"checksum plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da55423d5704ee357503ce020f88b90269610ec85708331e6a7879dd4cea3122" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" "checksum ransid 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "754ed82fc56508fc1353f0ab24affd4b055683a8ad4d53d39f7e4d8764c3efa4" diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index a5f5e61a27..e14cb52f24 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "0.7" +plain = "0.2" spin = "0.4" redox_syscall = "0.1" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 4fc13e53c6..96de918a50 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -1,11 +1,13 @@ #[macro_use] extern crate bitflags; +extern crate plain; extern crate syscall; use std::env; use xhci::Xhci; +mod usb; mod xhci; fn main() { @@ -35,5 +37,7 @@ fn main() { } unsafe { let _ = syscall::physunmap(address); } + + let _ = syscall::kill(1, syscall::SIGINT); } } diff --git a/xhcid/src/usb/config.rs b/xhcid/src/usb/config.rs new file mode 100644 index 0000000000..e387c731dc --- /dev/null +++ b/xhcid/src/usb/config.rs @@ -0,0 +1,12 @@ +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct ConfigDescriptor { + pub length: u8, + pub kind: u8, + pub total_length: u16, + pub interfaces: u8, + pub configuration_value: u8, + pub configuration_str: u8, + pub attributes: u8, + pub max_power: u8, +} diff --git a/xhcid/src/usb/device.rs b/xhcid/src/usb/device.rs new file mode 100644 index 0000000000..5ca20c6498 --- /dev/null +++ b/xhcid/src/usb/device.rs @@ -0,0 +1,18 @@ +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct DeviceDescriptor { + pub length: u8, + pub kind: u8, + pub usb: u16, + pub class: u8, + pub sub_class: u8, + pub protocol: u8, + pub packet_size: u8, + pub vendor: u16, + pub product: u16, + pub release: u16, + pub manufacturer_str: u8, + pub product_str: u8, + pub serial_str: u8, + pub configurations: u8, +} diff --git a/xhcid/src/usb/endpoint.rs b/xhcid/src/usb/endpoint.rs new file mode 100644 index 0000000000..b06648f151 --- /dev/null +++ b/xhcid/src/usb/endpoint.rs @@ -0,0 +1,14 @@ +use plain::Plain; + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct EndpointDescriptor { + pub length: u8, + pub kind: u8, + pub address: u8, + pub attributes: u8, + pub max_packet_size: u16, + pub interval: u8, +} + +unsafe impl Plain for EndpointDescriptor {} diff --git a/xhcid/src/usb/interface.rs b/xhcid/src/usb/interface.rs new file mode 100644 index 0000000000..5931e71893 --- /dev/null +++ b/xhcid/src/usb/interface.rs @@ -0,0 +1,17 @@ +use plain::Plain; + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct InterfaceDescriptor { + pub length: u8, + pub kind: u8, + pub number: u8, + pub alternate_setting: u8, + pub endpoints: u8, + pub class: u8, + pub sub_class: u8, + pub protocol: u8, + pub interface_str: u8, +} + +unsafe impl Plain for InterfaceDescriptor {} diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs new file mode 100644 index 0000000000..27d0e94b6d --- /dev/null +++ b/xhcid/src/usb/mod.rs @@ -0,0 +1,25 @@ +pub use self::config::ConfigDescriptor; +pub use self::device::DeviceDescriptor; +pub use self::endpoint::EndpointDescriptor; +pub use self::interface::InterfaceDescriptor; +pub use self::setup::Setup; + +#[repr(u8)] +pub enum DescriptorKind { + None, + Device, + Configuration, + String, + Interface, + Endpoint, + DeviceQualifier, + OtherSpeedConfiguration, + InterfacePower, + OnTheGo, +} + +mod config; +mod device; +mod endpoint; +mod interface; +mod setup; diff --git a/xhcid/src/usb/setup.rs b/xhcid/src/usb/setup.rs new file mode 100644 index 0000000000..366ed8f405 --- /dev/null +++ b/xhcid/src/usb/setup.rs @@ -0,0 +1,93 @@ +use super::DescriptorKind; + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct Setup { + pub kind: u8, + pub request: u8, + pub value: u16, + pub index: u16, + pub length: u16, +} + +impl Setup { + pub fn get_status() -> Self { + Self { + kind: 0b1000_0000, + request: 0x00, + value: 0, + index: 0, + length: 2, + } + } + + pub fn clear_feature(feature: u16) -> Self { + Self { + kind: 0b0000_0000, + request: 0x01, + value: feature, + index: 0, + length: 0, + } + } + + pub fn set_feature(feature: u16) -> Self { + Self { + kind: 0b0000_0000, + request: 0x03, + value: feature, + index: 0, + length: 0, + } + } + + pub fn set_address(address: u16) -> Self { + Self { + kind: 0b0000_0000, + request: 0x05, + value: address, + index: 0, + length: 0, + } + } + + pub fn get_descriptor(kind: DescriptorKind, index: u8, language: u16, length: u16) -> Self { + Self { + kind: 0b1000_0000, + request: 0x06, + value: ((kind as u16) << 8) | (index as u16), + index: language, + length: length, + } + } + + pub fn set_descriptor(kind: u8, index: u8, language: u16, length: u16) -> Self { + Self { + kind: 0b0000_0000, + request: 0x07, + value: ((kind as u16) << 8) | (index as u16), + index: language, + length: length, + } + } + + pub fn get_configuration() -> Self { + Self { + kind: 0b1000_0000, + request: 0x08, + value: 0, + index: 0, + length: 1, + } + } + + pub fn set_configuration(value: u16) -> Self { + Self { + kind: 0b0000_0000, + request: 0x09, + value: value, + index: 0, + length: 0, + } + } +} diff --git a/xhcid/src/xhci/command.rs b/xhcid/src/xhci/command.rs index 3f0a5e8fe8..8355d637fe 100644 --- a/xhcid/src/xhci/command.rs +++ b/xhcid/src/xhci/command.rs @@ -25,6 +25,22 @@ impl CommandRing { self.trbs.physical() as u64 | 1 } + pub fn next(&mut self) -> (&mut Trb, &mut Trb) { + let cmd_i = self.cmd_i; + self.cmd_i += 1; + if self.cmd_i >= self.trbs.len() { + self.cmd_i = 0; + } + + let event_i = self.event_i; + self.event_i += 1; + if self.event_i >= self.events.trbs.len() { + self.event_i = 0; + } + + (&mut self.trbs[cmd_i], &mut self.events.trbs[event_i]) + } + pub fn next_cmd(&mut self) -> &mut Trb { let i = self.cmd_i; self.cmd_i += 1; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 5fced67c70..d7e8981101 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,6 +1,8 @@ -use std::slice; +use plain::Plain; +use std::{mem, slice}; use syscall::error::Result; use syscall::io::{Dma, Io}; +use usb; mod capability; mod command; @@ -19,6 +21,58 @@ use self::doorbell::Doorbell; use self::operational::OperationalRegs; use self::port::Port; use self::runtime::RuntimeRegs; +use self::trb::TransferKind; + +struct Device<'a> { + trbs: Dma<[trb::Trb; 256]>, + trb_i: usize, + cmd: &'a mut CommandRing, + db: &'a mut Doorbell, +} + +impl<'a> Device<'a> { + fn get_desc(&mut self, kind: usb::DescriptorKind, index: u8, desc: &mut Dma) { + let len = mem::size_of::(); + + self.trbs[self.trb_i].setup( + usb::Setup::get_descriptor(kind, index, 0, len as u16), + TransferKind::In, true + ); + + self.trbs[self.trb_i + 1].data(desc.physical(), len as u16, true, true); + + self.trbs[self.trb_i + 2].status(false, true); + + self.db.write(1); + + let event = self.cmd.next_event(); + while event.data.read() == 0 { + println!(" - Waiting for event"); + } + + for _i in 0..3 { + self.trbs[self.trb_i].reserved(false); + self.trb_i += 1; + } + event.reserved(false); + } + + fn get_string(&mut self, index: u8) -> Result { + let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; + self.get_desc( + usb::DescriptorKind::String, + index, + &mut sdesc + ); + + let len = sdesc.0 as usize; + if len > 2 { + Ok(String::from_utf16(&sdesc.2[.. (len - 2)/2]).unwrap_or(String::new())) + } else { + Ok(String::new()) + } + } +} pub struct Xhci { cap: &'static mut CapabilityRegs, @@ -150,39 +204,33 @@ impl Xhci { println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags); if flags.contains(port::PORT_CCS) { - println!(" - Running Enable Slot command"); + //TODO: Link TRB when running to the end of the ring buffer - let db = &mut self.dbs[0]; - let crcr = &mut self.op.crcr; - let mut run = || { - db.write(0); - while crcr.readf(1 << 3) { - println!(" - Waiting for command completion"); - } - }; - - { - let cmd = self.cmd.next_cmd(); - cmd.enable_slot(0, true); - println!(" - Command: {}", cmd); - - run(); - - cmd.reserved(false); - } + println!(" - Enable slot"); let slot; { - let event = self.cmd.next_event(); + let (cmd, event) = self.cmd.next(); + + cmd.enable_slot(0, true); + println!(" - Command: {}", cmd); + + self.dbs[0].write(0); + + while event.data.read() == 0 { + println!(" - Waiting for event"); + } println!(" - Response: {}", event); slot = (event.control.read() >> 24) as u8; + cmd.reserved(false); event.reserved(false); } - println!(" Slot {}", slot); + println!(" - Slot {}", slot); let mut trbs = Dma::<[trb::Trb; 256]>::zeroed()?; + let mut trb_i = 0; let mut input = Dma::::zeroed()?; { input.add_context.write(1 << 1 | 1); @@ -197,22 +245,89 @@ impl Xhci { } { - let cmd = self.cmd.next_cmd(); + let (cmd, event) = self.cmd.next(); + cmd.address_device(slot, input.physical(), true); println!(" - Command: {}", cmd); - run(); + self.dbs[0].write(0); + + while event.data.read() == 0 { + println!(" - Waiting for event"); + } + println!(" - Response: {}", event); cmd.reserved(false); + event.reserved(false); } - let address; - { - let event = self.cmd.next_event(); - println!(" - Response: {}", event); - address = (event.control.read() >> 24) as u8; + let mut dev = Device { + trbs: trbs, + trb_i: trb_i, + cmd: &mut self.cmd, + db: &mut self.dbs[slot as usize], + }; - event.reserved(false); + println!(" - Get descriptor"); + + let mut ddesc = Dma::::zeroed()?; + dev.get_desc( + usb::DescriptorKind::Device, + 0, + &mut ddesc + ); + println!("{:?}", *ddesc); + + if ddesc.manufacturer_str > 0 { + println!(" Manufacturer: {}", dev.get_string(ddesc.manufacturer_str)?); + } + + if ddesc.product_str > 0 { + println!(" Product: {}", dev.get_string(ddesc.product_str)?); + } + + if ddesc.serial_str > 0 { + println!(" Serial: {}", dev.get_string(ddesc.serial_str)?); + } + + for config in 0..ddesc.configurations { + let mut cdesc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; + dev.get_desc( + usb::DescriptorKind::Configuration, + config, + &mut cdesc + ); + println!(" {}: {:?}", config, cdesc.0); + + if cdesc.0.configuration_str > 0 { + println!(" Name: {}", dev.get_string(cdesc.0.configuration_str)?); + } + + if cdesc.0.total_length as usize > mem::size_of::() { + let len = cdesc.0.total_length as usize - mem::size_of::(); + let data = &cdesc.1[..len]; + + let mut i = 0; + for interface in 0..cdesc.0.interfaces { + let mut idesc = usb::InterfaceDescriptor::default(); + if i < data.len() && idesc.copy_from_bytes(&data[i..]).is_ok() { + i += mem::size_of_val(&idesc); + println!(" {}: {:?}", interface, idesc); + + if idesc.interface_str > 0 { + println!(" Name: {}", dev.get_string(idesc.interface_str)?); + } + + for endpoint in 0..idesc.endpoints { + let mut edesc = usb::EndpointDescriptor::default(); + if i < data.len() && edesc.copy_from_bytes(&data[i..]).is_ok() { + i += mem::size_of_val(&edesc); + println!(" {}: {:?}", endpoint, edesc); + } + } + } + } + } } } } diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index b57f23dfbd..72c14c3dc8 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -1,5 +1,6 @@ -use std::fmt; +use std::{fmt, mem}; use syscall::io::{Io, Mmio}; +use usb; #[repr(u8)] pub enum TrbType { @@ -94,6 +95,14 @@ pub enum TrbCompletionCode { /* 224 to 255 are vendor defined information */ } +#[repr(u8)] +pub enum TransferKind { + NoData, + Reserved, + Out, + In, +} + #[repr(packed)] pub struct Trb { pub data: Mmio, @@ -102,31 +111,74 @@ pub struct Trb { } impl Trb { - pub fn reset(&mut self, param: u64, status: u32, control: u16, trb_type: TrbType, cycle: bool) { - let full_control = - (control as u32) << 16 | - ((trb_type as u32) & 0x3F) << 10 | - if cycle { 1 << 0 } else { 0 }; - - self.data.write(param); - self.status.write(status); - self.control.write(full_control); - } - pub fn reserved(&mut self, cycle: bool) { - self.reset(0, 0, 0, TrbType::Reserved, cycle); + self.data.write(0); + self.status.write(0); + self.control.write( + ((TrbType::Reserved as u32) << 10) | + (cycle as u32) + ); } pub fn no_op_cmd(&mut self, cycle: bool) { - self.reset(0, 0, 0, TrbType::NoOpCmd, cycle); + self.data.write(0); + self.status.write(0); + self.control.write( + ((TrbType::NoOpCmd as u32) << 10) | + (cycle as u32) + ); } pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) { - self.reset(0, 0, (slot_type as u16) & 0x1F, TrbType::EnableSlot, cycle); + self.data.write(0); + self.status.write(0); + self.control.write( + (((slot_type as u32) & 0x1F) << 16) | + ((TrbType::EnableSlot as u32) << 10) | + (cycle as u32) + ); } pub fn address_device(&mut self, slot_id: u8, input: usize, cycle: bool) { - self.reset(input as u64, 0, (slot_id as u16) << 8, TrbType::AddressDevice, cycle); + self.data.write(input as u64); + self.status.write(0); + self.control.write( + ((slot_id as u32) << 24) | + ((TrbType::AddressDevice as u32) << 10) | + (cycle as u32) + ); + } + + pub fn setup(&mut self, setup: usb::Setup, transfer: TransferKind, cycle: bool) { + self.data.write(unsafe { mem::transmute(setup) }); + self.status.write((0 << 22) | 8); + self.control.write( + ((transfer as u32) << 16) | + ((TrbType::SetupStage as u32) << 10) | + (1 << 6) | + (cycle as u32) + ); + } + + pub fn data(&mut self, buffer: usize, length: u16, input: bool, cycle: bool) { + self.data.write(buffer as u64); + self.status.write((0 << 22) | length as u32); + self.control.write( + ((input as u32) << 16) | + ((TrbType::DataStage as u32) << 10) | + (cycle as u32) + ); + } + + pub fn status(&mut self, input: bool, cycle: bool) { + self.data.write(0); + self.status.write(0 << 22); + self.control.write( + ((input as u32) << 16) | + ((TrbType::StatusStage as u32) << 10) | + (1 << 5) | + (cycle as u32) + ); } } From 144cc2a995b1434c0cca72f74e5ad511c8e31ad2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 5 Aug 2017 21:07:08 -0600 Subject: [PATCH 0181/1301] Prettier format of debug data --- xhcid/src/xhci/mod.rs | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index d7e8981101..fece88f241 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -206,28 +206,26 @@ impl Xhci { if flags.contains(port::PORT_CCS) { //TODO: Link TRB when running to the end of the ring buffer - println!(" - Enable slot"); + println!(" - Enable slot"); let slot; { let (cmd, event) = self.cmd.next(); cmd.enable_slot(0, true); - println!(" - Command: {}", cmd); self.dbs[0].write(0); while event.data.read() == 0 { - println!(" - Waiting for event"); + println!(" - Waiting for event"); } - println!(" - Response: {}", event); slot = (event.control.read() >> 24) as u8; cmd.reserved(false); event.reserved(false); } - println!(" - Slot {}", slot); + println!(" - Slot {}", slot); let mut trbs = Dma::<[trb::Trb; 256]>::zeroed()?; let mut trb_i = 0; @@ -237,7 +235,6 @@ impl Xhci { input.device.slot.a.write(1 << 27); input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16); - println!("{:>08X}", input.device.slot.b.read()); input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1); input.device.endpoints[0].trh.write((trbs.physical() >> 32) as u32); @@ -248,14 +245,12 @@ impl Xhci { let (cmd, event) = self.cmd.next(); cmd.address_device(slot, input.physical(), true); - println!(" - Command: {}", cmd); self.dbs[0].write(0); while event.data.read() == 0 { - println!(" - Waiting for event"); + println!(" - Waiting for event"); } - println!(" - Response: {}", event); cmd.reserved(false); event.reserved(false); @@ -268,7 +263,7 @@ impl Xhci { db: &mut self.dbs[slot as usize], }; - println!(" - Get descriptor"); + println!(" - Get descriptor"); let mut ddesc = Dma::::zeroed()?; dev.get_desc( @@ -276,18 +271,18 @@ impl Xhci { 0, &mut ddesc ); - println!("{:?}", *ddesc); + println!(" {:?}", *ddesc); if ddesc.manufacturer_str > 0 { - println!(" Manufacturer: {}", dev.get_string(ddesc.manufacturer_str)?); + println!(" Manufacturer: {}", dev.get_string(ddesc.manufacturer_str)?); } if ddesc.product_str > 0 { - println!(" Product: {}", dev.get_string(ddesc.product_str)?); + println!(" Product: {}", dev.get_string(ddesc.product_str)?); } if ddesc.serial_str > 0 { - println!(" Serial: {}", dev.get_string(ddesc.serial_str)?); + println!(" Serial: {}", dev.get_string(ddesc.serial_str)?); } for config in 0..ddesc.configurations { @@ -297,10 +292,10 @@ impl Xhci { config, &mut cdesc ); - println!(" {}: {:?}", config, cdesc.0); + println!(" {}: {:?}", config, cdesc.0); if cdesc.0.configuration_str > 0 { - println!(" Name: {}", dev.get_string(cdesc.0.configuration_str)?); + println!(" Name: {}", dev.get_string(cdesc.0.configuration_str)?); } if cdesc.0.total_length as usize > mem::size_of::() { @@ -312,17 +307,17 @@ impl Xhci { let mut idesc = usb::InterfaceDescriptor::default(); if i < data.len() && idesc.copy_from_bytes(&data[i..]).is_ok() { i += mem::size_of_val(&idesc); - println!(" {}: {:?}", interface, idesc); + println!(" {}: {:?}", interface, idesc); if idesc.interface_str > 0 { - println!(" Name: {}", dev.get_string(idesc.interface_str)?); + println!(" Name: {}", dev.get_string(idesc.interface_str)?); } for endpoint in 0..idesc.endpoints { let mut edesc = usb::EndpointDescriptor::default(); if i < data.len() && edesc.copy_from_bytes(&data[i..]).is_ok() { i += mem::size_of_val(&edesc); - println!(" {}: {:?}", endpoint, edesc); + println!(" {}: {:?}", endpoint, edesc); } } } From d15635e24202c34c92c785059550d46d34dd6637 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 6 Aug 2017 08:09:11 -0600 Subject: [PATCH 0182/1301] Do not shut down after running --- xhcid/src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 96de918a50..cf8dcef795 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -37,7 +37,5 @@ fn main() { } unsafe { let _ = syscall::physunmap(address); } - - let _ = syscall::kill(1, syscall::SIGINT); } } From 0231e4489276867ff6ee1f48e3eec8c887e43ab6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 6 Aug 2017 08:20:31 -0600 Subject: [PATCH 0183/1301] Print out more values --- xhcid/src/xhci/mod.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index fece88f241..f2668595e2 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -162,21 +162,27 @@ impl Xhci { println!(" - Enabled Slots: {}", self.op.config.read() & 0xFF); // Set device context address array pointer - println!(" - Write DCBAAP"); - self.op.dcbaap.write(self.devices.dcbaap()); + let dcbaap = self.devices.dcbaap(); + println!(" - Write DCBAAP: {:X}", dcbaap); + self.op.dcbaap.write(dcbaap as u64); // Set command ring control register - println!(" - Write CRCR"); - self.op.crcr.write(self.cmd.crcr()); + let crcr = self.cmd.crcr(); + println!(" - Write CRCR: {:X}", crcr); + self.op.crcr.write(crcr as u64); // Set event ring segment table registers println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); println!(" - Write ERSTZ"); self.run.ints[0].erstsz.write(1); - println!(" - Write ERDP"); - self.run.ints[0].erdp.write(self.cmd.events.trbs.physical() as u64); - println!(" - Write ERSTBA: {:X}", self.cmd.events.ste.physical() as u64); - self.run.ints[0].erstba.write(self.cmd.events.ste.physical() as u64); + + let erdp = self.cmd.events.trbs.physical(); + println!(" - Write ERDP: {:X}", erdp); + self.run.ints[0].erdp.write(erdp as u64); + + let erstba = self.cmd.events.ste.physical(); + println!(" - Write ERSTBA: {:X}", erstba); + self.run.ints[0].erstba.write(erstba as u64); // Set run/stop to 1 println!(" - Start"); From 14d816507914b7c4c2c5e6389f3aeeea0e911b3f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 6 Aug 2017 15:19:56 -0600 Subject: [PATCH 0184/1301] Cleanup xhci, add basic IRQ event functions, cleanup e1000d and rtl8168d --- Cargo.lock | 10 +++ e1000d/src/main.rs | 4 +- rtl8168d/src/main.rs | 2 +- xhcid/Cargo.toml | 1 + xhcid/src/main.rs | 92 +++++++++++++++++++++--- xhcid/src/xhci/{device.rs => context.rs} | 8 +-- xhcid/src/xhci/mod.rs | 90 +++++++++++++---------- 7 files changed, 151 insertions(+), 56 deletions(-) rename xhcid/src/xhci/{device.rs => context.rs} (90%) diff --git a/Cargo.lock b/Cargo.lock index 5d16f15d8c..a0da78a630 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,6 +4,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -416,6 +417,14 @@ dependencies = [ "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox_event" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_syscall" version = "0.1.29" @@ -739,6 +748,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" "checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" "checksum redox_event 0.1.0 (git+https://github.com/redox-os/event.git)" = "" +"checksum redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98e1a40d38f45a3ad65fd088640eeee7b215adcd73041b9f94b92204cca9572a" "checksum redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9309631a35303bffb47e397198e3668cb544fe8834cd3da2a744441e70e524" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 0d59ed52b7..00a6d81301 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -29,7 +29,7 @@ fn main() { let irq_str = args.next().expect("e1000d: no irq provided"); let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); - print!("{}", format!(" + E1000 {} on: {:X}, IRQ: {}\n", name, bar, irq)); + print!("{}", format!(" + E1000 {} on: {:X} IRQ: {}\n", name, bar, irq)); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { @@ -100,7 +100,7 @@ fn main() { } Ok(None) - }).expect("e1000d: failed to catch events on IRQ file"); + }).expect("e1000d: failed to catch events on scheme file"); for event_count in event_queue.trigger_all(0).expect("e1000d: failed to trigger events") { socket.borrow_mut().write(&Packet { diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 27ba048aa7..3f7b905a58 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -104,7 +104,7 @@ fn main() { } Ok(None) - }).expect("rtl8168d: failed to catch events on IRQ file"); + }).expect("rtl8168d: failed to catch events on scheme file"); for event_count in event_queue.trigger_all(0).expect("rtl8168d: failed to trigger events") { socket.borrow_mut().write(&Packet { diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index e14cb52f24..3618ef835b 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -6,4 +6,5 @@ version = "0.1.0" bitflags = "0.7" plain = "0.2" spin = "0.4" +redox_event = "0.1" redox_syscall = "0.1" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index cf8dcef795..4839fd2cf8 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -1,9 +1,19 @@ #[macro_use] extern crate bitflags; +extern crate event; extern crate plain; extern crate syscall; +use event::EventQueue; +use std::cell::RefCell; use std::env; +use std::fs::File; +use std::io::{Result, Read, Write}; +use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::sync::Arc; +use syscall::data::Packet; +use syscall::error::EWOULDBLOCK; +use syscall::scheme::SchemeMut; use xhci::Xhci; @@ -19,23 +29,85 @@ fn main() { let bar_str = args.next().expect("xhcid: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("xhcid: failed to parse address"); - print!("{}", format!(" + XHCI {} on: {:X}\n", name, bar)); + let irq_str = args.next().expect("xhcid: no IRQ provided"); + let irq = irq_str.parse::().expect("xhcid: failed to parse irq"); + + print!("{}", format!(" + XHCI {} on: {:X} IRQ: {}\n", name, bar, irq)); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { + let socket_fd = syscall::open(":usb", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme"); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + + let mut irq_file = File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); + let address = unsafe { syscall::physmap(bar, 65536, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; + { + let mut hci = Xhci::new(address).expect("xhcid: failed to allocate device"); - match Xhci::new(address) { - Ok(mut xhci) => { - if let Err(err) = xhci.probe() { - println!("xhcid: probe error: {}", err); + hci.probe().expect("xhcid: failed to probe"); + + let mut event_queue = EventQueue::<()>::new().expect("xhcid: failed to create event queue"); + + let todo = Arc::new(RefCell::new(Vec::::new())); + + //let device_irq = device.clone(); + let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + /* + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + + let isr = unsafe { device_irq.borrow_mut().irq() }; + if isr != 0 { + irq_file.write(&mut irq)?; + + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + device_irq.borrow_mut().handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; + } else { + socket_irq.borrow_mut().write(&mut todo[i])?; + todo.remove(i); + } + } } - }, - Err(err) => { - println!("xhcid: open error: {}", err); - } - } + */ + Ok(None) + }).expect("xhcid: failed to catch events on IRQ file"); + let socket_fd = socket.borrow().as_raw_fd(); + let socket_packet = socket.clone(); + event_queue.add(socket_fd, move |_count: usize| -> Result> { + /* + loop { + let mut packet = Packet::default(); + if socket_packet.borrow_mut().read(&mut packet)? == 0 { + break; + } + + let a = packet.a; + device.borrow_mut().handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket_packet.borrow_mut().write(&mut packet)?; + } + } + */ + Ok(None) + }).expect("xhcid: failed to catch events on scheme file"); + + event_queue.trigger_all(0).expect("xhcid: failed to trigger events"); + + event_queue.run().expect("xhcid: failed to handle events"); + } unsafe { let _ = syscall::physunmap(address); } } } diff --git a/xhcid/src/xhci/device.rs b/xhcid/src/xhci/context.rs similarity index 90% rename from xhcid/src/xhci/device.rs rename to xhcid/src/xhci/context.rs index d082f561ce..0203922628 100644 --- a/xhcid/src/xhci/device.rs +++ b/xhcid/src/xhci/context.rs @@ -35,13 +35,13 @@ pub struct InputContext { pub device: DeviceContext, } -pub struct DeviceList { +pub struct DeviceContextList { pub dcbaa: Dma<[u64; 256]>, pub contexts: Vec>, } -impl DeviceList { - pub fn new(max_slots: u8) -> Result { +impl DeviceContextList { + pub fn new(max_slots: u8) -> Result { let mut dcbaa = Dma::<[u64; 256]>::zeroed()?; let mut contexts = vec![]; @@ -53,7 +53,7 @@ impl DeviceList { contexts.push(context); } - Ok(DeviceList { + Ok(DeviceContextList { dcbaa: dcbaa, contexts: contexts }) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index f2668595e2..239995788c 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -6,7 +6,7 @@ use usb; mod capability; mod command; -mod device; +mod context; mod doorbell; mod event; mod operational; @@ -16,7 +16,7 @@ mod trb; use self::capability::CapabilityRegs; use self::command::CommandRing; -use self::device::DeviceList; +use self::context::{DeviceContextList, InputContext}; use self::doorbell::Doorbell; use self::operational::OperationalRegs; use self::port::Port; @@ -57,6 +57,26 @@ impl<'a> Device<'a> { event.reserved(false); } + fn get_device(&mut self) -> Result { + let mut desc = Dma::::zeroed()?; + self.get_desc( + usb::DescriptorKind::Device, + 0, + &mut desc + ); + Ok(*desc) + } + + fn get_config(&mut self, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { + let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; + self.get_desc( + usb::DescriptorKind::Configuration, + config, + &mut desc + ); + Ok(*desc) + } + fn get_string(&mut self, index: u8) -> Result { let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; self.get_desc( @@ -80,7 +100,7 @@ pub struct Xhci { ports: &'static mut [Port], dbs: &'static mut [Doorbell], run: &'static mut RuntimeRegs, - devices: DeviceList, + dev_ctx: DeviceContextList, cmd: CommandRing, } @@ -146,7 +166,7 @@ impl Xhci { ports: ports, dbs: dbs, run: run, - devices: DeviceList::new(max_slots)?, + dev_ctx: DeviceContextList::new(max_slots)?, cmd: CommandRing::new()?, }; @@ -162,7 +182,7 @@ impl Xhci { println!(" - Enabled Slots: {}", self.op.config.read() & 0xFF); // Set device context address array pointer - let dcbaap = self.devices.dcbaap(); + let dcbaap = self.dev_ctx.dcbaap(); println!(" - Write DCBAAP: {:X}", dcbaap); self.op.dcbaap.write(dcbaap as u64); @@ -173,16 +193,19 @@ impl Xhci { // Set event ring segment table registers println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); - println!(" - Write ERSTZ"); - self.run.ints[0].erstsz.write(1); + { + let erstz = 1; + println!(" - Write ERSTZ: {}", erstz); + self.run.ints[0].erstsz.write(erstz); - let erdp = self.cmd.events.trbs.physical(); - println!(" - Write ERDP: {:X}", erdp); - self.run.ints[0].erdp.write(erdp as u64); + let erdp = self.cmd.events.trbs.physical(); + println!(" - Write ERDP: {:X}", erdp); + self.run.ints[0].erdp.write(erdp as u64); - let erstba = self.cmd.events.ste.physical(); - println!(" - Write ERSTBA: {:X}", erstba); - self.run.ints[0].erstba.write(erstba as u64); + let erstba = self.cmd.events.ste.physical(); + println!(" - Write ERSTBA: {:X}", erstba); + self.run.ints[0].erstba.write(erstba as u64); + } // Set run/stop to 1 println!(" - Start"); @@ -234,12 +257,12 @@ impl Xhci { println!(" - Slot {}", slot); let mut trbs = Dma::<[trb::Trb; 256]>::zeroed()?; - let mut trb_i = 0; - let mut input = Dma::::zeroed()?; + + let mut input = Dma::::zeroed()?; { input.add_context.write(1 << 1 | 1); - input.device.slot.a.write(1 << 27); + input.device.slot.a.write((1 << 27) | (speed << 20)); input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16); input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1); @@ -264,20 +287,15 @@ impl Xhci { let mut dev = Device { trbs: trbs, - trb_i: trb_i, + trb_i: 0, cmd: &mut self.cmd, db: &mut self.dbs[slot as usize], }; println!(" - Get descriptor"); - let mut ddesc = Dma::::zeroed()?; - dev.get_desc( - usb::DescriptorKind::Device, - 0, - &mut ddesc - ); - println!(" {:?}", *ddesc); + let ddesc = dev.get_device()?; + println!(" {:?}", ddesc); if ddesc.manufacturer_str > 0 { println!(" Manufacturer: {}", dev.get_string(ddesc.manufacturer_str)?); @@ -292,26 +310,20 @@ impl Xhci { } for config in 0..ddesc.configurations { - let mut cdesc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; - dev.get_desc( - usb::DescriptorKind::Configuration, - config, - &mut cdesc - ); - println!(" {}: {:?}", config, cdesc.0); + let (cdesc, data) = dev.get_config(config)?; + println!(" {}: {:?}", config, cdesc); - if cdesc.0.configuration_str > 0 { - println!(" Name: {}", dev.get_string(cdesc.0.configuration_str)?); + if cdesc.configuration_str > 0 { + println!(" Name: {}", dev.get_string(cdesc.configuration_str)?); } - if cdesc.0.total_length as usize > mem::size_of::() { - let len = cdesc.0.total_length as usize - mem::size_of::(); - let data = &cdesc.1[..len]; + if cdesc.total_length as usize > mem::size_of::() { + let len = cdesc.total_length as usize - mem::size_of::(); let mut i = 0; - for interface in 0..cdesc.0.interfaces { + for interface in 0..cdesc.interfaces { let mut idesc = usb::InterfaceDescriptor::default(); - if i < data.len() && idesc.copy_from_bytes(&data[i..]).is_ok() { + if i < len && i < data.len() && idesc.copy_from_bytes(&data[i..len]).is_ok() { i += mem::size_of_val(&idesc); println!(" {}: {:?}", interface, idesc); @@ -321,7 +333,7 @@ impl Xhci { for endpoint in 0..idesc.endpoints { let mut edesc = usb::EndpointDescriptor::default(); - if i < data.len() && edesc.copy_from_bytes(&data[i..]).is_ok() { + if i < len && i < data.len() && edesc.copy_from_bytes(&data[i..len]).is_ok() { i += mem::size_of_val(&edesc); println!(" {}: {:?}", endpoint, edesc); } From 87342d6fce2c8869e676d0a557e7e4e96f526ad1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 6 Aug 2017 17:16:07 -0600 Subject: [PATCH 0185/1301] Improve ring state machine --- xhcid/src/main.rs | 18 ++++----- xhcid/src/xhci/command.rs | 53 +++++++++--------------- xhcid/src/xhci/context.rs | 1 - xhcid/src/xhci/event.rs | 13 ++++-- xhcid/src/xhci/mod.rs | 84 ++++++++++++++++++++++++++------------- xhcid/src/xhci/ring.rs | 53 ++++++++++++++++++++++++ xhcid/src/xhci/scheme.rs | 4 ++ xhcid/src/xhci/trb.rs | 58 +++++++++++++++++---------- 8 files changed, 184 insertions(+), 100 deletions(-) create mode 100644 xhcid/src/xhci/ring.rs create mode 100644 xhcid/src/xhci/scheme.rs diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 4839fd2cf8..18fba44441 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -43,31 +43,29 @@ fn main() { let address = unsafe { syscall::physmap(bar, 65536, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; { - let mut hci = Xhci::new(address).expect("xhcid: failed to allocate device"); + let hci = Arc::new(RefCell::new(Xhci::new(address).expect("xhcid: failed to allocate device"))); - hci.probe().expect("xhcid: failed to probe"); + hci.borrow_mut().probe().expect("xhcid: failed to probe"); let mut event_queue = EventQueue::<()>::new().expect("xhcid: failed to create event queue"); let todo = Arc::new(RefCell::new(Vec::::new())); - //let device_irq = device.clone(); + let hci_irq = hci.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { - /* let mut irq = [0; 8]; irq_file.read(&mut irq)?; - let isr = unsafe { device_irq.borrow_mut().irq() }; - if isr != 0 { + if hci_irq.borrow_mut().irq() { irq_file.write(&mut irq)?; let mut todo = todo_irq.borrow_mut(); let mut i = 0; while i < todo.len() { let a = todo[i].a; - device_irq.borrow_mut().handle(&mut todo[i]); + hci_irq.borrow_mut().handle(&mut todo[i]); if todo[i].a == (-EWOULDBLOCK) as usize { todo[i].a = a; i += 1; @@ -77,14 +75,13 @@ fn main() { } } } - */ + Ok(None) }).expect("xhcid: failed to catch events on IRQ file"); let socket_fd = socket.borrow().as_raw_fd(); let socket_packet = socket.clone(); event_queue.add(socket_fd, move |_count: usize| -> Result> { - /* loop { let mut packet = Packet::default(); if socket_packet.borrow_mut().read(&mut packet)? == 0 { @@ -92,7 +89,7 @@ fn main() { } let a = packet.a; - device.borrow_mut().handle(&mut packet); + hci.borrow_mut().handle(&mut packet); if packet.a == (-EWOULDBLOCK) as usize { packet.a = a; todo.borrow_mut().push(packet); @@ -100,7 +97,6 @@ fn main() { socket_packet.borrow_mut().write(&mut packet)?; } } - */ Ok(None) }).expect("xhcid: failed to catch events on scheme file"); diff --git a/xhcid/src/xhci/command.rs b/xhcid/src/xhci/command.rs index 8355d637fe..76ba0e6b4e 100644 --- a/xhcid/src/xhci/command.rs +++ b/xhcid/src/xhci/command.rs @@ -2,62 +2,45 @@ use syscall::error::Result; use syscall::io::Dma; use super::event::EventRing; +use super::ring::Ring; use super::trb::Trb; pub struct CommandRing { - trbs: Dma<[Trb; 256]>, - cmd_i: usize, + pub ring: Ring, pub events: EventRing, - event_i: usize, } impl CommandRing { pub fn new() -> Result { Ok(CommandRing { - trbs: Dma::zeroed()?, - cmd_i: 0, + ring: Ring::new(true)?, events: EventRing::new()?, - event_i: 0, }) } pub fn crcr(&self) -> u64 { - self.trbs.physical() as u64 | 1 + self.ring.register() } - pub fn next(&mut self) -> (&mut Trb, &mut Trb) { - let cmd_i = self.cmd_i; - self.cmd_i += 1; - if self.cmd_i >= self.trbs.len() { - self.cmd_i = 0; - } - - let event_i = self.event_i; - self.event_i += 1; - if self.event_i >= self.events.trbs.len() { - self.event_i = 0; - } - - (&mut self.trbs[cmd_i], &mut self.events.trbs[event_i]) + pub fn erdp(&self) -> u64 { + self.events.ring.register() } - pub fn next_cmd(&mut self) -> &mut Trb { - let i = self.cmd_i; - self.cmd_i += 1; - if self.cmd_i >= self.trbs.len() { - self.cmd_i = 0; - } + pub fn erstba(&self) -> u64 { + self.events.ste.physical() as u64 + } - &mut self.trbs[i] + pub fn next(&mut self) -> (&mut Trb, bool, &mut Trb) { + let cmd = self.ring.next(); + let event = self.events.next(); + (cmd.0, cmd.1, event) + } + + pub fn next_cmd(&mut self) -> (&mut Trb, bool) { + self.ring.next() } pub fn next_event(&mut self) -> &mut Trb { - let i = self.event_i; - self.event_i += 1; - if self.event_i >= self.events.trbs.len() { - self.event_i = 0; - } - - &mut self.events.trbs[i] + self.events.next() } } diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 0203922628..5f9a978bfe 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -47,7 +47,6 @@ impl DeviceContextList { // Create device context buffers for each slot for i in 0..max_slots as usize { - println!(" - Setup dev ctx {}", i); let context: Dma = Dma::zeroed()?; dcbaa[i] = context.physical() as u64; contexts.push(context); diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index 309eed226b..903b34cbb6 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -1,6 +1,7 @@ use syscall::error::Result; use syscall::io::{Dma, Io, Mmio}; +use super::ring::Ring; use super::trb::Trb; #[repr(packed)] @@ -13,19 +14,23 @@ pub struct EventRingSte { pub struct EventRing { pub ste: Dma, - pub trbs: Dma<[Trb; 256]> + pub ring: Ring, } impl EventRing { pub fn new() -> Result { let mut ring = EventRing { ste: Dma::zeroed()?, - trbs: Dma::zeroed()? + ring: Ring::new(false)?, }; - ring.ste.address.write(ring.trbs.physical() as u64); - ring.ste.size.write(ring.trbs.len() as u16); + ring.ste.address.write(ring.ring.trbs.physical() as u64); + ring.ste.size.write(ring.ring.trbs.len() as u16); Ok(ring) } + + pub fn next(&mut self) -> &mut Trb { + self.ring.next().0 + } } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 239995788c..795d9a7169 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -12,6 +12,8 @@ mod event; mod operational; mod port; mod runtime; +mod ring; +mod scheme; mod trb; use self::capability::CapabilityRegs; @@ -20,41 +22,49 @@ use self::context::{DeviceContextList, InputContext}; use self::doorbell::Doorbell; use self::operational::OperationalRegs; use self::port::Port; -use self::runtime::RuntimeRegs; +use self::ring::Ring; +use self::runtime::{RuntimeRegs, Interrupter}; use self::trb::TransferKind; struct Device<'a> { - trbs: Dma<[trb::Trb; 256]>, - trb_i: usize, + ring: &'a mut Ring, cmd: &'a mut CommandRing, db: &'a mut Doorbell, + int: &'a mut Interrupter, } impl<'a> Device<'a> { fn get_desc(&mut self, kind: usb::DescriptorKind, index: u8, desc: &mut Dma) { let len = mem::size_of::(); - self.trbs[self.trb_i].setup( - usb::Setup::get_descriptor(kind, index, 0, len as u16), - TransferKind::In, true - ); + { + let (cmd, cycle) = self.ring.next(); + cmd.setup( + usb::Setup::get_descriptor(kind, index, 0, len as u16), + TransferKind::In, cycle + ); + } - self.trbs[self.trb_i + 1].data(desc.physical(), len as u16, true, true); + { + let (cmd, cycle) = self.ring.next(); + cmd.data(desc.physical(), len as u16, true, cycle); + } - self.trbs[self.trb_i + 2].status(false, true); + { + let (cmd, cycle) = self.ring.next(); + cmd.status(false, cycle); + } self.db.write(1); - let event = self.cmd.next_event(); - while event.data.read() == 0 { - println!(" - Waiting for event"); + { + let event = self.cmd.next_event(); + while event.data.read() == 0 { + println!(" - Waiting for event"); + } } - for _i in 0..3 { - self.trbs[self.trb_i].reserved(false); - self.trb_i += 1; - } - event.reserved(false); + self.int.erdp.write(self.cmd.erdp()); } fn get_device(&mut self) -> Result { @@ -198,13 +208,16 @@ impl Xhci { println!(" - Write ERSTZ: {}", erstz); self.run.ints[0].erstsz.write(erstz); - let erdp = self.cmd.events.trbs.physical(); + let erdp = self.cmd.erdp(); println!(" - Write ERDP: {:X}", erdp); self.run.ints[0].erdp.write(erdp as u64); - let erstba = self.cmd.events.ste.physical(); + let erstba = self.cmd.erstba(); println!(" - Write ERSTBA: {:X}", erstba); self.run.ints[0].erstba.write(erstba as u64); + + println!(" - Enable interrupts"); + self.run.ints[0].iman.writef(1 << 1, true); } // Set run/stop to 1 @@ -239,9 +252,9 @@ impl Xhci { let slot; { - let (cmd, event) = self.cmd.next(); + let (cmd, cycle, event) = self.cmd.next(); - cmd.enable_slot(0, true); + cmd.enable_slot(0, cycle); self.dbs[0].write(0); @@ -254,9 +267,11 @@ impl Xhci { event.reserved(false); } + self.run.ints[0].erdp.write(self.cmd.erdp()); + println!(" - Slot {}", slot); - let mut trbs = Dma::<[trb::Trb; 256]>::zeroed()?; + let mut ring = Ring::new(true)?; let mut input = Dma::::zeroed()?; { @@ -266,14 +281,15 @@ impl Xhci { input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16); input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1); - input.device.endpoints[0].trh.write((trbs.physical() >> 32) as u32); - input.device.endpoints[0].trl.write(trbs.physical() as u32 | 1); + let tr = ring.register(); + input.device.endpoints[0].trh.write((tr >> 32) as u32); + input.device.endpoints[0].trl.write(tr as u32); } { - let (cmd, event) = self.cmd.next(); + let (cmd, cycle, event) = self.cmd.next(); - cmd.address_device(slot, input.physical(), true); + cmd.address_device(slot, input.physical(), cycle); self.dbs[0].write(0); @@ -285,11 +301,13 @@ impl Xhci { event.reserved(false); } + self.run.ints[0].erdp.write(self.cmd.erdp()); + let mut dev = Device { - trbs: trbs, - trb_i: 0, + ring: &mut ring, cmd: &mut self.cmd, db: &mut self.dbs[slot as usize], + int: &mut self.run.ints[0], }; println!(" - Get descriptor"); @@ -347,4 +365,14 @@ impl Xhci { Ok(()) } + + pub fn irq(&mut self) -> bool { + if self.run.ints[0].iman.readf(1) { + println!("XHCI Interrupt"); + self.run.ints[0].iman.writef(1, true); + true + } else { + false + } + } } diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs new file mode 100644 index 0000000000..e615e95a10 --- /dev/null +++ b/xhcid/src/xhci/ring.rs @@ -0,0 +1,53 @@ +use syscall::error::Result; +use syscall::io::Dma; + +use super::trb::Trb; + +pub struct Ring { + pub link: bool, + pub trbs: Dma<[Trb; 16]>, + pub i: usize, + pub cycle: bool, +} + +impl Ring { + pub fn new(link: bool) -> Result { + Ok(Ring { + link: link, + trbs: Dma::zeroed()?, + i: 0, + cycle: link, + }) + } + + pub fn register(&self) -> u64 { + let base = self.trbs.physical() as *const Trb; + let addr = unsafe { base.offset(self.i as isize) }; + addr as u64 | self.cycle as u64 + } + + pub fn next(&mut self) -> (&mut Trb, bool) { + let mut i; + loop { + i = self.i; + self.i += 1; + if self.i >= self.trbs.len() { + self.i = 0; + + if self.link { + println!("Link"); + let address = self.trbs.physical(); + self.trbs[i].link(address, true, self.cycle); + self.cycle = !self.cycle; + } else { + println!("No-link"); + break; + } + } else { + break; + } + } + + (&mut self.trbs[i], self.cycle) + } +} diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs new file mode 100644 index 0000000000..e1531c7dd1 --- /dev/null +++ b/xhcid/src/xhci/scheme.rs @@ -0,0 +1,4 @@ +use super::Xhci; +use syscall::scheme::SchemeMut; + +impl SchemeMut for Xhci {} diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 72c14c3dc8..c4193422ae 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -111,28 +111,44 @@ pub struct Trb { } impl Trb { + pub fn set(&mut self, data: u64, status: u32, control: u32) { + self.data.write(data); + self.status.write(status); + self.control.write(control); + } + pub fn reserved(&mut self, cycle: bool) { - self.data.write(0); - self.status.write(0); - self.control.write( + self.set( + 0, + 0, ((TrbType::Reserved as u32) << 10) | (cycle as u32) ); } + pub fn link(&mut self, address: usize, toggle: bool, cycle: bool) { + self.set( + address as u64, + 0, + ((TrbType::Link as u32) << 10) | + ((toggle as u32) << 1) | + (cycle as u32) + ); + } + pub fn no_op_cmd(&mut self, cycle: bool) { - self.data.write(0); - self.status.write(0); - self.control.write( + self.set( + 0, + 0, ((TrbType::NoOpCmd as u32) << 10) | (cycle as u32) ); } pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) { - self.data.write(0); - self.status.write(0); - self.control.write( + self.set( + 0, + 0, (((slot_type as u32) & 0x1F) << 16) | ((TrbType::EnableSlot as u32) << 10) | (cycle as u32) @@ -140,9 +156,9 @@ impl Trb { } pub fn address_device(&mut self, slot_id: u8, input: usize, cycle: bool) { - self.data.write(input as u64); - self.status.write(0); - self.control.write( + self.set( + input as u64, + 0, ((slot_id as u32) << 24) | ((TrbType::AddressDevice as u32) << 10) | (cycle as u32) @@ -150,9 +166,9 @@ impl Trb { } pub fn setup(&mut self, setup: usb::Setup, transfer: TransferKind, cycle: bool) { - self.data.write(unsafe { mem::transmute(setup) }); - self.status.write((0 << 22) | 8); - self.control.write( + self.set( + unsafe { mem::transmute(setup) }, + 8, ((transfer as u32) << 16) | ((TrbType::SetupStage as u32) << 10) | (1 << 6) | @@ -161,9 +177,9 @@ impl Trb { } pub fn data(&mut self, buffer: usize, length: u16, input: bool, cycle: bool) { - self.data.write(buffer as u64); - self.status.write((0 << 22) | length as u32); - self.control.write( + self.set( + buffer as u64, + length as u32, ((input as u32) << 16) | ((TrbType::DataStage as u32) << 10) | (cycle as u32) @@ -171,9 +187,9 @@ impl Trb { } pub fn status(&mut self, input: bool, cycle: bool) { - self.data.write(0); - self.status.write(0 << 22); - self.control.write( + self.set( + 0, + 0, ((input as u32) << 16) | ((TrbType::StatusStage as u32) << 10) | (1 << 5) | From 649f1c8b208a311479ccf0a0c835ea9b50f1f7b0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 6 Aug 2017 17:19:07 -0600 Subject: [PATCH 0186/1301] Remove debugging of ring --- xhcid/src/xhci/ring.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index e615e95a10..b1fae6ffdb 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -35,12 +35,10 @@ impl Ring { self.i = 0; if self.link { - println!("Link"); let address = self.trbs.physical(); self.trbs[i].link(address, true, self.cycle); self.cycle = !self.cycle; } else { - println!("No-link"); break; } } else { From 18f28d46b459368412e9943b6d05ba26c5362597 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 12 Aug 2017 11:20:56 -0600 Subject: [PATCH 0187/1301] Update mut usage in vesad --- vesad/src/scheme.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 7d9fede491..3e538c27ca 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -133,7 +133,7 @@ impl SchemeMut for DisplayScheme { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(mut screen) = self.screens.get_mut(&screen_i) { + if let Some(screen) = self.screens.get_mut(&screen_i) { return screen.event(flags).and(Ok(screen_i)); } } @@ -182,7 +182,7 @@ impl SchemeMut for DisplayScheme { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(mut screen) = self.screens.get_mut(&screen_i) { + if let Some(screen) = self.screens.get_mut(&screen_i) { if screen_i == self.active { screen.sync(); } @@ -197,7 +197,7 @@ impl SchemeMut for DisplayScheme { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(mut screen) = self.screens.get_mut(&screen_i) { + if let Some(screen) = self.screens.get_mut(&screen_i) { return screen.read(buf); } } @@ -211,7 +211,7 @@ impl SchemeMut for DisplayScheme { match handle.kind { HandleKind::Input => if buf.len() == 1 && buf[0] >= 0xF4 { let new_active = (buf[0] - 0xF4) as usize + 1; - if let Some(mut screen) = self.screens.get_mut(&new_active) { + if let Some(screen) = self.screens.get_mut(&new_active) { self.active = new_active; screen.redraw(); } @@ -247,12 +247,12 @@ impl SchemeMut for DisplayScheme { }; if let Some(new_active) = new_active_opt { - if let Some(mut screen) = self.screens.get_mut(&new_active) { + if let Some(screen) = self.screens.get_mut(&new_active) { self.active = new_active; screen.redraw(); } } else { - if let Some(mut screen) = self.screens.get_mut(&self.active) { + if let Some(screen) = self.screens.get_mut(&self.active) { screen.input(event); } } @@ -260,7 +260,7 @@ impl SchemeMut for DisplayScheme { Ok(events.len() * mem::size_of::()) }, - HandleKind::Screen(screen_i) => if let Some(mut screen) = self.screens.get_mut(&screen_i) { + HandleKind::Screen(screen_i) => if let Some(screen) = self.screens.get_mut(&screen_i) { screen.write(buf, screen_i == self.active) } else { Err(Error::new(EBADF)) @@ -272,7 +272,7 @@ impl SchemeMut for DisplayScheme { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(mut screen) = self.screens.get_mut(&screen_i) { + if let Some(screen) = self.screens.get_mut(&screen_i) { return screen.seek(pos, whence); } } From 68938a755c318474fbce22e64a4b8858568137ef Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 19 Aug 2017 14:47:03 -0600 Subject: [PATCH 0188/1301] Update Cargo.lock --- Cargo.lock | 95 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 67 insertions(+), 28 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0da78a630..b6bea8a05f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -14,7 +14,7 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -25,9 +25,14 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arg_parser" +version = "0.1.0" +source = "git+https://github.com/redox-os/arg-parser.git#1b6a9505a1e9c39af1836ecbee293a987619a539" + [[package]] name = "arrayvec" version = "0.3.23" @@ -58,7 +63,7 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -110,7 +115,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -118,6 +123,11 @@ name = "either" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "extra" +version = "0.1.0" +source = "git+https://github.com/redox-os/libextra.git#402932084acd5fef4812945887ceaaa2ddd5f264" + [[package]] name = "futures" version = "0.1.14" @@ -125,7 +135,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "gcc" -version = "0.3.51" +version = "0.3.52" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -177,7 +187,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -248,14 +258,17 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://github.com/redox-os/netutils.git#47c0003ae18d23ff63cebe75e22bdc0bdbc069d7" +source = "git+https://github.com/redox-os/netutils.git#a09e97dbe67e1e8d194da7c9900e1e5b2111cded" dependencies = [ + "arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)", + "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", "hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", + "pbr 1.0.0 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.0 (git+https://github.com/redox-os/termion.git?branch=redox_termios)", ] @@ -321,7 +334,7 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -335,18 +348,30 @@ name = "orbclient" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pbr" +version = "1.0.0" +source = "git+https://github.com/a8m/pb#e9369ed2b94df4f554fe79c2643de41f7338475f" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pcid" version = "0.1.0" dependencies = [ - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -366,7 +391,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -414,7 +439,7 @@ name = "redox_event" version = "0.1.0" source = "git+https://github.com/redox-os/event.git#42d552e4765efbfb4ec39ce174900d3f48548a70" dependencies = [ - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -422,12 +447,12 @@ name = "redox_event" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.29" +version = "0.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -435,7 +460,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -443,7 +468,7 @@ name = "ring" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.52 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -457,7 +482,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -575,7 +600,17 @@ version = "1.5.0" source = "git+https://github.com/redox-os/termion.git?branch=redox_termios#18e589b9d92e8f93ae75475389e234bbe5deb109" dependencies = [ "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -586,13 +621,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -655,7 +690,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -669,7 +704,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -703,6 +738,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "699e63a93b79d717e8c3b5eb1b28b7780d0d6d9e59a72eb769291c83b0c8dc67" "checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" @@ -714,8 +750,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" +"checksum extra 0.1.0 (git+https://github.com/redox-os/libextra.git)" = "" "checksum futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4b63a4792d4f8f686defe3b39b92127fea6344de5d38202b2ee5a11bbbf29d6a" -"checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a" +"checksum gcc 0.3.52 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7d19683108136d21d32723077e69cd5df2bfd6d102c74a01d743cf2b65cf97" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" "checksum hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0f01e4a20f5dfa5278d7762b7bdb7cab96e24378b9eca3889fbd4b5e94dc7063" "checksum hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04535774f79684c99528944ebdb89756c945c027e55ce52faa245879d836c8fb" @@ -740,6 +777,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" "checksum orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9411f6bf9f60d65de1dcb601735ac0c904960f0f6ca03a13e6f02d25f842ea2c" +"checksum pbr 1.0.0 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" "checksum plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da55423d5704ee357503ce020f88b90269610ec85708331e6a7879dd4cea3122" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" @@ -749,7 +787,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" "checksum redox_event 0.1.0 (git+https://github.com/redox-os/event.git)" = "" "checksum redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98e1a40d38f45a3ad65fd088640eeee7b215adcd73041b9f94b92204cca9572a" -"checksum redox_syscall 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "3c9309631a35303bffb47e397198e3668cb544fe8834cd3da2a744441e70e524" +"checksum redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "8312fba776a49cf390b7b62f3135f9b294d8617f7a7592cfd0ac2492b658cd7b" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" "checksum rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17727f4b991294da2c84d75a43c003151ff58072212768800f66c56ee46dca43" @@ -766,8 +804,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum termion 1.5.0 (git+https://github.com/redox-os/termion.git?branch=redox_termios)" = "" +"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" -"checksum toml 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3e5e16033aacf7eead46cbcb62d06cf9d1c2aa1b12faa4039072f7ae5921103b" +"checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" From 1e7240eda6563019d9fc85552ae7dafb1287d0da Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Aug 2017 09:24:13 -0600 Subject: [PATCH 0189/1301] Update config.rs --- pcid/src/config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pcid/src/config.rs b/pcid/src/config.rs index efe88944a5..44c5e71df9 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -8,6 +8,7 @@ pub struct DriverConfig { pub name: Option, pub class: Option, pub subclass: Option, + pub interface: Option, pub vendor: Option, pub device: Option, pub command: Option> From 1d7e51b42323bba3621983c2c2516557ff2c5ce0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Aug 2017 09:24:55 -0600 Subject: [PATCH 0190/1301] Update main.rs --- pcid/src/main.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index a4345608c6..8d2b99b963 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -100,6 +100,10 @@ fn main() { if subclass != header.subclass { continue; } } + if let Some(interface) = driver.interface { + if interface != header.interface { continue; } + } + if let Some(vendor) = driver.vendor { if vendor != header.vendor_id { continue; } } From ee58fcaa6176c26d13a5a1433e2eb85b860c3a0c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Aug 2017 19:19:07 -0600 Subject: [PATCH 0191/1301] Spin for reset, do not yield --- e1000d/src/device.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 95e6bf2990..d7be0e9630 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -281,9 +281,8 @@ impl Intel8254x { pub unsafe fn init(&mut self) { self.flag(CTRL, CTRL_RST, true); - thread::sleep(time::Duration::new(0, 1000)); while self.read(CTRL) & CTRL_RST == CTRL_RST { - thread::yield_now(); + print!(" - Waiting for reset: {:X}\n", self.read(CTRL)); } // Enable auto negotiate, link, clear reset, do not Invert Loss-Of Signal @@ -360,9 +359,8 @@ impl Intel8254x { // TIPG Packet Gap // TODO ... - print!(" - Waiting for link up\n"); while self.read(STATUS) & 2 != 2 { - thread::yield_now(); + print!(" - Waiting for link up: {:X}\n", self.read(STATUS)); } print!(" - Link is up with speed {}\n", match (self.read(STATUS) >> 6) & 0b11 { 0b00 => "10 Mb/s", From 770a23ef942e5614952b5117659f4fc805721420 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Aug 2017 20:08:37 -0600 Subject: [PATCH 0192/1301] Add ability to query BGA --- bgad/src/main.rs | 16 +++++++++ bgad/src/scheme.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 bgad/src/scheme.rs diff --git a/bgad/src/main.rs b/bgad/src/main.rs index eef1377e6e..699c09eb63 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -3,11 +3,17 @@ extern crate syscall; use std::env; +use std::fs::File; +use std::io::{Read, Write}; use syscall::iopl; +use syscall::data::Packet; +use syscall::scheme::SchemeMut; use bga::Bga; +use scheme::BgaScheme; mod bga; +mod scheme; fn main() { let mut args = env::args().skip(1); @@ -24,7 +30,17 @@ fn main() { if unsafe { syscall::clone(0).unwrap() } == 0 { unsafe { iopl(3).unwrap() }; + let mut socket = File::create(":bga").expect("bgad: failed to create bga scheme"); + let mut bga = Bga::new(); print!("{}", format!(" - BGA {}x{}\n", bga.width(), bga.height())); + + let mut scheme = BgaScheme { bga: bga }; + loop { + let mut packet = Packet::default(); + socket.read(&mut packet).expect("bgad: failed to read events from bga scheme"); + scheme.handle(&mut packet); + socket.write(&packet).expect("bgad: failed to write responses to bga scheme"); + } } } diff --git a/bgad/src/scheme.rs b/bgad/src/scheme.rs new file mode 100644 index 0000000000..d87e1f06b5 --- /dev/null +++ b/bgad/src/scheme.rs @@ -0,0 +1,88 @@ +use std::str; + +use syscall::{Error, Result, SchemeMut, EACCES, EINVAL, MODE_CHR}; +use syscall::data::Stat; + +use bga::Bga; + +pub struct BgaScheme { + pub bga: Bga +} + +impl SchemeMut for BgaScheme { + fn open(&mut self, _path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { + if uid == 0 { + Ok(0) + } else { + Err(Error::new(EACCES)) + } + } + + fn dup(&mut self, file: usize, buf: &[u8]) -> Result { + if ! buf.is_empty() { + return Err(Error::new(EINVAL)); + } + + Ok(file) + } + + fn read(&mut self, _file: usize, buf: &mut [u8]) -> Result { + let mut i = 0; + let data = format!("{},{}\n", self.bga.width(), self.bga.height()).into_bytes(); + while i < buf.len() && i < data.len() { + buf[i] = data[i]; + i += 1; + } + Ok(i) + } + + fn write(&mut self, _file: usize, buf: &[u8]) -> Result { + let string = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?; + let string = string.trim(); + + let mut parts = string.split(','); + + let width = if let Some(part) = parts.next() { + part.parse::().or(Err(Error::new(EINVAL)))? + } else { + self.bga.width() + }; + + let height = if let Some(part) = parts.next() { + part.parse::().or(Err(Error::new(EINVAL)))? + } else { + self.bga.height() + }; + + self.bga.set_size(width, height); + + Ok(buf.len()) + } + + fn fpath(&mut self, _file: usize, buf: &mut [u8]) -> Result { + let mut i = 0; + let scheme_path = b"bga"; + while i < buf.len() && i < scheme_path.len() { + buf[i] = scheme_path[i]; + i += 1; + } + Ok(i) + } + + fn fstat(&mut self, _id: usize, stat: &mut Stat) -> Result { + *stat = Stat { + st_mode: MODE_CHR | 0o666, + ..Default::default() + }; + + Ok(0) + } + + fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize) -> Result { + Ok(0) + } + + fn close(&mut self, _file: usize) -> Result { + Ok(0) + } +} From 4e40c1c8afb64c714fdfc80704038cc69b176e69 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Aug 2017 20:19:58 -0600 Subject: [PATCH 0193/1301] Add method for resizing display --- Cargo.lock | 1 + bgad/Cargo.toml | 1 + bgad/src/main.rs | 6 +++++- bgad/src/scheme.rs | 14 ++++++++++++-- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b6bea8a05f..c6f29da420 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,6 +63,7 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ + "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml index 9a28ece41e..289f65cd54 100644 --- a/bgad/Cargo.toml +++ b/bgad/Cargo.toml @@ -3,4 +3,5 @@ name = "bgad" version = "0.1.0" [dependencies] +orbclient = "0.3" redox_syscall = "0.1" diff --git a/bgad/src/main.rs b/bgad/src/main.rs index 699c09eb63..e5ee67d723 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -1,5 +1,6 @@ #![deny(warnings)] +extern crate orbclient; extern crate syscall; use std::env; @@ -35,7 +36,10 @@ fn main() { let mut bga = Bga::new(); print!("{}", format!(" - BGA {}x{}\n", bga.width(), bga.height())); - let mut scheme = BgaScheme { bga: bga }; + let mut scheme = BgaScheme { + bga: bga, + display: File::open("display:input").ok() + }; loop { let mut packet = Packet::default(); socket.read(&mut packet).expect("bgad: failed to read events from bga scheme"); diff --git a/bgad/src/scheme.rs b/bgad/src/scheme.rs index d87e1f06b5..e4ce64eced 100644 --- a/bgad/src/scheme.rs +++ b/bgad/src/scheme.rs @@ -1,12 +1,15 @@ +use orbclient; +use std::fs::File; +use std::io::Write; use std::str; - use syscall::{Error, Result, SchemeMut, EACCES, EINVAL, MODE_CHR}; use syscall::data::Stat; use bga::Bga; pub struct BgaScheme { - pub bga: Bga + pub bga: Bga, + pub display: Option, } impl SchemeMut for BgaScheme { @@ -56,6 +59,13 @@ impl SchemeMut for BgaScheme { self.bga.set_size(width, height); + if let Some(ref mut display) = self.display { + let _ = display.write(&orbclient::ResizeEvent { + width: width as u32, + height: height as u32, + }.to_event()); + } + Ok(buf.len()) } From ebbd50d299e7d6220da9231321dbc32e35e2cf62 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 23 Aug 2017 19:59:15 -0600 Subject: [PATCH 0194/1301] Update lock file --- Cargo.lock | 40 ++++++++++------------------------------ 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6f29da420..478f23d985 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,14 +42,6 @@ dependencies = [ "odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "base64" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "base64" version = "0.6.0" @@ -136,7 +128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "gcc" -version = "0.3.52" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -146,10 +138,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hyper" -version = "0.10.12" +version = "0.10.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -167,7 +159,7 @@ name = "hyper-rustls" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -259,18 +251,18 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://github.com/redox-os/netutils.git#a09e97dbe67e1e8d194da7c9900e1e5b2111cded" +source = "git+https://github.com/redox-os/netutils.git#849b72c5b9e77a654a51521276dc6f2223a67aec" dependencies = [ "arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", - "hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.0 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.0 (git+https://github.com/redox-os/termion.git?branch=redox_termios)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -469,7 +461,7 @@ name = "ring" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.52 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -595,16 +587,6 @@ dependencies = [ "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "termion" -version = "1.5.0" -source = "git+https://github.com/redox-os/termion.git?branch=redox_termios#18e589b9d92e8f93ae75475389e234bbe5deb109" -dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "termion" version = "1.5.1" @@ -741,7 +723,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "699e63a93b79d717e8c3b5eb1b28b7780d0d6d9e59a72eb769291c83b0c8dc67" -"checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" @@ -753,9 +734,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" "checksum extra 0.1.0 (git+https://github.com/redox-os/libextra.git)" = "" "checksum futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4b63a4792d4f8f686defe3b39b92127fea6344de5d38202b2ee5a11bbbf29d6a" -"checksum gcc 0.3.52 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7d19683108136d21d32723077e69cd5df2bfd6d102c74a01d743cf2b65cf97" +"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" -"checksum hyper 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0f01e4a20f5dfa5278d7762b7bdb7cab96e24378b9eca3889fbd4b5e94dc7063" +"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04535774f79684c99528944ebdb89756c945c027e55ce52faa245879d836c8fb" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" @@ -804,7 +785,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21b5c3b588a493a477e0d99769ee091b3627625f9ba4bdd882e6b4b0b0958805" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum termion 1.5.0 (git+https://github.com/redox-os/termion.git?branch=redox_termios)" = "" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" From bc186fbb0d1a648d5985c02eceb07a75586189d6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 27 Aug 2017 11:23:05 -0600 Subject: [PATCH 0195/1301] Disable XHCI driver due to lockups --- filesystem.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/filesystem.toml b/filesystem.toml index 2124a24a6b..7405c0736e 100644 --- a/filesystem.toml +++ b/filesystem.toml @@ -45,9 +45,9 @@ device = 33128 command = ["rtl8168d", "$NAME", "$BAR2", "$IRQ"] # xhcid -[[drivers]] -name = "XHCI" -class = 12 -subclass = 3 -interface = 48 -command = ["xhcid", "$NAME", "$BAR0", "$IRQ"] +# [[drivers]] +# name = "XHCI" +# class = 12 +# subclass = 3 +# interface = 48 +# command = ["xhcid", "$NAME", "$BAR0", "$IRQ"] From 053524acacb197156f119e8033425818cc6be41c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 30 Aug 2017 22:03:10 -0600 Subject: [PATCH 0196/1301] Remove unused extern crate --- ahcid/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 19a37a8250..d887a3f021 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -1,7 +1,6 @@ #![deny(warnings)] #![feature(asm)] -extern crate bitflags; extern crate spin; extern crate syscall; From 17b592b0642b0e4a96b46d9785ada9b57b3dac8c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 30 Aug 2017 22:05:56 -0600 Subject: [PATCH 0197/1301] Remove unnecessary extern crate --- pcid/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 8d2b99b963..b3017391c3 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,7 +1,6 @@ #![deny(warnings)] #![feature(asm)] -extern crate serde; #[macro_use] extern crate serde_derive; extern crate syscall; extern crate toml; From 46c84616ec12e157765e11b7e69b3408db8b8013 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 9 Sep 2017 15:06:22 -0600 Subject: [PATCH 0198/1301] Fix static --- ihdad/src/HDA/stream.rs | 87 ++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 40 deletions(-) diff --git a/ihdad/src/HDA/stream.rs b/ihdad/src/HDA/stream.rs index c87faf8690..fb8f1cd75e 100644 --- a/ihdad/src/HDA/stream.rs +++ b/ihdad/src/HDA/stream.rs @@ -52,16 +52,16 @@ pub enum BitsPerSample { Bits16 = 1, Bits20 = 2, Bits24 = 3, - Bits32 = 4, + Bits32 = 4, } pub fn format_to_u16(sr: &SampleRate, bps: BitsPerSample, channels:u8) -> u16{ - + // 3.3.41 - + let base:u16 = match sr.base { BaseRate::BR44_1 => { 1 << 14}, BaseRate::BR48 => { 0 }, @@ -76,7 +76,7 @@ pub fn format_to_u16(sr: &SampleRate, bps: BitsPerSample, channels:u8) -> u16{ let chan = ((channels - 1) & 0xF) as u16; let val:u16 = base | mult | div | bits | chan; - + val } @@ -95,7 +95,7 @@ pub struct StreamDescriptorRegs { format: Mmio, resv2: Mmio, buff_desc_list_lo: Mmio, - buff_desc_list_hi: Mmio, + buff_desc_list_hi: Mmio, } @@ -112,7 +112,7 @@ impl StreamDescriptorRegs { pub fn control(&self) -> u32 { let mut ctrl = self.ctrl_lo.read() as u32; ctrl |= (self.ctrl_hi.read() as u32) << 16; - ctrl + ctrl } pub fn set_control(&mut self, control:u32) { @@ -121,10 +121,10 @@ impl StreamDescriptorRegs { } pub fn set_pcm_format(&mut self, sr: &SampleRate, bps: BitsPerSample, channels:u8) { - + // 3.3.41 - + let val = format_to_u16(sr,bps,channels); self.format.write(val); @@ -151,11 +151,11 @@ impl StreamDescriptorRegs { let val = self.control() & !(1 << 1); self.set_control(val); } - + pub fn stream_number(&self) -> u8 { ((self.control() >> 20) & 0xF) as u8 } - + pub fn set_stream_number(&mut self, stream_number: u8) { let val = (self.control() & 0x00FFFF ) | (((stream_number & 0xF ) as u32) << 20); self.set_control(val); @@ -194,7 +194,7 @@ impl StreamDescriptorRegs { // get sample size in bytes pub fn sample_size(&self) -> usize { - let format = self.format.read(); + let format = self.format.read(); let chan = (format & 0xF) as usize; let bits = ((format >> 4) & 0xF) as usize; match bits { @@ -203,8 +203,8 @@ impl StreamDescriptorRegs { _ => 4 * (chan + 1), } } - - + + } pub struct OutputStream { @@ -219,12 +219,12 @@ impl OutputStream { unsafe { OutputStream { buff: StreamBuffer::new(block_length, block_count).unwrap(), - + desc_regs: regs, } } } - + pub fn write_block(&mut self, buf: &[u8]) -> Result { self.buff.write_block(buf) } @@ -232,11 +232,11 @@ impl OutputStream { pub fn block_size(&self) -> usize { self.buff.block_size() } - + pub fn block_count(&self) -> usize { self.buff.block_count() } - + pub fn current_block(&self) -> usize { self.buff.current_block() } @@ -291,36 +291,43 @@ impl BufferDescriptorListEntry { pub struct StreamBuffer { phys: usize, addr: usize, - + block_cnt: usize, block_len: usize, - + cur_pos: usize, } impl StreamBuffer { pub fn new(block_length: usize, block_count: usize) -> result::Result { - let phys = unsafe { + let phys = match unsafe { syscall::physalloc(block_length * block_count) - }; - if !phys.is_ok() { - return Err("Could not allocate physical memory for buffer."); - } - - let phys_addr = phys.unwrap(); - - let addr = unsafe { - syscall::physmap(phys_addr, block_length * block_count, MAP_WRITE) + } { + Ok(phys) => phys, + Err(err) => { + return Err("Could not allocate physical memory for buffer."); + } }; - if !addr.is_ok() { - unsafe {syscall::physfree(phys_addr, block_length * block_count);} - return Err("Could not map physical memory for buffer."); + let addr = match unsafe { + syscall::physmap(phys, block_length * block_count, MAP_WRITE) + } { + Ok(addr) => addr, + Err(err) => { + unsafe { + syscall::physfree(phys, block_length * block_count); + } + return Err("Could not map physical memory for buffer."); + } + }; + + unsafe { + ptr::write_bytes(addr as *mut u8, 0, block_length * block_count); } - + Ok(StreamBuffer { - phys: phys_addr, - addr: addr.unwrap(), + phys: phys, + addr: addr, block_len: block_length, block_cnt: block_count, cur_pos: 0, @@ -330,7 +337,7 @@ impl StreamBuffer { pub fn length(&self) -> usize { self.block_len * self.block_cnt } - + pub fn addr(&self) -> usize { self.addr } @@ -342,7 +349,7 @@ impl StreamBuffer { pub fn block_size(&self) -> usize { self.block_len } - + pub fn block_count(&self) -> usize { self.block_cnt } @@ -355,9 +362,9 @@ impl StreamBuffer { if buf.len() != self.block_size() { return Err(Error::new(EIO)) } - let len = min(self.block_size(), buf.len()); - - + let len = min(self.block_size(), buf.len()); + + print!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}\n", self.phys(), self.addr(), self.current_block() * self.block_size(), len); unsafe { copy_nonoverlapping(buf.as_ptr(), (self.addr() + self.current_block() * self.block_size()) as * mut u8, len); From 94b869cd61957e340c648788fd2de8bb87ed5150 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 27 Sep 2017 20:32:08 -0600 Subject: [PATCH 0199/1301] Update cargo.lock --- Cargo.lock | 174 ++++++++++++++++++++++++++--------------------------- 1 file changed, 87 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 478f23d985..e48204d4af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,8 +5,8 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -14,8 +14,8 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -25,17 +25,17 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "arg_parser" version = "0.1.0" -source = "git+https://github.com/redox-os/arg-parser.git#1b6a9505a1e9c39af1836ecbee293a987619a539" +source = "git+https://github.com/redox-os/arg-parser.git#288d2fd9ae27ed2c7a3aaf5a77cf07e2b2bd356c" [[package]] name = "arrayvec" -version = "0.3.23" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -55,8 +55,8 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -84,7 +84,7 @@ name = "coco" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -108,12 +108,12 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "either" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -123,12 +123,12 @@ source = "git+https://github.com/redox-os/libextra.git#402932084acd5fef481294588 [[package]] name = "futures" -version = "0.1.14" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "gcc" -version = "0.3.53" +version = "0.3.54" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -180,8 +180,8 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -205,12 +205,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.29" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "linked-hash-map" -version = "0.0.10" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -251,17 +251,17 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://github.com/redox-os/netutils.git#849b72c5b9e77a654a51521276dc6f2223a67aec" +source = "git+https://github.com/redox-os/netutils.git#ec1a835a9d4a95a8e41c4e994a540d298d897cd4" dependencies = [ "arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.0 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -319,7 +319,7 @@ name = "num_cpus" version = "1.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -327,8 +327,8 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -338,11 +338,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "orbclient" -version = "0.3.8" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -351,7 +351,7 @@ version = "1.0.0" source = "git+https://github.com/a8m/pb#e9369ed2b94df4f554fe79c2643de41f7338475f" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -361,9 +361,9 @@ dependencies = [ name = "pcid" version = "0.1.0" dependencies = [ - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -382,9 +382,9 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -397,7 +397,7 @@ name = "rand" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -420,9 +420,9 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -432,7 +432,7 @@ name = "redox_event" version = "0.1.0" source = "git+https://github.com/redox-os/event.git#42d552e4765efbfb4ec39ce174900d3f48548a70" dependencies = [ - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -440,12 +440,12 @@ name = "redox_event" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -453,7 +453,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -461,11 +461,11 @@ name = "ring" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)", + "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -475,7 +475,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -487,17 +487,17 @@ dependencies = [ "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rusttype" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", - "linked-hash-map 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -513,43 +513,43 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "sdl2" -version = "0.29.1" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2-sys 0.27.3 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sdl2-sys" -version = "0.27.3" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -558,7 +558,7 @@ dependencies = [ [[package]] name = "spin" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -592,8 +592,8 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -603,8 +603,8 @@ version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -613,7 +613,7 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -654,7 +654,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "untrusted" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -671,9 +671,9 @@ dependencies = [ name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -685,10 +685,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "rusttype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -698,7 +698,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -706,7 +706,7 @@ name = "webpki-roots" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -722,7 +722,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)" = "" -"checksum arrayvec 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "699e63a93b79d717e8c3b5eb1b28b7780d0d6d9e59a72eb769291c83b0c8dc67" +"checksum arrayvec 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "21d05247d0ce9c50156398593448df5c96616439217563a64d279a0489078427" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" @@ -731,10 +731,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" "checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" -"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" +"checksum either 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbee135e9245416869bf52bd6ccc9b59e2482651510784e089b874272f02a252" "checksum extra 0.1.0 (git+https://github.com/redox-os/libextra.git)" = "" -"checksum futures 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4b63a4792d4f8f686defe3b39b92127fea6344de5d38202b2ee5a11bbbf29d6a" -"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" +"checksum futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "05a23db7bd162d4e8265968602930c476f688f0c180b44bdaf55e0cb2c687558" +"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04535774f79684c99528944ebdb89756c945c027e55ce52faa245879d836c8fb" @@ -742,8 +742,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum libc 0.2.29 (registry+https://github.com/rust-lang/crates.io-index)" = "8a014d9226c2cc402676fbe9ea2e15dd5222cd1dd57f576b5b283178c944a264" -"checksum linked-hash-map 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "f26e961e0c884309cd527b1402a5409d35db612b36915d755e1a4f5c1547a31c" +"checksum libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d1419b2939a0bc44b77feb34661583c7546b532b192feab36249ab584b86856c" +"checksum linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2aab0478615bb586559b0114d94dd8eca4fdbb73b443adcb0d00b61692b4bf" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" "checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" @@ -758,7 +758,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" "checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" -"checksum orbclient 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9411f6bf9f60d65de1dcb601735ac0c904960f0f6ca03a13e6f02d25f842ea2c" +"checksum orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "6e5d8d9900998fb4b9394e27058aa22a6d3509fb67dd860f74ba0507d4406943" "checksum pbr 1.0.0 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" "checksum plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da55423d5704ee357503ce020f88b90269610ec85708331e6a7879dd4cea3122" @@ -769,19 +769,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" "checksum redox_event 0.1.0 (git+https://github.com/redox-os/event.git)" = "" "checksum redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98e1a40d38f45a3ad65fd088640eeee7b215adcd73041b9f94b92204cca9572a" -"checksum redox_syscall 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "8312fba776a49cf390b7b62f3135f9b294d8617f7a7592cfd0ac2492b658cd7b" +"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" "checksum rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17727f4b991294da2c84d75a43c003151ff58072212768800f66c56ee46dca43" -"checksum rusttype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c64ffc93b0cc5a6f5e5e84da2a4082b0271e0a1dd76e821bdac570bda7797e" +"checksum rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30047cc747a78ae042bf2cd65c79f83c3485d90107535b532d6e8f60e2c89cb1" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918" -"checksum sdl2 0.29.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c366cfa1f22d001774214ce2fb13f369af760b016bc79cc62d7f5ae15c00fea" -"checksum sdl2-sys 0.27.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d9f87e3d948f94f2d8688970422f49249c20e97f8f3aad76cb8729901d4eb10" -"checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9" -"checksum serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cf823e706be268e73e7747b147aa31c8f633ab4ba31f115efb57e5047c3a76dd" -"checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a" -"checksum spin 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1d16a26e2b789f86aabddbe91cb82ee2e822beb8a59840d631941b625ef77e53" +"checksum sdl2 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63066036ad426250ac56d23e38fd05063b38b661556acd596f4046cc92d98415" +"checksum sdl2-sys 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b48638b7882759f3421038fcd38ad5f1ea19b119d80c99f1601933004629e34d" +"checksum serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7046c9d4c6c522d10b2d098f9bebe2bef227e0e74044d8c1bfcf6b476af799" +"checksum serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1afcaae083fd1c46952a315062326bc9957f182358eb7da03b57ef1c688f7aa9" +"checksum serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd381f6d01a6616cdba8530492d453b7761b456ba974e98768a18cad2cd76f58" +"checksum spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7e4deb3c2455c73779e6d3eebceae9599fc70957e54c69fe88f93aa48e62f432" "checksum stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21b5c3b588a493a477e0d99769ee091b3627625f9ba4bdd882e6b4b0b0958805" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" @@ -794,7 +794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" -"checksum untrusted 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b65243989ef6aacd9c0d6bd2b822765c3361d8ed352185a6f3a41f3a718c673" +"checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" "checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e499345fc4c6b7c79a5b8756d4592c4305510a13512e79efafe00dfbd67bbac6" From 8e41cb9f032593c078f129aa740cc4c2a6124a4e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 30 Sep 2017 20:49:11 -0600 Subject: [PATCH 0200/1301] Use disk heirarchy --- ahcid/src/main.rs | 21 +++++++------------ ahcid/src/scheme.rs | 51 ++++++++++++++++++++++++++++++++++----------- nvmed/src/main.rs | 2 ++ 3 files changed, 49 insertions(+), 25 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index d887a3f021..50bd63467a 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -7,23 +7,14 @@ extern crate syscall; use std::{env, usize}; use std::fs::File; use std::io::{Read, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Result, Scheme}; +use std::os::unix::io::{AsRawFd, FromRawFd}; +use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme}; use scheme::DiskScheme; pub mod ahci; pub mod scheme; -fn create_scheme_fallback<'a>(name: &'a str, fallback: &'a str) -> Result<(&'a str, RawFd)> { - if let Ok(fd) = syscall::open(&format!(":{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) { - Ok((name, fd)) - } else { - syscall::open(&format!(":{}", fallback), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) - .map(|fd| (fallback, fd)) - } -} - fn main() { let mut args = env::args().skip(1); @@ -42,7 +33,11 @@ fn main() { if unsafe { syscall::clone(0).unwrap() } == 0 { let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; { - let (_scheme_name, socket_fd) = create_scheme_fallback("disk", &name).expect("ahcid: failed to create disk scheme"); + let scheme_name = format!("disk/{}", name); + let socket_fd = syscall::open( + &format!(":{}", scheme_name), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK + ).expect("ahcid: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd) }; syscall::fevent(socket_fd, EVENT_READ).expect("ahcid: failed to fevent disk scheme"); @@ -52,7 +47,7 @@ fn main() { let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); - let scheme = DiskScheme::new(ahci::disks(address, &name)); + let scheme = DiskScheme::new(scheme_name, ahci::disks(address, &name)); loop { let mut event = Event::default(); if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 { diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index d76b046232..c02e3f5322 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -12,23 +12,25 @@ use ahci::disk::Disk; #[derive(Clone)] enum Handle { List(Vec, usize), - Disk(Arc>, usize) + Disk(Arc>, usize, usize) } pub struct DiskScheme { + scheme_name: String, disks: Box<[Arc>]>, handles: Mutex>, next_id: AtomicUsize } impl DiskScheme { - pub fn new(disks: Vec) -> DiskScheme { + pub fn new(scheme_name: String, disks: Vec) -> DiskScheme { let mut disk_arcs = vec![]; for disk in disks { disk_arcs.push(Arc::new(Mutex::new(disk))); } DiskScheme { + scheme_name: scheme_name, disks: disk_arcs.into_boxed_slice(), handles: Mutex::new(BTreeMap::new()), next_id: AtomicUsize::new(0) @@ -59,7 +61,7 @@ impl Scheme for DiskScheme { if let Some(disk) = self.disks.get(i) { let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0)); + self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0, i)); Ok(id) } else { Err(Error::new(ENOENT)) @@ -94,7 +96,7 @@ impl Scheme for DiskScheme { stat.st_size = handle.len() as u64; Ok(0) }, - Handle::Disk(ref handle, _) => { + Handle::Disk(ref handle, _, _) => { stat.st_mode = MODE_FILE; stat.st_size = handle.lock().size(); Ok(0) @@ -102,14 +104,39 @@ impl Scheme for DiskScheme { } } - fn fpath(&self, _id: usize, buf: &mut [u8]) -> Result { - //TODO: Get path + fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { + let handles = self.handles.lock(); + let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + let mut i = 0; - let scheme_path = b"disk:"; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; + + let scheme_name = self.scheme_name.as_bytes(); + let mut j = 0; + while i < buf.len() && j < scheme_name.len() { + buf[i] = scheme_name[j]; + i += 1; + j += 1; + } + + if i < buf.len() { + buf[i] = b':'; i += 1; } + + match *handle { + Handle::List(_, _) => (), + Handle::Disk(_, _, number) => { + let number_str = format!("{}", number); + let number_bytes = number_str.as_bytes(); + j = 0; + while i < buf.len() && j < number_bytes.len() { + buf[i] = number_bytes[j]; + i += 1; + j += 1; + } + } + } + Ok(i) } @@ -121,7 +148,7 @@ impl Scheme for DiskScheme { *size += count; Ok(count) }, - Handle::Disk(ref mut handle, ref mut size) => { + Handle::Disk(ref mut handle, ref mut size, _) => { let mut disk = handle.lock(); let count = disk.read((*size as u64)/512, buf)?; *size += count; @@ -136,7 +163,7 @@ impl Scheme for DiskScheme { Handle::List(_, _) => { Err(Error::new(EBADF)) }, - Handle::Disk(ref mut handle, ref mut size) => { + Handle::Disk(ref mut handle, ref mut size, _) => { let mut disk = handle.lock(); let count = disk.write((*size as u64)/512, buf)?; *size += count; @@ -159,7 +186,7 @@ impl Scheme for DiskScheme { Ok(*size) }, - Handle::Disk(ref mut handle, ref mut size) => { + Handle::Disk(ref mut handle, ref mut size, _) => { let len = handle.lock().size() as usize; *size = match whence { SEEK_SET => cmp::min(len, pos), diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 14af0cf0f2..ee26f6f776 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -15,6 +15,7 @@ use self::nvme::Nvme; mod nvme; +/* fn create_scheme_fallback<'a>(name: &'a str, fallback: &'a str) -> Result<(&'a str, RawFd)> { if let Ok(fd) = syscall::open(&format!(":{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) { Ok((name, fd)) @@ -23,6 +24,7 @@ fn create_scheme_fallback<'a>(name: &'a str, fallback: &'a str) -> Result<(&'a s .map(|fd| (fallback, fd)) } } +*/ fn main() { let mut args = env::args().skip(1); From e4a297b725c0b3339920d00f826e8fa1cc43ecb9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 3 Oct 2017 20:54:49 -0600 Subject: [PATCH 0201/1301] vmmouse support --- ps2d/src/main.rs | 78 ++++++++++++++++++++++++++++++++++++++++----- ps2d/src/vm.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 7 deletions(-) create mode 100644 ps2d/src/vm.rs diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 76ad116f95..be59ebc6d3 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -22,6 +22,7 @@ use controller::Ps2; mod controller; mod keymap; +mod vm; bitflags! { flags MousePacketFlags: u8 { @@ -38,6 +39,7 @@ bitflags! { struct Ps2d char> { ps2: Ps2, + vmmouse: bool, input: File, width: u32, height: u32, @@ -60,6 +62,8 @@ impl char> Ps2d { let mut ps2 = Ps2::new(); let extra_packet = ps2.init(); + let vmmouse = vm::enable(); + let mut width = 0; let mut height = 0; { @@ -74,6 +78,7 @@ impl char> Ps2d { Ps2d { ps2: ps2, + vmmouse: vmmouse, input: input, width: width, height: height, @@ -116,6 +121,65 @@ impl char> Ps2d { scancode: scancode, pressed: pressed }.to_event()).expect("ps2d: failed to write key event"); + } else if self.vmmouse { + for _i in 0..256 { + let (status, _, _, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) }; + //TODO if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) + + let queue_length = status & 0xffff; + if queue_length == 0 { + break; + } + + if queue_length % 4 != 0 { + println!("queue length not a multiple of 4: {}", queue_length); + break; + } + + let (status, dx, dy, dz, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; + + let (x, y) = if status & vm::RELATIVE_PACKET == vm::RELATIVE_PACKET { + ( + cmp::max(0, cmp::min(self.width as i32, self.mouse_x + dx as i32)), + cmp::max(0, cmp::min(self.height as i32, self.mouse_y - dy as i32)) + ) + } else { + ( + dx as i32 * self.width as i32 / 0xFFFF, + dy as i32 * self.height as i32 / 0xFFFF + ) + }; + + if x != self.mouse_x || y != self.mouse_y { + self.mouse_x = x; + self.mouse_y = y; + self.input.write(&MouseEvent { + x: x, + y: y, + }.to_event()).expect("ps2d: failed to write mouse event"); + } + + if dz != 0 { + self.input.write(&ScrollEvent { + x: 0, + y: -(dz as i32), + }.to_event()).expect("ps2d: failed to write scroll event"); + } + + let left = status & vm::LEFT_BUTTON == vm::LEFT_BUTTON; + let middle = status & vm::MIDDLE_BUTTON == vm::MIDDLE_BUTTON; + let right = status & vm::RIGHT_BUTTON == vm::RIGHT_BUTTON; + if left != self.mouse_left || middle != self.mouse_middle || right != self.mouse_right { + self.mouse_left = left; + self.mouse_middle = middle; + self.mouse_right = right; + self.input.write(&ButtonEvent { + left: left, + middle: middle, + right: right, + }.to_event()).expect("ps2d: failed to write button event"); + } + } } else { self.packets[self.packet_i] = data; self.packet_i += 1; @@ -158,6 +222,13 @@ impl char> Ps2d { }.to_event()).expect("ps2d: failed to write mouse event"); } + if dz != 0 { + self.input.write(&ScrollEvent { + x: 0, + y: dz, + }.to_event()).expect("ps2d: failed to write scroll event"); + } + let left = flags.contains(LEFT_BUTTON); let middle = flags.contains(MIDDLE_BUTTON); let right = flags.contains(RIGHT_BUTTON); @@ -171,13 +242,6 @@ impl char> Ps2d { right: right, }.to_event()).expect("ps2d: failed to write button event"); } - - if dz != 0 { - self.input.write(&ScrollEvent { - x: 0, - y: dz, - }.to_event()).expect("ps2d: failed to write scroll event"); - } } else { println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); } diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs new file mode 100644 index 0000000000..a772829aaf --- /dev/null +++ b/ps2d/src/vm.rs @@ -0,0 +1,82 @@ +// This code is informed by the QEMU implementation found here: +// https://github.com/qemu/qemu/blob/master/hw/input/vmmouse.c +// +// As well as the Linux implementation here: +// http://elixir.free-electrons.com/linux/v4.1/source/drivers/input/mouse/vmmouse.c + +const MAGIC: u32 = 0x564D5868; +const PORT: u16 = 0x5658; + +pub const ABSPOINTER_DATA: u32 = 39; +pub const ABSPOINTER_STATUS: u32 = 40; +pub const ABSPOINTER_COMMAND: u32 = 41; + +pub const CMD_ENABLE: u32 = 0x45414552; +pub const CMD_DISABLE: u32 = 0x000000f5; +pub const CMD_REQUEST_ABSOLUTE: u32 = 0x53424152; + +const VERSION: u32 = 0x3442554a; + +pub const RELATIVE_PACKET: u32 = 0x00010000; + +pub const LEFT_BUTTON: u32 = 0x20; +pub const RIGHT_BUTTON: u32 = 0x10; +pub const MIDDLE_BUTTON: u32 = 0x08; + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32, u32, u32) { + let a: u32; + let b: u32; + let c: u32; + let d: u32; + let si: u32; + let di: u32; + + asm!( + "in eax, dx" + : + "={eax}"(a), + "={ebx}"(b), + "={ecx}"(c), + "={edx}"(d), + "={esi}"(si), + "={edi}"(di) + : + "{eax}"(MAGIC), + "{ebx}"(arg), + "{ecx}"(cmd), + "{dx}"(PORT) + : + "memory" + : + "intel", "volatile" + ); + + (a, b, c, d, si, di) +} + +pub fn enable() -> bool { + println!("Enable"); + + unsafe { + let _ = cmd(ABSPOINTER_COMMAND, CMD_ENABLE); + + let (status, _, _, _, _, _) = cmd(ABSPOINTER_STATUS, 0); + if (status & 0x0000ffff) == 0 { + println!("No vmmouse"); + return false; + } + + let (version, _, _, _, _, _) = cmd(ABSPOINTER_DATA, 1); + if version != VERSION { + println!("Invalid vmmouse version: {} instead of {}", version, VERSION); + let _ = cmd(ABSPOINTER_COMMAND, CMD_DISABLE); + return false; + } + + cmd(ABSPOINTER_COMMAND, CMD_REQUEST_ABSOLUTE); + + } + + return true; +} From e3a9314a5a2ba2fe5ae3f6653371b5b67e3c558b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 4 Oct 2017 20:29:41 -0600 Subject: [PATCH 0202/1301] Update Cargo.lock --- Cargo.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e48204d4af..d7ac3ad146 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,7 +146,7 @@ dependencies = [ "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -200,7 +200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -316,7 +316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.6.2" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -421,9 +421,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -462,7 +462,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -517,7 +517,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -741,7 +741,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" +"checksum lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9e5e58fa1a4c3b915a561a78a22ee0cac6ab97dca2504428bc1cb074375f8d5" "checksum libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d1419b2939a0bc44b77feb34661583c7546b532b192feab36249ab584b86856c" "checksum linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2aab0478615bb586559b0114d94dd8eca4fdbb73b443adcb0d00b61692b4bf" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" @@ -756,7 +756,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" "checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" -"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" +"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" "checksum orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "6e5d8d9900998fb4b9394e27058aa22a6d3509fb67dd860f74ba0507d4406943" "checksum pbr 1.0.0 (git+https://github.com/a8m/pb)" = "" From bd8a377c784a5e8c777e583e529a52d2927e4ce5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 9 Oct 2017 20:36:16 -0600 Subject: [PATCH 0203/1301] Use capability mode (null namespace) for drivers --- ahcid/src/main.rs | 3 +++ alxd/src/main.rs | 5 ++++- bgad/src/main.rs | 3 +++ e1000d/src/main.rs | 5 ++++- ihdad/src/main.rs | 38 +++++++++++--------------------------- nvmed/src/main.rs | 3 +++ ps2d/src/main.rs | 9 +++++++-- rtl8168d/src/main.rs | 2 ++ vboxd/src/main.rs | 2 ++ vesad/src/main.rs | 2 ++ xhcid/src/main.rs | 2 ++ 11 files changed, 43 insertions(+), 31 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 50bd63467a..d9339c41a4 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -48,6 +48,9 @@ fn main() { let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); let scheme = DiskScheme::new(scheme_name, ahci::disks(address, &name)); + + syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace"); + loop { let mut event = Event::default(); if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 { diff --git a/alxd/src/main.rs b/alxd/src/main.rs index c38bb99682..9762d68301 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -41,18 +41,21 @@ fn main() { let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("alxd: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + let mut irq_file = File::open(format!("irq:{}", irq)).expect("alxd: failed to open IRQ file"); + let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("alxd: failed to map address") }; { let device = Arc::new(RefCell::new(unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") })); let mut event_queue = EventQueue::::new().expect("alxd: failed to create event queue"); + syscall::setrens(0, 0).expect("alxd: failed to enter null namespace"); + let todo = Arc::new(RefCell::new(Vec::::new())); let device_irq = device.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("alxd: failed to open IRQ file"); event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; diff --git a/bgad/src/main.rs b/bgad/src/main.rs index e5ee67d723..e326899aba 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -40,6 +40,9 @@ fn main() { bga: bga, display: File::open("display:input").ok() }; + + syscall::setrens(0, 0).expect("bgad: failed to enter null namespace"); + loop { let mut packet = Packet::default(); socket.read(&mut packet).expect("bgad: failed to read events from bga scheme"); diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 00a6d81301..2278cc2a57 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -36,18 +36,21 @@ fn main() { let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("e1000d: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); + let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") }; { let device = Arc::new(unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }); let mut event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); + syscall::setrens(0, 0).expect("e1000d: failed to enter null namespace"); + let todo = Arc::new(RefCell::new(Vec::::new())); let device_irq = device.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index e914783d00..c6e1d9af05 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -20,7 +20,7 @@ use syscall::error::EWOULDBLOCK; pub mod HDA; - + use HDA::IntelHDA; @@ -28,11 +28,11 @@ use HDA::IntelHDA; -/* +/* VEND:PROD Virtualbox 8086:2668 QEMU ICH9 8086:293E - 82801H ICH8 8086:284B + 82801H ICH8 8086:284B */ fn main() { @@ -47,54 +47,43 @@ fn main() { let irq_str = args.next().expect("ihda: no irq provided"); let irq = irq_str.parse::().expect("ihda: failed to parse irq"); - let vend_str = args.next().expect("ihda: no vendor id provided"); let vend = usize::from_str_radix(&vend_str, 16).expect("ihda: failed to parse vendor id"); - let prod_str = args.next().expect("ihda: no product id provided"); let prod = usize::from_str_radix(&prod_str, 16).expect("ihda: failed to parse product id"); print!("{}", format!(" + ihda {} on: {:X} IRQ: {}\n", name, bar, irq)); - // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - - let address = unsafe { syscall::physmap(bar, 0x4000, MAP_WRITE).expect("ihdad: failed to map address") }; { - let mut irq_file = File::open(format!("irq:{}", irq)).expect("IHDA: failed to open IRQ file"); - - let vend_prod:u32 = ((vend as u32) << 16) | (prod as u32); + let vend_prod:u32 = ((vend as u32) << 16) | (prod as u32); let device = Arc::new(RefCell::new(unsafe { HDA::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); let socket_fd = syscall::open(":audio", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create audio scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); - - - - let mut event_queue = EventQueue::::new().expect("IHDA: Could not create event queue."); - + + syscall::setrens(0, 0).expect("ihdad: failed to enter null namespace"); + let todo = Arc::new(RefCell::new(Vec::::new())); - - + let todo_irq = todo.clone(); let device_irq = device.clone(); let socket_irq = socket.clone(); let device_loop = device.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; - + let _irq = unsafe { device_irq.borrow_mut().irq()}; - + if _irq { irq_file.write(&mut irq)?; @@ -161,10 +150,7 @@ fn main() { }).expect("IHDA: failed to write event"); } - - - - loop { + loop { { //device_loop.borrow_mut().handle_interrupts(); } @@ -186,5 +172,3 @@ fn main() { unsafe { let _ = syscall::physunmap(address); } } } - - diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index ee26f6f776..531fc74c9d 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -58,6 +58,9 @@ fn main() { let mut event_file = File::open("event:").expect("nvmed: failed to open event file"); let scheme = DiskScheme::new(nvme::disks(address, &name)); + + syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + loop { let mut event = Event::default(); if event_file.read(&mut event).expect("nvmed: failed to read event file") == 0 { diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index be59ebc6d3..7d4081a7eb 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -269,11 +269,17 @@ fn daemon(input: File) { }, None => (keymap::us::get_char) }; + + let mut key_irq = File::open("irq:1").expect("ps2d: failed to open irq:1"); + + let mut mouse_irq = File::open("irq:12").expect("ps2d: failed to open irq:12"); + let ps2d = Arc::new(RefCell::new(Ps2d::new(input, keymap))); let mut event_queue = EventQueue::<()>::new().expect("ps2d: failed to create event queue"); - let mut key_irq = File::open("irq:1").expect("ps2d: failed to open irq:1"); + syscall::setrens(0, 0).expect("ps2d: failed to enter null namespace"); + let key_ps2d = ps2d.clone(); event_queue.add(key_irq.as_raw_fd(), move |_count: usize| -> Result> { let mut irq = [0; 8]; @@ -284,7 +290,6 @@ fn daemon(input: File) { Ok(None) }).expect("ps2d: failed to poll irq:1"); - let mut mouse_irq = File::open("irq:12").expect("ps2d: failed to open irq:12"); let mouse_ps2d = ps2d; event_queue.add(mouse_irq.as_raw_fd(), move |_count: usize| -> Result> { let mut irq = [0; 8]; diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 3f7b905a58..5b5cc076d3 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -44,6 +44,8 @@ fn main() { let mut event_queue = EventQueue::::new().expect("rtl8168d: failed to create event queue"); + syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); + let todo = Arc::new(RefCell::new(Vec::::new())); let device_irq = device.clone(); diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index d84342a41c..90b5205ab1 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -238,6 +238,8 @@ fn main() { let mut event_queue = EventQueue::<()>::new().expect("vboxd: failed to create event queue"); + syscall::setrens(0, 0).expect("vboxd: failed to enter null namespace"); + let mut bga = Bga::new(); let get_mouse = VboxGetMouse::new().expect("vboxd: failed to map GetMouse"); let display_change = VboxDisplayChange::new().expect("vboxd: failed to map DisplayChange"); diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 5f9211bca1..634f3d4687 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -62,6 +62,8 @@ fn main() { let mut scheme = DisplayScheme::new(width, height, onscreen, &spec); + syscall::setrens(0, 0).expect("vesad: failed to enter null namespace"); + let mut blocked = Vec::new(); loop { let mut packet = Packet::default(); diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 18fba44441..dac58b0c49 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -49,6 +49,8 @@ fn main() { let mut event_queue = EventQueue::<()>::new().expect("xhcid: failed to create event queue"); + syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); + let todo = Arc::new(RefCell::new(Vec::::new())); let hci_irq = hci.clone(); From 12989384c050273002b11ce55406e9ffb334b89b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 11 Oct 2017 20:54:45 -0600 Subject: [PATCH 0204/1301] Update Cargo.lock --- Cargo.lock | 88 ++++++++++++++++++++++-------------------------------- 1 file changed, 36 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7ac3ad146..1deeedc0cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,19 +88,6 @@ dependencies = [ "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "conv" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "custom_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "e1000d" version = "0.1.0" @@ -121,6 +108,22 @@ name = "extra" version = "0.1.0" source = "git+https://github.com/redox-os/libextra.git#402932084acd5fef4812945887ceaaa2ddd5f264" +[[package]] +name = "fuchsia-zircon" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "futures" version = "0.1.16" @@ -205,7 +208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.31" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -218,23 +221,6 @@ name = "log" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "magenta" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "magenta-sys" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "matches" version = "0.1.6" @@ -251,13 +237,13 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://github.com/redox-os/netutils.git#ec1a835a9d4a95a8e41c4e994a540d298d897cd4" +source = "git+https://github.com/redox-os/netutils.git#29b8efd41d8c56b33c619db78e5b019934dbb7a3" dependencies = [ "arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.0 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", @@ -319,7 +305,7 @@ name = "num_cpus" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -351,7 +337,7 @@ version = "1.0.0" source = "git+https://github.com/a8m/pb#e9369ed2b94df4f554fe79c2643de41f7338475f" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -394,11 +380,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -422,9 +408,9 @@ dependencies = [ "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -463,7 +449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -518,9 +504,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -529,7 +515,7 @@ name = "sdl2-sys" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -592,7 +578,7 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -603,7 +589,7 @@ version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -729,10 +715,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" -"checksum conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" -"checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" "checksum either 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbee135e9245416869bf52bd6ccc9b59e2482651510784e089b874272f02a252" "checksum extra 0.1.0 (git+https://github.com/redox-os/libextra.git)" = "" +"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" +"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" "checksum futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "05a23db7bd162d4e8265968602930c476f688f0c180b44bdaf55e0cb2c687558" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" @@ -742,11 +728,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9e5e58fa1a4c3b915a561a78a22ee0cac6ab97dca2504428bc1cb074375f8d5" -"checksum libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "d1419b2939a0bc44b77feb34661583c7546b532b192feab36249ab584b86856c" +"checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148" "checksum linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2aab0478615bb586559b0114d94dd8eca4fdbb73b443adcb0d00b61692b4bf" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" -"checksum magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" -"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)" = "" @@ -763,7 +747,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" "checksum plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da55423d5704ee357503ce020f88b90269610ec85708331e6a7879dd4cea3122" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" +"checksum rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "61efcbcd9fa8d8fbb07c84e34a8af18a1ff177b449689ad38a6e9457ecc7b2ae" "checksum ransid 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "754ed82fc56508fc1353f0ab24affd4b055683a8ad4d53d39f7e4d8764c3efa4" "checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" "checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" From bd102d7f0d80e354bface3cfab79fc5b5fc1119e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 20 Oct 2017 20:05:49 -0600 Subject: [PATCH 0205/1301] Create LICENSE --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..5deeece4f4 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Redox OS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. From ce05b12a7a4b80a3aa0b0ccb3a7df023f0cf8c08 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 20 Nov 2017 19:26:16 -0700 Subject: [PATCH 0206/1301] Update ransid for vesad --- Cargo.lock | 173 ++++++++++++++++++++------------------- vesad/Cargo.toml | 2 +- vesad/src/display.rs | 15 ---- vesad/src/screen/text.rs | 59 +++++++++---- 4 files changed, 131 insertions(+), 118 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1deeedc0cc..941a29bc33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,14 +1,3 @@ -[root] -name = "xhcid" -version = "0.1.0" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ahcid" version = "0.1.0" @@ -31,15 +20,14 @@ dependencies = [ [[package]] name = "arg_parser" version = "0.1.0" -source = "git+https://github.com/redox-os/arg-parser.git#288d2fd9ae27ed2c7a3aaf5a77cf07e2b2bd356c" +source = "git+https://github.com/redox-os/arg-parser.git#d16e2d02e87996bbe2bce4a201c66c0df4a1e866" [[package]] name = "arrayvec" -version = "0.4.2" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -84,8 +72,8 @@ name = "coco" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -100,7 +88,7 @@ dependencies = [ [[package]] name = "either" -version = "1.2.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -124,11 +112,6 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "futures" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "gcc" version = "0.3.54" @@ -154,7 +137,7 @@ dependencies = [ "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -203,12 +186,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.32" +version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -237,13 +220,13 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://github.com/redox-os/netutils.git#29b8efd41d8c56b33c619db78e5b019934dbb7a3" +source = "git+https://github.com/redox-os/netutils.git#a719fa50b065840ffacc81d989e47f258b3e5170" dependencies = [ "arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.0 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", @@ -253,11 +236,8 @@ dependencies = [ [[package]] name = "nodrop" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "ntpclient" @@ -305,7 +285,7 @@ name = "num_cpus" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -317,11 +297,6 @@ dependencies = [ "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "odds" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "orbclient" version = "0.3.12" @@ -337,7 +312,7 @@ version = "1.0.0" source = "git+https://github.com/a8m/pb#e9369ed2b94df4f554fe79c2643de41f7338475f" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -348,14 +323,14 @@ name = "pcid" version = "0.1.0" dependencies = [ "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "percent-encoding" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -380,43 +355,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ransid" -version = "0.2.10" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "vte 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "rayon" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_event" version = "0.1.0" -source = "git+https://github.com/redox-os/event.git#42d552e4765efbfb4ec39ce174900d3f48548a70" +source = "git+https://github.com/redox-os/event.git#bb96d9cd6dd01d4118deae84722a522b8328fa9f" dependencies = [ "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -448,8 +425,8 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -482,7 +459,7 @@ name = "rusttype" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -494,7 +471,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "scopeguard" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -503,10 +480,10 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -515,27 +492,27 @@ name = "sdl2-sys" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" -version = "1.0.15" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.15" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -578,7 +555,7 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -589,7 +566,7 @@ version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -599,7 +576,7 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -645,14 +622,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "url" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "utf8parse" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vboxd" version = "0.1.0" @@ -672,11 +654,19 @@ name = "vesad" version = "0.1.0" dependencies = [ "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ransid 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "ransid 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vte" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "utf8parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "webpki" version = "0.14.0" @@ -706,20 +696,30 @@ name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "xhcid" +version = "0.1.0" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [metadata] "checksum arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)" = "" -"checksum arrayvec 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "21d05247d0ce9c50156398593448df5c96616439217563a64d279a0489078427" +"checksum arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0ef4a9820019a0c91d918918c93dc71d469f581a49b47ddc1d285d4270bbe2" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" -"checksum either 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbee135e9245416869bf52bd6ccc9b59e2482651510784e089b874272f02a252" +"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" "checksum extra 0.1.0 (git+https://github.com/redox-os/libextra.git)" = "" "checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" "checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" -"checksum futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "05a23db7bd162d4e8265968602930c476f688f0c180b44bdaf55e0cb2c687558" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" @@ -727,30 +727,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9e5e58fa1a4c3b915a561a78a22ee0cac6ab97dca2504428bc1cb074375f8d5" -"checksum libc 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "56cce3130fd040c28df6f495c8492e5ec5808fb4c9093c310df02b0c8f030148" +"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" +"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2" "checksum linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2aab0478615bb586559b0114d94dd8eca4fdbb73b443adcb0d00b61692b4bf" "checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)" = "" -"checksum nodrop 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "52cd74cd09beba596430cc6e3091b74007169a56246e1262f0ba451ea95117b2" +"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" "checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" "checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" -"checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" "checksum orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "6e5d8d9900998fb4b9394e27058aa22a6d3509fb67dd860f74ba0507d4406943" "checksum pbr 1.0.0 (git+https://github.com/a8m/pb)" = "" -"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" +"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da55423d5704ee357503ce020f88b90269610ec85708331e6a7879dd4cea3122" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum rand 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "61efcbcd9fa8d8fbb07c84e34a8af18a1ff177b449689ad38a6e9457ecc7b2ae" -"checksum ransid 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "754ed82fc56508fc1353f0ab24affd4b055683a8ad4d53d39f7e4d8764c3efa4" +"checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd" +"checksum ransid 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6cff8161c032c6c37e794ac4544c91dce9fd9c568d266ba4d171976bb6ffae97" "checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" -"checksum rayon-core 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7febc28567082c345f10cddc3612c6ea020fc3297a1977d472cf9fdb73e6e493" +"checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53" "checksum redox_event 0.1.0 (git+https://github.com/redox-os/event.git)" = "" "checksum redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98e1a40d38f45a3ad65fd088640eeee7b215adcd73041b9f94b92204cca9572a" "checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" @@ -759,12 +758,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17727f4b991294da2c84d75a43c003151ff58072212768800f66c56ee46dca43" "checksum rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30047cc747a78ae042bf2cd65c79f83c3485d90107535b532d6e8f60e2c89cb1" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum scopeguard 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c79eb2c3ac4bc2507cda80e7f3ac5b88bd8eae4c0914d5663e6a8933994be918" +"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum sdl2 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63066036ad426250ac56d23e38fd05063b38b661556acd596f4046cc92d98415" "checksum sdl2-sys 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b48638b7882759f3421038fcd38ad5f1ea19b119d80c99f1601933004629e34d" -"checksum serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7046c9d4c6c522d10b2d098f9bebe2bef227e0e74044d8c1bfcf6b476af799" -"checksum serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1afcaae083fd1c46952a315062326bc9957f182358eb7da03b57ef1c688f7aa9" -"checksum serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd381f6d01a6616cdba8530492d453b7761b456ba974e98768a18cad2cd76f58" +"checksum serde 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6eda663e865517ee783b0891a3f6eb3a253e0b0dabb46418969ee9635beadd9e" +"checksum serde_derive 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "652bc323d694dc925829725ec6c890156d8e70ae5202919869cb00fe2eff3788" +"checksum serde_derive_internals 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32f1926285523b2db55df263d2aa4eb69ddcfa7a7eade6430323637866b513ab" "checksum spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7e4deb3c2455c73779e6d3eebceae9599fc70957e54c69fe88f93aa48e62f432" "checksum stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21b5c3b588a493a477e0d99769ee091b3627625f9ba4bdd882e6b4b0b0958805" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" @@ -779,8 +778,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" -"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27" +"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2" +"checksum utf8parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a15ea87f3194a3a454c78d79082b4f5e85f6956ddb6cb86bbfbe4892aa3c0323" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" +"checksum vte 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a01634c75db59478405de08d8567c40c578bba80c565217ee709934b551720d8" "checksum webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e499345fc4c6b7c79a5b8756d4592c4305510a13512e79efafe00dfbd67bbac6" "checksum webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb3f50499f21ad2317f442845e3b5805b007f1e728f59885c99e61b8c181a7" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index a71776a129..76a4553d3f 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" [dependencies] orbclient = "0.3" -ransid = "0.2" +ransid = "0.4" rusttype = { version = "0.2", optional = true } redox_syscall = "0.1" diff --git a/vesad/src/display.rs b/vesad/src/display.rs index b3b5498626..0744c5e45e 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -245,21 +245,6 @@ impl Display { } } - /// Scroll display - pub fn scroll(&mut self, rows: usize, color: u32) { - let width = self.width; - let height = self.height; - if rows > 0 && rows < height { - let off1 = rows * width; - let off2 = height * width - off1; - unsafe { - let data_ptr = self.offscreen.as_mut_ptr() as *mut u32; - fast_copy(data_ptr as *mut u8, data_ptr.offset(off1 as isize) as *const u8, off2 as usize * 4); - fast_set32(data_ptr.offset(off2 as isize), color, off1 as usize); - } - } - } - /// Copy from offscreen to onscreen pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize) { let start_y = cmp::min(self.height, y); diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 06f450f1b2..2de79579a4 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -1,6 +1,7 @@ extern crate ransid; use std::collections::{BTreeSet, VecDeque}; +use std::ptr; use orbclient::{Event, EventOption}; use syscall::error::*; @@ -32,17 +33,17 @@ impl TextScreen { impl Screen for TextScreen { fn width(&self) -> usize { - self.console.w + self.console.state.w } fn height(&self) -> usize { - self.console.h + self.console.state.h } fn resize(&mut self, width: usize, height: usize) { self.display.resize(width, height); - self.console.w = width / 8; - self.console.h = height / 16; + self.console.state.w = width / 8; + self.console.state.h = height / 16; } fn event(&mut self, flags: usize) -> Result { @@ -138,9 +139,9 @@ impl Screen for TextScreen { } fn write(&mut self, buf: &[u8], sync: bool) -> Result { - if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h { - let x = self.console.x; - let y = self.console.y; + if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { + let x = self.console.state.x; + let y = self.console.state.y; self.display.invert(x * 8, y * 16, 8, 16); self.changed.insert(y); } @@ -152,33 +153,59 @@ impl Screen for TextScreen { self.console.write(buf, |event| { match event { ransid::Event::Char { x, y, c, color, bold, .. } => { - display.char(x * 8, y * 16, c, color.data, bold, false); + display.char(x * 8, y * 16, c, color.as_rgb(), bold, false); changed.insert(y); }, ransid::Event::Input { data } => { input.extend(data); }, ransid::Event::Rect { x, y, w, h, color } => { - display.rect(x * 8, y * 16, w * 8, h * 16, color.data); + display.rect(x * 8, y * 16, w * 8, h * 16, color.as_rgb()); for y2 in y..y + h { changed.insert(y2); } }, ransid::Event::ScreenBuffer { .. } => (), - ransid::Event::Scroll { rows, color } => { - display.scroll(rows * 16, color.data); - for y in 0..display.height/16 { - changed.insert(y); + ransid::Event::Move {from_x, from_y, to_x, to_y, w, h } => { + println!("Move {}, {} to {}, {} size {}, {}", from_x, from_y, to_x, to_y, w, h); + + let width = display.width; + let pixels = &mut display.offscreen; + + for raw_y in 0..h { + let y = if from_y > to_y { + raw_y + } else { + h - raw_y - 1 + }; + + for pixel_y in 0..16 { + { + let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8; + let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8; + let len = w * 8; + + if off_from + len <= pixels.len() && off_to + len <= pixels.len() { + unsafe { + let data_ptr = pixels.as_mut_ptr() as *mut u32; + ptr::copy(data_ptr.offset(off_from as isize), data_ptr.offset(off_to as isize), len); + } + } + } + } + + changed.insert(to_y + y); } }, + ransid::Event::Resize { .. } => (), ransid::Event::Title { .. } => () } }); } - if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h { - let x = self.console.x; - let y = self.console.y; + if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { + let x = self.console.state.x; + let y = self.console.state.y; self.display.invert(x * 8, y * 16, 8, 16); self.changed.insert(y); } From b7fe49ccd0977e4675449068ee822990a16f5f0a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 20 Nov 2017 19:45:23 -0700 Subject: [PATCH 0207/1301] Remove debug statement --- vesad/src/screen/text.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 2de79579a4..9bc7df0f67 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -167,8 +167,6 @@ impl Screen for TextScreen { }, ransid::Event::ScreenBuffer { .. } => (), ransid::Event::Move {from_x, from_y, to_x, to_y, w, h } => { - println!("Move {}, {} to {}, {} size {}, {}", from_x, from_y, to_x, to_y, w, h); - let width = display.width; let pixels = &mut display.offscreen; From 66826a8bf899ec7064b7a4c708332f61fb9e9524 Mon Sep 17 00:00:00 2001 From: Date: Fri, 1 Dec 2017 20:34:15 +0900 Subject: [PATCH 0208/1301] unsafe edited --- pcid/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index b3017391c3..08ce285bef 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -38,7 +38,7 @@ fn main() { for bus in pci.buses() { for dev in bus.devs() { for func in dev.funcs() { - if let Some(header) = func.header() { + if let Some(header) = unsafe func.header() { let pci_class = PciClass::from(header.class); let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", From 2b4b94036022f61d4ba1cacbfa8d8b8150c621fd Mon Sep 17 00:00:00 2001 From: Date: Fri, 1 Dec 2017 21:35:55 +0900 Subject: [PATCH 0209/1301] unsafe problem fixed --- pcid/src/main.rs | 72 +++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 08ce285bef..46575570f8 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -38,14 +38,18 @@ fn main() { for bus in pci.buses() { for dev in bus.devs() { for func in dev.funcs() { - if let Some(header) = unsafe func.header() { + if let Some(header) = func.header() { let pci_class = PciClass::from(header.class); - let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", - bus.num, dev.num, func.num, - header.vendor_id, header.device_id, - header.class, header.subclass, header.interface, header.revision, - pci_class); + let mut string; + + unsafe { + string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", + bus.num, dev.num, func.num, + header.vendor_id, header.device_id, + header.class, header.subclass, header.interface, header.revision, + pci_class); + } match pci_class { PciClass::Storage => match header.subclass { @@ -78,14 +82,16 @@ fn main() { _ => () } - for i in 0..header.bars.len() { - match PciBar::from(header.bars[i]) { - PciBar::None => (), - PciBar::Memory(address) => string.push_str(&format!(" {}={:>08X}", i, address)), - PciBar::Port(address) => string.push_str(&format!(" {}={:>04X}", i, address)) + unsafe { + for i in 0..header.bars.len() { + match PciBar::from(header.bars[i]) { + PciBar::None => (), + PciBar::Memory(address) => string.push_str(&format!(" {}={:>08X}", i, address)), + PciBar::Port(address) => string.push_str(&format!(" {}={:>04X}", i, address)) + } } } - + string.push('\n'); print!("{}", string); @@ -124,27 +130,31 @@ fn main() { let mut command = Command::new(program); for arg in args { let bar_arg = |i| -> String { - match PciBar::from(header.bars[i]) { - PciBar::None => String::new(), - PciBar::Memory(address) => format!("{:>08X}", address), - PciBar::Port(address) => format!("{:>04X}", address) + unsafe { + match PciBar::from(header.bars[i]) { + PciBar::None => String::new(), + PciBar::Memory(address) => format!("{:>08X}", address), + PciBar::Port(address) => format!("{:>04X}", address) + } } }; - let arg = match arg.as_str() { - "$BUS" => format!("{:>02X}", bus.num), - "$DEV" => format!("{:>02X}", dev.num), - "$FUNC" => format!("{:>02X}", func.num), - "$NAME" => format!("pci-{:>02X}.{:>02X}.{:>02X}", bus.num, dev.num, func.num), - "$BAR0" => bar_arg(0), - "$BAR1" => bar_arg(1), - "$BAR2" => bar_arg(2), - "$BAR3" => bar_arg(3), - "$BAR4" => bar_arg(4), - "$BAR5" => bar_arg(5), - "$IRQ" => format!("{}", header.interrupt_line), - "$VENID" => format!("{:>04X}",header.vendor_id), - "$DEVID" => format!("{:>04X}",header.device_id), - _ => arg.clone() + let arg = unsafe { + match arg.as_str() { + "$BUS" => format!("{:>02X}", bus.num), + "$DEV" => format!("{:>02X}", dev.num), + "$FUNC" => format!("{:>02X}", func.num), + "$NAME" => format!("pci-{:>02X}.{:>02X}.{:>02X}", bus.num, dev.num, func.num), + "$BAR0" => bar_arg(0), + "$BAR1" => bar_arg(1), + "$BAR2" => bar_arg(2), + "$BAR3" => bar_arg(3), + "$BAR4" => bar_arg(4), + "$BAR5" => bar_arg(5), + "$IRQ" => format!("{}", header.interrupt_line), + "$VENID" => format!("{:>04X}",header.vendor_id), + "$DEVID" => format!("{:>04X}",header.device_id), + _ => arg.clone() + } }; command.arg(&arg); } From 2e07aab6de8d14c9c370f436c783989d372b5e7e Mon Sep 17 00:00:00 2001 From: Date: Fri, 1 Dec 2017 21:41:21 +0900 Subject: [PATCH 0210/1301] fixed pcid unsafe problem --- pcid/src/main.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 46575570f8..2cd365928d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -41,15 +41,13 @@ fn main() { if let Some(header) = func.header() { let pci_class = PciClass::from(header.class); - let mut string; - - unsafe { - string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", + let mut string = unsafe { + format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", bus.num, dev.num, func.num, header.vendor_id, header.device_id, header.class, header.subclass, header.interface, header.revision, - pci_class); - } + pci_class) + }; match pci_class { PciClass::Storage => match header.subclass { From dd5f83cd39135a025f3f13c778ea92b5cf912302 Mon Sep 17 00:00:00 2001 From: SeongUk Cho Date: Fri, 1 Dec 2017 21:52:01 +0900 Subject: [PATCH 0211/1301] solved error: #[derive] can't be used on a non-Copy #[repr(packed)] struct (error E0133) --- pcid/src/pci/header.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index 2cc335e388..332542a569 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -1,7 +1,7 @@ use std::ops::{Deref, DerefMut}; use std::{slice, mem}; -#[derive(Debug, Default)] +#[derive(Default)] #[repr(packed)] pub struct PciHeader { pub vendor_id: u16, From c78d4dcff091e5ea5f8f12511cf9a5e24aabb1b7 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Tue, 2 Jan 2018 23:03:54 -0800 Subject: [PATCH 0212/1301] ahci: atapi support (incomplete) It can currently retrieve the capacity; no reads or writes yet. --- Cargo.lock | 193 +++++++++++++----------- ahcid/Cargo.toml | 1 + ahcid/src/ahci/{disk.rs => disk_ata.rs} | 17 ++- ahcid/src/ahci/disk_atapi.rs | 81 ++++++++++ ahcid/src/ahci/hba.rs | 76 +++++++++- ahcid/src/ahci/mod.rs | 38 ++++- ahcid/src/main.rs | 1 + ahcid/src/scheme.rs | 8 +- 8 files changed, 309 insertions(+), 106 deletions(-) rename ahcid/src/ahci/{disk.rs => disk_ata.rs} (91%) create mode 100644 ahcid/src/ahci/disk_atapi.rs diff --git a/Cargo.lock b/Cargo.lock index 941a29bc33..fffa149671 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,7 +3,8 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -14,13 +15,13 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "arg_parser" version = "0.1.0" -source = "git+https://github.com/redox-os/arg-parser.git#d16e2d02e87996bbe2bce4a201c66c0df4a1e866" +source = "git+https://github.com/redox-os/arg-parser.git#7503531821b0c111f9fac77a5d2536ea221105fe" [[package]] name = "arrayvec" @@ -35,7 +36,7 @@ name = "base64" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -44,7 +45,7 @@ name = "bgad" version = "0.1.0" dependencies = [ "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -52,6 +53,11 @@ name = "bitflags" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bitflags" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "0.4.2" @@ -64,7 +70,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.1.0" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -83,7 +94,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -94,23 +105,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "extra" version = "0.1.0" -source = "git+https://github.com/redox-os/libextra.git#402932084acd5fef4812945887ceaaa2ddd5f264" +source = "git+https://github.com/redox-os/libextra.git#f38608acd9cc00e1c8bd41a1a96d31becf239913" [[package]] name = "fuchsia-zircon" -version = "0.2.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fuchsia-zircon-sys" -version = "0.2.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "gcc" @@ -130,9 +139,9 @@ dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -166,7 +175,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -191,7 +200,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.33" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -201,8 +210,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "matches" @@ -214,7 +234,7 @@ name = "mime" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -226,11 +246,11 @@ dependencies = [ "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.0 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -250,12 +270,12 @@ dependencies = [ [[package]] name = "num" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -263,7 +283,7 @@ name = "num-integer" version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -272,20 +292,20 @@ version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -293,7 +313,7 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -302,17 +322,17 @@ name = "orbclient" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pbr" version = "1.0.0" -source = "git+https://github.com/a8m/pb#e9369ed2b94df4f554fe79c2643de41f7338475f" +source = "git+https://github.com/a8m/pb#d077b49ac6ea18ef63a9bb9f0f0b58abc29580f3" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -322,9 +342,9 @@ dependencies = [ name = "pcid" version = "0.1.0" dependencies = [ - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -335,7 +355,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "plain" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -345,7 +365,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -355,16 +375,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ransid" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "vte 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -385,9 +405,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -395,7 +415,7 @@ name = "redox_event" version = "0.1.0" source = "git+https://github.com/redox-os/event.git#bb96d9cd6dd01d4118deae84722a522b8328fa9f" dependencies = [ - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -403,12 +423,12 @@ name = "redox_event" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.31" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -416,7 +436,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -426,7 +446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -438,7 +458,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -447,7 +467,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -481,9 +501,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -492,27 +512,27 @@ name = "sdl2-sys" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" -version = "1.0.21" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.21" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.17.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -555,8 +575,8 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -566,8 +586,8 @@ version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -576,7 +596,7 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -641,7 +661,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -654,8 +674,8 @@ name = "vesad" version = "0.1.0" dependencies = [ "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ransid 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "ransid 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -701,9 +721,9 @@ name = "xhcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -712,14 +732,16 @@ dependencies = [ "checksum arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0ef4a9820019a0c91d918918c93dc71d469f581a49b47ddc1d285d4270bbe2" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" "checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" +"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" +"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" "checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" "checksum extra 0.1.0 (git+https://github.com/redox-os/libextra.git)" = "" -"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159" -"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82" +"checksum fuchsia-zircon 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd510087c325af53ba24f3be8f1c081b0982319adcb8b03cad764512923ccc19" +"checksum fuchsia-zircon-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "08b3a6f13ad6b96572b53ce7af74543132f1a7055ccceb6d073dd36c54481859" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" @@ -728,31 +750,32 @@ dependencies = [ "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum libc 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "5ba3df4dcb460b9dfbd070d41c94c19209620c191b0340b929ce748a2bcd42d2" +"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0" "checksum linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2aab0478615bb586559b0114d94dd8eca4fdbb73b443adcb0d00b61692b4bf" -"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b" +"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" +"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)" = "" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" -"checksum num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "a311b77ebdc5dd4cf6449d81e4135d9f0e3b153839ac90e648a8ef538f923525" +"checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca" "checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" -"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" -"checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d" +"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" +"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "6e5d8d9900998fb4b9394e27058aa22a6d3509fb67dd860f74ba0507d4406943" "checksum pbr 1.0.0 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum plain 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da55423d5704ee357503ce020f88b90269610ec85708331e6a7879dd4cea3122" +"checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd" -"checksum ransid 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6cff8161c032c6c37e794ac4544c91dce9fd9c568d266ba4d171976bb6ffae97" +"checksum rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7944d95d25ace8f377da3ac7068ce517e4c646754c43a1b1849177bbf72e59" +"checksum ransid 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "40d85bc00ee0c715880755a40426b51c81fd1fce338f0a0fd82164041e62ab53" "checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" "checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53" "checksum redox_event 0.1.0 (git+https://github.com/redox-os/event.git)" = "" "checksum redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98e1a40d38f45a3ad65fd088640eeee7b215adcd73041b9f94b92204cca9572a" -"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509" +"checksum redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "07b8f011e3254d5a9b318fde596d409a0001c9ae4c6e7907520c2eaa4d988c99" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" "checksum rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17727f4b991294da2c84d75a43c003151ff58072212768800f66c56ee46dca43" @@ -761,9 +784,9 @@ dependencies = [ "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum sdl2 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63066036ad426250ac56d23e38fd05063b38b661556acd596f4046cc92d98415" "checksum sdl2-sys 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b48638b7882759f3421038fcd38ad5f1ea19b119d80c99f1601933004629e34d" -"checksum serde 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6eda663e865517ee783b0891a3f6eb3a253e0b0dabb46418969ee9635beadd9e" -"checksum serde_derive 1.0.21 (registry+https://github.com/rust-lang/crates.io-index)" = "652bc323d694dc925829725ec6c890156d8e70ae5202919869cb00fe2eff3788" -"checksum serde_derive_internals 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32f1926285523b2db55df263d2aa4eb69ddcfa7a7eade6430323637866b513ab" +"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526" +"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0" +"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5" "checksum spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7e4deb3c2455c73779e6d3eebceae9599fc70957e54c69fe88f93aa48e62f432" "checksum stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21b5c3b588a493a477e0d99769ee091b3627625f9ba4bdd882e6b4b0b0958805" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index b881ce614b..bf17750b2c 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -6,3 +6,4 @@ version = "0.1.0" bitflags = "0.7" spin = "0.4" redox_syscall = "0.1" +byteorder = "1.2" diff --git a/ahcid/src/ahci/disk.rs b/ahcid/src/ahci/disk_ata.rs similarity index 91% rename from ahcid/src/ahci/disk.rs rename to ahcid/src/ahci/disk_ata.rs index 52170af710..9168c52804 100644 --- a/ahcid/src/ahci/disk.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -4,8 +4,9 @@ use syscall::io::Dma; use syscall::error::Result; use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; +use super::Disk; -pub struct Disk { +pub struct DiskATA { id: usize, port: &'static mut HbaPort, size: u64, @@ -15,7 +16,7 @@ pub struct Disk { buf: Dma<[u8; 256 * 512]> } -impl Disk { +impl DiskATA { pub fn new(id: usize, port: &'static mut HbaPort) -> Result { let mut clb = Dma::zeroed()?; let mut ctbas = [ @@ -35,7 +36,7 @@ impl Disk { let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) }; - Ok(Disk { + Ok(DiskATA { id: id, port: port, size: size, @@ -45,16 +46,18 @@ impl Disk { buf: buf }) } +} - pub fn id(&self) -> usize { +impl Disk for DiskATA { + fn id(&self) -> usize { self.id } - pub fn size(&self) -> u64 { + fn size(&mut self) -> u64 { self.size } - pub fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { + fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { let sectors = buffer.len()/512; let mut sector: usize = 0; @@ -80,7 +83,7 @@ impl Disk { Ok(sector * 512) } - pub fn write(&mut self, block: u64, buffer: &[u8]) -> Result { + fn write(&mut self, block: u64, buffer: &[u8]) -> Result { let sectors = buffer.len()/512; let mut sector: usize = 0; diff --git a/ahcid/src/ahci/disk_atapi.rs b/ahcid/src/ahci/disk_atapi.rs new file mode 100644 index 0000000000..3ddc531690 --- /dev/null +++ b/ahcid/src/ahci/disk_atapi.rs @@ -0,0 +1,81 @@ +#![allow(dead_code)] + +use byteorder::{ByteOrder, BigEndian}; + +use syscall::io::Dma; +use syscall::error::{Result, ENOSYS, Error}; + +use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; +use super::Disk; + +const SCSI_READ_CAPACITY: u8 = 0x25; + +pub struct DiskATAPI { + id: usize, + port: &'static mut HbaPort, + size: u64, + clb: Dma<[HbaCmdHeader; 32]>, + ctbas: [Dma; 32], + _fb: Dma<[u8; 256]>, + buf: Dma<[u8; 256 * 512]> +} + +impl DiskATAPI { + pub fn new(id: usize, port: &'static mut HbaPort) -> Result { + let mut clb = Dma::zeroed()?; + let mut ctbas = [ + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + ]; + let mut fb = Dma::zeroed()?; + let buf = Dma::zeroed()?; + + port.init(&mut clb, &mut ctbas, &mut fb); + + let size = unsafe { port.identify_packet(&mut clb, &mut ctbas).unwrap_or(0) }; + + Ok(DiskATAPI { + id: id, + port: port, + size: size, + clb: clb, + ctbas: ctbas, + _fb: fb, + buf: buf + }) + } +} + +impl Disk for DiskATAPI { + fn id(&self) -> usize { + self.id + } + + fn size(&mut self) -> u64 { + let mut cmd = [0; 16]; + cmd[0] = SCSI_READ_CAPACITY; + if let Err(_) = self.port.packet(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf) { + return 0; // XXX + } + + let blk_count = BigEndian::read_u32(&self.buf[0..4]); + let blk_size = BigEndian::read_u32(&self.buf[4..8]); + + (blk_count as u64) * (blk_size as u64) + } + + fn read(&mut self, _block: u64, _buffer: &mut [u8]) -> Result { + Err(Error::new(ENOSYS)) + } + + fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result { + Err(Error::new(ENOSYS)) // TODO: Implement writting + } + +} diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 53f54d77dc..550dc50e4e 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -10,6 +10,8 @@ use super::fis::{FisType, FisRegH2D}; const ATA_CMD_READ_DMA_EXT: u8 = 0x25; const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35; const ATA_CMD_IDENTIFY: u8 = 0xEC; +const ATA_CMD_IDENTIFY_PACKET: u8 = 0xA1; +const ATA_CMD_PACKET: u8 = 0xA0; const ATA_DEV_BUSY: u8 = 0x80; const ATA_DEV_DRQ: u8 = 0x08; @@ -129,6 +131,15 @@ impl HbaPort { } pub unsafe fn identify(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { + self.identify_inner(ATA_CMD_IDENTIFY, clb, ctbas) + } + + pub unsafe fn identify_packet(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { + self.identify_inner(ATA_CMD_IDENTIFY_PACKET, clb, ctbas) + } + + // Shared between identify() and identify_packet() + unsafe fn identify_inner(&mut self, cmd: u8, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { self.is.write(u32::MAX); let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); @@ -152,7 +163,7 @@ impl HbaPort { cmdfis.fis_type.write(FisType::RegH2D as u8); cmdfis.pm.write(1 << 7); - cmdfis.command.write(ATA_CMD_IDENTIFY); + cmdfis.command.write(cmd); cmdfis.device.write(0); cmdfis.countl.write(1); cmdfis.counth.write(0); @@ -335,6 +346,67 @@ impl HbaPort { Err(Error::new(EIO)) } } + + /// Send ATAPI packet + pub fn packet(&mut self, cmd: &[u8; 16], size: u32, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<()> { + self.is.write(u32::MAX); + + if let Some(slot) = self.slot() { + let cmdheader = &mut clb[slot as usize]; + cmdheader.cfl.write(((size_of::() / size_of::()) as u8) | (1 << 5)); + cmdheader.prdtl.write(1); + + { + let cmdtbl = &mut ctbas[slot as usize]; + unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()) }; + + let prdt_entry = &mut cmdtbl.prdt_entry[0]; + prdt_entry.dba.write(buf.physical() as u64); + prdt_entry.dbc.write(size - 1); + } + + { + let cmdfis = unsafe { &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D) }; + + cmdfis.fis_type.write(FisType::RegH2D as u8); + cmdfis.pm.write(1 << 7); + cmdfis.command.write(ATA_CMD_PACKET); + cmdfis.device.write(0); + cmdfis.lba1.write(0); + cmdfis.lba2.write(0); + cmdfis.featurel.write(1); + cmdfis.featureh.write(0); + } + + let acmd = unsafe { &mut *(ctbas[slot as usize].acmd.as_mut_ptr() as *mut [u8; 16]) }; + *acmd = *cmd; + + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { + thread::yield_now(); + } + + self.ci.writef(1 << slot, true); + + self.start(); + + while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { + thread::yield_now(); + } + + self.stop(); + + if self.is.read() & HBA_PORT_IS_ERR != 0 { + print!("{}", format!("ERROR IS {:X} TFD {:X} SERR {:X}\n", self.is.read(), self.tfd.read(), self.serr.read())); + return Err(Error::new(EIO)); + } + + Ok(()) + + } else { + print!("No Command Slots\n"); + Err(Error::new(EIO)) + } + } } #[repr(packed)] @@ -384,7 +456,7 @@ pub struct HbaCmdTable { cfis: [Mmio; 64], // Command FIS // 0x40 - _acmd: [Mmio; 16], // ATAPI command, 12 or 16 bytes + acmd: [Mmio; 16], // ATAPI command, 12 or 16 bytes // 0x50 _rsv: [Mmio; 48], // Reserved diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index 072be72025..b91f68558b 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -1,25 +1,45 @@ use syscall::io::Io; +use syscall::error::Result; -use self::disk::Disk; +use self::disk_ata::DiskATA; +use self::disk_atapi::DiskATAPI; use self::hba::{HbaMem, HbaPortType}; -pub mod disk; +pub mod disk_ata; +pub mod disk_atapi; pub mod fis; pub mod hba; -pub fn disks(base: usize, name: &str) -> Vec { +pub trait Disk { + fn id(&self) -> usize; + fn size(&mut self) -> u64; + fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result; + fn write(&mut self, block: u64, buffer: &[u8]) -> Result; +} + +pub fn disks(base: usize, name: &str) -> Vec> { unsafe { &mut *(base as *mut HbaMem) }.init(); let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); - let ret: Vec = (0..32) + let ret: Vec> = (0..32) .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) .filter_map(|i| { let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i]; let port_type = port.probe(); print!("{}", format!("{}-{}: {:?}\n", name, i, port_type)); - match port_type { + + let disk: Option> = match port_type { HbaPortType::SATA => { - match Disk::new(i, port) { - Ok(disk) => Some(disk), + match DiskATA::new(i, port) { + Ok(disk) => Some(Box::new(disk)), + Err(err) => { + print!("{}", format!("{}: {}\n", i, err)); + None + } + } + } + HbaPortType::SATAPI => { + match DiskATAPI::new(i, port) { + Ok(disk) => Some(Box::new(disk)), Err(err) => { print!("{}", format!("{}: {}\n", i, err)); None @@ -27,7 +47,9 @@ pub fn disks(base: usize, name: &str) -> Vec { } } _ => None, - } + }; + + disk }) .collect(); diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index d9339c41a4..9eaffe2653 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -3,6 +3,7 @@ extern crate spin; extern crate syscall; +extern crate byteorder; use std::{env, usize}; use std::fs::File; diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index c02e3f5322..7701496a28 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -7,23 +7,23 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use spin::Mutex; use syscall::{Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, Result, Scheme, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; -use ahci::disk::Disk; +use ahci::Disk; #[derive(Clone)] enum Handle { List(Vec, usize), - Disk(Arc>, usize, usize) + Disk(Arc>>, usize, usize) } pub struct DiskScheme { scheme_name: String, - disks: Box<[Arc>]>, + disks: Box<[Arc>>]>, handles: Mutex>, next_id: AtomicUsize } impl DiskScheme { - pub fn new(scheme_name: String, disks: Vec) -> DiskScheme { + pub fn new(scheme_name: String, disks: Vec>) -> DiskScheme { let mut disk_arcs = vec![]; for disk in disks { disk_arcs.push(Arc::new(Mutex::new(disk))); From 78ab38626853047babc50e23e25f3989deab2c50 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 4 Jan 2018 12:25:47 -0800 Subject: [PATCH 0213/1301] Move capacity reading to seperate method --- ahcid/src/ahci/disk_atapi.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/ahcid/src/ahci/disk_atapi.rs b/ahcid/src/ahci/disk_atapi.rs index 3ddc531690..8159c39bf3 100644 --- a/ahcid/src/ahci/disk_atapi.rs +++ b/ahcid/src/ahci/disk_atapi.rs @@ -50,6 +50,19 @@ impl DiskATAPI { buf: buf }) } + + fn read_capacity(&mut self) -> Result<(u32, u32)> { + // TODO: only query when needed (disk changed) + + let mut cmd = [0; 16]; + cmd[0] = SCSI_READ_CAPACITY; + self.port.packet(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + + let blk_count = BigEndian::read_u32(&self.buf[0..4]); + let blk_size = BigEndian::read_u32(&self.buf[4..8]); + + Ok((blk_count, blk_size)) + } } impl Disk for DiskATAPI { @@ -58,16 +71,10 @@ impl Disk for DiskATAPI { } fn size(&mut self) -> u64 { - let mut cmd = [0; 16]; - cmd[0] = SCSI_READ_CAPACITY; - if let Err(_) = self.port.packet(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return 0; // XXX + match self.read_capacity() { + Ok((blk_count, blk_size)) => (blk_count as u64) * (blk_size as u64), + Err(_) => 0 // XXX } - - let blk_count = BigEndian::read_u32(&self.buf[0..4]); - let blk_size = BigEndian::read_u32(&self.buf[4..8]); - - (blk_count as u64) * (blk_size as u64) } fn read(&mut self, _block: u64, _buffer: &mut [u8]) -> Result { From 9de5eb7045f447b0fa1febaca78ccb892ce8625b Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 4 Jan 2018 14:20:12 -0800 Subject: [PATCH 0214/1301] atapi: Implement read support --- ahcid/src/ahci/disk_ata.rs | 12 +++++----- ahcid/src/ahci/disk_atapi.rs | 45 ++++++++++++++++++++++++++++++++++-- ahcid/src/ahci/mod.rs | 1 + ahcid/src/scheme.rs | 6 +++-- 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index 9168c52804..8ac33d56b4 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -62,18 +62,14 @@ impl Disk for DiskATA { let mut sector: usize = 0; while sectors - sector >= 255 { - if let Err(err) = self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } + self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf)?; unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); } sector += 255; } if sector < sectors { - if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } + self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf)?; unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); } @@ -108,4 +104,8 @@ impl Disk for DiskATA { Ok(sector * 512) } + + fn block_length(&mut self) -> Result { + Ok(512) + } } diff --git a/ahcid/src/ahci/disk_atapi.rs b/ahcid/src/ahci/disk_atapi.rs index 8159c39bf3..0dd7b69966 100644 --- a/ahcid/src/ahci/disk_atapi.rs +++ b/ahcid/src/ahci/disk_atapi.rs @@ -1,5 +1,7 @@ #![allow(dead_code)] +use std::ptr; + use byteorder::{ByteOrder, BigEndian}; use syscall::io::Dma; @@ -9,6 +11,7 @@ use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; use super::Disk; const SCSI_READ_CAPACITY: u8 = 0x25; +const SCSI_READ10: u8 = 0x28; pub struct DiskATAPI { id: usize, @@ -17,6 +20,8 @@ pub struct DiskATAPI { clb: Dma<[HbaCmdHeader; 32]>, ctbas: [Dma; 32], _fb: Dma<[u8; 256]>, + // Just using the same buffer size as DiskATA + // Although the sector size is different (and varies) buf: Dma<[u8; 256 * 512]> } @@ -77,12 +82,48 @@ impl Disk for DiskATAPI { } } - fn read(&mut self, _block: u64, _buffer: &mut [u8]) -> Result { - Err(Error::new(ENOSYS)) + fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { + // TODO: Handle audio CDs, which use special READ CD command + + let blk_len = self.block_length()?; + let sectors = buffer.len() as u32 / blk_len; + + fn read10_cmd(block: u32, count: u16) -> [u8; 16] { + let mut cmd = [0; 16]; + cmd[0] = SCSI_READ10; + BigEndian::write_u32(&mut cmd[2..6], block as u32); + BigEndian::write_u16(&mut cmd[7..9], count as u16); + cmd + } + + let mut sector = 0; + let buf_len = (256 * 512) / blk_len; + let buf_size = buf_len * blk_len; + while sectors - sector >= buf_len { + let cmd = read10_cmd(block as u32 + sector, buf_len as u16); + self.port.packet(&cmd, buf_size, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * blk_len as isize), buf_size as usize); } + + sector += blk_len; + } + if sector < sectors { + let cmd = read10_cmd(block as u32 + sector, (sectors - sector) as u16); + self.port.packet(&cmd, buf_size, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * blk_len as isize), ((sectors - sector) * blk_len) as usize); } + + sector += sectors - sector; + } + + Ok((sector * blk_len) as usize) } fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result { Err(Error::new(ENOSYS)) // TODO: Implement writting } + fn block_length(&mut self) -> Result { + Ok(self.read_capacity()?.1) + } } diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index b91f68558b..7b8444d749 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -15,6 +15,7 @@ pub trait Disk { fn size(&mut self) -> u64; fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result; fn write(&mut self, block: u64, buffer: &[u8]) -> Result; + fn block_length(&mut self) -> Result; } pub fn disks(base: usize, name: &str) -> Vec> { diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 7701496a28..e981443e9e 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -150,7 +150,8 @@ impl Scheme for DiskScheme { }, Handle::Disk(ref mut handle, ref mut size, _) => { let mut disk = handle.lock(); - let count = disk.read((*size as u64)/512, buf)?; + let blk_len = disk.block_length()?; + let count = disk.read((*size as u64)/(blk_len as u64), buf)?; *size += count; Ok(count) } @@ -165,7 +166,8 @@ impl Scheme for DiskScheme { }, Handle::Disk(ref mut handle, ref mut size, _) => { let mut disk = handle.lock(); - let count = disk.write((*size as u64)/512, buf)?; + let blk_len = disk.block_length()?; + let count = disk.write((*size as u64)/(blk_len as u64), buf)?; *size += count; Ok(count) } From c8154e7607ee4e4f8a133b4f961bab85213a4621 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Sat, 6 Jan 2018 23:47:45 -0800 Subject: [PATCH 0215/1301] ahci: refactor duplicated ATA command code into a method --- ahcid/src/ahci/disk_ata.rs | 8 +- ahcid/src/ahci/hba.rs | 249 +++++++++++++------------------------ 2 files changed, 93 insertions(+), 164 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index 8ac33d56b4..2eb48ea63d 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -62,14 +62,14 @@ impl Disk for DiskATA { let mut sector: usize = 0; while sectors - sector >= 255 { - self.port.ata_dma(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + self.port.dma_read_write(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf)?; unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); } sector += 255; } if sector < sectors { - self.port.ata_dma(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + self.port.dma_read_write(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf)?; unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); } @@ -86,7 +86,7 @@ impl Disk for DiskATA { while sectors - sector >= 255 { unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), 255 * 512); } - if let Err(err) = self.port.ata_dma(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { + if let Err(err) = self.port.dma_read_write(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { return Err(err); } @@ -95,7 +95,7 @@ impl Disk for DiskATA { if sector < sectors { unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), (sectors - sector) * 512); } - if let Err(err) = self.port.ata_dma(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { + if let Err(err) = self.port.dma_read_write(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { return Err(err); } diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 550dc50e4e..982ad5e820 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -140,54 +140,24 @@ impl HbaPort { // Shared between identify() and identify_packet() unsafe fn identify_inner(&mut self, cmd: u8, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { - self.is.write(u32::MAX); let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); - if let Some(slot) = self.slot() { - let cmdheader = &mut clb[slot as usize]; - cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); + let res = self.ata_dma(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { cmdheader.prdtl.write(1); - { - let cmdtbl = &mut ctbas[slot as usize]; - ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()); + let prdt_entry = &mut prdt_entries[0]; + prdt_entry.dba.write(dest.physical() as u64); + prdt_entry.dbc.write(512 | 1); - let prdt_entry = &mut cmdtbl.prdt_entry[0]; - prdt_entry.dba.write(dest.physical() as u64); - prdt_entry.dbc.write(512 | 1); - } - - { - let cmdfis = &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D); - - cmdfis.fis_type.write(FisType::RegH2D as u8); - cmdfis.pm.write(1 << 7); - cmdfis.command.write(cmd); - cmdfis.device.write(0); - cmdfis.countl.write(1); - cmdfis.counth.write(0); - } - - while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - thread::yield_now(); - } - - self.ci.writef(1 << slot, true); - - self.start(); - - while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { - thread::yield_now(); - } - - self.stop(); - - if self.is.read() & HBA_PORT_IS_ERR != 0 { - print!("{}", format!("ERROR IS {:X} TFD {:X} SERR {:X}\n", self.is.read(), self.tfd.read(), self.serr.read())); - return None; - } + cmdfis.pm.write(1 << 7); + cmdfis.command.write(cmd); + cmdfis.device.write(0); + cmdfis.countl.write(1); + cmdfis.counth.write(0); + }); + if res.is_ok() { let mut serial = String::new(); for word in 10..20 { let d = dest[word]; @@ -248,82 +218,105 @@ impl HbaPort { } } - pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result { + pub fn dma_read_write(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result { if write { //print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write)); } assert!(sectors > 0 && sectors < 256); - self.is.write(u32::MAX); - - if let Some(slot) = self.slot() { + let res = self.ata_dma(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { if write { - //print!("{}", format!("SLOT {}\n", slot)); + let cfl = cmdheader.cfl.read(); + cmdheader.cfl.write(cfl | 1 << 7 | 1 << 6) } - let cmdheader = &mut clb[slot as usize]; - - cmdheader.cfl.write(((size_of::() / size_of::()) as u8) | if write { 1 << 7 | 1 << 6 } else { 0 }); - cmdheader.prdtl.write(1); - { - let cmdtbl = &mut ctbas[slot as usize]; - unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()) }; - - let prdt_entry = &mut cmdtbl.prdt_entry[0]; - prdt_entry.dba.write(buf.physical() as u64); - prdt_entry.dbc.write(((sectors * 512) as u32) | 1); - } - - { - let cmdfis = unsafe { &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D) }; - - cmdfis.fis_type.write(FisType::RegH2D as u8); - cmdfis.pm.write(1 << 7); - if write { - cmdfis.command.write(ATA_CMD_WRITE_DMA_EXT); - } else { - cmdfis.command.write(ATA_CMD_READ_DMA_EXT); - } - - cmdfis.lba0.write(block as u8); - cmdfis.lba1.write((block >> 8) as u8); - cmdfis.lba2.write((block >> 16) as u8); - - cmdfis.device.write(1 << 6); - - cmdfis.lba3.write((block >> 24) as u8); - cmdfis.lba4.write((block >> 32) as u8); - cmdfis.lba5.write((block >> 40) as u8); - - cmdfis.countl.write(sectors as u8); - cmdfis.counth.write((sectors >> 8) as u8); - } + let prdt_entry = &mut prdt_entries[0]; + prdt_entry.dba.write(buf.physical() as u64); + prdt_entry.dbc.write(((sectors * 512) as u32) | 1); + cmdfis.pm.write(1 << 7); if write { - //print!("WAIT ATA_DEV_BUSY | ATA_DEV_DRQ\n"); + cmdfis.command.write(ATA_CMD_WRITE_DMA_EXT); + } else { + cmdfis.command.write(ATA_CMD_READ_DMA_EXT); } + + cmdfis.lba0.write(block as u8); + cmdfis.lba1.write((block >> 8) as u8); + cmdfis.lba2.write((block >> 16) as u8); + + cmdfis.device.write(1 << 6); + + cmdfis.lba3.write((block >> 24) as u8); + cmdfis.lba4.write((block >> 32) as u8); + cmdfis.lba5.write((block >> 40) as u8); + + cmdfis.countl.write(sectors as u8); + cmdfis.counth.write((sectors >> 8) as u8); + }); + + res.and(Ok(sectors * 512)) + } + + /// Send ATAPI packet + pub fn packet(&mut self, cmd: &[u8; 16], size: u32, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<()> { + self.ata_dma(clb, ctbas, |cmdheader, cmdfis, prdt_entries, acmd| { + let cfl = cmdheader.cfl.read(); + cmdheader.cfl.write(cfl | 1 << 5); + + cmdheader.prdtl.write(1); + + let prdt_entry = &mut prdt_entries[0]; + prdt_entry.dba.write(buf.physical() as u64); + prdt_entry.dbc.write(size - 1); + + cmdfis.pm.write(1 << 7); + cmdfis.command.write(ATA_CMD_PACKET); + cmdfis.device.write(0); + cmdfis.lba1.write(0); + cmdfis.lba2.write(0); + cmdfis.featurel.write(1); + cmdfis.featureh.write(0); + + unsafe { ptr::write_volatile(acmd.as_mut_ptr() as *mut [u8; 16], *cmd) }; + }) + } + + fn ata_dma(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], callback: F) -> Result<()> + where F: FnOnce(&mut HbaCmdHeader, &mut FisRegH2D, &mut [HbaPrdtEntry; 65536], &mut [Mmio; 16]) { + + self.is.write(u32::MAX); + + if let Some(slot) = self.slot() { + { + let cmdheader = &mut clb[slot as usize]; + cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); + + let cmdtbl = &mut ctbas[slot as usize]; + unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()); } + + let cmdfis = unsafe { &mut *(cmdtbl.cfis.as_mut_ptr() as *mut FisRegH2D) }; + cmdfis.fis_type.write(FisType::RegH2D as u8); + + let prdt_entry = unsafe { &mut *(&mut cmdtbl.prdt_entry as *mut _) }; + let acmd = unsafe { &mut *(&mut cmdtbl.acmd as *mut _) }; + + callback(cmdheader, cmdfis, prdt_entry, acmd) + } + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { thread::yield_now(); } - if write { - //print!("{}", format!("WRITE CI {:X} in {:X}\n", 1 << slot, self.ci.read())); - } self.ci.writef(1 << slot, true); self.start(); - if write { - //print!("{}", format!("WAIT CI {:X} in {:X}\n", 1 << slot, self.ci.read())); - } while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { thread::yield_now(); - if write { - //print!("{}", format!("WAIT CI {:X} TFD {:X} IS {:X} CMD {:X} SERR {:X}\n", self.ci.read(), self.tfd.read(), self.is.read(), self.cmd.read(), self.serr.read())); - } } self.stop(); @@ -334,74 +327,10 @@ impl HbaPort { self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(), self.ci.read(), self.sntf.read(), self.fbs.read())); self.is.write(u32::MAX); - return Err(Error::new(EIO)); + Err(Error::new(EIO)) + } else { + Ok(()) } - - if write { - //print!("{}", format!("SUCCESS {}\n", sectors)); - } - Ok(sectors * 512) - } else { - print!("No Command Slots\n"); - Err(Error::new(EIO)) - } - } - - /// Send ATAPI packet - pub fn packet(&mut self, cmd: &[u8; 16], size: u32, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<()> { - self.is.write(u32::MAX); - - if let Some(slot) = self.slot() { - let cmdheader = &mut clb[slot as usize]; - cmdheader.cfl.write(((size_of::() / size_of::()) as u8) | (1 << 5)); - cmdheader.prdtl.write(1); - - { - let cmdtbl = &mut ctbas[slot as usize]; - unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()) }; - - let prdt_entry = &mut cmdtbl.prdt_entry[0]; - prdt_entry.dba.write(buf.physical() as u64); - prdt_entry.dbc.write(size - 1); - } - - { - let cmdfis = unsafe { &mut *(ctbas[slot as usize].cfis.as_mut_ptr() as *mut FisRegH2D) }; - - cmdfis.fis_type.write(FisType::RegH2D as u8); - cmdfis.pm.write(1 << 7); - cmdfis.command.write(ATA_CMD_PACKET); - cmdfis.device.write(0); - cmdfis.lba1.write(0); - cmdfis.lba2.write(0); - cmdfis.featurel.write(1); - cmdfis.featureh.write(0); - } - - let acmd = unsafe { &mut *(ctbas[slot as usize].acmd.as_mut_ptr() as *mut [u8; 16]) }; - *acmd = *cmd; - - while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - thread::yield_now(); - } - - self.ci.writef(1 << slot, true); - - self.start(); - - while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { - thread::yield_now(); - } - - self.stop(); - - if self.is.read() & HBA_PORT_IS_ERR != 0 { - print!("{}", format!("ERROR IS {:X} TFD {:X} SERR {:X}\n", self.is.read(), self.tfd.read(), self.serr.read())); - return Err(Error::new(EIO)); - } - - Ok(()) - } else { print!("No Command Slots\n"); Err(Error::new(EIO)) From 78cff3f57cae934ce690b8d130e9a015662d0077 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 28 Jan 2018 14:49:29 -0700 Subject: [PATCH 0216/1301] Remove unnecessary parens --- ahcid/src/ahci/hba.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 982ad5e820..22358e7955 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -293,7 +293,7 @@ impl HbaPort { if let Some(slot) = self.slot() { { let cmdheader = &mut clb[slot as usize]; - cmdheader.cfl.write(((size_of::() / size_of::()) as u8)); + cmdheader.cfl.write((size_of::() / size_of::()) as u8); let cmdtbl = &mut ctbas[slot as usize]; unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()); } From 0897ddff17becd94990df0f8a536ea6187b752d2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 28 Jan 2018 14:50:14 -0700 Subject: [PATCH 0217/1301] Remove unnecessary parens --- vesad/src/screen/graphic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 45d4f9fcd2..d672426f22 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -102,7 +102,7 @@ impl Screen for GraphicScreen { let size = self.display.offscreen.len(); self.seek = match whence { - SEEK_SET => cmp::min(size, (pos/4)), + SEEK_SET => cmp::min(size, pos/4), SEEK_CUR => cmp::max(0, cmp::min(size as isize, self.seek as isize + (pos/4) as isize)) as usize, SEEK_END => cmp::max(0, cmp::min(size as isize, size as isize + (pos/4) as isize)) as usize, _ => return Err(Error::new(EINVAL)) From 1461404502ce86787007f33c603825721a31a239 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 28 Jan 2018 14:51:24 -0700 Subject: [PATCH 0218/1301] Remove unnecessary unsafe --- pcid/src/main.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 2cd365928d..a59a104fbe 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -89,7 +89,7 @@ fn main() { } } } - + string.push('\n'); print!("{}", string); @@ -128,12 +128,10 @@ fn main() { let mut command = Command::new(program); for arg in args { let bar_arg = |i| -> String { - unsafe { - match PciBar::from(header.bars[i]) { - PciBar::None => String::new(), - PciBar::Memory(address) => format!("{:>08X}", address), - PciBar::Port(address) => format!("{:>04X}", address) - } + match PciBar::from(header.bars[i]) { + PciBar::None => String::new(), + PciBar::Memory(address) => format!("{:>08X}", address), + PciBar::Port(address) => format!("{:>04X}", address) } }; let arg = unsafe { From b332607d774948eb375ee724b404f12ac581f4b8 Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Sun, 4 Feb 2018 02:35:36 +0000 Subject: [PATCH 0219/1301] Allow using a device ID range in toml config --- pcid/src/config.rs | 3 +++ pcid/src/main.rs | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/pcid/src/config.rs b/pcid/src/config.rs index 44c5e71df9..8a36d8df1d 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -1,3 +1,5 @@ +use std::ops::Range; + #[derive(Debug, Default, Deserialize)] pub struct Config { pub drivers: Vec @@ -11,5 +13,6 @@ pub struct DriverConfig { pub interface: Option, pub vendor: Option, pub device: Option, + pub device_id_range: Option>, pub command: Option> } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index a59a104fbe..ea8f3495a7 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -115,6 +115,11 @@ fn main() { if device != header.device_id { continue; } } + if let Some(ref device_id_range) = driver.device_id_range { + if header.device_id < device_id_range.start || + device_id_range.end <= header.device_id { continue; } + } + if let Some(ref args) = driver.command { // Enable bus mastering, memory space, and I/O space unsafe { @@ -149,6 +154,7 @@ fn main() { "$IRQ" => format!("{}", header.interrupt_line), "$VENID" => format!("{:>04X}",header.vendor_id), "$DEVID" => format!("{:>04X}",header.device_id), + "$SUBSYSID" => format!("{:>04X}",header.subsystem_id), _ => arg.clone() } }; From 1b60f10b0e47773ef85584bdbc19999af52f969a Mon Sep 17 00:00:00 2001 From: Tibor Nagy Date: Tue, 6 Feb 2018 05:02:55 +0100 Subject: [PATCH 0220/1301] vesad: Fix Unicode character input Characters beyond 0x80 now properly encoded as UTF-8. --- vesad/src/screen/text.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 9bc7df0f67..af247c1238 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -105,7 +105,8 @@ impl Screen for TextScreen { }; if c != '\0' { - buf.extend_from_slice(&[c as u8]); + let mut b = [0; 4]; + buf.extend_from_slice(c.encode_utf8(&mut b).as_bytes()); } } } From 42adde5809a18c660ad6fd80272ad33ff9f8794f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 6 Feb 2018 09:52:14 -0700 Subject: [PATCH 0221/1301] Resize ps2d bounding box when vesad resizes --- ps2d/src/main.rs | 235 +----------------------------------------- ps2d/src/state.rs | 243 ++++++++++++++++++++++++++++++++++++++++++++ vesad/src/scheme.rs | 2 + 3 files changed, 248 insertions(+), 232 deletions(-) create mode 100644 ps2d/src/state.rs diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 7d4081a7eb..085ad529af 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -7,7 +7,7 @@ extern crate event; extern crate orbclient; extern crate syscall; -use std::{cmp, env, process}; +use std::{env, process}; use std::cell::RefCell; use std::fs::File; use std::io::{Read, Write, Result}; @@ -15,244 +15,15 @@ use std::os::unix::io::AsRawFd; use std::sync::Arc; use event::EventQueue; -use orbclient::{KeyEvent, MouseEvent, ButtonEvent, ScrollEvent}; use syscall::iopl; -use controller::Ps2; +use state::Ps2d; mod controller; mod keymap; +mod state; mod vm; -bitflags! { - flags MousePacketFlags: u8 { - const LEFT_BUTTON = 1, - const RIGHT_BUTTON = 1 << 1, - const MIDDLE_BUTTON = 1 << 2, - const ALWAYS_ON = 1 << 3, - const X_SIGN = 1 << 4, - const Y_SIGN = 1 << 5, - const X_OVERFLOW = 1 << 6, - const Y_OVERFLOW = 1 << 7 - } -} - -struct Ps2d char> { - ps2: Ps2, - vmmouse: bool, - input: File, - width: u32, - height: u32, - lshift: bool, - rshift: bool, - mouse_x: i32, - mouse_y: i32, - mouse_left: bool, - mouse_middle: bool, - mouse_right: bool, - packets: [u8; 4], - packet_i: usize, - extra_packet: bool, - //Keymap function - get_char: F -} - -impl char> Ps2d { - fn new(input: File, keymap: F) -> Self { - let mut ps2 = Ps2::new(); - let extra_packet = ps2.init(); - - let vmmouse = vm::enable(); - - let mut width = 0; - let mut height = 0; - { - let mut buf: [u8; 4096] = [0; 4096]; - if let Ok(count) = syscall::fpath(input.as_raw_fd() as usize, &mut buf) { - let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; - let res = path.split(":").nth(1).unwrap_or(""); - width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); - height = res.split("/").nth(2).unwrap_or("").parse::().unwrap_or(0); - } - } - - Ps2d { - ps2: ps2, - vmmouse: vmmouse, - input: input, - width: width, - height: height, - lshift: false, - rshift: false, - mouse_x: 0, - mouse_y: 0, - mouse_left: false, - mouse_middle: false, - mouse_right: false, - packets: [0; 4], - packet_i: 0, - extra_packet: extra_packet, - get_char: keymap - } - } - - fn irq(&mut self) { - while let Some((keyboard, data)) = self.ps2.next() { - self.handle(keyboard, data); - } - } - - fn handle(&mut self, keyboard: bool, data: u8) { - if keyboard { - let (scancode, pressed) = if data >= 0x80 { - (data - 0x80, false) - } else { - (data, true) - }; - - if scancode == 0x2A { - self.lshift = pressed; - } else if scancode == 0x36 { - self.rshift = pressed; - } - - self.input.write(&KeyEvent { - character: (self.get_char)(scancode, self.lshift || self.rshift), - scancode: scancode, - pressed: pressed - }.to_event()).expect("ps2d: failed to write key event"); - } else if self.vmmouse { - for _i in 0..256 { - let (status, _, _, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) }; - //TODO if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) - - let queue_length = status & 0xffff; - if queue_length == 0 { - break; - } - - if queue_length % 4 != 0 { - println!("queue length not a multiple of 4: {}", queue_length); - break; - } - - let (status, dx, dy, dz, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; - - let (x, y) = if status & vm::RELATIVE_PACKET == vm::RELATIVE_PACKET { - ( - cmp::max(0, cmp::min(self.width as i32, self.mouse_x + dx as i32)), - cmp::max(0, cmp::min(self.height as i32, self.mouse_y - dy as i32)) - ) - } else { - ( - dx as i32 * self.width as i32 / 0xFFFF, - dy as i32 * self.height as i32 / 0xFFFF - ) - }; - - if x != self.mouse_x || y != self.mouse_y { - self.mouse_x = x; - self.mouse_y = y; - self.input.write(&MouseEvent { - x: x, - y: y, - }.to_event()).expect("ps2d: failed to write mouse event"); - } - - if dz != 0 { - self.input.write(&ScrollEvent { - x: 0, - y: -(dz as i32), - }.to_event()).expect("ps2d: failed to write scroll event"); - } - - let left = status & vm::LEFT_BUTTON == vm::LEFT_BUTTON; - let middle = status & vm::MIDDLE_BUTTON == vm::MIDDLE_BUTTON; - let right = status & vm::RIGHT_BUTTON == vm::RIGHT_BUTTON; - if left != self.mouse_left || middle != self.mouse_middle || right != self.mouse_right { - self.mouse_left = left; - self.mouse_middle = middle; - self.mouse_right = right; - self.input.write(&ButtonEvent { - left: left, - middle: middle, - right: right, - }.to_event()).expect("ps2d: failed to write button event"); - } - } - } else { - self.packets[self.packet_i] = data; - self.packet_i += 1; - - let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); - if ! flags.contains(ALWAYS_ON) { - println!("MOUSE MISALIGN {:X}", self.packets[0]); - - self.packets = [0; 4]; - self.packet_i = 0; - } else if self.packet_i >= self.packets.len() || (!self.extra_packet && self.packet_i >= 3) { - if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { - let mut dx = self.packets[1] as i32; - if flags.contains(X_SIGN) { - dx -= 0x100; - } - - let mut dy = -(self.packets[2] as i32); - if flags.contains(Y_SIGN) { - dy += 0x100; - } - - let mut dz = 0; - if self.extra_packet { - let mut scroll = (self.packets[3] & 0xF) as i8; - if scroll & (1 << 3) == 1 << 3 { - scroll -= 16; - } - dz = -scroll as i32; - } - - let x = cmp::max(0, cmp::min(self.width as i32, self.mouse_x + dx)); - let y = cmp::max(0, cmp::min(self.height as i32, self.mouse_y + dy)); - if x != self.mouse_x || y != self.mouse_y { - self.mouse_x = x; - self.mouse_y = y; - self.input.write(&MouseEvent { - x: x, - y: y, - }.to_event()).expect("ps2d: failed to write mouse event"); - } - - if dz != 0 { - self.input.write(&ScrollEvent { - x: 0, - y: dz, - }.to_event()).expect("ps2d: failed to write scroll event"); - } - - let left = flags.contains(LEFT_BUTTON); - let middle = flags.contains(MIDDLE_BUTTON); - let right = flags.contains(RIGHT_BUTTON); - if left != self.mouse_left || middle != self.mouse_middle || right != self.mouse_right { - self.mouse_left = left; - self.mouse_middle = middle; - self.mouse_right = right; - self.input.write(&ButtonEvent { - left: left, - middle: middle, - right: right, - }.to_event()).expect("ps2d: failed to write button event"); - } - } else { - println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); - } - - self.packets = [0; 4]; - self.packet_i = 0; - } - } - } -} - fn daemon(input: File) { unsafe { iopl(3).expect("ps2d: failed to get I/O permission"); diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs new file mode 100644 index 0000000000..11472767a0 --- /dev/null +++ b/ps2d/src/state.rs @@ -0,0 +1,243 @@ +use orbclient::{KeyEvent, MouseEvent, ButtonEvent, ScrollEvent}; +use std::cmp; +use std::fs::File; +use std::io::Write; +use std::os::unix::io::AsRawFd; +use syscall; + +use controller::Ps2; +use vm; + +bitflags! { + flags MousePacketFlags: u8 { + const LEFT_BUTTON = 1, + const RIGHT_BUTTON = 1 << 1, + const MIDDLE_BUTTON = 1 << 2, + const ALWAYS_ON = 1 << 3, + const X_SIGN = 1 << 4, + const Y_SIGN = 1 << 5, + const X_OVERFLOW = 1 << 6, + const Y_OVERFLOW = 1 << 7 + } +} + +pub struct Ps2d char> { + ps2: Ps2, + vmmouse: bool, + input: File, + width: u32, + height: u32, + lshift: bool, + rshift: bool, + mouse_x: i32, + mouse_y: i32, + mouse_left: bool, + mouse_middle: bool, + mouse_right: bool, + packets: [u8; 4], + packet_i: usize, + extra_packet: bool, + //Keymap function + get_char: F +} + +impl char> Ps2d { + pub fn new(input: File, keymap: F) -> Self { + let mut ps2 = Ps2::new(); + let extra_packet = ps2.init(); + + let vmmouse = vm::enable(); + + let mut ps2d = Ps2d { + ps2: ps2, + vmmouse: vmmouse, + input: input, + width: 0, + height: 0, + lshift: false, + rshift: false, + mouse_x: 0, + mouse_y: 0, + mouse_left: false, + mouse_middle: false, + mouse_right: false, + packets: [0; 4], + packet_i: 0, + extra_packet: extra_packet, + get_char: keymap + }; + + ps2d.resize(); + + ps2d + } + + pub fn resize(&mut self) { + let mut buf: [u8; 4096] = [0; 4096]; + if let Ok(count) = syscall::fpath(self.input.as_raw_fd() as usize, &mut buf) { + let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; + let res = path.split(":").nth(1).unwrap_or(""); + self.width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); + self.height = res.split("/").nth(2).unwrap_or("").parse::().unwrap_or(0); + } + } + + pub fn irq(&mut self) { + while let Some((keyboard, data)) = self.ps2.next() { + self.handle(keyboard, data); + } + } + + pub fn handle(&mut self, keyboard: bool, data: u8) { + // TODO: Improve efficiency + self.resize(); + + if keyboard { + let (scancode, pressed) = if data >= 0x80 { + (data - 0x80, false) + } else { + (data, true) + }; + + if scancode == 0x2A { + self.lshift = pressed; + } else if scancode == 0x36 { + self.rshift = pressed; + } + + self.input.write(&KeyEvent { + character: (self.get_char)(scancode, self.lshift || self.rshift), + scancode: scancode, + pressed: pressed + }.to_event()).expect("ps2d: failed to write key event"); + } else if self.vmmouse { + for _i in 0..256 { + let (status, _, _, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) }; + //TODO if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) + + let queue_length = status & 0xffff; + if queue_length == 0 { + break; + } + + if queue_length % 4 != 0 { + println!("queue length not a multiple of 4: {}", queue_length); + break; + } + + let (status, dx, dy, dz, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; + + let (x, y) = if status & vm::RELATIVE_PACKET == vm::RELATIVE_PACKET { + ( + cmp::max(0, cmp::min(self.width as i32, self.mouse_x + dx as i32)), + cmp::max(0, cmp::min(self.height as i32, self.mouse_y - dy as i32)) + ) + } else { + ( + dx as i32 * self.width as i32 / 0xFFFF, + dy as i32 * self.height as i32 / 0xFFFF + ) + }; + + if x != self.mouse_x || y != self.mouse_y { + self.mouse_x = x; + self.mouse_y = y; + self.input.write(&MouseEvent { + x: x, + y: y, + }.to_event()).expect("ps2d: failed to write mouse event"); + } + + if dz != 0 { + self.input.write(&ScrollEvent { + x: 0, + y: -(dz as i32), + }.to_event()).expect("ps2d: failed to write scroll event"); + } + + let left = status & vm::LEFT_BUTTON == vm::LEFT_BUTTON; + let middle = status & vm::MIDDLE_BUTTON == vm::MIDDLE_BUTTON; + let right = status & vm::RIGHT_BUTTON == vm::RIGHT_BUTTON; + if left != self.mouse_left || middle != self.mouse_middle || right != self.mouse_right { + self.mouse_left = left; + self.mouse_middle = middle; + self.mouse_right = right; + self.input.write(&ButtonEvent { + left: left, + middle: middle, + right: right, + }.to_event()).expect("ps2d: failed to write button event"); + } + } + } else { + self.packets[self.packet_i] = data; + self.packet_i += 1; + + let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); + if ! flags.contains(ALWAYS_ON) { + println!("MOUSE MISALIGN {:X}", self.packets[0]); + + self.packets = [0; 4]; + self.packet_i = 0; + } else if self.packet_i >= self.packets.len() || (!self.extra_packet && self.packet_i >= 3) { + if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { + let mut dx = self.packets[1] as i32; + if flags.contains(X_SIGN) { + dx -= 0x100; + } + + let mut dy = -(self.packets[2] as i32); + if flags.contains(Y_SIGN) { + dy += 0x100; + } + + let mut dz = 0; + if self.extra_packet { + let mut scroll = (self.packets[3] & 0xF) as i8; + if scroll & (1 << 3) == 1 << 3 { + scroll -= 16; + } + dz = -scroll as i32; + } + + let x = cmp::max(0, cmp::min(self.width as i32, self.mouse_x + dx)); + let y = cmp::max(0, cmp::min(self.height as i32, self.mouse_y + dy)); + if x != self.mouse_x || y != self.mouse_y { + self.mouse_x = x; + self.mouse_y = y; + self.input.write(&MouseEvent { + x: x, + y: y, + }.to_event()).expect("ps2d: failed to write mouse event"); + } + + if dz != 0 { + self.input.write(&ScrollEvent { + x: 0, + y: dz, + }.to_event()).expect("ps2d: failed to write scroll event"); + } + + let left = flags.contains(LEFT_BUTTON); + let middle = flags.contains(MIDDLE_BUTTON); + let right = flags.contains(RIGHT_BUTTON); + if left != self.mouse_left || middle != self.mouse_middle || right != self.mouse_right { + self.mouse_left = left; + self.mouse_middle = middle; + self.mouse_right = right; + self.input.write(&ButtonEvent { + left: left, + middle: middle, + right: right, + }.to_event()).expect("ps2d: failed to write button event"); + } + } else { + println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); + } + + self.packets = [0; 4]; + self.packet_i = 0; + } + } + } +} diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 3e538c27ca..88382ea3af 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -236,6 +236,8 @@ impl SchemeMut for DisplayScheme { }, EventOption::Resize(resize_event) => { println!("Resizing to {}, {}", resize_event.width, resize_event.height); + self.width = resize_event.width as usize; + self.height = resize_event.height as usize; for (screen_i, screen) in self.screens.iter_mut() { screen.resize(resize_event.width as usize, resize_event.height as usize); if *screen_i == self.active { From 4d349192dacf3d103eef5cd38e06407f1dc1722d Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Tue, 20 Feb 2018 02:56:30 +0000 Subject: [PATCH 0222/1301] Allow PCI Config space parsing to handle types - Update the PCI config space parsing to be able to handle multiple types. - Use a trait to abstract out reading from the config space in order to allow testing/fuzzing of the parser. --- Cargo.lock | 2 + pcid/Cargo.toml | 2 + pcid/src/main.rs | 270 ++++++++++++++-------------- pcid/src/pci/bar.rs | 23 ++- pcid/src/pci/class.rs | 29 ++- pcid/src/pci/func.rs | 41 ++--- pcid/src/pci/header.rs | 388 +++++++++++++++++++++++++++++++++++++---- pcid/src/pci/mod.rs | 20 +-- 8 files changed, 574 insertions(+), 201 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fffa149671..4818f23456 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -342,6 +342,8 @@ dependencies = [ name = "pcid" version = "0.1.0" dependencies = [ + "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index bc28166532..56465ba9fd 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -3,6 +3,8 @@ name = "pcid" version = "0.1.0" [dependencies] +bitflags = "1.0" +byteorder = "1.2" redox_syscall = "0.1" serde = "1.0" serde_derive = "1.0" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index ea8f3495a7..e8f8eea829 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,6 +1,9 @@ #![deny(warnings)] #![feature(asm)] +#![feature(iterator_step_by)] +#[macro_use] extern crate bitflags; +extern crate byteorder; #[macro_use] extern crate serde_derive; extern crate syscall; extern crate toml; @@ -12,11 +15,136 @@ use std::process::Command; use syscall::iopl; use config::Config; -use pci::{Pci, PciBar, PciClass}; +use pci::{Pci, PciClass, PciHeader, PciHeaderError, PciHeaderType}; mod config; mod pci; +fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, + dev_num: u8, func_num: u8, header: PciHeader) { + let raw_class: u8 = header.class().into(); + let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", + bus_num, dev_num, func_num, header.vendor_id(), header.device_id(), raw_class, + header.subclass(), header.interface(), header.revision(), header.class()); + + match header.class() { + PciClass::Storage => match header.subclass() { + 0x01 => { + string.push_str(" IDE"); + }, + 0x06 => { + string.push_str(" SATA"); + }, + _ => () + }, + PciClass::SerialBus => match header.subclass() { + 0x03 => match header.interface() { + 0x00 => { + string.push_str(" UHCI"); + }, + 0x10 => { + string.push_str(" OHCI"); + }, + 0x20 => { + string.push_str(" EHCI"); + }, + 0x30 => { + string.push_str(" XHCI"); + }, + _ => () + }, + _ => () + }, + _ => () + } + + for (i, bar) in header.bars().iter().enumerate() { + if !bar.is_none() { + string.push_str(&format!(" {}={}", i, bar)); + } + } + + string.push('\n'); + + print!("{}", string); + + for driver in config.drivers.iter() { + if let Some(class) = driver.class { + if class != raw_class { continue; } + } + + if let Some(subclass) = driver.subclass { + if subclass != header.subclass() { continue; } + } + + if let Some(interface) = driver.interface { + if interface != header.interface() { continue; } + } + + if let Some(vendor) = driver.vendor { + if vendor != header.vendor_id() { continue; } + } + + if let Some(device) = driver.device { + if device != header.device_id() { continue; } + } + + if let Some(ref device_id_range) = driver.device_id_range { + if header.device_id() < device_id_range.start || + device_id_range.end <= header.device_id() { continue; } + } + + if let Some(ref args) = driver.command { + // Enable bus mastering, memory space, and I/O space + unsafe { + let cmd = pci.read(bus_num, dev_num, func_num, 0x04); + println!("PCI CMD: {:>02X}", cmd); + pci.write(bus_num, dev_num, func_num, 0x04, cmd | 7); + } + + // TODO: find a better way to pass the header data down to the + // device driver, making passing the capabilities list etc + // posible. + let mut args = args.iter(); + if let Some(program) = args.next() { + let mut command = Command::new(program); + for arg in args { + let arg = match arg.as_str() { + "$BUS" => format!("{:>02X}", bus_num), + "$DEV" => format!("{:>02X}", dev_num), + "$FUNC" => format!("{:>02X}", func_num), + "$NAME" => format!("pci-{:>02X}.{:>02X}.{:>02X}", bus_num, dev_num, func_num), + "$BAR0" => format!("{}", header.get_bar(0)), + "$BAR1" => format!("{}", header.get_bar(1)), + "$BAR2" if header.header_type() == PciHeaderType::GENERAL => + format!("{}", header.get_bar(2)), + "$BAR3" if header.header_type() == PciHeaderType::GENERAL => + format!("{}", header.get_bar(2)), + "$BAR4" if header.header_type() == PciHeaderType::GENERAL => + format!("{}", header.get_bar(2)), + "$BAR5" if header.header_type() == PciHeaderType::GENERAL => + format!("{}", header.get_bar(2)), + "$IRQ" => format!("{}", header.interrupt_line()), + "$VENID" => format!("{:>04X}", header.vendor_id()), + "$DEVID" => format!("{:>04X}", header.device_id()), + _ => arg.clone() + }; + command.arg(&arg); + } + + println!("PCID SPAWN {:?}", command); + match command.spawn() { + Ok(mut child) => match child.wait() { + Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()), + Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err) + }, + Err(err) => println!("pcid: failed to execute {:?}: {}", command, err) + } + } + } + } +} + fn main() { let mut config = Config::default(); @@ -38,140 +166,14 @@ fn main() { for bus in pci.buses() { for dev in bus.devs() { for func in dev.funcs() { - if let Some(header) = func.header() { - let pci_class = PciClass::from(header.class); - - let mut string = unsafe { - format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", - bus.num, dev.num, func.num, - header.vendor_id, header.device_id, - header.class, header.subclass, header.interface, header.revision, - pci_class) - }; - - match pci_class { - PciClass::Storage => match header.subclass { - 0x01 => { - string.push_str(" IDE"); - }, - 0x06 => { - string.push_str(" SATA"); - }, - _ => () - }, - PciClass::SerialBus => match header.subclass { - 0x03 => match header.interface { - 0x00 => { - string.push_str(" UHCI"); - }, - 0x10 => { - string.push_str(" OHCI"); - }, - 0x20 => { - string.push_str(" EHCI"); - }, - 0x30 => { - string.push_str(" XHCI"); - }, - _ => () - }, - _ => () - }, - _ => () + let func_num = func.num; + match PciHeader::from_reader(func) { + Ok(header) => { + handle_parsed_header(&config, &pci, bus.num, dev.num, func_num, header); } - - unsafe { - for i in 0..header.bars.len() { - match PciBar::from(header.bars[i]) { - PciBar::None => (), - PciBar::Memory(address) => string.push_str(&format!(" {}={:>08X}", i, address)), - PciBar::Port(address) => string.push_str(&format!(" {}={:>04X}", i, address)) - } - } - } - - string.push('\n'); - - print!("{}", string); - - for driver in config.drivers.iter() { - if let Some(class) = driver.class { - if class != header.class { continue; } - } - - if let Some(subclass) = driver.subclass { - if subclass != header.subclass { continue; } - } - - if let Some(interface) = driver.interface { - if interface != header.interface { continue; } - } - - if let Some(vendor) = driver.vendor { - if vendor != header.vendor_id { continue; } - } - - if let Some(device) = driver.device { - if device != header.device_id { continue; } - } - - if let Some(ref device_id_range) = driver.device_id_range { - if header.device_id < device_id_range.start || - device_id_range.end <= header.device_id { continue; } - } - - if let Some(ref args) = driver.command { - // Enable bus mastering, memory space, and I/O space - unsafe { - let cmd = pci.read(bus.num, dev.num, func.num, 0x04); - println!("PCI CMD: {:>02X}", cmd); - pci.write(bus.num, dev.num, func.num, 0x04, cmd | 7); - } - - let mut args = args.iter(); - if let Some(program) = args.next() { - let mut command = Command::new(program); - for arg in args { - let bar_arg = |i| -> String { - match PciBar::from(header.bars[i]) { - PciBar::None => String::new(), - PciBar::Memory(address) => format!("{:>08X}", address), - PciBar::Port(address) => format!("{:>04X}", address) - } - }; - let arg = unsafe { - match arg.as_str() { - "$BUS" => format!("{:>02X}", bus.num), - "$DEV" => format!("{:>02X}", dev.num), - "$FUNC" => format!("{:>02X}", func.num), - "$NAME" => format!("pci-{:>02X}.{:>02X}.{:>02X}", bus.num, dev.num, func.num), - "$BAR0" => bar_arg(0), - "$BAR1" => bar_arg(1), - "$BAR2" => bar_arg(2), - "$BAR3" => bar_arg(3), - "$BAR4" => bar_arg(4), - "$BAR5" => bar_arg(5), - "$IRQ" => format!("{}", header.interrupt_line), - "$VENID" => format!("{:>04X}",header.vendor_id), - "$DEVID" => format!("{:>04X}",header.device_id), - "$SUBSYSID" => format!("{:>04X}",header.subsystem_id), - _ => arg.clone() - } - }; - command.arg(&arg); - } - - //println!("PCID SPAWN {:?}", command); - - match command.spawn() { - Ok(mut child) => match child.wait() { - Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()), - Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err) - }, - Err(err) => println!("pcid: failed to execute {:?}: {}", command, err) - } - } - } + Err(PciHeaderError::NoDevice) => {}, + Err(PciHeaderError::UnknownHeaderType(id)) => { + println!("pcid: unknown header type: {}", id); } } } diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index 190fa05d2d..b1efde2e38 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -1,10 +1,21 @@ -#[derive(Debug)] +use std::fmt; + +#[derive(Clone, Copy, Debug, PartialEq)] pub enum PciBar { None, Memory(u32), Port(u16) } +impl PciBar { + pub fn is_none(&self) -> bool { + match self { + &PciBar::None => true, + _ => false, + } + } +} + impl From for PciBar { fn from(bar: u32) -> Self { if bar & 0xFFFFFFFC == 0 { @@ -16,3 +27,13 @@ impl From for PciBar { } } } + +impl fmt::Display for PciBar { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &PciBar::Memory(address) => write!(f, "{:>08X}", address), + &PciBar::Port(address) => write!(f, "{:>04X}", address), + &PciBar::None => write!(f, "None") + } + } +} diff --git a/pcid/src/pci/class.rs b/pcid/src/pci/class.rs index 21f7f69bbe..98c503c2b3 100644 --- a/pcid/src/pci/class.rs +++ b/pcid/src/pci/class.rs @@ -1,4 +1,4 @@ -#[derive(Debug)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum PciClass { Legacy, Storage, @@ -48,3 +48,30 @@ impl From for PciClass { } } } + +impl Into for PciClass { + fn into(self) -> u8 { + match self { + PciClass::Legacy => 0x00, + PciClass::Storage => 0x01, + PciClass::Network => 0x02, + PciClass::Display => 0x03, + PciClass::Multimedia => 0x04, + PciClass::Memory => 0x05, + PciClass::Bridge => 0x06, + PciClass::SimpleComms => 0x07, + PciClass::Peripheral => 0x08, + PciClass::Input => 0x09, + PciClass::Docking => 0x0A, + PciClass::Processor => 0x0B, + PciClass::SerialBus => 0x0C, + PciClass::Wireless => 0x0D, + PciClass::IntelligentIo => 0x0E, + PciClass::SatelliteComms => 0x0F, + PciClass::Cryptography => 0x10, + PciClass::SignalProc => 0x11, + PciClass::Unknown => 0xFF, + PciClass::Reserved(reserved) => reserved + } + } +} diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index 578e5c61be..5c206f3607 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -1,30 +1,31 @@ -use std::ops::DerefMut; +use byteorder::{LittleEndian, ByteOrder}; -use super::{PciDev, PciHeader}; +use super::PciDev; + +pub trait ConfigReader { + unsafe fn read_range(&self, offset: u8, len: u8) -> Vec { + assert!(len > 3 && len % 4 == 0); + let mut ret = Vec::with_capacity(len as usize); + let results = (offset..offset + len).step_by(4).fold(Vec::new(), |mut acc, offset| { + let val = self.read_u32(offset); + acc.push(val); + acc + }); + ret.set_len(len as usize); + LittleEndian::write_u32_into(&*results, &mut ret); + ret + } + + unsafe fn read_u32(&self, offset: u8) -> u32; +} pub struct PciFunc<'pci> { pub dev: &'pci PciDev<'pci>, pub num: u8 } -impl<'pci> PciFunc<'pci> { - pub fn header(&self) -> Option { - if unsafe { self.read(0) } != 0xFFFFFFFF { - let mut header = PciHeader::default(); - { - let dwords = header.deref_mut(); - dwords.iter_mut().fold(0usize, |offset, dword| { - *dword = unsafe { self.read(offset as u8) }; - offset + 4 - }); - } - Some(header) - } else { - None - } - } - - pub unsafe fn read(&self, offset: u8) -> u32 { +impl<'pci> ConfigReader for PciFunc<'pci> { + unsafe fn read_u32(&self, offset: u8) -> u32 { self.dev.read(self.num, offset) } } diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index 332542a569..272d917b1f 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -1,43 +1,361 @@ -use std::ops::{Deref, DerefMut}; -use std::{slice, mem}; +use byteorder::{LittleEndian, ByteOrder}; -#[derive(Default)] -#[repr(packed)] -pub struct PciHeader { - pub vendor_id: u16, - pub device_id: u16, - pub command: u16, - pub status: u16, - pub revision: u8, - pub interface: u8, - pub subclass: u8, - pub class: u8, - pub cache_line_size: u8, - pub latency_timer: u8, - pub header_type: u8, - pub bist: u8, - pub bars: [u32; 6], - pub cardbus_cis_ptr: u32, - pub subsystem_vendor_id: u16, - pub subsystem_id: u16, - pub expansion_rom_bar: u32, - pub capabilities: u8, - pub reserved: [u8; 7], - pub interrupt_line: u8, - pub interrupt_pin: u8, - pub min_grant: u8, - pub max_latency: u8 +use super::func::ConfigReader; +use super::class::PciClass; +use super::bar::PciBar; + +#[derive(Debug, PartialEq)] +pub enum PciHeaderError { + NoDevice, + UnknownHeaderType(u8) } -impl Deref for PciHeader { - type Target = [u32]; - fn deref(&self) -> &[u32] { - unsafe { slice::from_raw_parts(self as *const PciHeader as *const u32, mem::size_of::()/4) as &[u32] } +bitflags! { + /// Flags found in the status register of a PCI device + pub struct PciHeaderType: u8 { + /// A general PCI device (Type 0x01). + const GENERAL = 0b00000000; + /// A PCI-to-PCI bridge device (Type 0x01). + const PCITOPCI = 0b00000001; + /// A PCI-to-PCI bridge device (Type 0x02). + const CARDBUSBRIDGE = 0b00000010; + /// A multifunction device. + const MULTIFUNCTION = 0b01000000; + /// Mask used for fetching the header type. + const HEADER_TYPE = 0b00000011; } } -impl DerefMut for PciHeader { - fn deref_mut(&mut self) -> &mut [u32] { - unsafe { slice::from_raw_parts_mut(self as *mut PciHeader as *mut u32, mem::size_of::()/4) as &mut [u32] } +#[derive(Debug, PartialEq)] +pub enum PciHeader { + General { + vendor_id: u16, + device_id: u16, + command: u16, + status: u16, + revision: u8, + interface: u8, + subclass: u8, + class: PciClass, + cache_line_size: u8, + latency_timer: u8, + header_type: PciHeaderType, + bist: u8, + bars: [PciBar; 6], + cardbus_cis_ptr: u32, + subsystem_vendor_id: u16, + subsystem_id: u16, + expansion_rom_bar: u32, + cap_pointer: u8, + interrupt_line: u8, + interrupt_pin: u8, + min_grant: u8, + max_latency: u8 + }, + PciToPci { + vendor_id: u16, + device_id: u16, + command: u16, + status: u16, + revision: u8, + interface: u8, + subclass: u8, + class: PciClass, + cache_line_size: u8, + latency_timer: u8, + header_type: PciHeaderType, + bist: u8, + bars: [PciBar; 2], + primary_bus_num: u8, + secondary_bus_num: u8, + subordinate_bus_num: u8, + secondary_latency_timer: u8, + io_base: u8, + io_limit: u8, + secondary_status: u16, + mem_base: u16, + mem_limit: u16, + prefetch_base: u16, + prefetch_limit: u16, + prefetch_base_upper: u32, + prefetch_limit_upper: u32, + io_base_upper: u16, + io_limit_upper: u16, + cap_pointer: u8, + expansion_rom: u32, + interrupt_line: u8, + interrupt_pin : u8, + bridge_control: u16 } } + +impl PciHeader { + /// Parse the bytes found in the Configuration Space of the PCI device into + /// a more usable PciHeader. + pub fn from_reader(reader: T) -> Result { + if unsafe { reader.read_u32(0) } != 0xffffffff { + // Read the initial 16 bytes and set variables used by all header types. + let bytes = unsafe { reader.read_range(0, 16) }; + let vendor_id = LittleEndian::read_u16(&bytes[0..2]); + let device_id = LittleEndian::read_u16(&bytes[2..4]); + let command = LittleEndian::read_u16(&bytes[4..6]); + let status = LittleEndian::read_u16(&bytes[6..8]); + let revision = bytes[8]; + let interface = bytes[9]; + let subclass = bytes[10]; + let class = PciClass::from(bytes[11]); + let cache_line_size = bytes[12]; + let latency_timer = bytes[13]; + let header_type = PciHeaderType::from_bits_truncate(bytes[14]); + let bist = bytes[15]; + match header_type & PciHeaderType::HEADER_TYPE { + PciHeaderType::GENERAL => { + let bytes = unsafe { reader.read_range(16, 48) }; + let bars = [ + PciBar::from(LittleEndian::read_u32(&bytes[0..4])), + PciBar::from(LittleEndian::read_u32(&bytes[4..8])), + PciBar::from(LittleEndian::read_u32(&bytes[8..12])), + PciBar::from(LittleEndian::read_u32(&bytes[12..16])), + PciBar::from(LittleEndian::read_u32(&bytes[16..20])), + PciBar::from(LittleEndian::read_u32(&bytes[20..24])), + ]; + let cardbus_cis_ptr = LittleEndian::read_u32(&bytes[24..28]); + let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]); + let subsystem_id = LittleEndian::read_u16(&bytes[30..32]); + let expansion_rom_bar = LittleEndian::read_u32(&bytes[32..36]); + // TODO: Parse out the capabilities list. + let cap_pointer = bytes[36]; + let interrupt_line = bytes[44]; + let interrupt_pin = bytes[45]; + let min_grant = bytes[46]; + let max_latency = bytes[47]; + Ok(PciHeader::General { + vendor_id, device_id, command, status, revision, interface, + subclass, class, cache_line_size, latency_timer, header_type, + bist, bars, cardbus_cis_ptr, subsystem_vendor_id, subsystem_id, + expansion_rom_bar, cap_pointer, interrupt_line, interrupt_pin, + min_grant, max_latency + }) + }, + PciHeaderType::PCITOPCI => { + let bytes = unsafe { reader.read_range(16, 48) }; + let bars = [ + PciBar::from(LittleEndian::read_u32(&bytes[0..4])), + PciBar::from(LittleEndian::read_u32(&bytes[4..8])), + ]; + let primary_bus_num = bytes[8]; + let secondary_bus_num = bytes[9]; + let subordinate_bus_num = bytes[10]; + let secondary_latency_timer = bytes[11]; + let io_base = bytes[12]; + let io_limit = bytes[13]; + let secondary_status = LittleEndian::read_u16(&bytes[14..16]); + let mem_base = LittleEndian::read_u16(&bytes[16..18]); + let mem_limit = LittleEndian::read_u16(&bytes[18..20]); + let prefetch_base = LittleEndian::read_u16(&bytes[20..22]); + let prefetch_limit = LittleEndian::read_u16(&bytes[22..24]); + let prefetch_base_upper = LittleEndian::read_u32(&bytes[24..28]); + let prefetch_limit_upper = LittleEndian::read_u32(&bytes[28..32]); + let io_base_upper = LittleEndian::read_u16(&bytes[32..34]); + let io_limit_upper = LittleEndian::read_u16(&bytes[34..36]); + // TODO: Parse out the capabilities list. + let cap_pointer = bytes[36]; + let expansion_rom = LittleEndian::read_u32(&bytes[40..44]); + let interrupt_line = bytes[44]; + let interrupt_pin = bytes[45]; + let bridge_control = LittleEndian::read_u16(&bytes[46..48]); + Ok(PciHeader::PciToPci { + vendor_id, device_id, command, status, revision, interface, + subclass, class, cache_line_size, latency_timer, header_type, + bist, bars, primary_bus_num, secondary_bus_num, subordinate_bus_num, + secondary_latency_timer, io_base, io_limit, secondary_status, + mem_base, mem_limit, prefetch_base, prefetch_limit, prefetch_base_upper, + prefetch_limit_upper, io_base_upper, io_limit_upper, cap_pointer, + expansion_rom, interrupt_line, interrupt_pin, bridge_control + }) + + }, + id => Err(PciHeaderError::UnknownHeaderType(id.bits())) + } + } else { + Err(PciHeaderError::NoDevice) + } + } + + /// Return the Header Type. + pub fn header_type(&self) -> PciHeaderType { + match self { + &PciHeader::General { header_type, .. } | &PciHeader::PciToPci { header_type, .. } => header_type, + } + } + + /// Return the Vendor ID field. + pub fn vendor_id(&self) -> u16 { + match self { + &PciHeader::General { vendor_id, .. } | &PciHeader::PciToPci { vendor_id, .. } => vendor_id, + } + } + + /// Return the Device ID field. + pub fn device_id(&self) -> u16 { + match self { + &PciHeader::General { device_id, .. } | &PciHeader::PciToPci { device_id, .. } => device_id, + } + } + + /// Return the Revision field. + pub fn revision(&self) -> u8 { + match self { + &PciHeader::General { revision, .. } | &PciHeader::PciToPci { revision, .. } => revision, + } + } + + /// Return the Interface field. + pub fn interface(&self) -> u8 { + match self { + &PciHeader::General { interface, .. } | &PciHeader::PciToPci { interface, .. } => interface, + } + } + + /// Return the Subclass field. + pub fn subclass(&self) -> u8 { + match self { + &PciHeader::General { subclass, .. } | &PciHeader::PciToPci { subclass, .. } => subclass, + } + } + + /// Return the Class field. + pub fn class(&self) -> PciClass { + match self { + &PciHeader::General { class, .. } | &PciHeader::PciToPci { class, .. } => class, + } + } + + /// Return the Headers BARs. + pub fn bars(&self) -> &[PciBar] { + match self { + &PciHeader::General { ref bars, .. } => bars, + &PciHeader::PciToPci { ref bars, .. } => bars, + } + } + + /// Return the BAR at the given index. + /// + /// # Panics + /// This function panics if the requested BAR index is beyond the length of the header + /// types BAR array. + pub fn get_bar(&self, idx: usize) -> PciBar { + match self { + &PciHeader::General { bars, .. } => { + assert!(idx < 6, "the general PCI device only has 6 BARs"); + bars[idx] + }, + &PciHeader::PciToPci { bars, .. } => { + assert!(idx < 2, "the general PCI device only has 2 BARs"); + bars[idx] + } + } + } + + /// Return the Interrupt Line field. + pub fn interrupt_line(&self) -> u8 { + match self { + &PciHeader::General { interrupt_line, .. } | &PciHeader::PciToPci { interrupt_line, .. } => + interrupt_line, + } + } + +} + +#[cfg(test)] +impl<'a> ConfigReader for &'a [u8] { + unsafe fn read_u32(&self, offset: u8) -> u32 { + let offset = offset as usize; + assert!(offset < self.len()); + LittleEndian::read_u32(&self[offset..offset + 4]) + } +} + +#[cfg(test)] +mod test { + use super::{PciHeaderError, PciHeader, PciHeaderType}; + use super::super::func::ConfigReader; + use super::super::class::PciClass; + use super::super::bar::PciBar; + + const IGB_DEV_BYTES: [u8; 256] = [ + 0x86, 0x80, 0x33, 0x15, 0x07, 0x04, 0x10, 0x00, 0x03, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x50, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x15, 0x33, 0x15, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, + 0x01, 0x50, 0x23, 0xc8, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x70, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0xa0, 0x04, 0x80, 0x03, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0x10, 0x00, 0x02, 0x00, 0xc2, 0x8c, 0x00, 0x10, 0x0f, 0x28, 0x19, 0x00, 0x11, 0x5c, 0x42, 0x00, + 0x42, 0x00, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + ]; + + #[test] + fn tset_parse_igb_dev() { + let header = PciHeader::from_reader(&IGB_DEV_BYTES[..]).unwrap(); + assert_eq!(header.header_type(), PciHeaderType::GENERAL); + assert_eq!(header.device_id(), 0x1533); + assert_eq!(header.vendor_id(), 0x8086); + assert_eq!(header.revision(), 3); + assert_eq!(header.interface(), 0); + assert_eq!(header.class(), PciClass::Network); + assert_eq!(header.subclass(), 0); + assert_eq!(header.bars().len(), 6); + assert_eq!(header.get_bar(0), PciBar::Memory(0xf7500000)); + assert_eq!(header.get_bar(1), PciBar::None); + assert_eq!(header.get_bar(2), PciBar::Port(0xb000)); + assert_eq!(header.get_bar(3), PciBar::Memory(0xf7580000)); + assert_eq!(header.get_bar(4), PciBar::None); + assert_eq!(header.get_bar(5), PciBar::None); + assert_eq!(header.interrupt_line(), 10); + } + + #[test] + fn test_parse_nonexistent() { + let bytes = [ + 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff + ]; + assert_eq!(PciHeader::from_reader(&bytes[..]), Err(PciHeaderError::NoDevice)); + } + + #[test] + fn test_read_range() { + let res = unsafe { (&IGB_DEV_BYTES[..]).read_range(0, 4) }; + assert_eq!(res, &[0x86, 0x80, 0x33, 0x15][..]); + + let res = unsafe { (&IGB_DEV_BYTES[..]).read_range(16, 32) }; + let expected = [ + 0x00, 0x00, 0x50, 0xf7, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf7, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd9, 0x15, 0x33, 0x15 + ]; + assert_eq!(res, expected); + } + + macro_rules! read_range_should_panic { + ($name:ident, $len:expr) => { + #[test] + #[should_panic(expected = "assertion failed: len > 3 && len % 4 == 0")] + fn $name() { + let _ = unsafe { (&IGB_DEV_BYTES[..]).read_range(0, $len) }; + } + } + } + + read_range_should_panic!(test_short_len, 2); + read_range_should_panic!(test_not_mod_4_len, 7); +} diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index ef83986e60..e70048fd84 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -3,14 +3,14 @@ pub use self::bus::{PciBus, PciBusIter}; pub use self::class::PciClass; pub use self::dev::{PciDev, PciDevIter}; pub use self::func::PciFunc; -pub use self::header::PciHeader; +pub use self::header::{PciHeader, PciHeaderError, PciHeaderType}; mod bar; mod bus; mod class; mod dev; mod func; -mod header; +pub mod header; pub struct Pci; @@ -28,10 +28,10 @@ impl Pci { let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); let value: u32; asm!("mov dx, 0xCF8 - out dx, eax - mov dx, 0xCFC - in eax, dx" - : "={eax}"(value) : "{eax}"(address) : "dx" : "intel", "volatile"); + out dx, eax + mov dx, 0xCFC + in eax, dx" + : "={eax}"(value) : "{eax}"(address) : "dx" : "intel", "volatile"); value } @@ -39,11 +39,11 @@ impl Pci { pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) { let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); asm!("mov dx, 0xCF8 - out dx, eax" - : : "{eax}"(address) : "dx" : "intel", "volatile"); + out dx, eax" + : : "{eax}"(address) : "dx" : "intel", "volatile"); asm!("mov dx, 0xCFC - out dx, eax" - : : "{eax}"(value) : "dx" : "intel", "volatile"); + out dx, eax" + : : "{eax}"(value) : "dx" : "intel", "volatile"); } } From 7fbb2c32e265c0a2edb2fcf3c17ccddc64d5c283 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 1 Mar 2018 08:24:24 -0700 Subject: [PATCH 0223/1301] Fix BAR variables --- pcid/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index e8f8eea829..853829be18 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -119,11 +119,11 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, "$BAR2" if header.header_type() == PciHeaderType::GENERAL => format!("{}", header.get_bar(2)), "$BAR3" if header.header_type() == PciHeaderType::GENERAL => - format!("{}", header.get_bar(2)), + format!("{}", header.get_bar(3)), "$BAR4" if header.header_type() == PciHeaderType::GENERAL => - format!("{}", header.get_bar(2)), + format!("{}", header.get_bar(4)), "$BAR5" if header.header_type() == PciHeaderType::GENERAL => - format!("{}", header.get_bar(2)), + format!("{}", header.get_bar(5)), "$IRQ" => format!("{}", header.interrupt_line()), "$VENID" => format!("{:>04X}", header.vendor_id()), "$DEVID" => format!("{:>04X}", header.device_id()), From 5bccc80152e612624a37deedf279b1ea679d1356 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 10 Mar 2018 15:12:55 -0700 Subject: [PATCH 0224/1301] Fix rtl8168 driver --- rtl8168d/src/device.rs | 103 ++++++++++++++++++++++++++--------------- rtl8168d/src/main.rs | 2 + 2 files changed, 68 insertions(+), 37 deletions(-) diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index a85c0a8e25..41425b9d2b 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -66,10 +66,12 @@ struct Td { pub struct Rtl8168 { regs: &'static mut Regs, - receive_buffer: [Dma<[Mmio; 0x1FF8]>; 16], - receive_ring: Dma<[Rd; 16]>, + receive_buffer: [Dma<[Mmio; 0x1FF8]>; 64], + receive_ring: Dma<[Rd; 64]>, + receive_i: usize, transmit_buffer: [Dma<[Mmio; 7552]>; 16], transmit_ring: Dma<[Td; 16]>, + transmit_i: usize, transmit_buffer_h: [Dma<[Mmio; 7552]>; 1], transmit_ring_h: Dma<[Td; 1]> } @@ -92,23 +94,30 @@ impl SchemeMut for Rtl8168 { } fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { - for (rd_i, rd) in self.receive_ring.iter_mut().enumerate() { - if ! rd.ctrl.readf(OWN) { - let rd_len = rd.ctrl.read() & 0x3FFF; + if self.receive_i >= self.receive_ring.len() { + self.receive_i = 0; + } - let data = &self.receive_buffer[rd_i as usize]; + let rd = &mut self.receive_ring[self.receive_i]; + if ! rd.ctrl.readf(OWN) { + let rd_len = rd.ctrl.read() & 0x3FFF; - let mut i = 0; - while i < buf.len() && i < rd_len as usize { - buf[i] = data[i].read(); - i += 1; - } + let data = &self.receive_buffer[self.receive_i]; - let eor = rd.ctrl.read() & EOR; - rd.ctrl.write(OWN | eor | data.len() as u32); - - return Ok(i); + let mut i = 0; + while i < buf.len() && i < rd_len as usize { + buf[i] = data[i].read(); + i += 1; } + + let eor = rd.ctrl.read() & EOR; + rd.ctrl.write(OWN | eor | data.len() as u32); + + print!("{}", format!("rtl8168d: read {}: {}\n", self.receive_i, i)); + + self.receive_i += 1; + + return Ok(i); } if id & O_NONBLOCK == O_NONBLOCK { @@ -120,28 +129,34 @@ impl SchemeMut for Rtl8168 { fn write(&mut self, _id: usize, buf: &[u8]) -> Result { loop { - for (td_i, td) in self.transmit_ring.iter_mut().enumerate() { - if ! td.ctrl.readf(OWN) { + if self.transmit_i >= self.transmit_ring.len() { + self.transmit_i = 0; + } - let mut data = &mut self.transmit_buffer[td_i as usize]; + let td = &mut self.transmit_ring[self.transmit_i]; + if ! td.ctrl.readf(OWN) { + let data = &mut self.transmit_buffer[self.transmit_i]; - let mut i = 0; - while i < buf.len() && i < data.len() { - data[i].write(buf[i]); - i += 1; - } - - let eor = td.ctrl.read() & EOR; - td.ctrl.write(OWN | eor | FS | LS | i as u32); - - self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet - - while self.regs.tppoll.readf(1 << 6) { - thread::yield_now(); - } - - return Ok(i); + let mut i = 0; + while i < buf.len() && i < data.len() { + data[i].write(buf[i]); + i += 1; } + + let eor = td.ctrl.read() & EOR; + td.ctrl.write(OWN | eor | FS | LS | i as u32); + + self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet + + while self.regs.tppoll.readf(1 << 6) { + thread::yield_now(); + } + + print!("{}", format!("rtl8168d: write {}: {}\n", self.transmit_i, i)); + + self.transmit_i += 1; + + return Ok(i); } thread::yield_now(); @@ -179,15 +194,29 @@ impl Rtl8168 { let mut module = Rtl8168 { regs: regs, receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], receive_ring: Dma::zeroed()?, + receive_i: 0, transmit_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], transmit_ring: Dma::zeroed()?, + transmit_i: 0, transmit_buffer_h: [Dma::zeroed()?], transmit_ring_h: Dma::zeroed()? }; @@ -239,7 +268,7 @@ impl Rtl8168 { rd.buffer.write(data.physical() as u64); rd.ctrl.write(OWN | data.len() as u32); } - if let Some(mut rd) = self.receive_ring.last_mut() { + if let Some(rd) = self.receive_ring.last_mut() { rd.ctrl.writef(EOR, true); } @@ -247,7 +276,7 @@ impl Rtl8168 { for i in 0..self.transmit_ring.len() { self.transmit_ring[i].buffer.write(self.transmit_buffer[i].physical() as u64); } - if let Some(mut td) = self.transmit_ring.last_mut() { + if let Some(td) = self.transmit_ring.last_mut() { td.ctrl.writef(EOR, true); } @@ -255,7 +284,7 @@ impl Rtl8168 { for i in 0..self.transmit_ring_h.len() { self.transmit_ring_h[i].buffer.write(self.transmit_buffer_h[i].physical() as u64); } - if let Some(mut td) = self.transmit_ring_h.last_mut() { + if let Some(td) = self.transmit_ring_h.last_mut() { td.ctrl.writef(EOR, true); } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 5b5cc076d3..79d8b5e39a 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -59,6 +59,8 @@ fn main() { if isr != 0 { irq_file.write(&mut irq)?; + print!("{}", format!("rtl8168d: IRQ: {:X}\n", isr)); + let mut todo = todo_irq.borrow_mut(); let mut i = 0; while i < todo.len() { From 329750afb95c8fbd12b22826b8a4043e07e7703e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 10 Mar 2018 16:02:06 -0700 Subject: [PATCH 0225/1301] Remove debug prints --- ahcid/src/ahci/hba.rs | 1 - rtl8168d/src/device.rs | 4 ---- 2 files changed, 5 deletions(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 22358e7955..6a582f7430 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -140,7 +140,6 @@ impl HbaPort { // Shared between identify() and identify_packet() unsafe fn identify_inner(&mut self, cmd: u8, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { - let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); let res = self.ata_dma(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 41425b9d2b..b49466d332 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -113,8 +113,6 @@ impl SchemeMut for Rtl8168 { let eor = rd.ctrl.read() & EOR; rd.ctrl.write(OWN | eor | data.len() as u32); - print!("{}", format!("rtl8168d: read {}: {}\n", self.receive_i, i)); - self.receive_i += 1; return Ok(i); @@ -152,8 +150,6 @@ impl SchemeMut for Rtl8168 { thread::yield_now(); } - print!("{}", format!("rtl8168d: write {}: {}\n", self.transmit_i, i)); - self.transmit_i += 1; return Ok(i); From a081f9e2ff2ba8a6ea5b79c18b7cb58c9999f98f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 10 Mar 2018 16:03:21 -0700 Subject: [PATCH 0226/1301] Remove IRQ debug print --- rtl8168d/src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 79d8b5e39a..5b5cc076d3 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -59,8 +59,6 @@ fn main() { if isr != 0 { irq_file.write(&mut irq)?; - print!("{}", format!("rtl8168d: IRQ: {:X}\n", isr)); - let mut todo = todo_irq.borrow_mut(); let mut i = 0; while i < todo.len() { From d893a73e1ed7467b2a69e2e62c3a021045f16b42 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Sun, 11 Mar 2018 18:24:23 -0700 Subject: [PATCH 0227/1301] ahcid: fix atapi capacity detection --- ahcid/src/ahci/disk_atapi.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ahcid/src/ahci/disk_atapi.rs b/ahcid/src/ahci/disk_atapi.rs index 0dd7b69966..a0aa71baff 100644 --- a/ahcid/src/ahci/disk_atapi.rs +++ b/ahcid/src/ahci/disk_atapi.rs @@ -63,7 +63,8 @@ impl DiskATAPI { cmd[0] = SCSI_READ_CAPACITY; self.port.packet(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf)?; - let blk_count = BigEndian::read_u32(&self.buf[0..4]); + // Instead of a count, contains number of last LBA, so add 1 + let blk_count = BigEndian::read_u32(&self.buf[0..4]) + 1; let blk_size = BigEndian::read_u32(&self.buf[4..8]); Ok((blk_count, blk_size)) From 390f04baaf66272589cb63435e0452a1f1375982 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 24 Mar 2018 12:14:24 -0600 Subject: [PATCH 0228/1301] Update lock file --- Cargo.lock | 390 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 231 insertions(+), 159 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4818f23456..f5e8eb52c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,8 +4,8 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -15,7 +15,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -25,7 +25,7 @@ source = "git+https://github.com/redox-os/arg-parser.git#7503531821b0c111f9fac77 [[package]] name = "arrayvec" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -44,8 +44,8 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -58,11 +58,6 @@ name = "bitflags" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "byteorder" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "0.5.3" @@ -79,14 +74,36 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "coco" -version = "0.1.1" +name = "crossbeam-deque" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-utils" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "e1000d" version = "0.1.0" @@ -94,14 +111,9 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "either" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "extra" version = "0.1.0" @@ -109,16 +121,16 @@ source = "git+https://github.com/redox-os/libextra.git#f38608acd9cc00e1c8bd41a1a [[package]] name = "fuchsia-zircon" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fuchsia-zircon-sys" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -128,7 +140,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "httparse" -version = "1.2.3" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -137,16 +149,16 @@ version = "0.10.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -175,8 +187,8 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -198,14 +210,19 @@ name = "lazy_static" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazy_static" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" -version = "0.2.34" +version = "0.2.39" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "linked-hash-map" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -229,6 +246,11 @@ name = "matches" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "memoffset" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "mime" version = "0.2.6" @@ -240,17 +262,17 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://github.com/redox-os/netutils.git#a719fa50b065840ffacc81d989e47f258b3e5170" +source = "git+https://github.com/redox-os/netutils.git#7eda176e6b4e2edbcc0616247598ec5e87bfe8e8" dependencies = [ "arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.0 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -265,39 +287,39 @@ version = "0.0.1" source = "git+https://github.com/willem66745/ntpclient-rust#7e3bdf60eb940825789a8da5181025320e3050b0" dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.1.41" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -305,7 +327,7 @@ name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -313,17 +335,19 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "orbclient" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -332,9 +356,9 @@ version = "1.0.0" source = "git+https://github.com/a8m/pb#d077b49ac6ea18ef63a9bb9f0f0b58abc29580f3" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -344,9 +368,9 @@ version = "0.1.0" dependencies = [ "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -360,33 +384,55 @@ name = "plain" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "proc-macro2" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.3.15" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "rand" -version = "0.3.19" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ransid" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "vte 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -397,27 +443,35 @@ name = "rayon" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_event" version = "0.1.0" -source = "git+https://github.com/redox-os/event.git#bb96d9cd6dd01d4118deae84722a522b8328fa9f" +source = "git+https://github.com/redox-os/event.git#68f4c7e55615ecede98f2085c81801a3dc4b74e0" dependencies = [ - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -425,12 +479,12 @@ name = "redox_event" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.33" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -438,7 +492,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -448,7 +502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -460,7 +514,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -471,7 +525,7 @@ dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -481,9 +535,9 @@ name = "rusttype" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stb_truetype 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -498,78 +552,71 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "sdl2" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2-sys 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sdl2-sys" -version = "0.30.0" +version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" -version = "1.0.27" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.27" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive_internals 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive_internals" -version = "0.19.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "spin" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "stb_truetype" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.11.11" +version = "0.12.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -577,20 +624,19 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "time" -version = "0.1.38" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -598,7 +644,7 @@ name = "toml" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -634,7 +680,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-xid" -version = "0.0.4" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -644,7 +690,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "url" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -661,9 +707,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -675,9 +721,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "ransid 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -695,7 +741,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -713,11 +759,30 @@ name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "xhcid" version = "0.1.0" @@ -725,89 +790,96 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)" = "" -"checksum arrayvec 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2f0ef4a9820019a0c91d918918c93dc71d469f581a49b47ddc1d285d4270bbe2" +"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" -"checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd" -"checksum either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740178ddf48b1a9e878e6d6509a1442a2d42fd2928aae8e7a6f8a36fb01981b3" +"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" +"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" +"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum extra 0.1.0 (git+https://github.com/redox-os/libextra.git)" = "" -"checksum fuchsia-zircon 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd510087c325af53ba24f3be8f1c081b0982319adcb8b03cad764512923ccc19" -"checksum fuchsia-zircon-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "08b3a6f13ad6b96572b53ce7af74543132f1a7055ccceb6d073dd36c54481859" +"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" -"checksum httparse 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "af2f2dd97457e8fb1ae7c5a420db346af389926e36f43768b96f101546b04a07" +"checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04535774f79684c99528944ebdb89756c945c027e55ce52faa245879d836c8fb" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0" -"checksum linked-hash-map 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2aab0478615bb586559b0114d94dd8eca4fdbb73b443adcb0d00b61692b4bf" +"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" +"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff" +"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" +"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)" = "" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" -"checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca" -"checksum num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "d1452e8b06e448a07f0e6ebb0bb1d92b8890eea63288c0b627331d53514d0fba" -"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" -"checksum num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cacfcab5eb48250ee7d0c7896b51a2c5eec99c1feea5f32025635f5ae4b00070" +"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +"checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe" +"checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593" +"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum orbclient 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "6e5d8d9900998fb4b9394e27058aa22a6d3509fb67dd860f74ba0507d4406943" +"checksum orbclient 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f07bacf59f2efd7520b9c9c6ec068a5749553ac6dca7cd79f299041123cc1dfb" "checksum pbr 1.0.0 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" -"checksum rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7944d95d25ace8f377da3ac7068ce517e4c646754c43a1b1849177bbf72e59" -"checksum ransid 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "40d85bc00ee0c715880755a40426b51c81fd1fce338f0a0fd82164041e62ab53" +"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" +"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" +"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" +"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" +"checksum ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc5fdcd7a4ca0bb24bf033534e0c137045538c84b0924af1c950d3ae41a2f71" "checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" -"checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53" +"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" +"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum redox_event 0.1.0 (git+https://github.com/redox-os/event.git)" = "" "checksum redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98e1a40d38f45a3ad65fd088640eeee7b215adcd73041b9f94b92204cca9572a" -"checksum redox_syscall 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "07b8f011e3254d5a9b318fde596d409a0001c9ae4c6e7907520c2eaa4d988c99" +"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" "checksum rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17727f4b991294da2c84d75a43c003151ff58072212768800f66c56ee46dca43" "checksum rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30047cc747a78ae042bf2cd65c79f83c3485d90107535b532d6e8f60e2c89cb1" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum sdl2 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "63066036ad426250ac56d23e38fd05063b38b661556acd596f4046cc92d98415" -"checksum sdl2-sys 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b48638b7882759f3421038fcd38ad5f1ea19b119d80c99f1601933004629e34d" -"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526" -"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0" -"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5" -"checksum spin 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7e4deb3c2455c73779e6d3eebceae9599fc70957e54c69fe88f93aa48e62f432" -"checksum stb_truetype 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "21b5c3b588a493a477e0d99769ee091b3627625f9ba4bdd882e6b4b0b0958805" -"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" +"checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60" +"checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" +"checksum serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "0e100d00fb985a5bf16b857a436450e404fa613de3321b2e383947a93cbd75df" +"checksum serde_derive 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "86daebd995aa948b069d886f2105f2425cd66103049855e45c15c58c573f12c5" +"checksum serde_derive_internals 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3f714f52a41e371c5e141e9dafcead60921349bec76b44d79000c88aba3cfc" +"checksum spin 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dc28a8d2f2efa706fc9d3d074e265c1d529db41c1603679861662cb88e05e70a" +"checksum stb_truetype 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52ce2b38abdd11cffbc68928810248e0dd003fea489a88a404dc1ba7ae2d5538" +"checksum syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8c5bc2d6ff27891209efa5f63e9de78648d7801f085e4653701a692ce938d6fd" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" +"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" "checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" -"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2" +"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" "checksum utf8parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a15ea87f3194a3a454c78d79082b4f5e85f6956ddb6cb86bbfbe4892aa3c0323" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum vte 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a01634c75db59478405de08d8567c40c578bba80c565217ee709934b551720d8" "checksum webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e499345fc4c6b7c79a5b8756d4592c4305510a13512e79efafe00dfbd67bbac6" "checksum webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb3f50499f21ad2317f442845e3b5805b007f1e728f59885c99e61b8c181a7" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" From 79df020cbd7aa40c10c4b95c64d6f07a64956f62 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 21 Apr 2018 09:43:49 -0600 Subject: [PATCH 0229/1301] If an IRQ is not set, use IRQ #9 --- pcid/src/main.rs | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 853829be18..259664612a 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,4 +1,3 @@ -#![deny(warnings)] #![feature(asm)] #![feature(iterator_step_by)] @@ -97,9 +96,21 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, if let Some(ref args) = driver.command { // Enable bus mastering, memory space, and I/O space unsafe { - let cmd = pci.read(bus_num, dev_num, func_num, 0x04); - println!("PCI CMD: {:>02X}", cmd); - pci.write(bus_num, dev_num, func_num, 0x04, cmd | 7); + let mut data = pci.read(bus_num, dev_num, func_num, 0x04); + data |= 7; + pci.write(bus_num, dev_num, func_num, 0x04, data); + } + + // Set IRQ line to 9 if not set + let mut irq; + unsafe { + let mut data = pci.read(bus_num, dev_num, func_num, 0x3C); + irq = (data & 0xFF) as u8; + if irq == 0xFF { + irq = 9; + } + data = (data & 0xFFFFFF00) | irq as u32; + pci.write(bus_num, dev_num, func_num, 0x3C, data); } // TODO: find a better way to pass the header data down to the @@ -124,7 +135,7 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, format!("{}", header.get_bar(4)), "$BAR5" if header.header_type() == PciHeaderType::GENERAL => format!("{}", header.get_bar(5)), - "$IRQ" => format!("{}", header.interrupt_line()), + "$IRQ" => format!("{}", irq), "$VENID" => format!("{:>04X}", header.vendor_id()), "$DEVID" => format!("{:>04X}", header.device_id()), _ => arg.clone() From 287fdde19aa5b99c997331e685ff201d1702e8bb Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 28 Apr 2018 21:35:13 -0600 Subject: [PATCH 0230/1301] Update to new heap API --- vesad/src/display.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 0744c5e45e..f8795a10b2 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -2,8 +2,9 @@ extern crate rusttype; use alloc::allocator::{Alloc, Layout}; -use alloc::heap::Heap; +use alloc::heap::Global; use std::{cmp, slice}; +use std::ptr::NonNull; use primitive::{fast_set32, fast_set64, fast_copy}; @@ -42,7 +43,7 @@ impl Display { #[cfg(not(feature="rusttype"))] pub fn new(width: usize, height: usize, onscreen: usize) -> Display { let size = width * height; - let offscreen = unsafe { Heap.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap() }; + let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap().as_ptr() }; unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; Display { width: width, @@ -55,7 +56,7 @@ impl Display { #[cfg(feature="rusttype")] pub fn new(width: usize, height: usize, onscreen: usize) -> Display { let size = width * height; - let offscreen = unsafe { Heap.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap() }; + let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap().as_ptr() }; unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; Display { width: width, @@ -74,7 +75,7 @@ impl Display { println!("Resize display to {}, {}", width, height); let size = width * height; - let offscreen = unsafe { Heap.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap() }; + let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap().as_ptr() }; { let mut old_ptr = self.offscreen.as_ptr(); @@ -107,7 +108,7 @@ impl Display { let onscreen = self.onscreen.as_mut_ptr(); self.onscreen = unsafe { slice::from_raw_parts_mut(onscreen, size) }; - unsafe { Heap.dealloc(self.offscreen.as_mut_ptr() as *mut u8, Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; + unsafe { Global.dealloc(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8).as_opaque(), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; self.offscreen = unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }; } else { println!("Display is already {}, {}", width, height); @@ -276,6 +277,6 @@ impl Display { impl Drop for Display { fn drop(&mut self) { - unsafe { Heap.dealloc(self.offscreen.as_mut_ptr() as *mut u8, Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; + unsafe { Global.dealloc(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8).as_opaque(), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; } } From 0a9b15939e957153ccaf2f9f9746abe2fbd38140 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 20 May 2018 11:05:10 -0600 Subject: [PATCH 0231/1301] Update to new event --- Cargo.lock | 191 ++++++++++++++++++++----------------------- ahcid/src/main.rs | 23 ++++-- alxd/src/main.rs | 9 +- e1000d/src/main.rs | 9 +- ihdad/src/main.rs | 14 ++-- ps2d/src/main.rs | 9 +- rtl8168d/src/main.rs | 9 +- vboxd/src/main.rs | 11 ++- 8 files changed, 145 insertions(+), 130 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f5e8eb52c4..6c4aea5d26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,9 +3,9 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -36,7 +36,7 @@ name = "base64" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -44,7 +44,7 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -55,7 +55,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -65,12 +65,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.2.1" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -88,7 +88,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -101,7 +101,7 @@ name = "crossbeam-utils" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -124,7 +124,7 @@ name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -154,7 +154,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -178,7 +178,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -188,7 +188,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -217,7 +217,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.39" +version = "0.2.40" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -238,7 +238,7 @@ name = "log" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -268,9 +268,9 @@ dependencies = [ "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", - "pbr 1.0.0 (git+https://github.com/a8m/pb)", + "pbr 1.0.1 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -287,7 +287,7 @@ version = "0.0.1" source = "git+https://github.com/willem66745/ntpclient-rust#7e3bdf60eb940825789a8da5181025320e3050b0" dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -295,31 +295,31 @@ name = "num" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.36" +version = "0.1.38" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" -version = "0.1.35" +version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -327,7 +327,7 @@ name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -336,29 +336,29 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "orbclient" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pbr" -version = "1.0.0" -source = "git+https://github.com/a8m/pb#d077b49ac6ea18ef63a9bb9f0f0b58abc29580f3" +version = "1.0.1" +source = "git+https://github.com/a8m/pb#e1df7361a08e2c7e210a3e483e3086bfe62dfe71" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -366,12 +366,12 @@ dependencies = [ name = "pcid" version = "0.1.0" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -386,7 +386,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.2.3" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -397,17 +397,17 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -416,7 +416,7 @@ version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -426,7 +426,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -461,7 +461,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -469,7 +469,7 @@ dependencies = [ [[package]] name = "redox_event" version = "0.1.0" -source = "git+https://github.com/redox-os/event.git#68f4c7e55615ecede98f2085c81801a3dc4b74e0" +source = "git+https://github.com/redox-os/event.git#f2448cdafefa5a8deb304d7ea09faf3feb5ff328" dependencies = [ "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -502,7 +502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -525,7 +525,7 @@ dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -557,7 +557,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -568,37 +568,27 @@ name = "sdl2-sys" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" -version = "1.0.34" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.34" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive_internals" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "spin" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -606,16 +596,16 @@ name = "stb_truetype" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.12.14" +version = "0.13.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -624,27 +614,27 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "time" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "toml" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -675,7 +665,7 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -707,7 +697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -721,7 +711,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -741,7 +731,7 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -791,7 +781,7 @@ dependencies = [ "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] @@ -799,10 +789,10 @@ dependencies = [ "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" +"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "652805b7e73fada9d85e9a6682a4abd490cb52d96aeecc12e33a0de34dfd0d23" -"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" +"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" +"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" @@ -818,7 +808,7 @@ dependencies = [ "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" -"checksum libc 0.2.39 (registry+https://github.com/rust-lang/crates.io-index)" = "f54263ad99207254cf58b5f701ecb432c717445ea2ee8af387334bdd1a03fdff" +"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" @@ -829,16 +819,16 @@ dependencies = [ "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -"checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe" -"checksum num-iter 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "4b226df12c5a59b63569dd57fafb926d91b385dfce33d8074a412411b689d593" -"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" +"checksum num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac0ea58d64a89d9d6b7688031b3be9358d6c919badcf7fbb0527ccfd891ee45" +"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" +"checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum orbclient 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f07bacf59f2efd7520b9c9c6ec068a5749553ac6dca7cd79f299041123cc1dfb" -"checksum pbr 1.0.0 (git+https://github.com/a8m/pb)" = "" +"checksum orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ed8bb95b73402c263324f1074744ed951bb0c4aa519ab5db917eebf592ba0b" +"checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" -"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" +"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" +"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc5fdcd7a4ca0bb24bf033534e0c137045538c84b0924af1c950d3ae41a2f71" @@ -856,20 +846,19 @@ dependencies = [ "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60" "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" -"checksum serde 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "0e100d00fb985a5bf16b857a436450e404fa613de3321b2e383947a93cbd75df" -"checksum serde_derive 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)" = "86daebd995aa948b069d886f2105f2425cd66103049855e45c15c58c573f12c5" -"checksum serde_derive_internals 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3f714f52a41e371c5e141e9dafcead60921349bec76b44d79000c88aba3cfc" -"checksum spin 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "dc28a8d2f2efa706fc9d3d074e265c1d529db41c1603679861662cb88e05e70a" +"checksum serde 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "34e9df8efbe7a2c12ceec1fc8744d56ae3374d8ae325f4a0028949d16433d554" +"checksum serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ac38f51a52a556cd17545798e29536885fb1a3fa63d6399f5ef650f4a7d35901" +"checksum spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14db77c5b914df6d6173dda9a3b3f5937bd802934fa5edaf934df06a3491e56f" "checksum stb_truetype 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52ce2b38abdd11cffbc68928810248e0dd003fea489a88a404dc1ba7ae2d5538" -"checksum syn 0.12.14 (registry+https://github.com/rust-lang/crates.io-index)" = "8c5bc2d6ff27891209efa5f63e9de78648d7801f085e4653701a692ce938d6fd" +"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" -"checksum toml 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a7540f4ffc193e0d3c94121edb19b055670d369f77d5804db11ae053a45b6e7e" +"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" +"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" +"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" "checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 9eaffe2653..1ceaad116c 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -8,7 +8,7 @@ extern crate byteorder; use std::{env, usize}; use std::fs::File; use std::io::{Read, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::os::unix::io::FromRawFd; use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme}; use scheme::DiskScheme; @@ -40,14 +40,27 @@ fn main() { syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK ).expect("ahcid: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd) }; - syscall::fevent(socket_fd, EVENT_READ).expect("ahcid: failed to fevent disk scheme"); - let mut irq_file = File::open(&format!("irq:{}", irq)).expect("ahcid: failed to open irq file"); - let irq_fd = irq_file.as_raw_fd(); - syscall::fevent(irq_fd, EVENT_READ).expect("ahcid: failed to fevent irq file"); + let irq_fd = syscall::open( + &format!("irq:{}", irq), + syscall::O_RDWR | syscall::O_NONBLOCK + ).expect("ahcid: failed to open irq file"); + let mut irq_file = unsafe { File::from_raw_fd(irq_fd) }; let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); + event_file.write(&Event { + id: socket_fd, + flags: EVENT_READ, + data: 0 + }).expect("ahcid: failed to event disk scheme"); + + event_file.write(&Event { + id: irq_fd, + flags: EVENT_READ, + data: 0 + }).expect("ahcid: failed to event irq scheme"); + let scheme = DiskScheme::new(scheme_name, ahci::disks(address, &name)); syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace"); diff --git a/alxd/src/main.rs b/alxd/src/main.rs index 9762d68301..196eff7280 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -56,7 +56,7 @@ fn main() { let device_irq = device.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; if unsafe { device_irq.borrow_mut().intr_legacy() } { @@ -85,7 +85,7 @@ fn main() { }).expect("alxd: failed to catch events on IRQ file"); let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_count: usize| -> Result> { + event_queue.add(socket_fd, move |_event| -> Result> { loop { let mut packet = Packet::default(); if socket_packet.borrow_mut().read(&mut packet)? == 0 { @@ -110,7 +110,10 @@ fn main() { Ok(None) }).expect("alxd: failed to catch events on IRQ file"); - for event_count in event_queue.trigger_all(0).expect("alxd: failed to trigger events") { + for event_count in event_queue.trigger_all(event::Event { + fd: 0, + flags: 0, + }).expect("alxd: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, pid: 0, diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 2278cc2a57..02b6bcb838 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -51,7 +51,7 @@ fn main() { let device_irq = device.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; if unsafe { device_irq.irq() } { @@ -80,7 +80,7 @@ fn main() { }).expect("e1000d: failed to catch events on IRQ file"); let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_count: usize| -> Result> { + event_queue.add(socket_fd, move |_event| -> Result> { loop { let mut packet = Packet::default(); if socket_packet.borrow_mut().read(&mut packet)? == 0 { @@ -105,7 +105,10 @@ fn main() { Ok(None) }).expect("e1000d: failed to catch events on scheme file"); - for event_count in event_queue.trigger_all(0).expect("e1000d: failed to trigger events") { + for event_count in event_queue.trigger_all(event::Event { + fd: 0, + flags: 0, + }).expect("e1000d: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, pid: 0, diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index c6e1d9af05..027a592ff8 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -23,11 +23,6 @@ pub mod HDA; use HDA::IntelHDA; - - - - - /* VEND:PROD Virtualbox 8086:2668 @@ -78,7 +73,7 @@ fn main() { let socket_irq = socket.clone(); let device_loop = device.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; @@ -110,7 +105,7 @@ fn main() { }).expect("IHDA: failed to catch events on IRQ file"); let socket_fd = socket.borrow().as_raw_fd(); let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_count: usize| -> Result> { + event_queue.add(socket_fd, move |_event| -> Result> { loop { let mut packet = Packet::default(); if socket_packet.borrow_mut().read(&mut packet)? == 0 { @@ -137,7 +132,10 @@ fn main() { Ok(None) }).expect("IHDA: failed to catch events on IRQ file"); - for event_count in event_queue.trigger_all(0).expect("IHDA: failed to trigger events") { + for event_count in event_queue.trigger_all(event::Event { + fd: 0, + flags: 0, + }).expect("IHDA: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, pid: 0, diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 085ad529af..0dc1c9bd4c 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -52,7 +52,7 @@ fn daemon(input: File) { syscall::setrens(0, 0).expect("ps2d: failed to enter null namespace"); let key_ps2d = ps2d.clone(); - event_queue.add(key_irq.as_raw_fd(), move |_count: usize| -> Result> { + event_queue.add(key_irq.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; if key_irq.read(&mut irq)? >= irq.len() { key_ps2d.borrow_mut().irq(); @@ -62,7 +62,7 @@ fn daemon(input: File) { }).expect("ps2d: failed to poll irq:1"); let mouse_ps2d = ps2d; - event_queue.add(mouse_irq.as_raw_fd(), move |_count: usize| -> Result> { + event_queue.add(mouse_irq.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; if mouse_irq.read(&mut irq)? >= irq.len() { mouse_ps2d.borrow_mut().irq(); @@ -71,7 +71,10 @@ fn daemon(input: File) { Ok(None) }).expect("ps2d: failed to poll irq:12"); - event_queue.trigger_all(0).expect("ps2d: failed to trigger events"); + event_queue.trigger_all(event::Event { + fd: 0, + flags: 0, + }).expect("ps2d: failed to trigger events"); event_queue.run().expect("ps2d: failed to handle events"); } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 5b5cc076d3..46b53ccbc8 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -51,7 +51,7 @@ fn main() { let device_irq = device.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; @@ -83,7 +83,7 @@ fn main() { let socket_fd = socket.borrow().as_raw_fd(); let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_count: usize| -> Result> { + event_queue.add(socket_fd, move |_event| -> Result> { loop { let mut packet = Packet::default(); if socket_packet.borrow_mut().read(&mut packet)? == 0 { @@ -108,7 +108,10 @@ fn main() { Ok(None) }).expect("rtl8168d: failed to catch events on scheme file"); - for event_count in event_queue.trigger_all(0).expect("rtl8168d: failed to trigger events") { + for event_count in event_queue.trigger_all(event::Event { + fd: 0, + flags: 0, + }).expect("rtl8168d: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, pid: 0, diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 90b5205ab1..6b8d181b68 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -5,7 +5,7 @@ extern crate orbclient; extern crate syscall; use event::EventQueue; -use std::{env, mem, slice}; +use std::{env, mem}; use std::os::unix::io::AsRawFd; use std::fs::File; use std::io::{Result, Read, Write}; @@ -219,7 +219,7 @@ fn main() { let mut port = Pio::::new(bar0 as u16); let address = unsafe { syscall::physmap(bar1, 4096, MAP_WRITE).expect("vboxd: failed to map address") }; { - let mut vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; + let vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; let mut guest_info = VboxGuestInfo::new().expect("vboxd: failed to map GuestInfo"); guest_info.version.write(VBOX_VMMDEV_VERSION); @@ -244,7 +244,7 @@ fn main() { let get_mouse = VboxGetMouse::new().expect("vboxd: failed to map GetMouse"); let display_change = VboxDisplayChange::new().expect("vboxd: failed to map DisplayChange"); let ack_events = VboxAckEvents::new().expect("vboxd: failed to map AckEvents"); - event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; if irq_file.read(&mut irq)? >= irq.len() { let host_events = vmmdev.host_events.read(); @@ -286,7 +286,10 @@ fn main() { Ok(None) }).expect("vboxd: failed to poll irq"); - event_queue.trigger_all(0).expect("vboxd: failed to trigger events"); + event_queue.trigger_all(event::Event { + fd: 0, + flags: 0 + }).expect("vboxd: failed to trigger events"); event_queue.run().expect("vboxd: failed to run event loop"); } From 1fc5ebd797748fc0aea7ca4fa2e852285873ac31 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 20 May 2018 13:37:01 -0600 Subject: [PATCH 0232/1301] Make vesad handle events per handle --- vesad/src/main.rs | 28 +++++++++++++++------------- vesad/src/scheme.rs | 30 ++++++++++++++++-------------- vesad/src/screen/graphic.rs | 7 ------- vesad/src/screen/mod.rs | 2 -- vesad/src/screen/text.rs | 7 ------- 5 files changed, 31 insertions(+), 43 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 634f3d4687..ea11dd9006 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -91,20 +91,22 @@ fn main() { } } - for (screen_id, screen) in scheme.screens.iter() { - if let Some(count) = screen.can_read() { - let event_packet = Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *screen_id, - c: EVENT_READ, - d: count - }; + for (handle_id, handle) in scheme.handles.iter() { + if handle.flags & EVENT_READ != 0 { + if let Some(count) = scheme.can_read(*handle_id) { + let event_packet = Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: EVENT_READ, + d: count + }; - socket.write(&event_packet).expect("vesad: failed to write display event"); + socket.write(&event_packet).expect("vesad: failed to write display event"); + } } } } diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 88382ea3af..f4d59a78ce 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -8,15 +8,16 @@ use display::Display; use screen::{Screen, GraphicScreen, TextScreen}; #[derive(Clone)] -enum HandleKind { +pub enum HandleKind { Input, Screen(usize), } #[derive(Clone)] -struct Handle { - kind: HandleKind, - flags: usize, +pub struct Handle { + pub kind: HandleKind, + pub flags: usize, + pub events: usize, } pub struct DisplayScheme { @@ -25,7 +26,7 @@ pub struct DisplayScheme { active: usize, pub screens: BTreeMap>, next_id: usize, - handles: BTreeMap, + pub handles: BTreeMap, } impl DisplayScheme { @@ -81,7 +82,8 @@ impl SchemeMut for DisplayScheme { self.handles.insert(id, Handle { kind: HandleKind::Input, - flags: flags + flags: flags, + events: 0, }); Ok(id) @@ -104,7 +106,8 @@ impl SchemeMut for DisplayScheme { self.handles.insert(id, Handle { kind: HandleKind::Screen(screen_i), - flags: flags + flags: flags, + events: 0, }); Ok(id) @@ -130,15 +133,14 @@ impl SchemeMut for DisplayScheme { } fn fevent(&mut self, id: usize, flags: usize) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(screen) = self.screens.get_mut(&screen_i) { - return screen.event(flags).and(Ok(screen_i)); - } + if let HandleKind::Screen(_screen_i) = handle.kind { + handle.events = flags; + Ok(id) + } else { + Err(Error::new(EBADF)) } - - Err(Error::new(EBADF)) } fn fmap(&mut self, id: usize, offset: usize, size: usize) -> Result { diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index d672426f22..f428099c7a 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -13,7 +13,6 @@ pub struct GraphicScreen { pub display: Display, pub seek: usize, pub input: VecDeque, - pub requested: usize } impl GraphicScreen { @@ -22,7 +21,6 @@ impl GraphicScreen { display: display, seek: 0, input: VecDeque::new(), - requested: 0 } } } @@ -45,11 +43,6 @@ impl Screen for GraphicScreen { }.to_event()); } - fn event(&mut self, flags: usize) -> Result { - self.requested = flags; - Ok(0) - } - fn map(&self, offset: usize, size: usize) -> Result { if offset + size <= self.display.offscreen.len() * 4 { Ok(self.display.offscreen.as_ptr() as usize + offset) diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs index 5927cf4f50..9983728e5b 100644 --- a/vesad/src/screen/mod.rs +++ b/vesad/src/screen/mod.rs @@ -14,8 +14,6 @@ pub trait Screen { fn resize(&mut self, width: usize, height: usize); - fn event(&mut self, flags: usize) -> Result; - fn map(&self, offset: usize, size: usize) -> Result; fn input(&mut self, event: &Event); diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index af247c1238..34e794ff17 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -15,7 +15,6 @@ pub struct TextScreen { pub changed: BTreeSet, pub ctrl: bool, pub input: VecDeque, - pub requested: usize } impl TextScreen { @@ -26,7 +25,6 @@ impl TextScreen { changed: BTreeSet::new(), ctrl: false, input: VecDeque::new(), - requested: 0 } } } @@ -46,11 +44,6 @@ impl Screen for TextScreen { self.console.state.h = height / 16; } - fn event(&mut self, flags: usize) -> Result { - self.requested = flags; - Ok(0) - } - fn map(&self, _offset: usize, _size: usize) -> Result { Err(Error::new(EBADF)) } From 9bc5c5197e6cedc479a9c6362bba46b729e2acf5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 20 May 2018 13:40:14 -0600 Subject: [PATCH 0233/1301] Fix mistaken use of flags --- vesad/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index ea11dd9006..37ef329902 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -92,7 +92,7 @@ fn main() { } for (handle_id, handle) in scheme.handles.iter() { - if handle.flags & EVENT_READ != 0 { + if handle.events & EVENT_READ != 0 { if let Some(count) = scheme.can_read(*handle_id) { let event_packet = Packet { id: 0, From 32a58c3b6434ea8c54bfab618f5dd8bd972b4316 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 20 May 2018 15:19:40 -0600 Subject: [PATCH 0234/1301] Update event crate --- Cargo.lock | 4 ++-- vesad/src/main.rs | 24 +++++++++++++----------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c4aea5d26..91d6e506e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -262,7 +262,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://github.com/redox-os/netutils.git#7eda176e6b4e2edbcc0616247598ec5e87bfe8e8" +source = "git+https://github.com/redox-os/netutils.git#f1861a0caa73c5351a3594cc39a677af709b8cbe" dependencies = [ "arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", @@ -469,7 +469,7 @@ dependencies = [ [[package]] name = "redox_event" version = "0.1.0" -source = "git+https://github.com/redox-os/event.git#f2448cdafefa5a8deb304d7ea09faf3feb5ff328" +source = "git+https://github.com/redox-os/event.git#e9bf8ee4622cb82af2a10032ed711174b2188afd" dependencies = [ "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 37ef329902..97e25180dc 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -94,18 +94,20 @@ fn main() { for (handle_id, handle) in scheme.handles.iter() { if handle.events & EVENT_READ != 0 { if let Some(count) = scheme.can_read(*handle_id) { - let event_packet = Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: EVENT_READ, - d: count - }; + if count > 0 { + let event_packet = Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: EVENT_READ, + d: count + }; - socket.write(&event_packet).expect("vesad: failed to write display event"); + socket.write(&event_packet).expect("vesad: failed to write display event"); + } } } } From aaafbbad33b7614099a1743b7d3b477ef1ae485f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 20 May 2018 16:11:19 -0600 Subject: [PATCH 0235/1301] Update e1000d to new event --- e1000d/src/device.rs | 128 +++++++++++++++++++++++++------------------ e1000d/src/main.rs | 53 +++++++++--------- 2 files changed, 100 insertions(+), 81 deletions(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index d7be0e9630..59e5dab609 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,10 +1,11 @@ -use std::{cmp, mem, ptr, slice, thread, time}; +use std::{cmp, mem, ptr, slice, thread}; +use std::collections::BTreeMap; use netutils::setcfg; -use syscall::error::{Error, EACCES, EINVAL, EWOULDBLOCK, Result}; +use syscall::error::{Error, EACCES, EBADF, EINVAL, EWOULDBLOCK, Result}; use syscall::flag::O_NONBLOCK; use syscall::io::Dma; -use syscall::scheme::Scheme; +use syscall::scheme::SchemeMut; const CTRL: u32 = 0x00; const CTRL_LRST: u32 = 1 << 3; @@ -98,29 +99,41 @@ pub struct Intel8254x { receive_buffer: [Dma<[u8; 16384]>; 16], receive_ring: Dma<[Rd; 16]>, transmit_buffer: [Dma<[u8; 16384]>; 16], - transmit_ring: Dma<[Td; 16]> + transmit_ring: Dma<[Td; 16]>, + next_id: usize, + pub handles: BTreeMap, } -impl Scheme for Intel8254x { - fn open(&self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { +impl SchemeMut for Intel8254x { + fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if uid == 0 { - Ok(flags) + self.next_id += 1; + self.handles.insert(self.next_id, flags); + Ok(self.next_id) } else { Err(Error::new(EACCES)) } } - fn dup(&self, id: usize, buf: &[u8]) -> Result { + fn dup(&mut self, id: usize, buf: &[u8]) -> Result { if ! buf.is_empty() { return Err(Error::new(EINVAL)); } - Ok(id) + let flags = { + let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + *flags + }; + self.next_id += 1; + self.handles.insert(self.next_id, flags); + Ok(self.next_id) } - fn read(&self, id: usize, buf: &mut [u8]) -> Result { - let head = unsafe { self.read(RDH) }; - let mut tail = unsafe { self.read(RDT) }; + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let head = unsafe { self.read_reg(RDH) }; + let mut tail = unsafe { self.read_reg(RDT) }; tail += 1; if tail >= self.receive_ring.len() as u32 { @@ -140,23 +153,25 @@ impl Scheme for Intel8254x { i += 1; } - unsafe { self.write(RDT, tail) }; + unsafe { self.write_reg(RDT, tail) }; return Ok(i); } } - if id & O_NONBLOCK == O_NONBLOCK { + if flags & O_NONBLOCK == O_NONBLOCK { Ok(0) } else { Err(Error::new(EWOULDBLOCK)) } } - fn write(&self, _id: usize, buf: &[u8]) -> Result { + fn write(&mut self, id: usize, buf: &[u8]) -> Result { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + loop { - let head = unsafe { self.read(TDH) }; - let mut tail = unsafe { self.read(TDT) }; + let head = unsafe { self.read_reg(TDH) }; + let mut tail = unsafe { self.read_reg(TDT) }; let old_tail = tail; tail += 1; @@ -183,7 +198,7 @@ impl Scheme for Intel8254x { i += 1; } - unsafe { self.write(TDT, tail) }; + unsafe { self.write_reg(TDT, tail) }; while td.status == 0 { thread::yield_now(); @@ -194,11 +209,14 @@ impl Scheme for Intel8254x { } } - fn fevent(&self, _id: usize, _flags: usize) -> Result { - Ok(0) + fn fevent(&mut self, id: usize, _flags: usize) -> Result { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + Ok(id) } - fn fpath(&self, _id: usize, buf: &mut [u8]) -> Result { + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let mut i = 0; let scheme_path = b"network:"; while i < buf.len() && i < scheme_path.len() { @@ -208,11 +226,13 @@ impl Scheme for Intel8254x { Ok(i) } - fn fsync(&self, _id: usize) -> Result { + fn fsync(&mut self, id: usize) -> Result { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; Ok(0) } - fn close(&self, _id: usize) -> Result { + fn close(&mut self, id: usize) -> Result { + self.handles.remove(&id).ok_or(Error::new(EBADF))?; Ok(0) } } @@ -230,7 +250,9 @@ impl Intel8254x { Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], - transmit_ring: Dma::zeroed()? + transmit_ring: Dma::zeroed()?, + next_id: 0, + handles: BTreeMap::new() }; module.init(); @@ -239,13 +261,13 @@ impl Intel8254x { } pub unsafe fn irq(&self) -> bool { - let icr = self.read(ICR); + let icr = self.read_reg(ICR); icr != 0 } pub fn next_read(&self) -> usize { - let head = unsafe { self.read(RDH) }; - let mut tail = unsafe { self.read(RDT) }; + let head = unsafe { self.read_reg(RDH) }; + let mut tail = unsafe { self.read_reg(RDT) }; tail += 1; if tail >= self.receive_ring.len() as u32 { @@ -262,27 +284,27 @@ impl Intel8254x { 0 } - pub unsafe fn read(&self, register: u32) -> u32 { + pub unsafe fn read_reg(&self, register: u32) -> u32 { ptr::read_volatile((self.base + register as usize) as *mut u32) } - pub unsafe fn write(&self, register: u32, data: u32) -> u32 { + pub unsafe fn write_reg(&self, register: u32, data: u32) -> u32 { ptr::write_volatile((self.base + register as usize) as *mut u32, data); ptr::read_volatile((self.base + register as usize) as *mut u32) } pub unsafe fn flag(&self, register: u32, flag: u32, value: bool) { if value { - self.write(register, self.read(register) | flag); + self.write_reg(register, self.read_reg(register) | flag); } else { - self.write(register, self.read(register) & (0xFFFFFFFF - flag)); + self.write_reg(register, self.read_reg(register) & !flag); } } pub unsafe fn init(&mut self) { self.flag(CTRL, CTRL_RST, true); - while self.read(CTRL) & CTRL_RST == CTRL_RST { - print!(" - Waiting for reset: {:X}\n", self.read(CTRL)); + while self.read_reg(CTRL) & CTRL_RST == CTRL_RST { + print!(" - Waiting for reset: {:X}\n", self.read_reg(CTRL)); } // Enable auto negotiate, link, clear reset, do not Invert Loss-Of Signal @@ -290,18 +312,18 @@ impl Intel8254x { self.flag(CTRL, CTRL_LRST | CTRL_PHY_RST | CTRL_ILOS, false); // No flow control - self.write(FCAH, 0); - self.write(FCAL, 0); - self.write(FCT, 0); - self.write(FCTTV, 0); + self.write_reg(FCAH, 0); + self.write_reg(FCAL, 0); + self.write_reg(FCT, 0); + self.write_reg(FCTTV, 0); // Do not use VLANs self.flag(CTRL, CTRL_VME, false); // TODO: Clear statistical counters - let mac_low = self.read(RAL0); - let mac_high = self.read(RAH0); + let mac_low = self.read_reg(RAL0); + let mac_high = self.read_reg(RAH0); let mac = [mac_low as u8, (mac_low >> 8) as u8, (mac_low >> 16) as u8, @@ -320,24 +342,24 @@ impl Intel8254x { self.receive_ring[i].buffer = self.receive_buffer[i].physical() as u64; } - self.write(RDBAH, (self.receive_ring.physical() >> 32) as u32); - self.write(RDBAL, self.receive_ring.physical() as u32); - self.write(RDLEN, (self.receive_ring.len() * mem::size_of::()) as u32); - self.write(RDH, 0); - self.write(RDT, self.receive_ring.len() as u32 - 1); + self.write_reg(RDBAH, (self.receive_ring.physical() >> 32) as u32); + self.write_reg(RDBAL, self.receive_ring.physical() as u32); + self.write_reg(RDLEN, (self.receive_ring.len() * mem::size_of::()) as u32); + self.write_reg(RDH, 0); + self.write_reg(RDT, self.receive_ring.len() as u32 - 1); // Transmit Buffer for i in 0..self.transmit_ring.len() { self.transmit_ring[i].buffer = self.transmit_buffer[i].physical() as u64; } - self.write(TDBAH, (self.transmit_ring.physical() >> 32) as u32); - self.write(TDBAL, self.transmit_ring.physical() as u32); - self.write(TDLEN, (self.transmit_ring.len() * mem::size_of::()) as u32); - self.write(TDH, 0); - self.write(TDT, 0); + self.write_reg(TDBAH, (self.transmit_ring.physical() >> 32) as u32); + self.write_reg(TDBAL, self.transmit_ring.physical() as u32); + self.write_reg(TDLEN, (self.transmit_ring.len() * mem::size_of::()) as u32); + self.write_reg(TDH, 0); + self.write_reg(TDT, 0); - self.write(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ); // | IMS_LSC | IMS_TXQE | IMS_TXDW + self.write_reg(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ); // | IMS_LSC | IMS_TXQE | IMS_TXDW self.flag(RCTL, RCTL_EN, true); self.flag(RCTL, RCTL_UPE, true); @@ -359,10 +381,10 @@ impl Intel8254x { // TIPG Packet Gap // TODO ... - while self.read(STATUS) & 2 != 2 { - print!(" - Waiting for link up: {:X}\n", self.read(STATUS)); + while self.read_reg(STATUS) & 2 != 2 { + print!(" - Waiting for link up: {:X}\n", self.read_reg(STATUS)); } - print!(" - Link is up with speed {}\n", match (self.read(STATUS) >> 6) & 0b11 { + print!(" - Link is up with speed {}\n", match (self.read_reg(STATUS) >> 6) & 0b11 { 0b00 => "10 Mb/s", 0b01 => "100 Mb/s", _ => "1000 Mb/s", diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 02b6bcb838..41e8e4d198 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -12,7 +12,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, Scheme, MAP_WRITE}; +use syscall::{Packet, SchemeMut, MAP_WRITE}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -40,7 +40,7 @@ fn main() { let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") }; { - let device = Arc::new(unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }); + let device = Arc::new(RefCell::new(unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") })); let mut event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); @@ -54,14 +54,14 @@ fn main() { event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; - if unsafe { device_irq.irq() } { + if unsafe { device_irq.borrow().irq() } { irq_file.write(&mut irq)?; let mut todo = todo_irq.borrow_mut(); let mut i = 0; while i < todo.len() { let a = todo[i].a; - device_irq.handle(&mut todo[i]); + device_irq.borrow_mut().handle(&mut todo[i]); if todo[i].a == (-EWOULDBLOCK) as usize { todo[i].a = a; i += 1; @@ -71,7 +71,7 @@ fn main() { } } - let next_read = device_irq.next_read(); + let next_read = device_irq.borrow().next_read(); if next_read > 0 { return Ok(Some(next_read)); } @@ -79,6 +79,7 @@ fn main() { Ok(None) }).expect("e1000d: failed to catch events on IRQ file"); + let device_packet = device.clone(); let socket_packet = socket.clone(); event_queue.add(socket_fd, move |_event| -> Result> { loop { @@ -88,7 +89,7 @@ fn main() { } let a = packet.a; - device.handle(&mut packet); + device_packet.borrow_mut().handle(&mut packet); if packet.a == (-EWOULDBLOCK) as usize { packet.a = a; todo.borrow_mut().push(packet); @@ -97,7 +98,7 @@ fn main() { } } - let next_read = device.next_read(); + let next_read = device_packet.borrow().next_read(); if next_read > 0 { return Ok(Some(next_read)); } @@ -105,35 +106,31 @@ fn main() { Ok(None) }).expect("e1000d: failed to catch events on scheme file"); + let send_events = |event_count| { + for (handle_id, _handle) in device.borrow().handles.iter() { + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: syscall::flag::EVENT_READ, + d: event_count + }).expect("e1000d: failed to write event"); + } + }; + for event_count in event_queue.trigger_all(event::Event { fd: 0, flags: 0, }).expect("e1000d: failed to trigger events") { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ, - d: event_count - }).expect("e1000d: failed to write event"); + send_events(event_count); } loop { let event_count = event_queue.run().expect("e1000d: failed to handle events"); - - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ, - d: event_count - }).expect("e1000d: failed to write event"); + send_events(event_count); } } unsafe { let _ = syscall::physunmap(address); } From 202ead3b93eaf31eaab5bc35014e69540ccce55f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 20 May 2018 16:16:45 -0600 Subject: [PATCH 0236/1301] Update rtl8168d to new events --- rtl8168d/src/device.rs | 58 ++++++++++++++++++++++++++++++++---------- rtl8168d/src/main.rs | 44 +++++++++++++++----------------- 2 files changed, 65 insertions(+), 37 deletions(-) diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index b49466d332..37dbb74456 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -1,7 +1,8 @@ use std::{mem, thread}; +use std::collections::BTreeMap; use netutils::setcfg; -use syscall::error::{Error, EACCES, EINVAL, EWOULDBLOCK, Result}; +use syscall::error::{Error, EACCES, EBADF, EINVAL, EWOULDBLOCK, Result}; use syscall::flag::O_NONBLOCK; use syscall::io::{Dma, Mmio, Io, ReadOnly}; use syscall::scheme::SchemeMut; @@ -73,13 +74,17 @@ pub struct Rtl8168 { transmit_ring: Dma<[Td; 16]>, transmit_i: usize, transmit_buffer_h: [Dma<[Mmio; 7552]>; 1], - transmit_ring_h: Dma<[Td; 1]> + transmit_ring_h: Dma<[Td; 1]>, + next_id: usize, + pub handles: BTreeMap } impl SchemeMut for Rtl8168 { fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if uid == 0 { - Ok(flags) + self.next_id += 1; + self.handles.insert(self.next_id, flags); + Ok(self.next_id) } else { Err(Error::new(EACCES)) } @@ -90,10 +95,18 @@ impl SchemeMut for Rtl8168 { return Err(Error::new(EINVAL)); } - Ok(id) + let flags = { + let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + *flags + }; + self.next_id += 1; + self.handles.insert(self.next_id, flags); + Ok(self.next_id) } fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + if self.receive_i >= self.receive_ring.len() { self.receive_i = 0; } @@ -118,14 +131,16 @@ impl SchemeMut for Rtl8168 { return Ok(i); } - if id & O_NONBLOCK == O_NONBLOCK { + if flags & O_NONBLOCK == O_NONBLOCK { Ok(0) } else { Err(Error::new(EWOULDBLOCK)) } } - fn write(&mut self, _id: usize, buf: &[u8]) -> Result { + fn write(&mut self, id: usize, buf: &[u8]) -> Result { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + loop { if self.transmit_i >= self.transmit_ring.len() { self.transmit_i = 0; @@ -159,15 +174,30 @@ impl SchemeMut for Rtl8168 { } } - fn fevent(&mut self, _id: usize, _flags: usize) -> Result { + fn fevent(&mut self, id: usize, _flags: usize) -> Result { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + Ok(id) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let mut i = 0; + let scheme_path = b"network:"; + while i < buf.len() && i < scheme_path.len() { + buf[i] = scheme_path[i]; + i += 1; + } + Ok(i) + } + + fn fsync(&mut self, id: usize) -> Result { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; Ok(0) } - fn fsync(&mut self, _id: usize) -> Result { - Ok(0) - } - - fn close(&mut self, _id: usize) -> Result { + fn close(&mut self, id: usize) -> Result { + self.handles.remove(&id).ok_or(Error::new(EBADF))?; Ok(0) } } @@ -214,7 +244,9 @@ impl Rtl8168 { transmit_ring: Dma::zeroed()?, transmit_i: 0, transmit_buffer_h: [Dma::zeroed()?], - transmit_ring_h: Dma::zeroed()? + transmit_ring_h: Dma::zeroed()?, + next_id: 0, + handles: BTreeMap::new() }; module.init(); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 46b53ccbc8..460da0ac57 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -81,7 +81,7 @@ fn main() { Ok(None) }).expect("rtl8168d: failed to catch events on IRQ file"); - let socket_fd = socket.borrow().as_raw_fd(); + let device_packet = device.clone(); let socket_packet = socket.clone(); event_queue.add(socket_fd, move |_event| -> Result> { loop { @@ -91,7 +91,7 @@ fn main() { } let a = packet.a; - device.borrow_mut().handle(&mut packet); + device_packet.borrow_mut().handle(&mut packet); if packet.a == (-EWOULDBLOCK) as usize { packet.a = a; todo.borrow_mut().push(packet); @@ -100,7 +100,7 @@ fn main() { } } - let next_read = device.borrow().next_read(); + let next_read = device_packet.borrow().next_read(); if next_read > 0 { return Ok(Some(next_read)); } @@ -108,35 +108,31 @@ fn main() { Ok(None) }).expect("rtl8168d: failed to catch events on scheme file"); + let send_events = |event_count| { + for (handle_id, _handle) in device.borrow().handles.iter() { + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: syscall::flag::EVENT_READ, + d: event_count + }).expect("e1000d: failed to write event"); + } + }; + for event_count in event_queue.trigger_all(event::Event { fd: 0, flags: 0, }).expect("rtl8168d: failed to trigger events") { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ, - d: event_count - }).expect("rtl8168d: failed to write event"); + send_events(event_count); } loop { let event_count = event_queue.run().expect("rtl8168d: failed to handle events"); - - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ, - d: event_count - }).expect("rtl8168d: failed to write event"); + send_events(event_count); } } unsafe { let _ = syscall::physunmap(address); } From fd5b7b2921947e61faafd5114f31a7d9256c2165 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 4 Jun 2018 05:37:18 +0200 Subject: [PATCH 0237/1301] Make it edge-triggered --- vesad/src/main.rs | 47 +++++++++++++++++++++++++++++---------------- vesad/src/scheme.rs | 18 +++++++++-------- 2 files changed, 40 insertions(+), 25 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 97e25180dc..1d63798123 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -14,7 +14,7 @@ use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, MAP_WRITE, MAP_ use mode_info::VBEModeInfo; use primitive::fast_set64; -use scheme::DisplayScheme; +use scheme::{DisplayScheme, HandleKind}; pub mod display; pub mod mode_info; @@ -91,24 +91,37 @@ fn main() { } } - for (handle_id, handle) in scheme.handles.iter() { - if handle.events & EVENT_READ != 0 { - if let Some(count) = scheme.can_read(*handle_id) { - if count > 0 { - let event_packet = Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: EVENT_READ, - d: count - }; + for (handle_id, handle) in scheme.handles.iter_mut() { + if handle.events & EVENT_READ == 0 { + continue; + } - socket.write(&event_packet).expect("vesad: failed to write display event"); - } + // Can't use scheme.can_read() because we borrow handles as mutable. + // (and because it'd treat O_NONBLOCK sockets differently) + let count = if let HandleKind::Screen(screen_i) = handle.kind { + scheme.screens.get(&screen_i) + .and_then(|screen| screen.can_read()) + .unwrap_or(0) + } else { 0 }; + + if count > 0 { + if !handle.notified_read { + handle.notified_read = true; + let event_packet = Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: EVENT_READ, + d: count + }; + + socket.write(&event_packet).expect("vesad: failed to write display event"); } + } else { + handle.notified_read = false; } } } diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index f4d59a78ce..c43f2b5b4c 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -18,6 +18,7 @@ pub struct Handle { pub kind: HandleKind, pub flags: usize, pub events: usize, + pub notified_read: bool } pub struct DisplayScheme { @@ -57,14 +58,11 @@ impl DisplayScheme { if let Some(handle) = self.handles.get(&id) { if let HandleKind::Screen(screen_i) = handle.kind { if let Some(screen) = self.screens.get(&screen_i) { - match screen.can_read() { - Some(count) => return Some(count), - None => if handle.flags & O_NONBLOCK == O_NONBLOCK { - return Some(0); - } else { - return None; - } - } + screen.can_read().or(if handle.flags & O_NONBLOCK == O_NONBLOCK { + Some(0) + } else { + None + }); } } } @@ -84,6 +82,7 @@ impl SchemeMut for DisplayScheme { kind: HandleKind::Input, flags: flags, events: 0, + notified_read: false }); Ok(id) @@ -108,6 +107,7 @@ impl SchemeMut for DisplayScheme { kind: HandleKind::Screen(screen_i), flags: flags, events: 0, + notified_read: false }); Ok(id) @@ -135,6 +135,8 @@ impl SchemeMut for DisplayScheme { fn fevent(&mut self, id: usize, flags: usize) -> Result { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + handle.notified_read = false; + if let HandleKind::Screen(_screen_i) = handle.kind { handle.events = flags; Ok(id) From 35a21cee2f76334c94904e521a549f72b0cfa4df Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 12 Jun 2018 12:30:43 -0600 Subject: [PATCH 0238/1301] Update links to gitlab --- Cargo.lock | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 91d6e506e3..e03d801ff3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,15 +13,15 @@ name = "alxd" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", - "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", + "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "arg_parser" version = "0.1.0" -source = "git+https://github.com/redox-os/arg-parser.git#7503531821b0c111f9fac77a5d2536ea221105fe" +source = "git+https://gitlab.redox-os.org/redox-os/arg-parser.git#7503531821b0c111f9fac77a5d2536ea221105fe" [[package]] name = "arrayvec" @@ -109,15 +109,15 @@ name = "e1000d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", - "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", + "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "extra" version = "0.1.0" -source = "git+https://github.com/redox-os/libextra.git#f38608acd9cc00e1c8bd41a1a96d31becf239913" +source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#f38608acd9cc00e1c8bd41a1a96d31becf239913" [[package]] name = "fuchsia-zircon" @@ -186,7 +186,7 @@ name = "ihdad" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -262,16 +262,16 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://github.com/redox-os/netutils.git#f1861a0caa73c5351a3594cc39a677af709b8cbe" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#f1861a0caa73c5351a3594cc39a677af709b8cbe" dependencies = [ - "arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)", - "extra 0.1.0 (git+https://github.com/redox-os/libextra.git)", + "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", + "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.1 (git+https://github.com/a8m/pb)", - "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -398,7 +398,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -469,7 +469,7 @@ dependencies = [ [[package]] name = "redox_event" version = "0.1.0" -source = "git+https://github.com/redox-os/event.git#e9bf8ee4622cb82af2a10032ed711174b2188afd" +source = "git+https://gitlab.redox-os.org/redox-os/event.git#e9bf8ee4622cb82af2a10032ed711174b2188afd" dependencies = [ "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -512,8 +512,8 @@ name = "rtl8168d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)", - "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", + "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -698,7 +698,7 @@ name = "vboxd" version = "0.1.0" dependencies = [ "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_event 0.1.0 (git+https://github.com/redox-os/event.git)", + "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -785,7 +785,7 @@ dependencies = [ ] [metadata] -"checksum arg_parser 0.1.0 (git+https://github.com/redox-os/arg-parser.git)" = "" +"checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" @@ -796,7 +796,7 @@ dependencies = [ "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum extra 0.1.0 (git+https://github.com/redox-os/libextra.git)" = "" +"checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" @@ -815,7 +815,7 @@ dependencies = [ "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -"checksum netutils 0.1.0 (git+https://github.com/redox-os/netutils.git)" = "" +"checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)" = "" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" @@ -835,7 +835,7 @@ dependencies = [ "checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" "checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" -"checksum redox_event 0.1.0 (git+https://github.com/redox-os/event.git)" = "" +"checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98e1a40d38f45a3ad65fd088640eeee7b215adcd73041b9f94b92204cca9572a" "checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" From c6b1dea60de8d87459b13bce983b80cdb6ff2758 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Wed, 13 Jun 2018 07:20:05 +0200 Subject: [PATCH 0239/1301] Fix compilation There was a version mismatch because of outdated redox_event and some issues with the Cargo.lock that `cargo update` fixed --- Cargo.lock | 404 +++++++++++++++++++++++++++++++++++--------- alxd/Cargo.toml | 4 +- e1000d/Cargo.toml | 4 +- ihdad/Cargo.toml | 2 +- ps2d/Cargo.toml | 2 +- rtl8168d/Cargo.toml | 4 +- vboxd/Cargo.toml | 2 +- xhcid/Cargo.toml | 2 +- xhcid/src/main.rs | 11 +- 9 files changed, 345 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e03d801ff3..9d3b602f3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -15,7 +15,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -45,7 +45,7 @@ name = "bgad" version = "0.1.0" dependencies = [ "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -68,6 +68,15 @@ name = "byteorder" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bytes" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cfg-if" version = "0.1.3" @@ -82,6 +91,15 @@ dependencies = [ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-deque" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-epoch" version = "0.3.1" @@ -90,12 +108,25 @@ dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-epoch" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-utils" version = "0.2.2" @@ -104,6 +135,14 @@ dependencies = [ "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-utils" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "e1000d" version = "0.1.0" @@ -111,13 +150,13 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "extra" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#f38608acd9cc00e1c8bd41a1a96d31becf239913" +source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#0b50f3f2127fa62b1fe74090feffbae357266eac" [[package]] name = "fuchsia-zircon" @@ -133,6 +172,11 @@ name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "futures" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "gcc" version = "0.3.54" @@ -187,10 +231,19 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "iovec" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -212,12 +265,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.0.0" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazycell" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.40" +version = "0.2.42" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -230,12 +288,12 @@ name = "log" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -259,21 +317,80 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mio" +version = "0.6.14" +source = "git+https://github.com/redox-os/mio?branch=owned-eventedfd#f35b81830b592dd7e117b6b36cc97a48b0ff91c4" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.3.1 (git+https://github.com/redox-os/miow?rev=5b10500)", + "net2 0.2.32 (git+https://github.com/redox-os/net2-rs)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mio" +version = "0.6.14" +source = "git+https://gitlab.redox-os.org/redox-os/mio?branch=owned-eventedfd#f35b81830b592dd7e117b6b36cc97a48b0ff91c4" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.3.1 (git+https://github.com/redox-os/miow?rev=5b10500)", + "net2 0.2.32 (git+https://github.com/redox-os/net2-rs)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miow" +version = "0.3.1" +source = "git+https://github.com/redox-os/miow?rev=5b10500#5b10500df2c560245d532e77c54a8b8b2d15cfd5" +dependencies = [ + "socket2 0.3.7 (git+https://github.com/redox-os/socket2-rs)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "net2" +version = "0.2.32" +source = "git+https://github.com/redox-os/net2-rs#0eae9193ba04270a4ded81c0d3c76d918c3bbcc6" +dependencies = [ + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#f1861a0caa73c5351a3594cc39a677af709b8cbe" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#a705495d11595db8cc31f1c3132142b8a5c204cc" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio?branch=owned-eventedfd)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.1 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", ] [[package]] @@ -327,7 +444,7 @@ name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -335,7 +452,7 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -345,7 +462,7 @@ version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -353,10 +470,10 @@ dependencies = [ [[package]] name = "pbr" version = "1.0.1" -source = "git+https://github.com/a8m/pb#e1df7361a08e2c7e210a3e483e3086bfe62dfe71" +source = "git+https://github.com/a8m/pb#bff135f7eed7931a1103e593c74160d28fdd2314" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -368,9 +485,9 @@ version = "0.1.0" dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -386,7 +503,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.3.8" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -399,15 +516,15 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.5.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -416,7 +533,7 @@ version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -426,8 +543,8 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -460,8 +577,8 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -469,22 +586,14 @@ dependencies = [ [[package]] name = "redox_event" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/event.git#e9bf8ee4622cb82af2a10032ed711174b2188afd" +source = "git+https://gitlab.redox-os.org/redox-os/event.git#c31e3d3d5f44d60ff9fec2b1ee58b982e72c0d77" dependencies = [ - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_event" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -492,7 +601,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -502,7 +611,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -514,7 +623,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -557,7 +666,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -573,17 +682,33 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.58" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.58" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "slab" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "socket2" +version = "0.3.7" +source = "git+https://github.com/redox-os/socket2-rs#3543915f09e41f6e010d4d9e2d5217b27faf5e70" +dependencies = [ + "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -601,11 +726,11 @@ dependencies = [ [[package]] name = "syn" -version = "0.13.11" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -614,8 +739,8 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -624,9 +749,115 @@ name = "time" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio" +version = "0.1.6" +source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.14 (git+https://github.com/redox-os/mio?branch=owned-eventedfd)", + "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-fs 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-tcp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-timer 0.2.3 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-udp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", +] + +[[package]] +name = "tokio-executor" +version = "0.1.2" +source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-fs" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", +] + +[[package]] +name = "tokio-io" +version = "0.1.6" +source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.1" +source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.14 (git+https://github.com/redox-os/mio?branch=owned-eventedfd)", + "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.14 (git+https://github.com/redox-os/mio?branch=owned-eventedfd)", + "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.3" +source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +dependencies = [ + "crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", +] + +[[package]] +name = "tokio-timer" +version = "0.2.3" +source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +dependencies = [ + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", +] + +[[package]] +name = "tokio-udp" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +dependencies = [ + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.14 (git+https://github.com/redox-os/mio?branch=owned-eventedfd)", + "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", ] [[package]] @@ -634,7 +865,7 @@ name = "toml" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -699,7 +930,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -713,7 +944,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -751,7 +982,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -779,8 +1010,8 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -792,29 +1023,40 @@ dependencies = [ "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" +"checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff" "checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" +"checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" +"checksum crossbeam-epoch 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2af0e75710d6181e234c8ecc79f14a97907850a541b13b0be1dd10992f2e4620" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" +"checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04535774f79684c99528944ebdb89756c945c027e55ce52faa245879d836c8fb" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" +"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" -"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" +"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" +"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" +"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" +"checksum log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fddaa003a65722a7fb9e26b0ce95921fe4ba590542ced664d8ce2fa26f9f3ac" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" +"checksum mio 0.6.14 (git+https://github.com/redox-os/mio?branch=owned-eventedfd)" = "" +"checksum mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio?branch=owned-eventedfd)" = "" +"checksum miow 0.3.1 (git+https://github.com/redox-os/miow?rev=5b10500)" = "" +"checksum net2 0.2.32 (git+https://github.com/redox-os/net2-rs)" = "" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)" = "" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" @@ -827,8 +1069,8 @@ dependencies = [ "checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" -"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" +"checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" +"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc5fdcd7a4ca0bb24bf033534e0c137045538c84b0924af1c950d3ae41a2f71" @@ -836,8 +1078,7 @@ dependencies = [ "checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" -"checksum redox_event 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98e1a40d38f45a3ad65fd088640eeee7b215adcd73041b9f94b92204cca9572a" -"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" +"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" "checksum rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17727f4b991294da2c84d75a43c003151ff58072212768800f66c56ee46dca43" @@ -846,13 +1087,24 @@ dependencies = [ "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60" "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" -"checksum serde 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "34e9df8efbe7a2c12ceec1fc8744d56ae3374d8ae325f4a0028949d16433d554" -"checksum serde_derive 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "ac38f51a52a556cd17545798e29536885fb1a3fa63d6399f5ef650f4a7d35901" +"checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95" +"checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79" +"checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" +"checksum socket2 0.3.7 (git+https://github.com/redox-os/socket2-rs)" = "" "checksum spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14db77c5b914df6d6173dda9a3b3f5937bd802934fa5edaf934df06a3491e56f" "checksum stb_truetype 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52ce2b38abdd11cffbc68928810248e0dd003fea489a88a404dc1ba7ae2d5538" -"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" +"checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" +"checksum tokio 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" +"checksum tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" +"checksum tokio-fs 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" +"checksum tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" +"checksum tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" +"checksum tokio-tcp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" +"checksum tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" +"checksum tokio-timer 0.2.3 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" +"checksum tokio-udp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" @@ -868,7 +1120,7 @@ dependencies = [ "checksum webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e499345fc4c6b7c79a5b8756d4592c4305510a13512e79efafe00dfbd67bbac6" "checksum webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb3f50499f21ad2317f442845e3b5805b007f1e728f59885c99e61b8c181a7" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" +"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml index ac2329863e..804a3de336 100644 --- a/alxd/Cargo.toml +++ b/alxd/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "0.7" -netutils = { git = "https://github.com/redox-os/netutils.git" } -redox_event = { git = "https://github.com/redox-os/event.git" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 45f71f1576..eaa8ae9d35 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "0.7" -netutils = { git = "https://github.com/redox-os/netutils.git" } -redox_event = { git = "https://github.com/redox-os/event.git" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/ihdad/Cargo.toml b/ihdad/Cargo.toml index e0e18f8906..23e365aa01 100755 --- a/ihdad/Cargo.toml +++ b/ihdad/Cargo.toml @@ -5,6 +5,6 @@ version = "0.1.0" [dependencies] bitflags = "0.7" spin = "0.4" -redox_event = { git = "https://github.com/redox-os/event.git" } +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index d1df438016..559e6340c8 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -5,5 +5,5 @@ version = "0.1.0" [dependencies] bitflags = "0.7" orbclient = "0.3" -redox_event = { git = "https://github.com/redox-os/event.git" } +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index 13bb96f689..661cda88f4 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "0.7" -netutils = { git = "https://github.com/redox-os/netutils.git" } -redox_event = { git = "https://github.com/redox-os/event.git" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index 07c81b675a..99d1448cf9 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" [dependencies] orbclient = "0.3" -redox_event = { git = "https://github.com/redox-os/event.git" } +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 3618ef835b..f7eca3c226 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -6,5 +6,5 @@ version = "0.1.0" bitflags = "0.7" plain = "0.2" spin = "0.4" -redox_event = "0.1" +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index dac58b0c49..5616583908 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -4,7 +4,7 @@ extern crate event; extern crate plain; extern crate syscall; -use event::EventQueue; +use event::{Event, EventQueue}; use std::cell::RefCell; use std::env; use std::fs::File; @@ -56,7 +56,7 @@ fn main() { let hci_irq = hci.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result> { + event_queue.add(irq_file.as_raw_fd(), move |_| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; @@ -83,7 +83,7 @@ fn main() { let socket_fd = socket.borrow().as_raw_fd(); let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_count: usize| -> Result> { + event_queue.add(socket_fd, move |_| -> Result> { loop { let mut packet = Packet::default(); if socket_packet.borrow_mut().read(&mut packet)? == 0 { @@ -102,7 +102,10 @@ fn main() { Ok(None) }).expect("xhcid: failed to catch events on scheme file"); - event_queue.trigger_all(0).expect("xhcid: failed to trigger events"); + event_queue.trigger_all(Event { + fd: 0, + flags: 0 + }).expect("xhcid: failed to trigger events"); event_queue.run().expect("xhcid: failed to handle events"); } From 1f1c2ff4e89562b334c4a98081f36e70f673d487 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Thu, 14 Jun 2018 08:08:59 +0200 Subject: [PATCH 0240/1301] Bump Cargo.lock --- Cargo.lock | 135 +++++++++++++++++++++++------------------------------ 1 file changed, 58 insertions(+), 77 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9d3b602f3a..47a86dc527 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,7 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -320,7 +320,7 @@ dependencies = [ [[package]] name = "mio" version = "0.6.14" -source = "git+https://github.com/redox-os/mio?branch=owned-eventedfd#f35b81830b592dd7e117b6b36cc97a48b0ff91c4" +source = "git+https://gitlab.redox-os.org/redox-os/mio#1339f362be63592de538a4ea52367e820e846988" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -328,26 +328,8 @@ dependencies = [ "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.1 (git+https://github.com/redox-os/miow?rev=5b10500)", - "net2 0.2.32 (git+https://github.com/redox-os/net2-rs)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio" -version = "0.6.14" -source = "git+https://gitlab.redox-os.org/redox-os/mio?branch=owned-eventedfd#f35b81830b592dd7e117b6b36cc97a48b0ff91c4" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.1 (git+https://github.com/redox-os/miow?rev=5b10500)", - "net2 0.2.32 (git+https://github.com/redox-os/net2-rs)", + "miow 0.3.1 (git+https://gitlab.redox-os.org/redox-os/miow?rev=5b10500)", + "net2 0.2.32 (git+https://gitlab.redox-os.org/redox-os/net2-rs)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -356,7 +338,7 @@ dependencies = [ [[package]] name = "miow" version = "0.3.1" -source = "git+https://github.com/redox-os/miow?rev=5b10500#5b10500df2c560245d532e77c54a8b8b2d15cfd5" +source = "git+https://gitlab.redox-os.org/redox-os/miow?rev=5b10500#5b10500df2c560245d532e77c54a8b8b2d15cfd5" dependencies = [ "socket2 0.3.7 (git+https://github.com/redox-os/socket2-rs)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -365,7 +347,7 @@ dependencies = [ [[package]] name = "net2" version = "0.2.32" -source = "git+https://github.com/redox-os/net2-rs#0eae9193ba04270a4ded81c0d3c76d918c3bbcc6" +source = "git+https://gitlab.redox-os.org/redox-os/net2-rs#0eae9193ba04270a4ded81c0d3c76d918c3bbcc6" dependencies = [ "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -375,22 +357,22 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#a705495d11595db8cc31f1c3132142b8a5c204cc" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#c728870d6a1d9d8938117798e6caab22b09c37a6" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio?branch=owned-eventedfd)", + "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.1 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] @@ -458,7 +440,7 @@ dependencies = [ [[package]] name = "orbclient" -version = "0.3.14" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -514,7 +496,7 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -757,24 +739,24 @@ dependencies = [ [[package]] name = "tokio" version = "0.1.6" -source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (git+https://github.com/redox-os/mio?branch=owned-eventedfd)", - "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-fs 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-tcp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-timer 0.2.3 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-udp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)", + "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-fs 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-tcp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-timer 0.2.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-udp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-executor" version = "0.1.2" -source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -782,17 +764,17 @@ dependencies = [ [[package]] name = "tokio-fs" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-io" version = "0.1.6" -source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -802,62 +784,62 @@ dependencies = [ [[package]] name = "tokio-reactor" version = "0.1.1" -source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (git+https://github.com/redox-os/mio?branch=owned-eventedfd)", + "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-tcp" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (git+https://github.com/redox-os/mio?branch=owned-eventedfd)", - "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)", + "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-threadpool" version = "0.1.3" -source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-timer" version = "0.2.3" -source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-udp" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd#65a7aa275d58ed6b03b982508a32d68f4b2e73b4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (git+https://github.com/redox-os/mio?branch=owned-eventedfd)", - "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", - "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)", + "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)", + "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] @@ -928,7 +910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -942,7 +924,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1053,10 +1035,9 @@ dependencies = [ "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -"checksum mio 0.6.14 (git+https://github.com/redox-os/mio?branch=owned-eventedfd)" = "" -"checksum mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio?branch=owned-eventedfd)" = "" -"checksum miow 0.3.1 (git+https://github.com/redox-os/miow?rev=5b10500)" = "" -"checksum net2 0.2.32 (git+https://github.com/redox-os/net2-rs)" = "" +"checksum mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" +"checksum miow 0.3.1 (git+https://gitlab.redox-os.org/redox-os/miow?rev=5b10500)" = "" +"checksum net2 0.2.32 (git+https://gitlab.redox-os.org/redox-os/net2-rs)" = "" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)" = "" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" @@ -1065,7 +1046,7 @@ dependencies = [ "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum orbclient 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b4ed8bb95b73402c263324f1074744ed951bb0c4aa519ab5db917eebf592ba0b" +"checksum orbclient 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "539086aa68e65febd8e76f8b6ed244f9671063ee85f0b67bc96c4b69f07f81bc" "checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" @@ -1096,15 +1077,15 @@ dependencies = [ "checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum tokio 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" -"checksum tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" -"checksum tokio-fs 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" -"checksum tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" -"checksum tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" -"checksum tokio-tcp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" -"checksum tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" -"checksum tokio-timer 0.2.3 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" -"checksum tokio-udp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio?branch=owned-eventedfd)" = "" +"checksum tokio 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-fs 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-tcp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-timer 0.2.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-udp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" From 8a52c84f1a3984a1d7e322dee0457de83311a2d5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 19 Jun 2018 17:44:51 -0600 Subject: [PATCH 0241/1301] Update to new alloc API --- vesad/src/display.rs | 7 +++---- vesad/src/main.rs | 2 -- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index f8795a10b2..bb25dcb841 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -1,8 +1,7 @@ #[cfg(feature="rusttype")] extern crate rusttype; -use alloc::allocator::{Alloc, Layout}; -use alloc::heap::Global; +use std::alloc::{Alloc, Global, Layout}; use std::{cmp, slice}; use std::ptr::NonNull; @@ -108,7 +107,7 @@ impl Display { let onscreen = self.onscreen.as_mut_ptr(); self.onscreen = unsafe { slice::from_raw_parts_mut(onscreen, size) }; - unsafe { Global.dealloc(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8).as_opaque(), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; + unsafe { Global.dealloc(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; self.offscreen = unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }; } else { println!("Display is already {}, {}", width, height); @@ -277,6 +276,6 @@ impl Display { impl Drop for Display { fn drop(&mut self) { - unsafe { Global.dealloc(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8).as_opaque(), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; + unsafe { Global.dealloc(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; } } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 1d63798123..008417fc6e 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -1,9 +1,7 @@ #![deny(warnings)] -#![feature(alloc)] #![feature(allocator_api)] #![feature(asm)] -extern crate alloc; extern crate orbclient; extern crate syscall; From 18bb29bcd7e4a672f32c9b12eb37fd8345c1f509 Mon Sep 17 00:00:00 2001 From: bujiraso Date: Sun, 24 Jun 2018 13:13:37 -0300 Subject: [PATCH 0242/1301] Update Cargo.lock to use socket2 on our GitLab --- Cargo.lock | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47a86dc527..cff3e77d0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,7 +184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "httparse" -version = "1.2.4" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -193,7 +193,7 @@ version = "0.10.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -320,7 +320,7 @@ dependencies = [ [[package]] name = "mio" version = "0.6.14" -source = "git+https://gitlab.redox-os.org/redox-os/mio#1339f362be63592de538a4ea52367e820e846988" +source = "git+https://gitlab.redox-os.org/redox-os/mio#529f2e8c58a5b7fe38f7f8d698d7f2e95adb8e01" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -328,7 +328,7 @@ dependencies = [ "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.1 (git+https://gitlab.redox-os.org/redox-os/miow?rev=5b10500)", + "miow 0.3.1 (git+https://gitlab.redox-os.org/redox-os/miow)", "net2 0.2.32 (git+https://gitlab.redox-os.org/redox-os/net2-rs)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -338,9 +338,9 @@ dependencies = [ [[package]] name = "miow" version = "0.3.1" -source = "git+https://gitlab.redox-os.org/redox-os/miow?rev=5b10500#5b10500df2c560245d532e77c54a8b8b2d15cfd5" +source = "git+https://gitlab.redox-os.org/redox-os/miow#a55870b7f2b24155931125acc1d9ecedf25b7b0e" dependencies = [ - "socket2 0.3.7 (git+https://github.com/redox-os/socket2-rs)", + "socket2 0.3.7 (git+https://gitlab.redox-os.org/redox-os/socket2-rs)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -394,17 +394,17 @@ name = "num" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.38" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -412,13 +412,13 @@ name = "num-iter" version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -685,7 +685,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "socket2" version = "0.3.7" -source = "git+https://github.com/redox-os/socket2-rs#3543915f09e41f6e010d4d9e2d5217b27faf5e70" +source = "git+https://gitlab.redox-os.org/redox-os/socket2-rs#3543915f09e41f6e010d4d9e2d5217b27faf5e70" dependencies = [ "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1018,7 +1018,7 @@ dependencies = [ "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" -"checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37" +"checksum httparse 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23801d98b42eed0318e5709b0527894ba7c3793d0236814618d6a9b6224152ff" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04535774f79684c99528944ebdb89756c945c027e55ce52faa245879d836c8fb" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" @@ -1036,15 +1036,15 @@ dependencies = [ "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" -"checksum miow 0.3.1 (git+https://gitlab.redox-os.org/redox-os/miow?rev=5b10500)" = "" +"checksum miow 0.3.1 (git+https://gitlab.redox-os.org/redox-os/miow)" = "" "checksum net2 0.2.32 (git+https://gitlab.redox-os.org/redox-os/net2-rs)" = "" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)" = "" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -"checksum num-integer 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "6ac0ea58d64a89d9d6b7688031b3be9358d6c919badcf7fbb0527ccfd891ee45" +"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" -"checksum num-traits 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775393e285254d2f5004596d69bb8bc1149754570dcc08cf30cabeba67955e28" +"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum orbclient 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "539086aa68e65febd8e76f8b6ed244f9671063ee85f0b67bc96c4b69f07f81bc" "checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" @@ -1071,7 +1071,7 @@ dependencies = [ "checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95" "checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" -"checksum socket2 0.3.7 (git+https://github.com/redox-os/socket2-rs)" = "" +"checksum socket2 0.3.7 (git+https://gitlab.redox-os.org/redox-os/socket2-rs)" = "" "checksum spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14db77c5b914df6d6173dda9a3b3f5937bd802934fa5edaf934df06a3491e56f" "checksum stb_truetype 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52ce2b38abdd11cffbc68928810248e0dd003fea489a88a404dc1ba7ae2d5538" "checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d" From 9d923a9794382c43a6ae2ed674151e7985fa2cfc Mon Sep 17 00:00:00 2001 From: Paul Sajna Date: Thu, 5 Jul 2018 13:51:51 -0700 Subject: [PATCH 0243/1301] cargo update --- Cargo.lock | 129 +++++++++++++++++++++++++++-------------------------- 1 file changed, 65 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cff3e77d0d..849c95c588 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,7 +79,7 @@ dependencies = [ [[package]] name = "cfg-if" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -106,7 +106,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -120,7 +120,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -132,7 +132,7 @@ name = "crossbeam-utils" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -140,7 +140,7 @@ name = "crossbeam-utils" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -184,7 +184,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "httparse" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -193,7 +193,7 @@ version = "0.10.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -288,15 +288,15 @@ name = "log" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -319,37 +319,40 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.14" -source = "git+https://gitlab.redox-os.org/redox-os/mio#529f2e8c58a5b7fe38f7f8d698d7f2e95adb8e01" +version = "0.6.15" +source = "git+https://gitlab.redox-os.org/redox-os/mio#94485d62a91ac728f9ffc358319aeb8e15becab0" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.1 (git+https://gitlab.redox-os.org/redox-os/miow)", - "net2 0.2.32 (git+https://gitlab.redox-os.org/redox-os/net2-rs)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "miow" -version = "0.3.1" -source = "git+https://gitlab.redox-os.org/redox-os/miow#a55870b7f2b24155931125acc1d9ecedf25b7b0e" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "socket2 0.3.7 (git+https://gitlab.redox-os.org/redox-os/socket2-rs)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "net2" -version = "0.2.32" -source = "git+https://gitlab.redox-os.org/redox-os/net2-rs#0eae9193ba04270a4ded81c0d3c76d918c3bbcc6" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -364,7 +367,7 @@ dependencies = [ "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)", + "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.1 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", @@ -468,8 +471,8 @@ dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -659,22 +662,22 @@ name = "sdl2-sys" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.66" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -682,17 +685,6 @@ name = "slab" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "socket2" -version = "0.3.7" -source = "git+https://gitlab.redox-os.org/redox-os/socket2-rs#3543915f09e41f6e010d4d9e2d5217b27faf5e70" -dependencies = [ - "cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "spin" version = "0.4.8" @@ -708,7 +700,7 @@ dependencies = [ [[package]] name = "syn" -version = "0.14.2" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -742,7 +734,7 @@ version = "0.1.6" source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)", + "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-fs 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -778,7 +770,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56 dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -787,8 +779,8 @@ version = "0.1.1" source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -802,7 +794,7 @@ dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)", + "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -814,7 +806,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56 dependencies = [ "crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -836,8 +828,8 @@ source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56 dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -847,7 +839,7 @@ name = "toml" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -865,7 +857,7 @@ name = "unicase" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -917,7 +909,7 @@ dependencies = [ [[package]] name = "version_check" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -986,6 +978,15 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "xhcid" version = "0.1.0" @@ -1006,7 +1007,7 @@ dependencies = [ "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" "checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff" -"checksum cfg-if 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "405216fd8fe65f718daa7102ea808a946b6ce40c742998fbfd3463645552de18" +"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" @@ -1018,7 +1019,7 @@ dependencies = [ "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" -"checksum httparse 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23801d98b42eed0318e5709b0527894ba7c3793d0236814618d6a9b6224152ff" +"checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04535774f79684c99528944ebdb89756c945c027e55ce52faa245879d836c8fb" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" @@ -1031,13 +1032,13 @@ dependencies = [ "checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fddaa003a65722a7fb9e26b0ce95921fe4ba590542ced664d8ce2fa26f9f3ac" +"checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -"checksum mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" -"checksum miow 0.3.1 (git+https://gitlab.redox-os.org/redox-os/miow)" = "" -"checksum net2 0.2.32 (git+https://gitlab.redox-os.org/redox-os/net2-rs)" = "" +"checksum mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" +"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)" = "" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" @@ -1068,13 +1069,12 @@ dependencies = [ "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60" "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" -"checksum serde 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "e9a2d9a9ac5120e0f768801ca2b58ad6eec929dc9d1d616c162f208869c2ce95" -"checksum serde_derive 1.0.66 (registry+https://github.com/rust-lang/crates.io-index)" = "0a90213fa7e0f5eac3f7afe2d5ff6b088af515052cc7303bd68c7e3b91a3fb79" +"checksum serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)" = "210e5a3b159c566d7527e9b22e44be73f2e0fcc330bb78fef4dbccb56d2e74c8" +"checksum serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)" = "dd724d68017ae3a7e63600ee4b2fdb3cad2158ffd1821d44aff4580f63e2b593" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" -"checksum socket2 0.3.7 (git+https://gitlab.redox-os.org/redox-os/socket2-rs)" = "" "checksum spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14db77c5b914df6d6173dda9a3b3f5937bd802934fa5edaf934df06a3491e56f" "checksum stb_truetype 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52ce2b38abdd11cffbc68928810248e0dd003fea489a88a404dc1ba7ae2d5538" -"checksum syn 0.14.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c67da57e61ebc7b7b6fff56bb34440ca3a83db037320b0507af4c10368deda7d" +"checksum syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2beff8ebc3658f07512a413866875adddd20f4fd47b2a4e6c9da65cd281baaea" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" "checksum tokio 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" @@ -1096,7 +1096,7 @@ dependencies = [ "checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" "checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" "checksum utf8parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a15ea87f3194a3a454c78d79082b4f5e85f6956ddb6cb86bbfbe4892aa3c0323" -"checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" +"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" "checksum vte 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a01634c75db59478405de08d8567c40c578bba80c565217ee709934b551720d8" "checksum webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e499345fc4c6b7c79a5b8756d4592c4305510a13512e79efafe00dfbd67bbac6" "checksum webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb3f50499f21ad2317f442845e3b5805b007f1e728f59885c99e61b8c181a7" @@ -1105,3 +1105,4 @@ dependencies = [ "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" From 1616f6399a17794b82b38de30bb96ae44015039f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 12 Jul 2018 07:09:59 -0600 Subject: [PATCH 0244/1301] Update Cargo.lock --- Cargo.lock | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 849c95c588..d23ba2f51c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -174,7 +174,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -202,7 +202,7 @@ dependencies = [ "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -217,7 +217,7 @@ dependencies = [ [[package]] name = "idna" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -320,7 +320,7 @@ dependencies = [ [[package]] name = "mio" version = "0.6.15" -source = "git+https://gitlab.redox-os.org/redox-os/mio#94485d62a91ac728f9ffc358319aeb8e15becab0" +source = "git+https://gitlab.redox-os.org/redox-os/mio#58cc19074dad2380e474917656bc14b0d63657d3" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -471,8 +471,8 @@ dependencies = [ "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -667,12 +667,12 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.69" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -733,7 +733,7 @@ name = "tokio" version = "0.1.6" source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-fs 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -750,7 +750,7 @@ name = "tokio-executor" version = "0.1.2" source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -758,7 +758,7 @@ name = "tokio-fs" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -769,7 +769,7 @@ version = "0.1.6" source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -778,7 +778,7 @@ name = "tokio-reactor" version = "0.1.1" source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -792,7 +792,7 @@ version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -805,7 +805,7 @@ version = "0.1.3" source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -817,7 +817,7 @@ name = "tokio-timer" version = "0.2.3" source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -827,7 +827,7 @@ version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -839,7 +839,7 @@ name = "toml" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -885,10 +885,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "url" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1017,12 +1017,12 @@ dependencies = [ "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" +"checksum futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "80599c995ed197a276e27c27f94a6346446538adde3b87c1ab384f6f8cabfed4" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" "checksum hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04535774f79684c99528944ebdb89756c945c027e55ce52faa245879d836c8fb" -"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" @@ -1069,8 +1069,8 @@ dependencies = [ "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60" "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" -"checksum serde 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)" = "210e5a3b159c566d7527e9b22e44be73f2e0fcc330bb78fef4dbccb56d2e74c8" -"checksum serde_derive 1.0.69 (registry+https://github.com/rust-lang/crates.io-index)" = "dd724d68017ae3a7e63600ee4b2fdb3cad2158ffd1821d44aff4580f63e2b593" +"checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920" +"checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124" "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" "checksum spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14db77c5b914df6d6173dda9a3b3f5937bd802934fa5edaf934df06a3491e56f" "checksum stb_truetype 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52ce2b38abdd11cffbc68928810248e0dd003fea489a88a404dc1ba7ae2d5538" @@ -1094,7 +1094,7 @@ dependencies = [ "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" -"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" +"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" "checksum utf8parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a15ea87f3194a3a454c78d79082b4f5e85f6956ddb6cb86bbfbe4892aa3c0323" "checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" "checksum vte 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a01634c75db59478405de08d8567c40c578bba80c565217ee709934b551720d8" From cc2a5ff01d42be53cc1cfc638758c3d02e26a12a Mon Sep 17 00:00:00 2001 From: Robin Randhawa Date: Wed, 25 Jul 2018 18:02:27 +0100 Subject: [PATCH 0245/1301] Update Cargo.lock A 'precise' cargo update of tokio is needed for builds to succeed. --- Cargo.lock | 260 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 154 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d23ba2f51c..449e38b706 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,7 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -70,7 +70,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -82,6 +82,14 @@ name = "cfg-if" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.2.0" @@ -93,11 +101,11 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.3.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -108,7 +116,7 @@ dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -116,13 +124,13 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.4.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -137,11 +145,8 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "e1000d" @@ -174,7 +179,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -220,7 +225,7 @@ name = "idna" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -265,12 +270,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazycell" -version = "0.6.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -301,7 +306,7 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -320,13 +325,13 @@ dependencies = [ [[package]] name = "mio" version = "0.6.15" -source = "git+https://gitlab.redox-os.org/redox-os/mio#58cc19074dad2380e474917656bc14b0d63657d3" +source = "git+https://gitlab.redox-os.org/redox-os/mio#cc0fc26c55b0005da1c275dc4a0115420ecfb14c" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -374,8 +379,8 @@ dependencies = [ "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] @@ -443,7 +448,7 @@ dependencies = [ [[package]] name = "orbclient" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -455,7 +460,7 @@ dependencies = [ [[package]] name = "pbr" version = "1.0.1" -source = "git+https://github.com/a8m/pb#bff135f7eed7931a1103e593c74160d28fdd2314" +source = "git+https://github.com/a8m/pb#e0ab10be58c79d58dcdda9b79a82d28c54b3b4e3" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -488,7 +493,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.6" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -499,17 +504,17 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -532,6 +537,23 @@ dependencies = [ "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ransid" version = "0.4.6" @@ -545,7 +567,7 @@ name = "rayon" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -553,19 +575,18 @@ name = "rayon" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -675,9 +696,9 @@ name = "serde_derive" version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -700,11 +721,11 @@ dependencies = [ [[package]] name = "syn" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -730,108 +751,130 @@ dependencies = [ [[package]] name = "tokio" -version = "0.1.6" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" +version = "0.1.7" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" dependencies = [ - "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", + "tokio-current-thread 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-fs 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-fs 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-tcp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-timer 0.2.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-udp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-threadpool 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-timer 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-udp 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-codec" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +dependencies = [ + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +dependencies = [ + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-executor" version = "0.1.2" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" dependencies = [ - "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-fs" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" +version = "0.1.2" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" dependencies = [ - "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-threadpool 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-io" -version = "0.1.6" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" +version = "0.1.7" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" dependencies = [ - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-reactor" -version = "0.1.1" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" +version = "0.1.2" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" dependencies = [ - "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-tcp" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" dependencies = [ - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", - "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-threadpool" -version = "0.1.3" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" +version = "0.1.5" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" dependencies = [ - "crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-timer" -version = "0.2.3" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" +version = "0.2.4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" dependencies = [ - "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-udp" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#4db6ce75b5059c42cbbad56d7c441da19fe18c1a" +version = "0.1.1" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" dependencies = [ - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", - "tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-codec 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] @@ -865,7 +908,7 @@ name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -889,7 +932,7 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -902,7 +945,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -916,7 +959,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1006,18 +1049,19 @@ dependencies = [ "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" -"checksum bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7dd32989a66957d3f0cba6588f15d4281a733f4e9ffc43fcd2385f57d3bf99ff" +"checksum bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e178b8e0e239e844b083d5a0d4a156b2654e67f9f80144d48398fcd736a24fb8" "checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-deque 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe8153ef04a7594ded05b427ffad46ddeaf22e63fd48d42b3e1e3bb4db07cae7" +"checksum crossbeam-deque 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce1357a7a2ad69ff9f090ee8641b5b94c622138bb2c3eae16ad7917a8e35a801" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-epoch 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2af0e75710d6181e234c8ecc79f14a97907850a541b13b0be1dd10992f2e4620" +"checksum crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "285987a59c4d91388e749850e3cb7b3a92299668528caaacd08005b8f238c0ea" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b" +"checksum crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ea52fab26a99d96cdff39d0ca75c9716125937f5dba2ab83923aaaf5928f684a" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "80599c995ed197a276e27c27f94a6346446538adde3b87c1ab384f6f8cabfed4" +"checksum futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "884dbe32a6ae4cd7da5c6db9b78114449df9953b8d490c9d7e1b51720b922c62" "checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" "checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" @@ -1027,13 +1071,13 @@ dependencies = [ "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" -"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" +"checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3" +"checksum lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d33a48d0365c96081958cc663eef834975cb1e8d8bea3378513fc72bdbf11e50" "checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2" -"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" +"checksum matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "835511bab37c34c47da5cb44844bea2cfde0236db0b506f90ea4224482c9774a" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" @@ -1047,18 +1091,20 @@ dependencies = [ "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum orbclient 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "539086aa68e65febd8e76f8b6ed244f9671063ee85f0b67bc96c4b69f07f81bc" +"checksum orbclient 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "09b950dc49039b2ae191344ccac56de00887e62af3ac71d6346536d1d9695ff8" "checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro2 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "effdb53b25cdad54f8f48843d67398f7ef2e14f12c1b4cb4effc549a6462a4d6" -"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" +"checksum proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "cccdc7557a98fe98453030f077df7f3a042052fae465bb61d2c2c41435cfd9b6" +"checksum quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b71f9f575d55555aa9c06188be9d4e2bfc83ed02537948ac0d520c24d0419f1a" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" +"checksum rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "12397506224b2f93e6664ffc4f664b29be8208e5157d3d90b44f09b5fae470ea" +"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" "checksum ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc5fdcd7a4ca0bb24bf033534e0c137045538c84b0924af1c950d3ae41a2f71" "checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" "checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" -"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" +"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" @@ -1074,18 +1120,20 @@ dependencies = [ "checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" "checksum spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14db77c5b914df6d6173dda9a3b3f5937bd802934fa5edaf934df06a3491e56f" "checksum stb_truetype 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52ce2b38abdd11cffbc68928810248e0dd003fea489a88a404dc1ba7ae2d5538" -"checksum syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2beff8ebc3658f07512a413866875adddd20f4fd47b2a4e6c9da65cd281baaea" +"checksum syn 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4bad7abdf6633f07c7046b90484f1d9dc055eca39f8c991177b1046ce61dba9a" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum tokio 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-codec 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-current-thread 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-fs 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-io 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-reactor 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-fs 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-reactor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-tcp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-threadpool 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-timer 0.2.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-udp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-threadpool 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-timer 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-udp 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" From 9f253fe92ed60901f56b53c395b6697351469d38 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sun, 26 Aug 2018 13:01:57 +0200 Subject: [PATCH 0246/1301] Update Cargo.lock --- Cargo.lock | 242 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 178 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 449e38b706..6d52c69da5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,11 +101,11 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -148,6 +148,11 @@ name = "crossbeam-utils" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "crossbeam-utils" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "e1000d" version = "0.1.0" @@ -288,6 +293,15 @@ name = "linked-hash-map" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lock_api" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.3.9" @@ -325,7 +339,7 @@ dependencies = [ [[package]] name = "mio" version = "0.6.15" -source = "git+https://gitlab.redox-os.org/redox-os/mio#cc0fc26c55b0005da1c275dc4a0115420ecfb14c" +source = "git+https://gitlab.redox-os.org/redox-os/mio#2092161d53366c07a064888ccb0d41d359383701" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -337,10 +351,20 @@ dependencies = [ "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mio-uds" +version = "0.6.6" +source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#2936ef82070ea0c4aa8a7360455b8c512d8c88c0" +dependencies = [ + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", +] + [[package]] name = "miow" version = "0.2.1" @@ -379,8 +403,8 @@ dependencies = [ "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] @@ -457,6 +481,34 @@ dependencies = [ "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "owning_ref" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pbr" version = "1.0.1" @@ -703,14 +755,27 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smallvec" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "spin" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "stable_deref_trait" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "stb_truetype" version = "0.2.2" @@ -751,63 +816,66 @@ dependencies = [ [[package]] name = "tokio" -version = "0.1.7" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +version = "0.1.8" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", - "tokio-current-thread 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-fs 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-tcp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-threadpool 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-timer 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-udp 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-codec 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-current-thread 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-fs 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-tcp 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-threadpool 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-timer 0.2.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-udp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-uds 0.2.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-codec" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-current-thread" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +version = "0.1.1" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-executor" -version = "0.1.2" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +version = "0.1.4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-fs" -version = "0.1.2" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +version = "0.1.3" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-threadpool 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-threadpool 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-io" -version = "0.1.7" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +version = "0.1.8" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", @@ -816,65 +884,87 @@ dependencies = [ [[package]] name = "tokio-reactor" -version = "0.1.2" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +version = "0.1.4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", - "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-tcp" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +version = "0.1.1" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", - "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-threadpool" -version = "0.1.5" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +version = "0.1.6" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ - "crossbeam-deque 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-timer" -version = "0.2.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +version = "0.2.6" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-udp" -version = "0.1.1" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#12c80a60c2ac2f7c3ff62d0fd2dc98f99c91b378" +version = "0.1.2" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-codec 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-uds" +version = "0.2.1" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +dependencies = [ + "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", + "mio-uds 0.6.6 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", + "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] @@ -921,6 +1011,14 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "untrusted" version = "0.5.1" @@ -965,6 +1063,11 @@ dependencies = [ "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vte" version = "0.3.2" @@ -1053,11 +1156,12 @@ dependencies = [ "checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-deque 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce1357a7a2ad69ff9f090ee8641b5b94c622138bb2c3eae16ad7917a8e35a801" +"checksum crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3486aefc4c0487b9cb52372c97df0a48b8c249514af1ee99703bf70d2f2ceda1" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" "checksum crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "285987a59c4d91388e749850e3cb7b3a92299668528caaacd08005b8f238c0ea" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" "checksum crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ea52fab26a99d96cdff39d0ca75c9716125937f5dba2ab83923aaaf5928f684a" +"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" @@ -1075,12 +1179,14 @@ dependencies = [ "checksum lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d33a48d0365c96081958cc663eef834975cb1e8d8bea3378513fc72bdbf11e50" "checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" +"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2" "checksum matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "835511bab37c34c47da5cb44844bea2cfde0236db0b506f90ea4224482c9774a" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" +"checksum mio-uds 0.6.6 (git+https://gitlab.redox-os.org/redox-os/mio-uds)" = "" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)" = "" @@ -1092,6 +1198,9 @@ dependencies = [ "checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum orbclient 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "09b950dc49039b2ae191344ccac56de00887e62af3ac71d6346536d1d9695ff8" +"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" +"checksum parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69376b761943787ebd5cc85a5bc95958651a22609c5c1c2b65de21786baec72b" +"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" "checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" @@ -1117,23 +1226,26 @@ dependencies = [ "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" "checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920" "checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124" -"checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" +"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" +"checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d" "checksum spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14db77c5b914df6d6173dda9a3b3f5937bd802934fa5edaf934df06a3491e56f" +"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52ce2b38abdd11cffbc68928810248e0dd003fea489a88a404dc1ba7ae2d5538" "checksum syn 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4bad7abdf6633f07c7046b90484f1d9dc055eca39f8c991177b1046ce61dba9a" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum tokio 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-codec 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-current-thread 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-executor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-fs 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-io 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-reactor 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-tcp 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-threadpool 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-timer 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-udp 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-current-thread 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-fs 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-tcp 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-threadpool 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-timer 0.2.6 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-udp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-uds 0.2.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" @@ -1141,10 +1253,12 @@ dependencies = [ "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" "checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" "checksum utf8parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a15ea87f3194a3a454c78d79082b4f5e85f6956ddb6cb86bbfbe4892aa3c0323" "checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" +"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum vte 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a01634c75db59478405de08d8567c40c578bba80c565217ee709934b551720d8" "checksum webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e499345fc4c6b7c79a5b8756d4592c4305510a13512e79efafe00dfbd67bbac6" "checksum webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb3f50499f21ad2317f442845e3b5805b007f1e728f59885c99e61b8c181a7" From 795b86db13bee303c8c79e5fcb2ec385b5ab6d30 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Sep 2018 09:45:31 -0600 Subject: [PATCH 0247/1301] Disable ihdad --- filesystem.toml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/filesystem.toml b/filesystem.toml index 7405c0736e..37eb15c829 100644 --- a/filesystem.toml +++ b/filesystem.toml @@ -29,12 +29,12 @@ vendor = 32902 device = 5379 command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] -#ihdad -[[drivers]] -name = "Intel HD Audio" -class = 4 -subclass = 3 -command = ["ihdad", "$NAME", "$BAR0", "$IRQ", "$VENID", "$DEVID"] +# ihdad +# [[drivers]] +# name = "Intel HD Audio" +# class = 4 +# subclass = 3 +# command = ["ihdad", "$NAME", "$BAR0", "$IRQ", "$VENID", "$DEVID"] # rtl8168d [[drivers]] From f1d3aa6480568440fc4ef66fc7faf23e1b5bf611 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 14 Oct 2018 19:56:24 -0600 Subject: [PATCH 0248/1301] Update Cargo.lock --- Cargo.lock | 493 +++++++++++++++++++++++++++++------------------------ 1 file changed, 270 insertions(+), 223 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6d52c69da5..7b50243b4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,9 +3,9 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -36,15 +36,24 @@ name = "base64" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -55,7 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -65,21 +74,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.2.3" +version = "1.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cc" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -87,7 +101,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -104,7 +118,7 @@ name = "crossbeam-deque" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -114,9 +128,9 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -124,13 +138,13 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -140,14 +154,9 @@ name = "crossbeam-utils" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-utils" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "crossbeam-utils" version = "0.5.0" @@ -173,7 +182,7 @@ name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -184,17 +193,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "gcc" -version = "0.3.54" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "httparse" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -203,7 +207,7 @@ version = "0.10.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -217,12 +221,13 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", - "rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -230,7 +235,7 @@ name = "idna" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -242,7 +247,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -250,7 +255,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -275,17 +280,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.0.2" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "lazycell" -version = "1.0.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.42" +version = "0.2.43" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -295,7 +303,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lock_api" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -307,20 +315,20 @@ name = "log" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "matches" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -339,15 +347,15 @@ dependencies = [ [[package]] name = "mio" version = "0.6.15" -source = "git+https://gitlab.redox-os.org/redox-os/mio#2092161d53366c07a064888ccb0d41d359383701" +source = "git+https://gitlab.redox-os.org/redox-os/mio#8a4c08faee0483976bd345b6d88d2455e4c1a4db" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -361,7 +369,7 @@ version = "0.6.6" source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#2936ef82070ea0c4aa8a7360455b8c512d8c88c0" dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", ] @@ -381,21 +389,21 @@ name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#c728870d6a1d9d8938117798e6caab22b09c37a6" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#2dee37719bd1bf1fbe3d0fdd33e350d32dda1330" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.1 (git+https://github.com/a8m/pb)", @@ -428,7 +436,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -436,7 +444,7 @@ name = "num-integer" version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -445,12 +453,12 @@ version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -458,7 +466,7 @@ name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -467,12 +475,12 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "orbclient" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -491,31 +499,32 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot_core" -version = "0.2.14" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pbr" version = "1.0.1" -source = "git+https://github.com/a8m/pb#e0ab10be58c79d58dcdda9b79a82d28c54b3b4e3" +source = "git+https://github.com/a8m/pb#8774a4627dabfacb1d0c80f409232c4f82231119" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -525,12 +534,12 @@ dependencies = [ name = "pcid" version = "0.1.0" dependencies = [ - "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -545,7 +554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.9" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -556,17 +565,17 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.6.4" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -575,35 +584,43 @@ version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.2.1" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -611,15 +628,7 @@ name = "ransid" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "vte 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -636,8 +645,8 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -664,14 +673,13 @@ dependencies = [ [[package]] name = "ring" -version = "0.11.0" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -685,16 +693,24 @@ dependencies = [ ] [[package]] -name = "rustls" -version = "0.9.0" +name = "rustc_version" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustls" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -704,7 +720,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "stb_truetype 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "stb_truetype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -712,11 +728,25 @@ name = "safemem" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "safemem" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "sct" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sdl2" version = "0.31.0" @@ -724,7 +754,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -735,22 +765,35 @@ name = "sdl2-sys" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" -version = "1.0.70" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.70" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -768,7 +811,7 @@ dependencies = [ [[package]] name = "spin" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -778,19 +821,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "stb_truetype" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.14.5" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -799,7 +842,7 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -809,9 +852,9 @@ name = "time" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -819,8 +862,8 @@ name = "tokio" version = "0.1.8" source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ - "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-codec 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-current-thread 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -840,8 +883,8 @@ name = "tokio-codec" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ - "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -850,7 +893,7 @@ name = "tokio-current-thread" version = "0.1.1" source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -859,7 +902,7 @@ name = "tokio-executor" version = "0.1.4" source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -867,7 +910,7 @@ name = "tokio-fs" version = "0.1.3" source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-threadpool 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -877,9 +920,9 @@ name = "tokio-io" version = "0.1.8" source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ - "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -888,12 +931,12 @@ version = "0.1.4" source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -904,8 +947,8 @@ name = "tokio-tcp" version = "0.1.1" source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ - "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -919,10 +962,10 @@ source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f5946 dependencies = [ "crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -932,7 +975,7 @@ version = "0.2.6" source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -942,9 +985,9 @@ name = "tokio-udp" version = "0.1.2" source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ - "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-codec 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -956,11 +999,11 @@ name = "tokio-uds" version = "0.2.1" source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" dependencies = [ - "bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", "mio-uds 0.6.6 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -969,10 +1012,10 @@ dependencies = [ [[package]] name = "toml" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -990,7 +1033,7 @@ name = "unicase" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -998,7 +1041,7 @@ name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1021,7 +1064,7 @@ dependencies = [ [[package]] name = "untrusted" -version = "0.5.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1030,34 +1073,34 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "utf8parse" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "version_check" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1070,29 +1113,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vte" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "utf8parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "webpki" -version = "0.14.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "webpki-roots" -version = "0.11.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1102,7 +1144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1141,48 +1183,48 @@ dependencies = [ "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" "checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" +"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" -"checksum bytes 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e178b8e0e239e844b083d5a0d4a156b2654e67f9f80144d48398fcd736a24fb8" -"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e" +"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" +"checksum bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0ce55bd354b095246fc34caf4e9e242f5297a7fd938b090cadfea6eee614aa62" +"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" +"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3486aefc4c0487b9cb52372c97df0a48b8c249514af1ee99703bf70d2f2ceda1" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "285987a59c4d91388e749850e3cb7b3a92299668528caaacd08005b8f238c0ea" +"checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ea52fab26a99d96cdff39d0ca75c9716125937f5dba2ab83923aaaf5928f684a" "checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "884dbe32a6ae4cd7da5c6db9b78114449df9953b8d490c9d7e1b51720b922c62" -"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb" -"checksum httparse 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7b6288d7db100340ca12873fd4d08ad1b8f206a9457798dfb17c018a33fee540" +"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" +"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" -"checksum hyper-rustls 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04535774f79684c99528944ebdb89756c945c027e55ce52faa245879d836c8fb" +"checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3" -"checksum lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d33a48d0365c96081958cc663eef834975cb1e8d8bea3378513fc72bdbf11e50" -"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" +"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" +"checksum lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddba4c30a78328befecec92fc94970e53b3ae385827d28620f0f5bb2493081e0" +"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" -"checksum lock_api 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "949826a5ccf18c1b3a7c3d57692778d21768b79e46eb9dd07bfc4c2160036c54" +"checksum lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775751a3e69bde4df9b38dd00a1b5d6ac13791e4223d4a0506577f0dd27cfb7a" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2" -"checksum matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "835511bab37c34c47da5cb44844bea2cfde0236db0b506f90ea4224482c9774a" +"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f" +"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" @@ -1195,43 +1237,48 @@ dependencies = [ "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" -"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" +"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum orbclient 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "09b950dc49039b2ae191344ccac56de00887e62af3ac71d6346536d1d9695ff8" +"checksum orbclient 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "3abb51a8964ed904abb6bc7b77c1e468fea1ea390385ee52b0e38e3966c1002c" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum parking_lot 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "69376b761943787ebd5cc85a5bc95958651a22609c5c1c2b65de21786baec72b" -"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" +"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" +"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" "checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro2 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "cccdc7557a98fe98453030f077df7f3a042052fae465bb61d2c2c41435cfd9b6" -"checksum quote 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b71f9f575d55555aa9c06188be9d4e2bfc83ed02537948ac0d520c24d0419f1a" +"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee" +"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" -"checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" -"checksum rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "12397506224b2f93e6664ffc4f664b29be8208e5157d3d90b44f09b5fae470ea" -"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" +"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" +"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" +"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" +"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" "checksum ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc5fdcd7a4ca0bb24bf033534e0c137045538c84b0924af1c950d3ae41a2f71" -"checksum rayon 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a77c51c07654ddd93f6cb543c7a849863b03abc7e82591afda6dc8ad4ac3ac4a" "checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" "checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum ring 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2a6dc7fc06a05e6de183c5b97058582e9da2de0c136eafe49609769c507724" -"checksum rustls 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17727f4b991294da2c84d75a43c003151ff58072212768800f66c56ee46dca43" +"checksum ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe642b9dd1ba0038d78c4a3999d1ee56178b4d415c1e1fbaba83b06dce012f0" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b" "checksum rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30047cc747a78ae042bf2cd65c79f83c3485d90107535b532d6e8f60e2c89cb1" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" +"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" "checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60" "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" -"checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920" -"checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef" +"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" "checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d" -"checksum spin 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14db77c5b914df6d6173dda9a3b3f5937bd802934fa5edaf934df06a3491e56f" +"checksum spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "37b5646825922b96b5d7d676b5bb3458a54498e96ed7b0ce09dc43a07038fea4" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum stb_truetype 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52ce2b38abdd11cffbc68928810248e0dd003fea489a88a404dc1ba7ae2d5538" -"checksum syn 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "4bad7abdf6633f07c7046b90484f1d9dc055eca39f8c991177b1046ce61dba9a" +"checksum stb_truetype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "48fa7d3136d8645909de1f7c7eb5416cc43057a75ace08fc39ae736bc9da8af1" +"checksum syn 0.15.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b036b7b35e846707c0e55c2c9441fa47867c0f87fca416921db3261b1d8c741a" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" "checksum tokio 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" @@ -1246,7 +1293,7 @@ dependencies = [ "checksum tokio-timer 0.2.6 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-udp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-uds 0.2.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" +"checksum toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4a2ecc31b0351ea18b3fe11274b8db6e4d82bce861bbb22e6dbed40417902c65" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" @@ -1254,16 +1301,16 @@ dependencies = [ "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum untrusted 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f392d7819dbe58833e26872f5f6f0d68b7bbbe90fc3667e98731c4a15ad9a7ae" +"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" -"checksum utf8parse 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a15ea87f3194a3a454c78d79082b4f5e85f6956ddb6cb86bbfbe4892aa3c0323" -"checksum version_check 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7716c242968ee87e5542f8021178248f267f295a5c4803beae8b8b7fd9bc6051" +"checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum vte 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a01634c75db59478405de08d8567c40c578bba80c565217ee709934b551720d8" -"checksum webpki 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e499345fc4c6b7c79a5b8756d4592c4305510a13512e79efafe00dfbd67bbac6" -"checksum webpki-roots 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5bfb3f50499f21ad2317f442845e3b5805b007f1e728f59885c99e61b8c181a7" +"checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" +"checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" +"checksum webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85d1f408918fd590908a70d36b7ac388db2edc221470333e4d6e5b598e44cabf" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" From fe9338c94b206e272cb4df77635e710cb0e19024 Mon Sep 17 00:00:00 2001 From: Tibor Nagy Date: Sat, 15 Dec 2018 01:00:26 +0100 Subject: [PATCH 0249/1301] ihdad: Implement fpath Fixes the output of sys:/iostat. The correct implementation is TODO like most of the scheme related code in this driver. --- ihdad/src/HDA/device.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ihdad/src/HDA/device.rs b/ihdad/src/HDA/device.rs index 64774ea760..567933730a 100755 --- a/ihdad/src/HDA/device.rs +++ b/ihdad/src/HDA/device.rs @@ -992,7 +992,7 @@ impl SchemeMut for IntelHDA { // TODO: if uid == 0 { - Ok(flags) + Ok(0) } else { Err(Error::new(EACCES)) } @@ -1030,4 +1030,16 @@ impl SchemeMut for IntelHDA { handles.remove(&_id).ok_or(Error::new(EBADF)).and(Ok(0)) } + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + //let mut handles = self.handles.lock(); + //let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let mut i = 0; + let scheme_path = b"audio:"; + while i < buf.len() && i < scheme_path.len() { + buf[i] = scheme_path[i]; + i += 1; + } + Ok(i) + } } From fb9b68405c8aa66d4247d1525cc77dd8071629e4 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 24 Dec 2018 16:43:58 +0100 Subject: [PATCH 0250/1301] Bump Cargo.lock --- Cargo.lock | 651 +++++++++++++++++++++++++---------------------------- 1 file changed, 309 insertions(+), 342 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b50243b4c..c5b9eb8f01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,9 +3,9 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -15,7 +15,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -25,19 +25,10 @@ source = "git+https://gitlab.redox-os.org/redox-os/arg-parser.git#7503531821b0c1 [[package]] name = "arrayvec" -version = "0.4.7" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "base64" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -45,7 +36,7 @@ name = "base64" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -53,8 +44,8 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -74,26 +65,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.2.6" +version = "1.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.25" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -106,62 +97,34 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.2.0" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" -version = "0.3.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-utils" -version = "0.2.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-utils" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "e1000d" version = "0.1.0" @@ -169,7 +132,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -203,20 +166,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hyper" -version = "0.10.13" +version = "0.10.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -224,7 +187,7 @@ name = "hyper-rustls" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", "rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", "webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -246,8 +209,8 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -255,7 +218,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -280,20 +243,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lazycell" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.43" +version = "0.2.45" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -303,10 +258,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lock_api" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -315,15 +270,15 @@ name = "log" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -346,19 +301,18 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.15" -source = "git+https://gitlab.redox-os.org/redox-os/mio#8a4c08faee0483976bd345b6d88d2455e4c1a4db" +version = "0.6.16" +source = "git+https://gitlab.redox-os.org/redox-os/mio#493d2b65c12b269c4481fd1dc2cd7d3670a880c9" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -369,8 +323,8 @@ version = "0.6.6" source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#2936ef82070ea0c4aa8a7360455b8c512d8c88c0" dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", ] [[package]] @@ -389,35 +343,36 @@ name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#2dee37719bd1bf1fbe3d0fdd33e350d32dda1330" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#91dd30c5ffe5902ec40c8d08b2f9769b62da57b7" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.1 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nodrop" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -426,7 +381,7 @@ version = "0.0.1" source = "git+https://github.com/willem66745/ntpclient-rust#7e3bdf60eb940825789a8da5181025320e3050b0" dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -463,10 +418,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -474,24 +429,22 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "orbclient" -version = "0.3.17" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "owning_ref" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -499,35 +452,34 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.6.4" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot_core" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pbr" version = "1.0.1" -source = "git+https://github.com/a8m/pb#8774a4627dabfacb1d0c80f409232c4f82231119" +source = "git+https://github.com/a8m/pb#b9792c9fe37343234316e23c263874cf383b208d" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -535,11 +487,11 @@ name = "pcid" version = "0.1.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -554,7 +506,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.20" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -565,17 +517,17 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.6.8" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -584,7 +536,7 @@ version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -594,28 +546,35 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand_core" -version = "0.2.2" +name = "rand_chacha" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -623,44 +582,59 @@ name = "rand_core" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ransid" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rayon" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rayon-core" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "redox_event" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/event.git#c31e3d3d5f44d60ff9fec2b1ee58b982e72c0d77" dependencies = [ - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.40" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -668,17 +642,17 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ring" -version = "0.13.2" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -689,7 +663,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -706,8 +680,8 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", "sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -718,16 +692,11 @@ name = "rusttype" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "stb_truetype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "stb_truetype 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "safemem" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "safemem" version = "0.3.0" @@ -743,7 +712,7 @@ name = "sct" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -754,7 +723,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -765,7 +734,7 @@ name = "sdl2-sys" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -783,17 +752,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.80" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.80" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -803,7 +772,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -811,7 +780,7 @@ dependencies = [ [[package]] name = "spin" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -821,19 +790,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "stb_truetype" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.15.11" +version = "0.15.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -842,180 +811,182 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "time" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio" -version = "0.1.8" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.1.13" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", - "tokio-codec 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-current-thread 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-fs 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-tcp 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-threadpool 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-timer 0.2.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-udp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-uds 0.2.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-fs 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-tcp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-codec" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.1.1" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-current-thread" -version = "0.1.1" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.1.4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-executor" -version = "0.1.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.1.5" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-fs" -version = "0.1.3" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.1.4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-threadpool 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-io" -version = "0.1.8" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.1.10" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-reactor" -version = "0.1.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.1.7" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-tcp" -version = "0.1.1" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.1.2" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", - "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-threadpool" -version = "0.1.6" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.1.9" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ - "crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-timer" -version = "0.2.6" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.2.8" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ - "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-udp" -version = "0.1.2" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.1.3" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", - "tokio-codec 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-uds" -version = "0.2.1" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#1a12087013a68747f6f59460ea95bd597b898dab" +version = "0.2.4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ - "bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)", + "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "mio-uds 0.6.6 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", - "tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "toml" -version = "0.4.8" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1069,7 +1040,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "url" -version = "1.7.1" +version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1086,9 +1057,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1100,9 +1071,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", - "ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1124,7 +1095,7 @@ name = "webpki" version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1182,88 +1153,84 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" -"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum base64 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96434f987501f0ed4eb336a411e0631ecd1afa11574fe148587adc4ff96143c9" +"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "90492c5858dd7d2e78691cfb89f90d273a2800fc11d98f60786e5d87e2f83781" -"checksum bytes 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0ce55bd354b095246fc34caf4e9e242f5297a7fd938b090cadfea6eee614aa62" -"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16" -"checksum cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0c4e7bb64a8ebb0d856483e1e682ea3422f883c5f5615a90d51a2c82fe87fdd3" +"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" +"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" +"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" +"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" -"checksum crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3486aefc4c0487b9cb52372c97df0a48b8c249514af1ee99703bf70d2f2ceda1" -"checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" -"checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9" -"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" +"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" +"checksum crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f10a4f8f409aaac4b16a5474fb233624238fcdeefb9ba50d5ea059aab63ba31c" +"checksum crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" -"checksum hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)" = "368cb56b2740ebf4230520e2b90ebb0461e69034d85d1945febd9b3971426db2" +"checksum hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "df0caae6b71d266b91b4a83111a61d2b94ed2e2bea024c532b933dcff867e58c" "checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7" -"checksum lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddba4c30a78328befecec92fc94970e53b3ae385827d28620f0f5bb2493081e0" -"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" +"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" +"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" -"checksum lock_api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "775751a3e69bde4df9b38dd00a1b5d6ac13791e4223d4a0506577f0dd27cfb7a" +"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f" +"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -"checksum mio 0.6.15 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" +"checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" "checksum mio-uds 0.6.6 (git+https://gitlab.redox-os.org/redox-os/mio-uds)" = "" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)" = "" -"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum orbclient 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "3abb51a8964ed904abb6bc7b77c1e468fea1ea390385ee52b0e38e3966c1002c" -"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5" -"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c" +"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" +"checksum orbclient 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "0a35fa1b5d90c19bc174dd4b392e29e8eecf6cf794a7626d9b115b1f40237526" +"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" +"checksum parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9723236a9525c757d9725b993511e3fc941e33f27751942232f0058298297edf" +"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee" -"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" +"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" +"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" "checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" "checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" -"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c" -"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" +"checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" +"checksum rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771b009e3a508cb67e8823dda454aaa5368c7bc1c16829fb77d3e980440dd34a" "checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" -"checksum ransid 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8fc5fdcd7a4ca0bb24bf033534e0c137045538c84b0924af1c950d3ae41a2f71" -"checksum rayon 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b614fe08b6665cb9a231d07ac1364b0ef3cb3698f1239ee0c4c3a88a524f54c8" -"checksum rayon-core 1.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b055d1e92aba6877574d8fe604a63c8b5df60f60e5982bf7ccbb1338ea527356" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" +"checksum rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3" +"checksum ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e02b6e263e6d8ab6a7a7637268785506f26860f0c4be83d8d940014d2b3e1601" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" -"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" +"checksum redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a84bcd297b87a545980a2d25a0beb72a1f490c31f0a9fde52fca35bfbb1ceb70" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum ring 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe642b9dd1ba0038d78c4a3999d1ee56178b4d415c1e1fbaba83b06dce012f0" +"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b" "checksum rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30047cc747a78ae042bf2cd65c79f83c3485d90107535b532d6e8f60e2c89cb1" -"checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" @@ -1271,29 +1238,29 @@ dependencies = [ "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef" -"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c" +"checksum serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "6fa52f19aee12441d5ad11c9a00459122bd8f98707cadf9778c540674f1935b6" +"checksum serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "96a7f9496ac65a2db5929afa087b54f8fc5008dcfbe48a8874ed20049b0d6154" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" -"checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d" -"checksum spin 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "37b5646825922b96b5d7d676b5bb3458a54498e96ed7b0ce09dc43a07038fea4" +"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" +"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum stb_truetype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "48fa7d3136d8645909de1f7c7eb5416cc43057a75ace08fc39ae736bc9da8af1" -"checksum syn 0.15.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b036b7b35e846707c0e55c2c9441fa47867c0f87fca416921db3261b1d8c741a" +"checksum stb_truetype 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71a7d260b43b6129a22dc341be18a231044ca67a48b7e32625f380cc5ec9ad70" +"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" -"checksum tokio 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-codec 0.1.0 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-current-thread 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-executor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-fs 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-io 0.1.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-reactor 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-tcp 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-threadpool 0.1.6 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-timer 0.2.6 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-udp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-uds 0.2.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4a2ecc31b0351ea18b3fe11274b8db6e4d82bce861bbb22e6dbed40417902c65" +"checksum time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "847da467bf0db05882a9e2375934a8a55cffdc9db0d128af1518200260ba1f6c" +"checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-fs 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-tcp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" @@ -1302,7 +1269,7 @@ dependencies = [ "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" -"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" +"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" From c47c68f44cec4fe7f8fd94c542e68afbe81d75aa Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 28 Dec 2018 16:19:09 -0700 Subject: [PATCH 0251/1301] Update fmap support --- Cargo.lock | 70 ++++++++++++++++++++--------------------- ahcid/src/main.rs | 4 +-- alxd/src/main.rs | 4 +-- e1000d/src/main.rs | 4 +-- ihdad/src/HDA/device.rs | 6 ++-- ihdad/src/HDA/stream.rs | 4 +-- ihdad/src/main.rs | 4 +-- nvmed/src/main.rs | 4 +-- rtl8168d/src/main.rs | 4 +-- vboxd/src/main.rs | 4 +-- vesad/src/main.rs | 4 +-- vesad/src/scheme.rs | 6 ++-- xhcid/src/main.rs | 2 +- 13 files changed, 60 insertions(+), 60 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c5b9eb8f01..73ebdf2aa3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,7 +4,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -15,7 +15,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -44,8 +44,8 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -132,7 +132,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -209,7 +209,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -312,7 +312,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -351,7 +351,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#91dd30c5ffe5902ec40c8d08b2f9769b62da57b7" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#03d76ff3b5c4a42e300e3016f42fd632193bbc9d" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", @@ -362,7 +362,7 @@ dependencies = [ "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.1 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -429,16 +429,16 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "orbclient" -version = "0.3.19" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -488,9 +488,9 @@ version = "0.1.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.83 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.83 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -517,9 +517,9 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -629,12 +629,12 @@ name = "redox_event" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/event.git#c31e3d3d5f44d60ff9fec2b1ee58b982e72c0d77" dependencies = [ - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -642,7 +642,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -663,7 +663,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -752,12 +752,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.82" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -812,7 +812,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -822,7 +822,7 @@ version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -986,7 +986,7 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.83 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1057,9 +1057,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1071,9 +1071,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1153,7 +1153,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1205,7 +1205,7 @@ dependencies = [ "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" -"checksum orbclient 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "0a35fa1b5d90c19bc174dd4b392e29e8eecf6cf794a7626d9b115b1f40237526" +"checksum orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e9209ac5081710688c453af03a9e92b3d4e1e445cd4c60052692758e08e47c5e" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9723236a9525c757d9725b993511e3fc941e33f27751942232f0058298297edf" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" @@ -1225,7 +1225,7 @@ dependencies = [ "checksum rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3" "checksum ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e02b6e263e6d8ab6a7a7637268785506f26860f0c4be83d8d940014d2b3e1601" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" -"checksum redox_syscall 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "a84bcd297b87a545980a2d25a0beb72a1f490c31f0a9fde52fca35bfbb1ceb70" +"checksum redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)" = "7b7aac97a11cf928b13c97f726b1bfe8542969fcbc39007ce566a888da5964a3" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -1238,8 +1238,8 @@ dependencies = [ "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "6fa52f19aee12441d5ad11c9a00459122bd8f98707cadf9778c540674f1935b6" -"checksum serde_derive 1.0.82 (registry+https://github.com/rust-lang/crates.io-index)" = "96a7f9496ac65a2db5929afa087b54f8fc5008dcfbe48a8874ed20049b0d6154" +"checksum serde 1.0.83 (registry+https://github.com/rust-lang/crates.io-index)" = "157e12af46859e968da75dea9845530e13d03bcab2009a41b9b7bb3cf4eb3ec2" +"checksum serde_derive 1.0.83 (registry+https://github.com/rust-lang/crates.io-index)" = "9469829702497daf2daf3c190e130c3fa72f719920f73c86160d43e8f8d76951" "checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" "checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 1ceaad116c..916c72569a 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -9,7 +9,7 @@ use std::{env, usize}; use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::FromRawFd; -use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme}; +use syscall::{EVENT_READ, PHYSMAP_WRITE, Event, Packet, Scheme}; use scheme::DiskScheme; @@ -32,7 +32,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 4096, PHYSMAP_WRITE).expect("ahcid: failed to map address") }; { let scheme_name = format!("disk/{}", name); let socket_fd = syscall::open( diff --git a/alxd/src/main.rs b/alxd/src/main.rs index 196eff7280..828e24e48a 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -16,7 +16,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, SchemeMut, MAP_WRITE}; +use syscall::{Packet, SchemeMut, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -43,7 +43,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("alxd: failed to open IRQ file"); - let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("alxd: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 128*1024, PHYSMAP_WRITE).expect("alxd: failed to map address") }; { let device = Arc::new(RefCell::new(unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") })); diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 41e8e4d198..96c8eff59e 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -12,7 +12,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, SchemeMut, MAP_WRITE}; +use syscall::{Packet, SchemeMut, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -38,7 +38,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); - let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 128*1024, PHYSMAP_WRITE).expect("e1000d: failed to map address") }; { let device = Arc::new(RefCell::new(unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") })); diff --git a/ihdad/src/HDA/device.rs b/ihdad/src/HDA/device.rs index 567933730a..f17c79f08c 100755 --- a/ihdad/src/HDA/device.rs +++ b/ihdad/src/HDA/device.rs @@ -14,7 +14,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; extern crate syscall; -use syscall::MAP_WRITE; +use syscall::PHYSMAP_WRITE; use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::io::{Mmio, Io}; @@ -184,7 +184,7 @@ impl IntelHDA { let buff_desc_virt = unsafe { - syscall::physmap(buff_desc_phys, 0x1000, MAP_WRITE) + syscall::physmap(buff_desc_phys, 0x1000, PHYSMAP_WRITE) .expect("ihdad: failed to map address for buffer descriptor list.") }; @@ -201,7 +201,7 @@ impl IntelHDA { }; - let cmd_buff_virt = unsafe { syscall::physmap(cmd_buff_address, 0x1000, MAP_WRITE).expect("ihdad: failed to map address for CORB/RIRB buff") }; + let cmd_buff_virt = unsafe { syscall::physmap(cmd_buff_address, 0x1000, PHYSMAP_WRITE).expect("ihdad: failed to map address for CORB/RIRB buff") }; print!("Virt: {:016X}, Phys: {:016X}\n", cmd_buff_virt, cmd_buff_address); let mut module = IntelHDA { diff --git a/ihdad/src/HDA/stream.rs b/ihdad/src/HDA/stream.rs index fb8f1cd75e..b905f8d24c 100644 --- a/ihdad/src/HDA/stream.rs +++ b/ihdad/src/HDA/stream.rs @@ -1,7 +1,7 @@ -use syscall::MAP_WRITE; +use syscall::PHYSMAP_WRITE; use syscall::error::{Error, EACCES, EWOULDBLOCK, EIO, Result}; use syscall::flag::O_NONBLOCK; use syscall::io::{Dma, Mmio, Io, ReadOnly}; @@ -310,7 +310,7 @@ impl StreamBuffer { }; let addr = match unsafe { - syscall::physmap(phys, block_length * block_count, MAP_WRITE) + syscall::physmap(phys, block_length * block_count, PHYSMAP_WRITE) } { Ok(addr) => addr, Err(err) => { diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 027a592ff8..87374bb66a 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -10,7 +10,7 @@ use std::{env, usize, u16, thread}; use std::fs::File; use std::io::{Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme, SchemeMut}; +use syscall::{EVENT_READ, PHYSMAP_WRITE, Event, Packet, Scheme, SchemeMut}; use std::cell::RefCell; use std::sync::Arc; @@ -52,7 +52,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 0x4000, MAP_WRITE).expect("ihdad: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 0x4000, PHYSMAP_WRITE).expect("ihdad: failed to map address") }; { let mut irq_file = File::open(format!("irq:{}", irq)).expect("IHDA: failed to open IRQ file"); diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 531fc74c9d..9aea3c3501 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -9,7 +9,7 @@ use std::{env, usize}; use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Result, Scheme}; +use syscall::{EVENT_READ, PHYSMAP_WRITE, Event, Packet, Result, Scheme}; use self::nvme::Nvme; @@ -42,7 +42,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("nvmed: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 4096, PHYSMAP_WRITE).expect("nvmed: failed to map address") }; { let mut nvme = Nvme::new(address); nvme.init(); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 460da0ac57..39433a8531 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -12,7 +12,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, SchemeMut, MAP_WRITE}; +use syscall::{Packet, SchemeMut, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -38,7 +38,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open IRQ file"); - let address = unsafe { syscall::physmap(bar, 256, MAP_WRITE).expect("rtl8168d: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 256, PHYSMAP_WRITE).expect("rtl8168d: failed to map address") }; { let device = Arc::new(RefCell::new(unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") })); diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 6b8d181b68..90ca4aa105 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -9,7 +9,7 @@ use std::{env, mem}; use std::os::unix::io::AsRawFd; use std::fs::File; use std::io::{Result, Read, Write}; -use syscall::flag::MAP_WRITE; +use syscall::flag::PHYSMAP_WRITE; use syscall::io::{Dma, Io, Mmio, Pio}; use syscall::iopl; @@ -217,7 +217,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("vboxd: failed to open IRQ file"); let mut port = Pio::::new(bar0 as u16); - let address = unsafe { syscall::physmap(bar1, 4096, MAP_WRITE).expect("vboxd: failed to map address") }; + let address = unsafe { syscall::physmap(bar1, 4096, PHYSMAP_WRITE).expect("vboxd: failed to map address") }; { let vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 008417fc6e..b5ec9cd7b8 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -8,7 +8,7 @@ extern crate syscall; use std::env; use std::fs::File; use std::io::{Read, Write}; -use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, MAP_WRITE, MAP_WRITE_COMBINE}; +use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE}; use mode_info::VBEModeInfo; use primitive::fast_set64; @@ -55,7 +55,7 @@ fn main() { let size = width * height; //TODO: Remap on resize let largest_size = 8 * 1024 * 1024; - let onscreen = unsafe { physmap(physbaseptr, largest_size * 4, MAP_WRITE | MAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; + let onscreen = unsafe { physmap(physbaseptr, largest_size * 4, PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; unsafe { fast_set64(onscreen as *mut u64, 0, size/2) }; let mut scheme = DisplayScheme::new(width, height, onscreen, &spec); diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index c43f2b5b4c..23902152b7 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::{mem, slice, str}; use orbclient::{Event, EventOption}; -use syscall::{Result, Error, EACCES, EBADF, EINVAL, ENOENT, O_NONBLOCK, SchemeMut}; +use syscall::{Result, Error, EACCES, EBADF, EINVAL, ENOENT, O_NONBLOCK, Map, SchemeMut}; use display::Display; use screen::{Screen, GraphicScreen, TextScreen}; @@ -145,12 +145,12 @@ impl SchemeMut for DisplayScheme { } } - fn fmap(&mut self, id: usize, offset: usize, size: usize) -> Result { + fn fmap(&mut self, id: usize, map: &Map) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(screen_i) = handle.kind { if let Some(screen) = self.screens.get(&screen_i) { - return screen.map(offset, size); + return screen.map(map.offset, map.size); } } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 5616583908..2974555369 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -41,7 +41,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); - let address = unsafe { syscall::physmap(bar, 65536, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 65536, syscall::PHYSMAP_WRITE).expect("xhcid: failed to map address") }; { let hci = Arc::new(RefCell::new(Xhci::new(address).expect("xhcid: failed to allocate device"))); From 939b294eaef3a644b2ca093b7fbf27f8a78a4b8d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 29 Dec 2018 12:21:12 -0700 Subject: [PATCH 0252/1301] ihdad: cleanup, fix blocking code, decrease buffer size to decrease latency --- ihdad/src/HDA/cmdbuff.rs | 469 ------------------------------- ihdad/src/HDA/common.rs | 193 ------------- ihdad/src/hda/cmdbuff.rs | 430 ++++++++++++++++++++++++++++ ihdad/src/hda/common.rs | 195 +++++++++++++ ihdad/src/{HDA => hda}/device.rs | 393 ++++++++++---------------- ihdad/src/{HDA => hda}/mod.rs | 3 - ihdad/src/{HDA => hda}/node.rs | 61 ++-- ihdad/src/{HDA => hda}/stream.rs | 26 +- ihdad/src/main.rs | 52 ++-- 9 files changed, 825 insertions(+), 997 deletions(-) delete mode 100644 ihdad/src/HDA/cmdbuff.rs delete mode 100644 ihdad/src/HDA/common.rs create mode 100644 ihdad/src/hda/cmdbuff.rs create mode 100644 ihdad/src/hda/common.rs rename ihdad/src/{HDA => hda}/device.rs (86%) rename ihdad/src/{HDA => hda}/mod.rs (99%) rename ihdad/src/{HDA => hda}/node.rs (68%) rename ihdad/src/{HDA => hda}/stream.rs (93%) diff --git a/ihdad/src/HDA/cmdbuff.rs b/ihdad/src/HDA/cmdbuff.rs deleted file mode 100644 index 17efa8cdf7..0000000000 --- a/ihdad/src/HDA/cmdbuff.rs +++ /dev/null @@ -1,469 +0,0 @@ -use std::{mem, thread, ptr, fmt}; -use syscall::io::{Dma, Mmio, Io, ReadOnly}; - -use super::common::*; - -// CORBCTL -const CMEIE: u8 = 1 << 0; // 1 bit -const CORBRUN: u8 = 1 << 1; // 1 bit - -// CORBSIZE -const CORBSZCAP: (u8,u8) = (4, 4); -const CORBSIZE: (u8,u8) = (0, 2); - -// CORBRP -const CORBRPRST: u16 = 1 << 15; - -// RIRBWP -const RIRBWPRST: u16 = 1 << 15; - -// RIRBCTL -const RINTCTL: u8 = 1 << 0; // 1 bit -const RIRBDMAEN: u8 = 1 << 1; // 1 bit - - -const CORB_OFFSET: usize = 0x00; -const RIRB_OFFSET: usize = 0x10; -const ICMD_OFFSET: usize = 0x20; - -// ICS -const ICB: u16 = 1 << 0; -const IRV: u16 = 1 << 1; - - -// CORB and RIRB offset - -const COMMAND_BUFFER_OFFSET: usize = 0x40; -const CORB_BUFF_MAX_SIZE: usize = 1024; - -struct CommandBufferRegs { - corblbase: Mmio, - corbubase: Mmio, - corbwp: Mmio, - corbrp: Mmio, - corbctl: Mmio, - corbsts: Mmio, - corbsize: Mmio, - rsvd5: Mmio, - - rirblbase: Mmio, - rirbubase: Mmio, - rirbwp: Mmio, - rintcnt: Mmio, - rirbctl: Mmio, - rirbsts: Mmio, - rirbsize: Mmio, - rsvd6: Mmio, -} - - -struct CorbRegs { - corblbase: Mmio, - corbubase: Mmio, - corbwp: Mmio, - corbrp: Mmio, - corbctl: Mmio, - corbsts: Mmio, - corbsize: Mmio, - rsvd5: Mmio, -} - -struct Corb { - regs: &'static mut CorbRegs, - corb_base: *mut u32, - corb_base_phys: usize, - corb_count: usize, -} - -impl Corb { - - pub fn new(regs_addr:usize, corb_buff_phys:usize, corb_buff_virt:usize) -> Corb { - - unsafe { - Corb { - regs: &mut *(regs_addr as *mut CorbRegs), - corb_base: (corb_buff_virt) as *mut u32, - corb_base_phys: corb_buff_phys, - corb_count: 0, - } - } - } - //Intel 4.4.1.3 - pub fn init(&mut self) { - self.stop(); - //Determine CORB and RIRB size and allocate buffer - - - //3.3.24 - let corbsize_reg = self.regs.corbsize.read(); - let corbszcap = (corbsize_reg >> 4) & 0xF; - - let mut corbsize_bytes: usize = 0; - let mut corbsize: u8 = 0; - - if (corbszcap & 4) == 4 { - corbsize = 2; - corbsize_bytes = 1024; - - self.corb_count = 256; - } else if (corbszcap & 2) == 2 { - corbsize = 1; - corbsize_bytes = 64; - - self.corb_count = 16; - } else if (corbszcap & 1) == 1 { - corbsize = 0; - corbsize_bytes = 8; - - self.corb_count = 2; - } - - assert!(self.corb_count != 0); - let addr = self.corb_base_phys; - self.set_address(addr); - self.regs.corbwp.write(0); - self.reset_read_pointer(); - - } - - - pub fn start(&mut self) { - self.regs.corbctl.writef(CORBRUN,true); - } - - - pub fn stop(&mut self) { - while self.regs.corbctl.readf(CORBRUN) { self.regs.corbctl.write(0); } - } - - pub fn set_address(&mut self, addr: usize) { - self.regs.corblbase.write((addr & 0xFFFFFFFF) as u32); - self.regs.corbubase.write((addr >> 32) as u32); - } - - pub fn reset_read_pointer(&mut self){ - - - /* - * FIRST ISSUE/PATCH - * This will loop forever in virtualbox - * So maybe just resetting the read pointer - * and leaving for the specific model? - */ - if true { - self.regs.corbrp.writef(CORBRPRST, true); - - } - else - { - // 3.3.21 - - self.stop(); - // Set CORBRPRST to 1 - print!("CORBRP {:X}\n",self.regs.corbrp.read()); - self.regs.corbrp.writef(CORBRPRST, true); - print!("CORBRP {:X}\n",self.regs.corbrp.read()); - print!("Here!\n"); - - // Wait for it to become 1 - while ! self.regs.corbrp.readf(CORBRPRST) { - self.regs.corbrp.writef(CORBRPRST, true); - } - print!("Here!!\n"); - // Clear the bit again - self.regs.corbrp.write(0); - - // Read back the bit until zero to verify that it is cleared. - - loop { - - if !self.regs.corbrp.readf(CORBRPRST) { - break; - } - self.regs.corbrp.write(0); - } - print!("Here!!!\n"); - } - } - - - fn send_command(&mut self, cmd: u32) { - - // wait for the commands to finish - while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {} - let mut write_pos: usize = ( (self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count; - unsafe { - *self.corb_base.offset(write_pos as isize) = cmd; - } - - self.regs.corbwp.write(write_pos as u16); - - print!("Corb: {:08X}\n", cmd); - } -} - -struct RirbRegs { - rirblbase: Mmio, - rirbubase: Mmio, - rirbwp: Mmio, - rintcnt: Mmio, - rirbctl: Mmio, - rirbsts: Mmio, - rirbsize: Mmio, - rsvd6: Mmio, -} - -struct Rirb { - regs: &'static mut RirbRegs, - rirb_base: *mut u64, - rirb_base_phys: usize, - rirb_rp: u16, - rirb_count: usize, -} - -impl Rirb { - - pub fn new(regs_addr:usize, rirb_buff_phys:usize, rirb_buff_virt:usize) -> Rirb { - - unsafe { - Rirb { - regs: &mut *(regs_addr as *mut RirbRegs), - rirb_base: (rirb_buff_virt) as *mut u64, - rirb_rp: 0, - rirb_base_phys: rirb_buff_phys, - rirb_count: 0, - } - } - } - //Intel 4.4.1.3 - pub fn init(&mut self) { - self.stop(); - - - let rirbsize_reg = self.regs.rirbsize.read(); - let rirbszcap = (rirbsize_reg >> 4) & 0xF; - - let mut rirbsize_bytes: usize = 0; - let mut rirbsize: u8 = 0; - - if (rirbszcap & 4) == 4 { - rirbsize = 2; - rirbsize_bytes = 2048; - - self.rirb_count = 256; - } else if (rirbszcap & 2) == 2 { - rirbsize = 1; - rirbsize_bytes = 128; - - self.rirb_count = 8; - } else if (rirbszcap & 1) == 1 { - rirbsize = 0; - rirbsize_bytes = 16; - - self.rirb_count = 2; - } - - assert!(self.rirb_count != 0); - - let addr = self.rirb_base_phys; - self.set_address(addr); - - self.reset_write_pointer(); - self.rirb_rp = 0; - - self.regs.rintcnt.write(1); - - } - - pub fn start(&mut self) { - self.regs.rirbctl.writef(RIRBDMAEN | RINTCTL,true); - } - - pub fn stop(&mut self) { - let mut val = self.regs.rirbctl.read(); - val &= !(RIRBDMAEN); - self.regs.rirbctl.write(val); - } - - - pub fn set_address(&mut self, addr: usize) { - self.regs.rirblbase.write((addr & 0xFFFFFFFF) as u32); - self.regs.rirbubase.write((addr >> 32) as u32); - } - - pub fn reset_write_pointer(&mut self) { - self.regs.rirbwp.writef(RIRBWPRST, true); - } - - fn read_response(&mut self) -> u64 { - // wait for response - while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) {} - let mut read_pos: u16 = (self.rirb_rp + 1) % self.rirb_count as u16; - - let mut res: u64; - unsafe { - res = *self.rirb_base.offset(read_pos as isize); - } - self.rirb_rp = read_pos; - print!("Rirb: {:08X}\n", res); - res - - } - -} - - -struct ImmediateCommandRegs { - icoi: Mmio, - irii: Mmio, - ics: Mmio, - rsvd7: [Mmio; 6], -} - -pub struct ImmediateCommand { - regs: &'static mut ImmediateCommandRegs, - -} - -impl ImmediateCommand { - - pub fn new(regs_addr:usize) -> ImmediateCommand { - - unsafe { - ImmediateCommand { - regs: &mut *(regs_addr as *mut ImmediateCommandRegs), - } - } - } - - pub fn cmd(&mut self, cmd:u32) -> u64 { - - // wait for ready - while self.regs.ics.readf(ICB) {} - - // write command - self.regs.icoi.write(cmd); - - - // set ICB bit to send command - self.regs.ics.writef(ICB, true); - - - // wait for IRV bit to be set to indicate a response is latched - while !self.regs.ics.readf(IRV) {} - - // read the result register twice, total of 8 bytes - // highest 4 will most likely be zeros (so I've heard) - let mut res:u64 = self.regs.irii.read() as u64; - res |= (self.regs.irii.read() as u64) << 32; - - - // clear the bit so we know when the next response comes - self.regs.ics.writef(IRV, false); - - res - - - } - -} - -pub struct CommandBuffer { - - // regs: &'static mut CommandBufferRegs, - - corb: Corb, - rirb: Rirb, - icmd: ImmediateCommand, - - corb_rirb_base_phys: usize, - - use_immediate_cmd: bool, -} - - - - -impl CommandBuffer { - pub fn new(regs_addr:usize, cmd_buff_frame_phys:usize, cmd_buff_frame:usize ) -> CommandBuffer { - - let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff_frame_phys, cmd_buff_frame); - let rirb = Rirb::new(regs_addr + RIRB_OFFSET, - cmd_buff_frame_phys + CORB_BUFF_MAX_SIZE, - cmd_buff_frame + CORB_BUFF_MAX_SIZE); - - let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET); - - let cmdbuff = CommandBuffer { - corb: corb, - rirb: rirb, - icmd: icmd, - - corb_rirb_base_phys: cmd_buff_frame_phys, - - use_immediate_cmd: false, - }; - - cmdbuff - } - - pub fn init(&mut self, use_imm_cmds: bool) { - self.corb.init(); - self.rirb.init(); - self.set_use_imm_cmds(use_imm_cmds); - - } - - pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> u64 { - let mut ncmd: u32 = 0; - - ncmd |= (addr.0 as u32 & 0x00F) << 28; - ncmd |= (addr.1 as u32 & 0x0FF) << 20; - ncmd |= (command & 0xFFF) << 8; - ncmd |= (data as u32 & 0x0FF) << 0; - self.cmd(ncmd) - - } - pub fn cmd4(&mut self, addr: WidgetAddr, command: u32, data: u16) -> u64 { - let mut ncmd: u32 = 0; - - ncmd |= (addr.0 as u32 & 0x000F) << 28; - ncmd |= (addr.1 as u32 & 0x00FF) << 20; - ncmd |= (command & 0x000F) << 16; - ncmd |= (data as u32 & 0xFFFF) << 0; - self.cmd(ncmd) - } - - pub fn cmd(&mut self, cmd:u32) -> u64 { - if self.use_immediate_cmd { - self.cmd_imm(cmd) - } else { - self.cmd_buff(cmd) - } - } - - pub fn cmd_imm(&mut self, cmd:u32) -> u64{ - self.icmd.cmd(cmd) - } - - pub fn cmd_buff(&mut self, cmd:u32) -> u64{ - self.corb.send_command(cmd); - self.rirb.read_response() - } - - pub fn set_use_imm_cmds(&mut self, use_imm: bool) { - self.use_immediate_cmd = use_imm; - - if self.use_immediate_cmd { - self.corb.stop(); - self.rirb.stop(); - } else { - self.corb.start(); - self.rirb.start(); - } - - } - - -} - diff --git a/ihdad/src/HDA/common.rs b/ihdad/src/HDA/common.rs deleted file mode 100644 index 67a35350a0..0000000000 --- a/ihdad/src/HDA/common.rs +++ /dev/null @@ -1,193 +0,0 @@ - - -use std::{mem, thread, ptr, fmt}; -use std::mem::transmute; -pub type HDANodeAddr = u16; -pub type HDACodecAddr = u8; - -pub type NodeAddr = u16; -pub type CodecAddr = u8; - -pub type WidgetAddr = (CodecAddr, NodeAddr); -/* -impl fmt::Display for WidgetAddr { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:01X}:{:02X}\n", self.0, self.1) - } -}*/ - -#[derive(Debug, PartialEq)] -#[repr(u8)] -pub enum HDAWidgetType{ - AudioOutput = 0x0, - AudioInput = 0x1, - AudioMixer = 0x2, - AudioSelector = 0x3, - PinComplex = 0x4, - Power = 0x5, - VolumeKnob = 0x6, - BeepGenerator = 0x7, - - - VendorDefined = 0xf, -} - -impl fmt::Display for HDAWidgetType { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self) - } -} - - -#[derive(Debug, PartialEq)] -#[repr(u8)] -pub enum DefaultDevice { - LineOut = 0x0, - Speaker = 0x1, - HPOut = 0x2, - CD = 0x3, - SPDIF = 0x4, - DigitalOtherOut = 0x5, - ModemLineSide = 0x6, - ModemHandsetSide = 0x7, - LineIn = 0x8, - AUX = 0x9, - MicIn = 0xA, - Telephony = 0xB, - SPDIFIn = 0xC, - DigitalOtherIn = 0xD, - Reserved = 0xE, - Other = 0xF, -} - -#[derive(Debug)] -#[repr(u8)] -pub enum PortConnectivity { - ConnectedToJack = 0x0, - NoPhysicalConnection = 0x1, - FixedFunction = 0x2, - JackAndInternal = 0x3, -} - -#[derive(Debug)] -#[repr(u8)] -pub enum GrossLocation { - ExternalOnPrimary = 0x0, - Internal = 0x1, - SeperateChasis = 0x2, - Other = 0x3, -} - -#[derive(Debug)] -#[repr(u8)] -pub enum GeometricLocation { - NA = 0x0, - Rear = 0x1, - Front = 0x2, - Left = 0x3, - Right = 0x4, - Top = 0x5, - Bottom = 0x6, - Special1 = 0x7, - Special2 = 0x8, - Special3 = 0x9, - Resvd1 = 0xA, - Resvd2 = 0xB, - Resvd3 = 0xC, - Resvd4 = 0xD, - Resvd5 = 0xE, - Resvd6 = 0xF, -} - -#[derive(Debug)] -#[repr(u8)] -pub enum Color{ - Unknown = 0x0, - Black = 0x1, - Grey = 0x2, - Blue = 0x3, - Green = 0x4, - Red = 0x5, - Orange = 0x6, - Yellow = 0x7, - Purple = 0x8, - Pink = 0x9, - Resvd1 = 0xA, - Resvd2 = 0xB, - Resvd3 = 0xC, - Resvd4 = 0xD, - White = 0xE, - Other = 0xF, -} - -pub struct ConfigurationDefault { - value: u32, -} - -impl ConfigurationDefault { - pub fn from_u32(value:u32) -> ConfigurationDefault { - ConfigurationDefault { - value: value, - } - } - - pub fn color(&self) -> Color { - unsafe {transmute(((self.value >> 12) & 0xF) as u8)} - } - - pub fn default_device(&self) -> DefaultDevice { - unsafe {transmute(((self.value >> 20) & 0xF) as u8)} - } - - pub fn port_connectivity(&self) -> PortConnectivity { - unsafe {transmute(((self.value >> 30) & 0x3) as u8)} - } - - pub fn gross_location(&self) -> GrossLocation { - unsafe {transmute(((self.value >> 28) & 0x3) as u8)} - } - - pub fn geometric_location(&self) -> GeometricLocation { - unsafe {transmute(((self.value >> 24) & 0x7) as u8)} - } - - pub fn is_output(&self) -> bool { - match self.default_device() { - DefaultDevice::LineOut | - DefaultDevice::Speaker | - DefaultDevice::HPOut | - DefaultDevice::CD | - DefaultDevice::SPDIF | - DefaultDevice::DigitalOtherOut | - DefaultDevice::ModemLineSide => true, - _ => false, - } - } - - pub fn is_input(&self) -> bool { - match self.default_device() { - DefaultDevice::ModemHandsetSide | - DefaultDevice::LineIn | - DefaultDevice::AUX | - DefaultDevice::MicIn | - DefaultDevice::Telephony | - DefaultDevice::SPDIFIn | - DefaultDevice::DigitalOtherIn => true, - _ => false, - } - } - - pub fn sequence(&self) -> u8 { - (self.value & 0xF) as u8 - } - - pub fn default_association(&self) -> u8 { - ((self.value >> 4) & 0xF) as u8 - } -} - -impl fmt::Display for ConfigurationDefault { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?} {:?} {:?} {:?}", self.default_device(), self.color(), self.gross_location(), self.geometric_location()) - } -} \ No newline at end of file diff --git a/ihdad/src/hda/cmdbuff.rs b/ihdad/src/hda/cmdbuff.rs new file mode 100644 index 0000000000..730ae1518c --- /dev/null +++ b/ihdad/src/hda/cmdbuff.rs @@ -0,0 +1,430 @@ +use syscall::io::{Io, Mmio}; + +use super::common::*; + +// CORBCTL +const CMEIE: u8 = 1 << 0; // 1 bit +const CORBRUN: u8 = 1 << 1; // 1 bit + +// CORBSIZE +const CORBSZCAP: (u8, u8) = (4, 4); +const CORBSIZE: (u8, u8) = (0, 2); + +// CORBRP +const CORBRPRST: u16 = 1 << 15; + +// RIRBWP +const RIRBWPRST: u16 = 1 << 15; + +// RIRBCTL +const RINTCTL: u8 = 1 << 0; // 1 bit +const RIRBDMAEN: u8 = 1 << 1; // 1 bit + +const CORB_OFFSET: usize = 0x00; +const RIRB_OFFSET: usize = 0x10; +const ICMD_OFFSET: usize = 0x20; + +// ICS +const ICB: u16 = 1 << 0; +const IRV: u16 = 1 << 1; + +// CORB and RIRB offset + +const COMMAND_BUFFER_OFFSET: usize = 0x40; +const CORB_BUFF_MAX_SIZE: usize = 1024; + +struct CommandBufferRegs { + corblbase: Mmio, + corbubase: Mmio, + corbwp: Mmio, + corbrp: Mmio, + corbctl: Mmio, + corbsts: Mmio, + corbsize: Mmio, + rsvd5: Mmio, + + rirblbase: Mmio, + rirbubase: Mmio, + rirbwp: Mmio, + rintcnt: Mmio, + rirbctl: Mmio, + rirbsts: Mmio, + rirbsize: Mmio, + rsvd6: Mmio, +} + +struct CorbRegs { + corblbase: Mmio, + corbubase: Mmio, + corbwp: Mmio, + corbrp: Mmio, + corbctl: Mmio, + corbsts: Mmio, + corbsize: Mmio, + rsvd5: Mmio, +} + +struct Corb { + regs: &'static mut CorbRegs, + corb_base: *mut u32, + corb_base_phys: usize, + corb_count: usize, +} + +impl Corb { + pub fn new(regs_addr: usize, corb_buff_phys: usize, corb_buff_virt: usize) -> Corb { + unsafe { + Corb { + regs: &mut *(regs_addr as *mut CorbRegs), + corb_base: (corb_buff_virt) as *mut u32, + corb_base_phys: corb_buff_phys, + corb_count: 0, + } + } + } + //Intel 4.4.1.3 + pub fn init(&mut self) { + self.stop(); + //Determine CORB and RIRB size and allocate buffer + + //3.3.24 + let corbsize_reg = self.regs.corbsize.read(); + let corbszcap = (corbsize_reg >> 4) & 0xF; + + let mut corbsize_bytes: usize = 0; + let mut corbsize: u8 = 0; + + if (corbszcap & 4) == 4 { + corbsize = 2; + corbsize_bytes = 1024; + + self.corb_count = 256; + } else if (corbszcap & 2) == 2 { + corbsize = 1; + corbsize_bytes = 64; + + self.corb_count = 16; + } else if (corbszcap & 1) == 1 { + corbsize = 0; + corbsize_bytes = 8; + + self.corb_count = 2; + } + + assert!(self.corb_count != 0); + let addr = self.corb_base_phys; + self.set_address(addr); + self.regs.corbwp.write(0); + self.reset_read_pointer(); + } + + pub fn start(&mut self) { + self.regs.corbctl.writef(CORBRUN, true); + } + + pub fn stop(&mut self) { + while self.regs.corbctl.readf(CORBRUN) { + self.regs.corbctl.write(0); + } + } + + pub fn set_address(&mut self, addr: usize) { + self.regs.corblbase.write((addr & 0xFFFFFFFF) as u32); + self.regs.corbubase.write((addr >> 32) as u32); + } + + pub fn reset_read_pointer(&mut self) { + /* + * FIRST ISSUE/PATCH + * This will loop forever in virtualbox + * So maybe just resetting the read pointer + * and leaving for the specific model? + */ + if true { + self.regs.corbrp.writef(CORBRPRST, true); + } else { + // 3.3.21 + + self.stop(); + // Set CORBRPRST to 1 + print!("CORBRP {:X}\n", self.regs.corbrp.read()); + self.regs.corbrp.writef(CORBRPRST, true); + print!("CORBRP {:X}\n", self.regs.corbrp.read()); + print!("Here!\n"); + + // Wait for it to become 1 + while !self.regs.corbrp.readf(CORBRPRST) { + self.regs.corbrp.writef(CORBRPRST, true); + } + print!("Here!!\n"); + // Clear the bit again + self.regs.corbrp.write(0); + + // Read back the bit until zero to verify that it is cleared. + + loop { + if !self.regs.corbrp.readf(CORBRPRST) { + break; + } + self.regs.corbrp.write(0); + } + print!("Here!!!\n"); + } + } + + fn send_command(&mut self, cmd: u32) { + // wait for the commands to finish + while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {} + let write_pos: usize = + ((self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count; + unsafe { + *self.corb_base.offset(write_pos as isize) = cmd; + } + + self.regs.corbwp.write(write_pos as u16); + + print!("Corb: {:08X}\n", cmd); + } +} + +struct RirbRegs { + rirblbase: Mmio, + rirbubase: Mmio, + rirbwp: Mmio, + rintcnt: Mmio, + rirbctl: Mmio, + rirbsts: Mmio, + rirbsize: Mmio, + rsvd6: Mmio, +} + +struct Rirb { + regs: &'static mut RirbRegs, + rirb_base: *mut u64, + rirb_base_phys: usize, + rirb_rp: u16, + rirb_count: usize, +} + +impl Rirb { + pub fn new(regs_addr: usize, rirb_buff_phys: usize, rirb_buff_virt: usize) -> Rirb { + unsafe { + Rirb { + regs: &mut *(regs_addr as *mut RirbRegs), + rirb_base: (rirb_buff_virt) as *mut u64, + rirb_rp: 0, + rirb_base_phys: rirb_buff_phys, + rirb_count: 0, + } + } + } + //Intel 4.4.1.3 + pub fn init(&mut self) { + self.stop(); + + let rirbsize_reg = self.regs.rirbsize.read(); + let rirbszcap = (rirbsize_reg >> 4) & 0xF; + + let mut rirbsize_bytes: usize = 0; + let mut rirbsize: u8 = 0; + + if (rirbszcap & 4) == 4 { + rirbsize = 2; + rirbsize_bytes = 2048; + + self.rirb_count = 256; + } else if (rirbszcap & 2) == 2 { + rirbsize = 1; + rirbsize_bytes = 128; + + self.rirb_count = 8; + } else if (rirbszcap & 1) == 1 { + rirbsize = 0; + rirbsize_bytes = 16; + + self.rirb_count = 2; + } + + assert!(self.rirb_count != 0); + + let addr = self.rirb_base_phys; + self.set_address(addr); + + self.reset_write_pointer(); + self.rirb_rp = 0; + + self.regs.rintcnt.write(1); + } + + pub fn start(&mut self) { + self.regs.rirbctl.writef(RIRBDMAEN | RINTCTL, true); + } + + pub fn stop(&mut self) { + let mut val = self.regs.rirbctl.read(); + val &= !(RIRBDMAEN); + self.regs.rirbctl.write(val); + } + + pub fn set_address(&mut self, addr: usize) { + self.regs.rirblbase.write((addr & 0xFFFFFFFF) as u32); + self.regs.rirbubase.write((addr >> 32) as u32); + } + + pub fn reset_write_pointer(&mut self) { + self.regs.rirbwp.writef(RIRBWPRST, true); + } + + fn read_response(&mut self) -> u64 { + // wait for response + while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) {} + let read_pos: u16 = (self.rirb_rp + 1) % self.rirb_count as u16; + + let res: u64; + unsafe { + res = *self.rirb_base.offset(read_pos as isize); + } + self.rirb_rp = read_pos; + print!("Rirb: {:08X}\n", res); + res + } +} + +struct ImmediateCommandRegs { + icoi: Mmio, + irii: Mmio, + ics: Mmio, + rsvd7: [Mmio; 6], +} + +pub struct ImmediateCommand { + regs: &'static mut ImmediateCommandRegs, +} + +impl ImmediateCommand { + pub fn new(regs_addr: usize) -> ImmediateCommand { + unsafe { + ImmediateCommand { + regs: &mut *(regs_addr as *mut ImmediateCommandRegs), + } + } + } + + pub fn cmd(&mut self, cmd: u32) -> u64 { + // wait for ready + while self.regs.ics.readf(ICB) {} + + // write command + self.regs.icoi.write(cmd); + + // set ICB bit to send command + self.regs.ics.writef(ICB, true); + + // wait for IRV bit to be set to indicate a response is latched + while !self.regs.ics.readf(IRV) {} + + // read the result register twice, total of 8 bytes + // highest 4 will most likely be zeros (so I've heard) + let mut res: u64 = self.regs.irii.read() as u64; + res |= (self.regs.irii.read() as u64) << 32; + + // clear the bit so we know when the next response comes + self.regs.ics.writef(IRV, false); + + res + } +} + +pub struct CommandBuffer { + // regs: &'static mut CommandBufferRegs, + corb: Corb, + rirb: Rirb, + icmd: ImmediateCommand, + + corb_rirb_base_phys: usize, + + use_immediate_cmd: bool, +} + +impl CommandBuffer { + pub fn new( + regs_addr: usize, + cmd_buff_frame_phys: usize, + cmd_buff_frame: usize, + ) -> CommandBuffer { + let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff_frame_phys, cmd_buff_frame); + let rirb = Rirb::new( + regs_addr + RIRB_OFFSET, + cmd_buff_frame_phys + CORB_BUFF_MAX_SIZE, + cmd_buff_frame + CORB_BUFF_MAX_SIZE, + ); + + let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET); + + let cmdbuff = CommandBuffer { + corb: corb, + rirb: rirb, + icmd: icmd, + + corb_rirb_base_phys: cmd_buff_frame_phys, + + use_immediate_cmd: false, + }; + + cmdbuff + } + + pub fn init(&mut self, use_imm_cmds: bool) { + self.corb.init(); + self.rirb.init(); + self.set_use_imm_cmds(use_imm_cmds); + } + + pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> u64 { + let mut ncmd: u32 = 0; + + ncmd |= (addr.0 as u32 & 0x00F) << 28; + ncmd |= (addr.1 as u32 & 0x0FF) << 20; + ncmd |= (command & 0xFFF) << 8; + ncmd |= (data as u32 & 0x0FF) << 0; + self.cmd(ncmd) + } + pub fn cmd4(&mut self, addr: WidgetAddr, command: u32, data: u16) -> u64 { + let mut ncmd: u32 = 0; + + ncmd |= (addr.0 as u32 & 0x000F) << 28; + ncmd |= (addr.1 as u32 & 0x00FF) << 20; + ncmd |= (command & 0x000F) << 16; + ncmd |= (data as u32 & 0xFFFF) << 0; + self.cmd(ncmd) + } + + pub fn cmd(&mut self, cmd: u32) -> u64 { + if self.use_immediate_cmd { + self.cmd_imm(cmd) + } else { + self.cmd_buff(cmd) + } + } + + pub fn cmd_imm(&mut self, cmd: u32) -> u64 { + self.icmd.cmd(cmd) + } + + pub fn cmd_buff(&mut self, cmd: u32) -> u64 { + self.corb.send_command(cmd); + self.rirb.read_response() + } + + pub fn set_use_imm_cmds(&mut self, use_imm: bool) { + self.use_immediate_cmd = use_imm; + + if self.use_immediate_cmd { + self.corb.stop(); + self.rirb.stop(); + } else { + self.corb.start(); + self.rirb.start(); + } + } +} diff --git a/ihdad/src/hda/common.rs b/ihdad/src/hda/common.rs new file mode 100644 index 0000000000..c2d5215e94 --- /dev/null +++ b/ihdad/src/hda/common.rs @@ -0,0 +1,195 @@ +use std::fmt; +use std::mem::transmute; + +pub type HDANodeAddr = u16; +pub type HDACodecAddr = u8; + +pub type NodeAddr = u16; +pub type CodecAddr = u8; + +pub type WidgetAddr = (CodecAddr, NodeAddr); +/* +impl fmt::Display for WidgetAddr { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:01X}:{:02X}\n", self.0, self.1) + } +}*/ + +#[derive(Debug, PartialEq)] +#[repr(u8)] +pub enum HDAWidgetType { + AudioOutput = 0x0, + AudioInput = 0x1, + AudioMixer = 0x2, + AudioSelector = 0x3, + PinComplex = 0x4, + Power = 0x5, + VolumeKnob = 0x6, + BeepGenerator = 0x7, + + VendorDefined = 0xf, +} + +impl fmt::Display for HDAWidgetType { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +#[derive(Debug, PartialEq)] +#[repr(u8)] +pub enum DefaultDevice { + LineOut = 0x0, + Speaker = 0x1, + HPOut = 0x2, + CD = 0x3, + SPDIF = 0x4, + DigitalOtherOut = 0x5, + ModemLineSide = 0x6, + ModemHandsetSide = 0x7, + LineIn = 0x8, + AUX = 0x9, + MicIn = 0xA, + Telephony = 0xB, + SPDIFIn = 0xC, + DigitalOtherIn = 0xD, + Reserved = 0xE, + Other = 0xF, +} + +#[derive(Debug)] +#[repr(u8)] +pub enum PortConnectivity { + ConnectedToJack = 0x0, + NoPhysicalConnection = 0x1, + FixedFunction = 0x2, + JackAndInternal = 0x3, +} + +#[derive(Debug)] +#[repr(u8)] +pub enum GrossLocation { + ExternalOnPrimary = 0x0, + Internal = 0x1, + SeperateChasis = 0x2, + Other = 0x3, +} + +#[derive(Debug)] +#[repr(u8)] +pub enum GeometricLocation { + NA = 0x0, + Rear = 0x1, + Front = 0x2, + Left = 0x3, + Right = 0x4, + Top = 0x5, + Bottom = 0x6, + Special1 = 0x7, + Special2 = 0x8, + Special3 = 0x9, + Resvd1 = 0xA, + Resvd2 = 0xB, + Resvd3 = 0xC, + Resvd4 = 0xD, + Resvd5 = 0xE, + Resvd6 = 0xF, +} + +#[derive(Debug)] +#[repr(u8)] +pub enum Color { + Unknown = 0x0, + Black = 0x1, + Grey = 0x2, + Blue = 0x3, + Green = 0x4, + Red = 0x5, + Orange = 0x6, + Yellow = 0x7, + Purple = 0x8, + Pink = 0x9, + Resvd1 = 0xA, + Resvd2 = 0xB, + Resvd3 = 0xC, + Resvd4 = 0xD, + White = 0xE, + Other = 0xF, +} + +pub struct ConfigurationDefault { + value: u32, +} + +impl ConfigurationDefault { + pub fn from_u32(value: u32) -> ConfigurationDefault { + ConfigurationDefault { value: value } + } + + pub fn color(&self) -> Color { + unsafe { transmute(((self.value >> 12) & 0xF) as u8) } + } + + pub fn default_device(&self) -> DefaultDevice { + unsafe { transmute(((self.value >> 20) & 0xF) as u8) } + } + + pub fn port_connectivity(&self) -> PortConnectivity { + unsafe { transmute(((self.value >> 30) & 0x3) as u8) } + } + + pub fn gross_location(&self) -> GrossLocation { + unsafe { transmute(((self.value >> 28) & 0x3) as u8) } + } + + pub fn geometric_location(&self) -> GeometricLocation { + unsafe { transmute(((self.value >> 24) & 0x7) as u8) } + } + + pub fn is_output(&self) -> bool { + match self.default_device() { + DefaultDevice::LineOut + | DefaultDevice::Speaker + | DefaultDevice::HPOut + | DefaultDevice::CD + | DefaultDevice::SPDIF + | DefaultDevice::DigitalOtherOut + | DefaultDevice::ModemLineSide => true, + _ => false, + } + } + + pub fn is_input(&self) -> bool { + match self.default_device() { + DefaultDevice::ModemHandsetSide + | DefaultDevice::LineIn + | DefaultDevice::AUX + | DefaultDevice::MicIn + | DefaultDevice::Telephony + | DefaultDevice::SPDIFIn + | DefaultDevice::DigitalOtherIn => true, + _ => false, + } + } + + pub fn sequence(&self) -> u8 { + (self.value & 0xF) as u8 + } + + pub fn default_association(&self) -> u8 { + ((self.value >> 4) & 0xF) as u8 + } +} + +impl fmt::Display for ConfigurationDefault { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{:?} {:?} {:?} {:?}", + self.default_device(), + self.color(), + self.gross_location(), + self.geometric_location() + ) + } +} diff --git a/ihdad/src/HDA/device.rs b/ihdad/src/hda/device.rs similarity index 86% rename from ihdad/src/HDA/device.rs rename to ihdad/src/hda/device.rs index f17c79f08c..7a832d1670 100755 --- a/ihdad/src/HDA/device.rs +++ b/ihdad/src/hda/device.rs @@ -1,24 +1,16 @@ #![allow(dead_code)] -use std::{mem, thread, ptr, fmt}; use std::cmp; -use std::cmp::{max, min}; -use std::ptr::copy_nonoverlapping; -use std::sync::Arc; -use std::cell::RefCell; use std::collections::HashMap; use std::str; -use std::string::String; use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; -extern crate syscall; - use syscall::PHYSMAP_WRITE; use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::io::{Mmio, Io}; -use syscall::scheme::SchemeMut; +use syscall::scheme::SchemeBlockMut; use spin::Mutex; @@ -58,24 +50,20 @@ const RIRBDMAEN: u8 = 1 << 1; // 1 bit const ICB: u16 = 1 << 0; const IRV: u16 = 1 << 1; - // CORB and RIRB offset const COMMAND_BUFFER_OFFSET: usize = 0x40; - const NUM_SUB_BUFFS: usize = 2; -const SUB_BUFF_SIZE: usize = 0x4000; - +const SUB_BUFF_SIZE: usize = 2048; enum Handle { + Todo, Pcmout(usize, usize, usize), // Card, index, block_ptr Pcmin(usize, usize, usize), // Card, index, block_ptr StrBuf(Vec,usize), } - - #[repr(packed)] #[allow(dead_code)] struct Regs { @@ -125,26 +113,20 @@ struct Regs { dplbase: Mmio, // 0x70 dpubase: Mmio, // 0x74 - } pub struct IntelHDA { - vend_prod: u32, base: usize, regs: &'static mut Regs, - //corb_rirb_base_phys: usize, - cmd: CommandBuffer, codecs: Vec, - - outputs: Vec, inputs: Vec, @@ -152,14 +134,12 @@ pub struct IntelHDA { output_pins: Vec, input_pins: Vec, - + beep_addr: WidgetAddr, - buff_desc: &'static mut [BufferDescriptorListEntry; 256], buff_desc_phys: usize, - - + output_streams: Vec, buffs: Vec>, @@ -169,38 +149,29 @@ pub struct IntelHDA { next_id: AtomicUsize, } - impl IntelHDA { pub unsafe fn new(base: usize, vend_prod:u32) -> Result { - let regs = &mut *(base as *mut Regs); - - let buff_desc_phys = unsafe { syscall::physalloc(0x1000) .expect("Could not allocate physical memory for buffer descriptor list.") }; - - let buff_desc_virt = unsafe { + let buff_desc_virt = unsafe { syscall::physmap(buff_desc_phys, 0x1000, PHYSMAP_WRITE) - .expect("ihdad: failed to map address for buffer descriptor list.") + .expect("ihdad: failed to map address for buffer descriptor list.") }; print!("Virt: {:016X}, Phys: {:016X}\n", buff_desc_virt, buff_desc_phys); - let buff_desc = &mut *(buff_desc_virt as *mut [BufferDescriptorListEntry;256]); - - let cmd_buff_address = unsafe { syscall::physalloc(0x1000) .expect("Could not allocate physical memory for CORB and RIRB.") }; - let cmd_buff_virt = unsafe { syscall::physmap(cmd_buff_address, 0x1000, PHYSMAP_WRITE).expect("ihdad: failed to map address for CORB/RIRB buff") }; print!("Virt: {:016X}, Phys: {:016X}\n", cmd_buff_virt, cmd_buff_address); @@ -208,16 +179,15 @@ impl IntelHDA { vend_prod: vend_prod, base: base, regs: regs, - + cmd: CommandBuffer::new(base + COMMAND_BUFFER_OFFSET, cmd_buff_address, cmd_buff_virt), beep_addr: (0,0), - + widget_map: HashMap::::new(), - codecs: Vec::::new(), - + outputs: Vec::::new(), inputs: Vec::::new(), @@ -227,24 +197,20 @@ impl IntelHDA { buff_desc: buff_desc, buff_desc_phys: buff_desc_phys, - - output_streams: Vec::::new(), - buffs: Vec::>::new(), - int_counter: 0, handles: Mutex::new(BTreeMap::new()), - next_id: AtomicUsize::new(0), + next_id: AtomicUsize::new(0), }; - + module.init(); - + // module.info(); module.enumerate(); - + module.configure(); print!("IHDA: Initialization finished.\n"); Ok(module) @@ -255,14 +221,14 @@ impl IntelHDA { self.reset_controller(); let use_immediate_command_interface = match self.vend_prod { - + 0x8086_2668 => false, _ => true, - }; + }; - self.cmd.init(use_immediate_command_interface); + self.cmd.init(use_immediate_command_interface); self.init_interrupts(); - + true } @@ -274,15 +240,10 @@ impl IntelHDA { self.regs.intctl.write((1 << 31) | /* (1 << 30) |*/ (1 << 4)); } - - - - pub fn irq(&mut self) -> bool { + pub fn irq(&mut self) -> bool { self.int_counter += 1; - - self.handle_interrupts(); - true + self.handle_interrupts() } pub fn int_count(&self) -> usize { @@ -294,12 +255,12 @@ impl IntelHDA { let mut temp:u64; node.addr = addr; - + temp = self.cmd.cmd12( addr, 0xF00, 0x04); node.subnode_count = (temp & 0xff) as u16; node.subnode_start = ((temp >> 16) & 0xff) as u16; - + if addr == (0,0) { return node; } @@ -316,41 +277,39 @@ impl IntelHDA { node.conn_list_len = (temp & 0xFF) as u8; node.connections = self.node_get_connection_list(&node); - + node.config_default = self.cmd.cmd12(addr, 0xF1C, 0x00) as u32; node - } pub fn node_get_connection_list(&mut self, node: &HDANode) -> Vec { - let len_field: u8 = (self.cmd.cmd12(node.addr, 0xF00, 0x0E) & 0xFF) as u8; - + // Highest bit is if addresses are represented in longer notation // lower 7 is actual count - + let count:u8 = len_field & 0x7F; let use_long_addr: bool = (len_field >> 7) & 0x1 == 1; - + let mut current: u8 = 0; - + let mut list = Vec::::new(); while current < count { - + let response: u32 = (self.cmd.cmd12(node.addr, 0xF02, current) & 0xFFFFFFFF) as u32; - + if use_long_addr { for i in 0..2 { let addr_field = ((response >> (16 * i)) & 0xFFFF) as u16; - let addr = (addr_field & 0x7FFF); + let addr = addr_field & 0x7FFF; if addr == 0 { break; } - + if (addr_field >> 15) & 0x1 == 0x1 { - for i in (list.pop().unwrap().1 .. (addr + 1)) { + for i in list.pop().unwrap().1 .. (addr + 1) { list.push((node.addr.0, i)); } } else { @@ -359,56 +318,50 @@ impl IntelHDA { } } else { - for i in 0..4 { let addr_field = ((response >> (8 * i)) & 0xff) as u16; - let addr = (addr_field & 0x7F); - - if addr == 0 { break; } + let addr = addr_field & 0x7F; + + if addr == 0 { break; } if (addr_field >> 7) & 0x1 == 0x1 { - for i in (list.pop().unwrap().1 .. (addr + 1)) { + for i in list.pop().unwrap().1 .. (addr + 1) { list.push((node.addr.0, i)); } } else { list.push((node.addr.0, addr)); } } - } - + current = list.len() as u8; - } + list - } + pub fn enumerate(&mut self) { - - self.output_pins.clear(); self.input_pins.clear(); - let codec:u8 = 0; - + let root = self.read_node((codec,0)); - + // print!("{}\n", root); let root_count = root.subnode_count; let root_start = root.subnode_start; - //FIXME: So basically the way this is set up is to only support one codec and hopes the first one is an audio - for i in 0..root_count { + for i in 0..root_count { let afg = self.read_node((codec, root_start + i)); // print!("{}\n", afg); let afg_count = afg.subnode_count; let afg_start = afg.subnode_start; - + for j in 0..afg_count { - + let mut widget = self.read_node((codec, afg_start + j)); widget.is_widget = true; match widget.widget_type() { @@ -419,26 +372,22 @@ impl IntelHDA { let config = widget.configuration_default(); if config.is_output() { self.output_pins.push(widget.addr); - } else if (config.is_input()) { + } else if config.is_input() { self.input_pins.push(widget.addr); } - print!("{:02X}{:02X} {}\n", widget.addr().0, widget.addr().1, config); - + }, _ => {}, } - + print!("{}\n", widget); self.widget_map.insert(widget.addr(), widget); - } + } } } - - - pub fn find_best_output_pin(&self) -> Option{ let outs = &self.output_pins; if outs.len() == 0 { @@ -448,10 +397,10 @@ impl IntelHDA { } else { // TODO: Somehow find the best. // Slightly okay is find the speaker with the lowest sequence number. - + for &out in outs { let widget = self.widget_map.get(&out).unwrap(); - + let cd = widget.configuration_default(); if cd.sequence() == 0 && cd.default_device() == DefaultDevice::Speaker { return Some(out); @@ -462,8 +411,6 @@ impl IntelHDA { } } - - pub fn find_path_to_dac(&self, addr: WidgetAddr) -> Option>{ let widget = self.widget_map.get(&addr).unwrap(); if widget.widget_type() == HDAWidgetType::AudioOutput { @@ -474,7 +421,7 @@ impl IntelHDA { }else{ // TODO: do more than just first widget - let mut res = self.find_path_to_dac(widget.connections[0]); + let res = self.find_path_to_dac(widget.connections[0]); match res { Some(p) => { let mut ret = p.clone(); @@ -486,11 +433,8 @@ impl IntelHDA { } } - } + } - - - /* Here we update the buffers and split them into 128 byte sub chunks because each BufferDescriptorList needs to be 128 byte aligned, @@ -503,7 +447,7 @@ impl IntelHDA { Fixed? */ - + pub fn update_sound_buffers(&mut self) { /* for i in 0..self.buffs.len(){ @@ -516,31 +460,22 @@ impl IntelHDA { let r = self.get_output_stream_descriptor(0).unwrap(); - - self.output_streams.push(OutputStream::new(2, 0x4000, r)); + self.output_streams.push(OutputStream::new(NUM_SUB_BUFFS, SUB_BUFF_SIZE, r)); let o = self.output_streams.get_mut(0).unwrap(); - self.buff_desc[0].set_address(o.phys()); self.buff_desc[0].set_length(o.block_size() as u32); - self.buff_desc[0].set_interrupt_on_complete(true); + self.buff_desc[0].set_interrupt_on_complete(true); - self.buff_desc[1].set_address(o.phys() + o.block_size()); self.buff_desc[1].set_length(o.block_size() as u32); self.buff_desc[1].set_interrupt_on_complete(true); - - } - - - pub fn configure(&mut self) { - let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); - + //print!("Best pin: {:01X}:{:02X}\n", outpin.0, outpin.1); let path = self.find_path_to_dac(outpin).unwrap(); @@ -552,7 +487,6 @@ impl IntelHDA { // Pin enable self.cmd.cmd12(pin, 0x707, 0x40); - // EAPD enable self.cmd.cmd12(pin, 0x70C, 2); @@ -561,16 +495,12 @@ impl IntelHDA { self.update_sound_buffers(); - //print!("Supported Formats: {:08X}\n", self.get_supported_formats((0,0x1))); //print!("Capabilities: {:08X}\n", self.get_capabilities(path[0])); let output = self.get_output_stream_descriptor(0).unwrap(); - - - - output.set_address(self.buff_desc_phys); + output.set_address(self.buff_desc_phys); output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); output.set_cyclic_buffer_length(0x8000); // number of bytes @@ -581,8 +511,8 @@ impl IntelHDA { self.set_power_state(dac, 0); // Power state 0 is fully on self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2); - - + + self.cmd.cmd12(dac, 0xA00, 0); // Unmute and set gain for pin complex and DAC @@ -590,14 +520,14 @@ impl IntelHDA { self.set_amplifier_gain_mute(pin, true, true, true, true, 0, false, 0x7f); output.run(); - + } /* pub fn configure_vbox(&mut self) { - + let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); - + print!("Best pin: {:01X}:{:02X}\n", outpin.0, outpin.1); let path = self.find_path_to_dac(outpin).unwrap(); @@ -605,7 +535,7 @@ impl IntelHDA { // Pin enable self.cmd.cmd12((0,0xC), 0x707, 0x40); - + // EAPD enable self.cmd.cmd12((0,0xC), 0x70C, 2); @@ -619,11 +549,11 @@ impl IntelHDA { print!("Capabilities: {:08X}\n", self.get_capabilities((0,0x1))); let output = self.get_output_stream_descriptor(0).unwrap(); - + output.set_address(self.buff_desc_phys); output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); - output.set_cyclic_buffer_length(0x8000); + output.set_cyclic_buffer_length(0x8000); output.set_stream_number(1); output.set_last_valid_index(1); output.set_interrupt_on_completion(true); @@ -631,8 +561,8 @@ impl IntelHDA { self.set_power_state((0,0x3), 0); // Power state 0 is fully on self.set_converter_format((0,0x3), &super::SR_44_1, BitsPerSample::Bits16, 2); - - + + self.cmd.cmd12((0,0x3), 0xA00, 0); // Unmute and set gain for pin complex and DAC @@ -642,35 +572,29 @@ impl IntelHDA { output.run(); self.beep(1); - + } - + */ // BEEP!! pub fn beep(&mut self, div:u8) { let addr = self.beep_addr; if addr != (0,0) { - let _ = self.cmd.cmd12(addr, 0xF0A, div); - } - } - + pub fn read_beep(&mut self) -> u8 { let addr = self.beep_addr; if addr != (0,0) { - self.cmd.cmd12(addr, 0x70A, 0) as u8 }else{ 0 } - } pub fn reset_controller(&mut self) -> bool { - self.regs.statests.write(0xFFFF); // 3.3.7 @@ -700,17 +624,17 @@ impl IntelHDA { for i in 0..15 { if (statests >> i) & 0x1 == 1 { self.codecs.push(i as CodecAddr); - } + } } true } - + pub fn num_output_streams(&self) -> usize{ let gcap = self.regs.gcap.read(); ((gcap >> 12) & 0xF) as usize } - + pub fn num_input_streams(&self) -> usize{ let gcap = self.regs.gcap.read(); ((gcap >> 8) & 0xF) as usize @@ -735,8 +659,6 @@ impl IntelHDA { print!("IHDA: 64-Bit: {}\n", self.regs.gcap.read() & 1 == 1); } - - fn get_input_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { unsafe { if index < self.num_input_streams() { @@ -750,7 +672,7 @@ impl IntelHDA { fn get_output_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { unsafe { if index < self.num_output_streams() { - Some(&mut *((self.base + 0x80 + + Some(&mut *((self.base + 0x80 + self.num_input_streams() * 0x20 + index * 0x20) as *mut StreamDescriptorRegs)) }else{ @@ -763,7 +685,7 @@ impl IntelHDA { fn get_bidirectional_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { unsafe { if index < self.num_bidirectional_streams() { - Some(&mut *((self.base + 0x80 + + Some(&mut *((self.base + 0x80 + self.num_input_streams() * 0x20 + self.num_output_streams() * 0x20 + index * 0x20) as *mut StreamDescriptorRegs)) @@ -802,38 +724,29 @@ impl IntelHDA { self.cmd.cmd4(addr, 0x2, fmt); } - - fn set_amplifier_gain_mute(&mut self, addr: WidgetAddr, output:bool, input:bool, left:bool, right:bool, index:u8, mute:bool, gain: u8) { - let mut payload: u16 = 0; - - if output { payload |= (1 << 15); } - if input { payload |= (1 << 14); } - if left { payload |= (1 << 13); } - if right { payload |= (1 << 12); } - if mute { payload |= (1 << 7); } + + if output { payload |= 1 << 15; } + if input { payload |= 1 << 14; } + if left { payload |= 1 << 13; } + if right { payload |= 1 << 12; } + if mute { payload |= 1 << 7; } payload |= ((index as u16) & 0x0F) << 8; - payload |= ((gain as u16) & 0x7F); + payload |= (gain as u16) & 0x7F; self.cmd.cmd4(addr, 0x3, payload); - + } - pub fn write_to_output(&mut self, index:u8, buf: &[u8]) -> Result { + pub fn write_to_output(&mut self, index:u8, buf: &[u8]) -> Result> { + let output = self.get_output_stream_descriptor(index as usize).unwrap(); + let os = self.output_streams.get_mut(index as usize).unwrap(); - let mut output = self.get_output_stream_descriptor(index as usize).unwrap(); - let mut os = self.output_streams.get_mut(index as usize).unwrap(); - - - - let sample_size:usize = output.sample_size(); + //let sample_size:usize = output.sample_size(); let mut open_block = (output.link_position() as usize) / os.block_size(); - - - if open_block == 0 { open_block = 1; } else { @@ -841,43 +754,33 @@ impl IntelHDA { } //print!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}\n", output.status(), output.link_position(), output.control()); - while open_block == os.current_block() { - open_block = (output.link_position() as usize) / os.block_size(); - - if open_block == 0 { - open_block = os.block_count() - 1; - } else { - open_block = open_block - 1; - } - - - thread::yield_now(); + if open_block == os.current_block() { + Ok(None) + } else { + os.write_block(buf).map(|count| Some(count)) } - - let len = min(os.block_size(), buf.len()); - - os.write_block(buf) } - pub fn handle_interrupts(&mut self) { - + pub fn handle_interrupts(&mut self) -> bool { let intsts = self.regs.intsts.read(); - let sis = intsts & 0x3FFFFFFF; - // print!("IHDA INTSTS: {:08X}\n", intsts); + let sis = intsts & 0x3FFFFFFF; + //print!("IHDA INTSTS: {:08X}\n", intsts); if ((intsts >> 31) & 1) == 1 { // Global Interrupt Status if ((intsts >> 30) & 1) == 1 { // Controller Interrupt Status self.handle_controller_interrupt(); - } + } if sis != 0 { self.handle_stream_interrupts(sis); } } + + intsts != 0 } pub fn handle_controller_interrupt(&mut self) { - + } pub fn handle_stream_interrupts(&mut self, sis: u32) { @@ -887,78 +790,76 @@ impl IntelHDA { for i in 0..iss { if ((sis >> i) & 1 ) == 1 { - let mut input = self.get_input_stream_descriptor(i).unwrap(); + let mut input = self.get_input_stream_descriptor(i).unwrap(); input.clear_interrupts(); } } for i in 0..oss { if ((sis >> (i + iss)) & 1 ) == 1 { - let mut output = self.get_output_stream_descriptor(i).unwrap(); + let mut output = self.get_output_stream_descriptor(i).unwrap(); output.clear_interrupts(); } } for i in 0..bss { if ((sis >> (i + iss + oss)) & 1 ) == 1 { - let mut bid = self.get_bidirectional_stream_descriptor(i).unwrap(); + let mut bid = self.get_bidirectional_stream_descriptor(i).unwrap(); bid.clear_interrupts(); } } } - - fn validate_path(&mut self, path: &Vec<&str>) -> bool { + fn validate_path(&mut self, path: &Vec<&str>) -> bool { print!("Path: {:?}\n", path); let mut it = path.iter(); match it.next() { - Some(card_str) if (*card_str).starts_with("card") => { + Some(card_str) if (*card_str).starts_with("card") => { match usize::from_str_radix(&(*card_str)[4..], 10) { Ok(card_num) => { print!("Card# {}\n", card_num); match it.next() { - Some(codec_str) if (*codec_str).starts_with("codec#") => { + Some(codec_str) if (*codec_str).starts_with("codec#") => { match usize::from_str_radix(&(*codec_str)[6..], 10) { - Ok(codec_num) => { - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - //self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0)); + Ok(_codec_num) => { + //let id = self.next_id.fetch_add(1, Ordering::SeqCst); + //self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0)); true }, _ => false, - } + } }, - Some(pcmout_str) if (*pcmout_str).starts_with("pcmout") => { + Some(pcmout_str) if (*pcmout_str).starts_with("pcmout") => { match usize::from_str_radix(&(*pcmout_str)[6..], 10) { Ok(pcmout_num) => { print!("pcmout {}\n", pcmout_num); true }, _ => false, - } + } }, - Some(pcmin_str) if (*pcmin_str).starts_with("pcmin") => { + Some(pcmin_str) if (*pcmin_str).starts_with("pcmin") => { match usize::from_str_radix(&(*pcmin_str)[6..], 10) { Ok(pcmin_num) => { print!("pcmin {}\n", pcmin_num); true }, _ => false, - } + } }, _ => false, } }, _ => false, - } + } }, Some(cards_str) if *cards_str == "cards" => { true }, - _ => false, + _ => false, } - } + } } @@ -969,44 +870,43 @@ impl Drop for IntelHDA { } } - -impl SchemeMut for IntelHDA { - - - - fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - let path: Vec<&str>; +impl SchemeBlockMut for IntelHDA { + fn open(&mut self, _path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result> { + //let path: Vec<&str>; /* match str::from_utf8(_path) { Ok(p) => { path = p.split("/").collect(); if !self.validate_path(&path) { return Err(Error::new(EINVAL)); - + }, Err(_) => {return Err(Error::new(EINVAL));}, }*/ - - - // TODO: if uid == 0 { - Ok(0) + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, Handle::Todo); + Ok(Some(id)) } else { Err(Error::new(EACCES)) } } - fn write(&mut self, _id: usize, buf: &[u8]) -> Result { - - //print!("Int count: {}\n", self.int_counter); - + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + let index = { + let mut handles = self.handles.lock(); + let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + 0 + }; - self.write_to_output(0, buf) + //print!("Int count: {}\n", self.int_counter); + + self.write_to_output(index, buf) } - fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result { + fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result> { let mut handles = self.handles.lock(); match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::StrBuf(ref mut strbuf, ref mut size) => { @@ -1017,29 +917,28 @@ impl SchemeMut for IntelHDA { SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, _ => return Err(Error::new(EINVAL)) }; - Ok(*size) + Ok(Some(*size)) }, - + _ => Err(Error::new(EINVAL)), - } - } + } + } - - fn close(&mut self, _id: usize) -> Result { - let mut handles = self.handles.lock(); - handles.remove(&_id).ok_or(Error::new(EBADF)).and(Ok(0)) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - //let mut handles = self.handles.lock(); - //let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let mut handles = self.handles.lock(); + let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; let mut i = 0; - let scheme_path = b"audio:"; + let scheme_path = b"hda:"; while i < buf.len() && i < scheme_path.len() { buf[i] = scheme_path[i]; i += 1; } - Ok(i) + Ok(Some(i)) } + + fn close(&mut self, id: usize) -> Result> { + let mut handles = self.handles.lock(); + handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + } } diff --git a/ihdad/src/HDA/mod.rs b/ihdad/src/hda/mod.rs similarity index 99% rename from ihdad/src/HDA/mod.rs rename to ihdad/src/hda/mod.rs index 90330ee8d6..36b40d3fa3 100644 --- a/ihdad/src/HDA/mod.rs +++ b/ihdad/src/hda/mod.rs @@ -15,6 +15,3 @@ pub use self::stream::BufferDescriptorListEntry; pub use self::stream::BitsPerSample; pub use self::stream::StreamBuffer; pub use self::device::IntelHDA; - - - diff --git a/ihdad/src/HDA/node.rs b/ihdad/src/hda/node.rs similarity index 68% rename from ihdad/src/HDA/node.rs rename to ihdad/src/hda/node.rs index edbb3727e0..69e6c7e137 100644 --- a/ihdad/src/HDA/node.rs +++ b/ihdad/src/hda/node.rs @@ -1,50 +1,43 @@ - -use std::{mem, thread, ptr, fmt}; +use std::{mem, fmt}; use super::common::*; #[derive(Clone)] pub struct HDANode { pub addr: WidgetAddr, - - // 0x4 pub subnode_count: u16, pub subnode_start: u16, - + // 0x5 pub function_group_type: u8, - // 0x9 pub capabilities: u32, // 0xC pub pin_caps: u32, - + // 0xD pub in_amp: u32, - + // 0xE pub conn_list_len: u8, - // 0x12 pub out_amp: u32, // 0x13 pub vol_knob: u8, - + pub connections: Vec, - + pub is_widget: bool, pub config_default: u32, } - impl HDANode { - pub fn new() -> HDANode { HDANode { addr: (0,0), @@ -76,7 +69,7 @@ impl HDANode { Some(unsafe { mem::transmute( ((self.config_default >> 20) & 0xF) as u8 )} ) } } - + pub fn configuration_default(&self) -> ConfigurationDefault { ConfigurationDefault::from_u32(self.config_default) } @@ -89,29 +82,23 @@ impl HDANode { impl fmt::Display for HDANode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if self.addr == (0,0) { - write!(f, "Addr: {:02X}:{:02X}, Root Node.", self.addr.0, self.addr.1) - } else if self.is_widget { - match self.widget_type() { - - HDAWidgetType::PinComplex => { - write!(f, "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {:X}: {:?}.", - self.addr.0, - self.addr.1, - self.widget_type(), - self.device_default().unwrap(), - self.conn_list_len, - self.connections) - }, - - _ => { write!(f, "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {:X}: {:?}.", self.addr.0, self.addr.1, self.widget_type(), self.conn_list_len, self.connections) }, - + write!(f, "Addr: {:02X}:{:02X}, Root Node.", self.addr.0, self.addr.1) + } else if self.is_widget { + match self.widget_type() { + HDAWidgetType::PinComplex => write!( + f, + "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {:X}: {:?}.", + self.addr.0, + self.addr.1, + self.widget_type(), + self.device_default().unwrap(), + self.conn_list_len, + self.connections + ), + _ => write!(f, "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {:X}: {:?}.", self.addr.0, self.addr.1, self.widget_type(), self.conn_list_len, self.connections), + } + } else { + write!(f, "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", self.addr.0, self.addr.1, self.function_group_type, self.subnode_count) } - } else { - write!(f, "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", self.addr.0, self.addr.1, self.function_group_type, self.subnode_count) - } } } - - - - diff --git a/ihdad/src/HDA/stream.rs b/ihdad/src/hda/stream.rs similarity index 93% rename from ihdad/src/HDA/stream.rs rename to ihdad/src/hda/stream.rs index b905f8d24c..9d630fbb1f 100644 --- a/ihdad/src/HDA/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -1,17 +1,10 @@ - - - use syscall::PHYSMAP_WRITE; -use syscall::error::{Error, EACCES, EWOULDBLOCK, EIO, Result}; -use syscall::flag::O_NONBLOCK; -use syscall::io::{Dma, Mmio, Io, ReadOnly}; -use syscall::scheme::SchemeMut; -use std::sync::Arc; -use std::cell::RefCell; +use syscall::error::{Error, EIO, Result}; +use syscall::io::{Mmio, Io}; use std::result; -use std::cmp::{max, min}; +use std::cmp::min; use std::ptr::copy_nonoverlapping; -use std::{mem, thread, ptr, fmt}; +use std::ptr; extern crate syscall; @@ -177,7 +170,7 @@ impl StreamDescriptorRegs { pub fn set_interrupt_on_completion(&mut self, enable:bool) { let mut ctrl = self.control(); if enable { - ctrl |= (1 << 2); + ctrl |= 1 << 2; } else { ctrl &= !(1 << 2); } @@ -286,8 +279,6 @@ impl BufferDescriptorListEntry { } } - - pub struct StreamBuffer { phys: usize, addr: usize, @@ -365,7 +356,7 @@ impl StreamBuffer { let len = min(self.block_size(), buf.len()); - print!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}\n", self.phys(), self.addr(), self.current_block() * self.block_size(), len); + //print!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}\n", self.phys(), self.addr(), self.current_block() * self.block_size(), len); unsafe { copy_nonoverlapping(buf.as_ptr(), (self.addr() + self.current_block() * self.block_size()) as * mut u8, len); } @@ -381,8 +372,9 @@ impl Drop for StreamBuffer { fn drop(&mut self) { unsafe { print!("IHDA: Deallocating buffer.\n"); - syscall::physunmap(self.addr); - syscall::physfree(self.phys, self.block_len * self.block_cnt); + if syscall::physunmap(self.addr).is_ok() { + let _ = syscall::physfree(self.phys, self.block_len * self.block_cnt); + } } } } diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 87374bb66a..b970ecbad5 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -6,22 +6,17 @@ extern crate spin; extern crate syscall; extern crate event; -use std::{env, usize, u16, thread}; +use std::{env, usize}; use std::fs::File; use std::io::{Read, Write, Result}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use syscall::{EVENT_READ, PHYSMAP_WRITE, Event, Packet, Scheme, SchemeMut}; +use std::os::unix::io::{AsRawFd, FromRawFd}; +use syscall::{PHYSMAP_WRITE, Packet, SchemeBlockMut}; use std::cell::RefCell; use std::sync::Arc; - use event::EventQueue; -use syscall::error::EWOULDBLOCK; - -pub mod HDA; - -use HDA::IntelHDA; +pub mod hda; /* VEND:PROD @@ -58,8 +53,8 @@ fn main() { let vend_prod:u32 = ((vend as u32) << 16) | (prod as u32); - let device = Arc::new(RefCell::new(unsafe { HDA::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); - let socket_fd = syscall::open(":audio", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create audio scheme"); + let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); + let socket_fd = syscall::open(":hda", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); let mut event_queue = EventQueue::::new().expect("IHDA: Could not create event queue."); @@ -71,35 +66,32 @@ fn main() { let todo_irq = todo.clone(); let device_irq = device.clone(); let socket_irq = socket.clone(); - let device_loop = device.clone(); event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; - let _irq = unsafe { device_irq.borrow_mut().irq()}; - - if _irq { + if unsafe { device_irq.borrow_mut().irq() } { irq_file.write(&mut irq)?; let mut todo = todo_irq.borrow_mut(); let mut i = 0; while i < todo.len() { - let a = todo[i].a; - device_irq.borrow_mut().handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket_irq.borrow_mut().write(&mut todo[i])?; - todo.remove(i); + if let Some(a) = device_irq.borrow_mut().handle(&mut todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket_irq.borrow_mut().write(&packet)?; + } else { + i += 1; } } + /* let next_read = device_irq.next_read(); if next_read > 0 { return Ok(Some(next_read)); - }*/ + } + */ } Ok(Some(0)) }).expect("IHDA: failed to catch events on IRQ file"); @@ -112,22 +104,20 @@ fn main() { break; } - let a = packet.a; - device.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { + if let Some(a) = device.borrow_mut().handle(&mut packet) { packet.a = a; - todo.borrow_mut().push(packet); + socket_packet.borrow_mut().write(&packet)?; } else { - socket_packet.borrow_mut().write(&mut packet)?; + todo.borrow_mut().push(packet); } } - /* let next_read = device.borrow().next_read(); if next_read > 0 { return Ok(Some(next_read)); - }*/ + } + */ Ok(None) }).expect("IHDA: failed to catch events on IRQ file"); From 1e65a212429fe80cf6ed177a40d42b249b063007 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 1 Jan 2019 20:22:08 -0700 Subject: [PATCH 0253/1301] Attempt to read scheme after interrupt --- e1000d/src/main.rs | 65 ++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 96c8eff59e..38db2df33f 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -17,6 +17,41 @@ use syscall::error::EWOULDBLOCK; pub mod device; +fn handle_update(socket: &mut File, device: &mut device::Intel8254x, todo: &mut Vec) -> Result<()> { + // Handle any blocked packets + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + device.handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; + } else { + socket.write(&mut todo[i])?; + todo.remove(i); + } + } + + // Check that the socket is empty + loop { + let mut packet = Packet::default(); + if socket.read(&mut packet)? == 0 { + break; + } + + let a = packet.a; + device.handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.push(packet); + } else { + socket.write(&mut packet)?; + } + } + + Ok(()) +} + fn main() { let mut args = env::args().skip(1); @@ -57,19 +92,7 @@ fn main() { if unsafe { device_irq.borrow().irq() } { irq_file.write(&mut irq)?; - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - device_irq.borrow_mut().handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket_irq.borrow_mut().write(&mut todo[i])?; - todo.remove(i); - } - } + handle_update(&mut socket_irq.borrow_mut(), &mut device_irq.borrow_mut(), &mut todo_irq.borrow_mut())?; let next_read = device_irq.borrow().next_read(); if next_read > 0 { @@ -82,21 +105,7 @@ fn main() { let device_packet = device.clone(); let socket_packet = socket.clone(); event_queue.add(socket_fd, move |_event| -> Result> { - loop { - let mut packet = Packet::default(); - if socket_packet.borrow_mut().read(&mut packet)? == 0 { - break; - } - - let a = packet.a; - device_packet.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); - } else { - socket_packet.borrow_mut().write(&mut packet)?; - } - } + handle_update(&mut socket_packet.borrow_mut(), &mut device_packet.borrow_mut(), &mut todo.borrow_mut()); let next_read = device_packet.borrow().next_read(); if next_read > 0 { From ca748c99f98c3fea91b0621617f7e1c085669a4b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 12 Jan 2019 08:02:02 -0700 Subject: [PATCH 0254/1301] Enable HD audio --- filesystem.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/filesystem.toml b/filesystem.toml index 37eb15c829..ff38fb336a 100644 --- a/filesystem.toml +++ b/filesystem.toml @@ -30,11 +30,11 @@ device = 5379 command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] # ihdad -# [[drivers]] -# name = "Intel HD Audio" -# class = 4 -# subclass = 3 -# command = ["ihdad", "$NAME", "$BAR0", "$IRQ", "$VENID", "$DEVID"] +[[drivers]] +name = "Intel HD Audio" +class = 4 +subclass = 3 +command = ["ihdad", "$NAME", "$BAR0", "$IRQ", "$VENID", "$DEVID"] # rtl8168d [[drivers]] From a38dfb32315a48c069802c300c3c760852771602 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 12 Jan 2019 12:52:57 -0700 Subject: [PATCH 0255/1301] Use IRQs to prevent spin loops in ahcid --- Cargo.lock | 1 - ahcid/Cargo.toml | 1 - ahcid/src/ahci/disk_ata.rs | 124 ++++++++++++++++--------- ahcid/src/ahci/disk_atapi.rs | 20 ++--- ahcid/src/ahci/hba.rs | 68 +++++++------- ahcid/src/ahci/mod.rs | 17 ++-- ahcid/src/main.rs | 50 ++++++++--- ahcid/src/scheme.rs | 169 ++++++++++++++++++++--------------- 8 files changed, 269 insertions(+), 181 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 73ebdf2aa3..6104f9b471 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,6 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index bf17750b2c..0e9644e386 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -4,6 +4,5 @@ version = "0.1.0" [dependencies] bitflags = "0.7" -spin = "0.4" redox_syscall = "0.1" byteorder = "1.2" diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index 2eb48ea63d..468f47437b 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -6,10 +6,23 @@ use syscall::error::Result; use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; use super::Disk; +enum BufferKind<'a> { + Read(&'a mut [u8]), + Write(&'a [u8]), +} + +struct Request { + address: usize, + total_sectors: usize, + sector: usize, + running_opt: Option<(u32, usize)>, +} + pub struct DiskATA { id: usize, port: &'static mut HbaPort, size: u64, + request_opt: Option, clb: Dma<[HbaCmdHeader; 32]>, ctbas: [Dma; 32], _fb: Dma<[u8; 256]>, @@ -40,12 +53,75 @@ impl DiskATA { id: id, port: port, size: size, + request_opt: None, clb: clb, ctbas: ctbas, _fb: fb, buf: buf }) } + + fn request(&mut self, block: u64, mut buffer_kind: BufferKind) -> Result> { + let (write, address, total_sectors) = match buffer_kind { + BufferKind::Read(ref buffer) => (false, buffer.as_ptr() as usize, buffer.len()/512), + BufferKind::Write(ref buffer) => (true, buffer.as_ptr() as usize, buffer.len()/512), + }; + + let mut request = match self.request_opt.take() { + Some(request) => if address == request.address && total_sectors == request.total_sectors { + // Keep servicing current request + request + } else { + // Have to wait for another request to finish + self.request_opt = Some(request); + return Ok(None); + }, + None => { + // Create new request + Request { + address, + total_sectors, + sector: 0, + running_opt: None, + } + } + }; + + // Finish a previously running request + if let Some(running) = request.running_opt.take() { + self.port.ata_stop(running.0)?; + + if let BufferKind::Read(ref mut buffer) = buffer_kind { + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().add(request.sector * 512), running.1 * 512); } + } + + request.sector += running.1; + } + + if request.sector < request.total_sectors { + // Start a new request + let sectors = if request.total_sectors - request.sector >= 255 { + 255 + } else { + request.total_sectors - request.sector + }; + + if let BufferKind::Write(ref buffer) = buffer_kind { + unsafe { ptr::copy(buffer.as_ptr().add(request.sector * 512), self.buf.as_mut_ptr(), sectors * 512); } + } + + if let Some(slot) = self.port.ata_dma(block + request.sector as u64, sectors, write, &mut self.clb, &mut self.ctbas, &mut self.buf) { + request.running_opt = Some((slot, sectors)); + } + + self.request_opt = Some(request); + + Ok(None) + } else { + // Done + Ok(Some(request.sector * 512)) + } + } } impl Disk for DiskATA { @@ -57,52 +133,12 @@ impl Disk for DiskATA { self.size } - fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { - let sectors = buffer.len()/512; - - let mut sector: usize = 0; - while sectors - sector >= 255 { - self.port.dma_read_write(block + sector as u64, 255, false, &mut self.clb, &mut self.ctbas, &mut self.buf)?; - - unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), 255 * 512); } - - sector += 255; - } - if sector < sectors { - self.port.dma_read_write(block + sector as u64, sectors - sector, false, &mut self.clb, &mut self.ctbas, &mut self.buf)?; - - unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * 512), (sectors - sector) * 512); } - - sector += sectors - sector; - } - - Ok(sector * 512) + fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result> { + self.request(block, BufferKind::Read(buffer)) } - fn write(&mut self, block: u64, buffer: &[u8]) -> Result { - let sectors = buffer.len()/512; - - let mut sector: usize = 0; - while sectors - sector >= 255 { - unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), 255 * 512); } - - if let Err(err) = self.port.dma_read_write(block + sector as u64, 255, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } - - sector += 255; - } - if sector < sectors { - unsafe { ptr::copy(buffer.as_ptr().offset(sector as isize * 512), self.buf.as_mut_ptr(), (sectors - sector) * 512); } - - if let Err(err) = self.port.dma_read_write(block + sector as u64, sectors - sector, true, &mut self.clb, &mut self.ctbas, &mut self.buf) { - return Err(err); - } - - sector += sectors - sector; - } - - Ok(sector * 512) + fn write(&mut self, block: u64, buffer: &[u8]) -> Result> { + self.request(block, BufferKind::Write(buffer)) } fn block_length(&mut self) -> Result { diff --git a/ahcid/src/ahci/disk_atapi.rs b/ahcid/src/ahci/disk_atapi.rs index a0aa71baff..3a140195d7 100644 --- a/ahcid/src/ahci/disk_atapi.rs +++ b/ahcid/src/ahci/disk_atapi.rs @@ -5,7 +5,7 @@ use std::ptr; use byteorder::{ByteOrder, BigEndian}; use syscall::io::Dma; -use syscall::error::{Result, ENOSYS, Error}; +use syscall::error::{Result, EBADF, Error}; use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; use super::Disk; @@ -61,7 +61,7 @@ impl DiskATAPI { let mut cmd = [0; 16]; cmd[0] = SCSI_READ_CAPACITY; - self.port.packet(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + self.port.atapi_dma(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf)?; // Instead of a count, contains number of last LBA, so add 1 let blk_count = BigEndian::read_u32(&self.buf[0..4]) + 1; @@ -83,9 +83,9 @@ impl Disk for DiskATAPI { } } - fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { + fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result> { // TODO: Handle audio CDs, which use special READ CD command - + let blk_len = self.block_length()?; let sectors = buffer.len() as u32 / blk_len; @@ -102,7 +102,7 @@ impl Disk for DiskATAPI { let buf_size = buf_len * blk_len; while sectors - sector >= buf_len { let cmd = read10_cmd(block as u32 + sector, buf_len as u16); - self.port.packet(&cmd, buf_size, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + self.port.atapi_dma(&cmd, buf_size, &mut self.clb, &mut self.ctbas, &mut self.buf)?; unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * blk_len as isize), buf_size as usize); } @@ -110,20 +110,20 @@ impl Disk for DiskATAPI { } if sector < sectors { let cmd = read10_cmd(block as u32 + sector, (sectors - sector) as u16); - self.port.packet(&cmd, buf_size, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + self.port.atapi_dma(&cmd, buf_size, &mut self.clb, &mut self.ctbas, &mut self.buf)?; unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * blk_len as isize), ((sectors - sector) * blk_len) as usize); } sector += sectors - sector; } - Ok((sector * blk_len) as usize) + Ok(Some((sector * blk_len) as usize)) } - fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result { - Err(Error::new(ENOSYS)) // TODO: Implement writting + fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result> { + Err(Error::new(EBADF)) // TODO: Implement writing } - + fn block_length(&mut self) -> Result { Ok(self.read_capacity()?.1) } diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 6a582f7430..375615e4b5 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -116,7 +116,7 @@ impl HbaPort { self.fb[1].write((fb.physical() >> 32) as u32); let is = self.is.read(); self.is.write(is); - self.ie.write(0); + self.ie.write(0b10111); let serr = self.serr.read(); self.serr.write(serr); @@ -142,7 +142,7 @@ impl HbaPort { unsafe fn identify_inner(&mut self, cmd: u8, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); - let res = self.ata_dma(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { + let slot = self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { cmdheader.prdtl.write(1); let prdt_entry = &mut prdt_entries[0]; @@ -154,9 +154,9 @@ impl HbaPort { cmdfis.device.write(0); cmdfis.countl.write(1); cmdfis.counth.write(0); - }); + })?; - if res.is_ok() { + if self.ata_stop(slot).is_ok() { let mut serial = String::new(); for word in 10..20 { let d = dest[word]; @@ -217,14 +217,12 @@ impl HbaPort { } } - pub fn dma_read_write(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result { - if write { - //print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write)); - } + pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Option { + // print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write)); assert!(sectors > 0 && sectors < 256); - let res = self.ata_dma(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { + self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { if write { let cfl = cmdheader.cfl.read(); cmdheader.cfl.write(cfl | 1 << 7 | 1 << 6) @@ -255,14 +253,12 @@ impl HbaPort { cmdfis.countl.write(sectors as u8); cmdfis.counth.write((sectors >> 8) as u8); - }); - - res.and(Ok(sectors * 512)) + }) } /// Send ATAPI packet - pub fn packet(&mut self, cmd: &[u8; 16], size: u32, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<()> { - self.ata_dma(clb, ctbas, |cmdheader, cmdfis, prdt_entries, acmd| { + pub fn atapi_dma(&mut self, cmd: &[u8; 16], size: u32, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<()> { + let slot = self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, acmd| { let cfl = cmdheader.cfl.read(); cmdheader.cfl.write(cfl | 1 << 5); @@ -281,12 +277,14 @@ impl HbaPort { cmdfis.featureh.write(0); unsafe { ptr::write_volatile(acmd.as_mut_ptr() as *mut [u8; 16], *cmd) }; - }) + }).ok_or(Error::new(EIO))?; + self.ata_stop(slot) } - fn ata_dma(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], callback: F) -> Result<()> + pub fn ata_start(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], callback: F) -> Option where F: FnOnce(&mut HbaCmdHeader, &mut FisRegH2D, &mut [HbaPrdtEntry; 65536], &mut [Mmio; 16]) { + //TODO: Should probably remove self.is.write(u32::MAX); if let Some(slot) = self.slot() { @@ -312,27 +310,31 @@ impl HbaPort { self.ci.writef(1 << slot, true); + //TODO: Should probably remove self.start(); - while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { - thread::yield_now(); - } - - self.stop(); - - if self.is.read() & HBA_PORT_IS_ERR != 0 { - print!("{}", format!("ERROR IS {:X} IE {:X} CMD {:X} TFD {:X}\nSSTS {:X} SCTL {:X} SERR {:X} SACT {:X}\nCI {:X} SNTF {:X} FBS {:X}\n", - self.is.read(), self.ie.read(), self.cmd.read(), self.tfd.read(), - self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(), - self.ci.read(), self.sntf.read(), self.fbs.read())); - self.is.write(u32::MAX); - Err(Error::new(EIO)) - } else { - Ok(()) - } + Some(slot) } else { - print!("No Command Slots\n"); + None + } + } + + pub fn ata_stop(&mut self, slot: u32) -> Result<()> { + while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { + thread::yield_now(); + } + + self.stop(); + + if self.is.read() & HBA_PORT_IS_ERR != 0 { + print!("{}", format!("ERROR IS {:X} IE {:X} CMD {:X} TFD {:X}\nSSTS {:X} SCTL {:X} SERR {:X} SACT {:X}\nCI {:X} SNTF {:X} FBS {:X}\n", + self.is.read(), self.ie.read(), self.cmd.read(), self.tfd.read(), + self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(), + self.ci.read(), self.sntf.read(), self.fbs.read())); + self.is.write(u32::MAX); Err(Error::new(EIO)) + } else { + Ok(()) } } } diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index 7b8444d749..05792712fd 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -13,18 +13,19 @@ pub mod hba; pub trait Disk { fn id(&self) -> usize; fn size(&mut self) -> u64; - fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result; - fn write(&mut self, block: u64, buffer: &[u8]) -> Result; + fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result>; + fn write(&mut self, block: u64, buffer: &[u8]) -> Result>; fn block_length(&mut self) -> Result; } -pub fn disks(base: usize, name: &str) -> Vec> { - unsafe { &mut *(base as *mut HbaMem) }.init(); - let pi = unsafe { &mut *(base as *mut HbaMem) }.pi.read(); - let ret: Vec> = (0..32) +pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec>) { + let hba_mem = unsafe { &mut *(base as *mut HbaMem) }; + hba_mem.init(); + let pi = hba_mem.pi.read(); + let disks: Vec> = (0..hba_mem.ports.len()) .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) .filter_map(|i| { - let port = &mut unsafe { &mut *(base as *mut HbaMem) }.ports[i]; + let port = unsafe { &mut *hba_mem.ports.as_mut_ptr().add(i) }; let port_type = port.probe(); print!("{}", format!("{}-{}: {:?}\n", name, i, port_type)); @@ -54,5 +55,5 @@ pub fn disks(base: usize, name: &str) -> Vec> { }) .collect(); - ret + (hba_mem, disks) } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 916c72569a..44596d8bbd 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -1,7 +1,5 @@ -#![deny(warnings)] -#![feature(asm)] +//#![deny(warnings)] -extern crate spin; extern crate syscall; extern crate byteorder; @@ -9,7 +7,7 @@ use std::{env, usize}; use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::FromRawFd; -use syscall::{EVENT_READ, PHYSMAP_WRITE, Event, Packet, Scheme}; +use syscall::{EVENT_READ, PHYSMAP_WRITE, Event, Packet, SchemeBlockMut}; use scheme::DiskScheme; @@ -49,6 +47,8 @@ fn main() { let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); + syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace"); + event_file.write(&Event { id: socket_fd, flags: EVENT_READ, @@ -61,10 +61,10 @@ fn main() { data: 0 }).expect("ahcid: failed to event irq scheme"); - let scheme = DiskScheme::new(scheme_name, ahci::disks(address, &name)); - - syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace"); + let (hba_mem, disks) = ahci::disks(address, &name); + let mut scheme = DiskScheme::new(scheme_name, hba_mem, disks); + let mut todo = Vec::new(); loop { let mut event = Event::default(); if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 { @@ -76,14 +76,42 @@ fn main() { if socket.read(&mut packet).expect("ahcid: failed to read disk scheme") == 0 { break; } - scheme.handle(&mut packet); - socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + + if let Some(a) = scheme.handle(&packet) { + packet.a = a; + socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + } else { + todo.push(packet); + } } + + // let mut i = 0; + // while i < todo.len() { + // if let Some(a) = scheme.handle(&todo[i]) { + // let mut packet = todo.remove(i); + // packet.a = a; + // socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + // } else { + // i += 1; + // } + // } } else if event.id == irq_fd { let mut irq = [0; 8]; if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() { - //TODO : Test for IRQ - //irq_file.write(&irq).expect("ahcid: failed to write irq file"); + if scheme.irq() { + irq_file.write(&irq).expect("ahcid: failed to write irq file"); + + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + } else { + i += 1; + } + } + } } } else { println!("Unknown event {}", event.id); diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index e981443e9e..b8374f8ce8 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -2,44 +2,63 @@ use std::collections::BTreeMap; use std::{cmp, str}; use std::fmt::Write; use std::io::Read; -use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering}; -use spin::Mutex; -use syscall::{Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, Result, Scheme, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; +use syscall::{ + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, Result, + Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, + O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; use ahci::Disk; +use ahci::hba::HbaMem; #[derive(Clone)] enum Handle { List(Vec, usize), - Disk(Arc>>, usize, usize) + Disk(usize, usize) } pub struct DiskScheme { scheme_name: String, - disks: Box<[Arc>>]>, - handles: Mutex>, - next_id: AtomicUsize + hba_mem: &'static mut HbaMem, + disks: Box<[Box]>, + handles: BTreeMap, + next_id: usize } impl DiskScheme { - pub fn new(scheme_name: String, disks: Vec>) -> DiskScheme { - let mut disk_arcs = vec![]; - for disk in disks { - disk_arcs.push(Arc::new(Mutex::new(disk))); - } - + pub fn new(scheme_name: String, hba_mem: &'static mut HbaMem, disks: Vec>) -> DiskScheme { DiskScheme { scheme_name: scheme_name, - disks: disk_arcs.into_boxed_slice(), - handles: Mutex::new(BTreeMap::new()), - next_id: AtomicUsize::new(0) + hba_mem: hba_mem, + disks: disks.into_boxed_slice(), + handles: BTreeMap::new(), + next_id: 0 } } } -impl Scheme for DiskScheme { - fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { +impl DiskScheme { + pub fn irq(&mut self) -> bool { + let pi = self.hba_mem.pi.read(); + let is = self.hba_mem.is.read(); + let pi_is = pi & is; + + for i in 0..self.hba_mem.ports.len() { + if pi_is & 1 << i > 0 { + let port = &mut self.hba_mem.ports[i]; + let is = port.is.read(); + //println!("IRQ Port {}: {:#>08x}", i, is); + //TODO: Handle requests for only this port here + port.is.write(is); + } + } + + self.hba_mem.is.write(is); + is != 0 + } +} + +impl SchemeBlockMut for DiskScheme { + fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { if uid == 0 { let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_matches('/'); if path_str.is_empty() { @@ -50,19 +69,21 @@ impl Scheme for DiskScheme { write!(list, "{}\n", i).unwrap(); } - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, Handle::List(list.into_bytes(), 0)); - Ok(id) + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle::List(list.into_bytes(), 0)); + Ok(Some(id)) } else { Err(Error::new(EISDIR)) } } else { let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; - if let Some(disk) = self.disks.get(i) { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0, i)); - Ok(id) + if self.disks.get(i).is_some() { + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle::Disk(i, 0)); + Ok(Some(id)) } else { Err(Error::new(ENOENT)) } @@ -72,41 +93,40 @@ impl Scheme for DiskScheme { } } - fn dup(&self, id: usize, buf: &[u8]) -> Result { + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { if ! buf.is_empty() { return Err(Error::new(EINVAL)); } - let mut handles = self.handles.lock(); let new_handle = { - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; handle.clone() }; - let new_id = self.next_id.fetch_add(1, Ordering::SeqCst); - handles.insert(new_id, new_handle); - Ok(new_id) + let new_id = self.next_id; + self.next_id += 1; + self.handles.insert(new_id, new_handle); + Ok(Some(new_id)) } - fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - let handles = self.handles.lock(); - match *handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle, _) => { + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + match *self.handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref data, _) => { stat.st_mode = MODE_DIR; - stat.st_size = handle.len() as u64; - Ok(0) + stat.st_size = data.len() as u64; + Ok(Some(0)) }, - Handle::Disk(ref handle, _, _) => { + Handle::Disk(number, _) => { + let mut disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; - stat.st_size = handle.lock().size(); - Ok(0) + stat.st_size = disk.size(); + Ok(Some(0)) } } } - fn fpath(&self, id: usize, buf: &mut [u8]) -> Result { - let handles = self.handles.lock(); - let handle = handles.get(&id).ok_or(Error::new(EBADF))?; + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; let mut i = 0; @@ -125,7 +145,7 @@ impl Scheme for DiskScheme { match *handle { Handle::List(_, _) => (), - Handle::Disk(_, _, number) => { + Handle::Disk(number, _) => { let number_str = format!("{}", number); let number_bytes = number_str.as_bytes(); j = 0; @@ -137,46 +157,49 @@ impl Scheme for DiskScheme { } } - Ok(i) + Ok(Some(i)) } - fn read(&self, id: usize, buf: &mut [u8]) -> Result { - let mut handles = self.handles.lock(); - match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(ref mut handle, ref mut size) => { let count = (&handle[*size..]).read(buf).unwrap(); *size += count; - Ok(count) + Ok(Some(count)) }, - Handle::Disk(ref mut handle, ref mut size, _) => { - let mut disk = handle.lock(); + Handle::Disk(number, ref mut size) => { + let mut disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; - let count = disk.read((*size as u64)/(blk_len as u64), buf)?; - *size += count; - Ok(count) + if let Some(count) = disk.read((*size as u64)/(blk_len as u64), buf)? { + *size += count; + Ok(Some(count)) + } else { + Ok(None) + } } } } - fn write(&self, id: usize, buf: &[u8]) -> Result { - let mut handles = self.handles.lock(); - match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(_, _) => { Err(Error::new(EBADF)) }, - Handle::Disk(ref mut handle, ref mut size, _) => { - let mut disk = handle.lock(); + Handle::Disk(number, ref mut size) => { + let mut disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; - let count = disk.write((*size as u64)/(blk_len as u64), buf)?; - *size += count; - Ok(count) + if let Some(count) = disk.write((*size as u64)/(blk_len as u64), buf)? { + *size += count; + Ok(Some(count)) + } else { + Ok(None) + } } } } - fn seek(&self, id: usize, pos: usize, whence: usize) -> Result { - let mut handles = self.handles.lock(); - match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { + fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(ref mut handle, ref mut size) => { let len = handle.len() as usize; *size = match whence { @@ -186,10 +209,11 @@ impl Scheme for DiskScheme { _ => return Err(Error::new(EINVAL)) }; - Ok(*size) + Ok(Some(*size)) }, - Handle::Disk(ref mut handle, ref mut size, _) => { - let len = handle.lock().size() as usize; + Handle::Disk(number, ref mut size) => { + let mut disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + let len = disk.size() as usize; *size = match whence { SEEK_SET => cmp::min(len, pos), SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, @@ -197,13 +221,12 @@ impl Scheme for DiskScheme { _ => return Err(Error::new(EINVAL)) }; - Ok(*size) + Ok(Some(*size)) } } } - fn close(&self, id: usize) -> Result { - let mut handles = self.handles.lock(); - handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(0)) + fn close(&mut self, id: usize) -> Result> { + self.handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) } } From ee3569d4840a778b65610690a63b6123a6ce638a Mon Sep 17 00:00:00 2001 From: Nagy Tibor Date: Sat, 2 Feb 2019 00:20:33 +0000 Subject: [PATCH 0256/1301] ihdad: Fix audiod blocking --- ihdad/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index b970ecbad5..ae940498c9 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -93,7 +93,7 @@ fn main() { } */ } - Ok(Some(0)) + Ok(None) }).expect("IHDA: failed to catch events on IRQ file"); let socket_fd = socket.borrow().as_raw_fd(); let socket_packet = socket.clone(); From 3f41225d78eb2b403ecb2cd8bada1da92f8ec34f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 2 Feb 2019 13:59:49 -0700 Subject: [PATCH 0257/1301] Convert e1000d to using SchemeBlockMut, update dependencies --- Cargo.lock | 314 ++++++++++++++++++++++++++----------------- e1000d/src/device.rs | 40 +++--- e1000d/src/main.rs | 22 ++- 3 files changed, 216 insertions(+), 160 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6104f9b471..b1852a7efc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3,8 +3,8 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -14,7 +14,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -30,12 +30,17 @@ dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "autocfg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "base64" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -44,7 +49,7 @@ name = "bgad" version = "0.1.0" dependencies = [ "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -64,7 +69,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.2.7" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -72,7 +77,7 @@ name = "bytes" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -99,18 +104,18 @@ name = "crossbeam-deque" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -118,10 +123,11 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -131,7 +137,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -139,6 +145,11 @@ name = "extra" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#0b50f3f2127fa62b1fe74090feffbae357266eac" +[[package]] +name = "fuchsia-cprng" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -174,7 +185,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -199,7 +210,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -208,7 +219,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -217,7 +228,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -247,7 +258,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.45" +version = "0.2.48" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -307,12 +318,12 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -322,7 +333,7 @@ version = "0.6.6" source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#2936ef82070ea0c4aa8a7360455b8c512d8c88c0" dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", ] @@ -343,7 +354,7 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -356,12 +367,12 @@ dependencies = [ "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.1 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -380,7 +391,7 @@ version = "0.0.1" source = "git+https://github.com/willem66745/ntpclient-rust#7e3bdf60eb940825789a8da5181025320e3050b0" dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -420,7 +431,7 @@ name = "num_cpus" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -428,7 +439,7 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -437,7 +448,7 @@ name = "orbclient" version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -451,7 +462,7 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -463,10 +474,10 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -475,9 +486,9 @@ name = "pbr" version = "1.0.1" source = "git+https://github.com/a8m/pb#b9792c9fe37343234316e23c263874cf383b208d" dependencies = [ - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -486,10 +497,10 @@ name = "pcid" version = "0.1.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.83 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.83 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -505,7 +516,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.24" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -518,67 +529,76 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.6.10" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.3.22" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.6.1" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_chacha" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.3.0" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -586,7 +606,7 @@ name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -594,7 +614,30 @@ name = "rand_isaac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -602,16 +645,16 @@ name = "rand_pcg" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_xorshift" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -623,17 +666,25 @@ dependencies = [ "vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_event" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/event.git#c31e3d3d5f44d60ff9fec2b1ee58b982e72c0d77" dependencies = [ - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.45" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -641,7 +692,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -651,7 +702,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -662,7 +713,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -693,7 +744,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "stb_truetype 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -722,9 +773,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -751,27 +802,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "slab" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -789,19 +840,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "stb_truetype" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.15.23" +version = "0.15.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -810,18 +861,18 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "time" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -899,14 +950,14 @@ name = "tokio-reactor" version = "0.1.7" source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ - "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -930,11 +981,11 @@ version = "0.1.9" source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -943,9 +994,9 @@ name = "tokio-timer" version = "0.2.8" source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" dependencies = [ - "crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -971,7 +1022,7 @@ dependencies = [ "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "mio-uds 0.6.6 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", @@ -985,7 +1036,7 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.83 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1016,8 +1067,11 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "unicode-xid" @@ -1058,7 +1112,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1072,7 +1126,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1152,26 +1206,28 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" +"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d" +"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" "checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" "checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" -"checksum crossbeam-epoch 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f10a4f8f409aaac4b16a5474fb233624238fcdeefb9ba50d5ea059aab63ba31c" -"checksum crossbeam-utils 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "41ee4864f4797060e52044376f7d107429ce1fb43460021b126424b7180ee21a" +"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" +"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" +"checksum fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81f7f8eb465745ea9b02e2704612a9946a59fa40572086c6fd49d6ddcf30bf31" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" @@ -1184,7 +1240,7 @@ dependencies = [ "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" -"checksum libc 0.2.45 (registry+https://github.com/rust-lang/crates.io-index)" = "2d2857ec59fadc0773853c664d2d18e7198e83883e7060b63c924cb077bd5c74" +"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" @@ -1206,25 +1262,29 @@ dependencies = [ "checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" "checksum orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e9209ac5081710688c453af03a9e92b3d4e1e445cd4c60052692758e08e47c5e" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" -"checksum parking_lot 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9723236a9525c757d9725b993511e3fc941e33f27751942232f0058298297edf" +"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09" -"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c" -"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" -"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd" -"checksum rand 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae9d223d52ae411a33cf7e54ec6034ec165df296ccd23533d671a28252b6f66a" -"checksum rand_chacha 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "771b009e3a508cb67e8823dda454aaa5368c7bc1c16829fb77d3e980440dd34a" -"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db" +"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" +"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" +"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0" +"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" "checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" -"checksum rand_xorshift 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effa3fcaa47e18db002bdde6060944b6d2f9cfd8db471c30e873448ad9187be3" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e02b6e263e6d8ab6a7a7637268785506f26860f0c4be83d8d940014d2b3e1601" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" -"checksum redox_syscall 0.1.45 (registry+https://github.com/rust-lang/crates.io-index)" = "7b7aac97a11cf928b13c97f726b1bfe8542969fcbc39007ce566a888da5964a3" +"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -1237,16 +1297,16 @@ dependencies = [ "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.83 (registry+https://github.com/rust-lang/crates.io-index)" = "157e12af46859e968da75dea9845530e13d03bcab2009a41b9b7bb3cf4eb3ec2" -"checksum serde_derive 1.0.83 (registry+https://github.com/rust-lang/crates.io-index)" = "9469829702497daf2daf3c190e130c3fa72f719920f73c86160d43e8f8d76951" -"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" -"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db" +"checksum serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)" = "52ab457c27b091c27b887eef7181b3ea11ab4f92f66e3a99b2e556b77f9cc6bd" +"checksum serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)" = "51eac71e1171246f337655221882f2f55a9c2e1d8ddc6990cee766509f15b702" +"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +"checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum stb_truetype 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71a7d260b43b6129a22dc341be18a231044ca67a48b7e32625f380cc5ec9ad70" -"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc" +"checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" +"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum time 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "847da467bf0db05882a9e2375934a8a55cffdc9db0d128af1518200260ba1f6c" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" @@ -1264,7 +1324,7 @@ dependencies = [ "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" +"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 59e5dab609..13b875e30d 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -5,7 +5,7 @@ use netutils::setcfg; use syscall::error::{Error, EACCES, EBADF, EINVAL, EWOULDBLOCK, Result}; use syscall::flag::O_NONBLOCK; use syscall::io::Dma; -use syscall::scheme::SchemeMut; +use syscall::scheme::SchemeBlockMut; const CTRL: u32 = 0x00; const CTRL_LRST: u32 = 1 << 3; @@ -104,18 +104,18 @@ pub struct Intel8254x { pub handles: BTreeMap, } -impl SchemeMut for Intel8254x { - fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { +impl SchemeBlockMut for Intel8254x { + fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { if uid == 0 { self.next_id += 1; self.handles.insert(self.next_id, flags); - Ok(self.next_id) + Ok(Some(self.next_id)) } else { Err(Error::new(EACCES)) } } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result { + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { if ! buf.is_empty() { return Err(Error::new(EINVAL)); } @@ -126,10 +126,10 @@ impl SchemeMut for Intel8254x { }; self.next_id += 1; self.handles.insert(self.next_id, flags); - Ok(self.next_id) + Ok(Some(self.next_id)) } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; let head = unsafe { self.read_reg(RDH) }; @@ -155,18 +155,18 @@ impl SchemeMut for Intel8254x { unsafe { self.write_reg(RDT, tail) }; - return Ok(i); + return Ok(Some(i)); } } if flags & O_NONBLOCK == O_NONBLOCK { - Ok(0) - } else { Err(Error::new(EWOULDBLOCK)) + } else { + Ok(None) } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result { + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; loop { @@ -204,17 +204,17 @@ impl SchemeMut for Intel8254x { thread::yield_now(); } - return Ok(i); + return Ok(Some(i)); } } } - fn fevent(&mut self, id: usize, _flags: usize) -> Result { + fn fevent(&mut self, id: usize, _flags: usize) -> Result> { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(id) + Ok(Some(id)) } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; let mut i = 0; @@ -223,17 +223,17 @@ impl SchemeMut for Intel8254x { buf[i] = scheme_path[i]; i += 1; } - Ok(i) + Ok(Some(i)) } - fn fsync(&mut self, id: usize) -> Result { + fn fsync(&mut self, id: usize) -> Result> { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(0) + Ok(Some(0)) } - fn close(&mut self, id: usize) -> Result { + fn close(&mut self, id: usize) -> Result> { self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(0) + Ok(Some(0)) } } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 38db2df33f..d6d8a7e613 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -12,7 +12,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, SchemeMut, PHYSMAP_WRITE}; +use syscall::{Packet, SchemeBlockMut, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -21,14 +21,12 @@ fn handle_update(socket: &mut File, device: &mut device::Intel8254x, todo: &mut // Handle any blocked packets let mut i = 0; while i < todo.len() { - let a = todo[i].a; - device.handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; + if let Some(a) = device.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&packet)?; } else { - socket.write(&mut todo[i])?; - todo.remove(i); + i += 1; } } @@ -39,13 +37,11 @@ fn handle_update(socket: &mut File, device: &mut device::Intel8254x, todo: &mut break; } - let a = packet.a; - device.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { + if let Some(a) = device.handle(&packet) { packet.a = a; - todo.push(packet); + socket.write(&packet)?; } else { - socket.write(&mut packet)?; + todo.push(packet); } } From c9e0dc4fd5a81e2ec84c1cbc97e2ba3ad57cb795 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 18 Feb 2019 21:05:44 -0700 Subject: [PATCH 0258/1301] Go back to polling ahcid to prevent hangs --- ahcid/src/ahci/disk_ata.rs | 115 ++++++++++++++++++++++--------------- ahcid/src/ahci/hba.rs | 6 +- ahcid/src/main.rs | 24 ++++---- 3 files changed, 86 insertions(+), 59 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index 468f47437b..03d51d838f 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -67,59 +67,80 @@ impl DiskATA { BufferKind::Write(ref buffer) => (true, buffer.as_ptr() as usize, buffer.len()/512), }; - let mut request = match self.request_opt.take() { - Some(request) => if address == request.address && total_sectors == request.total_sectors { - // Keep servicing current request - request - } else { - // Have to wait for another request to finish - self.request_opt = Some(request); - return Ok(None); - }, - None => { - // Create new request - Request { - address, - total_sectors, - sector: 0, - running_opt: None, + //TODO: Go back to interrupt magic + let use_interrupts = false; + loop { + let mut request = match self.request_opt.take() { + Some(request) => if address == request.address && total_sectors == request.total_sectors { + // Keep servicing current request + request + } else { + // Have to wait for another request to finish + self.request_opt = Some(request); + return Ok(None); + }, + None => { + // Create new request + Request { + address, + total_sectors, + sector: 0, + running_opt: None, + } } - } - }; - - // Finish a previously running request - if let Some(running) = request.running_opt.take() { - self.port.ata_stop(running.0)?; - - if let BufferKind::Read(ref mut buffer) = buffer_kind { - unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().add(request.sector * 512), running.1 * 512); } - } - - request.sector += running.1; - } - - if request.sector < request.total_sectors { - // Start a new request - let sectors = if request.total_sectors - request.sector >= 255 { - 255 - } else { - request.total_sectors - request.sector }; - if let BufferKind::Write(ref buffer) = buffer_kind { - unsafe { ptr::copy(buffer.as_ptr().add(request.sector * 512), self.buf.as_mut_ptr(), sectors * 512); } + // Finish a previously running request + if let Some(running) = request.running_opt.take() { + if self.port.ata_running(running.0) { + // Continue waiting for request + request.running_opt = Some(running); + self.request_opt = Some(request); + if use_interrupts { + return Ok(None); + } else { + ::std::thread::yield_now(); + continue; + } + } + + self.port.ata_stop(running.0)?; + + if let BufferKind::Read(ref mut buffer) = buffer_kind { + unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().add(request.sector * 512), running.1 * 512); } + } + + request.sector += running.1; } - if let Some(slot) = self.port.ata_dma(block + request.sector as u64, sectors, write, &mut self.clb, &mut self.ctbas, &mut self.buf) { - request.running_opt = Some((slot, sectors)); + if request.sector < request.total_sectors { + // Start a new request + let sectors = if request.total_sectors - request.sector >= 255 { + 255 + } else { + request.total_sectors - request.sector + }; + + if let BufferKind::Write(ref buffer) = buffer_kind { + unsafe { ptr::copy(buffer.as_ptr().add(request.sector * 512), self.buf.as_mut_ptr(), sectors * 512); } + } + + if let Some(slot) = self.port.ata_dma(block + request.sector as u64, sectors, write, &mut self.clb, &mut self.ctbas, &mut self.buf) { + request.running_opt = Some((slot, sectors)); + } + + self.request_opt = Some(request); + + if use_interrupts { + return Ok(None); + } else { + ::std::thread::yield_now(); + continue; + } + } else { + // Done + return Ok(Some(request.sector * 512)); } - - self.request_opt = Some(request); - - Ok(None) - } else { - // Done - Ok(Some(request.sector * 512)) } } } diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 375615e4b5..35b57f2582 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -319,8 +319,12 @@ impl HbaPort { } } + pub fn ata_running(&self, slot: u32) -> bool { + (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 + } + pub fn ata_stop(&mut self, slot: u32) -> Result<()> { - while (self.ci.readf(1 << slot) || self.tfd.readf(0x80)) && self.is.read() & HBA_PORT_IS_ERR == 0 { + while self.ata_running(slot) { thread::yield_now(); } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 44596d8bbd..bcab6c4894 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -84,23 +84,13 @@ fn main() { todo.push(packet); } } - - // let mut i = 0; - // while i < todo.len() { - // if let Some(a) = scheme.handle(&todo[i]) { - // let mut packet = todo.remove(i); - // packet.a = a; - // socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); - // } else { - // i += 1; - // } - // } } else if event.id == irq_fd { let mut irq = [0; 8]; if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() { if scheme.irq() { irq_file.write(&irq).expect("ahcid: failed to write irq file"); + // Handle todos in order to finish previous packets if possible let mut i = 0; while i < todo.len() { if let Some(a) = scheme.handle(&todo[i]) { @@ -116,6 +106,18 @@ fn main() { } else { println!("Unknown event {}", event.id); } + + // Handle todos to start new packets if possible + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + } else { + i += 1; + } + } } } unsafe { let _ = syscall::physunmap(address); } From 25aec9f2a797c6451b48d39bcde57f58907a109e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 18 Feb 2019 21:11:41 -0700 Subject: [PATCH 0259/1301] Disable interrupts for ahcid --- ahcid/src/ahci/hba.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 35b57f2582..fec4e0c574 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -116,7 +116,7 @@ impl HbaPort { self.fb[1].write((fb.physical() >> 32) as u32); let is = self.is.read(); self.is.write(is); - self.ie.write(0b10111); + self.ie.write(0 /*TODO: Enable interrupts: 0b10111*/); let serr = self.serr.read(); self.serr.write(serr); From ae8a6075a28517e844ff22e59306d2351b5b3f96 Mon Sep 17 00:00:00 2001 From: Tibor Nagy Date: Tue, 5 Mar 2019 18:35:01 +0100 Subject: [PATCH 0260/1301] Add pcspkr driver --- Cargo.lock | 7 ++++ Cargo.toml | 1 + pcspkrd/Cargo.toml | 8 ++++ pcspkrd/src/main.rs | 42 ++++++++++++++++++++ pcspkrd/src/pcspkr.rs | 35 +++++++++++++++++ pcspkrd/src/scheme.rs | 91 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 184 insertions(+) create mode 100644 pcspkrd/Cargo.toml create mode 100644 pcspkrd/src/main.rs create mode 100644 pcspkrd/src/pcspkr.rs create mode 100644 pcspkrd/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index b1852a7efc..768079d894 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -504,6 +504,13 @@ dependencies = [ "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pcspkrd" +version = "0.1.0" +dependencies = [ + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "percent-encoding" version = "1.0.1" diff --git a/Cargo.toml b/Cargo.toml index 143e3a8b44..b023c37ba3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "ihdad", "nvmed", "pcid", + "pcspkrd", "ps2d", "rtl8168d", "vboxd", diff --git a/pcspkrd/Cargo.toml b/pcspkrd/Cargo.toml new file mode 100644 index 0000000000..ba42a0de19 --- /dev/null +++ b/pcspkrd/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "pcspkrd" +version = "0.1.0" +authors = ["Tibor Nagy "] +edition = "2018" + +[dependencies] +redox_syscall = "0.1" diff --git a/pcspkrd/src/main.rs b/pcspkrd/src/main.rs new file mode 100644 index 0000000000..f84de4e024 --- /dev/null +++ b/pcspkrd/src/main.rs @@ -0,0 +1,42 @@ +mod pcspkr; +mod scheme; + +use std::fs::File; +use std::io::{Read, Write}; +use syscall::data::Packet; +use syscall::iopl; +use syscall::scheme::SchemeMut; + +use self::pcspkr::Pcspkr; +use self::scheme::PcspkrScheme; + +fn main() { + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + unsafe { iopl(3).unwrap() }; + + let mut socket = File::create(":pcspkr").expect("pcspkrd: failed to create pcspkr scheme"); + + let pcspkr = Pcspkr::new(); + println!(" + pcspkr"); + + let mut scheme = PcspkrScheme { + pcspkr: pcspkr, + handle: None, + next_id: 0, + }; + + syscall::setrens(0, 0).expect("pcspkrd: failed to enter null namespace"); + + loop { + let mut packet = Packet::default(); + socket + .read(&mut packet) + .expect("pcspkrd: failed to read events from pcspkr scheme"); + scheme.handle(&mut packet); + socket + .write(&packet) + .expect("pcspkrd: failed to write responses to pcspkr scheme"); + } + } +} diff --git a/pcspkrd/src/pcspkr.rs b/pcspkrd/src/pcspkr.rs new file mode 100644 index 0000000000..f8c6760683 --- /dev/null +++ b/pcspkrd/src/pcspkr.rs @@ -0,0 +1,35 @@ +use syscall::io::{Io, Pio}; + +pub struct Pcspkr { + command: Pio, + channel: Pio, + gate: Pio, +} + +const PIT_FREQUENCY: usize = 0x1234DC; + +impl Pcspkr { + pub fn new() -> Pcspkr { + Pcspkr { + command: Pio::new(0x43), + channel: Pio::new(0x42), + gate: Pio::new(0x61), + } + } + + pub fn set_frequency(&mut self, frequency: usize) { + let div = PIT_FREQUENCY.checked_div(frequency).unwrap_or(0); + self.command.write(0xB6); + self.channel.write((div & 0xFF) as u8); + self.channel.write(((div >> 8) & 0xFF) as u8); + } + + pub fn set_gate(&mut self, state: bool) { + let gate_value = self.gate.read(); + if state { + self.gate.write(gate_value | 0x03); + } else { + self.gate.write(gate_value & 0xFC); + } + } +} diff --git a/pcspkrd/src/scheme.rs b/pcspkrd/src/scheme.rs new file mode 100644 index 0000000000..647e585881 --- /dev/null +++ b/pcspkrd/src/scheme.rs @@ -0,0 +1,91 @@ +use syscall::data::Stat; +use syscall::{ + Error, Result, SchemeMut, EBUSY, EINVAL, EPERM, MODE_CHR, O_ACCMODE, O_STAT, O_WRONLY, +}; + +use crate::pcspkr::Pcspkr; + +pub struct PcspkrScheme { + pub pcspkr: Pcspkr, + pub handle: Option, + pub next_id: usize, +} + +impl SchemeMut for PcspkrScheme { + fn open(&mut self, _path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result { + if (flags & O_ACCMODE == 0) && (flags & O_STAT == O_STAT) { + Ok(0) + } else if flags & O_ACCMODE == O_WRONLY { + if self.handle.is_none() { + self.next_id += 1; + self.handle = Some(self.next_id); + Ok(self.next_id) + } else { + Err(Error::new(EBUSY)) + } + } else { + Err(Error::new(EINVAL)) + } + } + + fn dup(&mut self, _id: usize, _buf: &[u8]) -> Result { + Err(Error::new(EPERM)) + } + + fn read(&mut self, _id: usize, _buf: &mut [u8]) -> Result { + Err(Error::new(EPERM)) + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result { + if self.handle != Some(id) { + return Err(Error::new(EINVAL)); + } + + if buf.len() != 2 { + return Err(Error::new(EINVAL)); + } + + let frequency = buf[0] as usize + ((buf[1] as usize) << 8); + + if frequency == 0 { + self.pcspkr.set_gate(false); + } else { + self.pcspkr.set_frequency(frequency); + self.pcspkr.set_gate(true); + } + + Ok(buf.len()) + } + + fn fpath(&mut self, _id: usize, buf: &mut [u8]) -> Result { + let mut i = 0; + let scheme_path = b"pcspkr"; + while i < buf.len() && i < scheme_path.len() { + buf[i] = scheme_path[i]; + i += 1; + } + Ok(i) + } + + fn fstat(&mut self, _id: usize, stat: &mut Stat) -> Result { + *stat = Stat { + st_mode: MODE_CHR | 0o222, + ..Default::default() + }; + + Ok(0) + } + + fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize) -> Result { + Ok(0) + } + + fn close(&mut self, id: usize) -> Result { + if self.handle == Some(id) { + self.pcspkr.set_gate(false); + self.handle = None; + } + + Ok(0) + } +} From e090281086e35ff5518b0a92812519e6d968b045 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 13 Mar 2019 13:58:55 -0600 Subject: [PATCH 0261/1301] Support for new fevent --- e1000d/src/device.rs | 2 +- rtl8168d/src/device.rs | 2 +- vesad/src/scheme.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 13b875e30d..b4b675fd33 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -211,7 +211,7 @@ impl SchemeBlockMut for Intel8254x { fn fevent(&mut self, id: usize, _flags: usize) -> Result> { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(id)) + Ok(Some(0)) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 37dbb74456..892ee7c5d1 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -176,7 +176,7 @@ impl SchemeMut for Rtl8168 { fn fevent(&mut self, id: usize, _flags: usize) -> Result { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(id) + Ok(0) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 23902152b7..65fec1585b 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -139,7 +139,7 @@ impl SchemeMut for DisplayScheme { if let HandleKind::Screen(_screen_i) = handle.kind { handle.events = flags; - Ok(id) + Ok(0) } else { Err(Error::new(EBADF)) } From 7afaadabd94d8a33368366ccd756ff6b86f2bf0e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 8 Apr 2019 20:22:01 -0600 Subject: [PATCH 0262/1301] Ensure that MMIO memory is mapped without caching --- Cargo.lock | 312 +++++++++++++++++++--------------------- ahcid/src/main.rs | 4 +- alxd/src/main.rs | 4 +- e1000d/src/main.rs | 4 +- ihdad/src/hda/device.rs | 6 +- ihdad/src/hda/stream.rs | 4 +- ihdad/src/main.rs | 4 +- nvmed/src/main.rs | 4 +- rtl8168d/src/main.rs | 4 +- vboxd/src/main.rs | 4 +- xhcid/src/main.rs | 3 +- 11 files changed, 169 insertions(+), 184 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b1852a7efc..662d046acd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,10 +1,12 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. [[package]] name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -14,7 +16,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -48,8 +50,8 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -74,7 +76,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -83,12 +85,12 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.28" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -114,9 +116,9 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -126,8 +128,8 @@ name = "crossbeam-utils" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -137,7 +139,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -147,7 +149,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#0b50f3f2127fa62b [[package]] name = "fuchsia-cprng" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -166,7 +168,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -184,7 +186,7 @@ dependencies = [ "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -219,7 +221,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -228,7 +230,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -253,17 +255,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.48" +version = "0.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "linked-hash-map" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -288,7 +290,7 @@ name = "log" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -318,11 +320,11 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -333,7 +335,7 @@ version = "0.6.6" source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#2936ef82070ea0c4aa8a7360455b8c512d8c88c0" dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", ] @@ -353,26 +355,26 @@ name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#03d76ff3b5c4a42e300e3016f42fd632193bbc9d" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#e28efbd6bbfabe42290e7ef84bca5e4c7f0d4aa2" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.1 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -428,10 +430,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -439,16 +441,16 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "orbclient" -version = "0.3.20" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -474,11 +476,11 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -486,10 +488,10 @@ name = "pbr" version = "1.0.1" source = "git+https://github.com/a8m/pb#b9792c9fe37343234316e23c263874cf383b208d" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -498,9 +500,9 @@ version = "0.1.0" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -527,9 +529,9 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -545,7 +547,7 @@ name = "rand" version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -554,11 +556,11 @@ name = "rand" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -567,16 +569,16 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -619,34 +621,34 @@ dependencies = [ [[package]] name = "rand_jitter" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_os" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_pcg" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -679,12 +681,12 @@ name = "redox_event" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/event.git#c31e3d3d5f44d60ff9fec2b1ee58b982e72c0d77" dependencies = [ - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.51" +version = "0.1.54" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -692,7 +694,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -700,9 +702,9 @@ name = "ring" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -713,7 +715,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -743,7 +745,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -773,7 +775,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -784,7 +786,7 @@ name = "sdl2-sys" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -802,17 +804,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.86" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.86" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -822,11 +824,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "spin" @@ -848,7 +847,7 @@ dependencies = [ [[package]] name = "syn" -version = "0.15.26" +version = "0.15.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", @@ -861,8 +860,8 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -871,20 +870,20 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio" version = "0.1.13" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -901,36 +900,36 @@ dependencies = [ [[package]] name = "tokio-codec" version = "0.1.1" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-current-thread" version = "0.1.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] [[package]] name = "tokio-executor" version = "0.1.5" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-fs" version = "0.1.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -938,24 +937,24 @@ dependencies = [ [[package]] name = "tokio-io" version = "0.1.10" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-reactor" version = "0.1.7" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -965,10 +964,10 @@ dependencies = [ [[package]] name = "tokio-tcp" version = "0.1.2" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -978,13 +977,13 @@ dependencies = [ [[package]] name = "tokio-threadpool" version = "0.1.9" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -992,10 +991,10 @@ dependencies = [ [[package]] name = "tokio-timer" version = "0.2.8" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -1003,10 +1002,10 @@ dependencies = [ [[package]] name = "tokio-udp" version = "0.1.3" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -1017,12 +1016,12 @@ dependencies = [ [[package]] name = "tokio-uds" version = "0.2.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#e90845fe8a0e259eeb569d0424f27e276851dced" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "mio-uds 0.6.6 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", @@ -1036,7 +1035,7 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1070,7 +1069,7 @@ name = "unicode-normalization" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1078,14 +1077,6 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unreachable" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "untrusted" version = "0.6.2" @@ -1110,9 +1101,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1124,17 +1115,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "vte" version = "0.3.3" @@ -1168,7 +1154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1206,7 +1192,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1219,18 +1205,18 @@ dependencies = [ "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" -"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa" -"checksum cc 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4a8b715cb4597106ea87c7c84b2f1d452c7492033765df7f32651e66fcf749" -"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4" +"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" +"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" -"checksum fuchsia-cprng 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81f7f8eb465745ea9b02e2704612a9946a59fa40572086c6fd49d6ddcf30bf31" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b" +"checksum futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "62941eff9507c8177d448bd83a44d9b9760856e184081d8cd79ba9f03dd24981" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "df0caae6b71d266b91b4a83111a61d2b94ed2e2bea024c532b933dcff867e58c" "checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" @@ -1239,9 +1225,9 @@ dependencies = [ "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" -"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" -"checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" +"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" @@ -1259,8 +1245,8 @@ dependencies = [ "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum num_cpus 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5a69d464bdc213aaaff628444e99578ede64e9c854025aa43b9796530afa9238" -"checksum orbclient 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e9209ac5081710688c453af03a9e92b3d4e1e445cd4c60052692758e08e47c5e" +"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" +"checksum orbclient 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc3cb6a2e27e7635ffb7333ce0d32f1bb4f1735979ce6dacc647b1122c86e53" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" @@ -1277,14 +1263,14 @@ dependencies = [ "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0" -"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" -"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" +"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e02b6e263e6d8ab6a7a7637268785506f26860f0c4be83d8d940014d2b3e1601" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" -"checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" +"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -1297,14 +1283,14 @@ dependencies = [ "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)" = "52ab457c27b091c27b887eef7181b3ea11ab4f92f66e3a99b2e556b77f9cc6bd" -"checksum serde_derive 1.0.86 (registry+https://github.com/rust-lang/crates.io-index)" = "51eac71e1171246f337655221882f2f55a9c2e1d8ddc6990cee766509f15b702" +"checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4" +"checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "88aea073965ab29f6edb5493faf96ad662fb18aa9eeb186a3b7057951605ed15" +"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" -"checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" +"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" @@ -1326,17 +1312,15 @@ dependencies = [ "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" -"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" "checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" "checksum webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85d1f408918fd590908a70d36b7ac388db2edc221470333e4d6e5b598e44cabf" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index bcab6c4894..2cc86f79fc 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -7,7 +7,7 @@ use std::{env, usize}; use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::FromRawFd; -use syscall::{EVENT_READ, PHYSMAP_WRITE, Event, Packet, SchemeBlockMut}; +use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, SchemeBlockMut}; use scheme::DiskScheme; @@ -30,7 +30,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 4096, PHYSMAP_WRITE).expect("ahcid: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 4096, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("ahcid: failed to map address") }; { let scheme_name = format!("disk/{}", name); let socket_fd = syscall::open( diff --git a/alxd/src/main.rs b/alxd/src/main.rs index 828e24e48a..f98631e36d 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -16,7 +16,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, SchemeMut, PHYSMAP_WRITE}; +use syscall::{Packet, SchemeMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -43,7 +43,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("alxd: failed to open IRQ file"); - let address = unsafe { syscall::physmap(bar, 128*1024, PHYSMAP_WRITE).expect("alxd: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 128*1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("alxd: failed to map address") }; { let device = Arc::new(RefCell::new(unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") })); diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index d6d8a7e613..b420a0863b 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -12,7 +12,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, SchemeBlockMut, PHYSMAP_WRITE}; +use syscall::{Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -69,7 +69,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); - let address = unsafe { syscall::physmap(bar, 128*1024, PHYSMAP_WRITE).expect("e1000d: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 128*1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("e1000d: failed to map address") }; { let device = Arc::new(RefCell::new(unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") })); diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 7a832d1670..dd74824a97 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -6,7 +6,7 @@ use std::str; use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; -use syscall::PHYSMAP_WRITE; +use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::io::{Mmio, Io}; @@ -159,7 +159,7 @@ impl IntelHDA { }; let buff_desc_virt = unsafe { - syscall::physmap(buff_desc_phys, 0x1000, PHYSMAP_WRITE) + syscall::physmap(buff_desc_phys, 0x1000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("ihdad: failed to map address for buffer descriptor list.") }; @@ -172,7 +172,7 @@ impl IntelHDA { .expect("Could not allocate physical memory for CORB and RIRB.") }; - let cmd_buff_virt = unsafe { syscall::physmap(cmd_buff_address, 0x1000, PHYSMAP_WRITE).expect("ihdad: failed to map address for CORB/RIRB buff") }; + let cmd_buff_virt = unsafe { syscall::physmap(cmd_buff_address, 0x1000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("ihdad: failed to map address for CORB/RIRB buff") }; print!("Virt: {:016X}, Phys: {:016X}\n", cmd_buff_virt, cmd_buff_address); let mut module = IntelHDA { diff --git a/ihdad/src/hda/stream.rs b/ihdad/src/hda/stream.rs index 9d630fbb1f..ecb791aacc 100644 --- a/ihdad/src/hda/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -1,4 +1,4 @@ -use syscall::PHYSMAP_WRITE; +use syscall::{PHYSMAP_WRITE, PHYSMAP_NO_CACHE}; use syscall::error::{Error, EIO, Result}; use syscall::io::{Mmio, Io}; use std::result; @@ -301,7 +301,7 @@ impl StreamBuffer { }; let addr = match unsafe { - syscall::physmap(phys, block_length * block_count, PHYSMAP_WRITE) + syscall::physmap(phys, block_length * block_count, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) } { Ok(addr) => addr, Err(err) => { diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index ae940498c9..abff02312d 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -10,7 +10,7 @@ use std::{env, usize}; use std::fs::File; use std::io::{Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd}; -use syscall::{PHYSMAP_WRITE, Packet, SchemeBlockMut}; +use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Packet, SchemeBlockMut}; use std::cell::RefCell; use std::sync::Arc; @@ -47,7 +47,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 0x4000, PHYSMAP_WRITE).expect("ihdad: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 0x4000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("ihdad: failed to map address") }; { let mut irq_file = File::open(format!("irq:{}", irq)).expect("IHDA: failed to open IRQ file"); diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 9aea3c3501..6035739dd3 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -9,7 +9,7 @@ use std::{env, usize}; use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use syscall::{EVENT_READ, PHYSMAP_WRITE, Event, Packet, Result, Scheme}; +use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, Result, Scheme}; use self::nvme::Nvme; @@ -42,7 +42,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 4096, PHYSMAP_WRITE).expect("nvmed: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 4096, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("nvmed: failed to map address") }; { let mut nvme = Nvme::new(address); nvme.init(); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 39433a8531..03eb75be10 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -12,7 +12,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, SchemeMut, PHYSMAP_WRITE}; +use syscall::{Packet, SchemeMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -38,7 +38,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open IRQ file"); - let address = unsafe { syscall::physmap(bar, 256, PHYSMAP_WRITE).expect("rtl8168d: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 256, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("rtl8168d: failed to map address") }; { let device = Arc::new(RefCell::new(unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") })); diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 90ca4aa105..6d30b4763e 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -9,7 +9,7 @@ use std::{env, mem}; use std::os::unix::io::AsRawFd; use std::fs::File; use std::io::{Result, Read, Write}; -use syscall::flag::PHYSMAP_WRITE; +use syscall::flag::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::io::{Dma, Io, Mmio, Pio}; use syscall::iopl; @@ -217,7 +217,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("vboxd: failed to open IRQ file"); let mut port = Pio::::new(bar0 as u16); - let address = unsafe { syscall::physmap(bar1, 4096, PHYSMAP_WRITE).expect("vboxd: failed to map address") }; + let address = unsafe { syscall::physmap(bar1, 4096, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("vboxd: failed to map address") }; { let vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 2974555369..a5c1d82725 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -12,6 +12,7 @@ use std::io::{Result, Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd}; use std::sync::Arc; use syscall::data::Packet; +use syscall::flag::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; use syscall::scheme::SchemeMut; @@ -41,7 +42,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); - let address = unsafe { syscall::physmap(bar, 65536, syscall::PHYSMAP_WRITE).expect("xhcid: failed to map address") }; + let address = unsafe { syscall::physmap(bar, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("xhcid: failed to map address") }; { let hci = Arc::new(RefCell::new(Xhci::new(address).expect("xhcid: failed to allocate device"))); From 50652ceb9370c533b6d8801290a0602b49837878 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 23 Apr 2019 13:25:41 -0600 Subject: [PATCH 0263/1301] Temporary patches for Redox with unix target family --- Cargo.lock | 717 ++++--------------------------------------- Cargo.toml | 9 + ahcid/src/main.rs | 6 +- alxd/Cargo.toml | 2 +- alxd/src/main.rs | 6 +- e1000d/Cargo.toml | 2 +- e1000d/src/main.rs | 6 +- ihdad/src/main.rs | 4 +- rtl8168d/Cargo.toml | 2 +- rtl8168d/src/main.rs | 6 +- xhcid/src/main.rs | 4 +- 11 files changed, 87 insertions(+), 677 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 662d046acd..4712e5aeda 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ name = "alxd" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", + "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -32,25 +32,11 @@ dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "autocfg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "base64" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -74,70 +60,17 @@ name = "byteorder" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cc" -version = "1.0.35" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cfg-if" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-deque" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "e1000d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", + "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -166,45 +99,6 @@ name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "futures" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "httparse" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hyper" -version = "0.10.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hyper-rustls" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", - "rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "idna" version = "0.1.5" @@ -230,7 +124,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -243,48 +137,21 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "lazy_static" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "lazy_static" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "libc" version = "0.2.51" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix#5c5373d530b61d9fdd7e2dee0dff55003e9268a8" [[package]] name = "linked-hash-map" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "lock_api" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "log" version = "0.4.6" @@ -298,54 +165,31 @@ name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "memoffset" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "mime" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "mio" version = "0.6.16" -source = "git+https://gitlab.redox-os.org/redox-os/mio#493d2b65c12b269c4481fd1dc2cd7d3670a880c9" +source = "git+https://gitlab.redox-os.org/redox-os/mio#439a559b2aa734e0970d37b3375889a57a465360" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "mio-uds" -version = "0.6.6" -source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#2936ef82070ea0c4aa8a7360455b8c512d8c88c0" -dependencies = [ - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", -] - [[package]] name = "miow" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -353,32 +197,28 @@ dependencies = [ [[package]] name = "net2" version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix#b2c7c1e7773f13eebd9b4421172d9e4b5b806ce6" dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#e28efbd6bbfabe42290e7ef84bca5e4c7f0d4aa2" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#482c8285faa70c592d235336faaf7223f195b5d7" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", - "pbr 1.0.1 (git+https://github.com/a8m/pb)", + "pbr 1.0.1 (git+https://gitlab.redox-os.org/redox-os/pb.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -393,7 +233,7 @@ version = "0.0.1" source = "git+https://github.com/willem66745/ntpclient-rust#7e3bdf60eb940825789a8da5181025320e3050b0" dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (git+https://gitlab.redox-os.org/redox-os/time.git?branch=redox-unix)", ] [[package]] @@ -429,12 +269,9 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "num_cpus" -version = "1.10.0" +name = "numtoa" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "nvmed" @@ -447,50 +284,20 @@ dependencies = [ [[package]] name = "orbclient" -version = "0.3.21" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "owning_ref" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "pbr" version = "1.0.1" -source = "git+https://github.com/a8m/pb#b9792c9fe37343234316e23c263874cf383b208d" +source = "git+https://gitlab.redox-os.org/redox-os/pb.git?branch=redox-unix#743300cf9566f77962a5b550db1ba27cc922b6a5" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", + "time 0.1.42 (git+https://gitlab.redox-os.org/redox-os/time.git?branch=redox-unix)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -518,7 +325,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -529,17 +336,17 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -547,7 +354,7 @@ name = "rand" version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -557,39 +364,12 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand_core" version = "0.3.1" @@ -603,62 +383,6 @@ name = "rand_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ransid" version = "0.4.7" @@ -697,48 +421,16 @@ dependencies = [ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ring" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rtl8168d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", + "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustls" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rusttype" version = "0.2.3" @@ -749,25 +441,6 @@ dependencies = [ "stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "safemem" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "scopeguard" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "sct" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "sdl2" version = "0.31.0" @@ -775,7 +448,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -789,19 +462,6 @@ dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "serde" version = "1.0.90" @@ -812,9 +472,9 @@ name = "serde_derive" version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -832,11 +492,6 @@ name = "spin" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "stable_deref_trait" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "stb_truetype" version = "0.2.6" @@ -847,20 +502,21 @@ dependencies = [ [[package]] name = "syn" -version = "0.15.30" +version = "0.15.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "termion" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", + "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -868,168 +524,12 @@ dependencies = [ [[package]] name = "time" version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://gitlab.redox-os.org/redox-os/time.git?branch=redox-unix#fc118e5752aaac833808a25f0850606b675b32ec" dependencies = [ - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio" -version = "0.1.13" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-fs 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-tcp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-codec" -version = "0.1.1" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-executor" -version = "0.1.5" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-fs" -version = "0.1.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-io" -version = "0.1.10" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.7" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.2" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.9" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-timer" -version = "0.2.8" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-udp" -version = "0.1.3" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-uds" -version = "0.2.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "mio-uds 0.6.6 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", - "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - [[package]] name = "toml" version = "0.4.10" @@ -1038,24 +538,6 @@ dependencies = [ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "traitobject" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "typeable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicase" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unicode-bidi" version = "0.3.4" @@ -1077,11 +559,6 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "untrusted" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "url" version = "1.7.2" @@ -1101,21 +578,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "version_check" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1129,24 +601,6 @@ dependencies = [ "utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "webpki" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "webpki-roots" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "winapi" version = "0.2.8" @@ -1196,129 +650,76 @@ dependencies = [ "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[patch.unused]] +name = "ring" +version = "0.14.6" +source = "git+https://gitlab.redox-os.org/redox-os/ring.git?branch=redox-unix#1e177479981854cb7d06bea12e0a6514d26e09a6" + [metadata] "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" -"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" -"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum cc 1.0.35 (registry+https://github.com/rust-lang/crates.io-index)" = "5e5f3fee5eeb60324c2781f1e41286bdee933850fff9b3c672587fed5ec58c83" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" -"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" -"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "62941eff9507c8177d448bd83a44d9b9760856e184081d8cd79ba9f03dd24981" -"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" -"checksum hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "df0caae6b71d266b91b4a83111a61d2b94ed2e2bea024c532b933dcff867e58c" -"checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)" = "bedcc7a809076656486ffe045abeeac163da1b558e963a31e29fbfbeba916917" +"checksum libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)" = "" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" -"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" -"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" -"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" -"checksum mio-uds 0.6.6 (git+https://gitlab.redox-os.org/redox-os/mio-uds)" = "" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)" = "" +"checksum net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)" = "" +"checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)" = "" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" -"checksum num_cpus 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a23f0ed30a54abaa0c7e83b1d2d87ada7c3c23078d1d87815af3e3b6385fbba" -"checksum orbclient 0.3.21 (registry+https://github.com/rust-lang/crates.io-index)" = "3fc3cb6a2e27e7635ffb7333ce0d32f1bb4f1735979ce6dacc647b1122c86e53" -"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" -"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" -"checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" +"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" +"checksum orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0e398a001ca5f52b252d1cf5679d52ddd347d3130ac9ded98549f16537c546" +"checksum pbr 1.0.1 (git+https://gitlab.redox-os.org/redox-os/pb.git?branch=redox-unix)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" -"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" +"checksum proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)" = "ba92c84f814b3f9a44c5cfca7d2ad77fa10710867d2bbb1b3d175ab5f47daa12" +"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e02b6e263e6d8ab6a7a7637268785506f26860f0c4be83d8d940014d2b3e1601" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b" "checksum rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30047cc747a78ae042bf2cd65c79f83c3485d90107535b532d6e8f60e2c89cb1" -"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" -"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" "checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60" "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4" "checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" -"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-fs 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-tcp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)" = "846620ec526c1599c070eff393bfeeeb88a93afa2513fc3b49f1fea84cf7b0ed" +"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" +"checksum time 0.1.42 (git+https://gitlab.redox-os.org/redox-os/time.git?branch=redox-unix)" = "" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" -"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" -"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" -"checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" -"checksum webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85d1f408918fd590908a70d36b7ac388db2edc221470333e4d6e5b598e44cabf" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index 143e3a8b44..664b08e23b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,3 +13,12 @@ members = [ "vesad", "xhcid" ] + +[patch.crates-io] +libc = { git = "https://gitlab.redox-os.org/redox-os/liblibc.git", branch = "redox-unix" } +mio = { git = "https://gitlab.redox-os.org/redox-os/mio" } +net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "redox-unix" } +pbr = { git = "https://gitlab.redox-os.org/redox-os/pb.git", branch = "redox-unix" } +ring = { git = "https://gitlab.redox-os.org/redox-os/ring.git", branch = "redox-unix" } +time = { git = "https://gitlab.redox-os.org/redox-os/time.git", branch = "redox-unix" } +#untrusted = { git = "https://github.com/briansmith/untrusted", tag = "ring-master" } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 2cc86f79fc..43ac054e43 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -6,7 +6,7 @@ extern crate byteorder; use std::{env, usize}; use std::fs::File; use std::io::{Read, Write}; -use std::os::unix::io::FromRawFd; +use std::os::unix::io::{FromRawFd, RawFd}; use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, SchemeBlockMut}; use scheme::DiskScheme; @@ -37,13 +37,13 @@ fn main() { &format!(":{}", scheme_name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK ).expect("ahcid: failed to create disk scheme"); - let mut socket = unsafe { File::from_raw_fd(socket_fd) }; + let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; let irq_fd = syscall::open( &format!("irq:{}", irq), syscall::O_RDWR | syscall::O_NONBLOCK ).expect("ahcid: failed to open irq file"); - let mut irq_file = unsafe { File::from_raw_fd(irq_fd) }; + let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml index 804a3de336..764df5c39d 100644 --- a/alxd/Cargo.toml +++ b/alxd/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "0.7" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/alxd/src/main.rs b/alxd/src/main.rs index f98631e36d..4d0ac6c88b 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -12,7 +12,7 @@ use std::cell::RefCell; use std::env; use std::fs::File; use std::io::{Read, Write, Result}; -use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; @@ -39,7 +39,7 @@ fn main() { if unsafe { syscall::clone(0).unwrap() } == 0 { let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("alxd: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); let mut irq_file = File::open(format!("irq:{}", irq)).expect("alxd: failed to open IRQ file"); @@ -85,7 +85,7 @@ fn main() { }).expect("alxd: failed to catch events on IRQ file"); let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_event| -> Result> { + event_queue.add(socket_fd as RawFd, move |_event| -> Result> { loop { let mut packet = Packet::default(); if socket_packet.borrow_mut().read(&mut packet)? == 0 { diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index eaa8ae9d35..fd1f0a48dd 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "0.7" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index b420a0863b..719685c9e4 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -8,7 +8,7 @@ use std::cell::RefCell; use std::env; use std::fs::File; use std::io::{Read, Write, Result}; -use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; @@ -65,7 +65,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("e1000d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); @@ -100,7 +100,7 @@ fn main() { let device_packet = device.clone(); let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_event| -> Result> { + event_queue.add(socket_fd as RawFd, move |_event| -> Result> { handle_update(&mut socket_packet.borrow_mut(), &mut device_packet.borrow_mut(), &mut todo.borrow_mut()); let next_read = device_packet.borrow().next_read(); diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index abff02312d..feba8a3680 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -9,7 +9,7 @@ extern crate event; use std::{env, usize}; use std::fs::File; use std::io::{Read, Write, Result}; -use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Packet, SchemeBlockMut}; use std::cell::RefCell; use std::sync::Arc; @@ -55,7 +55,7 @@ fn main() { let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); let socket_fd = syscall::open(":hda", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create hda scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); let mut event_queue = EventQueue::::new().expect("IHDA: Could not create event queue."); diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index 661cda88f4..9f5859c1e8 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" [dependencies] bitflags = "0.7" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 03eb75be10..b3b0dd7255 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -8,7 +8,7 @@ use std::cell::RefCell; use std::env; use std::fs::File; use std::io::{Read, Write, Result}; -use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; @@ -34,7 +34,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("rtl8168d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); let mut irq_file = File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open IRQ file"); @@ -83,7 +83,7 @@ fn main() { let device_packet = device.clone(); let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_event| -> Result> { + event_queue.add(socket_fd as RawFd, move |_event| -> Result> { loop { let mut packet = Packet::default(); if socket_packet.borrow_mut().read(&mut packet)? == 0 { diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index a5c1d82725..41ec4b6118 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -9,7 +9,7 @@ use std::cell::RefCell; use std::env; use std::fs::File; use std::io::{Result, Read, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use syscall::data::Packet; use syscall::flag::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; @@ -38,7 +38,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { let socket_fd = syscall::open(":usb", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd) })); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); let mut irq_file = File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); From d1a50d0fd05637b665b285c59998a13e2d4db23c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 15 Jun 2019 10:54:29 -0600 Subject: [PATCH 0264/1301] Remove libc patch --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 664b08e23b..8225d57d8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ members = [ ] [patch.crates-io] -libc = { git = "https://gitlab.redox-os.org/redox-os/liblibc.git", branch = "redox-unix" } mio = { git = "https://gitlab.redox-os.org/redox-os/mio" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "redox-unix" } pbr = { git = "https://gitlab.redox-os.org/redox-os/pb.git", branch = "redox-unix" } From c55307073c11feeb75bf690ba5b52b009093d081 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 16 Jun 2019 11:08:49 -0600 Subject: [PATCH 0265/1301] Remove patches which are now done in the cookbook --- Cargo.toml | 8 -------- 1 file changed, 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8225d57d8c..143e3a8b44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,11 +13,3 @@ members = [ "vesad", "xhcid" ] - -[patch.crates-io] -mio = { git = "https://gitlab.redox-os.org/redox-os/mio" } -net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "redox-unix" } -pbr = { git = "https://gitlab.redox-os.org/redox-os/pb.git", branch = "redox-unix" } -ring = { git = "https://gitlab.redox-os.org/redox-os/ring.git", branch = "redox-unix" } -time = { git = "https://gitlab.redox-os.org/redox-os/time.git", branch = "redox-unix" } -#untrusted = { git = "https://github.com/briansmith/untrusted", tag = "ring-master" } From b50437af8ae6a56156c65ba549d61e2a0fac5abc Mon Sep 17 00:00:00 2001 From: Roland Ruckerbauer Date: Sat, 29 Jun 2019 20:20:28 +0200 Subject: [PATCH 0266/1301] Fixed deprecated syntax in vesad 2018 edition upgrade & fixes for a bunch of 'future error warnings' Actually upgrading all crates to 2018 edition --- Cargo.lock | 67 ++++++++++++++++++------------------- ahcid/Cargo.toml | 1 + ahcid/src/ahci/mod.rs | 6 ++-- ahcid/src/main.rs | 2 +- ahcid/src/scheme.rs | 16 ++++----- alxd/Cargo.toml | 1 + alxd/src/device/mod.rs | 6 ++-- bgad/Cargo.toml | 1 + bgad/src/main.rs | 4 +-- bgad/src/scheme.rs | 2 +- e1000d/Cargo.toml | 1 + e1000d/src/device.rs | 6 ++-- e1000d/src/main.rs | 2 +- ihdad/Cargo.toml | 1 + ihdad/src/hda/device.rs | 10 +++--- ihdad/src/hda/stream.rs | 4 +-- nvmed/Cargo.toml | 1 + nvmed/src/main.rs | 6 ++-- pcid/Cargo.toml | 1 + pcid/src/main.rs | 5 ++- ps2d/Cargo.toml | 1 + ps2d/src/main.rs | 2 +- ps2d/src/state.rs | 4 +-- rtl8168d/Cargo.toml | 1 + vboxd/Cargo.toml | 1 + vboxd/src/main.rs | 2 +- vesad/Cargo.toml | 1 + vesad/src/display.rs | 2 +- vesad/src/main.rs | 6 ++-- vesad/src/scheme.rs | 10 +++--- vesad/src/screen/graphic.rs | 6 ++-- vesad/src/screen/text.rs | 8 ++--- xhcid/Cargo.toml | 1 + xhcid/src/main.rs | 2 +- xhcid/src/xhci/command.rs | 2 +- xhcid/src/xhci/mod.rs | 2 +- xhcid/src/xhci/trb.rs | 2 +- 37 files changed, 102 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4712e5aeda..e8f68a1aea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -124,7 +124,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -144,8 +144,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.51" -source = "git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix#5c5373d530b61d9fdd7e2dee0dff55003e9268a8" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "linked-hash-map" @@ -167,18 +167,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "mio" -version = "0.6.16" -source = "git+https://gitlab.redox-os.org/redox-os/mio#439a559b2aa734e0970d37b3375889a57a465360" +version = "0.6.19" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -189,7 +188,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -197,10 +196,10 @@ dependencies = [ [[package]] name = "net2" version = "0.2.33" -source = "git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix#b2c7c1e7773f13eebd9b4421172d9e4b5b806ce6" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -211,10 +210,10 @@ source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-uni dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", - "pbr 1.0.1 (git+https://gitlab.redox-os.org/redox-os/pb.git?branch=redox-unix)", + "pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -233,7 +232,7 @@ version = "0.0.1" source = "git+https://github.com/willem66745/ntpclient-rust#7e3bdf60eb940825789a8da5181025320e3050b0" dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (git+https://gitlab.redox-os.org/redox-os/time.git?branch=redox-unix)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -294,11 +293,13 @@ dependencies = [ [[package]] name = "pbr" version = "1.0.1" -source = "git+https://gitlab.redox-os.org/redox-os/pb.git?branch=redox-unix#743300cf9566f77962a5b550db1ba27cc922b6a5" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", - "time 0.1.42 (git+https://gitlab.redox-os.org/redox-os/time.git?branch=redox-unix)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -354,7 +355,7 @@ name = "rand" version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -364,7 +365,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -448,7 +449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -515,7 +516,7 @@ name = "termion" version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -524,9 +525,10 @@ dependencies = [ [[package]] name = "time" version = "0.1.42" -source = "git+https://gitlab.redox-os.org/redox-os/time.git?branch=redox-unix#fc118e5752aaac833808a25f0850606b675b32ec" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -650,11 +652,6 @@ dependencies = [ "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[patch.unused]] -name = "ring" -version = "0.14.6" -source = "git+https://gitlab.redox-os.org/redox-os/ring.git?branch=redox-unix#1e177479981854cb7d06bea12e0a6514d26e09a6" - [metadata] "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" @@ -671,13 +668,13 @@ source = "git+https://gitlab.redox-os.org/redox-os/ring.git?branch=redox-unix#1e "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum libc 0.2.51 (git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=redox-unix)" = "" +"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" +"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)" = "" +"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)" = "" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" @@ -687,7 +684,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/ring.git?branch=redox-unix#1e "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0e398a001ca5f52b252d1cf5679d52ddd347d3130ac9ded98549f16537c546" -"checksum pbr 1.0.1 (git+https://gitlab.redox-os.org/redox-os/pb.git?branch=redox-unix)" = "" +"checksum pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "deb73390ab68d81992bd994d145f697451bb0b54fd39738e72eef32458ad6907" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)" = "ba92c84f814b3f9a44c5cfca7d2ad77fa10710867d2bbb1b3d175ab5f47daa12" @@ -712,7 +709,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/ring.git?branch=redox-unix#1e "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" "checksum syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)" = "846620ec526c1599c070eff393bfeeeb88a93afa2513fc3b49f1fea84cf7b0ed" "checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" -"checksum time 0.1.42 (git+https://gitlab.redox-os.org/redox-os/time.git?branch=redox-unix)" = "" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index 0e9644e386..789f7e0b38 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "ahcid" version = "0.1.0" +edition = "2018" [dependencies] bitflags = "0.7" diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index 05792712fd..b72aa59ac5 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -18,18 +18,18 @@ pub trait Disk { fn block_length(&mut self) -> Result; } -pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec>) { +pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec>) { let hba_mem = unsafe { &mut *(base as *mut HbaMem) }; hba_mem.init(); let pi = hba_mem.pi.read(); - let disks: Vec> = (0..hba_mem.ports.len()) + let disks: Vec> = (0..hba_mem.ports.len()) .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) .filter_map(|i| { let port = unsafe { &mut *hba_mem.ports.as_mut_ptr().add(i) }; let port_type = port.probe(); print!("{}", format!("{}-{}: {:?}\n", name, i, port_type)); - let disk: Option> = match port_type { + let disk: Option> = match port_type { HbaPortType::SATA => { match DiskATA::new(i, port) { Ok(disk) => Some(Box::new(disk)), diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 43ac054e43..370b593723 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -9,7 +9,7 @@ use std::io::{Read, Write}; use std::os::unix::io::{FromRawFd, RawFd}; use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, SchemeBlockMut}; -use scheme::DiskScheme; +use crate::scheme::DiskScheme; pub mod ahci; pub mod scheme; diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index b8374f8ce8..28684b2cbc 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -7,8 +7,8 @@ use syscall::{ Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; -use ahci::Disk; -use ahci::hba::HbaMem; +use crate::ahci::Disk; +use crate::ahci::hba::HbaMem; #[derive(Clone)] enum Handle { @@ -19,13 +19,13 @@ enum Handle { pub struct DiskScheme { scheme_name: String, hba_mem: &'static mut HbaMem, - disks: Box<[Box]>, + disks: Box<[Box]>, handles: BTreeMap, next_id: usize } impl DiskScheme { - pub fn new(scheme_name: String, hba_mem: &'static mut HbaMem, disks: Vec>) -> DiskScheme { + pub fn new(scheme_name: String, hba_mem: &'static mut HbaMem, disks: Vec>) -> DiskScheme { DiskScheme { scheme_name: scheme_name, hba_mem: hba_mem, @@ -117,7 +117,7 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(0)) }, Handle::Disk(number, _) => { - let mut disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = disk.size(); Ok(Some(0)) @@ -168,7 +168,7 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(count)) }, Handle::Disk(number, ref mut size) => { - let mut disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; if let Some(count) = disk.read((*size as u64)/(blk_len as u64), buf)? { *size += count; @@ -186,7 +186,7 @@ impl SchemeBlockMut for DiskScheme { Err(Error::new(EBADF)) }, Handle::Disk(number, ref mut size) => { - let mut disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; if let Some(count) = disk.write((*size as u64)/(blk_len as u64), buf)? { *size += count; @@ -212,7 +212,7 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(*size)) }, Handle::Disk(number, ref mut size) => { - let mut disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let len = disk.size() as usize; *size = match whence { SEEK_SET => cmp::min(len, pos), diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml index 764df5c39d..f4466be864 100644 --- a/alxd/Cargo.toml +++ b/alxd/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "alxd" version = "0.1.0" +edition = "2018" [dependencies] bitflags = "0.7" diff --git a/alxd/src/device/mod.rs b/alxd/src/device/mod.rs index 2afdbdaf8a..143f1e48a4 100644 --- a/alxd/src/device/mod.rs +++ b/alxd/src/device/mod.rs @@ -1721,7 +1721,7 @@ impl Alx { } unsafe fn open(&mut self) -> usize { - let mut err: usize = 0; + let _err: usize = 0; macro_rules! goto_out { () => {{ @@ -1805,7 +1805,7 @@ impl scheme::SchemeMut for Alx { Ok(id) } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + fn read(&mut self, id: usize, _buf: &mut [u8]) -> Result { /* let head = unsafe { self.read(RDH) }; let mut tail = unsafe { self.read(RDT) }; @@ -1842,7 +1842,7 @@ impl scheme::SchemeMut for Alx { } } - fn write(&mut self, _id: usize, buf: &[u8]) -> Result { + fn write(&mut self, _id: usize, _buf: &[u8]) -> Result { /* loop { let head = unsafe { self.read(TDH) }; diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml index 289f65cd54..f240b720fc 100644 --- a/bgad/Cargo.toml +++ b/bgad/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "bgad" version = "0.1.0" +edition = "2018" [dependencies] orbclient = "0.3" diff --git a/bgad/src/main.rs b/bgad/src/main.rs index e326899aba..0c8f2835e5 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -10,8 +10,8 @@ use syscall::iopl; use syscall::data::Packet; use syscall::scheme::SchemeMut; -use bga::Bga; -use scheme::BgaScheme; +use crate::bga::Bga; +use crate::scheme::BgaScheme; mod bga; mod scheme; diff --git a/bgad/src/scheme.rs b/bgad/src/scheme.rs index e4ce64eced..bad949c717 100644 --- a/bgad/src/scheme.rs +++ b/bgad/src/scheme.rs @@ -5,7 +5,7 @@ use std::str; use syscall::{Error, Result, SchemeMut, EACCES, EINVAL, MODE_CHR}; use syscall::data::Stat; -use bga::Bga; +use crate::bga::Bga; pub struct BgaScheme { pub bga: Bga, diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index fd1f0a48dd..bdd4a8844a 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "e1000d" version = "0.1.0" +edition = "2018" [dependencies] bitflags = "0.7" diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index b4b675fd33..72e066b063 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -55,7 +55,7 @@ const RDT: u32 = 0x2818; const RAL0: u32 = 0x5400; const RAH0: u32 = 0x5404; -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] #[repr(packed)] struct Rd { buffer: u64, @@ -78,7 +78,7 @@ const TDLEN: u32 = 0x3808; const TDH: u32 = 0x3810; const TDT: u32 = 0x3818; -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] #[repr(packed)] struct Td { buffer: u64, @@ -190,7 +190,7 @@ impl SchemeBlockMut for Intel8254x { td.length = (cmp::min(buf.len(), 0x3FFF)) as u16; - let mut data = unsafe { slice::from_raw_parts_mut(self.transmit_buffer[old_tail as usize].as_ptr() as *mut u8, td.length as usize) }; + let data = unsafe { slice::from_raw_parts_mut(self.transmit_buffer[old_tail as usize].as_ptr() as *mut u8, td.length as usize) }; let mut i = 0; while i < buf.len() && i < data.len() { diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 719685c9e4..755bff8d89 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -13,7 +13,7 @@ use std::sync::Arc; use event::EventQueue; use syscall::{Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; -use syscall::error::EWOULDBLOCK; + pub mod device; diff --git a/ihdad/Cargo.toml b/ihdad/Cargo.toml index 23e365aa01..ec6d85b871 100755 --- a/ihdad/Cargo.toml +++ b/ihdad/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "ihdad" version = "0.1.0" +edition = "2018" [dependencies] bitflags = "0.7" diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index dd74824a97..ae77fe5b98 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -790,21 +790,21 @@ impl IntelHDA { for i in 0..iss { if ((sis >> i) & 1 ) == 1 { - let mut input = self.get_input_stream_descriptor(i).unwrap(); + let input = self.get_input_stream_descriptor(i).unwrap(); input.clear_interrupts(); } } for i in 0..oss { if ((sis >> (i + iss)) & 1 ) == 1 { - let mut output = self.get_output_stream_descriptor(i).unwrap(); + let output = self.get_output_stream_descriptor(i).unwrap(); output.clear_interrupts(); } } for i in 0..bss { if ((sis >> (i + iss + oss)) & 1 ) == 1 { - let mut bid = self.get_bidirectional_stream_descriptor(i).unwrap(); + let bid = self.get_bidirectional_stream_descriptor(i).unwrap(); bid.clear_interrupts(); } } @@ -897,7 +897,7 @@ impl SchemeBlockMut for IntelHDA { fn write(&mut self, id: usize, buf: &[u8]) -> Result> { let index = { let mut handles = self.handles.lock(); - let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; 0 }; @@ -926,7 +926,7 @@ impl SchemeBlockMut for IntelHDA { fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let mut handles = self.handles.lock(); - let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; let mut i = 0; let scheme_path = b"hda:"; diff --git a/ihdad/src/hda/stream.rs b/ihdad/src/hda/stream.rs index ecb791aacc..0f46da305a 100644 --- a/ihdad/src/hda/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -295,7 +295,7 @@ impl StreamBuffer { syscall::physalloc(block_length * block_count) } { Ok(phys) => phys, - Err(err) => { + Err(_err) => { return Err("Could not allocate physical memory for buffer."); } }; @@ -304,7 +304,7 @@ impl StreamBuffer { syscall::physmap(phys, block_length * block_count, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) } { Ok(addr) => addr, - Err(err) => { + Err(_err) => { unsafe { syscall::physfree(phys, block_length * block_count); } diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index fbdc36977d..7bd235dc99 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "nvmed" version = "0.1.0" +edition = "2018" [dependencies] bitflags = "0.7" diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 6035739dd3..bacc3878e6 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -6,9 +6,9 @@ extern crate spin; extern crate syscall; use std::{env, usize}; -use std::fs::File; -use std::io::{Read, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; + + + use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, Result, Scheme}; use self::nvme::Nvme; diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 56465ba9fd..e35303f094 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "pcid" version = "0.1.0" +edition = "2018" [dependencies] bitflags = "1.0" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 259664612a..dbad37c1c2 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,5 +1,4 @@ #![feature(asm)] -#![feature(iterator_step_by)] #[macro_use] extern crate bitflags; extern crate byteorder; @@ -13,8 +12,8 @@ use std::io::Read; use std::process::Command; use syscall::iopl; -use config::Config; -use pci::{Pci, PciClass, PciHeader, PciHeaderError, PciHeaderType}; +use crate::config::Config; +use crate::pci::{Pci, PciClass, PciHeader, PciHeaderError, PciHeaderType}; mod config; mod pci; diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 559e6340c8..f8ac54ebb9 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "ps2d" version = "0.1.0" +edition = "2018" [dependencies] bitflags = "0.7" diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 0dc1c9bd4c..9fd7922d62 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use event::EventQueue; use syscall::iopl; -use state::Ps2d; +use crate::state::Ps2d; mod controller; mod keymap; diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 11472767a0..eb428dc309 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -5,8 +5,8 @@ use std::io::Write; use std::os::unix::io::AsRawFd; use syscall; -use controller::Ps2; -use vm; +use crate::controller::Ps2; +use crate::vm; bitflags! { flags MousePacketFlags: u8 { diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index 9f5859c1e8..0ad6373cb3 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "rtl8168d" version = "0.1.0" +edition = "2018" [dependencies] bitflags = "0.7" diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index 99d1448cf9..dfb5bbe505 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "vboxd" version = "0.1.0" +edition = "2018" [dependencies] orbclient = "0.3" diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 6d30b4763e..74ee1612b4 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -13,7 +13,7 @@ use syscall::flag::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::io::{Dma, Io, Mmio, Pio}; use syscall::iopl; -use bga::Bga; +use crate::bga::Bga; mod bga; diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 76a4553d3f..4e12f77657 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "vesad" version = "0.1.0" +edition = "2018" [dependencies] orbclient = "0.3" diff --git a/vesad/src/display.rs b/vesad/src/display.rs index bb25dcb841..1b4f2cb8bb 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -5,7 +5,7 @@ use std::alloc::{Alloc, Global, Layout}; use std::{cmp, slice}; use std::ptr::NonNull; -use primitive::{fast_set32, fast_set64, fast_copy}; +use crate::primitive::{fast_set32, fast_set64, fast_copy}; #[cfg(feature="rusttype")] use self::rusttype::{Font, FontCollection, Scale, point}; diff --git a/vesad/src/main.rs b/vesad/src/main.rs index b5ec9cd7b8..b8aaceabb6 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -10,9 +10,9 @@ use std::fs::File; use std::io::{Read, Write}; use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE}; -use mode_info::VBEModeInfo; -use primitive::fast_set64; -use scheme::{DisplayScheme, HandleKind}; +use crate::mode_info::VBEModeInfo; +use crate::primitive::fast_set64; +use crate::scheme::{DisplayScheme, HandleKind}; pub mod display; pub mod mode_info; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 65fec1585b..46eff7639a 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -4,8 +4,8 @@ use std::{mem, slice, str}; use orbclient::{Event, EventOption}; use syscall::{Result, Error, EACCES, EBADF, EINVAL, ENOENT, O_NONBLOCK, Map, SchemeMut}; -use display::Display; -use screen::{Screen, GraphicScreen, TextScreen}; +use crate::display::Display; +use crate::screen::{Screen, GraphicScreen, TextScreen}; #[derive(Clone)] pub enum HandleKind { @@ -25,14 +25,14 @@ pub struct DisplayScheme { width: usize, height: usize, active: usize, - pub screens: BTreeMap>, + pub screens: BTreeMap>, next_id: usize, pub handles: BTreeMap, } impl DisplayScheme { pub fn new(width: usize, height: usize, onscreen: usize, spec: &[bool]) -> DisplayScheme { - let mut screens: BTreeMap> = BTreeMap::new(); + let mut screens: BTreeMap> = BTreeMap::new(); let mut screen_i = 1; for &screen_type in spec.iter() { @@ -227,7 +227,7 @@ impl SchemeMut for DisplayScheme { let mut new_active_opt = None; match event.to_option() { EventOption::Key(key_event) => match key_event.scancode { - f @ 0x3B ... 0x44 => { // F1 through F10 + f @ 0x3B ..= 0x44 => { // F1 through F10 new_active_opt = Some((f - 0x3A) as usize); }, 0x57 => { // F11 diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index f428099c7a..0cb6739594 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -5,9 +5,9 @@ use orbclient::{Event, ResizeEvent}; use syscall::error::*; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; -use display::Display; -use primitive::fast_copy; -use screen::Screen; +use crate::display::Display; +use crate::primitive::fast_copy; +use crate::screen::Screen; pub struct GraphicScreen { pub display: Display, diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 34e794ff17..38b7a2976f 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -6,8 +6,8 @@ use std::ptr; use orbclient::{Event, EventOption}; use syscall::error::*; -use display::Display; -use screen::Screen; +use crate::display::Display; +use crate::screen::Screen; pub struct TextScreen { pub console: ransid::Console, @@ -92,8 +92,8 @@ impl Screen for TextScreen { }, _ => { let c = match key_event.character { - c @ 'A' ... 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char, - c @ 'a' ... 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char, + c @ 'A' ..= 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char, + c @ 'a' ..= 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char, c => c }; diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index f7eca3c226..9d8b2e7bd1 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "xhcid" version = "0.1.0" +edition = "2018" [dependencies] bitflags = "0.7" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 41ec4b6118..4fa3e5ea3a 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -16,7 +16,7 @@ use syscall::flag::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; use syscall::scheme::SchemeMut; -use xhci::Xhci; +use crate::xhci::Xhci; mod usb; mod xhci; diff --git a/xhcid/src/xhci/command.rs b/xhcid/src/xhci/command.rs index 76ba0e6b4e..56449a66e3 100644 --- a/xhcid/src/xhci/command.rs +++ b/xhcid/src/xhci/command.rs @@ -1,5 +1,5 @@ use syscall::error::Result; -use syscall::io::Dma; + use super::event::EventRing; use super::ring::Ring; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 795d9a7169..64bd94e539 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -2,7 +2,7 @@ use plain::Plain; use std::{mem, slice}; use syscall::error::Result; use syscall::io::{Dma, Io}; -use usb; +use crate::usb; mod capability; mod command; diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index c4193422ae..459fdc6b4a 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -1,6 +1,6 @@ use std::{fmt, mem}; use syscall::io::{Io, Mmio}; -use usb; +use crate::usb; #[repr(u8)] pub enum TrbType { From 42c2184d7030e240ddf79096347c2f352c1b31aa Mon Sep 17 00:00:00 2001 From: Simon Ellmann Date: Tue, 25 Jun 2019 01:05:24 +0200 Subject: [PATCH 0267/1301] Add ixgbe driver --- .gitmodules | 3 +++ Cargo.toml | 1 + filesystem.toml | 8 ++++++++ ixgbed | 1 + 4 files changed, 13 insertions(+) create mode 100644 .gitmodules create mode 160000 ixgbed diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..73ccf1a62a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ixgbed"] + path = ixgbed + url = https://github.com/ackxolotl/ixgbed.git diff --git a/Cargo.toml b/Cargo.toml index b023c37ba3..b871350843 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "bgad", "e1000d", "ihdad", + "ixgbed", "nvmed", "pcid", "pcspkrd", diff --git a/filesystem.toml b/filesystem.toml index ff38fb336a..8362313d0f 100644 --- a/filesystem.toml +++ b/filesystem.toml @@ -1,5 +1,13 @@ ## Drivers for FS ## +# ixgbed +[[drivers]] +name = "Intel 10G X550T NIC" +class = 2 +vendor = 32902 +device = 5475 +command = ["ixgbed", "$NAME", "$BAR0", "$IRQ"] + # e1000d [[drivers]] name = "82543GC NIC" diff --git a/ixgbed b/ixgbed new file mode 160000 index 0000000000..50154bdbde --- /dev/null +++ b/ixgbed @@ -0,0 +1 @@ +Subproject commit 50154bdbde634e9ca872fa8edf413af076e31053 From 581110082711aefea2f9e16073df95893377b8e8 Mon Sep 17 00:00:00 2001 From: Simon Ellmann Date: Mon, 1 Jul 2019 02:31:55 +0200 Subject: [PATCH 0268/1301] Make pcid parse config files from directory --- pcid/src/main.rs | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 259664612a..2c247cdfda 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -8,7 +8,7 @@ extern crate syscall; extern crate toml; use std::env; -use std::fs::File; +use std::fs::{File, metadata, read_dir}; use std::io::Read; use std::process::Command; use syscall::iopl; @@ -161,11 +161,28 @@ fn main() { let mut args = env::args().skip(1); if let Some(config_path) = args.next() { - if let Ok(mut config_file) = File::open(&config_path) { - let mut config_data = String::new(); - if let Ok(_) = config_file.read_to_string(&mut config_data) { - config = toml::from_str(&config_data).unwrap_or(Config::default()); + if metadata(&config_path).unwrap().is_file() { + if let Ok(mut config_file) = File::open(&config_path) { + let mut config_data = String::new(); + if let Ok(_) = config_file.read_to_string(&mut config_data) { + config = toml::from_str(&config_data).unwrap_or(Config::default()); + } } + } else { + let paths = read_dir(&config_path).unwrap(); + + let mut config_data = String::new(); + + for path in paths { + if let Ok(mut config_file) = File::open(&path.unwrap().path()) { + let mut tmp = String::new(); + if let Ok(_) = config_file.read_to_string(&mut tmp) { + config_data.push_str(&tmp); + } + } + } + + config = toml::from_str(&config_data).unwrap_or(Config::default()); } } From 645c54e9a40e5db2b095178f90d0e936d4cdec13 Mon Sep 17 00:00:00 2001 From: Simon Ellmann Date: Mon, 1 Jul 2019 23:10:03 +0200 Subject: [PATCH 0269/1301] Simplify mapping of vendor and device ids in driver toml files by adding an ids field --- pcid/src/config.rs | 1 + pcid/src/main.rs | 30 ++++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/pcid/src/config.rs b/pcid/src/config.rs index 8a36d8df1d..ee7756c82e 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -11,6 +11,7 @@ pub struct DriverConfig { pub class: Option, pub subclass: Option, pub interface: Option, + pub ids: Option>>, pub vendor: Option, pub device: Option, pub device_id_range: Option>, diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 2c247cdfda..bf5581fc0d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -7,7 +7,7 @@ extern crate byteorder; extern crate syscall; extern crate toml; -use std::env; +use std::{env, i64}; use std::fs::{File, metadata, read_dir}; use std::io::Read; use std::process::Command; @@ -80,12 +80,30 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, if interface != header.interface() { continue; } } - if let Some(vendor) = driver.vendor { - if vendor != header.vendor_id() { continue; } - } + if let Some(ref ids) = driver.ids { + let mut device_found = false; + for (vendor, devices) in ids { + let vendor_without_prefix = vendor.trim_left_matches("0x"); + let vendor = i64::from_str_radix(vendor_without_prefix, 16).unwrap() as u16; - if let Some(device) = driver.device { - if device != header.device_id() { continue; } + if vendor != header.vendor_id() { continue; } + + for device in devices { + if *device == header.device_id() { + device_found = true; + break; + } + } + } + if !device_found { continue; } + } else { + if let Some(vendor) = driver.vendor { + if vendor != header.vendor_id() { continue; } + } + + if let Some(device) = driver.device { + if device != header.device_id() { continue; } + } } if let Some(ref device_id_range) = driver.device_id_range { From e70bdc838ae9d555911f81f14d84025192a3dbd5 Mon Sep 17 00:00:00 2001 From: Simon Ellmann Date: Tue, 2 Jul 2019 14:38:57 +0200 Subject: [PATCH 0270/1301] Split filesystem.toml into separate config.toml for each driver --- e1000d/config.toml | 6 +++++ filesystem.toml | 52 -------------------------------------------- ihdad/config.toml | 6 +++++ ixgbed | 2 +- rtl8168d/config.toml | 6 +++++ 5 files changed, 19 insertions(+), 53 deletions(-) create mode 100644 e1000d/config.toml create mode 100644 ihdad/config.toml create mode 100644 rtl8168d/config.toml diff --git a/e1000d/config.toml b/e1000d/config.toml new file mode 100644 index 0000000000..0f5f3339b3 --- /dev/null +++ b/e1000d/config.toml @@ -0,0 +1,6 @@ +[[drivers]] +name = "E1000 NIC" +class = 2 +ids = { 0x8086 = [0x1004, 0x100e, 0x100f, 0x1503] } +command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] + diff --git a/filesystem.toml b/filesystem.toml index 8362313d0f..20871a0272 100644 --- a/filesystem.toml +++ b/filesystem.toml @@ -1,57 +1,5 @@ ## Drivers for FS ## -# ixgbed -[[drivers]] -name = "Intel 10G X550T NIC" -class = 2 -vendor = 32902 -device = 5475 -command = ["ixgbed", "$NAME", "$BAR0", "$IRQ"] - -# e1000d -[[drivers]] -name = "82543GC NIC" -class = 2 -vendor = 32902 -device = 4100 -command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] - -[[drivers]] -name = "82540EM NIC" -class = 2 -vendor = 32902 -device = 4110 -command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] - -[[drivers]] -name = "82545EM NIC" -class = 2 -vendor = 32902 -device = 4111 -command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] - -[[drivers]] -name = "82579V NIC" -class = 2 -vendor = 32902 -device = 5379 -command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] - -# ihdad -[[drivers]] -name = "Intel HD Audio" -class = 4 -subclass = 3 -command = ["ihdad", "$NAME", "$BAR0", "$IRQ", "$VENID", "$DEVID"] - -# rtl8168d -[[drivers]] -name = "RTL8168 NIC" -class = 2 -vendor = 4332 -device = 33128 -command = ["rtl8168d", "$NAME", "$BAR2", "$IRQ"] - # xhcid # [[drivers]] # name = "XHCI" diff --git a/ihdad/config.toml b/ihdad/config.toml new file mode 100644 index 0000000000..2bee08c1f4 --- /dev/null +++ b/ihdad/config.toml @@ -0,0 +1,6 @@ +[[drivers]] +name = "Intel HD Audio" +class = 4 +subclass = 3 +command = ["ihdad", "$NAME", "$BAR0", "$IRQ", "$VENID", "$DEVID"] + diff --git a/ixgbed b/ixgbed index 50154bdbde..26c0142179 160000 --- a/ixgbed +++ b/ixgbed @@ -1 +1 @@ -Subproject commit 50154bdbde634e9ca872fa8edf413af076e31053 +Subproject commit 26c0142179a8fbcae22d1d48979681fe029c04e3 diff --git a/rtl8168d/config.toml b/rtl8168d/config.toml new file mode 100644 index 0000000000..04a3626044 --- /dev/null +++ b/rtl8168d/config.toml @@ -0,0 +1,6 @@ +[[drivers]] +name = "RTL8168 NIC" +class = 2 +ids = { 0x10ec = [0x8168] } +command = ["rtl8168d", "$NAME", "$BAR2", "$IRQ"] + From 1e3413acaa90849877fd1ccc23c2d57e1fb0cda0 Mon Sep 17 00:00:00 2001 From: Simon Ellmann Date: Wed, 3 Jul 2019 20:20:54 +0200 Subject: [PATCH 0271/1301] Add ixgbe driver and split filesystem.toml into separate driver config files --- .gitmodules | 3 +++ e1000d/config.toml | 6 +++++ filesystem.toml | 44 ---------------------------------- ihdad/config.toml | 6 +++++ ixgbed | 1 + pcid/src/config.rs | 1 + pcid/src/main.rs | 57 +++++++++++++++++++++++++++++++++++--------- rtl8168d/config.toml | 6 +++++ 8 files changed, 69 insertions(+), 55 deletions(-) create mode 100644 .gitmodules create mode 100644 e1000d/config.toml create mode 100644 ihdad/config.toml create mode 160000 ixgbed create mode 100644 rtl8168d/config.toml diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..73ccf1a62a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ixgbed"] + path = ixgbed + url = https://github.com/ackxolotl/ixgbed.git diff --git a/e1000d/config.toml b/e1000d/config.toml new file mode 100644 index 0000000000..0f5f3339b3 --- /dev/null +++ b/e1000d/config.toml @@ -0,0 +1,6 @@ +[[drivers]] +name = "E1000 NIC" +class = 2 +ids = { 0x8086 = [0x1004, 0x100e, 0x100f, 0x1503] } +command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] + diff --git a/filesystem.toml b/filesystem.toml index ff38fb336a..20871a0272 100644 --- a/filesystem.toml +++ b/filesystem.toml @@ -1,49 +1,5 @@ ## Drivers for FS ## -# e1000d -[[drivers]] -name = "82543GC NIC" -class = 2 -vendor = 32902 -device = 4100 -command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] - -[[drivers]] -name = "82540EM NIC" -class = 2 -vendor = 32902 -device = 4110 -command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] - -[[drivers]] -name = "82545EM NIC" -class = 2 -vendor = 32902 -device = 4111 -command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] - -[[drivers]] -name = "82579V NIC" -class = 2 -vendor = 32902 -device = 5379 -command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] - -# ihdad -[[drivers]] -name = "Intel HD Audio" -class = 4 -subclass = 3 -command = ["ihdad", "$NAME", "$BAR0", "$IRQ", "$VENID", "$DEVID"] - -# rtl8168d -[[drivers]] -name = "RTL8168 NIC" -class = 2 -vendor = 4332 -device = 33128 -command = ["rtl8168d", "$NAME", "$BAR2", "$IRQ"] - # xhcid # [[drivers]] # name = "XHCI" diff --git a/ihdad/config.toml b/ihdad/config.toml new file mode 100644 index 0000000000..2bee08c1f4 --- /dev/null +++ b/ihdad/config.toml @@ -0,0 +1,6 @@ +[[drivers]] +name = "Intel HD Audio" +class = 4 +subclass = 3 +command = ["ihdad", "$NAME", "$BAR0", "$IRQ", "$VENID", "$DEVID"] + diff --git a/ixgbed b/ixgbed new file mode 160000 index 0000000000..26c0142179 --- /dev/null +++ b/ixgbed @@ -0,0 +1 @@ +Subproject commit 26c0142179a8fbcae22d1d48979681fe029c04e3 diff --git a/pcid/src/config.rs b/pcid/src/config.rs index 8a36d8df1d..ee7756c82e 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -11,6 +11,7 @@ pub struct DriverConfig { pub class: Option, pub subclass: Option, pub interface: Option, + pub ids: Option>>, pub vendor: Option, pub device: Option, pub device_id_range: Option>, diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 259664612a..bf5581fc0d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -7,8 +7,8 @@ extern crate byteorder; extern crate syscall; extern crate toml; -use std::env; -use std::fs::File; +use std::{env, i64}; +use std::fs::{File, metadata, read_dir}; use std::io::Read; use std::process::Command; use syscall::iopl; @@ -80,12 +80,30 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, if interface != header.interface() { continue; } } - if let Some(vendor) = driver.vendor { - if vendor != header.vendor_id() { continue; } - } + if let Some(ref ids) = driver.ids { + let mut device_found = false; + for (vendor, devices) in ids { + let vendor_without_prefix = vendor.trim_left_matches("0x"); + let vendor = i64::from_str_radix(vendor_without_prefix, 16).unwrap() as u16; - if let Some(device) = driver.device { - if device != header.device_id() { continue; } + if vendor != header.vendor_id() { continue; } + + for device in devices { + if *device == header.device_id() { + device_found = true; + break; + } + } + } + if !device_found { continue; } + } else { + if let Some(vendor) = driver.vendor { + if vendor != header.vendor_id() { continue; } + } + + if let Some(device) = driver.device { + if device != header.device_id() { continue; } + } } if let Some(ref device_id_range) = driver.device_id_range { @@ -161,11 +179,28 @@ fn main() { let mut args = env::args().skip(1); if let Some(config_path) = args.next() { - if let Ok(mut config_file) = File::open(&config_path) { - let mut config_data = String::new(); - if let Ok(_) = config_file.read_to_string(&mut config_data) { - config = toml::from_str(&config_data).unwrap_or(Config::default()); + if metadata(&config_path).unwrap().is_file() { + if let Ok(mut config_file) = File::open(&config_path) { + let mut config_data = String::new(); + if let Ok(_) = config_file.read_to_string(&mut config_data) { + config = toml::from_str(&config_data).unwrap_or(Config::default()); + } } + } else { + let paths = read_dir(&config_path).unwrap(); + + let mut config_data = String::new(); + + for path in paths { + if let Ok(mut config_file) = File::open(&path.unwrap().path()) { + let mut tmp = String::new(); + if let Ok(_) = config_file.read_to_string(&mut tmp) { + config_data.push_str(&tmp); + } + } + } + + config = toml::from_str(&config_data).unwrap_or(Config::default()); } } diff --git a/rtl8168d/config.toml b/rtl8168d/config.toml new file mode 100644 index 0000000000..04a3626044 --- /dev/null +++ b/rtl8168d/config.toml @@ -0,0 +1,6 @@ +[[drivers]] +name = "RTL8168 NIC" +class = 2 +ids = { 0x10ec = [0x8168] } +command = ["rtl8168d", "$NAME", "$BAR2", "$IRQ"] + From 55da4bcb84a0a3086d18fb37423bd1ca613323c5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 3 Jul 2019 19:57:32 -0600 Subject: [PATCH 0272/1301] Add missing import --- pcid/src/config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pcid/src/config.rs b/pcid/src/config.rs index ee7756c82e..74ba8b4eaa 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -1,3 +1,4 @@ +use std::collections::BTreeMap; use std::ops::Range; #[derive(Debug, Default, Deserialize)] From e88a65e11bc2e484f83e9fd38b7409bb0c998606 Mon Sep 17 00:00:00 2001 From: Simon Ellmann Date: Fri, 5 Jul 2019 16:03:38 +0200 Subject: [PATCH 0273/1301] Add ixgbed to Cargo.toml --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 143e3a8b44..e64eaaa390 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "bgad", "e1000d", "ihdad", + "ixgbed", "nvmed", "pcid", "ps2d", From 6c993af1a21ccdc771db851738fd5fa988308f30 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Sat, 6 Jul 2019 18:42:51 +0200 Subject: [PATCH 0274/1301] Update ixgbed --- Cargo.lock | 669 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ixgbed | 2 +- 2 files changed, 670 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index e8f68a1aea..51807078cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,20 @@ dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "autocfg" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "base64" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bgad" version = "0.1.0" @@ -60,11 +74,64 @@ name = "byteorder" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "bytes" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-deque" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "e1000d" version = "0.1.0" @@ -99,6 +166,45 @@ name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "futures" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hyper" +version = "0.10.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hyper-rustls" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", + "rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "idna" version = "0.1.5" @@ -128,6 +234,16 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ixgbed" +version = "1.0.0" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", + "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -137,11 +253,21 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "language-tags" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazy_static" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.2.58" @@ -152,6 +278,23 @@ name = "linked-hash-map" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lock_api" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "log" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.6" @@ -165,6 +308,37 @@ name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "memoffset" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "mime" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mio" +version = "0.6.16" +source = "git+https://gitlab.redox-os.org/redox-os/mio#439a559b2aa734e0970d37b3375889a57a465360" +dependencies = [ + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "mio" version = "0.6.19" @@ -182,6 +356,16 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "mio-uds" +version = "0.6.7" +source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#22580ca398cdb5ed6f50fb61134e5579e2213999" +dependencies = [ + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", +] + [[package]] name = "miow" version = "0.2.1" @@ -203,6 +387,28 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "netutils" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#e28efbd6bbfabe42290e7ef84bca5e4c7f0d4aa2" +dependencies = [ + "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", + "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", + "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", + "pbr 1.0.1 (git+https://github.com/a8m/pb)", + "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", + "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "netutils" version = "0.1.0" @@ -267,6 +473,14 @@ name = "num-traits" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "num_cpus" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "numtoa" version = "0.1.0" @@ -290,6 +504,46 @@ dependencies = [ "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "owning_ref" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pbr" +version = "1.0.1" +source = "git+https://github.com/a8m/pb#b9792c9fe37343234316e23c263874cf383b208d" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pbr" version = "1.0.1" @@ -371,6 +625,33 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -384,6 +665,62 @@ name = "rand_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ransid" version = "0.4.7" @@ -422,6 +759,17 @@ dependencies = [ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ring" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rtl8168d" version = "0.1.0" @@ -432,6 +780,27 @@ dependencies = [ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustls" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", + "sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rusttype" version = "0.2.3" @@ -442,6 +811,25 @@ dependencies = [ "stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "safemem" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "scopeguard" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "sct" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sdl2" version = "0.31.0" @@ -463,6 +851,19 @@ dependencies = [ "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" version = "1.0.90" @@ -493,6 +894,11 @@ name = "spin" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "stable_deref_trait" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "stb_truetype" version = "0.2.6" @@ -532,6 +938,161 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tokio" +version = "0.1.13" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-fs 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-tcp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-codec" +version = "0.1.1" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-executor" +version = "0.1.5" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-fs" +version = "0.1.4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-io" +version = "0.1.10" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-reactor" +version = "0.1.7" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-tcp" +version = "0.1.2" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-threadpool" +version = "0.1.9" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-timer" +version = "0.2.8" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-udp" +version = "0.1.3" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + +[[package]] +name = "tokio-uds" +version = "0.2.4" +source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" +dependencies = [ + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", + "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", + "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", +] + [[package]] name = "toml" version = "0.4.10" @@ -540,6 +1101,24 @@ dependencies = [ "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "traitobject" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "typeable" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicase" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-bidi" version = "0.3.4" @@ -561,6 +1140,11 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "untrusted" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "url" version = "1.7.2" @@ -585,6 +1169,11 @@ dependencies = [ "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vesad" version = "0.1.0" @@ -603,6 +1192,24 @@ dependencies = [ "utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "webpki" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "webpki-roots" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -655,26 +1262,47 @@ dependencies = [ [metadata] "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" +"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" +"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" +"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" +"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" +"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" +"checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" +"checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" +"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" +"checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" +"checksum mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)" = "" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +"checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)" = "" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)" = "" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" @@ -682,8 +1310,13 @@ dependencies = [ "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" +"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0e398a001ca5f52b252d1cf5679d52ddd347d3130ac9ded98549f16537c546" +"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" +"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +"checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" "checksum pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "deb73390ab68d81992bd994d145f697451bb0b54fd39738e72eef32458ad6907" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" @@ -691,32 +1324,68 @@ dependencies = [ "checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e02b6e263e6d8ab6a7a7637268785506f26860f0c4be83d8d940014d2b3e1601" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b" "checksum rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30047cc747a78ae042bf2cd65c79f83c3485d90107535b532d6e8f60e2c89cb1" +"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" +"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" "checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60" "checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4" "checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" +"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" "checksum syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)" = "846620ec526c1599c070eff393bfeeeb88a93afa2513fc3b49f1fea84cf7b0ed" "checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-fs 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-tcp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" +"checksum tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" +"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" +"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" +"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" +"checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" +"checksum webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85d1f408918fd590908a70d36b7ac388db2edc221470333e4d6e5b598e44cabf" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/ixgbed b/ixgbed index 26c0142179..96d9becf66 160000 --- a/ixgbed +++ b/ixgbed @@ -1 +1 @@ -Subproject commit 26c0142179a8fbcae22d1d48979681fe029c04e3 +Subproject commit 96d9becf66cda99c03431b6b0763481d2e6d3d77 From 217e51f8307adb03b06a8f06f2540f2a56c6992d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 18 Jul 2019 21:04:52 -0600 Subject: [PATCH 0275/1301] ahcid: Handle EOF --- ahcid/src/main.rs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 370b593723..9522634593 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -5,9 +5,9 @@ extern crate byteorder; use std::{env, usize}; use std::fs::File; -use std::io::{Read, Write}; +use std::io::{ErrorKind, Read, Write}; use std::os::unix::io::{FromRawFd, RawFd}; -use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, SchemeBlockMut}; +use syscall::{ENODEV, EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Error, Event, Packet, SchemeBlockMut}; use crate::scheme::DiskScheme; @@ -64,8 +64,9 @@ fn main() { let (hba_mem, disks) = ahci::disks(address, &name); let mut scheme = DiskScheme::new(scheme_name, hba_mem, disks); + let mut mounted = true; let mut todo = Vec::new(); - loop { + while mounted { let mut event = Event::default(); if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 { break; @@ -73,8 +74,17 @@ fn main() { if event.id == socket_fd { loop { let mut packet = Packet::default(); - if socket.read(&mut packet).expect("ahcid: failed to read disk scheme") == 0 { - break; + match socket.read(&mut packet) { + Ok(0) => { + mounted = false; + break; + }, + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; + } else { + panic!("ahcid: failed to read disk scheme: {}", err); + } } if let Some(a) = scheme.handle(&packet) { @@ -113,11 +123,18 @@ fn main() { if let Some(a) = scheme.handle(&todo[i]) { let mut packet = todo.remove(i); packet.a = a; - socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + socket.write(&packet).expect("ahcid: failed to write disk scheme"); } else { i += 1; } } + + if ! mounted { + for mut packet in todo.drain(..) { + packet.a = Error::mux(Err(Error::new(ENODEV))); + socket.write(&packet).expect("ahcid: failed to write disk scheme"); + } + } } } unsafe { let _ = syscall::physunmap(address); } From 974fe7488fa8750602caa90ca4bb1a2b6ec2a2c6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 18 Jul 2019 21:10:02 -0600 Subject: [PATCH 0276/1301] e1000d: handle EOF --- e1000d/src/main.rs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 755bff8d89..a2e88466e8 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -7,7 +7,7 @@ extern crate syscall; use std::cell::RefCell; use std::env; use std::fs::File; -use std::io::{Read, Write, Result}; +use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; @@ -17,7 +17,7 @@ use syscall::{Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; pub mod device; -fn handle_update(socket: &mut File, device: &mut device::Intel8254x, todo: &mut Vec) -> Result<()> { +fn handle_update(socket: &mut File, device: &mut device::Intel8254x, todo: &mut Vec) -> Result { // Handle any blocked packets let mut i = 0; while i < todo.len() { @@ -33,8 +33,14 @@ fn handle_update(socket: &mut File, device: &mut device::Intel8254x, todo: &mut // Check that the socket is empty loop { let mut packet = Packet::default(); - if socket.read(&mut packet)? == 0 { - break; + match socket.read(&mut packet) { + Ok(0) => return Ok(true), + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } } if let Some(a) = device.handle(&packet) { @@ -45,7 +51,7 @@ fn handle_update(socket: &mut File, device: &mut device::Intel8254x, todo: &mut } } - Ok(()) + Ok(false) } fn main() { @@ -88,7 +94,9 @@ fn main() { if unsafe { device_irq.borrow().irq() } { irq_file.write(&mut irq)?; - handle_update(&mut socket_irq.borrow_mut(), &mut device_irq.borrow_mut(), &mut todo_irq.borrow_mut())?; + if handle_update(&mut socket_irq.borrow_mut(), &mut device_irq.borrow_mut(), &mut todo_irq.borrow_mut())? { + return Ok(Some(0)) + } let next_read = device_irq.borrow().next_read(); if next_read > 0 { @@ -101,7 +109,9 @@ fn main() { let device_packet = device.clone(); let socket_packet = socket.clone(); event_queue.add(socket_fd as RawFd, move |_event| -> Result> { - handle_update(&mut socket_packet.borrow_mut(), &mut device_packet.borrow_mut(), &mut todo.borrow_mut()); + if handle_update(&mut socket_packet.borrow_mut(), &mut device_packet.borrow_mut(), &mut todo.borrow_mut())? { + return Ok(Some(0)); + } let next_read = device_packet.borrow().next_read(); if next_read > 0 { @@ -135,6 +145,9 @@ fn main() { loop { let event_count = event_queue.run().expect("e1000d: failed to handle events"); + if event_count == 0 { + break; + } send_events(event_count); } } From dfd21dfd36c509530a5613ae672e1bf4b2b548a9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 18 Jul 2019 21:13:30 -0600 Subject: [PATCH 0277/1301] ihdad: Handle EOF --- ihdad/src/main.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index feba8a3680..d1f37307be 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -8,7 +8,7 @@ extern crate event; use std::{env, usize}; use std::fs::File; -use std::io::{Read, Write, Result}; +use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Packet, SchemeBlockMut}; use std::cell::RefCell; @@ -100,8 +100,14 @@ fn main() { event_queue.add(socket_fd, move |_event| -> Result> { loop { let mut packet = Packet::default(); - if socket_packet.borrow_mut().read(&mut packet)? == 0 { - break; + match socket_packet.borrow_mut().read(&mut packet) { + Ok(0) => return Ok(Some(0)), + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } } if let Some(a) = device.borrow_mut().handle(&mut packet) { @@ -143,6 +149,10 @@ fn main() { //device_loop.borrow_mut().handle_interrupts(); } let event_count = event_queue.run().expect("IHDA: failed to handle events"); + if event_count == 0 { + //TODO: Handle todo + break; + } socket.borrow_mut().write(&Packet { id: 0, From c259b9d44c535683a01a754b77382b76532815a9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 18 Jul 2019 21:14:20 -0600 Subject: [PATCH 0278/1301] Add TODO to eventually handle in-flight syscalls with ENODEV --- e1000d/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index a2e88466e8..1ca21f1969 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -146,6 +146,7 @@ fn main() { loop { let event_count = event_queue.run().expect("e1000d: failed to handle events"); if event_count == 0 { + //TODO: Handle todo break; } send_events(event_count); From b77f9f6b2f70170dc35f8d82eaf2292bcbca4042 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 18 Jul 2019 21:15:24 -0600 Subject: [PATCH 0279/1301] bgad: handle EOF --- bgad/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bgad/src/main.rs b/bgad/src/main.rs index 0c8f2835e5..d2ff217f30 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -45,7 +45,9 @@ fn main() { loop { let mut packet = Packet::default(); - socket.read(&mut packet).expect("bgad: failed to read events from bga scheme"); + if socket.read(&mut packet).expect("bgad: failed to read events from bga scheme") == 0 { + break; + } scheme.handle(&mut packet); socket.write(&packet).expect("bgad: failed to write responses to bga scheme"); } From 41f689bec36c6fe649320adfd64a585ee7b2dba0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 18 Jul 2019 21:17:13 -0600 Subject: [PATCH 0280/1301] vesad: handle EOF --- vesad/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index b8aaceabb6..9bcb62d251 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -65,7 +65,10 @@ fn main() { let mut blocked = Vec::new(); loop { let mut packet = Packet::default(); - socket.read(&mut packet).expect("vesad: failed to read display scheme"); + if socket.read(&mut packet).expect("vesad: failed to read display scheme") == 0 { + //TODO: Handle blocked + break; + } // If it is a read packet, and there is no data, block it. Otherwise, handle packet if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.can_read(packet.b).is_none() { From 56894fbdc2b6241fce93e324f549f883e36ec9e7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 26 Jul 2019 20:13:37 -0600 Subject: [PATCH 0281/1301] rtl8168d: handle EOF --- rtl8168d/src/main.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index b3b0dd7255..19908dba1b 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -7,7 +7,7 @@ extern crate syscall; use std::cell::RefCell; use std::env; use std::fs::File; -use std::io::{Read, Write, Result}; +use std::io::{self, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; @@ -86,8 +86,14 @@ fn main() { event_queue.add(socket_fd as RawFd, move |_event| -> Result> { loop { let mut packet = Packet::default(); - if socket_packet.borrow_mut().read(&mut packet)? == 0 { - break; + match socket_packet.borrow_mut().read(&mut packet) { + Ok(0) => return Ok(Some(0)), + Ok(_) => (), + Err(err) => if err.kind() == io::ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } } let a = packet.a; @@ -132,6 +138,9 @@ fn main() { loop { let event_count = event_queue.run().expect("rtl8168d: failed to handle events"); + if event_count == 0 { + break; + } send_events(event_count); } } From 16dfc7785ed24b884c29c419c5edd65600129e61 Mon Sep 17 00:00:00 2001 From: Simon Ellmann Date: Tue, 30 Jul 2019 13:01:54 +0200 Subject: [PATCH 0282/1301] ixgbed: handle EOF --- ixgbed | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ixgbed b/ixgbed index 96d9becf66..4b10450a7a 160000 --- a/ixgbed +++ b/ixgbed @@ -1 +1 @@ -Subproject commit 96d9becf66cda99c03431b6b0763481d2e6d3d77 +Subproject commit 4b10450a7aabcabfda8b6b4367eacdd8f38c13e0 From 5e4b53fe929671fdb9cd4ce43f83bac44e446b5d Mon Sep 17 00:00:00 2001 From: Simon Ellmann Date: Tue, 30 Jul 2019 13:20:30 +0200 Subject: [PATCH 0283/1301] Speed up e1000 driver --- e1000d/src/device.rs | 214 +++++++++++++++++++++++++------------------ e1000d/src/main.rs | 149 +++++++++++++++++++----------- 2 files changed, 218 insertions(+), 145 deletions(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 72e066b063..bded679c9e 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,8 +1,8 @@ -use std::{cmp, mem, ptr, slice, thread}; use std::collections::BTreeMap; +use std::{cmp, mem, ptr, slice, thread}; use netutils::setcfg; -use syscall::error::{Error, EACCES, EBADF, EINVAL, EWOULDBLOCK, Result}; +use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; use syscall::flag::O_NONBLOCK; use syscall::io::Dma; use syscall::scheme::SchemeBlockMut; @@ -98,12 +98,20 @@ pub struct Intel8254x { base: usize, receive_buffer: [Dma<[u8; 16384]>; 16], receive_ring: Dma<[Rd; 16]>, + receive_index: usize, transmit_buffer: [Dma<[u8; 16384]>; 16], transmit_ring: Dma<[Td; 16]>, + transmit_ring_free: usize, + transmit_index: usize, + transmit_clean_index: usize, next_id: usize, pub handles: BTreeMap, } +fn wrap_ring(index: usize, ring_size: usize) -> usize { + (index + 1) & (ring_size - 1) +} + impl SchemeBlockMut for Intel8254x { fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { if uid == 0 { @@ -116,7 +124,7 @@ impl SchemeBlockMut for Intel8254x { } fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if ! buf.is_empty() { + if !buf.is_empty() { return Err(Error::new(EINVAL)); } @@ -132,31 +140,20 @@ impl SchemeBlockMut for Intel8254x { fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - let head = unsafe { self.read_reg(RDH) }; - let mut tail = unsafe { self.read_reg(RDT) }; + let desc = unsafe { &mut *(self.receive_ring.as_ptr().add(self.receive_index) as *mut Rd) }; - tail += 1; - if tail >= self.receive_ring.len() as u32 { - tail = 0; - } + if desc.status & RD_DD == RD_DD { + desc.status = 0; - if tail != head { - let rd = unsafe { &mut * (self.receive_ring.as_ptr().offset(tail as isize) as *mut Rd) }; - if rd.status & RD_DD == RD_DD { - rd.status = 0; + let data = &self.receive_buffer[self.receive_index][..desc.length as usize]; - let data = &self.receive_buffer[tail as usize][.. rd.length as usize]; + let i = cmp::min(buf.len(), data.len()); + buf[..i].copy_from_slice(&data[..i]); - let mut i = 0; - while i < buf.len() && i < data.len() { - buf[i] = data[i]; - i += 1; - } + unsafe { self.write_reg(RDT, self.receive_index as u32) }; + self.receive_index = wrap_ring(self.receive_index, self.receive_ring.len()); - unsafe { self.write_reg(RDT, tail) }; - - return Ok(Some(i)); - } + return Ok(Some(i)); } if flags & O_NONBLOCK == O_NONBLOCK { @@ -169,44 +166,56 @@ impl SchemeBlockMut for Intel8254x { fn write(&mut self, id: usize, buf: &[u8]) -> Result> { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - loop { - let head = unsafe { self.read_reg(TDH) }; - let mut tail = unsafe { self.read_reg(TDT) }; - let old_tail = tail; + if self.transmit_ring_free == 0 { + loop { + let desc = unsafe { + &*(self.transmit_ring.as_ptr().add(self.transmit_clean_index) as *const Td) + }; - tail += 1; - if tail >= self.transmit_ring.len() as u32 { - tail = 0; - } - - if tail != head { - let td = unsafe { &mut * (self.transmit_ring.as_ptr().offset(old_tail as isize) as *mut Td) }; - - td.cso = 0; - td.command = TD_CMD_EOP | TD_CMD_IFCS | TD_CMD_RS; - td.status = 0; - td.css = 0; - td.special = 0; - - td.length = (cmp::min(buf.len(), 0x3FFF)) as u16; - - let data = unsafe { slice::from_raw_parts_mut(self.transmit_buffer[old_tail as usize].as_ptr() as *mut u8, td.length as usize) }; - - let mut i = 0; - while i < buf.len() && i < data.len() { - data[i] = buf[i]; - i += 1; + if desc.status != 0 { + self.transmit_clean_index = + wrap_ring(self.transmit_clean_index, self.transmit_ring.len()); + self.transmit_ring_free += 1; + } else if self.transmit_ring_free > 0 { + break; } - unsafe { self.write_reg(TDT, tail) }; - - while td.status == 0 { - thread::yield_now(); + if self.transmit_ring_free >= self.transmit_ring.len() { + break; } - - return Ok(Some(i)); } } + + let desc = + unsafe { &mut *(self.transmit_ring.as_ptr().add(self.transmit_index) as *mut Td) }; + + let data = unsafe { + slice::from_raw_parts_mut( + self.transmit_buffer[self.transmit_index].as_ptr() as *mut u8, + cmp::min(buf.len(), self.transmit_buffer[self.transmit_index].len()) as usize, + ) + }; + + let i = cmp::min(buf.len(), data.len()); + data[..i].copy_from_slice(&buf[..i]); + + desc.cso = 0; + desc.command = TD_CMD_EOP | TD_CMD_IFCS | TD_CMD_RS; + desc.status = 0; + desc.css = 0; + desc.special = 0; + + desc.length = (cmp::min( + buf.len(), + self.transmit_buffer[self.transmit_index].len() - 1, + )) as u16; + + self.transmit_index = wrap_ring(self.transmit_index, self.transmit_ring.len()); + self.transmit_ring_free -= 1; + + unsafe { self.write_reg(TDT, self.transmit_index as u32) }; + + Ok(Some(i)) } fn fevent(&mut self, id: usize, _flags: usize) -> Result> { @@ -239,20 +248,29 @@ impl SchemeBlockMut for Intel8254x { impl Intel8254x { pub unsafe fn new(base: usize) -> Result { + #[rustfmt::skip] let mut module = Intel8254x { base: base, - receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], + receive_buffer: [ + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + ], receive_ring: Dma::zeroed()?, - transmit_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], + transmit_buffer: [ + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + ], + receive_index: 0, transmit_ring: Dma::zeroed()?, + transmit_ring_free: 16, + transmit_index: 0, + transmit_clean_index: 0, next_id: 0, - handles: BTreeMap::new() + handles: BTreeMap::new(), }; module.init(); @@ -266,19 +284,10 @@ impl Intel8254x { } pub fn next_read(&self) -> usize { - let head = unsafe { self.read_reg(RDH) }; - let mut tail = unsafe { self.read_reg(RDT) }; + let desc = unsafe { &*(self.receive_ring.as_ptr().add(self.receive_index) as *const Rd) }; - tail += 1; - if tail >= self.receive_ring.len() as u32 { - tail = 0; - } - - if tail != head { - let rd = unsafe { &* (self.receive_ring.as_ptr().offset(tail as isize) as *const Rd) }; - if rd.status & RD_DD == RD_DD { - return rd.length as usize; - } + if desc.status & RD_DD == RD_DD { + return desc.length as usize; } 0 @@ -324,14 +333,28 @@ impl Intel8254x { let mac_low = self.read_reg(RAL0); let mac_high = self.read_reg(RAH0); - let mac = [mac_low as u8, - (mac_low >> 8) as u8, - (mac_low >> 16) as u8, - (mac_low >> 24) as u8, - mac_high as u8, - (mac_high >> 8) as u8]; - print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); - let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + let mac = [ + mac_low as u8, + (mac_low >> 8) as u8, + (mac_low >> 16) as u8, + (mac_low >> 24) as u8, + mac_high as u8, + (mac_high >> 8) as u8, + ]; + print!( + "{}", + format!( + " - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + ) + ); + let _ = setcfg( + "mac", + &format!( + "{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + ), + ); // // MTA => 0; @@ -344,7 +367,10 @@ impl Intel8254x { self.write_reg(RDBAH, (self.receive_ring.physical() >> 32) as u32); self.write_reg(RDBAL, self.receive_ring.physical() as u32); - self.write_reg(RDLEN, (self.receive_ring.len() * mem::size_of::()) as u32); + self.write_reg( + RDLEN, + (self.receive_ring.len() * mem::size_of::()) as u32, + ); self.write_reg(RDH, 0); self.write_reg(RDT, self.receive_ring.len() as u32 - 1); @@ -355,7 +381,10 @@ impl Intel8254x { self.write_reg(TDBAH, (self.transmit_ring.physical() >> 32) as u32); self.write_reg(TDBAL, self.transmit_ring.physical() as u32); - self.write_reg(TDLEN, (self.transmit_ring.len() * mem::size_of::()) as u32); + self.write_reg( + TDLEN, + (self.transmit_ring.len() * mem::size_of::()) as u32, + ); self.write_reg(TDH, 0); self.write_reg(TDT, 0); @@ -384,10 +413,13 @@ impl Intel8254x { while self.read_reg(STATUS) & 2 != 2 { print!(" - Waiting for link up: {:X}\n", self.read_reg(STATUS)); } - print!(" - Link is up with speed {}\n", match (self.read_reg(STATUS) >> 6) & 0b11 { - 0b00 => "10 Mb/s", - 0b01 => "100 Mb/s", - _ => "1000 Mb/s", - }); + print!( + " - Link is up with speed {}\n", + match (self.read_reg(STATUS) >> 6) & 0b11 { + 0b00 => "10 Mb/s", + 0b01 => "100 Mb/s", + _ => "1000 Mb/s", + } + ); } } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 1ca21f1969..fb87503ef4 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -7,17 +7,20 @@ extern crate syscall; use std::cell::RefCell; use std::env; use std::fs::File; -use std::io::{ErrorKind, Read, Write, Result}; +use std::io::{ErrorKind, Read, Result, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; use syscall::{Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; - pub mod device; -fn handle_update(socket: &mut File, device: &mut device::Intel8254x, todo: &mut Vec) -> Result { +fn handle_update( + socket: &mut File, + device: &mut device::Intel8254x, + todo: &mut Vec, +) -> Result { // Handle any blocked packets let mut i = 0; while i < todo.len() { @@ -36,10 +39,12 @@ fn handle_update(socket: &mut File, device: &mut device::Intel8254x, todo: &mut match socket.read(&mut packet) { Ok(0) => return Ok(true), Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); + Err(err) => { + if err.kind() == ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } } } @@ -66,20 +71,36 @@ fn main() { let irq_str = args.next().expect("e1000d: no irq provided"); let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); - print!("{}", format!(" + E1000 {} on: {:X} IRQ: {}\n", name, bar, irq)); + print!( + "{}", + format!(" + E1000 {} on: {:X} IRQ: {}\n", name, bar, irq) + ); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("e1000d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + let socket_fd = syscall::open( + ":network", + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + ) + .expect("e1000d: failed to create network scheme"); + let socket = Arc::new(RefCell::new(unsafe { + File::from_raw_fd(socket_fd as RawFd) + })); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); + let mut irq_file = + File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); - let address = unsafe { syscall::physmap(bar, 128*1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("e1000d: failed to map address") }; + let address = unsafe { + syscall::physmap(bar, 128 * 1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("e1000d: failed to map address") + }; { - let device = Arc::new(RefCell::new(unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") })); + let device = Arc::new(RefCell::new(unsafe { + device::Intel8254x::new(address).expect("e1000d: failed to allocate device") + })); - let mut event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); + let mut event_queue = + EventQueue::::new().expect("e1000d: failed to create event queue"); syscall::setrens(0, 0).expect("e1000d: failed to enter null namespace"); @@ -88,58 +109,76 @@ fn main() { let device_irq = device.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - if unsafe { device_irq.borrow().irq() } { - irq_file.write(&mut irq)?; + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + if unsafe { device_irq.borrow().irq() } { + irq_file.write(&mut irq)?; - if handle_update(&mut socket_irq.borrow_mut(), &mut device_irq.borrow_mut(), &mut todo_irq.borrow_mut())? { - return Ok(Some(0)) - } + if handle_update( + &mut socket_irq.borrow_mut(), + &mut device_irq.borrow_mut(), + &mut todo_irq.borrow_mut(), + )? { + return Ok(Some(0)); + } - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }).expect("e1000d: failed to catch events on IRQ file"); + let next_read = device_irq.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + } + Ok(None) + }, + ) + .expect("e1000d: failed to catch events on IRQ file"); let device_packet = device.clone(); let socket_packet = socket.clone(); - event_queue.add(socket_fd as RawFd, move |_event| -> Result> { - if handle_update(&mut socket_packet.borrow_mut(), &mut device_packet.borrow_mut(), &mut todo.borrow_mut())? { - return Ok(Some(0)); - } + event_queue + .add(socket_fd as RawFd, move |_event| -> Result> { + if handle_update( + &mut socket_packet.borrow_mut(), + &mut device_packet.borrow_mut(), + &mut todo.borrow_mut(), + )? { + return Ok(Some(0)); + } - let next_read = device_packet.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } + let next_read = device_packet.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } - Ok(None) - }).expect("e1000d: failed to catch events on scheme file"); + Ok(None) + }) + .expect("e1000d: failed to catch events on scheme file"); let send_events = |event_count| { for (handle_id, _handle) in device.borrow().handles.iter() { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: syscall::flag::EVENT_READ, - d: event_count - }).expect("e1000d: failed to write event"); + socket + .borrow_mut() + .write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: syscall::flag::EVENT_READ, + d: event_count, + }) + .expect("e1000d: failed to write event"); } }; - for event_count in event_queue.trigger_all(event::Event { - fd: 0, - flags: 0, - }).expect("e1000d: failed to trigger events") { + for event_count in event_queue + .trigger_all(event::Event { fd: 0, flags: 0 }) + .expect("e1000d: failed to trigger events") + { send_events(event_count); } @@ -152,6 +191,8 @@ fn main() { send_events(event_count); } } - unsafe { let _ = syscall::physunmap(address); } + unsafe { + let _ = syscall::physunmap(address); + } } } From 89d8a8a6f6cfe9d369c34d45a7e241b10887ba12 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 12 Aug 2019 13:37:03 -0600 Subject: [PATCH 0284/1301] Support MouseRelativeEvent --- Cargo.lock | 390 ++++++++++++++++++++++------------------------ bgad/Cargo.toml | 2 +- ps2d/Cargo.toml | 2 +- ps2d/src/main.rs | 1 - ps2d/src/state.rs | 61 ++++---- vboxd/Cargo.toml | 2 +- vesad/Cargo.toml | 2 +- 7 files changed, 220 insertions(+), 240 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 51807078cb..6503d68d9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,8 +5,8 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -16,17 +16,17 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "arg_parser" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/arg-parser.git#7503531821b0c111f9fac77a5d2536ea221105fe" +source = "git+https://gitlab.redox-os.org/redox-os/arg-parser.git#1c434b55f3e1a0375ebcca85b3e88db7378e82fa" [[package]] name = "arrayvec" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -34,7 +34,7 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -42,16 +42,16 @@ name = "base64" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "safemem 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -61,7 +61,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -71,7 +71,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.3.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -79,18 +79,18 @@ name = "bytes" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.7" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -98,7 +98,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -106,29 +106,29 @@ name = "crossbeam-deque" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-utils" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -139,7 +139,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -157,7 +157,7 @@ name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -221,7 +221,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -230,7 +230,7 @@ name = "iovec" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -238,10 +238,10 @@ dependencies = [ name = "ixgbed" version = "1.0.0" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -258,11 +258,6 @@ name = "language-tags" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "lazy_static" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "lazy_static" version = "1.3.0" @@ -270,7 +265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.58" +version = "0.2.61" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -292,15 +287,15 @@ name = "log" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -310,8 +305,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memoffset" -version = "0.2.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "mime" @@ -330,11 +328,11 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -348,8 +346,8 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -362,7 +360,7 @@ version = "0.6.7" source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#22580ca398cdb5ed6f50fb61134e5579e2213999" dependencies = [ "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", ] @@ -382,8 +380,8 @@ name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -396,14 +394,14 @@ dependencies = [ "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.1 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -412,18 +410,18 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#482c8285faa70c592d235336faaf7223f195b5d7" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#649265429a25c80a7e30063c932367d625ff79c5" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -446,39 +444,44 @@ name = "num" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.39" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" -version = "0.1.37" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -491,17 +494,17 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "orbclient" -version = "0.3.22" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -526,10 +529,10 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -538,8 +541,8 @@ name = "pbr" version = "1.0.1" source = "git+https://github.com/a8m/pb#b9792c9fe37343234316e23c263874cf383b208d" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -550,8 +553,8 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -560,11 +563,11 @@ dependencies = [ name = "pcid" version = "0.1.0" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -580,7 +583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.28" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -591,38 +594,17 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.6.12" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.3.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -630,10 +612,10 @@ name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -648,7 +630,7 @@ name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -657,12 +639,12 @@ name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -686,8 +668,8 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -698,8 +680,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -709,8 +691,8 @@ name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -723,10 +705,10 @@ dependencies = [ [[package]] name = "ransid" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -743,12 +725,12 @@ name = "redox_event" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/event.git#c31e3d3d5f44d60ff9fec2b1ee58b982e72c0d77" dependencies = [ - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.54" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -756,7 +738,7 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -764,9 +746,9 @@ name = "ring" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -777,7 +759,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -794,7 +776,7 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", "sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -806,14 +788,14 @@ name = "rusttype" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "safemem" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -821,6 +803,11 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "sct" version = "0.4.0" @@ -832,23 +819,24 @@ dependencies = [ [[package]] name = "sdl2" -version = "0.31.0" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sdl2-sys" -version = "0.31.0" +version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -866,17 +854,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.90" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.90" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -886,7 +874,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.9" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -904,27 +892,27 @@ name = "stb_truetype" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.15.32" +version = "0.15.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "termion" -version = "1.5.2" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -933,8 +921,8 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1004,7 +992,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc1 dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1012,10 +1000,10 @@ name = "tokio-reactor" version = "0.1.7" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1043,9 +1031,9 @@ version = "0.1.9" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -1056,7 +1044,7 @@ name = "tokio-timer" version = "0.2.8" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -1069,7 +1057,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc1 dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -1084,8 +1072,8 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -1098,7 +1086,7 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1132,7 +1120,7 @@ name = "unicode-normalization" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1164,9 +1152,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1178,9 +1166,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", + "ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1255,26 +1243,26 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" -"checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" -"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)" = "39f75544d7bbaf57560d2168f28fd649ff9c76153874db88bdbdfd839b1a7e7d" -"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" +"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" -"checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" -"checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" +"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" +"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" @@ -1287,15 +1275,14 @@ dependencies = [ "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" +"checksum libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)" = "c665266eb592905e8503ba3403020f4b8794d26263f412ca33171600eca9a6fa" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" @@ -1307,12 +1294,12 @@ dependencies = [ "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" -"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124" -"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" -"checksum orbclient 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0e398a001ca5f52b252d1cf5679d52ddd347d3130ac9ded98549f16537c546" +"checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" @@ -1320,45 +1307,44 @@ dependencies = [ "checksum pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "deb73390ab68d81992bd994d145f697451bb0b54fd39738e72eef32458ad6907" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro2 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)" = "ba92c84f814b3f9a44c5cfca7d2ad77fa10710867d2bbb1b3d175ab5f47daa12" -"checksum quote 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "faf4799c5d274f3868a4aae320a0a182cbd2baee377b378f080e16a23e9d80db" -"checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" "checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" "checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum ransid 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "e02b6e263e6d8ab6a7a7637268785506f26860f0c4be83d8d940014d2b3e1601" +"checksum ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" -"checksum redox_syscall 0.1.54 (registry+https://github.com/rust-lang/crates.io-index)" = "12229c14a0f65c4f1cb046a3b52047cdd9da1f4b30f8a39c5063c8bae515e252" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b" "checksum rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30047cc747a78ae042bf2cd65c79f83c3485d90107535b532d6e8f60e2c89cb1" -"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9" +"checksum safemem 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e133ccc4f4d1cd4f89cc8a7ff618287d56dc7f638b8e38fc32c5fdcadc339dd5" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" -"checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60" -"checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7" +"checksum sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d051a07231e303f5f719da78cb6f7394f6d5b54f733aef5b0b447804a83edd7b" +"checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "aa5f7c20820475babd2c077c3ab5f8c77a31c15e16ea38687b4c02d3e48680f4" -"checksum serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)" = "58fc82bec244f168b23d1963b45c8bf5726e9a15a9d146a067f9081aeed2de79" +"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113" +"checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c4488ae950c49d403731982257768f48fada354a5203fe81f9bb6f43ca9002be" +"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" -"checksum syn 0.15.32 (registry+https://github.com/rust-lang/crates.io-index)" = "846620ec526c1599c070eff393bfeeeb88a93afa2513fc3b49f1fea84cf7b0ed" -"checksum termion 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dde0593aeb8d47accea5392b39350015b5eccb12c0d98044d856983d89548dea" +"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml index f240b720fc..d7611f9d8a 100644 --- a/bgad/Cargo.toml +++ b/bgad/Cargo.toml @@ -4,5 +4,5 @@ version = "0.1.0" edition = "2018" [dependencies] -orbclient = "0.3" +orbclient = "0.3.27" redox_syscall = "0.1" diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index f8ac54ebb9..34ef208a98 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -5,6 +5,6 @@ edition = "2018" [dependencies] bitflags = "0.7" -orbclient = "0.3" +orbclient = "0.3.27" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 9fd7922d62..38c8a3c5ff 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -1,4 +1,3 @@ -#![deny(warnings)] #![feature(asm)] #[macro_use] diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index eb428dc309..13c71c0876 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -1,8 +1,8 @@ -use orbclient::{KeyEvent, MouseEvent, ButtonEvent, ScrollEvent}; -use std::cmp; +use orbclient::{KeyEvent, MouseEvent, MouseRelativeEvent, ButtonEvent, ScrollEvent}; use std::fs::File; use std::io::Write; use std::os::unix::io::AsRawFd; +use std::str; use syscall; use crate::controller::Ps2; @@ -46,7 +46,7 @@ impl char> Ps2d { let mut ps2 = Ps2::new(); let extra_packet = ps2.init(); - let vmmouse = vm::enable(); + let vmmouse = false; //vm::enable(); let mut ps2d = Ps2d { ps2: ps2, @@ -75,7 +75,7 @@ impl char> Ps2d { pub fn resize(&mut self) { let mut buf: [u8; 4096] = [0; 4096]; if let Ok(count) = syscall::fpath(self.input.as_raw_fd() as usize, &mut buf) { - let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; + let path = unsafe { str::from_utf8_unchecked(&buf[..count]) }; let res = path.split(":").nth(1).unwrap_or(""); self.width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); self.height = res.split("/").nth(2).unwrap_or("").parse::().unwrap_or(0); @@ -89,9 +89,6 @@ impl char> Ps2d { } pub fn handle(&mut self, keyboard: bool, data: u8) { - // TODO: Improve efficiency - self.resize(); - if keyboard { let (scancode, pressed) = if data >= 0x80 { (data - 0x80, false) @@ -127,26 +124,28 @@ impl char> Ps2d { let (status, dx, dy, dz, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; - let (x, y) = if status & vm::RELATIVE_PACKET == vm::RELATIVE_PACKET { - ( - cmp::max(0, cmp::min(self.width as i32, self.mouse_x + dx as i32)), - cmp::max(0, cmp::min(self.height as i32, self.mouse_y - dy as i32)) - ) + if status & vm::RELATIVE_PACKET == vm::RELATIVE_PACKET { + if dx != 0 || dy != 0 { + self.input.write(&MouseRelativeEvent { + dx: dx as i32, + dy: -(dy as i32), + }.to_event()).expect("ps2d: failed to write mouse event"); + } } else { - ( - dx as i32 * self.width as i32 / 0xFFFF, - dy as i32 * self.height as i32 / 0xFFFF - ) - }; + // TODO: Improve efficiency + self.resize(); - if x != self.mouse_x || y != self.mouse_y { - self.mouse_x = x; - self.mouse_y = y; - self.input.write(&MouseEvent { - x: x, - y: y, - }.to_event()).expect("ps2d: failed to write mouse event"); - } + let x = dx as i32 * self.width as i32 / 0xFFFF; + let y = dy as i32 * self.height as i32 / 0xFFFF; + if x != self.mouse_x || y != self.mouse_y { + self.mouse_x = x; + self.mouse_y = y; + self.input.write(&MouseEvent { + x: x, + y: y, + }.to_event()).expect("ps2d: failed to write mouse event"); + } + }; if dz != 0 { self.input.write(&ScrollEvent { @@ -200,14 +199,10 @@ impl char> Ps2d { dz = -scroll as i32; } - let x = cmp::max(0, cmp::min(self.width as i32, self.mouse_x + dx)); - let y = cmp::max(0, cmp::min(self.height as i32, self.mouse_y + dy)); - if x != self.mouse_x || y != self.mouse_y { - self.mouse_x = x; - self.mouse_y = y; - self.input.write(&MouseEvent { - x: x, - y: y, + if dx != 0 || dy != 0 { + self.input.write(&MouseRelativeEvent { + dx: dx, + dy: dy, }.to_event()).expect("ps2d: failed to write mouse event"); } diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index dfb5bbe505..bab0ee130a 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2018" [dependencies] -orbclient = "0.3" +orbclient = "0.3.27" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 4e12f77657..6223c0672e 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2018" [dependencies] -orbclient = "0.3" +orbclient = "0.3.27" ransid = "0.4" rusttype = { version = "0.2", optional = true } redox_syscall = "0.1" From 6022bcc1e63231604da84bd3886da04c71a9cfab Mon Sep 17 00:00:00 2001 From: Fabio Di Francesco Date: Fri, 16 Aug 2019 13:08:55 +0000 Subject: [PATCH 0285/1301] Add italian keyboard layout (it) --- ps2d/src/keymap.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/ps2d/src/keymap.rs b/ps2d/src/keymap.rs index 34860c5d58..4c99127a77 100644 --- a/ps2d/src/keymap.rs +++ b/ps2d/src/keymap.rs @@ -401,3 +401,78 @@ pub mod bepo { } } } + +pub mod it { + static IT: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\\', '|'], + ['1', '"'], + ['2', '£'], + ['3', '$'], + ['4', '%'], + ['5', '%'], + ['6', '&'], + ['7', '/'], + ['8', '('], + ['9', ')'], + ['0', '='], + ['?', '\''], + ['ì', '^'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['q', 'Q'], + ['w', 'W'], + ['e', 'E'], + ['r', 'R'], + ['t', 'T'], + ['y', 'Y'], + ['u', 'U'], + ['i', 'I'], + ['o', 'O'], + ['p', 'P'], + ['è', 'é'], + ['+', '*'], + ['\n', '\n'], + ['\0', '\0'], + ['a', 'A'], + ['s', 'S'], + ['d', 'D'], + ['f', 'F'], + ['g', 'G'], + ['h', 'H'], + ['j', 'J'], + ['k', 'K'], + ['l', 'L'], + ['ò', 'ç'], + ['à', '°'], + ['ù', '§'], + ['\0', '\0'], + ['<', '>'], + ['z', 'Z'], + ['x', 'X'], + ['c', 'C'], + ['v', 'V'], + ['b', 'B'], + ['n', 'N'], + ['m', 'M'], + [',', ';'], + ['.', ':'], + ['-', '_'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] + ]; + + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = IT.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } + } else { + '\0' + } + } +} From f9dbc94979257ec271c36b179693d6b2307bb327 Mon Sep 17 00:00:00 2001 From: Fabio Di Francesco Date: Fri, 16 Aug 2019 18:58:25 +0000 Subject: [PATCH 0286/1301] Fixed main inclusion --- ps2d/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 0dc1c9bd4c..3249d4f750 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -36,6 +36,7 @@ fn daemon(input: File) { "gb" => (keymap::gb::get_char), "azerty" => (keymap::azerty::get_char), "bepo" => (keymap::bepo::get_char), + "it" => (keymap::it::get_char), &_ => (keymap::us::get_char) }, None => (keymap::us::get_char) From 37e92ac8e53f2702b01f4f37f4090905548d559c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 23 Aug 2019 20:29:19 -0600 Subject: [PATCH 0287/1301] nvmed: Implement admin queue --- initfs.toml | 7 -- nvmed/config.toml | 5 ++ nvmed/src/main.rs | 7 +- nvmed/src/nvme.rs | 202 +++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 198 insertions(+), 23 deletions(-) create mode 100644 nvmed/config.toml diff --git a/initfs.toml b/initfs.toml index 4e68571eaa..14dbfc3a3d 100644 --- a/initfs.toml +++ b/initfs.toml @@ -22,13 +22,6 @@ vendor = 33006 device = 48879 command = ["bgad", "$NAME", "$BAR0"] -# nvmed -[[drivers]] -name = "NVME storage" -class = 1 -subclass = 8 -command = ["nvmed", "$NAME", "$BAR0", "$IRQ"] - # vboxd [[drivers]] name = "VirtualBox Guest Device" diff --git a/nvmed/config.toml b/nvmed/config.toml new file mode 100644 index 0000000000..9b83c8802f --- /dev/null +++ b/nvmed/config.toml @@ -0,0 +1,5 @@ +[[drivers]] +name = "NVME storage" +class = 1 +subclass = 8 +command = ["nvmed", "$NAME", "$BAR0", "$IRQ"] diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index bacc3878e6..d8c911aad5 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -42,10 +42,11 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 4096, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("nvmed: failed to map address") }; + //TODO: Figure out correct size of mapping, not just 256 * 1024 + let address = unsafe { syscall::physmap(bar, 256 * 1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("nvmed: failed to map address") }; { - let mut nvme = Nvme::new(address); - nvme.init(); + let mut nvme = Nvme::new(address).expect("nvmed: failed to allocate queues"); + unsafe { nvme.init(); } /* let (_scheme_name, socket_fd) = create_scheme_fallback("disk", &name).expect("nvmed: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd) }; diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index 63c6d78ec7..793c32a2da 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -1,4 +1,6 @@ -use syscall::io::{Io, Mmio}; +use std::thread; +use syscall::io::{Dma, Io, Mmio}; +use syscall::error::Result; #[repr(packed)] pub struct NvmeCmd { @@ -31,15 +33,87 @@ pub struct NvmeCmd { } impl NvmeCmd { - pub fn read(cid: u16, lba: u64, count: u16, dst: u64) -> Self { - NvmeCmd { + pub fn create_io_completion_queue(cid: u16, qid: u16, ptr: usize, size: u16) -> Self { + Self { + opcode: 5, + flags: 0, + cid: cid, + nsid: 0xFFFFFFFF, + _rsvd: 0, + mptr: 0, + dptr: [ptr as u64, 0], + cdw10: ((size as u32) << 16) | (qid as u32), + cdw11: 1 /* Physically Contiguous */, //TODO: IV, IEN + cdw12: 0, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + + pub fn create_io_submission_queue(cid: u16, qid: u16, ptr: usize, size: u16, cqid: u16) -> Self { + Self { + opcode: 1, + flags: 0, + cid: cid, + nsid: 0xFFFFFFFF, + _rsvd: 0, + mptr: 0, + dptr: [ptr as u64, 0], + cdw10: ((size as u32) << 16) | (qid as u32), + cdw11: ((cqid as u32) << 16) | 1 /* Physically Contiguous */, //TODO: QPRIO + cdw12: 0, //TODO: NVMSETID + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + + pub fn identify_controller(cid: u16, ptr: usize) -> Self { + Self { + opcode: 6, + flags: 0, + cid: cid, + nsid: 0xFFFFFFFF, + _rsvd: 0, + mptr: 0, + dptr: [ptr as u64, 0], + cdw10: 1, + cdw11: 0, + cdw12: 0, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + + pub fn identify_namespace_list(cid: u16, ptr: usize, base: u32) -> Self { + Self { + opcode: 6, + flags: 0, + cid: cid, + nsid: base, + _rsvd: 0, + mptr: 0, + dptr: [ptr as u64, 0], + cdw10: 2, + cdw11: 0, + cdw12: 0, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + + pub fn io_read(cid: u16, lba: u64, count: u16, ptr: usize) -> Self { + Self { opcode: 2, flags: 1 << 6, cid: cid, nsid: 0xFFFFFFFF, _rsvd: 0, mptr: 0, - dptr: [dst, (count as u64) << 9], + dptr: [ptr as u64, (count as u64) << 9], cdw10: lba as u32, cdw11: (lba >> 32) as u32, cdw12: count as u32, @@ -49,15 +123,15 @@ impl NvmeCmd { } } - pub fn write(cid: u16, lba: u64, count: u16, src: u64) -> Self { - NvmeCmd { + pub fn io_write(cid: u16, lba: u64, count: u16, ptr: usize) -> Self { + Self { opcode: 1, flags: 1 << 6, cid: cid, nsid: 0xFFFFFFFF, _rsvd: 0, mptr: 0, - dptr: [src, (count as u64) << 9], + dptr: [ptr as u64, (count as u64) << 9], cdw10: lba as u32, cdw11: (lba >> 32) as u32, cdw12: count as u32, @@ -68,6 +142,16 @@ impl NvmeCmd { } } +#[repr(packed)] +pub struct NvmeComp { + command_specific: u32, + _rsvd: u32, + sq_head: u16, + sq_id: u16, + cid: u16, + status: u16, +} + #[repr(packed)] pub struct NvmeRegs { /// Controller Capabilities @@ -99,18 +183,110 @@ pub struct NvmeRegs { } pub struct Nvme { - regs: &'static mut NvmeRegs + regs: &'static mut NvmeRegs, + submission_queues: [Dma<[NvmeCmd; 64]>; 2], + completion_queues: [Dma<[NvmeComp; 256]>; 2], + } impl Nvme { - pub fn new(address: usize) -> Self { - Nvme { - regs: unsafe { &mut *(address as *mut NvmeRegs) } - } + pub fn new(address: usize) -> Result { + Ok(Nvme { + regs: unsafe { &mut *(address as *mut NvmeRegs) }, + submission_queues: [Dma::zeroed()?, Dma::zeroed()?], + completion_queues: [Dma::zeroed()?, Dma::zeroed()?], + }) } - pub fn init(&mut self) { + unsafe fn doorbell(&mut self, index: usize) -> &'static mut Mmio { + let dstrd = ((self.regs.cap.read() >> 32) & 0b1111) as usize; + let addr = (self.regs as *mut _ as usize) + + 0x1000 + + index * (4 << dstrd); + println!("doorbell {:X}", addr); + &mut *(addr as *mut Mmio) + } + + pub unsafe fn submission_queue_tail(&mut self, qid: u16, tail: u16) { + self.doorbell(2 * (qid as usize)).write(tail as u32); + } + + pub unsafe fn completion_queue_head(&mut self, qid: u16, head: u16) { + self.doorbell(2 * (qid as usize) + 1).write(head as u32) + } + + pub unsafe fn init(&mut self) { println!(" - CAPS: {:X}", self.regs.cap.read()); println!(" - VS: {:X}", self.regs.vs.read()); + println!(" - CC: {:X}", self.regs.cc.read()); + println!(" - CSTS: {:X}", self.regs.csts.read()); + + println!(" - Disable"); + self.regs.cc.writef(1, false); + + for (qid, queue) in self.completion_queues.iter().enumerate() { + println!(" - completion queue {}: {:X}, {}", qid, queue.physical(), queue.len()); + } + + for (qid, queue) in self.submission_queues.iter().enumerate() { + println!(" - submission queue {}: {:X}, {}", qid, queue.physical(), queue.len()); + } + + { + let asq = &self.submission_queues[0]; + let acq = &self.completion_queues[0]; + self.regs.aqa.write(((acq.len() as u32) << 16) | (asq.len() as u32)); + self.regs.asq.write(asq.physical() as u64); + self.regs.acq.write(acq.physical() as u64); + + // Set IOCQES, IOSQES, AMS, MPS, and CSS + let mut cc = self.regs.cc.read(); + cc &= 0xFF00000F; + cc |= (4 << 20) | (6 << 16); + self.regs.cc.write(cc); + } + + println!(" - Enable"); + self.regs.cc.writef(1, true); + + println!(" - Waiting for ready"); + while ! self.regs.csts.readf(1) { + thread::yield_now(); + } + + let nsids: Dma<[u16; 2048]> = Dma::zeroed().unwrap(); + + println!(" - Attempting to retrieve namespace ID list"); + { + let qid = 0; + let queue = &mut self.submission_queues[qid]; + let cid = 0; + let cmd = &mut queue[cid]; + + *cmd = NvmeCmd::identify_namespace_list(cid as u16, nsids.physical(), 0); + + self.submission_queue_tail(qid as u16, (cid as u16) + 1); + } + + println!(" - Waiting to retrieve namespace ID list"); + { + let qid = 0; + let queue = &self.completion_queues[qid]; + let cid = 0; + let comp = &queue[cid]; + + while comp.status & 1 == 0 { + thread::yield_now(); + } + + self.completion_queue_head(qid as u16, (cid as u16) + 1); + } + + println!(" - Dumping namespace ID list"); + for &nsid in nsids.iter() { + if nsid != 0 { + println!("{:X}", nsid); + } + } } } From df4a7b054b1e1b387aaaf1218ce279acfe44aa34 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 24 Aug 2019 08:37:38 -0600 Subject: [PATCH 0288/1301] nvmed: Identify controller and namespaces --- nvmed/src/nvme.rs | 246 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 202 insertions(+), 44 deletions(-) diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index 793c32a2da..0dcf29cd82 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -1,7 +1,8 @@ -use std::thread; +use std::{mem, thread}; use syscall::io::{Dma, Io, Mmio}; use syscall::error::Result; +#[derive(Clone, Copy)] #[repr(packed)] pub struct NvmeCmd { /// Opcode @@ -38,7 +39,7 @@ impl NvmeCmd { opcode: 5, flags: 0, cid: cid, - nsid: 0xFFFFFFFF, + nsid: 0, _rsvd: 0, mptr: 0, dptr: [ptr as u64, 0], @@ -56,7 +57,7 @@ impl NvmeCmd { opcode: 1, flags: 0, cid: cid, - nsid: 0xFFFFFFFF, + nsid: 0, _rsvd: 0, mptr: 0, dptr: [ptr as u64, 0], @@ -69,12 +70,30 @@ impl NvmeCmd { } } + pub fn identify_namespace(cid: u16, ptr: usize, nsid: u32) -> Self { + Self { + opcode: 6, + flags: 0, + cid: cid, + nsid: nsid, + _rsvd: 0, + mptr: 0, + dptr: [ptr as u64, 0], + cdw10: 0, + cdw11: 0, + cdw12: 0, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + pub fn identify_controller(cid: u16, ptr: usize) -> Self { Self { opcode: 6, flags: 0, cid: cid, - nsid: 0xFFFFFFFF, + nsid: 0, _rsvd: 0, mptr: 0, dptr: [ptr as u64, 0], @@ -105,12 +124,12 @@ impl NvmeCmd { } } - pub fn io_read(cid: u16, lba: u64, count: u16, ptr: usize) -> Self { + pub fn io_read(cid: u16, nsid: u32, lba: u64, count: u16, ptr: usize) -> Self { Self { opcode: 2, flags: 1 << 6, cid: cid, - nsid: 0xFFFFFFFF, + nsid: nsid, _rsvd: 0, mptr: 0, dptr: [ptr as u64, (count as u64) << 9], @@ -123,12 +142,12 @@ impl NvmeCmd { } } - pub fn io_write(cid: u16, lba: u64, count: u16, ptr: usize) -> Self { + pub fn io_write(cid: u16, nsid: u32, lba: u64, count: u16, ptr: usize) -> Self { Self { opcode: 1, flags: 1 << 6, cid: cid, - nsid: 0xFFFFFFFF, + nsid: nsid, _rsvd: 0, mptr: 0, dptr: [ptr as u64, (count as u64) << 9], @@ -142,6 +161,7 @@ impl NvmeCmd { } } +#[derive(Clone, Copy, Debug)] #[repr(packed)] pub struct NvmeComp { command_specific: u32, @@ -182,19 +202,77 @@ pub struct NvmeRegs { cmbsz: Mmio, } +pub struct NvmeCmdQueue { + data: Dma<[NvmeCmd; 64]>, + i: usize, +} + +impl NvmeCmdQueue { + fn new() -> Result { + Ok(Self { + data: Dma::zeroed()?, + i: 0, + }) + } + + fn submit(&mut self, entry: NvmeCmd) -> usize { + self.data[self.i] = entry; + self.i = (self.i + 1) % self.data.len(); + self.i + } +} + +pub struct NvmeCompQueue { + data: Dma<[NvmeComp; 256]>, + i: usize, + phase: bool, +} + +impl NvmeCompQueue { + fn new() -> Result { + Ok(Self { + data: Dma::zeroed()?, + i: 0, + phase: true, + }) + } + + fn complete(&mut self) -> Option<(usize, NvmeComp)> { + let entry = self.data[self.i]; + if ((entry.status & 1) == 1) == self.phase { + self.i = (self.i + 1) % self.data.len(); + if self.i == 0 { + self.phase = ! self.phase; + } + Some((self.i, entry)) + } else { + None + } + } + + fn complete_spin(&mut self) -> (usize, NvmeComp) { + loop { + if let Some(some) = self.complete() { + return some; + } else { + thread::yield_now(); + } + } + } +} + pub struct Nvme { regs: &'static mut NvmeRegs, - submission_queues: [Dma<[NvmeCmd; 64]>; 2], - completion_queues: [Dma<[NvmeComp; 256]>; 2], - + submission_queues: [NvmeCmdQueue; 2], + completion_queues: [NvmeCompQueue; 2], } impl Nvme { pub fn new(address: usize) -> Result { Ok(Nvme { regs: unsafe { &mut *(address as *mut NvmeRegs) }, - submission_queues: [Dma::zeroed()?, Dma::zeroed()?], - completion_queues: [Dma::zeroed()?, Dma::zeroed()?], + submission_queues: [NvmeCmdQueue::new()?, NvmeCmdQueue::new()?], + completion_queues: [NvmeCompQueue::new()?, NvmeCompQueue::new()?], }) } @@ -203,7 +281,6 @@ impl Nvme { let addr = (self.regs as *mut _ as usize) + 0x1000 + index * (4 << dstrd); - println!("doorbell {:X}", addr); &mut *(addr as *mut Mmio) } @@ -225,19 +302,21 @@ impl Nvme { self.regs.cc.writef(1, false); for (qid, queue) in self.completion_queues.iter().enumerate() { - println!(" - completion queue {}: {:X}, {}", qid, queue.physical(), queue.len()); + let data = &queue.data; + println!(" - completion queue {}: {:X}, {}", qid, data.physical(), data.len()); } for (qid, queue) in self.submission_queues.iter().enumerate() { - println!(" - submission queue {}: {:X}, {}", qid, queue.physical(), queue.len()); + let data = &queue.data; + println!(" - submission queue {}: {:X}, {}", qid, data.physical(), data.len()); } { let asq = &self.submission_queues[0]; let acq = &self.completion_queues[0]; - self.regs.aqa.write(((acq.len() as u32) << 16) | (asq.len() as u32)); - self.regs.asq.write(asq.physical() as u64); - self.regs.acq.write(acq.physical() as u64); + self.regs.aqa.write(((acq.data.len() as u32) << 16) | (asq.data.len() as u32)); + self.regs.asq.write(asq.data.physical() as u64); + self.regs.acq.write(acq.data.physical() as u64); // Set IOCQES, IOSQES, AMS, MPS, and CSS let mut cc = self.regs.cc.read(); @@ -254,39 +333,118 @@ impl Nvme { thread::yield_now(); } - let nsids: Dma<[u16; 2048]> = Dma::zeroed().unwrap(); - - println!(" - Attempting to retrieve namespace ID list"); { - let qid = 0; - let queue = &mut self.submission_queues[qid]; - let cid = 0; - let cmd = &mut queue[cid]; + let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); - *cmd = NvmeCmd::identify_namespace_list(cid as u16, nsids.physical(), 0); - - self.submission_queue_tail(qid as u16, (cid as u16) + 1); - } - - println!(" - Waiting to retrieve namespace ID list"); - { - let qid = 0; - let queue = &self.completion_queues[qid]; - let cid = 0; - let comp = &queue[cid]; - - while comp.status & 1 == 0 { - thread::yield_now(); + println!(" - Attempting to identify controller"); + { + let qid = 0; + let queue = &mut self.submission_queues[qid]; + let cid = queue.i as u16; + let entry = NvmeCmd::identify_controller(cid, data.physical()); + let tail = queue.submit(entry); + self.submission_queue_tail(qid as u16, tail as u16); } - self.completion_queue_head(qid as u16, (cid as u16) + 1); + println!(" - Waiting to identify controller"); + { + let qid = 0; + let queue = &mut self.completion_queues[qid]; + let (head, entry) = queue.complete_spin(); + self.completion_queue_head(qid as u16, head as u16); + } + + println!(" - Dumping identify controller"); + + let mut serial = String::new(); + for &b in &data[4..24] { + if b == 0 { + break; + } + serial.push(b as char); + } + println!(" - Serial: {}", serial); + + let mut model = String::new(); + for &b in &data[24..64] { + if b == 0 { + break; + } + model.push(b as char); + } + println!(" - Model: {}", model); + + let mut firmware = String::new(); + for &b in &data[64..72] { + if b == 0 { + break; + } + firmware.push(b as char); + } + println!(" - Firmware: {}", firmware); + } + + let mut nsids = Vec::new(); + { + let data: Dma<[u32; 1024]> = Dma::zeroed().unwrap(); + + println!(" - Attempting to retrieve namespace ID list"); + { + let qid = 0; + let queue = &mut self.submission_queues[qid]; + let cid = queue.i as u16; + let entry = NvmeCmd::identify_namespace_list(cid, data.physical(), 0); + let tail = queue.submit(entry); + self.submission_queue_tail(qid as u16, tail as u16); + } + + println!(" - Waiting to retrieve namespace ID list"); + { + let qid = 0; + let queue = &mut self.completion_queues[qid]; + let (head, entry) = queue.complete_spin(); + self.completion_queue_head(qid as u16, head as u16); + } + + println!(" - Dumping namespace ID list"); + for &nsid in data.iter() { + if nsid != 0 { + println!(" - {}", nsid); + nsids.push(nsid); + } + } } - println!(" - Dumping namespace ID list"); for &nsid in nsids.iter() { - if nsid != 0 { - println!("{:X}", nsid); + let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); + + println!(" - Attempting to identify namespace {}", nsid); + { + let qid = 0; + let queue = &mut self.submission_queues[qid]; + let cid = queue.i as u16; + let entry = NvmeCmd::identify_namespace(cid, data.physical(), nsid); + let tail = queue.submit(entry); + self.submission_queue_tail(qid as u16, tail as u16); } + + println!(" - Waiting to identify namespace {}", nsid); + { + let qid = 0; + let queue = &mut self.completion_queues[qid]; + let (head, entry) = queue.complete_spin(); + self.completion_queue_head(qid as u16, head as u16); + } + + println!(" - Dumping identify namespace"); + + let size = *(data.as_ptr().offset(0) as *const u64); + println!(" - Size: {}", size); + + let capacity = *(data.as_ptr().offset(8) as *const u64); + println!(" - Capacity: {}", capacity); + + //TODO: Read block size } } } From 9c277981be6532b4d0a548a07019f7989cc883a5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 24 Aug 2019 09:26:13 -0600 Subject: [PATCH 0289/1301] nvmed: Set up I/O queues --- nvmed/src/nvme.rs | 74 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index 0dcf29cd82..46a32cdda7 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -135,7 +135,7 @@ impl NvmeCmd { dptr: [ptr as u64, (count as u64) << 9], cdw10: lba as u32, cdw11: (lba >> 32) as u32, - cdw12: count as u32, + cdw12: count.saturating_sub(1) as u32, //TODO: Prevent count of 0 cdw13: 0, cdw14: 0, cdw15: 0, @@ -153,7 +153,7 @@ impl NvmeCmd { dptr: [ptr as u64, (count as u64) << 9], cdw10: lba as u32, cdw11: (lba >> 32) as u32, - cdw12: count as u32, + cdw12: count.saturating_sub(1) as u32, //TODO: Prevent count of 0 cdw13: 0, cdw14: 0, cdw15: 0, @@ -301,6 +301,9 @@ impl Nvme { println!(" - Disable"); self.regs.cc.writef(1, false); + println!(" - Mask all interrupts"); + self.regs.intms.write(0xFFFFFFFF); + for (qid, queue) in self.completion_queues.iter().enumerate() { let data = &queue.data; println!(" - completion queue {}: {:X}, {}", qid, data.physical(), data.len()); @@ -341,7 +344,9 @@ impl Nvme { let qid = 0; let queue = &mut self.submission_queues[qid]; let cid = queue.i as u16; - let entry = NvmeCmd::identify_controller(cid, data.physical()); + let entry = NvmeCmd::identify_controller( + cid, data.physical() + ); let tail = queue.submit(entry); self.submission_queue_tail(qid as u16, tail as u16); } @@ -393,7 +398,9 @@ impl Nvme { let qid = 0; let queue = &mut self.submission_queues[qid]; let cid = queue.i as u16; - let entry = NvmeCmd::identify_namespace_list(cid, data.physical(), 0); + let entry = NvmeCmd::identify_namespace_list( + cid, data.physical(), 0 + ); let tail = queue.submit(entry); self.submission_queue_tail(qid as u16, tail as u16); } @@ -423,7 +430,9 @@ impl Nvme { let qid = 0; let queue = &mut self.submission_queues[qid]; let cid = queue.i as u16; - let entry = NvmeCmd::identify_namespace(cid, data.physical(), nsid); + let entry = NvmeCmd::identify_namespace( + cid, data.physical(), nsid + ); let tail = queue.submit(entry); self.submission_queue_tail(qid as u16, tail as u16); } @@ -446,5 +455,60 @@ impl Nvme { //TODO: Read block size } + + for io_qid in 1..self.completion_queues.len() { + let (ptr, len) = { + let queue = &self.completion_queues[io_qid]; + (queue.data.physical(), queue.data.len()) + }; + + println!(" - Attempting to create I/O completion queue {}", io_qid); + { + let qid = 0; + let queue = &mut self.submission_queues[qid]; + let cid = queue.i as u16; + let entry = NvmeCmd::create_io_completion_queue( + cid, io_qid as u16, ptr, len as u16 + ); + let tail = queue.submit(entry); + self.submission_queue_tail(qid as u16, tail as u16); + } + + println!(" - Waiting to create I/O completion queue {}", io_qid); + { + let qid = 0; + let queue = &mut self.completion_queues[qid]; + let (head, entry) = queue.complete_spin(); + self.completion_queue_head(qid as u16, head as u16); + } + } + + for io_qid in 1..self.submission_queues.len() { + let (ptr, len) = { + let queue = &self.submission_queues[io_qid]; + (queue.data.physical(), queue.data.len()) + }; + + println!(" - Attempting to create I/O submission queue {}", io_qid); + { + let qid = 0; + let queue = &mut self.submission_queues[qid]; + let cid = queue.i as u16; + //TODO: Get completion queue ID through smarter mechanism + let entry = NvmeCmd::create_io_submission_queue( + cid, io_qid as u16, ptr, len as u16, io_qid as u16 + ); + let tail = queue.submit(entry); + self.submission_queue_tail(qid as u16, tail as u16); + } + + println!(" - Waiting to create I/O submission queue {}", io_qid); + { + let qid = 0; + let queue = &mut self.completion_queues[qid]; + let (head, entry) = queue.complete_spin(); + self.completion_queue_head(qid as u16, head as u16); + } + } } } From b2c76034b76a2dbc400e4d6fa3dfb653d049e67b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 24 Aug 2019 20:24:01 -0600 Subject: [PATCH 0290/1301] nvmed: add scheme with read/write implemented using polling --- nvmed/src/main.rs | 117 ++++++++++++++--------- nvmed/src/nvme.rs | 157 ++++++++++++++++++++++++++++--- nvmed/src/scheme.rs | 221 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 438 insertions(+), 57 deletions(-) create mode 100644 nvmed/src/scheme.rs diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index d8c911aad5..daaa633fe7 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -1,4 +1,3 @@ -//#![deny(warnings)] #![feature(asm)] extern crate bitflags; @@ -6,25 +5,17 @@ extern crate spin; extern crate syscall; use std::{env, usize}; +use std::fs::File; +use std::io::{ErrorKind, Read, Write}; +use std::os::unix::io::{RawFd, FromRawFd}; - - -use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, Result, Scheme}; +use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, Result, SchemeBlockMut}; use self::nvme::Nvme; +use self::scheme::DiskScheme; mod nvme; - -/* -fn create_scheme_fallback<'a>(name: &'a str, fallback: &'a str) -> Result<(&'a str, RawFd)> { - if let Ok(fd) = syscall::open(&format!(":{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) { - Ok((name, fd)) - } else { - syscall::open(&format!(":{}", fallback), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK) - .map(|fd| (fallback, fd)) - } -} -*/ +mod scheme; fn main() { let mut args = env::args().skip(1); @@ -45,48 +36,84 @@ fn main() { //TODO: Figure out correct size of mapping, not just 256 * 1024 let address = unsafe { syscall::physmap(bar, 256 * 1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("nvmed: failed to map address") }; { - let mut nvme = Nvme::new(address).expect("nvmed: failed to allocate queues"); - unsafe { nvme.init(); } - /* - let (_scheme_name, socket_fd) = create_scheme_fallback("disk", &name).expect("nvmed: failed to create disk scheme"); - let mut socket = unsafe { File::from_raw_fd(socket_fd) }; - syscall::fevent(socket_fd, EVENT_READ).expect("nvmed: failed to fevent disk scheme"); + let event_fd = syscall::open("event:", syscall::O_RDWR | syscall::O_CLOEXEC) + .expect("nvmed: failed to open event queue"); + let mut event_file = unsafe { File::from_raw_fd(event_fd as RawFd) }; - let mut irq_file = File::open(&format!("irq:{}", irq)).expect("nvmed: failed to open irq file"); - let irq_fd = irq_file.as_raw_fd(); - syscall::fevent(irq_fd, EVENT_READ).expect("nvmed: failed to fevent irq file"); + let irq_fd = syscall::open( + &format!("irq:{}", irq), + syscall::O_RDWR | syscall::O_NONBLOCK | syscall::O_CLOEXEC + ).expect("nvmed: failed to open irq file"); + syscall::write(event_fd, &syscall::Event { + id: irq_fd, + flags: syscall::EVENT_READ, + data: 0, + }).expect("nvmed: failed to watch irq file events"); + let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; - let mut event_file = File::open("event:").expect("nvmed: failed to open event file"); - - let scheme = DiskScheme::new(nvme::disks(address, &name)); + let scheme_name = format!("disk/{}", name); + let socket_fd = syscall::open( + &format!(":{}", scheme_name), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK | syscall::O_CLOEXEC + ).expect("nvmed: failed to create disk scheme"); + syscall::write(event_fd, &syscall::Event { + id: socket_fd, + flags: syscall::EVENT_READ, + data: 1, + }).expect("nvmed: failed to watch disk scheme events"); + let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - loop { + let mut nvme = Nvme::new(address).expect("nvmed: failed to allocate driver data"); + let namespaces = unsafe { nvme.init() }; + let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); + let mut todo = Vec::new(); + 'events: loop { let mut event = Event::default(); - if event_file.read(&mut event).expect("nvmed: failed to read event file") == 0 { + if event_file.read(&mut event).expect("nvmed: failed to read event queue") == 0 { break; } - if event.id == socket_fd { - loop { - let mut packet = Packet::default(); - if socket.read(&mut packet).expect("nvmed: failed to read disk scheme") == 0 { - break; + + match event.data { + 0 => { + let mut irq = [0; 8]; + if irq_file.read(&mut irq).expect("nvmed: failed to read irq file") >= irq.len() { + if scheme.irq() { + irq_file.write(&irq).expect("nvmed: failed to write irq file"); + } } - scheme.handle(&mut packet); - socket.write(&mut packet).expect("nvmed: failed to write disk scheme"); + }, + 1 => loop { + let mut packet = Packet::default(); + match socket_file.read(&mut packet) { + Ok(0) => break 'events, + Ok(_) => (), + Err(err) => match err.kind() { + ErrorKind::WouldBlock => break, + _ => Err(err).expect("nvmed: failed to read disk scheme"), + } + } + todo.push(packet); + }, + unknown => { + panic!("nvmed: unknown event data {}", unknown); + }, + } + + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket_file.write(&packet).expect("nvmed: failed to write disk scheme"); + } else { + i += 1; } - } else if event.id == irq_fd { - let mut irq = [0; 8]; - if irq_file.read(&mut irq).expect("nvmed: failed to read irq file") >= irq.len() { - //TODO : Test for IRQ - //irq_file.write(&irq).expect("nvmed: failed to write irq file"); - } - } else { - println!("Unknown event {}", event.id); } } - */ + + //TODO: destroy NVMe stuff } unsafe { let _ = syscall::physunmap(address); } } diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index 46a32cdda7..8bce947fce 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -1,6 +1,7 @@ -use std::{mem, thread}; +use std::thread; +use std::collections::BTreeMap; use syscall::io::{Dma, Io, Mmio}; -use syscall::error::Result; +use syscall::error::{Error, Result, EINVAL}; #[derive(Clone, Copy)] #[repr(packed)] @@ -124,7 +125,7 @@ impl NvmeCmd { } } - pub fn io_read(cid: u16, nsid: u32, lba: u64, count: u16, ptr: usize) -> Self { + pub fn io_read(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { Self { opcode: 2, flags: 1 << 6, @@ -132,17 +133,17 @@ impl NvmeCmd { nsid: nsid, _rsvd: 0, mptr: 0, - dptr: [ptr as u64, (count as u64) << 9], + dptr: [ptr0, ptr1], cdw10: lba as u32, cdw11: (lba >> 32) as u32, - cdw12: count.saturating_sub(1) as u32, //TODO: Prevent count of 0 + cdw12: blocks_1 as u32, cdw13: 0, cdw14: 0, cdw15: 0, } } - pub fn io_write(cid: u16, nsid: u32, lba: u64, count: u16, ptr: usize) -> Self { + pub fn io_write(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { Self { opcode: 1, flags: 1 << 6, @@ -150,10 +151,10 @@ impl NvmeCmd { nsid: nsid, _rsvd: 0, mptr: 0, - dptr: [ptr as u64, (count as u64) << 9], + dptr: [ptr0, ptr1], cdw10: lba as u32, cdw11: (lba >> 32) as u32, - cdw12: count.saturating_sub(1) as u32, //TODO: Prevent count of 0 + cdw12: blocks_1 as u32, cdw13: 0, cdw14: 0, cdw15: 0, @@ -261,10 +262,18 @@ impl NvmeCompQueue { } } +pub struct NvmeNamespace { + pub id: u32, + pub blocks: u64, + pub block_size: u64, +} + pub struct Nvme { regs: &'static mut NvmeRegs, submission_queues: [NvmeCmdQueue; 2], completion_queues: [NvmeCompQueue; 2], + buffer: Dma<[u8; 512 * 4096]>, // 2MB of buffer + buffer_prp: Dma<[u64; 512]>, // 4KB of PRP for the buffer } impl Nvme { @@ -273,6 +282,8 @@ impl Nvme { regs: unsafe { &mut *(address as *mut NvmeRegs) }, submission_queues: [NvmeCmdQueue::new()?, NvmeCmdQueue::new()?], completion_queues: [NvmeCompQueue::new()?, NvmeCompQueue::new()?], + buffer: Dma::zeroed()?, + buffer_prp: Dma::zeroed()?, }) } @@ -292,7 +303,11 @@ impl Nvme { self.doorbell(2 * (qid as usize) + 1).write(head as u32) } - pub unsafe fn init(&mut self) { + pub unsafe fn init(&mut self) -> BTreeMap { + for i in 0..self.buffer_prp.len() { + self.buffer_prp[i] = (self.buffer.physical() + i * 4096) as u64; + } + println!(" - CAPS: {:X}", self.regs.cap.read()); println!(" - VS: {:X}", self.regs.vs.read()); println!(" - CC: {:X}", self.regs.cc.read()); @@ -317,7 +332,7 @@ impl Nvme { { let asq = &self.submission_queues[0]; let acq = &self.completion_queues[0]; - self.regs.aqa.write(((acq.data.len() as u32) << 16) | (asq.data.len() as u32)); + self.regs.aqa.write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1)); self.regs.asq.write(asq.data.physical() as u64); self.regs.acq.write(acq.data.physical() as u64); @@ -337,6 +352,7 @@ impl Nvme { } { + //TODO: Use buffer let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); println!(" - Attempting to identify controller"); @@ -391,6 +407,7 @@ impl Nvme { let mut nsids = Vec::new(); { + //TODO: Use buffer let data: Dma<[u32; 1024]> = Dma::zeroed().unwrap(); println!(" - Attempting to retrieve namespace ID list"); @@ -422,7 +439,9 @@ impl Nvme { } } + let mut namespaces = BTreeMap::new(); for &nsid in nsids.iter() { + //TODO: Use buffer let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); println!(" - Attempting to identify namespace {}", nsid); @@ -454,6 +473,12 @@ impl Nvme { println!(" - Capacity: {}", capacity); //TODO: Read block size + + namespaces.insert(nsid, NvmeNamespace { + id: nsid, + blocks: size, + block_size: 512, // TODO + }); } for io_qid in 1..self.completion_queues.len() { @@ -468,7 +493,7 @@ impl Nvme { let queue = &mut self.submission_queues[qid]; let cid = queue.i as u16; let entry = NvmeCmd::create_io_completion_queue( - cid, io_qid as u16, ptr, len as u16 + cid, io_qid as u16, ptr, (len - 1) as u16 ); let tail = queue.submit(entry); self.submission_queue_tail(qid as u16, tail as u16); @@ -496,7 +521,7 @@ impl Nvme { let cid = queue.i as u16; //TODO: Get completion queue ID through smarter mechanism let entry = NvmeCmd::create_io_submission_queue( - cid, io_qid as u16, ptr, len as u16, io_qid as u16 + cid, io_qid as u16, ptr, (len - 1) as u16, io_qid as u16 ); let tail = queue.submit(entry); self.submission_queue_tail(qid as u16, tail as u16); @@ -510,5 +535,113 @@ impl Nvme { self.completion_queue_head(qid as u16, head as u16); } } + + namespaces + } + + unsafe fn namespace_rw(&mut self, nsid: u32, lba: u64, blocks_1: u16, write: bool) -> Result<()> { + let (ptr0, ptr1) = if blocks_1 == 0 { + (self.buffer_prp[0], 0) + } else if blocks_1 == 1 { + (self.buffer_prp[0], self.buffer_prp[1]) + } else { + (self.buffer_prp[0], (self.buffer_prp.physical() + 8) as u64) + }; + + { + let qid = 1; + let queue = &mut self.submission_queues[qid]; + let cid = queue.i as u16; + //TODO: Get completion queue ID through smarter mechanism + let entry = if write { + NvmeCmd::io_write( + cid, nsid, lba, blocks_1, ptr0, ptr1 + ) + } else { + NvmeCmd::io_read( + cid, nsid, lba, blocks_1, ptr0, ptr1 + ) + }; + let tail = queue.submit(entry); + self.submission_queue_tail(qid as u16, tail as u16); + } + + { + let qid = 1; + let queue = &mut self.completion_queues[qid]; + let (head, entry) = queue.complete_spin(); + //TODO: Handle errors + self.completion_queue_head(qid as u16, head as u16); + } + + Ok(()) + } + + pub unsafe fn namespace_read(&mut self, nsid: u32, lba: u64, buf: &mut [u8]) -> Result> { + //TODO: Use interrupts + + //TODO: Get real block size + let block_size = 512; + + //TODO: Support this + if buf.len() % block_size != 0 { + return Err(Error::new(EINVAL)); + } + + //TODO: Support this + if buf.len() > self.buffer.len() { + return Err(Error::new(EINVAL)); + } + + let blocks = buf.len() / block_size; + + if blocks == 0 { + return Ok(Some(0)); + } + + //TODO: Support this + if blocks > 0x1_0000 { + return Err(Error::new(EINVAL)); + } + + self.namespace_rw(nsid, lba, (blocks - 1) as u16, false)?; + + buf.copy_from_slice(&self.buffer[..buf.len()]); + + Ok(Some(buf.len())) + } + + pub unsafe fn namespace_write(&mut self, nsid: u32, lba: u64, buf: &[u8]) -> Result> { + //TODO: Use interrupts + + //TODO: Get real block size + let block_size = 512; + + //TODO: Support this + if buf.len() % block_size != 0 { + return Err(Error::new(EINVAL)); + } + + //TODO: Support this + if buf.len() > self.buffer.len() { + return Err(Error::new(EINVAL)); + } + + let blocks = buf.len() / block_size; + + if blocks == 0 { + return Ok(Some(0)); + } + + //TODO: Support this + if blocks > 0x1_0000 { + return Err(Error::new(EINVAL)); + } + + self.buffer[..buf.len()].copy_from_slice(buf); + + self.namespace_rw(nsid, lba, (blocks - 1) as u16, true)?; + + Ok(Some(buf.len())) } } diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs new file mode 100644 index 0000000000..58edb0dae2 --- /dev/null +++ b/nvmed/src/scheme.rs @@ -0,0 +1,221 @@ +use std::collections::BTreeMap; +use std::{cmp, str}; +use std::fmt::Write; +use std::io::Read; +use syscall::{ + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, Result, + Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, + O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; + +use crate::nvme::{Nvme, NvmeNamespace}; + +#[derive(Clone)] +enum Handle { + List(Vec, usize), + Disk(u32, usize) +} + +pub struct DiskScheme { + scheme_name: String, + nvme: Nvme, + disks: BTreeMap, + handles: BTreeMap, + next_id: usize +} + +impl DiskScheme { + pub fn new(scheme_name: String, nvme: Nvme, disks: BTreeMap) -> DiskScheme { + DiskScheme { + scheme_name, + nvme, + disks, + handles: BTreeMap::new(), + next_id: 0 + } + } +} + +impl DiskScheme { + pub fn irq(&mut self) -> bool { + // TODO: implement + false + } +} + +impl SchemeBlockMut for DiskScheme { + fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { + if uid == 0 { + let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_matches('/'); + if path_str.is_empty() { + if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { + let mut list = String::new(); + + for (nsid, _disk) in self.disks.iter() { + write!(list, "{}\n", nsid).unwrap(); + } + + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle::List(list.into_bytes(), 0)); + Ok(Some(id)) + } else { + Err(Error::new(EISDIR)) + } + } else { + let nsid = path_str.parse::().or(Err(Error::new(ENOENT)))?; + + if self.disks.contains_key(&nsid) { + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle::Disk(nsid, 0)); + Ok(Some(id)) + } else { + Err(Error::new(ENOENT)) + } + } + } else { + Err(Error::new(EACCES)) + } + } + + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { + if ! buf.is_empty() { + return Err(Error::new(EINVAL)); + } + + let new_handle = { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + handle.clone() + }; + + let new_id = self.next_id; + self.next_id += 1; + self.handles.insert(new_id, new_handle); + Ok(Some(new_id)) + } + + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + match *self.handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref data, _) => { + stat.st_mode = MODE_DIR; + stat.st_size = data.len() as u64; + Ok(Some(0)) + }, + Handle::Disk(number, _) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + stat.st_mode = MODE_FILE; + stat.st_size = disk.blocks * disk.block_size; + Ok(Some(0)) + } + } + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let mut i = 0; + + let scheme_name = self.scheme_name.as_bytes(); + let mut j = 0; + while i < buf.len() && j < scheme_name.len() { + buf[i] = scheme_name[j]; + i += 1; + j += 1; + } + + if i < buf.len() { + buf[i] = b':'; + i += 1; + } + + match *handle { + Handle::List(_, _) => (), + Handle::Disk(number, _) => { + let number_str = format!("{}", number); + let number_bytes = number_str.as_bytes(); + j = 0; + while i < buf.len() && j < number_bytes.len() { + buf[i] = number_bytes[j]; + i += 1; + j += 1; + } + } + } + + Ok(Some(i)) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref mut handle, ref mut size) => { + let count = (&handle[*size..]).read(buf).unwrap(); + *size += count; + Ok(Some(count)) + }, + Handle::Disk(number, ref mut size) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + let block_size = disk.block_size; + if let Some(count) = unsafe { + self.nvme.namespace_read(disk.id, (*size as u64)/block_size, buf)? + } { + *size += count; + Ok(Some(count)) + } else { + Ok(None) + } + } + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(_, _) => { + Err(Error::new(EBADF)) + }, + Handle::Disk(number, ref mut size) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + let block_size = disk.block_size; + if let Some(count) = unsafe { + self.nvme.namespace_write(disk.id, (*size as u64)/block_size, buf)? + } { + *size += count; + Ok(Some(count)) + } else { + Ok(None) + } + } + } + } + + fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref mut handle, ref mut size) => { + let len = handle.len() as usize; + *size = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(Some(*size)) + }, + Handle::Disk(number, ref mut size) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + let len = (disk.blocks * disk.block_size) as usize; + *size = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(Some(*size)) + } + } + } + + fn close(&mut self, id: usize) -> Result> { + self.handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + } +} From 13dd6ae28f21caee72c2602a7675b9ab012f42dc Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 24 Aug 2019 20:45:48 -0600 Subject: [PATCH 0291/1301] nvmed: add to initfs and fix reading larger block sizes --- initfs.toml | 7 ++++ nvmed/config.toml | 5 --- nvmed/src/nvme.rs | 81 ++++++++++++++++++----------------------------- 3 files changed, 37 insertions(+), 56 deletions(-) delete mode 100644 nvmed/config.toml diff --git a/initfs.toml b/initfs.toml index 14dbfc3a3d..15b49d522f 100644 --- a/initfs.toml +++ b/initfs.toml @@ -22,6 +22,13 @@ vendor = 33006 device = 48879 command = ["bgad", "$NAME", "$BAR0"] +#nvmed +[[drivers]] +name = "NVME storage" +class = 1 +subclass = 8 +command = ["nvmed", "$NAME", "$BAR0", "$IRQ"] + # vboxd [[drivers]] name = "VirtualBox Guest Device" diff --git a/nvmed/config.toml b/nvmed/config.toml deleted file mode 100644 index 9b83c8802f..0000000000 --- a/nvmed/config.toml +++ /dev/null @@ -1,5 +0,0 @@ -[[drivers]] -name = "NVME storage" -class = 1 -subclass = 8 -command = ["nvmed", "$NAME", "$BAR0", "$IRQ"] diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index 8bce947fce..66590b3488 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -540,9 +540,13 @@ impl Nvme { } unsafe fn namespace_rw(&mut self, nsid: u32, lba: u64, blocks_1: u16, write: bool) -> Result<()> { - let (ptr0, ptr1) = if blocks_1 == 0 { + //TODO: Get real block size + let block_size = 512; + + let bytes = ((blocks_1 as u64) + 1) * block_size; + let (ptr0, ptr1) = if bytes <= 4096 { (self.buffer_prp[0], 0) - } else if blocks_1 == 1 { + } else if bytes <= 8192 { (self.buffer_prp[0], self.buffer_prp[1]) } else { (self.buffer_prp[0], (self.buffer_prp.physical() + 8) as u64) @@ -552,7 +556,6 @@ impl Nvme { let qid = 1; let queue = &mut self.submission_queues[qid]; let cid = queue.i as u16; - //TODO: Get completion queue ID through smarter mechanism let entry = if write { NvmeCmd::io_write( cid, nsid, lba, blocks_1, ptr0, ptr1 @@ -577,71 +580,47 @@ impl Nvme { Ok(()) } - pub unsafe fn namespace_read(&mut self, nsid: u32, lba: u64, buf: &mut [u8]) -> Result> { + pub unsafe fn namespace_read(&mut self, nsid: u32, mut lba: u64, buf: &mut [u8]) -> Result> { //TODO: Use interrupts //TODO: Get real block size let block_size = 512; - //TODO: Support this - if buf.len() % block_size != 0 { - return Err(Error::new(EINVAL)); + for chunk in buf.chunks_mut(self.buffer.len()) { + let blocks = (chunk.len() + block_size - 1) / block_size; + + assert!(blocks > 0); + assert!(blocks <= 0x1_0000); + + self.namespace_rw(nsid, lba, (blocks - 1) as u16, false)?; + + chunk.copy_from_slice(&self.buffer[..chunk.len()]); + + lba += blocks as u64; } - //TODO: Support this - if buf.len() > self.buffer.len() { - return Err(Error::new(EINVAL)); - } - - let blocks = buf.len() / block_size; - - if blocks == 0 { - return Ok(Some(0)); - } - - //TODO: Support this - if blocks > 0x1_0000 { - return Err(Error::new(EINVAL)); - } - - self.namespace_rw(nsid, lba, (blocks - 1) as u16, false)?; - - buf.copy_from_slice(&self.buffer[..buf.len()]); - Ok(Some(buf.len())) } - pub unsafe fn namespace_write(&mut self, nsid: u32, lba: u64, buf: &[u8]) -> Result> { + pub unsafe fn namespace_write(&mut self, nsid: u32, mut lba: u64, buf: &[u8]) -> Result> { //TODO: Use interrupts //TODO: Get real block size let block_size = 512; - //TODO: Support this - if buf.len() % block_size != 0 { - return Err(Error::new(EINVAL)); + for chunk in buf.chunks(self.buffer.len()) { + let blocks = (chunk.len() + block_size - 1) / block_size; + + assert!(blocks > 0); + assert!(blocks <= 0x1_0000); + + self.buffer[..chunk.len()].copy_from_slice(chunk); + + self.namespace_rw(nsid, lba, (blocks - 1) as u16, true)?; + + lba += blocks as u64; } - //TODO: Support this - if buf.len() > self.buffer.len() { - return Err(Error::new(EINVAL)); - } - - let blocks = buf.len() / block_size; - - if blocks == 0 { - return Ok(Some(0)); - } - - //TODO: Support this - if blocks > 0x1_0000 { - return Err(Error::new(EINVAL)); - } - - self.buffer[..buf.len()].copy_from_slice(buf); - - self.namespace_rw(nsid, lba, (blocks - 1) as u16, true)?; - Ok(Some(buf.len())) } } From f86495e0c561e506f8483aa94a885d0cf03e889f Mon Sep 17 00:00:00 2001 From: Fabio Di Francesco Date: Sun, 25 Aug 2019 03:35:37 +0000 Subject: [PATCH 0292/1301] Fixed inverted chars --- ps2d/src/keymap.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ps2d/src/keymap.rs b/ps2d/src/keymap.rs index 4c99127a77..236e7caa07 100644 --- a/ps2d/src/keymap.rs +++ b/ps2d/src/keymap.rs @@ -405,11 +405,11 @@ pub mod bepo { pub mod it { static IT: [[char; 2]; 58] = [ ['\0', '\0'], - ['\\', '|'], - ['1', '"'], - ['2', '£'], - ['3', '$'], - ['4', '%'], + ['\x1B', '\x1B'], + ['1', '!'], + ['2', '"'], + ['3', '£'], + ['4', '$'], ['5', '%'], ['6', '&'], ['7', '/'], @@ -433,7 +433,7 @@ pub mod it { ['è', 'é'], ['+', '*'], ['\n', '\n'], - ['\0', '\0'], + ['\x20', '\x20'], ['a', 'A'], ['s', 'S'], ['d', 'D'], From 0e7b056508909f5dc6bd0ea4a2e08beeb827c3fa Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 26 Aug 2019 17:27:02 -0600 Subject: [PATCH 0293/1301] Update redox_syscall for pcspkrd --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index fd63763246..8c602a0414 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -575,7 +575,7 @@ dependencies = [ name = "pcspkrd" version = "0.1.0" dependencies = [ - "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] From 745d8818e12f5f61e2f781928df9e603b09f5dfd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 27 Aug 2019 21:16:58 -0600 Subject: [PATCH 0294/1301] Read completion using ptr::read_volatile --- nvmed/src/nvme.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index 66590b3488..9b37fd3f65 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -1,4 +1,4 @@ -use std::thread; +use std::{ptr, thread}; use std::collections::BTreeMap; use syscall::io::{Dma, Io, Mmio}; use syscall::error::{Error, Result, EINVAL}; @@ -239,7 +239,9 @@ impl NvmeCompQueue { } fn complete(&mut self) -> Option<(usize, NvmeComp)> { - let entry = self.data[self.i]; + let entry = unsafe { + ptr::read_volatile(self.data.as_ptr().add(self.i)) + }; if ((entry.status & 1) == 1) == self.phase { self.i = (self.i + 1) % self.data.len(); if self.i == 0 { From 249606a8c9a49b685b132e56bae72c20d220c719 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 28 Aug 2019 20:15:03 -0600 Subject: [PATCH 0295/1301] Fix nvmed on real hardware --- nvmed/src/nvme.rs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index 9b37fd3f65..f32a2601a5 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -242,6 +242,7 @@ impl NvmeCompQueue { let entry = unsafe { ptr::read_volatile(self.data.as_ptr().add(self.i)) }; + // println!("{:?}", entry); if ((entry.status & 1) == 1) == self.phase { self.i = (self.i + 1) % self.data.len(); if self.i == 0 { @@ -258,7 +259,7 @@ impl NvmeCompQueue { if let Some(some) = self.complete() { return some; } else { - thread::yield_now(); + unsafe { asm!("pause"); } } } } @@ -318,6 +319,17 @@ impl Nvme { println!(" - Disable"); self.regs.cc.writef(1, false); + println!(" - Waiting for not ready"); + loop { + let csts = self.regs.csts.read(); + // println!("CSTS: {:X}", csts); + if csts & 1 == 1 { + asm!("pause"); + } else { + break; + } + } + println!(" - Mask all interrupts"); self.regs.intms.write(0xFFFFFFFF); @@ -349,8 +361,14 @@ impl Nvme { self.regs.cc.writef(1, true); println!(" - Waiting for ready"); - while ! self.regs.csts.readf(1) { - thread::yield_now(); + loop { + let csts = self.regs.csts.read(); + // println!("CSTS: {:X}", csts); + if csts & 1 == 0 { + asm!("pause"); + } else { + break; + } } { @@ -538,6 +556,8 @@ impl Nvme { } } + println!(" - Complete"); + namespaces } From d49c9458269bd124d1a0ca8a92ed4e201dfe31c3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 29 Aug 2019 08:22:16 -0600 Subject: [PATCH 0296/1301] rtl8168d: Use pause in spin loops --- rtl8168d/src/device.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 892ee7c5d1..58830fedc7 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -1,4 +1,4 @@ -use std::{mem, thread}; +use std::mem; use std::collections::BTreeMap; use netutils::setcfg; @@ -162,7 +162,7 @@ impl SchemeMut for Rtl8168 { self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet while self.regs.tppoll.readf(1 << 6) { - thread::yield_now(); + unsafe { asm!("pause"); } } self.transmit_i += 1; @@ -170,7 +170,7 @@ impl SchemeMut for Rtl8168 { return Ok(i); } - thread::yield_now(); + unsafe { asm!("pause"); } } } @@ -286,7 +286,7 @@ impl Rtl8168 { // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value self.regs.cmd.writef(1 << 4, true); while self.regs.cmd.readf(1 << 4) { - thread::yield_now(); + asm!("pause"); } // Set up rx buffers From a0ada39f1badbcd92b6e8b01d67bd0d39067db54 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 29 Aug 2019 19:31:56 -0600 Subject: [PATCH 0297/1301] rtl8168d: Open irq file with O_NONBLOCK --- rtl8168d/src/main.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 19908dba1b..e2cb2e51c1 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -33,10 +33,17 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("rtl8168d: failed to create network scheme"); + let socket_fd = syscall::open( + ":network", + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK + ).expect("rtl8168d: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open IRQ file"); + let irq_fd = syscall::open( + format!("irq:{}", irq), + syscall::O_RDWR | syscall::O_NONBLOCK + ).expect("rtl8168d: failed to open IRQ file"); + let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; let address = unsafe { syscall::physmap(bar, 256, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("rtl8168d: failed to map address") }; { From 2de4a526fb6158344647a766ef3b7c616eeed4a5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 29 Aug 2019 20:16:48 -0600 Subject: [PATCH 0298/1301] Merge scheme handling in e1000d and rtl8168d --- e1000d/src/main.rs | 12 +-- rtl8168d/src/device.rs | 157 ++++++++++++++++++--------------- rtl8168d/src/main.rs | 196 +++++++++++++++++++++++++---------------- 3 files changed, 213 insertions(+), 152 deletions(-) diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index fb87503ef4..6518764fc2 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -71,10 +71,7 @@ fn main() { let irq_str = args.next().expect("e1000d: no irq provided"); let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); - print!( - "{}", - format!(" + E1000 {} on: {:X} IRQ: {}\n", name, bar, irq) - ); + println!(" + E1000 {} on: {:X} IRQ: {}", name, bar, irq); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { @@ -87,8 +84,11 @@ fn main() { File::from_raw_fd(socket_fd as RawFd) })); - let mut irq_file = - File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file"); + let irq_fd = syscall::open( + format!("irq:{}", irq), + syscall::O_RDWR | syscall::O_NONBLOCK + ).expect("e1000d: failed to open IRQ file"); + let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; let address = unsafe { syscall::physmap(bar, 128 * 1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 58830fedc7..906fdae221 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -5,7 +5,7 @@ use netutils::setcfg; use syscall::error::{Error, EACCES, EBADF, EINVAL, EWOULDBLOCK, Result}; use syscall::flag::O_NONBLOCK; use syscall::io::{Dma, Mmio, Io, ReadOnly}; -use syscall::scheme::SchemeMut; +use syscall::scheme::SchemeBlockMut; #[repr(packed)] struct Regs { @@ -79,18 +79,18 @@ pub struct Rtl8168 { pub handles: BTreeMap } -impl SchemeMut for Rtl8168 { - fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { +impl SchemeBlockMut for Rtl8168 { + fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { if uid == 0 { self.next_id += 1; self.handles.insert(self.next_id, flags); - Ok(self.next_id) + Ok(Some(self.next_id)) } else { Err(Error::new(EACCES)) } } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result { + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { if ! buf.is_empty() { return Err(Error::new(EINVAL)); } @@ -101,85 +101,97 @@ impl SchemeMut for Rtl8168 { }; self.next_id += 1; self.handles.insert(self.next_id, flags); - Ok(self.next_id) + Ok(Some(self.next_id)) } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let mut inner = |buf: &mut [u8]| -> Result> { + let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if self.receive_i >= self.receive_ring.len() { - self.receive_i = 0; - } - - let rd = &mut self.receive_ring[self.receive_i]; - if ! rd.ctrl.readf(OWN) { - let rd_len = rd.ctrl.read() & 0x3FFF; - - let data = &self.receive_buffer[self.receive_i]; - - let mut i = 0; - while i < buf.len() && i < rd_len as usize { - buf[i] = data[i].read(); - i += 1; + if self.receive_i >= self.receive_ring.len() { + self.receive_i = 0; } - let eor = rd.ctrl.read() & EOR; - rd.ctrl.write(OWN | eor | data.len() as u32); + let rd = &mut self.receive_ring[self.receive_i]; + if ! rd.ctrl.readf(OWN) { + let rd_len = rd.ctrl.read() & 0x3FFF; - self.receive_i += 1; - - return Ok(i); - } - - if flags & O_NONBLOCK == O_NONBLOCK { - Ok(0) - } else { - Err(Error::new(EWOULDBLOCK)) - } - } - - fn write(&mut self, id: usize, buf: &[u8]) -> Result { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - loop { - if self.transmit_i >= self.transmit_ring.len() { - self.transmit_i = 0; - } - - let td = &mut self.transmit_ring[self.transmit_i]; - if ! td.ctrl.readf(OWN) { - let data = &mut self.transmit_buffer[self.transmit_i]; + let data = &self.receive_buffer[self.receive_i]; let mut i = 0; - while i < buf.len() && i < data.len() { - data[i].write(buf[i]); + while i < buf.len() && i < rd_len as usize { + buf[i] = data[i].read(); i += 1; } - let eor = td.ctrl.read() & EOR; - td.ctrl.write(OWN | eor | FS | LS | i as u32); + let eor = rd.ctrl.read() & EOR; + rd.ctrl.write(OWN | eor | data.len() as u32); - self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet + self.receive_i += 1; - while self.regs.tppoll.readf(1 << 6) { - unsafe { asm!("pause"); } + Ok(Some(i)) + } else if flags & O_NONBLOCK == O_NONBLOCK { + Err(Error::new(EWOULDBLOCK)) + } else { + Ok(None) + } + }; + + println!("rtl8168d read {}", buf.len()); + let res = inner(buf); + println!("rtl8168d read {} = {:?}", buf.len(), res); + res + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + let mut inner = |buf: &[u8]| -> Result> { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + loop { + if self.transmit_i >= self.transmit_ring.len() { + self.transmit_i = 0; } - self.transmit_i += 1; + let td = &mut self.transmit_ring[self.transmit_i]; + if ! td.ctrl.readf(OWN) { + let data = &mut self.transmit_buffer[self.transmit_i]; - return Ok(i); + let mut i = 0; + while i < buf.len() && i < data.len() { + data[i].write(buf[i]); + i += 1; + } + + let eor = td.ctrl.read() & EOR; + td.ctrl.write(OWN | eor | FS | LS | i as u32); + + self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet + + while self.regs.tppoll.readf(1 << 6) { + unsafe { asm!("pause"); } + } + + self.transmit_i += 1; + + return Ok(Some(i)); + } + + unsafe { asm!("pause"); } } + }; - unsafe { asm!("pause"); } - } + println!("rtl8168d write {}", buf.len()); + let res = inner(buf); + println!("rtl8168d write {} = {:?}", buf.len(), res); + res } - fn fevent(&mut self, id: usize, _flags: usize) -> Result { + fn fevent(&mut self, id: usize, _flags: usize) -> Result> { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(0) + Ok(Some(0)) } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; let mut i = 0; @@ -188,17 +200,17 @@ impl SchemeMut for Rtl8168 { buf[i] = scheme_path[i]; i += 1; } - Ok(i) + Ok(Some(i)) } - fn fsync(&mut self, id: usize) -> Result { + fn fsync(&mut self, id: usize) -> Result> { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(0) + Ok(Some(0)) } - fn close(&mut self, id: usize) -> Result { + fn close(&mut self, id: usize) -> Result> { self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(0) + Ok(Some(0)) } } @@ -254,12 +266,12 @@ impl Rtl8168 { Ok(module) } - pub unsafe fn irq(&mut self) -> u16 { + pub unsafe fn irq(&mut self) -> bool { // Read and then clear the ISR let isr = self.regs.isr.read(); self.regs.isr.write(isr); let imr = self.regs.imr.read(); - isr & imr + (isr & imr) != 0 } pub fn next_read(&self) -> usize { @@ -280,16 +292,18 @@ impl Rtl8168 { (mac_low >> 24) as u8, mac_high as u8, (mac_high >> 8) as u8]; - print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value + println!(" - Reset"); self.regs.cmd.writef(1 << 4, true); while self.regs.cmd.readf(1 << 4) { asm!("pause"); } // Set up rx buffers + println!(" - Receive buffers"); for i in 0..self.receive_ring.len() { let rd = &mut self.receive_ring[i]; let data = &mut self.receive_buffer[i]; @@ -301,6 +315,7 @@ impl Rtl8168 { } // Set up normal priority tx buffers + println!(" - Transmit buffers (normal priority)"); for i in 0..self.transmit_ring.len() { self.transmit_ring[i].buffer.write(self.transmit_buffer[i].physical() as u64); } @@ -309,6 +324,7 @@ impl Rtl8168 { } // Set up high priority tx buffers + println!(" - Transmit buffers (high priority)"); for i in 0..self.transmit_ring_h.len() { self.transmit_ring_h[i].buffer.write(self.transmit_buffer_h[i].physical() as u64); } @@ -316,6 +332,7 @@ impl Rtl8168 { td.ctrl.writef(EOR, true); } + println!(" - Set config"); // Unlock config self.regs.cmd_9346.write(1 << 7 | 1 << 6); @@ -358,5 +375,7 @@ impl Rtl8168 { // Lock config self.regs.cmd_9346.write(0); + + println!(" - Complete!"); } } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index e2cb2e51c1..9abaf31648 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -7,16 +7,58 @@ extern crate syscall; use std::cell::RefCell; use std::env; use std::fs::File; -use std::io::{self, Read, Write, Result}; +use std::io::{ErrorKind, Read, Result, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, SchemeMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; -use syscall::error::EWOULDBLOCK; +use syscall::{Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; pub mod device; +fn handle_update( + socket: &mut File, + device: &mut device::Rtl8168, + todo: &mut Vec, +) -> Result { + // Handle any blocked packets + let mut i = 0; + while i < todo.len() { + if let Some(a) = device.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&packet)?; + } else { + i += 1; + } + } + + // Check that the socket is empty + loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => return Ok(true), + Ok(_) => (), + Err(err) => { + if err.kind() == ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } + } + } + + if let Some(a) = device.handle(&packet) { + packet.a = a; + socket.write(&packet)?; + } else { + todo.push(packet); + } + } + + Ok(false) +} + fn main() { let mut args = env::args().skip(1); @@ -29,15 +71,18 @@ fn main() { let irq_str = args.next().expect("rtl8168d: no irq provided"); let irq = irq_str.parse::().expect("rtl8168d: failed to parse irq"); - print!("{}", format!(" + RTL8168 {} on: {:X}, IRQ: {}\n", name, bar, irq)); + println!(" + RTL8168 {} on: {:X}, IRQ: {}", name, bar, irq); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { let socket_fd = syscall::open( ":network", - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK - ).expect("rtl8168d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + ) + .expect("rtl8168d: failed to create network scheme"); + let socket = Arc::new(RefCell::new(unsafe { + File::from_raw_fd(socket_fd as RawFd) + })); let irq_fd = syscall::open( format!("irq:{}", irq), @@ -45,11 +90,17 @@ fn main() { ).expect("rtl8168d: failed to open IRQ file"); let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; - let address = unsafe { syscall::physmap(bar, 256, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("rtl8168d: failed to map address") }; + let address = unsafe { + syscall::physmap(bar, 256, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("rtl8168d: failed to map address") + }; { - let device = Arc::new(RefCell::new(unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") })); + let device = Arc::new(RefCell::new(unsafe { + device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") + })); - let mut event_queue = EventQueue::::new().expect("rtl8168d: failed to create event queue"); + let mut event_queue = + EventQueue::::new().expect("rtl8168d: failed to create event queue"); syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); @@ -58,99 +109,90 @@ fn main() { let device_irq = device.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + if unsafe { device_irq.borrow_mut().irq() } { + irq_file.write(&mut irq)?; - let isr = unsafe { device_irq.borrow_mut().irq() }; - if isr != 0 { - irq_file.write(&mut irq)?; + if handle_update( + &mut socket_irq.borrow_mut(), + &mut device_irq.borrow_mut(), + &mut todo_irq.borrow_mut(), + )? { + return Ok(Some(0)); + } - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - device_irq.borrow_mut().handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket_irq.borrow_mut().write(&mut todo[i])?; - todo.remove(i); + let next_read = device_irq.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } } - } - - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }).expect("rtl8168d: failed to catch events on IRQ file"); + Ok(None) + }, + ) + .expect("rtl8168d: failed to catch events on IRQ file"); let device_packet = device.clone(); let socket_packet = socket.clone(); - event_queue.add(socket_fd as RawFd, move |_event| -> Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => return Ok(Some(0)), - Ok(_) => (), - Err(err) => if err.kind() == io::ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } + event_queue + .add(socket_fd as RawFd, move |_event| -> Result> { + if handle_update( + &mut socket_packet.borrow_mut(), + &mut device_packet.borrow_mut(), + &mut todo.borrow_mut(), + )? { + return Ok(Some(0)); } - let a = packet.a; - device_packet.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); - } else { - socket_packet.borrow_mut().write(&mut packet)?; + let next_read = device_packet.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); } - } - let next_read = device_packet.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - - Ok(None) - }).expect("rtl8168d: failed to catch events on scheme file"); + Ok(None) + }) + .expect("rtl8168d: failed to catch events on scheme file"); let send_events = |event_count| { for (handle_id, _handle) in device.borrow().handles.iter() { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: syscall::flag::EVENT_READ, - d: event_count - }).expect("e1000d: failed to write event"); + socket + .borrow_mut() + .write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: syscall::flag::EVENT_READ, + d: event_count, + }) + .expect("rtl8168d: failed to write event"); } }; - for event_count in event_queue.trigger_all(event::Event { - fd: 0, - flags: 0, - }).expect("rtl8168d: failed to trigger events") { + for event_count in event_queue + .trigger_all(event::Event { fd: 0, flags: 0 }) + .expect("rtl8168d: failed to trigger events") + { send_events(event_count); } loop { let event_count = event_queue.run().expect("rtl8168d: failed to handle events"); if event_count == 0 { + //TODO: Handle todo break; } send_events(event_count); } } - unsafe { let _ = syscall::physunmap(address); } + unsafe { + let _ = syscall::physunmap(address); + } } } From aecb345abc3a546641cfbb6333661475f3ac6bcd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 29 Aug 2019 20:31:33 -0600 Subject: [PATCH 0299/1301] Remove rtl8168d debugging --- rtl8168d/src/device.rs | 122 ++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 68 deletions(-) diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 906fdae221..84f24203d5 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -105,85 +105,71 @@ impl SchemeBlockMut for Rtl8168 { } fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let mut inner = |buf: &mut [u8]| -> Result> { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if self.receive_i >= self.receive_ring.len() { - self.receive_i = 0; + if self.receive_i >= self.receive_ring.len() { + self.receive_i = 0; + } + + let rd = &mut self.receive_ring[self.receive_i]; + if ! rd.ctrl.readf(OWN) { + let rd_len = rd.ctrl.read() & 0x3FFF; + + let data = &self.receive_buffer[self.receive_i]; + + let mut i = 0; + while i < buf.len() && i < rd_len as usize { + buf[i] = data[i].read(); + i += 1; } - let rd = &mut self.receive_ring[self.receive_i]; - if ! rd.ctrl.readf(OWN) { - let rd_len = rd.ctrl.read() & 0x3FFF; + let eor = rd.ctrl.read() & EOR; + rd.ctrl.write(OWN | eor | data.len() as u32); - let data = &self.receive_buffer[self.receive_i]; + self.receive_i += 1; - let mut i = 0; - while i < buf.len() && i < rd_len as usize { - buf[i] = data[i].read(); - i += 1; - } - - let eor = rd.ctrl.read() & EOR; - rd.ctrl.write(OWN | eor | data.len() as u32); - - self.receive_i += 1; - - Ok(Some(i)) - } else if flags & O_NONBLOCK == O_NONBLOCK { - Err(Error::new(EWOULDBLOCK)) - } else { - Ok(None) - } - }; - - println!("rtl8168d read {}", buf.len()); - let res = inner(buf); - println!("rtl8168d read {} = {:?}", buf.len(), res); - res + Ok(Some(i)) + } else if flags & O_NONBLOCK == O_NONBLOCK { + Err(Error::new(EWOULDBLOCK)) + } else { + Ok(None) + } } fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let mut inner = |buf: &[u8]| -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - loop { - if self.transmit_i >= self.transmit_ring.len() { - self.transmit_i = 0; - } - - let td = &mut self.transmit_ring[self.transmit_i]; - if ! td.ctrl.readf(OWN) { - let data = &mut self.transmit_buffer[self.transmit_i]; - - let mut i = 0; - while i < buf.len() && i < data.len() { - data[i].write(buf[i]); - i += 1; - } - - let eor = td.ctrl.read() & EOR; - td.ctrl.write(OWN | eor | FS | LS | i as u32); - - self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet - - while self.regs.tppoll.readf(1 << 6) { - unsafe { asm!("pause"); } - } - - self.transmit_i += 1; - - return Ok(Some(i)); - } - - unsafe { asm!("pause"); } + loop { + if self.transmit_i >= self.transmit_ring.len() { + self.transmit_i = 0; } - }; - println!("rtl8168d write {}", buf.len()); - let res = inner(buf); - println!("rtl8168d write {} = {:?}", buf.len(), res); - res + let td = &mut self.transmit_ring[self.transmit_i]; + if ! td.ctrl.readf(OWN) { + let data = &mut self.transmit_buffer[self.transmit_i]; + + let mut i = 0; + while i < buf.len() && i < data.len() { + data[i].write(buf[i]); + i += 1; + } + + let eor = td.ctrl.read() & EOR; + td.ctrl.write(OWN | eor | FS | LS | i as u32); + + self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet + + while self.regs.tppoll.readf(1 << 6) { + unsafe { asm!("pause"); } + } + + self.transmit_i += 1; + + return Ok(Some(i)); + } + + unsafe { asm!("pause"); } + } } fn fevent(&mut self, id: usize, _flags: usize) -> Result> { From a1144552d57209c8678b873a0124d781006b0c5e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 4 Sep 2019 19:55:28 -0600 Subject: [PATCH 0300/1301] Re-enable QEMU mouse integration --- ps2d/src/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 13c71c0876..58539c71f0 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -46,7 +46,7 @@ impl char> Ps2d { let mut ps2 = Ps2::new(); let extra_packet = ps2.init(); - let vmmouse = false; //vm::enable(); + let vmmouse = vm::enable(); let mut ps2d = Ps2d { ps2: ps2, From eda6bc6f92bd2f72f95f1ca6c0cd7f0444d00afb Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 4 Sep 2019 20:38:08 -0600 Subject: [PATCH 0301/1301] Calculate and use PCI BAR memory sizes in most drivers. --- ahcid/src/main.rs | 10 +++++-- e1000d/config.toml | 3 +-- e1000d/src/main.rs | 7 +++-- initfs.toml | 4 +-- nvmed/src/main.rs | 11 +++++--- pcid/src/main.rs | 62 +++++++++++++++++++++++++++++++++++--------- rtl8168d/config.toml | 3 +-- rtl8168d/src/main.rs | 7 +++-- 8 files changed, 80 insertions(+), 27 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 9522634593..9cc8857992 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -23,14 +23,20 @@ fn main() { let bar_str = args.next().expect("ahcid: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("ahcid: failed to parse address"); + let bar_size_str = args.next().expect("ahcid: no address size provided"); + let bar_size = usize::from_str_radix(&bar_str, 16).expect("ahcid: failed to parse address size"); + let irq_str = args.next().expect("ahcid: no irq provided"); let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); - print!("{}", format!(" + AHCI {} on: {:X} IRQ: {}\n", name, bar, irq)); + print!("{}", format!(" + AHCI {} on: {:X} size: {} IRQ: {}\n", name, bar, bar_size, irq)); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 4096, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("ahcid: failed to map address") }; + let address = unsafe { + syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("ahcid: failed to map address") + }; { let scheme_name = format!("disk/{}", name); let socket_fd = syscall::open( diff --git a/e1000d/config.toml b/e1000d/config.toml index 0f5f3339b3..19d0b57f84 100644 --- a/e1000d/config.toml +++ b/e1000d/config.toml @@ -2,5 +2,4 @@ name = "E1000 NIC" class = 2 ids = { 0x8086 = [0x1004, 0x100e, 0x100f, 0x1503] } -command = ["e1000d", "$NAME", "$BAR0", "$IRQ"] - +command = ["e1000d", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ"] diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 6518764fc2..98e924259f 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -68,10 +68,13 @@ fn main() { let bar_str = args.next().expect("e1000d: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address"); + let bar_size_str = args.next().expect("e1000d: no address size provided"); + let bar_size = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address size"); + let irq_str = args.next().expect("e1000d: no irq provided"); let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); - println!(" + E1000 {} on: {:X} IRQ: {}", name, bar, irq); + println!(" + E1000 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { @@ -91,7 +94,7 @@ fn main() { let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; let address = unsafe { - syscall::physmap(bar, 128 * 1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("e1000d: failed to map address") }; { diff --git a/initfs.toml b/initfs.toml index 15b49d522f..a6eb2dddd6 100644 --- a/initfs.toml +++ b/initfs.toml @@ -5,7 +5,7 @@ name = "AHCI storage" class = 1 subclass = 6 -command = ["ahcid", "$NAME", "$BAR5", "$IRQ"] +command = ["ahcid", "$NAME", "$BAR5", "$BARSIZE5", "$IRQ"] # bgad [[drivers]] @@ -27,7 +27,7 @@ command = ["bgad", "$NAME", "$BAR0"] name = "NVME storage" class = 1 subclass = 8 -command = ["nvmed", "$NAME", "$BAR0", "$IRQ"] +command = ["nvmed", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ"] # vboxd [[drivers]] diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index daaa633fe7..5939430b8e 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -26,15 +26,20 @@ fn main() { let bar_str = args.next().expect("nvmed: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("nvmed: failed to parse address"); + let bar_size_str = args.next().expect("nvmed: no address size provided"); + let bar_size = usize::from_str_radix(&bar_str, 16).expect("nvmed: failed to parse address size"); + let irq_str = args.next().expect("nvmed: no irq provided"); let irq = irq_str.parse::().expect("nvmed: failed to parse irq"); - print!("{}", format!(" + NVME {} on: {:X} IRQ: {}\n", name, bar, irq)); + print!("{}", format!(" + NVME {} on: {:X} size: {} IRQ: {}\n", name, bar, bar_size, irq)); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - //TODO: Figure out correct size of mapping, not just 256 * 1024 - let address = unsafe { syscall::physmap(bar, 256 * 1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("nvmed: failed to map address") }; + let address = unsafe { + syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("nvmed: failed to map address") + }; { let event_fd = syscall::open("event:", syscall::O_RDWR | syscall::O_CLOEXEC) .expect("nvmed: failed to open event queue"); diff --git a/pcid/src/main.rs b/pcid/src/main.rs index a977e0fcfb..340eb6dbcb 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -13,7 +13,7 @@ use std::process::Command; use syscall::iopl; use crate::config::Config; -use crate::pci::{Pci, PciClass, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::{Pci, PciBar, PciClass, PciHeader, PciHeaderError, PciHeaderType}; mod config; mod pci; @@ -82,7 +82,7 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, if let Some(ref ids) = driver.ids { let mut device_found = false; for (vendor, devices) in ids { - let vendor_without_prefix = vendor.trim_left_matches("0x"); + let vendor_without_prefix = vendor.trim_start_matches("0x"); let vendor = i64::from_str_radix(vendor_without_prefix, 16).unwrap() as u16; if vendor != header.vendor_id() { continue; } @@ -130,6 +130,42 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, pci.write(bus_num, dev_num, func_num, 0x3C, data); } + // Find BAR sizes + let mut bars = [PciBar::None; 6]; + let mut bar_sizes = [0; 6]; + unsafe { + let count = match header.header_type() { + PciHeaderType::GENERAL => 6, + PciHeaderType::PCITOPCI => 2, + _ => 0, + }; + + for i in 0..count { + bars[i] = header.get_bar(i); + + let offset = 0x10 + (i as u8) * 4; + + let original = pci.read(bus_num, dev_num, func_num, offset); + pci.write(bus_num, dev_num, func_num, offset, 0xFFFFFFFF); + + let new = pci.read(bus_num, dev_num, func_num, offset); + pci.write(bus_num, dev_num, func_num, offset, original); + + let masked = if new & 1 == 1 { + new & 0xFFFFFFFC + } else { + new & 0xFFFFFFF0 + }; + + let size = !masked + 1; + bar_sizes[i] = if size <= 1 { + 0 + } else { + size + }; + } + } + // TODO: find a better way to pass the header data down to the // device driver, making passing the capabilities list etc // posible. @@ -142,16 +178,18 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, "$DEV" => format!("{:>02X}", dev_num), "$FUNC" => format!("{:>02X}", func_num), "$NAME" => format!("pci-{:>02X}.{:>02X}.{:>02X}", bus_num, dev_num, func_num), - "$BAR0" => format!("{}", header.get_bar(0)), - "$BAR1" => format!("{}", header.get_bar(1)), - "$BAR2" if header.header_type() == PciHeaderType::GENERAL => - format!("{}", header.get_bar(2)), - "$BAR3" if header.header_type() == PciHeaderType::GENERAL => - format!("{}", header.get_bar(3)), - "$BAR4" if header.header_type() == PciHeaderType::GENERAL => - format!("{}", header.get_bar(4)), - "$BAR5" if header.header_type() == PciHeaderType::GENERAL => - format!("{}", header.get_bar(5)), + "$BAR0" => format!("{}", bars[0]), + "$BAR1" => format!("{}", bars[1]), + "$BAR2" => format!("{}", bars[2]), + "$BAR3" => format!("{}", bars[3]), + "$BAR4" => format!("{}", bars[4]), + "$BAR5" => format!("{}", bars[5]), + "$BARSIZE0" => format!("{:>08X}", bar_sizes[0]), + "$BARSIZE1" => format!("{:>08X}", bar_sizes[1]), + "$BARSIZE2" => format!("{:>08X}", bar_sizes[2]), + "$BARSIZE3" => format!("{:>08X}", bar_sizes[3]), + "$BARSIZE4" => format!("{:>08X}", bar_sizes[4]), + "$BARSIZE5" => format!("{:>08X}", bar_sizes[5]), "$IRQ" => format!("{}", irq), "$VENID" => format!("{:>04X}", header.vendor_id()), "$DEVID" => format!("{:>04X}", header.device_id()), diff --git a/rtl8168d/config.toml b/rtl8168d/config.toml index 04a3626044..72660448ff 100644 --- a/rtl8168d/config.toml +++ b/rtl8168d/config.toml @@ -2,5 +2,4 @@ name = "RTL8168 NIC" class = 2 ids = { 0x10ec = [0x8168] } -command = ["rtl8168d", "$NAME", "$BAR2", "$IRQ"] - +command = ["rtl8168d", "$NAME", "$BAR2", "$BARSIZE2", "$IRQ"] diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 9abaf31648..ddc7cbe4e4 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -68,10 +68,13 @@ fn main() { let bar_str = args.next().expect("rtl8168d: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("rtl8168d: failed to parse address"); + let bar_size_str = args.next().expect("rtl8168d: no address size provided"); + let bar_size = usize::from_str_radix(&bar_str, 16).expect("rtl8168d: failed to parse address size"); + let irq_str = args.next().expect("rtl8168d: no irq provided"); let irq = irq_str.parse::().expect("rtl8168d: failed to parse irq"); - println!(" + RTL8168 {} on: {:X}, IRQ: {}", name, bar, irq); + println!(" + RTL8168 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { @@ -91,7 +94,7 @@ fn main() { let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; let address = unsafe { - syscall::physmap(bar, 256, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("rtl8168d: failed to map address") }; { From 2087f0ad03d1f388f3385fa06a6962c9e789bdb6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 4 Sep 2019 20:40:18 -0600 Subject: [PATCH 0302/1301] Fix parsing of bar size --- ahcid/src/main.rs | 2 +- e1000d/src/main.rs | 2 +- nvmed/src/main.rs | 2 +- rtl8168d/src/main.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 9cc8857992..5e261cc2d0 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -24,7 +24,7 @@ fn main() { let bar = usize::from_str_radix(&bar_str, 16).expect("ahcid: failed to parse address"); let bar_size_str = args.next().expect("ahcid: no address size provided"); - let bar_size = usize::from_str_radix(&bar_str, 16).expect("ahcid: failed to parse address size"); + let bar_size = usize::from_str_radix(&bar_size_str, 16).expect("ahcid: failed to parse address size"); let irq_str = args.next().expect("ahcid: no irq provided"); let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 98e924259f..dd4800371e 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -69,7 +69,7 @@ fn main() { let bar = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address"); let bar_size_str = args.next().expect("e1000d: no address size provided"); - let bar_size = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address size"); + let bar_size = usize::from_str_radix(&bar_size_str, 16).expect("e1000d: failed to parse address size"); let irq_str = args.next().expect("e1000d: no irq provided"); let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 5939430b8e..fb37c0f6b9 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -27,7 +27,7 @@ fn main() { let bar = usize::from_str_radix(&bar_str, 16).expect("nvmed: failed to parse address"); let bar_size_str = args.next().expect("nvmed: no address size provided"); - let bar_size = usize::from_str_radix(&bar_str, 16).expect("nvmed: failed to parse address size"); + let bar_size = usize::from_str_radix(&bar_size_str, 16).expect("nvmed: failed to parse address size"); let irq_str = args.next().expect("nvmed: no irq provided"); let irq = irq_str.parse::().expect("nvmed: failed to parse irq"); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index ddc7cbe4e4..d169b25ca3 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -69,7 +69,7 @@ fn main() { let bar = usize::from_str_radix(&bar_str, 16).expect("rtl8168d: failed to parse address"); let bar_size_str = args.next().expect("rtl8168d: no address size provided"); - let bar_size = usize::from_str_radix(&bar_str, 16).expect("rtl8168d: failed to parse address size"); + let bar_size = usize::from_str_radix(&bar_size_str, 16).expect("rtl8168d: failed to parse address size"); let irq_str = args.next().expect("rtl8168d: no irq provided"); let irq = irq_str.parse::().expect("rtl8168d: failed to parse irq"); From 8da1c13b737c6af68b37a79b9415671c4dbfd95f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 4 Sep 2019 20:44:24 -0600 Subject: [PATCH 0303/1301] Use BAR size for ihda --- ihdad/config.toml | 3 +-- ihdad/src/main.rs | 10 ++++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ihdad/config.toml b/ihdad/config.toml index 2bee08c1f4..11fc35efb1 100644 --- a/ihdad/config.toml +++ b/ihdad/config.toml @@ -2,5 +2,4 @@ name = "Intel HD Audio" class = 4 subclass = 3 -command = ["ihdad", "$NAME", "$BAR0", "$IRQ", "$VENID", "$DEVID"] - +command = ["ihdad", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ", "$VENID", "$DEVID"] diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index d1f37307be..3fe24d8713 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -34,6 +34,9 @@ fn main() { let bar_str = args.next().expect("ihda: no address provided"); let bar = usize::from_str_radix(&bar_str, 16).expect("ihda: failed to parse address"); + let bar_size_str = args.next().expect("ihda: no address size provided"); + let bar_size = usize::from_str_radix(&bar_size_str, 16).expect("ihda: failed to parse address size"); + let irq_str = args.next().expect("ihda: no irq provided"); let irq = irq_str.parse::().expect("ihda: failed to parse irq"); @@ -43,11 +46,14 @@ fn main() { let prod_str = args.next().expect("ihda: no product id provided"); let prod = usize::from_str_radix(&prod_str, 16).expect("ihda: failed to parse product id"); - print!("{}", format!(" + ihda {} on: {:X} IRQ: {}\n", name, bar, irq)); + print!("{}", format!(" + ihda {} on: {:X} size: {} IRQ: {}\n", name, bar, bar_size, irq)); // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { syscall::physmap(bar, 0x4000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("ihdad: failed to map address") }; + let address = unsafe { + syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("ihdad: failed to map address") + }; { let mut irq_file = File::open(format!("irq:{}", irq)).expect("IHDA: failed to open IRQ file"); From a38a20984e25d95b0ed0ee3bcc8b70c4ba6c3f7d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 5 Sep 2019 20:37:20 -0600 Subject: [PATCH 0304/1301] Basic implementation of NVMe IRQ handler --- nvmed/src/nvme.rs | 4 ++-- nvmed/src/scheme.rs | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index f32a2601a5..9169dce064 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -238,7 +238,7 @@ impl NvmeCompQueue { }) } - fn complete(&mut self) -> Option<(usize, NvmeComp)> { + pub (crate) fn complete(&mut self) -> Option<(usize, NvmeComp)> { let entry = unsafe { ptr::read_volatile(self.data.as_ptr().add(self.i)) }; @@ -274,7 +274,7 @@ pub struct NvmeNamespace { pub struct Nvme { regs: &'static mut NvmeRegs, submission_queues: [NvmeCmdQueue; 2], - completion_queues: [NvmeCompQueue; 2], + pub (crate) completion_queues: [NvmeCompQueue; 2], buffer: Dma<[u8; 512 * 4096]>, // 2MB of buffer buffer_prp: Dma<[u64; 512]>, // 4KB of PRP for the buffer } diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index 58edb0dae2..15edcbdb45 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -37,8 +37,19 @@ impl DiskScheme { impl DiskScheme { pub fn irq(&mut self) -> bool { - // TODO: implement - false + let mut found_completion = false; + + let nvme = &mut self.nvme; + for qid in 0..nvme.completion_queues.len() { + while let Some((head, entry)) = nvme.completion_queues[qid].complete() { + found_completion = true; + println!("nvmed: Unhandled completion {:?}", entry); + //TODO: Handle errors + unsafe { nvme.completion_queue_head(qid as u16, head as u16); } + } + } + + found_completion } } From 283ff736c6d85a5be35bd2f36d960ac37ada241f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 11 Sep 2019 20:09:13 -0600 Subject: [PATCH 0305/1301] Make separate config for xhcid --- filesystem.toml => xhcid/config.toml | 3 --- 1 file changed, 3 deletions(-) rename filesystem.toml => xhcid/config.toml (80%) diff --git a/filesystem.toml b/xhcid/config.toml similarity index 80% rename from filesystem.toml rename to xhcid/config.toml index 20871a0272..74db47d8e1 100644 --- a/filesystem.toml +++ b/xhcid/config.toml @@ -1,6 +1,3 @@ -## Drivers for FS ## - -# xhcid # [[drivers]] # name = "XHCI" # class = 12 From 7f95962fa2cc52d4fd29e1f16d93c0cee3d43803 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 11 Sep 2019 20:35:09 -0600 Subject: [PATCH 0306/1301] rtl8168d: match 8169 device and add documentation --- rtl8168d/config.toml | 2 +- rtl8168d/src/device.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rtl8168d/config.toml b/rtl8168d/config.toml index 72660448ff..a65ba291e3 100644 --- a/rtl8168d/config.toml +++ b/rtl8168d/config.toml @@ -1,5 +1,5 @@ [[drivers]] name = "RTL8168 NIC" class = 2 -ids = { 0x10ec = [0x8168] } +ids = { 0x10ec = [0x8168, 0x8169] } command = ["rtl8168d", "$NAME", "$BAR2", "$BARSIZE2", "$IRQ"] diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 84f24203d5..502d66ec31 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -1,3 +1,6 @@ +// Supports Realtek RTL8168, RTL8169, and other compatible devices +// See https://people.freebsd.org/~wpaul/RealTek/rtl8169spec-121.pdf + use std::mem; use std::collections::BTreeMap; From c7f02e5e2141c0dbf07bc82fd40ee7d6cad95229 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 11 Sep 2019 21:03:07 -0600 Subject: [PATCH 0307/1301] rtl8168d: fix calculation of next read size --- rtl8168d/src/device.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 502d66ec31..a1b19c44c4 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -264,12 +264,17 @@ impl Rtl8168 { } pub fn next_read(&self) -> usize { - for rd in self.receive_ring.iter() { - if ! rd.ctrl.readf(OWN) { - return rd.ctrl.read() as usize & 0x3FFF; - } + let mut receive_i = self.receive_i; + if receive_i >= self.receive_ring.len() { + receive_i = 0; + } + + let rd = &self.receive_ring[receive_i]; + if ! rd.ctrl.readf(OWN) { + (rd.ctrl.read() & 0x3FFF) as usize + } else { + 0 } - 0 } pub unsafe fn init(&mut self) { From 084587ed0245098c9d28916f34aae90d96001964 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 11 Sep 2019 22:03:34 -0600 Subject: [PATCH 0308/1301] Add TODO to address spurious interrupts --- rtl8168d/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index d169b25ca3..6b5e676f13 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -118,6 +118,7 @@ fn main() { move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; + //TODO: This may be causing spurious interrupts if unsafe { device_irq.borrow_mut().irq() } { irq_file.write(&mut irq)?; From 119f7a55956a25e3fc7c2490dd86031bdbe18b3d Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 4 Jan 2020 19:35:16 +1100 Subject: [PATCH 0309/1301] Add partition support for ahcid (untested). --- Cargo.lock | 119 +++++++++++++++++++-- ahcid/.gitignore | 1 + ahcid/Cargo.toml | 5 +- ahcid/src/scheme.rs | 254 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 361 insertions(+), 18 deletions(-) create mode 100644 ahcid/.gitignore diff --git a/Cargo.lock b/Cargo.lock index 8c602a0414..c325744907 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,8 +4,9 @@ name = "ahcid" version = "0.1.0" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -61,7 +62,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.1.0" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "build_const" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -98,7 +104,15 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crc" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -157,7 +171,7 @@ name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -171,6 +185,17 @@ name = "futures" version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "gpt" +version = "0.6.3" +source = "git+https://github.com/4lDO2/gpt#20160d7089faa44c3566cad0fa6e49b2824b599c" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "httparse" version = "1.3.4" @@ -238,7 +263,7 @@ dependencies = [ name = "ixgbed" version = "1.0.0" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", @@ -536,6 +561,16 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "partitionlib" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/partitionlib.git#ae8157fde75ac3589b7e8ff831bbba538b8009d8" +dependencies = [ + "gpt 0.6.3 (git+https://github.com/4lDO2/gpt)", + "scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pbr" version = "1.0.1" @@ -563,7 +598,7 @@ dependencies = [ name = "pcid" version = "0.1.0" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", @@ -596,6 +631,14 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ps2d" version = "0.1.0" @@ -614,6 +657,14 @@ dependencies = [ "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.6.5" @@ -815,6 +866,24 @@ name = "scopeguard" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "scroll" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scroll_derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "sct" version = "0.4.0" @@ -829,7 +898,7 @@ name = "sdl2" version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -912,6 +981,16 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termion" version = "1.5.3" @@ -1135,6 +1214,11 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "untrusted" version = "0.6.2" @@ -1155,6 +1239,14 @@ name = "utf8parse" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "uuid" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "vboxd" version = "0.1.0" @@ -1260,13 +1352,15 @@ dependencies = [ "checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" @@ -1275,6 +1369,7 @@ dependencies = [ "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" +"checksum gpt 0.6.3 (git+https://github.com/4lDO2/gpt)" = "" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" "checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" @@ -1310,12 +1405,15 @@ dependencies = [ "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +"checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" "checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" "checksum pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "deb73390ab68d81992bd994d145f697451bb0b54fd39738e72eef32458ad6907" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" @@ -1338,6 +1436,8 @@ dependencies = [ "checksum safemem 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e133ccc4f4d1cd4f89cc8a7ff618287d56dc7f638b8e38fc32c5fdcadc339dd5" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" +"checksum scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28" "checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" "checksum sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d051a07231e303f5f719da78cb6f7394f6d5b54f733aef5b0b447804a83edd7b" "checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" @@ -1351,6 +1451,7 @@ dependencies = [ "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" "checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +"checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8" "checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" @@ -1372,9 +1473,11 @@ dependencies = [ "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" +"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" "checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" diff --git a/ahcid/.gitignore b/ahcid/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/ahcid/.gitignore @@ -0,0 +1 @@ +/target diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index 789f7e0b38..bfd9f21315 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "0.7" -redox_syscall = "0.1" +bitflags = "1.2" byteorder = "1.2" +partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +redox_syscall = "0.1" diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 28684b2cbc..d13985757b 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -1,25 +1,148 @@ use std::collections::BTreeMap; use std::{cmp, str}; +use std::convert::{TryFrom, TryInto}; use std::fmt::Write; -use std::io::Read; +use std::io::prelude::*; +use std::io::SeekFrom; +use std::io; + use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, Result, + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, EOVERFLOW, Result, Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; use crate::ahci::Disk; use crate::ahci::hba::HbaMem; +use partitionlib::{LogicalBlockSize, PartitionTable}; + #[derive(Clone)] enum Handle { - List(Vec, usize), - Disk(usize, usize) + List(Vec, usize), // Dir contents buffer, position + Disk(usize, usize), // Disk index, position + Partition(usize, u32, usize), // Disk index, partition index, position +} + +pub struct DiskWrapper { + disk: Box, + pt: Option, +} + +impl DiskWrapper { + fn pt(disk: &mut dyn Disk) -> Option { + let bs = match disk.block_length().unwrap() { + 512 => LogicalBlockSize::Lb512, + 4096 => LogicalBlockSize::Lb4096, + _ => return None, + }; + struct Device<'a, 'b> { disk: &'a mut dyn Disk, offset: u64, block_bytes: &'b mut [u8] } + + impl<'a, 'b> Seek for Device<'a, 'b> { + fn seek(&mut self, from: SeekFrom) -> io::Result { + let size = i64::try_from(self.disk.size()).or(Err(io::Error::new(io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes")))?; + + self.offset = match from { + SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos), + SeekFrom::Current(new_pos) => cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64, + SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64, + }; + + Ok(self.offset) + } + } + // Perhaps this impl should be used in the rest of the scheme. + impl<'a, 'b> Read for Device<'a, 'b> { + fn read(&mut self, mut buf: &mut [u8]) -> io::Result { + // TODO: Yield sometimes, perhaps after a few blocks or something. + use std::ops::{Add, Div, Rem}; + + fn div_round_up(a: T, b: T) -> T + where + T: Add + Div + Rem + PartialEq + From + Copy + { + if a % b != T::from(0u8) { + a / b + T::from(1u8) + } else { + a / b + } + } + + let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?; + + let start_block = self.offset / u64::from(blksize); + let end_block = div_round_up(self.offset + buf.len() as u64, u64::from(blksize)); // The first block not in the range + + let offset_from_start_block: u64 = self.offset % u64::from(blksize); + let offset_to_end_block: u64 = u64::from(blksize) - (self.offset + buf.len() as u64) % u64::from(blksize); + + let first_whole_block = start_block + if offset_from_start_block > 0 { 1 } else { 0 }; + let last_whole_block = end_block - if offset_to_end_block > 0 { 1 } else { 0 } - 1; + + let whole_blocks_to_read = last_whole_block - first_whole_block + 1; + + for block in start_block..end_block { + // TODO: Async/await? I mean, shouldn't AHCI be async? + + loop { + let block = self.offset / u64::from(blksize); + + match self.disk.read(block, self.block_bytes) { + Ok(Some(bytes)) => { + assert_eq!(bytes, blksize as usize); + break; + } + Ok(None) => continue, + Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), + } + } + + let (bytes_to_read, src_buf): (u64, &[u8]) = if block == start_block { + (u64::from(blksize) - offset_from_start_block, &self.block_bytes[offset_from_start_block as usize..]) + } else if block == end_block { + (u64::from(blksize) - offset_to_end_block, &self.block_bytes[..offset_to_end_block as usize]) + } else { + (blksize.into(), &self.block_bytes[..]) + }; + buf[..bytes_to_read as usize].copy_from_slice(src_buf); + buf = &mut buf[..bytes_to_read as usize]; + } + + let bytes_read = std::cmp::min(buf.len(), whole_blocks_to_read as usize * blksize as usize + offset_from_start_block as usize + offset_to_end_block as usize); + self.offset += bytes_read as u64; + + Ok(bytes_read) + } + } + + let mut block_bytes = [0u8; 4096]; + + partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() + } + fn new(mut disk: Box) -> Self { + Self { + pt: Self::pt(&mut *disk), + disk, + } + } +} + +impl std::ops::Deref for DiskWrapper { + type Target = dyn Disk; + + fn deref(&self) -> &Self::Target { + &*self.disk + } +} +impl std::ops::DerefMut for DiskWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.disk + } } pub struct DiskScheme { scheme_name: String, hba_mem: &'static mut HbaMem, - disks: Box<[Box]>, + disks: Box<[DiskWrapper]>, handles: BTreeMap, next_id: usize } @@ -29,7 +152,7 @@ impl DiskScheme { DiskScheme { scheme_name: scheme_name, hba_mem: hba_mem, - disks: disks.into_boxed_slice(), + disks: disks.into_iter().map(DiskWrapper::new).collect::>().into_boxed_slice(), handles: BTreeMap::new(), next_id: 0 } @@ -65,8 +188,15 @@ impl SchemeBlockMut for DiskScheme { if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { let mut list = String::new(); - for i in 0..self.disks.len() { - write!(list, "{}\n", i).unwrap(); + for (disk_index, disk) in self.disks.iter().enumerate() { + write!(list, "{}\n", disk_index).unwrap(); + + if disk.pt.is_none() { + continue + } + for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { + write!(list, "{}p{}\n", disk_index, part_index).unwrap(); + } } let id = self.next_id; @@ -76,6 +206,28 @@ impl SchemeBlockMut for DiskScheme { } else { Err(Error::new(EISDIR)) } + } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { + let disk_id_str = &path_str[..p_pos]; + if p_pos + 1 >= path_str.len() { + return Err(Error::new(ENOENT)); + } + let part_id_str = &path_str[p_pos + 1..]; + let i = disk_id_str.parse::().or(Err(Error::new(ENOENT)))?; + let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; + + if let Some(disk) = self.disks.get(i) { + if disk.pt.is_none() || disk.pt.as_ref().unwrap().partitions.get(p as usize).is_none() { + return Err(Error::new(ENOENT)); + } + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, Handle::Partition(i, p, 0)); + + Ok(Some(id)) + } else { + Err(Error::new(ENOENT)) + } } else { let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; @@ -120,6 +272,21 @@ impl SchemeBlockMut for DiskScheme { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = disk.size(); + stat.st_blksize = disk.block_length()?; + Ok(Some(0)) + } + Handle::Partition(disk_id, part_num, _) => { + let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; + let size = { + let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; + let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + partition.size + }; + + stat.st_mode = MODE_FILE; // TODO: Block device? + stat.st_size = size * u64::from(disk.block_length()?); + stat.st_blksize = disk.block_length()?; + stat.st_blocks = size; Ok(Some(0)) } } @@ -155,6 +322,16 @@ impl SchemeBlockMut for DiskScheme { j += 1; } } + Handle::Partition(disk_num, part_num, _) => { + let path = format!("{}p{}", disk_num, part_num); + let path_bytes = path.as_bytes(); + j = 0; + while i < buf.len() && j < path_bytes.len() { + buf[i] = path_bytes[j]; + i += 1; + j += 1; + } + } } Ok(Some(i)) @@ -177,6 +354,30 @@ impl SchemeBlockMut for DiskScheme { Ok(None) } } + Handle::Partition(disk_num, part_num, ref mut position) => { + let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; + let blksize = disk.block_length()?; + + // validate that we're actually reading within the bounds of the partition + let rel_block = *position as u64 / blksize as u64; + + let abs_block = { + let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; + let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + + let abs_block = partition.start_lba + rel_block; + if rel_block >= partition.size { + return Err(Error::new(EOVERFLOW)); + } + abs_block + }; + + if let Some(count) = disk.read(abs_block, buf)? { + Ok(Some(count)) + } else { + Ok(None) + } + } } } @@ -195,6 +396,30 @@ impl SchemeBlockMut for DiskScheme { Ok(None) } } + Handle::Partition(disk_num, part_num, ref mut position) => { + let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; + let blksize = disk.block_length()?; + + // validate that we're actually reading within the bounds of the partition + let rel_block = *position as u64 / blksize as u64; + + let abs_block = { + let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; + let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + + let abs_block = partition.start_lba + rel_block; + if rel_block >= partition.size { + return Err(Error::new(EOVERFLOW)); + } + abs_block + }; + + if let Some(count) = disk.write(abs_block, buf)? { + Ok(Some(count)) + } else { + Ok(None) + } + } } } @@ -223,6 +448,19 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(*size)) } + Handle::Partition(disk_num, part_num, ref mut position) => { + let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; + let block_count = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?.size; + let len = u64::from(disk.block_length()?) * block_count; + + *position = match whence { + SEEK_SET => cmp::min(len as usize, pos) as usize, // Why isn't pos u64? + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *position as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)), + }; + Ok(Some(*position as usize)) + } } } From 2a7216c342525601a658f9df414dd8ebdf6ec71b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 5 Jan 2020 10:43:07 +1100 Subject: [PATCH 0310/1301] It (partition support) works! --- ahcid/src/scheme.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index d13985757b..1a0f917b0d 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -67,6 +67,8 @@ impl DiskWrapper { } } + let orig_buf_len = buf.len(); + let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?; let start_block = self.offset / u64::from(blksize); @@ -88,6 +90,7 @@ impl DiskWrapper { match self.disk.read(block, self.block_bytes) { Ok(Some(bytes)) => { + assert_eq!(bytes, self.block_bytes.len()); assert_eq!(bytes, blksize as usize); break; } @@ -103,11 +106,12 @@ impl DiskWrapper { } else { (blksize.into(), &self.block_bytes[..]) }; - buf[..bytes_to_read as usize].copy_from_slice(src_buf); - buf = &mut buf[..bytes_to_read as usize]; + let bytes_to_read = std::cmp::min(bytes_to_read as usize, buf.len()); + buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]); + buf = &mut buf[..bytes_to_read]; } - let bytes_read = std::cmp::min(buf.len(), whole_blocks_to_read as usize * blksize as usize + offset_from_start_block as usize + offset_to_end_block as usize); + let bytes_read = std::cmp::min(orig_buf_len, whole_blocks_to_read as usize * blksize as usize + offset_from_start_block as usize + offset_to_end_block as usize); self.offset += bytes_read as u64; Ok(bytes_read) From 5848f668a6ecf2f55e2f420d9afba148962d8e14 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 5 Jan 2020 12:17:47 +1100 Subject: [PATCH 0311/1301] Don't fail when the blocksize couldn't be retrieved. This is required for ahcid to work with make qemu_efi. --- ahcid/src/scheme.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 1a0f917b0d..1e13a744f3 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -30,9 +30,9 @@ pub struct DiskWrapper { impl DiskWrapper { fn pt(disk: &mut dyn Disk) -> Option { - let bs = match disk.block_length().unwrap() { - 512 => LogicalBlockSize::Lb512, - 4096 => LogicalBlockSize::Lb4096, + let bs = match disk.block_length() { + Ok(512) => LogicalBlockSize::Lb512, + Ok(4096) => LogicalBlockSize::Lb4096, _ => return None, }; struct Device<'a, 'b> { disk: &'a mut dyn Disk, offset: u64, block_bytes: &'b mut [u8] } @@ -343,7 +343,7 @@ impl SchemeBlockMut for DiskScheme { fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle, ref mut size) => { + Handle::List(ref handle, ref mut size) => { let count = (&handle[*size..]).read(buf).unwrap(); *size += count; Ok(Some(count)) From 60f05af55594bfa8200659c3dec6ff22fbd2275f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 8 Jan 2020 22:34:28 +1100 Subject: [PATCH 0312/1301] Move the block-io-to-unaligned-io wrapper to its own crate. --- Cargo.lock | 5 +++ Cargo.toml | 3 +- ahcid/Cargo.toml | 1 + ahcid/src/scheme.rs | 79 ++++++++++--------------------------- block-io-wrapper/.gitignore | 1 + block-io-wrapper/Cargo.toml | 9 +++++ block-io-wrapper/src/lib.rs | 47 ++++++++++++++++++++++ 7 files changed, 86 insertions(+), 59 deletions(-) create mode 100644 block-io-wrapper/.gitignore create mode 100644 block-io-wrapper/Cargo.toml create mode 100644 block-io-wrapper/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c325744907..5d201fb9dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,7 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "block-io-wrapper 0.1.0", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", @@ -65,6 +66,10 @@ name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "block-io-wrapper" +version = "0.1.0" + [[package]] name = "build_const" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index b871350843..8ec096c08a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "ahcid", "alxd", "bgad", + "block-io-wrapper", "e1000d", "ihdad", "ixgbed", @@ -13,5 +14,5 @@ members = [ "rtl8168d", "vboxd", "vesad", - "xhcid" + "xhcid", ] diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index bfd9f21315..458d8cac56 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -8,3 +8,4 @@ bitflags = "1.2" byteorder = "1.2" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } redox_syscall = "0.1" +block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 1e13a744f3..3e87040b61 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -50,77 +50,40 @@ impl DiskWrapper { Ok(self.offset) } } - // Perhaps this impl should be used in the rest of the scheme. + // TODO: Perhaps this impl should be used in the rest of the scheme. impl<'a, 'b> Read for Device<'a, 'b> { - fn read(&mut self, mut buf: &mut [u8]) -> io::Result { - // TODO: Yield sometimes, perhaps after a few blocks or something. - use std::ops::{Add, Div, Rem}; - - fn div_round_up(a: T, b: T) -> T - where - T: Add + Div + Rem + PartialEq + From + Copy - { - if a % b != T::from(0u8) { - a / b + T::from(1u8) - } else { - a / b - } - } - - let orig_buf_len = buf.len(); - + fn read(&mut self, buf: &mut [u8]) -> io::Result { let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?; + let size_in_blocks = self.disk.size() / u64::from(blksize); - let start_block = self.offset / u64::from(blksize); - let end_block = div_round_up(self.offset + buf.len() as u64, u64::from(blksize)); // The first block not in the range + let disk = &mut self.disk; - let offset_from_start_block: u64 = self.offset % u64::from(blksize); - let offset_to_end_block: u64 = u64::from(blksize) - (self.offset + buf.len() as u64) % u64::from(blksize); - - let first_whole_block = start_block + if offset_from_start_block > 0 { 1 } else { 0 }; - let last_whole_block = end_block - if offset_to_end_block > 0 { 1 } else { 0 } - 1; - - let whole_blocks_to_read = last_whole_block - first_whole_block + 1; - - for block in start_block..end_block { - // TODO: Async/await? I mean, shouldn't AHCI be async? - - loop { - let block = self.offset / u64::from(blksize); - - match self.disk.read(block, self.block_bytes) { - Ok(Some(bytes)) => { - assert_eq!(bytes, self.block_bytes.len()); - assert_eq!(bytes, blksize as usize); - break; - } - Ok(None) => continue, - Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), - } + let read_block = |block: u64, block_bytes: &mut [u8]| { + if block >= size_in_blocks { + return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); } + loop { + match disk.read(block, block_bytes) { + Ok(Some(bytes)) => { + assert_eq!(bytes, block_bytes.len()); + assert_eq!(bytes, blksize as usize); + return Ok(()); + } + Ok(None) => continue, + Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), + } + } + }; + let bytes_read = block_io_wrapper::read(self.offset, blksize, buf, self.block_bytes, read_block)?; - let (bytes_to_read, src_buf): (u64, &[u8]) = if block == start_block { - (u64::from(blksize) - offset_from_start_block, &self.block_bytes[offset_from_start_block as usize..]) - } else if block == end_block { - (u64::from(blksize) - offset_to_end_block, &self.block_bytes[..offset_to_end_block as usize]) - } else { - (blksize.into(), &self.block_bytes[..]) - }; - let bytes_to_read = std::cmp::min(bytes_to_read as usize, buf.len()); - buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]); - buf = &mut buf[..bytes_to_read]; - } - - let bytes_read = std::cmp::min(orig_buf_len, whole_blocks_to_read as usize * blksize as usize + offset_from_start_block as usize + offset_to_end_block as usize); self.offset += bytes_read as u64; - Ok(bytes_read) } } let mut block_bytes = [0u8; 4096]; - partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() + partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).map_err(|x| dbg!(x)).ok().flatten() } fn new(mut disk: Box) -> Self { Self { diff --git a/block-io-wrapper/.gitignore b/block-io-wrapper/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/block-io-wrapper/.gitignore @@ -0,0 +1 @@ +/target diff --git a/block-io-wrapper/Cargo.toml b/block-io-wrapper/Cargo.toml new file mode 100644 index 0000000000..e40054ccf1 --- /dev/null +++ b/block-io-wrapper/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "block-io-wrapper" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/block-io-wrapper/src/lib.rs b/block-io-wrapper/src/lib.rs new file mode 100644 index 0000000000..6556067d42 --- /dev/null +++ b/block-io-wrapper/src/lib.rs @@ -0,0 +1,47 @@ +pub fn read(offset: u64, blksize: u32, mut buf: &mut [u8], block_bytes: &mut [u8], mut read: impl FnMut(u64, &mut [u8]) -> Result<(), E>) -> Result { + // TODO: Yield sometimes, perhaps after a few blocks or something. + use std::ops::{Add, Div, Rem}; + + fn div_round_up(a: T, b: T) -> T + where + T: Add + Div + Rem + PartialEq + From + Copy + { + if a % b != T::from(0u8) { + a / b + T::from(1u8) + } else { + a / b + } + } + + let orig_buf_len = buf.len(); + + let start_block = offset / u64::from(blksize); + let end_block = div_round_up(offset + buf.len() as u64, u64::from(blksize)); // The first block not in the range + + let offset_from_start_block: u64 = offset % u64::from(blksize); + let offset_to_end_block: u64 = u64::from(blksize) - (offset + buf.len() as u64) % u64::from(blksize); + + let first_whole_block = start_block + if offset_from_start_block > 0 { 1 } else { 0 }; + let last_whole_block = end_block - if offset_to_end_block > 0 { 1 } else { 0 } - 1; + + let whole_blocks_to_read = last_whole_block - first_whole_block + 1; + + for block in start_block..=end_block { + // TODO: Async/await? I mean, shouldn't AHCI be async? + + read(block, block_bytes)?; + + let (bytes_to_read, src_buf): (u64, &[u8]) = if block == start_block { + (u64::from(blksize) - offset_from_start_block, &block_bytes[offset_from_start_block as usize..]) + } else if block == end_block { + (u64::from(blksize) - offset_to_end_block, &block_bytes[..offset_to_end_block as usize]) + } else { + (blksize.into(), &block_bytes[..]) + }; + let bytes_to_read = std::cmp::min(bytes_to_read as usize, buf.len()); + buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]); + buf = &mut buf[bytes_to_read..]; + } + + Ok(std::cmp::min(orig_buf_len, whole_blocks_to_read as usize * blksize as usize + offset_from_start_block as usize + offset_to_end_block as usize)) +} From 5807909ed17a16494d6fa86e3d10b166191755a5 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 9 Jan 2020 10:38:31 +1100 Subject: [PATCH 0313/1301] Add partitioning support to nvmed. --- Cargo.lock | 2 + ahcid/src/scheme.rs | 4 +- nvmed/.gitignore | 1 + nvmed/Cargo.toml | 2 + nvmed/src/scheme.rs | 226 ++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 217 insertions(+), 18 deletions(-) create mode 100644 nvmed/.gitignore diff --git a/Cargo.lock b/Cargo.lock index 5d201fb9dd..23f2855227 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -524,6 +524,8 @@ name = "nvmed" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "block-io-wrapper 0.1.0", + "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 3e87040b61..f2e523c37a 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -69,7 +69,7 @@ impl DiskWrapper { assert_eq!(bytes, blksize as usize); return Ok(()); } - Ok(None) => continue, + Ok(None) => { std::thread::yield_now(); continue } Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), } } @@ -83,7 +83,7 @@ impl DiskWrapper { let mut block_bytes = [0u8; 4096]; - partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).map_err(|x| dbg!(x)).ok().flatten() + partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() } fn new(mut disk: Box) -> Self { Self { diff --git a/nvmed/.gitignore b/nvmed/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/nvmed/.gitignore @@ -0,0 +1 @@ +/target diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index 7bd235dc99..b0bbfee4b2 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -7,3 +7,5 @@ edition = "2018" bitflags = "0.7" spin = "0.4" redox_syscall = "0.1" +partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index 15edcbdb45..6a2da55dde 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -1,34 +1,118 @@ use std::collections::BTreeMap; use std::{cmp, str}; +use std::convert::{TryFrom, TryInto}; use std::fmt::Write; -use std::io::Read; +use std::io::prelude::*; +use std::io; use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, Result, + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, EOVERFLOW, Result, Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; use crate::nvme::{Nvme, NvmeNamespace}; +use partitionlib::{LogicalBlockSize, PartitionTable}; + #[derive(Clone)] enum Handle { - List(Vec, usize), - Disk(u32, usize) + List(Vec, usize), // entries, offset + Disk(u32, usize), // disk num, offset + Partition(u32, u32, usize), // disk num, part num, offset +} + +pub struct DiskWrapper { + inner: NvmeNamespace, + pt: Option, +} + +impl AsRef for DiskWrapper { + fn as_ref(&self) -> &NvmeNamespace { + &self.inner + } +} + +impl DiskWrapper { + fn pt(disk: &mut NvmeNamespace, nvme: &mut Nvme) -> Option { + let bs = match disk.block_size { + 512 => LogicalBlockSize::Lb512, + 4096 => LogicalBlockSize::Lb4096, + _ => return None, + }; + struct Device<'a, 'b> { disk: &'a mut NvmeNamespace, nvme: &'a mut Nvme, offset: u64, block_bytes: &'b mut [u8] } + + impl<'a, 'b> Seek for Device<'a, 'b> { + fn seek(&mut self, from: io::SeekFrom) -> io::Result { + let size_u = self.disk.blocks * self.disk.block_size; + let size = i64::try_from(size_u).or(Err(io::Error::new(io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes")))?; + + self.offset = match from { + io::SeekFrom::Start(new_pos) => cmp::min(size_u, new_pos), + io::SeekFrom::Current(new_pos) => cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64, + io::SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64, + }; + + Ok(self.offset) + } + } + + impl<'a, 'b> Read for Device<'a, 'b> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let blksize = self.disk.block_size; + let size_in_blocks = self.disk.blocks; + + let disk = &mut self.disk; + let nvme = &mut self.nvme; + + let read_block = |block: u64, block_bytes: &mut [u8]| { + if block >= size_in_blocks { + return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); + } + loop { + match unsafe { + nvme.namespace_read(disk.id, block, block_bytes).map_err(|err| io::Error::from_raw_os_error(err.errno))? + } { + Some(bytes) => { + assert_eq!(bytes, block_bytes.len()); + assert_eq!(bytes, blksize as usize); + return Ok(()); + } + None => { std::thread::yield_now(); continue } + // TODO: Does this driver have (internal) error handling at all? + } + } + }; + let bytes_read = block_io_wrapper::read(self.offset, blksize.try_into().expect("Unreasonable block size above 2^32 bytes"), buf, self.block_bytes, read_block)?; + self.offset += bytes_read as u64; + Ok(bytes_read) + } + } + + let mut block_bytes = [0u8; 4096]; + + partitionlib::get_partitions(&mut Device { disk, nvme, offset: 0, block_bytes: &mut block_bytes[..bs as usize] }, bs).ok().flatten() + } + fn new(mut inner: NvmeNamespace, nvme: &mut Nvme) -> Self { + Self { + pt: Self::pt(&mut inner, nvme), + inner, + } + } } pub struct DiskScheme { scheme_name: String, nvme: Nvme, - disks: BTreeMap, + disks: BTreeMap, handles: BTreeMap, next_id: usize } impl DiskScheme { - pub fn new(scheme_name: String, nvme: Nvme, disks: BTreeMap) -> DiskScheme { + pub fn new(scheme_name: String, mut nvme: Nvme, disks: BTreeMap) -> DiskScheme { DiskScheme { scheme_name, + disks: disks.into_iter().map(|(k, v)| (k, DiskWrapper::new(v, &mut nvme))).collect(), nvme, - disks, handles: BTreeMap::new(), next_id: 0 } @@ -61,8 +145,15 @@ impl SchemeBlockMut for DiskScheme { if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { let mut list = String::new(); - for (nsid, _disk) in self.disks.iter() { + for (nsid, disk) in self.disks.iter() { write!(list, "{}\n", nsid).unwrap(); + + if disk.pt.is_none() { + continue; + } + for part_num in 0..disk.pt.as_ref().unwrap().partitions.len() { + write!(list, "{}p{}\n", nsid, part_num).unwrap(); + } } let id = self.next_id; @@ -72,6 +163,29 @@ impl SchemeBlockMut for DiskScheme { } else { Err(Error::new(EISDIR)) } + } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { + let nsid_str = &path_str[..p_pos]; + + if p_pos + 1 >= path_str.len() { + return Err(Error::new(ENOENT)); + } + let part_num_str = &path_str[p_pos + 1..]; + + let nsid = nsid_str.parse::().or(Err(Error::new(ENOENT)))?; + let part_num = part_num_str.parse::().or(Err(Error::new(ENOENT)))?; + + if let Some(disk) = self.disks.get(&nsid) { + if disk.pt.as_ref().ok_or(Error::new(ENOENT))?.partitions.get(part_num as usize).is_some() { + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle::Partition(nsid, part_num, 0)); + Ok(Some(id)) + } else { + Err(Error::new(ENOENT)) + } + } else { + Err(Error::new(ENOENT)) + } } else { let nsid = path_str.parse::().or(Err(Error::new(ENOENT)))?; @@ -115,7 +229,18 @@ impl SchemeBlockMut for DiskScheme { Handle::Disk(number, _) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; - stat.st_size = disk.blocks * disk.block_size; + stat.st_blocks = disk.as_ref().blocks; + stat.st_blksize = disk.as_ref().block_size.try_into().expect("Unreasonable block size of over 2^32 bytes"); + stat.st_size = disk.as_ref().blocks * disk.as_ref().block_size; + Ok(Some(0)) + } + Handle::Partition(disk_num, part_num, _) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let part = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + stat.st_mode = MODE_FILE; + stat.st_size = part.size * disk.as_ref().block_size; + stat.st_blocks = part.size; + stat.st_blksize = disk.as_ref().block_size.try_into().expect("Unreasonable block size of over 2^32 bytes"); Ok(Some(0)) } } @@ -151,6 +276,16 @@ impl SchemeBlockMut for DiskScheme { j += 1; } } + Handle::Partition(disk_num, part_num, _) => { + let number_str = format!("{}p{}", disk_num, part_num); + let number_bytes = number_str.as_bytes(); + j = 0; + while i < buf.len() && j < number_bytes.len() { + buf[i] = number_bytes[j]; + i += 1; + j += 1; + } + } } Ok(Some(i)) @@ -162,12 +297,12 @@ impl SchemeBlockMut for DiskScheme { let count = (&handle[*size..]).read(buf).unwrap(); *size += count; Ok(Some(count)) - }, + } Handle::Disk(number, ref mut size) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block_size = disk.block_size; + let block_size = disk.as_ref().block_size; if let Some(count) = unsafe { - self.nvme.namespace_read(disk.id, (*size as u64)/block_size, buf)? + self.nvme.namespace_read(disk.as_ref().id, (*size as u64)/block_size, buf)? } { *size += count; Ok(Some(count)) @@ -175,6 +310,28 @@ impl SchemeBlockMut for DiskScheme { Ok(None) } } + Handle::Partition(disk_num, part_num, ref mut offset) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let part = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + + let block_size = disk.as_ref().block_size; + let rel_block = (*offset as u64) / block_size; + + if rel_block + *offset as u64 / block_size >= part.size { + return Err(Error::new(EOVERFLOW)); + } + + let abs_block = part.start_lba + rel_block; + + if let Some(count) = unsafe { + self.nvme.namespace_read(disk.as_ref().id, abs_block, buf)? + } { + *offset += count; + Ok(Some(count)) + } else { + Ok(None) + } + } } } @@ -185,9 +342,9 @@ impl SchemeBlockMut for DiskScheme { }, Handle::Disk(number, ref mut size) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block_size = disk.block_size; + let block_size = disk.as_ref().block_size; if let Some(count) = unsafe { - self.nvme.namespace_write(disk.id, (*size as u64)/block_size, buf)? + self.nvme.namespace_write(disk.as_ref().id, (*size as u64)/block_size, buf)? } { *size += count; Ok(Some(count)) @@ -195,6 +352,28 @@ impl SchemeBlockMut for DiskScheme { Ok(None) } } + Handle::Partition(disk_num, part_num, ref mut offset) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let part = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + + let block_size = disk.as_ref().block_size; + let rel_block = (*offset as u64) / block_size; + + if rel_block + *offset as u64 / block_size >= part.size { + return Err(Error::new(EOVERFLOW)); + } + + let abs_block = part.start_lba + rel_block; + + if let Some(count) = unsafe { + self.nvme.namespace_write(disk.as_ref().id, abs_block, buf)? + } { + *offset += count; + Ok(Some(count)) + } else { + Ok(None) + } + } } } @@ -210,10 +389,25 @@ impl SchemeBlockMut for DiskScheme { }; Ok(Some(*size)) - }, + } Handle::Disk(number, ref mut size) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let len = (disk.blocks * disk.block_size) as usize; + let len = (disk.as_ref().blocks * disk.as_ref().block_size) as usize; + *size = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(Some(*size)) + } + Handle::Partition(disk_num, part_num, ref mut size) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let part = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + + let len = (part.size * disk.as_ref().block_size) as usize; + *size = match whence { SEEK_SET => cmp::min(len, pos), SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, From faa29b1854e0f45be1fd7cfb9984aa9a3c347726 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 10 Jan 2020 20:02:19 +1100 Subject: [PATCH 0314/1301] Add a really basic interface to xhcid. --- Cargo.lock | 40 ++++- initfs.toml | 6 + xhcid/.gitignore | 1 + xhcid/Cargo.toml | 5 +- xhcid/config.toml | 12 +- xhcid/src/main.rs | 11 +- xhcid/src/xhci/mod.rs | 59 +++++--- xhcid/src/xhci/port.rs | 44 +++--- xhcid/src/xhci/scheme.rs | 311 ++++++++++++++++++++++++++++++++++++++- 9 files changed, 434 insertions(+), 55 deletions(-) create mode 100644 xhcid/.gitignore diff --git a/Cargo.lock b/Cargo.lock index 23f2855227..ab822c01a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -264,6 +264,11 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ixgbed" version = "1.0.0" @@ -858,6 +863,11 @@ dependencies = [ "stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ryu" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "safemem" version = "0.3.1" @@ -939,6 +949,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "serde" version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "serde_derive" @@ -950,6 +963,16 @@ dependencies = [ "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "serde_json" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "slab" version = "0.4.2" @@ -960,6 +983,14 @@ name = "smallvec" version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "smallvec" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "spin" version = "0.4.10" @@ -1346,10 +1377,13 @@ dependencies = [ name = "xhcid" version = "0.1.0" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1382,6 +1416,7 @@ dependencies = [ "checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" @@ -1440,6 +1475,7 @@ dependencies = [ "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b" "checksum rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30047cc747a78ae042bf2cd65c79f83c3485d90107535b532d6e8f60e2c89cb1" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum safemem 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e133ccc4f4d1cd4f89cc8a7ff618287d56dc7f638b8e38fc32c5fdcadc339dd5" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" @@ -1452,8 +1488,10 @@ dependencies = [ "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113" "checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c" +"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" +"checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" diff --git a/initfs.toml b/initfs.toml index a6eb2dddd6..6430657f3e 100644 --- a/initfs.toml +++ b/initfs.toml @@ -36,3 +36,9 @@ class = 8 vendor = 33006 device = 51966 command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] +[[drivers]] +name = "XHCI" +class = 12 +subclass = 3 +interface = 48 +command = ["xhcid", "$NAME", "$BAR0", "$IRQ"] diff --git a/xhcid/.gitignore b/xhcid/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/xhcid/.gitignore @@ -0,0 +1 @@ +/target diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 9d8b2e7bd1..6a1907d8c4 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -4,8 +4,11 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "0.7" +bitflags = "1" plain = "0.2" spin = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +smallvec = { version = "1", features = ["serde"] } diff --git a/xhcid/config.toml b/xhcid/config.toml index 74db47d8e1..6654d5b598 100644 --- a/xhcid/config.toml +++ b/xhcid/config.toml @@ -1,6 +1,6 @@ -# [[drivers]] -# name = "XHCI" -# class = 12 -# subclass = 3 -# interface = 48 -# command = ["xhcid", "$NAME", "$BAR0", "$IRQ"] +[[drivers]] +name = "XHCI" +class = 12 +subclass = 3 +interface = 48 +command = ["xhcid", "$NAME", "$BAR0", "$IRQ"] diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 4fa3e5ea3a..c97a0f382f 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -6,7 +6,7 @@ extern crate syscall; use event::{Event, EventQueue}; use std::cell::RefCell; -use std::env; +use std::{io, env}; use std::fs::File; use std::io::{Result, Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; @@ -37,7 +37,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let socket_fd = syscall::open(":usb", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme"); + let socket_fd = syscall::open(format!(":usb/{}-{}-{}", name, bar_str, irq_str), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); let mut irq_file = File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); @@ -87,8 +87,11 @@ fn main() { event_queue.add(socket_fd, move |_| -> Result> { loop { let mut packet = Packet::default(); - if socket_packet.borrow_mut().read(&mut packet)? == 0 { - break; + match socket_packet.borrow_mut().read(&mut packet) { + Ok(0) => break, + Err(err) if err.kind() == io::ErrorKind::WouldBlock => break, + Ok(_) => (), + Err(err) => return Err(err), } let a = packet.a; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 64bd94e539..1a3255f137 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,5 +1,6 @@ use plain::Plain; use std::{mem, slice}; +use std::collections::BTreeMap; use syscall::error::Result; use syscall::io::{Dma, Io}; use crate::usb; @@ -112,6 +113,16 @@ pub struct Xhci { run: &'static mut RuntimeRegs, dev_ctx: DeviceContextList, cmd: CommandRing, + + handles: BTreeMap, + next_handle: usize, + port_states: BTreeMap, +} + +struct PortState { + slot: u8, + input_context: Dma, + ring: Ring, } impl Xhci { @@ -178,6 +189,9 @@ impl Xhci { run: run, dev_ctx: DeviceContextList::new(max_slots)?, cmd: CommandRing::new()?, + handles: BTreeMap::new(), + next_handle: 0, + port_states: BTreeMap::new(), }; xhci.init(max_slots); @@ -237,6 +251,24 @@ impl Xhci { println!(" - XHCI initialized"); } + pub fn enable_port_slot(cmd: &mut CommandRing, dbs: &mut [Doorbell]) -> u8 { + let (cmd, cycle, event) = cmd.next(); + + cmd.enable_slot(0, cycle); + + dbs[0].write(0); + + while event.data.read() == 0 { + println!(" - Waiting for event"); + } + let slot = (event.control.read() >> 24) as u8; + + cmd.reserved(false); + event.reserved(false); + + slot + } + pub fn probe(&mut self) -> Result<()> { for (i, port) in self.ports.iter().enumerate() { let data = port.read(); @@ -245,32 +277,18 @@ impl Xhci { let flags = port.flags(); println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags); - if flags.contains(port::PORT_CCS) { + if flags.contains(port::PortFlags::PORT_CCS) { //TODO: Link TRB when running to the end of the ring buffer println!(" - Enable slot"); - let slot; - { - let (cmd, cycle, event) = self.cmd.next(); + self.run.ints[0].erdp.write(self.cmd.erdp()); // TODO: ? - cmd.enable_slot(0, cycle); - - self.dbs[0].write(0); - - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - slot = (event.control.read() >> 24) as u8; - - cmd.reserved(false); - event.reserved(false); - } - - self.run.ints[0].erdp.write(self.cmd.erdp()); + let slot = Self::enable_port_slot(&mut self.cmd, &mut self.dbs); println!(" - Slot {}", slot); + // transfer ring? let mut ring = Ring::new(true)?; let mut input = Dma::::zeroed()?; @@ -360,6 +378,11 @@ impl Xhci { } } } + self.port_states.insert(i, PortState { + slot, + input_context: input, + ring, + }); } } diff --git a/xhcid/src/xhci/port.rs b/xhcid/src/xhci/port.rs index 50f23c9f18..0f62d66140 100644 --- a/xhcid/src/xhci/port.rs +++ b/xhcid/src/xhci/port.rs @@ -1,28 +1,28 @@ use syscall::io::{Io, Mmio}; bitflags! { - pub flags PortFlags: u32 { - const PORT_CCS = 1 << 0, - const PORT_PED = 1 << 1, - const PORT_OCA = 1 << 3, - const PORT_PR = 1 << 4, - const PORT_PP = 1 << 9, - const PORT_PIC_AMB = 1 << 14, - const PORT_PIC_GRN = 1 << 15, - const PORT_LWS = 1 << 16, - const PORT_CSC = 1 << 17, - const PORT_PEC = 1 << 18, - const PORT_WRC = 1 << 19, - const PORT_OCC = 1 << 20, - const PORT_PRC = 1 << 21, - const PORT_PLC = 1 << 22, - const PORT_CEC = 1 << 23, - const PORT_CAS = 1 << 24, - const PORT_WCE = 1 << 25, - const PORT_WDE = 1 << 26, - const PORT_WOE = 1 << 27, - const PORT_DR = 1 << 30, - const PORT_WPR = 1 << 31, + pub struct PortFlags: u32 { + const PORT_CCS = 1 << 0; + const PORT_PED = 1 << 1; + const PORT_OCA = 1 << 3; + const PORT_PR = 1 << 4; + const PORT_PP = 1 << 9; + const PORT_PIC_AMB = 1 << 14; + const PORT_PIC_GRN = 1 << 15; + const PORT_LWS = 1 << 16; + const PORT_CSC = 1 << 17; + const PORT_PEC = 1 << 18; + const PORT_WRC = 1 << 19; + const PORT_OCC = 1 << 20; + const PORT_PRC = 1 << 21; + const PORT_PLC = 1 << 22; + const PORT_CEC = 1 << 23; + const PORT_CAS = 1 << 24; + const PORT_WCE = 1 << 25; + const PORT_WDE = 1 << 26; + const PORT_WOE = 1 << 27; + const PORT_DR = 1 << 30; + const PORT_WPR = 1 << 31; } } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index e1531c7dd1..4e8816c34b 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,4 +1,309 @@ -use super::Xhci; -use syscall::scheme::SchemeMut; +use std::{cmp, mem, str}; +use std::io::prelude::*; -impl SchemeMut for Xhci {} +use plain::Plain; +use serde::Serialize; +use smallvec::SmallVec; + +use syscall::io::Io; +use syscall::scheme::SchemeMut; +use syscall::{ + EACCES, EBADF, EINVAL, EISDIR, ENOENT, + O_CREAT, O_DIRECTORY, O_STAT, ENOSYS, ENOTDIR, + MODE_DIR, MODE_FILE, + SEEK_CUR, SEEK_END, SEEK_SET, + Stat, + Error, Result +}; + +use super::{Device, Xhci}; +use super::{port, usb}; + +pub enum Handle { + TopLevel(usize, Vec), // offset, contents (ports) + Port(usize, usize, Vec), // port, offset, contents + PortDesc(usize, usize, Vec), // port, offset, contents +} + +#[derive(Serialize)] +struct PortDesc { + // I have no idea whether this number is useful to the API users. + slot: u8, + dev_desc: DevDescJson, +} + +#[derive(Serialize)] +struct DevDescJson { + // TODO: length? + kind: u8, + usb: u16, + class: u8, + sub_class: u8, + protocol: u8, + packet_size: u8, + vendor: u16, + product: u16, + release: u16, + manufacturer_str: Option, + product_str: Option, + serial_str: Option, + config_descs: SmallVec<[ConfDescJson; 1]>, +} + +#[derive(Serialize)] +struct ConfDescJson { + // TODO: length? + kind: u8, + // TODO: total_length? + // TODO: configuration_value? + configuration: Option, + attributes: u8, + max_power: u8, + interface_descs: SmallVec<[IfDescJson; 1]>, +} + +#[derive(Serialize)] +struct EndpDescJson { + kind: u8, + address: u8, + attributes: u8, + max_packet_size: u16, + interval: u8, +} + +#[derive(Serialize)] +struct IfDescJson { + // TODO: length? + kind: u8, + number: u8, + alternate_setting: u8, + class: u8, + sub_class: u8, + protocol: u8, + interface_str: Option, + endpoints: SmallVec<[EndpDescJson; 2]>, +} + +impl Xhci { + fn write_port_desc(&mut self, port_id: usize, contents: &mut Vec) -> Result<()> { + let port = self.ports.get(port_id).ok_or(Error::new(ENOENT))?; + if !port.flags().contains(port::PortFlags::PORT_CCS) { + return Err(Error::new(ENOENT)); + } + + let st = self.port_states.get_mut(&port_id).unwrap(); + + // TODO: Should the descriptors be stored in PortState? + + self.run.ints[0].erdp.write(self.cmd.erdp()); + + let mut dev = Device { + ring: &mut st.ring, + cmd: &mut self.cmd, + db: &mut self.dbs[st.slot as usize], + int: &mut self.run.ints[0], + }; + + let raw_dd = dev.get_device()?; + + let (manufacturer_str, product_str, serial_str) = ( + if raw_dd.manufacturer_str > 0 { + Some(dev.get_string(raw_dd.manufacturer_str)?) + } else { None }, + if raw_dd.product_str > 0 { + Some(dev.get_string(raw_dd.product_str)?) + } else { None }, + if raw_dd.serial_str > 0 { + Some(dev.get_string(raw_dd.serial_str)?) + } else { None }, + ); + + let config_descs = (0..raw_dd.configurations).map(|index| -> Result<_> { + let (desc, data) = dev.get_config(index)?; + + let extra_length = desc.total_length as usize - mem::size_of::(); + + let mut i = 0; + + let interface_descs = (0..desc.interfaces).filter_map(|_| -> Option> { + let mut idesc = usb::InterfaceDescriptor::default(); + if i < extra_length && i < data.len() && idesc.copy_from_bytes(&data[i..extra_length]).is_ok() { + i += mem::size_of_val(&idesc); + + let endpoints = (0..idesc.endpoints).filter_map(|_| { + let mut edesc = usb::EndpointDescriptor::default(); + if i < extra_length && i < data.len() && edesc.copy_from_bytes(&data[i..extra_length]).is_ok() { + Some(EndpDescJson { + address: edesc.address, + attributes: edesc.attributes, + interval: edesc.interval, + kind: edesc.kind, + max_packet_size: edesc.max_packet_size, + }) + } else { None } + }).collect(); + + Some(Ok(IfDescJson { + kind: idesc.kind, + number: idesc.number, + alternate_setting: idesc.alternate_setting, + class: idesc.class, + sub_class: idesc.sub_class, + protocol: idesc.protocol, + interface_str: match if idesc.interface_str > 0 { Some(dev.get_string(idesc.interface_str)) } else { None } { + Some(Err(err)) => return Some(Err(err)), + Some(Ok(ok)) => Some(ok), + None => None, + }, + endpoints, + })) + } else { + None + } + }).collect::>>()?; + + Ok(ConfDescJson { + kind: desc.kind, + configuration: if desc.configuration_str > 0 { Some(dev.get_string(desc.configuration_str)?) } else { None }, + attributes: desc.attributes, + max_power: desc.max_power, + interface_descs, + }) + }).collect::>>()?; + + let dev_desc = DevDescJson { + kind: raw_dd.kind, + usb: raw_dd.usb, + class: raw_dd.class, + sub_class: raw_dd.sub_class, + protocol: raw_dd.protocol, + packet_size: raw_dd.packet_size, + vendor: raw_dd.vendor, + product: raw_dd.product, + release: raw_dd.release, + manufacturer_str, + product_str, + serial_str, + config_descs, + }; + + let desc = PortDesc { + slot: st.slot, + dev_desc, + }; + + serde_json::to_writer_pretty(contents, &desc).unwrap(); + + Ok(()) + } +} + +impl SchemeMut for Xhci { + fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + if uid != 0 { return Err(Error::new(EACCES)) } + if flags & O_CREAT != 0 { return Err(Error::new(EINVAL) ) } + + let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_start_matches('/'); + + if path_str.is_empty() { + if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { + let mut contents = Vec::new(); + + for (index, _) in self.ports.iter().enumerate().filter(|(_, port)| port.flags().contains(port::PortFlags::PORT_CCS)) { + write!(contents, "port{}\n", index).unwrap(); + } + + let fd = self.next_handle; + self.handles.insert(fd, Handle::TopLevel(0, contents)); + self.next_handle += 1; + Ok(fd) + } else { + return Err(Error::new(EISDIR)); + } + } else if path_str.starts_with("port") { + let slash_idx = path_str.chars().position(|c| c == '/'); + + let num_str = &path_str[4..slash_idx.unwrap_or(path_str.len())]; + let num = num_str.parse::().or(Err(Error::new(ENOENT)))?; + + if slash_idx.is_some() && slash_idx.unwrap() + 1 < path_str.len() && path_str[slash_idx.unwrap() + 1..].starts_with("descriptor") { + if flags & O_DIRECTORY != 0 { + return Err(Error::new(ENOTDIR)); + } + + let mut contents = Vec::new(); + self.write_port_desc(num, &mut contents)?; + + let fd = self.next_handle; + self.handles.insert(fd, Handle::PortDesc(num, 0, contents)); + self.next_handle += 1; + return Ok(fd); + } + + if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { + let mut contents = Vec::new(); + + write!(contents, "descriptor\n").unwrap(); + + let fd = self.next_handle; + self.handles.insert(fd, Handle::Port(num, 0, contents)); + self.next_handle += 1; + Ok(fd) + } else { + return Err(Error::new(EISDIR)); + } + } else { + return Err(Error::new(ENOSYS)); + } + } + + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { + match self.handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::TopLevel(_, ref buf) | Handle::Port(_, _, ref buf) => { + // TODO: Known size perhaps? + stat.st_mode = MODE_DIR; + stat.st_size = buf.len() as u64; + Ok(0) + } + Handle::PortDesc(_, _, ref buf) => { + stat.st_mode = MODE_FILE; + stat.st_size = buf.len() as u64; + Ok(0) + } + } + } + + fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) => { + *offset = match whence { + SEEK_SET => cmp::max(0, cmp::min(pos, buf.len())), + SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, buf.len())), + SEEK_END => cmp::max(0, cmp::min(buf.len() + pos, buf.len())), + _ => return Err(Error::new(EINVAL)), + }; + Ok(*offset) + } + } + } + + fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) => { + let max_bytes_to_read = cmp::min(src_buf.len(), buf.len()); + let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset; + + buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]); + *offset += bytes_to_read; + + Ok(bytes_to_read) + } + } + } + fn close(&mut self, fd: usize) -> Result { + if self.handles.remove(&fd).is_none() { + return Err(Error::new(EBADF)); + } + Ok(0) + } +} From 8b375518d94165166d0120c41d627abab1b52e08 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 11 Jan 2020 09:28:24 +1100 Subject: [PATCH 0315/1301] Fix the descriptor parsing by somewhat. --- xhcid/src/xhci/scheme.rs | 48 ++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 4e8816c34b..218779b5cf 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -119,48 +119,58 @@ impl Xhci { ); let config_descs = (0..raw_dd.configurations).map(|index| -> Result<_> { + // TODO: Actually, it seems like all descriptors contain a length field, and I + // encountered a SuperSpeed descriptor when endpoints were expected. The right way + // would probably be to have an enum of all possible descs, and sort them based on + // location, even though they might not necessarily be ordered trivially. + let (desc, data) = dev.get_config(index)?; - let extra_length = desc.total_length as usize - mem::size_of::(); + let extra_length = desc.total_length as usize - mem::size_of_val(&desc); let mut i = 0; - let interface_descs = (0..desc.interfaces).filter_map(|_| -> Option> { + let mut interface_descs = SmallVec::with_capacity(desc.interfaces as usize); + + for _ in 0..desc.interfaces { let mut idesc = usb::InterfaceDescriptor::default(); if i < extra_length && i < data.len() && idesc.copy_from_bytes(&data[i..extra_length]).is_ok() { i += mem::size_of_val(&idesc); - let endpoints = (0..idesc.endpoints).filter_map(|_| { + let mut endpoints = SmallVec::with_capacity(idesc.endpoints as usize); + + while endpoints.len() < idesc.endpoints as usize { let mut edesc = usb::EndpointDescriptor::default(); if i < extra_length && i < data.len() && edesc.copy_from_bytes(&data[i..extra_length]).is_ok() { - Some(EndpDescJson { + match edesc.kind { + // TODO: Constants + 5 => i += mem::size_of_val(&edesc), + 48 => { i += 6; continue } // SuperSpeed Endpoint Companion Descriptor + _ => unimplemented!(), + } + + endpoints.push(EndpDescJson { address: edesc.address, attributes: edesc.attributes, interval: edesc.interval, kind: edesc.kind, max_packet_size: edesc.max_packet_size, }) - } else { None } - }).collect(); + } else { break } + } - Some(Ok(IfDescJson { + interface_descs.push(IfDescJson { kind: idesc.kind, number: idesc.number, alternate_setting: idesc.alternate_setting, class: idesc.class, sub_class: idesc.sub_class, protocol: idesc.protocol, - interface_str: match if idesc.interface_str > 0 { Some(dev.get_string(idesc.interface_str)) } else { None } { - Some(Err(err)) => return Some(Err(err)), - Some(Ok(ok)) => Some(ok), - None => None, - }, + interface_str: if idesc.interface_str > 0 { Some(dev.get_string(idesc.interface_str)?) } else { None }, endpoints, - })) - } else { - None + }); } - }).collect::>>()?; + } Ok(ConfDescJson { kind: desc.kind, @@ -193,7 +203,7 @@ impl Xhci { }; serde_json::to_writer_pretty(contents, &desc).unwrap(); - + Ok(()) } } @@ -226,7 +236,7 @@ impl SchemeMut for Xhci { let num_str = &path_str[4..slash_idx.unwrap_or(path_str.len())]; let num = num_str.parse::().or(Err(Error::new(ENOENT)))?; - if slash_idx.is_some() && slash_idx.unwrap() + 1 < path_str.len() && path_str[slash_idx.unwrap() + 1..].starts_with("descriptor") { + if slash_idx.is_some() && slash_idx.unwrap() + 1 < path_str.len() && &path_str[slash_idx.unwrap() + 1..] == "descriptors" { if flags & O_DIRECTORY != 0 { return Err(Error::new(ENOTDIR)); } @@ -243,7 +253,7 @@ impl SchemeMut for Xhci { if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { let mut contents = Vec::new(); - write!(contents, "descriptor\n").unwrap(); + write!(contents, "descriptors\n").unwrap(); let fd = self.next_handle; self.handles.insert(fd, Handle::Port(num, 0, contents)); From dd4dd952d051ac23b147e01ec625bfabee505646 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 12 Jan 2020 13:18:39 +1100 Subject: [PATCH 0316/1301] Improve (subjective...) the descriptor fetching. --- xhcid/src/main.rs | 2 +- xhcid/src/usb/bos.rs | 134 ++++++++++++++++++++ xhcid/src/usb/config.rs | 2 + xhcid/src/usb/device.rs | 2 + xhcid/src/usb/endpoint.rs | 12 ++ xhcid/src/usb/mod.rs | 6 +- xhcid/src/xhci/context.rs | 3 +- xhcid/src/xhci/mod.rs | 20 ++- xhcid/src/xhci/scheme.rs | 254 ++++++++++++++++++++++++++++---------- xhcid/src/xhci/trb.rs | 12 ++ 10 files changed, 380 insertions(+), 67 deletions(-) create mode 100644 xhcid/src/usb/bos.rs diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index c97a0f382f..5ec46d9ee9 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -37,7 +37,7 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { - let socket_fd = syscall::open(format!(":usb/{}-{}-{}", name, bar_str, irq_str), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme"); + let socket_fd = syscall::open(format!(":usb/{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); let mut irq_file = File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); diff --git a/xhcid/src/usb/bos.rs b/xhcid/src/usb/bos.rs new file mode 100644 index 0000000000..f72563fbee --- /dev/null +++ b/xhcid/src/usb/bos.rs @@ -0,0 +1,134 @@ +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct BosDescriptor { + pub len: u8, + pub kind: u8, + pub total_len: u16, + pub cap_count: u8, +} + +unsafe impl plain::Plain for BosDescriptor {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct BosDevDescriptorBase { + pub len: u8, + pub kind: u8, + pub cap_ty: u8, +} + +unsafe impl plain::Plain for BosDevDescriptorBase {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct BosSuperSpeedDesc { + pub len: u8, + pub kind: u8, + pub cap_ty: u8, + + pub attrs: u8, + pub speed_supp: u16, + pub func_supp: u8, + pub u1_dev_exit_lat: u8, + pub u2_dev_exit_lat: u16, +} +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct BosUsb2ExtDesc { + pub len: u8, + pub kind: u8, + pub cap_ty: u8, + + pub attrs: u32, +} + +unsafe impl plain::Plain for BosUsb2ExtDesc {} + +#[repr(u8)] +pub enum DeviceCapability { + Usb2Ext = 2, + SuperSpeed = 3, +} + +unsafe impl plain::Plain for BosSuperSpeedDesc {} + +pub struct BosDevDescIter<'a> { + bytes: &'a [u8], +} +impl<'a> BosDevDescIter<'a> { + pub fn new(bytes: &'a [u8]) -> Self { + Self { + bytes, + } + } +} +impl<'a> From<&'a [u8]> for BosDevDescIter<'a> { + fn from(slice: &'a [u8]) -> Self { + Self::new(slice) + } +} +impl<'a> Iterator for BosDevDescIter<'a> { + type Item = (BosDevDescriptorBase, &'a [u8]); + + fn next(&mut self) -> Option { + if let Some(desc) = plain::from_bytes::(self.bytes).ok() { + if desc.len as usize > self.bytes.len() { return None }; + let bytes_ret = &self.bytes[..desc.len as usize]; + self.bytes = &self.bytes[desc.len as usize..]; + Some((*desc, bytes_ret)) + } else { + return None; + } + } +} + +#[derive(Debug)] +pub enum BosAnyDevDesc { + SuperSpeed(BosSuperSpeedDesc), + Usb2Ext(BosUsb2ExtDesc), +} + +impl BosAnyDevDesc { + pub fn is_superspeed(&self) -> bool { + match self { + Self::SuperSpeed(_) => true, + _ => false, + } + } +} + +pub struct BosAnyDevDescIter<'a> { + inner: BosDevDescIter<'a>, +} +impl<'a> From> for BosAnyDevDescIter<'a> { + fn from(ll: BosDevDescIter<'a>) -> Self { + Self { inner: ll } + } +} +impl<'a> From<&'a [u8]> for BosAnyDevDescIter<'a> { + fn from(slice: &'a [u8]) -> Self { + Self::from(BosDevDescIter::from(slice)) + } +} +impl<'a> Iterator for BosAnyDevDescIter<'a> { + type Item = BosAnyDevDesc; + + fn next(&mut self) -> Option { + let (base, slice) = self.inner.next()?; + + if base.cap_ty == DeviceCapability::Usb2Ext as u8 { + Some(BosAnyDevDesc::Usb2Ext(*plain::from_bytes(slice).ok()?)) + } else if base.cap_ty == DeviceCapability::SuperSpeed as u8 { + Some(BosAnyDevDesc::SuperSpeed(*plain::from_bytes(slice).ok()?)) + } else if base.cap_ty == 0 { + // TODO + return None; + } else { + unimplemented!("USB device capability of type: {}", base.cap_ty) + } + } +} + +pub fn bos_capability_descs<'a>(desc: BosDescriptor, data: &'a [u8]) -> impl Iterator + 'a { + BosAnyDevDescIter::from(&data[..desc.total_len as usize - std::mem::size_of_val(&desc)]).take(desc.cap_count as usize) +} diff --git a/xhcid/src/usb/config.rs b/xhcid/src/usb/config.rs index e387c731dc..28dfe96199 100644 --- a/xhcid/src/usb/config.rs +++ b/xhcid/src/usb/config.rs @@ -10,3 +10,5 @@ pub struct ConfigDescriptor { pub attributes: u8, pub max_power: u8, } + +unsafe impl plain::Plain for ConfigDescriptor {} diff --git a/xhcid/src/usb/device.rs b/xhcid/src/usb/device.rs index 5ca20c6498..baeff1828a 100644 --- a/xhcid/src/usb/device.rs +++ b/xhcid/src/usb/device.rs @@ -16,3 +16,5 @@ pub struct DeviceDescriptor { pub serial_str: u8, pub configurations: u8, } + +unsafe impl plain::Plain for DeviceDescriptor {} diff --git a/xhcid/src/usb/endpoint.rs b/xhcid/src/usb/endpoint.rs index b06648f151..b50e0fa82a 100644 --- a/xhcid/src/usb/endpoint.rs +++ b/xhcid/src/usb/endpoint.rs @@ -12,3 +12,15 @@ pub struct EndpointDescriptor { } unsafe impl Plain for EndpointDescriptor {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct SuperSpeedCompanionDescriptor { + pub length: u8, + pub kind: u8, + pub max_burst: u8, + pub attributes: u8, + pub bytes_per_interval: u16, +} + +unsafe impl Plain for SuperSpeedCompanionDescriptor {} diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 27d0e94b6d..86496898e0 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -1,6 +1,7 @@ +pub use self::bos::{BosDescriptor, BosAnyDevDesc, BosSuperSpeedDesc, bos_capability_descs}; pub use self::config::ConfigDescriptor; pub use self::device::DeviceDescriptor; -pub use self::endpoint::EndpointDescriptor; +pub use self::endpoint::{EndpointDescriptor, SuperSpeedCompanionDescriptor}; pub use self::interface::InterfaceDescriptor; pub use self::setup::Setup; @@ -16,8 +17,11 @@ pub enum DescriptorKind { OtherSpeedConfiguration, InterfacePower, OnTheGo, + BinaryObjectStorage = 15, + SuperSpeedCompanion = 48, } +mod bos; mod config; mod device; mod endpoint; diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 5f9a978bfe..bd8fb7c464 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -23,7 +23,8 @@ pub struct EndpointContext { #[repr(packed)] pub struct DeviceContext { pub slot: SlotContext, - pub endpoints: [EndpointContext; 15] + pub endpoints: [EndpointContext; 15], + // Shouldn't this be 31 (both for in and out)? } #[repr(packed)] diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 1a3255f137..4aceacd553 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -88,6 +88,16 @@ impl<'a> Device<'a> { Ok(*desc) } + fn get_bos(&mut self) -> Result<(usb::BosDescriptor, [u8; 4087])> { + let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?; + self.get_desc( + usb::DescriptorKind::BinaryObjectStorage, + 0, + &mut desc, + ); + Ok(*desc) + } + fn get_string(&mut self, index: u8) -> Result { let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; self.get_desc( @@ -295,13 +305,19 @@ impl Xhci { { input.add_context.write(1 << 1 | 1); - input.device.slot.a.write((1 << 27) | (speed << 20)); + input.device.slot.a.write((1 << 27) | (speed << 20)); // FIXME: The speed field, bits 23:20, is deprecated. input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16); - input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1); + // control endpoint? + input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1); // packet size | control endpoint | allowed error count let tr = ring.register(); input.device.endpoints[0].trh.write((tr >> 32) as u32); input.device.endpoints[0].trl.write(tr as u32); + + // TODO: I presume that there should be additional endpoint contexts, for the + // endpoints specified in the USB descriptors. Perhaps the specific USB drivers + // (HID drivers, mass storage drivers, etc.) should enable these endpoints + // themselves. } { diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 218779b5cf..3f63908f6f 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,4 +1,5 @@ use std::{cmp, mem, str}; +use std::convert::TryFrom; use std::io::prelude::*; use plain::Plain; @@ -23,6 +24,8 @@ pub enum Handle { TopLevel(usize, Vec), // offset, contents (ports) Port(usize, usize, Vec), // port, offset, contents PortDesc(usize, usize, Vec), // port, offset, contents + Endpoints(usize, usize, Vec), // port, offset, contents + Endpoint(usize, usize, usize), // port, endpoint, offset } #[derive(Serialize)] @@ -70,6 +73,17 @@ struct EndpDescJson { max_packet_size: u16, interval: u8, } +impl From for EndpDescJson { + fn from(d: usb::EndpointDescriptor) -> Self { + Self { + kind: d.kind, + address: d.address, + attributes: d.attributes, + interval: d.interval, + max_packet_size: d.max_packet_size, + } + } +} #[derive(Serialize)] struct IfDescJson { @@ -81,7 +95,81 @@ struct IfDescJson { sub_class: u8, protocol: u8, interface_str: Option, - endpoints: SmallVec<[EndpDescJson; 2]>, + endpoints: SmallVec<[AnyEndpDescJson; 4]>, +} +impl IfDescJson { + fn new(dev: &mut Device, desc: usb::InterfaceDescriptor, endps: impl IntoIterator) -> Result { + Ok(Self { + alternate_setting: desc.alternate_setting, + class: desc.class, + interface_str: if desc.interface_str > 0 { Some(dev.get_string(desc.interface_str)?) } else { None }, + kind: desc.kind, + number: desc.number, + protocol: desc.protocol, + sub_class: desc.sub_class, + endpoints: endps.into_iter().collect(), + }) + } +} + +#[derive(Serialize)] +struct SuperSpeedCmpJson { + kind: u8, + max_burst: u8, + attributes: u8, + bytes_per_interval: u16, +} + +impl From for SuperSpeedCmpJson { + fn from(d: usb::SuperSpeedCompanionDescriptor) -> Self { + Self { + kind: d.kind, + attributes: d.attributes, + bytes_per_interval: d.bytes_per_interval, + max_burst: d.max_burst, + } + } +} + +#[derive(Serialize)] +enum AnyEndpDescJson { + Endp(EndpDescJson), + SuperSpeedCmp(SuperSpeedCmpJson), +} + +/// Any descriptor that can be stored in the config desc "data" area. +#[derive(Debug)] +enum AnyDescriptor { + // These are the ones that I have found, but there are more. + Device(usb::DeviceDescriptor), + Config(usb::ConfigDescriptor), + Interface(usb::InterfaceDescriptor), + Endpoint(usb::EndpointDescriptor), + SuperSpeedCompanion(usb::SuperSpeedCompanionDescriptor), +} + +impl AnyDescriptor { + fn parse(bytes: &[u8]) -> Option<(Self, usize)> { + // There has to be at least two bytes for the kind and length. + if bytes.len() < 2 { return None } + + let len = bytes[0]; + let kind = bytes[1]; + + if bytes.len() < len.into() { return None } + + Some((match kind { + 1 => Self::Device(*plain::from_bytes(bytes).ok()?), + 2 => Self::Config(*plain::from_bytes(bytes).ok()?), + 4 => Self::Interface(*plain::from_bytes(bytes).ok()?), + 5 => Self::Endpoint(*plain::from_bytes(bytes).ok()?), + 48 => Self::SuperSpeedCompanion(*plain::from_bytes(bytes).ok()?), + _ => { + //println!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes); + return None; + } + }, len.into())) + } } impl Xhci { @@ -118,6 +206,11 @@ impl Xhci { } else { None }, ); + let (bos_desc, bos_data) = dev.get_bos()?; + writeln!(contents, "BOS BASE {:?}", bos_desc).unwrap(); + + let has_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).inspect(|item| println!("{:?}", item)).any(|desc| desc.is_superspeed()); + let config_descs = (0..raw_dd.configurations).map(|index| -> Result<_> { // TODO: Actually, it seems like all descriptors contain a length field, and I // encountered a SuperSpeed descriptor when endpoints were expected. The right way @@ -127,48 +220,45 @@ impl Xhci { let (desc, data) = dev.get_config(index)?; let extra_length = desc.total_length as usize - mem::size_of_val(&desc); + let data = &data[..extra_length]; let mut i = 0; + let mut descriptors = Vec::new(); - let mut interface_descs = SmallVec::with_capacity(desc.interfaces as usize); + while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) { + descriptors.push(descriptor); + i += len; + } - for _ in 0..desc.interfaces { - let mut idesc = usb::InterfaceDescriptor::default(); - if i < extra_length && i < data.len() && idesc.copy_from_bytes(&data[i..extra_length]).is_ok() { - i += mem::size_of_val(&idesc); + let mut interface_descs = SmallVec::new(); + let mut iter = descriptors.into_iter(); - let mut endpoints = SmallVec::with_capacity(idesc.endpoints as usize); + while let Some(item) = iter.next() { + if let AnyDescriptor::Interface(idesc) = item { + let mut endpoints = SmallVec::<[AnyEndpDescJson; 4]>::new(); - while endpoints.len() < idesc.endpoints as usize { - let mut edesc = usb::EndpointDescriptor::default(); - if i < extra_length && i < data.len() && edesc.copy_from_bytes(&data[i..extra_length]).is_ok() { - match edesc.kind { - // TODO: Constants - 5 => i += mem::size_of_val(&edesc), - 48 => { i += 6; continue } // SuperSpeed Endpoint Companion Descriptor - _ => unimplemented!(), - } + for _ in 0..idesc.endpoints { + let next = match iter.next() { + Some(AnyDescriptor::Endpoint(n)) => n, + _ => break, + }; + endpoints.push(AnyEndpDescJson::Endp(EndpDescJson::from(next))); - endpoints.push(EndpDescJson { - address: edesc.address, - attributes: edesc.attributes, - interval: edesc.interval, - kind: edesc.kind, - max_packet_size: edesc.max_packet_size, - }) - } else { break } + if has_superspeed { + dbg!(); + let next = match iter.next() { + Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, + _ => break, + }; + dbg!(); + endpoints.push(AnyEndpDescJson::SuperSpeedCmp(SuperSpeedCmpJson::from(next))); + } } - interface_descs.push(IfDescJson { - kind: idesc.kind, - number: idesc.number, - alternate_setting: idesc.alternate_setting, - class: idesc.class, - sub_class: idesc.sub_class, - protocol: idesc.protocol, - interface_str: if idesc.interface_str > 0 { Some(dev.get_string(idesc.interface_str)?) } else { None }, - endpoints, - }); + interface_descs.push(IfDescJson::new(&mut dev, idesc, endpoints)?); + } else { + // TODO + break; } } @@ -236,32 +326,66 @@ impl SchemeMut for Xhci { let num_str = &path_str[4..slash_idx.unwrap_or(path_str.len())]; let num = num_str.parse::().or(Err(Error::new(ENOENT)))?; - if slash_idx.is_some() && slash_idx.unwrap() + 1 < path_str.len() && &path_str[slash_idx.unwrap() + 1..] == "descriptors" { - if flags & O_DIRECTORY != 0 { - return Err(Error::new(ENOTDIR)); - } - - let mut contents = Vec::new(); - self.write_port_desc(num, &mut contents)?; - - let fd = self.next_handle; - self.handles.insert(fd, Handle::PortDesc(num, 0, contents)); - self.next_handle += 1; - return Ok(fd); - } - - if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { - let mut contents = Vec::new(); - - write!(contents, "descriptors\n").unwrap(); - - let fd = self.next_handle; - self.handles.insert(fd, Handle::Port(num, 0, contents)); - self.next_handle += 1; - Ok(fd) + let subdir_str = if slash_idx.is_some() && slash_idx.unwrap() + 1 < path_str.len() { + Some(&path_str[slash_idx.unwrap() + 1..]) } else { - return Err(Error::new(EISDIR)); - } + None + }; + + let handle = match subdir_str { + Some("descriptors") => { + if flags & O_DIRECTORY != 0 { + return Err(Error::new(ENOTDIR)); + } + + let mut contents = Vec::new(); + self.write_port_desc(num, &mut contents)?; + + Handle::PortDesc(num, 0, contents) + } + Some(other) if other.contains('/') => { + let slash_idx = other.chars().position(|c| c == '/').ok_or(Error::new(ENOENT))?; + if slash_idx + 2 >= other.len() { + return Err(Error::new(ENOENT)); + } + + let slice = &other[slash_idx + 2..]; + let endpoint_num = slice.parse::().or(Err(Error::new(ENOENT)))?; + Handle::Endpoint(num, endpoint_num, 0) + } + Some("endpoints") => { + if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { + return Err(Error::new(EISDIR)); + }; + let mut contents = Vec::new(); + let ps = &self.port_states[&num]; + + for (ep_num, _) in ps.input_context.device.endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { + write!(contents, "i{}", ep_num).unwrap(); + } + for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { + write!(contents, "o{}", ep_num).unwrap(); + } + + Handle::Endpoints(num, 0, contents) + } + Some(_) => return Err(Error::new(ENOENT)), + None => if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { + let mut contents = Vec::new(); + + write!(contents, "descriptors\n").unwrap(); + + Handle::Port(num, 0, contents) + } else { + return Err(Error::new(EISDIR)); + } + }; + + let fd = self.next_handle; + self.next_handle += 1; + self.handles.insert(fd, handle); + + Ok(fd) } else { return Err(Error::new(ENOSYS)); } @@ -269,7 +393,7 @@ impl SchemeMut for Xhci { fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { match self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::TopLevel(_, ref buf) | Handle::Port(_, _, ref buf) => { + Handle::TopLevel(_, ref buf) | Handle::Port(_, _, ref buf) | Handle::Endpoints(_, _, ref buf) => { // TODO: Known size perhaps? stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; @@ -280,12 +404,16 @@ impl SchemeMut for Xhci { stat.st_size = buf.len() as u64; Ok(0) } + Handle::Endpoint(_, _, _) => { + stat.st_mode = MODE_FILE; + Ok(0) + } } } fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) => { + Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) | Handle::Endpoints(_, ref mut offset, ref buf) => { *offset = match whence { SEEK_SET => cmp::max(0, cmp::min(pos, buf.len())), SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, buf.len())), @@ -294,12 +422,13 @@ impl SchemeMut for Xhci { }; Ok(*offset) } + Handle::Endpoint(_, _, _) => unimplemented!(), } } fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) => { + Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) | Handle::Endpoints(_, ref mut offset, ref src_buf) => { let max_bytes_to_read = cmp::min(src_buf.len(), buf.len()); let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset; @@ -308,6 +437,7 @@ impl SchemeMut for Xhci { Ok(bytes_to_read) } + Handle::Endpoint(_, _, _) => unimplemented!(), } } fn close(&mut self, fd: usize) -> Result { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 459fdc6b4a..49db6e5115 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -164,6 +164,18 @@ impl Trb { (cycle as u32) ); } + // Synchronizes the input context endpoints with the device context endpoints, it think. + pub fn configure_endpoint(&mut self, slot_id: u8, input_ctx_ptr: usize, cycle: bool) { + assert_eq!(input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0, input_ctx_ptr); + + self.set( + (input_ctx_ptr >> 4) as u64, + 0, + (u32::from(slot_id) << 24) | + ((TrbType::ConfigureEndpoint as u32) << 10) | + (cycle as u32), + ) + } pub fn setup(&mut self, setup: usb::Setup, transfer: TransferKind, cycle: bool) { self.set( From 93d99c4f4f46e83edbd34220f142dd79b5431eae Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 12 Jan 2020 21:14:25 +1100 Subject: [PATCH 0317/1301] Add a skeleton for endpoint enabling (in the driver API). --- xhcid/src/xhci/context.rs | 5 +- xhcid/src/xhci/scheme.rs | 274 ++++++++++++++++++++++++++------------ 2 files changed, 191 insertions(+), 88 deletions(-) diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index bd8fb7c464..bc6acbdf2c 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -20,11 +20,12 @@ pub struct EndpointContext { _rsvd: [Mmio; 3], } +pub const ENDPOINT_CONTEXT_STATUS_MASK: u32 = 0x7; + #[repr(packed)] pub struct DeviceContext { pub slot: SlotContext, - pub endpoints: [EndpointContext; 15], - // Shouldn't this be 31 (both for in and out)? + pub endpoints: [EndpointContext; 31], } #[repr(packed)] diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 3f63908f6f..db4bf2e37a 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,16 +1,14 @@ -use std::{cmp, mem, str}; -use std::convert::TryFrom; +use std::{cmp, mem, path, str}; use std::io::prelude::*; -use plain::Plain; -use serde::Serialize; +use serde::{Serialize, Deserialize}; use smallvec::SmallVec; -use syscall::io::Io; +use syscall::io::{Dma, Io}; use syscall::scheme::SchemeMut; use syscall::{ - EACCES, EBADF, EINVAL, EISDIR, ENOENT, - O_CREAT, O_DIRECTORY, O_STAT, ENOSYS, ENOTDIR, + EACCES, EBADF, EBADMSG, EINVAL, EISDIR, ENOENT, ENOSYS, ENOTDIR, ENXIO, ESPIPE, + O_CREAT, O_DIRECTORY, O_STAT, MODE_DIR, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET, Stat, @@ -19,13 +17,30 @@ use syscall::{ use super::{Device, Xhci}; use super::{port, usb}; +use super::context::{ENDPOINT_CONTEXT_STATUS_MASK, InputContext}; + +/// Subdirs of an endpoint +enum EndpointState { + /// `/portX/endpoints/Y/init`, used for a one-write-call initialization of an endpoint. + Init, + + /// portX/endpoints/Y/transfer. Write calls transfer data to the device, and read calls + /// transfer data from the device. + Transfer, + + /// portX/endpoints/Y/status + Status(usize), // offset + + /// portX/endpoints/Y/ + Root(usize, Vec), // offset, content +} pub enum Handle { TopLevel(usize, Vec), // offset, contents (ports) Port(usize, usize, Vec), // port, offset, contents PortDesc(usize, usize, Vec), // port, offset, contents Endpoints(usize, usize, Vec), // port, offset, contents - Endpoint(usize, usize, usize), // port, endpoint, offset + Endpoint(usize, usize, EndpointState), // port, endpoint, offset, state } #[derive(Serialize)] @@ -131,11 +146,18 @@ impl From for SuperSpeedCmpJson { } } -#[derive(Serialize)] enum AnyEndpDescJson { Endp(EndpDescJson), SuperSpeedCmp(SuperSpeedCmpJson), } +impl serde::Serialize for AnyEndpDescJson { + fn serialize(&self, serializer: S) -> std::result::Result { + match self { + Self::Endp(e) => e.serialize(serializer), + Self::SuperSpeedCmp(c) => c.serialize(serializer), + } + } +} /// Any descriptor that can be stored in the config desc "data" area. #[derive(Debug)] @@ -150,7 +172,6 @@ enum AnyDescriptor { impl AnyDescriptor { fn parse(bytes: &[u8]) -> Option<(Self, usize)> { - // There has to be at least two bytes for the kind and length. if bytes.len() < 2 { return None } let len = bytes[0]; @@ -172,7 +193,25 @@ impl AnyDescriptor { } } +#[derive(Deserialize)] +struct InitEndpointReqJson { + index: u8, +} + impl Xhci { + fn init_endpoint(&mut self, buf: &[u8]) -> Result<()> { + let req: InitEndpointReqJson = serde_json::from_slice(buf).or(Err(Error::new(EBADMSG)))?; + let input_context = Dma::::zeroed()?; + + // Endpoint zero is the control endpoint, which is always enabled. + if !(1..=31).contains(&req.index) { return Err(Error::new(EINVAL)) } + + input_context.add_context.write(1 << req.index); + // FIXME: A port string is required + //input_context.device.slot. + + Ok(()) + } fn write_port_desc(&mut self, port_id: usize, contents: &mut Vec) -> Result<()> { let port = self.ports.get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { @@ -245,12 +284,10 @@ impl Xhci { endpoints.push(AnyEndpDescJson::Endp(EndpDescJson::from(next))); if has_superspeed { - dbg!(); let next = match iter.next() { Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, _ => break, }; - dbg!(); endpoints.push(AnyEndpDescJson::SuperSpeedCmp(SuperSpeedCmpJson::from(next))); } } @@ -305,90 +342,101 @@ impl SchemeMut for Xhci { let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_start_matches('/'); - if path_str.is_empty() { - if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { + let components = path::Path::new(path_str).components().map(|component| -> Option<_> { + match component { + path::Component::Normal(n) => Some(n.to_str()?), + _ => None, + } + }).collect::>>().ok_or(Error::new(ENOENT))?; + + let handle = match &components[..] { + &[] => if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { let mut contents = Vec::new(); for (index, _) in self.ports.iter().enumerate().filter(|(_, port)| port.flags().contains(port::PortFlags::PORT_CCS)) { write!(contents, "port{}\n", index).unwrap(); } - let fd = self.next_handle; - self.handles.insert(fd, Handle::TopLevel(0, contents)); - self.next_handle += 1; - Ok(fd) + Handle::TopLevel(0, contents) } else { return Err(Error::new(EISDIR)); } - } else if path_str.starts_with("port") { - let slash_idx = path_str.chars().position(|c| c == '/'); + &[port, "descriptors"] if port.starts_with("port") => { + let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; - let num_str = &path_str[4..slash_idx.unwrap_or(path_str.len())]; - let num = num_str.parse::().or(Err(Error::new(ENOENT)))?; - - let subdir_str = if slash_idx.is_some() && slash_idx.unwrap() + 1 < path_str.len() { - Some(&path_str[slash_idx.unwrap() + 1..]) - } else { - None - }; - - let handle = match subdir_str { - Some("descriptors") => { - if flags & O_DIRECTORY != 0 { - return Err(Error::new(ENOTDIR)); - } - - let mut contents = Vec::new(); - self.write_port_desc(num, &mut contents)?; - - Handle::PortDesc(num, 0, contents) + if flags & O_DIRECTORY != 0 { + return Err(Error::new(ENOTDIR)); } - Some(other) if other.contains('/') => { - let slash_idx = other.chars().position(|c| c == '/').ok_or(Error::new(ENOENT))?; - if slash_idx + 2 >= other.len() { - return Err(Error::new(ENOENT)); - } - let slice = &other[slash_idx + 2..]; - let endpoint_num = slice.parse::().or(Err(Error::new(ENOENT)))?; - Handle::Endpoint(num, endpoint_num, 0) + let mut contents = Vec::new(); + self.write_port_desc(port_num, &mut contents)?; + + Handle::PortDesc(port_num, 0, contents) + } + &[port, "endpoints"] if port.starts_with("port") => { + let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; + + if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { + return Err(Error::new(EISDIR)); + }; + let mut contents = Vec::new(); + let ps = self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?; + + for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { + write!(contents, "{}\n", ep_num).unwrap(); } - Some("endpoints") => { - if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { - return Err(Error::new(EISDIR)); - }; - let mut contents = Vec::new(); - let ps = &self.port_states[&num]; - for (ep_num, _) in ps.input_context.device.endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { - write!(contents, "i{}", ep_num).unwrap(); - } - for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { - write!(contents, "o{}", ep_num).unwrap(); - } + Handle::Endpoints(port_num, 0, contents) + } + &[port, "endpoints", endpoint_num_str] if port.starts_with("port") => { + let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; + let endpoint_num = endpoint_num_str.parse::().or(Err(Error::new(ENOENT)))?; - Handle::Endpoints(num, 0, contents) - } - Some(_) => return Err(Error::new(ENOENT)), - None => if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { - let mut contents = Vec::new(); - - write!(contents, "descriptors\n").unwrap(); - - Handle::Port(num, 0, contents) - } else { + if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { return Err(Error::new(EISDIR)); } - }; - let fd = self.next_handle; - self.next_handle += 1; - self.handles.insert(fd, handle); + if flags & O_CREAT != 0 { + Handle::Endpoint(port_num, endpoint_num, EndpointState::Init) + } else { + if self.dev_ctx.contexts[self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?.slot as usize].endpoints.get(endpoint_num).ok_or(Error::new(ENOENT))?.a.read() & 0b111 != 1 { + return Err(Error::new(ENXIO)); // TODO: Find a proper error code for "endpoint not initialized". + } + let contents = b"transfer\nstatus"[..].to_owned(); + Handle::Endpoint(port_num, endpoint_num, EndpointState::Root(0, contents)) + } + } + &[port, "endpoints", endpoint_num_str, sub] if port.starts_with("port") => { + let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; + let endpoint_num = endpoint_num_str.parse::().or(Err(Error::new(ENOENT)))?; - Ok(fd) - } else { - return Err(Error::new(ENOSYS)); - } + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { return Err(Error::new(EISDIR)) } + + let st = match sub { + "status" => EndpointState::Status(0), + "transfer" => EndpointState::Transfer, + _ => return Err(Error::new(ENOENT)), + }; + Handle::Endpoint(port_num, endpoint_num, st) + } + &[port] if port.starts_with("port") => if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { + let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; + let mut contents = Vec::new(); + + write!(contents, "descriptors\nendpoints\n").unwrap(); + + Handle::Port(port_num, 0, contents) + } else { + return Err(Error::new(EISDIR)); + } + _ => return Err(Error::new(ENOENT)), + }; + + let fd = self.next_handle; + self.next_handle += 1; + self.handles.insert(fd, handle); + + Ok(fd) } fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { @@ -397,23 +445,42 @@ impl SchemeMut for Xhci { // TODO: Known size perhaps? stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; - Ok(0) } Handle::PortDesc(_, _, ref buf) => { stat.st_mode = MODE_FILE; stat.st_size = buf.len() as u64; - Ok(0) } - Handle::Endpoint(_, _, _) => { - stat.st_mode = MODE_FILE; - Ok(0) + Handle::Endpoint(_, _, st) => match st { + EndpointState::Init | EndpointState::Status(_) | EndpointState::Transfer => stat.st_mode = MODE_FILE, + EndpointState::Root(_, _) => stat.st_mode = MODE_DIR, } } + Ok(0) + } + + fn fpath(&mut self, fd: usize, buffer: &mut [u8]) -> Result { + // XXX: write!() should return the length instead of (). + let mut src = Vec::::new(); + match self.handles.get(&fd).ok_or(Error::new(EBADF))? { + Handle::TopLevel(_, _) => write!(src, "/").unwrap(), + Handle::Port(port_num, _, _) => write!(src, "/port{}/", port_num).unwrap(), + Handle::PortDesc(port_num, _, _) => write!(src, "/port{}/descriptors", port_num).unwrap(), + Handle::Endpoints(port_num, _, _) => write!(src, "/port{}/endpoints/", port_num).unwrap(), + Handle::Endpoint(port_num, endp_num, st) => write!(src, "/port{}/endpoints/{}/{}", port_num, endp_num, match st { + EndpointState::Init => "init", + EndpointState::Root(_, _) => "", + EndpointState::Status(_) => "status", + EndpointState::Transfer => "transfer", + }).unwrap(), + } + let bytes_to_read = cmp::min(src.len(), buffer.len()); + buffer[..bytes_to_read].copy_from_slice(&src[..bytes_to_read]); + Ok(bytes_to_read) } fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) | Handle::Endpoints(_, ref mut offset, ref buf) => { + Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) | Handle::Endpoints(_, ref mut offset, ref buf) | Handle::Endpoint(_, _, EndpointState::Root(ref mut offset, ref buf)) => { *offset = match whence { SEEK_SET => cmp::max(0, cmp::min(pos, buf.len())), SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, buf.len())), @@ -422,13 +489,13 @@ impl SchemeMut for Xhci { }; Ok(*offset) } - Handle::Endpoint(_, _, _) => unimplemented!(), + Handle::Endpoint(_, _, _) => return Err(Error::new(ESPIPE)), } } fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) | Handle::Endpoints(_, ref mut offset, ref src_buf) => { + Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) | Handle::Endpoints(_, ref mut offset, ref src_buf) | Handle::Endpoint(_, _, EndpointState::Root(ref mut offset, ref src_buf)) => { let max_bytes_to_read = cmp::min(src_buf.len(), buf.len()); let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset; @@ -437,7 +504,42 @@ impl SchemeMut for Xhci { Ok(bytes_to_read) } - Handle::Endpoint(_, _, _) => unimplemented!(), + &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { + EndpointState::Init => return Err(Error::new(EINVAL)), + EndpointState::Transfer => unimplemented!(), + EndpointState::Status(ref mut offset) => { + let status = self.dev_ctx.contexts.get(port_num).ok_or(Error::new(EBADF))?.endpoints.get(endp_num).ok_or(Error::new(EBADF))?.a.read() & ENDPOINT_CONTEXT_STATUS_MASK; + + let string = match status { + // TODO: Give this its own enum. + 0 => "disabled", + 1 => "enabled", + 2 => "halted", + 3 => "stopped", + 4 => "error", + _ => "unknown", + }.as_bytes(); + + let max_bytes_to_read = cmp::min(string.len(), buf.len()); + let bytes_to_read = cmp::max(*offset, max_bytes_to_read) - *offset; + buf[..bytes_to_read].copy_from_slice(&string[..bytes_to_read]); + + *offset += bytes_to_read; + + Ok(bytes_to_read) + } + EndpointState::Root(_, _) => unreachable!(), + }, + } + } + fn write(&mut self, fd: usize, buf: &[u8]) -> Result { + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::Endpoint(_, _, EndpointState::Init) => { + self.init_endpoint(buf)?; + Ok(buf.len()) + }; + Handle::Endpoint(_, _, EndpointState::Transfer) => unimplemented!(), + _ => return Err(Error::new(EINVAL)), } } fn close(&mut self, fd: usize) -> Result { From cbd9d83b69f483805f39500050eedb0c79345c42 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 15 Jan 2020 10:50:02 +1100 Subject: [PATCH 0318/1301] SUPPORT CONFIGURE_ENDPOINTS! --- Cargo.lock | 432 ++++++++++++++------------ initfs.toml | 1 + xhcid/Cargo.toml | 2 +- xhcid/src/main.rs | 6 +- xhcid/src/usb/bos.rs | 2 +- xhcid/src/usb/device.rs | 9 + xhcid/src/usb/endpoint.rs | 23 ++ xhcid/src/usb/mod.rs | 14 +- xhcid/src/xhci/capability.rs | 20 +- xhcid/src/xhci/context.rs | 49 ++- xhcid/src/xhci/mod.rs | 195 +++++++----- xhcid/src/xhci/operational.rs | 13 +- xhcid/src/xhci/scheme.rs | 566 ++++++++++++++++++++++++---------- xhcid/src/xhci/trb.rs | 25 +- 14 files changed, 901 insertions(+), 456 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab822c01a2..542f7689f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,15 +28,20 @@ source = "git+https://gitlab.redox-os.org/redox-os/arg-parser.git#1c434b55f3e1a0 [[package]] name = "arrayvec" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "0.1.5" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "autocfg" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -45,7 +50,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -91,17 +96,17 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.38" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -120,6 +125,14 @@ dependencies = [ "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-channel" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.6.3" @@ -134,11 +147,11 @@ name = "crossbeam-epoch" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -147,8 +160,18 @@ name = "crossbeam-utils" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -187,13 +210,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "gpt" version = "0.6.3" -source = "git+https://github.com/4lDO2/gpt#20160d7089faa44c3566cad0fa6e49b2824b599c" +source = "git+https://gitlab.redox-os.org/redox-os/gpt#de8270848edf07b68b7e0d73d6efcb15b2e1f090" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -201,6 +224,14 @@ dependencies = [ "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hermit-abi" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "httparse" version = "1.3.4" @@ -216,7 +247,7 @@ dependencies = [ "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -242,7 +273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -257,11 +288,10 @@ dependencies = [ [[package]] name = "iovec" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -295,12 +325,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.61" +version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -330,7 +360,7 @@ name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -338,9 +368,14 @@ name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memoffset" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -361,9 +396,9 @@ source = "git+https://gitlab.redox-os.org/redox-os/mio#439a559b2aa734e0970d37b33 dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -374,14 +409,15 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.19" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -394,8 +430,8 @@ name = "mio-uds" version = "0.6.7" source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#22580ca398cdb5ed6f50fb61134e5579e2213999" dependencies = [ - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", ] @@ -415,28 +451,28 @@ name = "net2" version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#e28efbd6bbfabe42290e7ef84bca5e4c7f0d4aa2" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#7cfab705109a388c804ae624f8af2d930ab7a06c" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", - "pbr 1.0.1 (git+https://github.com/a8m/pb)", + "pbr 1.0.2 (git+https://github.com/a8m/pb)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -445,24 +481,24 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#649265429a25c80a7e30063c932367d625ff79c5" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#bcdac5927ec65217dfa02497d83e94a29b9b992d" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", - "pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "nodrop" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -479,44 +515,45 @@ name = "num" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" -version = "0.1.39" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num_cpus" -version = "1.10.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -566,44 +603,44 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "partitionlib" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/partitionlib.git#ae8157fde75ac3589b7e8ff831bbba538b8009d8" +source = "git+https://gitlab.redox-os.org/redox-os/partitionlib.git#1c12e0d93f7a16f7a209abdcf318388e850a73c7" dependencies = [ - "gpt 0.6.3 (git+https://github.com/4lDO2/gpt)", + "gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)", "scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pbr" -version = "1.0.1" -source = "git+https://github.com/a8m/pb#b9792c9fe37343234316e23c263874cf383b208d" +version = "1.0.2" +source = "git+https://github.com/a8m/pb#87c29c05486afa7335916c870ea3621ff7ef2966" dependencies = [ - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pbr" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -613,8 +650,8 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -637,15 +674,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro2" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -661,20 +690,12 @@ dependencies = [ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -682,8 +703,8 @@ name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -692,7 +713,7 @@ dependencies = [ "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -700,7 +721,7 @@ name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -738,9 +759,9 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -750,10 +771,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -761,7 +782,7 @@ name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -798,6 +819,14 @@ dependencies = [ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=dma-slices#13dea70f6bdd09f0128595ebf640e203abff7392" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_syscall" version = "0.1.56" @@ -816,9 +845,9 @@ name = "ring" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -855,12 +884,12 @@ dependencies = [ [[package]] name = "rusttype" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -870,7 +899,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "safemem" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -896,7 +925,7 @@ name = "scroll_derive" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -916,8 +945,8 @@ version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -928,8 +957,8 @@ name = "sdl2-sys" version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -947,20 +976,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.98" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.98" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -970,7 +999,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -980,15 +1009,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.10" +version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "smallvec" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1003,38 +1035,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "stb_truetype" -version = "0.2.6" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "stb_truetype" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "syn" version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "termion" -version = "1.5.3" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1045,9 +1075,9 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1056,9 +1086,9 @@ version = "0.1.13" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -1078,7 +1108,7 @@ version = "0.1.1" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -1087,7 +1117,7 @@ name = "tokio-current-thread" version = "0.1.4" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -1096,7 +1126,7 @@ name = "tokio-executor" version = "0.1.5" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1104,7 +1134,7 @@ name = "tokio-fs" version = "0.1.4" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -1115,7 +1145,7 @@ version = "0.1.10" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1125,11 +1155,11 @@ version = "0.1.7" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -1142,8 +1172,8 @@ version = "0.1.2" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -1156,9 +1186,9 @@ source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc1 dependencies = [ "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -1169,7 +1199,7 @@ version = "0.2.8" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -1180,7 +1210,7 @@ version = "0.1.3" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -1194,9 +1224,9 @@ version = "0.2.4" source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", @@ -1210,7 +1240,7 @@ name = "toml" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1241,17 +1271,12 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.8" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.2.0" @@ -1306,7 +1331,7 @@ dependencies = [ "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1342,7 +1367,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1380,8 +1405,8 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=dma-slices)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1389,8 +1414,9 @@ dependencies = [ [metadata] "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" -"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" -"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" @@ -1398,63 +1424,65 @@ dependencies = [ "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "ce400c638d48ee0e9ab75aef7997609ec57367ccfe1463f21bf53c3eca67bf46" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" +"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "45dc39533a6cae6da2b56da48edae506bb767ec07370f86f70fc062e9d435869" -"checksum gpt 0.6.3 (git+https://github.com/4lDO2/gpt)" = "" +"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" +"checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" +"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" "checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" +"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.61 (registry+https://github.com/rust-lang/crates.io-index)" = "c665266eb592905e8503ba3403020f4b8794d26263f412ca33171600eca9a6fa" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" +"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" -"checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" +"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" "checksum mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)" = "" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)" = "" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)" = "" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "76bd5272412d173d6bf9afdf98db8612bbabc9a7a830b7bfc9c188911716132e" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" +"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +"checksum num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" +"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" -"checksum pbr 1.0.1 (git+https://github.com/a8m/pb)" = "" -"checksum pbr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "deb73390ab68d81992bd994d145f697451bb0b54fd39738e72eef32458ad6907" +"checksum pbr 1.0.2 (git+https://github.com/a8m/pb)" = "" +"checksum pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4403eb718d70c03ee279e51737782902c68cca01e870a33b6a2f9dfb50b9cd83" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" @@ -1469,14 +1497,15 @@ dependencies = [ "checksum ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" +"checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=dma-slices)" = "" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b" -"checksum rusttype 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "30047cc747a78ae042bf2cd65c79f83c3485d90107535b532d6e8f60e2c89cb1" +"checksum rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" -"checksum safemem 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e133ccc4f4d1cd4f89cc8a7ff618287d56dc7f638b8e38fc32c5fdcadc339dd5" +"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" "checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" "checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" @@ -1486,18 +1515,18 @@ dependencies = [ "checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5626ac617da2f2d9c48af5515a21d5a480dbd151e01bb1c355e26a3e68113" -"checksum serde_derive 1.0.98 (registry+https://github.com/rust-lang/crates.io-index)" = "01e69e1b8a631f245467ee275b8c757b818653c6d704cdbcaeb56b56767b529c" +"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" +"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" "checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" +"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum stb_truetype 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "69b7df505db8e81d54ff8be4693421e5b543e08214bd8d99eb761fcb4d5668ba" -"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +"checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" +"checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" "checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8" -"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" +"checksum termion 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "818ef3700c2a7b447dca1a1dd28341fe635e6ee103c806c636bb9c929991b2cd" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" @@ -1516,8 +1545,7 @@ dependencies = [ "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" @@ -1528,7 +1556,7 @@ dependencies = [ "checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" "checksum webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85d1f408918fd590908a70d36b7ac388db2edc221470333e4d6e5b598e44cabf" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/initfs.toml b/initfs.toml index 6430657f3e..b604eec197 100644 --- a/initfs.toml +++ b/initfs.toml @@ -36,6 +36,7 @@ class = 8 vendor = 33006 device = 51966 command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] + [[drivers]] name = "XHCI" class = 12 diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 6a1907d8c4..d103bdcb1c 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -8,7 +8,7 @@ bitflags = "1" plain = "0.2" spin = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.1" +redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "dma-slices" } serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1", features = ["serde"] } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 5ec46d9ee9..581e4f6449 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -12,7 +12,7 @@ use std::io::{Result, Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use syscall::data::Packet; -use syscall::flag::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; use syscall::scheme::SchemeMut; @@ -36,7 +36,7 @@ fn main() { print!("{}", format!(" + XHCI {} on: {:X} IRQ: {}\n", name, bar, irq)); // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { let socket_fd = syscall::open(format!(":usb/{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); @@ -61,7 +61,7 @@ fn main() { let mut irq = [0; 8]; irq_file.read(&mut irq)?; - if hci_irq.borrow_mut().irq() { + if hci_irq.borrow_mut().trigger_irq() { irq_file.write(&mut irq)?; let mut todo = todo_irq.borrow_mut(); diff --git a/xhcid/src/usb/bos.rs b/xhcid/src/usb/bos.rs index f72563fbee..2221b8e3a7 100644 --- a/xhcid/src/usb/bos.rs +++ b/xhcid/src/usb/bos.rs @@ -82,7 +82,7 @@ impl<'a> Iterator for BosDevDescIter<'a> { } } -#[derive(Debug)] +#[derive(Clone, Copy, Debug)] pub enum BosAnyDevDesc { SuperSpeed(BosSuperSpeedDesc), Usb2Ext(BosUsb2ExtDesc), diff --git a/xhcid/src/usb/device.rs b/xhcid/src/usb/device.rs index baeff1828a..93f50234ce 100644 --- a/xhcid/src/usb/device.rs +++ b/xhcid/src/usb/device.rs @@ -18,3 +18,12 @@ pub struct DeviceDescriptor { } unsafe impl plain::Plain for DeviceDescriptor {} + +impl DeviceDescriptor { + fn minor_usb_vers(&self) -> u8 { + (self.usb & 0xFF) as u8 + } + fn major_usb_vers(&self) -> u8 { + ((self.usb >> 8) & 0xFF) as u8 + } +} diff --git a/xhcid/src/usb/endpoint.rs b/xhcid/src/usb/endpoint.rs index b50e0fa82a..6611c57987 100644 --- a/xhcid/src/usb/endpoint.rs +++ b/xhcid/src/usb/endpoint.rs @@ -11,6 +11,29 @@ pub struct EndpointDescriptor { pub interval: u8, } +pub const ENDP_ATTR_TY_MASK: u8 = 0x3; + +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum EndpointTy { + Ctrl = 0, + Interrupt = 1, + Bulk = 2, + Isoch = 3, +} + +impl EndpointDescriptor { + fn ty(self) -> EndpointTy { + match self.attributes & ENDP_ATTR_TY_MASK { + 0 => EndpointTy::Ctrl, + 1 => EndpointTy::Interrupt, + 2 => EndpointTy::Bulk, + 3 => EndpointTy::Isoch, + _ => unreachable!(), + } + } +} + unsafe impl Plain for EndpointDescriptor {} #[repr(packed)] diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 86496898e0..65fca44afb 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -1,7 +1,7 @@ pub use self::bos::{BosDescriptor, BosAnyDevDesc, BosSuperSpeedDesc, bos_capability_descs}; pub use self::config::ConfigDescriptor; pub use self::device::DeviceDescriptor; -pub use self::endpoint::{EndpointDescriptor, SuperSpeedCompanionDescriptor}; +pub use self::endpoint::{EndpointDescriptor, SuperSpeedCompanionDescriptor, EndpointTy, ENDP_ATTR_TY_MASK}; pub use self::interface::InterfaceDescriptor; pub use self::setup::Setup; @@ -21,9 +21,9 @@ pub enum DescriptorKind { SuperSpeedCompanion = 48, } -mod bos; -mod config; -mod device; -mod endpoint; -mod interface; -mod setup; +pub(crate) mod bos; +pub(crate) mod config; +pub(crate) mod device; +pub(crate) mod endpoint; +pub(crate) mod interface; +pub(crate) mod setup; diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index 4c0af02144..66b8156310 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -1,4 +1,4 @@ -use syscall::io::Mmio; +use syscall::io::{Io, Mmio}; #[repr(packed)] pub struct CapabilityRegs { @@ -13,3 +13,21 @@ pub struct CapabilityRegs { pub rts_offset: Mmio, pub hcc_params2: Mmio } + +pub const HCC_PARAMS1_MAXPSASIZE_MASK: u32 = 0xF000; // 15:12 +pub const HCC_PARAMS1_MAXPSASIZE_SHIFT: u8 = 12; + +pub const HCC_PARAMS2_LEC_BIT: u32 = 1 << 4; +pub const HCC_PARAMS2_CIC_BIT: u32 = 1 << 5; + +impl CapabilityRegs { + pub fn lec(&self) -> bool { + self.hcc_params2.readf(HCC_PARAMS2_LEC_BIT) + } + pub fn cic(&self) -> bool { + self.hcc_params2.readf(HCC_PARAMS2_CIC_BIT) + } + pub fn max_psa_size(&self) -> u8 { + ((self.hcc_params1.read() & HCC_PARAMS1_MAXPSASIZE_MASK) >> HCC_PARAMS1_MAXPSASIZE_SHIFT) as u8 + } +} diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index bc6acbdf2c..95c86d6e4a 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -1,5 +1,5 @@ use syscall::error::Result; -use syscall::io::{Dma, Mmio}; +use syscall::io::{Dma, Mmio, Io}; #[repr(packed)] pub struct SlotContext { @@ -10,6 +10,23 @@ pub struct SlotContext { _rsvd: [Mmio; 4], } +pub const SLOT_CONTEXT_STATE_MASK: u32 = 0xF800_0000; +pub const SLOT_CONTEXT_STATE_SHIFT: u8 = 27; + +impl SlotContext { + pub fn state(&self) -> u8 { + ((self.d.read() & SLOT_CONTEXT_STATE_MASK) >> SLOT_CONTEXT_STATE_SHIFT) as u8 + } +} + +#[repr(u8)] +pub enum SlotState { + EnabledOrDisabled = 0, + Default = 1, + Addressed = 2, + Configured = 3, +} + #[repr(packed)] pub struct EndpointContext { pub a: Mmio, @@ -36,6 +53,11 @@ pub struct InputContext { pub control: Mmio, pub device: DeviceContext, } +impl InputContext { + pub fn dump_control(&self) { + println!("INPUT CONTEXT: {} {} [{} {} {} {} {}] {}", self.drop_context.read(), self.add_context.read(), self._rsvd[0].read(), self._rsvd[1].read(), self._rsvd[2].read(), self._rsvd[3].read(), self._rsvd[4].read(), self.control.read()); + } +} pub struct DeviceContextList { pub dcbaa: Dma<[u64; 256]>, @@ -64,3 +86,28 @@ impl DeviceContextList { self.dcbaa.physical() as u64 } } + +#[repr(packed)] +pub struct StreamContext { + trl: Mmio, + trh: Mmio, + edtla: Mmio, + rsvd: Mmio, +} + +pub struct StreamContextArray { + pub contexts: Dma<[StreamContext]>, +} + +impl StreamContextArray { + pub fn new(count: usize) -> Result { + unsafe { + Ok(Self { + contexts: Dma::zeroed_unsized(count)?, + }) + } + } + pub fn register(&self) -> u64 { + self.contexts.physical() as u64 + } +} diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 4aceacd553..cb817769ae 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,6 +1,8 @@ use plain::Plain; -use std::{mem, slice}; +use std::{mem, slice, sync::atomic, task}; use std::collections::BTreeMap; +use std::pin::Pin; +use std::sync::{Arc, Mutex, Weak, atomic::AtomicBool}; use syscall::error::Result; use syscall::io::{Dma, Io}; use crate::usb; @@ -19,13 +21,13 @@ mod trb; use self::capability::CapabilityRegs; use self::command::CommandRing; -use self::context::{DeviceContextList, InputContext}; +use self::context::{DeviceContextList, InputContext, StreamContextArray}; use self::doorbell::Doorbell; use self::operational::OperationalRegs; use self::port::Port; use self::ring::Ring; use self::runtime::{RuntimeRegs, Interrupter}; -use self::trb::TransferKind; +use self::trb::{TransferKind, TrbCompletionCode, TrbType}; struct Device<'a> { ring: &'a mut Ring, @@ -127,12 +129,41 @@ pub struct Xhci { handles: BTreeMap, next_handle: usize, port_states: BTreeMap, + + // TODO: Is this the correct implementation? I mean, there will be a really limited number of + // IRQs, if not just one, and since we probably wont use a thread pool scheduler like those of + // async-std or tokio, one could possibly assume that the futures themselves won't have to push + // all the wakers. + // TODO: This should probably be a BTreeMap (or just a VecMap) of states for each IRQ number, + // if more than one are used. I'm not sure if the XHCI interrupters actually use different + // IRQs, but it would make sense in case the hub has both isochronous (which trigger interrupts + // reapeatedly with some time in between), bulk, control, etc. I might be wrong though... + irq_state: Arc, } struct PortState { slot: u8, input_context: Dma, - ring: Ring, + dev_desc: scheme::DevDesc, + endpoint_states: BTreeMap, +} + +pub(crate) enum RingOrStreams { + Ring(Ring), + Streams(StreamContextArray), +} + +pub(crate) enum EndpointState { + Ready(RingOrStreams), + Init, +} +impl EndpointState { + fn ring(&mut self) -> Option<&mut Ring> { + match self { + Self::Ready(RingOrStreams::Ring(ring)) => Some(ring), + _ => None, + } + } } impl Xhci { @@ -202,6 +233,11 @@ impl Xhci { handles: BTreeMap::new(), next_handle: 0, port_states: BTreeMap::new(), + + irq_state: Arc::new(IrqState { + triggered: AtomicBool::new(false), + wakers: Mutex::new(Vec::new()), + }), }; xhci.init(max_slots); @@ -246,7 +282,7 @@ impl Xhci { // Set run/stop to 1 println!(" - Start"); - self.op.usb_cmd.writef(1, true); + self.op.usb_cmd.writef(1 | 1 << 2, true); // Wait until controller is running println!(" - Wait for running"); @@ -279,12 +315,21 @@ impl Xhci { slot } + pub fn slot_state(&self, slot: usize) -> u8 { + self.dev_ctx.contexts[slot].slot.state() + } + pub fn probe(&mut self) -> Result<()> { - for (i, port) in self.ports.iter().enumerate() { - let data = port.read(); - let state = port.state(); - let speed = port.speed(); - let flags = port.flags(); + for i in 0..self.ports.len() { + let (data, state, speed, flags) = { + let port = &self.ports[i]; + ( + port.read(), + port.state(), + port.speed(), + port.flags(), + ) + }; println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags); if flags.contains(port::PortFlags::PORT_CCS) { @@ -303,7 +348,7 @@ impl Xhci { let mut input = Dma::::zeroed()?; { - input.add_context.write(1 << 1 | 1); + input.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit). input.device.slot.a.write((1 << 27) | (speed << 20)); // FIXME: The speed field, bits 23:20, is deprecated. input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16); @@ -313,11 +358,6 @@ impl Xhci { let tr = ring.register(); input.device.endpoints[0].trh.write((tr >> 32) as u32); input.device.endpoints[0].trl.write(tr as u32); - - // TODO: I presume that there should be additional endpoint contexts, for the - // endpoints specified in the USB descriptors. Perhaps the specific USB drivers - // (HID drivers, mass storage drivers, etc.) should enable these endpoints - // themselves. } { @@ -331,73 +371,23 @@ impl Xhci { println!(" - Waiting for event"); } + if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::CommandCompletion as u8 { + panic!("ADDRESS DEVICE FAILED"); + } + cmd.reserved(false); event.reserved(false); } - self.run.ints[0].erdp.write(self.cmd.erdp()); + let dev_desc = Self::get_dev_desc_raw(&mut self.ports, &mut self.run, &mut self.cmd, &mut self.dbs, i, slot, &mut ring)?; - let mut dev = Device { - ring: &mut ring, - cmd: &mut self.cmd, - db: &mut self.dbs[slot as usize], - int: &mut self.run.ints[0], - }; - - println!(" - Get descriptor"); - - let ddesc = dev.get_device()?; - println!(" {:?}", ddesc); - - if ddesc.manufacturer_str > 0 { - println!(" Manufacturer: {}", dev.get_string(ddesc.manufacturer_str)?); - } - - if ddesc.product_str > 0 { - println!(" Product: {}", dev.get_string(ddesc.product_str)?); - } - - if ddesc.serial_str > 0 { - println!(" Serial: {}", dev.get_string(ddesc.serial_str)?); - } - - for config in 0..ddesc.configurations { - let (cdesc, data) = dev.get_config(config)?; - println!(" {}: {:?}", config, cdesc); - - if cdesc.configuration_str > 0 { - println!(" Name: {}", dev.get_string(cdesc.configuration_str)?); - } - - if cdesc.total_length as usize > mem::size_of::() { - let len = cdesc.total_length as usize - mem::size_of::(); - - let mut i = 0; - for interface in 0..cdesc.interfaces { - let mut idesc = usb::InterfaceDescriptor::default(); - if i < len && i < data.len() && idesc.copy_from_bytes(&data[i..len]).is_ok() { - i += mem::size_of_val(&idesc); - println!(" {}: {:?}", interface, idesc); - - if idesc.interface_str > 0 { - println!(" Name: {}", dev.get_string(idesc.interface_str)?); - } - - for endpoint in 0..idesc.endpoints { - let mut edesc = usb::EndpointDescriptor::default(); - if i < len && i < data.len() && edesc.copy_from_bytes(&data[i..len]).is_ok() { - i += mem::size_of_val(&edesc); - println!(" {}: {:?}", endpoint, edesc); - } - } - } - } - } - } self.port_states.insert(i, PortState { slot, input_context: input, - ring, + dev_desc, + endpoint_states: std::iter::once((0, EndpointState::Ready( + RingOrStreams::Ring(ring), + ))).collect::>(), }); } } @@ -405,13 +395,66 @@ impl Xhci { Ok(()) } - pub fn irq(&mut self) -> bool { + pub fn trigger_irq(&mut self) -> bool { + // Read the Interrupter Pending bit. + println!("preinterrupt"); if self.run.ints[0].iman.readf(1) { println!("XHCI Interrupt"); + + // If set, set it back to zero, so that new interrupts can be triggered. + // FIXME: MSI and MSI-X systems self.run.ints[0].iman.writef(1, true); + + // Wake all futures that await the IRQ. + for waker in self.irq_state.wakers.lock().unwrap().drain(..) { + waker.wake(); + } + true } else { false } } + pub(crate) fn irq(&self) -> IrqFuture { + IrqFuture { + state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state)) + } + } +} + +pub(crate) struct IrqFuture { state: IrqFutureState } + +struct IrqState { + triggered: AtomicBool, + // TODO: Perhaps a channel? + wakers: Mutex>, +} + +enum IrqFutureState { + Pending(Weak), + Finished, +} + +impl std::future::Future for IrqFuture { + type Output = (); + + fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { + let this = self.get_mut(); + + match &mut this.state { + // TODO: Ordering? + IrqFutureState::Pending(state_weak) => { + let state = state_weak.upgrade().expect("IRQ futures keep getting polled even after the driver has been deinitialized"); + + if state.triggered.load(atomic::Ordering::SeqCst) { + this.state = IrqFutureState::Finished; + task::Poll::Ready(()) + } else { + state.wakers.lock().unwrap().push(context.waker().clone()); + task::Poll::Pending + } + } + IrqFutureState::Finished => panic!("polling finished future"), + } + } } diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index 002be46506..3f3d6001ae 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -1,4 +1,4 @@ -use syscall::io::Mmio; +use syscall::io::{Mmio, Io}; #[repr(packed)] pub struct OperationalRegs { @@ -12,3 +12,14 @@ pub struct OperationalRegs { pub dcbaap: Mmio, pub config: Mmio, } + +pub const OP_CONFIG_CIE_BIT: u32 = 1 << 9; + +impl OperationalRegs { + fn cie(&self) -> bool { + self.config.readf(OP_CONFIG_CIE_BIT) + } + fn set_cie(&mut self, value: bool) { + self.config.writef(OP_CONFIG_CIE_BIT, value) + } +} diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index db4bf2e37a..5d936f00d2 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,4 +1,5 @@ use std::{cmp, mem, path, str}; +use std::convert::TryFrom; use std::io::prelude::*; use serde::{Serialize, Deserialize}; @@ -7,23 +8,28 @@ use smallvec::SmallVec; use syscall::io::{Dma, Io}; use syscall::scheme::SchemeMut; use syscall::{ - EACCES, EBADF, EBADMSG, EINVAL, EISDIR, ENOENT, ENOSYS, ENOTDIR, ENXIO, ESPIPE, - O_CREAT, O_DIRECTORY, O_STAT, - MODE_DIR, MODE_FILE, + EACCES, EBADF, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, ENOTDIR, ENXIO, ESPIPE, + O_CREAT, O_DIRECTORY, O_STAT, O_RDWR, O_RDONLY, O_WRONLY, + MODE_CHR, MODE_DIR, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET, Stat, Error, Result }; -use super::{Device, Xhci}; +use super::{Device, EndpointState, Xhci}; use super::{port, usb}; -use super::context::{ENDPOINT_CONTEXT_STATUS_MASK, InputContext}; + +use super::command::CommandRing; +use super::context::{ENDPOINT_CONTEXT_STATUS_MASK, InputContext, SlotState, StreamContextArray, StreamContext}; +use super::doorbell::Doorbell; +use super::operational::OperationalRegs; +use super::ring::Ring; +use super::runtime::RuntimeRegs; +use super::trb::{TransferKind, TrbCompletionCode, TrbType}; +use super::usb::endpoint::{ENDP_ATTR_TY_MASK, EndpointTy}; /// Subdirs of an endpoint -enum EndpointState { - /// `/portX/endpoints/Y/init`, used for a one-write-call initialization of an endpoint. - Init, - +pub enum EndpointHandleTy { /// portX/endpoints/Y/transfer. Write calls transfer data to the device, and read calls /// transfer data from the device. Transfer, @@ -40,55 +46,98 @@ pub enum Handle { Port(usize, usize, Vec), // port, offset, contents PortDesc(usize, usize, Vec), // port, offset, contents Endpoints(usize, usize, Vec), // port, offset, contents - Endpoint(usize, usize, EndpointState), // port, endpoint, offset, state + Endpoint(usize, u8, EndpointHandleTy), // port, endpoint, offset, state + ConfigureEndpoints(usize), // port } #[derive(Serialize)] -struct PortDesc { - // I have no idea whether this number is useful to the API users. - slot: u8, - dev_desc: DevDescJson, +struct PortDesc(DevDesc); + +// Even though these descriptors are originally intended for JSON, they should suffice.. + +#[derive(Clone, Debug, Serialize)] +pub(crate) struct DevDesc { + pub(crate) kind: u8, + pub(crate) usb: u16, + pub(crate) class: u8, + pub(crate) sub_class: u8, + pub(crate) protocol: u8, + pub(crate) packet_size: u8, + pub(crate) vendor: u16, + pub(crate) product: u16, + pub(crate) release: u16, + pub(crate) manufacturer_str: Option, + pub(crate) product_str: Option, + pub(crate) serial_str: Option, + pub(crate) config_descs: SmallVec<[ConfDesc; 1]>, } -#[derive(Serialize)] -struct DevDescJson { - // TODO: length? - kind: u8, - usb: u16, - class: u8, - sub_class: u8, - protocol: u8, - packet_size: u8, - vendor: u16, - product: u16, - release: u16, - manufacturer_str: Option, - product_str: Option, - serial_str: Option, - config_descs: SmallVec<[ConfDescJson; 1]>, +#[derive(Clone, Debug, Serialize)] +pub(crate) struct ConfDesc { + pub(crate) kind: u8, + pub(crate) configuration_value: u8, + pub(crate) configuration: Option, + pub(crate) attributes: u8, + pub(crate) max_power: u8, + pub(crate) interface_descs: SmallVec<[IfDesc; 1]>, } -#[derive(Serialize)] -struct ConfDescJson { - // TODO: length? - kind: u8, - // TODO: total_length? - // TODO: configuration_value? - configuration: Option, - attributes: u8, - max_power: u8, - interface_descs: SmallVec<[IfDescJson; 1]>, +#[derive(Clone, Copy, Debug, Serialize)] +pub(crate) struct EndpDesc { + pub(crate) kind: u8, + pub(crate) address: u8, + pub(crate) attributes: u8, + pub(crate) max_packet_size: u16, + pub(crate) interval: u8, + pub(crate) ssc: Option, } -#[derive(Serialize)] -struct EndpDescJson { - kind: u8, - address: u8, - attributes: u8, - max_packet_size: u16, - interval: u8, +enum EndpDirection { + Out, + In, + Bidirectional, } -impl From for EndpDescJson { + +impl EndpDesc { + fn ty(self) -> EndpointTy { + match self.attributes & ENDP_ATTR_TY_MASK { + 0 => EndpointTy::Ctrl, + 1 => EndpointTy::Interrupt, + 2 => EndpointTy::Bulk, + 3 => EndpointTy::Isoch, + _ => unreachable!(), + } + } + fn is_control(&self) -> bool { + self.ty() == EndpointTy::Ctrl + } + fn is_interrupt(&self) -> bool { + self.ty() == EndpointTy::Interrupt + } + fn is_bulk(&self) -> bool { + self.ty() == EndpointTy::Bulk + } + fn is_isoch(&self) -> bool { + self.ty() == EndpointTy::Isoch + } + fn direction(&self) -> EndpDirection { + if self.is_control() { return EndpDirection::Bidirectional } + if self.address & 0x80 != 0 { EndpDirection::In } else { EndpDirection::Out } + } + fn xhci_ep_type(&self) -> Result { + Ok(match self.direction() { + EndpDirection::Out if self.is_isoch() => 1, + EndpDirection::Out if self.is_bulk() => 2, + EndpDirection::Out if self.is_interrupt() => 3, + EndpDirection::Bidirectional if self.is_control() => 4, + EndpDirection::In if self.is_isoch() => 5, + EndpDirection::In if self.is_bulk() => 6, + EndpDirection::In if self.is_interrupt() => 7, + _ => return Err(Error::new(EINVAL)), + }) + } +} +impl From for EndpDesc { fn from(d: usb::EndpointDescriptor) -> Self { Self { kind: d.kind, @@ -96,24 +145,23 @@ impl From for EndpDescJson { attributes: d.attributes, interval: d.interval, max_packet_size: d.max_packet_size, + ssc: None, } } } - -#[derive(Serialize)] -struct IfDescJson { - // TODO: length? - kind: u8, - number: u8, - alternate_setting: u8, - class: u8, - sub_class: u8, - protocol: u8, - interface_str: Option, - endpoints: SmallVec<[AnyEndpDescJson; 4]>, +#[derive(Clone, Debug, Serialize)] +pub(crate) struct IfDesc { + pub(crate) kind: u8, + pub(crate) number: u8, + pub(crate) alternate_setting: u8, + pub(crate) class: u8, + pub(crate) sub_class: u8, + pub(crate) protocol: u8, + pub(crate) interface_str: Option, + pub(crate) endpoints: SmallVec<[EndpDesc; 4]>, } -impl IfDescJson { - fn new(dev: &mut Device, desc: usb::InterfaceDescriptor, endps: impl IntoIterator) -> Result { +impl IfDesc { + fn new(dev: &mut Device, desc: usb::InterfaceDescriptor, endps: impl IntoIterator) -> Result { Ok(Self { alternate_setting: desc.alternate_setting, class: desc.class, @@ -127,15 +175,15 @@ impl IfDescJson { } } -#[derive(Serialize)] -struct SuperSpeedCmpJson { - kind: u8, - max_burst: u8, - attributes: u8, - bytes_per_interval: u16, +#[derive(Clone, Copy, Debug, Serialize)] +pub(crate) struct SuperSpeedCmp { + pub(crate) kind: u8, + pub(crate) max_burst: u8, + pub(crate) attributes: u8, + pub(crate) bytes_per_interval: u16, } -impl From for SuperSpeedCmpJson { +impl From for SuperSpeedCmp { fn from(d: usb::SuperSpeedCompanionDescriptor) -> Self { Self { kind: d.kind, @@ -146,19 +194,6 @@ impl From for SuperSpeedCmpJson { } } -enum AnyEndpDescJson { - Endp(EndpDescJson), - SuperSpeedCmp(SuperSpeedCmpJson), -} -impl serde::Serialize for AnyEndpDescJson { - fn serialize(&self, serializer: S) -> std::result::Result { - match self { - Self::Endp(e) => e.serialize(serializer), - Self::SuperSpeedCmp(c) => c.serialize(serializer), - } - } -} - /// Any descriptor that can be stored in the config desc "data" area. #[derive(Debug)] enum AnyDescriptor { @@ -194,41 +229,218 @@ impl AnyDescriptor { } #[derive(Deserialize)] -struct InitEndpointReqJson { - index: u8, +struct ConfigureEndpointsJson { + /// Index into the configuration descriptors of the device descriptor. + config_desc: usize, + + // TODO: Support multiple interfaces as well. } impl Xhci { - fn init_endpoint(&mut self, buf: &[u8]) -> Result<()> { - let req: InitEndpointReqJson = serde_json::from_slice(buf).or(Err(Error::new(EBADMSG)))?; - let input_context = Dma::::zeroed()?; + fn set_configuration(&mut self, port: usize, config: u16) -> Result<()> { + let ps = self.port_states.get_mut(&port).ok_or(Error::new(EIO))?; + let ring = ps.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().ok_or(Error::new(EIO))?; - // Endpoint zero is the control endpoint, which is always enabled. - if !(1..=31).contains(&req.index) { return Err(Error::new(EINVAL)) } + { + let (cmd, cycle) = ring.next(); + cmd.setup( + usb::Setup::set_configuration(config), + TransferKind::NoData, cycle, + ); + } + { + let (cmd, cycle) = ring.next(); + cmd.status(false, cycle); + } + self.dbs[ps.slot as usize].write(1); - input_context.add_context.write(1 << req.index); - // FIXME: A port string is required - //input_context.device.slot. + { + let event = self.cmd.next_event(); + while event.data.read() == 0 { + println!(" - Waiting for event"); + } + let status = event.status.read(); + let control = event.control.read(); + + if (status >> 24) != TrbCompletionCode::Success as u32 { + println!("SET_CONFIGURATION ERROR, COMPLETION CODE {:#0x}", (status >> 24)); + } + + println!("SET_CONFIGURATION EVENT {:#0x} {:#0x} {:#0x}", event.data.read(), status, control); + } + + self.run.ints[0].erdp.write(self.cmd.erdp()); Ok(()) } - fn write_port_desc(&mut self, port_id: usize, contents: &mut Vec) -> Result<()> { - let port = self.ports.get(port_id).ok_or(Error::new(ENOENT))?; + + fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { + + let req: ConfigureEndpointsJson = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; + + let port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; + let input_context: &mut Dma = &mut port_state.input_context; + + // Configure the slot context as well, which holds the last index of the endp descs. + input_context.add_context.write(1); + input_context.drop_context.write(0); + + const CONTEXT_ENTRIES_MASK: u32 = 0xF800_0000; + const CONTEXT_ENTRIES_SHIFT: u8 = 27; + + let current_slot_a = input_context.device.slot.a.read(); + let current_context_entries = ((current_slot_a & CONTEXT_ENTRIES_MASK) >> CONTEXT_ENTRIES_SHIFT) as u8; + + let endpoints = &port_state.dev_desc.config_descs[req.config_desc].interface_descs[0].endpoints; + + if endpoints.len() >= 31 { + return Err(Error::new(EIO)); + } + + let new_context_entries = 1 + endpoints.len() as u32; + + input_context.device.slot.a.write((current_slot_a & !CONTEXT_ENTRIES_MASK) | ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT) & CONTEXT_ENTRIES_MASK)); + + let lec = self.cap.lec(); + + for index in 0..endpoints.len() as u8 { + let endp_num = index + 1; + + input_context.add_context.writef(1 << (endp_num + 1), true); + + let endp_ctx = input_context.device.endpoints.get_mut(endp_num as usize).ok_or(Error::new(EIO))?; + let endp_desc = endpoints.get(index as usize).ok_or(Error::new(EIO))?; + + let superspeed_companion = endp_desc.ssc; + + + // TODO: Check if streams are actually supported. + let max_streams = superspeed_companion.map(|ssc| if endp_desc.is_bulk() { 1 << (ssc.attributes & 0x1F) } else { 0 }).unwrap_or(0); + let max_psa_size = self.cap.max_psa_size(); + + // TODO: Secondary streams. + let primary_streams = if max_streams != 0 { cmp::min(max_streams, max_psa_size) } else { 0 }; + let linear_stream_array = if primary_streams != 0 { true } else { false }; + + // TODO: Interval related fields + // TODO: Max ESIT payload size. + + // TODO: The max burst size is non-zero for high-speed isoch endpoints. How are the USB2 + // speeds detected? + // I presume that USB 3 devices can never be in low/full/high-speed mode, but + // always SuperSpeed (gen 1 and 2 etc.). + + let max_burst_size = superspeed_companion.map(|ssc| ssc.max_burst).unwrap_or(0); + let max_packet_size = endp_desc.max_packet_size; + + let mult = if !lec && endp_desc.is_isoch() { + if let Some(ssc) = superspeed_companion { + ssc.attributes & 0x3 + } else { + 0 + } + } else { + 0 + }; + + let interval = endp_desc.interval; + let max_error_count = 3; + let ep_ty = endp_desc.xhci_ep_type()?; + let host_initiate_disable = false; + + // TODO: Maybe this value is out of scope for xhcid, because the actual usb device + // driver probably knows better. The spec says that the initial value should be 8 bytes + // for control, 1KiB for interrupt and 3KiB for bulk and isoch. + let avg_trb_len: u16 = match endp_desc.ty() { + EndpointTy::Ctrl => return Err(Error::new(EIO)), // only endpoint zero is of type control, and is configured separately with the address device command. + EndpointTy::Bulk | EndpointTy::Isoch => 3072, // 3 KiB + EndpointTy::Interrupt => 1024, // 1 KiB + }; + + assert_eq!(ep_ty & 0x7, ep_ty); + assert_eq!(mult & 0x3, mult); + assert_eq!(max_error_count & 0x3, max_error_count); + + assert_ne!(ep_ty, 0); // 0 means invalid. + + let ring_ptr = if max_streams != 0 { + let array = StreamContextArray::new(1 << (max_streams + 1))?; + let array_ptr = array.register(); + + assert_eq!(array_ptr & 0xFFFF_FFFF_FFFF_FF81, array_ptr, "stream ctx ptr not aligned to 16 bytes"); + + port_state.endpoint_states.insert(endp_num, EndpointState::Ready(super::RingOrStreams::Streams(array))); + + array_ptr + } else { + let ring = Ring::new(true)?; + let ring_ptr = ring.register(); + + assert_eq!(ring_ptr & 0xFFFF_FFFF_FFFF_FF81, ring_ptr, "ring pointer not aligned to 16 bytes"); + + port_state.endpoint_states.insert(endp_num, EndpointState::Ready(super::RingOrStreams::Ring(ring))); + + ring_ptr + }; + + assert_eq!(primary_streams & 0x1F, primary_streams); + + endp_ctx.a.write(u32::from(mult) << 8 | u32::from(interval) << 16 | u32::from(primary_streams) << 10 | u32::from(linear_stream_array) << 15); + endp_ctx.b.write(max_error_count << 1 | u32::from(ep_ty) << 3 | u32::from(host_initiate_disable) << 7 | u32::from(max_burst_size) << 8 | u32::from(max_packet_size) << 16); + endp_ctx.trl.write(ring_ptr as u32); + endp_ctx.trh.write((ring_ptr >> 32) as u32); + endp_ctx.c.write(u32::from(avg_trb_len)); + } + + input_context.dump_control(); + + self.run.ints[0].erdp.write(self.cmd.erdp()); + + { + let (cmd, cycle, event) = self.cmd.next(); + cmd.configure_endpoint(port_state.slot, input_context.physical(), cycle); + + self.dbs[0].write(0); + + while event.data.read() == 0 { + println!(" - Waiting for event"); + } + + if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::CommandCompletion as u8 { + println!("CONFIGURE_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); + return Err(Error::new(EIO)); + } + + cmd.reserved(false); + event.reserved(false); + } + + // Tell the device about this configuration. + + let configuration_value = port_state.dev_desc.config_descs.get(req.config_desc).ok_or(Error::new(EIO))?.configuration_value; + self.set_configuration(port, configuration_value.into())?; + + Ok(()) + } + pub(crate) fn get_dev_desc(&mut self, port_id: usize) -> Result { + let st = self.port_states.get_mut(&port_id).ok_or(Error::new(ENOENT))?; + Self::get_dev_desc_raw(&mut self.ports, &mut self.run, &mut self.cmd, &mut self.dbs, port_id, st.slot, st.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().ok_or(Error::new(EIO))?) + } + pub(crate) fn get_dev_desc_raw(ports: &mut [port::Port], run: &mut RuntimeRegs, cmd: &mut CommandRing, dbs: &mut [Doorbell], port_id: usize, slot: u8, ring: &mut Ring) -> Result { + let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); } - let st = self.port_states.get_mut(&port_id).unwrap(); - // TODO: Should the descriptors be stored in PortState? - self.run.ints[0].erdp.write(self.cmd.erdp()); + run.ints[0].erdp.write(cmd.erdp()); let mut dev = Device { - ring: &mut st.ring, - cmd: &mut self.cmd, - db: &mut self.dbs[st.slot as usize], - int: &mut self.run.ints[0], + ring, + cmd, + db: &mut dbs[slot as usize], + int: &mut run.ints[0], }; let raw_dd = dev.get_device()?; @@ -246,16 +458,9 @@ impl Xhci { ); let (bos_desc, bos_data) = dev.get_bos()?; - writeln!(contents, "BOS BASE {:?}", bos_desc).unwrap(); - - let has_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).inspect(|item| println!("{:?}", item)).any(|desc| desc.is_superspeed()); + let has_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); let config_descs = (0..raw_dd.configurations).map(|index| -> Result<_> { - // TODO: Actually, it seems like all descriptors contain a length field, and I - // encountered a SuperSpeed descriptor when endpoints were expected. The right way - // would probably be to have an enum of all possible descs, and sort them based on - // location, even though they might not necessarily be ordered trivially. - let (desc, data) = dev.get_config(index)?; let extra_length = desc.total_length as usize - mem::size_of_val(&desc); @@ -274,41 +479,43 @@ impl Xhci { while let Some(item) = iter.next() { if let AnyDescriptor::Interface(idesc) = item { - let mut endpoints = SmallVec::<[AnyEndpDescJson; 4]>::new(); + let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); for _ in 0..idesc.endpoints { let next = match iter.next() { Some(AnyDescriptor::Endpoint(n)) => n, _ => break, }; - endpoints.push(AnyEndpDescJson::Endp(EndpDescJson::from(next))); + let mut endp = EndpDesc::from(next); if has_superspeed { let next = match iter.next() { Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, _ => break, }; - endpoints.push(AnyEndpDescJson::SuperSpeedCmp(SuperSpeedCmpJson::from(next))); + endp.ssc = Some(SuperSpeedCmp::from(next)); } + endpoints.push(endp); } - interface_descs.push(IfDescJson::new(&mut dev, idesc, endpoints)?); + interface_descs.push(IfDesc::new(&mut dev, idesc, endpoints)?); } else { // TODO break; } } - Ok(ConfDescJson { + Ok(ConfDesc { kind: desc.kind, configuration: if desc.configuration_str > 0 { Some(dev.get_string(desc.configuration_str)?) } else { None }, + configuration_value: desc.configuration_value, attributes: desc.attributes, max_power: desc.max_power, interface_descs, }) }).collect::>>()?; - let dev_desc = DevDescJson { + Ok(DevDesc { kind: raw_dd.kind, usb: raw_dd.usb, class: raw_dd.class, @@ -322,15 +529,11 @@ impl Xhci { product_str, serial_str, config_descs, - }; - - let desc = PortDesc { - slot: st.slot, - dev_desc, - }; - - serde_json::to_writer_pretty(contents, &desc).unwrap(); - + }) + } + fn write_port_desc(&mut self, port_id: usize, contents: &mut Vec) -> Result<()> { + let dev_desc = &self.port_states.get(&port_id).ok_or(Error::new(ENOENT))?.dev_desc; + serde_json::to_writer_pretty(contents, dev_desc).unwrap(); Ok(()) } } @@ -338,7 +541,6 @@ impl Xhci { impl SchemeMut for Xhci { fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if uid != 0 { return Err(Error::new(EACCES)) } - if flags & O_CREAT != 0 { return Err(Error::new(EINVAL) ) } let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_start_matches('/'); @@ -361,6 +563,18 @@ impl SchemeMut for Xhci { } else { return Err(Error::new(EISDIR)); } + &[port, "configure"] if port.starts_with("port") => { + let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; + + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(ENOTDIR)); + } + if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { + return Err(Error::new(EACCES)); + } + + Handle::ConfigureEndpoints(port_num) + } &[port, "descriptors"] if port.starts_with("port") => { let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; @@ -382,7 +596,11 @@ impl SchemeMut for Xhci { let mut contents = Vec::new(); let ps = self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?; - for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { + /*for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { + write!(contents, "{}\n", ep_num).unwrap(); + }*/ + + for ep_num in ps.endpoint_states.keys() { write!(contents, "{}\n", ep_num).unwrap(); } @@ -390,31 +608,43 @@ impl SchemeMut for Xhci { } &[port, "endpoints", endpoint_num_str] if port.starts_with("port") => { let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; - let endpoint_num = endpoint_num_str.parse::().or(Err(Error::new(ENOENT)))?; + let endpoint_num = endpoint_num_str.parse::().or(Err(Error::new(ENOENT)))?; if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { return Err(Error::new(EISDIR)); } - if flags & O_CREAT != 0 { - Handle::Endpoint(port_num, endpoint_num, EndpointState::Init) - } else { - if self.dev_ctx.contexts[self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?.slot as usize].endpoints.get(endpoint_num).ok_or(Error::new(ENOENT))?.a.read() & 0b111 != 1 { - return Err(Error::new(ENXIO)); // TODO: Find a proper error code for "endpoint not initialized". - } - let contents = b"transfer\nstatus"[..].to_owned(); - Handle::Endpoint(port_num, endpoint_num, EndpointState::Root(0, contents)) - } + let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(ENOENT))?; + + /*if self.dev_ctx.contexts[port_state.slot as usize].endpoints.get(endpoint_num as usize).ok_or(Error::new(ENOENT))?.a.read() & 0b111 != 1 { + return Err(Error::new(ENXIO)); // TODO: Find a proper error code for "endpoint not initialized". + }*/ + let contents = match port_state.endpoint_states.get(&endpoint_num).ok_or(Error::new(ENOENT))? { + EndpointState::Init => "status\n", + EndpointState::Ready { .. } => "transfer\nstatus\n", + }.as_bytes().to_owned(); + + Handle::Endpoint(port_num, endpoint_num, EndpointHandleTy::Root(0, contents)) } &[port, "endpoints", endpoint_num_str, sub] if port.starts_with("port") => { let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; - let endpoint_num = endpoint_num_str.parse::().or(Err(Error::new(ENOENT)))?; + let endpoint_num = endpoint_num_str.parse::().or(Err(Error::new(ENOENT)))?; if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { return Err(Error::new(EISDIR)) } + if self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?.endpoint_states.get(&endpoint_num).is_none() { + return Err(Error::new(ENOENT)); + } + let st = match sub { - "status" => EndpointState::Status(0), - "transfer" => EndpointState::Transfer, + "status" => { + // status is read-only + if flags & O_RDWR != O_RDONLY && flags & O_STAT == 0 { + return Err(Error::new(EACCES)); + } + EndpointHandleTy::Status(0) + } + "transfer" => EndpointHandleTy::Transfer, _ => return Err(Error::new(ENOENT)), }; Handle::Endpoint(port_num, endpoint_num, st) @@ -424,6 +654,10 @@ impl SchemeMut for Xhci { let mut contents = Vec::new(); write!(contents, "descriptors\nendpoints\n").unwrap(); + + if dbg!(self.slot_state(self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?.slot as usize)) != SlotState::Configured as u8 { + write!(contents, "configure\n").unwrap(); + } Handle::Port(port_num, 0, contents) } else { @@ -442,7 +676,6 @@ impl SchemeMut for Xhci { fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { match self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::TopLevel(_, ref buf) | Handle::Port(_, _, ref buf) | Handle::Endpoints(_, _, ref buf) => { - // TODO: Known size perhaps? stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; } @@ -451,9 +684,13 @@ impl SchemeMut for Xhci { stat.st_size = buf.len() as u64; } Handle::Endpoint(_, _, st) => match st { - EndpointState::Init | EndpointState::Status(_) | EndpointState::Transfer => stat.st_mode = MODE_FILE, - EndpointState::Root(_, _) => stat.st_mode = MODE_DIR, + EndpointHandleTy::Status(_) | EndpointHandleTy::Transfer => stat.st_mode = MODE_CHR, + EndpointHandleTy::Root(_, ref buf) => { + stat.st_mode = MODE_DIR; + stat.st_size = buf.len() as u64; + } } + Handle::ConfigureEndpoints(_) => stat.st_mode = MODE_CHR, } Ok(0) } @@ -467,11 +704,11 @@ impl SchemeMut for Xhci { Handle::PortDesc(port_num, _, _) => write!(src, "/port{}/descriptors", port_num).unwrap(), Handle::Endpoints(port_num, _, _) => write!(src, "/port{}/endpoints/", port_num).unwrap(), Handle::Endpoint(port_num, endp_num, st) => write!(src, "/port{}/endpoints/{}/{}", port_num, endp_num, match st { - EndpointState::Init => "init", - EndpointState::Root(_, _) => "", - EndpointState::Status(_) => "status", - EndpointState::Transfer => "transfer", + EndpointHandleTy::Root(_, _) => "", + EndpointHandleTy::Status(_) => "status", + EndpointHandleTy::Transfer => "transfer", }).unwrap(), + Handle::ConfigureEndpoints(port_num) => write!(src, "/port{}/configure", port_num).unwrap(), } let bytes_to_read = cmp::min(src.len(), buffer.len()); buffer[..bytes_to_read].copy_from_slice(&src[..bytes_to_read]); @@ -480,7 +717,7 @@ impl SchemeMut for Xhci { fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) | Handle::Endpoints(_, ref mut offset, ref buf) | Handle::Endpoint(_, _, EndpointState::Root(ref mut offset, ref buf)) => { + Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) | Handle::Endpoints(_, ref mut offset, ref buf) | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref buf)) => { *offset = match whence { SEEK_SET => cmp::max(0, cmp::min(pos, buf.len())), SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, buf.len())), @@ -489,13 +726,22 @@ impl SchemeMut for Xhci { }; Ok(*offset) } - Handle::Endpoint(_, _, _) => return Err(Error::new(ESPIPE)), + Handle::Endpoint(_, _, EndpointHandleTy::Status(ref mut offset)) => { + *offset = match whence { + SEEK_SET => cmp::max(0, pos), + SEEK_CUR => cmp::max(0, *offset + pos), + SEEK_END => return Err(Error::new(ESPIPE)), + _ => return Err(Error::new(EINVAL)), + }; + Ok(*offset) + } + Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) => return Err(Error::new(ESPIPE)), } } fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) | Handle::Endpoints(_, ref mut offset, ref src_buf) | Handle::Endpoint(_, _, EndpointState::Root(ref mut offset, ref src_buf)) => { + Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) | Handle::Endpoints(_, ref mut offset, ref src_buf) | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref src_buf)) => { let max_bytes_to_read = cmp::min(src_buf.len(), buf.len()); let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset; @@ -504,11 +750,11 @@ impl SchemeMut for Xhci { Ok(bytes_to_read) } + Handle::ConfigureEndpoints(_) => return Err(Error::new(EBADF)), &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { - EndpointState::Init => return Err(Error::new(EINVAL)), - EndpointState::Transfer => unimplemented!(), - EndpointState::Status(ref mut offset) => { - let status = self.dev_ctx.contexts.get(port_num).ok_or(Error::new(EBADF))?.endpoints.get(endp_num).ok_or(Error::new(EBADF))?.a.read() & ENDPOINT_CONTEXT_STATUS_MASK; + EndpointHandleTy::Transfer => return Err(Error::new(ENOSYS)), + EndpointHandleTy::Status(ref mut offset) => { + let status = self.dev_ctx.contexts.get(port_num).ok_or(Error::new(EBADF))?.endpoints.get(endp_num as usize).ok_or(Error::new(EBADF))?.a.read() & ENDPOINT_CONTEXT_STATUS_MASK; let string = match status { // TODO: Give this its own enum. @@ -528,18 +774,18 @@ impl SchemeMut for Xhci { Ok(bytes_to_read) } - EndpointState::Root(_, _) => unreachable!(), + EndpointHandleTy::Root(_, _) => unreachable!(), }, } } fn write(&mut self, fd: usize, buf: &[u8]) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Endpoint(_, _, EndpointState::Init) => { - self.init_endpoint(buf)?; + match self.handles.get(&fd).ok_or(Error::new(EBADF))? { + &Handle::ConfigureEndpoints(port_num) => { + self.configure_endpoints(port_num, buf)?; Ok(buf.len()) - }; - Handle::Endpoint(_, _, EndpointState::Transfer) => unimplemented!(), - _ => return Err(Error::new(EINVAL)), + } + Handle::Endpoint(_, _, EndpointHandleTy::Transfer) => return Err(Error::new(ENOSYS)), + _ => return Err(Error::new(EBADF)), } } fn close(&mut self, fd: usize) -> Result { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 49db6e5115..53cf648a6a 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -110,6 +110,15 @@ pub struct Trb { pub control: Mmio, } +pub const TRB_STATUS_COMPLETION_CODE_SHIFT: u8 = 24; +pub const TRB_STATUS_COMPLETION_CODE_MASK: u32 = 0xFF00_0000; + +pub const TRB_STATUS_COMPLETION_PARAM_SHIFT: u8 = 0; +pub const TRB_STATUS_COMPLETION_PARAM_MASK: u32 = 0x00FF_FFFF; + +pub const TRB_CONTROL_TRB_TYPE_SHIFT: u8 = 10; +pub const TRB_CONTROL_TRB_TYPE_MASK: u32 = 0x0000_FC00; + impl Trb { pub fn set(&mut self, data: u64, status: u32, control: u32) { self.data.write(data); @@ -126,6 +135,16 @@ impl Trb { ); } + pub fn completion_code(&self) -> u8 { + (self.status.read() >> TRB_STATUS_COMPLETION_CODE_SHIFT) as u8 + } + pub fn completion_param(&self) -> u32 { + self.status.read() & TRB_STATUS_COMPLETION_PARAM_MASK + } + pub fn trb_type(&self) -> u8 { + ((self.control.read() & TRB_CONTROL_TRB_TYPE_MASK) >> TRB_CONTROL_TRB_TYPE_SHIFT) as u8 + } + pub fn link(&mut self, address: usize, toggle: bool, cycle: bool) { self.set( address as u64, @@ -164,12 +183,12 @@ impl Trb { (cycle as u32) ); } - // Synchronizes the input context endpoints with the device context endpoints, it think. + // Synchronizes the input context endpoints with the device context endpoints, I think. pub fn configure_endpoint(&mut self, slot_id: u8, input_ctx_ptr: usize, cycle: bool) { - assert_eq!(input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0, input_ctx_ptr); + assert_eq!(input_ctx_ptr & 0xFFFF_FFFF_FFFF_FF80, input_ctx_ptr, "unaligned input context ptr"); self.set( - (input_ctx_ptr >> 4) as u64, + input_ctx_ptr as u64, 0, (u32::from(slot_id) << 24) | ((TrbType::ConfigureEndpoint as u32) << 10) | From 295aa02e5db36f6c4e7db67bcae67bf699cd937b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 1 Feb 2020 18:20:24 +0100 Subject: [PATCH 0319/1301] Support reading the slot state. --- xhcid/src/xhci/scheme.rs | 142 ++++++++++++++++++++++++++------------- 1 file changed, 96 insertions(+), 46 deletions(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 5d936f00d2..ee57ec76ea 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -45,6 +45,7 @@ pub enum Handle { TopLevel(usize, Vec), // offset, contents (ports) Port(usize, usize, Vec), // port, offset, contents PortDesc(usize, usize, Vec), // port, offset, contents + PortState(usize, usize), // port, offset Endpoints(usize, usize, Vec), // port, offset, contents Endpoint(usize, u8, EndpointHandleTy), // port, endpoint, offset, state ConfigureEndpoints(usize), // port @@ -422,6 +423,12 @@ impl Xhci { Ok(()) } + fn transfer_read(&mut self, port_num: usize, endp_num: u8, buf: &mut [u8]) -> Result<()> { + Err(Error::new(ENOSYS)) + } + fn transfer_write(&mut self, port_num: usize, endp_num: u8, buf: &[u8]) -> Result<()> { + Err(Error::new(ENOSYS)) + } pub(crate) fn get_dev_desc(&mut self, port_id: usize) -> Result { let st = self.port_states.get_mut(&port_id).ok_or(Error::new(ENOENT))?; Self::get_dev_desc_raw(&mut self.ports, &mut self.run, &mut self.cmd, &mut self.dbs, port_id, st.slot, st.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().ok_or(Error::new(EIO))?) @@ -536,6 +543,15 @@ impl Xhci { serde_json::to_writer_pretty(contents, dev_desc).unwrap(); Ok(()) } + fn write_dyn_string(string: &[u8], buf: &mut [u8], offset: &mut usize) -> usize { + let max_bytes_to_read = cmp::min(string.len(), buf.len()); + let bytes_to_read = cmp::max(*offset, max_bytes_to_read) - *offset; + buf[..bytes_to_read].copy_from_slice(&string[..bytes_to_read]); + + *offset += bytes_to_read; + + bytes_to_read + } } impl SchemeMut for Xhci { @@ -563,48 +579,60 @@ impl SchemeMut for Xhci { } else { return Err(Error::new(EISDIR)); } - &[port, "configure"] if port.starts_with("port") => { + &[port, port_tl] if port.starts_with("port") => { let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; - - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { - return Err(Error::new(EACCES)); + if !self.port_states.contains_key(&port_num) { + return Err(Error::new(ENOENT)); } - Handle::ConfigureEndpoints(port_num) - } - &[port, "descriptors"] if port.starts_with("port") => { - let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; + match port_tl { + "descriptors" => { + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(ENOTDIR)); + } - if flags & O_DIRECTORY != 0 { - return Err(Error::new(ENOTDIR)); + let mut contents = Vec::new(); + self.write_port_desc(port_num, &mut contents)?; + + Handle::PortDesc(port_num, 0, contents) + } + "configure" => { + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(ENOTDIR)); + } + if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { + return Err(Error::new(EACCES)); + } + + Handle::ConfigureEndpoints(port_num) + } + "state" => { + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(ENOTDIR)); + } + + Handle::PortState(port_num, 0) + } + "endpoints" => { + if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { + return Err(Error::new(EISDIR)); + }; + let mut contents = Vec::new(); + let ps = self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?; + + /*for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { + write!(contents, "{}\n", ep_num).unwrap(); + }*/ + + for ep_num in ps.endpoint_states.keys() { + write!(contents, "{}\n", ep_num).unwrap(); + } + + Handle::Endpoints(port_num, 0, contents) + } + _ => return Err(Error::new(ENOENT)), } - let mut contents = Vec::new(); - self.write_port_desc(port_num, &mut contents)?; - - Handle::PortDesc(port_num, 0, contents) - } - &[port, "endpoints"] if port.starts_with("port") => { - let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; - - if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { - return Err(Error::new(EISDIR)); - }; - let mut contents = Vec::new(); - let ps = self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?; - - /*for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { - write!(contents, "{}\n", ep_num).unwrap(); - }*/ - - for ep_num in ps.endpoint_states.keys() { - write!(contents, "{}\n", ep_num).unwrap(); - } - - Handle::Endpoints(port_num, 0, contents) } &[port, "endpoints", endpoint_num_str] if port.starts_with("port") => { let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; @@ -683,6 +711,7 @@ impl SchemeMut for Xhci { stat.st_mode = MODE_FILE; stat.st_size = buf.len() as u64; } + Handle::PortState(_, _) => stat.st_mode = MODE_CHR, Handle::Endpoint(_, _, st) => match st { EndpointHandleTy::Status(_) | EndpointHandleTy::Transfer => stat.st_mode = MODE_CHR, EndpointHandleTy::Root(_, ref buf) => { @@ -702,6 +731,7 @@ impl SchemeMut for Xhci { Handle::TopLevel(_, _) => write!(src, "/").unwrap(), Handle::Port(port_num, _, _) => write!(src, "/port{}/", port_num).unwrap(), Handle::PortDesc(port_num, _, _) => write!(src, "/port{}/descriptors", port_num).unwrap(), + Handle::PortState(port_num, _) => write!(src, "/port{}/state", port_num).unwrap(), Handle::Endpoints(port_num, _, _) => write!(src, "/port{}/endpoints/", port_num).unwrap(), Handle::Endpoint(port_num, endp_num, st) => write!(src, "/port{}/endpoints/{}/{}", port_num, endp_num, match st { EndpointHandleTy::Root(_, _) => "", @@ -717,6 +747,7 @@ impl SchemeMut for Xhci { fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + // Directories, or fixed files Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) | Handle::Endpoints(_, ref mut offset, ref buf) | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref buf)) => { *offset = match whence { SEEK_SET => cmp::max(0, cmp::min(pos, buf.len())), @@ -726,7 +757,8 @@ impl SchemeMut for Xhci { }; Ok(*offset) } - Handle::Endpoint(_, _, EndpointHandleTy::Status(ref mut offset)) => { + // Read-only unknown-length status strings + Handle::Endpoint(_, _, EndpointHandleTy::Status(ref mut offset)) | Handle::PortState(_, ref mut offset) => { *offset = match whence { SEEK_SET => cmp::max(0, pos), SEEK_CUR => cmp::max(0, *offset + pos), @@ -735,6 +767,7 @@ impl SchemeMut for Xhci { }; Ok(*offset) } + // Write-once configure or transfer Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) => return Err(Error::new(ESPIPE)), } } @@ -752,7 +785,12 @@ impl SchemeMut for Xhci { } Handle::ConfigureEndpoints(_) => return Err(Error::new(EBADF)), &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { - EndpointHandleTy::Transfer => return Err(Error::new(ENOSYS)), + EndpointHandleTy::Transfer => { + self.transfer_read(port_num, endp_num, buf)?; + // TODO: Perhaps transfers with large buffers could be broken up a to smaller + // transfers. + Ok(buf.len()) + } EndpointHandleTy::Status(ref mut offset) => { let status = self.dev_ctx.contexts.get(port_num).ok_or(Error::new(EBADF))?.endpoints.get(endp_num as usize).ok_or(Error::new(EBADF))?.a.read() & ENDPOINT_CONTEXT_STATUS_MASK; @@ -766,16 +804,24 @@ impl SchemeMut for Xhci { _ => "unknown", }.as_bytes(); - let max_bytes_to_read = cmp::min(string.len(), buf.len()); - let bytes_to_read = cmp::max(*offset, max_bytes_to_read) - *offset; - buf[..bytes_to_read].copy_from_slice(&string[..bytes_to_read]); - - *offset += bytes_to_read; - - Ok(bytes_to_read) + Ok(Self::write_dyn_string(string, buf, offset)) } EndpointHandleTy::Root(_, _) => unreachable!(), }, + &mut Handle::PortState(port_num, ref mut offset) => { + let state = self.dev_ctx.contexts.get(port_num).ok_or(Error::new(EBADF))?.slot.state(); + + let string = match state { + // TODO: Give this its own enum. + 0 => "enabled_or_disabled", // Maybe "enabled/disabled"? + 1 => "default", + 2 => "addressed", + 3 => "configured", + _ => "unknown", + }.as_bytes(); + + Ok(Self::write_dyn_string(string, buf, offset)) + } } } fn write(&mut self, fd: usize, buf: &[u8]) -> Result { @@ -784,7 +830,11 @@ impl SchemeMut for Xhci { self.configure_endpoints(port_num, buf)?; Ok(buf.len()) } - Handle::Endpoint(_, _, EndpointHandleTy::Transfer) => return Err(Error::new(ENOSYS)), + &Handle::Endpoint(port_num, endp_num, EndpointHandleTy::Transfer) => { + self.transfer_write(port_num, endp_num, buf)?; + // TODO + Ok(buf.len()) + } _ => return Err(Error::new(EBADF)), } } From c4a393e2963fcc9b4443723b43e002c2571d3cc1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 1 Feb 2020 22:02:20 +0100 Subject: [PATCH 0320/1301] Correctly index the dev ctx arr for slot states. --- xhcid/src/xhci/mod.rs | 2 +- xhcid/src/xhci/scheme.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index cb817769ae..a1b9229859 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -337,7 +337,7 @@ impl Xhci { println!(" - Enable slot"); - self.run.ints[0].erdp.write(self.cmd.erdp()); // TODO: ? + self.run.ints[0].erdp.write(self.cmd.erdp()); let slot = Self::enable_port_slot(&mut self.cmd, &mut self.dbs); diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index ee57ec76ea..324998af8f 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -792,7 +792,8 @@ impl SchemeMut for Xhci { Ok(buf.len()) } EndpointHandleTy::Status(ref mut offset) => { - let status = self.dev_ctx.contexts.get(port_num).ok_or(Error::new(EBADF))?.endpoints.get(endp_num as usize).ok_or(Error::new(EBADF))?.a.read() & ENDPOINT_CONTEXT_STATUS_MASK; + let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?; + let status = self.dev_ctx.contexts.get(ps.slot as usize).ok_or(Error::new(EBADF))?.endpoints.get(endp_num as usize).ok_or(Error::new(EBADF))?.a.read() & ENDPOINT_CONTEXT_STATUS_MASK; let string = match status { // TODO: Give this its own enum. From d66b0c5bd8ad354e6b9421f0d191b67d25771463 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 1 Feb 2020 23:28:19 +0100 Subject: [PATCH 0321/1301] Fix the state virtual file. --- xhcid/src/xhci/scheme.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 324998af8f..560470984d 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -810,7 +810,8 @@ impl SchemeMut for Xhci { EndpointHandleTy::Root(_, _) => unreachable!(), }, &mut Handle::PortState(port_num, ref mut offset) => { - let state = self.dev_ctx.contexts.get(port_num).ok_or(Error::new(EBADF))?.slot.state(); + let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?; + let state = self.dev_ctx.contexts.get(ps.slot as usize).ok_or(Error::new(EBADF))?.slot.state(); let string = match state { // TODO: Give this its own enum. From d4f1480d1b1706f537052aa8b3025a063d3e4d21 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 2 Feb 2020 10:00:09 +0100 Subject: [PATCH 0322/1301] Add some basic HID descriptor handling. --- xhcid/src/usb/endpoint.rs | 16 +++++++++++++++ xhcid/src/usb/mod.rs | 2 +- xhcid/src/xhci/scheme.rs | 42 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/xhcid/src/usb/endpoint.rs b/xhcid/src/usb/endpoint.rs index 6611c57987..f6aa200b56 100644 --- a/xhcid/src/usb/endpoint.rs +++ b/xhcid/src/usb/endpoint.rs @@ -47,3 +47,19 @@ pub struct SuperSpeedCompanionDescriptor { } unsafe impl Plain for SuperSpeedCompanionDescriptor {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct HidDescriptor { + pub length: u8, + pub kind: u8, + pub hid_spec_release: u16, + pub country_code: u8, + pub num_descriptors: u8, + pub report_desc_ty: u8, + pub report_desc_len: u16, + pub optional_desc_ty: u8, + pub optional_desc_len: u16, +} + +unsafe impl Plain for HidDescriptor {} diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 65fca44afb..0abfacc1f0 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -1,7 +1,7 @@ pub use self::bos::{BosDescriptor, BosAnyDevDesc, BosSuperSpeedDesc, bos_capability_descs}; pub use self::config::ConfigDescriptor; pub use self::device::DeviceDescriptor; -pub use self::endpoint::{EndpointDescriptor, SuperSpeedCompanionDescriptor, EndpointTy, ENDP_ATTR_TY_MASK}; +pub use self::endpoint::{EndpointDescriptor, HidDescriptor, SuperSpeedCompanionDescriptor, EndpointTy, ENDP_ATTR_TY_MASK}; pub use self::interface::InterfaceDescriptor; pub use self::setup::Setup; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 560470984d..4688e19942 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -160,9 +160,10 @@ pub(crate) struct IfDesc { pub(crate) protocol: u8, pub(crate) interface_str: Option, pub(crate) endpoints: SmallVec<[EndpDesc; 4]>, + pub(crate) hid_descs: SmallVec<[HidDesc; 1]>, } impl IfDesc { - fn new(dev: &mut Device, desc: usb::InterfaceDescriptor, endps: impl IntoIterator) -> Result { + fn new(dev: &mut Device, desc: usb::InterfaceDescriptor, endps: impl IntoIterator, hid_descs: impl IntoIterator) -> Result { Ok(Self { alternate_setting: desc.alternate_setting, class: desc.class, @@ -172,6 +173,7 @@ impl IfDesc { protocol: desc.protocol, sub_class: desc.sub_class, endpoints: endps.into_iter().collect(), + hid_descs: hid_descs.into_iter().collect(), }) } } @@ -184,6 +186,33 @@ pub(crate) struct SuperSpeedCmp { pub(crate) bytes_per_interval: u16, } +#[derive(Clone, Copy, Debug, Serialize)] +pub(crate) struct HidDesc { + pub(crate) kind: u8, + pub(crate) hid_spec_release: u16, + pub(crate) country: u8, + pub(crate) desc_count: u8, + pub(crate) desc_ty: u8, + pub(crate) desc_len: u16, + pub(crate) optional_desc_ty: u8, + pub(crate) optional_desc_len: u16, +} + +impl From for HidDesc { + fn from(d: usb::HidDescriptor) -> Self { + Self { + kind: d.kind, + hid_spec_release: d.hid_spec_release, + country: d.country_code, + desc_count: d.num_descriptors, + desc_ty: d.report_desc_ty, + desc_len: d.report_desc_len, + optional_desc_ty: d.optional_desc_ty, + optional_desc_len: d.optional_desc_len, + } + } +} + impl From for SuperSpeedCmp { fn from(d: usb::SuperSpeedCompanionDescriptor) -> Self { Self { @@ -203,6 +232,7 @@ enum AnyDescriptor { Config(usb::ConfigDescriptor), Interface(usb::InterfaceDescriptor), Endpoint(usb::EndpointDescriptor), + Hid(usb::HidDescriptor), SuperSpeedCompanion(usb::SuperSpeedCompanionDescriptor), } @@ -220,9 +250,10 @@ impl AnyDescriptor { 2 => Self::Config(*plain::from_bytes(bytes).ok()?), 4 => Self::Interface(*plain::from_bytes(bytes).ok()?), 5 => Self::Endpoint(*plain::from_bytes(bytes).ok()?), + 33 => Self::Hid(*plain::from_bytes(bytes).ok()?), 48 => Self::SuperSpeedCompanion(*plain::from_bytes(bytes).ok()?), _ => { - //println!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes); + //panic!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes); return None; } }, len.into())) @@ -487,10 +518,15 @@ impl Xhci { while let Some(item) = iter.next() { if let AnyDescriptor::Interface(idesc) = item { let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); + let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); for _ in 0..idesc.endpoints { let next = match iter.next() { Some(AnyDescriptor::Endpoint(n)) => n, + Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { + hid_descs.push(h.into()); + break; + } _ => break, }; let mut endp = EndpDesc::from(next); @@ -505,7 +541,7 @@ impl Xhci { endpoints.push(endp); } - interface_descs.push(IfDesc::new(&mut dev, idesc, endpoints)?); + interface_descs.push(IfDesc::new(&mut dev, idesc, endpoints, hid_descs)?); } else { // TODO break; From 8c158328a3c411dce791f4e459aa83a8285430b9 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 2 Feb 2020 11:31:13 +0100 Subject: [PATCH 0323/1301] Add class and vendor device reqs to the API. --- xhcid/src/usb/mod.rs | 1 + xhcid/src/usb/setup.rs | 73 ++++++++++++++++++++++++--- xhcid/src/xhci/scheme.rs | 105 +++++++++++++++++++++++++++++++++++++-- 3 files changed, 168 insertions(+), 11 deletions(-) diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 0abfacc1f0..bd441c82be 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -18,6 +18,7 @@ pub enum DescriptorKind { InterfacePower, OnTheGo, BinaryObjectStorage = 15, + Hid = 33, SuperSpeedCompanion = 48, } diff --git a/xhcid/src/usb/setup.rs b/xhcid/src/usb/setup.rs index 366ed8f405..ca26114f2f 100644 --- a/xhcid/src/usb/setup.rs +++ b/xhcid/src/usb/setup.rs @@ -10,8 +10,65 @@ pub struct Setup { pub length: u16, } +#[repr(u8)] +pub enum ReqDirection { + HostToDevice = 0, + DeviceToHost = 1, +} + +#[repr(u8)] +pub enum ReqType { + /// Standard device requests, such as SET_ADDRESS and SET_CONFIGURATION. These aren't directly + /// accessible using the API, but are sent from xhcid when required. + Standard = 0, + + /// Class specific requests that are directly accessible from the API. + Class = 1, + + /// Vendor specific requests that are accessible using the API. + Vendor = 2, + + /// Reserved + Reserved = 3, +} + +#[repr(u8)] +pub enum ReqRecipient { + Device = 0, + Interface = 1, + Endpoint = 2, + Other = 3, + // 4..=30 are reserved + VendorSpecific = 31, +} + +pub const USB_SETUP_DIR_BIT: u8 = 1 << 7; +pub const USB_SETUP_DIR_SHIFT: u8 = 7; +pub const USB_SETUP_REQ_TY_MASK: u8 = 0x60; +pub const USB_SETUP_REQ_TY_SHIFT: u8 = 5; +pub const USB_SETUP_RECIPIENT_MASK: u8 = 0x1F; +pub const USB_SETUP_RECIPIENT_SHIFT: u8 = 0; + impl Setup { - pub fn get_status() -> Self { + pub fn direction(&self) -> ReqDirection { + if self.kind & USB_SETUP_DIR_BIT == 0 { + ReqDirection::HostToDevice + } else { + ReqDirection::DeviceToHost + } + } + pub const fn req_ty(&self) -> u8 { + (self.kind & USB_SETUP_REQ_TY_MASK) >> USB_SETUP_REQ_TY_SHIFT + } + + pub const fn req_recipient(&self) -> u8 { + (self.kind & USB_SETUP_RECIPIENT_MASK) >> USB_SETUP_RECIPIENT_SHIFT + } + pub fn is_allowed_from_api(&self) -> bool { + self.req_ty() == ReqType::Class as u8 || self.req_ty() == ReqType::Vendor as u8 + } + + pub const fn get_status() -> Self { Self { kind: 0b1000_0000, request: 0x00, @@ -21,7 +78,7 @@ impl Setup { } } - pub fn clear_feature(feature: u16) -> Self { + pub const fn clear_feature(feature: u16) -> Self { Self { kind: 0b0000_0000, request: 0x01, @@ -31,7 +88,7 @@ impl Setup { } } - pub fn set_feature(feature: u16) -> Self { + pub const fn set_feature(feature: u16) -> Self { Self { kind: 0b0000_0000, request: 0x03, @@ -41,7 +98,7 @@ impl Setup { } } - pub fn set_address(address: u16) -> Self { + pub const fn set_address(address: u16) -> Self { Self { kind: 0b0000_0000, request: 0x05, @@ -51,7 +108,7 @@ impl Setup { } } - pub fn get_descriptor(kind: DescriptorKind, index: u8, language: u16, length: u16) -> Self { + pub const fn get_descriptor(kind: DescriptorKind, index: u8, language: u16, length: u16) -> Self { Self { kind: 0b1000_0000, request: 0x06, @@ -61,7 +118,7 @@ impl Setup { } } - pub fn set_descriptor(kind: u8, index: u8, language: u16, length: u16) -> Self { + pub const fn set_descriptor(kind: u8, index: u8, language: u16, length: u16) -> Self { Self { kind: 0b0000_0000, request: 0x07, @@ -71,7 +128,7 @@ impl Setup { } } - pub fn get_configuration() -> Self { + pub const fn get_configuration() -> Self { Self { kind: 0b1000_0000, request: 0x08, @@ -81,7 +138,7 @@ impl Setup { } } - pub fn set_configuration(value: u16) -> Self { + pub const fn set_configuration(value: u16) -> Self { Self { kind: 0b0000_0000, request: 0x09, diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 4688e19942..6ef83756fc 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -46,6 +46,7 @@ pub enum Handle { Port(usize, usize, Vec), // port, offset, contents PortDesc(usize, usize, Vec), // port, offset, contents PortState(usize, usize), // port, offset + PortReq(usize), Endpoints(usize, usize, Vec), // port, offset, contents Endpoint(usize, u8, EndpointHandleTy), // port, endpoint, offset, state ConfigureEndpoints(usize), // port @@ -588,6 +589,87 @@ impl Xhci { bytes_to_read } + fn port_req(&mut self, port_num: usize, buf: &[u8]) -> Result<()> { + use usb::setup::*; + + #[derive(Deserialize)] + struct PortReq<'a> { + direction: &'a str, + req_type: &'a str, + req_recipient: &'a str, + request: u8, + value: u16, + index: u16, + length: u16, + } + // TODO: This json format might be too high level, but is useful for debugging, + // but when actual device-specific drivers are written, a binary format would + // be better. + + let req = serde_json::from_slice::>(buf).or(Err(Error::new(EBADMSG)))?; + + let direction = match req.direction { + "host_to_device" => ReqDirection::HostToDevice, + "device_to_host" => ReqDirection::DeviceToHost, + _ => return Err(Error::new(EBADMSG)), + } as u8; + + let ty = match req.req_type { + "class" => ReqType::Class, + "vendor" => ReqType::Vendor, + "standard" | _ => return Err(Error::new(EBADMSG)), + } as u8; + + let recipient = match req.req_recipient { + "device" => ReqRecipient::Device, + "interface" => ReqRecipient::Interface, + "endpoint" => ReqRecipient::Endpoint, + "other" => ReqRecipient::Other, + "vendor_specific" => ReqRecipient::VendorSpecific, + _ => return Err(Error::new(EBADMSG)), + } as u8; + + let setup = Setup { + kind: (direction << USB_SETUP_DIR_SHIFT) | (ty << USB_SETUP_REQ_TY_SHIFT) | (recipient << USB_SETUP_RECIPIENT_SHIFT), + request: req.request, + value: req.value, + index: req.index, + length: req.length, + }; + + let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?; + let ring = match port_state.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))? { + EndpointState::Ready(super::RingOrStreams::Ring(ref mut ring)) => ring, + + // Control endpoints never use streams + _ => return Err(Error::new(EIO)), + }; + + { + let (cmd, cycle) = ring.next(); + cmd.setup( + setup, + TransferKind::NoData, // FIXME + cycle, + ); + } + { + let (cmd, cycle) = ring.next(); + cmd.status(false, cycle); + } + self.dbs[port_state.slot as usize].write(1); + + { + let event = self.cmd.next_event(); + while event.data.read() == 0 { + println!(" - Waiting for event"); + } + } + + self.run.ints[0].erdp.write(self.cmd.erdp()); + + Ok(()) + } } impl SchemeMut for Xhci { @@ -649,6 +731,15 @@ impl SchemeMut for Xhci { Handle::PortState(port_num, 0) } + "request" => { + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(ENOTDIR)); + } + if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { + return Err(Error::new(EACCES)); + } + Handle::PortReq(port_num) + } "endpoints" => { if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { return Err(Error::new(EISDIR)); @@ -755,7 +846,9 @@ impl SchemeMut for Xhci { stat.st_size = buf.len() as u64; } } - Handle::ConfigureEndpoints(_) => stat.st_mode = MODE_CHR, + Handle::ConfigureEndpoints(_) | Handle::PortReq(_) => { + stat.st_mode = MODE_CHR | 0o200; // write only + } } Ok(0) } @@ -768,6 +861,7 @@ impl SchemeMut for Xhci { Handle::Port(port_num, _, _) => write!(src, "/port{}/", port_num).unwrap(), Handle::PortDesc(port_num, _, _) => write!(src, "/port{}/descriptors", port_num).unwrap(), Handle::PortState(port_num, _) => write!(src, "/port{}/state", port_num).unwrap(), + Handle::PortReq(port_num) => write!(src, "/port{}/request", port_num).unwrap(), Handle::Endpoints(port_num, _, _) => write!(src, "/port{}/endpoints/", port_num).unwrap(), Handle::Endpoint(port_num, endp_num, st) => write!(src, "/port{}/endpoints/{}/{}", port_num, endp_num, match st { EndpointHandleTy::Root(_, _) => "", @@ -804,7 +898,7 @@ impl SchemeMut for Xhci { Ok(*offset) } // Write-once configure or transfer - Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) => return Err(Error::new(ESPIPE)), + Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) | Handle::PortReq(_) => return Err(Error::new(ESPIPE)), } } @@ -819,7 +913,8 @@ impl SchemeMut for Xhci { Ok(bytes_to_read) } - Handle::ConfigureEndpoints(_) => return Err(Error::new(EBADF)), + Handle::ConfigureEndpoints(_) | Handle::PortReq(_) => return Err(Error::new(EBADF)), + &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { EndpointHandleTy::Transfer => { self.transfer_read(port_num, endp_num, buf)?; @@ -873,6 +968,10 @@ impl SchemeMut for Xhci { // TODO Ok(buf.len()) } + &Handle::PortReq(port_num) => { + self.port_req(port_num, buf)?; + Ok(buf.len()) + } _ => return Err(Error::new(EBADF)), } } From ae0d43c12a07279b43a81adb0e41262abb7c217c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 3 Feb 2020 21:48:35 +0100 Subject: [PATCH 0324/1301] Add a framework-ish for USB drivers. --- Cargo.lock | 15 ++++++++ Cargo.toml | 1 + usbscsid/.gitignore | 1 + usbscsid/Cargo.toml | 9 +++++ usbscsid/src/main.rs | 13 +++++++ xhcid/Cargo.toml | 2 ++ xhcid/drivers.toml | 5 +++ xhcid/src/main.rs | 2 +- xhcid/src/xhci/mod.rs | 75 +++++++++++++++++++++++++++++++++++----- xhcid/src/xhci/scheme.rs | 5 +-- 10 files changed, 117 insertions(+), 11 deletions(-) create mode 100644 usbscsid/.gitignore create mode 100644 usbscsid/Cargo.toml create mode 100644 usbscsid/src/main.rs create mode 100644 xhcid/drivers.toml diff --git a/Cargo.lock b/Cargo.lock index 542f7689f7..c4d93077a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1243,6 +1243,14 @@ dependencies = [ "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "traitobject" version = "0.1.0" @@ -1297,6 +1305,10 @@ dependencies = [ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "usbscsid" +version = "0.1.0" + [[package]] name = "utf8parse" version = "0.1.1" @@ -1403,6 +1415,7 @@ name = "xhcid" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=dma-slices)", @@ -1410,6 +1423,7 @@ dependencies = [ "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] @@ -1541,6 +1555,7 @@ dependencies = [ "checksum tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" +"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" diff --git a/Cargo.toml b/Cargo.toml index 8ec096c08a..023056b6c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,4 +15,5 @@ members = [ "vboxd", "vesad", "xhcid", + "usbscsid", ] diff --git a/usbscsid/.gitignore b/usbscsid/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/usbscsid/.gitignore @@ -0,0 +1 @@ +/target diff --git a/usbscsid/Cargo.toml b/usbscsid/Cargo.toml new file mode 100644 index 0000000000..098e899269 --- /dev/null +++ b/usbscsid/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "usbscsid" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs new file mode 100644 index 0000000000..b8733904ff --- /dev/null +++ b/usbscsid/src/main.rs @@ -0,0 +1,13 @@ +use std::env; + +fn main() { + let mut args = env::args().skip(1); + + const USAGE: &'static str = "usbscsid "; + + let scheme = args.next().expect(USAGE); + let port = args.next().expect(USAGE); + let protocol = args.next().expect(USAGE); + + println!("USB SCSI driver spawned with scheme `{}`, port {}, protocol {}", scheme, port, protocol); +} diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index d103bdcb1c..a523d36367 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -6,9 +6,11 @@ edition = "2018" [dependencies] bitflags = "1" plain = "0.2" +lazy_static = "1.4" spin = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "dma-slices" } serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1", features = ["serde"] } +toml = "0.5" diff --git a/xhcid/drivers.toml b/xhcid/drivers.toml new file mode 100644 index 0000000000..7376e52e70 --- /dev/null +++ b/xhcid/drivers.toml @@ -0,0 +1,5 @@ +[[drivers]] +name = "SCSI over USB" +class = 8 # Mass Storage class +subclass = 6 # SCSI transparent command set +command = ["usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"] diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 581e4f6449..9430af1eeb 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -44,7 +44,7 @@ fn main() { let address = unsafe { syscall::physmap(bar, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("xhcid: failed to map address") }; { - let hci = Arc::new(RefCell::new(Xhci::new(address).expect("xhcid: failed to allocate device"))); + let hci = Arc::new(RefCell::new(Xhci::new(name, address).expect("xhcid: failed to allocate device"))); hci.borrow_mut().probe().expect("xhcid: failed to probe"); diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index a1b9229859..250cb32207 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,10 +1,13 @@ -use plain::Plain; -use std::{mem, slice, sync::atomic, task}; +use std::{mem, slice, process, sync::atomic, task}; use std::collections::BTreeMap; +use std::ffi::OsStr; use std::pin::Pin; use std::sync::{Arc, Mutex, Weak, atomic::AtomicBool}; -use syscall::error::Result; + +use serde::Deserialize; +use syscall::error::{EBADF, EBADMSG, ENOENT, Error, Result}; use syscall::io::{Dma, Io}; + use crate::usb; mod capability; @@ -139,6 +142,9 @@ pub struct Xhci { // IRQs, but it would make sense in case the hub has both isochronous (which trigger interrupts // reapeatedly with some time in between), bulk, control, etc. I might be wrong though... irq_state: Arc, + + drivers: BTreeMap, + scheme_name: String, } struct PortState { @@ -167,7 +173,7 @@ impl EndpointState { } impl Xhci { - pub fn new(address: usize) -> Result { + pub fn new(scheme_name: String, address: usize) -> Result { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; println!(" - CAP {:X}", address); @@ -238,6 +244,8 @@ impl Xhci { triggered: AtomicBool::new(false), wakers: Mutex::new(Vec::new()), }), + drivers: BTreeMap::new(), + scheme_name, }; xhci.init(max_slots); @@ -380,15 +388,21 @@ impl Xhci { } let dev_desc = Self::get_dev_desc_raw(&mut self.ports, &mut self.run, &mut self.cmd, &mut self.dbs, i, slot, &mut ring)?; - - self.port_states.insert(i, PortState { + let mut port_state = PortState { slot, input_context: input, dev_desc, endpoint_states: std::iter::once((0, EndpointState::Ready( RingOrStreams::Ring(ring), ))).collect::>(), - }); + }; + + match self.spawn_drivers(i, &mut port_state) { + Ok(()) => (), + Err(err) => println!("Failed to spawn driver for port {}: `{}`", i, err), + } + + self.port_states.insert(i, port_state); } } @@ -405,7 +419,7 @@ impl Xhci { // FIXME: MSI and MSI-X systems self.run.ints[0].iman.writef(1, true); - // Wake all futures that await the IRQ. + // Wake all futures awaiting the IRQ. for waker in self.irq_state.wakers.lock().unwrap().drain(..) { waker.wake(); } @@ -420,6 +434,51 @@ impl Xhci { state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state)) } } + fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> { + // TODO: There should probably be a way to select alternate interfaces, and not just the + // first one. + // TODO: Now that there are some good error crates, I don't think errno.h error codes are + // suitable here. + + let ifdesc = &ps.dev_desc.config_descs.first().ok_or(Error::new(EBADF))?.interface_descs.first().ok_or(Error::new(EBADF))?; + let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; + + if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| driver.class == ifdesc.class && driver.subclass == ifdesc.sub_class) { + println!("Loading driver \"{}\"", driver.name); + let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; + + let if_proto = ifdesc.protocol; + + let process = process::Command::new(command).args(args.into_iter().map(|arg| arg.replace("$SCHEME", &self.scheme_name).replace("$PORT", &format!("{}", port)).replace("$IF_PROTO", &format!("{}", if_proto))).collect::>()).stdin(process::Stdio::null()).spawn().or(Err(Error::new(ENOENT)))?; + self.drivers.insert(port, process); + } else { + return Err(Error::new(ENOENT)); + } + + Ok(()) + } +} +#[derive(Deserialize)] +struct DriverConfig { + name: String, + class: u8, + subclass: u8, + command: Vec, +} +#[derive(Deserialize)] +struct DriversConfig { + drivers: Vec, +} + +use lazy_static::lazy_static; + +lazy_static! { + static ref DRIVERS_CONFIG: DriversConfig = { + // TODO: Load this at runtime. + const TOML: &'static [u8] = include_bytes!("../../drivers.toml"); + + toml::from_slice::(TOML).expect("Failed to parse internally embedded config file") + }; } pub(crate) struct IrqFuture { state: IrqFutureState } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 6ef83756fc..c28f8992b3 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -46,7 +46,7 @@ pub enum Handle { Port(usize, usize, Vec), // port, offset, contents PortDesc(usize, usize, Vec), // port, offset, contents PortState(usize, usize), // port, offset - PortReq(usize), + PortReq(usize), // port Endpoints(usize, usize, Vec), // port, offset, contents Endpoint(usize, u8, EndpointHandleTy), // port, endpoint, offset, state ConfigureEndpoints(usize), // port @@ -55,7 +55,8 @@ pub enum Handle { #[derive(Serialize)] struct PortDesc(DevDesc); -// Even though these descriptors are originally intended for JSON, they should suffice.. +// TODO: Even though these descriptors are originally intended for JSON, they should suffice... for +// now. #[derive(Clone, Debug, Serialize)] pub(crate) struct DevDesc { From 1b74f335b01a40689b89d7a73c9b8358fb68a27e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 6 Feb 2020 21:45:44 +0100 Subject: [PATCH 0325/1301] Add a driver interface accessible to class drivers. --- usbscsid/src/main.rs | 2 + usbscsid/src/protocol/bot.rs | 47 +++ usbscsid/src/protocol/mod.rs | 12 + xhcid/Cargo.toml | 8 + xhcid/drivers.toml | 2 +- xhcid/src/driver_interface.rs | 135 +++++++ xhcid/src/lib.rs | 4 + xhcid/src/main.rs | 128 +++--- xhcid/src/usb/bos.rs | 16 +- xhcid/src/usb/mod.rs | 6 +- xhcid/src/usb/setup.rs | 7 +- xhcid/src/xhci/capability.rs | 5 +- xhcid/src/xhci/command.rs | 1 - xhcid/src/xhci/context.rs | 16 +- xhcid/src/xhci/mod.rs | 125 +++--- xhcid/src/xhci/operational.rs | 2 +- xhcid/src/xhci/port.rs | 8 +- xhcid/src/xhci/scheme.rs | 706 +++++++++++++++++++--------------- xhcid/src/xhci/trb.rs | 80 ++-- 19 files changed, 839 insertions(+), 471 deletions(-) create mode 100644 usbscsid/src/protocol/bot.rs create mode 100644 usbscsid/src/protocol/mod.rs create mode 100644 xhcid/src/driver_interface.rs create mode 100644 xhcid/src/lib.rs diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index b8733904ff..f78299fb27 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -1,5 +1,7 @@ use std::env; +pub mod protocol; + fn main() { let mut args = env::args().skip(1); diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs new file mode 100644 index 0000000000..ab47b1a9a5 --- /dev/null +++ b/usbscsid/src/protocol/bot.rs @@ -0,0 +1,47 @@ +use super::Protocol; + +pub const CBW_SIGNATURE: u32 = 0x43425355; + +/// 0 means host to dev, 1 means dev to host +pub const CBW_FLAGS_DIRECTION_BIT: u8 = 1 << CBW_FLAGS_DIRECTION_SHIFT; +pub const CBW_FLAGS_DIRECTION_SHIFT: u8 = 7; + +#[repr(packed)] +pub struct CommandBlockWrapper { + pub signature: u32, + pub tag: u32, + pub data_transfer_len: u32, + pub flags: u8, // upper nibble reserved + pub lun: u8, // bits 7:5 reserved + pub cb_len: u8, + pub command_block: [u8; 16], +} + +pub const CSW_SIGNATURE: u32 = 0x53425355; + +#[repr(u8)] +pub enum CswStatus { + Passed = 0, + Failed = 1, + PhaseError = 2, + // the rest are reserved +} + +#[repr(packed)] +pub struct CommandStatusWrapper { + pub signature: u32, + pub tag: u32, + pub data_residue: u32, + pub status: u8, +} + +pub struct BulkOnlyTransport; + +impl Protocol for BulkOnlyTransport { + fn send_command_block(&mut self, cb: &[u8]) { + todo!() + } + fn recv_command_block(&mut self, cb: &mut [u8]) { + todo!() + } +} diff --git a/usbscsid/src/protocol/mod.rs b/usbscsid/src/protocol/mod.rs new file mode 100644 index 0000000000..ce63b4e4df --- /dev/null +++ b/usbscsid/src/protocol/mod.rs @@ -0,0 +1,12 @@ +pub trait Protocol { + fn send_command_block(&mut self, cb: &[u8]); + fn recv_command_block(&mut self, cb: &mut [u8]); +} + +/// Bulk-only transport +pub mod bot; + +/// Control-Bulk-Interface transpoint +mod cbi { + // TODO +} diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index a523d36367..a7a055459c 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -3,6 +3,14 @@ name = "xhcid" version = "0.1.0" edition = "2018" +[[bin]] +name = "xhcid" +path = "src/main.rs" + +[lib] +name = "xhcid_interface" +path = "src/lib.rs" + [dependencies] bitflags = "1" plain = "0.2" diff --git a/xhcid/drivers.toml b/xhcid/drivers.toml index 7376e52e70..426a19114e 100644 --- a/xhcid/drivers.toml +++ b/xhcid/drivers.toml @@ -2,4 +2,4 @@ name = "SCSI over USB" class = 8 # Mass Storage class subclass = 6 # SCSI transparent command set -command = ["usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"] +command = ["/bin/usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"] diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs new file mode 100644 index 0000000000..1b2a158a91 --- /dev/null +++ b/xhcid/src/driver_interface.rs @@ -0,0 +1,135 @@ +pub extern crate serde; +pub extern crate smallvec; + +use serde::{Deserialize, Serialize}; +use smallvec::SmallVec; +use syscall::{Error, Result, EINVAL}; + +pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK}; + +#[derive(Serialize, Deserialize)] +pub struct ConfigureEndpointsReq { + /// Index into the configuration descriptors of the device descriptor. + pub config_desc: usize, + // TODO: Support multiple alternate interfaces as well. +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct DevDesc { + pub kind: u8, + pub usb: u16, + pub class: u8, + pub sub_class: u8, + pub protocol: u8, + pub packet_size: u8, + pub vendor: u16, + pub product: u16, + pub release: u16, + pub manufacturer_str: Option, + pub product_str: Option, + pub serial_str: Option, + pub config_descs: SmallVec<[ConfDesc; 1]>, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct ConfDesc { + pub kind: u8, + pub configuration_value: u8, + pub configuration: Option, + pub attributes: u8, + pub max_power: u8, + pub interface_descs: SmallVec<[IfDesc; 1]>, +} + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct EndpDesc { + pub kind: u8, + pub address: u8, + pub attributes: u8, + pub max_packet_size: u16, + pub interval: u8, + pub ssc: Option, +} +pub enum EndpDirection { + Out, + In, + Bidirectional, +} + +impl EndpDesc { + pub fn ty(self) -> EndpointTy { + match self.attributes & ENDP_ATTR_TY_MASK { + 0 => EndpointTy::Ctrl, + 1 => EndpointTy::Interrupt, + 2 => EndpointTy::Bulk, + 3 => EndpointTy::Isoch, + _ => unreachable!(), + } + } + pub fn is_control(&self) -> bool { + self.ty() == EndpointTy::Ctrl + } + pub fn is_interrupt(&self) -> bool { + self.ty() == EndpointTy::Interrupt + } + pub fn is_bulk(&self) -> bool { + self.ty() == EndpointTy::Bulk + } + pub fn is_isoch(&self) -> bool { + self.ty() == EndpointTy::Isoch + } + pub fn direction(&self) -> EndpDirection { + if self.is_control() { + return EndpDirection::Bidirectional; + } + if self.address & 0x80 != 0 { + EndpDirection::In + } else { + EndpDirection::Out + } + } + pub fn xhci_ep_type(&self) -> Result { + Ok(match self.direction() { + EndpDirection::Out if self.is_isoch() => 1, + EndpDirection::Out if self.is_bulk() => 2, + EndpDirection::Out if self.is_interrupt() => 3, + EndpDirection::Bidirectional if self.is_control() => 4, + EndpDirection::In if self.is_isoch() => 5, + EndpDirection::In if self.is_bulk() => 6, + EndpDirection::In if self.is_interrupt() => 7, + _ => return Err(Error::new(EINVAL)), + }) + } +} +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct IfDesc { + pub kind: u8, + pub number: u8, + pub alternate_setting: u8, + pub class: u8, + pub sub_class: u8, + pub protocol: u8, + pub interface_str: Option, + pub endpoints: SmallVec<[EndpDesc; 4]>, + pub hid_descs: SmallVec<[HidDesc; 1]>, +} + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct SuperSpeedCmp { + pub kind: u8, + pub max_burst: u8, + pub attributes: u8, + pub bytes_per_interval: u16, +} + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct HidDesc { + pub kind: u8, + pub hid_spec_release: u16, + pub country: u8, + pub desc_count: u8, + pub desc_ty: u8, + pub desc_len: u16, + pub optional_desc_ty: u8, + pub optional_desc_len: u16, +} diff --git a/xhcid/src/lib.rs b/xhcid/src/lib.rs new file mode 100644 index 0000000000..e5e4b806ab --- /dev/null +++ b/xhcid/src/lib.rs @@ -0,0 +1,4 @@ +mod driver_interface; +mod usb; + +pub use driver_interface::*; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 9430af1eeb..2cc823886d 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -6,18 +6,19 @@ extern crate syscall; use event::{Event, EventQueue}; use std::cell::RefCell; -use std::{io, env}; use std::fs::File; -use std::io::{Result, Read, Write}; +use std::io::{Read, Result, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; +use std::{env, io}; use syscall::data::Packet; -use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; +use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::scheme::SchemeMut; use crate::xhci::Xhci; +mod driver_interface; mod usb; mod xhci; @@ -33,22 +34,38 @@ fn main() { let irq_str = args.next().expect("xhcid: no IRQ provided"); let irq = irq_str.parse::().expect("xhcid: failed to parse irq"); - print!("{}", format!(" + XHCI {} on: {:X} IRQ: {}\n", name, bar, irq)); + print!( + "{}", + format!(" + XHCI {} on: {:X} IRQ: {}\n", name, bar, irq) + ); // Daemonize if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { - let socket_fd = syscall::open(format!(":usb/{}", name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("xhcid: failed to create usb scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + let socket_fd = syscall::open( + format!(":usb/{}", name), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + ) + .expect("xhcid: failed to create usb scheme"); + let socket = Arc::new(RefCell::new(unsafe { + File::from_raw_fd(socket_fd as RawFd) + })); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); + let mut irq_file = + File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); - let address = unsafe { syscall::physmap(bar, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("xhcid: failed to map address") }; + let address = unsafe { + syscall::physmap(bar, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("xhcid: failed to map address") + }; { - let hci = Arc::new(RefCell::new(Xhci::new(name, address).expect("xhcid: failed to allocate device"))); + let hci = Arc::new(RefCell::new( + Xhci::new(name, address).expect("xhcid: failed to allocate device"), + )); hci.borrow_mut().probe().expect("xhcid: failed to probe"); - let mut event_queue = EventQueue::<()>::new().expect("xhcid: failed to create event queue"); + let mut event_queue = + EventQueue::<()>::new().expect("xhcid: failed to create event queue"); syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); @@ -57,62 +74,67 @@ fn main() { let hci_irq = hci.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; + event_queue + .add(irq_file.as_raw_fd(), move |_| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; - if hci_irq.borrow_mut().trigger_irq() { - irq_file.write(&mut irq)?; + if hci_irq.borrow_mut().trigger_irq() { + irq_file.write(&mut irq)?; - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - hci_irq.borrow_mut().handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket_irq.borrow_mut().write(&mut todo[i])?; - todo.remove(i); + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + hci_irq.borrow_mut().handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; + } else { + socket_irq.borrow_mut().write(&mut todo[i])?; + todo.remove(i); + } } } - } - Ok(None) - }).expect("xhcid: failed to catch events on IRQ file"); + Ok(None) + }) + .expect("xhcid: failed to catch events on IRQ file"); let socket_fd = socket.borrow().as_raw_fd(); let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_| -> Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => break, - Err(err) if err.kind() == io::ErrorKind::WouldBlock => break, - Ok(_) => (), - Err(err) => return Err(err), - } + event_queue + .add(socket_fd, move |_| -> Result> { + loop { + let mut packet = Packet::default(); + match socket_packet.borrow_mut().read(&mut packet) { + Ok(0) => break, + Err(err) if err.kind() == io::ErrorKind::WouldBlock => break, + Ok(_) => (), + Err(err) => return Err(err), + } - let a = packet.a; - hci.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); - } else { - socket_packet.borrow_mut().write(&mut packet)?; + let a = packet.a; + hci.borrow_mut().handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket_packet.borrow_mut().write(&mut packet)?; + } } - } - Ok(None) - }).expect("xhcid: failed to catch events on scheme file"); + Ok(None) + }) + .expect("xhcid: failed to catch events on scheme file"); - event_queue.trigger_all(Event { - fd: 0, - flags: 0 - }).expect("xhcid: failed to trigger events"); + event_queue + .trigger_all(Event { fd: 0, flags: 0 }) + .expect("xhcid: failed to trigger events"); event_queue.run().expect("xhcid: failed to handle events"); } - unsafe { let _ = syscall::physunmap(address); } + unsafe { + let _ = syscall::physunmap(address); + } } } diff --git a/xhcid/src/usb/bos.rs b/xhcid/src/usb/bos.rs index 2221b8e3a7..d2ef922288 100644 --- a/xhcid/src/usb/bos.rs +++ b/xhcid/src/usb/bos.rs @@ -57,9 +57,7 @@ pub struct BosDevDescIter<'a> { } impl<'a> BosDevDescIter<'a> { pub fn new(bytes: &'a [u8]) -> Self { - Self { - bytes, - } + Self { bytes } } } impl<'a> From<&'a [u8]> for BosDevDescIter<'a> { @@ -72,7 +70,9 @@ impl<'a> Iterator for BosDevDescIter<'a> { fn next(&mut self) -> Option { if let Some(desc) = plain::from_bytes::(self.bytes).ok() { - if desc.len as usize > self.bytes.len() { return None }; + if desc.len as usize > self.bytes.len() { + return None; + }; let bytes_ret = &self.bytes[..desc.len as usize]; self.bytes = &self.bytes[desc.len as usize..]; Some((*desc, bytes_ret)) @@ -129,6 +129,10 @@ impl<'a> Iterator for BosAnyDevDescIter<'a> { } } -pub fn bos_capability_descs<'a>(desc: BosDescriptor, data: &'a [u8]) -> impl Iterator + 'a { - BosAnyDevDescIter::from(&data[..desc.total_len as usize - std::mem::size_of_val(&desc)]).take(desc.cap_count as usize) +pub fn bos_capability_descs<'a>( + desc: BosDescriptor, + data: &'a [u8], +) -> impl Iterator + 'a { + BosAnyDevDescIter::from(&data[..desc.total_len as usize - std::mem::size_of_val(&desc)]) + .take(desc.cap_count as usize) } diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index bd441c82be..f6000a7843 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -1,7 +1,9 @@ -pub use self::bos::{BosDescriptor, BosAnyDevDesc, BosSuperSpeedDesc, bos_capability_descs}; +pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuperSpeedDesc}; pub use self::config::ConfigDescriptor; pub use self::device::DeviceDescriptor; -pub use self::endpoint::{EndpointDescriptor, HidDescriptor, SuperSpeedCompanionDescriptor, EndpointTy, ENDP_ATTR_TY_MASK}; +pub use self::endpoint::{ + EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, ENDP_ATTR_TY_MASK, +}; pub use self::interface::InterfaceDescriptor; pub use self::setup::Setup; diff --git a/xhcid/src/usb/setup.rs b/xhcid/src/usb/setup.rs index ca26114f2f..3ba4462206 100644 --- a/xhcid/src/usb/setup.rs +++ b/xhcid/src/usb/setup.rs @@ -108,7 +108,12 @@ impl Setup { } } - pub const fn get_descriptor(kind: DescriptorKind, index: u8, language: u16, length: u16) -> Self { + pub const fn get_descriptor( + kind: DescriptorKind, + index: u8, + language: u16, + length: u16, + ) -> Self { Self { kind: 0b1000_0000, request: 0x06, diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index 66b8156310..d79d93d8f2 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -11,7 +11,7 @@ pub struct CapabilityRegs { pub hcc_params1: Mmio, pub db_offset: Mmio, pub rts_offset: Mmio, - pub hcc_params2: Mmio + pub hcc_params2: Mmio, } pub const HCC_PARAMS1_MAXPSASIZE_MASK: u32 = 0xF000; // 15:12 @@ -28,6 +28,7 @@ impl CapabilityRegs { self.hcc_params2.readf(HCC_PARAMS2_CIC_BIT) } pub fn max_psa_size(&self) -> u8 { - ((self.hcc_params1.read() & HCC_PARAMS1_MAXPSASIZE_MASK) >> HCC_PARAMS1_MAXPSASIZE_SHIFT) as u8 + ((self.hcc_params1.read() & HCC_PARAMS1_MAXPSASIZE_MASK) >> HCC_PARAMS1_MAXPSASIZE_SHIFT) + as u8 } } diff --git a/xhcid/src/xhci/command.rs b/xhcid/src/xhci/command.rs index 56449a66e3..41c539fe2e 100644 --- a/xhcid/src/xhci/command.rs +++ b/xhcid/src/xhci/command.rs @@ -1,6 +1,5 @@ use syscall::error::Result; - use super::event::EventRing; use super::ring::Ring; use super::trb::Trb; diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 95c86d6e4a..0e7c882e0b 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -1,5 +1,5 @@ use syscall::error::Result; -use syscall::io::{Dma, Mmio, Io}; +use syscall::io::{Dma, Io, Mmio}; #[repr(packed)] pub struct SlotContext { @@ -55,7 +55,17 @@ pub struct InputContext { } impl InputContext { pub fn dump_control(&self) { - println!("INPUT CONTEXT: {} {} [{} {} {} {} {}] {}", self.drop_context.read(), self.add_context.read(), self._rsvd[0].read(), self._rsvd[1].read(), self._rsvd[2].read(), self._rsvd[3].read(), self._rsvd[4].read(), self.control.read()); + println!( + "INPUT CONTEXT: {} {} [{} {} {} {} {}] {}", + self.drop_context.read(), + self.add_context.read(), + self._rsvd[0].read(), + self._rsvd[1].read(), + self._rsvd[2].read(), + self._rsvd[3].read(), + self._rsvd[4].read(), + self.control.read() + ); } } @@ -78,7 +88,7 @@ impl DeviceContextList { Ok(DeviceContextList { dcbaa: dcbaa, - contexts: contexts + contexts: contexts, }) } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 250cb32207..640254b880 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,11 +1,11 @@ -use std::{mem, slice, process, sync::atomic, task}; use std::collections::BTreeMap; use std::ffi::OsStr; use std::pin::Pin; -use std::sync::{Arc, Mutex, Weak, atomic::AtomicBool}; +use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak}; +use std::{mem, process, slice, sync::atomic, task}; use serde::Deserialize; -use syscall::error::{EBADF, EBADMSG, ENOENT, Error, Result}; +use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT}; use syscall::io::{Dma, Io}; use crate::usb; @@ -17,8 +17,8 @@ mod doorbell; mod event; mod operational; mod port; -mod runtime; mod ring; +mod runtime; mod scheme; mod trb; @@ -29,9 +29,11 @@ use self::doorbell::Doorbell; use self::operational::OperationalRegs; use self::port::Port; use self::ring::Ring; -use self::runtime::{RuntimeRegs, Interrupter}; +use self::runtime::{Interrupter, RuntimeRegs}; use self::trb::{TransferKind, TrbCompletionCode, TrbType}; +use crate::driver_interface::*; + struct Device<'a> { ring: &'a mut Ring, cmd: &'a mut CommandRing, @@ -47,7 +49,8 @@ impl<'a> Device<'a> { let (cmd, cycle) = self.ring.next(); cmd.setup( usb::Setup::get_descriptor(kind, index, 0, len as u16), - TransferKind::In, cycle + TransferKind::In, + cycle, ); } @@ -75,45 +78,29 @@ impl<'a> Device<'a> { fn get_device(&mut self) -> Result { let mut desc = Dma::::zeroed()?; - self.get_desc( - usb::DescriptorKind::Device, - 0, - &mut desc - ); + self.get_desc(usb::DescriptorKind::Device, 0, &mut desc); Ok(*desc) } fn get_config(&mut self, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc( - usb::DescriptorKind::Configuration, - config, - &mut desc - ); + self.get_desc(usb::DescriptorKind::Configuration, config, &mut desc); Ok(*desc) } fn get_bos(&mut self) -> Result<(usb::BosDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc( - usb::DescriptorKind::BinaryObjectStorage, - 0, - &mut desc, - ); + self.get_desc(usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc); Ok(*desc) } fn get_string(&mut self, index: u8) -> Result { let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; - self.get_desc( - usb::DescriptorKind::String, - index, - &mut sdesc - ); + self.get_desc(usb::DescriptorKind::String, index, &mut sdesc); let len = sdesc.0 as usize; if len > 2 { - Ok(String::from_utf16(&sdesc.2[.. (len - 2)/2]).unwrap_or(String::new())) + Ok(String::from_utf16(&sdesc.2[..(len - 2) / 2]).unwrap_or(String::new())) } else { Ok(String::new()) } @@ -150,7 +137,7 @@ pub struct Xhci { struct PortState { slot: u8, input_context: Dma, - dev_desc: scheme::DevDesc, + dev_desc: DevDesc, endpoint_states: BTreeMap, } @@ -197,7 +184,7 @@ impl Xhci { println!(" - Wait for not running"); // Wait until controller not running - while ! op.usb_sts.readf(1) { + while !op.usb_sts.readf(1) { println!(" - Waiting for XHCI stopped"); } @@ -217,7 +204,8 @@ impl Xhci { } let port_base = op_base + 0x400; - let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut Port, max_ports as usize) }; + let ports = + unsafe { slice::from_raw_parts_mut(port_base as *mut Port, max_ports as usize) }; println!(" - PORT {:X}", port_base); let db_base = address + cap.db_offset.read() as usize; @@ -331,14 +319,12 @@ impl Xhci { for i in 0..self.ports.len() { let (data, state, speed, flags) = { let port = &self.ports[i]; - ( - port.read(), - port.state(), - port.speed(), - port.flags(), - ) + (port.read(), port.state(), port.speed(), port.flags()) }; - println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags); + println!( + " + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", + i, data, state, speed, flags + ); if flags.contains(port::PortFlags::PORT_CCS) { //TODO: Link TRB when running to the end of the ring buffer @@ -362,7 +348,9 @@ impl Xhci { input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16); // control endpoint? - input.device.endpoints[0].b.write(4096 << 16 | 4 << 3 | 3 << 1); // packet size | control endpoint | allowed error count + input.device.endpoints[0] + .b + .write(4096 << 16 | 4 << 3 | 3 << 1); // packet size | control endpoint | allowed error count let tr = ring.register(); input.device.endpoints[0].trh.write((tr >> 32) as u32); input.device.endpoints[0].trl.write(tr as u32); @@ -379,7 +367,9 @@ impl Xhci { println!(" - Waiting for event"); } - if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::CommandCompletion as u8 { + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::CommandCompletion as u8 + { panic!("ADDRESS DEVICE FAILED"); } @@ -387,14 +377,24 @@ impl Xhci { event.reserved(false); } - let dev_desc = Self::get_dev_desc_raw(&mut self.ports, &mut self.run, &mut self.cmd, &mut self.dbs, i, slot, &mut ring)?; + let dev_desc = Self::get_dev_desc_raw( + &mut self.ports, + &mut self.run, + &mut self.cmd, + &mut self.dbs, + i, + slot, + &mut ring, + )?; let mut port_state = PortState { slot, input_context: input, dev_desc, - endpoint_states: std::iter::once((0, EndpointState::Ready( - RingOrStreams::Ring(ring), - ))).collect::>(), + endpoint_states: std::iter::once(( + 0, + EndpointState::Ready(RingOrStreams::Ring(ring)), + )) + .collect::>(), }; match self.spawn_drivers(i, &mut port_state) { @@ -431,7 +431,7 @@ impl Xhci { } pub(crate) fn irq(&self) -> IrqFuture { IrqFuture { - state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state)) + state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state)), } } fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> { @@ -440,16 +440,39 @@ impl Xhci { // TODO: Now that there are some good error crates, I don't think errno.h error codes are // suitable here. - let ifdesc = &ps.dev_desc.config_descs.first().ok_or(Error::new(EBADF))?.interface_descs.first().ok_or(Error::new(EBADF))?; + let ifdesc = &ps + .dev_desc + .config_descs + .first() + .ok_or(Error::new(EBADF))? + .interface_descs + .first() + .ok_or(Error::new(EBADF))?; let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; - if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| driver.class == ifdesc.class && driver.subclass == ifdesc.sub_class) { + if let Some(driver) = drivers_usercfg + .drivers + .iter() + .find(|driver| driver.class == ifdesc.class && driver.subclass == ifdesc.sub_class) + { println!("Loading driver \"{}\"", driver.name); let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; let if_proto = ifdesc.protocol; - let process = process::Command::new(command).args(args.into_iter().map(|arg| arg.replace("$SCHEME", &self.scheme_name).replace("$PORT", &format!("{}", port)).replace("$IF_PROTO", &format!("{}", if_proto))).collect::>()).stdin(process::Stdio::null()).spawn().or(Err(Error::new(ENOENT)))?; + let process = process::Command::new(command) + .args( + args.into_iter() + .map(|arg| { + arg.replace("$SCHEME", &self.scheme_name) + .replace("$PORT", &format!("{}", port)) + .replace("$IF_PROTO", &format!("{}", if_proto)) + }) + .collect::>(), + ) + .stdin(process::Stdio::null()) + .spawn() + .or(Err(Error::new(ENOENT)))?; self.drivers.insert(port, process); } else { return Err(Error::new(ENOENT)); @@ -481,7 +504,9 @@ lazy_static! { }; } -pub(crate) struct IrqFuture { state: IrqFutureState } +pub(crate) struct IrqFuture { + state: IrqFutureState, +} struct IrqState { triggered: AtomicBool, @@ -503,7 +528,9 @@ impl std::future::Future for IrqFuture { match &mut this.state { // TODO: Ordering? IrqFutureState::Pending(state_weak) => { - let state = state_weak.upgrade().expect("IRQ futures keep getting polled even after the driver has been deinitialized"); + let state = state_weak.upgrade().expect( + "IRQ futures keep getting polled even after the driver has been deinitialized", + ); if state.triggered.load(atomic::Ordering::SeqCst) { this.state = IrqFutureState::Finished; diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index 3f3d6001ae..213cae4185 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -1,4 +1,4 @@ -use syscall::io::{Mmio, Io}; +use syscall::io::{Io, Mmio}; #[repr(packed)] pub struct OperationalRegs { diff --git a/xhcid/src/xhci/port.rs b/xhcid/src/xhci/port.rs index 0f62d66140..1745a793bd 100644 --- a/xhcid/src/xhci/port.rs +++ b/xhcid/src/xhci/port.rs @@ -28,10 +28,10 @@ bitflags! { #[repr(packed)] pub struct Port { - pub portsc : Mmio, - pub portpmsc : Mmio, - pub portli : Mmio, - pub porthlpmc : Mmio, + pub portsc: Mmio, + pub portpmsc: Mmio, + pub portli: Mmio, + pub porthlpmc: Mmio, } impl Port { diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c28f8992b3..287f78b534 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,38 +1,39 @@ -use std::{cmp, mem, path, str}; use std::convert::TryFrom; use std::io::prelude::*; +use std::{cmp, mem, path, str}; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use syscall::io::{Dma, Io}; use syscall::scheme::SchemeMut; use syscall::{ - EACCES, EBADF, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, ENOTDIR, ENXIO, ESPIPE, - O_CREAT, O_DIRECTORY, O_STAT, O_RDWR, O_RDONLY, O_WRONLY, - MODE_CHR, MODE_DIR, MODE_FILE, - SEEK_CUR, SEEK_END, SEEK_SET, - Stat, - Error, Result + Error, Result, Stat, EACCES, EBADF, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, + ENOTDIR, ENXIO, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_CREAT, O_DIRECTORY, O_RDONLY, O_RDWR, + O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, }; -use super::{Device, EndpointState, Xhci}; use super::{port, usb}; +use super::{Device, EndpointState, Xhci}; use super::command::CommandRing; -use super::context::{ENDPOINT_CONTEXT_STATUS_MASK, InputContext, SlotState, StreamContextArray, StreamContext}; +use super::context::{ + InputContext, SlotState, StreamContext, StreamContextArray, ENDPOINT_CONTEXT_STATUS_MASK, +}; use super::doorbell::Doorbell; use super::operational::OperationalRegs; use super::ring::Ring; use super::runtime::RuntimeRegs; use super::trb::{TransferKind, TrbCompletionCode, TrbType}; -use super::usb::endpoint::{ENDP_ATTR_TY_MASK, EndpointTy}; +use super::usb::endpoint::{EndpointTy, ENDP_ATTR_TY_MASK}; + +use crate::driver_interface::*; /// Subdirs of an endpoint pub enum EndpointHandleTy { /// portX/endpoints/Y/transfer. Write calls transfer data to the device, and read calls /// transfer data from the device. - Transfer, + Transfer, /// portX/endpoints/Y/status Status(usize), // offset @@ -42,104 +43,19 @@ pub enum EndpointHandleTy { } pub enum Handle { - TopLevel(usize, Vec), // offset, contents (ports) - Port(usize, usize, Vec), // port, offset, contents - PortDesc(usize, usize, Vec), // port, offset, contents - PortState(usize, usize), // port, offset - PortReq(usize), // port - Endpoints(usize, usize, Vec), // port, offset, contents + TopLevel(usize, Vec), // offset, contents (ports) + Port(usize, usize, Vec), // port, offset, contents + PortDesc(usize, usize, Vec), // port, offset, contents + PortState(usize, usize), // port, offset + PortReq(usize), // port + Endpoints(usize, usize, Vec), // port, offset, contents Endpoint(usize, u8, EndpointHandleTy), // port, endpoint, offset, state - ConfigureEndpoints(usize), // port + ConfigureEndpoints(usize), // port } -#[derive(Serialize)] -struct PortDesc(DevDesc); - -// TODO: Even though these descriptors are originally intended for JSON, they should suffice... for +// TODO: Even though the driver interface descriptors are originally intended for JSON, they should suffice... for // now. -#[derive(Clone, Debug, Serialize)] -pub(crate) struct DevDesc { - pub(crate) kind: u8, - pub(crate) usb: u16, - pub(crate) class: u8, - pub(crate) sub_class: u8, - pub(crate) protocol: u8, - pub(crate) packet_size: u8, - pub(crate) vendor: u16, - pub(crate) product: u16, - pub(crate) release: u16, - pub(crate) manufacturer_str: Option, - pub(crate) product_str: Option, - pub(crate) serial_str: Option, - pub(crate) config_descs: SmallVec<[ConfDesc; 1]>, -} - -#[derive(Clone, Debug, Serialize)] -pub(crate) struct ConfDesc { - pub(crate) kind: u8, - pub(crate) configuration_value: u8, - pub(crate) configuration: Option, - pub(crate) attributes: u8, - pub(crate) max_power: u8, - pub(crate) interface_descs: SmallVec<[IfDesc; 1]>, -} - -#[derive(Clone, Copy, Debug, Serialize)] -pub(crate) struct EndpDesc { - pub(crate) kind: u8, - pub(crate) address: u8, - pub(crate) attributes: u8, - pub(crate) max_packet_size: u16, - pub(crate) interval: u8, - pub(crate) ssc: Option, -} - -enum EndpDirection { - Out, - In, - Bidirectional, -} - -impl EndpDesc { - fn ty(self) -> EndpointTy { - match self.attributes & ENDP_ATTR_TY_MASK { - 0 => EndpointTy::Ctrl, - 1 => EndpointTy::Interrupt, - 2 => EndpointTy::Bulk, - 3 => EndpointTy::Isoch, - _ => unreachable!(), - } - } - fn is_control(&self) -> bool { - self.ty() == EndpointTy::Ctrl - } - fn is_interrupt(&self) -> bool { - self.ty() == EndpointTy::Interrupt - } - fn is_bulk(&self) -> bool { - self.ty() == EndpointTy::Bulk - } - fn is_isoch(&self) -> bool { - self.ty() == EndpointTy::Isoch - } - fn direction(&self) -> EndpDirection { - if self.is_control() { return EndpDirection::Bidirectional } - if self.address & 0x80 != 0 { EndpDirection::In } else { EndpDirection::Out } - } - fn xhci_ep_type(&self) -> Result { - Ok(match self.direction() { - EndpDirection::Out if self.is_isoch() => 1, - EndpDirection::Out if self.is_bulk() => 2, - EndpDirection::Out if self.is_interrupt() => 3, - EndpDirection::Bidirectional if self.is_control() => 4, - EndpDirection::In if self.is_isoch() => 5, - EndpDirection::In if self.is_bulk() => 6, - EndpDirection::In if self.is_interrupt() => 7, - _ => return Err(Error::new(EINVAL)), - }) - } -} impl From for EndpDesc { fn from(d: usb::EndpointDescriptor) -> Self { Self { @@ -152,53 +68,6 @@ impl From for EndpDesc { } } } -#[derive(Clone, Debug, Serialize)] -pub(crate) struct IfDesc { - pub(crate) kind: u8, - pub(crate) number: u8, - pub(crate) alternate_setting: u8, - pub(crate) class: u8, - pub(crate) sub_class: u8, - pub(crate) protocol: u8, - pub(crate) interface_str: Option, - pub(crate) endpoints: SmallVec<[EndpDesc; 4]>, - pub(crate) hid_descs: SmallVec<[HidDesc; 1]>, -} -impl IfDesc { - fn new(dev: &mut Device, desc: usb::InterfaceDescriptor, endps: impl IntoIterator, hid_descs: impl IntoIterator) -> Result { - Ok(Self { - alternate_setting: desc.alternate_setting, - class: desc.class, - interface_str: if desc.interface_str > 0 { Some(dev.get_string(desc.interface_str)?) } else { None }, - kind: desc.kind, - number: desc.number, - protocol: desc.protocol, - sub_class: desc.sub_class, - endpoints: endps.into_iter().collect(), - hid_descs: hid_descs.into_iter().collect(), - }) - } -} - -#[derive(Clone, Copy, Debug, Serialize)] -pub(crate) struct SuperSpeedCmp { - pub(crate) kind: u8, - pub(crate) max_burst: u8, - pub(crate) attributes: u8, - pub(crate) bytes_per_interval: u16, -} - -#[derive(Clone, Copy, Debug, Serialize)] -pub(crate) struct HidDesc { - pub(crate) kind: u8, - pub(crate) hid_spec_release: u16, - pub(crate) country: u8, - pub(crate) desc_count: u8, - pub(crate) desc_ty: u8, - pub(crate) desc_len: u16, - pub(crate) optional_desc_ty: u8, - pub(crate) optional_desc_len: u16, -} impl From for HidDesc { fn from(d: usb::HidDescriptor) -> Self { @@ -225,10 +94,34 @@ impl From for SuperSpeedCmp { } } } +impl IfDesc { + fn new( + dev: &mut Device, + desc: usb::InterfaceDescriptor, + endps: impl IntoIterator, + hid_descs: impl IntoIterator, + ) -> Result { + Ok(Self { + alternate_setting: desc.alternate_setting, + class: desc.class, + interface_str: if desc.interface_str > 0 { + Some(dev.get_string(desc.interface_str)?) + } else { + None + }, + kind: desc.kind, + number: desc.number, + protocol: desc.protocol, + sub_class: desc.sub_class, + endpoints: endps.into_iter().collect(), + hid_descs: hid_descs.into_iter().collect(), + }) + } +} /// Any descriptor that can be stored in the config desc "data" area. #[derive(Debug)] -enum AnyDescriptor { +pub enum AnyDescriptor { // These are the ones that I have found, but there are more. Device(usb::DeviceDescriptor), Config(usb::ConfigDescriptor), @@ -240,46 +133,51 @@ enum AnyDescriptor { impl AnyDescriptor { fn parse(bytes: &[u8]) -> Option<(Self, usize)> { - if bytes.len() < 2 { return None } + if bytes.len() < 2 { + return None; + } let len = bytes[0]; let kind = bytes[1]; - if bytes.len() < len.into() { return None } + if bytes.len() < len.into() { + return None; + } - Some((match kind { - 1 => Self::Device(*plain::from_bytes(bytes).ok()?), - 2 => Self::Config(*plain::from_bytes(bytes).ok()?), - 4 => Self::Interface(*plain::from_bytes(bytes).ok()?), - 5 => Self::Endpoint(*plain::from_bytes(bytes).ok()?), - 33 => Self::Hid(*plain::from_bytes(bytes).ok()?), - 48 => Self::SuperSpeedCompanion(*plain::from_bytes(bytes).ok()?), - _ => { - //panic!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes); - return None; - } - }, len.into())) + Some(( + match kind { + 1 => Self::Device(*plain::from_bytes(bytes).ok()?), + 2 => Self::Config(*plain::from_bytes(bytes).ok()?), + 4 => Self::Interface(*plain::from_bytes(bytes).ok()?), + 5 => Self::Endpoint(*plain::from_bytes(bytes).ok()?), + 33 => Self::Hid(*plain::from_bytes(bytes).ok()?), + 48 => Self::SuperSpeedCompanion(*plain::from_bytes(bytes).ok()?), + _ => { + //panic!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes); + return None; + } + }, + len.into(), + )) } } -#[derive(Deserialize)] -struct ConfigureEndpointsJson { - /// Index into the configuration descriptors of the device descriptor. - config_desc: usize, - - // TODO: Support multiple interfaces as well. -} - impl Xhci { fn set_configuration(&mut self, port: usize, config: u16) -> Result<()> { let ps = self.port_states.get_mut(&port).ok_or(Error::new(EIO))?; - let ring = ps.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().ok_or(Error::new(EIO))?; + let ring = ps + .endpoint_states + .get_mut(&0) + .ok_or(Error::new(EIO))? + .ring() + .ok_or(Error::new(EIO))?; { let (cmd, cycle) = ring.next(); cmd.setup( usb::Setup::set_configuration(config), - TransferKind::NoData, cycle, + TransferKind::NoData, + cycle, ); } { @@ -297,10 +195,18 @@ impl Xhci { let control = event.control.read(); if (status >> 24) != TrbCompletionCode::Success as u32 { - println!("SET_CONFIGURATION ERROR, COMPLETION CODE {:#0x}", (status >> 24)); + println!( + "SET_CONFIGURATION ERROR, COMPLETION CODE {:#0x}", + (status >> 24) + ); } - println!("SET_CONFIGURATION EVENT {:#0x} {:#0x} {:#0x}", event.data.read(), status, control); + println!( + "SET_CONFIGURATION EVENT {:#0x} {:#0x} {:#0x}", + event.data.read(), + status, + control + ); } self.run.ints[0].erdp.write(self.cmd.erdp()); @@ -309,8 +215,8 @@ impl Xhci { } fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { - - let req: ConfigureEndpointsJson = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; + let req: ConfigureEndpointsReq = + serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; let port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; let input_context: &mut Dma = &mut port_state.input_context; @@ -323,9 +229,11 @@ impl Xhci { const CONTEXT_ENTRIES_SHIFT: u8 = 27; let current_slot_a = input_context.device.slot.a.read(); - let current_context_entries = ((current_slot_a & CONTEXT_ENTRIES_MASK) >> CONTEXT_ENTRIES_SHIFT) as u8; + let current_context_entries = + ((current_slot_a & CONTEXT_ENTRIES_MASK) >> CONTEXT_ENTRIES_SHIFT) as u8; - let endpoints = &port_state.dev_desc.config_descs[req.config_desc].interface_descs[0].endpoints; + let endpoints = + &port_state.dev_desc.config_descs[req.config_desc].interface_descs[0].endpoints; if endpoints.len() >= 31 { return Err(Error::new(EIO)); @@ -333,7 +241,11 @@ impl Xhci { let new_context_entries = 1 + endpoints.len() as u32; - input_context.device.slot.a.write((current_slot_a & !CONTEXT_ENTRIES_MASK) | ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT) & CONTEXT_ENTRIES_MASK)); + input_context.device.slot.a.write( + (current_slot_a & !CONTEXT_ENTRIES_MASK) + | ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT) + & CONTEXT_ENTRIES_MASK), + ); let lec = self.cap.lec(); @@ -342,18 +254,33 @@ impl Xhci { input_context.add_context.writef(1 << (endp_num + 1), true); - let endp_ctx = input_context.device.endpoints.get_mut(endp_num as usize).ok_or(Error::new(EIO))?; + let endp_ctx = input_context + .device + .endpoints + .get_mut(endp_num as usize) + .ok_or(Error::new(EIO))?; let endp_desc = endpoints.get(index as usize).ok_or(Error::new(EIO))?; let superspeed_companion = endp_desc.ssc; - // TODO: Check if streams are actually supported. - let max_streams = superspeed_companion.map(|ssc| if endp_desc.is_bulk() { 1 << (ssc.attributes & 0x1F) } else { 0 }).unwrap_or(0); + let max_streams = superspeed_companion + .map(|ssc| { + if endp_desc.is_bulk() { + 1 << (ssc.attributes & 0x1F) + } else { + 0 + } + }) + .unwrap_or(0); let max_psa_size = self.cap.max_psa_size(); // TODO: Secondary streams. - let primary_streams = if max_streams != 0 { cmp::min(max_streams, max_psa_size) } else { 0 }; + let primary_streams = if max_streams != 0 { + cmp::min(max_streams, max_psa_size) + } else { + 0 + }; let linear_stream_array = if primary_streams != 0 { true } else { false }; // TODO: Interval related fields @@ -376,7 +303,7 @@ impl Xhci { } else { 0 }; - + let interval = endp_desc.interval; let max_error_count = 3; let ep_ty = endp_desc.xhci_ep_type()?; @@ -387,8 +314,8 @@ impl Xhci { // for control, 1KiB for interrupt and 3KiB for bulk and isoch. let avg_trb_len: u16 = match endp_desc.ty() { EndpointTy::Ctrl => return Err(Error::new(EIO)), // only endpoint zero is of type control, and is configured separately with the address device command. - EndpointTy::Bulk | EndpointTy::Isoch => 3072, // 3 KiB - EndpointTy::Interrupt => 1024, // 1 KiB + EndpointTy::Bulk | EndpointTy::Isoch => 3072, // 3 KiB + EndpointTy::Interrupt => 1024, // 1 KiB }; assert_eq!(ep_ty & 0x7, ep_ty); @@ -401,26 +328,51 @@ impl Xhci { let array = StreamContextArray::new(1 << (max_streams + 1))?; let array_ptr = array.register(); - assert_eq!(array_ptr & 0xFFFF_FFFF_FFFF_FF81, array_ptr, "stream ctx ptr not aligned to 16 bytes"); + assert_eq!( + array_ptr & 0xFFFF_FFFF_FFFF_FF81, + array_ptr, + "stream ctx ptr not aligned to 16 bytes" + ); - port_state.endpoint_states.insert(endp_num, EndpointState::Ready(super::RingOrStreams::Streams(array))); + port_state.endpoint_states.insert( + endp_num, + EndpointState::Ready(super::RingOrStreams::Streams(array)), + ); array_ptr } else { let ring = Ring::new(true)?; let ring_ptr = ring.register(); - assert_eq!(ring_ptr & 0xFFFF_FFFF_FFFF_FF81, ring_ptr, "ring pointer not aligned to 16 bytes"); + assert_eq!( + ring_ptr & 0xFFFF_FFFF_FFFF_FF81, + ring_ptr, + "ring pointer not aligned to 16 bytes" + ); - port_state.endpoint_states.insert(endp_num, EndpointState::Ready(super::RingOrStreams::Ring(ring))); + port_state.endpoint_states.insert( + endp_num, + EndpointState::Ready(super::RingOrStreams::Ring(ring)), + ); ring_ptr }; assert_eq!(primary_streams & 0x1F, primary_streams); - endp_ctx.a.write(u32::from(mult) << 8 | u32::from(interval) << 16 | u32::from(primary_streams) << 10 | u32::from(linear_stream_array) << 15); - endp_ctx.b.write(max_error_count << 1 | u32::from(ep_ty) << 3 | u32::from(host_initiate_disable) << 7 | u32::from(max_burst_size) << 8 | u32::from(max_packet_size) << 16); + endp_ctx.a.write( + u32::from(mult) << 8 + | u32::from(interval) << 16 + | u32::from(primary_streams) << 10 + | u32::from(linear_stream_array) << 15, + ); + endp_ctx.b.write( + max_error_count << 1 + | u32::from(ep_ty) << 3 + | u32::from(host_initiate_disable) << 7 + | u32::from(max_burst_size) << 8 + | u32::from(max_packet_size) << 16, + ); endp_ctx.trl.write(ring_ptr as u32); endp_ctx.trh.write((ring_ptr >> 32) as u32); endp_ctx.c.write(u32::from(avg_trb_len)); @@ -429,7 +381,7 @@ impl Xhci { input_context.dump_control(); self.run.ints[0].erdp.write(self.cmd.erdp()); - + { let (cmd, cycle, event) = self.cmd.next(); cmd.configure_endpoint(port_state.slot, input_context.physical(), cycle); @@ -440,7 +392,9 @@ impl Xhci { println!(" - Waiting for event"); } - if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::CommandCompletion as u8 { + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::CommandCompletion as u8 + { println!("CONFIGURE_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); return Err(Error::new(EIO)); } @@ -451,7 +405,12 @@ impl Xhci { // Tell the device about this configuration. - let configuration_value = port_state.dev_desc.config_descs.get(req.config_desc).ok_or(Error::new(EIO))?.configuration_value; + let configuration_value = port_state + .dev_desc + .config_descs + .get(req.config_desc) + .ok_or(Error::new(EIO))? + .configuration_value; self.set_configuration(port, configuration_value.into())?; Ok(()) @@ -463,10 +422,33 @@ impl Xhci { Err(Error::new(ENOSYS)) } pub(crate) fn get_dev_desc(&mut self, port_id: usize) -> Result { - let st = self.port_states.get_mut(&port_id).ok_or(Error::new(ENOENT))?; - Self::get_dev_desc_raw(&mut self.ports, &mut self.run, &mut self.cmd, &mut self.dbs, port_id, st.slot, st.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().ok_or(Error::new(EIO))?) + let st = self + .port_states + .get_mut(&port_id) + .ok_or(Error::new(ENOENT))?; + Self::get_dev_desc_raw( + &mut self.ports, + &mut self.run, + &mut self.cmd, + &mut self.dbs, + port_id, + st.slot, + st.endpoint_states + .get_mut(&0) + .ok_or(Error::new(EIO))? + .ring() + .ok_or(Error::new(EIO))?, + ) } - pub(crate) fn get_dev_desc_raw(ports: &mut [port::Port], run: &mut RuntimeRegs, cmd: &mut CommandRing, dbs: &mut [Doorbell], port_id: usize, slot: u8, ring: &mut Ring) -> Result { + pub(crate) fn get_dev_desc_raw( + ports: &mut [port::Port], + run: &mut RuntimeRegs, + cmd: &mut CommandRing, + dbs: &mut [Doorbell], + port_id: usize, + slot: u8, + ring: &mut Ring, + ) -> Result { let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); @@ -488,77 +470,90 @@ impl Xhci { let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { Some(dev.get_string(raw_dd.manufacturer_str)?) - } else { None }, + } else { + None + }, if raw_dd.product_str > 0 { Some(dev.get_string(raw_dd.product_str)?) - } else { None }, + } else { + None + }, if raw_dd.serial_str > 0 { Some(dev.get_string(raw_dd.serial_str)?) - } else { None }, + } else { + None + }, ); let (bos_desc, bos_data) = dev.get_bos()?; - let has_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); + let has_superspeed = + usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); - let config_descs = (0..raw_dd.configurations).map(|index| -> Result<_> { - let (desc, data) = dev.get_config(index)?; + let config_descs = (0..raw_dd.configurations) + .map(|index| -> Result<_> { + let (desc, data) = dev.get_config(index)?; - let extra_length = desc.total_length as usize - mem::size_of_val(&desc); - let data = &data[..extra_length]; + let extra_length = desc.total_length as usize - mem::size_of_val(&desc); + let data = &data[..extra_length]; - let mut i = 0; - let mut descriptors = Vec::new(); + let mut i = 0; + let mut descriptors = Vec::new(); - while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) { - descriptors.push(descriptor); - i += len; - } + while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) { + descriptors.push(descriptor); + i += len; + } - let mut interface_descs = SmallVec::new(); - let mut iter = descriptors.into_iter(); + let mut interface_descs = SmallVec::new(); + let mut iter = descriptors.into_iter(); - while let Some(item) = iter.next() { - if let AnyDescriptor::Interface(idesc) = item { - let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); - let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); + while let Some(item) = iter.next() { + if let AnyDescriptor::Interface(idesc) = item { + let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); + let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); - for _ in 0..idesc.endpoints { - let next = match iter.next() { - Some(AnyDescriptor::Endpoint(n)) => n, - Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { - hid_descs.push(h.into()); - break; - } - _ => break, - }; - let mut endp = EndpDesc::from(next); - - if has_superspeed { + for _ in 0..idesc.endpoints { let next = match iter.next() { - Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, + Some(AnyDescriptor::Endpoint(n)) => n, + Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { + hid_descs.push(h.into()); + break; + } _ => break, }; - endp.ssc = Some(SuperSpeedCmp::from(next)); + let mut endp = EndpDesc::from(next); + + if has_superspeed { + let next = match iter.next() { + Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, + _ => break, + }; + endp.ssc = Some(SuperSpeedCmp::from(next)); + } + endpoints.push(endp); } - endpoints.push(endp); + + interface_descs.push(IfDesc::new(&mut dev, idesc, endpoints, hid_descs)?); + } else { + // TODO + break; } - - interface_descs.push(IfDesc::new(&mut dev, idesc, endpoints, hid_descs)?); - } else { - // TODO - break; } - } - Ok(ConfDesc { - kind: desc.kind, - configuration: if desc.configuration_str > 0 { Some(dev.get_string(desc.configuration_str)?) } else { None }, - configuration_value: desc.configuration_value, - attributes: desc.attributes, - max_power: desc.max_power, - interface_descs, + Ok(ConfDesc { + kind: desc.kind, + configuration: if desc.configuration_str > 0 { + Some(dev.get_string(desc.configuration_str)?) + } else { + None + }, + configuration_value: desc.configuration_value, + attributes: desc.attributes, + max_power: desc.max_power, + interface_descs, + }) }) - }).collect::>>()?; + .collect::>>()?; Ok(DevDesc { kind: raw_dd.kind, @@ -577,7 +572,11 @@ impl Xhci { }) } fn write_port_desc(&mut self, port_id: usize, contents: &mut Vec) -> Result<()> { - let dev_desc = &self.port_states.get(&port_id).ok_or(Error::new(ENOENT))?.dev_desc; + let dev_desc = &self + .port_states + .get(&port_id) + .ok_or(Error::new(ENOENT))? + .dev_desc; serde_json::to_writer_pretty(contents, dev_desc).unwrap(); Ok(()) } @@ -631,15 +630,24 @@ impl Xhci { } as u8; let setup = Setup { - kind: (direction << USB_SETUP_DIR_SHIFT) | (ty << USB_SETUP_REQ_TY_SHIFT) | (recipient << USB_SETUP_RECIPIENT_SHIFT), + kind: (direction << USB_SETUP_DIR_SHIFT) + | (ty << USB_SETUP_REQ_TY_SHIFT) + | (recipient << USB_SETUP_RECIPIENT_SHIFT), request: req.request, value: req.value, index: req.index, length: req.length, }; - let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?; - let ring = match port_state.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))? { + let port_state = self + .port_states + .get_mut(&port_num) + .ok_or(Error::new(EBADF))?; + let ring = match port_state + .endpoint_states + .get_mut(&0) + .ok_or(Error::new(EIO))? + { EndpointState::Ready(super::RingOrStreams::Ring(ref mut ring)) => ring, // Control endpoints never use streams @@ -675,28 +683,43 @@ impl Xhci { impl SchemeMut for Xhci { fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - if uid != 0 { return Err(Error::new(EACCES)) } + if uid != 0 { + return Err(Error::new(EACCES)); + } - let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_start_matches('/'); + let path_str = str::from_utf8(path) + .or(Err(Error::new(ENOENT)))? + .trim_start_matches('/'); - let components = path::Path::new(path_str).components().map(|component| -> Option<_> { - match component { - path::Component::Normal(n) => Some(n.to_str()?), - _ => None, - } - }).collect::>>().ok_or(Error::new(ENOENT))?; + let components = path::Path::new(path_str) + .components() + .map(|component| -> Option<_> { + match component { + path::Component::Normal(n) => Some(n.to_str()?), + _ => None, + } + }) + .collect::>>() + .ok_or(Error::new(ENOENT))?; let handle = match &components[..] { - &[] => if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { - let mut contents = Vec::new(); + &[] => { + if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { + let mut contents = Vec::new(); - for (index, _) in self.ports.iter().enumerate().filter(|(_, port)| port.flags().contains(port::PortFlags::PORT_CCS)) { - write!(contents, "port{}\n", index).unwrap(); + for (index, _) in self + .ports + .iter() + .enumerate() + .filter(|(_, port)| port.flags().contains(port::PortFlags::PORT_CCS)) + { + write!(contents, "port{}\n", index).unwrap(); + } + + Handle::TopLevel(0, contents) + } else { + return Err(Error::new(EISDIR)); } - - Handle::TopLevel(0, contents) - } else { - return Err(Error::new(EISDIR)); } &[port, port_tl] if port.starts_with("port") => { let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; @@ -760,7 +783,6 @@ impl SchemeMut for Xhci { } _ => return Err(Error::new(ENOENT)), } - } &[port, "endpoints", endpoint_num_str] if port.starts_with("port") => { let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; @@ -770,15 +792,24 @@ impl SchemeMut for Xhci { return Err(Error::new(EISDIR)); } - let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(ENOENT))?; + let port_state = self + .port_states + .get_mut(&port_num) + .ok_or(Error::new(ENOENT))?; /*if self.dev_ctx.contexts[port_state.slot as usize].endpoints.get(endpoint_num as usize).ok_or(Error::new(ENOENT))?.a.read() & 0b111 != 1 { return Err(Error::new(ENXIO)); // TODO: Find a proper error code for "endpoint not initialized". }*/ - let contents = match port_state.endpoint_states.get(&endpoint_num).ok_or(Error::new(ENOENT))? { + let contents = match port_state + .endpoint_states + .get(&endpoint_num) + .ok_or(Error::new(ENOENT))? + { EndpointState::Init => "status\n", EndpointState::Ready { .. } => "transfer\nstatus\n", - }.as_bytes().to_owned(); + } + .as_bytes() + .to_owned(); Handle::Endpoint(port_num, endpoint_num, EndpointHandleTy::Root(0, contents)) } @@ -786,9 +817,18 @@ impl SchemeMut for Xhci { let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; let endpoint_num = endpoint_num_str.parse::().or(Err(Error::new(ENOENT)))?; - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { return Err(Error::new(EISDIR)) } + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(EISDIR)); + } - if self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?.endpoint_states.get(&endpoint_num).is_none() { + if self + .port_states + .get(&port_num) + .ok_or(Error::new(ENOENT))? + .endpoint_states + .get(&endpoint_num) + .is_none() + { return Err(Error::new(ENOENT)); } @@ -805,19 +845,27 @@ impl SchemeMut for Xhci { }; Handle::Endpoint(port_num, endpoint_num, st) } - &[port] if port.starts_with("port") => if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { - let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; - let mut contents = Vec::new(); + &[port] if port.starts_with("port") => { + if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { + let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; + let mut contents = Vec::new(); - write!(contents, "descriptors\nendpoints\n").unwrap(); - - if dbg!(self.slot_state(self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?.slot as usize)) != SlotState::Configured as u8 { - write!(contents, "configure\n").unwrap(); + write!(contents, "descriptors\nendpoints\n").unwrap(); + + if dbg!(self.slot_state( + self.port_states + .get(&port_num) + .ok_or(Error::new(ENOENT))? + .slot as usize + )) != SlotState::Configured as u8 + { + write!(contents, "configure\n").unwrap(); + } + + Handle::Port(port_num, 0, contents) + } else { + return Err(Error::new(EISDIR)); } - - Handle::Port(port_num, 0, contents) - } else { - return Err(Error::new(EISDIR)); } _ => return Err(Error::new(ENOENT)), }; @@ -831,7 +879,9 @@ impl SchemeMut for Xhci { fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { match self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::TopLevel(_, ref buf) | Handle::Port(_, _, ref buf) | Handle::Endpoints(_, _, ref buf) => { + Handle::TopLevel(_, ref buf) + | Handle::Port(_, _, ref buf) + | Handle::Endpoints(_, _, ref buf) => { stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; } @@ -846,7 +896,7 @@ impl SchemeMut for Xhci { stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; } - } + }, Handle::ConfigureEndpoints(_) | Handle::PortReq(_) => { stat.st_mode = MODE_CHR | 0o200; // write only } @@ -860,16 +910,29 @@ impl SchemeMut for Xhci { match self.handles.get(&fd).ok_or(Error::new(EBADF))? { Handle::TopLevel(_, _) => write!(src, "/").unwrap(), Handle::Port(port_num, _, _) => write!(src, "/port{}/", port_num).unwrap(), - Handle::PortDesc(port_num, _, _) => write!(src, "/port{}/descriptors", port_num).unwrap(), + Handle::PortDesc(port_num, _, _) => { + write!(src, "/port{}/descriptors", port_num).unwrap() + } Handle::PortState(port_num, _) => write!(src, "/port{}/state", port_num).unwrap(), Handle::PortReq(port_num) => write!(src, "/port{}/request", port_num).unwrap(), - Handle::Endpoints(port_num, _, _) => write!(src, "/port{}/endpoints/", port_num).unwrap(), - Handle::Endpoint(port_num, endp_num, st) => write!(src, "/port{}/endpoints/{}/{}", port_num, endp_num, match st { - EndpointHandleTy::Root(_, _) => "", - EndpointHandleTy::Status(_) => "status", - EndpointHandleTy::Transfer => "transfer", - }).unwrap(), - Handle::ConfigureEndpoints(port_num) => write!(src, "/port{}/configure", port_num).unwrap(), + Handle::Endpoints(port_num, _, _) => { + write!(src, "/port{}/endpoints/", port_num).unwrap() + } + Handle::Endpoint(port_num, endp_num, st) => write!( + src, + "/port{}/endpoints/{}/{}", + port_num, + endp_num, + match st { + EndpointHandleTy::Root(_, _) => "", + EndpointHandleTy::Status(_) => "status", + EndpointHandleTy::Transfer => "transfer", + } + ) + .unwrap(), + Handle::ConfigureEndpoints(port_num) => { + write!(src, "/port{}/configure", port_num).unwrap() + } } let bytes_to_read = cmp::min(src.len(), buffer.len()); buffer[..bytes_to_read].copy_from_slice(&src[..bytes_to_read]); @@ -879,7 +942,11 @@ impl SchemeMut for Xhci { fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { // Directories, or fixed files - Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) | Handle::PortDesc(_, ref mut offset, ref buf) | Handle::Endpoints(_, ref mut offset, ref buf) | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref buf)) => { + Handle::TopLevel(ref mut offset, ref buf) + | Handle::Port(_, ref mut offset, ref buf) + | Handle::PortDesc(_, ref mut offset, ref buf) + | Handle::Endpoints(_, ref mut offset, ref buf) + | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref buf)) => { *offset = match whence { SEEK_SET => cmp::max(0, cmp::min(pos, buf.len())), SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, buf.len())), @@ -889,7 +956,8 @@ impl SchemeMut for Xhci { Ok(*offset) } // Read-only unknown-length status strings - Handle::Endpoint(_, _, EndpointHandleTy::Status(ref mut offset)) | Handle::PortState(_, ref mut offset) => { + Handle::Endpoint(_, _, EndpointHandleTy::Status(ref mut offset)) + | Handle::PortState(_, ref mut offset) => { *offset = match whence { SEEK_SET => cmp::max(0, pos), SEEK_CUR => cmp::max(0, *offset + pos), @@ -899,13 +967,19 @@ impl SchemeMut for Xhci { Ok(*offset) } // Write-once configure or transfer - Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) | Handle::PortReq(_) => return Err(Error::new(ESPIPE)), + Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) | Handle::PortReq(_) => { + return Err(Error::new(ESPIPE)) + } } } fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) | Handle::Endpoints(_, ref mut offset, ref src_buf) | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref src_buf)) => { + Handle::TopLevel(ref mut offset, ref src_buf) + | Handle::Port(_, ref mut offset, ref src_buf) + | Handle::PortDesc(_, ref mut offset, ref src_buf) + | Handle::Endpoints(_, ref mut offset, ref src_buf) + | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref src_buf)) => { let max_bytes_to_read = cmp::min(src_buf.len(), buf.len()); let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset; @@ -925,7 +999,17 @@ impl SchemeMut for Xhci { } EndpointHandleTy::Status(ref mut offset) => { let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?; - let status = self.dev_ctx.contexts.get(ps.slot as usize).ok_or(Error::new(EBADF))?.endpoints.get(endp_num as usize).ok_or(Error::new(EBADF))?.a.read() & ENDPOINT_CONTEXT_STATUS_MASK; + let status = self + .dev_ctx + .contexts + .get(ps.slot as usize) + .ok_or(Error::new(EBADF))? + .endpoints + .get(endp_num as usize) + .ok_or(Error::new(EBADF))? + .a + .read() + & ENDPOINT_CONTEXT_STATUS_MASK; let string = match status { // TODO: Give this its own enum. @@ -935,7 +1019,8 @@ impl SchemeMut for Xhci { 3 => "stopped", 4 => "error", _ => "unknown", - }.as_bytes(); + } + .as_bytes(); Ok(Self::write_dyn_string(string, buf, offset)) } @@ -943,7 +1028,13 @@ impl SchemeMut for Xhci { }, &mut Handle::PortState(port_num, ref mut offset) => { let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?; - let state = self.dev_ctx.contexts.get(ps.slot as usize).ok_or(Error::new(EBADF))?.slot.state(); + let state = self + .dev_ctx + .contexts + .get(ps.slot as usize) + .ok_or(Error::new(EBADF))? + .slot + .state(); let string = match state { // TODO: Give this its own enum. @@ -952,7 +1043,8 @@ impl SchemeMut for Xhci { 2 => "addressed", 3 => "configured", _ => "unknown", - }.as_bytes(); + } + .as_bytes(); Ok(Self::write_dyn_string(string, buf, offset)) } diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 53cf648a6a..6eb6169b28 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -1,6 +1,6 @@ +use crate::usb; use std::{fmt, mem}; use syscall::io::{Io, Mmio}; -use crate::usb; #[repr(u8)] pub enum TrbType { @@ -127,12 +127,7 @@ impl Trb { } pub fn reserved(&mut self, cycle: bool) { - self.set( - 0, - 0, - ((TrbType::Reserved as u32) << 10) | - (cycle as u32) - ); + self.set(0, 0, ((TrbType::Reserved as u32) << 10) | (cycle as u32)); } pub fn completion_code(&self) -> u8 { @@ -149,28 +144,21 @@ impl Trb { self.set( address as u64, 0, - ((TrbType::Link as u32) << 10) | - ((toggle as u32) << 1) | - (cycle as u32) + ((TrbType::Link as u32) << 10) | ((toggle as u32) << 1) | (cycle as u32), ); } pub fn no_op_cmd(&mut self, cycle: bool) { - self.set( - 0, - 0, - ((TrbType::NoOpCmd as u32) << 10) | - (cycle as u32) - ); + self.set(0, 0, ((TrbType::NoOpCmd as u32) << 10) | (cycle as u32)); } pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) { self.set( 0, 0, - (((slot_type as u32) & 0x1F) << 16) | - ((TrbType::EnableSlot as u32) << 10) | - (cycle as u32) + (((slot_type as u32) & 0x1F) << 16) + | ((TrbType::EnableSlot as u32) << 10) + | (cycle as u32), ); } @@ -178,21 +166,23 @@ impl Trb { self.set( input as u64, 0, - ((slot_id as u32) << 24) | - ((TrbType::AddressDevice as u32) << 10) | - (cycle as u32) + ((slot_id as u32) << 24) | ((TrbType::AddressDevice as u32) << 10) | (cycle as u32), ); } // Synchronizes the input context endpoints with the device context endpoints, I think. pub fn configure_endpoint(&mut self, slot_id: u8, input_ctx_ptr: usize, cycle: bool) { - assert_eq!(input_ctx_ptr & 0xFFFF_FFFF_FFFF_FF80, input_ctx_ptr, "unaligned input context ptr"); + assert_eq!( + input_ctx_ptr & 0xFFFF_FFFF_FFFF_FF80, + input_ctx_ptr, + "unaligned input context ptr" + ); self.set( input_ctx_ptr as u64, 0, - (u32::from(slot_id) << 24) | - ((TrbType::ConfigureEndpoint as u32) << 10) | - (cycle as u32), + (u32::from(slot_id) << 24) + | ((TrbType::ConfigureEndpoint as u32) << 10) + | (cycle as u32), ) } @@ -200,10 +190,10 @@ impl Trb { self.set( unsafe { mem::transmute(setup) }, 8, - ((transfer as u32) << 16) | - ((TrbType::SetupStage as u32) << 10) | - (1 << 6) | - (cycle as u32) + ((transfer as u32) << 16) + | ((TrbType::SetupStage as u32) << 10) + | (1 << 6) + | (cycle as u32), ); } @@ -211,9 +201,7 @@ impl Trb { self.set( buffer as u64, length as u32, - ((input as u32) << 16) | - ((TrbType::DataStage as u32) << 10) | - (cycle as u32) + ((input as u32) << 16) | ((TrbType::DataStage as u32) << 10) | (cycle as u32), ); } @@ -221,24 +209,34 @@ impl Trb { self.set( 0, 0, - ((input as u32) << 16) | - ((TrbType::StatusStage as u32) << 10) | - (1 << 5) | - (cycle as u32) + ((input as u32) << 16) + | ((TrbType::StatusStage as u32) << 10) + | (1 << 5) + | (cycle as u32), ); } } impl fmt::Debug for Trb { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Trb {{ data: {:>016X}, status: {:>08X}, control: {:>08X} }}", - self.data.read(), self.status.read(), self.control.read()) + write!( + f, + "Trb {{ data: {:>016X}, status: {:>08X}, control: {:>08X} }}", + self.data.read(), + self.status.read(), + self.control.read() + ) } } impl fmt::Display for Trb { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "({:>016X}, {:>08X}, {:>08X})", - self.data.read(), self.status.read(), self.control.read()) + write!( + f, + "({:>016X}, {:>08X}, {:>08X})", + self.data.read(), + self.status.read(), + self.control.read() + ) } } From b308dad7c678079fe198f76c9f7926976ffac6e8 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 8 Feb 2020 10:21:21 +0100 Subject: [PATCH 0326/1301] Add a basic HID driver unable to parse report descs. Custom device requests are now implemented though. --- Cargo.lock | 46 ++++++ Cargo.toml | 1 + usbhidd/.gitignore | 1 + usbhidd/Cargo.toml | 14 ++ usbhidd/src/main.rs | 266 ++++++++++++++++++++++++++++++++++ usbscsid/Cargo.toml | 2 + xhcid/Cargo.toml | 1 + xhcid/drivers.toml | 6 + xhcid/src/driver_interface.rs | 202 ++++++++++++++++++++++++++ xhcid/src/usb/config.rs | 13 ++ xhcid/src/usb/device.rs | 15 ++ xhcid/src/xhci/extended.rs | 10 ++ xhcid/src/xhci/mod.rs | 22 ++- xhcid/src/xhci/scheme.rs | 202 +++++++++++++++----------- xhcid/src/xhci/trb.rs | 1 + 15 files changed, 712 insertions(+), 90 deletions(-) create mode 100644 usbhidd/.gitignore create mode 100644 usbhidd/Cargo.toml create mode 100644 usbhidd/src/main.rs create mode 100644 xhcid/src/xhci/extended.rs diff --git a/Cargo.lock b/Cargo.lock index c4d93077a9..3ac510dde4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,6 +53,11 @@ dependencies = [ "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bgad" version = "0.1.0" @@ -1070,6 +1075,24 @@ dependencies = [ "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thiserror" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "time" version = "0.1.42" @@ -1305,9 +1328,22 @@ dependencies = [ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "usbhidd" +version = "0.1.0" +dependencies = [ + "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "xhcid 0.1.0", +] + [[package]] name = "usbscsid" version = "0.1.0" +dependencies = [ + "xhcid 0.1.0", +] [[package]] name = "utf8parse" @@ -1322,6 +1358,11 @@ dependencies = [ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ux" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vboxd" version = "0.1.0" @@ -1423,6 +1464,7 @@ dependencies = [ "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1431,6 +1473,7 @@ dependencies = [ "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" @@ -1541,6 +1584,8 @@ dependencies = [ "checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" "checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8" "checksum termion 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "818ef3700c2a7b447dca1a1dd28341fe635e6ee103c806c636bb9c929991b2cd" +"checksum thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "205684fd018ca14432b12cce6ea3d46763311a571c3d294e71ba3f01adcf1aad" +"checksum thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57e4d2e50ca050ed44fb58309bdce3efa79948f84f9993ad1978de5eebdce5a7" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" @@ -1566,6 +1611,7 @@ dependencies = [ "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" +"checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" "checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" diff --git a/Cargo.toml b/Cargo.toml index 023056b6c8..0044204257 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,5 +15,6 @@ members = [ "vboxd", "vesad", "xhcid", + "usbhidd", "usbscsid", ] diff --git a/usbhidd/.gitignore b/usbhidd/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/usbhidd/.gitignore @@ -0,0 +1 @@ +/target diff --git a/usbhidd/Cargo.toml b/usbhidd/Cargo.toml new file mode 100644 index 0000000000..f535b7e35e --- /dev/null +++ b/usbhidd/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "usbhidd" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2018" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +base64 = "0.11" +bitflags = "1.2" +ux = "0.1" +xhcid = { path = "../xhcid" } diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs new file mode 100644 index 0000000000..76c80af142 --- /dev/null +++ b/usbhidd/src/main.rs @@ -0,0 +1,266 @@ +use std::convert::TryInto; +use std::env; + +use bitflags::bitflags; +use ux::{u2, u4}; +use xhcid_interface::{DevDesc, XhciClientHandle}; + +/*#[repr(u8)] +enum Protocol { + +}*/ + +bitflags! { + pub struct MainItemFlags: u32 { + const CONSTANT = 1 << 0; + const VARIABLE = 1 << 1; + const RELATIVE = 1 << 2; + const WRAP = 1 << 3; + const NONLINEAR = 1 << 4; + const NO_PREFERRED_STATE = 1 << 5; + const NULL_STATE = 1 << 6; + const VOLATILE = 1 << 7; + const BUFFERED_BYTES = 1 << 8; + } +} +#[repr(u8)] +pub enum MainCollectionFlags { + Physical = 0, + Application, + Logical, + Report, + NamedArray, + UsageSwitch, + UsageModifier, +} + +const REPORT_DESC_TY: u8 = 34; + +#[derive(Debug)] +enum MainItem { + Input(u32), + Output(u32), + Feature(u32), + Collection(u8), + EndOfCollection, +} +#[derive(Debug)] +enum GlobalItem { + UsagePage(u32), + LogicalMinimum(u32), + LogicalMaximum(u32), + PhysicalMinimum(u32), + PhysicalMaximum(u32), + UnitExponent(u32), + Unit(u32), + ReportSize(u32), + RepordId(u32), + ReportCount(u32), + Push(u32), + Pop(u32), +} +#[derive(Debug)] +enum LocalItem { + Usage(u32), + UsageMinimum(u32), + UsageMaximum(u32), + DesignatorIndex(u32), + DesignatorMinimum(u32), + DesignatorMaximum(u32), + StringIndex(u32), + StringMinimum(u32), + StringMaximum(u32), + Delimeter(u32), +} +#[derive(Debug)] +enum ReportItem { + Main(MainItem), + Global(GlobalItem), + Local(LocalItem), +} +impl From for ReportItem { + fn from(main: MainItem) -> Self { + Self::Main(main) + } +} +impl From for ReportItem { + fn from(main: GlobalItem) -> Self { + Self::Global(main) + } +} +impl From for ReportItem { + fn from(main: LocalItem) -> Self { + Self::Local(main) + } +} + +impl ReportItem { + fn size(size: u2) -> u8 { + match u8::from(size) { + 0 => 0, + 1 => 1, + 2 => 2, + 3 => 4, + _ => unreachable!(), + } + } + fn parse_short(size: u2, ty: u2, tag: u4, bytes: &[u8]) -> Option<(Self, usize)> { + Some(match (u8::from(tag), u8::from(ty)) { + (tag, 0b00) => { + let real_size = Self::size(size) as usize; + let mut value_bytes = [0u8; 4]; + if real_size > 0 { + value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) + }; + let value = u32::from_le_bytes(value_bytes); + + match tag { + 0b1000 => (MainItem::Input(value).into(), 1 + real_size), + 0b1001 => (MainItem::Output(value).into(), 1 + real_size), + 0b1011 => (MainItem::Feature(value).into(), 1 + real_size), + 0b1010 => (MainItem::Collection(bytes[0]).into(), 2), + 0b1100 => (MainItem::EndOfCollection.into(), 1 + real_size), + _ => return None, + } + } + (tag, 0b01) => { + let real_size = Self::size(size) as usize; + let mut value_bytes = [0u8; 4]; + if real_size > 0 { + value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) + }; + let value = u32::from_le_bytes(value_bytes); + match tag { + 0b0000 => (GlobalItem::UsagePage(value).into(), 1 + real_size), + 0b0001 => (GlobalItem::LogicalMinimum(value).into(), 1 + real_size), + 0b0010 => (GlobalItem::LogicalMaximum(value).into(), 1 + real_size), + 0b0011 => (GlobalItem::PhysicalMinimum(value).into(), 1 + real_size), + 0b0100 => (GlobalItem::PhysicalMaximum(value).into(), 1 + real_size), + 0b0101 => (GlobalItem::UnitExponent(value).into(), 1 + real_size), + 0b0110 => (GlobalItem::Unit(value).into(), 1 + real_size), + 0b0111 => (GlobalItem::ReportSize(value).into(), 1 + real_size), + 0b1000 => (GlobalItem::RepordId(value).into(), 1 + real_size), + 0b1001 => (GlobalItem::ReportCount(value).into(), 1 + real_size), + 0b1010 => (GlobalItem::Push(value).into(), 1 + real_size), + 0b1011 => (GlobalItem::Pop(value).into(), 1 + real_size), + _ => return None, + } + } + (tag, 0b10) => { + let real_size = Self::size(size) as usize; + let mut value_bytes = [0u8; 4]; + if real_size > 0 { + value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) + }; + let value = u32::from_le_bytes(value_bytes); + match tag { + 0b0000 => (LocalItem::Usage(value).into(), 1 + real_size), + 0b0001 => (LocalItem::UsageMinimum(value).into(), 1 + real_size), + 0b0010 => (LocalItem::UsageMaximum(value).into(), 1 + real_size), + 0b0011 => (LocalItem::DesignatorIndex(value).into(), 1 + real_size), + 0b0100 => (LocalItem::DesignatorMinimum(value).into(), 1 + real_size), + 0b0101 => (LocalItem::DesignatorMaximum(value).into(), 1 + real_size), + 0b0111 => (LocalItem::StringIndex(value).into(), 1 + real_size), + 0b1000 => (LocalItem::StringMinimum(value).into(), 1 + real_size), + 0b1001 => (LocalItem::StringMaximum(value).into(), 1 + real_size), + 0b1010 => (LocalItem::Delimeter(value).into(), 1 + real_size), + _ => return None, + } + } + (_, 0b11) => panic!("Calling parse_short but with long item"), + _ => unreachable!(), + }) + } + fn parse_long(size: u8, long_tag: u8, bytes: &[u8]) -> (Self, usize) { + todo!() + } +} + +struct ReportIter<'a> { + desc: &'a [u8], + offset: usize, +} +impl<'a> ReportIter<'a> { + fn new(desc: &'a [u8]) -> Self { + Self { desc, offset: 0 } + } +} +impl<'a> Iterator for ReportIter<'a> { + type Item = ReportItem; + + fn next(&mut self) -> Option { + let first = self.desc[self.offset]; + let size = first & 0b11; + let ty = first & 0b1100 >> 2; + let tag = first & 0b11110000 >> 4; + + if size == 0b10 && ty == 3 && tag == 0b1111 { + // Long Item + let size = self.desc[self.offset + 1]; + let long_tag = self.desc[self.offset + 2]; + let data = &self.desc[self.offset + 2..self.offset + 2 + size as usize]; + + let (item, len) = ReportItem::parse_long(size, long_tag, data); + self.offset += len; + Some(item) + } else { + // Short Item + + // Although there is a 2-bit size field, the size doesn't have to be the actual size of the data. + let data = &self.desc[self.offset + 1..]; + + let (item, len) = + ReportItem::parse_short(u2::new(size), u2::new(ty), u4::new(tag), data)?; + self.offset += len; + Some(item) + } + } +} + +fn main() { + let mut args = env::args().skip(1); + + const USAGE: &'static str = "usbhidd "; + + let scheme = args.next().expect(USAGE); + let port = args + .next() + .expect(USAGE) + .parse::() + .expect("Expected integer as input of port"); + let protocol = args.next().expect(USAGE); + + println!( + "USB HID driver spawned with scheme `{}`, port {}, protocol {}", + scheme, port, protocol + ); + + let handle = XhciClientHandle::new(scheme, port); + let dev_desc: DevDesc = handle + .get_standard_descs() + .expect("Failed to get standard descriptors"); + let hid_desc = dev_desc.config_descs[0].interface_descs[0].hid_descs[0]; + + // TODO: Currently it's assumed that config 0 and interface 0 are used. + + let interface_num = 0; + let report_desc_len = hid_desc.desc_len; + assert_eq!(hid_desc.desc_ty, REPORT_DESC_TY); + + let report_desc_bytes: Vec = handle + .get_class_descriptor( + u16::from(REPORT_DESC_TY) << 8, + interface_num, + report_desc_len, + ) + .expect("Failed to retrieve report descriptor"); + use std::io::Write as _; + std::io::stdout() + .write_all(base64::encode(&report_desc_bytes).as_bytes()) + .unwrap(); + let iterator = ReportIter::new(&report_desc_bytes); + + for item in iterator { + println!("HID ITEM {:?}", item); + } +} diff --git a/usbscsid/Cargo.toml b/usbscsid/Cargo.toml index 098e899269..90c80d0779 100644 --- a/usbscsid/Cargo.toml +++ b/usbscsid/Cargo.toml @@ -3,7 +3,9 @@ name = "usbscsid" version = "0.1.0" authors = ["4lDO2 <4lDO2@protonmail.com>"] edition = "2018" +license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +xhcid = { path = "../xhcid" } diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index a7a055459c..7a2b3de990 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -21,4 +21,5 @@ redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1", features = ["serde"] } +thiserror = "1" toml = "0.5" diff --git a/xhcid/drivers.toml b/xhcid/drivers.toml index 426a19114e..53cfc0eb39 100644 --- a/xhcid/drivers.toml +++ b/xhcid/drivers.toml @@ -3,3 +3,9 @@ name = "SCSI over USB" class = 8 # Mass Storage class subclass = 6 # SCSI transparent command set command = ["/bin/usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"] + +[[drivers]] +name = "USB HID" +class = 3 # HID class +subclass = -1 +command = ["/bin/usbhidd", "$SCHEME", "$PORT", "$IF_PROTO"] diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 1b2a158a91..b20cce5e74 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -1,9 +1,14 @@ pub extern crate serde; pub extern crate smallvec; +use std::fs::File; +use std::io::prelude::*; +use std::{io, result, str}; + use serde::{Deserialize, Serialize}; use smallvec::SmallVec; use syscall::{Error, Result, EINVAL}; +use thiserror::Error; pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK}; @@ -100,6 +105,31 @@ impl EndpDesc { _ => return Err(Error::new(EINVAL)), }) } + pub fn max_streams(&self) -> u8 { + self.ssc + .as_ref() + .map(|ssc| { + if self.is_bulk() { + 1 << (ssc.attributes & 0x1F) + } else { + 0 + } + }) + .unwrap_or(0) + } + pub fn isoch_mult(&self, lec: bool) -> u8 { + if !lec && self.is_isoch() { + self.ssc + .as_ref() + .map(|ssc| ssc.attributes & 0x3) + .unwrap_or(0) + } else { + 0 + } + } + pub fn max_burst(&self) -> u8 { + self.ssc.map(|ssc| ssc.max_burst).unwrap_or(0) + } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct IfDesc { @@ -133,3 +163,175 @@ pub struct HidDesc { pub optional_desc_ty: u8, pub optional_desc_len: u16, } +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct PortReq<'a> { + pub direction: &'a str, + pub req_type: &'a str, + pub req_recipient: &'a str, + pub request: u8, + pub value: u16, + pub index: u16, + pub length: u16, + pub transfers_data: bool, +} + +#[derive(Debug)] +pub struct XhciClientHandle { + scheme: String, + port: usize, +} +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum PortState { + EnabledOrDisabled, + Default, + Addressed, + Configured, +} +impl PortState { + pub fn as_str(&self) -> &'static str { + match self { + Self::EnabledOrDisabled => "enabled_or_disabled", + Self::Default => "default", + Self::Addressed => "addressed", + Self::Configured => "configured", + } + } +} +#[derive(Debug, Error)] +#[error("invalid input")] +pub struct Invalid; + +impl str::FromStr for PortState { + type Err = Invalid; + + fn from_str(s: &str) -> result::Result { + Ok(match s { + "enabled_or_disabled" | "enabled/disabled" => Self::EnabledOrDisabled, + "default" => Self::Default, + "addressed" => Self::Addressed, + "configured" => Self::Configured, + _ => return Err(Invalid), + }) + } +} + +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum EndpointStatus { + Disabled, + Enabled, + Halted, + Stopped, + Error, +} + +impl EndpointStatus { + pub fn as_str(&self) -> &'static str { + match self { + Self::Disabled => "disabled", + Self::Enabled => "enabled", + Self::Halted => "halted", + Self::Stopped => "stopped", + Self::Error => "error", + } + } +} + +impl str::FromStr for EndpointStatus { + type Err = Invalid; + + fn from_str(s: &str) -> result::Result { + Ok(match s { + "disabled" => Self::Disabled, + "enabled" => Self::Enabled, + "halted" => Self::Halted, + "stopped" => Self::Stopped, + "error" => Self::Error, + _ => return Err(Invalid), + }) + } +} + +impl XhciClientHandle { + pub fn new(scheme: String, port: usize) -> Self { + Self { scheme, port } + } + + pub fn get_standard_descs(&self) -> result::Result { + let path = format!("{}:port{}/descriptors", self.scheme, self.port); + let json = std::fs::read(path)?; + std::io::stdout().lock().write_all(&json)?; + Ok(serde_json::from_slice(&json)?) + } + pub fn configure_endpoints( + &self, + req: &ConfigureEndpointsReq, + ) -> result::Result<(), XhciClientHandleError> { + let path = format!("{}:port{}/configure_endpoints", self.scheme, self.port); + serde_json::to_writer(File::open(path)?, req)?; + Ok(()) + } + pub fn port_state(&self) -> result::Result { + let path = format!("{}:port{}/state", self.scheme, self.port); + let string = std::fs::read_to_string(path)?; + Ok(string.parse()?) + } + pub fn endpoint_status( + &self, + num: u8, + ) -> result::Result { + let path = format!("{}:port{}/endpoints/{}/status", self.scheme, self.port, num); + let string = std::fs::read_to_string(path)?; + Ok(string.parse()?) + } + // TODO: Device-specific request, with data + pub fn get_class_descriptor( + &self, + value: u16, + index: u16, + length: u16, + ) -> result::Result, XhciClientHandleError> { + // TODO: Base this on the to-be-written generic device request function. + let req = PortReq { + direction: "device_to_host", + req_type: "standard", // TODO: Add as a parameter, with its own enum. + req_recipient: "interface", + request: 0x06, + value, + index, + length, + transfers_data: true, + }; + let json = serde_json::to_vec(&req)?; + + let path = format!("{}:port{}/request", self.scheme, self.port); + let mut file = File::open(path)?; + + let bytes_written = file.write(&json)?; + if bytes_written != json.len() { + return Err(XhciClientHandleError::InvalidResponse(Invalid)); + } + + let mut buf = vec![0u8; length as usize]; + let bytes_read = file.read(&mut buf)?; + if bytes_read != buf.len() { + println!("HIDd B"); + return Err(XhciClientHandleError::InvalidResponse(Invalid)); + } + + Ok(buf) + } +} + +#[derive(Debug, Error)] +pub enum XhciClientHandleError { + #[error("i/o error: {0}")] + IoError(#[from] io::Error), + + #[error("serialization error: {0}")] + SerializationError(#[from] serde_json::Error), + + #[error("invalid response")] + InvalidResponse(#[from] Invalid), +} diff --git a/xhcid/src/usb/config.rs b/xhcid/src/usb/config.rs index 28dfe96199..11f5e4cbbd 100644 --- a/xhcid/src/usb/config.rs +++ b/xhcid/src/usb/config.rs @@ -12,3 +12,16 @@ pub struct ConfigDescriptor { } unsafe impl plain::Plain for ConfigDescriptor {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct OtherSpeedConfig { + pub length: u8, + pub kind: u8, + pub total_length: u16, + pub interfaces: u8, + pub configuration_value: u8, + pub configuration_str: u8, + pub attributes: u8, + pub max_power: u8, +} diff --git a/xhcid/src/usb/device.rs b/xhcid/src/usb/device.rs index 93f50234ce..7c99946bfb 100644 --- a/xhcid/src/usb/device.rs +++ b/xhcid/src/usb/device.rs @@ -27,3 +27,18 @@ impl DeviceDescriptor { ((self.usb >> 8) & 0xFF) as u8 } } + +#[repr(packed)] +pub struct DeviceQualifier { + pub length: u8, + pub kind: u8, + pub usb: u16, + pub class: u8, + pub sub_class: u8, + pub protocol: u8, + pub pkgsz_other_speed: u8, + pub num_other_speed_cfgs: u8, + pub _rsvd: u8, +} + +unsafe impl plain::Plain for DeviceQualifier {} diff --git a/xhcid/src/xhci/extended.rs b/xhcid/src/xhci/extended.rs new file mode 100644 index 0000000000..93962b8347 --- /dev/null +++ b/xhcid/src/xhci/extended.rs @@ -0,0 +1,10 @@ +use syscall::Mmio; + +#[repr(packed)] +pub struct SupportedProtoCap { + a: Mmio, + b: Mmio, + c: Mmio, + d: Mmio, + protocols: [Mmio], +} diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 640254b880..3b0fea760d 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,5 +1,5 @@ use std::collections::BTreeMap; -use std::ffi::OsStr; +use std::convert::TryFrom; use std::pin::Pin; use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak}; use std::{mem, process, slice, sync::atomic, task}; @@ -15,6 +15,7 @@ mod command; mod context; mod doorbell; mod event; +mod extended; mod operational; mod port; mod ring; @@ -450,11 +451,13 @@ impl Xhci { .ok_or(Error::new(EBADF))?; let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; - if let Some(driver) = drivers_usercfg - .drivers - .iter() - .find(|driver| driver.class == ifdesc.class && driver.subclass == ifdesc.sub_class) - { + if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| { + driver.class == ifdesc.class + && driver + .subclass() + .map(|subclass| subclass == ifdesc.sub_class) + .unwrap_or(true) + }) { println!("Loading driver \"{}\"", driver.name); let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; @@ -485,9 +488,14 @@ impl Xhci { struct DriverConfig { name: String, class: u8, - subclass: u8, + subclass: i16, // The subclass may be meaningless for some drivers, hence negative values (and values above 255) mean "undefined". command: Vec, } +impl DriverConfig { + fn subclass(&self) -> Option { + u8::try_from(self.subclass).ok() + } +} #[derive(Deserialize)] struct DriversConfig { drivers: Vec, diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 287f78b534..11b8b3d4f1 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -3,14 +3,14 @@ use std::io::prelude::*; use std::{cmp, mem, path, str}; use serde::{Deserialize, Serialize}; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use syscall::io::{Dma, Io}; use syscall::scheme::SchemeMut; use syscall::{ Error, Result, Stat, EACCES, EBADF, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, - ENOTDIR, ENXIO, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_CREAT, O_DIRECTORY, O_RDONLY, O_RDWR, - O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, + ENOTDIR, ENXIO, EOVERFLOW, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_CREAT, O_DIRECTORY, + O_RDONLY, O_RDWR, O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, }; use super::{port, usb}; @@ -42,12 +42,17 @@ pub enum EndpointHandleTy { Root(usize, Vec), // offset, content } +pub enum PortReqState { + Init, + Ready(TransferKind, Dma<[u8]>), // direction, buffers +} + pub enum Handle { TopLevel(usize, Vec), // offset, contents (ports) Port(usize, usize, Vec), // port, offset, contents PortDesc(usize, usize, Vec), // port, offset, contents PortState(usize, usize), // port, offset - PortReq(usize), // port + PortReq(usize, PortReqState), // port, state Endpoints(usize, usize, Vec), // port, offset, contents Endpoint(usize, u8, EndpointHandleTy), // port, endpoint, offset, state ConfigureEndpoints(usize), // port @@ -229,8 +234,6 @@ impl Xhci { const CONTEXT_ENTRIES_SHIFT: u8 = 27; let current_slot_a = input_context.device.slot.a.read(); - let current_context_entries = - ((current_slot_a & CONTEXT_ENTRIES_MASK) >> CONTEXT_ENTRIES_SHIFT) as u8; let endpoints = &port_state.dev_desc.config_descs[req.config_desc].interface_descs[0].endpoints; @@ -261,18 +264,8 @@ impl Xhci { .ok_or(Error::new(EIO))?; let endp_desc = endpoints.get(index as usize).ok_or(Error::new(EIO))?; - let superspeed_companion = endp_desc.ssc; - // TODO: Check if streams are actually supported. - let max_streams = superspeed_companion - .map(|ssc| { - if endp_desc.is_bulk() { - 1 << (ssc.attributes & 0x1F) - } else { - 0 - } - }) - .unwrap_or(0); + let max_streams = endp_desc.max_streams(); let max_psa_size = self.cap.max_psa_size(); // TODO: Secondary streams. @@ -291,18 +284,10 @@ impl Xhci { // I presume that USB 3 devices can never be in low/full/high-speed mode, but // always SuperSpeed (gen 1 and 2 etc.). - let max_burst_size = superspeed_companion.map(|ssc| ssc.max_burst).unwrap_or(0); + let max_burst_size = endp_desc.max_burst(); let max_packet_size = endp_desc.max_packet_size; - let mult = if !lec && endp_desc.is_isoch() { - if let Some(ssc) = superspeed_companion { - ssc.attributes & 0x3 - } else { - 0 - } - } else { - 0 - }; + let mult = endp_desc.isoch_mult(lec); let interval = endp_desc.interval; let max_error_count = 3; @@ -378,8 +363,6 @@ impl Xhci { endp_ctx.c.write(u32::from(avg_trb_len)); } - input_context.dump_control(); - self.run.ints[0].erdp.write(self.cmd.erdp()); { @@ -571,14 +554,13 @@ impl Xhci { config_descs, }) } - fn write_port_desc(&mut self, port_id: usize, contents: &mut Vec) -> Result<()> { + fn port_desc_json(&mut self, port_id: usize) -> Result> { let dev_desc = &self .port_states .get(&port_id) .ok_or(Error::new(ENOENT))? .dev_desc; - serde_json::to_writer_pretty(contents, dev_desc).unwrap(); - Ok(()) + serde_json::to_vec(dev_desc).or(Err(Error::new(EIO))) } fn write_dyn_string(string: &[u8], buf: &mut [u8], offset: &mut usize) -> usize { let max_bytes_to_read = cmp::min(string.len(), buf.len()); @@ -589,35 +571,29 @@ impl Xhci { bytes_to_read } - fn port_req(&mut self, port_num: usize, buf: &[u8]) -> Result<()> { + fn port_req(&mut self, fd: usize, port_num: usize, buf: &[u8]) -> Result<()> { use usb::setup::*; - #[derive(Deserialize)] - struct PortReq<'a> { - direction: &'a str, - req_type: &'a str, - req_recipient: &'a str, - request: u8, - value: u16, - index: u16, - length: u16, - } // TODO: This json format might be too high level, but is useful for debugging, // but when actual device-specific drivers are written, a binary format would // be better. + // FIXME: Make sure there aren't any other PortReq handles, perhaps by storing the state in + // PortState? + let req = serde_json::from_slice::>(buf).or(Err(Error::new(EBADMSG)))?; let direction = match req.direction { "host_to_device" => ReqDirection::HostToDevice, "device_to_host" => ReqDirection::DeviceToHost, _ => return Err(Error::new(EBADMSG)), - } as u8; + }; let ty = match req.req_type { "class" => ReqType::Class, "vendor" => ReqType::Vendor, - "standard" | _ => return Err(Error::new(EBADMSG)), + "standard" => ReqType::Standard, + _ => return Err(Error::new(EBADMSG)), } as u8; let recipient = match req.req_recipient { @@ -629,8 +605,14 @@ impl Xhci { _ => return Err(Error::new(EBADMSG)), } as u8; + let transfer_kind = match direction { + _ if !req.transfers_data => TransferKind::NoData, + ReqDirection::DeviceToHost => TransferKind::In, + ReqDirection::HostToDevice => TransferKind::Out, + }; + let setup = Setup { - kind: (direction << USB_SETUP_DIR_SHIFT) + kind: ((direction as u8) << USB_SETUP_DIR_SHIFT) | (ty << USB_SETUP_REQ_TY_SHIFT) | (recipient << USB_SETUP_RECIPIENT_SHIFT), request: req.request, @@ -643,6 +625,7 @@ impl Xhci { .port_states .get_mut(&port_num) .ok_or(Error::new(EBADF))?; + let ring = match port_state .endpoint_states .get_mut(&0) @@ -654,17 +637,32 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; + let mut buffer = None; + { let (cmd, cycle) = ring.next(); - cmd.setup( - setup, - TransferKind::NoData, // FIXME + cmd.setup(setup, transfer_kind, cycle); + } + if transfer_kind != TransferKind::NoData { + let (cmd, cycle) = ring.next(); + + // TODO: Reuse buffers, or something. + // TODO: Validate the size. + // TODO: Sizes above 65536, *perhaps*. + let data_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(req.length as usize)? }; + assert_eq!(data_buffer.len(), req.length as usize); + + cmd.data( + data_buffer.physical(), + req.length, + transfer_kind == TransferKind::In, cycle, ); + buffer = Some(data_buffer); } { let (cmd, cycle) = ring.next(); - cmd.status(false, cycle); + cmd.status(transfer_kind == TransferKind::In, cycle); } self.dbs[port_state.slot as usize].write(1); @@ -673,10 +671,27 @@ impl Xhci { while event.data.read() == 0 { println!(" - Waiting for event"); } + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::Transfer as u8 + { + println!( + "Custom device request failed with EVENT {:#0x} {:#0x} {:#0x}", + event.data.read(), + event.status.read(), + event.control.read() + ); + } } self.run.ints[0].erdp.write(self.cmd.erdp()); + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::PortReq(_, ref mut st) if buffer.is_some() => { + *st = PortReqState::Ready(transfer_kind, buffer.unwrap()) + } + _ => return Err(Error::new(EBADF)), + } + Ok(()) } } @@ -733,9 +748,7 @@ impl SchemeMut for Xhci { return Err(Error::new(ENOTDIR)); } - let mut contents = Vec::new(); - self.write_port_desc(port_num, &mut contents)?; - + let contents = self.port_desc_json(port_num)?; Handle::PortDesc(port_num, 0, contents) } "configure" => { @@ -759,10 +772,7 @@ impl SchemeMut for Xhci { if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { return Err(Error::new(ENOTDIR)); } - if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { - return Err(Error::new(EACCES)); - } - Handle::PortReq(port_num) + Handle::PortReq(port_num, PortReqState::Init) } "endpoints" => { if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { @@ -852,12 +862,12 @@ impl SchemeMut for Xhci { write!(contents, "descriptors\nendpoints\n").unwrap(); - if dbg!(self.slot_state( + if self.slot_state( self.port_states .get(&port_num) .ok_or(Error::new(ENOENT))? - .slot as usize - )) != SlotState::Configured as u8 + .slot as usize, + ) != SlotState::Configured as u8 { write!(contents, "configure\n").unwrap(); } @@ -889,7 +899,12 @@ impl SchemeMut for Xhci { stat.st_mode = MODE_FILE; stat.st_size = buf.len() as u64; } - Handle::PortState(_, _) => stat.st_mode = MODE_CHR, + Handle::PortReq(_, PortReqState::Ready(TransferKind::In, ref buf)) => { + stat.st_mode = MODE_CHR; + stat.st_size = buf.len() as u64; + } + + Handle::PortState(_, _) | Handle::PortReq(_, _) => stat.st_mode = MODE_CHR, Handle::Endpoint(_, _, st) => match st { EndpointHandleTy::Status(_) | EndpointHandleTy::Transfer => stat.st_mode = MODE_CHR, EndpointHandleTy::Root(_, ref buf) => { @@ -897,7 +912,7 @@ impl SchemeMut for Xhci { stat.st_size = buf.len() as u64; } }, - Handle::ConfigureEndpoints(_) | Handle::PortReq(_) => { + Handle::ConfigureEndpoints(_) => { stat.st_mode = MODE_CHR | 0o200; // write only } } @@ -914,7 +929,7 @@ impl SchemeMut for Xhci { write!(src, "/port{}/descriptors", port_num).unwrap() } Handle::PortState(port_num, _) => write!(src, "/port{}/state", port_num).unwrap(), - Handle::PortReq(port_num) => write!(src, "/port{}/request", port_num).unwrap(), + Handle::PortReq(port_num, _) => write!(src, "/port{}/request", port_num).unwrap(), Handle::Endpoints(port_num, _, _) => { write!(src, "/port{}/endpoints/", port_num).unwrap() } @@ -967,7 +982,7 @@ impl SchemeMut for Xhci { Ok(*offset) } // Write-once configure or transfer - Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) | Handle::PortReq(_) => { + Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) | Handle::PortReq(_, _) => { return Err(Error::new(ESPIPE)) } } @@ -988,7 +1003,7 @@ impl SchemeMut for Xhci { Ok(bytes_to_read) } - Handle::ConfigureEndpoints(_) | Handle::PortReq(_) => return Err(Error::new(EBADF)), + Handle::ConfigureEndpoints(_) => return Err(Error::new(EBADF)), &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { EndpointHandleTy::Transfer => { @@ -1012,14 +1027,16 @@ impl SchemeMut for Xhci { & ENDPOINT_CONTEXT_STATUS_MASK; let string = match status { - // TODO: Give this its own enum. - 0 => "disabled", - 1 => "enabled", - 2 => "halted", - 3 => "stopped", - 4 => "error", - _ => "unknown", + 0 => Some(EndpointStatus::Disabled), + 1 => Some(EndpointStatus::Enabled), + 2 => Some(EndpointStatus::Halted), + 3 => Some(EndpointStatus::Stopped), + 4 => Some(EndpointStatus::Error), + _ => None, } + .as_ref() + .map(EndpointStatus::as_str) + .unwrap_or("unknown") .as_bytes(); Ok(Self::write_dyn_string(string, buf, offset)) @@ -1037,34 +1054,53 @@ impl SchemeMut for Xhci { .state(); let string = match state { - // TODO: Give this its own enum. - 0 => "enabled_or_disabled", // Maybe "enabled/disabled"? - 1 => "default", - 2 => "addressed", - 3 => "configured", - _ => "unknown", + 0 => Some(PortState::EnabledOrDisabled), + 1 => Some(PortState::Default), + 2 => Some(PortState::Addressed), + 3 => Some(PortState::Configured), + _ => None, } + .as_ref() + .map(PortState::as_str) + .unwrap_or("unknown") .as_bytes(); Ok(Self::write_dyn_string(string, buf, offset)) } + Handle::PortReq(_, st) => { + if let PortReqState::Ready(TransferKind::In, ref src_buf) = st { + if buf.len() != src_buf.len() { + return Err(Error::new(EINVAL)); + } + buf.copy_from_slice(src_buf); + Ok(buf.len()) + } else { + Err(Error::new(EBADF)) + } + } } } fn write(&mut self, fd: usize, buf: &[u8]) -> Result { - match self.handles.get(&fd).ok_or(Error::new(EBADF))? { - &Handle::ConfigureEndpoints(port_num) => { + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + &mut Handle::ConfigureEndpoints(port_num) => { self.configure_endpoints(port_num, buf)?; Ok(buf.len()) } - &Handle::Endpoint(port_num, endp_num, EndpointHandleTy::Transfer) => { + &mut Handle::Endpoint(port_num, endp_num, EndpointHandleTy::Transfer) => { self.transfer_write(port_num, endp_num, buf)?; // TODO Ok(buf.len()) } - &Handle::PortReq(port_num) => { - self.port_req(port_num, buf)?; + &mut Handle::PortReq(port_num, PortReqState::Init) => { + self.port_req(fd, port_num, buf)?; Ok(buf.len()) } + // TODO: Introduce PortReqState::Waiting, which this write call changes to + // PortReqState::ReadyToWrite when all bytes are written. + &mut Handle::PortReq( + port_num, + PortReqState::Ready(TransferKind::Out, ref mut src_buf), + ) => return Err(Error::new(ENOSYS)), _ => return Err(Error::new(EBADF)), } } diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 6eb6169b28..03d2931e11 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -96,6 +96,7 @@ pub enum TrbCompletionCode { } #[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum TransferKind { NoData, Reserved, From 53ddfbb88eb50c93651c74c3db89faff4f2ed4b3 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 8 Feb 2020 11:05:29 +0100 Subject: [PATCH 0327/1301] Fix the HID report descriptor parsing. --- usbhidd/Cargo.toml | 1 - usbhidd/src/main.rs | 221 +-------------------------- usbhidd/src/report_desc.rs | 275 ++++++++++++++++++++++++++++++++++ xhcid/src/driver_interface.rs | 1 - xhcid/src/xhci/mod.rs | 4 +- 5 files changed, 281 insertions(+), 221 deletions(-) create mode 100644 usbhidd/src/report_desc.rs diff --git a/usbhidd/Cargo.toml b/usbhidd/Cargo.toml index f535b7e35e..b76c7ad501 100644 --- a/usbhidd/Cargo.toml +++ b/usbhidd/Cargo.toml @@ -8,7 +8,6 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -base64 = "0.11" bitflags = "1.2" ux = "0.1" xhcid = { path = "../xhcid" } diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 76c80af142..3723b45877 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -1,221 +1,11 @@ use std::convert::TryInto; use std::env; -use bitflags::bitflags; -use ux::{u2, u4}; use xhcid_interface::{DevDesc, XhciClientHandle}; -/*#[repr(u8)] -enum Protocol { +mod report_desc; -}*/ - -bitflags! { - pub struct MainItemFlags: u32 { - const CONSTANT = 1 << 0; - const VARIABLE = 1 << 1; - const RELATIVE = 1 << 2; - const WRAP = 1 << 3; - const NONLINEAR = 1 << 4; - const NO_PREFERRED_STATE = 1 << 5; - const NULL_STATE = 1 << 6; - const VOLATILE = 1 << 7; - const BUFFERED_BYTES = 1 << 8; - } -} -#[repr(u8)] -pub enum MainCollectionFlags { - Physical = 0, - Application, - Logical, - Report, - NamedArray, - UsageSwitch, - UsageModifier, -} - -const REPORT_DESC_TY: u8 = 34; - -#[derive(Debug)] -enum MainItem { - Input(u32), - Output(u32), - Feature(u32), - Collection(u8), - EndOfCollection, -} -#[derive(Debug)] -enum GlobalItem { - UsagePage(u32), - LogicalMinimum(u32), - LogicalMaximum(u32), - PhysicalMinimum(u32), - PhysicalMaximum(u32), - UnitExponent(u32), - Unit(u32), - ReportSize(u32), - RepordId(u32), - ReportCount(u32), - Push(u32), - Pop(u32), -} -#[derive(Debug)] -enum LocalItem { - Usage(u32), - UsageMinimum(u32), - UsageMaximum(u32), - DesignatorIndex(u32), - DesignatorMinimum(u32), - DesignatorMaximum(u32), - StringIndex(u32), - StringMinimum(u32), - StringMaximum(u32), - Delimeter(u32), -} -#[derive(Debug)] -enum ReportItem { - Main(MainItem), - Global(GlobalItem), - Local(LocalItem), -} -impl From for ReportItem { - fn from(main: MainItem) -> Self { - Self::Main(main) - } -} -impl From for ReportItem { - fn from(main: GlobalItem) -> Self { - Self::Global(main) - } -} -impl From for ReportItem { - fn from(main: LocalItem) -> Self { - Self::Local(main) - } -} - -impl ReportItem { - fn size(size: u2) -> u8 { - match u8::from(size) { - 0 => 0, - 1 => 1, - 2 => 2, - 3 => 4, - _ => unreachable!(), - } - } - fn parse_short(size: u2, ty: u2, tag: u4, bytes: &[u8]) -> Option<(Self, usize)> { - Some(match (u8::from(tag), u8::from(ty)) { - (tag, 0b00) => { - let real_size = Self::size(size) as usize; - let mut value_bytes = [0u8; 4]; - if real_size > 0 { - value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) - }; - let value = u32::from_le_bytes(value_bytes); - - match tag { - 0b1000 => (MainItem::Input(value).into(), 1 + real_size), - 0b1001 => (MainItem::Output(value).into(), 1 + real_size), - 0b1011 => (MainItem::Feature(value).into(), 1 + real_size), - 0b1010 => (MainItem::Collection(bytes[0]).into(), 2), - 0b1100 => (MainItem::EndOfCollection.into(), 1 + real_size), - _ => return None, - } - } - (tag, 0b01) => { - let real_size = Self::size(size) as usize; - let mut value_bytes = [0u8; 4]; - if real_size > 0 { - value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) - }; - let value = u32::from_le_bytes(value_bytes); - match tag { - 0b0000 => (GlobalItem::UsagePage(value).into(), 1 + real_size), - 0b0001 => (GlobalItem::LogicalMinimum(value).into(), 1 + real_size), - 0b0010 => (GlobalItem::LogicalMaximum(value).into(), 1 + real_size), - 0b0011 => (GlobalItem::PhysicalMinimum(value).into(), 1 + real_size), - 0b0100 => (GlobalItem::PhysicalMaximum(value).into(), 1 + real_size), - 0b0101 => (GlobalItem::UnitExponent(value).into(), 1 + real_size), - 0b0110 => (GlobalItem::Unit(value).into(), 1 + real_size), - 0b0111 => (GlobalItem::ReportSize(value).into(), 1 + real_size), - 0b1000 => (GlobalItem::RepordId(value).into(), 1 + real_size), - 0b1001 => (GlobalItem::ReportCount(value).into(), 1 + real_size), - 0b1010 => (GlobalItem::Push(value).into(), 1 + real_size), - 0b1011 => (GlobalItem::Pop(value).into(), 1 + real_size), - _ => return None, - } - } - (tag, 0b10) => { - let real_size = Self::size(size) as usize; - let mut value_bytes = [0u8; 4]; - if real_size > 0 { - value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) - }; - let value = u32::from_le_bytes(value_bytes); - match tag { - 0b0000 => (LocalItem::Usage(value).into(), 1 + real_size), - 0b0001 => (LocalItem::UsageMinimum(value).into(), 1 + real_size), - 0b0010 => (LocalItem::UsageMaximum(value).into(), 1 + real_size), - 0b0011 => (LocalItem::DesignatorIndex(value).into(), 1 + real_size), - 0b0100 => (LocalItem::DesignatorMinimum(value).into(), 1 + real_size), - 0b0101 => (LocalItem::DesignatorMaximum(value).into(), 1 + real_size), - 0b0111 => (LocalItem::StringIndex(value).into(), 1 + real_size), - 0b1000 => (LocalItem::StringMinimum(value).into(), 1 + real_size), - 0b1001 => (LocalItem::StringMaximum(value).into(), 1 + real_size), - 0b1010 => (LocalItem::Delimeter(value).into(), 1 + real_size), - _ => return None, - } - } - (_, 0b11) => panic!("Calling parse_short but with long item"), - _ => unreachable!(), - }) - } - fn parse_long(size: u8, long_tag: u8, bytes: &[u8]) -> (Self, usize) { - todo!() - } -} - -struct ReportIter<'a> { - desc: &'a [u8], - offset: usize, -} -impl<'a> ReportIter<'a> { - fn new(desc: &'a [u8]) -> Self { - Self { desc, offset: 0 } - } -} -impl<'a> Iterator for ReportIter<'a> { - type Item = ReportItem; - - fn next(&mut self) -> Option { - let first = self.desc[self.offset]; - let size = first & 0b11; - let ty = first & 0b1100 >> 2; - let tag = first & 0b11110000 >> 4; - - if size == 0b10 && ty == 3 && tag == 0b1111 { - // Long Item - let size = self.desc[self.offset + 1]; - let long_tag = self.desc[self.offset + 2]; - let data = &self.desc[self.offset + 2..self.offset + 2 + size as usize]; - - let (item, len) = ReportItem::parse_long(size, long_tag, data); - self.offset += len; - Some(item) - } else { - // Short Item - - // Although there is a 2-bit size field, the size doesn't have to be the actual size of the data. - let data = &self.desc[self.offset + 1..]; - - let (item, len) = - ReportItem::parse_short(u2::new(size), u2::new(ty), u4::new(tag), data)?; - self.offset += len; - Some(item) - } - } -} +use report_desc::{ReportIter, ReportFlatIter, REPORT_DESC_TY}; fn main() { let mut args = env::args().skip(1); @@ -254,11 +44,8 @@ fn main() { report_desc_len, ) .expect("Failed to retrieve report descriptor"); - use std::io::Write as _; - std::io::stdout() - .write_all(base64::encode(&report_desc_bytes).as_bytes()) - .unwrap(); - let iterator = ReportIter::new(&report_desc_bytes); + + let iterator = ReportIter::new(ReportFlatIter::new(&report_desc_bytes)); for item in iterator { println!("HID ITEM {:?}", item); diff --git a/usbhidd/src/report_desc.rs b/usbhidd/src/report_desc.rs new file mode 100644 index 0000000000..e77da8afb5 --- /dev/null +++ b/usbhidd/src/report_desc.rs @@ -0,0 +1,275 @@ +use bitflags::bitflags; +use ux::{u2, u4}; + +/*#[repr(u8)] +enum Protocol { + +}*/ + +bitflags! { + pub struct MainItemFlags: u32 { + const CONSTANT = 1 << 0; + const VARIABLE = 1 << 1; + const RELATIVE = 1 << 2; + const WRAP = 1 << 3; + const NONLINEAR = 1 << 4; + const NO_PREFERRED_STATE = 1 << 5; + const NULL_STATE = 1 << 6; + const VOLATILE = 1 << 7; + const BUFFERED_BYTES = 1 << 8; + } +} +#[repr(u8)] +pub enum MainCollectionFlags { + Physical = 0, + Application, + Logical, + Report, + NamedArray, + UsageSwitch, + UsageModifier, +} + +pub const REPORT_DESC_TY: u8 = 34; + +#[derive(Debug)] +pub enum MainItem { + Input(u32), + Output(u32), + Feature(u32), + Collection(u8), + EndOfCollection, +} +#[derive(Debug)] +pub enum GlobalItem { + UsagePage(u32), + LogicalMinimum(u32), + LogicalMaximum(u32), + PhysicalMinimum(u32), + PhysicalMaximum(u32), + UnitExponent(u32), + Unit(u32), + ReportSize(u32), + RepordId(u32), + ReportCount(u32), + Push(u32), + Pop(u32), +} +#[derive(Debug)] +pub enum LocalItem { + Usage(u32), + UsageMinimum(u32), + UsageMaximum(u32), + DesignatorIndex(u32), + DesignatorMinimum(u32), + DesignatorMaximum(u32), + StringIndex(u32), + StringMinimum(u32), + StringMaximum(u32), + Delimeter(u32), +} +#[derive(Debug)] +pub enum ReportItem { + Main(MainItem), + Global(GlobalItem), + Local(LocalItem), +} +impl From for ReportItem { + fn from(main: MainItem) -> Self { + Self::Main(main) + } +} +impl From for ReportItem { + fn from(main: GlobalItem) -> Self { + Self::Global(main) + } +} +impl From for ReportItem { + fn from(main: LocalItem) -> Self { + Self::Local(main) + } +} + +impl ReportItem { + pub fn size(size: u2) -> u8 { + match u8::from(size) { + 0 => 0, + 1 => 1, + 2 => 2, + 3 => 4, + _ => unreachable!(), + } + } + pub fn parse_short(size: u2, ty: u2, tag: u4, bytes: &[u8]) -> Option<(Self, usize)> { + Some(match (u8::from(tag), u8::from(ty)) { + (tag, 0b00) => { + let real_size = Self::size(size) as usize; + let mut value_bytes = [0u8; 4]; + if real_size > 0 { + value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) + }; + let value = u32::from_le_bytes(value_bytes); + + match tag { + 0b1000 => (MainItem::Input(value).into(), 1 + real_size), + 0b1001 => (MainItem::Output(value).into(), 1 + real_size), + 0b1011 => (MainItem::Feature(value).into(), 1 + real_size), + 0b1010 => (MainItem::Collection(bytes[0]).into(), 2), + 0b1100 => (MainItem::EndOfCollection.into(), 1 + real_size), + _ => return None, + } + } + (tag, 0b01) => { + let real_size = Self::size(size) as usize; + let mut value_bytes = [0u8; 4]; + if real_size > 0 { + value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) + }; + let value = u32::from_le_bytes(value_bytes); + match tag { + 0b0000 => (GlobalItem::UsagePage(value).into(), 1 + real_size), + 0b0001 => (GlobalItem::LogicalMinimum(value).into(), 1 + real_size), + 0b0010 => (GlobalItem::LogicalMaximum(value).into(), 1 + real_size), + 0b0011 => (GlobalItem::PhysicalMinimum(value).into(), 1 + real_size), + 0b0100 => (GlobalItem::PhysicalMaximum(value).into(), 1 + real_size), + 0b0101 => (GlobalItem::UnitExponent(value).into(), 1 + real_size), + 0b0110 => (GlobalItem::Unit(value).into(), 1 + real_size), + 0b0111 => (GlobalItem::ReportSize(value).into(), 1 + real_size), + 0b1000 => (GlobalItem::RepordId(value).into(), 1 + real_size), + 0b1001 => (GlobalItem::ReportCount(value).into(), 1 + real_size), + 0b1010 => (GlobalItem::Push(value).into(), 1 + real_size), + 0b1011 => (GlobalItem::Pop(value).into(), 1 + real_size), + _ => return None, + } + } + (tag, 0b10) => { + let real_size = Self::size(size) as usize; + let mut value_bytes = [0u8; 4]; + if real_size > 0 { + value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) + }; + let value = u32::from_le_bytes(value_bytes); + match tag { + 0b0000 => (LocalItem::Usage(value).into(), 1 + real_size), + 0b0001 => (LocalItem::UsageMinimum(value).into(), 1 + real_size), + 0b0010 => (LocalItem::UsageMaximum(value).into(), 1 + real_size), + 0b0011 => (LocalItem::DesignatorIndex(value).into(), 1 + real_size), + 0b0100 => (LocalItem::DesignatorMinimum(value).into(), 1 + real_size), + 0b0101 => (LocalItem::DesignatorMaximum(value).into(), 1 + real_size), + 0b0111 => (LocalItem::StringIndex(value).into(), 1 + real_size), + 0b1000 => (LocalItem::StringMinimum(value).into(), 1 + real_size), + 0b1001 => (LocalItem::StringMaximum(value).into(), 1 + real_size), + 0b1010 => (LocalItem::Delimeter(value).into(), 1 + real_size), + _ => return None, + } + } + (_, 0b11) => panic!("Calling parse_short but with long item"), + _ => unreachable!(), + }) + } + pub fn parse_long(size: u8, long_tag: u8, bytes: &[u8]) -> (Self, usize) { + todo!() + } +} + +pub struct ReportFlatIter<'a> { + desc: &'a [u8], + offset: usize, +} +impl<'a> ReportFlatIter<'a> { + pub fn new(desc: &'a [u8]) -> Self { + Self { desc, offset: 0 } + } +} +impl<'a> Iterator for ReportFlatIter<'a> { + type Item = ReportItem; + + fn next(&mut self) -> Option { + if self.offset >= self.desc.len() { return None } + + let first = self.desc[self.offset]; + let size = first & 0b11; + let ty = (first & 0b1100) >> 2; + let tag = (first & 0b11110000) >> 4; + + if size == 0b10 && ty == 3 && tag == 0b1111 { + // Long Item + let size = self.desc[self.offset + 1]; + let long_tag = self.desc[self.offset + 2]; + let data = &self.desc[self.offset + 2..self.offset + 2 + size as usize]; + + let (item, len) = ReportItem::parse_long(size, long_tag, data); + self.offset += len; + Some(item) + } else { + // Short Item + + // Although there is a 2-bit size field, the size doesn't have to be the actual size of the data. + let data = &self.desc[self.offset + 1..]; + + let (item, len) = + ReportItem::parse_short(u2::new(size), u2::new(ty), u4::new(tag), data)?; + self.offset += len; + Some(item) + } + } +} + +pub struct ReportIter<'a> { + flat: ReportFlatIter<'a>, + error: bool, + // this is just for reusing the vec + open_collections: Vec<(u8, Vec)>, +} +#[derive(Debug)] +pub enum ReportIterItem { + // collection and end of collection tags will never be found here + Item(ReportItem), + Collection(u8, Vec), +} +impl<'a> ReportIter<'a> { + pub fn new(flat: ReportFlatIter<'a>) -> Self { + Self { + flat, + error: false, + open_collections: Vec::new(), + } + } +} +impl<'a> Iterator for ReportIter<'a> { + type Item = ReportIterItem; + + fn next(&mut self) -> Option { + if self.error { return None } + + self.open_collections.clear(); + + loop { + let item = self.flat.next()?; + + match item { + ReportItem::Main(MainItem::Collection(m)) => { + self.open_collections.push((m, Vec::new())); + } + ReportItem::Main(MainItem::EndOfCollection) => { + let (value, finished_collection) = match self.open_collections.pop() { + Some(finished) => finished, + None => { + self.error = true; + return None; + } + }; + if let Some((_, ref mut last)) = self.open_collections.last_mut() { + last.push(ReportIterItem::Collection(value, finished_collection)); + } else { + return Some(ReportIterItem::Collection(value, finished_collection)); + } + } + other if self.open_collections.is_empty() => return Some(ReportIterItem::Item(other)), + other => { + self.open_collections.last_mut().unwrap().1.push(ReportIterItem::Item(other)) + } + } + } + } +} diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index b20cce5e74..dc88a7a6bc 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -261,7 +261,6 @@ impl XhciClientHandle { pub fn get_standard_descs(&self) -> result::Result { let path = format!("{}:port{}/descriptors", self.scheme, self.port); let json = std::fs::read(path)?; - std::io::stdout().lock().write_all(&json)?; Ok(serde_json::from_slice(&json)?) } pub fn configure_endpoints( diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 3b0fea760d..cf6923afd4 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -398,10 +398,10 @@ impl Xhci { .collect::>(), }; - match self.spawn_drivers(i, &mut port_state) { + /*match self.spawn_drivers(i, &mut port_state) { Ok(()) => (), Err(err) => println!("Failed to spawn driver for port {}: `{}`", i, err), - } + }*/ self.port_states.insert(i, port_state); } From 3fd4bc4b3b2ce26297da176db7d07c4376544f82 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 8 Feb 2020 12:28:17 +0100 Subject: [PATCH 0328/1301] Add functions for the HID-specific requests. --- Cargo.lock | 7 --- usbhidd/src/main.rs | 17 +++--- usbhidd/src/report_desc.rs | 22 +++++-- usbhidd/src/reqs.rs | 111 ++++++++++++++++++++++++++++++++++ xhcid/src/driver_interface.rs | 111 +++++++++++++++++++++++++++------- xhcid/src/usb/setup.rs | 29 +++++++++ xhcid/src/xhci/scheme.rs | 29 ++------- 7 files changed, 262 insertions(+), 64 deletions(-) create mode 100644 usbhidd/src/reqs.rs diff --git a/Cargo.lock b/Cargo.lock index 3ac510dde4..3326bb7579 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,11 +53,6 @@ dependencies = [ "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "base64" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bgad" version = "0.1.0" @@ -1332,7 +1327,6 @@ dependencies = [ name = "usbhidd" version = "0.1.0" dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", @@ -1473,7 +1467,6 @@ dependencies = [ "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 3723b45877..0f86635770 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -1,11 +1,11 @@ -use std::convert::TryInto; use std::env; -use xhcid_interface::{DevDesc, XhciClientHandle}; +use xhcid_interface::{DevDesc, PortReqRecipient, XhciClientHandle}; mod report_desc; +mod reqs; -use report_desc::{ReportIter, ReportFlatIter, REPORT_DESC_TY}; +use report_desc::{ReportFlatIter, ReportIter, REPORT_DESC_TY}; fn main() { let mut args = env::args().skip(1); @@ -37,11 +37,14 @@ fn main() { let report_desc_len = hid_desc.desc_len; assert_eq!(hid_desc.desc_ty, REPORT_DESC_TY); - let report_desc_bytes: Vec = handle - .get_class_descriptor( - u16::from(REPORT_DESC_TY) << 8, + let mut report_desc_bytes = vec![0u8; report_desc_len as usize]; + handle + .get_descriptor( + PortReqRecipient::Interface, + REPORT_DESC_TY, + 0, interface_num, - report_desc_len, + &mut report_desc_bytes, ) .expect("Failed to retrieve report descriptor"); diff --git a/usbhidd/src/report_desc.rs b/usbhidd/src/report_desc.rs index e77da8afb5..85d8526f85 100644 --- a/usbhidd/src/report_desc.rs +++ b/usbhidd/src/report_desc.rs @@ -185,7 +185,9 @@ impl<'a> Iterator for ReportFlatIter<'a> { type Item = ReportItem; fn next(&mut self) -> Option { - if self.offset >= self.desc.len() { return None } + if self.offset >= self.desc.len() { + return None; + } let first = self.desc[self.offset]; let size = first & 0b11; @@ -219,6 +221,9 @@ pub struct ReportIter<'a> { flat: ReportFlatIter<'a>, error: bool, // this is just for reusing the vec + // TODO: When GATs are available, this could be done simply using iterators. Every collection + // yields a child iterator, which returns the mutable reference to the flat iter to its parent + // when dropped. open_collections: Vec<(u8, Vec)>, } #[derive(Debug)] @@ -240,7 +245,9 @@ impl<'a> Iterator for ReportIter<'a> { type Item = ReportIterItem; fn next(&mut self) -> Option { - if self.error { return None } + if self.error { + return None; + } self.open_collections.clear(); @@ -265,10 +272,15 @@ impl<'a> Iterator for ReportIter<'a> { return Some(ReportIterItem::Collection(value, finished_collection)); } } - other if self.open_collections.is_empty() => return Some(ReportIterItem::Item(other)), - other => { - self.open_collections.last_mut().unwrap().1.push(ReportIterItem::Item(other)) + other if self.open_collections.is_empty() => { + return Some(ReportIterItem::Item(other)) } + other => self + .open_collections + .last_mut() + .unwrap() + .1 + .push(ReportIterItem::Item(other)), } } } diff --git a/usbhidd/src/reqs.rs b/usbhidd/src/reqs.rs new file mode 100644 index 0000000000..e834474fc2 --- /dev/null +++ b/usbhidd/src/reqs.rs @@ -0,0 +1,111 @@ +use std::slice; + +use xhcid_interface::{ + DeviceReqData, PortReqRecipient, PortReqTy, XhciClientHandle, XhciClientHandleError, +}; + +const GET_REPORT_REQ: u8 = 0x1; +const SET_REPORT_REQ: u8 = 0x9; +const GET_IDLE_REQ: u8 = 0x2; +const SET_IDLE_REQ: u8 = 0xA; +const GET_PROTOCOL_REQ: u8 = 0x3; +const SET_PROTOCOL_REQ: u8 = 0xB; + +fn concat(hi: u8, lo: u8) -> u16 { + (u16::from(hi) << 8) | u16::from(lo) +} + +pub fn get_report( + handle: &mut XhciClientHandle, + report_ty: u8, + report_id: u8, + if_num: u16, + buffer: &mut [u8], +) -> Result<(), XhciClientHandleError> { + handle.device_request( + PortReqTy::Class, + PortReqRecipient::Interface, + GET_REPORT_REQ, + concat(report_ty, report_id), + if_num, + DeviceReqData::In(buffer), + ) +} +pub fn set_report( + handle: &mut XhciClientHandle, + report_ty: u8, + report_id: u8, + if_num: u16, + buffer: &[u8], +) -> Result<(), XhciClientHandleError> { + handle.device_request( + PortReqTy::Class, + PortReqRecipient::Interface, + SET_REPORT_REQ, + concat(report_id, report_ty), + if_num, + DeviceReqData::Out(buffer), + ) +} +pub fn get_idle( + handle: &mut XhciClientHandle, + report_id: u8, + if_num: u16, +) -> Result { + let mut idle_rate = 0; + let buffer = slice::from_mut(&mut idle_rate); + handle.device_request( + PortReqTy::Class, + PortReqRecipient::Interface, + GET_IDLE_REQ, + u16::from(report_id), + if_num, + DeviceReqData::In(buffer), + )?; + Ok(idle_rate) +} +pub fn set_idle( + handle: &mut XhciClientHandle, + duration: u8, + report_id: u8, + if_num: u16, +) -> Result<(), XhciClientHandleError> { + handle.device_request( + PortReqTy::Class, + PortReqRecipient::Interface, + SET_IDLE_REQ, + concat(duration, report_id), + if_num, + DeviceReqData::NoData, + ) +} +pub fn get_protocol( + handle: &mut XhciClientHandle, + if_num: u16, +) -> Result { + let mut protocol = 0; + let buffer = slice::from_mut(&mut protocol); + handle.device_request( + PortReqTy::Class, + PortReqRecipient::Interface, + GET_PROTOCOL_REQ, + 0, + if_num, + DeviceReqData::In(buffer), + )?; + Ok(protocol) +} +pub fn set_protocol( + handle: &mut XhciClientHandle, + protocol: u8, + if_num: u16, +) -> Result<(), XhciClientHandleError> { + handle.device_request( + PortReqTy::Class, + PortReqRecipient::Interface, + SET_PROTOCOL_REQ, + u16::from(protocol), + if_num, + DeviceReqData::NoData, + ) +} diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index dc88a7a6bc..a2cb08b361 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -1,6 +1,7 @@ pub extern crate serde; pub extern crate smallvec; +use std::convert::TryFrom; use std::fs::File; use std::io::prelude::*; use std::{io, result, str}; @@ -164,16 +165,35 @@ pub struct HidDesc { pub optional_desc_len: u16, } #[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct PortReq<'a> { - pub direction: &'a str, - pub req_type: &'a str, - pub req_recipient: &'a str, +pub struct PortReq { + pub direction: PortReqDirection, + pub req_type: PortReqTy, + pub req_recipient: PortReqRecipient, pub request: u8, pub value: u16, pub index: u16, pub length: u16, pub transfers_data: bool, } +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub enum PortReqDirection { + HostToDevice, + DeviceToHost, +} +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub enum PortReqTy { + Class, + Vendor, + Standard, +} +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub enum PortReqRecipient { + Device, + Interface, + Endpoint, + Other, + VendorSpecific, +} #[derive(Debug)] pub struct XhciClientHandle { @@ -253,6 +273,34 @@ impl str::FromStr for EndpointStatus { } } +pub enum DeviceReqData<'a> { + In(&'a mut [u8]), + Out(&'a [u8]), + NoData, +} +impl DeviceReqData<'_> { + fn len(&self) -> usize { + match self { + Self::In(buf) => buf.len(), + Self::Out(buf) => buf.len(), + Self::NoData => 0, + } + } + fn is_empty(&self) -> bool { + self.len() == 0 + } +} + +impl<'a> DeviceReqData<'a> { + fn direction(&self) -> PortReqDirection { + match self { + DeviceReqData::Out(_) => PortReqDirection::HostToDevice, + DeviceReqData::NoData => PortReqDirection::HostToDevice, + DeviceReqData::In(_) => PortReqDirection::DeviceToHost, + } + } +} + impl XhciClientHandle { pub fn new(scheme: String, port: usize) -> Self { Self { scheme, port } @@ -284,19 +332,22 @@ impl XhciClientHandle { let string = std::fs::read_to_string(path)?; Ok(string.parse()?) } - // TODO: Device-specific request, with data - pub fn get_class_descriptor( + pub fn device_request<'a>( &self, + req_type: PortReqTy, + req_recipient: PortReqRecipient, + request: u8, value: u16, index: u16, - length: u16, - ) -> result::Result, XhciClientHandleError> { - // TODO: Base this on the to-be-written generic device request function. + data: DeviceReqData<'a>, + ) -> result::Result<(), XhciClientHandleError> { + let length = u16::try_from(data.len()).or(Err(XhciClientHandleError::TransferBufTooLarge(data.len())))?; + let req = PortReq { - direction: "device_to_host", - req_type: "standard", // TODO: Add as a parameter, with its own enum. - req_recipient: "interface", - request: 0x06, + direction: data.direction(), + req_type, + req_recipient, + request, value, index, length, @@ -307,19 +358,32 @@ impl XhciClientHandle { let path = format!("{}:port{}/request", self.scheme, self.port); let mut file = File::open(path)?; - let bytes_written = file.write(&json)?; - if bytes_written != json.len() { + let json_bytes_written = file.write(&json)?; + if json_bytes_written != json.len() { return Err(XhciClientHandleError::InvalidResponse(Invalid)); } - let mut buf = vec![0u8; length as usize]; - let bytes_read = file.read(&mut buf)?; - if bytes_read != buf.len() { - println!("HIDd B"); - return Err(XhciClientHandleError::InvalidResponse(Invalid)); - } + match data { + DeviceReqData::In(buf) => { + let bytes_read = file.read(buf)?; - Ok(buf) + if bytes_read != buf.len() { + return Err(XhciClientHandleError::InvalidResponse(Invalid)); + } + } + DeviceReqData::Out(buf) => { + let bytes_read = file.write(&buf)?; + + if bytes_read != buf.len() { + return Err(XhciClientHandleError::InvalidResponse(Invalid)); + } + } + DeviceReqData::NoData => (), + } + Ok(()) + } + pub fn get_descriptor(&self, recipient: PortReqRecipient, ty: u8, idx: u8, windex: u16, buffer: &mut [u8]) -> result::Result<(), XhciClientHandleError> { + self.device_request(PortReqTy::Standard, recipient, 0x06, (u16::from(ty) << 8) | u16::from(idx), windex, DeviceReqData::In(buffer)) } } @@ -333,4 +397,7 @@ pub enum XhciClientHandleError { #[error("invalid response")] InvalidResponse(#[from] Invalid), + + #[error("transfer buffer too large ({0} > 65536)")] + TransferBufTooLarge(usize), } diff --git a/xhcid/src/usb/setup.rs b/xhcid/src/usb/setup.rs index 3ba4462206..ff793c133f 100644 --- a/xhcid/src/usb/setup.rs +++ b/xhcid/src/usb/setup.rs @@ -1,4 +1,5 @@ use super::DescriptorKind; +use crate::driver_interface::*; #[repr(packed)] #[derive(Clone, Copy, Debug, Default)] @@ -15,6 +16,14 @@ pub enum ReqDirection { HostToDevice = 0, DeviceToHost = 1, } +impl From for ReqDirection { + fn from(d: PortReqDirection) -> Self { + match d { + PortReqDirection::DeviceToHost => Self::DeviceToHost, + PortReqDirection::HostToDevice => Self::HostToDevice, + } + } +} #[repr(u8)] pub enum ReqType { @@ -31,6 +40,15 @@ pub enum ReqType { /// Reserved Reserved = 3, } +impl From for ReqType { + fn from(d: PortReqTy) -> Self { + match d { + PortReqTy::Standard => Self::Standard, + PortReqTy::Class => Self::Class, + PortReqTy::Vendor => Self::Vendor, + } + } +} #[repr(u8)] pub enum ReqRecipient { @@ -41,6 +59,17 @@ pub enum ReqRecipient { // 4..=30 are reserved VendorSpecific = 31, } +impl From for ReqRecipient { + fn from(d: PortReqRecipient) -> Self { + match d { + PortReqRecipient::Device => Self::Device, + PortReqRecipient::Interface => Self::Interface, + PortReqRecipient::Endpoint => Self::Endpoint, + PortReqRecipient::Other => Self::Other, + PortReqRecipient::VendorSpecific => Self::VendorSpecific, + } + } +} pub const USB_SETUP_DIR_BIT: u8 = 1 << 7; pub const USB_SETUP_DIR_SHIFT: u8 = 7; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 11b8b3d4f1..1b8d6d63af 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -576,34 +576,17 @@ impl Xhci { // TODO: This json format might be too high level, but is useful for debugging, // but when actual device-specific drivers are written, a binary format would - // be better. + // be better. Maybe something simple like bincode could be used, if a custom binary struct + // is too much overkill. // FIXME: Make sure there aren't any other PortReq handles, perhaps by storing the state in // PortState? - let req = serde_json::from_slice::>(buf).or(Err(Error::new(EBADMSG)))?; + let req = serde_json::from_slice::(buf).or(Err(Error::new(EBADMSG)))?; - let direction = match req.direction { - "host_to_device" => ReqDirection::HostToDevice, - "device_to_host" => ReqDirection::DeviceToHost, - _ => return Err(Error::new(EBADMSG)), - }; - - let ty = match req.req_type { - "class" => ReqType::Class, - "vendor" => ReqType::Vendor, - "standard" => ReqType::Standard, - _ => return Err(Error::new(EBADMSG)), - } as u8; - - let recipient = match req.req_recipient { - "device" => ReqRecipient::Device, - "interface" => ReqRecipient::Interface, - "endpoint" => ReqRecipient::Endpoint, - "other" => ReqRecipient::Other, - "vendor_specific" => ReqRecipient::VendorSpecific, - _ => return Err(Error::new(EBADMSG)), - } as u8; + let direction = ReqDirection::from(req.direction); + let ty = ReqType::from(req.req_type) as u8; + let recipient = ReqRecipient::from(req.req_recipient) as u8; let transfer_kind = match direction { _ if !req.transfers_data => TransferKind::NoData, From 1013daf606d8ed92b37bbd3f3dcb58391140df44 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 8 Feb 2020 17:18:09 +0100 Subject: [PATCH 0329/1301] IT WORKS! --- Cargo.lock | 1 + ps2d/.gitignore | 1 + usbhidd/src/main.rs | 71 +++++++++++++++++++++++++++-- usbhidd/src/report_desc.rs | 86 ++++++++++++++++++++++++++++++++--- usbhidd/src/reqs.rs | 28 ++++++++---- usbhidd/src/usage_tables.rs | 45 ++++++++++++++++++ usbscsid/Cargo.toml | 1 + usbscsid/src/main.rs | 9 +++- usbscsid/src/protocol/bot.rs | 35 ++++++++++++-- usbscsid/src/protocol/mod.rs | 28 ++++++++++-- xhcid/src/driver_interface.rs | 11 +++-- 11 files changed, 281 insertions(+), 35 deletions(-) create mode 100644 ps2d/.gitignore create mode 100644 usbhidd/src/usage_tables.rs diff --git a/Cargo.lock b/Cargo.lock index 3326bb7579..45920958a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1336,6 +1336,7 @@ dependencies = [ name = "usbscsid" version = "0.1.0" dependencies = [ + "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] diff --git a/ps2d/.gitignore b/ps2d/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/ps2d/.gitignore @@ -0,0 +1 @@ +/target diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 0f86635770..7f21eb6d9d 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -1,11 +1,17 @@ use std::env; -use xhcid_interface::{DevDesc, PortReqRecipient, XhciClientHandle}; +use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle}; mod report_desc; mod reqs; +mod usage_tables; -use report_desc::{ReportFlatIter, ReportIter, REPORT_DESC_TY}; +use report_desc::{MainCollectionFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY}; +use reqs::ReportTy; + +fn div_round_up(num: u32, denom: u32) -> u32 { + if num % denom == 0 { num / denom } else { num / denom + 1 } +} fn main() { let mut args = env::args().skip(1); @@ -48,9 +54,64 @@ fn main() { ) .expect("Failed to retrieve report descriptor"); - let iterator = ReportIter::new(ReportFlatIter::new(&report_desc_bytes)); + let report_desc = ReportIter::new(ReportFlatIter::new(&report_desc_bytes)).collect::>(); - for item in iterator { - println!("HID ITEM {:?}", item); + for item in &report_desc { + println!("{:?}", item); } + + handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0 }).expect("Failed to configure endpoints"); + + let (mut state, mut stack) = (GlobalItemsState::default(), Vec::new()); + + let (_, application_collection) = report_desc.iter().inspect(|item: &&ReportIterItem| if let ReportIterItem::Item(ref item) = item { + report_desc::update_state(&mut state, &mut stack, item).unwrap() + }).filter_map(ReportIterItem::as_collection).find(|&(n, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection"); + + // Get all main items, and their global item options. + { + let items = application_collection.iter().filter_map(ReportIterItem::as_item).filter_map(|item| match item { + ReportItem::Global(_) => { + report_desc::update_state(&mut state, &mut stack, item).unwrap(); + None + } + ReportItem::Main(m) => Some((state, m)), + ReportItem::Local(_) => None, + }); + let total_length = items.filter_map(|(state, item)| { + let report_size = match state.report_size { + Some(s) => s, + None => return None, + }; + let report_count = match state.report_count { + Some(c) => c, + None => return None, + }; + let bit_length = report_size * report_count; + + if item.report_ty() != Some(ReportTy::Input) { + return None; + } + Some(bit_length) + }).sum(); + let length = div_round_up(total_length, 8); + + let mut report_buffer = vec! [0u8; length as usize]; + let mut last_buffer = report_buffer.clone(); + let report_ty = ReportTy::Input; + let report_id = 0; + + loop { + std::mem::swap(&mut report_buffer, &mut last_buffer); + reqs::get_report(&handle, report_ty, report_id, interface_num, &mut report_buffer).expect("Failed to get report"); + if report_buffer != last_buffer { + for byte in &report_buffer { + print!("{:#0x} ", byte); + } + println!(); + } + std::thread::sleep(std::time::Duration::from_millis(10)) + } + } + } diff --git a/usbhidd/src/report_desc.rs b/usbhidd/src/report_desc.rs index 85d8526f85..9a0019aaba 100644 --- a/usbhidd/src/report_desc.rs +++ b/usbhidd/src/report_desc.rs @@ -1,6 +1,8 @@ use bitflags::bitflags; use ux::{u2, u4}; +use crate::reqs::ReportTy; + /*#[repr(u8)] enum Protocol { @@ -40,6 +42,16 @@ pub enum MainItem { Collection(u8), EndOfCollection, } +impl MainItem { + pub fn report_ty(&self) -> Option { + match self { + Self::Input(_) => Some(ReportTy::Input), + Self::Output(_) => Some(ReportTy::Output), + Self::Feature(_) => Some(ReportTy::Feature), + _ => None, + } + } +} #[derive(Debug)] pub enum GlobalItem { UsagePage(u32), @@ -50,11 +62,51 @@ pub enum GlobalItem { UnitExponent(u32), Unit(u32), ReportSize(u32), - RepordId(u32), + ReportId(u32), ReportCount(u32), - Push(u32), - Pop(u32), + Push, + Pop, } + +#[derive(Clone, Copy, Debug, Default)] +pub struct GlobalItemsState { + pub usage_page: Option, + pub logical_min: Option, + pub logical_max: Option, + pub physical_min: Option, + pub physical_max: Option, + pub unit_exponent: Option, + pub unit: Option, + pub report_size: Option, + pub report_id: Option, + pub report_count: Option, +} + +#[derive(Debug)] +pub struct Invalid; + +pub fn update_state(current_state: &mut GlobalItemsState, stack: &mut Vec, report_item: &ReportItem) -> Result<(), Invalid> { + match report_item { + ReportItem::Global(global) => match global { + &GlobalItem::UsagePage(u) => current_state.usage_page = Some(u), + &GlobalItem::LogicalMinimum(m) => current_state.logical_min = Some(m), + &GlobalItem::LogicalMaximum(m) => current_state.logical_max = Some(m), + &GlobalItem::PhysicalMinimum(m) => current_state.physical_min = Some(m), + &GlobalItem::PhysicalMaximum(m) => current_state.physical_max = Some(m), + &GlobalItem::UnitExponent(e) => current_state.unit_exponent = Some(e), + &GlobalItem::Unit(u) => current_state.unit = Some(u), + &GlobalItem::ReportSize(s) => current_state.report_size = Some(s), + &GlobalItem::ReportId(i) => current_state.report_id = Some(i), + &GlobalItem::ReportCount(c) => current_state.report_count = Some(c), + &GlobalItem::Push => stack.push(*current_state), + &GlobalItem::Pop => *current_state = stack.pop().ok_or(Invalid)?, + } + ReportItem::Local(local) => (), // TODO + ReportItem::Main(_) => (), + } + Ok(()) +} + #[derive(Debug)] pub enum LocalItem { Usage(u32), @@ -74,6 +126,14 @@ pub enum ReportItem { Global(GlobalItem), Local(LocalItem), } +impl ReportItem { + pub fn as_main_item(&self) -> Option<&MainItem> { + match self { + Self::Main(m) => Some(m), + _ => None, + } + } +} impl From for ReportItem { fn from(main: MainItem) -> Self { Self::Main(main) @@ -135,10 +195,10 @@ impl ReportItem { 0b0101 => (GlobalItem::UnitExponent(value).into(), 1 + real_size), 0b0110 => (GlobalItem::Unit(value).into(), 1 + real_size), 0b0111 => (GlobalItem::ReportSize(value).into(), 1 + real_size), - 0b1000 => (GlobalItem::RepordId(value).into(), 1 + real_size), + 0b1000 => (GlobalItem::ReportId(value).into(), 1 + real_size), 0b1001 => (GlobalItem::ReportCount(value).into(), 1 + real_size), - 0b1010 => (GlobalItem::Push(value).into(), 1 + real_size), - 0b1011 => (GlobalItem::Pop(value).into(), 1 + real_size), + 0b1010 => (GlobalItem::Push.into(), 1), + 0b1011 => (GlobalItem::Pop.into(), 1), _ => return None, } } @@ -232,6 +292,20 @@ pub enum ReportIterItem { Item(ReportItem), Collection(u8, Vec), } +impl ReportIterItem { + pub fn as_item(&self) -> Option<&ReportItem> { + match self { + Self::Item(i) => Some(i), + _ => None, + } + } + pub fn as_collection(&self) -> Option<(u8, &[ReportIterItem])> { + match self { + &Self::Collection(n, ref c) => Some((n, c)), + _ => None, + } + } +} impl<'a> ReportIter<'a> { pub fn new(flat: ReportFlatIter<'a>) -> Self { Self { diff --git a/usbhidd/src/reqs.rs b/usbhidd/src/reqs.rs index e834474fc2..680497279b 100644 --- a/usbhidd/src/reqs.rs +++ b/usbhidd/src/reqs.rs @@ -11,13 +11,21 @@ const SET_IDLE_REQ: u8 = 0xA; const GET_PROTOCOL_REQ: u8 = 0x3; const SET_PROTOCOL_REQ: u8 = 0xB; +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum ReportTy { + Input = 1, + Output, + Feature, +} + fn concat(hi: u8, lo: u8) -> u16 { (u16::from(hi) << 8) | u16::from(lo) } pub fn get_report( - handle: &mut XhciClientHandle, - report_ty: u8, + handle: &XhciClientHandle, + report_ty: ReportTy, report_id: u8, if_num: u16, buffer: &mut [u8], @@ -26,14 +34,14 @@ pub fn get_report( PortReqTy::Class, PortReqRecipient::Interface, GET_REPORT_REQ, - concat(report_ty, report_id), + concat(report_ty as u8, report_id), if_num, DeviceReqData::In(buffer), ) } pub fn set_report( - handle: &mut XhciClientHandle, - report_ty: u8, + handle: &XhciClientHandle, + report_ty: ReportTy, report_id: u8, if_num: u16, buffer: &[u8], @@ -42,13 +50,13 @@ pub fn set_report( PortReqTy::Class, PortReqRecipient::Interface, SET_REPORT_REQ, - concat(report_id, report_ty), + concat(report_id, report_ty as u8), if_num, DeviceReqData::Out(buffer), ) } pub fn get_idle( - handle: &mut XhciClientHandle, + handle: &XhciClientHandle, report_id: u8, if_num: u16, ) -> Result { @@ -65,7 +73,7 @@ pub fn get_idle( Ok(idle_rate) } pub fn set_idle( - handle: &mut XhciClientHandle, + handle: &XhciClientHandle, duration: u8, report_id: u8, if_num: u16, @@ -80,7 +88,7 @@ pub fn set_idle( ) } pub fn get_protocol( - handle: &mut XhciClientHandle, + handle: &XhciClientHandle, if_num: u16, ) -> Result { let mut protocol = 0; @@ -96,7 +104,7 @@ pub fn get_protocol( Ok(protocol) } pub fn set_protocol( - handle: &mut XhciClientHandle, + handle: &XhciClientHandle, protocol: u8, if_num: u16, ) -> Result<(), XhciClientHandleError> { diff --git a/usbhidd/src/usage_tables.rs b/usbhidd/src/usage_tables.rs new file mode 100644 index 0000000000..cf7b8d3424 --- /dev/null +++ b/usbhidd/src/usage_tables.rs @@ -0,0 +1,45 @@ +// See https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf + +#[repr(u8)] +pub enum UsagePage { + GenericDesktop = 1, + SimulationsControl, + VrControls, + SportControls, + GameControls, + GenericDeviceControls, + KeyboardOrKeypad, + Led, + Button, + Ordinal, + TelephonyDevice, + Consumer, + Digitizer, + Unicode = 0x10, + AlphanumericDisplay = 0x14, + MedicalInstrument = 0x40, +} + +#[repr(u8)] +pub enum GenericDesktopUsage { + Pointer = 0x01, + Mouse, + Joystick = 0x04, + GamePad, + Keyboard, + Keypad, + MultiAxisController, + + // 0x0A-0x2F are reserved + + CountedBuffer = 0x3A, + SysControl = 0x80, +} + +#[repr(u8)] +pub enum KeyboardOrKeypadUsage { + KbdErrorRollover = 0x1, + KbdPostFail, + KbdErrorUndefined, + // the rest are used as regular keycodes +} diff --git a/usbscsid/Cargo.toml b/usbscsid/Cargo.toml index 90c80d0779..7b639e5938 100644 --- a/usbscsid/Cargo.toml +++ b/usbscsid/Cargo.toml @@ -8,4 +8,5 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +thiserror = "1" xhcid = { path = "../xhcid" } diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index f78299fb27..13ceec3a12 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -1,5 +1,7 @@ use std::env; +use xhcid_interface::XhciClientHandle; + pub mod protocol; fn main() { @@ -8,8 +10,11 @@ fn main() { const USAGE: &'static str = "usbscsid "; let scheme = args.next().expect(USAGE); - let port = args.next().expect(USAGE); - let protocol = args.next().expect(USAGE); + let port = args.next().expect(USAGE).parse::().expect("port has to be a number"); + let protocol = args.next().expect(USAGE).parse::().expect("protocol has to be a number 0-255"); println!("USB SCSI driver spawned with scheme `{}`, port {}, protocol {}", scheme, port, protocol); + + let handle = XhciClientHandle::new(scheme, port); + let protocol = protocol::setup(&handle, protocol); } diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index ab47b1a9a5..f2e8b5aab4 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -1,4 +1,9 @@ -use super::Protocol; +use std::slice; + +use thiserror::Error; +use xhcid_interface::{DeviceReqData, PortReqTy, PortReqRecipient, XhciClientHandle, XhciClientHandleError}; + +use super::{Protocol, ProtocolError}; pub const CBW_SIGNATURE: u32 = 0x43425355; @@ -35,13 +40,33 @@ pub struct CommandStatusWrapper { pub status: u8, } -pub struct BulkOnlyTransport; +pub struct BulkOnlyTransport<'a> { + handle: &'a XhciClientHandle, +} -impl Protocol for BulkOnlyTransport { - fn send_command_block(&mut self, cb: &[u8]) { +impl<'a> BulkOnlyTransport<'a> { + pub fn init(handle: &'a XhciClientHandle) -> Result { + Ok(Self { + handle, + }) + } +} + +impl<'a> Protocol for BulkOnlyTransport<'a> { + fn send_command_block(&mut self, cb: &[u8]) -> Result<(), ProtocolError> { todo!() } - fn recv_command_block(&mut self, cb: &mut [u8]) { + fn recv_command_block(&mut self, cb: &mut [u8]) -> Result<(), ProtocolError> { todo!() } } + +pub fn bulk_only_mass_storage_reset(handle: &XhciClientHandle, if_num: u16) -> Result<(), XhciClientHandleError> { + handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFF, 0, if_num, DeviceReqData::NoData) +} +pub fn get_max_lun(handle: &XhciClientHandle, if_num: u16) -> Result { + let mut lun = 0; + let buffer = slice::from_mut(&mut lun); + handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFE, 0, if_num, DeviceReqData::In(buffer))?; + Ok(lun) +} diff --git a/usbscsid/src/protocol/mod.rs b/usbscsid/src/protocol/mod.rs index ce63b4e4df..986f7801d6 100644 --- a/usbscsid/src/protocol/mod.rs +++ b/usbscsid/src/protocol/mod.rs @@ -1,12 +1,32 @@ +use thiserror::Error; +use xhcid_interface::{XhciClientHandle, XhciClientHandleError}; + +#[derive(Debug, Error)] +pub enum ProtocolError { + #[error("Too large command block ({0} > 16)")] + TooLargeCommandBlock(usize), + + #[error("xhcid connection error: {0}")] + XhciError(#[from] XhciClientHandleError), +} + pub trait Protocol { - fn send_command_block(&mut self, cb: &[u8]); - fn recv_command_block(&mut self, cb: &mut [u8]); + fn send_command_block(&mut self, cb: &[u8]) -> Result<(), ProtocolError>; + fn recv_command_block(&mut self, cb: &mut [u8]) -> Result<(), ProtocolError>; } /// Bulk-only transport pub mod bot; -/// Control-Bulk-Interface transpoint -mod cbi { +mod uas { // TODO } + +use bot::BulkOnlyTransport; + +pub fn setup<'a>(handle: &'a XhciClientHandle, protocol: u8) -> Option> { + match protocol { + 0x50 => Some(Box::new(BulkOnlyTransport::init(handle).unwrap())), + _ => None, + } +} diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index a2cb08b361..9d78352a3a 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -2,7 +2,7 @@ pub extern crate serde; pub extern crate smallvec; use std::convert::TryFrom; -use std::fs::File; +use std::fs::{File, OpenOptions}; use std::io::prelude::*; use std::{io, result, str}; @@ -315,8 +315,13 @@ impl XhciClientHandle { &self, req: &ConfigureEndpointsReq, ) -> result::Result<(), XhciClientHandleError> { - let path = format!("{}:port{}/configure_endpoints", self.scheme, self.port); - serde_json::to_writer(File::open(path)?, req)?; + let path = format!("{}:port{}/configure", self.scheme, self.port); + let json = serde_json::to_vec(req)?; + let mut file = OpenOptions::new().read(false).write(true).open(path)?; + let json_bytes_written = file.write(&json)?; + if json_bytes_written != json.len() { + return Err(XhciClientHandleError::InvalidResponse(Invalid)); + } Ok(()) } pub fn port_state(&self) -> result::Result { From ae76f571621be0267630ea1df88b586e7c475ce5 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 9 Feb 2020 11:12:18 +0100 Subject: [PATCH 0330/1301] Prepare for orbital communication. --- Cargo.lock | 1 + usbhidd/Cargo.toml | 1 + usbhidd/src/main.rs | 215 ++++++++++++++++++++++++++++++++----- usbhidd/src/report_desc.rs | 33 +++++- 4 files changed, 224 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45920958a4..7609327c6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1328,6 +1328,7 @@ name = "usbhidd" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] diff --git a/usbhidd/Cargo.toml b/usbhidd/Cargo.toml index b76c7ad501..7595756e7c 100644 --- a/usbhidd/Cargo.toml +++ b/usbhidd/Cargo.toml @@ -9,5 +9,6 @@ license = "MIT" [dependencies] bitflags = "1.2" +orbclient = "0.3.27" ux = "0.1" xhcid = { path = "../xhcid" } diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 7f21eb6d9d..40304bfb42 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -1,18 +1,78 @@ use std::env; +use std::fs::File; +use bitflags::bitflags; +use orbclient::KeyEvent as OrbKeyEvent; use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle}; mod report_desc; mod reqs; mod usage_tables; -use report_desc::{MainCollectionFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY}; +use report_desc::{LocalItemsState, MainCollectionFlags, MainItem, MainItemFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY}; use reqs::ReportTy; fn div_round_up(num: u32, denom: u32) -> u32 { if num % denom == 0 { num / denom } else { num / denom + 1 } } +bitflags! { + pub struct ModifierKeys: u8 { + const LEFT_CTRL = 1 << 0; + const LEFT_SHIFT = 1 << 1; + const LEFT_ALT = 1 << 2; + const LEFT_META = 1 << 3; + const RIGHT_CTRL = 1 << 4; + const RIGHT_SHIFT = 1 << 5; + const RIGHT_ALT = 1 << 6; + const RIGHT_META = 1 << 7; + } +} + +struct BinaryView<'a> { + data: &'a [u8], + offset: usize, + len: usize, +} +impl<'a> BinaryView<'a> { + pub fn new(data: &'a [u8], offset: usize, len: usize) -> Self { + Self { + data, + offset, + len, + } + } + pub fn get(&self, bit_index: usize) -> Option { + let bit_index = self.offset + bit_index; + + if bit_index >= self.offset + self.len { return None } + + let byte_index = bit_index / 8; + let bits_from_first = bit_index % 8; + let byte = self.data.get(byte_index)?; + Some(byte & (1 << bits_from_first) != 0) + } + pub fn read_u8(&self, bit_index: usize) -> Option { + let bit_index = self.offset + bit_index; + + if bit_index >= self.offset + self.len { return None } + + let first = bit_index / 8; + let bits_from_first = bit_index % 8; + let first_byte = self.data.get(first)?; + let lo = first_byte >> bits_from_first; + + let hi = if bits_from_first > 0 { + let hi = self.data.get(first + 1)? & ((1 << bits_from_first) - 1); + let bits_to_next = 8 - bits_from_first; + hi << bits_to_next + } else { 0 }; + + + Some(lo | hi) + } +} + fn main() { let mut args = env::args().skip(1); @@ -62,56 +122,161 @@ fn main() { handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0 }).expect("Failed to configure endpoints"); - let (mut state, mut stack) = (GlobalItemsState::default(), Vec::new()); + let (mut global_state, mut local_state, mut stack) = (GlobalItemsState::default(), LocalItemsState::default(), Vec::new()); - let (_, application_collection) = report_desc.iter().inspect(|item: &&ReportIterItem| if let ReportIterItem::Item(ref item) = item { - report_desc::update_state(&mut state, &mut stack, item).unwrap() - }).filter_map(ReportIterItem::as_collection).find(|&(n, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection"); + let (_, application_collection, application_global_state, application_local_state) = report_desc.iter().filter_map(|item: &ReportIterItem| + match item { + &ReportIterItem::Item(ref item) => { + report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); + report_desc::update_local_state(&mut local_state, item); + None + } + &ReportIterItem::Collection(n, ref collection) => { + let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default()); + Some((n, collection, global_state, lc_state)) + } + } + ).find(|&(n, _, _, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection"); // Get all main items, and their global item options. { let items = application_collection.iter().filter_map(ReportIterItem::as_item).filter_map(|item| match item { ReportItem::Global(_) => { - report_desc::update_state(&mut state, &mut stack, item).unwrap(); + report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); None } - ReportItem::Main(m) => Some((state, m)), - ReportItem::Local(_) => None, + ReportItem::Main(m) => { + let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default()); + Some((global_state, lc_state, m)) + } + ReportItem::Local(_) => { + report_desc::update_local_state(&mut local_state, item); + None + }, }); - let total_length = items.filter_map(|(state, item)| { - let report_size = match state.report_size { + let mut bit_offset = 0; + let inputs = items.filter_map(|(global_state, local_state, item)| { + let report_size = match global_state.report_size { Some(s) => s, None => return None, }; - let report_count = match state.report_count { + let report_count = match global_state.report_count { Some(c) => c, None => return None, }; - let bit_length = report_size * report_count; - - if item.report_ty() != Some(ReportTy::Input) { + if global_state.usage_page != Some(0x7) { return None; } - Some(bit_length) - }).sum(); - let length = div_round_up(total_length, 8); + let bit_length = report_size * report_count; - let mut report_buffer = vec! [0u8; length as usize]; + let offset = bit_offset; + bit_offset += bit_length; + + if let &MainItem::Input(flags) = item { + Some((bit_length, offset, global_state, local_state, MainItemFlags::from_bits_truncate(flags))) + } else { + None + } + }).collect::>(); + let total_bit_length = inputs.iter().map(|(bit_length, _, _, _, _)| bit_length).sum(); + + let total_byte_length = div_round_up(total_bit_length, 8); + + let mut report_buffer = vec! [0u8; total_byte_length as usize]; let mut last_buffer = report_buffer.clone(); let report_ty = ReportTy::Input; let report_id = 0; + let orbital_socket = File::open("display:input").expect("Failed to open orbital input socket"); + + let mut pressed_keys = vec! []; + let mut last_pressed_keys = pressed_keys.clone(); + + let mut modifier_keys = ModifierKeys::empty(); + let mut last_modifier_keys = modifier_keys; + loop { + std::thread::sleep(std::time::Duration::from_millis(10)); + std::mem::swap(&mut report_buffer, &mut last_buffer); reqs::get_report(&handle, report_ty, report_id, interface_num, &mut report_buffer).expect("Failed to get report"); - if report_buffer != last_buffer { - for byte in &report_buffer { - print!("{:#0x} ", byte); - } - println!(); + + if report_buffer == last_buffer { + continue } - std::thread::sleep(std::time::Duration::from_millis(10)) + + for &(bit_length, bit_offset, global_state, local_state, input) in &inputs { + let report_size = global_state.report_size.unwrap(); + let report_count = global_state.report_count.unwrap(); + + if input.contains(MainItemFlags::VARIABLE) { + // variable + //assert_eq!(state.logical_max.unwrap() - state.logical_min.unwrap(), report_count, "modifiers don't map"); + let binary_view = BinaryView::new(&report_buffer, bit_offset as usize, bit_length as usize); + // PRETTYFYME + if report_count == 8 && report_size == 1 && local_state.usage_min == Some(224) && local_state.usage_max == Some(231) && global_state.logical_min == Some(0) && global_state.logical_max == Some(1) { + std::mem::swap(&mut modifier_keys, &mut last_modifier_keys); + modifier_keys = match ModifierKeys::from_bits(binary_view.read_u8(0).unwrap()) { + Some(f) => f, + None => unreachable!(), + }; + } else { + println!("unknown report variable item"); + } + } else { + std::mem::swap(&mut pressed_keys, &mut last_pressed_keys); + pressed_keys.clear(); + + println!("INPUT FLAGS: {:?}", input); + assert_eq!(report_size, 8); + // array + for report_index in 0..report_count as usize { + let binary_view = BinaryView::new(&report_buffer, bit_offset as usize + report_index * report_size as usize, report_size as usize); + let usage = binary_view.read_u8(0).expect("Failed to read array item"); + if usage != 0 { + pressed_keys.push(usage); + } + println!("Report index array {}: {}", report_index, usage); + } + + } + } + let changed_modifier_keys = modifier_keys ^ last_modifier_keys; + for (current, last) in pressed_keys.iter().copied().zip(last_pressed_keys.iter().copied()) { + if current == last { continue } + if current != 0 { + // Keycode current changed state to "pressed". + } else { + // Keycode current changed state to "released". + } + } + println!(); } } - +} + +#[cfg(test)] +mod tests { + #[test] + fn binary_view() { + // 0000 1000 1100 0111 + // E S + let view = super::BinaryView::new(&[0xC7, 0x08], 3, 11); + assert_eq!(view.get(0), Some(false)); + assert_eq!(view.get(2), Some(false)); + assert_eq!(view.get(3), Some(true)); + assert_eq!(view.get(7), Some(false)); + assert_eq!(view.get(17), None); + + assert_eq!(view.read_u8(0), Some(0b0001_1000)); + assert_eq!(view.read_u8(1), Some(0b1000_1100)); + assert_eq!(view.read_u8(2), Some(0b0100_0110)); + assert_eq!(view.read_u8(3), Some(0b0010_0011)); + assert_eq!(view.read_u8(7), None); + + // 0000 1000 1100 0111 + // E S + let view = super::BinaryView::new(&[0xC7, 0x08], 8, 8); + assert_eq!(view.read_u8(0), Some(0b0000_1000)); + } } diff --git a/usbhidd/src/report_desc.rs b/usbhidd/src/report_desc.rs index 9a0019aaba..93c3083b78 100644 --- a/usbhidd/src/report_desc.rs +++ b/usbhidd/src/report_desc.rs @@ -85,7 +85,7 @@ pub struct GlobalItemsState { #[derive(Debug)] pub struct Invalid; -pub fn update_state(current_state: &mut GlobalItemsState, stack: &mut Vec, report_item: &ReportItem) -> Result<(), Invalid> { +pub fn update_global_state(current_state: &mut GlobalItemsState, stack: &mut Vec, report_item: &ReportItem) -> Result<(), Invalid> { match report_item { ReportItem::Global(global) => match global { &GlobalItem::UsagePage(u) => current_state.usage_page = Some(u), @@ -120,6 +120,37 @@ pub enum LocalItem { StringMaximum(u32), Delimeter(u32), } + +#[derive(Clone, Copy, Debug, Default)] +pub struct LocalItemsState { + pub usage: Option, + pub usage_min: Option, + pub usage_max: Option, + pub desig_idx: Option, + pub desig_min: Option, + pub desig_max: Option, + pub str_idx: Option, + pub str_min: Option, + pub str_max: Option, +} +pub fn update_local_state(current_state: &mut LocalItemsState, report_item: &ReportItem) { + match report_item { + ReportItem::Local(local) => match local { + &LocalItem::Usage(u) => current_state.usage = Some(u), + &LocalItem::UsageMinimum(m) => current_state.usage_min = Some(m), + &LocalItem::UsageMaximum(m) => current_state.usage_max = Some(m), + &LocalItem::DesignatorIndex(i) => current_state.desig_idx = Some(i), + &LocalItem::DesignatorMinimum(m) => current_state.desig_min = Some(m), + &LocalItem::DesignatorMaximum(m) => current_state.desig_max = Some(m), + &LocalItem::StringIndex(i) => current_state.str_idx = Some(i), + &LocalItem::StringMinimum(m) => current_state.str_min = Some(m), + &LocalItem::StringMaximum(m) => current_state.str_max = Some(m), + &LocalItem::Delimeter(_) => todo!(), + }, + _ => todo!(), + } +} + #[derive(Debug)] pub enum ReportItem { Main(MainItem), From 6b70e80d207bb275f85b3450c9255ec5a3e59f37 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 9 Feb 2020 17:17:36 +0100 Subject: [PATCH 0331/1301] Add (untested) transfer support. --- Cargo.lock | 1 + usbscsid/Cargo.toml | 1 + usbscsid/src/main.rs | 2 + usbscsid/src/protocol/bot.rs | 2 + usbscsid/src/scsi/cmds.rs | 104 ++++++++++++++++++++++++++++++ usbscsid/src/scsi/mod.rs | 6 ++ usbscsid/src/scsi/opcodes.rs | 112 ++++++++++++++++++++++++++++++++ xhcid/src/driver_interface.rs | 13 +++- xhcid/src/xhci/context.rs | 23 +++++++ xhcid/src/xhci/scheme.rs | 116 ++++++++++++++++++++++++++++++---- xhcid/src/xhci/trb.rs | 39 ++++++++++++ 11 files changed, 405 insertions(+), 14 deletions(-) create mode 100644 usbscsid/src/scsi/cmds.rs create mode 100644 usbscsid/src/scsi/mod.rs create mode 100644 usbscsid/src/scsi/opcodes.rs diff --git a/Cargo.lock b/Cargo.lock index 7609327c6f..99f7c69c29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1337,6 +1337,7 @@ dependencies = [ name = "usbscsid" version = "0.1.0" dependencies = [ + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] diff --git a/usbscsid/Cargo.toml b/usbscsid/Cargo.toml index 7b639e5938..8347ceb0e5 100644 --- a/usbscsid/Cargo.toml +++ b/usbscsid/Cargo.toml @@ -8,5 +8,6 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +plain = "0.2" thiserror = "1" xhcid = { path = "../xhcid" } diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index 13ceec3a12..c5d12dbba2 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -3,6 +3,7 @@ use std::env; use xhcid_interface::XhciClientHandle; pub mod protocol; +pub mod scsi; fn main() { let mut args = env::args().skip(1); @@ -17,4 +18,5 @@ fn main() { let handle = XhciClientHandle::new(scheme, port); let protocol = protocol::setup(&handle, protocol); + } diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index f2e8b5aab4..8db631e35d 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -46,6 +46,8 @@ pub struct BulkOnlyTransport<'a> { impl<'a> BulkOnlyTransport<'a> { pub fn init(handle: &'a XhciClientHandle) -> Result { + let lun = get_max_lun(handle, 0)?; + println!("BOT_MAX_LUN {}", lun); Ok(Self { handle, }) diff --git a/usbscsid/src/scsi/cmds.rs b/usbscsid/src/scsi/cmds.rs new file mode 100644 index 0000000000..dbd7f83fce --- /dev/null +++ b/usbscsid/src/scsi/cmds.rs @@ -0,0 +1,104 @@ +use super::opcodes::{Opcode, ServiceActionA3}; + +#[repr(packed)] +pub struct ReportIdentInfo { + pub opcode: u8, + /// bits 7:5 reserved + pub serviceaction: u8, + pub _rsvd: u16, + pub restricted: u16, + /// little endian + pub alloc_len: u32, + /// bit 0 reserved + pub info_ty: u8, + pub control: u8, +} + +pub const REP_ID_INFO_INFO_TY_MASK: u8 = 0xFE; +pub const REP_ID_INFO_INFO_TY_SHIFT: u8 = 1; + +#[repr(packed)] +pub struct ReportSuppOpcodes { + pub opcode: u8, + /// bits 7:5 reserved + pub serviceaction: u8, + /// bits 2:0 represent "REPORTING OPTIONS", bits 6:3 are reserved, and bit 7 is RCTD + pub rep_opts: u8, + pub req_opcode: u8, + /// little endian + pub req_serviceaction: u16, + /// little endian + pub alloc_len: u32, + pub _rsvd: u8, + pub control: u8, +} +impl ReportSuppOpcodes { + pub const fn new(rep_opts: ReportSuppOpcodesOptions, rctd: bool, req_opcode: u8, req_serviceaction: u16, alloc_len: u32, control: u8) -> Self { + Self { + opcode: Opcode::ServiceActionA3 as u8, + serviceaction: ServiceActionA3::ReportSuppOpcodes as u8, + rep_opts: ((rctd as u8) << REP_OPTS_RCTD_SHIFT) | rep_opts as u8, + req_opcode, + req_serviceaction: u16::to_le(req_serviceaction), + alloc_len: u32::to_le(alloc_len), + _rsvd: 0, + control, + } + } + pub const fn get_all(rctd: bool, alloc_len: u32, control: u8) -> Self { + Self::new(ReportSuppOpcodesOptions::ListAll, rctd, 0, 0, alloc_len, control) + } +} + +pub const REP_OPTS_MAIN_MASK: u8 = 0b0000_0111; +pub const REP_OPTS_MAIN_SHIFT: u8 = 0; +pub const REP_OPTS_RCTD_BIT: u8 = 1 << REP_OPTS_RCTD_SHIFT; +pub const REP_OPTS_RCTD_SHIFT: u8 = 7; + +/// Valid values of the `req_opts` field of `ReportSuppOpcodes`. +#[repr(u8)] +pub enum ReportSuppOpcodesOptions { + /// Returns all commands, no matter what parameters are set. + ListAll, + + /// Returns one command with the requested opcode. If the command has service actions, this + /// command fails. + NoServicaction, + + /// Returns one command with the requested opcode and service action. If the command doesn't + /// support service actions, this command fails. + ExplicitBoth, + + /// Returns one command with the requested opcode and service action. The command may or may + /// not implement service actions, but if it does, it has to be correct for the return value to + /// indicate SUPPORTED. + IndicateSupport, + +} + +#[repr(packed)] +pub struct AllCommandsParam { + /// Little endian + pub data_len: u32, + pub descs: [CommandDescriptor], +} + +#[repr(packed)] +pub struct CommandDescriptor { + pub opcode: u8, + pub _rsvd1: u8, + /// little endian + pub serviceaction: u16, + pub _rsvd2: u8, + /// bit 0 is SERVACTV, bit 1 is CTDP, and bits 7:2 reserved + pub a: u8, + /// little endian + pub cdb_len: u16, +} +#[repr(packed)] +pub struct OneCommandParam { + pub _rsvd: u8, + /// bits 2:0 for SUPPOR, bits 6:3 reserved, and bit 7 for CTDP + pub a: u8, + // TODO +} diff --git a/usbscsid/src/scsi/mod.rs b/usbscsid/src/scsi/mod.rs new file mode 100644 index 0000000000..1b01389e80 --- /dev/null +++ b/usbscsid/src/scsi/mod.rs @@ -0,0 +1,6 @@ +pub mod cmds; +pub mod opcodes; + + +pub struct Scsi { +} diff --git a/usbscsid/src/scsi/opcodes.rs b/usbscsid/src/scsi/opcodes.rs new file mode 100644 index 0000000000..d146238297 --- /dev/null +++ b/usbscsid/src/scsi/opcodes.rs @@ -0,0 +1,112 @@ +#[repr(u8)] +pub enum Opcode { + TestUnitReady = 0x00, + /// obsolete + RezeroUnit = 0x01, + RequestSense = 0x03, + FormatUnit = 0x04, + ReassignBlocks = 0x07, + /// obsolete + Read6 = 0x08, + /// obsolete + Write6 = 0x0A, + /// obsolete + Seek = 0x0B, + Inquiry = 0x12, + ModeSelect6 = 0x15, + /// obsolete + Reserve6 = 0x16, + /// obsolete + Release6 = 0x17, + ModeSense6 = 0x1A, + StartStopUnit = 0x1B, + RecvDiagnosticRes = 0x1C, + SendDiagnostic = 0x1D, + ReadCapacity10 = 0x25, + Read10 = 0x28, + Write10 = 0x2A, + /// obsolete + SeekExt = 0x2B, + WriteAndVerify10 = 0x2E, + Verify10 = 0x2F, + SyncCache10 = 0x35, + ReadDefectData10 = 0x37, + WriteBuf10 = 0x3B, + ReadBuf10 = 0x3C, + /// obsolete + ReadLong10 = 0x3E, + WriteLong10 = 0x3F, + /// obsolete + ChangeDef = 0x40, + WriteSame10 = 0x41, + Unmap = 0x42, + Sanitize = 0x48, + LogSelect = 0x4C, + LogSense = 0x4D, + ModeSelect10 = 0x55, + /// obsolete + Reserve10 = 0x56, + /// obsolete + Release10 = 0x57, + ModeSense10 = 0x5A, + PersistentResvIn = 0x5E, + PersistentResvOut = 0x5F, + ServiceAction7F = 0x7F, + Read16 = 0x88, + Write16 = 0x8A, + WriteAndVerify16 = 0x8E, + Verify16 = 0x8F, + SyncCache16 = 0x91, + WriteSame16 = 0x93, + WriteStream16 = 0x9A, + ReadBuf16 = 0x9B, + WriteAtomic16 = 0x9C, + ServiceAction9E = 0x9E, + ServiceAction9F, + ReportLuns = 0xA0, + SecurityProtoIn = 0xA2, + ServiceActionA3 = 0xA3, + ServiceActionA4 = 0xA4, + Read12 = 0xA8, + Write12 = 0xAA, + WriteAndVerify12 = 0xAE, + Verify12 = 0xAF, + SecurityProtoOut = 0xB5, + ReadDefectData12 = 0xB7, +} + +#[repr(u8)] +pub enum ServiceAction7F { + Read32 = 0x09, + Verify32 = 0x0A, + Write32 = 0x0B, + WriteAndVerify32 = 0x0C, + WriteSame32 = 0x0D, + WriteAtomic32 = 0x18, +} + +#[repr(u8)] +pub enum ServiceAction9E { + ReadCapacity16 = 0x10, + ReadLong16 = 0x11, + GetLbaStatus = 0x12, + StreamControl = 0x14, + BackgroundControl = 0x15, + GetStreamStatus = 0x16, +} +#[repr(u8)] +pub enum ServiceAction9F { + WriteLong16 = 0x11, +} +#[repr(u8)] +pub enum ServiceActionA3 { + ReportIdentInfo = 0x05, + ReportSuppOpcodes = 0x0C, + ReportSuppTaskManFuncs = 0x0D, + ReportTimestamp = 0x0F, +} +#[repr(u8)] +pub enum ServiceActionA4 { + SetIdentInfo = 0x06, + SetTimestamp = 0x0F, +} diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 9d78352a3a..c68aeed058 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -279,20 +279,27 @@ pub enum DeviceReqData<'a> { NoData, } impl DeviceReqData<'_> { - fn len(&self) -> usize { + pub fn len(&self) -> usize { match self { Self::In(buf) => buf.len(), Self::Out(buf) => buf.len(), Self::NoData => 0, } } - fn is_empty(&self) -> bool { + pub fn is_empty(&self) -> bool { self.len() == 0 } + pub fn map_buf T>(&self, f: F) -> Option { + match self { + Self::In(sbuf) => Some(f(sbuf)), + Self::Out(dbuf) => Some(f(dbuf)), + _ => None, + } + } } impl<'a> DeviceReqData<'a> { - fn direction(&self) -> PortReqDirection { + pub fn direction(&self) -> PortReqDirection { match self { DeviceReqData::Out(_) => PortReqDirection::HostToDevice, DeviceReqData::NoData => PortReqDirection::HostToDevice, diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 0e7c882e0b..77614e3d94 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -1,6 +1,8 @@ use syscall::error::Result; use syscall::io::{Dma, Io, Mmio}; +use super::ring::Ring; + #[repr(packed)] pub struct SlotContext { pub a: Mmio, @@ -105,8 +107,23 @@ pub struct StreamContext { rsvd: Mmio, } +unsafe impl plain::Plain for StreamContext {} + +#[repr(u8)] +pub enum StreamContextType { + SecondaryRing, + PrimaryRing, + PrimarySsa8, + PrimarySsa16, + PrimarySsa32, + PrimarySsa64, + PrimarySsa128, + PrimarySsa256, +} + pub struct StreamContextArray { pub contexts: Dma<[StreamContext]>, + pub rings: Vec, } impl StreamContextArray { @@ -114,9 +131,15 @@ impl StreamContextArray { unsafe { Ok(Self { contexts: Dma::zeroed_unsized(count)?, + rings: Vec::new(), }) } } + pub fn add_ring(&mut self, stream_id: u16, link: bool) -> Result<()> { + // NOTE: stream_id is reserved + self.rings.insert(stream_id as usize, Ring::new(link)?); + Ok(()) + } pub fn register(&self) -> u64 { self.contexts.physical() as u64 } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 1b8d6d63af..6811ff0216 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -9,7 +9,7 @@ use syscall::io::{Dma, Io}; use syscall::scheme::SchemeMut; use syscall::{ Error, Result, Stat, EACCES, EBADF, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, - ENOTDIR, ENXIO, EOVERFLOW, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_CREAT, O_DIRECTORY, + ENOTDIR, ENXIO, EOVERFLOW, EPERM, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_CREAT, O_DIRECTORY, O_RDONLY, O_RDWR, O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, }; @@ -310,7 +310,10 @@ impl Xhci { assert_ne!(ep_ty, 0); // 0 means invalid. let ring_ptr = if max_streams != 0 { - let array = StreamContextArray::new(1 << (max_streams + 1))?; + let mut array = StreamContextArray::new(1 << (max_streams + 1))?; + + // TODO: Use as many stream rings as needed. + array.add_ring(1, true)?; let array_ptr = array.register(); assert_eq!( @@ -398,11 +401,86 @@ impl Xhci { Ok(()) } - fn transfer_read(&mut self, port_num: usize, endp_num: u8, buf: &mut [u8]) -> Result<()> { - Err(Error::new(ENOSYS)) + fn transfer_read(&mut self, port_num: usize, endp_idx: u8, buf: &mut [u8]) -> Result { + self.transfer(port_num, endp_idx, if !buf.is_empty() { DeviceReqData::In(buf) } else { DeviceReqData::NoData }) } - fn transfer_write(&mut self, port_num: usize, endp_num: u8, buf: &[u8]) -> Result<()> { - Err(Error::new(ENOSYS)) + fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result { + self.transfer(port_num, endp_idx, if !buf.is_empty() { DeviceReqData::Out(buf) } else { DeviceReqData::NoData }) + } + // TODO: Rename DeviceReqData to something more general. + fn transfer(&mut self, port_num: usize, endp_idx: u8, buf: DeviceReqData) -> Result { + let endp_num = endp_idx + 1; + // TODO: Check that buf has a nonzero size, otherwise (at least for Rust's GlobalAlloc), + // UB. + let mut dma_buffer = match buf { + DeviceReqData::Out(sbuf) => { + let dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; + dma_buffer.copy_from_slice(sbuf); + Some(dma_buffer) + } + DeviceReqData::In(dbuf) => { + Some(unsafe { Dma::<[u8]>::zeroed_unsized(dbuf.len()) }?) + } + DeviceReqData::NoData => None, + }; + + let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?; + let endp_desc: &EndpDesc = port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endp_idx as usize).ok_or(Error::new(EBADF))?; + let endp_state = port_state.endpoint_states.get_mut(&endp_idx).ok_or(Error::new(EBADF))?; + + let ring: &mut Ring = match endp_state { + EndpointState::Ready(super::RingOrStreams::Ring(ref mut ring)) => ring, + EndpointState::Ready(super::RingOrStreams::Streams(stream_ctx_array)) => stream_ctx_array.rings.get_mut(1).ok_or(Error::new(EBADF))?, + EndpointState::Init => return Err(Error::new(EIO)), + }; + // TODO: Scatter-gather transfers, possibly allowing >64KiB sizes. + let len = u16::try_from(buf.len()).or(Err(Error::new(ENOSYS)))?; + let max_packet_size = endp_desc.max_packet_size; + { + let (trb, cycle) = ring.next(); + let (buffer, idt) = if len <= 8 && max_packet_size >= 8 { + buf.map_buf(|buf| { + let bytes = match <[u8; 8]>::try_from(buf) { + Ok(b) => b, + Err(_) => unreachable!(), + }; + // FIXME: little endian, right? + (u64::from_le_bytes(bytes), true) + }).unwrap_or((0, false)) + } else { + (dma_buffer.map(|dma| dma.physical()).unwrap_or(0) as u64, false) + }; + let estimated_td_size = mem::size_of_val(&trb) as u8; // one trb per td + trb.normal(buffer, len, cycle, estimated_td_size, false, true, false, true, idt, false); + } + + self.dbs[port_state.slot as usize].write(endp_num.into()); + + let bytes_transferred = { + let event = self.cmd.next_event(); + while event.data.read() == 0 { + println!(" - Waiting for event"); + } + + // FIXME: EDTLA if event data was set + if event.completion_code() != TrbCompletionCode::ShortPacket as u8 && event.transfer_length() != 0 { + println!("Event trb yielded a short packet, but all bytes were still transferred"); + } + + if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::Transfer as u8 { + println!("Custom transfer event failed with {:#0x} {:#0x} {:#0x}", event.data.read(), event.status.read(), event.control.read()); + } + // TODO: Handle event data + println!("EVENT DATA: {:?}", event.event_data()); + + u32::from(len) - event.transfer_length() + }; + + if let DeviceReqData::In(ref mut dbuf) = buf { + dbuf.copy_from_slice(dma_buffer.unwrap()); + } + + Ok(bytes_transferred) } pub(crate) fn get_dev_desc(&mut self, port_id: usize) -> Result { let st = self @@ -814,10 +892,9 @@ impl SchemeMut for Xhci { return Err(Error::new(EISDIR)); } - if self - .port_states - .get(&port_num) - .ok_or(Error::new(ENOENT))? + let port_state = self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?; + + if port_state .endpoint_states .get(&endpoint_num) .is_none() @@ -833,7 +910,24 @@ impl SchemeMut for Xhci { } EndpointHandleTy::Status(0) } - "transfer" => EndpointHandleTy::Transfer, + "transfer" => { + if endpoint_num == 0 { + // Don't allow user programs to interface directly with the control + // endpoint. + return Err(Error::new(EPERM)); + } + let endp_desc = &port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endpoint_num as usize).ok_or(Error::new(ENOENT))?; + match endp_desc.direction() { + EndpDirection::Out => if flags & O_RDWR != O_WRONLY && flags & O_STAT != 0 { + return Err(Error::new(EACCES)); + } + EndpDirection::In => if flags & O_RDWR != O_RDONLY && flags & O_STAT != 0 { + return Err(Error::new(EACCES)); + } + _ => (), + } + EndpointHandleTy::Transfer + } _ => return Err(Error::new(ENOENT)), }; Handle::Endpoint(port_num, endpoint_num, st) diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 03d2931e11..91e35115ce 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -117,9 +117,18 @@ pub const TRB_STATUS_COMPLETION_CODE_MASK: u32 = 0xFF00_0000; pub const TRB_STATUS_COMPLETION_PARAM_SHIFT: u8 = 0; pub const TRB_STATUS_COMPLETION_PARAM_MASK: u32 = 0x00FF_FFFF; +pub const TRB_STATUS_TRANSFER_LENGTH_SHIFT: u8 = 0; +pub const TRB_STATUS_TRANSFER_LENGTH_MASK: u32 = 0x00FF_FFFF; + pub const TRB_CONTROL_TRB_TYPE_SHIFT: u8 = 10; pub const TRB_CONTROL_TRB_TYPE_MASK: u32 = 0x0000_FC00; +pub const TRB_CONTROL_EVENT_DATA_SHIFT: u8 = 2; +pub const TRB_CONTROL_EVENT_DATA_BIT: u32 = 1 << TRB_CONTROL_EVENT_DATA_SHIFT; + +pub const TRB_CONTROL_ENDPOINT_ID_MASK: u32 = 0x001F_0000; +pub const TRB_CONTROL_ENDPOINT_ID_SHIFT: u8 = 16; + impl Trb { pub fn set(&mut self, data: u64, status: u32, control: u32) { self.data.write(data); @@ -137,6 +146,19 @@ impl Trb { pub fn completion_param(&self) -> u32 { self.status.read() & TRB_STATUS_COMPLETION_PARAM_MASK } + /// Returns the number of bytes that should have been transmitten, but weren't. + pub fn transfer_length(&self) -> u32 { + self.status.read() & TRB_STATUS_TRANSFER_LENGTH_MASK + } + pub fn event_data_bit(&self) -> bool { + self.control.readf(TRB_CONTROL_EVENT_DATA_BIT) + } + pub fn event_data(&self) -> Option { + if self.event_data_bit() { Some(self.data.read()) } else { None } + } + pub fn endpoint_id(&self) -> u8 { + ((self.control.read() & TRB_CONTROL_ENDPOINT_ID_MASK) >> TRB_CONTROL_ENDPOINT_ID_SHIFT) as u8 + } pub fn trb_type(&self) -> u8 { ((self.control.read() & TRB_CONTROL_TRB_TYPE_MASK) >> TRB_CONTROL_TRB_TYPE_SHIFT) as u8 } @@ -216,6 +238,23 @@ impl Trb { | (cycle as u32), ); } + pub fn normal(&mut self, buffer: u64, len: u16, cycle: bool, estimated_td_size: u8, ent: bool, isp: bool, chain: bool, ioc: bool, idt: bool, bei: bool) { + assert_eq!(estimated_td_size & 0x1F, estimated_td_size); + // NOTE: The interrupter target and no snoop flags have been omitted. + self.set( + buffer, + u32::from(len) + | (u32::from(estimated_td_size) << 17), + u32::from(cycle) + | (u32::from(ent) << 1) + | (u32::from(isp) << 2) + | (u32::from(ent) << 4) + | (u32::from(ioc) << 5) + | (u32::from(idt) << 6) + | (u32::from(bei) << 9) + | ((TrbType::Normal as u32) << 10) + ) + } } impl fmt::Debug for Trb { From 62915fadb1fabfef011941cc8fbacca5df5cf50b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 9 Feb 2020 22:35:56 +0100 Subject: [PATCH 0332/1301] Implement stream transfers. They only use one stream though, which defeats the purpose of streams, but at least transfers now work. --- usbhidd/src/main.rs | 50 ++++++++++++++--------------------- usbhidd/src/report_desc.rs | 2 +- usbscsid/src/main.rs | 8 ++++-- xhcid/src/driver_interface.rs | 16 +++++++++++ xhcid/src/xhci/context.rs | 23 +++++++++++++--- xhcid/src/xhci/mod.rs | 7 +++++ xhcid/src/xhci/scheme.rs | 42 +++++++++++++++++------------ 7 files changed, 94 insertions(+), 54 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 40304bfb42..8871b471fc 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -16,19 +16,6 @@ fn div_round_up(num: u32, denom: u32) -> u32 { if num % denom == 0 { num / denom } else { num / denom + 1 } } -bitflags! { - pub struct ModifierKeys: u8 { - const LEFT_CTRL = 1 << 0; - const LEFT_SHIFT = 1 << 1; - const LEFT_ALT = 1 << 2; - const LEFT_META = 1 << 3; - const RIGHT_CTRL = 1 << 4; - const RIGHT_SHIFT = 1 << 5; - const RIGHT_ALT = 1 << 6; - const RIGHT_META = 1 << 7; - } -} - struct BinaryView<'a> { data: &'a [u8], offset: usize, @@ -189,12 +176,9 @@ fn main() { let orbital_socket = File::open("display:input").expect("Failed to open orbital input socket"); - let mut pressed_keys = vec! []; + let mut pressed_keys = Vec::::new(); let mut last_pressed_keys = pressed_keys.clone(); - let mut modifier_keys = ModifierKeys::empty(); - let mut last_modifier_keys = modifier_keys; - loop { std::thread::sleep(std::time::Duration::from_millis(10)); @@ -209,27 +193,35 @@ fn main() { let report_size = global_state.report_size.unwrap(); let report_count = global_state.report_count.unwrap(); - if input.contains(MainItemFlags::VARIABLE) { - // variable - //assert_eq!(state.logical_max.unwrap() - state.logical_min.unwrap(), report_count, "modifiers don't map"); + // TODO: For now, the dynamic value usages cannot overlap with selector usages... + // for now. + + if local_state.usage_min == Some(224) && local_state.usage_max == Some(231) { + // The usages that this descriptor references are all dynamic values. + } else { + // The usages are selectors. + } + + for report_index in 0..report_count { + } + + /*if input.contains(MainItemFlags::VARIABLE) { + // The item is a variable. + let binary_view = BinaryView::new(&report_buffer, bit_offset as usize, bit_length as usize); - // PRETTYFYME + if report_count == 8 && report_size == 1 && local_state.usage_min == Some(224) && local_state.usage_max == Some(231) && global_state.logical_min == Some(0) && global_state.logical_max == Some(1) { - std::mem::swap(&mut modifier_keys, &mut last_modifier_keys); - modifier_keys = match ModifierKeys::from_bits(binary_view.read_u8(0).unwrap()) { - Some(f) => f, - None => unreachable!(), - }; } else { println!("unknown report variable item"); } } else { + // The item is an array. + std::mem::swap(&mut pressed_keys, &mut last_pressed_keys); pressed_keys.clear(); println!("INPUT FLAGS: {:?}", input); assert_eq!(report_size, 8); - // array for report_index in 0..report_count as usize { let binary_view = BinaryView::new(&report_buffer, bit_offset as usize + report_index * report_size as usize, report_size as usize); let usage = binary_view.read_u8(0).expect("Failed to read array item"); @@ -238,10 +230,8 @@ fn main() { } println!("Report index array {}: {}", report_index, usage); } - - } + }*/ } - let changed_modifier_keys = modifier_keys ^ last_modifier_keys; for (current, last) in pressed_keys.iter().copied().zip(last_pressed_keys.iter().copied()) { if current == last { continue } if current != 0 { diff --git a/usbhidd/src/report_desc.rs b/usbhidd/src/report_desc.rs index 93c3083b78..b33927e13e 100644 --- a/usbhidd/src/report_desc.rs +++ b/usbhidd/src/report_desc.rs @@ -147,7 +147,7 @@ pub fn update_local_state(current_state: &mut LocalItemsState, report_item: &Rep &LocalItem::StringMaximum(m) => current_state.str_max = Some(m), &LocalItem::Delimeter(_) => todo!(), }, - _ => todo!(), + _ => (), } } diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index c5d12dbba2..9f427f6a52 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -1,6 +1,6 @@ use std::env; -use xhcid_interface::XhciClientHandle; +use xhcid_interface::{ConfigureEndpointsReq, XhciClientHandle}; pub mod protocol; pub mod scsi; @@ -17,6 +17,10 @@ fn main() { println!("USB SCSI driver spawned with scheme `{}`, port {}, protocol {}", scheme, port, protocol); let handle = XhciClientHandle::new(scheme, port); + + handle.configure_endpoints(&ConfigureEndpointsReq { + config_desc: 0, + }).expect("Failed to configure endpoints"); + let protocol = protocol::setup(&handle, protocol); - } diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index c68aeed058..d019d420f9 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -56,11 +56,20 @@ pub struct EndpDesc { pub interval: u8, pub ssc: Option, } +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum EndpDirection { Out, In, Bidirectional, } +impl From for EndpDirection { + fn from(d: PortReqDirection) -> Self { + match d { + PortReqDirection::DeviceToHost => Self::In, + PortReqDirection::HostToDevice => Self::Out, + } + } +} impl EndpDesc { pub fn ty(self) -> EndpointTy { @@ -344,6 +353,13 @@ impl XhciClientHandle { let string = std::fs::read_to_string(path)?; Ok(string.parse()?) } + pub fn open_endpoint(&self, num: u8, direction: PortReqDirection) -> result::Result { + let path = format!("{}:port{}/endpoints/{}/transfer", self.scheme, self.port, num); + Ok(match direction { + PortReqDirection::HostToDevice => OpenOptions::new().read(false).write(true).create(false).open(path)?, + PortReqDirection::DeviceToHost => OpenOptions::new().read(true).write(false).create(false).open(path)?, + }) + } pub fn device_request<'a>( &self, req_type: PortReqTy, diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 77614e3d94..9403fa0ac5 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -1,3 +1,5 @@ +use std::collections::BTreeMap; + use syscall::error::Result; use syscall::io::{Dma, Io, Mmio}; @@ -123,7 +125,7 @@ pub enum StreamContextType { pub struct StreamContextArray { pub contexts: Dma<[StreamContext]>, - pub rings: Vec, + pub rings: BTreeMap, } impl StreamContextArray { @@ -131,13 +133,26 @@ impl StreamContextArray { unsafe { Ok(Self { contexts: Dma::zeroed_unsized(count)?, - rings: Vec::new(), + rings: BTreeMap::new(), }) } } pub fn add_ring(&mut self, stream_id: u16, link: bool) -> Result<()> { - // NOTE: stream_id is reserved - self.rings.insert(stream_id as usize, Ring::new(link)?); + // NOTE: stream_id 0 is reserved + assert_ne!(stream_id, 0); + + let ring = Ring::new(link)?; + let pointer = ring.register(); + let sct = StreamContextType::PrimaryRing; + + assert_eq!(pointer & (!0xE), pointer); + { + let context = &mut self.contexts[stream_id as usize]; + context.trl.write((pointer as u32) | ((sct as u32) << 1)); + context.trh.write((pointer >> 32) as u32); + // TODO: stopped edtla + } + self.rings.insert(stream_id, ring); Ok(()) } pub fn register(&self) -> u64 { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index cf6923afd4..ea50ba7aff 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -410,6 +410,13 @@ impl Xhci { Ok(()) } + pub fn ring_command_doorbell(&mut self) { + self.dbs[0].write(0); + } + pub fn ring_port_doorbell(&mut self, slot: u8, endpoint: u8, stream_id: u16) { + self.dbs[slot as usize].write(u32::from(endpoint) | (u32::from(stream_id) << 16)); + } + pub fn trigger_irq(&mut self) -> bool { // Read the Interrupter Pending bit. println!("preinterrupt"); diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 6811ff0216..5ba1810407 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -408,17 +408,17 @@ impl Xhci { self.transfer(port_num, endp_idx, if !buf.is_empty() { DeviceReqData::Out(buf) } else { DeviceReqData::NoData }) } // TODO: Rename DeviceReqData to something more general. - fn transfer(&mut self, port_num: usize, endp_idx: u8, buf: DeviceReqData) -> Result { + fn transfer(&mut self, port_num: usize, endp_idx: u8, mut buf: DeviceReqData) -> Result { let endp_num = endp_idx + 1; // TODO: Check that buf has a nonzero size, otherwise (at least for Rust's GlobalAlloc), // UB. - let mut dma_buffer = match buf { + let dma_buffer = match buf { DeviceReqData::Out(sbuf) => { - let dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; + let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; dma_buffer.copy_from_slice(sbuf); Some(dma_buffer) } - DeviceReqData::In(dbuf) => { + DeviceReqData::In(ref dbuf) => { Some(unsafe { Dma::<[u8]>::zeroed_unsized(dbuf.len()) }?) } DeviceReqData::NoData => None, @@ -426,11 +426,20 @@ impl Xhci { let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?; let endp_desc: &EndpDesc = port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endp_idx as usize).ok_or(Error::new(EBADF))?; + + if endp_desc.is_isoch() { + return Err(Error::new(ENOSYS)); + } + + if EndpDirection::from(buf.direction()) != endp_desc.direction() { + return Err(Error::new(EBADF)); + } + let endp_state = port_state.endpoint_states.get_mut(&endp_idx).ok_or(Error::new(EBADF))?; let ring: &mut Ring = match endp_state { EndpointState::Ready(super::RingOrStreams::Ring(ref mut ring)) => ring, - EndpointState::Ready(super::RingOrStreams::Streams(stream_ctx_array)) => stream_ctx_array.rings.get_mut(1).ok_or(Error::new(EBADF))?, + EndpointState::Ready(super::RingOrStreams::Streams(stream_ctx_array)) => stream_ctx_array.rings.get_mut(&1).ok_or(Error::new(EBADF))?, EndpointState::Init => return Err(Error::new(EIO)), }; // TODO: Scatter-gather transfers, possibly allowing >64KiB sizes. @@ -439,22 +448,21 @@ impl Xhci { { let (trb, cycle) = ring.next(); let (buffer, idt) = if len <= 8 && max_packet_size >= 8 { - buf.map_buf(|buf| { - let bytes = match <[u8; 8]>::try_from(buf) { - Ok(b) => b, - Err(_) => unreachable!(), - }; + buf.map_buf(|sbuf| { + let mut bytes = [0u8; 8]; + bytes[..len as usize].copy_from_slice(&sbuf[..len as usize]); // FIXME: little endian, right? (u64::from_le_bytes(bytes), true) }).unwrap_or((0, false)) } else { - (dma_buffer.map(|dma| dma.physical()).unwrap_or(0) as u64, false) + (dma_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, false) }; let estimated_td_size = mem::size_of_val(&trb) as u8; // one trb per td trb.normal(buffer, len, cycle, estimated_td_size, false, true, false, true, idt, false); } - self.dbs[port_state.slot as usize].write(endp_num.into()); + let stream_id = 1u16; + self.dbs[port_state.slot as usize].write(u32::from(endp_num) | (u32::from(stream_id) << 16)); let bytes_transferred = { let event = self.cmd.next_event(); @@ -476,8 +484,8 @@ impl Xhci { u32::from(len) - event.transfer_length() }; - if let DeviceReqData::In(ref mut dbuf) = buf { - dbuf.copy_from_slice(dma_buffer.unwrap()); + if let DeviceReqData::In(dbuf) = &mut buf { + dbuf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); } Ok(bytes_transferred) @@ -876,8 +884,8 @@ impl SchemeMut for Xhci { .get(&endpoint_num) .ok_or(Error::new(ENOENT))? { - EndpointState::Init => "status\n", - EndpointState::Ready { .. } => "transfer\nstatus\n", + EndpointState::Ready { .. } if endpoint_num != 0 => "transfer\nstatus\n", + EndpointState::Init | EndpointState::Ready { .. } => "status\n", } .as_bytes() .to_owned(); @@ -914,7 +922,7 @@ impl SchemeMut for Xhci { if endpoint_num == 0 { // Don't allow user programs to interface directly with the control // endpoint. - return Err(Error::new(EPERM)); + return Err(Error::new(ENOENT)); } let endp_desc = &port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endpoint_num as usize).ok_or(Error::new(ENOENT))?; match endp_desc.direction() { From cff3cf0d28e944347b5847a70b0f70ae8911006f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 10 Feb 2020 11:23:18 +0100 Subject: [PATCH 0333/1301] Add basic logic to usbscsid and support alternate interface. --- Cargo.lock | 7 +++ usbhidd/src/main.rs | 2 +- usbscsid/Cargo.toml | 1 + usbscsid/src/main.rs | 30 +++++++++- usbscsid/src/protocol/bot.rs | 102 ++++++++++++++++++++++++++++++---- usbscsid/src/protocol/mod.rs | 17 ++++-- usbscsid/src/scsi/cmds.rs | 20 +++++++ xhcid/src/driver_interface.rs | 35 +++++++++--- xhcid/src/usb/setup.rs | 13 ++++- xhcid/src/xhci/mod.rs | 4 ++ xhcid/src/xhci/operational.rs | 4 +- xhcid/src/xhci/scheme.rs | 60 ++++++++++++++------ 12 files changed, 248 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 99f7c69c29..acf300f158 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,6 +53,11 @@ dependencies = [ "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bgad" version = "0.1.0" @@ -1337,6 +1342,7 @@ dependencies = [ name = "usbscsid" version = "0.1.0" dependencies = [ + "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", @@ -1470,6 +1476,7 @@ dependencies = [ "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 8871b471fc..f862989fab 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -107,7 +107,7 @@ fn main() { println!("{:?}", item); } - handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0 }).expect("Failed to configure endpoints"); + handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0, interface_desc: None, alternate_setting: None }).expect("Failed to configure endpoints"); let (mut global_state, mut local_state, mut stack) = (GlobalItemsState::default(), LocalItemsState::default(), Vec::new()); diff --git a/usbscsid/Cargo.toml b/usbscsid/Cargo.toml index 8347ceb0e5..7d5f1abf88 100644 --- a/usbscsid/Cargo.toml +++ b/usbscsid/Cargo.toml @@ -8,6 +8,7 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +base64 = "0.11" # Only for debugging plain = "0.2" thiserror = "1" xhcid = { path = "../xhcid" } diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index 9f427f6a52..0d1be15988 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -18,9 +18,35 @@ fn main() { let handle = XhciClientHandle::new(scheme, port); + let desc = handle.get_standard_descs().expect("Failed to get standard descriptors"); + + // TODO: Perhaps the drivers should just be given the config, interface, and alternate setting + // from xhcid. + let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting)) = desc.config_descs.iter().find_map(|config_desc| { + let interface_desc = config_desc.interface_descs.iter().find_map(|if_desc| if if_desc.class == 8 && if_desc.sub_class == 6 && if_desc.protocol == 0x50 { + Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting)) + } else { + None + })?; + Some((config_desc.clone(), config_desc.configuration_value, interface_desc)) + }).expect("Failed to find suitable configuration"); + handle.configure_endpoints(&ConfigureEndpointsReq { - config_desc: 0, + config_desc: configuration_value, + interface_desc: Some(interface_num), + alternate_setting: Some(alternate_setting), }).expect("Failed to configure endpoints"); - let protocol = protocol::setup(&handle, protocol); + let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc).expect("Failed to setup protocol"); + + let get_info = { + // Max number of bytes that can be recieved from a "REPORT IDENTIFYING INFORMATION" + // command. + let alloc_len = 256; + let info_ty = scsi::cmds::ReportIdInfoInfoTy::IdentInfoSupp; + let control = 0; // TODO: NACA? + scsi::cmds::ReportIdentInfo::new(alloc_len, info_ty, control) + }; + use protocol::Protocol; + protocol.send_command(unsafe { plain::as_bytes(&get_info) }).expect("Failed to send command"); } diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index 8db631e35d..d4f3021457 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -1,7 +1,10 @@ -use std::slice; +use std::convert::TryInto; +use std::fs::File; +use std::io::prelude::*; +use std::{io, slice}; use thiserror::Error; -use xhcid_interface::{DeviceReqData, PortReqTy, PortReqRecipient, XhciClientHandle, XhciClientHandleError}; +use xhcid_interface::{ConfDesc, DeviceReqData, EndpDirection, EndpointStatus, IfDesc, PortReqDirection, PortReqTy, PortReqRecipient, XhciClientHandle, XhciClientHandleError, XhciEndpStatusHandle}; use super::{Protocol, ProtocolError}; @@ -12,6 +15,7 @@ pub const CBW_FLAGS_DIRECTION_BIT: u8 = 1 << CBW_FLAGS_DIRECTION_SHIFT; pub const CBW_FLAGS_DIRECTION_SHIFT: u8 = 7; #[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] pub struct CommandBlockWrapper { pub signature: u32, pub tag: u32, @@ -21,6 +25,7 @@ pub struct CommandBlockWrapper { pub cb_len: u8, pub command_block: [u8; 16], } +unsafe impl plain::Plain for CommandBlockWrapper {} pub const CSW_SIGNATURE: u32 = 0x53425355; @@ -33,33 +38,110 @@ pub enum CswStatus { } #[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] pub struct CommandStatusWrapper { pub signature: u32, pub tag: u32, pub data_residue: u32, pub status: u8, } +unsafe impl plain::Plain for CommandStatusWrapper {} pub struct BulkOnlyTransport<'a> { handle: &'a XhciClientHandle, + bulk_in: File, + bulk_out: File, + bulk_in_status: XhciEndpStatusHandle, + bulk_out_status: XhciEndpStatusHandle, + bulk_in_num: u8, + bulk_out_num: u8, + max_lun: u8, + current_tag: u32, } impl<'a> BulkOnlyTransport<'a> { - pub fn init(handle: &'a XhciClientHandle) -> Result { - let lun = get_max_lun(handle, 0)?; - println!("BOT_MAX_LUN {}", lun); + pub fn init(handle: &'a XhciClientHandle, config_desc: &ConfDesc, if_desc: &IfDesc) -> Result { + let endpoints = &if_desc.endpoints; + + let bulk_in_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::In).unwrap() + 1) as u8; + let bulk_out_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::Out).unwrap() + 1) as u8; + + let max_lun = get_max_lun(handle, 0)?; + println!("BOT_MAX_LUN {}", max_lun); + Ok(Self { + bulk_in: handle.open_endpoint(bulk_in_num, PortReqDirection::DeviceToHost)?, + bulk_out: handle.open_endpoint(bulk_out_num, PortReqDirection::HostToDevice)?, + bulk_in_status: handle.open_endpoint_status(bulk_in_num)?, + bulk_out_status: handle.open_endpoint_status(bulk_out_num)?, + bulk_in_num, + bulk_out_num, handle, + max_lun, + current_tag: 0, }) } + fn recover_from_stall(&mut self) -> Result<(), ProtocolError> { + bulk_only_mass_storage_reset(self.handle, 0)?; + const ENDPOINT_HALT: u16 = 0; + self.handle.clear_feature(PortReqRecipient::Endpoint, self.bulk_in_num.into(), ENDPOINT_HALT)?; + self.handle.clear_feature(PortReqRecipient::Endpoint, self.bulk_out_num.into(), ENDPOINT_HALT)?; + + if self.bulk_in_status.current_status()? == EndpointStatus::Halted || self.bulk_out_status.current_status()? == EndpointStatus::Halted { + return Err(ProtocolError::RecoveryFailed) + } + Ok(()) + } } impl<'a> Protocol for BulkOnlyTransport<'a> { - fn send_command_block(&mut self, cb: &[u8]) -> Result<(), ProtocolError> { - todo!() - } - fn recv_command_block(&mut self, cb: &mut [u8]) -> Result<(), ProtocolError> { - todo!() + fn send_command(&mut self, cb: &[u8]) -> Result<(), ProtocolError> { + dbg!(self.bulk_in_status.current_status()?); + dbg!(self.bulk_out_status.current_status()?); + self.current_tag += 1; + let tag = self.current_tag; + + let mut command_block = [0u8; 16]; + if cb.len() > 16 { + return Err(ProtocolError::TooLargeCommandBlock(cb.len())); + } + command_block[..cb.len()].copy_from_slice(&cb); + + let cbw = CommandBlockWrapper { + signature: CBW_SIGNATURE, + tag, + data_transfer_len: 256, // TODO + lun: 0, // TODO + flags: 1 << 7, // TODO + cb_len: cb.len().try_into().or(Err(ProtocolError::TooLargeCommandBlock(cb.len())))?, + command_block, + }; + let bytes_written = self.bulk_out.write(unsafe { plain::as_bytes(&cbw) })?; + if bytes_written != 31 { + panic!("invalid number of cbw bytes written"); + } + let mut buffer = [0u8; 256]; + let bytes_read = self.bulk_in.read(&mut buffer)?; + if bytes_read != 256 { + panic!("invalid number of bytes read"); + } + println!("{}", base64::encode(&buffer[..])); + + let mut csw = CommandStatusWrapper::default(); + let csw_bytes_read = self.bulk_in.read(unsafe { plain::as_mut_bytes(&mut csw) })?; + + if csw_bytes_read != 13 { + panic!("invalid number of csw bytes read"); + } + dbg!(csw); + + if self.bulk_in_status.current_status()? == EndpointStatus::Halted || self.bulk_out_status.current_status()? == EndpointStatus::Halted { + println!("Trying to recover from stall"); + self.recover_from_stall()?; + dbg!(self.bulk_in_status.current_status()?, self.bulk_out_status.current_status()?); + } + + Ok(()) } } diff --git a/usbscsid/src/protocol/mod.rs b/usbscsid/src/protocol/mod.rs index 986f7801d6..87a0b8eb69 100644 --- a/usbscsid/src/protocol/mod.rs +++ b/usbscsid/src/protocol/mod.rs @@ -1,5 +1,7 @@ +use std::io; + use thiserror::Error; -use xhcid_interface::{XhciClientHandle, XhciClientHandleError}; +use xhcid_interface::{DevDesc, ConfDesc, IfDesc, XhciClientHandle, XhciClientHandleError}; #[derive(Debug, Error)] pub enum ProtocolError { @@ -8,11 +10,16 @@ pub enum ProtocolError { #[error("xhcid connection error: {0}")] XhciError(#[from] XhciClientHandleError), + + #[error("i/o error")] + IoError(#[from] io::Error), + + #[error("attempted recovery failed")] + RecoveryFailed, } pub trait Protocol { - fn send_command_block(&mut self, cb: &[u8]) -> Result<(), ProtocolError>; - fn recv_command_block(&mut self, cb: &mut [u8]) -> Result<(), ProtocolError>; + fn send_command(&mut self, command: &[u8]) -> Result<(), ProtocolError>; } /// Bulk-only transport @@ -24,9 +31,9 @@ mod uas { use bot::BulkOnlyTransport; -pub fn setup<'a>(handle: &'a XhciClientHandle, protocol: u8) -> Option> { +pub fn setup<'a>(handle: &'a XhciClientHandle, protocol: u8, dev_desc: &DevDesc, conf_desc: &ConfDesc, if_desc: &IfDesc) -> Option> { match protocol { - 0x50 => Some(Box::new(BulkOnlyTransport::init(handle).unwrap())), + 0x50 => Some(Box::new(BulkOnlyTransport::init(handle, conf_desc, if_desc).unwrap())), _ => None, } } diff --git a/usbscsid/src/scsi/cmds.rs b/usbscsid/src/scsi/cmds.rs index dbd7f83fce..476ed5b758 100644 --- a/usbscsid/src/scsi/cmds.rs +++ b/usbscsid/src/scsi/cmds.rs @@ -13,6 +13,26 @@ pub struct ReportIdentInfo { pub info_ty: u8, pub control: u8, } +impl ReportIdentInfo { + pub fn new(alloc_len: u32, info_ty: ReportIdInfoInfoTy, control: u8) -> Self { + Self { + opcode: Opcode::ServiceActionA3 as u8, + serviceaction: ServiceActionA3::ReportIdentInfo as u8, + _rsvd: 0, + restricted: 0, + alloc_len: u32::to_le(alloc_len), + info_ty: (info_ty as u8) << REP_ID_INFO_INFO_TY_SHIFT, + control, + } + } +} +#[repr(u8)] +pub enum ReportIdInfoInfoTy { + PeripheralDevIdInfo = 0b000_0000, + PeripheralDevTextIdInfo = 0b000_0010, + IdentInfoSupp = 0b111_1111, + // every other number ending with a 1 is restricted +} pub const REP_ID_INFO_INFO_TY_MASK: u8 = 0xFE; pub const REP_ID_INFO_INFO_TY_SHIFT: u8 = 1; diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index d019d420f9..48c9c2fb0e 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -16,8 +16,9 @@ pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK}; #[derive(Serialize, Deserialize)] pub struct ConfigureEndpointsReq { /// Index into the configuration descriptors of the device descriptor. - pub config_desc: usize, - // TODO: Support multiple alternate interfaces as well. + pub config_desc: u8, + pub interface_desc: Option, + pub alternate_setting: Option, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -65,8 +66,8 @@ pub enum EndpDirection { impl From for EndpDirection { fn from(d: PortReqDirection) -> Self { match d { - PortReqDirection::DeviceToHost => Self::In, PortReqDirection::HostToDevice => Self::Out, + PortReqDirection::DeviceToHost => Self::In, } } } @@ -305,9 +306,6 @@ impl DeviceReqData<'_> { _ => None, } } -} - -impl<'a> DeviceReqData<'a> { pub fn direction(&self) -> PortReqDirection { match self { DeviceReqData::Out(_) => PortReqDirection::HostToDevice, @@ -345,7 +343,7 @@ impl XhciClientHandle { let string = std::fs::read_to_string(path)?; Ok(string.parse()?) } - pub fn endpoint_status( + pub fn endpoint_onetime_status( &self, num: u8, ) -> result::Result { @@ -353,6 +351,13 @@ impl XhciClientHandle { let string = std::fs::read_to_string(path)?; Ok(string.parse()?) } + pub fn open_endpoint_status( + &self, + num: u8, + ) -> result::Result { + let path = format!("{}:port{}/endpoints/{}/status", self.scheme, self.port, num); + Ok(XhciEndpStatusHandle(OpenOptions::new().read(true).write(false).create(false).open(path)?)) + } pub fn open_endpoint(&self, num: u8, direction: PortReqDirection) -> result::Result { let path = format!("{}:port{}/endpoints/{}/transfer", self.scheme, self.port, num); Ok(match direction { @@ -413,6 +418,22 @@ impl XhciClientHandle { pub fn get_descriptor(&self, recipient: PortReqRecipient, ty: u8, idx: u8, windex: u16, buffer: &mut [u8]) -> result::Result<(), XhciClientHandleError> { self.device_request(PortReqTy::Standard, recipient, 0x06, (u16::from(ty) << 8) | u16::from(idx), windex, DeviceReqData::In(buffer)) } + pub fn clear_feature(&self, recipient: PortReqRecipient, index: u16, feature_sel: u16) -> result::Result<(), XhciClientHandleError> { + self.device_request(PortReqTy::Standard, recipient, 0x01, feature_sel, index, DeviceReqData::NoData) + } +} + +#[derive(Debug)] +pub struct XhciEndpStatusHandle(File); + +impl XhciEndpStatusHandle { + pub fn current_status(&mut self) -> result::Result { + self.0.seek(io::SeekFrom::Start(0))?; + let mut status_buf = [0u8; 16]; + let len = self.0.read(&mut status_buf)?; + let status = std::str::from_utf8(&status_buf[..len]).or(Err(XhciClientHandleError::InvalidResponse(Invalid)))?; + Ok(status.parse::().or(Err(XhciClientHandleError::InvalidResponse(Invalid)))?) + } } #[derive(Debug, Error)] diff --git a/xhcid/src/usb/setup.rs b/xhcid/src/usb/setup.rs index ff793c133f..d62cb5b988 100644 --- a/xhcid/src/usb/setup.rs +++ b/xhcid/src/usb/setup.rs @@ -172,13 +172,22 @@ impl Setup { } } - pub const fn set_configuration(value: u16) -> Self { + pub const fn set_configuration(value: u8) -> Self { Self { kind: 0b0000_0000, request: 0x09, - value: value, + value: value as u16, index: 0, length: 0, } } + pub const fn set_interface(interface: u8, alternate_setting: u8) -> Self { + Self { + kind: 0b0000_0001, + request: 0x09, + value: alternate_setting as u16, + index: interface as u16, + length: 0, + } + } } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index ea50ba7aff..77b3150142 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -398,6 +398,10 @@ impl Xhci { .collect::>(), }; + if self.cap.cic() { + self.op.set_cie(true); + } + /*match self.spawn_drivers(i, &mut port_state) { Ok(()) => (), Err(err) => println!("Failed to spawn driver for port {}: `{}`", i, err), diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index 213cae4185..d7cc3dfc1a 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -16,10 +16,10 @@ pub struct OperationalRegs { pub const OP_CONFIG_CIE_BIT: u32 = 1 << 9; impl OperationalRegs { - fn cie(&self) -> bool { + pub fn cie(&self) -> bool { self.config.readf(OP_CONFIG_CIE_BIT) } - fn set_cie(&mut self, value: bool) { + pub fn set_cie(&mut self, value: bool) { self.config.writef(OP_CONFIG_CIE_BIT, value) } } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 5ba1810407..098c9d4670 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -8,8 +8,8 @@ use smallvec::{smallvec, SmallVec}; use syscall::io::{Dma, Io}; use syscall::scheme::SchemeMut; use syscall::{ - Error, Result, Stat, EACCES, EBADF, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, - ENOTDIR, ENXIO, EOVERFLOW, EPERM, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_CREAT, O_DIRECTORY, + Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, + ENOTDIR, ENXIO, EOPNOTSUPP, EOVERFLOW, EPERM, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_CREAT, O_DIRECTORY, O_RDONLY, O_RDWR, O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, }; @@ -168,7 +168,7 @@ impl AnyDescriptor { } impl Xhci { - fn set_configuration(&mut self, port: usize, config: u16) -> Result<()> { + fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { let ps = self.port_states.get_mut(&port).ok_or(Error::new(EIO))?; let ring = ps .endpoint_states @@ -180,7 +180,7 @@ impl Xhci { { let (cmd, cycle) = ring.next(); cmd.setup( - usb::Setup::set_configuration(config), + req, TransferKind::NoData, cycle, ); @@ -201,13 +201,13 @@ impl Xhci { if (status >> 24) != TrbCompletionCode::Success as u32 { println!( - "SET_CONFIGURATION ERROR, COMPLETION CODE {:#0x}", + "DEVICE_REQ ERROR, COMPLETION CODE {:#0x}", (status >> 24) ); } println!( - "SET_CONFIGURATION EVENT {:#0x} {:#0x} {:#0x}", + "DEVICE_REQ EVENT {:#0x} {:#0x} {:#0x}", event.data.read(), status, control @@ -218,11 +218,27 @@ impl Xhci { Ok(()) } + fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { + self.device_req_no_data(port, usb::Setup::set_configuration(config)) + } + fn set_interface(&mut self, port: usize, interface_num: u8, alternate_setting: u8) -> Result<()> { + self.device_req_no_data(port, usb::Setup::set_interface(interface_num, alternate_setting)) + } fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { - let req: ConfigureEndpointsReq = + let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; + if (!self.cap.cic() || !self.op.cie()) && (req.config_desc != 0 || req.interface_desc != None || req.alternate_setting != None) { + //return Err(Error::new(EOPNOTSUPP)); + req.config_desc = 0; + req.alternate_setting = None; + req.interface_desc = None; + } + if req.interface_desc.is_some() != req.alternate_setting.is_some() { + return Err(Error::new(EBADMSG)); + } + let port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; let input_context: &mut Dma = &mut port_state.input_context; @@ -236,7 +252,7 @@ impl Xhci { let current_slot_a = input_context.device.slot.a.read(); let endpoints = - &port_state.dev_desc.config_descs[req.config_desc].interface_descs[0].endpoints; + &port_state.dev_desc.config_descs.get(req.config_desc as usize).ok_or(Error::new(EBADMSG))?.interface_descs[0].endpoints; if endpoints.len() >= 31 { return Err(Error::new(EIO)); @@ -249,13 +265,15 @@ impl Xhci { | ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT) & CONTEXT_ENTRIES_MASK), ); + input_context.control.write((u32::from(req.alternate_setting.unwrap_or(0)) << 16) | (u32::from(req.interface_desc.unwrap_or(0)) << 8) | u32::from(req.config_desc)); let lec = self.cap.lec(); for index in 0..endpoints.len() as u8 { let endp_num = index + 1; + let xhc_endp_num = endp_num + 1; - input_context.add_context.writef(1 << (endp_num + 1), true); + input_context.add_context.writef(1 << xhc_endp_num, true); let endp_ctx = input_context .device @@ -394,10 +412,14 @@ impl Xhci { let configuration_value = port_state .dev_desc .config_descs - .get(req.config_desc) + .get(req.config_desc as usize) .ok_or(Error::new(EIO))? .configuration_value; - self.set_configuration(port, configuration_value.into())?; + self.set_configuration(port, configuration_value)?; + + if let (Some(interface_num), Some(alternate_setting)) = (req.interface_desc, req.alternate_setting) { + self.set_interface(port, interface_num, alternate_setting)?; + } Ok(()) } @@ -410,6 +432,7 @@ impl Xhci { // TODO: Rename DeviceReqData to something more general. fn transfer(&mut self, port_num: usize, endp_idx: u8, mut buf: DeviceReqData) -> Result { let endp_num = endp_idx + 1; + let xhc_endp_num = endp_num + 1; // TODO: Check that buf has a nonzero size, otherwise (at least for Rust's GlobalAlloc), // UB. let dma_buffer = match buf { @@ -424,18 +447,19 @@ impl Xhci { DeviceReqData::NoData => None, }; - let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?; - let endp_desc: &EndpDesc = port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endp_idx as usize).ok_or(Error::new(EBADF))?; + let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; + let endp_desc: &EndpDesc = port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endp_idx as usize).ok_or(Error::new(EBADFD))?; if endp_desc.is_isoch() { return Err(Error::new(ENOSYS)); } if EndpDirection::from(buf.direction()) != endp_desc.direction() { + dbg!(buf.direction(), endp_desc, endp_idx, endp_num); return Err(Error::new(EBADF)); } - let endp_state = port_state.endpoint_states.get_mut(&endp_idx).ok_or(Error::new(EBADF))?; + let endp_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?; let ring: &mut Ring = match endp_state { EndpointState::Ready(super::RingOrStreams::Ring(ref mut ring)) => ring, @@ -462,7 +486,7 @@ impl Xhci { } let stream_id = 1u16; - self.dbs[port_state.slot as usize].write(u32::from(endp_num) | (u32::from(stream_id) << 16)); + self.dbs[port_state.slot as usize].write(u32::from(xhc_endp_num) | (u32::from(stream_id) << 16)); let bytes_transferred = { let event = self.cmd.next_event(); @@ -924,7 +948,7 @@ impl SchemeMut for Xhci { // endpoint. return Err(Error::new(ENOENT)); } - let endp_desc = &port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endpoint_num as usize).ok_or(Error::new(ENOENT))?; + let endp_desc = &port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endpoint_num as usize - 1).ok_or(Error::new(ENOENT))?; match endp_desc.direction() { EndpDirection::Out => if flags & O_RDWR != O_WRONLY && flags & O_STAT != 0 { return Err(Error::new(EACCES)); @@ -1092,7 +1116,7 @@ impl SchemeMut for Xhci { &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { EndpointHandleTy::Transfer => { - self.transfer_read(port_num, endp_num, buf)?; + self.transfer_read(port_num, endp_num - 1, buf)?; // TODO: Perhaps transfers with large buffers could be broken up a to smaller // transfers. Ok(buf.len()) @@ -1172,7 +1196,7 @@ impl SchemeMut for Xhci { Ok(buf.len()) } &mut Handle::Endpoint(port_num, endp_num, EndpointHandleTy::Transfer) => { - self.transfer_write(port_num, endp_num, buf)?; + self.transfer_write(port_num, endp_num - 1, buf)?; // TODO Ok(buf.len()) } From e052c5968d6f73da2fe31b1389b52ab307630578 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 10 Feb 2020 16:23:19 +0100 Subject: [PATCH 0334/1301] Support detecting USB port speeds. --- Cargo.lock | 70 +++++----- xhcid/Cargo.toml | 2 +- xhcid/src/xhci/capability.rs | 16 +++ xhcid/src/xhci/extended.rs | 244 +++++++++++++++++++++++++++++++++- xhcid/src/xhci/mod.rs | 123 ++++++++++++++--- xhcid/src/xhci/operational.rs | 4 + xhcid/src/xhci/port.rs | 8 +- xhcid/src/xhci/scheme.rs | 5 + 8 files changed, 415 insertions(+), 57 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index acf300f158..8da1af7f15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,7 +6,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "block-io-wrapper 0.1.0", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -49,7 +49,7 @@ name = "base64" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -92,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.3.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -100,7 +100,7 @@ name = "bytes" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -278,7 +278,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -301,7 +301,7 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -464,7 +464,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#7cfab705109a388c804ae624f8af2d930ab7a06c" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#85c159fdd8bbdc562afb5041ae40dde566bed538" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", @@ -477,7 +477,7 @@ dependencies = [ "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -497,7 +497,7 @@ dependencies = [ "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -632,7 +632,7 @@ source = "git+https://github.com/a8m/pb#87c29c05486afa7335916c870ea3621ff7ef2966 dependencies = [ "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -643,7 +643,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -653,7 +653,7 @@ name = "pcid" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", @@ -827,7 +827,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.1.56" -source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=dma-slices#13dea70f6bdd09f0128595ebf640e203abff7392" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#8d0015be8693a81c2a4459f3c09fb47b98ff07b1" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -932,7 +932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -994,15 +994,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1022,7 +1022,7 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1051,12 +1051,12 @@ name = "stb_truetype" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1066,7 +1066,7 @@ dependencies = [ [[package]] name = "termion" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1090,7 +1090,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1302,10 +1302,10 @@ dependencies = [ [[package]] name = "unicode-normalization" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1462,10 +1462,10 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=dma-slices)", + "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1482,7 +1482,7 @@ dependencies = [ "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" @@ -1505,7 +1505,7 @@ dependencies = [ "checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" @@ -1557,7 +1557,7 @@ dependencies = [ "checksum ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" -"checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=dma-slices)" = "" +"checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" @@ -1577,16 +1577,16 @@ dependencies = [ "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" "checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" -"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7" +"checksum serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "15913895b61e0be854afd32fd4163fcd2a3df34142cf2cb961b310ce694cbf90" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -"checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4" +"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" "checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" -"checksum syn 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8" -"checksum termion 1.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "818ef3700c2a7b447dca1a1dd28341fe635e6ee103c806c636bb9c929991b2cd" +"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" +"checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "205684fd018ca14432b12cce6ea3d46763311a571c3d294e71ba3f01adcf1aad" "checksum thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57e4d2e50ca050ed44fb58309bdce3efa79948f84f9993ad1978de5eebdce5a7" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" @@ -1608,7 +1608,7 @@ dependencies = [ "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" +"checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 7a2b3de990..b67f291149 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -17,7 +17,7 @@ plain = "0.2" lazy_static = "1.4" spin = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "dma-slices" } +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1", features = ["serde"] } diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index d79d93d8f2..3654534f18 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -16,10 +16,17 @@ pub struct CapabilityRegs { pub const HCC_PARAMS1_MAXPSASIZE_MASK: u32 = 0xF000; // 15:12 pub const HCC_PARAMS1_MAXPSASIZE_SHIFT: u8 = 12; +pub const HCC_PARAMS1_XECP_MASK: u32 = 0xFFFF_0000; +pub const HCC_PARAMS1_XECP_SHIFT: u8 = 16; pub const HCC_PARAMS2_LEC_BIT: u32 = 1 << 4; pub const HCC_PARAMS2_CIC_BIT: u32 = 1 << 5; +pub const HCS_PARAMS1_MAX_PORTS_MASK: u32 = 0xFF00_0000; +pub const HCS_PARAMS1_MAX_PORTS_SHIFT: u8 = 24; +pub const HCS_PARAMS1_MAX_SLOTS_MASK: u32 = 0x0000_00FF; +pub const HCS_PARAMS1_MAX_SLOTS_SHIFT: u8 = 0; + impl CapabilityRegs { pub fn lec(&self) -> bool { self.hcc_params2.readf(HCC_PARAMS2_LEC_BIT) @@ -31,4 +38,13 @@ impl CapabilityRegs { ((self.hcc_params1.read() & HCC_PARAMS1_MAXPSASIZE_MASK) >> HCC_PARAMS1_MAXPSASIZE_SHIFT) as u8 } + pub fn max_ports(&self) -> u8 { + ((self.hcs_params1.read() & HCS_PARAMS1_MAX_PORTS_MASK) >> HCS_PARAMS1_MAX_PORTS_SHIFT) as u8 + } + pub fn max_slots(&self) -> u8 { + (self.hcs_params1.read() & HCS_PARAMS1_MAX_SLOTS_MASK) as u8 + } + pub fn ext_caps_ptr_in_dwords(&self) -> u16 { + ((self.hcc_params1.read() & HCC_PARAMS1_XECP_MASK) >> HCC_PARAMS1_XECP_SHIFT) as u16 + } } diff --git a/xhcid/src/xhci/extended.rs b/xhcid/src/xhci/extended.rs index 93962b8347..d444810b86 100644 --- a/xhcid/src/xhci/extended.rs +++ b/xhcid/src/xhci/extended.rs @@ -1,4 +1,54 @@ -use syscall::Mmio; +use std::ops::Range; +use std::ptr::NonNull; +use std::{fmt, mem, ptr, slice}; +use syscall::{Io, Mmio}; + +pub struct ExtendedCapabilitiesIter { + base: *const u8, +} +impl ExtendedCapabilitiesIter { + pub unsafe fn new(base: *const u8) -> Self { + Self { + base, + } + } +} +impl Iterator for ExtendedCapabilitiesIter { + type Item = (NonNull, u8); // pointer, capability id + + fn next(&mut self) -> Option { + unsafe { + let current = NonNull::new(self.base as *mut _)?; + + let reg = current.cast::>().as_ref().read(); + let capability_id = (reg & 0xFF) as u8; + let next_rel_in_dwords = ((reg & 0xFF00) >> 8) as u8; + + let next_rel = u16::from(next_rel_in_dwords) << 2; + + self.base = if next_rel != 0 { self.base.offset(next_rel as isize) } else { ptr::null() }; + + Some((current, capability_id)) + } + } +} + +#[repr(u8)] +pub enum CapabilityId { + // bit 0 is reserved + UsbLegacySupport = 1, + SupportedProtocol, + ExtendedPowerManagement, + IoVirtualization, + MessageInterrupt, + LocalMem, + // bits 7-9 are reserved + UsbDebugCapability = 10, + // bits 11-16 are reserved + ExtendedMessageInterrupt = 17, + // bits 18-191 are reserved + // bits 192-255 are vendor-defined +} #[repr(packed)] pub struct SupportedProtoCap { @@ -6,5 +56,195 @@ pub struct SupportedProtoCap { b: Mmio, c: Mmio, d: Mmio, - protocols: [Mmio], + protocol_speeds: [u8; 0], +} + +#[repr(packed)] +pub struct ProtocolSpeed { + a: Mmio, +} + +pub const PROTO_SPEED_PSIV_MASK: u32 = 0x0000_000F; +pub const PROTO_SPEED_PSIV_SHIFT: u8 = 0; + +pub const PROTO_SPEED_PSIE_MASK: u32 = 0x0000_0030; +pub const PROTO_SPEED_PSIE_SHIFT: u8 = 4; + +pub const PROTO_SPEED_PLT_MASK: u32 = 0x0000_00C0; +pub const PROTO_SPEED_PLT_SHIFT: u8 = 6; + +pub const PROTO_SPEED_PFD_BIT: u32 = 1 << PROTO_SPEED_PFD_SHIFT; +pub const PROTO_SPEED_PFD_SHIFT: u8 = 8; + +pub const PROTO_SPEED_LP_MASK: u32 = 0x0000_C000; +pub const PROTO_SPEED_LP_SHIFT: u8 = 14; + +pub const PROTO_SPEED_PSIM_MASK: u32 = 0xFFFF_0000; +pub const PROTO_SPEED_PSIM_SHIFT: u8 = 16; + +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub enum Psie { + Bps, + Kbps, + Mbps, + Gbps, +} +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum Plt { + Symmetric, + Reserved, + AsymmetricRx, + AsymmetricTx, +} +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum Lp { + SuperSpeed, + SuperSpeedPlus, + Rsvd2, + Rsvd3, +} + +impl ProtocolSpeed { + pub const fn from_raw(raw: u32) -> Self { + Self { + a: Mmio::from(raw), + } + } + pub fn is_lowspeed(&self) -> bool { + self.psim() == 1500 && self.psie() == Psie::Kbps + } + pub fn is_fullspeed(&self) -> bool { + self.psim() == 12 && self.psie() == Psie::Mbps + } + pub fn is_highspeed(&self) -> bool { + self.psim() == 480 && self.psie() == Psie::Mbps + } + /// Protocol speed ID value + pub fn psiv(&self) -> u8 { + ((self.a.read() & PROTO_SPEED_PSIV_MASK) >> PROTO_SPEED_PSIV_SHIFT) as u8 + } + pub fn psie_raw(&self) -> u8 { + ((self.a.read() & PROTO_SPEED_PSIE_MASK) >> PROTO_SPEED_PSIE_SHIFT) as u8 + } + /// Protocol speed ID exponent + pub fn psie(&self) -> Psie { + // safe because psie_raw can only return values in 0..=3 + unsafe { mem::transmute(self.psie_raw()) } + } + pub fn plt_raw(&self) -> u8 { + ((self.a.read() & PROTO_SPEED_PLT_MASK) >> PROTO_SPEED_PLT_SHIFT) as u8 + } + /// PSI type + pub fn plt(&self) -> Plt { + // safe because plt_raw can only return values in 0..=3 + unsafe { mem::transmute(self.plt_raw()) } + } + /// PSI Full-duplex + pub fn pfd(&self) -> bool { + self.a.readf(PROTO_SPEED_PFD_BIT) + } + pub fn lp_raw(&self) -> u8 { + ((self.a.read() & PROTO_SPEED_LP_MASK) >> PROTO_SPEED_LP_SHIFT) as u8 + } + /// Link protocol + pub fn lp(&self) -> Lp { + // safe because lp_raw can only return values in 0..=3 + unsafe { mem::transmute(self.lp_raw()) } + } + /// Protocol speed ID mantissa + pub fn psim(&self) -> u16 { + ((self.a.read() & PROTO_SPEED_PSIM_MASK) >> PROTO_SPEED_PSIM_SHIFT) as u16 + } +} + +impl fmt::Debug for ProtocolSpeed { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ProtocolSpeed") + .field("psiv", &self.psiv()) + .field("psie", &self.psie()) + .field("plt", &self.plt()) + .field("pfd", &self.pfd()) + .field("lp", &self.lp()) + .field("psim", &self.psim()) + .finish() + } +} + +pub const SUPP_PROTO_CAP_REV_MIN_MASK: u32 = 0x00FF_0000; +pub const SUPP_PROTO_CAP_REV_MIN_SHIFT: u8 = 16; + +pub const SUPP_PROTO_CAP_REV_MAJ_MASK: u32 = 0xFF00_0000; +pub const SUPP_PROTO_CAP_REV_MAJ_SHIFT: u8 = 24; + +pub const SUPP_PROTO_CAP_COMPAT_PORT_OFF_MASK: u32 = 0x0000_00FF; +pub const SUPP_PROTO_CAP_COMPAT_PORT_OFF_SHIFT: u8 = 0; + +pub const SUPP_PROTO_CAP_COMPAT_PORT_CNT_MASK: u32 = 0x0000_FF00; +pub const SUPP_PROTO_CAP_COMPAT_PORT_CNT_SHIFT: u8 = 8; + +pub const SUPP_PROTO_CAP_PROTO_DEF_MASK: u32 = 0x0FFF_0000; +pub const SUPP_PROTO_CAP_PROTO_DEF_SHIFT: u8 = 16; + +pub const SUPP_PROTO_CAP_PSIC_MASK: u32 = 0xF000_0000; +pub const SUPP_PROTO_CAP_PSIC_SHIFT: u8 = 28; + +pub const SUPP_PROTO_CAP_PORT_SLOT_TYPE_MASK: u32 = 0x0000_001F; +pub const SUPP_PROTO_CAP_PORT_SLOT_TYPE_SHIFT: u8 = 0; + +impl SupportedProtoCap { + pub unsafe fn protocol_speeds(&self) -> &[ProtocolSpeed] { + slice::from_raw_parts(&self.protocol_speeds as *const u8 as *const _, self.psic() as usize) + } + pub unsafe fn protocol_speeds_mut(&mut self) -> &mut [ProtocolSpeed] { + // XXX: Variance really is annoying sometimes. + slice::from_raw_parts_mut(&self.protocol_speeds as *const u8 as *mut u8 as *mut _, self.psic() as usize) + } + pub fn rev_minor(&self) -> u8 { + ((self.a.read() & SUPP_PROTO_CAP_REV_MIN_MASK) >> SUPP_PROTO_CAP_REV_MIN_SHIFT) as u8 + } + pub fn rev_major(&self) -> u8 { + ((self.a.read() & SUPP_PROTO_CAP_REV_MAJ_MASK) >> SUPP_PROTO_CAP_REV_MAJ_SHIFT) as u8 + } + pub fn name_string(&self) -> [u8; 4] { + // TODO: Little endian, right? + u32::to_le_bytes(self.b.read()) + } + pub fn compat_port_offset(&self) -> u8 { + ((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_OFF_MASK) >> SUPP_PROTO_CAP_COMPAT_PORT_OFF_SHIFT) as u8 + } + pub fn compat_port_count(&self) -> u8 { + ((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_CNT_MASK) >> SUPP_PROTO_CAP_COMPAT_PORT_CNT_SHIFT) as u8 + } + pub fn compat_port_range(&self) -> Range { + self.compat_port_offset()..self.compat_port_offset() + self.compat_port_count() + } + + pub fn proto_defined(&self) -> u16 { + ((self.c.read() & SUPP_PROTO_CAP_PROTO_DEF_MASK) >> SUPP_PROTO_CAP_PROTO_DEF_SHIFT) as u16 + } + pub fn psic(&self) -> u8 { + ((self.c.read() & SUPP_PROTO_CAP_PSIC_MASK) >> SUPP_PROTO_CAP_PSIC_SHIFT) as u8 + } + pub fn proto_slot_ty(&self) -> u8 { + ((self.d.read() & SUPP_PROTO_CAP_PORT_SLOT_TYPE_MASK) >> SUPP_PROTO_CAP_PORT_SLOT_TYPE_SHIFT) as u8 + } +} +impl fmt::Debug for SupportedProtoCap { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + + f.debug_struct("SupportedProtoCap") + .field("rev_minor", &self.rev_minor()) + .field("rev_major", &self.rev_major()) + .field("name_string", &String::from_utf8_lossy(&self.name_string())) + .field("compat_port_offset", &self.compat_port_count()) + .field("compat_port_count", &self.compat_port_offset()) + .field("proto_defined", &self.proto_defined()) + .field("psic", &self.psic()) + .field("proto_slot_ty", &self.proto_slot_ty()) + .field("proto_speeds", unsafe { &self.protocol_speeds().to_owned() }) + .finish() + } } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 77b3150142..a74b7b0c26 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::convert::TryFrom; use std::pin::Pin; +use std::ptr::NonNull; use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak}; use std::{mem, process, slice, sync::atomic, task}; @@ -27,6 +28,7 @@ use self::capability::CapabilityRegs; use self::command::CommandRing; use self::context::{DeviceContextList, InputContext, StreamContextArray}; use self::doorbell::Doorbell; +use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap}; use self::operational::OperationalRegs; use self::port::Port; use self::ring::Ring; @@ -117,6 +119,8 @@ pub struct Xhci { dev_ctx: DeviceContextList, cmd: CommandRing, + base: *const u8, + handles: BTreeMap, next_handle: usize, port_states: BTreeMap, @@ -169,10 +173,7 @@ impl Xhci { let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; println!(" - OP {:X}", op_base); - let max_slots; - let max_ports; - - { + let (max_slots, max_ports) = { println!(" - Wait for ready"); // Wait until controller is ready while op.usb_sts.readf(1 << 11) { @@ -196,13 +197,13 @@ impl Xhci { } println!(" - Read max slots"); - // Read maximum slots and ports - let hcs_params1 = cap.hcs_params1.read(); - max_slots = (hcs_params1 & 0xFF) as u8; - max_ports = ((hcs_params1 & 0xFF000000) >> 24) as u8; + + let max_slots = cap.max_slots(); + let max_ports = cap.max_ports(); println!(" - Max Slots: {}, Max Ports {}", max_slots, max_ports); - } + (max_slots, max_ports) + }; let port_base = op_base + 0x400; let ports = @@ -218,11 +219,12 @@ impl Xhci { println!(" - RUNTIME {:X}", run_base); let mut xhci = Xhci { - cap: cap, - op: op, - ports: ports, - dbs: dbs, - run: run, + base: address as *const u8, + cap, + op, + ports, + dbs, + run, dev_ctx: DeviceContextList::new(max_slots)?, cmd: CommandRing::new()?, handles: BTreeMap::new(), @@ -292,6 +294,10 @@ impl Xhci { self.dbs[0].write(0); println!(" - XHCI initialized"); + + for (pointer, capability) in self.capabilities_iter() { + dbg!(pointer, capability); + } } pub fn enable_port_slot(cmd: &mut CommandRing, dbs: &mut [Doorbell]) -> u8 { @@ -345,7 +351,7 @@ impl Xhci { { input.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit). - input.device.slot.a.write((1 << 27) | (speed << 20)); // FIXME: The speed field, bits 23:20, is deprecated. + input.device.slot.a.write((1 << 27) | (u32::from(speed) << 20)); // FIXME: The speed field, bits 23:20, is deprecated. input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16); // control endpoint? @@ -494,6 +500,93 @@ impl Xhci { Ok(()) } + pub fn capabilities_iter(&self) -> ExtendedCapabilitiesIter { + unsafe { ExtendedCapabilitiesIter::new((self.base as *mut u8).offset((self.cap.ext_caps_ptr_in_dwords() << 2) as isize)) } + } + pub fn supported_protocols_iter(&self) -> impl Iterator { + self.capabilities_iter().filter_map(|(pointer, cap_num)| unsafe { + if cap_num == CapabilityId::SupportedProtocol as u8 { + Some(&*pointer.cast::().as_ptr()) + } else { + None + } + }) + } + pub fn supported_protocol_speeds(&self, port: u8) -> Option> { + use extended::*; + const DEFAULT_SUPP_PROTO_SPEEDS: [ProtocolSpeed; 7] = [ + // Full-speed + ProtocolSpeed::from_raw( + (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT + | (false as u32) << PROTO_SPEED_PFD_SHIFT + | (Psie::Mbps as u32) << PROTO_SPEED_PSIE_SHIFT + | 12 << PROTO_SPEED_PSIM_SHIFT + | 1 << PROTO_SPEED_PSIV_SHIFT + ), + // Low-speed + ProtocolSpeed::from_raw( + (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT + | (false as u32) << PROTO_SPEED_PFD_SHIFT + | (Psie::Kbps as u32) << PROTO_SPEED_PSIE_SHIFT + | 1500 << PROTO_SPEED_PSIM_SHIFT + | 2 << PROTO_SPEED_PSIV_SHIFT + ), + // High-speed + ProtocolSpeed::from_raw( + (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT + | (false as u32) << PROTO_SPEED_PFD_SHIFT + | (Psie::Mbps as u32) << PROTO_SPEED_PSIE_SHIFT + | 480 << PROTO_SPEED_PSIM_SHIFT + | 3 << PROTO_SPEED_PSIV_SHIFT + ), + // SuperSpeed Gen1 x1 + ProtocolSpeed::from_raw( + (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT + | (true as u32) << PROTO_SPEED_PFD_SHIFT + | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT + | 5 << PROTO_SPEED_PSIM_SHIFT + | (Lp::SuperSpeed as u32) << PROTO_SPEED_LP_SHIFT + | 4 << PROTO_SPEED_PSIV_SHIFT + ), + // SuperSpeedPlus Gen2 x1 + ProtocolSpeed::from_raw( + (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT + | (true as u32) << PROTO_SPEED_PFD_SHIFT + | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT + | 10 << PROTO_SPEED_PSIM_SHIFT + | (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT + | 5 << PROTO_SPEED_PSIV_SHIFT + ), + // SuperSpeedPlus Gen1 x2 + ProtocolSpeed::from_raw( + (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT + | (true as u32) << PROTO_SPEED_PFD_SHIFT + | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT + | 10 << PROTO_SPEED_PSIM_SHIFT + | (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT + | 6 << PROTO_SPEED_PSIV_SHIFT + ), + // SuperSpeedPlus Gen2 x2 + ProtocolSpeed::from_raw( + (Plt::Symmetric as u32) << PROTO_SPEED_PLT_SHIFT + | (true as u32) << PROTO_SPEED_PFD_SHIFT + | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT + | 20 << PROTO_SPEED_PSIM_SHIFT + | (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT + | 7 << PROTO_SPEED_PSIV_SHIFT + ), + ]; + let supp_proto = self.supported_protocols_iter().find(|supp_proto| supp_proto.compat_port_range().contains(&port))?; + + Some(if supp_proto.psic() != 0 { + unsafe { supp_proto.protocol_speeds().iter() } + } else { + DEFAULT_SUPP_PROTO_SPEEDS.iter() + }) + } + pub fn lookup_psiv(&self, port: u8, psiv: u8) -> Option<&'static ProtocolSpeed> { + self.supported_protocol_speeds(port)?.find(|speed| speed.psiv() == psiv) + } } #[derive(Deserialize)] struct DriverConfig { diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index d7cc3dfc1a..638f210333 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -1,5 +1,9 @@ +use std::slice; +use std::num::NonZeroU8; use syscall::io::{Io, Mmio}; +use super::CapabilityRegs; + #[repr(packed)] pub struct OperationalRegs { pub usb_cmd: Mmio, diff --git a/xhcid/src/xhci/port.rs b/xhcid/src/xhci/port.rs index 1745a793bd..674a79332a 100644 --- a/xhcid/src/xhci/port.rs +++ b/xhcid/src/xhci/port.rs @@ -39,12 +39,12 @@ impl Port { self.portsc.read() } - pub fn state(&self) -> u32 { - (self.read() & (0b1111 << 5)) >> 5 + pub fn state(&self) -> u8 { + ((self.read() & (0b1111 << 5)) >> 5) as u8 } - pub fn speed(&self) -> u32 { - (self.read() & (0b1111 << 10)) >> 10 + pub fn speed(&self) -> u8 { + ((self.read() & (0b1111 << 10)) >> 10) as u8 } pub fn flags(&self) -> PortFlags { diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 098c9d4670..51633331e6 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -239,6 +239,11 @@ impl Xhci { return Err(Error::new(EBADMSG)); } + let port_speed_id = self.ports[port].speed(); + // FIXME + let speed_id = self.lookup_psiv(port as u8, port_speed_id); + dbg!(speed_id); + let port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; let input_context: &mut Dma = &mut port_state.input_context; From d64cb029868d84c5f65a0ee3264a04dec33d1579 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 10 Feb 2020 18:55:09 +0100 Subject: [PATCH 0335/1301] Allow (untested) usb device requests to send data. --- xhcid/src/xhci/scheme.rs | 179 ++++++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 69 deletions(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 51633331e6..e1f0917d02 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -44,7 +44,10 @@ pub enum EndpointHandleTy { pub enum PortReqState { Init, - Ready(TransferKind, Dma<[u8]>), // direction, buffers + WaitingForDeviceBytes(Dma<[u8]>, usb::Setup), // buffer, setup params + WaitingForHostBytes(Dma<[u8]>, usb::Setup), // buffer, setup params + TmpSetup(usb::Setup), + Tmp, } pub enum Handle { @@ -686,39 +689,12 @@ impl Xhci { bytes_to_read } - fn port_req(&mut self, fd: usize, port_num: usize, buf: &[u8]) -> Result<()> { - use usb::setup::*; - + fn port_req_transfer(&mut self, port_num: usize, data_buffer: Option<&mut Dma<[u8]>>, setup: usb::Setup, transfer_kind: TransferKind) -> Result<()> { // TODO: This json format might be too high level, but is useful for debugging, // but when actual device-specific drivers are written, a binary format would // be better. Maybe something simple like bincode could be used, if a custom binary struct // is too much overkill. - // FIXME: Make sure there aren't any other PortReq handles, perhaps by storing the state in - // PortState? - - let req = serde_json::from_slice::(buf).or(Err(Error::new(EBADMSG)))?; - - let direction = ReqDirection::from(req.direction); - let ty = ReqType::from(req.req_type) as u8; - let recipient = ReqRecipient::from(req.req_recipient) as u8; - - let transfer_kind = match direction { - _ if !req.transfers_data => TransferKind::NoData, - ReqDirection::DeviceToHost => TransferKind::In, - ReqDirection::HostToDevice => TransferKind::Out, - }; - - let setup = Setup { - kind: ((direction as u8) << USB_SETUP_DIR_SHIFT) - | (ty << USB_SETUP_REQ_TY_SHIFT) - | (recipient << USB_SETUP_RECIPIENT_SHIFT), - request: req.request, - value: req.value, - index: req.index, - length: req.length, - }; - let port_state = self .port_states .get_mut(&port_num) @@ -735,28 +711,19 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let mut buffer = None; - { let (cmd, cycle) = ring.next(); - cmd.setup(setup, transfer_kind, cycle); + cmd.setup(setup, TransferKind::In, cycle); } if transfer_kind != TransferKind::NoData { let (cmd, cycle) = ring.next(); - // TODO: Reuse buffers, or something. - // TODO: Validate the size. - // TODO: Sizes above 65536, *perhaps*. - let data_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(req.length as usize)? }; - assert_eq!(data_buffer.len(), req.length as usize); - cmd.data( - data_buffer.physical(), - req.length, + data_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0), + setup.length, transfer_kind == TransferKind::In, cycle, ); - buffer = Some(data_buffer); } { let (cmd, cycle) = ring.next(); @@ -780,18 +747,102 @@ impl Xhci { ); } } - - self.run.ints[0].erdp.write(self.cmd.erdp()); - - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::PortReq(_, ref mut st) if buffer.is_some() => { - *st = PortReqState::Ready(transfer_kind, buffer.unwrap()) - } - _ => return Err(Error::new(EBADF)), - } - Ok(()) } + fn port_req_init_st(&mut self, port_num: usize, req: &PortReq) -> Result { + use usb::setup::*; + + let direction = ReqDirection::from(req.direction); + let ty = ReqType::from(req.req_type) as u8; + let recipient = ReqRecipient::from(req.req_recipient) as u8; + + let transfer_kind = match direction { + _ if !req.transfers_data => TransferKind::NoData, + ReqDirection::DeviceToHost => TransferKind::In, + ReqDirection::HostToDevice => TransferKind::Out, + }; + + let setup = Setup { + kind: ((direction as u8) << USB_SETUP_DIR_SHIFT) + | (ty << USB_SETUP_REQ_TY_SHIFT) + | (recipient << USB_SETUP_RECIPIENT_SHIFT), + request: req.request, + value: req.value, + index: req.index, + length: req.length, + }; + // TODO: Reuse buffers, or something. + // TODO: Validate the size. + // TODO: Sizes above 65536, *perhaps*. + let data_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(req.length as usize)? }; + assert_eq!(data_buffer.len(), req.length as usize); + + Ok(match transfer_kind { + TransferKind::In => PortReqState::WaitingForDeviceBytes(data_buffer, setup), + TransferKind::Out => PortReqState::WaitingForHostBytes(data_buffer, setup), + TransferKind::NoData => PortReqState::TmpSetup(setup), + _ => unreachable!(), + }) + // FIXME: Make sure there aren't any other PortReq handles, perhaps by storing the state in + // PortState? + } + fn handle_port_req_write(&mut self, fd: usize, port_num: usize, mut st: PortReqState, buf: &[u8]) -> Result { + let bytes_written = match st { + PortReqState::Init => { + let req = serde_json::from_slice::(buf).or(Err(Error::new(EBADMSG)))?; + + st = self.port_req_init_st(port_num, &req)?; + + if let PortReqState::TmpSetup(setup) = st { + // No need for any additional reads or writes, before completing. + self.port_req_transfer(port_num, None, setup, TransferKind::NoData)?; + st = PortReqState::Init; + } + + buf.len() + } + PortReqState::WaitingForHostBytes(mut dma_buffer, setup) => { + if buf.len() != dma_buffer.len() { + return Err(Error::new(EINVAL)); + } + dma_buffer.copy_from_slice(buf); + + self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::Out)?; + st = PortReqState::Init; + + buf.len() + } + PortReqState::WaitingForDeviceBytes(_, _) => return Err(Error::new(EBADF)), + PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), + }; + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::PortReq(_, ref mut state) => *state = st, + _ => unreachable!(), + } + Ok(bytes_written) + } + fn handle_port_req_read(&mut self, fd: usize, port_num: usize, mut st: PortReqState, buf: &mut [u8]) -> Result { + let bytes_read = match st { + PortReqState::WaitingForDeviceBytes(mut dma_buffer, setup) => { + if buf.len() != dma_buffer.len() { + return Err(Error::new(EINVAL)); + } + self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::In)?; + buf.copy_from_slice(&dma_buffer); + + st = PortReqState::Init; + + buf.len() + } + PortReqState::Init | PortReqState::WaitingForHostBytes(_, _) => return Err(Error::new(EBADF)), + PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), + }; + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::PortReq(_, ref mut state) => *state = st, + _ => unreachable!(), + } + Ok(bytes_read) + } } impl SchemeMut for Xhci { @@ -1013,10 +1064,11 @@ impl SchemeMut for Xhci { stat.st_mode = MODE_FILE; stat.st_size = buf.len() as u64; } - Handle::PortReq(_, PortReqState::Ready(TransferKind::In, ref buf)) => { + Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) | Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => { stat.st_mode = MODE_CHR; stat.st_size = buf.len() as u64; } + Handle::PortReq(_, PortReqState::Tmp) | Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(), Handle::PortState(_, _) | Handle::PortReq(_, _) => stat.st_mode = MODE_CHR, Handle::Endpoint(_, _, st) => match st { @@ -1181,16 +1233,9 @@ impl SchemeMut for Xhci { Ok(Self::write_dyn_string(string, buf, offset)) } - Handle::PortReq(_, st) => { - if let PortReqState::Ready(TransferKind::In, ref src_buf) = st { - if buf.len() != src_buf.len() { - return Err(Error::new(EINVAL)); - } - buf.copy_from_slice(src_buf); - Ok(buf.len()) - } else { - Err(Error::new(EBADF)) - } + &mut Handle::PortReq(port_num, ref mut st) => { + let state = std::mem::replace(st, PortReqState::Tmp); + self.handle_port_req_read(fd, port_num, state, buf) } } } @@ -1205,16 +1250,12 @@ impl SchemeMut for Xhci { // TODO Ok(buf.len()) } - &mut Handle::PortReq(port_num, PortReqState::Init) => { - self.port_req(fd, port_num, buf)?; - Ok(buf.len()) + &mut Handle::PortReq(port_num, ref mut st) => { + let state = std::mem::replace(st, PortReqState::Tmp); + self.handle_port_req_write(fd, port_num, state, buf) } // TODO: Introduce PortReqState::Waiting, which this write call changes to // PortReqState::ReadyToWrite when all bytes are written. - &mut Handle::PortReq( - port_num, - PortReqState::Ready(TransferKind::Out, ref mut src_buf), - ) => return Err(Error::new(ENOSYS)), _ => return Err(Error::new(EBADF)), } } From d82ae0a5f6e1088aff0aaa1e422b3f9604f45147 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 10 Feb 2020 23:12:11 +0100 Subject: [PATCH 0336/1301] Add periodic (driver interface-level) transfers. --- usbscsid/src/main.rs | 10 +- usbscsid/src/protocol/bot.rs | 99 ++++++--- usbscsid/src/protocol/mod.rs | 4 +- usbscsid/src/scsi/cmds.rs | 23 +++ xhcid/src/driver_interface.rs | 176 ++++++++++++++-- xhcid/src/xhci/capability.rs | 3 +- xhcid/src/xhci/extended.rs | 38 ++-- xhcid/src/xhci/mod.rs | 53 +++-- xhcid/src/xhci/operational.rs | 2 +- xhcid/src/xhci/scheme.rs | 375 +++++++++++++++++++++++++++------- xhcid/src/xhci/trb.rs | 63 +++++- 11 files changed, 680 insertions(+), 166 deletions(-) diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index 0d1be15988..0c740af631 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -1,6 +1,6 @@ use std::env; -use xhcid_interface::{ConfigureEndpointsReq, XhciClientHandle}; +use xhcid_interface::{ConfigureEndpointsReq, DeviceReqData, XhciClientHandle}; pub mod protocol; pub mod scsi; @@ -39,14 +39,16 @@ fn main() { let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc).expect("Failed to setup protocol"); - let get_info = { + /*let get_info = { // Max number of bytes that can be recieved from a "REPORT IDENTIFYING INFORMATION" // command. let alloc_len = 256; let info_ty = scsi::cmds::ReportIdInfoInfoTy::IdentInfoSupp; let control = 0; // TODO: NACA? scsi::cmds::ReportIdentInfo::new(alloc_len, info_ty, control) - }; + };*/ + let inquiry = scsi::cmds::Inquiry::new(false, 0, 36, 0); + let mut buffer = [0u8; 36]; use protocol::Protocol; - protocol.send_command(unsafe { plain::as_bytes(&get_info) }).expect("Failed to send command"); + protocol.send_command(unsafe { plain::as_bytes(&inquiry) }, DeviceReqData::In(&mut buffer)).expect("Failed to send command"); } diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index d4f3021457..86065ac128 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -4,7 +4,7 @@ use std::io::prelude::*; use std::{io, slice}; use thiserror::Error; -use xhcid_interface::{ConfDesc, DeviceReqData, EndpDirection, EndpointStatus, IfDesc, PortReqDirection, PortReqTy, PortReqRecipient, XhciClientHandle, XhciClientHandleError, XhciEndpStatusHandle}; +use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqDirection, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpStatusHandle, XhciEndpTransferHandle}; use super::{Protocol, ProtocolError}; @@ -25,6 +25,28 @@ pub struct CommandBlockWrapper { pub cb_len: u8, pub command_block: [u8; 16], } +impl CommandBlockWrapper { + pub fn new(tag: u32, data_transfer_len: u32, direction: EndpBinaryDirection, lun: u8, cb: &[u8]) -> Result { + let mut command_block = [0u8; 16]; + if cb.len() > 16 { + return Err(ProtocolError::TooLargeCommandBlock(cb.len())); + } + + command_block[..cb.len()].copy_from_slice(&cb); + Ok(Self { + signature: CBW_SIGNATURE, + tag, + data_transfer_len, + flags: match direction { + EndpBinaryDirection::Out => 0, + EndpBinaryDirection::In => 1, + } << CBW_FLAGS_DIRECTION_SHIFT, + lun, + cb_len: cb.len() as u8, + command_block, + }) + } +} unsafe impl plain::Plain for CommandBlockWrapper {} pub const CSW_SIGNATURE: u32 = 0x53425355; @@ -47,10 +69,16 @@ pub struct CommandStatusWrapper { } unsafe impl plain::Plain for CommandStatusWrapper {} +impl CommandStatusWrapper { + pub fn is_valid(&self) -> bool { + self.signature == CSW_SIGNATURE + } +} + pub struct BulkOnlyTransport<'a> { handle: &'a XhciClientHandle, - bulk_in: File, - bulk_out: File, + bulk_in: XhciEndpTransferHandle, + bulk_out: XhciEndpTransferHandle, bulk_in_status: XhciEndpStatusHandle, bulk_out_status: XhciEndpStatusHandle, bulk_in_num: u8, @@ -59,6 +87,8 @@ pub struct BulkOnlyTransport<'a> { current_tag: u32, } +pub const FEATURE_ENDPOINT_HALT: u16 = 0; + impl<'a> BulkOnlyTransport<'a> { pub fn init(handle: &'a XhciClientHandle, config_desc: &ConfDesc, if_desc: &IfDesc) -> Result { let endpoints = &if_desc.endpoints; @@ -81,11 +111,13 @@ impl<'a> BulkOnlyTransport<'a> { current_tag: 0, }) } - fn recover_from_stall(&mut self) -> Result<(), ProtocolError> { + fn clear_stall(&mut self, endp_num: u8) -> Result<(), XhciClientHandleError> { + self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(endp_num), FEATURE_ENDPOINT_HALT) + } + fn reset_recovery(&mut self) -> Result<(), ProtocolError> { bulk_only_mass_storage_reset(self.handle, 0)?; - const ENDPOINT_HALT: u16 = 0; - self.handle.clear_feature(PortReqRecipient::Endpoint, self.bulk_in_num.into(), ENDPOINT_HALT)?; - self.handle.clear_feature(PortReqRecipient::Endpoint, self.bulk_out_num.into(), ENDPOINT_HALT)?; + self.clear_stall(self.bulk_in_num.into())?; + self.clear_stall(self.bulk_out_num.into())?; if self.bulk_in_status.current_status()? == EndpointStatus::Halted || self.bulk_out_status.current_status()? == EndpointStatus::Halted { return Err(ProtocolError::RecoveryFailed) @@ -95,7 +127,7 @@ impl<'a> BulkOnlyTransport<'a> { } impl<'a> Protocol for BulkOnlyTransport<'a> { - fn send_command(&mut self, cb: &[u8]) -> Result<(), ProtocolError> { + fn send_command(&mut self, cb: &[u8], data: DeviceReqData) -> Result<(), ProtocolError> { dbg!(self.bulk_in_status.current_status()?); dbg!(self.bulk_out_status.current_status()?); self.current_tag += 1; @@ -110,34 +142,55 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { let cbw = CommandBlockWrapper { signature: CBW_SIGNATURE, tag, - data_transfer_len: 256, // TODO + data_transfer_len: data.len() as u32, lun: 0, // TODO - flags: 1 << 7, // TODO + flags: u8::from(data.direction() == PortReqDirection::DeviceToHost) << 7, cb_len: cb.len().try_into().or(Err(ProtocolError::TooLargeCommandBlock(cb.len())))?, command_block, }; - let bytes_written = self.bulk_out.write(unsafe { plain::as_bytes(&cbw) })?; - if bytes_written != 31 { - panic!("invalid number of cbw bytes written"); + match self.bulk_out.transfer_write(unsafe { plain::as_bytes(&cbw) })? { + PortTransferStatus::ShortPacket(31) => (), + PortTransferStatus::Stalled => { + panic!("bulk out endpoint stalled when sending CBW"); + } + _ => panic!("invalid number of CBW bytes written; expected a short packed of length 31 (0x1F)"), } - let mut buffer = [0u8; 256]; - let bytes_read = self.bulk_in.read(&mut buffer)?; - if bytes_read != 256 { - panic!("invalid number of bytes read"); - } - println!("{}", base64::encode(&buffer[..])); + + match data { + DeviceReqData::In(buffer) => { + match self.bulk_in.transfer_read(buffer)? { + PortTransferStatus::Success => (), + PortTransferStatus::ShortPacket(len) => panic!("received short packed (len {}) when transferring data", len), + PortTransferStatus::Stalled => { + println!("bulk in endpoint stalled when reading data"); + self.clear_stall(self.bulk_in_num)?; + } + PortTransferStatus::Unknown => return Err(ProtocolError::XhciError(XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")))), + }; + println!("{}", base64::encode(&buffer[..])); + } + DeviceReqData::Out(ref buffer) => todo!(), + DeviceReqData::NoData => todo!(), + }; let mut csw = CommandStatusWrapper::default(); - let csw_bytes_read = self.bulk_in.read(unsafe { plain::as_mut_bytes(&mut csw) })?; - if csw_bytes_read != 13 { - panic!("invalid number of csw bytes read"); + match self.bulk_in.transfer_read(unsafe { plain::as_mut_bytes(&mut csw) })? { + PortTransferStatus::ShortPacket(13) => (), + PortTransferStatus::Stalled => { + println!("bulk in endpoint stalled when reading CSW"); + self.clear_stall(self.bulk_in_num)?; + } + _ => panic!("invalid number of CSW bytes read; expected a short packet of length 13 (0xD)"), + }; + + if !csw.is_valid() { + self.reset_recovery()?; } dbg!(csw); if self.bulk_in_status.current_status()? == EndpointStatus::Halted || self.bulk_out_status.current_status()? == EndpointStatus::Halted { println!("Trying to recover from stall"); - self.recover_from_stall()?; dbg!(self.bulk_in_status.current_status()?, self.bulk_out_status.current_status()?); } diff --git a/usbscsid/src/protocol/mod.rs b/usbscsid/src/protocol/mod.rs index 87a0b8eb69..569505199f 100644 --- a/usbscsid/src/protocol/mod.rs +++ b/usbscsid/src/protocol/mod.rs @@ -1,7 +1,7 @@ use std::io; use thiserror::Error; -use xhcid_interface::{DevDesc, ConfDesc, IfDesc, XhciClientHandle, XhciClientHandleError}; +use xhcid_interface::{DeviceReqData, DevDesc, ConfDesc, IfDesc, XhciClientHandle, XhciClientHandleError}; #[derive(Debug, Error)] pub enum ProtocolError { @@ -19,7 +19,7 @@ pub enum ProtocolError { } pub trait Protocol { - fn send_command(&mut self, command: &[u8]) -> Result<(), ProtocolError>; + fn send_command(&mut self, command: &[u8], data: DeviceReqData) -> Result<(), ProtocolError>; } /// Bulk-only transport diff --git a/usbscsid/src/scsi/cmds.rs b/usbscsid/src/scsi/cmds.rs index 476ed5b758..582d2dd628 100644 --- a/usbscsid/src/scsi/cmds.rs +++ b/usbscsid/src/scsi/cmds.rs @@ -122,3 +122,26 @@ pub struct OneCommandParam { pub a: u8, // TODO } + +#[repr(packed)] +pub struct Inquiry { + pub opcode: u8, + /// bits 7:2 are reserved, bit 1 (CMDDT) is obsolete, bit 0 is EVPD + pub evpd: u8, + pub page_code: u8, + /// little endian + pub alloc_len: u16, + pub control: u8, +} + +impl Inquiry { + pub fn new(evpd: bool, page_code: u8, alloc_len: u16, control: u8) -> Self { + Self { + opcode: Opcode::Inquiry as u8, + evpd: evpd as u8, + page_code, + alloc_len: u16::to_le(alloc_len), + control, + } + } +} diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 48c9c2fb0e..e029e4ab94 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -63,6 +63,21 @@ pub enum EndpDirection { In, Bidirectional, } + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum EndpBinaryDirection { + Out, + In, +} +impl From for EndpDirection { + fn from(b: EndpBinaryDirection) -> Self { + match b { + EndpBinaryDirection::In => Self::In, + EndpBinaryDirection::Out => Self::Out, + } + } +} + impl From for EndpDirection { fn from(d: PortReqDirection) -> Self { match d { @@ -185,7 +200,7 @@ pub struct PortReq { pub length: u16, pub transfers_data: bool, } -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum PortReqDirection { HostToDevice, DeviceToHost, @@ -230,7 +245,7 @@ impl PortState { } #[derive(Debug, Error)] #[error("invalid input")] -pub struct Invalid; +pub struct Invalid(pub &'static str); impl str::FromStr for PortState { type Err = Invalid; @@ -241,7 +256,7 @@ impl str::FromStr for PortState { "default" => Self::Default, "addressed" => Self::Addressed, "configured" => Self::Configured, - _ => return Err(Invalid), + _ => return Err(Invalid("read reserved port state")), }) } } @@ -256,6 +271,14 @@ pub enum EndpointStatus { Error, } +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub enum PortTransferStatus { + Success, + ShortPacket(u16), + Stalled, + Unknown, +} + impl EndpointStatus { pub fn as_str(&self) -> &'static str { match self { @@ -278,7 +301,7 @@ impl str::FromStr for EndpointStatus { "halted" => Self::Halted, "stopped" => Self::Stopped, "error" => Self::Error, - _ => return Err(Invalid), + _ => return Err(Invalid("read reserved endpoint state")), }) } } @@ -334,7 +357,9 @@ impl XhciClientHandle { let mut file = OpenOptions::new().read(false).write(true).open(path)?; let json_bytes_written = file.write(&json)?; if json_bytes_written != json.len() { - return Err(XhciClientHandleError::InvalidResponse(Invalid)); + return Err(XhciClientHandleError::InvalidResponse(Invalid( + "configure_endpoints didn't read as many bytes as were requested", + ))); } Ok(()) } @@ -356,14 +381,35 @@ impl XhciClientHandle { num: u8, ) -> result::Result { let path = format!("{}:port{}/endpoints/{}/status", self.scheme, self.port, num); - Ok(XhciEndpStatusHandle(OpenOptions::new().read(true).write(false).create(false).open(path)?)) + Ok(XhciEndpStatusHandle( + OpenOptions::new() + .read(true) + .write(false) + .create(false) + .open(path)?, + )) } - pub fn open_endpoint(&self, num: u8, direction: PortReqDirection) -> result::Result { - let path = format!("{}:port{}/endpoints/{}/transfer", self.scheme, self.port, num); - Ok(match direction { - PortReqDirection::HostToDevice => OpenOptions::new().read(false).write(true).create(false).open(path)?, - PortReqDirection::DeviceToHost => OpenOptions::new().read(true).write(false).create(false).open(path)?, - }) + pub fn open_endpoint( + &self, + num: u8, + direction: PortReqDirection, + ) -> result::Result { + let path = format!( + "{}:port{}/endpoints/{}/transfer", + self.scheme, self.port, num + ); + Ok(XhciEndpTransferHandle(match direction { + PortReqDirection::HostToDevice => OpenOptions::new() + .read(false) + .write(true) + .create(false) + .open(path)?, + PortReqDirection::DeviceToHost => OpenOptions::new() + .read(true) + .write(false) + .create(false) + .open(path)?, + })) } pub fn device_request<'a>( &self, @@ -374,7 +420,8 @@ impl XhciClientHandle { index: u16, data: DeviceReqData<'a>, ) -> result::Result<(), XhciClientHandleError> { - let length = u16::try_from(data.len()).or(Err(XhciClientHandleError::TransferBufTooLarge(data.len())))?; + let length = u16::try_from(data.len()) + .or(Err(XhciClientHandleError::TransferBufTooLarge(data.len())))?; let req = PortReq { direction: data.direction(), @@ -393,7 +440,9 @@ impl XhciClientHandle { let json_bytes_written = file.write(&json)?; if json_bytes_written != json.len() { - return Err(XhciClientHandleError::InvalidResponse(Invalid)); + return Err(XhciClientHandleError::InvalidResponse(Invalid( + "device_request didn't return the same number of bytes as were written", + ))); } match data { @@ -401,25 +450,55 @@ impl XhciClientHandle { let bytes_read = file.read(buf)?; if bytes_read != buf.len() { - return Err(XhciClientHandleError::InvalidResponse(Invalid)); + return Err(XhciClientHandleError::InvalidResponse(Invalid( + "device_request didn't transfer (host2dev) all bytes", + ))); } } DeviceReqData::Out(buf) => { let bytes_read = file.write(&buf)?; if bytes_read != buf.len() { - return Err(XhciClientHandleError::InvalidResponse(Invalid)); + return Err(XhciClientHandleError::InvalidResponse(Invalid( + "device_request didn't transfer (dev2host) all bytes", + ))); } } DeviceReqData::NoData => (), } Ok(()) } - pub fn get_descriptor(&self, recipient: PortReqRecipient, ty: u8, idx: u8, windex: u16, buffer: &mut [u8]) -> result::Result<(), XhciClientHandleError> { - self.device_request(PortReqTy::Standard, recipient, 0x06, (u16::from(ty) << 8) | u16::from(idx), windex, DeviceReqData::In(buffer)) + pub fn get_descriptor( + &self, + recipient: PortReqRecipient, + ty: u8, + idx: u8, + windex: u16, + buffer: &mut [u8], + ) -> result::Result<(), XhciClientHandleError> { + self.device_request( + PortReqTy::Standard, + recipient, + 0x06, + (u16::from(ty) << 8) | u16::from(idx), + windex, + DeviceReqData::In(buffer), + ) } - pub fn clear_feature(&self, recipient: PortReqRecipient, index: u16, feature_sel: u16) -> result::Result<(), XhciClientHandleError> { - self.device_request(PortReqTy::Standard, recipient, 0x01, feature_sel, index, DeviceReqData::NoData) + pub fn clear_feature( + &self, + recipient: PortReqRecipient, + index: u16, + feature_sel: u16, + ) -> result::Result<(), XhciClientHandleError> { + self.device_request( + PortReqTy::Standard, + recipient, + 0x01, + feature_sel, + index, + DeviceReqData::NoData, + ) } } @@ -431,8 +510,61 @@ impl XhciEndpStatusHandle { self.0.seek(io::SeekFrom::Start(0))?; let mut status_buf = [0u8; 16]; let len = self.0.read(&mut status_buf)?; - let status = std::str::from_utf8(&status_buf[..len]).or(Err(XhciClientHandleError::InvalidResponse(Invalid)))?; - Ok(status.parse::().or(Err(XhciClientHandleError::InvalidResponse(Invalid)))?) + let status = std::str::from_utf8(&status_buf[..len]).or(Err( + XhciClientHandleError::InvalidResponse(Invalid("non-utf8 endpoint state")), + ))?; + Ok(status + .parse::() + .or(Err(XhciClientHandleError::InvalidResponse(Invalid( + "malformed endpoint state", + ))))?) + } + pub fn into_inner(self) -> File { + self.0 + } +} + +#[derive(Debug)] +pub struct XhciEndpTransferHandle(File); + +impl XhciEndpTransferHandle { + fn get_status( + &mut self, + requested_len: usize, + bytes_transferred: usize, + ) -> result::Result { + let mut status_buf = [0u8; 32]; + let status_bytes_read = self.0.read(&mut status_buf)?; + + let status = serde_json::from_slice(dbg!(&status_buf[..status_bytes_read]))?; + + if let PortTransferStatus::ShortPacket(len) = status { + if len as usize != bytes_transferred { + return Err(XhciClientHandleError::InvalidResponse(Invalid("xhcid gave a short packet with a different length than the bytes transferred (which should have been the same)"))); + } + } else if let PortTransferStatus::Success = status { + if requested_len != bytes_transferred { + return Err(XhciClientHandleError::InvalidResponse(Invalid("xhcid transferred fewer or more bytes than requested, but didn't return a short packed"))); + } + } + Ok(status) + } + pub fn transfer_write( + &mut self, + buffer: &[u8], + ) -> result::Result { + let bytes_transferred = self.0.write(buffer)?; + self.get_status(buffer.len(), bytes_transferred) + } + pub fn transfer_read( + &mut self, + buffer: &mut [u8], + ) -> result::Result { + let bytes_transferred = self.0.read(buffer)?; + self.get_status(buffer.len(), bytes_transferred) + } + pub fn into_inner(self) -> File { + self.0 } } diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index 3654534f18..59e841b24e 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -39,7 +39,8 @@ impl CapabilityRegs { as u8 } pub fn max_ports(&self) -> u8 { - ((self.hcs_params1.read() & HCS_PARAMS1_MAX_PORTS_MASK) >> HCS_PARAMS1_MAX_PORTS_SHIFT) as u8 + ((self.hcs_params1.read() & HCS_PARAMS1_MAX_PORTS_MASK) >> HCS_PARAMS1_MAX_PORTS_SHIFT) + as u8 } pub fn max_slots(&self) -> u8 { (self.hcs_params1.read() & HCS_PARAMS1_MAX_SLOTS_MASK) as u8 diff --git a/xhcid/src/xhci/extended.rs b/xhcid/src/xhci/extended.rs index d444810b86..a128a778b4 100644 --- a/xhcid/src/xhci/extended.rs +++ b/xhcid/src/xhci/extended.rs @@ -8,9 +8,7 @@ pub struct ExtendedCapabilitiesIter { } impl ExtendedCapabilitiesIter { pub unsafe fn new(base: *const u8) -> Self { - Self { - base, - } + Self { base } } } impl Iterator for ExtendedCapabilitiesIter { @@ -26,7 +24,11 @@ impl Iterator for ExtendedCapabilitiesIter { let next_rel = u16::from(next_rel_in_dwords) << 2; - self.base = if next_rel != 0 { self.base.offset(next_rel as isize) } else { ptr::null() }; + self.base = if next_rel != 0 { + self.base.offset(next_rel as isize) + } else { + ptr::null() + }; Some((current, capability_id)) } @@ -109,9 +111,7 @@ pub enum Lp { impl ProtocolSpeed { pub const fn from_raw(raw: u32) -> Self { - Self { - a: Mmio::from(raw), - } + Self { a: Mmio::from(raw) } } pub fn is_lowspeed(&self) -> bool { self.psim() == 1500 && self.psie() == Psie::Kbps @@ -196,11 +196,17 @@ pub const SUPP_PROTO_CAP_PORT_SLOT_TYPE_SHIFT: u8 = 0; impl SupportedProtoCap { pub unsafe fn protocol_speeds(&self) -> &[ProtocolSpeed] { - slice::from_raw_parts(&self.protocol_speeds as *const u8 as *const _, self.psic() as usize) + slice::from_raw_parts( + &self.protocol_speeds as *const u8 as *const _, + self.psic() as usize, + ) } pub unsafe fn protocol_speeds_mut(&mut self) -> &mut [ProtocolSpeed] { // XXX: Variance really is annoying sometimes. - slice::from_raw_parts_mut(&self.protocol_speeds as *const u8 as *mut u8 as *mut _, self.psic() as usize) + slice::from_raw_parts_mut( + &self.protocol_speeds as *const u8 as *mut u8 as *mut _, + self.psic() as usize, + ) } pub fn rev_minor(&self) -> u8 { ((self.a.read() & SUPP_PROTO_CAP_REV_MIN_MASK) >> SUPP_PROTO_CAP_REV_MIN_SHIFT) as u8 @@ -213,10 +219,12 @@ impl SupportedProtoCap { u32::to_le_bytes(self.b.read()) } pub fn compat_port_offset(&self) -> u8 { - ((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_OFF_MASK) >> SUPP_PROTO_CAP_COMPAT_PORT_OFF_SHIFT) as u8 + ((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_OFF_MASK) + >> SUPP_PROTO_CAP_COMPAT_PORT_OFF_SHIFT) as u8 } pub fn compat_port_count(&self) -> u8 { - ((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_CNT_MASK) >> SUPP_PROTO_CAP_COMPAT_PORT_CNT_SHIFT) as u8 + ((self.c.read() & SUPP_PROTO_CAP_COMPAT_PORT_CNT_MASK) + >> SUPP_PROTO_CAP_COMPAT_PORT_CNT_SHIFT) as u8 } pub fn compat_port_range(&self) -> Range { self.compat_port_offset()..self.compat_port_offset() + self.compat_port_count() @@ -229,12 +237,12 @@ impl SupportedProtoCap { ((self.c.read() & SUPP_PROTO_CAP_PSIC_MASK) >> SUPP_PROTO_CAP_PSIC_SHIFT) as u8 } pub fn proto_slot_ty(&self) -> u8 { - ((self.d.read() & SUPP_PROTO_CAP_PORT_SLOT_TYPE_MASK) >> SUPP_PROTO_CAP_PORT_SLOT_TYPE_SHIFT) as u8 + ((self.d.read() & SUPP_PROTO_CAP_PORT_SLOT_TYPE_MASK) + >> SUPP_PROTO_CAP_PORT_SLOT_TYPE_SHIFT) as u8 } } impl fmt::Debug for SupportedProtoCap { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("SupportedProtoCap") .field("rev_minor", &self.rev_minor()) .field("rev_major", &self.rev_major()) @@ -244,7 +252,9 @@ impl fmt::Debug for SupportedProtoCap { .field("proto_defined", &self.proto_defined()) .field("psic", &self.psic()) .field("proto_slot_ty", &self.proto_slot_ty()) - .field("proto_speeds", unsafe { &self.protocol_speeds().to_owned() }) + .field("proto_speeds", unsafe { + &self.protocol_speeds().to_owned() + }) .finish() } } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index a74b7b0c26..6f3cd5d157 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -351,7 +351,11 @@ impl Xhci { { input.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit). - input.device.slot.a.write((1 << 27) | (u32::from(speed) << 20)); // FIXME: The speed field, bits 23:20, is deprecated. + input + .device + .slot + .a + .write((1 << 27) | (u32::from(speed) << 20)); // FIXME: The speed field, bits 23:20, is deprecated. input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16); // control endpoint? @@ -501,18 +505,26 @@ impl Xhci { Ok(()) } pub fn capabilities_iter(&self) -> ExtendedCapabilitiesIter { - unsafe { ExtendedCapabilitiesIter::new((self.base as *mut u8).offset((self.cap.ext_caps_ptr_in_dwords() << 2) as isize)) } + unsafe { + ExtendedCapabilitiesIter::new( + (self.base as *mut u8).offset((self.cap.ext_caps_ptr_in_dwords() << 2) as isize), + ) + } } pub fn supported_protocols_iter(&self) -> impl Iterator { - self.capabilities_iter().filter_map(|(pointer, cap_num)| unsafe { - if cap_num == CapabilityId::SupportedProtocol as u8 { - Some(&*pointer.cast::().as_ptr()) - } else { - None - } - }) + self.capabilities_iter() + .filter_map(|(pointer, cap_num)| unsafe { + if cap_num == CapabilityId::SupportedProtocol as u8 { + Some(&*pointer.cast::().as_ptr()) + } else { + None + } + }) } - pub fn supported_protocol_speeds(&self, port: u8) -> Option> { + pub fn supported_protocol_speeds( + &self, + port: u8, + ) -> Option> { use extended::*; const DEFAULT_SUPP_PROTO_SPEEDS: [ProtocolSpeed; 7] = [ // Full-speed @@ -521,7 +533,7 @@ impl Xhci { | (false as u32) << PROTO_SPEED_PFD_SHIFT | (Psie::Mbps as u32) << PROTO_SPEED_PSIE_SHIFT | 12 << PROTO_SPEED_PSIM_SHIFT - | 1 << PROTO_SPEED_PSIV_SHIFT + | 1 << PROTO_SPEED_PSIV_SHIFT, ), // Low-speed ProtocolSpeed::from_raw( @@ -529,7 +541,7 @@ impl Xhci { | (false as u32) << PROTO_SPEED_PFD_SHIFT | (Psie::Kbps as u32) << PROTO_SPEED_PSIE_SHIFT | 1500 << PROTO_SPEED_PSIM_SHIFT - | 2 << PROTO_SPEED_PSIV_SHIFT + | 2 << PROTO_SPEED_PSIV_SHIFT, ), // High-speed ProtocolSpeed::from_raw( @@ -537,7 +549,7 @@ impl Xhci { | (false as u32) << PROTO_SPEED_PFD_SHIFT | (Psie::Mbps as u32) << PROTO_SPEED_PSIE_SHIFT | 480 << PROTO_SPEED_PSIM_SHIFT - | 3 << PROTO_SPEED_PSIV_SHIFT + | 3 << PROTO_SPEED_PSIV_SHIFT, ), // SuperSpeed Gen1 x1 ProtocolSpeed::from_raw( @@ -546,7 +558,7 @@ impl Xhci { | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT | 5 << PROTO_SPEED_PSIM_SHIFT | (Lp::SuperSpeed as u32) << PROTO_SPEED_LP_SHIFT - | 4 << PROTO_SPEED_PSIV_SHIFT + | 4 << PROTO_SPEED_PSIV_SHIFT, ), // SuperSpeedPlus Gen2 x1 ProtocolSpeed::from_raw( @@ -555,7 +567,7 @@ impl Xhci { | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT | 10 << PROTO_SPEED_PSIM_SHIFT | (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT - | 5 << PROTO_SPEED_PSIV_SHIFT + | 5 << PROTO_SPEED_PSIV_SHIFT, ), // SuperSpeedPlus Gen1 x2 ProtocolSpeed::from_raw( @@ -564,7 +576,7 @@ impl Xhci { | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT | 10 << PROTO_SPEED_PSIM_SHIFT | (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT - | 6 << PROTO_SPEED_PSIV_SHIFT + | 6 << PROTO_SPEED_PSIV_SHIFT, ), // SuperSpeedPlus Gen2 x2 ProtocolSpeed::from_raw( @@ -573,10 +585,12 @@ impl Xhci { | (Psie::Gbps as u32) << PROTO_SPEED_PSIE_SHIFT | 20 << PROTO_SPEED_PSIM_SHIFT | (Lp::SuperSpeedPlus as u32) << PROTO_SPEED_LP_SHIFT - | 7 << PROTO_SPEED_PSIV_SHIFT + | 7 << PROTO_SPEED_PSIV_SHIFT, ), ]; - let supp_proto = self.supported_protocols_iter().find(|supp_proto| supp_proto.compat_port_range().contains(&port))?; + let supp_proto = self + .supported_protocols_iter() + .find(|supp_proto| supp_proto.compat_port_range().contains(&port))?; Some(if supp_proto.psic() != 0 { unsafe { supp_proto.protocol_speeds().iter() } @@ -585,7 +599,8 @@ impl Xhci { }) } pub fn lookup_psiv(&self, port: u8, psiv: u8) -> Option<&'static ProtocolSpeed> { - self.supported_protocol_speeds(port)?.find(|speed| speed.psiv() == psiv) + self.supported_protocol_speeds(port)? + .find(|speed| speed.psiv() == psiv) } } #[derive(Deserialize)] diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index 638f210333..0d4af23901 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -1,5 +1,5 @@ -use std::slice; use std::num::NonZeroU8; +use std::slice; use syscall::io::{Io, Mmio}; use super::CapabilityRegs; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index e1f0917d02..0ee5dc2448 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,6 +1,6 @@ use std::convert::TryFrom; use std::io::prelude::*; -use std::{cmp, mem, path, str}; +use std::{cmp, io, mem, path, str}; use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; @@ -8,9 +8,9 @@ use smallvec::{smallvec, SmallVec}; use syscall::io::{Dma, Io}; use syscall::scheme::SchemeMut; use syscall::{ - Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, - ENOTDIR, ENXIO, EOPNOTSUPP, EOVERFLOW, EPERM, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_CREAT, O_DIRECTORY, - O_RDONLY, O_RDWR, O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, + Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, + ENOSYS, ENOTDIR, ENXIO, EOPNOTSUPP, EOVERFLOW, EPERM, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, + O_CREAT, O_DIRECTORY, O_RDONLY, O_RDWR, O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, }; use super::{port, usb}; @@ -33,7 +33,7 @@ use crate::driver_interface::*; pub enum EndpointHandleTy { /// portX/endpoints/Y/transfer. Write calls transfer data to the device, and read calls /// transfer data from the device. - Transfer, + Transfer(PortTransferState), /// portX/endpoints/Y/status Status(usize), // offset @@ -42,10 +42,19 @@ pub enum EndpointHandleTy { Root(usize, Vec), // offset, content } +#[derive(Clone, Copy)] +pub enum PortTransferState { + /// Ready to read or write to do another transfer + Ready, + + /// Transfer has completed, and the status has to be read. + WaitingForStatusReq(PortTransferStatus), +} + pub enum PortReqState { Init, WaitingForDeviceBytes(Dma<[u8]>, usb::Setup), // buffer, setup params - WaitingForHostBytes(Dma<[u8]>, usb::Setup), // buffer, setup params + WaitingForHostBytes(Dma<[u8]>, usb::Setup), // buffer, setup params TmpSetup(usb::Setup), Tmp, } @@ -182,11 +191,7 @@ impl Xhci { { let (cmd, cycle) = ring.next(); - cmd.setup( - req, - TransferKind::NoData, - cycle, - ); + cmd.setup(req, TransferKind::NoData, cycle); } { let (cmd, cycle) = ring.next(); @@ -203,10 +208,7 @@ impl Xhci { let control = event.control.read(); if (status >> 24) != TrbCompletionCode::Success as u32 { - println!( - "DEVICE_REQ ERROR, COMPLETION CODE {:#0x}", - (status >> 24) - ); + println!("DEVICE_REQ ERROR, COMPLETION CODE {:#0x}", (status >> 24)); } println!( @@ -224,15 +226,56 @@ impl Xhci { fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { self.device_req_no_data(port, usb::Setup::set_configuration(config)) } - fn set_interface(&mut self, port: usize, interface_num: u8, alternate_setting: u8) -> Result<()> { - self.device_req_no_data(port, usb::Setup::set_interface(interface_num, alternate_setting)) + fn set_interface( + &mut self, + port: usize, + interface_num: u8, + alternate_setting: u8, + ) -> Result<()> { + self.device_req_no_data( + port, + usb::Setup::set_interface(interface_num, alternate_setting), + ) + } + + fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { + let slot = self + .port_states + .get(&port_num) + .ok_or(Error::new(EBADF))? + .slot; + { + let (cmd, cycle, event) = self.cmd.next(); + cmd.reset_endpoint(slot, endp_num + 1, tsp, cycle); + + self.dbs[0].write(0); + + while event.data.read() == 0 { + println!(" - Waiting for event"); + } + + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::CommandCompletion as u8 + { + println!("RESET_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); + return Err(Error::new(EIO)); + } + + cmd.reserved(false); + event.reserved(false); + + self.run.ints[0].erdp.write(self.cmd.erdp()); + } + Ok(()) } fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; - if (!self.cap.cic() || !self.op.cie()) && (req.config_desc != 0 || req.interface_desc != None || req.alternate_setting != None) { + if (!self.cap.cic() || !self.op.cie()) + && (req.config_desc != 0 || req.interface_desc != None || req.alternate_setting != None) + { //return Err(Error::new(EOPNOTSUPP)); req.config_desc = 0; req.alternate_setting = None; @@ -259,8 +302,13 @@ impl Xhci { let current_slot_a = input_context.device.slot.a.read(); - let endpoints = - &port_state.dev_desc.config_descs.get(req.config_desc as usize).ok_or(Error::new(EBADMSG))?.interface_descs[0].endpoints; + let endpoints = &port_state + .dev_desc + .config_descs + .get(req.config_desc as usize) + .ok_or(Error::new(EBADMSG))? + .interface_descs[0] + .endpoints; if endpoints.len() >= 31 { return Err(Error::new(EIO)); @@ -273,7 +321,11 @@ impl Xhci { | ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT) & CONTEXT_ENTRIES_MASK), ); - input_context.control.write((u32::from(req.alternate_setting.unwrap_or(0)) << 16) | (u32::from(req.interface_desc.unwrap_or(0)) << 8) | u32::from(req.config_desc)); + input_context.control.write( + (u32::from(req.alternate_setting.unwrap_or(0)) << 16) + | (u32::from(req.interface_desc.unwrap_or(0)) << 8) + | u32::from(req.config_desc), + ); let lec = self.cap.lec(); @@ -425,20 +477,49 @@ impl Xhci { .configuration_value; self.set_configuration(port, configuration_value)?; - if let (Some(interface_num), Some(alternate_setting)) = (req.interface_desc, req.alternate_setting) { + if let (Some(interface_num), Some(alternate_setting)) = + (req.interface_desc, req.alternate_setting) + { self.set_interface(port, interface_num, alternate_setting)?; } Ok(()) } - fn transfer_read(&mut self, port_num: usize, endp_idx: u8, buf: &mut [u8]) -> Result { - self.transfer(port_num, endp_idx, if !buf.is_empty() { DeviceReqData::In(buf) } else { DeviceReqData::NoData }) + fn transfer_read( + &mut self, + port_num: usize, + endp_idx: u8, + buf: &mut [u8], + ) -> Result<(u8, u32)> { + self.transfer( + port_num, + endp_idx, + if !buf.is_empty() { + DeviceReqData::In(buf) + } else { + DeviceReqData::NoData + }, + ) } - fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result { - self.transfer(port_num, endp_idx, if !buf.is_empty() { DeviceReqData::Out(buf) } else { DeviceReqData::NoData }) + fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<(u8, u32)> { + self.transfer( + port_num, + endp_idx, + if !buf.is_empty() { + DeviceReqData::Out(buf) + } else { + DeviceReqData::NoData + }, + ) } // TODO: Rename DeviceReqData to something more general. - fn transfer(&mut self, port_num: usize, endp_idx: u8, mut buf: DeviceReqData) -> Result { + fn transfer( + &mut self, + port_num: usize, + endp_idx: u8, + mut buf: DeviceReqData, + ) -> Result<(u8, u32)> { + // TODO: Check that only readable enpoints are read, etc. let endp_num = endp_idx + 1; let xhc_endp_num = endp_num + 1; // TODO: Check that buf has a nonzero size, otherwise (at least for Rust's GlobalAlloc), @@ -455,8 +536,21 @@ impl Xhci { DeviceReqData::NoData => None, }; - let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; - let endp_desc: &EndpDesc = port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endp_idx as usize).ok_or(Error::new(EBADFD))?; + let port_state = self + .port_states + .get_mut(&port_num) + .ok_or(Error::new(EBADFD))?; + let endp_desc: &EndpDesc = port_state + .dev_desc + .config_descs + .get(0) + .ok_or(Error::new(EIO))? + .interface_descs + .get(0) + .ok_or(Error::new(EIO))? + .endpoints + .get(endp_idx as usize) + .ok_or(Error::new(EBADFD))?; if endp_desc.is_isoch() { return Err(Error::new(ENOSYS)); @@ -467,11 +561,19 @@ impl Xhci { return Err(Error::new(EBADF)); } - let endp_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?; + let endp_state = port_state + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADF))?; let ring: &mut Ring = match endp_state { EndpointState::Ready(super::RingOrStreams::Ring(ref mut ring)) => ring, - EndpointState::Ready(super::RingOrStreams::Streams(stream_ctx_array)) => stream_ctx_array.rings.get_mut(&1).ok_or(Error::new(EBADF))?, + EndpointState::Ready(super::RingOrStreams::Streams(stream_ctx_array)) => { + stream_ctx_array + .rings + .get_mut(&1) + .ok_or(Error::new(EBADF))? + } EndpointState::Init => return Err(Error::new(EIO)), }; // TODO: Scatter-gather transfers, possibly allowing >64KiB sizes. @@ -485,42 +587,72 @@ impl Xhci { bytes[..len as usize].copy_from_slice(&sbuf[..len as usize]); // FIXME: little endian, right? (u64::from_le_bytes(bytes), true) - }).unwrap_or((0, false)) + }) + .unwrap_or((0, false)) } else { - (dma_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, false) + ( + dma_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, + false, + ) }; let estimated_td_size = mem::size_of_val(&trb) as u8; // one trb per td - trb.normal(buffer, len, cycle, estimated_td_size, false, true, false, true, idt, false); + trb.normal( + buffer, + len, + cycle, + estimated_td_size, + false, + true, + false, + true, + idt, + false, + ); } let stream_id = 1u16; - self.dbs[port_state.slot as usize].write(u32::from(xhc_endp_num) | (u32::from(stream_id) << 16)); + self.dbs[port_state.slot as usize] + .write(u32::from(xhc_endp_num) | (u32::from(stream_id) << 16)); - let bytes_transferred = { + let (completion_code, bytes_transferred) = { let event = self.cmd.next_event(); while event.data.read() == 0 { println!(" - Waiting for event"); } // FIXME: EDTLA if event data was set - if event.completion_code() != TrbCompletionCode::ShortPacket as u8 && event.transfer_length() != 0 { - println!("Event trb yielded a short packet, but all bytes were still transferred"); + if event.completion_code() != TrbCompletionCode::ShortPacket as u8 + && event.transfer_length() != 0 + { + println!( + "Event trb didn't yield a short packet, but some bytes were not transferred" + ); } - if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::Transfer as u8 { - println!("Custom transfer event failed with {:#0x} {:#0x} {:#0x}", event.data.read(), event.status.read(), event.control.read()); + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::Transfer as u8 + { + println!( + "Custom transfer event failed with {:#0x} {:#0x} {:#0x}", + event.data.read(), + event.status.read(), + event.control.read() + ); } // TODO: Handle event data println!("EVENT DATA: {:?}", event.event_data()); - u32::from(len) - event.transfer_length() + ( + event.completion_code(), + u32::from(len) - event.transfer_length(), + ) }; if let DeviceReqData::In(dbuf) = &mut buf { dbuf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); } - Ok(bytes_transferred) + Ok((completion_code, bytes_transferred as u32)) } pub(crate) fn get_dev_desc(&mut self, port_id: usize) -> Result { let st = self @@ -689,7 +821,13 @@ impl Xhci { bytes_to_read } - fn port_req_transfer(&mut self, port_num: usize, data_buffer: Option<&mut Dma<[u8]>>, setup: usb::Setup, transfer_kind: TransferKind) -> Result<()> { + fn port_req_transfer( + &mut self, + port_num: usize, + data_buffer: Option<&mut Dma<[u8]>>, + setup: usb::Setup, + transfer_kind: TransferKind, + ) -> Result<()> { // TODO: This json format might be too high level, but is useful for debugging, // but when actual device-specific drivers are written, a binary format would // be better. Maybe something simple like bincode could be used, if a custom binary struct @@ -786,7 +924,13 @@ impl Xhci { // FIXME: Make sure there aren't any other PortReq handles, perhaps by storing the state in // PortState? } - fn handle_port_req_write(&mut self, fd: usize, port_num: usize, mut st: PortReqState, buf: &[u8]) -> Result { + fn handle_port_req_write( + &mut self, + fd: usize, + port_num: usize, + mut st: PortReqState, + buf: &[u8], + ) -> Result { let bytes_written = match st { PortReqState::Init => { let req = serde_json::from_slice::(buf).or(Err(Error::new(EBADMSG)))?; @@ -821,7 +965,13 @@ impl Xhci { } Ok(bytes_written) } - fn handle_port_req_read(&mut self, fd: usize, port_num: usize, mut st: PortReqState, buf: &mut [u8]) -> Result { + fn handle_port_req_read( + &mut self, + fd: usize, + port_num: usize, + mut st: PortReqState, + buf: &mut [u8], + ) -> Result { let bytes_read = match st { PortReqState::WaitingForDeviceBytes(mut dma_buffer, setup) => { if buf.len() != dma_buffer.len() { @@ -834,7 +984,9 @@ impl Xhci { buf.len() } - PortReqState::Init | PortReqState::WaitingForHostBytes(_, _) => return Err(Error::new(EBADF)), + PortReqState::Init | PortReqState::WaitingForHostBytes(_, _) => { + return Err(Error::new(EBADF)) + } PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), }; match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { @@ -843,6 +995,84 @@ impl Xhci { } Ok(bytes_read) } + fn completion_code_to_status( + completion_code: u8, + bytes_transferred: u16, + ) -> PortTransferStatus { + if completion_code == TrbCompletionCode::Success as u8 { + PortTransferStatus::Success + } else if completion_code == TrbCompletionCode::ShortPacket as u8 { + PortTransferStatus::ShortPacket(bytes_transferred as u16) + } else if completion_code == TrbCompletionCode::Stall as u8 { + PortTransferStatus::Stalled + } else { + PortTransferStatus::Unknown + } + } + + fn handle_transfer_write( + &mut self, + fd: usize, + port_num: usize, + endp_num: u8, + mut st: PortTransferState, + buf: &[u8], + ) -> Result { + let bytes_written = match st { + PortTransferState::Ready => { + let (completion_code, bytes_written) = + self.transfer_write(port_num, endp_num - 1, buf)?; + st = PortTransferState::WaitingForStatusReq(Self::completion_code_to_status( + completion_code, + bytes_written as u16, + )); + bytes_written + } + PortTransferState::WaitingForStatusReq(_) => return Err(Error::new(EBADF)), + }; + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::Endpoint(_, _, EndpointHandleTy::Transfer(ref mut state)) => *state = st, + _ => unreachable!(), + } + Ok(bytes_written as usize) + } + fn handle_transfer_read( + &mut self, + fd: usize, + port_num: usize, + endp_num: u8, + mut st: PortTransferState, + mut buf: &mut [u8], + ) -> Result { + let bytes_read = match st { + PortTransferState::Ready => { + let (completion_code, bytes_transferred) = + self.transfer_read(port_num, endp_num - 1, buf)?; + // TODO: Perhaps transfers with large buffers could be broken up to smaller + // transfers. + st = PortTransferState::WaitingForStatusReq(Self::completion_code_to_status( + completion_code, + bytes_transferred as u16, + )); + bytes_transferred as usize + } + PortTransferState::WaitingForStatusReq(status) => { + // Use a cursor to count the number of bytes written + let mut cursor = io::Cursor::new(buf); + serde_json::to_writer(&mut cursor, &status).or(Err(Error::new(EIO)))?; + st = PortTransferState::Ready; + + cursor + .seek(io::SeekFrom::Current(0)) + .or(Err(Error::new(EIO)))? as usize + } + }; + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::Endpoint(_, _, EndpointHandleTy::Transfer(ref mut state)) => *state = st, + _ => unreachable!(), + } + Ok(bytes_read) + } } impl SchemeMut for Xhci { @@ -982,11 +1212,7 @@ impl SchemeMut for Xhci { let port_state = self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?; - if port_state - .endpoint_states - .get(&endpoint_num) - .is_none() - { + if port_state.endpoint_states.get(&endpoint_num).is_none() { return Err(Error::new(ENOENT)); } @@ -1004,17 +1230,23 @@ impl SchemeMut for Xhci { // endpoint. return Err(Error::new(ENOENT)); } - let endp_desc = &port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endpoint_num as usize - 1).ok_or(Error::new(ENOENT))?; - match endp_desc.direction() { - EndpDirection::Out => if flags & O_RDWR != O_WRONLY && flags & O_STAT != 0 { + let endp_desc = &port_state + .dev_desc + .config_descs + .get(0) + .ok_or(Error::new(EIO))? + .interface_descs + .get(0) + .ok_or(Error::new(EIO))? + .endpoints + .get(endpoint_num as usize - 1) + .ok_or(Error::new(ENOENT))?; + if let EndpDirection::In = endp_desc.direction() { + if flags & O_RDWR != O_RDONLY && flags & O_STAT != 0 { return Err(Error::new(EACCES)); } - EndpDirection::In => if flags & O_RDWR != O_RDONLY && flags & O_STAT != 0 { - return Err(Error::new(EACCES)); - } - _ => (), } - EndpointHandleTy::Transfer + EndpointHandleTy::Transfer(PortTransferState::Ready) } _ => return Err(Error::new(ENOENT)), }; @@ -1064,15 +1296,19 @@ impl SchemeMut for Xhci { stat.st_mode = MODE_FILE; stat.st_size = buf.len() as u64; } - Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) | Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => { + Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) + | Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => { stat.st_mode = MODE_CHR; stat.st_size = buf.len() as u64; } - Handle::PortReq(_, PortReqState::Tmp) | Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(), + Handle::PortReq(_, PortReqState::Tmp) + | Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(), Handle::PortState(_, _) | Handle::PortReq(_, _) => stat.st_mode = MODE_CHR, Handle::Endpoint(_, _, st) => match st { - EndpointHandleTy::Status(_) | EndpointHandleTy::Transfer => stat.st_mode = MODE_CHR, + EndpointHandleTy::Status(_) | EndpointHandleTy::Transfer(_) => { + stat.st_mode = MODE_CHR + } EndpointHandleTy::Root(_, ref buf) => { stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; @@ -1107,7 +1343,7 @@ impl SchemeMut for Xhci { match st { EndpointHandleTy::Root(_, _) => "", EndpointHandleTy::Status(_) => "status", - EndpointHandleTy::Transfer => "transfer", + EndpointHandleTy::Transfer(_) => "transfer", } ) .unwrap(), @@ -1172,11 +1408,8 @@ impl SchemeMut for Xhci { Handle::ConfigureEndpoints(_) => return Err(Error::new(EBADF)), &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { - EndpointHandleTy::Transfer => { - self.transfer_read(port_num, endp_num - 1, buf)?; - // TODO: Perhaps transfers with large buffers could be broken up a to smaller - // transfers. - Ok(buf.len()) + &mut EndpointHandleTy::Transfer(state) => { + self.handle_transfer_read(fd, port_num, endp_num, state, buf) } EndpointHandleTy::Status(ref mut offset) => { let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?; @@ -1245,10 +1478,8 @@ impl SchemeMut for Xhci { self.configure_endpoints(port_num, buf)?; Ok(buf.len()) } - &mut Handle::Endpoint(port_num, endp_num, EndpointHandleTy::Transfer) => { - self.transfer_write(port_num, endp_num - 1, buf)?; - // TODO - Ok(buf.len()) + &mut Handle::Endpoint(port_num, endp_num, EndpointHandleTy::Transfer(state)) => { + self.handle_transfer_write(fd, port_num, endp_num, state, buf) } &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 91e35115ce..e6a92f7ba8 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -154,10 +154,15 @@ impl Trb { self.control.readf(TRB_CONTROL_EVENT_DATA_BIT) } pub fn event_data(&self) -> Option { - if self.event_data_bit() { Some(self.data.read()) } else { None } + if self.event_data_bit() { + Some(self.data.read()) + } else { + None + } } pub fn endpoint_id(&self) -> u8 { - ((self.control.read() & TRB_CONTROL_ENDPOINT_ID_MASK) >> TRB_CONTROL_ENDPOINT_ID_SHIFT) as u8 + ((self.control.read() & TRB_CONTROL_ENDPOINT_ID_MASK) >> TRB_CONTROL_ENDPOINT_ID_SHIFT) + as u8 } pub fn trb_type(&self) -> u8 { ((self.control.read() & TRB_CONTROL_TRB_TYPE_MASK) >> TRB_CONTROL_TRB_TYPE_SHIFT) as u8 @@ -205,8 +210,39 @@ impl Trb { 0, (u32::from(slot_id) << 24) | ((TrbType::ConfigureEndpoint as u32) << 10) - | (cycle as u32), - ) + | u32::from(cycle), + ); + } + pub fn reset_endpoint(&mut self, slot_id: u8, endp_num_xhc: u8, tsp: bool, cycle: bool) { + assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc); + self.set( + 0, + 0, + (u32::from(slot_id) << 24) + | (u32::from(endp_num_xhc) << 16) + | ((TrbType::ResetEndpoint as u32) << 10) + | (u32::from(tsp) << 9) + | u32::from(cycle), + ); + } + pub fn stop_endpoint(&mut self, slot_id: u8, endp_num_xhc: u8, suspend: bool, cycle: bool) { + assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc); + self.set( + 0, + 0, + (u32::from(slot_id) << 24) + | (u32::from(suspend) << 23) + | (u32::from(endp_num_xhc) << 16) + | ((TrbType::StopEndpoint as u32) << 10) + | u32::from(cycle), + ); + } + pub fn reset_device(&mut self, slot_id: u8, cycle: bool) { + self.set( + 0, + 0, + (u32::from(slot_id) << 24) | ((TrbType::ResetDevice as u32) << 10) | u32::from(cycle), + ); } pub fn setup(&mut self, setup: usb::Setup, transfer: TransferKind, cycle: bool) { @@ -238,13 +274,24 @@ impl Trb { | (cycle as u32), ); } - pub fn normal(&mut self, buffer: u64, len: u16, cycle: bool, estimated_td_size: u8, ent: bool, isp: bool, chain: bool, ioc: bool, idt: bool, bei: bool) { + pub fn normal( + &mut self, + buffer: u64, + len: u16, + cycle: bool, + estimated_td_size: u8, + ent: bool, + isp: bool, + chain: bool, + ioc: bool, + idt: bool, + bei: bool, + ) { assert_eq!(estimated_td_size & 0x1F, estimated_td_size); // NOTE: The interrupter target and no snoop flags have been omitted. self.set( buffer, - u32::from(len) - | (u32::from(estimated_td_size) << 17), + u32::from(len) | (u32::from(estimated_td_size) << 17), u32::from(cycle) | (u32::from(ent) << 1) | (u32::from(isp) << 2) @@ -252,7 +299,7 @@ impl Trb { | (u32::from(ioc) << 5) | (u32::from(idt) << 6) | (u32::from(bei) << 9) - | ((TrbType::Normal as u32) << 10) + | ((TrbType::Normal as u32) << 10), ) } } From 05392696feba6002a84d8da1f0144cfbf88a91c3 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 11 Feb 2020 11:39:29 +0100 Subject: [PATCH 0337/1301] Use more correct params in configure_endpoint. Most importantly in the endpoint contexts of the input context, specifying the properties of the endpoints that are being configured. --- usbscsid/src/protocol/bot.rs | 8 ++- xhcid/src/driver_interface.rs | 46 +++++++++++- xhcid/src/usb/bos.rs | 42 ++++++++++- xhcid/src/usb/endpoint.rs | 11 ++- xhcid/src/usb/mod.rs | 2 +- xhcid/src/xhci/scheme.rs | 131 +++++++++++++++++++++++++++------- 6 files changed, 204 insertions(+), 36 deletions(-) diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index 86065ac128..ab4c1085b7 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -85,6 +85,7 @@ pub struct BulkOnlyTransport<'a> { bulk_out_num: u8, max_lun: u8, current_tag: u32, + interface_num: u8, } pub const FEATURE_ENDPOINT_HALT: u16 = 0; @@ -96,6 +97,8 @@ impl<'a> BulkOnlyTransport<'a> { let bulk_in_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::In).unwrap() + 1) as u8; let bulk_out_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::Out).unwrap() + 1) as u8; + bulk_only_mass_storage_reset(handle, if_desc.number.into())?; + let max_lun = get_max_lun(handle, 0)?; println!("BOT_MAX_LUN {}", max_lun); @@ -109,13 +112,14 @@ impl<'a> BulkOnlyTransport<'a> { handle, max_lun, current_tag: 0, + interface_num: if_desc.number, }) } fn clear_stall(&mut self, endp_num: u8) -> Result<(), XhciClientHandleError> { self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(endp_num), FEATURE_ENDPOINT_HALT) } fn reset_recovery(&mut self) -> Result<(), ProtocolError> { - bulk_only_mass_storage_reset(self.handle, 0)?; + bulk_only_mass_storage_reset(self.handle, self.interface_num.into())?; self.clear_stall(self.bulk_in_num.into())?; self.clear_stall(self.bulk_out_num.into())?; @@ -128,8 +132,6 @@ impl<'a> BulkOnlyTransport<'a> { impl<'a> Protocol for BulkOnlyTransport<'a> { fn send_command(&mut self, cb: &[u8], data: DeviceReqData) -> Result<(), ProtocolError> { - dbg!(self.bulk_in_status.current_status()?); - dbg!(self.bulk_out_status.current_status()?); self.current_tag += 1; let tag = self.current_tag; diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index e029e4ab94..7fbc3b1f49 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -38,6 +38,15 @@ pub struct DevDesc { pub config_descs: SmallVec<[ConfDesc; 1]>, } +impl DevDesc { + pub fn major_version(&self) -> u8 { + ((self.usb & 0xFF00) >> 8) as u8 + } + pub fn minor_version(&self) -> u8 { + self.usb as u8 + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct ConfDesc { pub kind: u8, @@ -56,6 +65,7 @@ pub struct EndpDesc { pub max_packet_size: u16, pub interval: u8, pub ssc: Option, + pub sspc: Option, } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum EndpDirection { @@ -131,6 +141,31 @@ impl EndpDesc { _ => return Err(Error::new(EINVAL)), }) } + pub fn is_superspeed(&self) -> bool { + self.ssc.is_some() + } + pub fn is_superspeedplus(&self) -> bool { + todo!() + } + fn interrupt_usage_bits(&self) -> u8 { + assert!(self.is_interrupt()); + (self.attributes & 0x20) >> 4 + } + pub fn is_periodic(&self) -> bool { + #[repr(u8)] + enum InterruptUsageBits { + Periodic, + Notification, + Rsvd2, + Rsvd3, + } + + if self.is_interrupt() { + self.interrupt_usage_bits() == InterruptUsageBits::Periodic as u8 + } else { + self.is_isoch() + } + } pub fn max_streams(&self) -> u8 { self.ssc .as_ref() @@ -156,6 +191,9 @@ impl EndpDesc { pub fn max_burst(&self) -> u8 { self.ssc.map(|ssc| ssc.max_burst).unwrap_or(0) } + pub fn has_ssp_companion(&self) -> bool { + self.ssc.map(|ssc| ssc.attributes & (1 << 7) != 0).unwrap_or(false) + } } #[derive(Clone, Debug, Serialize, Deserialize)] pub struct IfDesc { @@ -177,7 +215,11 @@ pub struct SuperSpeedCmp { pub attributes: u8, pub bytes_per_interval: u16, } - +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct SuperSpeedPlusIsochCmp { + pub kind: u8, + pub bytes_per_interval: u32, +} #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct HidDesc { pub kind: u8, @@ -536,7 +578,7 @@ impl XhciEndpTransferHandle { let mut status_buf = [0u8; 32]; let status_bytes_read = self.0.read(&mut status_buf)?; - let status = serde_json::from_slice(dbg!(&status_buf[..status_bytes_read]))?; + let status = serde_json::from_slice(&status_buf[..status_bytes_read])?; if let PortTransferStatus::ShortPacket(len) = status { if len as usize != bytes_transferred { diff --git a/xhcid/src/usb/bos.rs b/xhcid/src/usb/bos.rs index d2ef922288..116a8f6d76 100644 --- a/xhcid/src/usb/bos.rs +++ b/xhcid/src/usb/bos.rs @@ -1,3 +1,5 @@ +use std::slice; + #[repr(packed)] #[derive(Clone, Copy, Debug, Default)] pub struct BosDescriptor { @@ -32,6 +34,21 @@ pub struct BosSuperSpeedDesc { pub u1_dev_exit_lat: u8, pub u2_dev_exit_lat: u16, } +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct BosSuperSpeedPlusDesc { + pub len: u8, + pub kind: u8, + pub cap_ty: u8, + pub _rsvd0: u8, + pub attrs: u32, + pub func_supp: u32, + pub _rsvd1: u16, + sublink_speed_attr: [u32; 0], +} + +unsafe impl plain::Plain for BosSuperSpeedPlusDesc {} + #[repr(packed)] #[derive(Clone, Copy, Debug, Default)] pub struct BosUsb2ExtDesc { @@ -46,12 +63,22 @@ unsafe impl plain::Plain for BosUsb2ExtDesc {} #[repr(u8)] pub enum DeviceCapability { - Usb2Ext = 2, - SuperSpeed = 3, + Usb2Ext = 0x02, + SuperSpeed, + SuperSpeedPlus = 0x0A, } unsafe impl plain::Plain for BosSuperSpeedDesc {} +impl BosSuperSpeedPlusDesc { + pub fn ssac(&self) -> u8 { + (self.attrs & 0x0000_000F) as u8 + } + pub fn sublink_speed_attr(&self) -> &[u32] { + unsafe { slice::from_raw_parts(&self.sublink_speed_attr as *const u32, self.ssac() as usize + 1) } + } +} + pub struct BosDevDescIter<'a> { bytes: &'a [u8], } @@ -84,8 +111,9 @@ impl<'a> Iterator for BosDevDescIter<'a> { #[derive(Clone, Copy, Debug)] pub enum BosAnyDevDesc { - SuperSpeed(BosSuperSpeedDesc), Usb2Ext(BosUsb2ExtDesc), + SuperSpeed(BosSuperSpeedDesc), + SuperSpeedPlus(BosSuperSpeedPlusDesc), } impl BosAnyDevDesc { @@ -95,6 +123,12 @@ impl BosAnyDevDesc { _ => false, } } + pub fn is_superspeedplus(&self) -> bool { + match self { + Self::SuperSpeedPlus(_) => true, + _ => false, + } + } } pub struct BosAnyDevDescIter<'a> { @@ -120,6 +154,8 @@ impl<'a> Iterator for BosAnyDevDescIter<'a> { Some(BosAnyDevDesc::Usb2Ext(*plain::from_bytes(slice).ok()?)) } else if base.cap_ty == DeviceCapability::SuperSpeed as u8 { Some(BosAnyDevDesc::SuperSpeed(*plain::from_bytes(slice).ok()?)) + } else if base.cap_ty == DeviceCapability::SuperSpeedPlus as u8 { + Some(BosAnyDevDesc::SuperSpeedPlus(*plain::from_bytes(slice).ok()?)) } else if base.cap_ty == 0 { // TODO return None; diff --git a/xhcid/src/usb/endpoint.rs b/xhcid/src/usb/endpoint.rs index f6aa200b56..42ab8b1022 100644 --- a/xhcid/src/usb/endpoint.rs +++ b/xhcid/src/usb/endpoint.rs @@ -45,9 +45,18 @@ pub struct SuperSpeedCompanionDescriptor { pub attributes: u8, pub bytes_per_interval: u16, } - unsafe impl Plain for SuperSpeedCompanionDescriptor {} +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct SuperSpeedPlusIsochCmpDescriptor { + pub length: u8, + pub kind: u8, + pub reserved: u16, + pub bytes_per_interval: u32, +} +unsafe impl Plain for SuperSpeedPlusIsochCmpDescriptor {} + #[repr(packed)] #[derive(Clone, Copy, Debug, Default)] pub struct HidDescriptor { diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index f6000a7843..4b22430793 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -2,7 +2,7 @@ pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuper pub use self::config::ConfigDescriptor; pub use self::device::DeviceDescriptor; pub use self::endpoint::{ - EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, ENDP_ATTR_TY_MASK, + EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK, }; pub use self::interface::InterfaceDescriptor; pub use self::setup::Setup; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 0ee5dc2448..3ca6a3953e 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -21,6 +21,7 @@ use super::context::{ InputContext, SlotState, StreamContext, StreamContextArray, ENDPOINT_CONTEXT_STATUS_MASK, }; use super::doorbell::Doorbell; +use super::extended::ProtocolSpeed; use super::operational::OperationalRegs; use super::ring::Ring; use super::runtime::RuntimeRegs; @@ -82,6 +83,7 @@ impl From for EndpDesc { interval: d.interval, max_packet_size: d.max_packet_size, ssc: None, + sspc: None, } } } @@ -111,6 +113,15 @@ impl From for SuperSpeedCmp { } } } +impl From for SuperSpeedPlusIsochCmp { + fn from(r: usb::SuperSpeedPlusIsochCmpDescriptor) -> Self { + Self { + kind: r.kind, + bytes_per_interval: r.bytes_per_interval, + } + } +} + impl IfDesc { fn new( dev: &mut Device, @@ -146,6 +157,7 @@ pub enum AnyDescriptor { Endpoint(usb::EndpointDescriptor), Hid(usb::HidDescriptor), SuperSpeedCompanion(usb::SuperSpeedCompanionDescriptor), + SuperSpeedPlusCompanion(usb::SuperSpeedPlusIsochCmpDescriptor), } impl AnyDescriptor { @@ -169,6 +181,7 @@ impl AnyDescriptor { 5 => Self::Endpoint(*plain::from_bytes(bytes).ok()?), 33 => Self::Hid(*plain::from_bytes(bytes).ok()?), 48 => Self::SuperSpeedCompanion(*plain::from_bytes(bytes).ok()?), + 49 => Self::SuperSpeedPlusCompanion(*plain::from_bytes(bytes).ok()?), _ => { //panic!("Descriptor unknown {}: bytes {:#0x?}", kind, bytes); return None; @@ -269,6 +282,65 @@ impl Xhci { Ok(()) } + fn endp_ctx_interval(speed_id: &ProtocolSpeed, endp_desc: &EndpDesc) -> u8 { + /// Logarithmic (base 2) 125 µs periods per millisecond. + const MILLISEC_PERIODS: u8 = 3; + + // TODO: Also check the Speed ID for superspeed(plus). + if (speed_id.is_lowspeed() || speed_id.is_fullspeed()) && endp_desc.is_interrupt() { + // The interval field has values 1-255, ranging from 1 ms to 255 ms. + // TODO: This is correct, right? + let last_power_of_two = 8 - endp_desc.interval.leading_zeros() as u8; + last_power_of_two - 1 + MILLISEC_PERIODS + } else if speed_id.is_fullspeed() && endp_desc.is_isoch() { + // bInterval has values 1-16, ranging from 1 ms to 32,768 ms. + endp_desc.interval - 1 + MILLISEC_PERIODS + } else if (speed_id.is_fullspeed() || endp_desc.is_superspeed() || endp_desc.is_superspeedplus()) && (endp_desc.is_interrupt() || endp_desc.is_isoch()) { + // bInterval has values 1-16, but ranging from 125 µs to 4096 ms. + endp_desc.interval - 1 + } else { + // This includes superspeed(plus) control and bulk endpoints in particular. + 0 + } + } + fn endp_ctx_max_burst(speed_id: &ProtocolSpeed, dev_desc: &DevDesc, endp_desc: &EndpDesc) -> u8 { + if speed_id.is_highspeed() && (endp_desc.is_interrupt() || endp_desc.is_isoch()) { + assert_eq!(dev_desc.major_version(), 2); + ((endp_desc.max_packet_size & 0x0C00) >> 11) as u8 + } else if endp_desc.is_superspeed() { + endp_desc.max_burst() + } else { + 0 + } + + } + fn endp_ctx_max_packet_size(endp_desc: &EndpDesc) -> u16 { + // TODO: Control endpoint? Encoding? + endp_desc.max_packet_size & 0x03FF + } + fn endp_ctx_max_esit_payload(speed_id: &ProtocolSpeed, dev_desc: &DevDesc, endp_desc: &EndpDesc, max_packet_size: u16, max_burst_size: u8) -> u32 { + const KIB: u32 = 1024; + + if dev_desc.major_version() == 2 && endp_desc.is_periodic() { + u32::from(max_packet_size) * (u32::from(max_burst_size) + 1) + } else if !endp_desc.has_ssp_companion() { + u32::from(endp_desc.ssc.as_ref().unwrap().bytes_per_interval) + } else if endp_desc.has_ssp_companion() { + endp_desc.sspc.as_ref().unwrap().bytes_per_interval + } else if speed_id.is_fullspeed() && endp_desc.is_interrupt() { + 64 + } else if speed_id.is_fullspeed() && endp_desc.is_isoch() { + 1 * KIB + } else if (speed_id.is_highspeed() && (endp_desc.is_interrupt() || endp_desc.is_isoch())) || endp_desc.is_superspeed() && endp_desc.is_interrupt() { + 3 * KIB + } else if endp_desc.is_superspeed() && endp_desc.is_isoch() { + 48 * KIB + } else { + // TODO: Is "maximum allowed" ESIT payload, the same as "maximum" ESIT payload. + 0 + } + } + fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; @@ -286,9 +358,7 @@ impl Xhci { } let port_speed_id = self.ports[port].speed(); - // FIXME - let speed_id = self.lookup_psiv(port as u8, port_speed_id); - dbg!(speed_id); + let speed_id: &ProtocolSpeed = self.lookup_psiv(port as u8, port_speed_id).ok_or(Error::new(EIO))?; let port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; let input_context: &mut Dma = &mut port_state.input_context; @@ -302,12 +372,12 @@ impl Xhci { let current_slot_a = input_context.device.slot.a.read(); - let endpoints = &port_state - .dev_desc + let dev_desc = &port_state.dev_desc; + let endpoints = &dev_desc .config_descs .get(req.config_desc as usize) .ok_or(Error::new(EBADMSG))? - .interface_descs[0] + .interface_descs.get(req.interface_desc.unwrap_or(0) as usize).ok_or(Error::new(EBADMSG))? .endpoints; if endpoints.len() >= 31 { @@ -342,7 +412,6 @@ impl Xhci { .ok_or(Error::new(EIO))?; let endp_desc = endpoints.get(index as usize).ok_or(Error::new(EIO))?; - // TODO: Check if streams are actually supported. let max_streams = endp_desc.max_streams(); let max_psa_size = self.cap.max_psa_size(); @@ -357,17 +426,17 @@ impl Xhci { // TODO: Interval related fields // TODO: Max ESIT payload size. - // TODO: The max burst size is non-zero for high-speed isoch endpoints. How are the USB2 - // speeds detected? - // I presume that USB 3 devices can never be in low/full/high-speed mode, but - // always SuperSpeed (gen 1 and 2 etc.). - - let max_burst_size = endp_desc.max_burst(); - let max_packet_size = endp_desc.max_packet_size; - let mult = endp_desc.isoch_mult(lec); - let interval = endp_desc.interval; + let max_packet_size = Self::endp_ctx_max_packet_size(endp_desc); + let max_burst_size = Self::endp_ctx_max_burst(speed_id, dev_desc, endp_desc); + + let max_esit_payload = Self::endp_ctx_max_esit_payload(speed_id, dev_desc, endp_desc, max_packet_size, max_burst_size); + let max_esit_payload_lo = max_esit_payload as u16; + let max_esit_payload_hi = ((max_esit_payload & 0x00FF_0000) >> 16) as u8; + + let interval = Self::endp_ctx_interval(speed_id, endp_desc); + let max_error_count = 3; let ep_ty = endp_desc.xhci_ep_type()?; let host_initiate_disable = false; @@ -384,7 +453,6 @@ impl Xhci { assert_eq!(ep_ty & 0x7, ep_ty); assert_eq!(mult & 0x3, mult); assert_eq!(max_error_count & 0x3, max_error_count); - assert_ne!(ep_ty, 0); // 0 means invalid. let ring_ptr = if max_streams != 0 { @@ -399,7 +467,6 @@ impl Xhci { array_ptr, "stream ctx ptr not aligned to 16 bytes" ); - port_state.endpoint_states.insert( endp_num, EndpointState::Ready(super::RingOrStreams::Streams(array)), @@ -415,22 +482,20 @@ impl Xhci { ring_ptr, "ring pointer not aligned to 16 bytes" ); - port_state.endpoint_states.insert( endp_num, EndpointState::Ready(super::RingOrStreams::Ring(ring)), ); - ring_ptr }; - assert_eq!(primary_streams & 0x1F, primary_streams); endp_ctx.a.write( u32::from(mult) << 8 - | u32::from(interval) << 16 | u32::from(primary_streams) << 10 - | u32::from(linear_stream_array) << 15, + | u32::from(linear_stream_array) << 15 + | u32::from(interval) << 16 + | u32::from(max_esit_payload_hi) << 24 ); endp_ctx.b.write( max_error_count << 1 @@ -439,9 +504,14 @@ impl Xhci { | u32::from(max_burst_size) << 8 | u32::from(max_packet_size) << 16, ); + endp_ctx.trl.write(ring_ptr as u32); endp_ctx.trh.write((ring_ptr >> 32) as u32); - endp_ctx.c.write(u32::from(avg_trb_len)); + + endp_ctx.c.write( + u32::from(avg_trb_len) + | (u32::from(max_esit_payload_lo) << 16) + ); } self.run.ints[0].erdp.write(self.cmd.erdp()); @@ -719,8 +789,9 @@ impl Xhci { ); let (bos_desc, bos_data) = dev.get_bos()?; - let has_superspeed = + let supports_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); + let supports_superspeedplus = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus()); let config_descs = (0..raw_dd.configurations) .map(|index| -> Result<_> { @@ -756,12 +827,20 @@ impl Xhci { }; let mut endp = EndpDesc::from(next); - if has_superspeed { + if supports_superspeed { let next = match iter.next() { Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, _ => break, }; endp.ssc = Some(SuperSpeedCmp::from(next)); + + if endp.has_ssp_companion() && supports_superspeedplus { + let next = match iter.next() { + Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => n, + _ => break, + }; + endp.sspc = Some(SuperSpeedPlusIsochCmp::from(next)); + } } endpoints.push(endp); } From 127ef077c2d77d48b43e3912f2d164f57e1f637b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 11 Feb 2020 12:54:34 +0100 Subject: [PATCH 0338/1301] Select correct max packet sizes during init. --- xhcid/src/driver_interface.rs | 1 + xhcid/src/xhci/extended.rs | 21 +++- xhcid/src/xhci/mod.rs | 182 ++++++++++++++++++++++++++-------- xhcid/src/xhci/scheme.rs | 2 +- xhcid/src/xhci/trb.rs | 25 ++++- 5 files changed, 181 insertions(+), 50 deletions(-) diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 7fbc3b1f49..c11dc1dc01 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -180,6 +180,7 @@ impl EndpDesc { } pub fn isoch_mult(&self, lec: bool) -> u8 { if !lec && self.is_isoch() { + if self.is_superspeedplus() { return 0 } self.ssc .as_ref() .map(|ssc| ssc.attributes & 0x3) diff --git a/xhcid/src/xhci/extended.rs b/xhcid/src/xhci/extended.rs index a128a778b4..2330b29f0d 100644 --- a/xhcid/src/xhci/extended.rs +++ b/xhcid/src/xhci/extended.rs @@ -114,13 +114,28 @@ impl ProtocolSpeed { Self { a: Mmio::from(raw) } } pub fn is_lowspeed(&self) -> bool { - self.psim() == 1500 && self.psie() == Psie::Kbps + self.psim() == 1500 && self.psie() == Psie::Kbps && !self.pfd() } pub fn is_fullspeed(&self) -> bool { - self.psim() == 12 && self.psie() == Psie::Mbps + self.psim() == 12 && self.psie() == Psie::Mbps && !self.pfd() } pub fn is_highspeed(&self) -> bool { - self.psim() == 480 && self.psie() == Psie::Mbps + self.psim() == 480 && self.psie() == Psie::Mbps && !self.pfd() + } + pub fn is_superspeed_gen1x1(&self) -> bool { + self.psim() == 5 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeed + } + pub fn is_superspeedplus_gen2x1(&self) -> bool { + self.psim() == 10 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus + } + pub fn is_superspeedplus_gen1x2(&self) -> bool { + self.psim() == 10 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus + } + pub fn is_superspeedplus_gen2x2(&self) -> bool { + self.psim() == 20 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus + } + pub fn is_superspeed_gen_x(&self) -> bool { + self.is_superspeed_gen1x1() || self.is_superspeedplus_gen2x1() || self.is_superspeedplus_gen1x2() || self.is_superspeedplus_gen2x2() } /// Protocol speed ID value pub fn psiv(&self) -> u8 { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 6f3cd5d157..bf9c6a251a 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -344,49 +344,8 @@ impl Xhci { println!(" - Slot {}", slot); - // transfer ring? - let mut ring = Ring::new(true)?; - let mut input = Dma::::zeroed()?; - { - input.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit). - - input - .device - .slot - .a - .write((1 << 27) | (u32::from(speed) << 20)); // FIXME: The speed field, bits 23:20, is deprecated. - input.device.slot.b.write(((i as u32 + 1) & 0xFF) << 16); - - // control endpoint? - input.device.endpoints[0] - .b - .write(4096 << 16 | 4 << 3 | 3 << 1); // packet size | control endpoint | allowed error count - let tr = ring.register(); - input.device.endpoints[0].trh.write((tr >> 32) as u32); - input.device.endpoints[0].trl.write(tr as u32); - } - - { - let (cmd, cycle, event) = self.cmd.next(); - - cmd.address_device(slot, input.physical(), cycle); - - self.dbs[0].write(0); - - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::CommandCompletion as u8 - { - panic!("ADDRESS DEVICE FAILED"); - } - - cmd.reserved(false); - event.reserved(false); - } + let mut ring = self.address_device(&mut input, i, slot, speed)?; let dev_desc = Self::get_dev_desc_raw( &mut self.ports, @@ -397,6 +356,9 @@ impl Xhci { slot, &mut ring, )?; + + self.update_default_control_pipe(&mut input, slot, &dev_desc)?; + let mut port_state = PortState { slot, input_context: input, @@ -424,6 +386,142 @@ impl Xhci { Ok(()) } + pub fn update_default_control_pipe(&mut self, input_context: &mut Dma, slot_id: u8, dev_desc: &DevDesc) -> Result<()> { + let new_max_packet_size = if dev_desc.major_version() == 2 { + u32::from(dev_desc.packet_size) + } else { + 1u32 << dev_desc.packet_size + }; + let endp_ctx = &mut input_context.device.endpoints[0]; + let mut b = endp_ctx.b.read(); + b &= 0x0000_FFFF; + b |= (new_max_packet_size) << 16; + endp_ctx.b.write(b); + + { + let (cmd, cycle, event) = self.cmd.next(); + + cmd.evaluate_context(slot_id, input_context.physical(), false, cycle); + + self.dbs[0].write(0); + + while event.data.read() == 0 { + println!(" - Waiting for event"); + } + + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::CommandCompletion as u8 + { + panic!("EVALUATE_CONTEXT failed with {:#0x} {:#0x} {:#0x}", event.data.read(), event.status.read(), event.control.read()); + } + + cmd.reserved(false); + event.reserved(false); + } + Ok(()) + } + + pub fn address_device(&mut self, input_context: &mut Dma, i: usize, slot: u8, speed: u8) -> Result { + let mut ring = Ring::new(true)?; + + { + input_context.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit). + + let slot_ctx = &mut input_context.device.slot; + + let route_string = 0u32; // TODO + let context_entries = 1u8; + let mtt = false; + let hub = false; + + assert_eq!(route_string & 0x000F_FFFF, route_string); + slot_ctx.a.write( + route_string + | (u32::from(mtt) << 25) + | (u32::from(hub) << 26) + | (u32::from(context_entries) << 27) + ); + + let max_exit_latency = 0u16; + let root_hub_port_num = (i + 1) as u8; + let number_of_ports = 0u8; + slot_ctx.b.write( + u32::from(max_exit_latency) + | (u32::from(root_hub_port_num) << 16) + | (u32::from(number_of_ports) << 24) + ); + + // TODO + let parent_hud_slot_id = 0u8; + let parent_port_num = 0u8; + let ttt = 0u8; + let interrupter = 0u8; + + assert_eq!(ttt & 0b11, ttt); + slot_ctx.c.write( + u32::from(parent_hud_slot_id) + | (u32::from(parent_port_num) << 8) + | (u32::from(ttt) << 16) + | (u32::from(interrupter) << 22) + ); + + let endp_ctx = &mut input_context.device.endpoints[0]; + + let speed_id = self.lookup_psiv(root_hub_port_num, speed).expect("Failed to retrieve speed ID"); + + let max_error_count = 3u8; // recommended value according to the XHCI spec + let ep_ty = 4u8; // control endpoint, bidirectional + let max_packet_size: u32 = if speed_id.is_lowspeed() { + 8 // only valid value + } else if speed_id.is_fullspeed() { + 64 // valid values are 8, 16, 32, 64 + } else if speed_id.is_highspeed() { + 64 // only valid value + } else if speed_id.is_superspeed_gen_x() { + 512 // only valid value + } else { + unreachable!() + }; + let host_initiate_disable = false; // only applies to streams + let max_burst_size = 0u8; // TODO + + assert_eq!(max_error_count & 0b11, max_error_count); + endp_ctx.b.write( + (u32::from(max_error_count) << 1) + | (u32::from(ep_ty) << 3) + | (u32::from(host_initiate_disable) << 7) + | (u32::from(max_burst_size) << 8) + | (u32::from(max_packet_size) << 16) + ); + + let tr = ring.register(); + endp_ctx.trh.write((tr >> 32) as u32); + endp_ctx.trl.write(tr as u32); + } + + { + let (cmd, cycle, event) = self.cmd.next(); + + cmd.address_device(slot, input_context.physical(), false, cycle); + + self.dbs[0].write(0); + + while event.data.read() == 0 { + println!(" - Waiting for event"); + } + + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::CommandCompletion as u8 + { + panic!("ADDRESS DEVICE FAILED"); + } + + cmd.reserved(false); + event.reserved(false); + } + Ok(ring) + } + pub fn ring_command_doorbell(&mut self) { self.dbs[0].write(0); } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 3ca6a3953e..4bdbc60d7a 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -316,7 +316,7 @@ impl Xhci { } fn endp_ctx_max_packet_size(endp_desc: &EndpDesc) -> u16 { // TODO: Control endpoint? Encoding? - endp_desc.max_packet_size & 0x03FF + endp_desc.max_packet_size & 0x07FF } fn endp_ctx_max_esit_payload(speed_id: &ProtocolSpeed, dev_desc: &DevDesc, endp_desc: &EndpDesc, max_packet_size: u16, max_burst_size: u8) -> u32 { const KIB: u32 = 1024; diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index e6a92f7ba8..bc3e359f60 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -190,17 +190,22 @@ impl Trb { ); } - pub fn address_device(&mut self, slot_id: u8, input: usize, cycle: bool) { + pub fn address_device(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) { + assert_eq!( + input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0, + input_ctx_ptr, + "unaligned input context ptr" + ); self.set( - input as u64, + input_ctx_ptr as u64, 0, - ((slot_id as u32) << 24) | ((TrbType::AddressDevice as u32) << 10) | (cycle as u32), + (u32::from(slot_id) << 24) | ((TrbType::AddressDevice as u32) << 10) | (u32::from(bsr) << 9) | u32::from(cycle), ); } // Synchronizes the input context endpoints with the device context endpoints, I think. pub fn configure_endpoint(&mut self, slot_id: u8, input_ctx_ptr: usize, cycle: bool) { assert_eq!( - input_ctx_ptr & 0xFFFF_FFFF_FFFF_FF80, + input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0, input_ctx_ptr, "unaligned input context ptr" ); @@ -213,6 +218,18 @@ impl Trb { | u32::from(cycle), ); } + pub fn evaluate_context(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) { + assert_eq!( + input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0, + input_ctx_ptr, + "unaligned input context ptr" + ); + self.set( + input_ctx_ptr as u64, + 0, + (u32::from(slot_id) << 24) | ((TrbType::EvaluateContext as u32) << 10) | (u32::from(bsr) << 9) | u32::from(cycle), + ); + } pub fn reset_endpoint(&mut self, slot_id: u8, endp_num_xhc: u8, tsp: bool, cycle: bool) { assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc); self.set( From dd9124eb821920fafdf5eebc84a10add07f22485 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 11 Feb 2020 23:07:20 +0100 Subject: [PATCH 0339/1301] Simplify the endpoint interface. --- usbscsid/src/main.rs | 11 +- usbscsid/src/protocol/bot.rs | 77 ++++---- usbscsid/src/scsi/cmds.rs | 6 + xhcid/src/driver_interface.rs | 203 ++++++++++++--------- xhcid/src/xhci/mod.rs | 21 +-- xhcid/src/xhci/scheme.rs | 326 ++++++++++++++++------------------ xhcid/src/xhci/trb.rs | 5 +- 7 files changed, 331 insertions(+), 318 deletions(-) diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index 0c740af631..4dbd53b980 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -47,8 +47,11 @@ fn main() { let control = 0; // TODO: NACA? scsi::cmds::ReportIdentInfo::new(alloc_len, info_ty, control) };*/ - let inquiry = scsi::cmds::Inquiry::new(false, 0, 36, 0); - let mut buffer = [0u8; 36]; - use protocol::Protocol; - protocol.send_command(unsafe { plain::as_bytes(&inquiry) }, DeviceReqData::In(&mut buffer)).expect("Failed to send command"); + let mut buffer = [0u8; 5]; + let mut command_buffer = [0u8; 6]; + { + let mut inquiry = plain::from_mut_bytes(&mut command_buffer).unwrap(); + *inquiry = scsi::cmds::Inquiry::new(false, 0, 5, 0); + } + protocol.send_command(&command_buffer, DeviceReqData::In(&mut buffer)).expect("Failed to send command"); } diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index ab4c1085b7..dc2af73f54 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -4,7 +4,7 @@ use std::io::prelude::*; use std::{io, slice}; use thiserror::Error; -use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqDirection, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpStatusHandle, XhciEndpTransferHandle}; +use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqDirection, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpHandle}; use super::{Protocol, ProtocolError}; @@ -77,10 +77,8 @@ impl CommandStatusWrapper { pub struct BulkOnlyTransport<'a> { handle: &'a XhciClientHandle, - bulk_in: XhciEndpTransferHandle, - bulk_out: XhciEndpTransferHandle, - bulk_in_status: XhciEndpStatusHandle, - bulk_out_status: XhciEndpStatusHandle, + bulk_in: XhciEndpHandle, + bulk_out: XhciEndpHandle, bulk_in_num: u8, bulk_out_num: u8, max_lun: u8, @@ -103,10 +101,8 @@ impl<'a> BulkOnlyTransport<'a> { println!("BOT_MAX_LUN {}", max_lun); Ok(Self { - bulk_in: handle.open_endpoint(bulk_in_num, PortReqDirection::DeviceToHost)?, - bulk_out: handle.open_endpoint(bulk_out_num, PortReqDirection::HostToDevice)?, - bulk_in_status: handle.open_endpoint_status(bulk_in_num)?, - bulk_out_status: handle.open_endpoint_status(bulk_out_num)?, + bulk_in: handle.open_endpoint(bulk_in_num)?, + bulk_out: handle.open_endpoint(bulk_out_num)?, bulk_in_num, bulk_out_num, handle, @@ -115,15 +111,20 @@ impl<'a> BulkOnlyTransport<'a> { interface_num: if_desc.number, }) } - fn clear_stall(&mut self, endp_num: u8) -> Result<(), XhciClientHandleError> { - self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(endp_num), FEATURE_ENDPOINT_HALT) + fn clear_stall_in(&mut self) -> Result<(), XhciClientHandleError> { + self.bulk_in.reset(false); + self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_in_num), FEATURE_ENDPOINT_HALT) + } + fn clear_stall_out(&mut self) -> Result<(), XhciClientHandleError> { + self.bulk_out.reset(false); + self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_out_num), FEATURE_ENDPOINT_HALT) } fn reset_recovery(&mut self) -> Result<(), ProtocolError> { bulk_only_mass_storage_reset(self.handle, self.interface_num.into())?; - self.clear_stall(self.bulk_in_num.into())?; - self.clear_stall(self.bulk_out_num.into())?; + self.clear_stall_in()?; + self.clear_stall_out()?; - if self.bulk_in_status.current_status()? == EndpointStatus::Halted || self.bulk_out_status.current_status()? == EndpointStatus::Halted { + if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted { return Err(ProtocolError::RecoveryFailed) } Ok(()) @@ -135,25 +136,23 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { self.current_tag += 1; let tag = self.current_tag; - let mut command_block = [0u8; 16]; - if cb.len() > 16 { - return Err(ProtocolError::TooLargeCommandBlock(cb.len())); - } - command_block[..cb.len()].copy_from_slice(&cb); + println!("{}", base64::encode(cb)); + println!(); - let cbw = CommandBlockWrapper { - signature: CBW_SIGNATURE, - tag, - data_transfer_len: data.len() as u32, - lun: 0, // TODO - flags: u8::from(data.direction() == PortReqDirection::DeviceToHost) << 7, - cb_len: cb.len().try_into().or(Err(ProtocolError::TooLargeCommandBlock(cb.len())))?, - command_block, - }; - match self.bulk_out.transfer_write(unsafe { plain::as_bytes(&cbw) })? { + let mut cbw_bytes = [0u8; 31]; + let cbw = plain::from_mut_bytes::(&mut cbw_bytes).unwrap(); + + *cbw = CommandBlockWrapper::new(tag, data.len() as u32, data.direction().into(), 0, cb)?; + println!("{}", base64::encode(&cbw_bytes)); + + dbg!(self.bulk_in.status()?, self.bulk_out.status()?); + + match self.bulk_out.transfer_write(&cbw_bytes)? { PortTransferStatus::ShortPacket(31) => (), PortTransferStatus::Stalled => { - panic!("bulk out endpoint stalled when sending CBW"); + println!("bulk out endpoint stalled when sending CBW"); + self.reset_recovery()?; + dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } _ => panic!("invalid number of CBW bytes written; expected a short packed of length 31 (0x1F)"), } @@ -165,7 +164,7 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { PortTransferStatus::ShortPacket(len) => panic!("received short packed (len {}) when transferring data", len), PortTransferStatus::Stalled => { println!("bulk in endpoint stalled when reading data"); - self.clear_stall(self.bulk_in_num)?; + self.clear_stall_in()?; } PortTransferStatus::Unknown => return Err(ProtocolError::XhciError(XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")))), }; @@ -173,27 +172,29 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { } DeviceReqData::Out(ref buffer) => todo!(), DeviceReqData::NoData => todo!(), - }; + } - let mut csw = CommandStatusWrapper::default(); + let mut csw_buffer = [0u8; 13]; - match self.bulk_in.transfer_read(unsafe { plain::as_mut_bytes(&mut csw) })? { + match self.bulk_in.transfer_read(&mut csw_buffer)? { PortTransferStatus::ShortPacket(13) => (), PortTransferStatus::Stalled => { println!("bulk in endpoint stalled when reading CSW"); - self.clear_stall(self.bulk_in_num)?; + self.clear_stall_in()?; } _ => panic!("invalid number of CSW bytes read; expected a short packet of length 13 (0xD)"), }; + println!("{}", base64::encode(&csw_buffer)); + let csw = plain::from_bytes::(&csw_buffer).unwrap(); if !csw.is_valid() { self.reset_recovery()?; } dbg!(csw); - if self.bulk_in_status.current_status()? == EndpointStatus::Halted || self.bulk_out_status.current_status()? == EndpointStatus::Halted { + if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted { println!("Trying to recover from stall"); - dbg!(self.bulk_in_status.current_status()?, self.bulk_out_status.current_status()?); + dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } Ok(()) @@ -204,7 +205,7 @@ pub fn bulk_only_mass_storage_reset(handle: &XhciClientHandle, if_num: u16) -> R handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFF, 0, if_num, DeviceReqData::NoData) } pub fn get_max_lun(handle: &XhciClientHandle, if_num: u16) -> Result { - let mut lun = 0; + let mut lun = 0u8; let buffer = slice::from_mut(&mut lun); handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFE, 0, if_num, DeviceReqData::In(buffer))?; Ok(lun) diff --git a/usbscsid/src/scsi/cmds.rs b/usbscsid/src/scsi/cmds.rs index 582d2dd628..0b759886bb 100644 --- a/usbscsid/src/scsi/cmds.rs +++ b/usbscsid/src/scsi/cmds.rs @@ -13,6 +13,8 @@ pub struct ReportIdentInfo { pub info_ty: u8, pub control: u8, } +unsafe impl plain::Plain for ReportIdentInfo {} + impl ReportIdentInfo { pub fn new(alloc_len: u32, info_ty: ReportIdInfoInfoTy, control: u8) -> Self { Self { @@ -52,6 +54,8 @@ pub struct ReportSuppOpcodes { pub _rsvd: u8, pub control: u8, } +unsafe impl plain::Plain for ReportSuppOpcodes {} + impl ReportSuppOpcodes { pub const fn new(rep_opts: ReportSuppOpcodesOptions, rctd: bool, req_opcode: u8, req_serviceaction: u16, alloc_len: u32, control: u8) -> Self { Self { @@ -115,6 +119,7 @@ pub struct CommandDescriptor { /// little endian pub cdb_len: u16, } + #[repr(packed)] pub struct OneCommandParam { pub _rsvd: u8, @@ -133,6 +138,7 @@ pub struct Inquiry { pub alloc_len: u16, pub control: u8, } +unsafe impl plain::Plain for Inquiry {} impl Inquiry { pub fn new(evpd: bool, page_code: u8, alloc_len: u16, control: u8) -> Self { diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index c11dc1dc01..709ce85882 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -79,6 +79,16 @@ pub enum EndpBinaryDirection { Out, In, } + +impl From for EndpBinaryDirection { + fn from(d: PortReqDirection) -> Self { + match d { + PortReqDirection::DeviceToHost => Self::In, + PortReqDirection::HostToDevice => Self::Out, + } + } +} + impl From for EndpDirection { fn from(b: EndpBinaryDirection) -> Self { match b { @@ -305,7 +315,7 @@ impl str::FromStr for PortState { } #[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum EndpointStatus { Disabled, Enabled, @@ -411,48 +421,28 @@ impl XhciClientHandle { let string = std::fs::read_to_string(path)?; Ok(string.parse()?) } - pub fn endpoint_onetime_status( + pub fn open_endpoint_ctl( &self, num: u8, - ) -> result::Result { - let path = format!("{}:port{}/endpoints/{}/status", self.scheme, self.port, num); - let string = std::fs::read_to_string(path)?; - Ok(string.parse()?) + ) -> result::Result { + let path = format!("{}:port{}/endpoints/{}/ctl", self.scheme, self.port, num); + Ok(File::open(path)?) } - pub fn open_endpoint_status( + pub fn open_endpoint_data( &self, num: u8, - ) -> result::Result { - let path = format!("{}:port{}/endpoints/{}/status", self.scheme, self.port, num); - Ok(XhciEndpStatusHandle( - OpenOptions::new() - .read(true) - .write(false) - .create(false) - .open(path)?, - )) - } - pub fn open_endpoint( - &self, - num: u8, - direction: PortReqDirection, - ) -> result::Result { + ) -> result::Result { let path = format!( - "{}:port{}/endpoints/{}/transfer", + "{}:port{}/endpoints/{}/data", self.scheme, self.port, num ); - Ok(XhciEndpTransferHandle(match direction { - PortReqDirection::HostToDevice => OpenOptions::new() - .read(false) - .write(true) - .create(false) - .open(path)?, - PortReqDirection::DeviceToHost => OpenOptions::new() - .read(true) - .write(false) - .create(false) - .open(path)?, - })) + Ok(File::open(path)?) + } + pub fn open_endpoint(&self, num: u8) -> result::Result { + Ok(XhciEndpHandle { + ctl: self.open_endpoint_ctl(num)?, + data: self.open_endpoint_data(num)?, + }) } pub fn device_request<'a>( &self, @@ -546,68 +536,105 @@ impl XhciClientHandle { } #[derive(Debug)] -pub struct XhciEndpStatusHandle(File); - -impl XhciEndpStatusHandle { - pub fn current_status(&mut self) -> result::Result { - self.0.seek(io::SeekFrom::Start(0))?; - let mut status_buf = [0u8; 16]; - let len = self.0.read(&mut status_buf)?; - let status = std::str::from_utf8(&status_buf[..len]).or(Err( - XhciClientHandleError::InvalidResponse(Invalid("non-utf8 endpoint state")), - ))?; - Ok(status - .parse::() - .or(Err(XhciClientHandleError::InvalidResponse(Invalid( - "malformed endpoint state", - ))))?) - } - pub fn into_inner(self) -> File { - self.0 - } +pub struct XhciEndpHandle { + data: File, + ctl: File, } -#[derive(Debug)] -pub struct XhciEndpTransferHandle(File); +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub enum XhciEndpCtlDirection { + Out, + In, + NoData, +} -impl XhciEndpTransferHandle { - fn get_status( - &mut self, - requested_len: usize, - bytes_transferred: usize, - ) -> result::Result { - let mut status_buf = [0u8; 32]; - let status_bytes_read = self.0.read(&mut status_buf)?; +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub enum XhciEndpCtlReq { + // TODO: Reduce the number of direction enums from 5 to perhaps 2. + // TODO: Allow to send multiple buffers in one transfer. + /// Tells xhcid that a buffer is about to be sent from the Data interface file, to the + /// endpoint. + Transfer(XhciEndpCtlDirection), + // TODO: Allow clients to specify what to reset. - let status = serde_json::from_slice(&status_buf[..status_bytes_read])?; + /// Tells xhcid that the endpoint is going to be reset. + Reset { + /// Only issue the Reset Endpoint and Set TR Dequeue Pointer commands, and let the client + /// itself send a potential ClearFeature(ENDPOINT_HALT). + no_clear_feature: bool, + }, - if let PortTransferStatus::ShortPacket(len) = status { - if len as usize != bytes_transferred { - return Err(XhciClientHandleError::InvalidResponse(Invalid("xhcid gave a short packet with a different length than the bytes transferred (which should have been the same)"))); - } - } else if let PortTransferStatus::Success = status { - if requested_len != bytes_transferred { - return Err(XhciClientHandleError::InvalidResponse(Invalid("xhcid transferred fewer or more bytes than requested, but didn't return a short packed"))); - } + /// Tells xhcid that the endpoint status is going to be retrieved from the Ctl interface file. + Status, +} +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub enum XhciEndpCtlRes { + /// Xhcid responded with the current state of an endpoint. + Status(EndpointStatus), + + /// Xhci sent the result of a transfer. + TransferResult(PortTransferStatus), + + /// Xhcid is waiting for data to be sent or received on the Data interface file. + Pending, + + /// No Ctl request is currently being processed by xhcid. + Idle, +} + +impl XhciEndpHandle { + fn ctl_req(&mut self, ctl_req: &XhciEndpCtlReq) -> result::Result<(), XhciClientHandleError> { + let ctl_buffer = serde_json::to_vec(ctl_req)?; + + let ctl_bytes_written = self.ctl.write(&ctl_buffer)?; + if ctl_bytes_written != ctl_buffer.len() { + return Err(Invalid("xhcid didn't process all of the ctl bytes").into()); } - Ok(status) + + Ok(()) } - pub fn transfer_write( - &mut self, - buffer: &[u8], - ) -> result::Result { - let bytes_transferred = self.0.write(buffer)?; - self.get_status(buffer.len(), bytes_transferred) + fn ctl_res(&mut self) -> result::Result { + // a response must never exceed 256 bytes + let mut ctl_buffer = [0u8; 256]; + let ctl_bytes_read = self.ctl.read(&mut ctl_buffer)?; + + let ctl_res = serde_json::from_slice(&ctl_buffer[..ctl_bytes_read as usize])?; + Ok(ctl_res) } - pub fn transfer_read( - &mut self, - buffer: &mut [u8], - ) -> result::Result { - let bytes_transferred = self.0.read(buffer)?; - self.get_status(buffer.len(), bytes_transferred) + pub fn reset(&mut self, no_clear_feature: bool) -> result::Result<(), XhciClientHandleError> { + self.ctl_req(&XhciEndpCtlReq::Reset { no_clear_feature }) } - pub fn into_inner(self) -> File { - self.0 + pub fn status(&mut self) -> result::Result { + self.ctl_req(&XhciEndpCtlReq::Status)?; + match self.ctl_res()? { + XhciEndpCtlRes::Status(s) => Ok(s), + _ => Err(Invalid("expected status response").into()), + } + } + fn generic_transfer io::Result>(&mut self, direction: XhciEndpCtlDirection, f: F, expected_len: usize) -> result::Result { + let req = XhciEndpCtlReq::Transfer(XhciEndpCtlDirection::Out); + self.ctl_req(&req)?; + + let bytes_read = f(&mut self.data)?; + let res = self.ctl_res()?; + + match res { + XhciEndpCtlRes::TransferResult(PortTransferStatus::Success) if bytes_read != expected_len => Err(Invalid("no short packet, but fewer bytes were read/written").into()), + XhciEndpCtlRes::TransferResult(r) => Ok(r), + _ => Err(Invalid("expected transfer result").into()), + } + } + pub fn transfer_write(&mut self, buf: &[u8]) -> result::Result { + self.generic_transfer(XhciEndpCtlDirection::Out, |data| data.write(buf), buf.len()) + } + pub fn transfer_read(&mut self, buf: &mut [u8]) -> result::Result { + let len = buf.len(); + self.generic_transfer(XhciEndpCtlDirection::In, |data| data.read(buf), len) + } + pub fn transfer_nodata(&mut self, buf: &[u8]) -> result::Result { + self.generic_transfer(XhciEndpCtlDirection::NoData, |_| Ok(0), buf.len()) } } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index bf9c6a251a..2d0fe8fde9 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -35,6 +35,8 @@ use self::ring::Ring; use self::runtime::{Interrupter, RuntimeRegs}; use self::trb::{TransferKind, TrbCompletionCode, TrbType}; +use self::scheme::EndpIfState; + use crate::driver_interface::*; struct Device<'a> { @@ -151,14 +153,14 @@ pub(crate) enum RingOrStreams { Streams(StreamContextArray), } -pub(crate) enum EndpointState { - Ready(RingOrStreams), - Init, +pub(crate) struct EndpointState { + pub transfer: RingOrStreams, + pub driver_if_state: EndpIfState, } impl EndpointState { fn ring(&mut self) -> Option<&mut Ring> { - match self { - Self::Ready(RingOrStreams::Ring(ring)) => Some(ring), + match self.transfer { + RingOrStreams::Ring(ref mut ring) => Some(ring), _ => None, } } @@ -294,10 +296,6 @@ impl Xhci { self.dbs[0].write(0); println!(" - XHCI initialized"); - - for (pointer, capability) in self.capabilities_iter() { - dbg!(pointer, capability); - } } pub fn enable_port_slot(cmd: &mut CommandRing, dbs: &mut [Doorbell]) -> u8 { @@ -365,7 +363,10 @@ impl Xhci { dev_desc, endpoint_states: std::iter::once(( 0, - EndpointState::Ready(RingOrStreams::Ring(ring)), + EndpointState { + transfer: RingOrStreams::Ring(ring), + driver_if_state: EndpIfState::Init, + } )) .collect::>(), }; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 4bdbc60d7a..2f78a222e2 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -30,14 +30,21 @@ use super::usb::endpoint::{EndpointTy, ENDP_ATTR_TY_MASK}; use crate::driver_interface::*; +#[derive(Clone, Copy, Debug)] +pub enum EndpIfState { + Init, + WaitingForDataPipe(XhciEndpCtlDirection), + WaitingForStatus, + WaitingForTransferResult(PortTransferStatus), +} + /// Subdirs of an endpoint pub enum EndpointHandleTy { - /// portX/endpoints/Y/transfer. Write calls transfer data to the device, and read calls - /// transfer data from the device. - Transfer(PortTransferState), + /// portX/endpoints/Y/data. Allows clients to read and write data associated with ctl requests. + Data, /// portX/endpoints/Y/status - Status(usize), // offset + Ctl, /// portX/endpoints/Y/ Root(usize, Vec), // offset, content @@ -469,7 +476,7 @@ impl Xhci { ); port_state.endpoint_states.insert( endp_num, - EndpointState::Ready(super::RingOrStreams::Streams(array)), + EndpointState { transfer: super::RingOrStreams::Streams(array), driver_if_state: EndpIfState::Init }, ); array_ptr @@ -484,7 +491,7 @@ impl Xhci { ); port_state.endpoint_states.insert( endp_num, - EndpointState::Ready(super::RingOrStreams::Ring(ring)), + EndpointState { transfer: super::RingOrStreams::Ring(ring), driver_if_state: EndpIfState::Init }, ); ring_ptr }; @@ -627,7 +634,6 @@ impl Xhci { } if EndpDirection::from(buf.direction()) != endp_desc.direction() { - dbg!(buf.direction(), endp_desc, endp_idx, endp_num); return Err(Error::new(EBADF)); } @@ -637,14 +643,13 @@ impl Xhci { .ok_or(Error::new(EBADF))?; let ring: &mut Ring = match endp_state { - EndpointState::Ready(super::RingOrStreams::Ring(ref mut ring)) => ring, - EndpointState::Ready(super::RingOrStreams::Streams(stream_ctx_array)) => { + EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. } => ring, + EndpointState { transfer: super::RingOrStreams::Streams(stream_ctx_array), .. } => { stream_ctx_array .rings .get_mut(&1) .ok_or(Error::new(EBADF))? } - EndpointState::Init => return Err(Error::new(EIO)), }; // TODO: Scatter-gather transfers, possibly allowing >64KiB sizes. let len = u16::try_from(buf.len()).or(Err(Error::new(ENOSYS)))?; @@ -671,6 +676,7 @@ impl Xhci { len, cycle, estimated_td_size, + 0, false, true, false, @@ -922,7 +928,7 @@ impl Xhci { .get_mut(&0) .ok_or(Error::new(EIO))? { - EndpointState::Ready(super::RingOrStreams::Ring(ref mut ring)) => ring, + EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. } => ring, // Control endpoints never use streams _ => return Err(Error::new(EIO)), @@ -1074,84 +1080,6 @@ impl Xhci { } Ok(bytes_read) } - fn completion_code_to_status( - completion_code: u8, - bytes_transferred: u16, - ) -> PortTransferStatus { - if completion_code == TrbCompletionCode::Success as u8 { - PortTransferStatus::Success - } else if completion_code == TrbCompletionCode::ShortPacket as u8 { - PortTransferStatus::ShortPacket(bytes_transferred as u16) - } else if completion_code == TrbCompletionCode::Stall as u8 { - PortTransferStatus::Stalled - } else { - PortTransferStatus::Unknown - } - } - - fn handle_transfer_write( - &mut self, - fd: usize, - port_num: usize, - endp_num: u8, - mut st: PortTransferState, - buf: &[u8], - ) -> Result { - let bytes_written = match st { - PortTransferState::Ready => { - let (completion_code, bytes_written) = - self.transfer_write(port_num, endp_num - 1, buf)?; - st = PortTransferState::WaitingForStatusReq(Self::completion_code_to_status( - completion_code, - bytes_written as u16, - )); - bytes_written - } - PortTransferState::WaitingForStatusReq(_) => return Err(Error::new(EBADF)), - }; - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Endpoint(_, _, EndpointHandleTy::Transfer(ref mut state)) => *state = st, - _ => unreachable!(), - } - Ok(bytes_written as usize) - } - fn handle_transfer_read( - &mut self, - fd: usize, - port_num: usize, - endp_num: u8, - mut st: PortTransferState, - mut buf: &mut [u8], - ) -> Result { - let bytes_read = match st { - PortTransferState::Ready => { - let (completion_code, bytes_transferred) = - self.transfer_read(port_num, endp_num - 1, buf)?; - // TODO: Perhaps transfers with large buffers could be broken up to smaller - // transfers. - st = PortTransferState::WaitingForStatusReq(Self::completion_code_to_status( - completion_code, - bytes_transferred as u16, - )); - bytes_transferred as usize - } - PortTransferState::WaitingForStatusReq(status) => { - // Use a cursor to count the number of bytes written - let mut cursor = io::Cursor::new(buf); - serde_json::to_writer(&mut cursor, &status).or(Err(Error::new(EIO)))?; - st = PortTransferState::Ready; - - cursor - .seek(io::SeekFrom::Current(0)) - .or(Err(Error::new(EIO)))? as usize - } - }; - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Endpoint(_, _, EndpointHandleTy::Transfer(ref mut state)) => *state = st, - _ => unreachable!(), - } - Ok(bytes_read) - } } impl SchemeMut for Xhci { @@ -1268,16 +1196,10 @@ impl SchemeMut for Xhci { /*if self.dev_ctx.contexts[port_state.slot as usize].endpoints.get(endpoint_num as usize).ok_or(Error::new(ENOENT))?.a.read() & 0b111 != 1 { return Err(Error::new(ENXIO)); // TODO: Find a proper error code for "endpoint not initialized". }*/ - let contents = match port_state - .endpoint_states - .get(&endpoint_num) - .ok_or(Error::new(ENOENT))? - { - EndpointState::Ready { .. } if endpoint_num != 0 => "transfer\nstatus\n", - EndpointState::Init | EndpointState::Ready { .. } => "status\n", + if !port_state.endpoint_states.contains_key(&endpoint_num) { + return Err(Error::new(ENOENT)); } - .as_bytes() - .to_owned(); + let contents = "ctl\ndata\n".as_bytes().to_owned(); Handle::Endpoint(port_num, endpoint_num, EndpointHandleTy::Root(0, contents)) } @@ -1296,37 +1218,8 @@ impl SchemeMut for Xhci { } let st = match sub { - "status" => { - // status is read-only - if flags & O_RDWR != O_RDONLY && flags & O_STAT == 0 { - return Err(Error::new(EACCES)); - } - EndpointHandleTy::Status(0) - } - "transfer" => { - if endpoint_num == 0 { - // Don't allow user programs to interface directly with the control - // endpoint. - return Err(Error::new(ENOENT)); - } - let endp_desc = &port_state - .dev_desc - .config_descs - .get(0) - .ok_or(Error::new(EIO))? - .interface_descs - .get(0) - .ok_or(Error::new(EIO))? - .endpoints - .get(endpoint_num as usize - 1) - .ok_or(Error::new(ENOENT))?; - if let EndpDirection::In = endp_desc.direction() { - if flags & O_RDWR != O_RDONLY && flags & O_STAT != 0 { - return Err(Error::new(EACCES)); - } - } - EndpointHandleTy::Transfer(PortTransferState::Ready) - } + "ctl" => EndpointHandleTy::Ctl, + "data" => EndpointHandleTy::Data, _ => return Err(Error::new(ENOENT)), }; Handle::Endpoint(port_num, endpoint_num, st) @@ -1385,9 +1278,7 @@ impl SchemeMut for Xhci { Handle::PortState(_, _) | Handle::PortReq(_, _) => stat.st_mode = MODE_CHR, Handle::Endpoint(_, _, st) => match st { - EndpointHandleTy::Status(_) | EndpointHandleTy::Transfer(_) => { - stat.st_mode = MODE_CHR - } + EndpointHandleTy::Ctl | EndpointHandleTy::Data => stat.st_mode = MODE_CHR, EndpointHandleTy::Root(_, ref buf) => { stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; @@ -1421,8 +1312,8 @@ impl SchemeMut for Xhci { endp_num, match st { EndpointHandleTy::Root(_, _) => "", - EndpointHandleTy::Status(_) => "status", - EndpointHandleTy::Transfer(_) => "transfer", + EndpointHandleTy::Ctl => "ctl", + EndpointHandleTy::Data => "data", } ) .unwrap(), @@ -1451,13 +1342,11 @@ impl SchemeMut for Xhci { }; Ok(*offset) } - // Read-only unknown-length status strings - Handle::Endpoint(_, _, EndpointHandleTy::Status(ref mut offset)) - | Handle::PortState(_, ref mut offset) => { - *offset = match whence { - SEEK_SET => cmp::max(0, pos), - SEEK_CUR => cmp::max(0, *offset + pos), - SEEK_END => return Err(Error::new(ESPIPE)), + Handle::PortState(_, ref mut offset) => { + match whence { + SEEK_SET => *offset = pos, + SEEK_CUR => *offset = pos, + SEEK_END => *offset = pos, _ => return Err(Error::new(EINVAL)), }; Ok(*offset) @@ -1487,39 +1376,9 @@ impl SchemeMut for Xhci { Handle::ConfigureEndpoints(_) => return Err(Error::new(EBADF)), &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { - &mut EndpointHandleTy::Transfer(state) => { - self.handle_transfer_read(fd, port_num, endp_num, state, buf) - } - EndpointHandleTy::Status(ref mut offset) => { - let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?; - let status = self - .dev_ctx - .contexts - .get(ps.slot as usize) - .ok_or(Error::new(EBADF))? - .endpoints - .get(endp_num as usize) - .ok_or(Error::new(EBADF))? - .a - .read() - & ENDPOINT_CONTEXT_STATUS_MASK; - - let string = match status { - 0 => Some(EndpointStatus::Disabled), - 1 => Some(EndpointStatus::Enabled), - 2 => Some(EndpointStatus::Halted), - 3 => Some(EndpointStatus::Stopped), - 4 => Some(EndpointStatus::Error), - _ => None, - } - .as_ref() - .map(EndpointStatus::as_str) - .unwrap_or("unknown") - .as_bytes(); - - Ok(Self::write_dyn_string(string, buf, offset)) - } - EndpointHandleTy::Root(_, _) => unreachable!(), + EndpointHandleTy::Ctl => self.on_read_endp_ctl(port_num, endp_num, buf), + EndpointHandleTy::Data => self.on_read_endp_data(port_num, endp_num, buf), + EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), }, &mut Handle::PortState(port_num, ref mut offset) => { let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?; @@ -1557,8 +1416,10 @@ impl SchemeMut for Xhci { self.configure_endpoints(port_num, buf)?; Ok(buf.len()) } - &mut Handle::Endpoint(port_num, endp_num, EndpointHandleTy::Transfer(state)) => { - self.handle_transfer_write(fd, port_num, endp_num, state, buf) + &mut Handle::Endpoint(port_num, endp_num, ref ep_file_ty) => match ep_file_ty { + EndpointHandleTy::Ctl => self.on_write_endp_ctl(port_num, endp_num, buf), + EndpointHandleTy::Data => self.on_write_endp_data(port_num, endp_num, buf), + _ => return Err(Error::new(EBADF)), } &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); @@ -1576,3 +1437,116 @@ impl SchemeMut for Xhci { Ok(0) } } +impl Xhci { + pub fn get_endp_status(&mut self, port_num: usize, endp_num: u8) -> Result { + let slot = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?.slot; + let raw = self.dev_ctx.contexts.get(slot as usize).ok_or(Error::new(EBADFD))?.endpoints.get(endp_num as usize).ok_or(Error::new(EBADFD))?.a.read() & super::context::ENDPOINT_CONTEXT_STATUS_MASK; + Ok(match raw { + 0 => EndpointStatus::Disabled, + 1 => EndpointStatus::Enabled, + 2 => EndpointStatus::Halted, + 3 => EndpointStatus::Stopped, + 4 => EndpointStatus::Error, + _ => return Err(Error::new(EIO)), + }) + } + pub fn on_req_reset_device(&mut self, port_num: usize, endp_num: u8, no_clear_feature: bool) { + } + pub fn on_write_endp_ctl(&mut self, port_num: usize, endp_num: u8, buf: &[u8]) -> Result { + let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; + let req = serde_json::from_slice::(buf).or(Err(Error::new(EBADMSG)))?; + match req { + XhciEndpCtlReq::Status => match ep_if_state { + state @ EndpIfState::Init => *state = EndpIfState::WaitingForStatus, + _ => return Err(Error::new(EBADF)), + } + XhciEndpCtlReq::Reset { no_clear_feature } => match ep_if_state { + EndpIfState::Init => self.on_req_reset_device(port_num, endp_num, no_clear_feature), + _ => return Err(Error::new(EBADF)), + } + XhciEndpCtlReq::Transfer(direction) => match ep_if_state { + state @ EndpIfState::Init => if direction == XhciEndpCtlDirection::NoData { + // Yield the result directly because no bytes have to be sent or received + // beforehand. + let (completion_code, bytes_transferred) = self.transfer(port_num, endp_num - 1, DeviceReqData::NoData)?; + if bytes_transferred > 0 { return Err(Error::new(EIO)) } + let result = Self::transfer_result(completion_code, 0); + + let new_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; + *new_state = EndpIfState::WaitingForTransferResult(result) + } else { + *state = EndpIfState::WaitingForDataPipe(direction) + } + _ => return Err(Error::new(EBADF)), + } + _ => return Err(Error::new(ENOSYS)), + } + Ok(buf.len()) + } + fn transfer_result(completion_code: u8, bytes_transferred: u32) -> PortTransferStatus { + if completion_code == TrbCompletionCode::Success as u8 { + PortTransferStatus::Success + } else if completion_code == TrbCompletionCode::ShortPacket as u8 { + PortTransferStatus::ShortPacket(bytes_transferred as u16) + } else if completion_code == TrbCompletionCode::Stall as u8 { + PortTransferStatus::Stalled + } else { + PortTransferStatus::Unknown + } + } + pub fn on_write_endp_data(&mut self, port_num: usize, endp_num: u8, buf: &[u8]) -> Result { + { + let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; + match ep_if_state { + state @ EndpIfState::WaitingForDataPipe(XhciEndpCtlDirection::Out) => (), + _ => return Err(Error::new(EBADF)), + } + } + { + let (completion_code, bytes_transferred) = self.transfer_write(port_num, endp_num - 1, buf)?; + let result = Self::transfer_result(completion_code, bytes_transferred); + + let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; + *ep_if_state = EndpIfState::WaitingForTransferResult(result); + Ok(bytes_transferred as usize) + } + } + pub fn on_read_endp_ctl(&mut self, port_num: usize, endp_num: u8, buf: &mut [u8]) -> Result { + let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; + + let res: XhciEndpCtlRes = match ep_if_state { + &mut EndpIfState::Init => XhciEndpCtlRes::Idle, + + state @ &mut EndpIfState::WaitingForStatus => { + *state = EndpIfState::Init; + XhciEndpCtlRes::Status(self.get_endp_status(port_num, endp_num)?) + } + &mut EndpIfState::WaitingForDataPipe(_) => XhciEndpCtlRes::Pending, + &mut EndpIfState::WaitingForTransferResult(status) => { + *ep_if_state = EndpIfState::Init; + XhciEndpCtlRes::TransferResult(status) + } + }; + + let mut cursor = io::Cursor::new(buf); + serde_json::to_writer(&mut cursor, &res).or(Err(Error::new(EIO)))?; + Ok(cursor.seek(io::SeekFrom::Current(0)).unwrap() as usize) + } + pub fn on_read_endp_data(&mut self, port_num: usize, endp_num: u8, buf: &mut [u8]) -> Result { + { + let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; + match ep_if_state { + EndpIfState::WaitingForDataPipe(XhciEndpCtlDirection::In) => (), + _ => return Err(Error::new(EBADF)), + } + } + { + let (completion_code, bytes_transferred) = self.transfer_read(port_num, endp_num, buf)?; + let result = Self::transfer_result(completion_code, bytes_transferred); + + let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; + *ep_if_state = EndpIfState::WaitingForTransferResult(result); + Ok(bytes_transferred as usize) + } + } +} diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index bc3e359f60..9af2b96ee0 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -297,6 +297,7 @@ impl Trb { len: u16, cycle: bool, estimated_td_size: u8, + interrupter: u8, ent: bool, isp: bool, chain: bool, @@ -308,11 +309,11 @@ impl Trb { // NOTE: The interrupter target and no snoop flags have been omitted. self.set( buffer, - u32::from(len) | (u32::from(estimated_td_size) << 17), + u32::from(len) | (u32::from(estimated_td_size) << 17) | (u32::from(interrupter) << 21), u32::from(cycle) | (u32::from(ent) << 1) | (u32::from(isp) << 2) - | (u32::from(ent) << 4) + | (u32::from(chain) << 4) | (u32::from(ioc) << 5) | (u32::from(idt) << 6) | (u32::from(bei) << 9) From 1a7625c0bcefb0761dd17f329fce90ffb1fd6909 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 12 Feb 2020 13:46:28 +0100 Subject: [PATCH 0340/1301] Allow stalled endpoints to be reset. --- usbscsid/src/protocol/bot.rs | 2 +- xhcid/src/xhci/scheme.rs | 63 ++++++++++++++++++++++++++++++++++-- xhcid/src/xhci/trb.rs | 30 ++++++++++++++++- 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index dc2af73f54..faa2e427be 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -151,7 +151,7 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { PortTransferStatus::ShortPacket(31) => (), PortTransferStatus::Stalled => { println!("bulk out endpoint stalled when sending CBW"); - self.reset_recovery()?; + self.clear_stall_out()?; dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } _ => panic!("invalid number of CBW bytes written; expected a short packed of length 31 (0x1F)"), diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 2f78a222e2..38cb196584 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -18,7 +18,7 @@ use super::{Device, EndpointState, Xhci}; use super::command::CommandRing; use super::context::{ - InputContext, SlotState, StreamContext, StreamContextArray, ENDPOINT_CONTEXT_STATUS_MASK, + InputContext, SlotState, StreamContext, StreamContextArray, StreamContextType, ENDPOINT_CONTEXT_STATUS_MASK, }; use super::doorbell::Doorbell; use super::extended::ProtocolSpeed; @@ -1450,7 +1450,64 @@ impl Xhci { _ => return Err(Error::new(EIO)), }) } - pub fn on_req_reset_device(&mut self, port_num: usize, endp_num: u8, no_clear_feature: bool) { + pub fn on_req_reset_device(&mut self, port_num: usize, endp_num: u8, no_clear_feature: bool) -> Result<()> { + // Change the endpoint state from anything, but most likely HALTED (otherwise resetting + // would be quite meaningless), to stopped. + self.reset_endpoint(port_num, endp_num, false)?; + self.restart_endpoint(port_num, endp_num) + } + pub fn restart_endpoint(&mut self, port_num: usize, endp_num: u8) -> Result<()> { + let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; + let endpoint_state: &mut EndpointState = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + let ring = match &mut endpoint_state.transfer { + &mut super::RingOrStreams::Ring(ref mut ring) => ring, + &mut super::RingOrStreams::Streams(ref mut arr) => arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?, + }; + let (cmd, cycle) = ring.next(); + cmd.transfer_no_op(0, false, false, false, false); + let deque_ptr_and_cycle = ring.register(); + let slot = port_state.slot; + + self.set_tr_deque_ptr(slot, endp_num, deque_ptr_and_cycle)?; + + let endp_num_xhc = endp_num + 1; + self.dbs[slot as usize].write( + (1 << 16) // stream id + | u32::from(endp_num_xhc) + ); + Ok(()) + } + pub fn set_tr_deque_ptr(&mut self, slot: u8, endp_num: u8, deque_ptr_and_cycle: u64) -> Result<()> { + let endp_num_xhc = endp_num + 1; + + // TODO: Merge these command boilerplates into a single function. + self.run.ints[0].erdp.write(self.cmd.erdp()); + + { + let (cmd, cycle, event) = self.cmd.next(); + + + // TODO: I guess this very command is the one used to actually multiplex between + // streams. + cmd.set_tr_deque_ptr(deque_ptr_and_cycle, cycle, StreamContextType::PrimaryRing, 1, endp_num_xhc, slot); + + self.dbs[0].write(0); + + while event.data.read() == 0 { + println!(" - Waiting for event"); + } + + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::CommandCompletion as u8 + { + println!("SET_TR_DEQUEUE_POINTER failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); + return Err(Error::new(EIO)); + } + + cmd.reserved(false); + event.reserved(false); + } + Ok(()) } pub fn on_write_endp_ctl(&mut self, port_num: usize, endp_num: u8, buf: &[u8]) -> Result { let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; @@ -1461,7 +1518,7 @@ impl Xhci { _ => return Err(Error::new(EBADF)), } XhciEndpCtlReq::Reset { no_clear_feature } => match ep_if_state { - EndpIfState::Init => self.on_req_reset_device(port_num, endp_num, no_clear_feature), + EndpIfState::Init => self.on_req_reset_device(port_num, endp_num, no_clear_feature)?, _ => return Err(Error::new(EBADF)), } XhciEndpCtlReq::Transfer(direction) => match ep_if_state { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 9af2b96ee0..8e070d36e6 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -2,6 +2,8 @@ use crate::usb; use std::{fmt, mem}; use syscall::io::{Io, Mmio}; +use super::context::StreamContextType; + #[repr(u8)] pub enum TrbType { Reserved, @@ -242,6 +244,20 @@ impl Trb { | u32::from(cycle), ); } + /// The deque_ptr has to contain the DCS bit (bit 0). + pub fn set_tr_deque_ptr(&mut self, deque_ptr: u64, cycle: bool, sct: StreamContextType, stream_id: u16, endp_num_xhc: u8, slot: u8) { + assert_eq!(deque_ptr & 0xFFFF_FFFF_FFFF_FFF1, deque_ptr); + assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc); + + self.set( + deque_ptr | ((sct as u64) << 1), + u32::from(stream_id) << 16, + (u32::from(slot) << 24) + | (u32::from(endp_num_xhc) << 16) + | ((TrbType::SetTrDequeuePointer as u32) << 10) + | u32::from(cycle), + ) + } pub fn stop_endpoint(&mut self, slot_id: u8, endp_num_xhc: u8, suspend: bool, cycle: bool) { assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc); self.set( @@ -262,6 +278,18 @@ impl Trb { ); } + pub fn transfer_no_op(&mut self, interrupter: u8, ent: bool, ch: bool, ioc: bool, cycle: bool) { + self.set( + 0, + u32::from(interrupter) << 22, + ((TrbType::NoOp as u32) << 10) + | (u32::from(ioc) << 5) + | (u32::from(ch) << 4) + | (u32::from(ent) << 1) + | u32::from(cycle) + ); + } + pub fn setup(&mut self, setup: usb::Setup, transfer: TransferKind, cycle: bool) { self.set( unsafe { mem::transmute(setup) }, @@ -309,7 +337,7 @@ impl Trb { // NOTE: The interrupter target and no snoop flags have been omitted. self.set( buffer, - u32::from(len) | (u32::from(estimated_td_size) << 17) | (u32::from(interrupter) << 21), + u32::from(len) | (u32::from(estimated_td_size) << 17) | (u32::from(interrupter) << 22), u32::from(cycle) | (u32::from(ent) << 1) | (u32::from(isp) << 2) From 56541efd131bb3506518228259a3a1b84032e829 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 12 Feb 2020 15:10:01 +0100 Subject: [PATCH 0341/1301] Use correct endpoint indices. --- usbscsid/src/protocol/bot.rs | 4 ++-- xhcid/src/driver_interface.rs | 2 +- xhcid/src/xhci/scheme.rs | 25 ++++++++++++++++++++----- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index faa2e427be..57394c9d1f 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -112,11 +112,11 @@ impl<'a> BulkOnlyTransport<'a> { }) } fn clear_stall_in(&mut self) -> Result<(), XhciClientHandleError> { - self.bulk_in.reset(false); + self.bulk_in.reset(false)?; self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_in_num), FEATURE_ENDPOINT_HALT) } fn clear_stall_out(&mut self) -> Result<(), XhciClientHandleError> { - self.bulk_out.reset(false); + self.bulk_out.reset(false)?; self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_out_num), FEATURE_ENDPOINT_HALT) } fn reset_recovery(&mut self) -> Result<(), ProtocolError> { diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 709ce85882..5d2c248e12 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -614,7 +614,7 @@ impl XhciEndpHandle { } } fn generic_transfer io::Result>(&mut self, direction: XhciEndpCtlDirection, f: F, expected_len: usize) -> result::Result { - let req = XhciEndpCtlReq::Transfer(XhciEndpCtlDirection::Out); + let req = XhciEndpCtlReq::Transfer(direction); self.ctl_req(&req)?; let bytes_read = f(&mut self.data)?; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 38cb196584..8d37f2c6b7 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -634,6 +634,7 @@ impl Xhci { } if EndpDirection::from(buf.direction()) != endp_desc.direction() { + dbg!(buf.direction(), endp_desc.direction()); return Err(Error::new(EBADF)); } @@ -1450,11 +1451,25 @@ impl Xhci { _ => return Err(Error::new(EIO)), }) } - pub fn on_req_reset_device(&mut self, port_num: usize, endp_num: u8, no_clear_feature: bool) -> Result<()> { + pub fn on_req_reset_device(&mut self, port_num: usize, endp_num: u8, clear_feature: bool) -> Result<()> { + if self.get_endp_status(port_num, endp_num)? != EndpointStatus::Halted { + return Err(Error::new(EBADF)); + } // Change the endpoint state from anything, but most likely HALTED (otherwise resetting // would be quite meaningless), to stopped. self.reset_endpoint(port_num, endp_num, false)?; - self.restart_endpoint(port_num, endp_num) + self.restart_endpoint(port_num, endp_num)?; + + if clear_feature { + self.device_req_no_data(port_num, usb::Setup { + kind: 0b0000_0010, // endpoint recipient + request: 0x01, // CLEAR_FEATURE + value: 0x00, // ENDPOINT_HALT + index: 0, // TODO: interface num + length: 0, + })?; + } + Ok(()) } pub fn restart_endpoint(&mut self, port_num: usize, endp_num: u8) -> Result<()> { let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; @@ -1464,7 +1479,7 @@ impl Xhci { &mut super::RingOrStreams::Streams(ref mut arr) => arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?, }; let (cmd, cycle) = ring.next(); - cmd.transfer_no_op(0, false, false, false, false); + cmd.transfer_no_op(0, false, false, false, cycle); let deque_ptr_and_cycle = ring.register(); let slot = port_state.slot; @@ -1518,7 +1533,7 @@ impl Xhci { _ => return Err(Error::new(EBADF)), } XhciEndpCtlReq::Reset { no_clear_feature } => match ep_if_state { - EndpIfState::Init => self.on_req_reset_device(port_num, endp_num, no_clear_feature)?, + EndpIfState::Init => self.on_req_reset_device(port_num, endp_num, !no_clear_feature)?, _ => return Err(Error::new(EBADF)), } XhciEndpCtlReq::Transfer(direction) => match ep_if_state { @@ -1598,7 +1613,7 @@ impl Xhci { } } { - let (completion_code, bytes_transferred) = self.transfer_read(port_num, endp_num, buf)?; + let (completion_code, bytes_transferred) = self.transfer_read(port_num, endp_num - 1, buf)?; let result = Self::transfer_result(completion_code, bytes_transferred); let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; From 73ca5765583f6e8da31e57839fa5a6de129e03c7 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 12 Feb 2020 22:07:37 +0100 Subject: [PATCH 0342/1301] Use the real DCIs instead of driver-level numbers. Sidenote: instead of STALLing because the driver didn't configure the endpoints properly, regular transfers now work. Thus, QEMU was able to recognize that it received a Bulk-Only Transport CBW. Yay! Additionally, to make life easier when debugging, usbctl was added; now it can get endpoint statuses which were previously non-accessible from shell scripts, after the transition to the new ctl+data endpoint interface. --- Cargo.lock | 70 ++++++++++++++++++++ Cargo.toml | 1 + usbctl/.gitignore | 1 + usbctl/Cargo.toml | 11 ++++ usbctl/src/main.rs | 35 ++++++++++ usbscsid/src/protocol/bot.rs | 6 +- xhcid/src/xhci/mod.rs | 3 + xhcid/src/xhci/scheme.rs | 123 +++++++++++++++++++++++------------ 8 files changed, 207 insertions(+), 43 deletions(-) create mode 100644 usbctl/.gitignore create mode 100644 usbctl/Cargo.toml create mode 100644 usbctl/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 8da1af7f15..4b823ba54a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,14 @@ dependencies = [ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "arg_parser" version = "0.1.0" @@ -34,6 +42,16 @@ dependencies = [ "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "autocfg" version = "0.1.7" @@ -114,6 +132,20 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -1054,6 +1086,11 @@ dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "1.0.14" @@ -1075,6 +1112,14 @@ dependencies = [ "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thiserror" version = "1.0.10" @@ -1308,6 +1353,11 @@ dependencies = [ "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.2.0" @@ -1328,6 +1378,14 @@ dependencies = [ "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "usbctl" +version = "0.1.0" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "xhcid 0.1.0", +] + [[package]] name = "usbhidd" version = "0.1.0" @@ -1375,6 +1433,11 @@ dependencies = [ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "version_check" version = "0.1.5" @@ -1472,8 +1535,10 @@ dependencies = [ ] [metadata] +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" @@ -1486,6 +1551,7 @@ dependencies = [ "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" @@ -1585,8 +1651,10 @@ dependencies = [ "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" "checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "205684fd018ca14432b12cce6ea3d46763311a571c3d294e71ba3f01adcf1aad" "checksum thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57e4d2e50ca050ed44fb58309bdce3efa79948f84f9993ad1978de5eebdce5a7" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" @@ -1609,12 +1677,14 @@ dependencies = [ "checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" +"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" "checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" "checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" diff --git a/Cargo.toml b/Cargo.toml index 0044204257..3c1f2a91d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "vboxd", "vesad", "xhcid", + "usbctl", "usbhidd", "usbscsid", ] diff --git a/usbctl/.gitignore b/usbctl/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/usbctl/.gitignore @@ -0,0 +1 @@ +/target diff --git a/usbctl/Cargo.toml b/usbctl/Cargo.toml new file mode 100644 index 0000000000..ee18af204b --- /dev/null +++ b/usbctl/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "usbctl" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = "2.33" +xhcid = { path = "../xhcid" } diff --git a/usbctl/src/main.rs b/usbctl/src/main.rs new file mode 100644 index 0000000000..0a48029c9d --- /dev/null +++ b/usbctl/src/main.rs @@ -0,0 +1,35 @@ +use clap::{Arg, App}; +use xhcid_interface::XhciClientHandle; + +fn main() { + let matches = App::new("usbctl") + .arg(Arg::with_name("SCHEME").takes_value(true).required(true).long("scheme").short("s")) + .subcommand(App::new("port") + .arg(Arg::with_name("PORT").takes_value(true).required(true)) + .subcommand(App::new("status") + ) + .subcommand(App::new("endpoint") + .arg(Arg::with_name("ENDPOINT_NUM").takes_value(true).required(true)) + .subcommand(App::new("status")) + ) + ) + .get_matches(); + + let scheme = matches.value_of("SCHEME").expect("no scheme"); + + if let Some(port_scmd_matches) = matches.subcommand_matches("port") { + let port = port_scmd_matches.value_of("PORT").expect("invalid utf-8 for PORT argument").parse::().expect("expected PORT to be an integer"); + + let handle = XhciClientHandle::new(scheme.to_owned(), port); + + if let Some(_status_scmd_matches) = port_scmd_matches.subcommand_matches("status") { + let state = handle.port_state().expect("Failed to get port state"); + println!("{}", state.as_str()); + } else if let Some(endp_scmd_matches) = port_scmd_matches.subcommand_matches("endpoint") { + let endp_num = endp_scmd_matches.value_of("ENDPOINT_NUM").expect("no valid ENDPOINT_NUM").parse::().expect("expected ENDPOINT_NUM to be an 8-bit integer"); + let mut endp_handle = handle.open_endpoint(endp_num).expect("Failed to open endpoint"); + let state = endp_handle.status().expect("Failed to get endpoint state"); + println!("{}", state.as_str()); + } + } +} diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index 57394c9d1f..469a0006e1 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -95,8 +95,6 @@ impl<'a> BulkOnlyTransport<'a> { let bulk_in_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::In).unwrap() + 1) as u8; let bulk_out_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::Out).unwrap() + 1) as u8; - bulk_only_mass_storage_reset(handle, if_desc.number.into())?; - let max_lun = get_max_lun(handle, 0)?; println!("BOT_MAX_LUN {}", max_lun); @@ -147,6 +145,8 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { dbg!(self.bulk_in.status()?, self.bulk_out.status()?); + bulk_only_mass_storage_reset(&self.handle, self.interface_num.into())?; + match self.bulk_out.transfer_write(&cbw_bytes)? { PortTransferStatus::ShortPacket(31) => (), PortTransferStatus::Stalled => { @@ -154,7 +154,7 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { self.clear_stall_out()?; dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } - _ => panic!("invalid number of CBW bytes written; expected a short packed of length 31 (0x1F)"), + _ => (),//panic!("invalid number of CBW bytes written; expected a short packet of length 31 (0x1F)"), } match data { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 2d0fe8fde9..e49570a260 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -388,6 +388,9 @@ impl Xhci { } pub fn update_default_control_pipe(&mut self, input_context: &mut Dma, slot_id: u8, dev_desc: &DevDesc) -> Result<()> { + input_context.add_context.write(1 << 1); + input_context.drop_context.write(0); + let new_max_packet_size = if dev_desc.major_version() == 2 { u32::from(dev_desc.packet_size) } else { diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 8d37f2c6b7..d12f21f318 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -217,7 +217,7 @@ impl Xhci { let (cmd, cycle) = ring.next(); cmd.status(false, cycle); } - self.dbs[ps.slot as usize].write(1); + self.dbs[ps.slot as usize].write(Self::def_control_endp_doorbell()); { let event = self.cmd.next_event(); @@ -259,33 +259,34 @@ impl Xhci { } fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { + let endp_num_xhc = Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?); + let slot = self .port_states .get(&port_num) .ok_or(Error::new(EBADF))? .slot; - { - let (cmd, cycle, event) = self.cmd.next(); - cmd.reset_endpoint(slot, endp_num + 1, tsp, cycle); - self.dbs[0].write(0); + let (cmd, cycle, event) = self.cmd.next(); + cmd.reset_endpoint(slot, endp_num_xhc, tsp, cycle); - while event.data.read() == 0 { - println!(" - Waiting for event"); - } + self.dbs[0].write(0); - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::CommandCompletion as u8 - { - println!("RESET_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); - return Err(Error::new(EIO)); - } - - cmd.reserved(false); - event.reserved(false); - - self.run.ints[0].erdp.write(self.cmd.erdp()); + while event.data.read() == 0 { + println!(" - Waiting for event"); } + + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::CommandCompletion as u8 + { + println!("RESET_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); + return Err(Error::new(EIO)); + } + + cmd.reserved(false); + event.reserved(false); + + self.run.ints[0].erdp.write(self.cmd.erdp()); Ok(()) } @@ -391,7 +392,10 @@ impl Xhci { return Err(Error::new(EIO)); } - let new_context_entries = 1 + endpoints.len() as u32; + let new_context_entries = match endpoints.last() { + Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l), + None => 1, + } + 1; input_context.device.slot.a.write( (current_slot_a & !CONTEXT_ENTRIES_MASK) @@ -406,18 +410,19 @@ impl Xhci { let lec = self.cap.lec(); - for index in 0..endpoints.len() as u8 { - let endp_num = index + 1; - let xhc_endp_num = endp_num + 1; + for endp_idx in 0..endpoints.len() as u8 { + let endp_num = endp_idx + 1; - input_context.add_context.writef(1 << xhc_endp_num, true); + let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; + let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); + + input_context.add_context.writef(1 << endp_num_xhc, true); let endp_ctx = input_context .device .endpoints - .get_mut(endp_num as usize) + .get_mut(endp_num_xhc as usize - 1) .ok_or(Error::new(EIO))?; - let endp_desc = endpoints.get(index as usize).ok_or(Error::new(EIO))?; let max_streams = endp_desc.max_streams(); let max_psa_size = self.cap.max_psa_size(); @@ -589,6 +594,30 @@ impl Xhci { }, ) } + const fn def_control_endp_doorbell() -> u32 { + 1 + } + // TODO: Wrap DCIs and driver-level endp_num into distinct types, due to the high chance of + // mixing the two up. + fn endp_num_to_dci(endp_num: u8, desc: &EndpDesc) -> u8 { + if endp_num == 0 { unreachable!("EndpDesc cannot be obtained from the default control endpoint") } + + if desc.is_control() || desc.direction() == EndpDirection::In { + endp_num * 2 + 1 + } else if desc.direction() == EndpDirection::Out { + endp_num * 2 + } else { unreachable!() } + } + fn endp_desc(&self, port_num: usize, endp_num: u8) -> Result<&EndpDesc> { + self.port_states.get(&port_num).ok_or(Error::new(EIO))?.dev_desc.config_descs.first().ok_or(Error::new(EIO))?.interface_descs.first().ok_or(Error::new(EIO))?.endpoints.get(endp_num as usize - 1).ok_or(Error::new(EIO)) + } + fn endp_doorbell(endp_num: u8, desc: &EndpDesc, stream_id: u16) -> u32 { + let db_target = Self::endp_num_to_dci(endp_num, desc); + let db_task_id: u16 = stream_id; + + (u32::from(db_task_id) << 16) + | u32::from(db_target) + } // TODO: Rename DeviceReqData to something more general. fn transfer( &mut self, @@ -598,7 +627,6 @@ impl Xhci { ) -> Result<(u8, u32)> { // TODO: Check that only readable enpoints are read, etc. let endp_num = endp_idx + 1; - let xhc_endp_num = endp_num + 1; // TODO: Check that buf has a nonzero size, otherwise (at least for Rust's GlobalAlloc), // UB. let dma_buffer = match buf { @@ -629,12 +657,13 @@ impl Xhci { .get(endp_idx as usize) .ok_or(Error::new(EBADFD))?; + let direction = endp_desc.direction(); + if endp_desc.is_isoch() { return Err(Error::new(ENOSYS)); } if EndpDirection::from(buf.direction()) != endp_desc.direction() { - dbg!(buf.direction(), endp_desc.direction()); return Err(Error::new(EBADF)); } @@ -688,8 +717,7 @@ impl Xhci { } let stream_id = 1u16; - self.dbs[port_state.slot as usize] - .write(u32::from(xhc_endp_num) | (u32::from(stream_id) << 16)); + self.dbs[port_state.slot as usize].write(Self::endp_doorbell(endp_num, self.endp_desc(port_num, endp_num)?, stream_id)); let (completion_code, bytes_transferred) = { let event = self.cmd.next_event(); @@ -953,7 +981,7 @@ impl Xhci { let (cmd, cycle) = ring.next(); cmd.status(transfer_kind == TransferKind::In, cycle); } - self.dbs[port_state.slot as usize].write(1); + self.dbs[port_state.slot as usize].write(Self::def_control_endp_doorbell()); { let event = self.cmd.next_event(); @@ -1441,7 +1469,12 @@ impl SchemeMut for Xhci { impl Xhci { pub fn get_endp_status(&mut self, port_num: usize, endp_num: u8) -> Result { let slot = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?.slot; - let raw = self.dev_ctx.contexts.get(slot as usize).ok_or(Error::new(EBADFD))?.endpoints.get(endp_num as usize).ok_or(Error::new(EBADFD))?.a.read() & super::context::ENDPOINT_CONTEXT_STATUS_MASK; + let endp_num_xhc = if endp_num != 0 { + Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?) + } else { + 1 + }; + let raw = self.dev_ctx.contexts.get(slot as usize).ok_or(Error::new(EBADFD))?.endpoints.get(endp_num_xhc as usize - 1).ok_or(Error::new(EBADFD))?.a.read() & super::context::ENDPOINT_CONTEXT_STATUS_MASK; Ok(match raw { 0 => EndpointStatus::Disabled, 1 => EndpointStatus::Enabled, @@ -1473,6 +1506,12 @@ impl Xhci { } pub fn restart_endpoint(&mut self, port_num: usize, endp_num: u8) -> Result<()> { let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; + let direction = if endp_num != 0 { + let endp_desc = port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endp_num as usize - 1).ok_or(Error::new(EBADFD))?; + endp_desc.direction() + } else { + EndpDirection::Bidirectional + }; let endpoint_state: &mut EndpointState = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; let ring = match &mut endpoint_state.transfer { &mut super::RingOrStreams::Ring(ref mut ring) => ring, @@ -1483,17 +1522,21 @@ impl Xhci { let deque_ptr_and_cycle = ring.register(); let slot = port_state.slot; - self.set_tr_deque_ptr(slot, endp_num, deque_ptr_and_cycle)?; + self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle)?; - let endp_num_xhc = endp_num + 1; - self.dbs[slot as usize].write( - (1 << 16) // stream id - | u32::from(endp_num_xhc) - ); + let stream_id = 1u16; + self.dbs[slot as usize].write(Self::endp_doorbell(endp_num, self.endp_desc(port_num, endp_num)?, stream_id)); Ok(()) } - pub fn set_tr_deque_ptr(&mut self, slot: u8, endp_num: u8, deque_ptr_and_cycle: u64) -> Result<()> { - let endp_num_xhc = endp_num + 1; + pub fn endp_direction(&self, port_num: usize, endp_num: u8) -> Result { + Ok(self.port_states.get(&port_num).ok_or(Error::new(EIO))?.dev_desc.config_descs.first().ok_or(Error::new(EIO))?.interface_descs.first().ok_or(Error::new(EIO))?.endpoints.get(endp_num as usize).ok_or(Error::new(EIO))?.direction()) + } + pub fn slot(&self, port_num: usize) -> Result { + Ok(self.port_states.get(&port_num).ok_or(Error::new(EIO))?.slot) + } + pub fn set_tr_deque_ptr(&mut self, port_num: usize, endp_num: u8, deque_ptr_and_cycle: u64) -> Result<()> { + let slot = self.slot(port_num)?; + let endp_num_xhc = Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?); // TODO: Merge these command boilerplates into a single function. self.run.ints[0].erdp.write(self.cmd.erdp()); From 9d88528188bb10a63434161459309bafa33e1609 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 12 Feb 2020 23:17:50 +0100 Subject: [PATCH 0343/1301] Make SCSI commands working. --- usbscsid/src/main.rs | 34 ++++++++++++++++++++++------------ usbscsid/src/protocol/bot.rs | 32 ++++++++++++++++++++++---------- usbscsid/src/scsi/cmds.rs | 26 ++++++++++++++++++++++++++ xhcid/src/xhci/scheme.rs | 2 +- 4 files changed, 71 insertions(+), 23 deletions(-) diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index 4dbd53b980..a60712edf7 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -5,6 +5,8 @@ use xhcid_interface::{ConfigureEndpointsReq, DeviceReqData, XhciClientHandle}; pub mod protocol; pub mod scsi; +use scsi::cmds::StandardInquiryData; + fn main() { let mut args = env::args().skip(1); @@ -39,19 +41,27 @@ fn main() { let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc).expect("Failed to setup protocol"); - /*let get_info = { - // Max number of bytes that can be recieved from a "REPORT IDENTIFYING INFORMATION" - // command. - let alloc_len = 256; - let info_ty = scsi::cmds::ReportIdInfoInfoTy::IdentInfoSupp; - let control = 0; // TODO: NACA? - scsi::cmds::ReportIdentInfo::new(alloc_len, info_ty, control) - };*/ - let mut buffer = [0u8; 5]; + assert_eq!(std::mem::size_of::(), 96); + let mut inquiry_buffer = [0u8; 259]; // additional_len = 255 let mut command_buffer = [0u8; 6]; + + let min_inquiry_len = 5u16; + + let max_inquiry_len = { + { + let inquiry = plain::from_mut_bytes(&mut command_buffer).unwrap(); + *inquiry = scsi::cmds::Inquiry::new(false, 0, min_inquiry_len, 0); + } + protocol.send_command(&command_buffer, DeviceReqData::In(&mut inquiry_buffer[..min_inquiry_len as usize])).expect("Failed to send command"); + let standard_inquiry_data: &StandardInquiryData = dbg!(plain::from_bytes(&inquiry_buffer).unwrap()); + 4 + u16::from(standard_inquiry_data.additional_len) + }; { - let mut inquiry = plain::from_mut_bytes(&mut command_buffer).unwrap(); - *inquiry = scsi::cmds::Inquiry::new(false, 0, 5, 0); + { + let inquiry = plain::from_mut_bytes(&mut command_buffer).unwrap(); + *inquiry = scsi::cmds::Inquiry::new(false, 0, max_inquiry_len, 0); + } + protocol.send_command(&command_buffer, DeviceReqData::In(&mut inquiry_buffer[..max_inquiry_len as usize])).expect("Failed to send command"); + let standard_inquiry_data: &StandardInquiryData = dbg!(plain::from_bytes(&inquiry_buffer).unwrap()); } - protocol.send_command(&command_buffer, DeviceReqData::In(&mut buffer)).expect("Failed to send command"); } diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index 469a0006e1..e3ef9bf7d7 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -138,23 +138,25 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { println!(); let mut cbw_bytes = [0u8; 31]; - let cbw = plain::from_mut_bytes::(&mut cbw_bytes).unwrap(); - - *cbw = CommandBlockWrapper::new(tag, data.len() as u32, data.direction().into(), 0, cb)?; println!("{}", base64::encode(&cbw_bytes)); + let cbw = plain::from_mut_bytes::(&mut cbw_bytes).unwrap(); + *cbw = CommandBlockWrapper::new(tag, data.len() as u32, data.direction().into(), 0, cb)?; + let cbw = *cbw; dbg!(self.bulk_in.status()?, self.bulk_out.status()?); bulk_only_mass_storage_reset(&self.handle, self.interface_num.into())?; match self.bulk_out.transfer_write(&cbw_bytes)? { - PortTransferStatus::ShortPacket(31) => (), PortTransferStatus::Stalled => { println!("bulk out endpoint stalled when sending CBW"); self.clear_stall_out()?; dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } - _ => (),//panic!("invalid number of CBW bytes written; expected a short packet of length 31 (0x1F)"), + PortTransferStatus::ShortPacket(n) if n != 31 => { + panic!("received short packet when sending CBW ({} != 31)", n); + } + _ => (), } match data { @@ -170,24 +172,34 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { }; println!("{}", base64::encode(&buffer[..])); } - DeviceReqData::Out(ref buffer) => todo!(), - DeviceReqData::NoData => todo!(), + DeviceReqData::Out(buffer) => { + match self.bulk_out.transfer_write(buffer)? { + PortTransferStatus::Success => (), + PortTransferStatus::ShortPacket(len) => panic!("received short packed (len {}) when transferring data", len), + PortTransferStatus::Stalled => { + println!("bulk out endpoint stalled when reading data"); + self.clear_stall_out()?; + } + PortTransferStatus::Unknown => return Err(ProtocolError::XhciError(XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")))), + } + } + DeviceReqData::NoData => (), } let mut csw_buffer = [0u8; 13]; match self.bulk_in.transfer_read(&mut csw_buffer)? { - PortTransferStatus::ShortPacket(13) => (), PortTransferStatus::Stalled => { println!("bulk in endpoint stalled when reading CSW"); self.clear_stall_in()?; } - _ => panic!("invalid number of CSW bytes read; expected a short packet of length 13 (0xD)"), + PortTransferStatus::ShortPacket(n) if n != 13 => panic!("received a short packet when reading CSW ({} != 13)", n), + _ => (), }; println!("{}", base64::encode(&csw_buffer)); let csw = plain::from_bytes::(&csw_buffer).unwrap(); - if !csw.is_valid() { + if !csw.is_valid() || csw.tag != cbw.tag { self.reset_recovery()?; } dbg!(csw); diff --git a/usbscsid/src/scsi/cmds.rs b/usbscsid/src/scsi/cmds.rs index 0b759886bb..edc8ae69ac 100644 --- a/usbscsid/src/scsi/cmds.rs +++ b/usbscsid/src/scsi/cmds.rs @@ -151,3 +151,29 @@ impl Inquiry { } } } + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct StandardInquiryData { + /// Peripheral device type (bits 4:0), and peripheral device qualifier (bits 7:5). + pub a: u8, + /// Removable media bit (bit 7, bits 6:0 are reserved). + pub rmb: u8, + /// Version of the SCSI command set. + pub version: u8, + pub b: u8, + pub additional_len: u8, + pub c: u8, + pub d: u8, + pub e: u8, + pub t10_vendor_info: u64, + pub product_ident: [u8; 16], + pub product_rev_label: u32, + pub driver_serial_no: [u8; 8], + pub vendor_uniq: [u8; 12], + _rsvd1: [u8; 2], + pub vendor_descs: [u16; 8], + _rsvd2: [u8; 22], +} + +unsafe impl plain::Plain for StandardInquiryData {} diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index d12f21f318..acea2a2608 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -686,7 +686,7 @@ impl Xhci { let max_packet_size = endp_desc.max_packet_size; { let (trb, cycle) = ring.next(); - let (buffer, idt) = if len <= 8 && max_packet_size >= 8 { + let (buffer, idt) = if len <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { buf.map_buf(|sbuf| { let mut bytes = [0u8; 8]; bytes[..len as usize].copy_from_slice(&sbuf[..len as usize]); From 034e6bce7094b5ff8ce24ddbaf5b87d84c681d55 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 14 Feb 2020 00:02:13 +0100 Subject: [PATCH 0344/1301] Set up a basic SCSI scheme, and get disk size. Some commands are unused though, and probably won't be used, for example ReportSuppOpcodes. Also, there appears to be lots of different versions of the SCSI specification. --- Cargo.lock | 1 + usbscsid/Cargo.toml | 1 + usbscsid/src/main.rs | 52 +++--- usbscsid/src/protocol/bot.rs | 23 +-- usbscsid/src/protocol/mod.rs | 17 +- usbscsid/src/scheme.rs | 83 +++++++++ usbscsid/src/scsi/cmds.rs | 339 ++++++++++++++++++++++++++++++++++- usbscsid/src/scsi/mod.rs | 172 ++++++++++++++++++ 8 files changed, 650 insertions(+), 38 deletions(-) create mode 100644 usbscsid/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index 4b823ba54a..c41a1e0178 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1402,6 +1402,7 @@ version = "0.1.0" dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] diff --git a/usbscsid/Cargo.toml b/usbscsid/Cargo.toml index 7d5f1abf88..ed2808e70f 100644 --- a/usbscsid/Cargo.toml +++ b/usbscsid/Cargo.toml @@ -10,5 +10,6 @@ license = "MIT" [dependencies] base64 = "0.11" # Only for debugging plain = "0.2" +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } thiserror = "1" xhcid = { path = "../xhcid" } diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index a60712edf7..82a5529ccd 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -1,11 +1,18 @@ use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::os::unix::io::{FromRawFd, RawFd}; +use syscall::{CloneFlags, Packet, SchemeMut}; use xhcid_interface::{ConfigureEndpointsReq, DeviceReqData, XhciClientHandle}; pub mod protocol; pub mod scsi; -use scsi::cmds::StandardInquiryData; +mod scheme; + +use scheme::ScsiScheme; +use scsi::Scsi; fn main() { let mut args = env::args().skip(1); @@ -18,6 +25,15 @@ fn main() { println!("USB SCSI driver spawned with scheme `{}`, port {}, protocol {}", scheme, port, protocol); + // Daemonize so that xhcid can continue to do other useful work (until proper IRQs, + // async-await, and multithreading :D) + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { + return + } + + let disk_scheme_name = format!(":disk/{}-{}_scsi", scheme, port); + + // TODO: Use eventfds. let handle = XhciClientHandle::new(scheme, port); let desc = handle.get_standard_descs().expect("Failed to get standard descriptors"); @@ -41,27 +57,23 @@ fn main() { let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc).expect("Failed to setup protocol"); - assert_eq!(std::mem::size_of::(), 96); - let mut inquiry_buffer = [0u8; 259]; // additional_len = 255 - let mut command_buffer = [0u8; 6]; + // TODO: Let all of the USB drivers syscall clone(2), and xhcid won't have to keep track of all + // the drivers. + let socket_fd = syscall::open(disk_scheme_name, syscall::O_RDWR | syscall::O_CREAT).expect("usbscsid: failed to create disk scheme"); + let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - let min_inquiry_len = 5u16; + //syscall::setrens(0, 0).expect("scsid: failed to enter null namespace"); + let mut scsi = Scsi::new(&mut *protocol); + let mut scsi_scheme = ScsiScheme::new(&mut scsi); - let max_inquiry_len = { - { - let inquiry = plain::from_mut_bytes(&mut command_buffer).unwrap(); - *inquiry = scsi::cmds::Inquiry::new(false, 0, min_inquiry_len, 0); + // TODO: Use nonblocking and put all pending calls in a todo VecDeque. Use an eventfd as well. + 'scheme_loop: loop { + let mut packet = Packet::default(); + match socket_file.read(&mut packet) { + Ok(0) => break 'scheme_loop, + Ok(_) => (), + Err(err) => panic!("scsid: failed to read disk scheme: {}", err), } - protocol.send_command(&command_buffer, DeviceReqData::In(&mut inquiry_buffer[..min_inquiry_len as usize])).expect("Failed to send command"); - let standard_inquiry_data: &StandardInquiryData = dbg!(plain::from_bytes(&inquiry_buffer).unwrap()); - 4 + u16::from(standard_inquiry_data.additional_len) - }; - { - { - let inquiry = plain::from_mut_bytes(&mut command_buffer).unwrap(); - *inquiry = scsi::cmds::Inquiry::new(false, 0, max_inquiry_len, 0); - } - protocol.send_command(&command_buffer, DeviceReqData::In(&mut inquiry_buffer[..max_inquiry_len as usize])).expect("Failed to send command"); - let standard_inquiry_data: &StandardInquiryData = dbg!(plain::from_bytes(&inquiry_buffer).unwrap()); + scsi_scheme.handle(&mut packet); } } diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index e3ef9bf7d7..0aafe80aeb 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -1,12 +1,9 @@ -use std::convert::TryInto; -use std::fs::File; -use std::io::prelude::*; -use std::{io, slice}; +use std::num::NonZeroU32; +use std::slice; -use thiserror::Error; -use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqDirection, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpHandle}; +use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpHandle}; -use super::{Protocol, ProtocolError}; +use super::{Protocol, ProtocolError, SendCommandStatus}; pub const CBW_SIGNATURE: u32 = 0x43425355; @@ -130,7 +127,7 @@ impl<'a> BulkOnlyTransport<'a> { } impl<'a> Protocol for BulkOnlyTransport<'a> { - fn send_command(&mut self, cb: &[u8], data: DeviceReqData) -> Result<(), ProtocolError> { + fn send_command(&mut self, cb: &[u8], data: DeviceReqData) -> Result { self.current_tag += 1; let tag = self.current_tag; @@ -138,10 +135,10 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { println!(); let mut cbw_bytes = [0u8; 31]; - println!("{}", base64::encode(&cbw_bytes)); let cbw = plain::from_mut_bytes::(&mut cbw_bytes).unwrap(); *cbw = CommandBlockWrapper::new(tag, data.len() as u32, data.direction().into(), 0, cb)?; let cbw = *cbw; + println!("{}", base64::encode(&cbw_bytes)); dbg!(self.bulk_in.status()?, self.bulk_out.status()?); @@ -209,7 +206,13 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } - Ok(()) + Ok(if csw.status == CswStatus::Passed as u8 { + SendCommandStatus::Success + } else if csw.status == CswStatus::Failed as u8 { + SendCommandStatus::Failed { residue: NonZeroU32::new(csw.data_residue) } + } else { + return Err(ProtocolError::ProtocolError("bulk-only transport phase error, or other")); + }) } } diff --git a/usbscsid/src/protocol/mod.rs b/usbscsid/src/protocol/mod.rs index 569505199f..2ffe4e5d83 100644 --- a/usbscsid/src/protocol/mod.rs +++ b/usbscsid/src/protocol/mod.rs @@ -1,4 +1,5 @@ use std::io; +use std::num::NonZeroU32; use thiserror::Error; use xhcid_interface::{DeviceReqData, DevDesc, ConfDesc, IfDesc, XhciClientHandle, XhciClientHandleError}; @@ -16,10 +17,24 @@ pub enum ProtocolError { #[error("attempted recovery failed")] RecoveryFailed, + + #[error("protocol error")] + ProtocolError(&'static str), +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum SendCommandStatus { + Success, + Failed { residue: Option }, +} +impl Default for SendCommandStatus { + fn default() -> Self { + Self::Success + } } pub trait Protocol { - fn send_command(&mut self, command: &[u8], data: DeviceReqData) -> Result<(), ProtocolError>; + fn send_command(&mut self, command: &[u8], data: DeviceReqData) -> Result; } /// Bulk-only transport diff --git a/usbscsid/src/scheme.rs b/usbscsid/src/scheme.rs new file mode 100644 index 0000000000..46d1a18393 --- /dev/null +++ b/usbscsid/src/scheme.rs @@ -0,0 +1,83 @@ +use std::collections::BTreeMap; +use std::str; + +use crate::scsi::Scsi; + +use syscall::SchemeMut; +use syscall::error::{Error, Result}; +use syscall::error::{EACCES, EBADF, ENOENT, ENOSYS}; +use syscall::flag::{O_DIRECTORY, O_STAT}; +use syscall::flag::{MODE_CHR, MODE_DIR}; + +// TODO: Only one disk, right? +const LIST_CONTENTS: &'static [u8] = b"disk\n"; + +enum Handle { + List(usize), + Disk(usize), + //Partition(usize, u32, usize), +} + +pub struct ScsiScheme<'a> { + scsi: &'a mut Scsi, + handles: BTreeMap, + next_fd: usize, +} + +impl<'a> ScsiScheme<'a> { + pub fn new(scsi: &'a mut Scsi) -> Self { + Self { + scsi, + handles: BTreeMap::new(), + next_fd: 0, + } + } +} + +impl<'a> SchemeMut for ScsiScheme<'a> { + fn open(&mut self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result { + if uid != 0 { + return Err(Error::new(EACCES)); + } + let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_start_matches('/'); + let handle = if path_str.is_empty() { + // List + Handle::List(0) + } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { + // TODO: Partitions. + return Err(Error::new(ENOSYS)); + } else { + Handle::Disk(0) + }; + self.next_fd += 1; + self.handles.insert(self.next_fd, handle); + Err(Error::new(ENOSYS)) + } + fn fstat(&mut self, fd: usize, stat: &mut syscall::Stat) -> Result { + match self.handles.get(&fd).ok_or(Error::new(EBADF))? { + Handle::Disk(_) => { + stat.st_mode = MODE_CHR; + stat.st_size = self.scsi.get_disk_size(); + // TODO: stat.st_blocks + } + Handle::List(_) => { + stat.st_mode = MODE_DIR; + stat.st_size = LIST_CONTENTS.len() as u64; + // TODO: stat.st_blocks + } + } + Err(Error::new(ENOSYS)) + } + fn fpath(&mut self, fd: usize, path: &mut [u8]) -> Result { + Err(Error::new(ENOSYS)) + } + fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { + Err(Error::new(ENOSYS)) + } + fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { + Err(Error::new(ENOSYS)) + } + fn write(&mut self, fd: usize, buf: &[u8]) -> Result { + Err(Error::new(ENOSYS)) + } +} diff --git a/usbscsid/src/scsi/cmds.rs b/usbscsid/src/scsi/cmds.rs index edc8ae69ac..98c6006a86 100644 --- a/usbscsid/src/scsi/cmds.rs +++ b/usbscsid/src/scsi/cmds.rs @@ -1,3 +1,4 @@ +use std::{fmt, mem, slice}; use super::opcodes::{Opcode, ServiceActionA3}; #[repr(packed)] @@ -16,7 +17,7 @@ pub struct ReportIdentInfo { unsafe impl plain::Plain for ReportIdentInfo {} impl ReportIdentInfo { - pub fn new(alloc_len: u32, info_ty: ReportIdInfoInfoTy, control: u8) -> Self { + pub const fn new(alloc_len: u32, info_ty: ReportIdInfoInfoTy, control: u8) -> Self { Self { opcode: Opcode::ServiceActionA3 as u8, serviceaction: ServiceActionA3::ReportIdentInfo as u8, @@ -72,6 +73,12 @@ impl ReportSuppOpcodes { pub const fn get_all(rctd: bool, alloc_len: u32, control: u8) -> Self { Self::new(ReportSuppOpcodesOptions::ListAll, rctd, 0, 0, alloc_len, control) } + pub const fn get_supp_no_sa(rctd: bool, opcode: Opcode, alloc_len: u32, control: u8) -> Self { + Self::new(ReportSuppOpcodesOptions::NoServicaction, rctd, opcode as u8, 0, alloc_len, control) + } + pub const fn get_supp(rctd: bool, opcode: Opcode, serviceaction: u16, alloc_len: u32, control: u8) -> Self { + Self::new(ReportSuppOpcodesOptions::ExplicitBoth, rctd, opcode as u8, serviceaction, alloc_len, control) + } } pub const REP_OPTS_MAIN_MASK: u8 = 0b0000_0111; @@ -96,6 +103,8 @@ pub enum ReportSuppOpcodesOptions { /// Returns one command with the requested opcode and service action. The command may or may /// not implement service actions, but if it does, it has to be correct for the return value to /// indicate SUPPORTED. + /// + /// This option seems to be reserved for SPC-3 (inquiry version value of 5). IndicateSupport, } @@ -104,10 +113,23 @@ pub enum ReportSuppOpcodesOptions { pub struct AllCommandsParam { /// Little endian pub data_len: u32, - pub descs: [CommandDescriptor], + pub descs: [CommandDescriptor; 0], } +impl AllCommandsParam { + pub const fn alloc_len(&self) -> u32 { + 3 + u32::from_le(self.data_len) + } + pub unsafe fn descs(&self) -> &[CommandDescriptor] { + assert_eq!(mem::size_of::(), 20); + slice::from_raw_parts(&self.descs as *const CommandDescriptor, (self.alloc_len() as usize - 4) / mem::size_of::()) + } +} + +unsafe impl plain::Plain for AllCommandsParam {} + #[repr(packed)] +#[derive(Clone, Copy, Debug)] pub struct CommandDescriptor { pub opcode: u8, pub _rsvd1: u8, @@ -118,14 +140,47 @@ pub struct CommandDescriptor { pub a: u8, /// little endian pub cdb_len: u16, + pub cmd_timeouts_desc: [u8; 12], } #[repr(packed)] pub struct OneCommandParam { pub _rsvd: u8, - /// bits 2:0 for SUPPOR, bits 6:3 reserved, and bit 7 for CTDP pub a: u8, - // TODO + pub cdb_size: u16, + pub usage_data: [u8; 0], +} +unsafe impl plain::Plain for OneCommandParam {} + +impl OneCommandParam { + pub const fn ctdp(&self) -> bool { + self.a & (1 << 7) != 0 + } + pub fn support(&self) -> OneCommandParamSupport { + let raw = self.a & 0b111; + // Safe because all possible values are covered by the enum. + unsafe { mem::transmute(raw) } + } + pub const fn total_len(&self) -> u16 { + self.cdb_size as u16 + 3 + } + /// Unsafe because the reference to self has to be valid for an additional (self.cdb_size - 1) bytes. + pub unsafe fn cdb_usage_data(&self) -> &[u8] { + slice::from_raw_parts(&self.usage_data as *const u8, self.total_len() as usize - 4) + } +} + +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum OneCommandParamSupport { + NoDataAvail = 0b000, + NotSupported = 0b001, + Rsvd2 = 0b010, + Supported = 0b011, + Rsvd4 = 0b100, + SupportedVendor = 0b101, + Rsvd6 = 0b110, + Rsvd7 = 0b111, } #[repr(packed)] @@ -141,7 +196,7 @@ pub struct Inquiry { unsafe impl plain::Plain for Inquiry {} impl Inquiry { - pub fn new(evpd: bool, page_code: u8, alloc_len: u16, control: u8) -> Self { + pub const fn new(evpd: bool, page_code: u8, alloc_len: u16, control: u8) -> Self { Self { opcode: Opcode::Inquiry as u8, evpd: evpd as u8, @@ -172,8 +227,278 @@ pub struct StandardInquiryData { pub driver_serial_no: [u8; 8], pub vendor_uniq: [u8; 12], _rsvd1: [u8; 2], - pub vendor_descs: [u16; 8], + pub version_descs: [u16; 8], _rsvd2: [u8; 22], } - unsafe impl plain::Plain for StandardInquiryData {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct RequestSense { + pub opcode: u8, + pub desc: u8, // bits 7:1 reserved + _rsvd: u16, + pub alloc_len: u8, + pub control: u8, +} +unsafe impl plain::Plain for RequestSense {} + +impl RequestSense { + pub const MINIMAL_ALLOC_LEN: u8 = 252; + + pub const fn new(desc: bool, alloc_len: u8, control: u8) -> Self { + Self { + opcode: Opcode::RequestSense as u8, + desc: desc as u8, + _rsvd: 0, + alloc_len, + control, + } + } +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct FixedFormatSenseData { + pub a: u8, + _obsolete: u8, + pub b: u8, + pub info: u32, + pub add_sense_len: u8, + pub command_specific_info: u32, + pub add_sense_code: u8, + pub add_sense_code_qual: u8, + pub field_replacable_unit_code: u8, + pub sense_key_specific: [u8; 3], // little endian + pub add_sense_bytes: [u8; 0], +} +unsafe impl plain::Plain for FixedFormatSenseData {} + +impl FixedFormatSenseData { + pub const fn additional_len(&self) -> u16 { + self.add_sense_len as u16 + 7 + } + pub unsafe fn add_sense_bytes(&self) -> &[u8] { + slice::from_raw_parts(&self.add_sense_len as *const u8, self.add_sense_len as usize - 18) + } + pub fn sense_key(&self) -> SenseKey { + let sense_key_raw = self.b & 0b1111; + // Safe because all possible values (0-15) are used by the enum. + unsafe { mem::transmute(sense_key_raw) } + } +} + +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum SenseKey { + NoSense = 0x00, + RecoveredError = 0x01, + NotReady = 0x02, + MediumError = 0x03, + HardwareError = 0x04, + IllegalRequest = 0x05, + UnitAttention = 0x06, + DataProtect = 0x07, + BlankCheck = 0x08, + VendorSpecific = 0x09, + CopyAborted = 0x0A, + AbortedCommand = 0x0B, + Reserved = 0x0C, + VolumeOverflow = 0x0D, + Miscompare = 0x0E, + Completed = 0x0F, +} +impl Default for SenseKey { + fn default() -> Self { + Self::NoSense + } +} + +pub const ADD_SENSE_CODE05_INVAL_CDB_FIELD: u8 = 0x24; + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct Read16 { + pub opcode: u8, + pub a: u8, + pub lba: u64, + pub transfer_len: u32, + pub b: u8, + pub control: u8, +} + +impl Read16 { + pub const fn new(lba: u64, transfer_len: u32, control: u8) -> Self { + // TODO: RDPROTECT, DPO, FUA, RARC + // TODO: DLD + // TODO: Group number + Self { + opcode: Opcode::Read16 as u8, + a: 0, + lba: u64::to_le(lba), + transfer_len: u32::to_le(transfer_len), + b: 0, + control, + } + } +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct ModeSense6 { + pub opcode: u8, + pub a: u8, + pub b: u8, + pub subpage_code: u8, + pub alloc_len: u8, + pub control: u8, +} +unsafe impl plain::Plain for ModeSense6 {} + +impl ModeSense6 { + pub const fn new(dbd: bool, page_code: u8, pc: u8, subpage_code: u8, alloc_len: u8, control: u8) -> Self { + Self { + opcode: Opcode::ModeSense6 as u8, + a: (dbd as u8) << 3, + b: page_code | (pc << 6), + subpage_code, + alloc_len, + control, + } + } +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct ModeSense10 { + pub opcode: u8, + pub a: u8, + pub b: u8, + pub subpage_code: u8, + pub _rsvd: [u8; 3], + pub alloc_len: u16, + pub control: u8, +} +unsafe impl plain::Plain for ModeSense10 {} + +impl ModeSense10 { + pub const fn new(dbd: bool, llbaa: bool, page_code: u8, pc: ModePageControl, subpage_code: u8, alloc_len: u16, control: u8) -> Self { + Self { + opcode: Opcode::ModeSense10 as u8, + a: ((dbd as u8) << 3) | ((llbaa as u8) << 4), + b: page_code | ((pc as u8) << 6), + subpage_code, + _rsvd: [0u8; 3], + alloc_len: u16::from_le(alloc_len), + control, + } + } + pub const fn get_block_desc(alloc_len: u16, control: u8) -> Self { + Self::new(false, true, 0x3F, ModePageControl::CurrentValues, 0x00, alloc_len, control) + } +} + +#[repr(u8)] +pub enum ModePageControl { + CurrentValues, + ChangeableChanges, + DefaultValues, + SavedValue, +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct ShortLbaModeParamBlkDesc { + pub block_count: u32, + _rsvd: u8, + pub logical_block_len: [u8; 3], +} +unsafe impl plain::Plain for ShortLbaModeParamBlkDesc {} + +impl ShortLbaModeParamBlkDesc { + pub const fn block_count(&self) -> u32 { + u32::from_le(self.block_count) + } + pub const fn logical_block_len(&self) -> u32 { + u24_le_to_u32(self.logical_block_len) + } +} + +const fn u24_le_to_u32(u24: [u8; 3]) -> u32 { + ((u24[0] as u32) << 16) + | ((u24[1] as u32) << 8) + | (u24[2] as u32) +} + +/// From SPC-3, when LONGLBA is set. For newer devices, `ShortLbaModeParamBlkDesc` is used instead (I +/// think). +#[repr(packed)] +#[derive(Clone, Copy)] +pub struct GeneralModeParamBlkDesc { + pub density_code: u8, + pub block_count: [u8; 3], + _rsvd: u8, + pub block_length: [u8; 3], +} +unsafe impl plain::Plain for GeneralModeParamBlkDesc {} + +impl fmt::Debug for GeneralModeParamBlkDesc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("GeneralModeParamBlkDesc") + .field("density_code", &self.density_code) + .field("block_count", &u24_le_to_u32(self.block_count)) + .field("block_length", &u24_le_to_u32(self.block_length)) + .finish() + } +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct LongLbaModeParamBlkDesc { + pub block_count: u64, + _rsvd: u32, + pub logical_block_len: u32, +} +unsafe impl plain::Plain for LongLbaModeParamBlkDesc {} + +impl LongLbaModeParamBlkDesc { + pub const fn block_count(&self) -> u64 { + u64::from_le(self.block_count) + } + pub const fn logical_block_len(&self) -> u32 { + u32::from_le(self.logical_block_len) + } +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct ModeParamHeader6 { + pub mode_data_len: u8, + pub medium_ty: u8, + pub a: u8, + pub block_desc_len: u8, +} +unsafe impl plain::Plain for ModeParamHeader6 {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct ModeParamHeader10 { + pub mode_data_len: u16, + pub medium_ty: u8, + pub a: u8, + pub b: u8, + _rsvd: u8, + pub block_desc_len: u16, +} +unsafe impl plain::Plain for ModeParamHeader10 {} +impl ModeParamHeader10 { + pub const fn mode_data_len(&self) -> u16 { + u16::from_le(self.mode_data_len) + } + pub const fn block_desc_len(&self) -> u16 { + u16::from_le(self.block_desc_len) + } + pub const fn longlba(&self) -> bool { + (self.b & 0x01) != 0 + } +} diff --git a/usbscsid/src/scsi/mod.rs b/usbscsid/src/scsi/mod.rs index 1b01389e80..7254dcb7a1 100644 --- a/usbscsid/src/scsi/mod.rs +++ b/usbscsid/src/scsi/mod.rs @@ -1,6 +1,178 @@ +use std::mem; + pub mod cmds; pub mod opcodes; +use thiserror::Error; +use xhcid_interface::DeviceReqData; + +use crate::protocol::{Protocol, ProtocolError, SendCommandStatus}; +use cmds::{SenseKey, StandardInquiryData}; +use opcodes::Opcode; pub struct Scsi { + command_buffer: [u8; 16], + inquiry_buffer: [u8; 259], + data_buffer: Vec, +} + +const INQUIRY_CMD_LEN: u8 = 6; +const REPORT_SUPP_OPCODES_CMD_LEN: u8 = 12; +const REQUEST_SENSE_CMD_LEN: u8 = 6; +const MIN_INQUIRY_ALLOC_LEN: u16 = 5; +const MIN_REPORT_SUPP_OPCODES_ALLOC_LEN: u32 = 4; + +#[derive(Debug, Error)] +pub enum ScsiError { + #[error("protocol error when sending command: {0}")] + ProtocolError(#[from] ProtocolError), +} + +impl Scsi { + pub fn new(protocol: &mut dyn Protocol) -> Self { + assert_eq!(std::mem::size_of::(), 96); + let mut this = Self { + command_buffer: [0u8; 16], + inquiry_buffer: [0u8; 259], // additional_len = 255 max + data_buffer: Vec::new(), + }; + + // Get the max length that the device supports, of the Standard Inquiry Data. + let max_inquiry_len = this.get_inquiry_alloc_len(protocol); + // Get the Standard Inquiry Data. + this.get_standard_inquiry_data(protocol, max_inquiry_len); + this.res_standard_inquiry_data(); + + dbg!(this.get_mode_sense10(protocol).unwrap()); + + this + } + pub fn get_inquiry_alloc_len(&mut self, protocol: &mut dyn Protocol) -> u16 { + self.get_standard_inquiry_data(protocol, MIN_INQUIRY_ALLOC_LEN); + let standard_inquiry_data = self.res_standard_inquiry_data(); + 4 + u16::from(standard_inquiry_data.additional_len) + } + pub fn get_standard_inquiry_data(&mut self, protocol: &mut dyn Protocol, max_inquiry_len: u16) { + let inquiry = self.cmd_inquiry(); + *inquiry = cmds::Inquiry::new(false, 0, max_inquiry_len, 0); + + protocol.send_command(&self.command_buffer[..INQUIRY_CMD_LEN as usize], DeviceReqData::In(&mut self.inquiry_buffer[..max_inquiry_len as usize])).expect("Failed to send INQUIRY command"); + } + /*/// Similar to `check_supp_opcode_sized`, but simply checks whether the opcode is supported, + /// without fetching any actual data. + pub fn check_supp_opcode(&mut self, protocol: &mut dyn Protocol, opcode: Opcode, sa: Option) -> Result { + self.check_supp_opcode_sized(protocol, opcode, sa, 2) + } + pub fn check_supp_opcode_sized(&mut self, protocol: &mut dyn Protocol, opcode: Opcode, sa: Option, alloc_len: u32) -> Result { + let report_supp_opcodes = self.cmd_report_supp_opcodes(); + *report_supp_opcodes = if let Some(serviceaction) = sa { + cmds::ReportSuppOpcodes::get_supp(false, opcode, serviceaction, alloc_len, 0) + } else { + cmds::ReportSuppOpcodes::get_supp_no_sa(false, opcode, alloc_len, 0) + }; + self.data_buffer.resize(std::mem::size_of::(), 0); + protocol.send_command(&self.command_buffer[..REPORT_SUPP_OPCODES_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize]))?; + Ok(self.res_one_command().support() == cmds::OneCommandParamSupport::Supported) + }*/ + + /*pub fn get_supp_opcodes_alloc_len(&mut self, protocol: &mut dyn Protocol) -> u32 { + self.get_supp_opcodes(protocol, MIN_REPORT_SUPP_OPCODES_ALLOC_LEN); + self.res_all_commands().alloc_len() + }*/ + /*pub fn get_supp_opcodes(&mut self, protocol: &mut dyn Protocol, alloc_len: u32) { + let report_supp_opcodes = self.cmd_report_supp_opcodes(); + *report_supp_opcodes = cmds::ReportSuppOpcodes::get_all(false, alloc_len, 0); + self.data_buffer.resize(alloc_len as usize, 0); + let status = protocol.send_command(&self.command_buffer[..REPORT_SUPP_OPCODES_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize])).expect("Failed to send REPORT_SUPP_OPCODES command"); + if status != SendCommandStatus::Success { + self.get_ff_sense(protocol, cmds::RequestSense::MINIMAL_ALLOC_LEN); + let data = self.res_ff_sense_data(); + if data.sense_key() == SenseKey::IllegalRequest && data.add_sense_code == cmds::ADD_SENSE_CODE05_INVAL_CDB_FIELD { + } + } + }*/ + pub fn get_ff_sense(&mut self, protocol: &mut dyn Protocol, alloc_len: u8) { + let request_sense = self.cmd_request_sense(); + *request_sense = cmds::RequestSense::new(false, alloc_len, 0); + self.data_buffer.resize(alloc_len.into(), 0); + protocol.send_command(&self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize])).expect("Failed to send REQUEST_SENSE command"); + } + pub fn get_mode_sense10(&mut self, protocol: &mut dyn Protocol) -> Result<(&cmds::ModeParamHeader10, BlkDescSlice), ScsiError> { + let initial_alloc_len = 4; // covers both mode_data_len and blk_desc_len. + let mode_sense10 = self.cmd_mode_sense10(); + *mode_sense10 = cmds::ModeSense10::get_block_desc(initial_alloc_len, 0); + self.data_buffer.resize(mem::size_of::(), 0); + if let SendCommandStatus::Failed { .. } = protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..initial_alloc_len as usize]))? { + self.get_ff_sense(protocol, 252); + panic!("{:?}", self.res_ff_sense_data()); + } + + let optimal_alloc_len = self.res_mode_param_header10().block_desc_len() + self.res_mode_param_header10().mode_data_len() + mem::size_of::() as u16; + + let mode_sense10 = self.cmd_mode_sense10(); + *mode_sense10 = cmds::ModeSense10::get_block_desc(optimal_alloc_len, 0); + self.data_buffer.resize(optimal_alloc_len as usize, 0); + protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..optimal_alloc_len as usize]))?; + Ok((self.res_mode_param_header10(), self.res_blkdesc_mode10())) + } + + pub fn cmd_inquiry(&mut self) -> &mut cmds::Inquiry { + plain::from_mut_bytes(&mut self.command_buffer).unwrap() + } + pub fn cmd_mode_sense6(&mut self) -> &mut cmds::ModeSense6 { + plain::from_mut_bytes(&mut self.command_buffer).unwrap() + } + pub fn cmd_mode_sense10(&mut self) -> &mut cmds::ModeSense10 { + plain::from_mut_bytes(&mut self.command_buffer).unwrap() + } + /*pub fn cmd_report_supp_opcodes(&mut self) -> &mut cmds::ReportSuppOpcodes { + plain::from_mut_bytes(&mut self.command_buffer).unwrap() + }*/ + pub fn cmd_request_sense(&mut self) -> &mut cmds::RequestSense { + plain::from_mut_bytes(&mut self.command_buffer).unwrap() + } + pub fn res_standard_inquiry_data(&self) -> &StandardInquiryData { + plain::from_bytes(&self.inquiry_buffer).unwrap() + } + /* + pub fn res_all_commands(&self) -> &cmds::AllCommandsParam { + plain::from_bytes(&self.data_buffer).unwrap() + } + pub fn res_one_command(&self) -> &cmds::OneCommandParam { + plain::from_bytes(&self.data_buffer).unwrap() + }*/ + pub fn res_ff_sense_data(&self) -> &cmds::FixedFormatSenseData { + plain::from_bytes(&self.data_buffer).unwrap() + } + pub fn res_mode_param_header6(&self) -> &cmds::ModeParamHeader6 { + plain::from_bytes(&self.data_buffer).unwrap() + } + pub fn res_mode_param_header10(&self) -> &cmds::ModeParamHeader10 { + plain::from_bytes(&self.data_buffer).unwrap() + } + pub fn res_blkdesc_mode6(&self) -> &[cmds::ShortLbaModeParamBlkDesc] { + let header = self.res_mode_param_header6(); + let descs_start = mem::size_of::(); + plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap() + } + pub fn res_blkdesc_mode10(&self) -> BlkDescSlice { + let header = self.res_mode_param_header10(); + let descs_start = mem::size_of::(); + println!("MODE_SENSE PAGES: {}", base64::encode(&self.data_buffer[descs_start + header.block_desc_len() as usize..])); + if header.longlba() { + BlkDescSlice::Long(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap()) + } else { + //BlkDescSlice::Short(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap()) + BlkDescSlice::General(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap()) + } + } + pub fn get_disk_size(&mut self) -> u64 { + todo!() + } +} +#[derive(Debug)] +pub enum BlkDescSlice<'a> { + //Short(&'a [cmds::ShortLbaModeParamBlkDesc]), + General(&'a [cmds::GeneralModeParamBlkDesc]), + Long(&'a [cmds::LongLbaModeParamBlkDesc]), } From d44296dec9f43b0d710befe9dbb74a562e3e388d Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 14 Feb 2020 18:38:24 +0100 Subject: [PATCH 0345/1301] Almost successfully read blocks using SCSI. --- usbscsid/src/main.rs | 5 +- usbscsid/src/protocol/bot.rs | 17 +- usbscsid/src/protocol/mod.rs | 24 +- usbscsid/src/scheme.rs | 59 ++++- usbscsid/src/scsi/cmds.rs | 349 +++++++++++-------------- usbscsid/src/scsi/mod.rs | 134 ++++++---- xhcid/src/xhci/mod.rs | 92 ++----- xhcid/src/xhci/scheme.rs | 489 +++++++++++++++++------------------ xhcid/src/xhci/trb.rs | 12 + 9 files changed, 585 insertions(+), 596 deletions(-) diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index 82a5529ccd..932c57af8b 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -64,7 +64,10 @@ fn main() { //syscall::setrens(0, 0).expect("scsid: failed to enter null namespace"); let mut scsi = Scsi::new(&mut *protocol); - let mut scsi_scheme = ScsiScheme::new(&mut scsi); + let mut buffer = [0u8; 512]; + scsi.read(&mut *protocol, 0, &mut buffer).unwrap(); + println!("DISK CONTENT: {}", base64::encode(&buffer[..])); + let mut scsi_scheme = ScsiScheme::new(&mut scsi, &mut *protocol); // TODO: Use nonblocking and put all pending calls in a todo VecDeque. Use an eventfd as well. 'scheme_loop: loop { diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index 0aafe80aeb..13ab6a784f 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -3,7 +3,7 @@ use std::slice; use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpHandle}; -use super::{Protocol, ProtocolError, SendCommandStatus}; +use super::{Protocol, ProtocolError, SendCommandStatus, SendCommandStatusKind}; pub const CBW_SIGNATURE: u32 = 0x43425355; @@ -206,12 +206,15 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } - Ok(if csw.status == CswStatus::Passed as u8 { - SendCommandStatus::Success - } else if csw.status == CswStatus::Failed as u8 { - SendCommandStatus::Failed { residue: NonZeroU32::new(csw.data_residue) } - } else { - return Err(ProtocolError::ProtocolError("bulk-only transport phase error, or other")); + Ok(SendCommandStatus { + kind: if csw.status == CswStatus::Passed as u8 { + SendCommandStatusKind::Success + } else if csw.status == CswStatus::Failed as u8 { + SendCommandStatusKind::Failed + } else { + return Err(ProtocolError::ProtocolError("bulk-only transport phase error, or other")); + }, + residue: NonZeroU32::new(csw.data_residue), }) } } diff --git a/usbscsid/src/protocol/mod.rs b/usbscsid/src/protocol/mod.rs index 2ffe4e5d83..7315ab9805 100644 --- a/usbscsid/src/protocol/mod.rs +++ b/usbscsid/src/protocol/mod.rs @@ -22,12 +22,26 @@ pub enum ProtocolError { ProtocolError(&'static str), } -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum SendCommandStatus { - Success, - Failed { residue: Option }, +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)] +pub struct SendCommandStatus { + pub residue: Option, + pub kind: SendCommandStatusKind, } -impl Default for SendCommandStatus { + +impl SendCommandStatus { + pub fn bytes_transferred(&self, transfer_len: u32) -> u32 { + transfer_len - self.residue.map(u32::from).unwrap_or(0) + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum SendCommandStatusKind { + Success, + Failed, +} + + +impl Default for SendCommandStatusKind { fn default() -> Self { Self::Success } diff --git a/usbscsid/src/scheme.rs b/usbscsid/src/scheme.rs index 46d1a18393..0c88ba6177 100644 --- a/usbscsid/src/scheme.rs +++ b/usbscsid/src/scheme.rs @@ -1,16 +1,18 @@ use std::collections::BTreeMap; -use std::str; +use std::{cmp, str}; +use crate::protocol::Protocol; use crate::scsi::Scsi; use syscall::SchemeMut; use syscall::error::{Error, Result}; -use syscall::error::{EACCES, EBADF, ENOENT, ENOSYS}; +use syscall::error::{EACCES, EBADF, EINVAL, EIO, ENOENT, ENOSYS}; use syscall::flag::{O_DIRECTORY, O_STAT}; use syscall::flag::{MODE_CHR, MODE_DIR}; +use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET}; // TODO: Only one disk, right? -const LIST_CONTENTS: &'static [u8] = b"disk\n"; +const LIST_CONTENTS: &'static [u8] = b"0\n"; enum Handle { List(usize), @@ -20,14 +22,16 @@ enum Handle { pub struct ScsiScheme<'a> { scsi: &'a mut Scsi, + protocol: &'a mut Protocol, handles: BTreeMap, next_fd: usize, } impl<'a> ScsiScheme<'a> { - pub fn new(scsi: &'a mut Scsi) -> Self { + pub fn new(scsi: &'a mut Scsi, protocol: &'a mut dyn Protocol) -> Self { Self { scsi, + protocol, handles: BTreeMap::new(), next_fd: 0, } @@ -58,12 +62,12 @@ impl<'a> SchemeMut for ScsiScheme<'a> { Handle::Disk(_) => { stat.st_mode = MODE_CHR; stat.st_size = self.scsi.get_disk_size(); - // TODO: stat.st_blocks + stat.st_blksize = self.scsi.block_size; + stat.st_blocks = self.scsi.block_count; } Handle::List(_) => { stat.st_mode = MODE_DIR; stat.st_size = LIST_CONTENTS.len() as u64; - // TODO: stat.st_blocks } } Err(Error::new(ENOSYS)) @@ -72,10 +76,49 @@ impl<'a> SchemeMut for ScsiScheme<'a> { Err(Error::new(ENOSYS)) } fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { - Err(Error::new(ENOSYS)) + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::Disk(ref mut offset) => { + let len = self.scsi.get_disk_size() as usize; + *offset = match whence { + SEEK_SET => cmp::max(0, cmp::min(pos, len)), + SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, len)), + SEEK_END => cmp::max(0, cmp::min(len + pos, len)), + _ => return Err(Error::new(EINVAL)), + }; + Ok(*offset) + } + Handle::List(ref mut offset) => { + let len = LIST_CONTENTS.len(); + *offset = match whence { + SEEK_SET => cmp::max(0, cmp::min(pos, len)), + SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, len)), + SEEK_END => cmp::max(0, cmp::min(len + pos, len)), + _ => return Err(Error::new(EINVAL)), + }; + Ok(*offset) + } + } } fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { - Err(Error::new(ENOSYS)) + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::Disk(ref mut offset) => { + if *offset as u64 % u64::from(self.scsi.block_size) != 0 || buf.len() as u64 % u64::from(self.scsi.block_size) != 0 { + return Err(Error::new(EINVAL)); + } + let lba = *offset as u64 / u64::from(self.scsi.block_size); + let bytes_read = self.scsi.read(self.protocol, lba, buf).map_err(|err| dbg!(err)).or(Err(Error::new(EIO)))?; + Ok(bytes_read as usize) + } + Handle::List(ref mut offset) => { + let max_bytes_to_read = cmp::min(LIST_CONTENTS.len(), buf.len()); + let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset; + + buf[..bytes_to_read].copy_from_slice(&LIST_CONTENTS[..bytes_to_read]); + *offset += bytes_to_read; + + Ok(bytes_to_read) + } + } } fn write(&mut self, fd: usize, buf: &[u8]) -> Result { Err(Error::new(ENOSYS)) diff --git a/usbscsid/src/scsi/cmds.rs b/usbscsid/src/scsi/cmds.rs index 98c6006a86..31949566bd 100644 --- a/usbscsid/src/scsi/cmds.rs +++ b/usbscsid/src/scsi/cmds.rs @@ -1,187 +1,5 @@ use std::{fmt, mem, slice}; -use super::opcodes::{Opcode, ServiceActionA3}; - -#[repr(packed)] -pub struct ReportIdentInfo { - pub opcode: u8, - /// bits 7:5 reserved - pub serviceaction: u8, - pub _rsvd: u16, - pub restricted: u16, - /// little endian - pub alloc_len: u32, - /// bit 0 reserved - pub info_ty: u8, - pub control: u8, -} -unsafe impl plain::Plain for ReportIdentInfo {} - -impl ReportIdentInfo { - pub const fn new(alloc_len: u32, info_ty: ReportIdInfoInfoTy, control: u8) -> Self { - Self { - opcode: Opcode::ServiceActionA3 as u8, - serviceaction: ServiceActionA3::ReportIdentInfo as u8, - _rsvd: 0, - restricted: 0, - alloc_len: u32::to_le(alloc_len), - info_ty: (info_ty as u8) << REP_ID_INFO_INFO_TY_SHIFT, - control, - } - } -} -#[repr(u8)] -pub enum ReportIdInfoInfoTy { - PeripheralDevIdInfo = 0b000_0000, - PeripheralDevTextIdInfo = 0b000_0010, - IdentInfoSupp = 0b111_1111, - // every other number ending with a 1 is restricted -} - -pub const REP_ID_INFO_INFO_TY_MASK: u8 = 0xFE; -pub const REP_ID_INFO_INFO_TY_SHIFT: u8 = 1; - -#[repr(packed)] -pub struct ReportSuppOpcodes { - pub opcode: u8, - /// bits 7:5 reserved - pub serviceaction: u8, - /// bits 2:0 represent "REPORTING OPTIONS", bits 6:3 are reserved, and bit 7 is RCTD - pub rep_opts: u8, - pub req_opcode: u8, - /// little endian - pub req_serviceaction: u16, - /// little endian - pub alloc_len: u32, - pub _rsvd: u8, - pub control: u8, -} -unsafe impl plain::Plain for ReportSuppOpcodes {} - -impl ReportSuppOpcodes { - pub const fn new(rep_opts: ReportSuppOpcodesOptions, rctd: bool, req_opcode: u8, req_serviceaction: u16, alloc_len: u32, control: u8) -> Self { - Self { - opcode: Opcode::ServiceActionA3 as u8, - serviceaction: ServiceActionA3::ReportSuppOpcodes as u8, - rep_opts: ((rctd as u8) << REP_OPTS_RCTD_SHIFT) | rep_opts as u8, - req_opcode, - req_serviceaction: u16::to_le(req_serviceaction), - alloc_len: u32::to_le(alloc_len), - _rsvd: 0, - control, - } - } - pub const fn get_all(rctd: bool, alloc_len: u32, control: u8) -> Self { - Self::new(ReportSuppOpcodesOptions::ListAll, rctd, 0, 0, alloc_len, control) - } - pub const fn get_supp_no_sa(rctd: bool, opcode: Opcode, alloc_len: u32, control: u8) -> Self { - Self::new(ReportSuppOpcodesOptions::NoServicaction, rctd, opcode as u8, 0, alloc_len, control) - } - pub const fn get_supp(rctd: bool, opcode: Opcode, serviceaction: u16, alloc_len: u32, control: u8) -> Self { - Self::new(ReportSuppOpcodesOptions::ExplicitBoth, rctd, opcode as u8, serviceaction, alloc_len, control) - } -} - -pub const REP_OPTS_MAIN_MASK: u8 = 0b0000_0111; -pub const REP_OPTS_MAIN_SHIFT: u8 = 0; -pub const REP_OPTS_RCTD_BIT: u8 = 1 << REP_OPTS_RCTD_SHIFT; -pub const REP_OPTS_RCTD_SHIFT: u8 = 7; - -/// Valid values of the `req_opts` field of `ReportSuppOpcodes`. -#[repr(u8)] -pub enum ReportSuppOpcodesOptions { - /// Returns all commands, no matter what parameters are set. - ListAll, - - /// Returns one command with the requested opcode. If the command has service actions, this - /// command fails. - NoServicaction, - - /// Returns one command with the requested opcode and service action. If the command doesn't - /// support service actions, this command fails. - ExplicitBoth, - - /// Returns one command with the requested opcode and service action. The command may or may - /// not implement service actions, but if it does, it has to be correct for the return value to - /// indicate SUPPORTED. - /// - /// This option seems to be reserved for SPC-3 (inquiry version value of 5). - IndicateSupport, - -} - -#[repr(packed)] -pub struct AllCommandsParam { - /// Little endian - pub data_len: u32, - pub descs: [CommandDescriptor; 0], -} - -impl AllCommandsParam { - pub const fn alloc_len(&self) -> u32 { - 3 + u32::from_le(self.data_len) - } - pub unsafe fn descs(&self) -> &[CommandDescriptor] { - assert_eq!(mem::size_of::(), 20); - slice::from_raw_parts(&self.descs as *const CommandDescriptor, (self.alloc_len() as usize - 4) / mem::size_of::()) - } -} - -unsafe impl plain::Plain for AllCommandsParam {} - -#[repr(packed)] -#[derive(Clone, Copy, Debug)] -pub struct CommandDescriptor { - pub opcode: u8, - pub _rsvd1: u8, - /// little endian - pub serviceaction: u16, - pub _rsvd2: u8, - /// bit 0 is SERVACTV, bit 1 is CTDP, and bits 7:2 reserved - pub a: u8, - /// little endian - pub cdb_len: u16, - pub cmd_timeouts_desc: [u8; 12], -} - -#[repr(packed)] -pub struct OneCommandParam { - pub _rsvd: u8, - pub a: u8, - pub cdb_size: u16, - pub usage_data: [u8; 0], -} -unsafe impl plain::Plain for OneCommandParam {} - -impl OneCommandParam { - pub const fn ctdp(&self) -> bool { - self.a & (1 << 7) != 0 - } - pub fn support(&self) -> OneCommandParamSupport { - let raw = self.a & 0b111; - // Safe because all possible values are covered by the enum. - unsafe { mem::transmute(raw) } - } - pub const fn total_len(&self) -> u16 { - self.cdb_size as u16 + 3 - } - /// Unsafe because the reference to self has to be valid for an additional (self.cdb_size - 1) bytes. - pub unsafe fn cdb_usage_data(&self) -> &[u8] { - slice::from_raw_parts(&self.usage_data as *const u8, self.total_len() as usize - 4) - } -} - -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum OneCommandParamSupport { - NoDataAvail = 0b000, - NotSupported = 0b001, - Rsvd2 = 0b010, - Supported = 0b011, - Rsvd4 = 0b100, - SupportedVendor = 0b101, - Rsvd6 = 0b110, - Rsvd7 = 0b111, -} +use super::opcodes::Opcode; #[repr(packed)] pub struct Inquiry { @@ -189,7 +7,7 @@ pub struct Inquiry { /// bits 7:2 are reserved, bit 1 (CMDDT) is obsolete, bit 0 is EVPD pub evpd: u8, pub page_code: u8, - /// little endian + /// big endian pub alloc_len: u16, pub control: u8, } @@ -201,7 +19,7 @@ impl Inquiry { opcode: Opcode::Inquiry as u8, evpd: evpd as u8, page_code, - alloc_len: u16::to_le(alloc_len), + alloc_len: u16::to_be(alloc_len), control, } } @@ -231,6 +49,33 @@ pub struct StandardInquiryData { _rsvd2: [u8; 22], } unsafe impl plain::Plain for StandardInquiryData {} +impl StandardInquiryData { + pub const fn periph_dev_ty(&self) -> u8 { + self.a & 0x1F + } + pub const fn periph_dev_qual(&self) -> u8 { + (self.a & 0xE0) >> 5 + } + pub const fn version(&self) -> u8 { + self.version + } +} + +#[repr(u8)] +pub enum PeriphDeviceType { + DirectAccess, + SeqAccess, + // there are more +} +#[repr(u8)] +pub enum InquiryVersion { + NoConformance, + Spc, + Spc2, + Spc3, + Spc4, + Spc5, +} #[repr(packed)] #[derive(Clone, Copy, Debug)] @@ -269,7 +114,7 @@ pub struct FixedFormatSenseData { pub add_sense_code: u8, pub add_sense_code_qual: u8, pub field_replacable_unit_code: u8, - pub sense_key_specific: [u8; 3], // little endian + pub sense_key_specific: [u8; 3], // big endian pub add_sense_bytes: [u8; 0], } unsafe impl plain::Plain for FixedFormatSenseData {} @@ -326,6 +171,7 @@ pub struct Read16 { pub b: u8, pub control: u8, } +unsafe impl plain::Plain for Read16 {} impl Read16 { pub const fn new(lba: u64, transfer_len: u32, control: u8) -> Self { @@ -335,8 +181,8 @@ impl Read16 { Self { opcode: Opcode::Read16 as u8, a: 0, - lba: u64::to_le(lba), - transfer_len: u32::to_le(transfer_len), + lba: u64::to_be(lba), + transfer_len: u32::to_be(transfer_len), b: 0, control, } @@ -389,7 +235,7 @@ impl ModeSense10 { b: page_code | ((pc as u8) << 6), subpage_code, _rsvd: [0u8; 3], - alloc_len: u16::from_le(alloc_len), + alloc_len: u16::from_be(alloc_len), control, } } @@ -407,7 +253,7 @@ pub enum ModePageControl { } #[repr(packed)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] pub struct ShortLbaModeParamBlkDesc { pub block_count: u32, _rsvd: u8, @@ -417,21 +263,28 @@ unsafe impl plain::Plain for ShortLbaModeParamBlkDesc {} impl ShortLbaModeParamBlkDesc { pub const fn block_count(&self) -> u32 { - u32::from_le(self.block_count) + u32::from_be(self.block_count) } pub const fn logical_block_len(&self) -> u32 { - u24_le_to_u32(self.logical_block_len) + u24_be_to_u32(self.logical_block_len) + } +} +impl fmt::Debug for ShortLbaModeParamBlkDesc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ShortLbaModeParamBlkDesc") + .field("block_count", &self.block_count()) + .field("logical_block_len", &self.logical_block_len()) + .finish() } } -const fn u24_le_to_u32(u24: [u8; 3]) -> u32 { +const fn u24_be_to_u32(u24: [u8; 3]) -> u32 { ((u24[0] as u32) << 16) | ((u24[1] as u32) << 8) | (u24[2] as u32) } -/// From SPC-3, when LONGLBA is set. For newer devices, `ShortLbaModeParamBlkDesc` is used instead (I -/// think). +/// From SPC-3, when LONGLBA is not set, and the peripheral device type of the INQUIRY data indicates that the device is not a direct access device. Otherwise, `ShortLbaModeParamBlkDesc` is used instead. #[repr(packed)] #[derive(Clone, Copy)] pub struct GeneralModeParamBlkDesc { @@ -442,12 +295,21 @@ pub struct GeneralModeParamBlkDesc { } unsafe impl plain::Plain for GeneralModeParamBlkDesc {} +impl GeneralModeParamBlkDesc { + pub fn block_count(&self) -> u32 { + u24_be_to_u32(self.block_count) + } + pub fn logical_block_len(&self) -> u32 { + u24_be_to_u32(self.block_length) + } +} + impl fmt::Debug for GeneralModeParamBlkDesc { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("GeneralModeParamBlkDesc") .field("density_code", &self.density_code) - .field("block_count", &u24_le_to_u32(self.block_count)) - .field("block_length", &u24_le_to_u32(self.block_length)) + .field("block_count", &u24_be_to_u32(self.block_count)) + .field("block_length", &u24_be_to_u32(self.block_length)) .finish() } } @@ -463,10 +325,10 @@ unsafe impl plain::Plain for LongLbaModeParamBlkDesc {} impl LongLbaModeParamBlkDesc { pub const fn block_count(&self) -> u64 { - u64::from_le(self.block_count) + u64::from_be(self.block_count) } pub const fn logical_block_len(&self) -> u32 { - u32::from_le(self.logical_block_len) + u32::from_be(self.logical_block_len) } } @@ -493,12 +355,97 @@ pub struct ModeParamHeader10 { unsafe impl plain::Plain for ModeParamHeader10 {} impl ModeParamHeader10 { pub const fn mode_data_len(&self) -> u16 { - u16::from_le(self.mode_data_len) + u16::from_be(self.mode_data_len) } pub const fn block_desc_len(&self) -> u16 { - u16::from_le(self.block_desc_len) + u16::from_be(self.block_desc_len) } pub const fn longlba(&self) -> bool { (self.b & 0x01) != 0 } } + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct RwErrorRecoveryPage { + pub a: u8, + pub page_length: u8, + pub b: u8, + pub read_retry_count: u8, + _obsolete: [u8; 3], + _rsvd: u8, + pub recovery_time_limit: u16, +} +unsafe impl plain::Plain for RwErrorRecoveryPage {} + +pub(crate) struct ModePageIterRaw<'a> { + buffer: &'a [u8], +} + +impl<'a> Iterator for ModePageIterRaw<'a> { + type Item = &'a [u8]; + + fn next(&mut self) -> Option { + if self.buffer.len() < 2 { + return None; + } + + let a = self.buffer[0]; + let page_len = if a & (1 << 6) == 0 { + // item is page_0 mode + self.buffer[1] as usize + 1 + } else { + // item is sub_page mode + self.buffer[2] as usize + 3 + }; + if self.buffer.len() < page_len { + return None; + } + let buffer = &self.buffer[..page_len]; + + self.buffer = if page_len == self.buffer.len() { + &[] + } else { + &self.buffer[page_len..] + }; + + Some(buffer) + } +} + +#[derive(Clone, Copy, Debug)] +pub enum AnyModePage<'a> { + RwErrorRecovery(&'a RwErrorRecoveryPage), +} + +struct ModePageIter<'a> { + raw: ModePageIterRaw<'a>, +} + +impl<'a> Iterator for ModePageIter<'a> { + type Item = AnyModePage<'a>; + + fn next(&mut self) -> Option { + let next_buf = self.raw.next()?; + let a = next_buf[0]; + + let page_code = a & 0x1F; + let spf = a & (1 << 6) != 0; + + if !spf { + if page_code == 0x01 { + Some(AnyModePage::RwErrorRecovery(plain::from_bytes(next_buf).ok()?)) + } else { + println!("Unimplemented sub_page {}", base64::encode(next_buf)); + None + } + } else { + println!("Unimplemented page_0 {}", base64::encode(next_buf)); + None + } + } +} + +pub fn mode_page_iter(buffer: &[u8]) -> impl Iterator { + ModePageIter { raw: ModePageIterRaw { buffer } } +} diff --git a/usbscsid/src/scsi/mod.rs b/usbscsid/src/scsi/mod.rs index 7254dcb7a1..3368db7aac 100644 --- a/usbscsid/src/scsi/mod.rs +++ b/usbscsid/src/scsi/mod.rs @@ -1,4 +1,5 @@ -use std::mem; +use std::{mem, ops}; +use std::convert::TryFrom; pub mod cmds; pub mod opcodes; @@ -6,7 +7,7 @@ pub mod opcodes; use thiserror::Error; use xhcid_interface::DeviceReqData; -use crate::protocol::{Protocol, ProtocolError, SendCommandStatus}; +use crate::protocol::{Protocol, ProtocolError, SendCommandStatus, SendCommandStatusKind}; use cmds::{SenseKey, StandardInquiryData}; use opcodes::Opcode; @@ -14,6 +15,8 @@ pub struct Scsi { command_buffer: [u8; 16], inquiry_buffer: [u8; 259], data_buffer: Vec, + pub block_size: u32, + pub block_count: u64, } const INQUIRY_CMD_LEN: u8 = 6; @@ -35,6 +38,8 @@ impl Scsi { command_buffer: [0u8; 16], inquiry_buffer: [0u8; 259], // additional_len = 255 max data_buffer: Vec::new(), + block_size: 0, + block_count: 0, }; // Get the max length that the device supports, of the Standard Inquiry Data. @@ -43,7 +48,16 @@ impl Scsi { this.get_standard_inquiry_data(protocol, max_inquiry_len); this.res_standard_inquiry_data(); - dbg!(this.get_mode_sense10(protocol).unwrap()); + let (block_size, block_count) = { + let (_, blkdescs, mode_page_iter) = this.get_mode_sense10(protocol).unwrap(); + + // TODO: Can there be multiple disks at all? + let only_blkdesc = blkdescs.get(0).unwrap(); + (only_blkdesc.block_size(), only_blkdesc.block_count()) + }; + + this.block_size = block_size; + this.block_count = block_count; this } @@ -58,51 +72,18 @@ impl Scsi { protocol.send_command(&self.command_buffer[..INQUIRY_CMD_LEN as usize], DeviceReqData::In(&mut self.inquiry_buffer[..max_inquiry_len as usize])).expect("Failed to send INQUIRY command"); } - /*/// Similar to `check_supp_opcode_sized`, but simply checks whether the opcode is supported, - /// without fetching any actual data. - pub fn check_supp_opcode(&mut self, protocol: &mut dyn Protocol, opcode: Opcode, sa: Option) -> Result { - self.check_supp_opcode_sized(protocol, opcode, sa, 2) - } - pub fn check_supp_opcode_sized(&mut self, protocol: &mut dyn Protocol, opcode: Opcode, sa: Option, alloc_len: u32) -> Result { - let report_supp_opcodes = self.cmd_report_supp_opcodes(); - *report_supp_opcodes = if let Some(serviceaction) = sa { - cmds::ReportSuppOpcodes::get_supp(false, opcode, serviceaction, alloc_len, 0) - } else { - cmds::ReportSuppOpcodes::get_supp_no_sa(false, opcode, alloc_len, 0) - }; - self.data_buffer.resize(std::mem::size_of::(), 0); - protocol.send_command(&self.command_buffer[..REPORT_SUPP_OPCODES_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize]))?; - Ok(self.res_one_command().support() == cmds::OneCommandParamSupport::Supported) - }*/ - - /*pub fn get_supp_opcodes_alloc_len(&mut self, protocol: &mut dyn Protocol) -> u32 { - self.get_supp_opcodes(protocol, MIN_REPORT_SUPP_OPCODES_ALLOC_LEN); - self.res_all_commands().alloc_len() - }*/ - /*pub fn get_supp_opcodes(&mut self, protocol: &mut dyn Protocol, alloc_len: u32) { - let report_supp_opcodes = self.cmd_report_supp_opcodes(); - *report_supp_opcodes = cmds::ReportSuppOpcodes::get_all(false, alloc_len, 0); - self.data_buffer.resize(alloc_len as usize, 0); - let status = protocol.send_command(&self.command_buffer[..REPORT_SUPP_OPCODES_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize])).expect("Failed to send REPORT_SUPP_OPCODES command"); - if status != SendCommandStatus::Success { - self.get_ff_sense(protocol, cmds::RequestSense::MINIMAL_ALLOC_LEN); - let data = self.res_ff_sense_data(); - if data.sense_key() == SenseKey::IllegalRequest && data.add_sense_code == cmds::ADD_SENSE_CODE05_INVAL_CDB_FIELD { - } - } - }*/ pub fn get_ff_sense(&mut self, protocol: &mut dyn Protocol, alloc_len: u8) { let request_sense = self.cmd_request_sense(); *request_sense = cmds::RequestSense::new(false, alloc_len, 0); self.data_buffer.resize(alloc_len.into(), 0); protocol.send_command(&self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize])).expect("Failed to send REQUEST_SENSE command"); } - pub fn get_mode_sense10(&mut self, protocol: &mut dyn Protocol) -> Result<(&cmds::ModeParamHeader10, BlkDescSlice), ScsiError> { + pub fn get_mode_sense10(&mut self, protocol: &mut dyn Protocol) -> Result<(&cmds::ModeParamHeader10, BlkDescSlice, impl Iterator), ScsiError> { let initial_alloc_len = 4; // covers both mode_data_len and blk_desc_len. let mode_sense10 = self.cmd_mode_sense10(); *mode_sense10 = cmds::ModeSense10::get_block_desc(initial_alloc_len, 0); self.data_buffer.resize(mem::size_of::(), 0); - if let SendCommandStatus::Failed { .. } = protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..initial_alloc_len as usize]))? { + if let SendCommandStatus { kind: SendCommandStatusKind::Failed, .. } = protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..initial_alloc_len as usize]))? { self.get_ff_sense(protocol, 252); panic!("{:?}", self.res_ff_sense_data()); } @@ -113,7 +94,7 @@ impl Scsi { *mode_sense10 = cmds::ModeSense10::get_block_desc(optimal_alloc_len, 0); self.data_buffer.resize(optimal_alloc_len as usize, 0); protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..optimal_alloc_len as usize]))?; - Ok((self.res_mode_param_header10(), self.res_blkdesc_mode10())) + Ok((self.res_mode_param_header10(), self.res_blkdesc_mode10(), self.res_mode_pages10())) } pub fn cmd_inquiry(&mut self) -> &mut cmds::Inquiry { @@ -125,22 +106,15 @@ impl Scsi { pub fn cmd_mode_sense10(&mut self) -> &mut cmds::ModeSense10 { plain::from_mut_bytes(&mut self.command_buffer).unwrap() } - /*pub fn cmd_report_supp_opcodes(&mut self) -> &mut cmds::ReportSuppOpcodes { - plain::from_mut_bytes(&mut self.command_buffer).unwrap() - }*/ pub fn cmd_request_sense(&mut self) -> &mut cmds::RequestSense { plain::from_mut_bytes(&mut self.command_buffer).unwrap() } + pub fn cmd_read16(&mut self) -> &mut cmds::Read16 { + plain::from_mut_bytes(&mut self.command_buffer).unwrap() + } pub fn res_standard_inquiry_data(&self) -> &StandardInquiryData { plain::from_bytes(&self.inquiry_buffer).unwrap() } - /* - pub fn res_all_commands(&self) -> &cmds::AllCommandsParam { - plain::from_bytes(&self.data_buffer).unwrap() - } - pub fn res_one_command(&self) -> &cmds::OneCommandParam { - plain::from_bytes(&self.data_buffer).unwrap() - }*/ pub fn res_ff_sense_data(&self) -> &cmds::FixedFormatSenseData { plain::from_bytes(&self.data_buffer).unwrap() } @@ -158,21 +132,71 @@ impl Scsi { pub fn res_blkdesc_mode10(&self) -> BlkDescSlice { let header = self.res_mode_param_header10(); let descs_start = mem::size_of::(); - println!("MODE_SENSE PAGES: {}", base64::encode(&self.data_buffer[descs_start + header.block_desc_len() as usize..])); if header.longlba() { - BlkDescSlice::Long(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap()) + BlkDescSlice::Long(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap()) + } else if self.res_standard_inquiry_data().periph_dev_ty() != cmds::PeriphDeviceType::DirectAccess as u8 && self.res_standard_inquiry_data().version() == cmds::InquiryVersion::Spc3 as u8 { + BlkDescSlice::General(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap()) } else { - //BlkDescSlice::Short(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap()) - BlkDescSlice::General(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap()) + BlkDescSlice::Short(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap()) } } + + pub fn res_mode_pages10(&self) -> impl Iterator { + let header = self.res_mode_param_header10(); + let descs_start = mem::size_of::(); + let buffer = &self.data_buffer[descs_start + header.block_desc_len() as usize..]; + cmds::mode_page_iter(buffer) + } pub fn get_disk_size(&mut self) -> u64 { - todo!() + self.block_count * u64::from(self.block_size) + } + pub fn read(&mut self, protocol: &mut dyn Protocol, lba: u64, buffer: &mut [u8]) -> Result { + let blocks_to_read = buffer.len() as u64 / u64::from(self.block_size); + let transfer_len = u32::try_from(blocks_to_read * u64::from(self.block_size)).ok().unwrap_or(std::u32::MAX); + { + let read = self.cmd_read16(); + *read = cmds::Read16::new(lba, transfer_len, 0); + } + let status = protocol.send_command(&self.command_buffer[..16], DeviceReqData::In(&mut buffer[..transfer_len as usize]))?; + Ok(status.bytes_transferred(transfer_len)) } } #[derive(Debug)] pub enum BlkDescSlice<'a> { - //Short(&'a [cmds::ShortLbaModeParamBlkDesc]), + Short(&'a [cmds::ShortLbaModeParamBlkDesc]), General(&'a [cmds::GeneralModeParamBlkDesc]), Long(&'a [cmds::LongLbaModeParamBlkDesc]), } + +#[derive(Debug)] +pub enum BlkDesc<'a> { + Short(&'a cmds::ShortLbaModeParamBlkDesc), + General(&'a cmds::GeneralModeParamBlkDesc), + Long(&'a cmds::LongLbaModeParamBlkDesc), +} +impl<'a> BlkDesc<'a> { + fn block_size(&self) -> u32 { + match self { + Self::Short(s) => s.logical_block_len(), + Self::General(g) => g.logical_block_len(), + Self::Long(l) => l.logical_block_len(), + } + } + fn block_count(&self) -> u64 { + match self { + Self::Short(s) => s.block_count().into(), + Self::General(g) => g.block_count().into(), + Self::Long(l) => l.block_count(), + } + } +} + +impl<'a> BlkDescSlice<'a> { + fn get(&self, idx: usize) -> Option> { + match self { + Self::Short(s) => s.get(idx).map(BlkDesc::Short), + Self::Long(l) => l.get(idx).map(BlkDesc::Long), + Self::General(g) => g.get(idx).map(BlkDesc::General), + } + } +} diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index e49570a260..e71c9dc225 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -298,22 +298,15 @@ impl Xhci { println!(" - XHCI initialized"); } - pub fn enable_port_slot(cmd: &mut CommandRing, dbs: &mut [Doorbell]) -> u8 { - let (cmd, cycle, event) = cmd.next(); + pub fn enable_port_slot(&mut self, slot_ty: u8) -> Result { + assert_eq!(slot_ty & 0x1F, slot_ty); - cmd.enable_slot(0, cycle); - - dbs[0].write(0); - - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - let slot = (event.control.read() >> 24) as u8; - - cmd.reserved(false); - event.reserved(false); - - slot + let cloned_event_trb = self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?; + Ok(cloned_event_trb.event_slot()) + } + pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> { + self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?; + Ok(()) } pub fn slot_state(&self, slot: usize) -> u8 { @@ -336,14 +329,13 @@ impl Xhci { println!(" - Enable slot"); - self.run.ints[0].erdp.write(self.cmd.erdp()); - - let slot = Self::enable_port_slot(&mut self.cmd, &mut self.dbs); + let slot_ty = self.supported_protocol(i as u8).expect("Failed to find supported protocol information for port").proto_slot_ty(); + let slot = self.enable_port_slot(slot_ty)?; println!(" - Slot {}", slot); let mut input = Dma::::zeroed()?; - let mut ring = self.address_device(&mut input, i, slot, speed)?; + let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed)?; let dev_desc = Self::get_dev_desc_raw( &mut self.ports, @@ -401,31 +393,14 @@ impl Xhci { b &= 0x0000_FFFF; b |= (new_max_packet_size) << 16; endp_ctx.b.write(b); - - { - let (cmd, cycle, event) = self.cmd.next(); - - cmd.evaluate_context(slot_id, input_context.physical(), false, cycle); - - self.dbs[0].write(0); - - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::CommandCompletion as u8 - { - panic!("EVALUATE_CONTEXT failed with {:#0x} {:#0x} {:#0x}", event.data.read(), event.status.read(), event.control.read()); - } - - cmd.reserved(false); - event.reserved(false); - } + + self.execute_command("EVALUATE_CONTEXT", |trb, cycle| { + trb.evaluate_context(slot_id, input_context.physical(), false, cycle) + })?; Ok(()) } - pub fn address_device(&mut self, input_context: &mut Dma, i: usize, slot: u8, speed: u8) -> Result { + pub fn address_device(&mut self, input_context: &mut Dma, i: usize, slot_ty: u8, slot: u8, speed: u8) -> Result { let mut ring = Ring::new(true)?; { @@ -502,27 +477,12 @@ impl Xhci { endp_ctx.trh.write((tr >> 32) as u32); endp_ctx.trl.write(tr as u32); } + + let input_context_physical = input_context.physical(); - { - let (cmd, cycle, event) = self.cmd.next(); - - cmd.address_device(slot, input_context.physical(), false, cycle); - - self.dbs[0].write(0); - - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::CommandCompletion as u8 - { - panic!("ADDRESS DEVICE FAILED"); - } - - cmd.reserved(false); - event.reserved(false); - } + self.execute_command("ADDRESS_DEVICE", |trb, cycle| { + trb.address_device(slot, input_context_physical, false, cycle) + }).expect("ADDRESS_DEVICE failed"); Ok(ring) } @@ -623,6 +583,11 @@ impl Xhci { } }) } + pub fn supported_protocol(&self, port: u8) -> Option<&'static SupportedProtoCap> { + self + .supported_protocols_iter() + .find(|supp_proto| supp_proto.compat_port_range().contains(&port)) + } pub fn supported_protocol_speeds( &self, port: u8, @@ -690,9 +655,8 @@ impl Xhci { | 7 << PROTO_SPEED_PSIV_SHIFT, ), ]; - let supp_proto = self - .supported_protocols_iter() - .find(|supp_proto| supp_proto.compat_port_range().contains(&port))?; + + let supp_proto = self.supported_protocol(port)?; Some(if supp_proto.psic() != 0 { unsafe { supp_proto.protocol_speeds().iter() } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index acea2a2608..11465d64fb 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -25,11 +25,16 @@ use super::extended::ProtocolSpeed; use super::operational::OperationalRegs; use super::ring::Ring; use super::runtime::RuntimeRegs; -use super::trb::{TransferKind, TrbCompletionCode, TrbType}; +use super::trb::{TransferKind, Trb, TrbCompletionCode, TrbType}; use super::usb::endpoint::{EndpointTy, ENDP_ATTR_TY_MASK}; use crate::driver_interface::*; +pub enum ControlFlow { + Continue, + Break, +} + #[derive(Clone, Copy, Debug)] pub enum EndpIfState { Init, @@ -200,47 +205,149 @@ impl AnyDescriptor { } impl Xhci { - fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { - let ps = self.port_states.get_mut(&port).ok_or(Error::new(EIO))?; - let ring = ps - .endpoint_states - .get_mut(&0) - .ok_or(Error::new(EIO))? - .ring() - .ok_or(Error::new(EIO))?; + pub fn execute_command(&mut self, cmd_name: &str, f: F) -> Result { + self.run.ints[0].erdp.write(self.cmd.erdp()); + let (cmd, cycle, event) = self.cmd.next(); + + f(cmd, cycle); + + self.dbs[0].write(0); + + while event.data.read() == 0 { + println!(" - {} Waiting for event", cmd_name); + } + + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::CommandCompletion as u8 + { + println!("{} failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", cmd_name, event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); + return Err(Error::new(EIO)); + } + + let ret = event.clone(); + + cmd.reserved(false); + event.reserved(false); + + self.run.ints[0].erdp.write(self.cmd.erdp()); + Ok(ret) + } + pub fn execute_control_transfer(&mut self, port_num: usize, setup: usb::Setup, tk: TransferKind, name: &str, mut d: D) -> Result + where + D: FnMut(&mut Trb, bool) -> ControlFlow, + { + let slot = self.port_state(port_num)?.slot; + let ring = self.endpoint_state_mut(port_num, 0)?.ring().ok_or(Error::new(EIO))?; { let (cmd, cycle) = ring.next(); - cmd.setup(req, TransferKind::NoData, cycle); + cmd.setup(setup, tk, cycle); + } + if tk != TransferKind::NoData { + loop { + let (trb, cycle) = ring.next(); + match d(trb, cycle) { + ControlFlow::Break => break, + ControlFlow::Continue => continue, + } + } } { let (cmd, cycle) = ring.next(); - cmd.status(false, cycle); + cmd.status(tk == TransferKind::In, cycle); } - self.dbs[ps.slot as usize].write(Self::def_control_endp_doorbell()); + self.dbs[usize::from(slot)].write(Self::def_control_endp_doorbell()); - { + let cloned_trb = { let event = self.cmd.next_event(); while event.data.read() == 0 { - println!(" - Waiting for event"); - } - let status = event.status.read(); - let control = event.control.read(); - - if (status >> 24) != TrbCompletionCode::Success as u32 { - println!("DEVICE_REQ ERROR, COMPLETION CODE {:#0x}", (status >> 24)); + println!(" - {} Waiting for event", name); } - println!( - "DEVICE_REQ EVENT {:#0x} {:#0x} {:#0x}", - event.data.read(), - status, - control - ); - } + if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::Transfer as u8 { + println!("{} CONTROL TRANSFER ERROR, EVENT TRB {:#0x} {:#0x} {:#0}»", name, event.data.read(), event.status.read(), event.control.read()); + } + event.clone() + }; self.run.ints[0].erdp.write(self.cmd.erdp()); + Ok(cloned_trb) + } + /// NOTE: There has to be AT LEAST one successful invocation of `d`, that actually updates the + /// TRB (it could be a NO-OP in the worst case). + pub fn execute_transfer(&mut self, port_num: usize, endp_num: u8, stream_id: u16, name: &str, mut d: D) -> Result + where + D: FnMut(&mut Trb, bool) -> ControlFlow, + { + let port_state = self.port_state_mut(port_num)?; + let slot = port_state.slot; + let endp_state = port_state + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADF))?; + + + let ring: &mut Ring = match endp_state { + EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. } => ring, + EndpointState { transfer: super::RingOrStreams::Streams(stream_ctx_array), .. } => { + stream_ctx_array + .rings + .get_mut(&1) + .ok_or(Error::new(EBADF))? + } + }; + + loop { + let (trb, cycle) = ring.next(); + match d(trb, cycle) { + ControlFlow::Break => break, + ControlFlow::Continue => continue, + } + } + + self.dbs[usize::from(slot)].write(Self::endp_doorbell(endp_num, self.endp_desc(port_num, endp_num)?, stream_id)); + + let cloned_trb = { + let event = self.cmd.next_event(); + while event.data.read() == 0 { + println!(" - {} Waiting for event", name); + } + + // FIXME: EDTLA if event data was set + if event.completion_code() != TrbCompletionCode::ShortPacket as u8 + && event.transfer_length() != 0 + { + println!( + "Event trb didn't yield a short packet, but some bytes were not transferred" + ); + } + + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::Transfer as u8 + { + println!( + "Custom transfer event failed with {:#0x} {:#0x} {:#0x}", + event.data.read(), + event.status.read(), + event.control.read() + ); + } + // TODO: Handle event data + println!("EVENT DATA: {:?}", event.event_data()); + + let cloned_trb = event.clone(); + event.reserved(false); + + cloned_trb + }; + + self.run.ints[0].erdp.write(self.cmd.erdp()); + + Ok(cloned_trb) + } + fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { + self.execute_control_transfer(port, req, TransferKind::NoData, "DEVICE_REQ_NO_DATA", |_, _| ControlFlow::Break)?; Ok(()) } fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { @@ -267,26 +374,7 @@ impl Xhci { .ok_or(Error::new(EBADF))? .slot; - let (cmd, cycle, event) = self.cmd.next(); - cmd.reset_endpoint(slot, endp_num_xhc, tsp, cycle); - - self.dbs[0].write(0); - - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::CommandCompletion as u8 - { - println!("RESET_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); - return Err(Error::new(EIO)); - } - - cmd.reserved(false); - event.reserved(false); - - self.run.ints[0].erdp.write(self.cmd.erdp()); + self.execute_command("RESET_ENDPOINT", |trb, cycle| trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle))?; Ok(()) } @@ -349,6 +437,37 @@ impl Xhci { } } + fn port_state(&self, port: usize) -> Result<&super::PortState> { + self.port_states.get(&port).ok_or(Error::new(EBADF)) + } + fn port_state_mut(&mut self, port: usize) -> Result<&mut super::PortState> { + self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) + } + fn endpoint_state_mut(&mut self, port: usize, endp_num: u8) -> Result<&mut EndpointState> { + self.port_state_mut(port)?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF)) + } + fn input_context(&mut self, port: usize) -> Result<&mut Dma> { + Ok(&mut self.port_state_mut(port)?.input_context) + } + fn endp_ctx(&mut self, port: usize, endp_num_xhc: u8) -> Result<&mut super::context::EndpointContext> { + Ok(self.input_context(port)? + .device + .endpoints + .get_mut(endp_num_xhc as usize - 1) + .ok_or(Error::new(EIO))?) + } + fn dev_desc(&self, port: usize) -> Result<&DevDesc> { + Ok(&self.port_state(port)?.dev_desc) + } + fn config_descs(&self, port: usize) -> Result<&[ConfDesc]> { + Ok(&self.dev_desc(port)?.config_descs) + } + fn config_desc(&self, port: usize, desc: u8) -> Result<&ConfDesc> { + Ok(self.config_descs(port)?.get(usize::from(desc)).ok_or(Error::new(EBADF))?) + } + fn endp_descs(&self, port: usize, config_desc: u8, if_desc: u8) -> Result<&[EndpDesc]> { + Ok(&self.port_state(port)?.dev_desc.config_descs.get(usize::from(config_desc)).ok_or(Error::new(EIO))?.interface_descs.get(usize::from(if_desc)).ok_or(Error::new(EIO))?.endpoints) + } fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; @@ -365,67 +484,59 @@ impl Xhci { return Err(Error::new(EBADMSG)); } + let (endp_desc_count, new_context_entries) = { + let endpoints = self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?; + + if endpoints.len() >= 31 { + return Err(Error::new(EIO)); + } + + (endpoints.len(), (match endpoints.last() { + Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l), + None => 1, + }) + 1) + }; + let lec = self.cap.lec(); + let max_psa_size = self.cap.max_psa_size(); + let port_speed_id = self.ports[port].speed(); let speed_id: &ProtocolSpeed = self.lookup_psiv(port as u8, port_speed_id).ok_or(Error::new(EIO))?; - let port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; - let input_context: &mut Dma = &mut port_state.input_context; + { + let input_context = self.input_context(port)?; - // Configure the slot context as well, which holds the last index of the endp descs. - input_context.add_context.write(1); - input_context.drop_context.write(0); + // Configure the slot context as well, which holds the last index of the endp descs. + input_context.add_context.write(1); + input_context.drop_context.write(0); - const CONTEXT_ENTRIES_MASK: u32 = 0xF800_0000; - const CONTEXT_ENTRIES_SHIFT: u8 = 27; + const CONTEXT_ENTRIES_MASK: u32 = 0xF800_0000; + const CONTEXT_ENTRIES_SHIFT: u8 = 27; - let current_slot_a = input_context.device.slot.a.read(); + let current_slot_a = input_context.device.slot.a.read(); - let dev_desc = &port_state.dev_desc; - let endpoints = &dev_desc - .config_descs - .get(req.config_desc as usize) - .ok_or(Error::new(EBADMSG))? - .interface_descs.get(req.interface_desc.unwrap_or(0) as usize).ok_or(Error::new(EBADMSG))? - .endpoints; - - if endpoints.len() >= 31 { - return Err(Error::new(EIO)); + input_context.device.slot.a.write( + (current_slot_a & !CONTEXT_ENTRIES_MASK) + | ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT) + & CONTEXT_ENTRIES_MASK), + ); + input_context.control.write( + (u32::from(req.alternate_setting.unwrap_or(0)) << 16) + | (u32::from(req.interface_desc.unwrap_or(0)) << 8) + | u32::from(req.config_desc), + ); } - let new_context_entries = match endpoints.last() { - Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l), - None => 1, - } + 1; - input_context.device.slot.a.write( - (current_slot_a & !CONTEXT_ENTRIES_MASK) - | ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT) - & CONTEXT_ENTRIES_MASK), - ); - input_context.control.write( - (u32::from(req.alternate_setting.unwrap_or(0)) << 16) - | (u32::from(req.interface_desc.unwrap_or(0)) << 8) - | u32::from(req.config_desc), - ); - - let lec = self.cap.lec(); - - for endp_idx in 0..endpoints.len() as u8 { + for endp_idx in 0..endp_desc_count as u8 { let endp_num = endp_idx + 1; + let endpoints = self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?; + let dev_desc = self.dev_desc(port)?; let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; + let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); - input_context.add_context.writef(1 << endp_num_xhc, true); - - let endp_ctx = input_context - .device - .endpoints - .get_mut(endp_num_xhc as usize - 1) - .ok_or(Error::new(EIO))?; - let max_streams = endp_desc.max_streams(); - let max_psa_size = self.cap.max_psa_size(); // TODO: Secondary streams. let primary_streams = if max_streams != 0 { @@ -467,6 +578,8 @@ impl Xhci { assert_eq!(max_error_count & 0x3, max_error_count); assert_ne!(ep_ty, 0); // 0 means invalid. + let port_state = self.port_state_mut(port)?; + let ring_ptr = if max_streams != 0 { let mut array = StreamContextArray::new(1 << (max_streams + 1))?; @@ -502,6 +615,11 @@ impl Xhci { }; assert_eq!(primary_streams & 0x1F, primary_streams); + let input_context = self.input_context(port)?; + input_context.add_context.writef(1 << endp_num_xhc, true); + + let endp_ctx = self.endp_ctx(port, endp_num_xhc)?; + endp_ctx.a.write( u32::from(mult) << 8 | u32::from(primary_streams) << 10 @@ -526,37 +644,12 @@ impl Xhci { ); } - self.run.ints[0].erdp.write(self.cmd.erdp()); - - { - let (cmd, cycle, event) = self.cmd.next(); - cmd.configure_endpoint(port_state.slot, input_context.physical(), cycle); - - self.dbs[0].write(0); - - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::CommandCompletion as u8 - { - println!("CONFIGURE_ENDPOINT failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); - return Err(Error::new(EIO)); - } - - cmd.reserved(false); - event.reserved(false); - } + let slot = self.port_state(port)?.slot; + let input_context_physical = self.input_context(port)?.physical(); + self.execute_command("CONFIGURE_ENDPOINT", |trb, cycle| trb.configure_endpoint(slot, input_context_physical, cycle)); // Tell the device about this configuration. - - let configuration_value = port_state - .dev_desc - .config_descs - .get(req.config_desc as usize) - .ok_or(Error::new(EIO))? - .configuration_value; + let configuration_value = self.config_desc(port, req.config_desc)?.configuration_value; self.set_configuration(port, configuration_value)?; if let (Some(interface_num), Some(alternate_setting)) = @@ -609,7 +702,7 @@ impl Xhci { } else { unreachable!() } } fn endp_desc(&self, port_num: usize, endp_num: u8) -> Result<&EndpDesc> { - self.port_states.get(&port_num).ok_or(Error::new(EIO))?.dev_desc.config_descs.first().ok_or(Error::new(EIO))?.interface_descs.first().ok_or(Error::new(EIO))?.endpoints.get(endp_num as usize - 1).ok_or(Error::new(EIO)) + Ok(self.endp_descs(port_num, 0, 0)?.get(usize::from(endp_num) - 1).ok_or(Error::new(EBADF))?) } fn endp_doorbell(endp_num: u8, desc: &EndpDesc, stream_id: u16) -> u32 { let db_target = Self::endp_num_to_dci(endp_num, desc); @@ -667,25 +760,11 @@ impl Xhci { return Err(Error::new(EBADF)); } - let endp_state = port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADF))?; - - let ring: &mut Ring = match endp_state { - EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. } => ring, - EndpointState { transfer: super::RingOrStreams::Streams(stream_ctx_array), .. } => { - stream_ctx_array - .rings - .get_mut(&1) - .ok_or(Error::new(EBADF))? - } - }; // TODO: Scatter-gather transfers, possibly allowing >64KiB sizes. let len = u16::try_from(buf.len()).or(Err(Error::new(ENOSYS)))?; let max_packet_size = endp_desc.max_packet_size; - { - let (trb, cycle) = ring.next(); + + let (buffer, idt, estimated_td_size) = { let (buffer, idt) = if len <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { buf.map_buf(|sbuf| { let mut bytes = [0u8; 8]; @@ -700,7 +779,12 @@ impl Xhci { false, ) }; - let estimated_td_size = mem::size_of_val(&trb) as u8; // one trb per td + let estimated_td_size = mem::size_of::() as u8; // one trb per td + (buffer, idt, estimated_td_size) + }; + + let stream_id = 1u16; + let event = self.execute_transfer(port_num, endp_num, stream_id, "CUSTOM_TRANSFER", |trb, cycle| { trb.normal( buffer, len, @@ -714,50 +798,16 @@ impl Xhci { idt, false, ); - } + ControlFlow::Break + })?; - let stream_id = 1u16; - self.dbs[port_state.slot as usize].write(Self::endp_doorbell(endp_num, self.endp_desc(port_num, endp_num)?, stream_id)); - - let (completion_code, bytes_transferred) = { - let event = self.cmd.next_event(); - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - - // FIXME: EDTLA if event data was set - if event.completion_code() != TrbCompletionCode::ShortPacket as u8 - && event.transfer_length() != 0 - { - println!( - "Event trb didn't yield a short packet, but some bytes were not transferred" - ); - } - - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::Transfer as u8 - { - println!( - "Custom transfer event failed with {:#0x} {:#0x} {:#0x}", - event.data.read(), - event.status.read(), - event.control.read() - ); - } - // TODO: Handle event data - println!("EVENT DATA: {:?}", event.event_data()); - - ( - event.completion_code(), - u32::from(len) - event.transfer_length(), - ) - }; + let bytes_transferred = u32::from(len) - event.transfer_length(); if let DeviceReqData::In(dbuf) = &mut buf { dbuf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); } - Ok((completion_code, bytes_transferred as u32)) + Ok((event.completion_code(), bytes_transferred)) } pub(crate) fn get_dev_desc(&mut self, port_id: usize) -> Result { let st = self @@ -947,58 +997,10 @@ impl Xhci { // be better. Maybe something simple like bincode could be used, if a custom binary struct // is too much overkill. - let port_state = self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(EBADF))?; - - let ring = match port_state - .endpoint_states - .get_mut(&0) - .ok_or(Error::new(EIO))? - { - EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. } => ring, - - // Control endpoints never use streams - _ => return Err(Error::new(EIO)), - }; - - { - let (cmd, cycle) = ring.next(); - cmd.setup(setup, TransferKind::In, cycle); - } - if transfer_kind != TransferKind::NoData { - let (cmd, cycle) = ring.next(); - - cmd.data( - data_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0), - setup.length, - transfer_kind == TransferKind::In, - cycle, - ); - } - { - let (cmd, cycle) = ring.next(); - cmd.status(transfer_kind == TransferKind::In, cycle); - } - self.dbs[port_state.slot as usize].write(Self::def_control_endp_doorbell()); - - { - let event = self.cmd.next_event(); - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::Transfer as u8 - { - println!( - "Custom device request failed with EVENT {:#0x} {:#0x} {:#0x}", - event.data.read(), - event.status.read(), - event.control.read() - ); - } - } + self.execute_control_transfer(port_num, setup, transfer_kind, "CUSTOM_DEVICE_REQ", |trb, cycle| { + trb.data(data_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0), setup.length, transfer_kind == TransferKind::In, cycle); + ControlFlow::Break + })?; Ok(()) } fn port_req_init_st(&mut self, port_num: usize, req: &PortReq) -> Result { @@ -1517,8 +1519,10 @@ impl Xhci { &mut super::RingOrStreams::Ring(ref mut ring) => ring, &mut super::RingOrStreams::Streams(ref mut arr) => arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?, }; + let (cmd, cycle) = ring.next(); cmd.transfer_no_op(0, false, false, false, cycle); + let deque_ptr_and_cycle = ring.register(); let slot = port_state.slot; @@ -1538,33 +1542,8 @@ impl Xhci { let slot = self.slot(port_num)?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?); - // TODO: Merge these command boilerplates into a single function. - self.run.ints[0].erdp.write(self.cmd.erdp()); + self.execute_command("SET_TR_DEQUEUE_POINTER", |trb, cycle| trb.set_tr_deque_ptr(deque_ptr_and_cycle, cycle, StreamContextType::PrimaryRing, 1, endp_num_xhc, slot))?; - { - let (cmd, cycle, event) = self.cmd.next(); - - - // TODO: I guess this very command is the one used to actually multiplex between - // streams. - cmd.set_tr_deque_ptr(deque_ptr_and_cycle, cycle, StreamContextType::PrimaryRing, 1, endp_num_xhc, slot); - - self.dbs[0].write(0); - - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::CommandCompletion as u8 - { - println!("SET_TR_DEQUEUE_POINTER failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); - return Err(Error::new(EIO)); - } - - cmd.reserved(false); - event.reserved(false); - } Ok(()) } pub fn on_write_endp_ctl(&mut self, port_num: usize, endp_num: u8, buf: &[u8]) -> Result { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 8e070d36e6..4dafc85860 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -112,6 +112,15 @@ pub struct Trb { pub status: Mmio, pub control: Mmio, } +impl Clone for Trb { + fn clone(&self) -> Self { + Self { + data: Mmio::from(self.data.read()), + status: Mmio::from(self.status.read()), + control: Mmio::from(self.control.read()), + } + } +} pub const TRB_STATUS_COMPLETION_CODE_SHIFT: u8 = 24; pub const TRB_STATUS_COMPLETION_CODE_MASK: u32 = 0xFF00_0000; @@ -148,6 +157,9 @@ impl Trb { pub fn completion_param(&self) -> u32 { self.status.read() & TRB_STATUS_COMPLETION_PARAM_MASK } + pub fn event_slot(&self) -> u8 { + (self.control.read() >> 24) as u8 + } /// Returns the number of bytes that should have been transmitten, but weren't. pub fn transfer_length(&self) -> u32 { self.status.read() & TRB_STATUS_TRANSFER_LENGTH_MASK From bd0892e45d965c8ca3601eb3f5d35028fe2ad769 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Feb 2020 00:26:19 +0100 Subject: [PATCH 0346/1301] Make the usb scsi scheme able to do block I/O. --- usbscsid/src/main.rs | 70 +++- usbscsid/src/protocol/bot.rs | 131 +++++-- usbscsid/src/protocol/mod.rs | 23 +- usbscsid/src/scheme.rs | 53 ++- usbscsid/src/scsi/cmds.rs | 74 +++- usbscsid/src/scsi/mod.rs | 138 ++++++- xhcid/src/driver_interface.rs | 134 +++++-- xhcid/src/usb/bos.rs | 11 +- xhcid/src/usb/mod.rs | 3 +- xhcid/src/xhci/extended.rs | 20 +- xhcid/src/xhci/mod.rs | 48 ++- xhcid/src/xhci/scheme.rs | 696 +++++++++++++++++++++++++--------- xhcid/src/xhci/trb.rs | 26 +- 13 files changed, 1104 insertions(+), 323 deletions(-) diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index 932c57af8b..d6691d47c5 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -20,15 +20,26 @@ fn main() { const USAGE: &'static str = "usbscsid "; let scheme = args.next().expect(USAGE); - let port = args.next().expect(USAGE).parse::().expect("port has to be a number"); - let protocol = args.next().expect(USAGE).parse::().expect("protocol has to be a number 0-255"); + let port = args + .next() + .expect(USAGE) + .parse::() + .expect("port has to be a number"); + let protocol = args + .next() + .expect(USAGE) + .parse::() + .expect("protocol has to be a number 0-255"); - println!("USB SCSI driver spawned with scheme `{}`, port {}, protocol {}", scheme, port, protocol); + println!( + "USB SCSI driver spawned with scheme `{}`, port {}, protocol {}", + scheme, port, protocol + ); // Daemonize so that xhcid can continue to do other useful work (until proper IRQs, // async-await, and multithreading :D) if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { - return + return; } let disk_scheme_name = format!(":disk/{}-{}_scsi", scheme, port); @@ -36,30 +47,46 @@ fn main() { // TODO: Use eventfds. let handle = XhciClientHandle::new(scheme, port); - let desc = handle.get_standard_descs().expect("Failed to get standard descriptors"); + let desc = handle + .get_standard_descs() + .expect("Failed to get standard descriptors"); // TODO: Perhaps the drivers should just be given the config, interface, and alternate setting // from xhcid. - let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting)) = desc.config_descs.iter().find_map(|config_desc| { - let interface_desc = config_desc.interface_descs.iter().find_map(|if_desc| if if_desc.class == 8 && if_desc.sub_class == 6 && if_desc.protocol == 0x50 { - Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting)) - } else { - None - })?; - Some((config_desc.clone(), config_desc.configuration_value, interface_desc)) - }).expect("Failed to find suitable configuration"); + let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting)) = desc + .config_descs + .iter() + .find_map(|config_desc| { + let interface_desc = config_desc.interface_descs.iter().find_map(|if_desc| { + if if_desc.class == 8 && if_desc.sub_class == 6 && if_desc.protocol == 0x50 { + Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting)) + } else { + None + } + })?; + Some(( + config_desc.clone(), + config_desc.configuration_value, + interface_desc, + )) + }) + .expect("Failed to find suitable configuration"); - handle.configure_endpoints(&ConfigureEndpointsReq { - config_desc: configuration_value, - interface_desc: Some(interface_num), - alternate_setting: Some(alternate_setting), - }).expect("Failed to configure endpoints"); + handle + .configure_endpoints(&ConfigureEndpointsReq { + config_desc: configuration_value, + interface_desc: Some(interface_num), + alternate_setting: Some(alternate_setting), + }) + .expect("Failed to configure endpoints"); - let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc).expect("Failed to setup protocol"); + let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc) + .expect("Failed to setup protocol"); // TODO: Let all of the USB drivers syscall clone(2), and xhcid won't have to keep track of all // the drivers. - let socket_fd = syscall::open(disk_scheme_name, syscall::O_RDWR | syscall::O_CREAT).expect("usbscsid: failed to create disk scheme"); + let socket_fd = syscall::open(disk_scheme_name, syscall::O_RDWR | syscall::O_CREAT) + .expect("usbscsid: failed to create disk scheme"); let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; //syscall::setrens(0, 0).expect("scsid: failed to enter null namespace"); @@ -78,5 +105,8 @@ fn main() { Err(err) => panic!("scsid: failed to read disk scheme: {}", err), } scsi_scheme.handle(&mut packet); + socket_file + .write(&packet) + .expect("scsid: failed to write packet"); } } diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index 13ab6a784f..589dfa367f 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -1,7 +1,11 @@ use std::num::NonZeroU32; use std::slice; -use xhcid_interface::{ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, PortReqTy, PortReqRecipient, PortTransferStatus, XhciClientHandle, XhciClientHandleError, XhciEndpHandle}; +use xhcid_interface::{ + ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, + PortReqRecipient, PortReqTy, PortTransferStatus, XhciClientHandle, XhciClientHandleError, + XhciEndpHandle, +}; use super::{Protocol, ProtocolError, SendCommandStatus, SendCommandStatusKind}; @@ -18,12 +22,18 @@ pub struct CommandBlockWrapper { pub tag: u32, pub data_transfer_len: u32, pub flags: u8, // upper nibble reserved - pub lun: u8, // bits 7:5 reserved + pub lun: u8, // bits 7:5 reserved pub cb_len: u8, pub command_block: [u8; 16], } impl CommandBlockWrapper { - pub fn new(tag: u32, data_transfer_len: u32, direction: EndpBinaryDirection, lun: u8, cb: &[u8]) -> Result { + pub fn new( + tag: u32, + data_transfer_len: u32, + direction: EndpBinaryDirection, + lun: u8, + cb: &[u8], + ) -> Result { let mut command_block = [0u8; 16]; if cb.len() > 16 { return Err(ProtocolError::TooLargeCommandBlock(cb.len())); @@ -86,11 +96,23 @@ pub struct BulkOnlyTransport<'a> { pub const FEATURE_ENDPOINT_HALT: u16 = 0; impl<'a> BulkOnlyTransport<'a> { - pub fn init(handle: &'a XhciClientHandle, config_desc: &ConfDesc, if_desc: &IfDesc) -> Result { + pub fn init( + handle: &'a XhciClientHandle, + config_desc: &ConfDesc, + if_desc: &IfDesc, + ) -> Result { let endpoints = &if_desc.endpoints; - let bulk_in_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::In).unwrap() + 1) as u8; - let bulk_out_num = (endpoints.iter().position(|endpoint| endpoint.direction() == EndpDirection::Out).unwrap() + 1) as u8; + let bulk_in_num = (endpoints + .iter() + .position(|endpoint| endpoint.direction() == EndpDirection::In) + .unwrap() + + 1) as u8; + let bulk_out_num = (endpoints + .iter() + .position(|endpoint| endpoint.direction() == EndpDirection::Out) + .unwrap() + + 1) as u8; let max_lun = get_max_lun(handle, 0)?; println!("BOT_MAX_LUN {}", max_lun); @@ -108,26 +130,40 @@ impl<'a> BulkOnlyTransport<'a> { } fn clear_stall_in(&mut self) -> Result<(), XhciClientHandleError> { self.bulk_in.reset(false)?; - self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_in_num), FEATURE_ENDPOINT_HALT) + self.handle.clear_feature( + PortReqRecipient::Endpoint, + u16::from(self.bulk_in_num), + FEATURE_ENDPOINT_HALT, + ) } fn clear_stall_out(&mut self) -> Result<(), XhciClientHandleError> { self.bulk_out.reset(false)?; - self.handle.clear_feature(PortReqRecipient::Endpoint, u16::from(self.bulk_out_num), FEATURE_ENDPOINT_HALT) + self.handle.clear_feature( + PortReqRecipient::Endpoint, + u16::from(self.bulk_out_num), + FEATURE_ENDPOINT_HALT, + ) } fn reset_recovery(&mut self) -> Result<(), ProtocolError> { bulk_only_mass_storage_reset(self.handle, self.interface_num.into())?; self.clear_stall_in()?; self.clear_stall_out()?; - if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted { - return Err(ProtocolError::RecoveryFailed) + if self.bulk_in.status()? == EndpointStatus::Halted + || self.bulk_out.status()? == EndpointStatus::Halted + { + return Err(ProtocolError::RecoveryFailed); } Ok(()) } } impl<'a> Protocol for BulkOnlyTransport<'a> { - fn send_command(&mut self, cb: &[u8], data: DeviceReqData) -> Result { + fn send_command( + &mut self, + cb: &[u8], + data: DeviceReqData, + ) -> Result { self.current_tag += 1; let tag = self.current_tag; @@ -160,26 +196,38 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { DeviceReqData::In(buffer) => { match self.bulk_in.transfer_read(buffer)? { PortTransferStatus::Success => (), - PortTransferStatus::ShortPacket(len) => panic!("received short packed (len {}) when transferring data", len), + PortTransferStatus::ShortPacket(len) => { + panic!("received short packed (len {}) when transferring data", len) + } PortTransferStatus::Stalled => { println!("bulk in endpoint stalled when reading data"); self.clear_stall_in()?; } - PortTransferStatus::Unknown => return Err(ProtocolError::XhciError(XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")))), + PortTransferStatus::Unknown => { + return Err(ProtocolError::XhciError( + XhciClientHandleError::InvalidResponse(Invalid( + "unknown transfer status", + )), + )) + } }; println!("{}", base64::encode(&buffer[..])); } - DeviceReqData::Out(buffer) => { - match self.bulk_out.transfer_write(buffer)? { - PortTransferStatus::Success => (), - PortTransferStatus::ShortPacket(len) => panic!("received short packed (len {}) when transferring data", len), - PortTransferStatus::Stalled => { - println!("bulk out endpoint stalled when reading data"); - self.clear_stall_out()?; - } - PortTransferStatus::Unknown => return Err(ProtocolError::XhciError(XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")))), + DeviceReqData::Out(buffer) => match self.bulk_out.transfer_write(buffer)? { + PortTransferStatus::Success => (), + PortTransferStatus::ShortPacket(len) => { + panic!("received short packed (len {}) when transferring data", len) } - } + PortTransferStatus::Stalled => { + println!("bulk out endpoint stalled when reading data"); + self.clear_stall_out()?; + } + PortTransferStatus::Unknown => { + return Err(ProtocolError::XhciError( + XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")), + )) + } + }, DeviceReqData::NoData => (), } @@ -190,18 +238,22 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { println!("bulk in endpoint stalled when reading CSW"); self.clear_stall_in()?; } - PortTransferStatus::ShortPacket(n) if n != 13 => panic!("received a short packet when reading CSW ({} != 13)", n), + PortTransferStatus::ShortPacket(n) if n != 13 => { + panic!("received a short packet when reading CSW ({} != 13)", n) + } _ => (), }; println!("{}", base64::encode(&csw_buffer)); let csw = plain::from_bytes::(&csw_buffer).unwrap(); + dbg!(csw); if !csw.is_valid() || csw.tag != cbw.tag { self.reset_recovery()?; } - dbg!(csw); - if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted { + if self.bulk_in.status()? == EndpointStatus::Halted + || self.bulk_out.status()? == EndpointStatus::Halted + { println!("Trying to recover from stall"); dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } @@ -212,19 +264,38 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { } else if csw.status == CswStatus::Failed as u8 { SendCommandStatusKind::Failed } else { - return Err(ProtocolError::ProtocolError("bulk-only transport phase error, or other")); + return Err(ProtocolError::ProtocolError( + "bulk-only transport phase error, or other", + )); }, residue: NonZeroU32::new(csw.data_residue), }) } } -pub fn bulk_only_mass_storage_reset(handle: &XhciClientHandle, if_num: u16) -> Result<(), XhciClientHandleError> { - handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFF, 0, if_num, DeviceReqData::NoData) +pub fn bulk_only_mass_storage_reset( + handle: &XhciClientHandle, + if_num: u16, +) -> Result<(), XhciClientHandleError> { + handle.device_request( + PortReqTy::Class, + PortReqRecipient::Interface, + 0xFF, + 0, + if_num, + DeviceReqData::NoData, + ) } pub fn get_max_lun(handle: &XhciClientHandle, if_num: u16) -> Result { let mut lun = 0u8; let buffer = slice::from_mut(&mut lun); - handle.device_request(PortReqTy::Class, PortReqRecipient::Interface, 0xFE, 0, if_num, DeviceReqData::In(buffer))?; + handle.device_request( + PortReqTy::Class, + PortReqRecipient::Interface, + 0xFE, + 0, + if_num, + DeviceReqData::In(buffer), + )?; Ok(lun) } diff --git a/usbscsid/src/protocol/mod.rs b/usbscsid/src/protocol/mod.rs index 7315ab9805..a580765f1d 100644 --- a/usbscsid/src/protocol/mod.rs +++ b/usbscsid/src/protocol/mod.rs @@ -2,7 +2,9 @@ use std::io; use std::num::NonZeroU32; use thiserror::Error; -use xhcid_interface::{DeviceReqData, DevDesc, ConfDesc, IfDesc, XhciClientHandle, XhciClientHandleError}; +use xhcid_interface::{ + ConfDesc, DevDesc, DeviceReqData, IfDesc, XhciClientHandle, XhciClientHandleError, +}; #[derive(Debug, Error)] pub enum ProtocolError { @@ -40,7 +42,6 @@ pub enum SendCommandStatusKind { Failed, } - impl Default for SendCommandStatusKind { fn default() -> Self { Self::Success @@ -48,7 +49,11 @@ impl Default for SendCommandStatusKind { } pub trait Protocol { - fn send_command(&mut self, command: &[u8], data: DeviceReqData) -> Result; + fn send_command( + &mut self, + command: &[u8], + data: DeviceReqData, + ) -> Result; } /// Bulk-only transport @@ -60,9 +65,17 @@ mod uas { use bot::BulkOnlyTransport; -pub fn setup<'a>(handle: &'a XhciClientHandle, protocol: u8, dev_desc: &DevDesc, conf_desc: &ConfDesc, if_desc: &IfDesc) -> Option> { +pub fn setup<'a>( + handle: &'a XhciClientHandle, + protocol: u8, + dev_desc: &DevDesc, + conf_desc: &ConfDesc, + if_desc: &IfDesc, +) -> Option> { match protocol { - 0x50 => Some(Box::new(BulkOnlyTransport::init(handle, conf_desc, if_desc).unwrap())), + 0x50 => Some(Box::new( + BulkOnlyTransport::init(handle, conf_desc, if_desc).unwrap(), + )), _ => None, } } diff --git a/usbscsid/src/scheme.rs b/usbscsid/src/scheme.rs index 0c88ba6177..07b776604e 100644 --- a/usbscsid/src/scheme.rs +++ b/usbscsid/src/scheme.rs @@ -4,12 +4,12 @@ use std::{cmp, str}; use crate::protocol::Protocol; use crate::scsi::Scsi; -use syscall::SchemeMut; use syscall::error::{Error, Result}; use syscall::error::{EACCES, EBADF, EINVAL, EIO, ENOENT, ENOSYS}; -use syscall::flag::{O_DIRECTORY, O_STAT}; use syscall::flag::{MODE_CHR, MODE_DIR}; +use syscall::flag::{O_DIRECTORY, O_STAT}; use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET}; +use syscall::SchemeMut; // TODO: Only one disk, right? const LIST_CONTENTS: &'static [u8] = b"0\n"; @@ -43,7 +43,9 @@ impl<'a> SchemeMut for ScsiScheme<'a> { if uid != 0 { return Err(Error::new(EACCES)); } - let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_start_matches('/'); + let path_str = str::from_utf8(path) + .or(Err(Error::new(ENOENT)))? + .trim_start_matches('/'); let handle = if path_str.is_empty() { // List Handle::List(0) @@ -55,7 +57,7 @@ impl<'a> SchemeMut for ScsiScheme<'a> { }; self.next_fd += 1; self.handles.insert(self.next_fd, handle); - Err(Error::new(ENOSYS)) + Ok(self.next_fd) } fn fstat(&mut self, fd: usize, stat: &mut syscall::Stat) -> Result { match self.handles.get(&fd).ok_or(Error::new(EBADF))? { @@ -70,10 +72,17 @@ impl<'a> SchemeMut for ScsiScheme<'a> { stat.st_size = LIST_CONTENTS.len() as u64; } } - Err(Error::new(ENOSYS)) + Ok(0) } - fn fpath(&mut self, fd: usize, path: &mut [u8]) -> Result { - Err(Error::new(ENOSYS)) + fn fpath(&mut self, fd: usize, buf: &mut [u8]) -> Result { + let path = match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::Disk(_) => "0", + Handle::List(_) => "", + } + .as_bytes(); + let min = std::cmp::min(path.len(), buf.len()); + buf[..min].copy_from_slice(&path[..min]); + Ok(min) } fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { @@ -102,11 +111,18 @@ impl<'a> SchemeMut for ScsiScheme<'a> { fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { Handle::Disk(ref mut offset) => { - if *offset as u64 % u64::from(self.scsi.block_size) != 0 || buf.len() as u64 % u64::from(self.scsi.block_size) != 0 { + if *offset as u64 % u64::from(self.scsi.block_size) != 0 + || buf.len() as u64 % u64::from(self.scsi.block_size) != 0 + { return Err(Error::new(EINVAL)); } let lba = *offset as u64 / u64::from(self.scsi.block_size); - let bytes_read = self.scsi.read(self.protocol, lba, buf).map_err(|err| dbg!(err)).or(Err(Error::new(EIO)))?; + let bytes_read = self + .scsi + .read(self.protocol, lba, buf) + .map_err(|err| dbg!(err)) + .or(Err(Error::new(EIO)))?; + *offset += bytes_read as usize; Ok(bytes_read as usize) } Handle::List(ref mut offset) => { @@ -121,6 +137,23 @@ impl<'a> SchemeMut for ScsiScheme<'a> { } } fn write(&mut self, fd: usize, buf: &[u8]) -> Result { - Err(Error::new(ENOSYS)) + match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::Disk(ref mut offset) => { + if *offset as u64 % u64::from(self.scsi.block_size) != 0 + || buf.len() as u64 % u64::from(self.scsi.block_size) != 0 + { + return Err(Error::new(EINVAL)); + } + let lba = *offset as u64 / u64::from(self.scsi.block_size); + let bytes_written = self + .scsi + .write(self.protocol, lba, buf) + .map_err(|err| dbg!(err)) + .or(Err(Error::new(EIO)))?; + *offset += bytes_written as usize; + Ok(bytes_written as usize) + } + Handle::List(_) => Err(Error::new(EBADF)), + } } } diff --git a/usbscsid/src/scsi/cmds.rs b/usbscsid/src/scsi/cmds.rs index 31949566bd..ca6b2baf4e 100644 --- a/usbscsid/src/scsi/cmds.rs +++ b/usbscsid/src/scsi/cmds.rs @@ -1,5 +1,5 @@ -use std::{fmt, mem, slice}; use super::opcodes::Opcode; +use std::{fmt, mem, slice}; #[repr(packed)] pub struct Inquiry { @@ -124,7 +124,10 @@ impl FixedFormatSenseData { self.add_sense_len as u16 + 7 } pub unsafe fn add_sense_bytes(&self) -> &[u8] { - slice::from_raw_parts(&self.add_sense_len as *const u8, self.add_sense_len as usize - 18) + slice::from_raw_parts( + &self.add_sense_len as *const u8, + self.add_sense_len as usize - 18, + ) } pub fn sense_key(&self) -> SenseKey { let sense_key_raw = self.b & 0b1111; @@ -189,6 +192,32 @@ impl Read16 { } } +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct Write16 { + pub opcode: u8, + pub a: u8, + pub lba: u64, // big endian + pub transfer_len: u32, + pub b: u8, + pub control: u8, +} +unsafe impl plain::Plain for Write16 {} + +impl Write16 { + pub const fn new(lba: u64, transfer_len: u32, control: u8) -> Self { + Self { + // TODO + opcode: Opcode::Write16 as u8, + a: 0, + lba, + transfer_len, + b: 0, + control, + } + } +} + #[repr(packed)] #[derive(Clone, Copy, Debug)] pub struct ModeSense6 { @@ -202,7 +231,14 @@ pub struct ModeSense6 { unsafe impl plain::Plain for ModeSense6 {} impl ModeSense6 { - pub const fn new(dbd: bool, page_code: u8, pc: u8, subpage_code: u8, alloc_len: u8, control: u8) -> Self { + pub const fn new( + dbd: bool, + page_code: u8, + pc: u8, + subpage_code: u8, + alloc_len: u8, + control: u8, + ) -> Self { Self { opcode: Opcode::ModeSense6 as u8, a: (dbd as u8) << 3, @@ -228,7 +264,15 @@ pub struct ModeSense10 { unsafe impl plain::Plain for ModeSense10 {} impl ModeSense10 { - pub const fn new(dbd: bool, llbaa: bool, page_code: u8, pc: ModePageControl, subpage_code: u8, alloc_len: u16, control: u8) -> Self { + pub const fn new( + dbd: bool, + llbaa: bool, + page_code: u8, + pc: ModePageControl, + subpage_code: u8, + alloc_len: u16, + control: u8, + ) -> Self { Self { opcode: Opcode::ModeSense10 as u8, a: ((dbd as u8) << 3) | ((llbaa as u8) << 4), @@ -240,7 +284,15 @@ impl ModeSense10 { } } pub const fn get_block_desc(alloc_len: u16, control: u8) -> Self { - Self::new(false, true, 0x3F, ModePageControl::CurrentValues, 0x00, alloc_len, control) + Self::new( + false, + true, + 0x3F, + ModePageControl::CurrentValues, + 0x00, + alloc_len, + control, + ) } } @@ -279,9 +331,7 @@ impl fmt::Debug for ShortLbaModeParamBlkDesc { } const fn u24_be_to_u32(u24: [u8; 3]) -> u32 { - ((u24[0] as u32) << 16) - | ((u24[1] as u32) << 8) - | (u24[2] as u32) + ((u24[0] as u32) << 16) | ((u24[1] as u32) << 8) | (u24[2] as u32) } /// From SPC-3, when LONGLBA is not set, and the peripheral device type of the INQUIRY data indicates that the device is not a direct access device. Otherwise, `ShortLbaModeParamBlkDesc` is used instead. @@ -434,7 +484,9 @@ impl<'a> Iterator for ModePageIter<'a> { if !spf { if page_code == 0x01 { - Some(AnyModePage::RwErrorRecovery(plain::from_bytes(next_buf).ok()?)) + Some(AnyModePage::RwErrorRecovery( + plain::from_bytes(next_buf).ok()?, + )) } else { println!("Unimplemented sub_page {}", base64::encode(next_buf)); None @@ -447,5 +499,7 @@ impl<'a> Iterator for ModePageIter<'a> { } pub fn mode_page_iter(buffer: &[u8]) -> impl Iterator { - ModePageIter { raw: ModePageIterRaw { buffer } } + ModePageIter { + raw: ModePageIterRaw { buffer }, + } } diff --git a/usbscsid/src/scsi/mod.rs b/usbscsid/src/scsi/mod.rs index 3368db7aac..a4b1f3e243 100644 --- a/usbscsid/src/scsi/mod.rs +++ b/usbscsid/src/scsi/mod.rs @@ -1,5 +1,5 @@ -use std::{mem, ops}; use std::convert::TryFrom; +use std::{mem, ops}; pub mod cmds; pub mod opcodes; @@ -29,6 +29,9 @@ const MIN_REPORT_SUPP_OPCODES_ALLOC_LEN: u32 = 4; pub enum ScsiError { #[error("protocol error when sending command: {0}")] ProtocolError(#[from] ProtocolError), + + #[error("overflow")] + Overflow(&'static str), } impl Scsi { @@ -70,31 +73,67 @@ impl Scsi { let inquiry = self.cmd_inquiry(); *inquiry = cmds::Inquiry::new(false, 0, max_inquiry_len, 0); - protocol.send_command(&self.command_buffer[..INQUIRY_CMD_LEN as usize], DeviceReqData::In(&mut self.inquiry_buffer[..max_inquiry_len as usize])).expect("Failed to send INQUIRY command"); + protocol + .send_command( + &self.command_buffer[..INQUIRY_CMD_LEN as usize], + DeviceReqData::In(&mut self.inquiry_buffer[..max_inquiry_len as usize]), + ) + .expect("Failed to send INQUIRY command"); } pub fn get_ff_sense(&mut self, protocol: &mut dyn Protocol, alloc_len: u8) { let request_sense = self.cmd_request_sense(); *request_sense = cmds::RequestSense::new(false, alloc_len, 0); self.data_buffer.resize(alloc_len.into(), 0); - protocol.send_command(&self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize])).expect("Failed to send REQUEST_SENSE command"); + protocol + .send_command( + &self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize], + DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize]), + ) + .expect("Failed to send REQUEST_SENSE command"); } - pub fn get_mode_sense10(&mut self, protocol: &mut dyn Protocol) -> Result<(&cmds::ModeParamHeader10, BlkDescSlice, impl Iterator), ScsiError> { + pub fn get_mode_sense10( + &mut self, + protocol: &mut dyn Protocol, + ) -> Result< + ( + &cmds::ModeParamHeader10, + BlkDescSlice, + impl Iterator, + ), + ScsiError, + > { let initial_alloc_len = 4; // covers both mode_data_len and blk_desc_len. let mode_sense10 = self.cmd_mode_sense10(); *mode_sense10 = cmds::ModeSense10::get_block_desc(initial_alloc_len, 0); - self.data_buffer.resize(mem::size_of::(), 0); - if let SendCommandStatus { kind: SendCommandStatusKind::Failed, .. } = protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..initial_alloc_len as usize]))? { + self.data_buffer + .resize(mem::size_of::(), 0); + if let SendCommandStatus { + kind: SendCommandStatusKind::Failed, + .. + } = protocol.send_command( + &self.command_buffer[..10], + DeviceReqData::In(&mut self.data_buffer[..initial_alloc_len as usize]), + )? { self.get_ff_sense(protocol, 252); panic!("{:?}", self.res_ff_sense_data()); } - let optimal_alloc_len = self.res_mode_param_header10().block_desc_len() + self.res_mode_param_header10().mode_data_len() + mem::size_of::() as u16; + let optimal_alloc_len = self.res_mode_param_header10().block_desc_len() + + self.res_mode_param_header10().mode_data_len() + + mem::size_of::() as u16; let mode_sense10 = self.cmd_mode_sense10(); *mode_sense10 = cmds::ModeSense10::get_block_desc(optimal_alloc_len, 0); self.data_buffer.resize(optimal_alloc_len as usize, 0); - protocol.send_command(&self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..optimal_alloc_len as usize]))?; - Ok((self.res_mode_param_header10(), self.res_blkdesc_mode10(), self.res_mode_pages10())) + protocol.send_command( + &self.command_buffer[..10], + DeviceReqData::In(&mut self.data_buffer[..optimal_alloc_len as usize]), + )?; + Ok(( + self.res_mode_param_header10(), + self.res_blkdesc_mode10(), + self.res_mode_pages10(), + )) } pub fn cmd_inquiry(&mut self) -> &mut cmds::Inquiry { @@ -112,6 +151,9 @@ impl Scsi { pub fn cmd_read16(&mut self) -> &mut cmds::Read16 { plain::from_mut_bytes(&mut self.command_buffer).unwrap() } + pub fn cmd_write16(&mut self) -> &mut cmds::Write16 { + plain::from_mut_bytes(&mut self.command_buffer).unwrap() + } pub fn res_standard_inquiry_data(&self) -> &StandardInquiryData { plain::from_bytes(&self.inquiry_buffer).unwrap() } @@ -127,17 +169,41 @@ impl Scsi { pub fn res_blkdesc_mode6(&self) -> &[cmds::ShortLbaModeParamBlkDesc] { let header = self.res_mode_param_header6(); let descs_start = mem::size_of::(); - plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)]).unwrap() + plain::slice_from_bytes( + &self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len)], + ) + .unwrap() } pub fn res_blkdesc_mode10(&self) -> BlkDescSlice { let header = self.res_mode_param_header10(); let descs_start = mem::size_of::(); if header.longlba() { - BlkDescSlice::Long(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap()) - } else if self.res_standard_inquiry_data().periph_dev_ty() != cmds::PeriphDeviceType::DirectAccess as u8 && self.res_standard_inquiry_data().version() == cmds::InquiryVersion::Spc3 as u8 { - BlkDescSlice::General(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap()) + BlkDescSlice::Long( + plain::slice_from_bytes( + &self.data_buffer + [descs_start..descs_start + usize::from(header.block_desc_len())], + ) + .unwrap(), + ) + } else if self.res_standard_inquiry_data().periph_dev_ty() + != cmds::PeriphDeviceType::DirectAccess as u8 + && self.res_standard_inquiry_data().version() == cmds::InquiryVersion::Spc3 as u8 + { + BlkDescSlice::General( + plain::slice_from_bytes( + &self.data_buffer + [descs_start..descs_start + usize::from(header.block_desc_len())], + ) + .unwrap(), + ) } else { - BlkDescSlice::Short(plain::slice_from_bytes(&self.data_buffer[descs_start..descs_start + usize::from(header.block_desc_len())]).unwrap()) + BlkDescSlice::Short( + plain::slice_from_bytes( + &self.data_buffer + [descs_start..descs_start + usize::from(header.block_desc_len())], + ) + .unwrap(), + ) } } @@ -150,15 +216,51 @@ impl Scsi { pub fn get_disk_size(&mut self) -> u64 { self.block_count * u64::from(self.block_size) } - pub fn read(&mut self, protocol: &mut dyn Protocol, lba: u64, buffer: &mut [u8]) -> Result { + pub fn read( + &mut self, + protocol: &mut dyn Protocol, + lba: u64, + buffer: &mut [u8], + ) -> Result { let blocks_to_read = buffer.len() as u64 / u64::from(self.block_size); - let transfer_len = u32::try_from(blocks_to_read * u64::from(self.block_size)).ok().unwrap_or(std::u32::MAX); + let bytes_to_read = blocks_to_read as usize * self.block_size as usize; + let transfer_len = u32::try_from(blocks_to_read).or(Err(ScsiError::Overflow( + "number of blocks to read couldn't fit inside a u32", + )))?; { let read = self.cmd_read16(); *read = cmds::Read16::new(lba, transfer_len, 0); } - let status = protocol.send_command(&self.command_buffer[..16], DeviceReqData::In(&mut buffer[..transfer_len as usize]))?; - Ok(status.bytes_transferred(transfer_len)) + // TODO: Use the to-be-written TransferReadStream instead of relying on everything being + // able to fit within a single buffer. + let status = protocol.send_command( + &self.command_buffer[..16], + DeviceReqData::In(&mut buffer[..bytes_to_read]), + )?; + Ok(status.bytes_transferred(bytes_to_read as u32)) + } + pub fn write( + &mut self, + protocol: &mut dyn Protocol, + lba: u64, + buffer: &[u8], + ) -> Result { + let blocks_to_write = buffer.len() as u64 / u64::from(self.block_size); + let bytes_to_write = blocks_to_write as usize * self.block_size as usize; + let transfer_len = u32::try_from(blocks_to_write).or(Err(ScsiError::Overflow( + "number of blocks to write couldn't fit inside a u32", + )))?; + { + let read = self.cmd_write16(); + *read = cmds::Write16::new(lba, transfer_len, 0); + } + // TODO: Use the to-be-written TransferReadStream instead of relying on everything being + // able to fit within a single buffer. + let status = protocol.send_command( + &self.command_buffer[..16], + DeviceReqData::Out(&buffer[..bytes_to_write]), + )?; + Ok(status.bytes_transferred(bytes_to_write as u32)) } } #[derive(Debug)] diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 5d2c248e12..055bf3096f 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -190,7 +190,9 @@ impl EndpDesc { } pub fn isoch_mult(&self, lec: bool) -> u8 { if !lec && self.is_isoch() { - if self.is_superspeedplus() { return 0 } + if self.is_superspeedplus() { + return 0; + } self.ssc .as_ref() .map(|ssc| ssc.attributes & 0x3) @@ -203,7 +205,9 @@ impl EndpDesc { self.ssc.map(|ssc| ssc.max_burst).unwrap_or(0) } pub fn has_ssp_companion(&self) -> bool { - self.ssc.map(|ssc| ssc.attributes & (1 << 7) != 0).unwrap_or(false) + self.ssc + .map(|ssc| ssc.attributes & (1 << 7) != 0) + .unwrap_or(false) } } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -421,21 +425,12 @@ impl XhciClientHandle { let string = std::fs::read_to_string(path)?; Ok(string.parse()?) } - pub fn open_endpoint_ctl( - &self, - num: u8, - ) -> result::Result { + pub fn open_endpoint_ctl(&self, num: u8) -> result::Result { let path = format!("{}:port{}/endpoints/{}/ctl", self.scheme, self.port, num); Ok(File::open(path)?) } - pub fn open_endpoint_data( - &self, - num: u8, - ) -> result::Result { - let path = format!( - "{}:port{}/endpoints/{}/data", - self.scheme, self.port, num - ); + pub fn open_endpoint_data(&self, num: u8) -> result::Result { + let path = format!("{}:port{}/endpoints/{}/data", self.scheme, self.port, num); Ok(File::open(path)?) } pub fn open_endpoint(&self, num: u8) -> result::Result { @@ -541,13 +536,18 @@ pub struct XhciEndpHandle { ctl: File, } +/// The direction of a transfer. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum XhciEndpCtlDirection { + /// Host to device Out, + /// Device to host In, + /// No data, and hence no I/O on the Data interface file at all. NoData, } +/// A request to an endpoint Ctl interface file. Currently serialized with JSON. #[derive(Clone, Copy, Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum XhciEndpCtlReq { @@ -555,9 +555,19 @@ pub enum XhciEndpCtlReq { // TODO: Allow to send multiple buffers in one transfer. /// Tells xhcid that a buffer is about to be sent from the Data interface file, to the /// endpoint. - Transfer(XhciEndpCtlDirection), - // TODO: Allow clients to specify what to reset. + Transfer { + /// The direction of the transfer. If the direction is `XhciEndpCtlDirection::NoData`, no + /// bytes will be transferred, and therefore no reads or writes shall be done to the Data + /// driver interface file. + direction: XhciEndpCtlDirection, + /// The number of bytes to be read or written. This field must be set to zero if the + /// direction is `XhciEndpCtlDirection::NoData`. When all bytes have been read or written, + /// the transfer will be considered complete by xhcid, and a non-pending status will be + /// returned. + count: u32, + }, + // TODO: Allow clients to specify what to reset. /// Tells xhcid that the endpoint is going to be reset. Reset { /// Only issue the Reset Endpoint and Set TR Dequeue Pointer commands, and let the client @@ -568,6 +578,7 @@ pub enum XhciEndpCtlReq { /// Tells xhcid that the endpoint status is going to be retrieved from the Ctl interface file. Status, } +/// A response from an endpoint Ctl interface file. Currently serialized with JSON. #[derive(Clone, Copy, Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum XhciEndpCtlRes { @@ -586,9 +597,9 @@ pub enum XhciEndpCtlRes { impl XhciEndpHandle { fn ctl_req(&mut self, ctl_req: &XhciEndpCtlReq) -> result::Result<(), XhciClientHandleError> { - let ctl_buffer = serde_json::to_vec(ctl_req)?; + let ctl_buffer = serde_json::to_vec(ctl_req).expect("serde"); - let ctl_bytes_written = self.ctl.write(&ctl_buffer)?; + let ctl_bytes_written = self.ctl.write(&ctl_buffer).expect("ctlwrite"); if ctl_bytes_written != ctl_buffer.len() { return Err(Invalid("xhcid didn't process all of the ctl bytes").into()); } @@ -598,7 +609,7 @@ impl XhciEndpHandle { fn ctl_res(&mut self) -> result::Result { // a response must never exceed 256 bytes let mut ctl_buffer = [0u8; 256]; - let ctl_bytes_read = self.ctl.read(&mut ctl_buffer)?; + let ctl_bytes_read = self.ctl.read(&mut ctl_buffer).expect("ctlread"); let ctl_res = serde_json::from_slice(&ctl_buffer[..ctl_bytes_read as usize])?; Ok(ctl_res) @@ -607,35 +618,89 @@ impl XhciEndpHandle { self.ctl_req(&XhciEndpCtlReq::Reset { no_clear_feature }) } pub fn status(&mut self) -> result::Result { - self.ctl_req(&XhciEndpCtlReq::Status)?; - match self.ctl_res()? { + self.ctl_req(&XhciEndpCtlReq::Status) + .expect("status ctlreq"); + match self.ctl_res().expect("status ctlres") { XhciEndpCtlRes::Status(s) => Ok(s), _ => Err(Invalid("expected status response").into()), } } - fn generic_transfer io::Result>(&mut self, direction: XhciEndpCtlDirection, f: F, expected_len: usize) -> result::Result { - let req = XhciEndpCtlReq::Transfer(direction); - self.ctl_req(&req)?; + fn generic_transfer io::Result>( + &mut self, + direction: XhciEndpCtlDirection, + f: F, + expected_len: u32, + ) -> result::Result { + let req = XhciEndpCtlReq::Transfer { + direction, + count: expected_len, + }; + self.ctl_req(&req).expect("ctl_req"); - let bytes_read = f(&mut self.data)?; - let res = self.ctl_res()?; + let bytes_read = f(&mut self.data).expect("f"); + let res = self.ctl_res().expect("ctl_res"); match res { - XhciEndpCtlRes::TransferResult(PortTransferStatus::Success) if bytes_read != expected_len => Err(Invalid("no short packet, but fewer bytes were read/written").into()), + XhciEndpCtlRes::TransferResult(PortTransferStatus::Success) + if bytes_read != expected_len as usize => + { + Err(Invalid("no short packet, but fewer bytes were read/written").into()) + } XhciEndpCtlRes::TransferResult(r) => Ok(r), _ => Err(Invalid("expected transfer result").into()), } } - pub fn transfer_write(&mut self, buf: &[u8]) -> result::Result { - self.generic_transfer(XhciEndpCtlDirection::Out, |data| data.write(buf), buf.len()) + pub fn transfer_write( + &mut self, + buf: &[u8], + ) -> result::Result { + self.generic_transfer( + XhciEndpCtlDirection::Out, + |data| data.write(buf), + buf.len() as u32, + ) } - pub fn transfer_read(&mut self, buf: &mut [u8]) -> result::Result { - let len = buf.len(); + pub fn transfer_read( + &mut self, + buf: &mut [u8], + ) -> result::Result { + let len = buf.len() as u32; self.generic_transfer(XhciEndpCtlDirection::In, |data| data.read(buf), len) } - pub fn transfer_nodata(&mut self, buf: &[u8]) -> result::Result { - self.generic_transfer(XhciEndpCtlDirection::NoData, |_| Ok(0), buf.len()) + pub fn transfer_nodata(&mut self) -> result::Result { + self.generic_transfer(XhciEndpCtlDirection::NoData, |_| Ok(0), 0) } + fn transfer_stream(&mut self, total_len: u32) -> TransferStream { + TransferStream { + bytes_to_transfer: total_len, + bytes_transferred: 0, + bytes_per_transfer: 32768, // TODO + endp_handle: self, + } + } + pub fn transfer_write_stream(&mut self, total_len: u32) -> TransferWriteStream { + TransferWriteStream { + inner: self.transfer_stream(total_len), + } + } + pub fn transfer_read_stream(&mut self, total_len: u32) -> TransferReadStream { + TransferReadStream { + inner: self.transfer_stream(total_len), + } + } +} + +pub struct TransferWriteStream<'a> { + inner: TransferStream<'a>, +} +pub struct TransferReadStream<'a> { + inner: TransferStream<'a>, +} +struct TransferStream<'a> { + bytes_to_transfer: u32, + bytes_transferred: u32, + bytes_per_transfer: u32, + endp_handle: &'a mut XhciEndpHandle, } #[derive(Debug, Error)] @@ -651,4 +716,7 @@ pub enum XhciClientHandleError { #[error("transfer buffer too large ({0} > 65536)")] TransferBufTooLarge(usize), + + #[error("unexpected short packet of size {0}")] + UnexpectedShortPacket(usize), } diff --git a/xhcid/src/usb/bos.rs b/xhcid/src/usb/bos.rs index 116a8f6d76..ea6c0cfe23 100644 --- a/xhcid/src/usb/bos.rs +++ b/xhcid/src/usb/bos.rs @@ -75,7 +75,12 @@ impl BosSuperSpeedPlusDesc { (self.attrs & 0x0000_000F) as u8 } pub fn sublink_speed_attr(&self) -> &[u32] { - unsafe { slice::from_raw_parts(&self.sublink_speed_attr as *const u32, self.ssac() as usize + 1) } + unsafe { + slice::from_raw_parts( + &self.sublink_speed_attr as *const u32, + self.ssac() as usize + 1, + ) + } } } @@ -155,7 +160,9 @@ impl<'a> Iterator for BosAnyDevDescIter<'a> { } else if base.cap_ty == DeviceCapability::SuperSpeed as u8 { Some(BosAnyDevDesc::SuperSpeed(*plain::from_bytes(slice).ok()?)) } else if base.cap_ty == DeviceCapability::SuperSpeedPlus as u8 { - Some(BosAnyDevDesc::SuperSpeedPlus(*plain::from_bytes(slice).ok()?)) + Some(BosAnyDevDesc::SuperSpeedPlus( + *plain::from_bytes(slice).ok()?, + )) } else if base.cap_ty == 0 { // TODO return None; diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 4b22430793..00de50dfce 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -2,7 +2,8 @@ pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuper pub use self::config::ConfigDescriptor; pub use self::device::DeviceDescriptor; pub use self::endpoint::{ - EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK, + EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, + SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK, }; pub use self::interface::InterfaceDescriptor; pub use self::setup::Setup; diff --git a/xhcid/src/xhci/extended.rs b/xhcid/src/xhci/extended.rs index 2330b29f0d..6e303c30b7 100644 --- a/xhcid/src/xhci/extended.rs +++ b/xhcid/src/xhci/extended.rs @@ -126,16 +126,28 @@ impl ProtocolSpeed { self.psim() == 5 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeed } pub fn is_superspeedplus_gen2x1(&self) -> bool { - self.psim() == 10 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus + self.psim() == 10 + && self.psie() == Psie::Gbps + && self.pfd() + && self.lp() == Lp::SuperSpeedPlus } pub fn is_superspeedplus_gen1x2(&self) -> bool { - self.psim() == 10 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus + self.psim() == 10 + && self.psie() == Psie::Gbps + && self.pfd() + && self.lp() == Lp::SuperSpeedPlus } pub fn is_superspeedplus_gen2x2(&self) -> bool { - self.psim() == 20 && self.psie() == Psie::Gbps && self.pfd() && self.lp() == Lp::SuperSpeedPlus + self.psim() == 20 + && self.psie() == Psie::Gbps + && self.pfd() + && self.lp() == Lp::SuperSpeedPlus } pub fn is_superspeed_gen_x(&self) -> bool { - self.is_superspeed_gen1x1() || self.is_superspeedplus_gen2x1() || self.is_superspeedplus_gen1x2() || self.is_superspeedplus_gen2x2() + self.is_superspeed_gen1x1() + || self.is_superspeedplus_gen2x1() + || self.is_superspeedplus_gen1x2() + || self.is_superspeedplus_gen2x2() } /// Protocol speed ID value pub fn psiv(&self) -> u8 { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index e71c9dc225..d8f27df065 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -301,7 +301,8 @@ impl Xhci { pub fn enable_port_slot(&mut self, slot_ty: u8) -> Result { assert_eq!(slot_ty & 0x1F, slot_ty); - let cloned_event_trb = self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?; + let cloned_event_trb = + self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?; Ok(cloned_event_trb.event_slot()) } pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> { @@ -329,7 +330,10 @@ impl Xhci { println!(" - Enable slot"); - let slot_ty = self.supported_protocol(i as u8).expect("Failed to find supported protocol information for port").proto_slot_ty(); + let slot_ty = self + .supported_protocol(i as u8) + .expect("Failed to find supported protocol information for port") + .proto_slot_ty(); let slot = self.enable_port_slot(slot_ty)?; println!(" - Slot {}", slot); @@ -358,7 +362,7 @@ impl Xhci { EndpointState { transfer: RingOrStreams::Ring(ring), driver_if_state: EndpIfState::Init, - } + }, )) .collect::>(), }; @@ -379,7 +383,12 @@ impl Xhci { Ok(()) } - pub fn update_default_control_pipe(&mut self, input_context: &mut Dma, slot_id: u8, dev_desc: &DevDesc) -> Result<()> { + pub fn update_default_control_pipe( + &mut self, + input_context: &mut Dma, + slot_id: u8, + dev_desc: &DevDesc, + ) -> Result<()> { input_context.add_context.write(1 << 1); input_context.drop_context.write(0); @@ -393,14 +402,21 @@ impl Xhci { b &= 0x0000_FFFF; b |= (new_max_packet_size) << 16; endp_ctx.b.write(b); - + self.execute_command("EVALUATE_CONTEXT", |trb, cycle| { trb.evaluate_context(slot_id, input_context.physical(), false, cycle) })?; Ok(()) } - pub fn address_device(&mut self, input_context: &mut Dma, i: usize, slot_ty: u8, slot: u8, speed: u8) -> Result { + pub fn address_device( + &mut self, + input_context: &mut Dma, + i: usize, + slot_ty: u8, + slot: u8, + speed: u8, + ) -> Result { let mut ring = Ring::new(true)?; { @@ -418,7 +434,7 @@ impl Xhci { route_string | (u32::from(mtt) << 25) | (u32::from(hub) << 26) - | (u32::from(context_entries) << 27) + | (u32::from(context_entries) << 27), ); let max_exit_latency = 0u16; @@ -427,7 +443,7 @@ impl Xhci { slot_ctx.b.write( u32::from(max_exit_latency) | (u32::from(root_hub_port_num) << 16) - | (u32::from(number_of_ports) << 24) + | (u32::from(number_of_ports) << 24), ); // TODO @@ -441,12 +457,14 @@ impl Xhci { u32::from(parent_hud_slot_id) | (u32::from(parent_port_num) << 8) | (u32::from(ttt) << 16) - | (u32::from(interrupter) << 22) + | (u32::from(interrupter) << 22), ); let endp_ctx = &mut input_context.device.endpoints[0]; - let speed_id = self.lookup_psiv(root_hub_port_num, speed).expect("Failed to retrieve speed ID"); + let speed_id = self + .lookup_psiv(root_hub_port_num, speed) + .expect("Failed to retrieve speed ID"); let max_error_count = 3u8; // recommended value according to the XHCI spec let ep_ty = 4u8; // control endpoint, bidirectional @@ -470,19 +488,20 @@ impl Xhci { | (u32::from(ep_ty) << 3) | (u32::from(host_initiate_disable) << 7) | (u32::from(max_burst_size) << 8) - | (u32::from(max_packet_size) << 16) + | (u32::from(max_packet_size) << 16), ); let tr = ring.register(); endp_ctx.trh.write((tr >> 32) as u32); endp_ctx.trl.write(tr as u32); } - + let input_context_physical = input_context.physical(); self.execute_command("ADDRESS_DEVICE", |trb, cycle| { trb.address_device(slot, input_context_physical, false, cycle) - }).expect("ADDRESS_DEVICE failed"); + }) + .expect("ADDRESS_DEVICE failed"); Ok(ring) } @@ -584,8 +603,7 @@ impl Xhci { }) } pub fn supported_protocol(&self, port: u8) -> Option<&'static SupportedProtoCap> { - self - .supported_protocols_iter() + self.supported_protocols_iter() .find(|supp_proto| supp_proto.compat_port_range().contains(&port)) } pub fn supported_protocol_speeds( diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 11465d64fb..50fb886b2b 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -9,8 +9,9 @@ use syscall::io::{Dma, Io}; use syscall::scheme::SchemeMut; use syscall::{ Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, - ENOSYS, ENOTDIR, ENXIO, EOPNOTSUPP, EOVERFLOW, EPERM, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, - O_CREAT, O_DIRECTORY, O_RDONLY, O_RDWR, O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, + ENOSYS, ENOTDIR, ENXIO, EOPNOTSUPP, EOVERFLOW, EPERM, EPROTO, ESPIPE, MODE_CHR, MODE_DIR, + MODE_FILE, O_CREAT, O_DIRECTORY, O_RDONLY, O_RDWR, O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, + SEEK_SET, }; use super::{port, usb}; @@ -18,7 +19,8 @@ use super::{Device, EndpointState, Xhci}; use super::command::CommandRing; use super::context::{ - InputContext, SlotState, StreamContext, StreamContextArray, StreamContextType, ENDPOINT_CONTEXT_STATUS_MASK, + InputContext, SlotState, StreamContext, StreamContextArray, StreamContextType, + ENDPOINT_CONTEXT_STATUS_MASK, }; use super::doorbell::Doorbell; use super::extended::ProtocolSpeed; @@ -38,7 +40,11 @@ pub enum ControlFlow { #[derive(Clone, Copy, Debug)] pub enum EndpIfState { Init, - WaitingForDataPipe(XhciEndpCtlDirection), + WaitingForDataPipe { + direction: XhciEndpCtlDirection, + bytes_transferred: u32, + bytes_to_transfer: u32, + }, WaitingForStatus, WaitingForTransferResult(PortTransferStatus), } @@ -205,7 +211,11 @@ impl AnyDescriptor { } impl Xhci { - pub fn execute_command(&mut self, cmd_name: &str, f: F) -> Result { + pub fn execute_command( + &mut self, + cmd_name: &str, + f: F, + ) -> Result { self.run.ints[0].erdp.write(self.cmd.erdp()); let (cmd, cycle, event) = self.cmd.next(); @@ -232,12 +242,22 @@ impl Xhci { self.run.ints[0].erdp.write(self.cmd.erdp()); Ok(ret) } - pub fn execute_control_transfer(&mut self, port_num: usize, setup: usb::Setup, tk: TransferKind, name: &str, mut d: D) -> Result - where - D: FnMut(&mut Trb, bool) -> ControlFlow, + pub fn execute_control_transfer( + &mut self, + port_num: usize, + setup: usb::Setup, + tk: TransferKind, + name: &str, + mut d: D, + ) -> Result + where + D: FnMut(&mut Trb, bool) -> ControlFlow, { let slot = self.port_state(port_num)?.slot; - let ring = self.endpoint_state_mut(port_num, 0)?.ring().ok_or(Error::new(EIO))?; + let ring = self + .endpoint_state_mut(port_num, 0)? + .ring() + .ok_or(Error::new(EIO))?; { let (cmd, cycle) = ring.next(); @@ -264,8 +284,16 @@ impl Xhci { println!(" - {} Waiting for event", name); } - if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::Transfer as u8 { - println!("{} CONTROL TRANSFER ERROR, EVENT TRB {:#0x} {:#0x} {:#0}»", name, event.data.read(), event.status.read(), event.control.read()); + if event.completion_code() != TrbCompletionCode::Success as u8 + || event.trb_type() != TrbType::Transfer as u8 + { + println!( + "{} CONTROL TRANSFER ERROR, EVENT TRB {:#0x} {:#0x} {:#0}»", + name, + event.data.read(), + event.status.read(), + event.control.read() + ); } event.clone() }; @@ -276,9 +304,16 @@ impl Xhci { } /// NOTE: There has to be AT LEAST one successful invocation of `d`, that actually updates the /// TRB (it could be a NO-OP in the worst case). - pub fn execute_transfer(&mut self, port_num: usize, endp_num: u8, stream_id: u16, name: &str, mut d: D) -> Result - where - D: FnMut(&mut Trb, bool) -> ControlFlow, + pub fn execute_transfer( + &mut self, + port_num: usize, + endp_num: u8, + stream_id: u16, + name: &str, + mut d: D, + ) -> Result + where + D: FnMut(&mut Trb, bool) -> ControlFlow, { let port_state = self.port_state_mut(port_num)?; let slot = port_state.slot; @@ -287,15 +322,18 @@ impl Xhci { .get_mut(&endp_num) .ok_or(Error::new(EBADF))?; - let ring: &mut Ring = match endp_state { - EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. } => ring, - EndpointState { transfer: super::RingOrStreams::Streams(stream_ctx_array), .. } => { - stream_ctx_array - .rings - .get_mut(&1) - .ok_or(Error::new(EBADF))? - } + EndpointState { + transfer: super::RingOrStreams::Ring(ref mut ring), + .. + } => ring, + EndpointState { + transfer: super::RingOrStreams::Streams(stream_ctx_array), + .. + } => stream_ctx_array + .rings + .get_mut(&1) + .ok_or(Error::new(EBADF))?, }; loop { @@ -306,7 +344,11 @@ impl Xhci { } } - self.dbs[usize::from(slot)].write(Self::endp_doorbell(endp_num, self.endp_desc(port_num, endp_num)?, stream_id)); + self.dbs[usize::from(slot)].write(Self::endp_doorbell( + endp_num, + self.endp_desc(port_num, endp_num)?, + stream_id, + )); let cloned_trb = { let event = self.cmd.next_event(); @@ -347,7 +389,13 @@ impl Xhci { Ok(cloned_trb) } fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { - self.execute_control_transfer(port, req, TransferKind::NoData, "DEVICE_REQ_NO_DATA", |_, _| ControlFlow::Break)?; + self.execute_control_transfer( + port, + req, + TransferKind::NoData, + "DEVICE_REQ_NO_DATA", + |_, _| ControlFlow::Break, + )?; Ok(()) } fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { @@ -374,7 +422,9 @@ impl Xhci { .ok_or(Error::new(EBADF))? .slot; - self.execute_command("RESET_ENDPOINT", |trb, cycle| trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle))?; + self.execute_command("RESET_ENDPOINT", |trb, cycle| { + trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle) + })?; Ok(()) } @@ -391,7 +441,11 @@ impl Xhci { } else if speed_id.is_fullspeed() && endp_desc.is_isoch() { // bInterval has values 1-16, ranging from 1 ms to 32,768 ms. endp_desc.interval - 1 + MILLISEC_PERIODS - } else if (speed_id.is_fullspeed() || endp_desc.is_superspeed() || endp_desc.is_superspeedplus()) && (endp_desc.is_interrupt() || endp_desc.is_isoch()) { + } else if (speed_id.is_fullspeed() + || endp_desc.is_superspeed() + || endp_desc.is_superspeedplus()) + && (endp_desc.is_interrupt() || endp_desc.is_isoch()) + { // bInterval has values 1-16, but ranging from 125 µs to 4096 ms. endp_desc.interval - 1 } else { @@ -399,7 +453,11 @@ impl Xhci { 0 } } - fn endp_ctx_max_burst(speed_id: &ProtocolSpeed, dev_desc: &DevDesc, endp_desc: &EndpDesc) -> u8 { + fn endp_ctx_max_burst( + speed_id: &ProtocolSpeed, + dev_desc: &DevDesc, + endp_desc: &EndpDesc, + ) -> u8 { if speed_id.is_highspeed() && (endp_desc.is_interrupt() || endp_desc.is_isoch()) { assert_eq!(dev_desc.major_version(), 2); ((endp_desc.max_packet_size & 0x0C00) >> 11) as u8 @@ -408,13 +466,18 @@ impl Xhci { } else { 0 } - } fn endp_ctx_max_packet_size(endp_desc: &EndpDesc) -> u16 { // TODO: Control endpoint? Encoding? endp_desc.max_packet_size & 0x07FF } - fn endp_ctx_max_esit_payload(speed_id: &ProtocolSpeed, dev_desc: &DevDesc, endp_desc: &EndpDesc, max_packet_size: u16, max_burst_size: u8) -> u32 { + fn endp_ctx_max_esit_payload( + speed_id: &ProtocolSpeed, + dev_desc: &DevDesc, + endp_desc: &EndpDesc, + max_packet_size: u16, + max_burst_size: u8, + ) -> u32 { const KIB: u32 = 1024; if dev_desc.major_version() == 2 && endp_desc.is_periodic() { @@ -427,7 +490,9 @@ impl Xhci { 64 } else if speed_id.is_fullspeed() && endp_desc.is_isoch() { 1 * KIB - } else if (speed_id.is_highspeed() && (endp_desc.is_interrupt() || endp_desc.is_isoch())) || endp_desc.is_superspeed() && endp_desc.is_interrupt() { + } else if (speed_id.is_highspeed() && (endp_desc.is_interrupt() || endp_desc.is_isoch())) + || endp_desc.is_superspeed() && endp_desc.is_interrupt() + { 3 * KIB } else if endp_desc.is_superspeed() && endp_desc.is_isoch() { 48 * KIB @@ -444,13 +509,21 @@ impl Xhci { self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) } fn endpoint_state_mut(&mut self, port: usize, endp_num: u8) -> Result<&mut EndpointState> { - self.port_state_mut(port)?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF)) + self.port_state_mut(port)? + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADF)) } fn input_context(&mut self, port: usize) -> Result<&mut Dma> { Ok(&mut self.port_state_mut(port)?.input_context) } - fn endp_ctx(&mut self, port: usize, endp_num_xhc: u8) -> Result<&mut super::context::EndpointContext> { - Ok(self.input_context(port)? + fn endp_ctx( + &mut self, + port: usize, + endp_num_xhc: u8, + ) -> Result<&mut super::context::EndpointContext> { + Ok(self + .input_context(port)? .device .endpoints .get_mut(endp_num_xhc as usize - 1) @@ -463,10 +536,22 @@ impl Xhci { Ok(&self.dev_desc(port)?.config_descs) } fn config_desc(&self, port: usize, desc: u8) -> Result<&ConfDesc> { - Ok(self.config_descs(port)?.get(usize::from(desc)).ok_or(Error::new(EBADF))?) + Ok(self + .config_descs(port)? + .get(usize::from(desc)) + .ok_or(Error::new(EBADF))?) } fn endp_descs(&self, port: usize, config_desc: u8, if_desc: u8) -> Result<&[EndpDesc]> { - Ok(&self.port_state(port)?.dev_desc.config_descs.get(usize::from(config_desc)).ok_or(Error::new(EIO))?.interface_descs.get(usize::from(if_desc)).ok_or(Error::new(EIO))?.endpoints) + Ok(&self + .port_state(port)? + .dev_desc + .config_descs + .get(usize::from(config_desc)) + .ok_or(Error::new(EIO))? + .interface_descs + .get(usize::from(if_desc)) + .ok_or(Error::new(EIO))? + .endpoints) } fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = @@ -485,22 +570,28 @@ impl Xhci { } let (endp_desc_count, new_context_entries) = { - let endpoints = self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?; + let endpoints = + self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?; if endpoints.len() >= 31 { return Err(Error::new(EIO)); } - (endpoints.len(), (match endpoints.last() { - Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l), - None => 1, - }) + 1) + ( + endpoints.len(), + (match endpoints.last() { + Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l), + None => 1, + }) + 1, + ) }; let lec = self.cap.lec(); let max_psa_size = self.cap.max_psa_size(); let port_speed_id = self.ports[port].speed(); - let speed_id: &ProtocolSpeed = self.lookup_psiv(port as u8, port_speed_id).ok_or(Error::new(EIO))?; + let speed_id: &ProtocolSpeed = self + .lookup_psiv(port as u8, port_speed_id) + .ok_or(Error::new(EIO))?; { let input_context = self.input_context(port)?; @@ -526,11 +617,11 @@ impl Xhci { ); } - for endp_idx in 0..endp_desc_count as u8 { let endp_num = endp_idx + 1; - let endpoints = self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?; + let endpoints = + self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?; let dev_desc = self.dev_desc(port)?; let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; @@ -554,7 +645,13 @@ impl Xhci { let max_packet_size = Self::endp_ctx_max_packet_size(endp_desc); let max_burst_size = Self::endp_ctx_max_burst(speed_id, dev_desc, endp_desc); - let max_esit_payload = Self::endp_ctx_max_esit_payload(speed_id, dev_desc, endp_desc, max_packet_size, max_burst_size); + let max_esit_payload = Self::endp_ctx_max_esit_payload( + speed_id, + dev_desc, + endp_desc, + max_packet_size, + max_burst_size, + ); let max_esit_payload_lo = max_esit_payload as u16; let max_esit_payload_hi = ((max_esit_payload & 0x00FF_0000) >> 16) as u8; @@ -594,7 +691,10 @@ impl Xhci { ); port_state.endpoint_states.insert( endp_num, - EndpointState { transfer: super::RingOrStreams::Streams(array), driver_if_state: EndpIfState::Init }, + EndpointState { + transfer: super::RingOrStreams::Streams(array), + driver_if_state: EndpIfState::Init, + }, ); array_ptr @@ -609,7 +709,10 @@ impl Xhci { ); port_state.endpoint_states.insert( endp_num, - EndpointState { transfer: super::RingOrStreams::Ring(ring), driver_if_state: EndpIfState::Init }, + EndpointState { + transfer: super::RingOrStreams::Ring(ring), + driver_if_state: EndpIfState::Init, + }, ); ring_ptr }; @@ -625,7 +728,7 @@ impl Xhci { | u32::from(primary_streams) << 10 | u32::from(linear_stream_array) << 15 | u32::from(interval) << 16 - | u32::from(max_esit_payload_hi) << 24 + | u32::from(max_esit_payload_hi) << 24, ); endp_ctx.b.write( max_error_count << 1 @@ -638,15 +741,16 @@ impl Xhci { endp_ctx.trl.write(ring_ptr as u32); endp_ctx.trh.write((ring_ptr >> 32) as u32); - endp_ctx.c.write( - u32::from(avg_trb_len) - | (u32::from(max_esit_payload_lo) << 16) - ); + endp_ctx + .c + .write(u32::from(avg_trb_len) | (u32::from(max_esit_payload_lo) << 16)); } let slot = self.port_state(port)?.slot; let input_context_physical = self.input_context(port)?.physical(); - self.execute_command("CONFIGURE_ENDPOINT", |trb, cycle| trb.configure_endpoint(slot, input_context_physical, cycle)); + self.execute_command("CONFIGURE_ENDPOINT", |trb, cycle| { + trb.configure_endpoint(slot, input_context_physical, cycle) + }); // Tell the device about this configuration. let configuration_value = self.config_desc(port, req.config_desc)?.configuration_value; @@ -693,23 +797,29 @@ impl Xhci { // TODO: Wrap DCIs and driver-level endp_num into distinct types, due to the high chance of // mixing the two up. fn endp_num_to_dci(endp_num: u8, desc: &EndpDesc) -> u8 { - if endp_num == 0 { unreachable!("EndpDesc cannot be obtained from the default control endpoint") } + if endp_num == 0 { + unreachable!("EndpDesc cannot be obtained from the default control endpoint") + } if desc.is_control() || desc.direction() == EndpDirection::In { endp_num * 2 + 1 } else if desc.direction() == EndpDirection::Out { endp_num * 2 - } else { unreachable!() } + } else { + unreachable!() + } } fn endp_desc(&self, port_num: usize, endp_num: u8) -> Result<&EndpDesc> { - Ok(self.endp_descs(port_num, 0, 0)?.get(usize::from(endp_num) - 1).ok_or(Error::new(EBADF))?) + Ok(self + .endp_descs(port_num, 0, 0)? + .get(usize::from(endp_num) - 1) + .ok_or(Error::new(EBADF))?) } fn endp_doorbell(endp_num: u8, desc: &EndpDesc, stream_id: u16) -> u32 { let db_target = Self::endp_num_to_dci(endp_num, desc); let db_task_id: u16 = stream_id; - (u32::from(db_task_id) << 16) - | u32::from(db_target) + (u32::from(db_task_id) << 16) | u32::from(db_target) } // TODO: Rename DeviceReqData to something more general. fn transfer( @@ -724,11 +834,17 @@ impl Xhci { // UB. let dma_buffer = match buf { DeviceReqData::Out(sbuf) => { + if sbuf.is_empty() { + return Err(Error::new(EINVAL)); + } let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; dma_buffer.copy_from_slice(sbuf); Some(dma_buffer) } DeviceReqData::In(ref dbuf) => { + if dbuf.is_empty() { + return Err(Error::new(EINVAL)); + } Some(unsafe { Dma::<[u8]>::zeroed_unsized(dbuf.len()) }?) } DeviceReqData::NoData => None, @@ -760,48 +876,73 @@ impl Xhci { return Err(Error::new(EBADF)); } - // TODO: Scatter-gather transfers, possibly allowing >64KiB sizes. - let len = u16::try_from(buf.len()).or(Err(Error::new(ENOSYS)))?; let max_packet_size = endp_desc.max_packet_size; + let max_transfer_size = 65536u32; let (buffer, idt, estimated_td_size) = { - let (buffer, idt) = if len <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { - buf.map_buf(|sbuf| { - let mut bytes = [0u8; 8]; - bytes[..len as usize].copy_from_slice(&sbuf[..len as usize]); - // FIXME: little endian, right? - (u64::from_le_bytes(bytes), true) - }) - .unwrap_or((0, false)) - } else { - ( - dma_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, - false, + let (buffer, idt) = + if buf.len() <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { + buf.map_buf(|sbuf| { + let mut bytes = [0u8; 8]; + bytes[..buf.len()].copy_from_slice(&sbuf[..buf.len()]); + // FIXME: little endian, right? + (u64::from_le_bytes(bytes), true) + }) + .unwrap_or((0, false)) + } else { + ( + dma_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, + false, + ) + }; + let estimated_td_size = cmp::min( + u8::try_from( + div_round_up(buf.len(), max_transfer_size as usize) * mem::size_of::(), ) - }; - let estimated_td_size = mem::size_of::() as u8; // one trb per td + .ok() + .unwrap_or(0x1F), + 0x1F, + ); // one trb per td (buffer, idt, estimated_td_size) }; let stream_id = 1u16; - let event = self.execute_transfer(port_num, endp_num, stream_id, "CUSTOM_TRANSFER", |trb, cycle| { - trb.normal( - buffer, - len, - cycle, - estimated_td_size, - 0, - false, - true, - false, - true, - idt, - false, - ); - ControlFlow::Break - })?; - let bytes_transferred = u32::from(len) - event.transfer_length(); + let mut bytes_left = buf.len(); + + let event = self.execute_transfer( + port_num, + endp_num, + stream_id, + "CUSTOM_TRANSFER", + |trb, cycle| { + let len = cmp::min(bytes_left, max_transfer_size as usize) as u32; + + trb.normal( + buffer, + len, + cycle, + estimated_td_size, + 0, + false, + true, + false, + true, + idt, + false, + ); + + bytes_left -= len as usize; + + if bytes_left != 0 { + ControlFlow::Continue + } else { + ControlFlow::Break + } + }, + )?; + + let bytes_transferred = buf.len() as u32 - event.transfer_length(); if let DeviceReqData::In(dbuf) = &mut buf { dbuf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); @@ -876,7 +1017,8 @@ impl Xhci { let (bos_desc, bos_data) = dev.get_bos()?; let supports_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); - let supports_superspeedplus = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus()); + let supports_superspeedplus = + usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus()); let config_descs = (0..raw_dd.configurations) .map(|index| -> Result<_> { @@ -997,10 +1139,21 @@ impl Xhci { // be better. Maybe something simple like bincode could be used, if a custom binary struct // is too much overkill. - self.execute_control_transfer(port_num, setup, transfer_kind, "CUSTOM_DEVICE_REQ", |trb, cycle| { - trb.data(data_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0), setup.length, transfer_kind == TransferKind::In, cycle); - ControlFlow::Break - })?; + self.execute_control_transfer( + port_num, + setup, + transfer_kind, + "CUSTOM_DEVICE_REQ", + |trb, cycle| { + trb.data( + data_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0), + setup.length, + transfer_kind == TransferKind::In, + cycle, + ); + ControlFlow::Break + }, + )?; Ok(()) } fn port_req_init_st(&mut self, port_num: usize, req: &PortReq) -> Result { @@ -1450,8 +1603,8 @@ impl SchemeMut for Xhci { &mut Handle::Endpoint(port_num, endp_num, ref ep_file_ty) => match ep_file_ty { EndpointHandleTy::Ctl => self.on_write_endp_ctl(port_num, endp_num, buf), EndpointHandleTy::Data => self.on_write_endp_data(port_num, endp_num, buf), - _ => return Err(Error::new(EBADF)), - } + EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), + }, &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); self.handle_port_req_write(fd, port_num, state, buf) @@ -1470,13 +1623,27 @@ impl SchemeMut for Xhci { } impl Xhci { pub fn get_endp_status(&mut self, port_num: usize, endp_num: u8) -> Result { - let slot = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?.slot; + let slot = self + .port_states + .get(&port_num) + .ok_or(Error::new(EBADFD))? + .slot; let endp_num_xhc = if endp_num != 0 { Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?) } else { 1 }; - let raw = self.dev_ctx.contexts.get(slot as usize).ok_or(Error::new(EBADFD))?.endpoints.get(endp_num_xhc as usize - 1).ok_or(Error::new(EBADFD))?.a.read() & super::context::ENDPOINT_CONTEXT_STATUS_MASK; + let raw = self + .dev_ctx + .contexts + .get(slot as usize) + .ok_or(Error::new(EBADFD))? + .endpoints + .get(endp_num_xhc as usize - 1) + .ok_or(Error::new(EBADFD))? + .a + .read() + & super::context::ENDPOINT_CONTEXT_STATUS_MASK; Ok(match raw { 0 => EndpointStatus::Disabled, 1 => EndpointStatus::Enabled, @@ -1486,9 +1653,15 @@ impl Xhci { _ => return Err(Error::new(EIO)), }) } - pub fn on_req_reset_device(&mut self, port_num: usize, endp_num: u8, clear_feature: bool) -> Result<()> { + pub fn on_req_reset_device( + &mut self, + port_num: usize, + endp_num: u8, + clear_feature: bool, + ) -> Result<()> { + dbg!(); if self.get_endp_status(port_num, endp_num)? != EndpointStatus::Halted { - return Err(Error::new(EBADF)); + return Err(Error::new(EPROTO)); } // Change the endpoint state from anything, but most likely HALTED (otherwise resetting // would be quite meaningless), to stopped. @@ -1496,28 +1669,49 @@ impl Xhci { self.restart_endpoint(port_num, endp_num)?; if clear_feature { - self.device_req_no_data(port_num, usb::Setup { - kind: 0b0000_0010, // endpoint recipient - request: 0x01, // CLEAR_FEATURE - value: 0x00, // ENDPOINT_HALT - index: 0, // TODO: interface num - length: 0, - })?; + self.device_req_no_data( + port_num, + usb::Setup { + kind: 0b0000_0010, // endpoint recipient + request: 0x01, // CLEAR_FEATURE + value: 0x00, // ENDPOINT_HALT + index: 0, // TODO: interface num + length: 0, + }, + )?; } Ok(()) } pub fn restart_endpoint(&mut self, port_num: usize, endp_num: u8) -> Result<()> { - let port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; + let port_state = self + .port_states + .get_mut(&port_num) + .ok_or(Error::new(EBADFD))?; let direction = if endp_num != 0 { - let endp_desc = port_state.dev_desc.config_descs.get(0).ok_or(Error::new(EIO))?.interface_descs.get(0).ok_or(Error::new(EIO))?.endpoints.get(endp_num as usize - 1).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state + .dev_desc + .config_descs + .get(0) + .ok_or(Error::new(EIO))? + .interface_descs + .get(0) + .ok_or(Error::new(EIO))? + .endpoints + .get(endp_num as usize - 1) + .ok_or(Error::new(EBADFD))?; endp_desc.direction() } else { EndpDirection::Bidirectional }; - let endpoint_state: &mut EndpointState = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + let endpoint_state: &mut EndpointState = port_state + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADFD))?; let ring = match &mut endpoint_state.transfer { &mut super::RingOrStreams::Ring(ref mut ring) => ring, - &mut super::RingOrStreams::Streams(ref mut arr) => arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?, + &mut super::RingOrStreams::Streams(ref mut arr) => { + arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))? + } }; let (cmd, cycle) = ring.next(); @@ -1529,51 +1723,130 @@ impl Xhci { self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle)?; let stream_id = 1u16; - self.dbs[slot as usize].write(Self::endp_doorbell(endp_num, self.endp_desc(port_num, endp_num)?, stream_id)); + self.dbs[slot as usize].write(Self::endp_doorbell( + endp_num, + self.endp_desc(port_num, endp_num)?, + stream_id, + )); Ok(()) } pub fn endp_direction(&self, port_num: usize, endp_num: u8) -> Result { - Ok(self.port_states.get(&port_num).ok_or(Error::new(EIO))?.dev_desc.config_descs.first().ok_or(Error::new(EIO))?.interface_descs.first().ok_or(Error::new(EIO))?.endpoints.get(endp_num as usize).ok_or(Error::new(EIO))?.direction()) + Ok(self + .port_states + .get(&port_num) + .ok_or(Error::new(EIO))? + .dev_desc + .config_descs + .first() + .ok_or(Error::new(EIO))? + .interface_descs + .first() + .ok_or(Error::new(EIO))? + .endpoints + .get(endp_num as usize) + .ok_or(Error::new(EIO))? + .direction()) } pub fn slot(&self, port_num: usize) -> Result { Ok(self.port_states.get(&port_num).ok_or(Error::new(EIO))?.slot) } - pub fn set_tr_deque_ptr(&mut self, port_num: usize, endp_num: u8, deque_ptr_and_cycle: u64) -> Result<()> { + pub fn set_tr_deque_ptr( + &mut self, + port_num: usize, + endp_num: u8, + deque_ptr_and_cycle: u64, + ) -> Result<()> { let slot = self.slot(port_num)?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?); - self.execute_command("SET_TR_DEQUEUE_POINTER", |trb, cycle| trb.set_tr_deque_ptr(deque_ptr_and_cycle, cycle, StreamContextType::PrimaryRing, 1, endp_num_xhc, slot))?; + self.execute_command("SET_TR_DEQUEUE_POINTER", |trb, cycle| { + trb.set_tr_deque_ptr( + deque_ptr_and_cycle, + cycle, + StreamContextType::PrimaryRing, + 1, + endp_num_xhc, + slot, + ) + })?; Ok(()) } - pub fn on_write_endp_ctl(&mut self, port_num: usize, endp_num: u8, buf: &[u8]) -> Result { - let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; + pub fn on_write_endp_ctl( + &mut self, + port_num: usize, + endp_num: u8, + buf: &[u8], + ) -> Result { + dbg!(); + let ep_if_state = &mut self + .port_states + .get_mut(&port_num) + .ok_or(Error::new(EBADF))? + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADF))? + .driver_if_state; + dbg!(); let req = serde_json::from_slice::(buf).or(Err(Error::new(EBADMSG)))?; + dbg!(); match req { XhciEndpCtlReq::Status => match ep_if_state { state @ EndpIfState::Init => *state = EndpIfState::WaitingForStatus, - _ => return Err(Error::new(EBADF)), - } - XhciEndpCtlReq::Reset { no_clear_feature } => match ep_if_state { - EndpIfState::Init => self.on_req_reset_device(port_num, endp_num, !no_clear_feature)?, - _ => return Err(Error::new(EBADF)), - } - XhciEndpCtlReq::Transfer(direction) => match ep_if_state { - state @ EndpIfState::Init => if direction == XhciEndpCtlDirection::NoData { - // Yield the result directly because no bytes have to be sent or received - // beforehand. - let (completion_code, bytes_transferred) = self.transfer(port_num, endp_num - 1, DeviceReqData::NoData)?; - if bytes_transferred > 0 { return Err(Error::new(EIO)) } - let result = Self::transfer_result(completion_code, 0); - - let new_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; - *new_state = EndpIfState::WaitingForTransferResult(result) - } else { - *state = EndpIfState::WaitingForDataPipe(direction) + other => { + dbg!(other); + return Err(Error::new(EBADF)); } - _ => return Err(Error::new(EBADF)), + }, + XhciEndpCtlReq::Reset { no_clear_feature } => match ep_if_state { + EndpIfState::Init => { + self.on_req_reset_device(port_num, endp_num, !no_clear_feature)? + } + other => { + dbg!(other); + return Err(Error::new(EBADF)); + } + }, + XhciEndpCtlReq::Transfer { direction, count } => match ep_if_state { + state @ EndpIfState::Init => { + if direction == XhciEndpCtlDirection::NoData { + dbg!(); + // Yield the result directly because no bytes have to be sent or received + // beforehand. + let (completion_code, bytes_transferred) = + self.transfer(port_num, endp_num - 1, DeviceReqData::NoData)?; + if bytes_transferred > 0 { + return Err(Error::new(EIO)); + } + let result = Self::transfer_result(completion_code, 0); + dbg!(); + let new_state = &mut self + .port_states + .get_mut(&port_num) + .ok_or(Error::new(EBADF))? + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADF))? + .driver_if_state; + *new_state = EndpIfState::WaitingForTransferResult(result) + } else { + dbg!(); + *state = EndpIfState::WaitingForDataPipe { + direction, + bytes_to_transfer: count, + bytes_transferred: 0, + }; + } + } + other => { + dbg!(other); + return Err(Error::new(EBADF)); + } + }, + other => { + dbg!(other); + return Err(Error::new(EBADF)); } - _ => return Err(Error::new(ENOSYS)), } Ok(buf.len()) } @@ -1588,25 +1861,61 @@ impl Xhci { PortTransferStatus::Unknown } } - pub fn on_write_endp_data(&mut self, port_num: usize, endp_num: u8, buf: &[u8]) -> Result { - { - let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; - match ep_if_state { - state @ EndpIfState::WaitingForDataPipe(XhciEndpCtlDirection::Out) => (), - _ => return Err(Error::new(EBADF)), - } - } - { - let (completion_code, bytes_transferred) = self.transfer_write(port_num, endp_num - 1, buf)?; - let result = Self::transfer_result(completion_code, bytes_transferred); + pub fn on_write_endp_data( + &mut self, + port_num: usize, + endp_num: u8, + buf: &[u8], + ) -> Result { + let ep_if_state = &mut self.endpoint_state_mut(port_num, endp_num)?.driver_if_state; + match ep_if_state { + &mut EndpIfState::WaitingForDataPipe { + direction: XhciEndpCtlDirection::Out, + bytes_to_transfer: total_bytes_to_transfer, + bytes_transferred, + } => { + if buf.len() > total_bytes_to_transfer as usize - bytes_transferred as usize { + return Err(Error::new(EINVAL)); + } + let (completion_code, some_bytes_transferred) = + self.transfer_write(port_num, endp_num - 1, buf)?; + let result = Self::transfer_result(completion_code, some_bytes_transferred); - let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; - *ep_if_state = EndpIfState::WaitingForTransferResult(result); - Ok(bytes_transferred as usize) + let ep_if_state = &mut self.endpoint_state_mut(port_num, endp_num)?.driver_if_state; + + if let &mut EndpIfState::WaitingForDataPipe { + direction: XhciEndpCtlDirection::Out, + bytes_to_transfer, + ref mut bytes_transferred, + } = ep_if_state + { + if *bytes_transferred + some_bytes_transferred == bytes_to_transfer { + *ep_if_state = EndpIfState::WaitingForTransferResult(result); + } else { + *bytes_transferred += some_bytes_transferred; + } + } else { + unreachable!() + } + Ok(some_bytes_transferred as usize) + } + _ => return Err(Error::new(EBADF)), } } - pub fn on_read_endp_ctl(&mut self, port_num: usize, endp_num: u8, buf: &mut [u8]) -> Result { - let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; + pub fn on_read_endp_ctl( + &mut self, + port_num: usize, + endp_num: u8, + buf: &mut [u8], + ) -> Result { + let ep_if_state = &mut self + .port_states + .get_mut(&port_num) + .ok_or(Error::new(EBADF))? + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADF))? + .driver_if_state; let res: XhciEndpCtlRes = match ep_if_state { &mut EndpIfState::Init => XhciEndpCtlRes::Idle, @@ -1615,7 +1924,7 @@ impl Xhci { *state = EndpIfState::Init; XhciEndpCtlRes::Status(self.get_endp_status(port_num, endp_num)?) } - &mut EndpIfState::WaitingForDataPipe(_) => XhciEndpCtlRes::Pending, + &mut EndpIfState::WaitingForDataPipe { .. } => XhciEndpCtlRes::Pending, &mut EndpIfState::WaitingForTransferResult(status) => { *ep_if_state = EndpIfState::Init; XhciEndpCtlRes::TransferResult(status) @@ -1626,21 +1935,70 @@ impl Xhci { serde_json::to_writer(&mut cursor, &res).or(Err(Error::new(EIO)))?; Ok(cursor.seek(io::SeekFrom::Current(0)).unwrap() as usize) } - pub fn on_read_endp_data(&mut self, port_num: usize, endp_num: u8, buf: &mut [u8]) -> Result { - { - let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; - match ep_if_state { - EndpIfState::WaitingForDataPipe(XhciEndpCtlDirection::In) => (), - _ => return Err(Error::new(EBADF)), - } - } - { - let (completion_code, bytes_transferred) = self.transfer_read(port_num, endp_num - 1, buf)?; - let result = Self::transfer_result(completion_code, bytes_transferred); + pub fn on_read_endp_data( + &mut self, + port_num: usize, + endp_num: u8, + buf: &mut [u8], + ) -> Result { + let ep_if_state = &mut self + .port_states + .get_mut(&port_num) + .ok_or(Error::new(EBADF))? + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADF))? + .driver_if_state; + match ep_if_state { + &mut EndpIfState::WaitingForDataPipe { + direction: XhciEndpCtlDirection::In, + bytes_transferred, + bytes_to_transfer: total_bytes_to_transfer, + } => { + if buf.len() > total_bytes_to_transfer as usize - bytes_transferred as usize { + return Err(Error::new(EINVAL)); + } - let ep_if_state = &mut self.port_states.get_mut(&port_num).ok_or(Error::new(EBADF))?.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADF))?.driver_if_state; - *ep_if_state = EndpIfState::WaitingForTransferResult(result); - Ok(bytes_transferred as usize) + let (completion_code, some_bytes_transferred) = + self.transfer_read(port_num, endp_num - 1, buf)?; + let result = Self::transfer_result(completion_code, some_bytes_transferred); + + let ep_if_state = &mut self + .port_states + .get_mut(&port_num) + .ok_or(Error::new(EBADF))? + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADF))? + .driver_if_state; + if let &mut EndpIfState::WaitingForDataPipe { + direction: XhciEndpCtlDirection::In, + bytes_to_transfer, + ref mut bytes_transferred, + } = ep_if_state + { + if *bytes_transferred + some_bytes_transferred == bytes_to_transfer { + *ep_if_state = EndpIfState::WaitingForTransferResult(result); + } else { + *bytes_transferred += some_bytes_transferred; + } + } else { + unreachable!() + } + Ok(some_bytes_transferred as usize) + } + _ => return Err(Error::new(EBADF)), } } } +use std::ops::{Add, Div, Rem}; +fn div_round_up(a: T, b: T) -> T +where + T: Add + Div + Rem + PartialEq + From + Copy, +{ + if a % b != T::from(0u8) { + a / b + T::from(1u8) + } else { + a / b + } +} diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 4dafc85860..d6d4cb30e0 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -213,7 +213,10 @@ impl Trb { self.set( input_ctx_ptr as u64, 0, - (u32::from(slot_id) << 24) | ((TrbType::AddressDevice as u32) << 10) | (u32::from(bsr) << 9) | u32::from(cycle), + (u32::from(slot_id) << 24) + | ((TrbType::AddressDevice as u32) << 10) + | (u32::from(bsr) << 9) + | u32::from(cycle), ); } // Synchronizes the input context endpoints with the device context endpoints, I think. @@ -241,7 +244,10 @@ impl Trb { self.set( input_ctx_ptr as u64, 0, - (u32::from(slot_id) << 24) | ((TrbType::EvaluateContext as u32) << 10) | (u32::from(bsr) << 9) | u32::from(cycle), + (u32::from(slot_id) << 24) + | ((TrbType::EvaluateContext as u32) << 10) + | (u32::from(bsr) << 9) + | u32::from(cycle), ); } pub fn reset_endpoint(&mut self, slot_id: u8, endp_num_xhc: u8, tsp: bool, cycle: bool) { @@ -257,7 +263,15 @@ impl Trb { ); } /// The deque_ptr has to contain the DCS bit (bit 0). - pub fn set_tr_deque_ptr(&mut self, deque_ptr: u64, cycle: bool, sct: StreamContextType, stream_id: u16, endp_num_xhc: u8, slot: u8) { + pub fn set_tr_deque_ptr( + &mut self, + deque_ptr: u64, + cycle: bool, + sct: StreamContextType, + stream_id: u16, + endp_num_xhc: u8, + slot: u8, + ) { assert_eq!(deque_ptr & 0xFFFF_FFFF_FFFF_FFF1, deque_ptr); assert_eq!(endp_num_xhc & 0x1F, endp_num_xhc); @@ -298,7 +312,7 @@ impl Trb { | (u32::from(ioc) << 5) | (u32::from(ch) << 4) | (u32::from(ent) << 1) - | u32::from(cycle) + | u32::from(cycle), ); } @@ -334,7 +348,7 @@ impl Trb { pub fn normal( &mut self, buffer: u64, - len: u16, + len: u32, cycle: bool, estimated_td_size: u8, interrupter: u8, @@ -349,7 +363,7 @@ impl Trb { // NOTE: The interrupter target and no snoop flags have been omitted. self.set( buffer, - u32::from(len) | (u32::from(estimated_td_size) << 17) | (u32::from(interrupter) << 22), + len | (u32::from(estimated_td_size) << 17) | (u32::from(interrupter) << 22), u32::from(cycle) | (u32::from(ent) << 1) | (u32::from(isp) << 2) From 20e5c023919c8982aa40b818efb134800c6ccad9 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Feb 2020 09:55:36 +0100 Subject: [PATCH 0347/1301] Use correct ioc and chain bits when creating trbs. --- xhcid/src/xhci/scheme.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 50fb886b2b..f8c35f877b 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -918,6 +918,10 @@ impl Xhci { |trb, cycle| { let len = cmp::min(bytes_left, max_transfer_size as usize) as u32; + // set the interrupt on completion (IOC) flag for the last trb. + let ioc = bytes_left <= max_transfer_size as usize; + let chain = !ioc; + trb.normal( buffer, len, @@ -926,7 +930,7 @@ impl Xhci { 0, false, true, - false, + chain, true, idt, false, From 4d14310e2dffda14095565abe57529bf626164e7 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Feb 2020 09:56:32 +0100 Subject: [PATCH 0348/1301] Rustfmt. --- usbctl/src/main.rs | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/usbctl/src/main.rs b/usbctl/src/main.rs index 0a48029c9d..fb2f20d1c1 100644 --- a/usbctl/src/main.rs +++ b/usbctl/src/main.rs @@ -1,24 +1,39 @@ -use clap::{Arg, App}; +use clap::{App, Arg}; use xhcid_interface::XhciClientHandle; fn main() { let matches = App::new("usbctl") - .arg(Arg::with_name("SCHEME").takes_value(true).required(true).long("scheme").short("s")) - .subcommand(App::new("port") - .arg(Arg::with_name("PORT").takes_value(true).required(true)) - .subcommand(App::new("status") - ) - .subcommand(App::new("endpoint") - .arg(Arg::with_name("ENDPOINT_NUM").takes_value(true).required(true)) + .arg( + Arg::with_name("SCHEME") + .takes_value(true) + .required(true) + .long("scheme") + .short("s"), + ) + .subcommand( + App::new("port") + .arg(Arg::with_name("PORT").takes_value(true).required(true)) .subcommand(App::new("status")) - ) + .subcommand( + App::new("endpoint") + .arg( + Arg::with_name("ENDPOINT_NUM") + .takes_value(true) + .required(true), + ) + .subcommand(App::new("status")), + ), ) .get_matches(); let scheme = matches.value_of("SCHEME").expect("no scheme"); if let Some(port_scmd_matches) = matches.subcommand_matches("port") { - let port = port_scmd_matches.value_of("PORT").expect("invalid utf-8 for PORT argument").parse::().expect("expected PORT to be an integer"); + let port = port_scmd_matches + .value_of("PORT") + .expect("invalid utf-8 for PORT argument") + .parse::() + .expect("expected PORT to be an integer"); let handle = XhciClientHandle::new(scheme.to_owned(), port); @@ -26,8 +41,14 @@ fn main() { let state = handle.port_state().expect("Failed to get port state"); println!("{}", state.as_str()); } else if let Some(endp_scmd_matches) = port_scmd_matches.subcommand_matches("endpoint") { - let endp_num = endp_scmd_matches.value_of("ENDPOINT_NUM").expect("no valid ENDPOINT_NUM").parse::().expect("expected ENDPOINT_NUM to be an 8-bit integer"); - let mut endp_handle = handle.open_endpoint(endp_num).expect("Failed to open endpoint"); + let endp_num = endp_scmd_matches + .value_of("ENDPOINT_NUM") + .expect("no valid ENDPOINT_NUM") + .parse::() + .expect("expected ENDPOINT_NUM to be an 8-bit integer"); + let mut endp_handle = handle + .open_endpoint(endp_num) + .expect("Failed to open endpoint"); let state = endp_handle.status().expect("Failed to get endpoint state"); println!("{}", state.as_str()); } From 3c9527206fff27dc5f19ce117812430245341517 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Feb 2020 23:54:23 +0100 Subject: [PATCH 0349/1301] Add basic SCSI error handling. --- usbscsid/src/protocol/bot.rs | 40 ++++++++++------------ usbscsid/src/scsi/mod.rs | 38 ++++++++++++--------- xhcid/src/driver_interface.rs | 28 ++++++++-------- xhcid/src/xhci/command.rs | 2 +- xhcid/src/xhci/context.rs | 2 +- xhcid/src/xhci/event.rs | 10 +++--- xhcid/src/xhci/mod.rs | 8 +---- xhcid/src/xhci/ring.rs | 6 ++-- xhcid/src/xhci/scheme.rs | 63 ++++++++++++++++++----------------- 9 files changed, 98 insertions(+), 99 deletions(-) diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index 589dfa367f..62c78f4fd8 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -167,27 +167,23 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { self.current_tag += 1; let tag = self.current_tag; - println!("{}", base64::encode(cb)); - println!(); - let mut cbw_bytes = [0u8; 31]; let cbw = plain::from_mut_bytes::(&mut cbw_bytes).unwrap(); *cbw = CommandBlockWrapper::new(tag, data.len() as u32, data.direction().into(), 0, cb)?; let cbw = *cbw; - println!("{}", base64::encode(&cbw_bytes)); - - dbg!(self.bulk_in.status()?, self.bulk_out.status()?); + // TODO: Is this needed? bulk_only_mass_storage_reset(&self.handle, self.interface_num.into())?; match self.bulk_out.transfer_write(&cbw_bytes)? { PortTransferStatus::Stalled => { - println!("bulk out endpoint stalled when sending CBW"); - self.clear_stall_out()?; - dbg!(self.bulk_in.status()?, self.bulk_out.status()?); + // TODO: Error handling + panic!("bulk out endpoint stalled when sending CBW {:?}", cbw); + //self.clear_stall_out()?; + //dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } PortTransferStatus::ShortPacket(n) if n != 31 => { - panic!("received short packet when sending CBW ({} != 31)", n); + //panic!("received short packet when sending CBW ({} != 31)", n); } _ => (), } @@ -200,8 +196,8 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { panic!("received short packed (len {}) when transferring data", len) } PortTransferStatus::Stalled => { - println!("bulk in endpoint stalled when reading data"); - self.clear_stall_in()?; + panic!("bulk in endpoint stalled when reading data"); + //self.clear_stall_in()?; } PortTransferStatus::Unknown => { return Err(ProtocolError::XhciError( @@ -211,16 +207,15 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { )) } }; - println!("{}", base64::encode(&buffer[..])); } DeviceReqData::Out(buffer) => match self.bulk_out.transfer_write(buffer)? { PortTransferStatus::Success => (), PortTransferStatus::ShortPacket(len) => { - panic!("received short packed (len {}) when transferring data", len) + panic!("received short packet (len {}) when transferring data", len) } PortTransferStatus::Stalled => { - println!("bulk out endpoint stalled when reading data"); - self.clear_stall_out()?; + panic!("bulk out endpoint stalled when reading data"); + //self.clear_stall_out()?; } PortTransferStatus::Unknown => { return Err(ProtocolError::XhciError( @@ -235,28 +230,27 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { match self.bulk_in.transfer_read(&mut csw_buffer)? { PortTransferStatus::Stalled => { - println!("bulk in endpoint stalled when reading CSW"); - self.clear_stall_in()?; + panic!("bulk in endpoint stalled when reading CSW"); + //self.clear_stall_in()?; } PortTransferStatus::ShortPacket(n) if n != 13 => { panic!("received a short packet when reading CSW ({} != 13)", n) } _ => (), }; - println!("{}", base64::encode(&csw_buffer)); let csw = plain::from_bytes::(&csw_buffer).unwrap(); - dbg!(csw); if !csw.is_valid() || csw.tag != cbw.tag { - self.reset_recovery()?; + panic!("Invald CSW {:?} (for CBW {:?})", csw, cbw); + //self.reset_recovery()?; } - if self.bulk_in.status()? == EndpointStatus::Halted + /*if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted { println!("Trying to recover from stall"); dbg!(self.bulk_in.status()?, self.bulk_out.status()?); - } + }*/ Ok(SendCommandStatus { kind: if csw.status == CswStatus::Passed as u8 { diff --git a/usbscsid/src/scsi/mod.rs b/usbscsid/src/scsi/mod.rs index a4b1f3e243..5d4bd2d798 100644 --- a/usbscsid/src/scsi/mod.rs +++ b/usbscsid/src/scsi/mod.rs @@ -25,8 +25,12 @@ const REQUEST_SENSE_CMD_LEN: u8 = 6; const MIN_INQUIRY_ALLOC_LEN: u16 = 5; const MIN_REPORT_SUPP_OPCODES_ALLOC_LEN: u32 = 4; +type Result = Result; + #[derive(Debug, Error)] pub enum ScsiError { + // TODO: Add some kind of context here, since it's very useful indeed to be able to see which + // command returned the protocol error. #[error("protocol error when sending command: {0}")] ProtocolError(#[from] ProtocolError), @@ -35,10 +39,13 @@ pub enum ScsiError { } impl Scsi { - pub fn new(protocol: &mut dyn Protocol) -> Self { + pub fn new(protocol: &mut dyn Protocol) -> Result { assert_eq!(std::mem::size_of::(), 96); + let mut this = Self { command_buffer: [0u8; 16], + // separate buffer since the inquiry data is most likely going to be used in the + // future. inquiry_buffer: [0u8; 259], // additional_len = 255 max data_buffer: Vec::new(), block_size: 0, @@ -46,13 +53,15 @@ impl Scsi { }; // Get the max length that the device supports, of the Standard Inquiry Data. - let max_inquiry_len = this.get_inquiry_alloc_len(protocol); + let max_inquiry_len = this.get_inquiry_alloc_len(protocol)?; // Get the Standard Inquiry Data. - this.get_standard_inquiry_data(protocol, max_inquiry_len); - this.res_standard_inquiry_data(); + this.get_standard_inquiry_data(protocol, max_inquiry_len)?; + + let version = this.res_standard_inquiry_data().version(); + println!("Inquiry version: {}", version); let (block_size, block_count) = { - let (_, blkdescs, mode_page_iter) = this.get_mode_sense10(protocol).unwrap(); + let (_, blkdescs, mode_page_iter) = this.get_mode_sense10(protocol)?; // TODO: Can there be multiple disks at all? let only_blkdesc = blkdescs.get(0).unwrap(); @@ -62,14 +71,14 @@ impl Scsi { this.block_size = block_size; this.block_count = block_count; - this + Ok(this) } - pub fn get_inquiry_alloc_len(&mut self, protocol: &mut dyn Protocol) -> u16 { - self.get_standard_inquiry_data(protocol, MIN_INQUIRY_ALLOC_LEN); + pub fn get_inquiry_alloc_len(&mut self, protocol: &mut dyn Protocol) -> Result { + self.get_standard_inquiry_data(protocol, MIN_INQUIRY_ALLOC_LEN)?; let standard_inquiry_data = self.res_standard_inquiry_data(); - 4 + u16::from(standard_inquiry_data.additional_len) + Ok(4 + u16::from(standard_inquiry_data.additional_len)) } - pub fn get_standard_inquiry_data(&mut self, protocol: &mut dyn Protocol, max_inquiry_len: u16) { + pub fn get_standard_inquiry_data(&mut self, protocol: &mut dyn Protocol, max_inquiry_len: u16) -> Result<()> { let inquiry = self.cmd_inquiry(); *inquiry = cmds::Inquiry::new(false, 0, max_inquiry_len, 0); @@ -77,10 +86,10 @@ impl Scsi { .send_command( &self.command_buffer[..INQUIRY_CMD_LEN as usize], DeviceReqData::In(&mut self.inquiry_buffer[..max_inquiry_len as usize]), - ) - .expect("Failed to send INQUIRY command"); + )?; + Ok(()) } - pub fn get_ff_sense(&mut self, protocol: &mut dyn Protocol, alloc_len: u8) { + pub fn get_ff_sense(&mut self, protocol: &mut dyn Protocol, alloc_len: u8) -> Result<()> { let request_sense = self.cmd_request_sense(); *request_sense = cmds::RequestSense::new(false, alloc_len, 0); self.data_buffer.resize(alloc_len.into(), 0); @@ -88,8 +97,7 @@ impl Scsi { .send_command( &self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize]), - ) - .expect("Failed to send REQUEST_SENSE command"); + )?; } pub fn get_mode_sense10( &mut self, diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 055bf3096f..8d448edc84 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -4,6 +4,7 @@ pub extern crate smallvec; use std::convert::TryFrom; use std::fs::{File, OpenOptions}; use std::io::prelude::*; +use std::num::NonZeroU8; use std::{io, result, str}; use serde::{Deserialize, Serialize}; @@ -176,17 +177,17 @@ impl EndpDesc { self.is_isoch() } } - pub fn max_streams(&self) -> u8 { + pub fn log_max_streams(&self) -> Option { self.ssc .as_ref() .map(|ssc| { if self.is_bulk() { - 1 << (ssc.attributes & 0x1F) + let raw = ssc.attributes & 0x1F; + NonZeroU8::new(raw) } else { - 0 + None } - }) - .unwrap_or(0) + }).flatten() } pub fn isoch_mult(&self, lec: bool) -> u8 { if !lec && self.is_isoch() { @@ -597,9 +598,9 @@ pub enum XhciEndpCtlRes { impl XhciEndpHandle { fn ctl_req(&mut self, ctl_req: &XhciEndpCtlReq) -> result::Result<(), XhciClientHandleError> { - let ctl_buffer = serde_json::to_vec(ctl_req).expect("serde"); + let ctl_buffer = serde_json::to_vec(ctl_req)?; - let ctl_bytes_written = self.ctl.write(&ctl_buffer).expect("ctlwrite"); + let ctl_bytes_written = self.ctl.write(&ctl_buffer)?; if ctl_bytes_written != ctl_buffer.len() { return Err(Invalid("xhcid didn't process all of the ctl bytes").into()); } @@ -609,7 +610,7 @@ impl XhciEndpHandle { fn ctl_res(&mut self) -> result::Result { // a response must never exceed 256 bytes let mut ctl_buffer = [0u8; 256]; - let ctl_bytes_read = self.ctl.read(&mut ctl_buffer).expect("ctlread"); + let ctl_bytes_read = self.ctl.read(&mut ctl_buffer)?; let ctl_res = serde_json::from_slice(&ctl_buffer[..ctl_bytes_read as usize])?; Ok(ctl_res) @@ -618,9 +619,8 @@ impl XhciEndpHandle { self.ctl_req(&XhciEndpCtlReq::Reset { no_clear_feature }) } pub fn status(&mut self) -> result::Result { - self.ctl_req(&XhciEndpCtlReq::Status) - .expect("status ctlreq"); - match self.ctl_res().expect("status ctlres") { + self.ctl_req(&XhciEndpCtlReq::Status)?; + match self.ctl_res()? { XhciEndpCtlRes::Status(s) => Ok(s), _ => Err(Invalid("expected status response").into()), } @@ -635,10 +635,10 @@ impl XhciEndpHandle { direction, count: expected_len, }; - self.ctl_req(&req).expect("ctl_req"); + self.ctl_req(&req)?; - let bytes_read = f(&mut self.data).expect("f"); - let res = self.ctl_res().expect("ctl_res"); + let bytes_read = f(&mut self.data)?; + let res = self.ctl_res()?; match res { XhciEndpCtlRes::TransferResult(PortTransferStatus::Success) diff --git a/xhcid/src/xhci/command.rs b/xhcid/src/xhci/command.rs index 41c539fe2e..ca78d592fe 100644 --- a/xhcid/src/xhci/command.rs +++ b/xhcid/src/xhci/command.rs @@ -12,7 +12,7 @@ pub struct CommandRing { impl CommandRing { pub fn new() -> Result { Ok(CommandRing { - ring: Ring::new(true)?, + ring: Ring::new(16, true)?, events: EventRing::new()?, }) } diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 9403fa0ac5..74944da174 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -141,7 +141,7 @@ impl StreamContextArray { // NOTE: stream_id 0 is reserved assert_ne!(stream_id, 0); - let ring = Ring::new(link)?; + let ring = Ring::new(16, link)?; let pointer = ring.register(); let sct = StreamContextType::PrimaryRing; diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index 903b34cbb6..1ee8367d75 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -13,19 +13,19 @@ pub struct EventRingSte { } pub struct EventRing { - pub ste: Dma, + pub ste: Dma<[EventRingSte]>, pub ring: Ring, } impl EventRing { pub fn new() -> Result { let mut ring = EventRing { - ste: Dma::zeroed()?, - ring: Ring::new(false)?, + ste: unsafe { Dma::zeroed_unsized(1)? }, + ring: Ring::new(32, false)?, }; - ring.ste.address.write(ring.ring.trbs.physical() as u64); - ring.ste.size.write(ring.ring.trbs.len() as u16); + ring.ste[0].address.write(ring.ring.trbs.physical() as u64); + ring.ste[0].size.write(ring.ring.trbs.len() as u16); Ok(ring) } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index d8f27df065..6ccc58281a 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -417,7 +417,7 @@ impl Xhci { slot: u8, speed: u8, ) -> Result { - let mut ring = Ring::new(true)?; + let mut ring = Ring::new(16, true)?; { input_context.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit). @@ -505,12 +505,6 @@ impl Xhci { Ok(ring) } - pub fn ring_command_doorbell(&mut self) { - self.dbs[0].write(0); - } - pub fn ring_port_doorbell(&mut self, slot: u8, endpoint: u8, stream_id: u16) { - self.dbs[slot as usize].write(u32::from(endpoint) | (u32::from(stream_id) << 16)); - } pub fn trigger_irq(&mut self) -> bool { // Read the Interrupter Pending bit. diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index b1fae6ffdb..62aff3a2c6 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -5,16 +5,16 @@ use super::trb::Trb; pub struct Ring { pub link: bool, - pub trbs: Dma<[Trb; 16]>, + pub trbs: Dma<[Trb]>, pub i: usize, pub cycle: bool, } impl Ring { - pub fn new(link: bool) -> Result { + pub fn new(length: usize, link: bool) -> Result { Ok(Ring { link: link, - trbs: Dma::zeroed()?, + trbs: unsafe { Dma::zeroed_unsized(length)? }, i: 0, cycle: link, }) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index f8c35f877b..72dcd19638 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -322,18 +322,18 @@ impl Xhci { .get_mut(&endp_num) .ok_or(Error::new(EBADF))?; - let ring: &mut Ring = match endp_state { + let (has_streams, ring) = match endp_state { EndpointState { transfer: super::RingOrStreams::Ring(ref mut ring), .. - } => ring, + } => (false, ring), EndpointState { transfer: super::RingOrStreams::Streams(stream_ctx_array), .. - } => stream_ctx_array + } => (true, stream_ctx_array .rings .get_mut(&1) - .ok_or(Error::new(EBADF))?, + .ok_or(Error::new(EBADF))?), }; loop { @@ -347,7 +347,7 @@ impl Xhci { self.dbs[usize::from(slot)].write(Self::endp_doorbell( endp_num, self.endp_desc(port_num, endp_num)?, - stream_id, + if has_streams { stream_id } else { 0 }, )); let cloned_trb = { @@ -586,7 +586,7 @@ impl Xhci { ) }; let lec = self.cap.lec(); - let max_psa_size = self.cap.max_psa_size(); + let log_max_psa_size = self.cap.max_psa_size(); let port_speed_id = self.ports[port].speed(); let speed_id: &ProtocolSpeed = self @@ -627,11 +627,16 @@ impl Xhci { let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); - let max_streams = endp_desc.max_streams(); + let usb_log_max_streams = endp_desc.log_max_streams(); // TODO: Secondary streams. - let primary_streams = if max_streams != 0 { - cmp::min(max_streams, max_psa_size) + let primary_streams = if let Some(log_max_streams) = usb_log_max_streams { + // TODO: Can streams-capable be configured to not use streams? + if log_max_psa_size != 0 { + cmp::min(u8::from(log_max_streams), log_max_psa_size + 1) - 1 + } else { + 0 + } } else { 0 }; @@ -677,8 +682,8 @@ impl Xhci { let port_state = self.port_state_mut(port)?; - let ring_ptr = if max_streams != 0 { - let mut array = StreamContextArray::new(1 << (max_streams + 1))?; + let ring_ptr = if usb_log_max_streams.is_some() { + let mut array = StreamContextArray::new(1 << (primary_streams + 1))?; // TODO: Use as many stream rings as needed. array.add_ring(1, true)?; @@ -699,7 +704,7 @@ impl Xhci { array_ptr } else { - let ring = Ring::new(true)?; + let ring = Ring::new(16, true)?; let ring_ptr = ring.register(); assert_eq!( @@ -750,7 +755,7 @@ impl Xhci { let input_context_physical = self.input_context(port)?.physical(); self.execute_command("CONFIGURE_ENDPOINT", |trb, cycle| { trb.configure_endpoint(slot, input_context_physical, cycle) - }); + })?; // Tell the device about this configuration. let configuration_value = self.config_desc(port, req.config_desc)?.configuration_value; @@ -1663,7 +1668,6 @@ impl Xhci { endp_num: u8, clear_feature: bool, ) -> Result<()> { - dbg!(); if self.get_endp_status(port_num, endp_num)? != EndpointStatus::Halted { return Err(Error::new(EPROTO)); } @@ -1711,10 +1715,10 @@ impl Xhci { .endpoint_states .get_mut(&endp_num) .ok_or(Error::new(EBADFD))?; - let ring = match &mut endpoint_state.transfer { - &mut super::RingOrStreams::Ring(ref mut ring) => ring, + let (has_streams, ring) = match &mut endpoint_state.transfer { + &mut super::RingOrStreams::Ring(ref mut ring) => (false, ring), &mut super::RingOrStreams::Streams(ref mut arr) => { - arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))? + (true, arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?) } }; @@ -1730,7 +1734,7 @@ impl Xhci { self.dbs[slot as usize].write(Self::endp_doorbell( endp_num, self.endp_desc(port_num, endp_num)?, - stream_id, + if has_streams { stream_id } else { 0 }, )); Ok(()) } @@ -1782,7 +1786,6 @@ impl Xhci { endp_num: u8, buf: &[u8], ) -> Result { - dbg!(); let ep_if_state = &mut self .port_states .get_mut(&port_num) @@ -1791,14 +1794,11 @@ impl Xhci { .get_mut(&endp_num) .ok_or(Error::new(EBADF))? .driver_if_state; - dbg!(); let req = serde_json::from_slice::(buf).or(Err(Error::new(EBADMSG)))?; - dbg!(); match req { XhciEndpCtlReq::Status => match ep_if_state { state @ EndpIfState::Init => *state = EndpIfState::WaitingForStatus, other => { - dbg!(other); return Err(Error::new(EBADF)); } }, @@ -1807,14 +1807,12 @@ impl Xhci { self.on_req_reset_device(port_num, endp_num, !no_clear_feature)? } other => { - dbg!(other); return Err(Error::new(EBADF)); } }, XhciEndpCtlReq::Transfer { direction, count } => match ep_if_state { state @ EndpIfState::Init => { if direction == XhciEndpCtlDirection::NoData { - dbg!(); // Yield the result directly because no bytes have to be sent or received // beforehand. let (completion_code, bytes_transferred) = @@ -1823,7 +1821,6 @@ impl Xhci { return Err(Error::new(EIO)); } let result = Self::transfer_result(completion_code, 0); - dbg!(); let new_state = &mut self .port_states .get_mut(&port_num) @@ -1834,7 +1831,6 @@ impl Xhci { .driver_if_state; *new_state = EndpIfState::WaitingForTransferResult(result) } else { - dbg!(); *state = EndpIfState::WaitingForDataPipe { direction, bytes_to_transfer: count, @@ -1843,12 +1839,10 @@ impl Xhci { } } other => { - dbg!(other); return Err(Error::new(EBADF)); } }, other => { - dbg!(other); return Err(Error::new(EBADF)); } } @@ -1885,6 +1879,10 @@ impl Xhci { self.transfer_write(port_num, endp_num - 1, buf)?; let result = Self::transfer_result(completion_code, some_bytes_transferred); + // To avoid having to read from the Ctl interface file, the client should stop + // invoking further data transfer calls if any single transfer returns fewer bytes + // than requested. + let ep_if_state = &mut self.endpoint_state_mut(port_num, endp_num)?.driver_if_state; if let &mut EndpIfState::WaitingForDataPipe { @@ -1893,7 +1891,8 @@ impl Xhci { ref mut bytes_transferred, } = ep_if_state { - if *bytes_transferred + some_bytes_transferred == bytes_to_transfer { + if *bytes_transferred + some_bytes_transferred == bytes_to_transfer || completion_code == TrbCompletionCode::ShortPacket as u8 { + // TODO: Add an error flag to WaitingForTransferResult. *ep_if_state = EndpIfState::WaitingForTransferResult(result); } else { *bytes_transferred += some_bytes_transferred; @@ -1965,6 +1964,10 @@ impl Xhci { let (completion_code, some_bytes_transferred) = self.transfer_read(port_num, endp_num - 1, buf)?; + + // Just as with on_write_endp_data, a client issuing multiple reads must always + // stop reading if one read returns fewer bytes than expected. + let result = Self::transfer_result(completion_code, some_bytes_transferred); let ep_if_state = &mut self @@ -1981,7 +1984,7 @@ impl Xhci { ref mut bytes_transferred, } = ep_if_state { - if *bytes_transferred + some_bytes_transferred == bytes_to_transfer { + if *bytes_transferred + some_bytes_transferred == bytes_to_transfer || completion_code == TrbCompletionCode::ShortPacket as u8 { *ep_if_state = EndpIfState::WaitingForTransferResult(result); } else { *bytes_transferred += some_bytes_transferred; From fab13d6404ea5cc1f85e76c06dc89d7b88bc4ead Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 16 Feb 2020 21:27:41 +0100 Subject: [PATCH 0350/1301] Fix get_mode_sense10 and some bbb error handling. --- usbscsid/src/main.rs | 2 +- usbscsid/src/protocol/bot.rs | 141 +++++++++++++--------- usbscsid/src/scsi/mod.rs | 22 ++-- xhcid/{config.toml => config.toml.unused} | 0 xhcid/src/driver_interface.rs | 17 ++- xhcid/src/xhci/scheme.rs | 19 +-- 6 files changed, 121 insertions(+), 80 deletions(-) rename xhcid/{config.toml => config.toml.unused} (100%) diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index d6691d47c5..840dfb44bd 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -90,7 +90,7 @@ fn main() { let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; //syscall::setrens(0, 0).expect("scsid: failed to enter null namespace"); - let mut scsi = Scsi::new(&mut *protocol); + let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI"); let mut buffer = [0u8; 512]; scsi.read(&mut *protocol, 0, &mut buffer).unwrap(); println!("DISK CONTENT: {}", base64::encode(&buffer[..])); diff --git a/usbscsid/src/protocol/bot.rs b/usbscsid/src/protocol/bot.rs index 62c78f4fd8..17e2432b9f 100644 --- a/usbscsid/src/protocol/bot.rs +++ b/usbscsid/src/protocol/bot.rs @@ -3,7 +3,7 @@ use std::slice; use xhcid_interface::{ ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, - PortReqRecipient, PortReqTy, PortTransferStatus, XhciClientHandle, XhciClientHandleError, + PortReqRecipient, PortReqTy, PortTransferStatus, PortTransferStatusKind, XhciClientHandle, XhciClientHandleError, XhciEndpHandle, }; @@ -129,20 +129,26 @@ impl<'a> BulkOnlyTransport<'a> { }) } fn clear_stall_in(&mut self) -> Result<(), XhciClientHandleError> { - self.bulk_in.reset(false)?; - self.handle.clear_feature( - PortReqRecipient::Endpoint, - u16::from(self.bulk_in_num), - FEATURE_ENDPOINT_HALT, - ) + if self.bulk_in.status()? == EndpointStatus::Halted { + self.bulk_in.reset(false)?; + self.handle.clear_feature( + PortReqRecipient::Endpoint, + u16::from(self.bulk_in_num), + FEATURE_ENDPOINT_HALT, + )?; + } + Ok(()) } fn clear_stall_out(&mut self) -> Result<(), XhciClientHandleError> { - self.bulk_out.reset(false)?; - self.handle.clear_feature( - PortReqRecipient::Endpoint, - u16::from(self.bulk_out_num), - FEATURE_ENDPOINT_HALT, - ) + if self.bulk_out.status()? == EndpointStatus::Halted { + self.bulk_out.reset(false)?; + self.handle.clear_feature( + PortReqRecipient::Endpoint, + u16::from(self.bulk_out_num), + FEATURE_ENDPOINT_HALT, + )?; + } + Ok(()) } fn reset_recovery(&mut self) -> Result<(), ProtocolError> { bulk_only_mass_storage_reset(self.handle, self.interface_num.into())?; @@ -156,6 +162,26 @@ impl<'a> BulkOnlyTransport<'a> { } Ok(()) } + fn read_csw_raw(&mut self, csw_buffer: &mut [u8; 13], already: bool) -> Result<(), ProtocolError> { + match self.bulk_in.transfer_read(&mut csw_buffer[..])? { + PortTransferStatus { kind: PortTransferStatusKind::Stalled, .. } => { + if already { + self.reset_recovery()?; + } + println!("bulk in endpoint stalled when reading CSW"); + self.clear_stall_in()?; + self.read_csw_raw(csw_buffer, true)?; + } + PortTransferStatus { kind: PortTransferStatusKind::ShortPacket, bytes_transferred } if bytes_transferred != 13 => { + panic!("received a short packet when reading CSW ({} != 13)", bytes_transferred) + } + _ => (), + } + Ok(()) + } + fn read_csw(&mut self, csw_buffer: &mut [u8; 13]) -> Result<(), ProtocolError> { + self.read_csw_raw(csw_buffer, false) + } } impl<'a> Protocol for BulkOnlyTransport<'a> { @@ -172,77 +198,78 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { *cbw = CommandBlockWrapper::new(tag, data.len() as u32, data.direction().into(), 0, cb)?; let cbw = *cbw; - // TODO: Is this needed? - bulk_only_mass_storage_reset(&self.handle, self.interface_num.into())?; - match self.bulk_out.transfer_write(&cbw_bytes)? { - PortTransferStatus::Stalled => { + PortTransferStatus { kind: PortTransferStatusKind::Stalled, .. } => { // TODO: Error handling panic!("bulk out endpoint stalled when sending CBW {:?}", cbw); //self.clear_stall_out()?; //dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } - PortTransferStatus::ShortPacket(n) if n != 31 => { - //panic!("received short packet when sending CBW ({} != 31)", n); + PortTransferStatus { bytes_transferred, .. } if bytes_transferred != 31 => { + panic!("received short packet when sending CBW ({} != 31)", bytes_transferred); } _ => (), } - match data { - DeviceReqData::In(buffer) => { - match self.bulk_in.transfer_read(buffer)? { - PortTransferStatus::Success => (), - PortTransferStatus::ShortPacket(len) => { - panic!("received short packed (len {}) when transferring data", len) + let early_residue: Option = match data { + DeviceReqData::In(buffer) => match self.bulk_in.transfer_read(buffer)? { + PortTransferStatus { kind, bytes_transferred } => match kind { + PortTransferStatusKind::Success => None, + PortTransferStatusKind::ShortPacket => { + println!("received short packet (len {}) when transferring data", bytes_transferred); + NonZeroU32::new(bytes_transferred) } - PortTransferStatus::Stalled => { + PortTransferStatusKind::Stalled => { panic!("bulk in endpoint stalled when reading data"); //self.clear_stall_in()?; } - PortTransferStatus::Unknown => { + PortTransferStatusKind::Unknown => { return Err(ProtocolError::XhciError( XhciClientHandleError::InvalidResponse(Invalid( "unknown transfer status", )), - )) + )); } - }; + } } DeviceReqData::Out(buffer) => match self.bulk_out.transfer_write(buffer)? { - PortTransferStatus::Success => (), - PortTransferStatus::ShortPacket(len) => { - panic!("received short packet (len {}) when transferring data", len) - } - PortTransferStatus::Stalled => { - panic!("bulk out endpoint stalled when reading data"); - //self.clear_stall_out()?; - } - PortTransferStatus::Unknown => { - return Err(ProtocolError::XhciError( - XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")), - )) + PortTransferStatus { kind, bytes_transferred } => match kind { + PortTransferStatusKind::Success => None, + PortTransferStatusKind::ShortPacket => { + println!("received short packet (len {}) when transferring data", bytes_transferred); + NonZeroU32::new(bytes_transferred) + } + PortTransferStatusKind::Stalled => { + panic!("bulk out endpoint stalled when reading data"); + //self.clear_stall_out()?; + } + PortTransferStatusKind::Unknown => { + return Err(ProtocolError::XhciError( + XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")), + )); + } } }, - DeviceReqData::NoData => (), - } + DeviceReqData::NoData => None, + }; let mut csw_buffer = [0u8; 13]; - - match self.bulk_in.transfer_read(&mut csw_buffer)? { - PortTransferStatus::Stalled => { - panic!("bulk in endpoint stalled when reading CSW"); - //self.clear_stall_in()?; - } - PortTransferStatus::ShortPacket(n) if n != 13 => { - panic!("received a short packet when reading CSW ({} != 13)", n) - } - _ => (), - }; + self.read_csw(&mut csw_buffer)?; let csw = plain::from_bytes::(&csw_buffer).unwrap(); + let residue = early_residue.or(NonZeroU32::new(csw.data_residue)); + + if csw.status == CswStatus::Failed as u8 { + println!("CSW indicated failure (CSW {:?}, CBW {:?})", csw, cbw); + } + if !csw.is_valid() || csw.tag != cbw.tag { - panic!("Invald CSW {:?} (for CBW {:?})", csw, cbw); - //self.reset_recovery()?; + println!("Invald CSW {:?} (for CBW {:?})", csw, cbw); + self.reset_recovery()?; + if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted { + return Err(ProtocolError::ProtocolError("Reset Recovery didn't reset endpoints")); + } + return Err(ProtocolError::ProtocolError("CSW invalid, but a recover was successful")); } /*if self.bulk_in.status()? == EndpointStatus::Halted @@ -262,7 +289,7 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { "bulk-only transport phase error, or other", )); }, - residue: NonZeroU32::new(csw.data_residue), + residue, }) } } diff --git a/usbscsid/src/scsi/mod.rs b/usbscsid/src/scsi/mod.rs index 5d4bd2d798..0bbf289d2a 100644 --- a/usbscsid/src/scsi/mod.rs +++ b/usbscsid/src/scsi/mod.rs @@ -25,7 +25,7 @@ const REQUEST_SENSE_CMD_LEN: u8 = 6; const MIN_INQUIRY_ALLOC_LEN: u16 = 5; const MIN_REPORT_SUPP_OPCODES_ALLOC_LEN: u32 = 4; -type Result = Result; +type Result = std::result::Result; #[derive(Debug, Error)] pub enum ScsiError { @@ -57,7 +57,7 @@ impl Scsi { // Get the Standard Inquiry Data. this.get_standard_inquiry_data(protocol, max_inquiry_len)?; - let version = this.res_standard_inquiry_data().version(); + let version = dbg!(this.res_standard_inquiry_data()).version(); println!("Inquiry version: {}", version); let (block_size, block_count) = { @@ -98,6 +98,7 @@ impl Scsi { &self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize], DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize]), )?; + Ok(()) } pub fn get_mode_sense10( &mut self, @@ -107,10 +108,9 @@ impl Scsi { &cmds::ModeParamHeader10, BlkDescSlice, impl Iterator, - ), - ScsiError, + ) > { - let initial_alloc_len = 4; // covers both mode_data_len and blk_desc_len. + let initial_alloc_len = mem::size_of::() as u16; // covers both mode_data_len and blk_desc_len. let mode_sense10 = self.cmd_mode_sense10(); *mode_sense10 = cmds::ModeSense10::get_block_desc(initial_alloc_len, 0); self.data_buffer @@ -122,13 +122,13 @@ impl Scsi { &self.command_buffer[..10], DeviceReqData::In(&mut self.data_buffer[..initial_alloc_len as usize]), )? { - self.get_ff_sense(protocol, 252); + self.get_ff_sense(protocol, 252)?; panic!("{:?}", self.res_ff_sense_data()); } - let optimal_alloc_len = self.res_mode_param_header10().block_desc_len() - + self.res_mode_param_header10().mode_data_len() - + mem::size_of::() as u16; + let optimal_alloc_len = + self.res_mode_param_header10().mode_data_len() + + 2; // the length of the mode data field itself let mode_sense10 = self.cmd_mode_sense10(); *mode_sense10 = cmds::ModeSense10::get_block_desc(optimal_alloc_len, 0); @@ -229,7 +229,7 @@ impl Scsi { protocol: &mut dyn Protocol, lba: u64, buffer: &mut [u8], - ) -> Result { + ) -> Result { let blocks_to_read = buffer.len() as u64 / u64::from(self.block_size); let bytes_to_read = blocks_to_read as usize * self.block_size as usize; let transfer_len = u32::try_from(blocks_to_read).or(Err(ScsiError::Overflow( @@ -252,7 +252,7 @@ impl Scsi { protocol: &mut dyn Protocol, lba: u64, buffer: &[u8], - ) -> Result { + ) -> Result { let blocks_to_write = buffer.len() as u64 / u64::from(self.block_size); let bytes_to_write = blocks_to_write as usize * self.block_size as usize; let transfer_len = u32::try_from(blocks_to_write).or(Err(ScsiError::Overflow( diff --git a/xhcid/config.toml b/xhcid/config.toml.unused similarity index 100% rename from xhcid/config.toml rename to xhcid/config.toml.unused diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 8d448edc84..1d0968f402 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -329,13 +329,24 @@ pub enum EndpointStatus { Error, } +#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct PortTransferStatus { + pub kind: PortTransferStatusKind, + pub bytes_transferred: u32, +} + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub enum PortTransferStatus { +pub enum PortTransferStatusKind { Success, - ShortPacket(u16), + ShortPacket, Stalled, Unknown, } +impl Default for PortTransferStatusKind { + fn default() -> Self { + Self::Success + } +} impl EndpointStatus { pub fn as_str(&self) -> &'static str { @@ -641,7 +652,7 @@ impl XhciEndpHandle { let res = self.ctl_res()?; match res { - XhciEndpCtlRes::TransferResult(PortTransferStatus::Success) + XhciEndpCtlRes::TransferResult(PortTransferStatus { kind: PortTransferStatusKind::Success, .. }) if bytes_read != expected_len as usize => { Err(Invalid("no short packet, but fewer bytes were read/written").into()) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 72dcd19638..02a604429f 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1849,14 +1849,18 @@ impl Xhci { Ok(buf.len()) } fn transfer_result(completion_code: u8, bytes_transferred: u32) -> PortTransferStatus { - if completion_code == TrbCompletionCode::Success as u8 { - PortTransferStatus::Success + let kind = if completion_code == TrbCompletionCode::Success as u8 { + PortTransferStatusKind::Success } else if completion_code == TrbCompletionCode::ShortPacket as u8 { - PortTransferStatus::ShortPacket(bytes_transferred as u16) + PortTransferStatusKind::ShortPacket } else if completion_code == TrbCompletionCode::Stall as u8 { - PortTransferStatus::Stalled + PortTransferStatusKind::Stalled } else { - PortTransferStatus::Unknown + PortTransferStatusKind::Unknown + }; + PortTransferStatus { + kind, + bytes_transferred, } } pub fn on_write_endp_data( @@ -1891,8 +1895,7 @@ impl Xhci { ref mut bytes_transferred, } = ep_if_state { - if *bytes_transferred + some_bytes_transferred == bytes_to_transfer || completion_code == TrbCompletionCode::ShortPacket as u8 { - // TODO: Add an error flag to WaitingForTransferResult. + if *bytes_transferred + some_bytes_transferred == bytes_to_transfer || completion_code != TrbCompletionCode::Success as u8 { *ep_if_state = EndpIfState::WaitingForTransferResult(result); } else { *bytes_transferred += some_bytes_transferred; @@ -1984,7 +1987,7 @@ impl Xhci { ref mut bytes_transferred, } = ep_if_state { - if *bytes_transferred + some_bytes_transferred == bytes_to_transfer || completion_code == TrbCompletionCode::ShortPacket as u8 { + if *bytes_transferred + some_bytes_transferred == bytes_to_transfer || completion_code != TrbCompletionCode::Success as u8 { *ep_if_state = EndpIfState::WaitingForTransferResult(result); } else { *bytes_transferred += some_bytes_transferred; From 4072d5d282ae23b8babd406326e9498cc8684fb1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 18 Feb 2020 19:18:20 +0100 Subject: [PATCH 0351/1301] Implement READ CAPACITY 10. This allows the block count and block size to be determined when no block descriptors in the mode sense data are returned. --- usbscsid/src/main.rs | 2 ++ usbscsid/src/scsi/cmds.rs | 58 ++++++++++++++++++++++++++++++++++++++- usbscsid/src/scsi/mod.rs | 45 +++++++++++++++++++++++++----- 3 files changed, 97 insertions(+), 8 deletions(-) diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index 840dfb44bd..601512b558 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -91,9 +91,11 @@ fn main() { //syscall::setrens(0, 0).expect("scsid: failed to enter null namespace"); let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI"); + println!("SCSI initialized"); let mut buffer = [0u8; 512]; scsi.read(&mut *protocol, 0, &mut buffer).unwrap(); println!("DISK CONTENT: {}", base64::encode(&buffer[..])); + let mut scsi_scheme = ScsiScheme::new(&mut scsi, &mut *protocol); // TODO: Use nonblocking and put all pending calls in a todo VecDeque. Use an eventfd as well. diff --git a/usbscsid/src/scsi/cmds.rs b/usbscsid/src/scsi/cmds.rs index ca6b2baf4e..8eb58a0cb6 100644 --- a/usbscsid/src/scsi/cmds.rs +++ b/usbscsid/src/scsi/cmds.rs @@ -1,5 +1,6 @@ use super::opcodes::Opcode; use std::{fmt, mem, slice}; +use std::convert::TryInto; #[repr(packed)] pub struct Inquiry { @@ -415,6 +416,47 @@ impl ModeParamHeader10 { } } +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct ReadCapacity10 { + pub opcode: u8, + _rsvd1: u8, + obsolete_lba: u32, + _rsvd2: [u8; 3], + pub control: u8, +} +unsafe impl plain::Plain for ReadCapacity10 {} + +impl ReadCapacity10 { + pub const fn new(control: u8) -> Self { + Self { + opcode: Opcode::ReadCapacity10 as u8, + _rsvd1: 0, + obsolete_lba: 0, + _rsvd2: [0; 3], + control, + } + } +} +// TODO: ReadCapacity16 + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct ReadCapacity10ParamData { + pub max_lba: u32, + pub block_len: u32, +} +unsafe impl plain::Plain for ReadCapacity10ParamData {} + +impl ReadCapacity10ParamData { + pub const fn block_count(&self) -> u32 { + u32::from_be(self.max_lba) + } + pub const fn logical_block_len(&self) -> u32 { + u32::from_be(self.block_len) + } +} + #[repr(packed)] #[derive(Clone, Copy, Debug)] pub struct RwErrorRecoveryPage { @@ -428,6 +470,15 @@ pub struct RwErrorRecoveryPage { } unsafe impl plain::Plain for RwErrorRecoveryPage {} +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct CachingModePage { + pub a: u8, + pub page_length: u8, + // TODO: more +} +unsafe impl plain::Plain for CachingModePage {} + pub(crate) struct ModePageIterRaw<'a> { buffer: &'a [u8], } @@ -446,7 +497,7 @@ impl<'a> Iterator for ModePageIterRaw<'a> { self.buffer[1] as usize + 1 } else { // item is sub_page mode - self.buffer[2] as usize + 3 + u16::from_be_bytes((&self.buffer[2..3]).try_into().ok()?) as usize + 3 }; if self.buffer.len() < page_len { return None; @@ -466,6 +517,7 @@ impl<'a> Iterator for ModePageIterRaw<'a> { #[derive(Clone, Copy, Debug)] pub enum AnyModePage<'a> { RwErrorRecovery(&'a RwErrorRecoveryPage), + Caching(&'a CachingModePage) } struct ModePageIter<'a> { @@ -487,6 +539,10 @@ impl<'a> Iterator for ModePageIter<'a> { Some(AnyModePage::RwErrorRecovery( plain::from_bytes(next_buf).ok()?, )) + } else if page_code == 0x08 { + Some(AnyModePage::Caching( + plain::from_bytes(next_buf).ok()?, + )) } else { println!("Unimplemented sub_page {}", base64::encode(next_buf)); None diff --git a/usbscsid/src/scsi/mod.rs b/usbscsid/src/scsi/mod.rs index 0bbf289d2a..7fa0b2eade 100644 --- a/usbscsid/src/scsi/mod.rs +++ b/usbscsid/src/scsi/mod.rs @@ -63,9 +63,20 @@ impl Scsi { let (block_size, block_count) = { let (_, blkdescs, mode_page_iter) = this.get_mode_sense10(protocol)?; + for page in mode_page_iter { + println!("PAGE: {:?}", page); + } + // TODO: Can there be multiple disks at all? - let only_blkdesc = blkdescs.get(0).unwrap(); - (only_blkdesc.block_size(), only_blkdesc.block_count()) + if let Some(only_blkdesc) = blkdescs.get(0) { + println!("Found block desc: {:?}", only_blkdesc); + (only_blkdesc.block_size(), only_blkdesc.block_count()) + } else { + println!("read_capacity10"); + let r = this.read_capacity(protocol)?; + println!("read_capacity10 result: {:?}", r); + (r.logical_block_len(), r.block_count().into()) + } }; this.block_size = block_size; @@ -100,6 +111,18 @@ impl Scsi { )?; Ok(()) } + pub fn read_capacity(&mut self, protocol: &mut dyn Protocol) -> Result<&cmds::ReadCapacity10ParamData> { + // The spec explicitly states that the allocation length is 8 bytes. + let read_capacity10 = self.cmd_read_capacity10(); + *read_capacity10 = cmds::ReadCapacity10::new(0); + self.data_buffer.resize(10usize, 0u8); + protocol + .send_command( + &self.command_buffer[..10], + DeviceReqData::In(&mut self.data_buffer[..8]), + )?; + Ok(self.res_read_capacity10()) + } pub fn get_mode_sense10( &mut self, protocol: &mut dyn Protocol, @@ -156,6 +179,9 @@ impl Scsi { pub fn cmd_request_sense(&mut self) -> &mut cmds::RequestSense { plain::from_mut_bytes(&mut self.command_buffer).unwrap() } + pub fn cmd_read_capacity10(&mut self) -> &mut cmds::ReadCapacity10 { + plain::from_mut_bytes(&mut self.command_buffer).unwrap() + } pub fn cmd_read16(&mut self) -> &mut cmds::Read16 { plain::from_mut_bytes(&mut self.command_buffer).unwrap() } @@ -221,6 +247,9 @@ impl Scsi { let buffer = &self.data_buffer[descs_start + header.block_desc_len() as usize..]; cmds::mode_page_iter(buffer) } + pub fn res_read_capacity10(&self) -> &cmds::ReadCapacity10ParamData { + plain::from_bytes(&self.data_buffer).unwrap() + } pub fn get_disk_size(&mut self) -> u64 { self.block_count * u64::from(self.block_size) } @@ -230,21 +259,23 @@ impl Scsi { lba: u64, buffer: &mut [u8], ) -> Result { - let blocks_to_read = buffer.len() as u64 / u64::from(self.block_size); - let bytes_to_read = blocks_to_read as usize * self.block_size as usize; - let transfer_len = u32::try_from(blocks_to_read).or(Err(ScsiError::Overflow( + let blocks_to_read = dbg!(buffer.len() as u64 / u64::from(dbg!(self.block_size))); + let bytes_to_read = dbg!(blocks_to_read as usize * self.block_size as usize); + let transfer_len = dbg!(u32::try_from(blocks_to_read).or(Err(ScsiError::Overflow( "number of blocks to read couldn't fit inside a u32", - )))?; + )))?); { let read = self.cmd_read16(); *read = cmds::Read16::new(lba, transfer_len, 0); } // TODO: Use the to-be-written TransferReadStream instead of relying on everything being // able to fit within a single buffer. + self.data_buffer.resize(bytes_to_read, 0u8); let status = protocol.send_command( &self.command_buffer[..16], - DeviceReqData::In(&mut buffer[..bytes_to_read]), + DeviceReqData::In(&mut self.data_buffer[..bytes_to_read]), )?; + buffer[..bytes_to_read].copy_from_slice(&self.data_buffer[..bytes_to_read]); Ok(status.bytes_transferred(bytes_to_read as u32)) } pub fn write( From 3203a33498ba2796529b2387414d71495b11049d Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 21 Feb 2020 16:45:35 +0100 Subject: [PATCH 0352/1301] REDOXFS WORKS (read-only) ON USB! --- usbscsid/src/scheme.rs | 9 ++++++--- usbscsid/src/scsi/mod.rs | 12 +++++++----- xhcid/src/xhci/event.rs | 2 +- xhcid/src/xhci/ring.rs | 38 ++++++++++++++++++++++++++++++++++++++ xhcid/src/xhci/scheme.rs | 3 ++- 5 files changed, 54 insertions(+), 10 deletions(-) diff --git a/usbscsid/src/scheme.rs b/usbscsid/src/scheme.rs index 07b776604e..6b12fbcbee 100644 --- a/usbscsid/src/scheme.rs +++ b/usbscsid/src/scheme.rs @@ -22,7 +22,7 @@ enum Handle { pub struct ScsiScheme<'a> { scsi: &'a mut Scsi, - protocol: &'a mut Protocol, + protocol: &'a mut dyn Protocol, handles: BTreeMap, next_fd: usize, } @@ -39,17 +39,20 @@ impl<'a> ScsiScheme<'a> { } impl<'a> SchemeMut for ScsiScheme<'a> { - fn open(&mut self, path: &[u8], flags: usize, uid: u32, gid: u32) -> Result { + fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if uid != 0 { return Err(Error::new(EACCES)); } + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(EACCES)); + } let path_str = str::from_utf8(path) .or(Err(Error::new(ENOENT)))? .trim_start_matches('/'); let handle = if path_str.is_empty() { // List Handle::List(0) - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { + } else if let Some(_p_pos) = path_str.chars().position(|c| c == 'p') { // TODO: Partitions. return Err(Error::new(ENOSYS)); } else { diff --git a/usbscsid/src/scsi/mod.rs b/usbscsid/src/scsi/mod.rs index 7fa0b2eade..ad818421a9 100644 --- a/usbscsid/src/scsi/mod.rs +++ b/usbscsid/src/scsi/mod.rs @@ -57,7 +57,7 @@ impl Scsi { // Get the Standard Inquiry Data. this.get_standard_inquiry_data(protocol, max_inquiry_len)?; - let version = dbg!(this.res_standard_inquiry_data()).version(); + let version = this.res_standard_inquiry_data().version(); println!("Inquiry version: {}", version); let (block_size, block_count) = { @@ -259,11 +259,11 @@ impl Scsi { lba: u64, buffer: &mut [u8], ) -> Result { - let blocks_to_read = dbg!(buffer.len() as u64 / u64::from(dbg!(self.block_size))); - let bytes_to_read = dbg!(blocks_to_read as usize * self.block_size as usize); - let transfer_len = dbg!(u32::try_from(blocks_to_read).or(Err(ScsiError::Overflow( + let blocks_to_read = buffer.len() as u64 / u64::from(self.block_size); + let bytes_to_read = blocks_to_read as usize * self.block_size as usize; + let transfer_len = u32::try_from(blocks_to_read).or(Err(ScsiError::Overflow( "number of blocks to read couldn't fit inside a u32", - )))?); + )))?; { let read = self.cmd_read16(); *read = cmds::Read16::new(lba, transfer_len, 0); @@ -295,6 +295,8 @@ impl Scsi { } // TODO: Use the to-be-written TransferReadStream instead of relying on everything being // able to fit within a single buffer. + self.data_buffer.resize(bytes_to_write, 0u8); + self.data_buffer[..bytes_to_write].copy_from_slice(&buffer[..bytes_to_write]); let status = protocol.send_command( &self.command_buffer[..16], DeviceReqData::Out(&buffer[..bytes_to_write]), diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index 1ee8367d75..b8301b34be 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -21,7 +21,7 @@ impl EventRing { pub fn new() -> Result { let mut ring = EventRing { ste: unsafe { Dma::zeroed_unsized(1)? }, - ring: Ring::new(32, false)?, + ring: Ring::new(256, false)?, }; ring.ste[0].address.write(ring.ring.trbs.physical() as u64); diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index 62aff3a2c6..c941c70dca 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -48,4 +48,42 @@ impl Ring { (&mut self.trbs[i], self.cycle) } + /// Endless iterator that iterates through the ring items, over and over again. The iterator + /// doesn't enqueue or dequeue anything. + pub fn iter(&self) -> impl Iterator + '_ { + Iter { ring: self, i: self.i } + } + /* + /// Endless mutable iterator that iterates through the ring items, over and over again. The + /// iterator doesn't enqueue or dequeue anything, but the trbs are mutably borrowed. + pub fn iter_mut(&mut self) -> impl Iterator + '_ { + IterMut { ring: self, i: self.i } + }*/ } +struct Iter<'ring> { + ring: &'ring Ring, + i: usize, + +} +impl<'ring> Iterator for Iter<'ring> { + type Item = &'ring Trb; + + fn next(&mut self) -> Option { + let i = self.i; + self.i = (self.i + 1) % self.ring.trbs.len(); + Some(&self.ring.trbs[i]) + } +} +/*struct IterMut<'ring> { + ring: &'ring mut Ring, + i: usize, +} +impl<'ring> Iterator for IterMut<'ring> { + type Item = &'ring mut Trb; + + fn next(&mut self) -> Option { + let i = self.i; + self.i = (self.i + 1) % self.ring.trbs.len(); + Some(&mut self.ring.trbs[i]) + } +}*/ diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 02a604429f..e26b032810 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -295,6 +295,7 @@ impl Xhci { event.control.read() ); } + event.reserved(false); event.clone() }; @@ -936,7 +937,7 @@ impl Xhci { false, true, chain, - true, + ioc, idt, false, ); From c1b429267551da85c39b1ccb34152e01cc274dd6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Feb 2020 19:46:28 -0700 Subject: [PATCH 0353/1301] Improve ahcid interrupt handling --- ahcid/src/ahci/hba.rs | 10 +++++----- ahcid/src/main.rs | 2 +- ahcid/src/scheme.rs | 28 ++++++++++++++-------------- ihdad/src/hda/device.rs | 4 +--- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index fec4e0c574..86764ec767 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -1,6 +1,6 @@ use std::mem::size_of; use std::ops::DerefMut; -use std::{ptr, u32, thread}; +use std::{ptr, u32}; use syscall::io::{Dma, Io, Mmio}; use syscall::error::{Error, Result, EIO}; @@ -75,7 +75,7 @@ impl HbaPort { pub fn start(&mut self) { while self.cmd.readf(HBA_PORT_CMD_CR) { - thread::yield_now(); + unsafe { asm!("pause"); } } self.cmd.writef(HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST, true); @@ -85,7 +85,7 @@ impl HbaPort { self.cmd.writef(HBA_PORT_CMD_ST, false); while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { - thread::yield_now(); + unsafe { asm!("pause"); } } self.cmd.writef(HBA_PORT_CMD_FRE, false); @@ -305,7 +305,7 @@ impl HbaPort { } while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - thread::yield_now(); + unsafe { asm!("pause"); } } self.ci.writef(1 << slot, true); @@ -325,7 +325,7 @@ impl HbaPort { pub fn ata_stop(&mut self, slot: u32) -> Result<()> { while self.ata_running(slot) { - thread::yield_now(); + unsafe { asm!("pause"); } } self.stop(); diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 5e261cc2d0..513cf81a57 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -1,4 +1,4 @@ -//#![deny(warnings)] +#![feature(asm)] extern crate syscall; extern crate byteorder; diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index f2e523c37a..48d0721d61 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -95,7 +95,7 @@ impl DiskWrapper { impl std::ops::Deref for DiskWrapper { type Target = dyn Disk; - + fn deref(&self) -> &Self::Target { &*self.disk } @@ -128,22 +128,22 @@ impl DiskScheme { impl DiskScheme { pub fn irq(&mut self) -> bool { - let pi = self.hba_mem.pi.read(); let is = self.hba_mem.is.read(); - let pi_is = pi & is; - - for i in 0..self.hba_mem.ports.len() { - if pi_is & 1 << i > 0 { - let port = &mut self.hba_mem.ports[i]; - let is = port.is.read(); - //println!("IRQ Port {}: {:#>08x}", i, is); - //TODO: Handle requests for only this port here - port.is.write(is); + if is > 0 { + let pi = self.hba_mem.pi.read(); + let pi_is = pi & is; + for i in 0..self.hba_mem.ports.len() { + if pi_is & 1 << i > 0 { + let port = &mut self.hba_mem.ports[i]; + let is = port.is.read(); + port.is.write(is); + } } + self.hba_mem.is.write(is); + true + } else { + false } - - self.hba_mem.is.write(is); - is != 0 } } diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index ae77fe5b98..78a8e61062 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -764,18 +764,16 @@ impl IntelHDA { pub fn handle_interrupts(&mut self) -> bool { let intsts = self.regs.intsts.read(); - let sis = intsts & 0x3FFFFFFF; - //print!("IHDA INTSTS: {:08X}\n", intsts); if ((intsts >> 31) & 1) == 1 { // Global Interrupt Status if ((intsts >> 30) & 1) == 1 { // Controller Interrupt Status self.handle_controller_interrupt(); } + let sis = intsts & 0x3FFFFFFF; if sis != 0 { self.handle_stream_interrupts(sis); } } - intsts != 0 } From f00a049439483e6b87189ec500587646a70c032b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Feb 2020 20:10:43 -0700 Subject: [PATCH 0354/1301] Enable ahcid interrupts --- ahcid/src/ahci/disk_ata.rs | 2 +- ahcid/src/ahci/hba.rs | 2 +- ahcid/src/scheme.rs | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index 03d51d838f..30c4de7e9d 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -68,7 +68,7 @@ impl DiskATA { }; //TODO: Go back to interrupt magic - let use_interrupts = false; + let use_interrupts = true; loop { let mut request = match self.request_opt.take() { Some(request) => if address == request.address && total_sectors == request.total_sectors { diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 86764ec767..d0318e54cc 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -116,7 +116,7 @@ impl HbaPort { self.fb[1].write((fb.physical() >> 32) as u32); let is = self.is.read(); self.is.write(is); - self.ie.write(0 /*TODO: Enable interrupts: 0b10111*/); + self.ie.write(0b10111); let serr = self.serr.read(); self.serr.write(serr); diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 48d0721d61..0d1f3d9e00 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -136,6 +136,7 @@ impl DiskScheme { if pi_is & 1 << i > 0 { let port = &mut self.hba_mem.ports[i]; let is = port.is.read(); + //TODO: Handle requests for only this port here port.is.write(is); } } From 3dbf9ad3e75349d8897cb2bbceb3e6007f2f0987 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 11 Mar 2020 11:58:52 -0600 Subject: [PATCH 0355/1301] Comment out XHCI interrupt message --- xhcid/src/xhci/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 6ccc58281a..ed4a0e29e8 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -508,9 +508,8 @@ impl Xhci { pub fn trigger_irq(&mut self) -> bool { // Read the Interrupter Pending bit. - println!("preinterrupt"); if self.run.ints[0].iman.readf(1) { - println!("XHCI Interrupt"); + //println!("XHCI Interrupt"); // If set, set it back to zero, so that new interrupts can be triggered. // FIXME: MSI and MSI-X systems From 4fd8664debfbfccb8fbc96c36cfca6e6440cf4fa Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 28 Mar 2020 13:35:50 -0600 Subject: [PATCH 0356/1301] pcid: Skip empty buses and devices --- pcid/src/main.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 340eb6dbcb..88d85e07c0 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -246,15 +246,25 @@ fn main() { print!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV\n"); let pci = Pci::new(); - for bus in pci.buses() { - for dev in bus.devs() { + 'bus: for bus in pci.buses() { + 'dev: for dev in bus.devs() { for func in dev.funcs() { let func_num = func.num; match PciHeader::from_reader(func) { Ok(header) => { handle_parsed_header(&config, &pci, bus.num, dev.num, func_num, header); } - Err(PciHeaderError::NoDevice) => {}, + Err(PciHeaderError::NoDevice) => { + if func_num == 0 { + if dev.num == 0 { + // println!("PCI {:>02X}: no bus", bus.num); + continue 'bus; + } else { + // println!("PCI {:>02X}/{:>02X}: no dev", bus.num, dev.num); + continue 'dev; + } + } + }, Err(PciHeaderError::UnknownHeaderType(id)) => { println!("pcid: unknown header type: {}", id); } From a01f1c4c80e4ef1c95f0d0fe47e31235dbdeed1a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 28 Mar 2020 13:53:42 -0600 Subject: [PATCH 0357/1301] nvmed: fix block size conversion --- nvmed/src/scheme.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index 6a2da55dde..67d6f72161 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -89,7 +89,7 @@ impl DiskWrapper { let mut block_bytes = [0u8; 4096]; - partitionlib::get_partitions(&mut Device { disk, nvme, offset: 0, block_bytes: &mut block_bytes[..bs as usize] }, bs).ok().flatten() + partitionlib::get_partitions(&mut Device { disk, nvme, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() } fn new(mut inner: NvmeNamespace, nvme: &mut Nvme) -> Self { Self { @@ -320,7 +320,7 @@ impl SchemeBlockMut for DiskScheme { if rel_block + *offset as u64 / block_size >= part.size { return Err(Error::new(EOVERFLOW)); } - + let abs_block = part.start_lba + rel_block; if let Some(count) = unsafe { @@ -362,7 +362,7 @@ impl SchemeBlockMut for DiskScheme { if rel_block + *offset as u64 / block_size >= part.size { return Err(Error::new(EOVERFLOW)); } - + let abs_block = part.start_lba + rel_block; if let Some(count) = unsafe { From 2cac3cb7528961fc4713b2640b10dcfb300c4425 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 29 Mar 2020 19:26:13 -0600 Subject: [PATCH 0358/1301] nvmed: Fix partition offset check --- nvmed/src/scheme.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index 67d6f72161..108518a3e6 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -316,8 +316,7 @@ impl SchemeBlockMut for DiskScheme { let block_size = disk.as_ref().block_size; let rel_block = (*offset as u64) / block_size; - - if rel_block + *offset as u64 / block_size >= part.size { + if rel_block >= part.size { return Err(Error::new(EOVERFLOW)); } @@ -358,8 +357,7 @@ impl SchemeBlockMut for DiskScheme { let block_size = disk.as_ref().block_size; let rel_block = (*offset as u64) / block_size; - - if rel_block + *offset as u64 / block_size >= part.size { + if rel_block >= part.size { return Err(Error::new(EOVERFLOW)); } From a24b73efcf66f43accfed6b391c0d1bd6afab4a7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 29 Mar 2020 19:56:37 -0600 Subject: [PATCH 0359/1301] nvmed: Simplify init logging --- nvmed/src/nvme.rs | 71 ++++++++++++++++++++++++++--------------------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index 9169dce064..8754ded99b 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -311,15 +311,15 @@ impl Nvme { self.buffer_prp[i] = (self.buffer.physical() + i * 4096) as u64; } - println!(" - CAPS: {:X}", self.regs.cap.read()); - println!(" - VS: {:X}", self.regs.vs.read()); - println!(" - CC: {:X}", self.regs.cc.read()); - println!(" - CSTS: {:X}", self.regs.csts.read()); + // println!(" - CAPS: {:X}", self.regs.cap.read()); + // println!(" - VS: {:X}", self.regs.vs.read()); + // println!(" - CC: {:X}", self.regs.cc.read()); + // println!(" - CSTS: {:X}", self.regs.csts.read()); - println!(" - Disable"); + // println!(" - Disable"); self.regs.cc.writef(1, false); - println!(" - Waiting for not ready"); + // println!(" - Waiting for not ready"); loop { let csts = self.regs.csts.read(); // println!("CSTS: {:X}", csts); @@ -330,17 +330,17 @@ impl Nvme { } } - println!(" - Mask all interrupts"); + // println!(" - Mask all interrupts"); self.regs.intms.write(0xFFFFFFFF); for (qid, queue) in self.completion_queues.iter().enumerate() { let data = &queue.data; - println!(" - completion queue {}: {:X}, {}", qid, data.physical(), data.len()); + // println!(" - completion queue {}: {:X}, {}", qid, data.physical(), data.len()); } for (qid, queue) in self.submission_queues.iter().enumerate() { let data = &queue.data; - println!(" - submission queue {}: {:X}, {}", qid, data.physical(), data.len()); + // println!(" - submission queue {}: {:X}, {}", qid, data.physical(), data.len()); } { @@ -357,10 +357,10 @@ impl Nvme { self.regs.cc.write(cc); } - println!(" - Enable"); + // println!(" - Enable"); self.regs.cc.writef(1, true); - println!(" - Waiting for ready"); + // println!(" - Waiting for ready"); loop { let csts = self.regs.csts.read(); // println!("CSTS: {:X}", csts); @@ -375,7 +375,7 @@ impl Nvme { //TODO: Use buffer let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); - println!(" - Attempting to identify controller"); + // println!(" - Attempting to identify controller"); { let qid = 0; let queue = &mut self.submission_queues[qid]; @@ -387,7 +387,7 @@ impl Nvme { self.submission_queue_tail(qid as u16, tail as u16); } - println!(" - Waiting to identify controller"); + // println!(" - Waiting to identify controller"); { let qid = 0; let queue = &mut self.completion_queues[qid]; @@ -395,7 +395,7 @@ impl Nvme { self.completion_queue_head(qid as u16, head as u16); } - println!(" - Dumping identify controller"); + // println!(" - Dumping identify controller"); let mut serial = String::new(); for &b in &data[4..24] { @@ -404,7 +404,6 @@ impl Nvme { } serial.push(b as char); } - println!(" - Serial: {}", serial); let mut model = String::new(); for &b in &data[24..64] { @@ -413,7 +412,6 @@ impl Nvme { } model.push(b as char); } - println!(" - Model: {}", model); let mut firmware = String::new(); for &b in &data[64..72] { @@ -422,7 +420,13 @@ impl Nvme { } firmware.push(b as char); } - println!(" - Firmware: {}", firmware); + + println!( + " - Model: {} Serial: {} Firmware: {}", + model.trim(), + serial.trim(), + firmware.trim() + ); } let mut nsids = Vec::new(); @@ -430,7 +434,7 @@ impl Nvme { //TODO: Use buffer let data: Dma<[u32; 1024]> = Dma::zeroed().unwrap(); - println!(" - Attempting to retrieve namespace ID list"); + // println!(" - Attempting to retrieve namespace ID list"); { let qid = 0; let queue = &mut self.submission_queues[qid]; @@ -442,7 +446,7 @@ impl Nvme { self.submission_queue_tail(qid as u16, tail as u16); } - println!(" - Waiting to retrieve namespace ID list"); + // println!(" - Waiting to retrieve namespace ID list"); { let qid = 0; let queue = &mut self.completion_queues[qid]; @@ -450,10 +454,9 @@ impl Nvme { self.completion_queue_head(qid as u16, head as u16); } - println!(" - Dumping namespace ID list"); + // println!(" - Dumping namespace ID list"); for &nsid in data.iter() { if nsid != 0 { - println!(" - {}", nsid); nsids.push(nsid); } } @@ -464,7 +467,7 @@ impl Nvme { //TODO: Use buffer let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); - println!(" - Attempting to identify namespace {}", nsid); + // println!(" - Attempting to identify namespace {}", nsid); { let qid = 0; let queue = &mut self.submission_queues[qid]; @@ -476,7 +479,7 @@ impl Nvme { self.submission_queue_tail(qid as u16, tail as u16); } - println!(" - Waiting to identify namespace {}", nsid); + // println!(" - Waiting to identify namespace {}", nsid); { let qid = 0; let queue = &mut self.completion_queues[qid]; @@ -484,13 +487,17 @@ impl Nvme { self.completion_queue_head(qid as u16, head as u16); } - println!(" - Dumping identify namespace"); + // println!(" - Dumping identify namespace"); + let size = *(data.as_ptr().offset(0) as *const u64); - println!(" - Size: {}", size); - let capacity = *(data.as_ptr().offset(8) as *const u64); - println!(" - Capacity: {}", capacity); + println!( + " - ID: {} Size: {} Capacity: {}", + nsid, + size, + capacity + ); //TODO: Read block size @@ -507,7 +514,7 @@ impl Nvme { (queue.data.physical(), queue.data.len()) }; - println!(" - Attempting to create I/O completion queue {}", io_qid); + // println!(" - Attempting to create I/O completion queue {}", io_qid); { let qid = 0; let queue = &mut self.submission_queues[qid]; @@ -519,7 +526,7 @@ impl Nvme { self.submission_queue_tail(qid as u16, tail as u16); } - println!(" - Waiting to create I/O completion queue {}", io_qid); + // println!(" - Waiting to create I/O completion queue {}", io_qid); { let qid = 0; let queue = &mut self.completion_queues[qid]; @@ -534,7 +541,7 @@ impl Nvme { (queue.data.physical(), queue.data.len()) }; - println!(" - Attempting to create I/O submission queue {}", io_qid); + // println!(" - Attempting to create I/O submission queue {}", io_qid); { let qid = 0; let queue = &mut self.submission_queues[qid]; @@ -547,7 +554,7 @@ impl Nvme { self.submission_queue_tail(qid as u16, tail as u16); } - println!(" - Waiting to create I/O submission queue {}", io_qid); + // println!(" - Waiting to create I/O submission queue {}", io_qid); { let qid = 0; let queue = &mut self.completion_queues[qid]; @@ -556,7 +563,7 @@ impl Nvme { } } - println!(" - Complete"); + // println!(" - Complete"); namespaces } From bd860de51e67f26319714c73fce0eac620ee7ee0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Apr 2020 11:24:05 -0600 Subject: [PATCH 0360/1301] Temporarily disable qemu mouse integration --- ps2d/src/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 58539c71f0..13c71c0876 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -46,7 +46,7 @@ impl char> Ps2d { let mut ps2 = Ps2::new(); let extra_packet = ps2.init(); - let vmmouse = vm::enable(); + let vmmouse = false; //vm::enable(); let mut ps2d = Ps2d { ps2: ps2, From 7536048ceb5115c5fe883bb6824e9aa48a070b7f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 14 Mar 2020 12:13:47 +0100 Subject: [PATCH 0361/1301] Parse some of the PCI capabilities, and setup IPC. --- Cargo.lock | 16 +- initfs.toml | 4 +- pcid/.gitignore | 1 + pcid/Cargo.toml | 18 +- pcid/src/config.rs | 7 +- pcid/src/driver_interface.rs | 132 ++++++++++++++ pcid/src/lib.rs | 7 + pcid/src/main.rs | 84 +++++++-- pcid/src/pci/bar.rs | 4 +- pcid/src/pci/bus.rs | 3 + pcid/src/pci/cap.rs | 344 +++++++++++++++++++++++++++++++++++ pcid/src/pci/dev.rs | 3 + pcid/src/pci/func.rs | 21 ++- pcid/src/pci/header.rs | 5 +- pcid/src/pci/mod.rs | 1 + xhcid/Cargo.toml | 1 + xhcid/src/main.rs | 9 + 17 files changed, 626 insertions(+), 34 deletions(-) create mode 100644 pcid/.gitignore create mode 100644 pcid/src/driver_interface.rs create mode 100644 pcid/src/lib.rs create mode 100644 pcid/src/pci/cap.rs diff --git a/Cargo.lock b/Cargo.lock index c41a1e0178..aa3a88a748 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -686,10 +686,12 @@ version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1303,14 +1305,6 @@ dependencies = [ "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] -[[package]] -name = "toml" -version = "0.4.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "toml" version = "0.5.6" @@ -1524,6 +1518,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "pcid 0.1.0", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", @@ -1671,7 +1666,6 @@ dependencies = [ "checksum tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" "checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" diff --git a/initfs.toml b/initfs.toml index b604eec197..6861491750 100644 --- a/initfs.toml +++ b/initfs.toml @@ -22,7 +22,7 @@ vendor = 33006 device = 48879 command = ["bgad", "$NAME", "$BAR0"] -#nvmed +# nvmed [[drivers]] name = "NVME storage" class = 1 @@ -37,9 +37,11 @@ vendor = 33006 device = 51966 command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] +# xhcid [[drivers]] name = "XHCI" class = 12 subclass = 3 interface = 48 command = ["xhcid", "$NAME", "$BAR0", "$IRQ"] +channel_name = "pcid-xhcid" diff --git a/pcid/.gitignore b/pcid/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/pcid/.gitignore @@ -0,0 +1 @@ +/target diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index e35303f094..a899c78fa4 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -3,10 +3,20 @@ name = "pcid" version = "0.1.0" edition = "2018" +[[bin]] +name = "pcid" +path = "src/main.rs" + +[lib] +name = "pcid_interface" +path = "src/lib.rs" + [dependencies] -bitflags = "1.0" +bitflags = "1" byteorder = "1.2" +libc = "0.2" redox_syscall = "0.1" -serde = "1.0" -serde_derive = "1.0" -toml = "0.4" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +thiserror = "1" +toml = "0.5" diff --git a/pcid/src/config.rs b/pcid/src/config.rs index 74ba8b4eaa..b57ef14dd3 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -1,9 +1,11 @@ use std::collections::BTreeMap; use std::ops::Range; +use serde::Deserialize; + #[derive(Debug, Default, Deserialize)] pub struct Config { - pub drivers: Vec + pub drivers: Vec, } #[derive(Debug, Default, Deserialize)] @@ -16,5 +18,6 @@ pub struct DriverConfig { pub vendor: Option, pub device: Option, pub device_id_range: Option>, - pub command: Option> + pub command: Option>, + pub channel_name: Option, } diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface.rs new file mode 100644 index 0000000000..7a514b8426 --- /dev/null +++ b/pcid/src/driver_interface.rs @@ -0,0 +1,132 @@ +use std::fs::{File, OpenOptions}; +use std::io::prelude::*; +use std::{env, io}; + +use std::os::unix::io::{FromRawFd, RawFd}; + +use serde::{Serialize, Deserialize, de::DeserializeOwned}; +use thiserror::Error; + +use crate::pci; + +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub struct PciFunction { + /// Number of PCI bus + pub bus_num: u8, + /// Number of PCI device + pub dev_num: u8, + /// Number of PCI function + pub func_num: u8, + /// PCI Base Address Registers + pub bars: [pci::PciBar; 6], + /// BAR sizes + pub bar_sizes: [u32; 6], + /// Legacy IRQ line + // TODO: Stop using legacy IRQ lines, and physical pins, but MSI/MSI-X instead. + pub legacy_interrupt_line: u8, + /// Vendor ID + pub venid: u16, + /// Device ID + pub devid: u16, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct SubdriverArguments { + pub func: PciFunction, + pub capabilities: Vec, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub enum PciCapabilitiy { + Msi, + MsiX, +} + +#[derive(Debug, Error)] +pub enum PcidClientHandleError { + #[error("i/o error: {0}")] + IoError(#[from] io::Error), + + #[error("JSON ser/de error: {0}")] + SerializationError(#[from] serde_json::Error), + + #[error("environment variable error: {0}")] + EnvError(#[from] env::VarError), + + #[error("malformed fd: {0}")] + EnvValidityError(std::num::ParseIntError), + + #[error("invalid response: {0:?}")] + InvalidResponse(PcidClientResponse), +} +pub type Result = std::result::Result; + +#[derive(Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub enum PcidClientRequest { + RequestConfig, +} + +#[derive(Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub enum PcidClientResponse { + Config(SubdriverArguments), +} + +// TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over +// a channel, the communication could potentially be done via mmap, using a channel +// very similar to crossbeam-channel or libstd's mpsc (except the cycle, enqueue and dequeue fields +// are stored in the same buffer). +/// A handle from a `pcid` client (e.g. `ahcid`) to `pcid`. +pub struct PcidServerHandle { + pcid_to_client: File, + pcid_from_client: File, +} + +pub(crate) fn send(w: &mut W, message: &T) -> Result<()> { + // TODO: Use bincode. + let data = serde_json::to_vec(message)?; + let length_bytes = u64::to_le_bytes(data.len() as u64); + w.write_all(&length_bytes)?; + w.write_all(&data)?; + Ok(()) +} +pub(crate) fn recv(r: &mut R) -> Result { + let mut length_bytes = [0u8; 8]; + r.read_exact(&mut length_bytes)?; + let length = u64::from_le_bytes(length_bytes); + if length > 0x100_000 { + panic!("pcid_interface: Too large buffer"); + } + let mut data = vec! [0u8; length as usize]; + r.read_exact(&mut data)?; + + Ok(serde_json::from_slice(&data)?) +} + +impl PcidServerHandle { + pub fn connect(pcid_to_client: RawFd, pcid_from_client: RawFd) -> Result { + Ok(Self { + pcid_to_client: unsafe { File::from_raw_fd(pcid_to_client) }, + pcid_from_client: unsafe { File::from_raw_fd(pcid_from_client) }, + }) + } + pub fn connect_default() -> Result { + let pcid_to_client_fd = env::var("PCID_TO_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; + let pcid_from_client_fd = env::var("PCID_FROM_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; + + Self::connect(pcid_to_client_fd, pcid_from_client_fd) + } + pub(crate) fn send(&mut self, req: &PcidClientRequest) -> Result<()> { + send(&mut self.pcid_from_client, req) + } + pub(crate) fn recv(&mut self) -> Result { + recv(&mut self.pcid_to_client) + } + pub fn fetch_config(&mut self) -> Result { + self.send(&PcidClientRequest::RequestConfig)?; + match self.recv()? { + PcidClientResponse::Config(a) => Ok(a), + } + } +} diff --git a/pcid/src/lib.rs b/pcid/src/lib.rs new file mode 100644 index 0000000000..e03e5bfccf --- /dev/null +++ b/pcid/src/lib.rs @@ -0,0 +1,7 @@ +//! Interface to `pcid`. + +#![feature(asm)] + +mod driver_interface; +mod pci; +pub use driver_interface::*; diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 88d85e07c0..34e4876973 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,21 +1,24 @@ #![feature(asm)] -#[macro_use] extern crate bitflags; +extern crate bitflags; extern crate byteorder; -#[macro_use] extern crate serde_derive; extern crate syscall; extern crate toml; -use std::{env, i64}; +use std::{env, io, i64}; use std::fs::{File, metadata, read_dir}; -use std::io::Read; +use std::io::prelude::*; +use std::os::unix::io::{FromRawFd, RawFd}; use std::process::Command; use syscall::iopl; +use std::os::unix::process::CommandExt; + use crate::config::Config; use crate::pci::{Pci, PciBar, PciClass, PciHeader, PciHeaderError, PciHeaderType}; mod config; +mod driver_interface; mod pci; fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, @@ -24,14 +27,16 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", bus_num, dev_num, func_num, header.vendor_id(), header.device_id(), raw_class, header.subclass(), header.interface(), header.revision(), header.class()); - match header.class() { + PciClass::Legacy if header.subclass() == 1 => string.push_str(" VGA CTL"), PciClass::Storage => match header.subclass() { 0x01 => { string.push_str(" IDE"); }, - 0x06 => { - string.push_str(" SATA"); + 0x06 => if header.interface() == 0 { + string.push_str(" SATA VND"); + } else if header.interface() == 1 { + string.push_str(" SATA AHCI"); }, _ => () }, @@ -166,6 +171,23 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, } } + let func = driver_interface::PciFunction { + bars, + bar_sizes, + bus_num, + dev_num, + func_num, + devid: header.device_id(), + legacy_interrupt_line: irq, + venid: header.vendor_id(), + }; + let capabilities = Vec::new(); + + let subdriver_args = driver_interface::SubdriverArguments { + capabilities, + func, + }; + // TODO: find a better way to pass the header data down to the // device driver, making passing the capabilities list etc // posible. @@ -199,16 +221,54 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, } println!("PCID SPAWN {:?}", command); - match command.spawn() { - Ok(mut child) => match child.wait() { - Ok(_status) => (), //println!("pcid: waited for {}: {:?}", line, status.code()), - Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err) - }, + + let (pcid_to_client_write, pcid_from_client_read, envs) = if driver.channel_name.is_some() { + let mut fds1 = [0usize; 2]; + let mut fds2 = [0usize; 2]; + + syscall::pipe2(&mut fds1, 0).expect("pcid: failed to create pcid->client pipe"); + syscall::pipe2(&mut fds2, 0).expect("pcid: failed to create client->pcid pipe"); + + let [pcid_to_client_read, pcid_to_client_write] = fds1; + let [pcid_from_client_read, pcid_from_client_write] = fds2; + + (Some(pcid_to_client_write), Some(pcid_from_client_read), vec! [("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write))]) + } else { + (None, None, vec! []) + }; + + match command.envs(envs).spawn() { + Ok(mut child) => { + handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); + match child.wait() { + Ok(_status) => (), + Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err), + } + } Err(err) => println!("pcid: failed to execute {:?}: {}", command, err) } } } } + fn handle_spawn(pcid_to_client_write: Option, pcid_from_client_read: Option, args: driver_interface::SubdriverArguments) { + use driver_interface::*; + + // TODO: Instead of relying on the subdriver to correctly close the pipe, there should be a + // dedicated thread responsible for this. Or alternatively, a thread pool with Futures. + + if let (Some(pcid_to_client_fd), Some(pcid_from_client_fd)) = (pcid_to_client_write, pcid_from_client_read) { + let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd as RawFd) }; + let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd as RawFd) }; + + if let Ok(msg) = recv(&mut pcid_from_client) { + match msg { + PcidClientRequest::RequestConfig => { + send(&mut pcid_to_client, &PcidClientResponse::Config(args.clone())).unwrap(); + } + } + } + } + } } fn main() { diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index b1efde2e38..1ff92f9739 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -1,6 +1,8 @@ use std::fmt; -#[derive(Clone, Copy, Debug, PartialEq)] +use serde::{Serialize, Deserialize}; + +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum PciBar { None, Memory(u32), diff --git a/pcid/src/pci/bus.rs b/pcid/src/pci/bus.rs index 120fa458f9..388e796e61 100644 --- a/pcid/src/pci/bus.rs +++ b/pcid/src/pci/bus.rs @@ -13,6 +13,9 @@ impl<'pci> PciBus<'pci> { pub unsafe fn read(&self, dev: u8, func: u8, offset: u8) -> u32 { self.pci.read(self.num, dev, func, offset) } + pub unsafe fn write(&self, dev: u8, func: u8, offset: u8, value: u32) { + self.pci.write(self.num, dev, func, offset, value) + } } pub struct PciBusIter<'pci> { diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs new file mode 100644 index 0000000000..7ac6c3a07a --- /dev/null +++ b/pcid/src/pci/cap.rs @@ -0,0 +1,344 @@ +use super::func::{ConfigReader, ConfigWriter}; + +pub struct CapabilityOffsetsIter<'a, R> { + offset: u8, + reader: &'a R, +} +impl<'a, R> CapabilityOffsetsIter<'a, R> { + pub fn new(offset: u8, reader: &'a R) -> Self { + Self { + offset, + reader, + } + } +} +impl<'a, R> Iterator for CapabilityOffsetsIter<'a, R> +where + R: ConfigReader +{ + type Item = u8; + + fn next(&mut self) -> Option { + unsafe { + assert_eq!(self.offset & 0xF8, self.offset, "capability must be dword aligned"); + + if self.offset == 0 { return None }; + + let first_dword = dbg!(self.reader.read_u32(dbg!(self.offset))); + let next = ((first_dword >> 8) & 0xFF) as u8; + + let offset = self.offset; + self.offset = next; + + Some(offset) + } + } +} + +#[repr(u8)] +pub enum CapabilityId { + Msi = 0x05, + MsiX = 0x11, + Pcie = 0x10, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum MsiCapability { + _32BitAddress { + message_control: u32, + message_address: u32, + message_data: u32, + }, + _64BitAddress { + message_control: u32, + message_address_lo: u32, + message_address_hi: u32, + message_data: u32, + }, + _32BitAddressWithPvm { + message_control: u32, + message_address: u32, + message_data: u32, + mask_bits: u32, + pending_bits: u32, + }, + _64BitAddressWithPvm { + message_control: u32, + message_address_lo: u32, + message_address_hi: u32, + message_data: u32, + mask_bits: u32, + pending_bits: u32, + }, +} + +impl MsiCapability { + pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8; + pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7; + + pub const MC_MULTI_MESSAGE_MASK: u16 = 0x000E; + pub const MC_MULTI_MESSAGE_SHIFT: u8 = 1; + + pub const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070; + pub const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4; + + pub const MC_MSI_ENABLED_BIT: u16 = 1; + + pub unsafe fn parse(reader: &R, offset: u8) -> Self { + let dword = reader.read_u32(offset); + + let message_control = (dword >> 16) as u16; + + if message_control & Self::MC_PVT_CAPABLE_BIT != 0 { + if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { + Self::_64BitAddressWithPvm { + message_control: dword, + message_address_lo: reader.read_u32(offset + 4), + message_address_hi: reader.read_u32(offset + 8), + message_data: reader.read_u32(offset + 12), + mask_bits: reader.read_u32(offset + 16), + pending_bits: reader.read_u32(offset + 20), + } + } else { + Self::_32BitAddressWithPvm { + message_control: dword, + message_address: reader.read_u32(offset + 4), + message_data: reader.read_u32(offset + 8), + mask_bits: reader.read_u32(offset + 12), + pending_bits: reader.read_u32(offset + 16), + } + } + } else { + if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { + Self::_64BitAddress { + message_control: dword, + message_address_lo: reader.read_u32(offset + 4), + message_address_hi: reader.read_u32(offset + 8), + message_data: reader.read_u32(offset + 12), + } + } else { + Self::_32BitAddress { + message_control: dword, + message_address: reader.read_u32(offset + 4), + message_data: reader.read_u32(offset + 8), + } + } + } + } + + fn message_control_raw(&self) -> u32 { + match self { + Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control, + } + } + pub fn message_control(&self) -> u16 { + self.message_control_raw() as u16 + } + pub unsafe fn set_message_control(&mut self, writer: &mut W, offset: u8, value: u16) { + let mut new_message_control = self.message_control_raw(); + new_message_control &= 0x0000_FFFF; + new_message_control |= u32::from(value) << 16; + writer.write_u32(offset, new_message_control); + + match self { + Self::_32BitAddress { ref mut message_control, .. } + | Self::_64BitAddress { ref mut message_control, .. } + | Self::_32BitAddressWithPvm { ref mut message_control, .. } + | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, + } + } + pub fn is_pvt_capable(&self) -> bool { + self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 + } + pub fn has_64_bit_addr(&self) -> bool { + self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0 + } + pub fn enabled(&self) -> bool { + self.message_control() & Self::MC_MSI_ENABLED_BIT != 0 + } + pub unsafe fn set_enabled(&mut self, writer: &mut W, offset: u8, enabled: bool) { + let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); + new_message_control |= u16::from(enabled); + self.set_message_control(writer, offset, new_message_control) + } + pub fn multi_message_capable(&self) -> u8 { + ((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8 + } + pub fn multi_message_enabled(&self) -> u8 { + ((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_MASK) as u8 + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct PcieCapability { +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct MsixCapability { + pub a: u32, + pub b: u32, + pub c: u32, +} + +impl MsixCapability { + pub const MC_MSIX_ENABLED_BIT: u16 = 1 << 15; + pub const MC_MSIX_ENABLED_SHIFT: u8 = 15; + pub const MC_FUNCTION_MASK_BIT: u16 = 1 << 14; + pub const MC_FUNCTION_MASK_SHIFT: u8 = 14; + pub const MC_TABLE_SIZE_MASK: u16 = 0x03FF; + + /// The Message Control field, containing the enabled and function mask bits, as well as the + /// table size. + pub const fn message_control(&self) -> u16 { + (self.a >> 16) as u16 + } + pub fn set_message_control(&mut self, message_control: u16) { + self.a &= 0x0000_FFFF; + self.a |= u32::from(message_control) << 16; + } + /// Returns the MSI-X table size, subtracted by one. + pub const fn table_size_raw(&self) -> u16 { + self.message_control() & Self::MC_TABLE_SIZE_MASK + } + /// Returns the MSI-X table size. + pub const fn table_size(&self) -> u16 { + self.table_size_raw() + 1 + } + /// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the + /// MSI capability structure. + pub const fn msix_enabled(&self) -> bool { + self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0 + } + /// The MSI-X function mask, which overrides each of the vectors' mask bit, when set. + pub const fn function_mask(&self) -> bool { + self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0 + } + + pub fn set_msix_enabled(&mut self, enabled: bool) { + let mut new_message_control = self.message_control(); + new_message_control &= !(Self::MC_MSIX_ENABLED_BIT); + new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT; + self.set_message_control(new_message_control); + } + + pub fn set_function_mask(&mut self, function_mask: bool) { + let mut new_message_control = self.message_control(); + new_message_control &= !(Self::MC_FUNCTION_MASK_BIT); + new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT; + self.set_message_control(new_message_control); + } + pub const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8; + pub const TABLE_BIR_MASK: u32 = 0x0000_0007; + + /// The table offset is guaranteed to be QWORD aligned (8 bytes). + pub const fn table_offset(&self) -> u32 { + self.b & Self::TABLE_OFFSET_MASK + } + /// The table BIR, which is used to map the offset to a memory location. + pub const fn table_bir(&self) -> u8 { + (self.b & Self::TABLE_BIR_MASK) as u8 + } + + pub fn set_table_offset(&mut self, offset: u32) { + assert_eq!(offset & Self::TABLE_OFFSET_MASK, offset, "MSI-X table offset has to be QWORD aligned"); + self.b &= !Self::TABLE_OFFSET_MASK; + self.b |= offset; + } + pub const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8; + pub const PBA_BIR_MASK: u32 = 0x0000_0007; + + /// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes). + pub const fn pba_offset(&self) -> u32 { + self.b & Self::PBA_OFFSET_MASK + } + /// The Pending Bit Array BIR, which is used to map the offset to a memory location. + pub const fn pba_bir(&self) -> u8 { + (self.b & Self::PBA_BIR_MASK) as u8 + } + + pub fn set_pba_offset(&mut self, offset: u32) { + assert_eq!(offset & Self::PBA_OFFSET_MASK, offset, "MSI-X Pending Bit Array offset has to be QWORD aligned"); + self.c &= !Self::PBA_OFFSET_MASK; + self.c |= offset; + } + + /// Write the first DWORD into configuration space (containing the partially modifiable Message + /// Control field). + pub unsafe fn write_a(&self, writer: &W, offset: u8) { + writer.write_u32(offset, self.a) + } + /// Write the second DWORD into configuration space (containing the modifiable table + /// offset and the readonly table BIR). + pub unsafe fn write_b(&self, writer: &W, offset: u8) { + writer.write_u32(offset + 4, self.a) + } + /// Write the third DWORD into configuration space (containing the modifiable pending bit array + /// offset, and the readonly PBA BIR). + pub unsafe fn write_c(&self, writer: &W, offset: u8) { + writer.write_u32(offset + 8, self.a) + } + /// Write this capability structure back to configuration space. + pub unsafe fn write_all(&self, writer: &W, offset: u8) { + self.write_a(writer, offset); + self.write_b(writer, offset); + self.write_c(writer, offset); + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum Capability { + Msi(MsiCapability), + MsiX(MsixCapability), + Pcie(PcieCapability), + Other(u8), +} + +impl Capability { + unsafe fn parse_msi(reader: &R, offset: u8) -> Self { + Self::Msi(MsiCapability::parse(reader, offset)) + } + unsafe fn parse_msix(reader: &R, offset: u8) -> Self { + Self::MsiX(MsixCapability { + a: reader.read_u32(offset), + b: reader.read_u32(offset + 4), + c: reader.read_u32(offset + 8), + }) + } + unsafe fn parse_pcie(reader: &R, offset: u8) -> Self { + // TODO + Self::Pcie(PcieCapability {}) + } + unsafe fn parse(reader: &R, offset: u8) -> Self { + assert_eq!(offset & 0xF8, offset, "capability must be dword aligned"); + + let dword = reader.read_u32(offset); + let capability_id = (dword & 0xFF) as u8; + + if capability_id == CapabilityId::Msi as u8 { + Self::parse_msi(reader, offset) + } else if capability_id == CapabilityId::MsiX as u8 { + Self::parse_msix(reader, offset) + } else if capability_id == CapabilityId::Pcie as u8 { + Self::parse_pcie(reader, offset) + } else { + Self::Other(capability_id) + //panic!("unimplemented or malformed capability id: {}", capability_id) + } + } +} + +pub struct CapabilitiesIter<'a, R> { + pub inner: CapabilityOffsetsIter<'a, R>, +} + +impl<'a, R> Iterator for CapabilitiesIter<'a, R> +where + R: ConfigReader +{ + type Item = Capability; + + fn next(&mut self) -> Option { + let offset = self.inner.next()?; + Some(unsafe { Capability::parse(self.inner.reader, offset) }) + } +} diff --git a/pcid/src/pci/dev.rs b/pcid/src/pci/dev.rs index 05088886e8..6d021994e5 100644 --- a/pcid/src/pci/dev.rs +++ b/pcid/src/pci/dev.rs @@ -13,6 +13,9 @@ impl<'pci> PciDev<'pci> { pub unsafe fn read(&self, func: u8, offset: u8) -> u32 { self.bus.read(self.num, func, offset) } + pub unsafe fn write(&self, func: u8, offset: u8, value: u32) { + self.bus.write(self.num, func, offset, value); + } } pub struct PciDevIter<'pci> { diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index 5c206f3607..0a3be3c874 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -2,6 +2,9 @@ use byteorder::{LittleEndian, ByteOrder}; use super::PciDev; +// TODO: PCI Express Configuration Space, which uses a flat memory buffer, rather than IN/OUT +// instructions. + pub trait ConfigReader { unsafe fn read_range(&self, offset: u8, len: u8) -> Vec { assert!(len > 3 && len % 4 == 0); @@ -17,11 +20,22 @@ pub trait ConfigReader { } unsafe fn read_u32(&self, offset: u8) -> u32; + + unsafe fn read_u8(&self, offset: u8) -> u8 { + let dword_offset = (offset / 4) * 4; + let dword = self.read_u32(dword_offset); + + let shift = (offset % 4) * 8; + ((dword >> shift) & 0xFF) as u8 + } +} +pub trait ConfigWriter { + unsafe fn write_u32(&self, offset: u8, value: u32); } pub struct PciFunc<'pci> { pub dev: &'pci PciDev<'pci>, - pub num: u8 + pub num: u8, } impl<'pci> ConfigReader for PciFunc<'pci> { @@ -29,3 +43,8 @@ impl<'pci> ConfigReader for PciFunc<'pci> { self.dev.read(self.num, offset) } } +impl<'pci> ConfigWriter for PciFunc<'pci> { + unsafe fn write_u32(&self, offset: u8, value: u32) { + self.dev.write(self.num, offset, value); + } +} diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index 272d917b1f..e4197436a9 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -3,6 +3,7 @@ use byteorder::{LittleEndian, ByteOrder}; use super::func::ConfigReader; use super::class::PciClass; use super::bar::PciBar; +use bitflags::bitflags; #[derive(Debug, PartialEq)] pub enum PciHeaderError { @@ -123,8 +124,9 @@ impl PciHeader { let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]); let subsystem_id = LittleEndian::read_u16(&bytes[30..32]); let expansion_rom_bar = LittleEndian::read_u32(&bytes[32..36]); - // TODO: Parse out the capabilities list. let cap_pointer = bytes[36]; + println!("PCI DEVICE CAPABILITIES: {:?}", crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(cap_pointer, &reader) }.collect::>()); + let interrupt_line = bytes[44]; let interrupt_pin = bytes[45]; let min_grant = bytes[46]; @@ -158,7 +160,6 @@ impl PciHeader { let prefetch_limit_upper = LittleEndian::read_u32(&bytes[28..32]); let io_base_upper = LittleEndian::read_u16(&bytes[32..34]); let io_limit_upper = LittleEndian::read_u16(&bytes[34..36]); - // TODO: Parse out the capabilities list. let cap_pointer = bytes[36]; let expansion_rom = LittleEndian::read_u32(&bytes[40..44]); let interrupt_line = bytes[44]; diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index e70048fd84..8209e09a45 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -7,6 +7,7 @@ pub use self::header::{PciHeader, PciHeaderError, PciHeaderType}; mod bar; mod bus; +pub mod cap; mod class; mod dev; mod func; diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index b67f291149..0ef92d5fd7 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -23,3 +23,4 @@ serde_json = "1" smallvec = { version = "1", features = ["serde"] } thiserror = "1" toml = "0.5" +pcid = { path = "../pcid" } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 2cc823886d..0de08d86e9 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -23,6 +23,15 @@ mod usb; mod xhci; fn main() { + println!("xhcid started"); + let mut pcid_handle = pcid_interface::PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); + dbg!(); + println!("XHCI from PCI config: {:?}", pcid_handle.fetch_config().expect("xhcid: failed to fetch config")); + + // Close the pipe, allowing pcid to continue. + drop(pcid_handle); + + let mut args = env::args().skip(1); let mut name = args.next().expect("xhcid: no name provided"); From 735c55f65621b4a47cc79c0c37164b899ce341b1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 14 Mar 2020 14:19:58 +0100 Subject: [PATCH 0362/1301] Rebase. --- Cargo.lock | 11 +++ pcid/Cargo.toml | 1 + pcid/src/config.rs | 4 +- pcid/src/driver_interface.rs | 47 +++++++-- pcid/src/main.rs | 182 +++++++++++++++++++++++++++++------ pcid/src/pci/cap.rs | 45 ++++++++- pcid/src/pci/header.rs | 9 +- pcid/src/pci/mod.rs | 25 ++++- 8 files changed, 273 insertions(+), 51 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aa3a88a748..e0a97cc6da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,6 +84,15 @@ dependencies = [ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bincode" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "0.7.0" @@ -684,6 +693,7 @@ dependencies = [ name = "pcid" version = "0.1.0" dependencies = [ + "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1539,6 +1549,7 @@ dependencies = [ "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index a899c78fa4..189aed0338 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -12,6 +12,7 @@ name = "pcid_interface" path = "src/lib.rs" [dependencies] +bincode = "1.2" bitflags = "1" byteorder = "1.2" libc = "0.2" diff --git a/pcid/src/config.rs b/pcid/src/config.rs index b57ef14dd3..3c79746816 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -3,12 +3,12 @@ use std::ops::Range; use serde::Deserialize; -#[derive(Debug, Default, Deserialize)] +#[derive(Clone, Debug, Default, Deserialize)] pub struct Config { pub drivers: Vec, } -#[derive(Debug, Default, Deserialize)] +#[derive(Clone, Debug, Default, Deserialize)] pub struct DriverConfig { pub name: Option, pub class: Option, diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface.rs index 7a514b8426..cf5e24336d 100644 --- a/pcid/src/driver_interface.rs +++ b/pcid/src/driver_interface.rs @@ -33,11 +33,26 @@ pub struct PciFunction { #[derive(Clone, Debug, Serialize, Deserialize)] pub struct SubdriverArguments { pub func: PciFunction, - pub capabilities: Vec, } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub enum PciCapabilitiy { +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub enum FeatureStatus { + Enabled, + Disabled, +} + +impl FeatureStatus { + pub fn enabled(enabled: bool) -> Self { + if enabled { + Self::Enabled + } else { + Self::Disabled + } + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub enum PciFeature { Msi, MsiX, } @@ -48,7 +63,7 @@ pub enum PcidClientHandleError { IoError(#[from] io::Error), #[error("JSON ser/de error: {0}")] - SerializationError(#[from] serde_json::Error), + SerializationError(#[from] bincode::Error), #[error("environment variable error: {0}")] EnvError(#[from] env::VarError), @@ -65,18 +80,31 @@ pub type Result = std::result::Result; #[non_exhaustive] pub enum PcidClientRequest { RequestConfig, + RequestFeatures, + EnableFeature(PciFeature), + FeatureStatus(PciFeature), +} + +#[derive(Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub enum PcidServerResponseError { + NonexistentFeature(PciFeature), } #[derive(Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum PcidClientResponse { Config(SubdriverArguments), + AllFeatures(Vec<(PciFeature, FeatureStatus)>), + FeatureEnabled(PciFeature), + FeatureStatus(PciFeature, FeatureStatus), + Error(PcidServerResponseError), } // TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over // a channel, the communication could potentially be done via mmap, using a channel // very similar to crossbeam-channel or libstd's mpsc (except the cycle, enqueue and dequeue fields -// are stored in the same buffer). +// are stored in the same buffer as the actual data). /// A handle from a `pcid` client (e.g. `ahcid`) to `pcid`. pub struct PcidServerHandle { pcid_to_client: File, @@ -84,8 +112,8 @@ pub struct PcidServerHandle { } pub(crate) fn send(w: &mut W, message: &T) -> Result<()> { - // TODO: Use bincode. - let data = serde_json::to_vec(message)?; + let mut data = Vec::new(); + bincode::serialize_into(&mut data, message)?; let length_bytes = u64::to_le_bytes(data.len() as u64); w.write_all(&length_bytes)?; w.write_all(&data)?; @@ -96,12 +124,12 @@ pub(crate) fn recv(r: &mut R) -> Result { r.read_exact(&mut length_bytes)?; let length = u64::from_le_bytes(length_bytes); if length > 0x100_000 { - panic!("pcid_interface: Too large buffer"); + panic!("pcid_interface: buffer too large"); } let mut data = vec! [0u8; length as usize]; r.read_exact(&mut data)?; - Ok(serde_json::from_slice(&data)?) + Ok(bincode::deserialize_from(&data[..])?) } impl PcidServerHandle { @@ -127,6 +155,7 @@ impl PcidServerHandle { self.send(&PcidClientRequest::RequestConfig)?; match self.recv()? { PcidClientResponse::Config(a) => Ok(a), + other => Err(PcidClientHandleError::InvalidResponse(other)), } } } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 34e4876973..78416db8c3 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -5,24 +5,132 @@ extern crate byteorder; extern crate syscall; extern crate toml; -use std::{env, io, i64}; use std::fs::{File, metadata, read_dir}; use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; use std::process::Command; +use std::sync::{Arc, Mutex}; +use std::{env, io, i64, thread}; + use syscall::iopl; -use std::os::unix::process::CommandExt; - use crate::config::Config; -use crate::pci::{Pci, PciBar, PciClass, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::{Pci, PciBar, PciBus, PciClass, PciDev, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::cap::Capability as PciCapability; mod config; mod driver_interface; mod pci; -fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, +pub struct DriverHandler { + config: config::DriverConfig, + bus_num: u8, + dev_num: u8, + func_num: u8, + header: PciHeader, + capabilities: Vec<(u8, PciCapability)>, + + state: Arc, +} +fn with_pci_func_raw T>(pci: &Pci, bus_num: u8, dev_num: u8, func_num: u8, function: F) -> T { + let bus = PciBus { + pci, + num: bus_num, + }; + let dev = PciDev { + bus: &bus, + num: dev_num, + }; + let func = PciFunc { + dev: &dev, + num: func_num, + }; + function(&func) +} +impl DriverHandler { + fn with_pci_func_raw T>(&self, function: F) -> T { + with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, function) + } + fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse { + use driver_interface::*; + use crate::pci::cap::{MsiCapability, MsixCapability}; + + match request { + PcidClientRequest::RequestConfig => { + PcidClientResponse::Config(args.clone()) + } + PcidClientRequest::RequestFeatures => { + PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability { + PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))), + // TODO: For MSI-X to actually be enabled, MSI also has to be enabled. + // How should this be reported to the subdrivers? + PciCapability::MsiX(msix) => Some((PciFeature::MsiX, FeatureStatus::enabled(msix.msix_enabled()))), + _ => None, + }).collect()) + } + PcidClientRequest::EnableFeature(feature) => match feature { + PciFeature::Msi => { + let (offset, capability): (u8, &mut MsiCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msi_mut().map(|cap| (offset, cap))) { + Some(tuple) => tuple, + None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), + }; + unsafe { + with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| capability.set_enabled(func, offset, true)); + } + PcidClientResponse::FeatureEnabled(feature) + } + PciFeature::MsiX => { + let (offset, capability): (u8, &mut MsixCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msix_mut().map(|cap| (offset, cap))) { + Some(tuple) => tuple, + None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), + }; + unsafe { + with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| { + capability.set_msix_enabled(true); + capability.write_a(func, offset); + }); + } + PcidClientResponse::FeatureEnabled(feature) + } + } + PcidClientRequest::FeatureStatus(feature) => PcidClientResponse::FeatureStatus(feature, match feature { + PciFeature::Msi => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::Msi(msi) = capability { + Some(FeatureStatus::enabled(msi.enabled())) + } else { + None + }).unwrap_or(FeatureStatus::Disabled), + PciFeature::MsiX => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::MsiX(msix) = capability { + Some(FeatureStatus::enabled(msix.msix_enabled())) + } else { + None + }).unwrap_or(FeatureStatus::Disabled), + }), + } + } + fn handle_spawn(mut self, pcid_to_client_write: Option, pcid_from_client_read: Option, args: driver_interface::SubdriverArguments) { + use driver_interface::*; + + if let (Some(pcid_to_client_fd), Some(pcid_from_client_fd)) = (pcid_to_client_write, pcid_from_client_read) { + let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd as RawFd) }; + let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd as RawFd) }; + + while let Ok(msg) = recv(&mut pcid_from_client) { + let response = self.respond(msg, &args); + send(&mut pcid_to_client, &response); + } + } + } +} + +pub struct State { + threads: Mutex>>, + pci: Pci, +} + +fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, dev_num: u8, func_num: u8, header: PciHeader) { + let pci = &state.pci; + let raw_class: u8 = header.class().into(); let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", bus_num, dev_num, func_num, header.vendor_id(), header.device_id(), raw_class, @@ -171,6 +279,22 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, } } + let capabilities = { + let bus = PciBus { + pci, + num: bus_num, + }; + let dev = PciDev { + bus: &bus, + num: dev_num + }; + let func = PciFunc { + dev: &dev, + num: func_num, + }; + crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() + }; + let func = driver_interface::PciFunction { bars, bar_sizes, @@ -181,10 +305,8 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, legacy_interrupt_line: irq, venid: header.vendor_id(), }; - let capabilities = Vec::new(); let subdriver_args = driver_interface::SubdriverArguments { - capabilities, func, }; @@ -239,7 +361,18 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, match command.envs(envs).spawn() { Ok(mut child) => { - handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); + let driver_handler = DriverHandler { + bus_num, + dev_num, + func_num, + config: driver.clone(), + header, + state: Arc::clone(&state), + capabilities, + }; + let thread = thread::spawn(move || { + driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); + }); match child.wait() { Ok(_status) => (), Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err), @@ -250,25 +383,6 @@ fn handle_parsed_header(config: &Config, pci: &Pci, bus_num: u8, } } } - fn handle_spawn(pcid_to_client_write: Option, pcid_from_client_read: Option, args: driver_interface::SubdriverArguments) { - use driver_interface::*; - - // TODO: Instead of relying on the subdriver to correctly close the pipe, there should be a - // dedicated thread responsible for this. Or alternatively, a thread pool with Futures. - - if let (Some(pcid_to_client_fd), Some(pcid_from_client_fd)) = (pcid_to_client_write, pcid_from_client_read) { - let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd as RawFd) }; - let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd as RawFd) }; - - if let Ok(msg) = recv(&mut pcid_from_client) { - match msg { - PcidClientRequest::RequestConfig => { - send(&mut pcid_to_client, &PcidClientResponse::Config(args.clone())).unwrap(); - } - } - } - } - } } fn main() { @@ -301,18 +415,24 @@ fn main() { } } + let state = Arc::new(State { + pci: Pci::new(), + threads: Mutex::new(Vec::new()), + }); + + let pci = &state.pci; + unsafe { iopl(3).unwrap() }; print!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV\n"); - let pci = Pci::new(); 'bus: for bus in pci.buses() { 'dev: for dev in bus.devs() { for func in dev.funcs() { let func_num = func.num; match PciHeader::from_reader(func) { Ok(header) => { - handle_parsed_header(&config, &pci, bus.num, dev.num, func_num, header); + handle_parsed_header(Arc::clone(&state), &config, bus.num, dev.num, func_num, header); } Err(PciHeaderError::NoDevice) => { if func_num == 0 { @@ -332,4 +452,8 @@ fn main() { } } } + + for thread in state.threads.lock().unwrap().drain(..) { + thread.join().unwrap(); + } } diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 7ac6c3a07a..c458174536 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -134,7 +134,7 @@ impl MsiCapability { pub fn message_control(&self) -> u16 { self.message_control_raw() as u16 } - pub unsafe fn set_message_control(&mut self, writer: &mut W, offset: u8, value: u16) { + pub unsafe fn set_message_control(&mut self, writer: &W, offset: u8, value: u16) { let mut new_message_control = self.message_control_raw(); new_message_control &= 0x0000_FFFF; new_message_control |= u32::from(value) << 16; @@ -156,7 +156,7 @@ impl MsiCapability { pub fn enabled(&self) -> bool { self.message_control() & Self::MC_MSI_ENABLED_BIT != 0 } - pub unsafe fn set_enabled(&mut self, writer: &mut W, offset: u8, enabled: bool) { + pub unsafe fn set_enabled(&mut self, writer: &W, offset: u8, enabled: bool) { let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); new_message_control |= u16::from(enabled); self.set_message_control(writer, offset, new_message_control) @@ -192,6 +192,7 @@ impl MsixCapability { pub const fn message_control(&self) -> u16 { (self.a >> 16) as u16 } + pub fn set_message_control(&mut self, message_control: u16) { self.a &= 0x0000_FFFF; self.a |= u32::from(message_control) << 16; @@ -294,6 +295,42 @@ pub enum Capability { } impl Capability { + pub fn as_msi(&self) -> Option<&MsiCapability> { + match self { + &Self::Msi(ref msi) => Some(msi), + _ => None, + } + } + pub fn as_msix(&self) -> Option<&MsixCapability> { + match self { + &Self::MsiX(ref msix) => Some(msix), + _ => None, + } + } + pub fn as_msi_mut(&mut self) -> Option<&mut MsiCapability> { + match self { + &mut Self::Msi(ref mut msi) => Some(msi), + _ => None, + } + } + pub fn as_msix_mut(&mut self) -> Option<&mut MsixCapability> { + match self { + &mut Self::MsiX(ref mut msix) => Some(msix), + _ => None, + } + } + pub fn into_msi(self) -> Option { + match self { + Self::Msi(msi) => Some(msi), + _ => None, + } + } + pub fn into_msix(self) -> Option { + match self { + Self::MsiX(msix) => Some(msix), + _ => None, + } + } unsafe fn parse_msi(reader: &R, offset: u8) -> Self { Self::Msi(MsiCapability::parse(reader, offset)) } @@ -335,10 +372,10 @@ impl<'a, R> Iterator for CapabilitiesIter<'a, R> where R: ConfigReader { - type Item = Capability; + type Item = (u8, Capability); fn next(&mut self) -> Option { let offset = self.inner.next()?; - Some(unsafe { Capability::parse(self.inner.reader, offset) }) + Some((offset, unsafe { Capability::parse(self.inner.reader, offset) })) } } diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index e4197436a9..0d8513bb82 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -27,7 +27,7 @@ bitflags! { } } -#[derive(Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum PciHeader { General { vendor_id: u16, @@ -125,8 +125,6 @@ impl PciHeader { let subsystem_id = LittleEndian::read_u16(&bytes[30..32]); let expansion_rom_bar = LittleEndian::read_u32(&bytes[32..36]); let cap_pointer = bytes[36]; - println!("PCI DEVICE CAPABILITIES: {:?}", crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(cap_pointer, &reader) }.collect::>()); - let interrupt_line = bytes[44]; let interrupt_pin = bytes[45]; let min_grant = bytes[46]; @@ -266,6 +264,11 @@ impl PciHeader { } } + pub fn cap_pointer(&self) -> u8 { + match self { + &PciHeader::General { cap_pointer, .. } | &PciHeader::PciToPci { cap_pointer, .. } => cap_pointer, + } + } } #[cfg(test)] diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 8209e09a45..6e763a89e4 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,3 +1,5 @@ +use std::sync::Mutex; + pub use self::bar::PciBar; pub use self::bus::{PciBus, PciBusIter}; pub use self::class::PciClass; @@ -13,11 +15,15 @@ mod dev; mod func; pub mod header; -pub struct Pci; +pub struct Pci { + lock: Mutex<()>, +} impl Pci { pub fn new() -> Self { - Pci + Self { + lock: Mutex::new(()), + } } pub fn buses<'pci>(&'pci self) -> PciIter<'pci> { @@ -25,7 +31,7 @@ impl Pci { } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 { + pub unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 { let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); let value: u32; asm!("mov dx, 0xCF8 @@ -37,7 +43,13 @@ impl Pci { } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) { + pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 { + let _guard = self.lock.lock().unwrap(); + self.read_nolock(bus, dev, func, offset) + } + + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) { let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); asm!("mov dx, 0xCF8 out dx, eax" @@ -46,6 +58,11 @@ impl Pci { out dx, eax" : : "{eax}"(value) : "dx" : "intel", "volatile"); } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) { + let _guard = self.lock.lock().unwrap(); + self.write_nolock(bus, dev, func, offset, value) + } } pub struct PciIter<'pci> { From fa594155c9c8aedadd5e63be2b06e79ad1352bd9 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 15 Mar 2020 14:05:19 +0100 Subject: [PATCH 0363/1301] Allow subdrivers to get the capability structs. --- bgad/src/scheme.rs | 1 - pcid/src/driver_interface.rs | 51 +++++- pcid/src/main.rs | 15 +- pcid/src/pci/cap.rs | 209 +------------------------ pcid/src/pci/mod.rs | 1 + pcid/src/pci/msi.rs | 296 +++++++++++++++++++++++++++++++++++ xhcid/src/main.rs | 253 ++++++++++++++++++------------ xhcid/src/xhci/mod.rs | 4 +- xhcid/src/xhci/scheme.rs | 2 +- xhcid/src/xhci/trb.rs | 9 ++ 10 files changed, 533 insertions(+), 308 deletions(-) create mode 100644 pcid/src/pci/msi.rs diff --git a/bgad/src/scheme.rs b/bgad/src/scheme.rs index bad949c717..635d581017 100644 --- a/bgad/src/scheme.rs +++ b/bgad/src/scheme.rs @@ -1,4 +1,3 @@ -use orbclient; use std::fs::File; use std::io::Write; use std::str; diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface.rs index cf5e24336d..47b8e108a2 100644 --- a/pcid/src/driver_interface.rs +++ b/pcid/src/driver_interface.rs @@ -7,7 +7,8 @@ use std::os::unix::io::{FromRawFd, RawFd}; use serde::{Serialize, Deserialize, de::DeserializeOwned}; use thiserror::Error; -use crate::pci; +pub use crate::pci::PciBar; +pub use crate::pci::msi::{MsiCapability, MsixCapability, MsixTableEntry}; #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct PciFunction { @@ -18,7 +19,7 @@ pub struct PciFunction { /// Number of PCI function pub func_num: u8, /// PCI Base Address Registers - pub bars: [pci::PciBar; 6], + pub bars: [PciBar; 6], /// BAR sizes pub bar_sizes: [u32; 6], /// Legacy IRQ line @@ -49,6 +50,9 @@ impl FeatureStatus { Self::Disabled } } + pub fn is_enabled(&self) -> bool { + if let &Self::Enabled = self { true } else { false } + } } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] @@ -56,6 +60,19 @@ pub enum PciFeature { Msi, MsiX, } +impl PciFeature { + pub fn is_msi(&self) -> bool { + if let &Self::Msi = self { true } else { false } + } + pub fn is_msix(&self) -> bool { + if let &Self::MsiX = self { true } else { false } + } +} +#[derive(Debug, Serialize, Deserialize)] +pub enum PciFeatureInfo { + Msi(MsiCapability), + MsiX(MsixCapability), +} #[derive(Debug, Error)] pub enum PcidClientHandleError { @@ -83,6 +100,7 @@ pub enum PcidClientRequest { RequestFeatures, EnableFeature(PciFeature), FeatureStatus(PciFeature), + FeatureInfo(PciFeature), } #[derive(Debug, Serialize, Deserialize)] @@ -99,6 +117,7 @@ pub enum PcidClientResponse { FeatureEnabled(PciFeature), FeatureStatus(PciFeature, FeatureStatus), Error(PcidServerResponseError), + FeatureInfo(PciFeature, PciFeatureInfo), } // TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over @@ -158,4 +177,32 @@ impl PcidServerHandle { other => Err(PcidClientHandleError::InvalidResponse(other)), } } + pub fn fetch_all_features(&mut self) -> Result> { + self.send(&PcidClientRequest::RequestFeatures)?; + match self.recv()? { + PcidClientResponse::AllFeatures(a) => Ok(a), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } + pub fn feature_status(&mut self, feature: PciFeature) -> Result { + self.send(&PcidClientRequest::FeatureStatus(feature))?; + match self.recv()? { + PcidClientResponse::FeatureStatus(feat, status) if feat == feature => Ok(status), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } + pub fn enable_feature(&mut self, feature: PciFeature) -> Result<()> { + self.send(&PcidClientRequest::EnableFeature(feature))?; + match self.recv()? { + PcidClientResponse::FeatureEnabled(feat) if feat == feature => Ok(()), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } + pub fn feature_info(&mut self, feature: PciFeature) -> Result { + self.send(&PcidClientRequest::FeatureInfo(feature))?; + match self.recv()? { + PcidClientResponse::FeatureInfo(feat, info) if feat == feature => Ok(info), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 78416db8c3..42f28f29bf 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -105,6 +105,18 @@ impl DriverHandler { None }).unwrap_or(FeatureStatus::Disabled), }), + PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo(feature, match feature { + PciFeature::Msi => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msi()) { + PciFeatureInfo::Msi(*info) + } else { + return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)); + } + PciFeature::MsiX => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msix()) { + PciFeatureInfo::MsiX(*info) + } else { + return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)); + } + }), } } fn handle_spawn(mut self, pcid_to_client_write: Option, pcid_from_client_read: Option, args: driver_interface::SubdriverArguments) { @@ -116,7 +128,7 @@ impl DriverHandler { while let Ok(msg) = recv(&mut pcid_from_client) { let response = self.respond(msg, &args); - send(&mut pcid_to_client, &response); + send(&mut pcid_to_client, &response).unwrap(); } } } @@ -294,6 +306,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, }; crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() }; + println!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); let func = driver_interface::PciFunction { bars, diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index c458174536..6159dc0f6a 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -1,4 +1,5 @@ -use super::func::{ConfigReader, ConfigWriter}; +use super::func::ConfigReader; +use serde::{Serialize, Deserialize}; pub struct CapabilityOffsetsIter<'a, R> { offset: u8, @@ -42,7 +43,7 @@ pub enum CapabilityId { Pcie = 0x10, } -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum MsiCapability { _32BitAddress { message_control: u32, @@ -72,220 +73,18 @@ pub enum MsiCapability { }, } -impl MsiCapability { - pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8; - pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7; - - pub const MC_MULTI_MESSAGE_MASK: u16 = 0x000E; - pub const MC_MULTI_MESSAGE_SHIFT: u8 = 1; - - pub const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070; - pub const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4; - - pub const MC_MSI_ENABLED_BIT: u16 = 1; - - pub unsafe fn parse(reader: &R, offset: u8) -> Self { - let dword = reader.read_u32(offset); - - let message_control = (dword >> 16) as u16; - - if message_control & Self::MC_PVT_CAPABLE_BIT != 0 { - if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { - Self::_64BitAddressWithPvm { - message_control: dword, - message_address_lo: reader.read_u32(offset + 4), - message_address_hi: reader.read_u32(offset + 8), - message_data: reader.read_u32(offset + 12), - mask_bits: reader.read_u32(offset + 16), - pending_bits: reader.read_u32(offset + 20), - } - } else { - Self::_32BitAddressWithPvm { - message_control: dword, - message_address: reader.read_u32(offset + 4), - message_data: reader.read_u32(offset + 8), - mask_bits: reader.read_u32(offset + 12), - pending_bits: reader.read_u32(offset + 16), - } - } - } else { - if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { - Self::_64BitAddress { - message_control: dword, - message_address_lo: reader.read_u32(offset + 4), - message_address_hi: reader.read_u32(offset + 8), - message_data: reader.read_u32(offset + 12), - } - } else { - Self::_32BitAddress { - message_control: dword, - message_address: reader.read_u32(offset + 4), - message_data: reader.read_u32(offset + 8), - } - } - } - } - - fn message_control_raw(&self) -> u32 { - match self { - Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control, - } - } - pub fn message_control(&self) -> u16 { - self.message_control_raw() as u16 - } - pub unsafe fn set_message_control(&mut self, writer: &W, offset: u8, value: u16) { - let mut new_message_control = self.message_control_raw(); - new_message_control &= 0x0000_FFFF; - new_message_control |= u32::from(value) << 16; - writer.write_u32(offset, new_message_control); - - match self { - Self::_32BitAddress { ref mut message_control, .. } - | Self::_64BitAddress { ref mut message_control, .. } - | Self::_32BitAddressWithPvm { ref mut message_control, .. } - | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, - } - } - pub fn is_pvt_capable(&self) -> bool { - self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 - } - pub fn has_64_bit_addr(&self) -> bool { - self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0 - } - pub fn enabled(&self) -> bool { - self.message_control() & Self::MC_MSI_ENABLED_BIT != 0 - } - pub unsafe fn set_enabled(&mut self, writer: &W, offset: u8, enabled: bool) { - let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); - new_message_control |= u16::from(enabled); - self.set_message_control(writer, offset, new_message_control) - } - pub fn multi_message_capable(&self) -> u8 { - ((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8 - } - pub fn multi_message_enabled(&self) -> u8 { - ((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_MASK) as u8 - } -} #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct PcieCapability { } -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct MsixCapability { pub a: u32, pub b: u32, pub c: u32, } -impl MsixCapability { - pub const MC_MSIX_ENABLED_BIT: u16 = 1 << 15; - pub const MC_MSIX_ENABLED_SHIFT: u8 = 15; - pub const MC_FUNCTION_MASK_BIT: u16 = 1 << 14; - pub const MC_FUNCTION_MASK_SHIFT: u8 = 14; - pub const MC_TABLE_SIZE_MASK: u16 = 0x03FF; - - /// The Message Control field, containing the enabled and function mask bits, as well as the - /// table size. - pub const fn message_control(&self) -> u16 { - (self.a >> 16) as u16 - } - - pub fn set_message_control(&mut self, message_control: u16) { - self.a &= 0x0000_FFFF; - self.a |= u32::from(message_control) << 16; - } - /// Returns the MSI-X table size, subtracted by one. - pub const fn table_size_raw(&self) -> u16 { - self.message_control() & Self::MC_TABLE_SIZE_MASK - } - /// Returns the MSI-X table size. - pub const fn table_size(&self) -> u16 { - self.table_size_raw() + 1 - } - /// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the - /// MSI capability structure. - pub const fn msix_enabled(&self) -> bool { - self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0 - } - /// The MSI-X function mask, which overrides each of the vectors' mask bit, when set. - pub const fn function_mask(&self) -> bool { - self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0 - } - - pub fn set_msix_enabled(&mut self, enabled: bool) { - let mut new_message_control = self.message_control(); - new_message_control &= !(Self::MC_MSIX_ENABLED_BIT); - new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT; - self.set_message_control(new_message_control); - } - - pub fn set_function_mask(&mut self, function_mask: bool) { - let mut new_message_control = self.message_control(); - new_message_control &= !(Self::MC_FUNCTION_MASK_BIT); - new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT; - self.set_message_control(new_message_control); - } - pub const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8; - pub const TABLE_BIR_MASK: u32 = 0x0000_0007; - - /// The table offset is guaranteed to be QWORD aligned (8 bytes). - pub const fn table_offset(&self) -> u32 { - self.b & Self::TABLE_OFFSET_MASK - } - /// The table BIR, which is used to map the offset to a memory location. - pub const fn table_bir(&self) -> u8 { - (self.b & Self::TABLE_BIR_MASK) as u8 - } - - pub fn set_table_offset(&mut self, offset: u32) { - assert_eq!(offset & Self::TABLE_OFFSET_MASK, offset, "MSI-X table offset has to be QWORD aligned"); - self.b &= !Self::TABLE_OFFSET_MASK; - self.b |= offset; - } - pub const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8; - pub const PBA_BIR_MASK: u32 = 0x0000_0007; - - /// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes). - pub const fn pba_offset(&self) -> u32 { - self.b & Self::PBA_OFFSET_MASK - } - /// The Pending Bit Array BIR, which is used to map the offset to a memory location. - pub const fn pba_bir(&self) -> u8 { - (self.b & Self::PBA_BIR_MASK) as u8 - } - - pub fn set_pba_offset(&mut self, offset: u32) { - assert_eq!(offset & Self::PBA_OFFSET_MASK, offset, "MSI-X Pending Bit Array offset has to be QWORD aligned"); - self.c &= !Self::PBA_OFFSET_MASK; - self.c |= offset; - } - - /// Write the first DWORD into configuration space (containing the partially modifiable Message - /// Control field). - pub unsafe fn write_a(&self, writer: &W, offset: u8) { - writer.write_u32(offset, self.a) - } - /// Write the second DWORD into configuration space (containing the modifiable table - /// offset and the readonly table BIR). - pub unsafe fn write_b(&self, writer: &W, offset: u8) { - writer.write_u32(offset + 4, self.a) - } - /// Write the third DWORD into configuration space (containing the modifiable pending bit array - /// offset, and the readonly PBA BIR). - pub unsafe fn write_c(&self, writer: &W, offset: u8) { - writer.write_u32(offset + 8, self.a) - } - /// Write this capability structure back to configuration space. - pub unsafe fn write_all(&self, writer: &W, offset: u8) { - self.write_a(writer, offset); - self.write_b(writer, offset); - self.write_c(writer, offset); - } -} - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum Capability { Msi(MsiCapability), diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 6e763a89e4..b3395517eb 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -14,6 +14,7 @@ mod class; mod dev; mod func; pub mod header; +pub mod msi; pub struct Pci { lock: Mutex<()>, diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs new file mode 100644 index 0000000000..2a662f6737 --- /dev/null +++ b/pcid/src/pci/msi.rs @@ -0,0 +1,296 @@ +use std::fmt; + +use super::bar::PciBar; +pub use super::cap::{MsiCapability, MsixCapability}; +use super::func::{ConfigReader, ConfigWriter}; + +use syscall::{Io, Mmio}; + +impl MsiCapability { + pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8; + pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7; + + pub const MC_MULTI_MESSAGE_MASK: u16 = 0x000E; + pub const MC_MULTI_MESSAGE_SHIFT: u8 = 1; + + pub const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070; + pub const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4; + + pub const MC_MSI_ENABLED_BIT: u16 = 1; + + pub unsafe fn parse(reader: &R, offset: u8) -> Self { + let dword = reader.read_u32(offset); + + let message_control = (dword >> 16) as u16; + + if message_control & Self::MC_PVT_CAPABLE_BIT != 0 { + if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { + Self::_64BitAddressWithPvm { + message_control: dword, + message_address_lo: reader.read_u32(offset + 4), + message_address_hi: reader.read_u32(offset + 8), + message_data: reader.read_u32(offset + 12), + mask_bits: reader.read_u32(offset + 16), + pending_bits: reader.read_u32(offset + 20), + } + } else { + Self::_32BitAddressWithPvm { + message_control: dword, + message_address: reader.read_u32(offset + 4), + message_data: reader.read_u32(offset + 8), + mask_bits: reader.read_u32(offset + 12), + pending_bits: reader.read_u32(offset + 16), + } + } + } else { + if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { + Self::_64BitAddress { + message_control: dword, + message_address_lo: reader.read_u32(offset + 4), + message_address_hi: reader.read_u32(offset + 8), + message_data: reader.read_u32(offset + 12), + } + } else { + Self::_32BitAddress { + message_control: dword, + message_address: reader.read_u32(offset + 4), + message_data: reader.read_u32(offset + 8), + } + } + } + } + + fn message_control_raw(&self) -> u32 { + match self { + Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control, + } + } + pub fn message_control(&self) -> u16 { + (self.message_control_raw() >> 16) as u16 + } + pub unsafe fn set_message_control(&mut self, writer: &W, offset: u8, value: u16) { + let mut new_message_control = self.message_control_raw(); + new_message_control &= 0x0000_FFFF; + new_message_control |= u32::from(value) << 16; + writer.write_u32(offset, new_message_control); + + match self { + Self::_32BitAddress { ref mut message_control, .. } + | Self::_64BitAddress { ref mut message_control, .. } + | Self::_32BitAddressWithPvm { ref mut message_control, .. } + | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, + } + } + pub fn is_pvt_capable(&self) -> bool { + self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 + } + pub fn has_64_bit_addr(&self) -> bool { + self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0 + } + pub fn enabled(&self) -> bool { + self.message_control() & Self::MC_MSI_ENABLED_BIT != 0 + } + pub unsafe fn set_enabled(&mut self, writer: &W, offset: u8, enabled: bool) { + let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); + new_message_control |= u16::from(enabled); + self.set_message_control(writer, offset, new_message_control) + } + pub fn multi_message_capable(&self) -> u8 { + ((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8 + } + pub fn multi_message_enabled(&self) -> u8 { + ((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8 + } +} + +impl MsixCapability { + pub const MC_MSIX_ENABLED_BIT: u16 = 1 << 15; + pub const MC_MSIX_ENABLED_SHIFT: u8 = 15; + pub const MC_FUNCTION_MASK_BIT: u16 = 1 << 14; + pub const MC_FUNCTION_MASK_SHIFT: u8 = 14; + pub const MC_TABLE_SIZE_MASK: u16 = 0x03FF; + + /// The Message Control field, containing the enabled and function mask bits, as well as the + /// table size. + pub const fn message_control(&self) -> u16 { + (self.a >> 16) as u16 + } + + pub fn set_message_control(&mut self, message_control: u16) { + self.a &= 0x0000_FFFF; + self.a |= u32::from(message_control) << 16; + } + /// Returns the MSI-X table size, subtracted by one. + pub const fn table_size_raw(&self) -> u16 { + self.message_control() & Self::MC_TABLE_SIZE_MASK + } + /// Returns the MSI-X table size. + pub const fn table_size(&self) -> u16 { + self.table_size_raw() + 1 + } + /// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the + /// MSI capability structure. + pub const fn msix_enabled(&self) -> bool { + self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0 + } + /// The MSI-X function mask, which overrides each of the vectors' mask bit, when set. + pub const fn function_mask(&self) -> bool { + self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0 + } + + pub fn set_msix_enabled(&mut self, enabled: bool) { + let mut new_message_control = self.message_control(); + new_message_control &= !(Self::MC_MSIX_ENABLED_BIT); + new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT; + self.set_message_control(new_message_control); + } + + pub fn set_function_mask(&mut self, function_mask: bool) { + let mut new_message_control = self.message_control(); + new_message_control &= !(Self::MC_FUNCTION_MASK_BIT); + new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT; + self.set_message_control(new_message_control); + } + pub const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8; + pub const TABLE_BIR_MASK: u32 = 0x0000_0007; + + /// The table offset is guaranteed to be QWORD aligned (8 bytes). + pub const fn table_offset(&self) -> u32 { + self.b & Self::TABLE_OFFSET_MASK + } + /// The table BIR, which is used to map the offset to a memory location. + pub const fn table_bir(&self) -> u8 { + (self.b & Self::TABLE_BIR_MASK) as u8 + } + + pub fn set_table_offset(&mut self, offset: u32) { + assert_eq!(offset & Self::TABLE_OFFSET_MASK, offset, "MSI-X table offset has to be QWORD aligned"); + self.b &= !Self::TABLE_OFFSET_MASK; + self.b |= offset; + } + pub const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8; + pub const PBA_BIR_MASK: u32 = 0x0000_0007; + + /// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes). + pub const fn pba_offset(&self) -> u32 { + self.c & Self::PBA_OFFSET_MASK + } + /// The Pending Bit Array BIR, which is used to map the offset to a memory location. + pub const fn pba_bir(&self) -> u8 { + (self.c & Self::PBA_BIR_MASK) as u8 + } + + pub fn set_pba_offset(&mut self, offset: u32) { + assert_eq!(offset & Self::PBA_OFFSET_MASK, offset, "MSI-X Pending Bit Array offset has to be QWORD aligned"); + self.c &= !Self::PBA_OFFSET_MASK; + self.c |= offset; + } + + pub fn table_base_pointer(&self, bars: [PciBar; 6]) -> usize { + if self.table_bir() > 5 { + panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir()); + } + let base = bars[usize::from(self.table_bir())]; + + if let PciBar::Memory(ptr) = base { + ptr as usize + self.table_offset() as usize + } else { + panic!("MSI-X Table BIR referenced a non-memory BAR: {:?}", base); + } + } + pub fn table_pointer(&self, bars: [PciBar; 6], k: u16) -> usize { + self.table_base_pointer(bars) + k as usize * 16 + } + + pub fn pba_base_pointer(&self, bars: [PciBar; 6]) -> usize { + if self.pba_bir() > 5 { + panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir()); + } + let base = bars[usize::from(self.pba_bir())]; + + if let PciBar::Memory(ptr) = base { + ptr as usize + self.pba_offset() as usize + } else { + panic!("MSI-X PBA BIR referenced a non-memory BAR: {:?}", base); + } + } + pub fn pba_pointer_dword(&self, bars: [PciBar; 6], k: u16) -> usize { + self.pba_base_pointer(bars) + (k as usize / 32) * 4 + } + pub const fn pba_bit_dword(&self, k: u16) -> u8 { + (k % 32) as u8 + } + + pub fn pba_pointer_qword(&self, bars: [PciBar; 6], k: u16) -> usize { + self.pba_base_pointer(bars) + (k as usize / 64) * 8 + } + pub const fn pba_bit_qword(&self, k: u16) -> u8 { + (k % 64) as u8 + } + + /// Write the first DWORD into configuration space (containing the partially modifiable Message + /// Control field). + pub unsafe fn write_a(&self, writer: &W, offset: u8) { + writer.write_u32(offset, self.a) + } + /// Write the second DWORD into configuration space (containing the modifiable table + /// offset and the readonly table BIR). + pub unsafe fn write_b(&self, writer: &W, offset: u8) { + writer.write_u32(offset + 4, self.a) + } + /// Write the third DWORD into configuration space (containing the modifiable pending bit array + /// offset, and the readonly PBA BIR). + pub unsafe fn write_c(&self, writer: &W, offset: u8) { + writer.write_u32(offset + 8, self.a) + } + /// Write this capability structure back to configuration space. + pub unsafe fn write_all(&self, writer: &W, offset: u8) { + self.write_a(writer, offset); + self.write_b(writer, offset); + self.write_c(writer, offset); + } +} + +#[repr(packed)] +pub struct MsixTableEntry { + pub addr_lo: Mmio, + pub addr_hi: Mmio, + pub msg_data: Mmio, + pub vec_ctl: Mmio, +} + +impl MsixTableEntry { + pub fn addr_lo(&self) -> u32 { + self.addr_lo.read() + } + pub fn addr_hi(&self) -> u32 { + self.addr_hi.read() + } + pub fn msg_data(&self) -> u32 { + self.msg_data.read() + } + pub fn vec_ctl(&self) -> u32 { + self.vec_ctl.read() + } + pub fn addr(&self) -> u64 { + u64::from(self.addr_lo()) | (u64::from(self.addr_hi()) << 32) + } + pub const VEC_CTL_MASK_BIT: u32 = 1; + + pub fn mask(&mut self) { + self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, true) + } + pub fn unmask(&mut self) { + self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, false) + } +} + +impl fmt::Debug for MsixTableEntry { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("MsixTableEntry") + .field("addr", &self.addr()) + .field("msg_data", &self.msg_data()) + .field("vec_ctl", &self.vec_ctl()) + .finish() + } +} diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 0de08d86e9..87a09d7d36 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -4,6 +4,9 @@ extern crate event; extern crate plain; extern crate syscall; +use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo}; +use pcid_interface::MsixTableEntry; + use event::{Event, EventQueue}; use std::cell::RefCell; use std::fs::File; @@ -23,127 +26,185 @@ mod usb; mod xhci; fn main() { - println!("xhcid started"); - let mut pcid_handle = pcid_interface::PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); - dbg!(); - println!("XHCI from PCI config: {:?}", pcid_handle.fetch_config().expect("xhcid: failed to fetch config")); + let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); + let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); + println!("XHCI PCI CONFIG: {:?}", pci_config); - // Close the pipe, allowing pcid to continue. - drop(pcid_handle); + let bar = pci_config.func.bars[0]; + let irq = pci_config.func.legacy_interrupt_line; + let bar_ptr = match bar { + pcid_interface::PciBar::Memory(ptr) => ptr, + other => panic!("Expected memory bar, found {}", other), + }; + + let address = unsafe { + syscall::physmap(bar_ptr as usize, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("xhcid: failed to map address") + }; + + let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); + println!("XHCI PCI FEATURES: {:?}", all_pci_features); + + let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + + dbg!(has_msi, msi_enabled); + dbg!(has_msix, msix_enabled); + + if has_msi && !msi_enabled { + pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); + msi_enabled = true; + println!("Enabled MSI"); + } + if has_msi && msi_enabled && has_msix && !msix_enabled { + pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); + msix_enabled = true; + println!("Enabled MSI-X"); + } + + if msi_enabled && !msix_enabled { + todo!("only msi-x is currently implemented") + } + if msix_enabled { + let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") { + PciFeatureInfo::Msi(_) => panic!(), + PciFeatureInfo::MsiX(s) => s, + }; + let table_size = capability.table_size(); + let table_base = capability.table_base_pointer(pci_config.func.bars); + let table_min_length = table_size * 16; + let pba_min_length = crate::xhci::scheme::div_round_up(table_size, 8); + + let pba_base = capability.pba_base_pointer(pci_config.func.bars); + dbg!(table_size, table_base, table_min_length, pba_base); + + if !(bar_ptr..bar_ptr + 65536).contains(&(table_base as u32 + table_min_length as u32)) { + todo!() + } + if !(bar_ptr..bar_ptr + 65536).contains(&(pba_base as u32 + pba_min_length as u32)) { + todo!() + } + + let virt_table_base = ((table_base - bar_ptr as usize) + address) as *const MsixTableEntry; + let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *const u64; + + for k in 0..table_size { + assert_eq!(std::mem::size_of::(), 16); + let table_entry_pointer = unsafe { virt_table_base.offset(k as isize).as_ref().unwrap() }; + let pba_pointer = unsafe { virt_pba_base.offset(k as isize / 64).as_ref().unwrap() }; + let pba_bit = k % 64; + + dbg!(table_entry_pointer, (*pba_pointer >> pba_bit) & 1); + } + } + + std::thread::sleep(std::time::Duration::from_millis(300)); + + // Daemonize + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { + return; + } let mut args = env::args().skip(1); let mut name = args.next().expect("xhcid: no name provided"); name.push_str("_xhci"); - let bar_str = args.next().expect("xhcid: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("xhcid: failed to parse address"); - - let irq_str = args.next().expect("xhcid: no IRQ provided"); - let irq = irq_str.parse::().expect("xhcid: failed to parse irq"); - print!( "{}", - format!(" + XHCI {} on: {:X} IRQ: {}\n", name, bar, irq) + format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq) ); - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { - let socket_fd = syscall::open( - format!(":usb/{}", name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ) - .expect("xhcid: failed to create usb scheme"); - let socket = Arc::new(RefCell::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) - })); + let socket_fd = syscall::open( + format!(":usb/{}", name), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + ) + .expect("xhcid: failed to create usb scheme"); + let socket = Arc::new(RefCell::new(unsafe { + File::from_raw_fd(socket_fd as RawFd) + })); - let mut irq_file = - File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); + let mut irq_file = + File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); - let address = unsafe { - syscall::physmap(bar, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("xhcid: failed to map address") - }; - { - let hci = Arc::new(RefCell::new( - Xhci::new(name, address).expect("xhcid: failed to allocate device"), - )); + { + let hci = Arc::new(RefCell::new( + Xhci::new(name, address).expect("xhcid: failed to allocate device"), + )); - hci.borrow_mut().probe().expect("xhcid: failed to probe"); + hci.borrow_mut().probe().expect("xhcid: failed to probe"); - let mut event_queue = - EventQueue::<()>::new().expect("xhcid: failed to create event queue"); + let mut event_queue = + EventQueue::<()>::new().expect("xhcid: failed to create event queue"); - syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); + syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + let todo = Arc::new(RefCell::new(Vec::::new())); - let hci_irq = hci.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add(irq_file.as_raw_fd(), move |_| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; + let hci_irq = hci.clone(); + let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + event_queue + .add(irq_file.as_raw_fd(), move |_| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; - if hci_irq.borrow_mut().trigger_irq() { - irq_file.write(&mut irq)?; + if hci_irq.borrow_mut().trigger_irq() { + irq_file.write(&mut irq)?; - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - hci_irq.borrow_mut().handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket_irq.borrow_mut().write(&mut todo[i])?; - todo.remove(i); - } - } - } - - Ok(None) - }) - .expect("xhcid: failed to catch events on IRQ file"); - - let socket_fd = socket.borrow().as_raw_fd(); - let socket_packet = socket.clone(); - event_queue - .add(socket_fd, move |_| -> Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => break, - Err(err) if err.kind() == io::ErrorKind::WouldBlock => break, - Ok(_) => (), - Err(err) => return Err(err), - } - - let a = packet.a; - hci.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + hci_irq.borrow_mut().handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; } else { - socket_packet.borrow_mut().write(&mut packet)?; + socket_irq.borrow_mut().write(&mut todo[i])?; + todo.remove(i); } } - Ok(None) - }) - .expect("xhcid: failed to catch events on scheme file"); + } - event_queue - .trigger_all(Event { fd: 0, flags: 0 }) - .expect("xhcid: failed to trigger events"); + Ok(None) + }) + .expect("xhcid: failed to catch events on IRQ file"); - event_queue.run().expect("xhcid: failed to handle events"); - } - unsafe { - let _ = syscall::physunmap(address); - } + let socket_fd = socket.borrow().as_raw_fd(); + let socket_packet = socket.clone(); + event_queue + .add(socket_fd, move |_| -> Result> { + loop { + let mut packet = Packet::default(); + match socket_packet.borrow_mut().read(&mut packet) { + Ok(0) => break, + Err(err) if err.kind() == io::ErrorKind::WouldBlock => break, + Ok(_) => (), + Err(err) => return Err(err), + } + + let a = packet.a; + hci.borrow_mut().handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.borrow_mut().push(packet); + } else { + socket_packet.borrow_mut().write(&mut packet)?; + } + } + Ok(None) + }) + .expect("xhcid: failed to catch events on scheme file"); + + event_queue + .trigger_all(Event { fd: 0, flags: 0 }) + .expect("xhcid: failed to trigger events"); + + event_queue.run().expect("xhcid: failed to handle events"); + } + unsafe { + let _ = syscall::physunmap(address); } } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index ed4a0e29e8..530bb30fad 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -21,7 +21,7 @@ mod operational; mod port; mod ring; mod runtime; -mod scheme; +pub mod scheme; mod trb; use self::capability::CapabilityRegs; @@ -306,7 +306,7 @@ impl Xhci { Ok(cloned_event_trb.event_slot()) } pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> { - self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?; + self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.disable_slot(0, cycle))?; Ok(()) } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index e26b032810..20d8e81c9c 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -2003,7 +2003,7 @@ impl Xhci { } } use std::ops::{Add, Div, Rem}; -fn div_round_up(a: T, b: T) -> T +pub fn div_round_up(a: T, b: T) -> T where T: Add + Div + Rem + PartialEq + From + Copy, { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index d6d4cb30e0..4ad02bee37 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -203,6 +203,15 @@ impl Trb { | (cycle as u32), ); } + pub fn disable_slot(&mut self, slot: u8, cycle: bool) { + self.set( + 0, + 0, + (u32::from(slot) << 24) + | ((TrbType::DisableSlot as u32) << 10) + | u32::from(cycle) + ); + } pub fn address_device(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) { assert_eq!( From cb5a72fbc100cca943f7995b96311f835f019b6f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 20 Mar 2020 18:50:39 +0100 Subject: [PATCH 0364/1301] Successfully recognize (only one) MSI-X IRQ. Somehow it only happens once though. --- Cargo.lock | 2 +- pcid/Cargo.toml | 2 +- pcid/src/driver_interface.rs | 6 +- pcid/src/pci/msi.rs | 48 +++++++++++++ xhcid/src/main.rs | 126 +++++++++++++++++++++++++++-------- xhcid/src/xhci/command.rs | 3 +- xhcid/src/xhci/executor.rs | 1 + xhcid/src/xhci/mod.rs | 76 +++++++++++++++++---- 8 files changed, 218 insertions(+), 46 deletions(-) create mode 100644 xhcid/src/xhci/executor.rs diff --git a/Cargo.lock b/Cargo.lock index e0a97cc6da..43d3e114a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -697,7 +697,7 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 189aed0338..966d0ebff2 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -16,7 +16,7 @@ bincode = "1.2" bitflags = "1" byteorder = "1.2" libc = "0.2" -redox_syscall = "0.1" +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } serde = { version = "1", features = ["derive"] } serde_json = "1" thiserror = "1" diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface.rs index 47b8e108a2..e2f5b68d8c 100644 --- a/pcid/src/driver_interface.rs +++ b/pcid/src/driver_interface.rs @@ -8,7 +8,7 @@ use serde::{Serialize, Deserialize, de::DeserializeOwned}; use thiserror::Error; pub use crate::pci::PciBar; -pub use crate::pci::msi::{MsiCapability, MsixCapability, MsixTableEntry}; +pub use crate::pci::msi; #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct PciFunction { @@ -70,8 +70,8 @@ impl PciFeature { } #[derive(Debug, Serialize, Deserialize)] pub enum PciFeatureInfo { - Msi(MsiCapability), - MsiX(MsixCapability), + Msi(msi::MsiCapability), + MsiX(msi::MsixCapability), } #[derive(Debug, Error)] diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 2a662f6737..da993840ec 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -259,6 +259,54 @@ pub struct MsixTableEntry { pub vec_ctl: Mmio, } +#[cfg(target_arch = "x86_64")] +pub mod x86_64 { + #[repr(u8)] + pub enum TriggerMode { + Level = 0, + Edge = 1, + } + + #[repr(u8)] + pub enum LevelTriggerMode { + Deassert = 0, + Assert = 1, + } + + #[repr(u8)] + pub enum DeliveryMode { + Fixed = 0b000, + LowestPriority = 0b001, + Smi = 0b010, + // 0b011 is reserved + Nmi = 0b100, + Init = 0b101, + // 0b110 is reserved + ExtInit = 0b111, + } + + // TODO: should the reserved field be preserved? + pub const fn message_address(destination_id: u8, rh: bool, dm: bool, xx: u8) -> u32 { + 0xFEE0_0000u32 + | ((destination_id as u32) << 12) + | ((rh as u32) << 3) + | ((dm as u32) << 2) + | xx as u32 + } + pub const fn message_data(trigger_mode: TriggerMode, level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 { + ((trigger_mode as u32) << 15) + | ((level_trigger_mode as u32) << 14) + | ((delivery_mode as u32) << 8) + | vector as u32 + } + pub const fn message_data_level_triggered(level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 { + message_data(TriggerMode::Level, level_trigger_mode, delivery_mode, vector) + } + pub const fn message_data_edge_triggered(delivery_mode: DeliveryMode, vector: u8) -> u32 { + message_data(TriggerMode::Edge, LevelTriggerMode::Deassert, delivery_mode, vector) + } +} + impl MsixTableEntry { pub fn addr_lo(&self) -> u32 { self.addr_lo.read() diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 87a09d7d36..e8c29b2848 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -5,19 +5,22 @@ extern crate plain; extern crate syscall; use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo}; -use pcid_interface::MsixTableEntry; +use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; use event::{Event, EventQueue}; use std::cell::RefCell; -use std::fs::File; -use std::io::{Read, Result, Write}; +use std::convert::TryInto; +use std::fs::{self, File}; +use std::io::{self, Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::ptr::NonNull; use std::sync::Arc; -use std::{env, io}; +use std::env; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::scheme::SchemeMut; +use syscall::io::Io; use crate::xhci::Xhci; @@ -25,7 +28,55 @@ mod driver_interface; mod usb; mod xhci; +/// Read the local APIC id of the bootstrap processor. +fn read_bsp_apic_id() -> io::Result { + let mut buffer = [0u8; 8]; + + let mut file = File::open("irq:bsp")?; + let bytes_read = file.read(&mut buffer)?; + + Ok(if bytes_read == 8 { + u64::from_le_bytes(buffer) as u32 + } else if bytes_read == 4 { + u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]) + } else { + panic!("`irq:` scheme responded with {} bytes, expected {}", bytes_read, std::mem::size_of::()); + }) +} +/// Allocate an interrupt vector, located at the BSP's IDT. +fn allocate_interrupt_vector() -> io::Result> { + let available_irqs = fs::read_dir("irq:")?; + + for entry in available_irqs { + let entry = entry?; + let path = entry.path(); + + let file_name = match path.file_name() { + Some(f) => f, + None => continue, + }; + + let path_str = match file_name.to_str() { + Some(s) => s, + None => continue, + }; + + if let Ok(irq_number) = path_str.parse::() { + // if found, reserve the irq + let irq_handle = File::create(format!("irq:{}", irq_number))?; + let interrupt_vector = irq_number + 32; + return Ok(Some((interrupt_vector, irq_handle))); + } + } + Ok(None) +} + fn main() { + // Daemonize + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { + return; + } + let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); println!("XHCI PCI CONFIG: {:?}", pci_config); @@ -63,10 +114,9 @@ fn main() { println!("Enabled MSI-X"); } - if msi_enabled && !msix_enabled { + let (mut irq_file, msix_info) = if msi_enabled && !msix_enabled { todo!("only msi-x is currently implemented") - } - if msix_enabled { + } else if msix_enabled { let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, @@ -86,26 +136,49 @@ fn main() { todo!() } - let virt_table_base = ((table_base - bar_ptr as usize) + address) as *const MsixTableEntry; - let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *const u64; + let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; + let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; + + let mut info = xhci::MsixInfo { + virt_table_base: NonNull::new(virt_table_base).unwrap(), + virt_pba_base: NonNull::new(virt_pba_base).unwrap(), + capability, + }; + + // Allocate one msi vector. + + { + use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; + + // primary interrupter + let k = 0; - for k in 0..table_size { assert_eq!(std::mem::size_of::(), 16); - let table_entry_pointer = unsafe { virt_table_base.offset(k as isize).as_ref().unwrap() }; - let pba_pointer = unsafe { virt_pba_base.offset(k as isize / 64).as_ref().unwrap() }; - let pba_bit = k % 64; + let table_entry_pointer = info.table_entry_pointer(k); - dbg!(table_entry_pointer, (*pba_pointer >> pba_bit) & 1); + let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); + let rh = false; + let dm = false; + let addr = x86_64_msix::message_address(destination_id.try_into().expect("xhcid: BSP apic id couldn't fit u8"), rh, dm, 0b00); + + let (vector, interrupt_handle) = allocate_interrupt_vector().expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); + let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + + dbg!(vector, destination_id); + + table_entry_pointer.addr_lo.write(addr); + table_entry_pointer.addr_hi.write(0); + table_entry_pointer.msg_data.write(msg_data); + table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + + (interrupt_handle, Some(info)) } - } + } else { + (File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file"), None) + }; std::thread::sleep(std::time::Duration::from_millis(300)); - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { - return; - } - let mut args = env::args().skip(1); let mut name = args.next().expect("xhcid: no name provided"); @@ -125,12 +198,9 @@ fn main() { File::from_raw_fd(socket_fd as RawFd) })); - let mut irq_file = - File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file"); - { let hci = Arc::new(RefCell::new( - Xhci::new(name, address).expect("xhcid: failed to allocate device"), + Xhci::new(name, address, msi_enabled, msix_enabled, msix_info).expect("xhcid: failed to allocate device"), )); hci.borrow_mut().probe().expect("xhcid: failed to probe"); @@ -146,11 +216,13 @@ fn main() { let socket_irq = socket.clone(); let todo_irq = todo.clone(); event_queue - .add(irq_file.as_raw_fd(), move |_| -> Result> { + .add(irq_file.as_raw_fd(), move |_| -> io::Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; - if hci_irq.borrow_mut().trigger_irq() { + if hci_irq.borrow_mut().received_irq() { + hci_irq.borrow_mut().on_irq(); + irq_file.write(&mut irq)?; let mut todo = todo_irq.borrow_mut(); @@ -175,7 +247,7 @@ fn main() { let socket_fd = socket.borrow().as_raw_fd(); let socket_packet = socket.clone(); event_queue - .add(socket_fd, move |_| -> Result> { + .add(socket_fd, move |_| -> io::Result> { loop { let mut packet = Packet::default(); match socket_packet.borrow_mut().read(&mut packet) { diff --git a/xhcid/src/xhci/command.rs b/xhcid/src/xhci/command.rs index ca78d592fe..c82dc4311e 100644 --- a/xhcid/src/xhci/command.rs +++ b/xhcid/src/xhci/command.rs @@ -22,7 +22,8 @@ impl CommandRing { } pub fn erdp(&self) -> u64 { - self.events.ring.register() + let address = self.events.ring.register(); + address & 0xFFFF_FFFF_FFFF_FFF0 } pub fn erstba(&self) -> u64 { diff --git a/xhcid/src/xhci/executor.rs b/xhcid/src/xhci/executor.rs new file mode 100644 index 0000000000..01fe6603d8 --- /dev/null +++ b/xhcid/src/xhci/executor.rs @@ -0,0 +1 @@ +use super::Xhci; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 530bb30fad..47df7db0a8 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -11,11 +11,14 @@ use syscall::io::{Dma, Io}; use crate::usb; +use pcid_interface::msi::{MsixTableEntry, MsixCapability}; + mod capability; mod command; mod context; mod doorbell; mod event; +pub mod executor; mod extended; mod operational; mod port; @@ -39,6 +42,33 @@ use self::scheme::EndpIfState; use crate::driver_interface::*; +pub struct MsixInfo { + pub virt_table_base: NonNull, + pub virt_pba_base: NonNull, + pub capability: MsixCapability, +} +impl MsixInfo { + pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { + &mut *self.virt_table_base.as_ptr().offset(k as isize) + } + pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { + assert!(k < self.capability.table_size() as usize); + unsafe { self.table_entry_pointer_unchecked(k) } + } + pub unsafe fn pba_pointer_unchecked(&mut self, k: usize) -> &mut u64 { + &mut *self.virt_pba_base.as_ptr().offset(k as isize) + } + pub fn pba_pointer(&mut self, k: usize) -> &mut u64 { + assert!(k < self.capability.table_size() as usize); + unsafe { self.pba_pointer_unchecked(k) } + } + pub fn pba(&mut self, k: usize) -> bool { + let byte = k / 64; + let bit = k % 64; + *self.pba_pointer(byte) & (1 << bit) != 0 + } +} + struct Device<'a> { ring: &'a mut Ring, cmd: &'a mut CommandRing, @@ -139,6 +169,10 @@ pub struct Xhci { drivers: BTreeMap, scheme_name: String, + + msi: bool, + msix: bool, + msix_info: Option, } struct PortState { @@ -167,7 +201,7 @@ impl EndpointState { } impl Xhci { - pub fn new(scheme_name: String, address: usize) -> Result { + pub fn new(scheme_name: String, address: usize, msi: bool, msix: bool, msix_info: Option) -> Result { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; println!(" - CAP {:X}", address); @@ -239,6 +273,9 @@ impl Xhci { }), drivers: BTreeMap::new(), scheme_name, + msi, + msix, + msix_info, }; xhci.init(max_slots); @@ -277,7 +314,11 @@ impl Xhci { println!(" - Write ERSTBA: {:X}", erstba); self.run.ints[0].erstba.write(erstba as u64); + println!(" - Write IMODC and IMODI: {} and {}", 0, 0); + self.run.ints[0].imod.write(0); + println!(" - Enable interrupts"); + self.run.ints[0].iman.writef(1, true); // clear interrupt pending if set earlier by the BIOS self.run.ints[0].iman.writef(1 << 1, true); } @@ -506,25 +547,34 @@ impl Xhci { } - pub fn trigger_irq(&mut self) -> bool { - // Read the Interrupter Pending bit. - if self.run.ints[0].iman.readf(1) { - //println!("XHCI Interrupt"); - - // If set, set it back to zero, so that new interrupts can be triggered. - // FIXME: MSI and MSI-X systems + /// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always + /// true when using MSI/MSI-X. + pub fn received_irq(&mut self) -> bool { + if self.msi || self.msix { + // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit + // doesn't have to be touched. + println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", self.run.ints[0].iman.readf(1), self.run.ints[0].erdp.readf(3)); + println!("MSI-X PB={}", self.msix_info.as_ref().unwrap().pba(0)); + true + } else if self.run.ints[0].iman.readf(1) { + // If MSI and/or MSI-X are not used, the interrupt has to be shared, and thus there is + // a special register to specify whether the IRQ actually came from the xHC. self.run.ints[0].iman.writef(1, true); - // Wake all futures awaiting the IRQ. - for waker in self.irq_state.wakers.lock().unwrap().drain(..) { - waker.wake(); - } - + // The interrupt came from the xHC. true } else { + // The interrupt came from a different device. false } } + /// Handle an IRQ event. + pub fn on_irq(&mut self) { + // Wake all futures awaiting the IRQ. + for waker in self.irq_state.wakers.lock().unwrap().drain(..) { + waker.wake(); + } + } pub(crate) fn irq(&self) -> IrqFuture { IrqFuture { state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state)), From cfc4d65d4882be57b745e430299bbdf19c578990 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 22 Mar 2020 15:34:14 +0100 Subject: [PATCH 0365/1301] THE INTERRUPTS ARE GETTING GENERATED! --- pcid/src/pci/msi.rs | 4 ++-- xhcid/src/main.rs | 8 ++------ xhcid/src/xhci/mod.rs | 41 +++++++++++++++++++++++++++++++++------- xhcid/src/xhci/scheme.rs | 16 ++++++++++------ 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index da993840ec..8b420501aa 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -263,8 +263,8 @@ pub struct MsixTableEntry { pub mod x86_64 { #[repr(u8)] pub enum TriggerMode { - Level = 0, - Edge = 1, + Edge = 0, + Level = 1, } #[repr(u8)] diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index e8c29b2848..a415b5cc24 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -104,14 +104,10 @@ fn main() { dbg!(has_msix, msix_enabled); if has_msi && !msi_enabled { - pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); msi_enabled = true; - println!("Enabled MSI"); } - if has_msi && msi_enabled && has_msix && !msix_enabled { - pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); + if has_msix && !msix_enabled { msix_enabled = true; - println!("Enabled MSI-X"); } let (mut irq_file, msix_info) = if msi_enabled && !msix_enabled { @@ -200,7 +196,7 @@ fn main() { { let hci = Arc::new(RefCell::new( - Xhci::new(name, address, msi_enabled, msix_enabled, msix_info).expect("xhcid: failed to allocate device"), + Xhci::new(name, address, msi_enabled, msix_enabled, msix_info, pcid_handle).expect("xhcid: failed to allocate device"), )); hci.borrow_mut().probe().expect("xhcid: failed to probe"); diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 47df7db0a8..813ec2728b 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -12,6 +12,7 @@ use syscall::io::{Dma, Io}; use crate::usb; use pcid_interface::msi::{MsixTableEntry, MsixCapability}; +use pcid_interface::{PcidServerHandle, PciFeature}; mod capability; mod command; @@ -108,7 +109,7 @@ impl<'a> Device<'a> { } } - self.int.erdp.write(self.cmd.erdp()); + self.int.erdp.write(self.cmd.erdp() | (1 << 3)); } fn get_device(&mut self) -> Result { @@ -173,6 +174,8 @@ pub struct Xhci { msi: bool, msix: bool, msix_info: Option, + + pcid_handle: PcidServerHandle, } struct PortState { @@ -201,7 +204,7 @@ impl EndpointState { } impl Xhci { - pub fn new(scheme_name: String, address: usize, msi: bool, msix: bool, msix_info: Option) -> Result { + pub fn new(scheme_name: String, address: usize, msi: bool, msix: bool, msix_info: Option, handle: PcidServerHandle) -> Result { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; println!(" - CAP {:X}", address); @@ -276,6 +279,7 @@ impl Xhci { msi, msix, msix_info, + pcid_handle: handle, }; xhci.init(max_slots); @@ -302,13 +306,29 @@ impl Xhci { // Set event ring segment table registers println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); { + self.run.ints[0].iman.writef(1, true); // clear interrupt pending if set earlier by the BIOS + + println!("IP={}", self.run.ints[0].iman.readf(1)); + + /*if self.msi { + self.pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); + println!("Enabled MSI"); + }*/ + if self.msix { + self.pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); + println!("Enabled MSI-X"); + } + + dbg!(self.pcid_handle.feature_info(PciFeature::MsiX).unwrap()); + dbg!(self.pcid_handle.feature_info(PciFeature::Msi).unwrap()); + let erstz = 1; println!(" - Write ERSTZ: {}", erstz); self.run.ints[0].erstsz.write(erstz); let erdp = self.cmd.erdp(); println!(" - Write ERDP: {:X}", erdp); - self.run.ints[0].erdp.write(erdp as u64); + self.run.ints[0].erdp.write(erdp as u64 | (1 << 3)); let erstba = self.cmd.erstba(); println!(" - Write ERSTBA: {:X}", erstba); @@ -318,13 +338,14 @@ impl Xhci { self.run.ints[0].imod.write(0); println!(" - Enable interrupts"); - self.run.ints[0].iman.writef(1, true); // clear interrupt pending if set earlier by the BIOS self.run.ints[0].iman.writef(1 << 1, true); + } + self.op.usb_cmd.writef(1 << 2, true); // Set run/stop to 1 println!(" - Start"); - self.op.usb_cmd.writef(1 | 1 << 2, true); + self.op.usb_cmd.writef(1, true); // Wait until controller is running println!(" - Wait for running"); @@ -332,6 +353,8 @@ impl Xhci { println!(" - Waiting for XHCI running"); } + println!("IP={}", self.run.ints[0].iman.readf(1)); + // Ring command doorbell println!(" - Ring doorbell"); self.dbs[0].write(0); @@ -356,6 +379,7 @@ impl Xhci { } pub fn probe(&mut self) -> Result<()> { + println!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); for i in 0..self.ports.len() { let (data, state, speed, flags) = { let port = &self.ports[i]; @@ -554,10 +578,12 @@ impl Xhci { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", self.run.ints[0].iman.readf(1), self.run.ints[0].erdp.readf(3)); - println!("MSI-X PB={}", self.msix_info.as_ref().unwrap().pba(0)); + println!("MSI-X PB={}", self.msix_info.as_mut().unwrap().pba(0)); + let entry = self.msix_info.as_mut().unwrap().table_entry_pointer(0); + println!("MSI-X entry (addr_lo, addr_hi, msg_data, vec_ctl: {:#0x} {:#0x} {:#0x} {:#0x}", entry.addr_lo.read(), entry.addr_hi.read(), entry.msg_data.read(), entry.vec_ctl.read()); true } else if self.run.ints[0].iman.readf(1) { - // If MSI and/or MSI-X are not used, the interrupt has to be shared, and thus there is + // If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is // a special register to specify whether the IRQ actually came from the xHC. self.run.ints[0].iman.writef(1, true); @@ -567,6 +593,7 @@ impl Xhci { // The interrupt came from a different device. false } + } /// Handle an IRQ event. pub fn on_irq(&mut self) { diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 20d8e81c9c..1abfc8b056 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -216,16 +216,20 @@ impl Xhci { cmd_name: &str, f: F, ) -> Result { - self.run.ints[0].erdp.write(self.cmd.erdp()); + self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); let (cmd, cycle, event) = self.cmd.next(); f(cmd, cycle); + println!("INTE={}", self.op.usb_cmd.readf(1 << 2)); + println!("IP={}", self.run.ints[0].iman.readf(1)); self.dbs[0].write(0); + println!("IP={}", self.run.ints[0].iman.readf(1)); - while event.data.read() == 0 { + while event.data.read() == 0/* || self.run.ints[0].iman.readf(1)*/ { println!(" - {} Waiting for event", cmd_name); } + println!("IP={}", self.run.ints[0].iman.readf(1)); if event.completion_code() != TrbCompletionCode::Success as u8 || event.trb_type() != TrbType::CommandCompletion as u8 @@ -239,7 +243,7 @@ impl Xhci { cmd.reserved(false); event.reserved(false); - self.run.ints[0].erdp.write(self.cmd.erdp()); + self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); Ok(ret) } pub fn execute_control_transfer( @@ -299,7 +303,7 @@ impl Xhci { event.clone() }; - self.run.ints[0].erdp.write(self.cmd.erdp()); + self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); Ok(cloned_trb) } @@ -385,7 +389,7 @@ impl Xhci { cloned_trb }; - self.run.ints[0].erdp.write(self.cmd.erdp()); + self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); Ok(cloned_trb) } @@ -995,7 +999,7 @@ impl Xhci { // TODO: Should the descriptors be stored in PortState? - run.ints[0].erdp.write(cmd.erdp()); + run.ints[0].erdp.write(cmd.erdp() | (1 << 3)); let mut dev = Device { ring, From 443b160b6d67dd67d8fd36c9c34fc5d12a3631e8 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 26 Mar 2020 18:18:00 +0100 Subject: [PATCH 0366/1301] Add internal locking to the Xhci struct. --- Cargo.lock | 172 +++++++++++++++ pcid/src/driver_interface.rs | 23 +- pcid/src/main.rs | 23 +- pcid/src/pci/msi.rs | 15 +- xhcid/Cargo.toml | 3 + xhcid/src/main.rs | 141 +++++++----- xhcid/src/xhci/capability.rs | 20 ++ xhcid/src/xhci/command.rs | 46 ---- xhcid/src/xhci/context.rs | 44 +++- xhcid/src/xhci/event.rs | 7 + xhcid/src/xhci/executor.rs | 1 - xhcid/src/xhci/irq_reactor.rs | 395 ++++++++++++++++++++++++++++++++++ xhcid/src/xhci/mod.rs | 279 ++++++++++++------------ xhcid/src/xhci/ring.rs | 53 ++++- xhcid/src/xhci/scheme.rs | 383 ++++++++++++++++---------------- xhcid/src/xhci/trb.rs | 71 +++++- 16 files changed, 1221 insertions(+), 455 deletions(-) delete mode 100644 xhcid/src/xhci/command.rs delete mode 100644 xhcid/src/xhci/executor.rs create mode 100644 xhcid/src/xhci/irq_reactor.rs diff --git a/Cargo.lock b/Cargo.lock index 43d3e114a3..2eeb19c3db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -141,6 +141,15 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chashmap" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "clap" version = "2.33.0" @@ -259,6 +268,88 @@ name = "futures" version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "futures" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-channel" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-executor" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-io" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "futures-sink" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-task" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futures-util" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gpt" version = "0.6.3" @@ -419,6 +510,11 @@ name = "maybe-uninit" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memoffset" version = "0.5.3" @@ -627,6 +723,14 @@ dependencies = [ "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "owning_ref" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "owning_ref" version = "0.4.0" @@ -635,6 +739,15 @@ dependencies = [ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parking_lot" version = "0.7.1" @@ -644,6 +757,17 @@ dependencies = [ "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot_core" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parking_lot_core" version = "0.4.0" @@ -716,11 +840,26 @@ name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "plain" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "proc-macro-hack" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro-nested" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "proc-macro2" version = "1.0.8" @@ -747,6 +886,18 @@ dependencies = [ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.6.5" @@ -1527,6 +1678,9 @@ name = "xhcid" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "pcid 0.1.0", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1558,6 +1712,7 @@ dependencies = [ "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff41a3c2c1e39921b9003de14bf0439c7b63a9039637c291e1a64925d8ddfa45" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" @@ -1571,6 +1726,15 @@ dependencies = [ "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" +"checksum futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" +"checksum futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" +"checksum futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" +"checksum futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" +"checksum futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" +"checksum futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" +"checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" +"checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" +"checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" "checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" "checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" @@ -1589,6 +1753,7 @@ dependencies = [ "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" @@ -1607,16 +1772,23 @@ dependencies = [ "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402" +"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" +"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" +"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" "checksum pbr 1.0.2 (git+https://github.com/a8m/pb)" = "" "checksum pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4403eb718d70c03ee279e51737782902c68cca01e870a33b6a2f9dfb50b9cd83" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +"checksum proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420" +"checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" "checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface.rs index e2f5b68d8c..28c06ef02a 100644 --- a/pcid/src/driver_interface.rs +++ b/pcid/src/driver_interface.rs @@ -10,21 +10,42 @@ use thiserror::Error; pub use crate::pci::PciBar; pub use crate::pci::msi; +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[repr(u8)] +pub enum LegacyInterruptPin { + /// INTa# + IntA = 1, + /// INTb# + IntB = 2, + /// INTc# + IntC = 3, + /// INTd# + IntD = 4, +} + #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct PciFunction { /// Number of PCI bus pub bus_num: u8, + /// Number of PCI device pub dev_num: u8, + /// Number of PCI function pub func_num: u8, + /// PCI Base Address Registers pub bars: [PciBar; 6], + /// BAR sizes pub bar_sizes: [u32; 6], + /// Legacy IRQ line - // TODO: Stop using legacy IRQ lines, and physical pins, but MSI/MSI-X instead. pub legacy_interrupt_line: u8, + + /// Legacy interrupt pin (INTx#), none if INTx# interrupts aren't supported at all. + pub legacy_interrupt_pin: Option, + /// Vendor ID pub venid: u16, /// Device ID diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 42f28f29bf..63637cb50b 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -75,7 +75,10 @@ impl DriverHandler { None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), }; unsafe { - with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| capability.set_enabled(func, offset, true)); + with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| { + capability.set_enabled(true); + capability.write_message_control(func, offset); + }); } PcidClientResponse::FeatureEnabled(feature) } @@ -255,6 +258,8 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, pci.write(bus_num, dev_num, func_num, 0x3C, data); } + let interrupt_pin = unsafe { pci.read(bus_num, dev_num, func_num, 0x3B) }; + // Find BAR sizes let mut bars = [PciBar::None; 6]; let mut bar_sizes = [0; 6]; @@ -308,6 +313,21 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, }; println!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); + use driver_interface::LegacyInterruptPin; + + let legacy_interrupt_pin = match interrupt_pin { + 0 => None, + 1 => Some(LegacyInterruptPin::IntA), + 2 => Some(LegacyInterruptPin::IntB), + 3 => Some(LegacyInterruptPin::IntC), + 4 => Some(LegacyInterruptPin::IntD), + + other => { + println!("pcid: invalid interrupt pin: {}", other); + None + } + }; + let func = driver_interface::PciFunction { bars, bar_sizes, @@ -316,6 +336,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, func_num, devid: header.device_id(), legacy_interrupt_line: irq, + legacy_interrupt_pin, venid: header.vendor_id(), }; diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 8b420501aa..d4400257f4 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -68,11 +68,10 @@ impl MsiCapability { pub fn message_control(&self) -> u16 { (self.message_control_raw() >> 16) as u16 } - pub unsafe fn set_message_control(&mut self, writer: &W, offset: u8, value: u16) { + pub fn set_message_control(&mut self, value: u16) { let mut new_message_control = self.message_control_raw(); new_message_control &= 0x0000_FFFF; new_message_control |= u32::from(value) << 16; - writer.write_u32(offset, new_message_control); match self { Self::_32BitAddress { ref mut message_control, .. } @@ -81,6 +80,9 @@ impl MsiCapability { | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, } } + pub unsafe fn write_message_control(&mut self, writer: &W, offset: u8) { + writer.write_u32(offset, self.message_control_raw()); + } pub fn is_pvt_capable(&self) -> bool { self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 } @@ -90,10 +92,10 @@ impl MsiCapability { pub fn enabled(&self) -> bool { self.message_control() & Self::MC_MSI_ENABLED_BIT != 0 } - pub unsafe fn set_enabled(&mut self, writer: &W, offset: u8, enabled: bool) { + pub fn set_enabled(&mut self, enabled: bool) { let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); new_message_control |= u16::from(enabled); - self.set_message_control(writer, offset, new_message_control) + self.set_message_control(new_message_control); } pub fn multi_message_capable(&self) -> u8 { ((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8 @@ -101,6 +103,11 @@ impl MsiCapability { pub fn multi_message_enabled(&self) -> u8 { ((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8 } + pub fn set_multi_message_enabled(&mut self, log_mme: u8) { + let mut new_message_control = self.message_control() & (!Self::MC_MULTI_MESSAGE_ENABLE_MASK); + new_message_control |= (u16::from(log_mme) << Self::MC_MULTI_MESSAGE_ENABLE_SHIFT); + self.set_message_control(new_message_control); + } } impl MsixCapability { diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 0ef92d5fd7..e46a79a13b 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -13,6 +13,9 @@ path = "src/lib.rs" [dependencies] bitflags = "1" +chashmap = "2.2.2" +crossbeam-channel = "0.4" +futures = "0.3" plain = "0.2" lazy_static = "1.4" spin = "0.4" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index a415b5cc24..1a3e35e03b 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -8,13 +8,14 @@ use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo}; use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; use event::{Event, EventQueue}; -use std::cell::RefCell; use std::convert::TryInto; use std::fs::{self, File}; +use std::future::Future; use std::io::{self, Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::pin::Pin; use std::ptr::NonNull; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::env; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; @@ -22,7 +23,7 @@ use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::scheme::SchemeMut; use syscall::io::Io; -use crate::xhci::Xhci; +use crate::xhci::{InterruptMethod, Xhci}; mod driver_interface; mod usb; @@ -71,6 +72,10 @@ fn allocate_interrupt_vector() -> io::Result> { Ok(None) } +async fn handle_packet(hci: Arc, packet: Packet) -> Packet { + todo!() +} + fn main() { // Daemonize if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { @@ -103,15 +108,26 @@ fn main() { dbg!(has_msi, msi_enabled); dbg!(has_msix, msix_enabled); - if has_msi && !msi_enabled { + if has_msi && !msi_enabled && !has_msix { + pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); + println!("Enabled MSI"); msi_enabled = true; } if has_msix && !msix_enabled { + pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); + println!("Enabled MSI-X"); msix_enabled = true; } - let (mut irq_file, msix_info) = if msi_enabled && !msix_enabled { - todo!("only msi-x is currently implemented") + let (mut irq_file, interrupt_method) = if msi_enabled && !msix_enabled { + let mut capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI capability structure from pcid") { + PciFeatureInfo::Msi(s) => s, + PciFeatureInfo::MsiX(_) => panic!(), + }; + // use one vector + capability.set_multi_message_enabled(0); + + todo!("msi (msix is implemented though)") } else if msix_enabled { let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), @@ -160,17 +176,19 @@ fn main() { let (vector, interrupt_handle) = allocate_interrupt_vector().expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); - dbg!(vector, destination_id); - table_entry_pointer.addr_lo.write(addr); table_entry_pointer.addr_hi.write(0); table_entry_pointer.msg_data.write(msg_data); table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); - (interrupt_handle, Some(info)) + (Some(interrupt_handle), InterruptMethod::MsiX(info)) } + } else if pci_config.func.legacy_interrupt_pin.is_some() { + // legacy INTx# interrupt pins. + (Some(File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file")), InterruptMethod::Intx) } else { - (File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file"), None) + // no interrupts at all + (None, InterruptMethod::Polling) }; std::thread::sleep(std::time::Duration::from_millis(300)); @@ -187,27 +205,25 @@ fn main() { let socket_fd = syscall::open( format!(":usb/{}", name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + syscall::O_RDWR | syscall::O_CREAT, ) .expect("xhcid: failed to create usb scheme"); - let socket = Arc::new(RefCell::new(unsafe { + let socket = Arc::new(Mutex::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); - { - let hci = Arc::new(RefCell::new( - Xhci::new(name, address, msi_enabled, msix_enabled, msix_info, pcid_handle).expect("xhcid: failed to allocate device"), - )); + let hci = Arc::new(Xhci::new(name, address, interrupt_method, irq_file.as_mut(), pcid_handle).expect("xhcid: failed to allocate device")); + hci.probe().expect("xhcid: failed to probe"); - hci.borrow_mut().probe().expect("xhcid: failed to probe"); + let mut event_queue = + EventQueue::<()>::new().expect("xhcid: failed to create event queue"); - let mut event_queue = - EventQueue::<()>::new().expect("xhcid: failed to create event queue"); + syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); - syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); - - let todo = Arc::new(RefCell::new(Vec::::new())); + let todo = Arc::new(Mutex::new(Vec::::new())); + let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); + if let Some(irq_file) = irq_file { let hci_irq = hci.clone(); let socket_irq = socket.clone(); let todo_irq = todo.clone(); @@ -216,21 +232,24 @@ fn main() { let mut irq = [0; 8]; irq_file.read(&mut irq)?; - if hci_irq.borrow_mut().received_irq() { - hci_irq.borrow_mut().on_irq(); + let hci = hci_irq.lock().unwrap(); + let socket = socket_irq.lock().unwrap(); + let todo = todo_irq.lock().unwrap(); + + if hci.received_irq() { + hci.on_irq(); irq_file.write(&mut irq)?; - let mut todo = todo_irq.borrow_mut(); let mut i = 0; while i < todo.len() { let a = todo[i].a; - hci_irq.borrow_mut().handle(&mut todo[i]); + hci.handle(&mut todo[i]); if todo[i].a == (-EWOULDBLOCK) as usize { todo[i].a = a; i += 1; } else { - socket_irq.borrow_mut().write(&mut todo[i])?; + socket.write(&todo[i])?; todo.remove(i); } } @@ -239,39 +258,43 @@ fn main() { Ok(None) }) .expect("xhcid: failed to catch events on IRQ file"); - - let socket_fd = socket.borrow().as_raw_fd(); - let socket_packet = socket.clone(); - event_queue - .add(socket_fd, move |_| -> io::Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => break, - Err(err) if err.kind() == io::ErrorKind::WouldBlock => break, - Ok(_) => (), - Err(err) => return Err(err), - } - - let a = packet.a; - hci.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); - } else { - socket_packet.borrow_mut().write(&mut packet)?; - } - } - Ok(None) - }) - .expect("xhcid: failed to catch events on scheme file"); - - event_queue - .trigger_all(Event { fd: 0, flags: 0 }) - .expect("xhcid: failed to trigger events"); - - event_queue.run().expect("xhcid: failed to handle events"); } + + let socket_fd = socket.lock().unwrap().as_raw_fd(); + let socket_packet = socket.clone(); + event_queue + .add(socket_fd, move |_| -> io::Result> { + let mut socket = socket_packet.lock().unwrap(); + let mut hci = hci.lock().unwrap(); + let mut todo = todo.lock().unwrap(); + + loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => break, + Ok(_) => (), + Err(err) => return Err(err), + } + + let a = packet.a; + hci.handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.push(packet); + } else { + socket.write(&packet)?; + } + } + Ok(None) + }) + .expect("xhcid: failed to catch events on scheme file"); + + event_queue + .trigger_all(Event { fd: 0, flags: 0 }) + .expect("xhcid: failed to trigger events"); + + event_queue.run().expect("xhcid: failed to handle events"); + unsafe { let _ = syscall::physunmap(address); } diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index 59e841b24e..98750bc12c 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -27,6 +27,13 @@ pub const HCS_PARAMS1_MAX_PORTS_SHIFT: u8 = 24; pub const HCS_PARAMS1_MAX_SLOTS_MASK: u32 = 0x0000_00FF; pub const HCS_PARAMS1_MAX_SLOTS_SHIFT: u8 = 0; +pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK: u32 = 0xF800_0000; +pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT: u8 = 27; +pub const HCS_PARAMS2_SPR_BIT: u32 = 1 << HCS_PARAMS2_SPR_SHIFT; +pub const HCS_PARAMS2_SPR_SHIFT: u8 = 26; +pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK: u32 = 0x03E0_0000; +pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT: u8 = 21; + impl CapabilityRegs { pub fn lec(&self) -> bool { self.hcc_params2.readf(HCC_PARAMS2_LEC_BIT) @@ -48,4 +55,17 @@ impl CapabilityRegs { pub fn ext_caps_ptr_in_dwords(&self) -> u16 { ((self.hcc_params1.read() & HCC_PARAMS1_XECP_MASK) >> HCC_PARAMS1_XECP_SHIFT) as u16 } + pub fn max_scratchpad_bufs_lo(&self) -> u8 { + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) + } + pub fn spr(&self) -> bool { + self.hcs_params2.readf(HCS_PARAMS2_SPR_BIT) + } + pub fn max_scratchpad_bufs_hi(&self) -> u8 { + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) + } + pub fn max_scratchpad_bufs(&self) -> u16 { + u16::from(self.max_scratchpad_bufs_lo()) + | (u16::from(self.max_scratchpad_bufs_hi()) << 5) + } } diff --git a/xhcid/src/xhci/command.rs b/xhcid/src/xhci/command.rs deleted file mode 100644 index c82dc4311e..0000000000 --- a/xhcid/src/xhci/command.rs +++ /dev/null @@ -1,46 +0,0 @@ -use syscall::error::Result; - -use super::event::EventRing; -use super::ring::Ring; -use super::trb::Trb; - -pub struct CommandRing { - pub ring: Ring, - pub events: EventRing, -} - -impl CommandRing { - pub fn new() -> Result { - Ok(CommandRing { - ring: Ring::new(16, true)?, - events: EventRing::new()?, - }) - } - - pub fn crcr(&self) -> u64 { - self.ring.register() - } - - pub fn erdp(&self) -> u64 { - let address = self.events.ring.register(); - address & 0xFFFF_FFFF_FFFF_FFF0 - } - - pub fn erstba(&self) -> u64 { - self.events.ste.physical() as u64 - } - - pub fn next(&mut self) -> (&mut Trb, bool, &mut Trb) { - let cmd = self.ring.next(); - let event = self.events.next(); - (cmd.0, cmd.1, event) - } - - pub fn next_cmd(&mut self) -> (&mut Trb, bool) { - self.ring.next() - } - - pub fn next_event(&mut self) -> &mut Trb { - self.events.next() - } -} diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 74944da174..f3eb970737 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -75,7 +75,7 @@ impl InputContext { pub struct DeviceContextList { pub dcbaa: Dma<[u64; 256]>, - pub contexts: Vec>, + pub contexts: Box<[Dma]>, } impl DeviceContextList { @@ -91,8 +91,8 @@ impl DeviceContextList { } Ok(DeviceContextList { - dcbaa: dcbaa, - contexts: contexts, + dcbaa, + contexts: contexts.into_boxed_slice(), }) } @@ -159,3 +159,41 @@ impl StreamContextArray { self.contexts.physical() as u64 } } + +#[repr(packed)] +#[derive(Clone, Debug)] +pub struct ScratchpadBufferEntry { + pub value: Mmio, +} +impl ScratchpadBufferEntry { + pub fn set_addr(&mut self, addr: u64) { + self.value.write(addr); + } +} + +pub struct ScratchpadBufferArray { + pub entries: Dma<[ScratchpadBufferEntry]>, + pub pages: Vec, +} +impl ScratchpadBufferArray { + pub fn new(entries: u16) -> Result { + let mut entries = unsafe { Dma::zeroed_unsized(entries as usize)? }; + + let pages = entries.iter_mut().map(|entry| { + // TODO: When a better memory allocation API arrives (like the `mem:` scheme which I think is + // being worked on), no assumptions about the page size always being 4k will have to be + // made. + let pointer = syscall::physalloc(4096); + assert_eq!(pointer & 0xFFFF_FFFF_FFFF_F000, pointer, "physically allocated pointer (physalloc) wasn't 4k page-aligned"); + entry.set_addr(pointer); + }); + + Ok(Self { + entries, + pages, + }) + } + pub fn register(&self) -> u64 { + self.entries.physical() + } +} diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index b8301b34be..b3e0af0e35 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -12,6 +12,7 @@ pub struct EventRingSte { _rsvd2: Mmio, } +// TODO: Use atomic operations, and perhaps an occasional lock for reallocating. pub struct EventRing { pub ste: Dma<[EventRingSte]>, pub ring: Ring, @@ -33,4 +34,10 @@ impl EventRing { pub fn next(&mut self) -> &mut Trb { self.ring.next().0 } + pub fn erdp(&self) -> u64 { + self.ring.register() & 0xFFFF_FFFF_FFFF_FFF0 + } + pub fn erstba(&self) -> u64 { + self.ste.physical() as u64 + } } diff --git a/xhcid/src/xhci/executor.rs b/xhcid/src/xhci/executor.rs deleted file mode 100644 index 01fe6603d8..0000000000 --- a/xhcid/src/xhci/executor.rs +++ /dev/null @@ -1 +0,0 @@ -use super::Xhci; diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs new file mode 100644 index 0000000000..a8b777f37a --- /dev/null +++ b/xhcid/src/xhci/irq_reactor.rs @@ -0,0 +1,395 @@ +use std::collections::BTreeMap; +use std::fs::File; +use std::future::Future; +use std::pin::Pin; +use std::sync::{Arc, Mutex}; +use std::sync::atomic::{self, AtomicUsize}; +use std::{mem, task, thread}; + +use crossbeam_channel::{Sender, Receiver}; +use futures::Stream; + +use super::Xhci; +use super::ring::Ring; +use super::trb::{Trb, TrbCompletionCode, TrbType}; + +/// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back +/// by the future unless it completed). +pub struct State { + waker: task::Waker, + kind: StateKind, + message: Arc>>, + is_isoch_or_vf: bool, +} + +pub struct NextEventTrb { + pub event_trb: Trb, + pub src_trb: Option, +} + +// TODO: Perhaps all of the transfer rings used by the xHC should be stored linearly, and then +// indexed using this struct instead. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct RingId { + pub slot: u8, + pub endpoint_num: u8, + pub stream_id: u16, +} + +/// The state specific to a TRB-type. Since some of the event TDs may asynchronously appear, for +/// example the Command Completion Event and the Transfer Event TDs, they have to be +/// distinguishable. Luckily, the xHC also gives us the actual (physical) pointer to the source +/// TRB, from the command ring, unless the event TD has one the completion codes Ring Underrun, +/// Ring Overrun, or VF Event Ring Full Error. When these errors are encountered, it simply +/// indicates that the commands causing the errors continue to be pending, and thus no information +/// is lost. +#[derive(Clone, Copy, Debug)] +pub enum StateKind { + CommandCompletion { phys_ptr: u64 }, + Transfer { phys_ptr: u64, ring_id: RingId }, + Other(TrbType), +} + +impl StateKind { + pub fn trb_type(&self) -> TrbType { + match self.kind { + Self::CommandCompletion { .. } => TrbType::CommandCompletion, + Self::Transfer { .. } => TrbType::Transfer, + Self::Other(ty) => ty, + } + } +} + + +pub struct IrqReactor { + hci: Arc, + current_count: Arc, + irq_file: Option, + receiver: Receiver, + + states: Vec, + + // TODO: Since the IRQ reactor is the only part of this driver that gets event TRBs, perhaps + // the event ring should be owned here? +} + +pub type NewPendingTrb = State; + +pub fn start_irq_reactor(hci: Arc, irq_file: Option) -> thread::JoinHandle<()> { + thread::spawn(move || { + IrqReactor::new(hci, irq_file).run() + }) +} + +impl IrqReactor { + pub fn new(hci: Arc, irq_file: Option) -> Self { + Self { + hci, + irq_file, + current_count: Arc::new(AtomicUsize::new()), + } + } + // TODO: Configure the amount of time to be awaited when no more work can be done. + fn pause(&self) { + std::thread::yield_now(); + } + fn run_polling(mut self) { + loop { + self.handle_requests(); + + let index = self.hci.primary_event_ring.lock().unwrap().next_index(); + + let mut trb; + + 'busy_waiting: loop { + trb = self.hci.primary_event_ring.lock().unwrap().trbs[index]; + + if trb.completion_code() == TrbCompletionCode::Invalid as u8 { + self.pause(); + continue 'busy_waiting; + } + } + self.acknowledge(trb); + self.update_erdp(); + } + } + fn run_with_irq_file(mut self) { + 'event_loop: loop { + self.handle_requests(); + + let irq_file = self.irq_file.as_mut().unwrap(); + + let mut buffer = [0u8; 8]; + let bytes_read = self.irq_file.read(&mut buffer).expect("Failed to read from irq scheme"); + if bytes_read < mem::size_of::() { + panic!("wrong number of bytes read from `irq:`: expected {}, got {}", mem::size_of::(), bytes_read); + } + + if !self.hci.received_irq() { + continue; + } + + let _ = self.irq_file.write(&buffer); + + // TODO: More event rings, probably even with different IRQs. + + let event_ring = self.hci.primary_event_ring.lock().unwrap(); + let trb = event_ring.next(); + + if trb.completion_code() == TrbCompletionCode::Invalid as u8 { + println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt."); + continue 'event_loop; + } + + self.acknowledge(*trb); + trb.reserved(false); + + self.update_erdp(); + } + } + fn update_erdp(&self) { + let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().register(); + let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; + assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); + + self.xhci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); + } + fn handle_requests(&mut self) { + self.states.extend(self.receiver.try_iter()); + } + fn acknowledge(&mut self, trb: Trb) { + let mut index = 0; + + loop { + match self.states[index].kind { + StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => if trb.completion_trb_pointer() == Some(phys_ptr) { + let state = self.states.remove(index).unwrap(); + + // Before waking, it's crucial that the command TRB that generated this event + // be fetched before removing this event TRB from the queue. + let command_trb = match self.hci.command_ring.lock().unwrap().ring.phys_addr_to_entry_mut(phys_ptr) { + Some(command_trb) => { + let t = command_trb.clone(); + command_trb.reserved(false); + t + }, + None => { + println!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb); + continue; + } + }; + + // TODO: Validate the command TRB. + *state.message.lock().unwrap() = Some(NextEventTrb { + src_trb: command_trb.clone(), + event_trb: trb, + }); + + state.waker.wake(); + } else if trb.completion_trb_pointer().is_none() { + println!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); + continue; + } else { + // The event TRB simply didn't match the current future + continue; + } + + StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => if let Some(src_trb) = self.xhc.lock().unwrap().get_transfer_trb(trb.transfer_event_trb_pointer(), ring_id) { + if trb.transfer_event_trb_pointer() == Some(phys_ptr) { + // Give the source transfer TRB together with the event TRB, to the future. + + let state = self.states.remove(index).unwrap(); + *state.message.lock().unwrap() = Some(NextEventTrb { + src_trb, + event_trb: trb, + }); + state.waker.wake(); + } else if trb.transfer_event_trb_pointer().is_none() { + // Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full. + // + // These errors are caused when either an isoch transfer that shall write data, doesn't + // have any data since the ring is empty, or if an isoch receive is impossible due to a + // full ring. The Virtual Function Event Ring Full is only for Virtual Machine + // Managers, and since this isn't implemented yet, they are irrelevant. + // + // The best solution here is to differentiate between isoch transfers (and + // virtual function event rings when virtualization gets implemented), with + // regular commands and transfers, and send the error TRB to all of them, or + // possibly an error code wrapped in a Result. + self.acknowledge_failed_transfer_trbs(trb); + return; + } else { + // The event TRB simply didn't match the current future + continue; + } + } else { continue } + + StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => { + let state = self.states.remove(index).unwrap(); + state.waker.wake(); + } + + _ => { + index += 1; + if index >= self.states.len() { + break; + } + continue; + } + } + } + } + pub fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { + let mut index = 0; + + loop { + if ! self.states[index].is_isoch_or_vf { + index += 1; + if index >= self.states.len() { + break; + } + continue; + } + let state = self.states.remove(index).unwrap(); + *state.message.lock().unwrap() = Some(NextEventTrb { + event_trb: trb, + src_trb: None, + }); + state.waker.wake(); + } + } + pub fn run(mut self) { + if self.irq_file.is_some() { + self.run_with_irq_file(); + } else { + self.run_polling(); + } + } +} + +struct FutureState { + message: Arc>>, + is_isoch_or_vf: bool, + state_kind: StateKind, +} + +enum EventTrbFuture { + Pending { state: FutureState, sender: Sender, }, + Finished, +} + +impl Future for EventTrbFuture { + type Output = NextEventTrb; + + fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { + match self.get_mut() { + &mut Self::Pending { ref mut state, ref mut sender } => if let Some(message) = state.message.lock().unwrap().take() { + *self.get_mut() = Self::Finished; + + task::Poll::Ready(message) + } else { + sender.send(State { + message: Arc::clone(&state.message), + is_isoch_or_vf: state.is_isoch_or_vf, + state_kind: state.state_kind, + waker: context.waker().clone(), + }).expect("IRQ reactor thread unexpectedly stopped"); + + task::Poll::Pending + } + &mut Self::Finished => panic!("Polling finished EventTrbFuture again."), + } + } +} + +impl Xhci { + pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option { + self.with_ring(id, |ring| ring.phys_addr_to_entry(paddr)) + } + pub fn with_ring T>(&self, id: RingId, function: F) -> T { + use super::RingOrStreams; + + let slot_state = self.slot_states.get(&id.slot)?; + let endpoint_state = slot_state.endpoint_states.get(&id.endpoint_num)?; + + let ring_ref = match endpoint_state.transfer { + RingOrStreams::Ring(ref ring) => ring, + RingOrStreams::Streams(ref ctx_arr) => ctx_arr.rings.get(&id.stream_id)?, + }; + + function(ring_ref) + } + pub fn with_ring_mut T>(&self, id: RingId, function: F) -> T { + use super::RingOrStreams; + + let slot_state = self.slot_states.get(&id.slot)?; + let endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?; + + let ring_ref = match endpoint_state.transfer { + RingOrStreams::Ring(ref mut ring) => ring, + RingOrStreams::Streams(ref mut ctx_arr) => ctx_arr.rings.get_mut(&id.stream_id)?, + }; + + function(ring_ref) + } + pub fn next_transfer_event_trb(&self, ring_id: RingId, trb: &Trb) -> impl Future + Send + Sync + 'static { + if ! trb.is_transfer_trb() { + panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", trb.trb_type(), trb) + } + + let is_isoch_or_vf = trb.trb_type() == TrbType::Isoch as u8; + + EventTrbFuture::Pending { + state: FutureState { + is_isoch_or_vf, + state_kind: StateKind::Transfer { + ring_id, + phys_ptr: self.with_ring(ring_id, |ring| ring.trb_phys_ptr(trb)/*.expect("Invalid TRB: transfer TRB wasn't in the ring specified. Only direct references to the TRBs of a ring can be used (ring address range: {:p}-{:p}).", ring.start_addr(), ring.end_addr())*/), + }, + message: Arc::new(Mutex::new(None)), + }, + sender: self.irq_reactor_sender.clone(), + } + } + pub fn next_command_completion_event_trb(&self, trb: &Trb) -> impl Future + Send + Sync + 'static { + if ! trb.is_command_trb() { + panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb) + } + + let command_ring = self.cmd.lock().unwrap(); + let ring = &command_ring.ring; + + EventTrbFuture::Pending { + state: FutureState { + // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). + is_isoch_or_vf: false, + state_kind: StateKind::CommandCompletion { + phys_ptr: ring.trb_phys_ptr(trb),//.expect("Invalid TRB: expected a command TRB within the address range of the command TRB ({:p} {:p}), found TRB {:?} at {:p}", ring.start_addr(), ring.end_addr(), trb, trb) + }, + message: Arc::new(Mutex::new(None)), + }, + sender: self.irq_reactor_sender.clone(), + } + } + pub fn next_misc_event_trb(&self, trb_type: TrbType) -> impl Future + Send + Sync + 'static { + let valid_trb_types = [ + TrbType::PortStatusChange as u8, + TrbType::BandwidthRequest as u8, + TrbType::Doorbell as u8, + TrbType::HostController as u8, + TrbType::DeviceNotification as u8, + TrbType::MfindexWrap as u8, + ]; + if ! valid_trb_types.contains(&trb_type) { + panic!("Invalid TRB type given to next_misc_event_trb(): {:?}. Only event TRB types that are neither transfer events or command completion events can be used.", trb_type) + } + EventTrbFuture::Pending { + state: FutureState { + is_isoch_or_vf: false, + state_kind: StateKind::Other(trb_type), + message: Arc::new(Mutex::new(None)), + }, + sender: self.irq_reactor_sender.clone(), + } + } +} diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 813ec2728b..3970677053 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,10 +1,14 @@ use std::collections::BTreeMap; use std::convert::TryFrom; +use std::fs::File; +use std::future::Future; use std::pin::Pin; use std::ptr::NonNull; use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak}; -use std::{mem, process, slice, sync::atomic, task}; +use std::{mem, process, slice, sync::atomic, task, thread}; +use chashmap::CHashMap; +use crossbeam_channel::Sender; use serde::Deserialize; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT}; use syscall::io::{Dma, Io}; @@ -15,12 +19,11 @@ use pcid_interface::msi::{MsixTableEntry, MsixCapability}; use pcid_interface::{PcidServerHandle, PciFeature}; mod capability; -mod command; mod context; mod doorbell; mod event; -pub mod executor; mod extended; +pub mod irq_reactor; mod operational; mod port; mod ring; @@ -29,9 +32,10 @@ pub mod scheme; mod trb; use self::capability::CapabilityRegs; -use self::command::CommandRing; -use self::context::{DeviceContextList, InputContext, StreamContextArray}; +use self::context::{DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray}; use self::doorbell::Doorbell; +use self::irq_reactor::NewPendingTrb; +use self::event::EventRing; use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap}; use self::operational::OperationalRegs; use self::port::Port; @@ -43,6 +47,20 @@ use self::scheme::EndpIfState; use crate::driver_interface::*; +pub enum InterruptMethod { + /// No interrupts whatsoever; the driver will instead rely on polling event rings. + Polling, + + /// Legacy PCI INTx# interrupt pin. + Intx, + + /// Message signaled interrupts. + Msi, + + /// Extended message signaled interrupts. + MsiX(Mutex), +} + pub struct MsixInfo { pub virt_table_base: NonNull, pub virt_pba_base: NonNull, @@ -72,7 +90,7 @@ impl MsixInfo { struct Device<'a> { ring: &'a mut Ring, - cmd: &'a mut CommandRing, + cmd: &'a mut Ring, db: &'a mut Doorbell, int: &'a mut Interrupter, } @@ -104,6 +122,7 @@ impl<'a> Device<'a> { { let event = self.cmd.next_event(); + // TODO: Replace polling here as well. while event.data.read() == 0 { println!(" - Waiting for event"); } @@ -144,43 +163,43 @@ impl<'a> Device<'a> { } pub struct Xhci { - cap: &'static mut CapabilityRegs, - op: &'static mut OperationalRegs, - ports: &'static mut [Port], - dbs: &'static mut [Doorbell], - run: &'static mut RuntimeRegs, - dev_ctx: DeviceContextList, - cmd: CommandRing, + // immutable + cap: &'static CapabilityRegs, + // XXX: It would be really useful to be able to mutably access individual elements of a slice, + // without having to wrap every element in a lock (which wouldn't work since they're packed). + op: Mutex<&'static mut OperationalRegs>, + ports: Mutex<&'static mut [Port]>, + dbs: Mutex<&'static mut [Doorbell]>, + run: Mutex<&'static mut RuntimeRegs>, + cmd: Mutex, + primary_event_ring: Mutex, + + // immutable + dev_ctx: DeviceContextList, + scratchpad_buf_arr: Option, + + // used for the extended capabilities, and so far none of them are mutated, and thus no lock. base: *const u8, - handles: BTreeMap, + handles: CHashMap, next_handle: usize, - port_states: BTreeMap, + port_states: CHashMap, - // TODO: Is this the correct implementation? I mean, there will be a really limited number of - // IRQs, if not just one, and since we probably wont use a thread pool scheduler like those of - // async-std or tokio, one could possibly assume that the futures themselves won't have to push - // all the wakers. - // TODO: This should probably be a BTreeMap (or just a VecMap) of states for each IRQ number, - // if more than one are used. I'm not sure if the XHCI interrupters actually use different - // IRQs, but it would make sense in case the hub has both isochronous (which trigger interrupts - // reapeatedly with some time in between), bulk, control, etc. I might be wrong though... - irq_state: Arc, - - drivers: BTreeMap, + drivers: CHashMap, scheme_name: String, - msi: bool, - msix: bool, - msix_info: Option, - - pcid_handle: PcidServerHandle, + interrupt_method: InterruptMethod, + pcid_handle: Mutex, + irq_reactor: Option>, + irq_reactor_sender: Sender, } struct PortState { slot: u8, - input_context: Dma, + cfg_idx: Option, + if_idx: Option, + input_context: Mutex>, dev_desc: DevDesc, endpoint_states: BTreeMap, } @@ -204,7 +223,7 @@ impl EndpointState { } impl Xhci { - pub fn new(scheme_name: String, address: usize, msi: bool, msix: bool, msix_info: Option, handle: PcidServerHandle) -> Result { + pub fn new(scheme_name: String, address: usize, interrupt_method: InterruptMethod, pcid_handle: PcidServerHandle) -> Result { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; println!(" - CAP {:X}", address); @@ -265,21 +284,17 @@ impl Xhci { dbs, run, dev_ctx: DeviceContextList::new(max_slots)?, - cmd: CommandRing::new()?, + cmd: Ring::new(), + primary_event_ring: EventRing::new(), handles: BTreeMap::new(), next_handle: 0, port_states: BTreeMap::new(), - irq_state: Arc::new(IrqState { - triggered: AtomicBool::new(false), - wakers: Mutex::new(Vec::new()), - }), drivers: BTreeMap::new(), scheme_name, - msi, - msix, - msix_info, - pcid_handle: handle, + + interrupt_method, + pcid_handle: Mutex::new(pcid_handle), }; xhci.init(max_slots); @@ -290,87 +305,87 @@ impl Xhci { pub fn init(&mut self, max_slots: u8) { // Set enabled slots println!(" - Set enabled slots to {}", max_slots); - self.op.config.write(max_slots as u32); - println!(" - Enabled Slots: {}", self.op.config.read() & 0xFF); + self.op.get_mut().config.write(max_slots as u32); + println!(" - Enabled Slots: {}", self.op.get_mut().config.read() & 0xFF); // Set device context address array pointer let dcbaap = self.dev_ctx.dcbaap(); println!(" - Write DCBAAP: {:X}", dcbaap); - self.op.dcbaap.write(dcbaap as u64); + self.op.get_mut().dcbaap.write(dcbaap as u64); // Set command ring control register - let crcr = self.cmd.crcr(); + let crcr = self.cmd.get_mut().register(); + assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR"); println!(" - Write CRCR: {:X}", crcr); - self.op.crcr.write(crcr as u64); + self.op.get_mut().crcr.write(crcr as u64); // Set event ring segment table registers println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); { - self.run.ints[0].iman.writef(1, true); // clear interrupt pending if set earlier by the BIOS - - println!("IP={}", self.run.ints[0].iman.readf(1)); - - /*if self.msi { - self.pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); - println!("Enabled MSI"); - }*/ - if self.msix { - self.pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); - println!("Enabled MSI-X"); - } - - dbg!(self.pcid_handle.feature_info(PciFeature::MsiX).unwrap()); - dbg!(self.pcid_handle.feature_info(PciFeature::Msi).unwrap()); + let int = &mut self.run.get_mut().ints[0]; let erstz = 1; println!(" - Write ERSTZ: {}", erstz); - self.run.ints[0].erstsz.write(erstz); + int.erstsz.write(erstz); - let erdp = self.cmd.erdp(); + let erdp = self.primary_event_ring.get_mut().erdp(); println!(" - Write ERDP: {:X}", erdp); - self.run.ints[0].erdp.write(erdp as u64 | (1 << 3)); + int.erdp.write(erdp as u64 | (1 << 3)); - let erstba = self.cmd.erstba(); + let erstba = self.primary_event_ring.get_mut().erstba(); println!(" - Write ERSTBA: {:X}", erstba); - self.run.ints[0].erstba.write(erstba as u64); + int.erstba.write(erstba as u64); println!(" - Write IMODC and IMODI: {} and {}", 0, 0); - self.run.ints[0].imod.write(0); + int.imod.write(0); println!(" - Enable interrupts"); - self.run.ints[0].iman.writef(1 << 1, true); + int.iman.writef(1 << 1, true); } - self.op.usb_cmd.writef(1 << 2, true); + self.op.get_mut().usb_cmd.writef(1 << 2, true); + + // Setup the scratchpad buffers that are required for the xHC to function. + self.setup_scratchpads(); // Set run/stop to 1 println!(" - Start"); - self.op.usb_cmd.writef(1, true); + self.op.get_mut().usb_cmd.writef(1, true); // Wait until controller is running println!(" - Wait for running"); - while self.op.usb_sts.readf(1) { + while self.op.get_mut().usb_sts.readf(1) { println!(" - Waiting for XHCI running"); } - println!("IP={}", self.run.ints[0].iman.readf(1)); + println!("IP={}", self.run.get_mut().ints[0].iman.readf(1)); // Ring command doorbell println!(" - Ring doorbell"); - self.dbs[0].write(0); + self.dbs.get_mut()[0].write(0); println!(" - XHCI initialized"); } + pub fn setup_scratchpads(&mut self) -> Result<()> { + let buf_count = self.cap.max_scratchpad_bufs(); + + if buf_count == 0 { + return; + } + self.scratchpad_buf_arr = Some(ScratchpadBufferArray::new(buf_count)?); + self.dev_ctx.dcbaa[0] = self.scratchpad_buf_arr.register(); + } + pub fn enable_port_slot(&mut self, slot_ty: u8) -> Result { assert_eq!(slot_ty & 0x1F, slot_ty); let cloned_event_trb = - self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?; + self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(slot_ty, cycle))?; Ok(cloned_event_trb.event_slot()) } pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> { - self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.disable_slot(0, cycle))?; + self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.disable_slot(slot, cycle))?; Ok(()) } @@ -378,11 +393,12 @@ impl Xhci { self.dev_ctx.contexts[slot].slot.state() } - pub fn probe(&mut self) -> Result<()> { + pub async fn probe(&self) -> Result<()> { println!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); - for i in 0..self.ports.len() { + + for i in 0..self.ports.lock().unwrap().len() { let (data, state, speed, flags) = { - let port = &self.ports[i]; + let port = &self.ports.lock().unwrap()[i]; (port.read(), port.state(), port.speed(), port.flags()) }; println!( @@ -404,13 +420,13 @@ impl Xhci { println!(" - Slot {}", slot); let mut input = Dma::::zeroed()?; - let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed)?; + let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; let dev_desc = Self::get_dev_desc_raw( - &mut self.ports, - &mut self.run, - &mut self.cmd, - &mut self.dbs, + &mut *self.ports.lock().unwrap(), + &mut *self.run.lock().unwrap(), + &mut *self.cmd.lock().unwrap(), + &mut *self.dbs.lock().unwrap(), i, slot, &mut ring, @@ -420,8 +436,10 @@ impl Xhci { let mut port_state = PortState { slot, - input_context: input, + input_context: Mutex::new(input), dev_desc, + cfg_idx: None, + if_idx: None, endpoint_states: std::iter::once(( 0, EndpointState { @@ -433,7 +451,7 @@ impl Xhci { }; if self.cap.cic() { - self.op.set_cie(true); + self.op.lock().unwrap().set_cie(true); } /*match self.spawn_drivers(i, &mut port_state) { @@ -474,8 +492,8 @@ impl Xhci { Ok(()) } - pub fn address_device( - &mut self, + pub async fn address_device( + &self, input_context: &mut Dma, i: usize, slot_ty: u8, @@ -563,23 +581,45 @@ impl Xhci { let input_context_physical = input_context.physical(); - self.execute_command("ADDRESS_DEVICE", |trb, cycle| { + let (event_trb, _) = self.execute_command(|trb, cycle| { trb.address_device(slot, input_context_physical, false, cycle) - }) - .expect("ADDRESS_DEVICE failed"); + }).await; + + if event_trb.completion_code() != TrbCompletionCode::Success as u8 { + println!("Failed to address device at slot {} (port {})", slot, i); + } + Ok(ring) } + pub fn uses_msi(&self) -> bool { + if let InterruptMethod::Msi = self.interrupt_method { true } else { false } + } + pub fn uses_msix(&self) -> bool { + if let InterruptMethod::MsiX(_) = self.interrupt_method { true } else { false } + } + pub fn msix_info(&self) -> Option<&MsixInfo> { + match self.interrupt_method { + InterruptMethod::MsiX(ref info) => Some(info), + _ => None, + } + } + pub fn msix_info_mut(&mut self) -> Option<&mut MsixInfo> { + match self.interrupt_method { + InterruptMethod::MsiX(ref mut info) => Some(info), + _ => None, + } + } /// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always /// true when using MSI/MSI-X. pub fn received_irq(&mut self) -> bool { - if self.msi || self.msix { + if self.uses_msi() || self.uses_msix() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", self.run.ints[0].iman.readf(1), self.run.ints[0].erdp.readf(3)); - println!("MSI-X PB={}", self.msix_info.as_mut().unwrap().pba(0)); - let entry = self.msix_info.as_mut().unwrap().table_entry_pointer(0); + println!("MSI-X PB={}", self.msix_info_mut().unwrap().pba(0)); + let entry = self.msix_info_mut().unwrap().table_entry_pointer(0); println!("MSI-X entry (addr_lo, addr_hi, msg_data, vec_ctl: {:#0x} {:#0x} {:#0x} {:#0x}", entry.addr_lo.read(), entry.addr_hi.read(), entry.msg_data.read(), entry.vec_ctl.read()); true } else if self.run.ints[0].iman.readf(1) { @@ -595,17 +635,7 @@ impl Xhci { } } - /// Handle an IRQ event. pub fn on_irq(&mut self) { - // Wake all futures awaiting the IRQ. - for waker in self.irq_state.wakers.lock().unwrap().drain(..) { - waker.wake(); - } - } - pub(crate) fn irq(&self) -> IrqFuture { - IrqFuture { - state: IrqFutureState::Pending(Arc::downgrade(&self.irq_state)), - } } fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> { // TODO: There should probably be a way to select alternate interfaces, and not just the @@ -784,44 +814,3 @@ lazy_static! { toml::from_slice::(TOML).expect("Failed to parse internally embedded config file") }; } - -pub(crate) struct IrqFuture { - state: IrqFutureState, -} - -struct IrqState { - triggered: AtomicBool, - // TODO: Perhaps a channel? - wakers: Mutex>, -} - -enum IrqFutureState { - Pending(Weak), - Finished, -} - -impl std::future::Future for IrqFuture { - type Output = (); - - fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { - let this = self.get_mut(); - - match &mut this.state { - // TODO: Ordering? - IrqFutureState::Pending(state_weak) => { - let state = state_weak.upgrade().expect( - "IRQ futures keep getting polled even after the driver has been deinitialized", - ); - - if state.triggered.load(atomic::Ordering::SeqCst) { - this.state = IrqFutureState::Finished; - task::Poll::Ready(()) - } else { - state.wakers.lock().unwrap().push(context.waker().clone()); - task::Poll::Pending - } - } - IrqFutureState::Finished => panic!("polling finished future"), - } - } -} diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index c941c70dca..26d0433277 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -1,3 +1,5 @@ +use std::mem; + use syscall::error::Result; use syscall::io::Dma; @@ -26,7 +28,7 @@ impl Ring { addr as u64 | self.cycle as u64 } - pub fn next(&mut self) -> (&mut Trb, bool) { + pub fn next_index(&mut self) -> usize { let mut i; loop { i = self.i; @@ -45,7 +47,11 @@ impl Ring { break; } } + i + } + pub fn next(&mut self) -> (&mut Trb, bool) { + let i = self.next_index(); (&mut self.trbs[i], self.cycle) } /// Endless iterator that iterates through the ring items, over and over again. The iterator @@ -53,6 +59,51 @@ impl Ring { pub fn iter(&self) -> impl Iterator + '_ { Iter { ring: self, i: self.i } } + /// Takes a physical address and returns the index into this ring, that the index represents. + /// Returns `None` if the address is outside the bounds of this ring. + /// + /// # Panics + /// Panics if paddr is not a multiple of 16 bytes, i.e. the size of a TRB. + pub fn phys_addr_to_index(&self, paddr: u64) -> Option { + let base = self.trbs.physical(); + let offset = paddr.checked_sub(base)?; + + assert_eq!(offset % mem::size_of::(), 0, "unaligned TRB physical address"); + + let index = offset / mem::size_of::(); + + if index > self.trbs.len() { + return None; + } + + Some(index) + } + pub fn phys_addr_to_entry_ref(&self, paddr: u64) -> Option<&Trb> { + &self.trbs[self.phys_addr_to_index(paddr)] + } + pub fn phys_addr_to_entry_mut(&self, paddr: u64) -> Option<&mut Trb> { + &mut self.trbs[self.phys_addr_to_index(paddr)] + } + pub fn phys_addr_to_entry(&self, paddr: u64) -> Option { + self.trbs[self.phys_addr_to_index(paddr)].clone() + } + pub(crate) fn start_virt_addr(&self) -> *const Trb { + self.trbs.as_ptr() + } + pub(crate) fn end_virt_addr(&self) -> *const Trb { + unsafe { self.start_virt_addr().offset(self.trbs.len()) } + } + pub fn trb_phys_ptr(&self, trb: &Trb) -> u64 { + let trb_virt_pointer = trb as *const Trb; + let trbs_base_virt_pointer = self.trbs.as_ptr(); + + if trb_virt_pointer < trbs_base_virt_pointer || trb_virt_pointer > trbs_base_virt_pointer + self.trbs.len() * mem::size_of::() { + panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb); + } + let trbs_base_phys_ptr = self.trbs.physical(); + let trb_phys_ptr = trb_virt_pointer - trbs_base_phys_ptr; + trb_phys_ptr + } /* /// Endless mutable iterator that iterates through the ring items, over and over again. The /// iterator doesn't enqueue or dequeue anything, but the trbs are mutably borrowed. diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 1abfc8b056..feaca29bcf 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -17,7 +17,6 @@ use syscall::{ use super::{port, usb}; use super::{Device, EndpointState, Xhci}; -use super::command::CommandRing; use super::context::{ InputContext, SlotState, StreamContext, StreamContextArray, StreamContextType, ENDPOINT_CONTEXT_STATUS_MASK, @@ -211,40 +210,38 @@ impl AnyDescriptor { } impl Xhci { - pub fn execute_command( - &mut self, - cmd_name: &str, - f: F, - ) -> Result { - self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); - let (cmd, cycle, event) = self.cmd.next(); - + pub fn execute_command_noreply(&self, f: F) { + let (cmd, cycle) = self.cmd.lock().unwrap(); f(cmd, cycle); - println!("INTE={}", self.op.usb_cmd.readf(1 << 2)); - println!("IP={}", self.run.ints[0].iman.readf(1)); - self.dbs[0].write(0); - println!("IP={}", self.run.ints[0].iman.readf(1)); + self.dbs.lock().unwrap()[0].write(0); - while event.data.read() == 0/* || self.run.ints[0].iman.readf(1)*/ { - println!(" - {} Waiting for event", cmd_name); - } - println!("IP={}", self.run.ints[0].iman.readf(1)); + // TODO: It's still possible not to reset the TRB, right? + } - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::CommandCompletion as u8 - { - println!("{} failed with event TRB ({:#0x} {:#0x} {:#0x}) and command TRB ({:#0x} {:#0x} {:#0x})", cmd_name, event.data.read(), event.status.read(), event.control.read(), cmd.data.read(), cmd.status.read(), cmd.control.read()); - return Err(Error::new(EIO)); - } + pub async fn execute_command( + &self, + f: F, + ) -> (Trb, Trb) { + let next_event = { + let command_ring = self.cmd.lock().unwrap(); - let ret = event.clone(); + let (cmd, cycle) = command_ring.next(); + f(cmd, cycle); - cmd.reserved(false); - event.reserved(false); + // get the future here before awaiting, to destroy the lock before deadlock + self.next_command_completion_event_trb(&cmd) + }; - self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); - Ok(ret) + self.dbs.lock().unwrap()[0].write(0); + + let trbs = next_event.await; + let event_trb = trbs.event_trb; + let command_trb = trbs.src_trb.expect("Command completion event TRBs shall always have a valid pointer to a valid source command TRB"); + + assert_eq!(command_trb.trb_type(), TrbType::CommandCompletion as u8, "The IRQ reactor (or the xHC) gave an invalid event TRB"); + + (event_trb, command_trb) } pub fn execute_control_transfer( &mut self, @@ -418,8 +415,16 @@ impl Xhci { ) } - fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { - let endp_num_xhc = Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?); + async fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { + let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; + + let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { + (Some(c), Some(i)) => (c, i), + _ => return Err(Error::new(EIO)), + }; + + let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); let slot = self .port_states @@ -427,10 +432,10 @@ impl Xhci { .ok_or(Error::new(EBADF))? .slot; - self.execute_command("RESET_ENDPOINT", |trb, cycle| { - trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle) - })?; - Ok(()) + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { + trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle); + }).await; + handle_event_trb("RESET_ENDPOINT", &event_trb, &command_trb) } fn endp_ctx_interval(speed_id: &ProtocolSpeed, endp_desc: &EndpDesc) -> u8 { @@ -507,62 +512,14 @@ impl Xhci { } } - fn port_state(&self, port: usize) -> Result<&super::PortState> { + fn port_state(&self, port: usize) -> Result> { self.port_states.get(&port).ok_or(Error::new(EBADF)) } - fn port_state_mut(&mut self, port: usize) -> Result<&mut super::PortState> { - self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) - } - fn endpoint_state_mut(&mut self, port: usize, endp_num: u8) -> Result<&mut EndpointState> { - self.port_state_mut(port)? - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADF)) - } - fn input_context(&mut self, port: usize) -> Result<&mut Dma> { - Ok(&mut self.port_state_mut(port)?.input_context) - } - fn endp_ctx( - &mut self, - port: usize, - endp_num_xhc: u8, - ) -> Result<&mut super::context::EndpointContext> { - Ok(self - .input_context(port)? - .device - .endpoints - .get_mut(endp_num_xhc as usize - 1) - .ok_or(Error::new(EIO))?) - } - fn dev_desc(&self, port: usize) -> Result<&DevDesc> { - Ok(&self.port_state(port)?.dev_desc) - } - fn config_descs(&self, port: usize) -> Result<&[ConfDesc]> { - Ok(&self.dev_desc(port)?.config_descs) - } - fn config_desc(&self, port: usize, desc: u8) -> Result<&ConfDesc> { - Ok(self - .config_descs(port)? - .get(usize::from(desc)) - .ok_or(Error::new(EBADF))?) - } - fn endp_descs(&self, port: usize, config_desc: u8, if_desc: u8) -> Result<&[EndpDesc]> { - Ok(&self - .port_state(port)? - .dev_desc - .config_descs - .get(usize::from(config_desc)) - .ok_or(Error::new(EIO))? - .interface_descs - .get(usize::from(if_desc)) - .ok_or(Error::new(EIO))? - .endpoints) - } - fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { + async fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; - if (!self.cap.cic() || !self.op.cie()) + if (!self.cap.cic() || !self.op.lock().unwrap().cie()) && (req.config_desc != 0 || req.interface_desc != None || req.alternate_setting != None) { //return Err(Error::new(EOPNOTSUPP)); @@ -574,9 +531,11 @@ impl Xhci { return Err(Error::new(EBADMSG)); } - let (endp_desc_count, new_context_entries) = { - let endpoints = - self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?; + let (endp_desc_count, new_context_entries, configuration_value) = { + let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let config_desc = port_state.dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; + + let endpoints = config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; if endpoints.len() >= 31 { return Err(Error::new(EIO)); @@ -588,18 +547,20 @@ impl Xhci { Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l), None => 1, }) + 1, + config_desc.configuration_value, ) }; let lec = self.cap.lec(); let log_max_psa_size = self.cap.max_psa_size(); - let port_speed_id = self.ports[port].speed(); + let port_speed_id = self.ports.lock().unwrap()[port].speed(); let speed_id: &ProtocolSpeed = self .lookup_psiv(port as u8, port_speed_id) .ok_or(Error::new(EIO))?; { - let input_context = self.input_context(port)?; + let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let input_context = port_state.input_context.lock().unwrap(); // Configure the slot context as well, which holds the last index of the endp descs. input_context.add_context.write(1); @@ -625,9 +586,9 @@ impl Xhci { for endp_idx in 0..endp_desc_count as u8 { let endp_num = endp_idx + 1; - let endpoints = - self.endp_descs(port, req.config_desc, req.interface_desc.unwrap_or(0))?; - let dev_desc = self.dev_desc(port)?; + let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let dev_desc = &port_state.dev_desc; + let endpoints = &dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); @@ -685,7 +646,7 @@ impl Xhci { assert_eq!(max_error_count & 0x3, max_error_count); assert_ne!(ep_ty, 0); // 0 means invalid. - let port_state = self.port_state_mut(port)?; + let port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; let ring_ptr = if usb_log_max_streams.is_some() { let mut array = StreamContextArray::new(1 << (primary_streams + 1))?; @@ -728,10 +689,11 @@ impl Xhci { }; assert_eq!(primary_streams & 0x1F, primary_streams); - let input_context = self.input_context(port)?; + let port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; + let input_context = port_state.input_context.lock().unwrap(); input_context.add_context.writef(1 << endp_num_xhc, true); - let endp_ctx = self.endp_ctx(port, endp_num_xhc)?; + let endp_ctx = input_context.device.endpoints.get_mut(endp_num_xhc as usize - 1).ok_or(Error::new(EIO))?; endp_ctx.a.write( u32::from(mult) << 8 @@ -756,14 +718,17 @@ impl Xhci { .write(u32::from(avg_trb_len) | (u32::from(max_esit_payload_lo) << 16)); } - let slot = self.port_state(port)?.slot; - let input_context_physical = self.input_context(port)?.physical(); - self.execute_command("CONFIGURE_ENDPOINT", |trb, cycle| { + let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let slot = port_state.slot; + let input_context_physical = port_state.input_context.lock().unwrap().physical(); + + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.configure_endpoint(slot, input_context_physical, cycle) - })?; + }).await; + + handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; // Tell the device about this configuration. - let configuration_value = self.config_desc(port, req.config_desc)?.configuration_value; self.set_configuration(port, configuration_value)?; if let (Some(interface_num), Some(alternate_setting)) = @@ -819,12 +784,6 @@ impl Xhci { unreachable!() } } - fn endp_desc(&self, port_num: usize, endp_num: u8) -> Result<&EndpDesc> { - Ok(self - .endp_descs(port_num, 0, 0)? - .get(usize::from(endp_num) - 1) - .ok_or(Error::new(EBADF))?) - } fn endp_doorbell(endp_num: u8, desc: &EndpDesc, stream_id: u16) -> u32 { let db_target = Self::endp_num_to_dci(endp_num, desc); let db_task_id: u16 = stream_id; @@ -969,11 +928,16 @@ impl Xhci { .port_states .get_mut(&port_id) .ok_or(Error::new(ENOENT))?; + let ports = self.ports.lock().unwrap(); + let run = self.run.lock().unwrap(); + let cmd = self.cmd.lock().unwrap(); + let dbs = self.dbs.lock().unwrap(); + Self::get_dev_desc_raw( - &mut self.ports, - &mut self.run, - &mut self.cmd, - &mut self.dbs, + &mut *ports, + &mut *run, + &mut *cmd, + &mut *dbs, port_id, st.slot, st.endpoint_states @@ -986,7 +950,7 @@ impl Xhci { pub(crate) fn get_dev_desc_raw( ports: &mut [port::Port], run: &mut RuntimeRegs, - cmd: &mut CommandRing, + cmd: &mut Ring, dbs: &mut [Doorbell], port_id: usize, slot: u8, @@ -999,7 +963,7 @@ impl Xhci { // TODO: Should the descriptors be stored in PortState? - run.ints[0].erdp.write(cmd.erdp() | (1 << 3)); + run.ints[0].erdp.write(cmd.register() | (1 << 3)); let mut dev = Device { ring, @@ -1148,11 +1112,6 @@ impl Xhci { setup: usb::Setup, transfer_kind: TransferKind, ) -> Result<()> { - // TODO: This json format might be too high level, but is useful for debugging, - // but when actual device-specific drivers are written, a binary format would - // be better. Maybe something simple like bincode could be used, if a custom binary struct - // is too much overkill. - self.execute_control_transfer( port_num, setup, @@ -1242,7 +1201,8 @@ impl Xhci { PortReqState::WaitingForDeviceBytes(_, _) => return Err(Error::new(EBADF)), PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), }; - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + match &mut *guard { Handle::PortReq(_, ref mut state) => *state = st, _ => unreachable!(), } @@ -1272,7 +1232,9 @@ impl Xhci { } PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), }; - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + + let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + match &mut *guard { Handle::PortReq(_, ref mut state) => *state = st, _ => unreachable!(), } @@ -1306,8 +1268,9 @@ impl SchemeMut for Xhci { if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { let mut contents = Vec::new(); - for (index, _) in self - .ports + let ports_guard = self.ports.lock().unwrap(); + + for (index, _) in ports_guard .iter() .enumerate() .filter(|(_, port)| port.flags().contains(port::PortFlags::PORT_CCS)) @@ -1455,34 +1418,36 @@ impl SchemeMut for Xhci { } fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { - match self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::TopLevel(_, ref buf) - | Handle::Port(_, _, ref buf) - | Handle::Endpoints(_, _, ref buf) => { + let guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + match &*guard { + &Handle::TopLevel(_, ref buf) + | &Handle::Port(_, _, ref buf) + | &Handle::Endpoints(_, _, ref buf) => { stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; } - Handle::PortDesc(_, _, ref buf) => { + &Handle::PortDesc(_, _, ref buf) => { stat.st_mode = MODE_FILE; stat.st_size = buf.len() as u64; } - Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) - | Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => { + &Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) + | &Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => { stat.st_mode = MODE_CHR; stat.st_size = buf.len() as u64; } - Handle::PortReq(_, PortReqState::Tmp) - | Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(), + &Handle::PortReq(_, PortReqState::Tmp) + | &Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(), - Handle::PortState(_, _) | Handle::PortReq(_, _) => stat.st_mode = MODE_CHR, - Handle::Endpoint(_, _, st) => match st { - EndpointHandleTy::Ctl | EndpointHandleTy::Data => stat.st_mode = MODE_CHR, - EndpointHandleTy::Root(_, ref buf) => { + &Handle::PortState(_, _) | &Handle::PortReq(_, _) => stat.st_mode = MODE_CHR, + &Handle::Endpoint(_, _, ref st) => match st { + &EndpointHandleTy::Ctl | &EndpointHandleTy::Data => stat.st_mode = MODE_CHR, + &EndpointHandleTy::Root(_, ref buf) => { stat.st_mode = MODE_DIR; stat.st_size = buf.len() as u64; } }, - Handle::ConfigureEndpoints(_) => { + &Handle::ConfigureEndpoints(_) => { stat.st_mode = MODE_CHR | 0o200; // write only } } @@ -1490,21 +1455,22 @@ impl SchemeMut for Xhci { } fn fpath(&mut self, fd: usize, buffer: &mut [u8]) -> Result { - // XXX: write!() should return the length instead of (). - let mut src = Vec::::new(); - match self.handles.get(&fd).ok_or(Error::new(EBADF))? { - Handle::TopLevel(_, _) => write!(src, "/").unwrap(), - Handle::Port(port_num, _, _) => write!(src, "/port{}/", port_num).unwrap(), - Handle::PortDesc(port_num, _, _) => { - write!(src, "/port{}/descriptors", port_num).unwrap() + let cursor = io::Cursor::new(buffer); + + let guard = self.handles.get(&fd).ok_or(Error::new(EBADF))?; + match &*guard { + &Handle::TopLevel(_, _) => write!(cursor, "/").unwrap(), + &Handle::Port(port_num, _, _) => write!(cursor, "/port{}/", port_num).unwrap(), + &Handle::PortDesc(port_num, _, _) => { + write!(cursor, "/port{}/descriptors", port_num).unwrap() } - Handle::PortState(port_num, _) => write!(src, "/port{}/state", port_num).unwrap(), - Handle::PortReq(port_num, _) => write!(src, "/port{}/request", port_num).unwrap(), - Handle::Endpoints(port_num, _, _) => { - write!(src, "/port{}/endpoints/", port_num).unwrap() + &Handle::PortState(port_num, _) => write!(cursor, "/port{}/state", port_num).unwrap(), + &Handle::PortReq(port_num, _) => write!(cursor, "/port{}/request", port_num).unwrap(), + &Handle::Endpoints(port_num, _, _) => { + write!(cursor, "/port{}/endpoints/", port_num).unwrap() } - Handle::Endpoint(port_num, endp_num, st) => write!( - src, + &Handle::Endpoint(port_num, endp_num, st) => write!( + cursor, "/port{}/endpoints/{}/{}", port_num, endp_num, @@ -1515,17 +1481,17 @@ impl SchemeMut for Xhci { } ) .unwrap(), - Handle::ConfigureEndpoints(port_num) => { - write!(src, "/port{}/configure", port_num).unwrap() + &Handle::ConfigureEndpoints(port_num) => { + write!(cursor, "/port{}/configure", port_num).unwrap() } } - let bytes_to_read = cmp::min(src.len(), buffer.len()); - buffer[..bytes_to_read].copy_from_slice(&src[..bytes_to_read]); - Ok(bytes_to_read) + let src_len = usize::try_from(cursor.seek(io::SeekFrom::End(0)).unwrap()).unwrap(); + Ok(src_len) } fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + match &mut *guard { // Directories, or fixed files Handle::TopLevel(ref mut offset, ref buf) | Handle::Port(_, ref mut offset, ref buf) @@ -1557,7 +1523,8 @@ impl SchemeMut for Xhci { } fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + match &mut *guard { Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) | Handle::PortDesc(_, ref mut offset, ref src_buf) @@ -1609,7 +1576,8 @@ impl SchemeMut for Xhci { } } fn write(&mut self, fd: usize, buf: &[u8]) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + match &mut *guard { &mut Handle::ConfigureEndpoints(port_num) => { self.configure_endpoints(port_num, buf)?; Ok(buf.len()) @@ -1667,7 +1635,7 @@ impl Xhci { _ => return Err(Error::new(EIO)), }) } - pub fn on_req_reset_device( + pub async fn on_req_reset_device( &mut self, port_num: usize, endp_num: u8, @@ -1678,8 +1646,8 @@ impl Xhci { } // Change the endpoint state from anything, but most likely HALTED (otherwise resetting // would be quite meaningless), to stopped. - self.reset_endpoint(port_num, endp_num, false)?; - self.restart_endpoint(port_num, endp_num)?; + self.reset_endpoint(port_num, endp_num, false).await?; + self.restart_endpoint(port_num, endp_num).await?; if clear_feature { self.device_req_no_data( @@ -1695,37 +1663,46 @@ impl Xhci { } Ok(()) } - pub fn restart_endpoint(&mut self, port_num: usize, endp_num: u8) -> Result<()> { + pub async fn restart_endpoint(&self, port_num: usize, endp_num: u8) -> Result<()> { let port_state = self .port_states .get_mut(&port_num) .ok_or(Error::new(EBADFD))?; + + let endp_desc = port_state + .dev_desc + .config_descs + .get(0) + .ok_or(Error::new(EIO))? + .interface_descs + .get(0) + .ok_or(Error::new(EIO))? + .endpoints + .get(endp_num as usize - 1) + .ok_or(Error::new(EBADFD))?; + let direction = if endp_num != 0 { - let endp_desc = port_state - .dev_desc - .config_descs - .get(0) - .ok_or(Error::new(EIO))? - .interface_descs - .get(0) - .ok_or(Error::new(EIO))? - .endpoints - .get(endp_num as usize - 1) - .ok_or(Error::new(EBADFD))?; endp_desc.direction() } else { EndpDirection::Bidirectional }; - let endpoint_state: &mut EndpointState = port_state + + let endpoint_state = port_state .endpoint_states .get_mut(&endp_num) .ok_or(Error::new(EBADFD))?; + let (has_streams, ring) = match &mut endpoint_state.transfer { &mut super::RingOrStreams::Ring(ref mut ring) => (false, ring), &mut super::RingOrStreams::Streams(ref mut arr) => { (true, arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?) } }; + let doorbell = Self::endp_doorbell( + endp_num, + endp_desc, + if has_streams { stream_id } else { 0 }, + ); let (cmd, cycle) = ring.next(); cmd.transfer_no_op(0, false, false, false, cycle); @@ -1733,14 +1710,12 @@ impl Xhci { let deque_ptr_and_cycle = ring.register(); let slot = port_state.slot; - self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle)?; + self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle).await?; + + let stream_id = 1u16; - self.dbs[slot as usize].write(Self::endp_doorbell( - endp_num, - self.endp_desc(port_num, endp_num)?, - if has_streams { stream_id } else { 0 }, - )); + self.dbs.lock().unwrap()[slot as usize].write(doorbell); Ok(()) } pub fn endp_direction(&self, port_num: usize, endp_num: u8) -> Result { @@ -1763,16 +1738,24 @@ impl Xhci { pub fn slot(&self, port_num: usize) -> Result { Ok(self.port_states.get(&port_num).ok_or(Error::new(EIO))?.slot) } - pub fn set_tr_deque_ptr( - &mut self, + pub async fn set_tr_deque_ptr( + &self, port_num: usize, endp_num: u8, deque_ptr_and_cycle: u64, ) -> Result<()> { - let slot = self.slot(port_num)?; - let endp_num_xhc = Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?); + let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; + let slot = port_state.slot; - self.execute_command("SET_TR_DEQUEUE_POINTER", |trb, cycle| { + let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { + (Some(c), Some(i)) => (c, i), + _ => return Err(Error::new(EIO)), + }; + + let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); + + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.set_tr_deque_ptr( deque_ptr_and_cycle, cycle, @@ -1781,11 +1764,11 @@ impl Xhci { endp_num_xhc, slot, ) - })?; + }).await; - Ok(()) + handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb) } - pub fn on_write_endp_ctl( + pub async fn on_write_endp_ctl( &mut self, port_num: usize, endp_num: u8, @@ -1808,9 +1791,7 @@ impl Xhci { } }, XhciEndpCtlReq::Reset { no_clear_feature } => match ep_if_state { - EndpIfState::Init => { - self.on_req_reset_device(port_num, endp_num, !no_clear_feature)? - } + EndpIfState::Init => self.on_req_reset_device(port_num, endp_num, !no_clear_feature).await?, other => { return Err(Error::new(EBADF)); } @@ -1874,7 +1855,11 @@ impl Xhci { endp_num: u8, buf: &[u8], ) -> Result { - let ep_if_state = &mut self.endpoint_state_mut(port_num, endp_num)?.driver_if_state; + let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; + let endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + + let ep_if_state = &mut endpoint_state.driver_if_state; + match ep_if_state { &mut EndpIfState::WaitingForDataPipe { direction: XhciEndpCtlDirection::Out, @@ -1892,7 +1877,9 @@ impl Xhci { // invoking further data transfer calls if any single transfer returns fewer bytes // than requested. - let ep_if_state = &mut self.endpoint_state_mut(port_num, endp_num)?.driver_if_state; + let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; + let endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + let ep_if_state = &mut endpoint_state.driver_if_state; if let &mut EndpIfState::WaitingForDataPipe { direction: XhciEndpCtlDirection::Out, @@ -2005,6 +1992,18 @@ impl Xhci { _ => return Err(Error::new(EBADF)), } } + pub fn event_handler_finished(&self) { + // write 1 to EHB to clear it + self.run.lock().unwrap().ints[0].erdp.writef(1 << 3, true); + } +} +fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()> { + if event_trb.completion_code() == TrbCompletionCode::Success as u8 { + Ok(()) + } else { + println!("{} command (TRB {:?}) failed with event trb {:?}", name, command_trb, event_trb); + Err(Error::new(EIO)) + } } use std::ops::{Add, Div, Rem}; pub fn div_round_up(a: T, b: T) -> T diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 4ad02bee37..c23f543a38 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -5,6 +5,7 @@ use syscall::io::{Io, Mmio}; use super::context::StreamContextType; #[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum TrbType { Reserved, /* Transfer */ @@ -33,8 +34,8 @@ pub enum TrbType { ForceHeader, NoOpCmd, /* Reserved */ - Rsv24, - Rsv25, + GetExtendedProperty, + SetExtendedProperty, Rsv26, Rsv27, Rsv28, @@ -54,6 +55,7 @@ pub enum TrbType { } #[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum TrbCompletionCode { Invalid, Success, @@ -157,6 +159,34 @@ impl Trb { pub fn completion_param(&self) -> u32 { self.status.read() & TRB_STATUS_COMPLETION_PARAM_MASK } + fn has_completion_trb_pointer(&self) -> bool { + if self.completion_code() == TrbCompletionCode::RingUnderrun as u8 || self.completion_code() == TrbCompletionCode::RingOverrun as u8 { + false + } else if self.completion_code() == TrbCompletionCode::VfEventRingFull as u8 { + false + } else { + true + } + } + pub fn completion_trb_pointer(&self) -> Option { + debug_assert_eq!(self.trb_type(), TrbType::CommandCompletion as u8); + + if self.has_completion_trb_pointer() { + Some(self.data.read()) + } else { + None + } + } + pub fn transfer_event_trb_pointer(&self) -> Option { + debug_assert_eq!(self.trb_type(), TrbType::Transfer as u8); + + if self.has_completion_trb_pointer() { + Some(self.data.read()) + } else { + None + } + } + pub fn event_slot(&self) -> u8 { (self.control.read() >> 24) as u8 } @@ -383,6 +413,43 @@ impl Trb { | ((TrbType::Normal as u32) << 10), ) } + pub fn is_command_trb(&self) -> bool { + let valid_trb_types = [ + TrbType::NoOpCmd as u8, + TrbType::EnableSlot as u8, + TrbType::DisableSlot as u8, + TrbType::AddressDevice as u8, + TrbType::ConfigureEndpoint as u8, + TrbType::EvaluateContext as u8, + TrbType::ResetEndpoint as u8, + TrbType::StopEndpoint as u8, + TrbType::SetTrDequeuePointer as u8, + TrbType::ResetDevice as u8, + TrbType::ForceEvent as u8, + TrbType::NegotiateBandwidth as u8, + TrbType::SetLatencyToleranceValue as u8, + TrbType::GetPortBandwidth as u8, + TrbType::ForceHeader as u8, + TrbType::GetExtendedProperty as u8, + TrbType::SetExtendedProperty as u8, + ]; + valid_trb_types.contains(&self.trb_type()) + } + pub fn is_transfer_trb(&self) -> bool { + // XXX: Unfortunately, the only way to use match statements with integer constants, is to + // precast them into valid enum values, which either requires a derive macro such as + // num_traits's #[derive(FromPrimitive)], or manually writing the reverse match statement + // first. + let valid_trb_types = [ + TrbType::Normal as u8, + TrbType::SetupStage as u8, + TrbType::DataStage as u8, + TrbType::StatusStage as u8, + TrbType::Isoch as u8, + TrbType::NoOp as u8, + ]; + valid_trb_types.contains(&self.trb_type()) + } } impl fmt::Debug for Trb { From bae238bbef3c8aa3d47f98d81d487aff610f2254 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 26 Mar 2020 19:17:31 +0100 Subject: [PATCH 0367/1301] Asyncify Xhci::execute_transfer. --- xhcid/src/xhci/irq_reactor.rs | 3 +- xhcid/src/xhci/scheme.rs | 112 +++++++++++++++++++--------------- 2 files changed, 63 insertions(+), 52 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index a8b777f37a..4d808f6f30 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -357,14 +357,13 @@ impl Xhci { } let command_ring = self.cmd.lock().unwrap(); - let ring = &command_ring.ring; EventTrbFuture::Pending { state: FutureState { // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). is_isoch_or_vf: false, state_kind: StateKind::CommandCompletion { - phys_ptr: ring.trb_phys_ptr(trb),//.expect("Invalid TRB: expected a command TRB within the address range of the command TRB ({:p} {:p}), found TRB {:?} at {:p}", ring.start_addr(), ring.end_addr(), trb, trb) + phys_ptr: command_ring.trb_phys_ptr(trb),//.expect("Invalid TRB: expected a command TRB within the address range of the command TRB ({:p} {:p}), found TRB {:?} at {:p}", ring.start_addr(), ring.end_addr(), trb, trb) }, message: Arc::new(Mutex::new(None)), }, diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index feaca29bcf..c96d3d9c08 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -306,7 +306,9 @@ impl Xhci { } /// NOTE: There has to be AT LEAST one successful invocation of `d`, that actually updates the /// TRB (it could be a NO-OP in the worst case). - pub fn execute_transfer( + /// The function is also required to set the Interrupt on Completion flag, or this function + /// will never complete. + pub async fn execute_transfer( &mut self, port_num: usize, endp_num: u8, @@ -318,6 +320,14 @@ impl Xhci { D: FnMut(&mut Trb, bool) -> ControlFlow, { let port_state = self.port_state_mut(port_num)?; + + let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { + (Some(c), Some(i)) => (c, i), + _ => return Err(Error::new(EIO)), + }; + + let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let slot = port_state.slot; let endp_state = port_state .endpoint_states @@ -338,57 +348,43 @@ impl Xhci { .ok_or(Error::new(EBADF))?), }; - loop { + let future = loop { let (trb, cycle) = ring.next(); + match d(trb, cycle) { - ControlFlow::Break => break, + ControlFlow::Break => { + break self.next_transfer_event_trb(super::irq_reactor::RingId { slot, endpoint_num: endp_num, stream_id }, &trb); + } ControlFlow::Continue => continue, } - } + }; - self.dbs[usize::from(slot)].write(Self::endp_doorbell( + self.dbs.lock().unwrap()[usize::from(slot)].write(Self::endp_doorbell( endp_num, - self.endp_desc(port_num, endp_num)?, + endp_desc, if has_streams { stream_id } else { 0 }, )); - let cloned_trb = { - let event = self.cmd.next_event(); - while event.data.read() == 0 { - println!(" - {} Waiting for event", name); - } + let trbs = future.await; + let event_trb = trbs.event_trb; + let transfer_trb = trbs.src_trb.unwrap(); - // FIXME: EDTLA if event data was set - if event.completion_code() != TrbCompletionCode::ShortPacket as u8 - && event.transfer_length() != 0 - { - println!( - "Event trb didn't yield a short packet, but some bytes were not transferred" - ); - } + handle_transfer_event_trb("EXECUTE_TRANSFER", &event_trb, &transfer_trb)?; - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::Transfer as u8 - { - println!( - "Custom transfer event failed with {:#0x} {:#0x} {:#0x}", - event.data.read(), - event.status.read(), - event.control.read() - ); - } - // TODO: Handle event data - println!("EVENT DATA: {:?}", event.event_data()); + // FIXME: EDTLA if event data was set + if event_trb.completion_code() != TrbCompletionCode::ShortPacket as u8 + && event_trb.transfer_length() != 0 + { + println!( + "Event trb didn't yield a short packet, but some bytes were not transferred" + ); + return Err(Error::new(EIO)); + } - let cloned_trb = event.clone(); - event.reserved(false); + // TODO: Handle event data + println!("EVENT DATA: {:?}", event_trb.event_data()); - cloned_trb - }; - - self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); - - Ok(cloned_trb) + Ok(event_trb) } fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { self.execute_control_transfer( @@ -435,6 +431,8 @@ impl Xhci { let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle); }).await; + self.event_handler_finished(); + handle_event_trb("RESET_ENDPOINT", &event_trb, &command_trb) } @@ -512,9 +510,12 @@ impl Xhci { } } - fn port_state(&self, port: usize) -> Result> { + fn port_state(&self, port: usize) -> Result> { self.port_states.get(&port).ok_or(Error::new(EBADF)) } + fn port_state_mut(&self, port: usize) -> Result> { + self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) + } async fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; @@ -725,6 +726,7 @@ impl Xhci { let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.configure_endpoint(slot, input_context_physical, cycle) }).await; + self.event_handler_finished(); handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; @@ -739,7 +741,7 @@ impl Xhci { Ok(()) } - fn transfer_read( + async fn transfer_read( &mut self, port_num: usize, endp_idx: u8, @@ -753,9 +755,9 @@ impl Xhci { } else { DeviceReqData::NoData }, - ) + ).await } - fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<(u8, u32)> { + async fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<(u8, u32)> { self.transfer( port_num, endp_idx, @@ -764,7 +766,7 @@ impl Xhci { } else { DeviceReqData::NoData }, - ) + ).await } const fn def_control_endp_doorbell() -> u32 { 1 @@ -791,7 +793,7 @@ impl Xhci { (u32::from(db_task_id) << 16) | u32::from(db_target) } // TODO: Rename DeviceReqData to something more general. - fn transfer( + async fn transfer( &mut self, port_num: usize, endp_idx: u8, @@ -913,7 +915,8 @@ impl Xhci { ControlFlow::Break } }, - )?; + ).await?; + self.event_handler_finished(); let bytes_transferred = buf.len() as u32 - event.transfer_length(); @@ -1615,6 +1618,7 @@ impl Xhci { } else { 1 }; + let raw = self .dev_ctx .contexts @@ -1626,6 +1630,7 @@ impl Xhci { .a .read() & super::context::ENDPOINT_CONTEXT_STATUS_MASK; + Ok(match raw { 0 => EndpointStatus::Disabled, 1 => EndpointStatus::Enabled, @@ -1698,6 +1703,7 @@ impl Xhci { (true, arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?) } }; + let stream_id = 1u16; let doorbell = Self::endp_doorbell( endp_num, endp_desc, @@ -1712,9 +1718,6 @@ impl Xhci { self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle).await?; - - - let stream_id = 1u16; self.dbs.lock().unwrap()[slot as usize].write(doorbell); Ok(()) } @@ -1765,6 +1768,7 @@ impl Xhci { slot, ) }).await; + self.event_handler_finished(); handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb) } @@ -1802,7 +1806,7 @@ impl Xhci { // Yield the result directly because no bytes have to be sent or received // beforehand. let (completion_code, bytes_transferred) = - self.transfer(port_num, endp_num - 1, DeviceReqData::NoData)?; + self.transfer(port_num, endp_num - 1, DeviceReqData::NoData).await?; if bytes_transferred > 0 { return Err(Error::new(EIO)); } @@ -2005,6 +2009,14 @@ fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<() Err(Error::new(EIO)) } } +fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb) -> Result<()> { + if event_trb.completion_code() == TrbCompletionCode::Success as u8 || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 { + Ok(()) + } else { + println!("{} transfer (TRB {:?}) failed with event trb {:?}", name, transfer_trb, event_trb); + Err(Error::new(EIO)) + } +} use std::ops::{Add, Div, Rem}; pub fn div_round_up(a: T, b: T) -> T where From 6791429cd2ff9476c2f36ee23bf659be048260ac Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 27 Mar 2020 23:44:01 +0100 Subject: [PATCH 0368/1301] Fix most high-level errors in xhcid. --- xhcid/src/main.rs | 52 +--- xhcid/src/xhci/capability.rs | 4 +- xhcid/src/xhci/context.rs | 16 +- xhcid/src/xhci/irq_reactor.rs | 134 ++++++---- xhcid/src/xhci/mod.rs | 271 +++++++++++-------- xhcid/src/xhci/ring.rs | 17 +- xhcid/src/xhci/scheme.rs | 490 ++++++++++++++++------------------ xhcid/src/xhci/trb.rs | 4 +- 8 files changed, 503 insertions(+), 485 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 1a3e35e03b..4077bdb912 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -25,7 +25,11 @@ use syscall::io::Io; use crate::xhci::{InterruptMethod, Xhci}; -mod driver_interface; +// Declare as pub so that no warnings appear due to parts of the interface code not being used by +// the driver. Since there's also a dedicated crate for the driver interface, those warnings don't +// mean anything. +pub mod driver_interface; + mod usb; mod xhci; @@ -181,7 +185,7 @@ fn main() { table_entry_pointer.msg_data.write(msg_data); table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); - (Some(interrupt_handle), InterruptMethod::MsiX(info)) + (Some(interrupt_handle), InterruptMethod::MsiX(Mutex::new(info))) } } else if pci_config.func.legacy_interrupt_pin.is_some() { // legacy INTx# interrupt pins. @@ -212,8 +216,9 @@ fn main() { File::from_raw_fd(socket_fd as RawFd) })); - let hci = Arc::new(Xhci::new(name, address, interrupt_method, irq_file.as_mut(), pcid_handle).expect("xhcid: failed to allocate device")); - hci.probe().expect("xhcid: failed to probe"); + let hci = Arc::new(Xhci::new(name, address, interrupt_method, pcid_handle).expect("xhcid: failed to allocate device")); + xhci::start_irq_reactor(&hci, irq_file); + futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe"); let mut event_queue = EventQueue::<()>::new().expect("xhcid: failed to create event queue"); @@ -223,49 +228,12 @@ fn main() { let todo = Arc::new(Mutex::new(Vec::::new())); let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); - if let Some(irq_file) = irq_file { - let hci_irq = hci.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add(irq_file.as_raw_fd(), move |_| -> io::Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - - let hci = hci_irq.lock().unwrap(); - let socket = socket_irq.lock().unwrap(); - let todo = todo_irq.lock().unwrap(); - - if hci.received_irq() { - hci.on_irq(); - - irq_file.write(&mut irq)?; - - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - hci.handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket.write(&todo[i])?; - todo.remove(i); - } - } - } - - Ok(None) - }) - .expect("xhcid: failed to catch events on IRQ file"); - } - let socket_fd = socket.lock().unwrap().as_raw_fd(); let socket_packet = socket.clone(); event_queue .add(socket_fd, move |_| -> io::Result> { let mut socket = socket_packet.lock().unwrap(); - let mut hci = hci.lock().unwrap(); + let mut hci = hci; let mut todo = todo.lock().unwrap(); loop { diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index 98750bc12c..4ec7b10a15 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -56,13 +56,13 @@ impl CapabilityRegs { ((self.hcc_params1.read() & HCC_PARAMS1_XECP_MASK) >> HCC_PARAMS1_XECP_SHIFT) as u16 } pub fn max_scratchpad_bufs_lo(&self) -> u8 { - ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) as u8 } pub fn spr(&self) -> bool { self.hcs_params2.readf(HCS_PARAMS2_SPR_BIT) } pub fn max_scratchpad_bufs_hi(&self) -> u8 { - ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) as u8 } pub fn max_scratchpad_bufs(&self) -> u16 { u16::from(self.max_scratchpad_bufs_lo()) diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index f3eb970737..1093a6e250 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -161,7 +161,6 @@ impl StreamContextArray { } #[repr(packed)] -#[derive(Clone, Debug)] pub struct ScratchpadBufferEntry { pub value: Mmio, } @@ -179,21 +178,20 @@ impl ScratchpadBufferArray { pub fn new(entries: u16) -> Result { let mut entries = unsafe { Dma::zeroed_unsized(entries as usize)? }; - let pages = entries.iter_mut().map(|entry| { - // TODO: When a better memory allocation API arrives (like the `mem:` scheme which I think is - // being worked on), no assumptions about the page size always being 4k will have to be - // made. - let pointer = syscall::physalloc(4096); + let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result { + // TODO: Get the page size using fstatvfs on the `memory:` scheme. + let pointer = syscall::physalloc(4096)?; assert_eq!(pointer & 0xFFFF_FFFF_FFFF_F000, pointer, "physically allocated pointer (physalloc) wasn't 4k page-aligned"); - entry.set_addr(pointer); - }); + entry.set_addr(pointer as u64); + Ok(pointer) + }).collect::, _>>()?; Ok(Self { entries, pages, }) } - pub fn register(&self) -> u64 { + pub fn register(&self) -> usize { self.entries.physical() } } diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 4d808f6f30..977fa56584 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::fs::File; use std::future::Future; +use std::io::prelude::*; use std::pin::Pin; use std::sync::{Arc, Mutex}; use std::sync::atomic::{self, AtomicUsize}; @@ -8,6 +9,7 @@ use std::{mem, task, thread}; use crossbeam_channel::{Sender, Receiver}; use futures::Stream; +use syscall::Io; use super::Xhci; use super::ring::Ring; @@ -31,10 +33,19 @@ pub struct NextEventTrb { // indexed using this struct instead. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct RingId { - pub slot: u8, + pub port: u8, pub endpoint_num: u8, pub stream_id: u16, } +impl RingId { + pub const fn default_control_pipe(port: u8) -> Self { + Self { + port, + endpoint_num: 0, + stream_id: 0, + } + } +} /// The state specific to a TRB-type. Since some of the event TDs may asynchronously appear, for /// example the Command Completion Event and the Transfer Event TDs, they have to be @@ -52,10 +63,10 @@ pub enum StateKind { impl StateKind { pub fn trb_type(&self) -> TrbType { - match self.kind { - Self::CommandCompletion { .. } => TrbType::CommandCompletion, - Self::Transfer { .. } => TrbType::Transfer, - Self::Other(ty) => ty, + match self { + &Self::CommandCompletion { .. } => TrbType::CommandCompletion, + &Self::Transfer { .. } => TrbType::Transfer, + &Self::Other(ty) => ty, } } } @@ -63,7 +74,6 @@ impl StateKind { pub struct IrqReactor { hci: Arc, - current_count: Arc, irq_file: Option, receiver: Receiver, @@ -75,18 +85,13 @@ pub struct IrqReactor { pub type NewPendingTrb = State; -pub fn start_irq_reactor(hci: Arc, irq_file: Option) -> thread::JoinHandle<()> { - thread::spawn(move || { - IrqReactor::new(hci, irq_file).run() - }) -} - impl IrqReactor { - pub fn new(hci: Arc, irq_file: Option) -> Self { + pub fn new(hci: Arc, receiver: Receiver, irq_file: Option) -> Self { Self { hci, irq_file, - current_count: Arc::new(AtomicUsize::new()), + receiver, + states: Vec::new(), } } // TODO: Configure the amount of time to be awaited when no more work can be done. @@ -97,30 +102,31 @@ impl IrqReactor { loop { self.handle_requests(); - let index = self.hci.primary_event_ring.lock().unwrap().next_index(); + let index = self.hci.primary_event_ring.lock().unwrap().ring.next_index(); let mut trb; 'busy_waiting: loop { - trb = self.hci.primary_event_ring.lock().unwrap().trbs[index]; + trb = self.hci.primary_event_ring.lock().unwrap().ring.trbs[index]; if trb.completion_code() == TrbCompletionCode::Invalid as u8 { self.pause(); continue 'busy_waiting; } } + if self.check_event_ring_full(&trb) { continue } self.acknowledge(trb); self.update_erdp(); } } fn run_with_irq_file(mut self) { + let irq_file = self.irq_file.as_mut().expect("Calling IrqReactor::run_with_irq_file without the IRQ file being None"); + 'event_loop: loop { self.handle_requests(); - let irq_file = self.irq_file.as_mut().unwrap(); - let mut buffer = [0u8; 8]; - let bytes_read = self.irq_file.read(&mut buffer).expect("Failed to read from irq scheme"); + let bytes_read = irq_file.read(&mut buffer).expect("Failed to read from irq scheme"); if bytes_read < mem::size_of::() { panic!("wrong number of bytes read from `irq:`: expected {}, got {}", mem::size_of::(), bytes_read); } @@ -129,30 +135,38 @@ impl IrqReactor { continue; } - let _ = self.irq_file.write(&buffer); + let _ = irq_file.write(&buffer); // TODO: More event rings, probably even with different IRQs. let event_ring = self.hci.primary_event_ring.lock().unwrap(); - let trb = event_ring.next(); - if trb.completion_code() == TrbCompletionCode::Invalid as u8 { - println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt."); - continue 'event_loop; + let mut count = 0; + + 'trb_loop: loop { + let trb = event_ring.next(); + + if trb.completion_code() == TrbCompletionCode::Invalid as u8 { + if count == 0 { println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } + continue 'event_loop; + } else { count += 1 } + + if self.check_event_ring_full(trb) { + continue 'trb_loop; + } + self.acknowledge(*trb); + trb.reserved(false); + + self.update_erdp(); } - - self.acknowledge(*trb); - trb.reserved(false); - - self.update_erdp(); } } fn update_erdp(&self) { - let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().register(); + let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().erdp(); let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); - self.xhci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); + self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); } fn handle_requests(&mut self) { self.states.extend(self.receiver.try_iter()); @@ -163,11 +177,11 @@ impl IrqReactor { loop { match self.states[index].kind { StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => if trb.completion_trb_pointer() == Some(phys_ptr) { - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); // Before waking, it's crucial that the command TRB that generated this event // be fetched before removing this event TRB from the queue. - let command_trb = match self.hci.command_ring.lock().unwrap().ring.phys_addr_to_entry_mut(phys_ptr) { + let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(phys_ptr) { Some(command_trb) => { let t = command_trb.clone(); command_trb.reserved(false); @@ -181,7 +195,7 @@ impl IrqReactor { // TODO: Validate the command TRB. *state.message.lock().unwrap() = Some(NextEventTrb { - src_trb: command_trb.clone(), + src_trb: Some(command_trb.clone()), event_trb: trb, }); @@ -194,13 +208,13 @@ impl IrqReactor { continue; } - StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => if let Some(src_trb) = self.xhc.lock().unwrap().get_transfer_trb(trb.transfer_event_trb_pointer(), ring_id) { + StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => if let Some(src_trb) = trb.transfer_event_trb_pointer().map(|ptr| self.hci.get_transfer_trb(ptr, ring_id)).flatten() { if trb.transfer_event_trb_pointer() == Some(phys_ptr) { // Give the source transfer TRB together with the event TRB, to the future. - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); *state.message.lock().unwrap() = Some(NextEventTrb { - src_trb, + src_trb: Some(src_trb), event_trb: trb, }); state.waker.wake(); @@ -225,7 +239,7 @@ impl IrqReactor { } else { continue } StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => { - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); state.waker.wake(); } @@ -239,7 +253,7 @@ impl IrqReactor { } } } - pub fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { + fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { let mut index = 0; loop { @@ -250,7 +264,7 @@ impl IrqReactor { } continue; } - let state = self.states.remove(index).unwrap(); + let state = self.states.remove(index); *state.message.lock().unwrap() = Some(NextEventTrb { event_trb: trb, src_trb: None, @@ -258,6 +272,23 @@ impl IrqReactor { state.waker.wake(); } } + /// Checks if an event TRB is a Host Controller Event, with the completion code Event Ring + /// Full. If so, it grows the event ring. The return value is whether the event ring was full, + /// and then grown. + fn check_event_ring_full(&mut self, event_trb: &Trb) -> bool { + let had_event_ring_full_error = event_trb.trb_type() == TrbType::HostController as u8 && event_trb.completion_code() == TrbCompletionCode::EventRingFull as u8; + + if had_event_ring_full_error { + self.grow_event_ring(); + } + had_event_ring_full_error + } + /// Grows the event ring + fn grow_event_ring(&mut self) { + // TODO + println!("TODO: grow event ring"); + } + pub fn run(mut self) { if self.irq_file.is_some() { self.run_with_irq_file(); @@ -291,7 +322,7 @@ impl Future for EventTrbFuture { sender.send(State { message: Arc::clone(&state.message), is_isoch_or_vf: state.is_isoch_or_vf, - state_kind: state.state_kind, + kind: state.state_kind, waker: context.waker().clone(), }).expect("IRQ reactor thread unexpectedly stopped"); @@ -304,12 +335,12 @@ impl Future for EventTrbFuture { impl Xhci { pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option { - self.with_ring(id, |ring| ring.phys_addr_to_entry(paddr)) + self.with_ring(id, |ring| ring.phys_addr_to_entry(paddr)).flatten() } - pub fn with_ring T>(&self, id: RingId, function: F) -> T { + pub fn with_ring T>(&self, id: RingId, function: F) -> Option { use super::RingOrStreams; - let slot_state = self.slot_states.get(&id.slot)?; + let slot_state = self.port_states.get(&(id.port as usize))?; let endpoint_state = slot_state.endpoint_states.get(&id.endpoint_num)?; let ring_ref = match endpoint_state.transfer { @@ -317,12 +348,12 @@ impl Xhci { RingOrStreams::Streams(ref ctx_arr) => ctx_arr.rings.get(&id.stream_id)?, }; - function(ring_ref) + Some(function(ring_ref)) } - pub fn with_ring_mut T>(&self, id: RingId, function: F) -> T { + pub fn with_ring_mut T>(&self, id: RingId, function: F) -> Option { use super::RingOrStreams; - let slot_state = self.slot_states.get(&id.slot)?; + let slot_state = self.port_states.get(&(id.port as usize))?; let endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?; let ring_ref = match endpoint_state.transfer { @@ -330,7 +361,7 @@ impl Xhci { RingOrStreams::Streams(ref mut ctx_arr) => ctx_arr.rings.get_mut(&id.stream_id)?, }; - function(ring_ref) + Some(function(ring_ref)) } pub fn next_transfer_event_trb(&self, ring_id: RingId, trb: &Trb) -> impl Future + Send + Sync + 'static { if ! trb.is_transfer_trb() { @@ -344,7 +375,7 @@ impl Xhci { is_isoch_or_vf, state_kind: StateKind::Transfer { ring_id, - phys_ptr: self.with_ring(ring_id, |ring| ring.trb_phys_ptr(trb)/*.expect("Invalid TRB: transfer TRB wasn't in the ring specified. Only direct references to the TRBs of a ring can be used (ring address range: {:p}-{:p}).", ring.start_addr(), ring.end_addr())*/), + phys_ptr: self.with_ring(ring_id, |ring| ring.trb_phys_ptr(trb)).unwrap(), }, message: Arc::new(Mutex::new(None)), }, @@ -363,7 +394,7 @@ impl Xhci { // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). is_isoch_or_vf: false, state_kind: StateKind::CommandCompletion { - phys_ptr: command_ring.trb_phys_ptr(trb),//.expect("Invalid TRB: expected a command TRB within the address range of the command TRB ({:p} {:p}), found TRB {:?} at {:p}", ring.start_addr(), ring.end_addr(), trb, trb) + phys_ptr: command_ring.trb_phys_ptr(trb), }, message: Arc::new(Mutex::new(None)), }, @@ -379,7 +410,7 @@ impl Xhci { TrbType::DeviceNotification as u8, TrbType::MfindexWrap as u8, ]; - if ! valid_trb_types.contains(&trb_type) { + if ! valid_trb_types.contains(&(trb_type as u8)) { panic!("Invalid TRB type given to next_misc_event_trb(): {:?}. Only event TRB types that are neither transfer events or command completion events can be used.", trb_type) } EventTrbFuture::Pending { @@ -391,4 +422,5 @@ impl Xhci { sender: self.irq_reactor_sender.clone(), } } + } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 3970677053..e2da2a887a 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -4,13 +4,16 @@ use std::fs::File; use std::future::Future; use std::pin::Pin; use std::ptr::NonNull; -use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak}; +use std::sync::{Arc, Mutex, MutexGuard, Weak}; +use std::sync::atomic::{AtomicBool, AtomicUsize}; + use std::{mem, process, slice, sync::atomic, task, thread}; use chashmap::CHashMap; -use crossbeam_channel::Sender; +use crossbeam_channel::{Receiver, Sender}; use serde::Deserialize; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT}; +use syscall::flag::O_RDONLY; use syscall::io::{Dma, Io}; use crate::usb; @@ -34,14 +37,14 @@ mod trb; use self::capability::CapabilityRegs; use self::context::{DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray}; use self::doorbell::Doorbell; -use self::irq_reactor::NewPendingTrb; +use self::irq_reactor::{IrqReactor, NewPendingTrb, RingId}; use self::event::EventRing; use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap}; use self::operational::OperationalRegs; use self::port::Port; use self::ring::Ring; use self::runtime::{Interrupter, RuntimeRegs}; -use self::trb::{TransferKind, TrbCompletionCode, TrbType}; +use self::trb::{TransferKind, Trb, TrbCompletionCode, TrbType}; use self::scheme::EndpIfState; @@ -88,70 +91,61 @@ impl MsixInfo { } } -struct Device<'a> { - ring: &'a mut Ring, - cmd: &'a mut Ring, - db: &'a mut Doorbell, - int: &'a mut Interrupter, -} - -impl<'a> Device<'a> { - fn get_desc(&mut self, kind: usb::DescriptorKind, index: u8, desc: &mut Dma) { +impl Xhci { + /// Gets descriptors, before the port state is initiated. + async fn get_desc_raw(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, ring: &mut Ring, desc: &mut Dma) -> Result<()> { let len = mem::size_of::(); - { - let (cmd, cycle) = self.ring.next(); + let future = { + let (cmd, cycle) = ring.next(); cmd.setup( usb::Setup::get_descriptor(kind, index, 0, len as u16), TransferKind::In, cycle, ); - } - { - let (cmd, cycle) = self.ring.next(); + let (cmd, cycle) = ring.next(); cmd.data(desc.physical(), len as u16, true, cycle); - } - { - let (cmd, cycle) = self.ring.next(); - cmd.status(false, cycle); - } + let (cmd, cycle) = ring.next(); + cmd.status(0, true, true, false, false, cycle); - self.db.write(1); + self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &cmd) + }; - { - let event = self.cmd.next_event(); - // TODO: Replace polling here as well. - while event.data.read() == 0 { - println!(" - Waiting for event"); - } - } + self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); - self.int.erdp.write(self.cmd.erdp() | (1 << 3)); + let trbs = future.await; + let event_trb = trbs.event_trb; + let status_trb = trbs.src_trb.unwrap(); + + self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?; + + self.event_handler_finished(); + Ok(()) } - fn get_device(&mut self) -> Result { + async fn fetch_dev_desc(&mut self, port: usize, slot: u8, ring: &mut Ring) -> Result { let mut desc = Dma::::zeroed()?; - self.get_desc(usb::DescriptorKind::Device, 0, &mut desc); + self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, ring, &mut desc).await?; Ok(*desc) } - fn get_config(&mut self, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { + async fn fetch_config_desc(&mut self, port: usize, slot: u8, ring: &mut Ring, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc(usb::DescriptorKind::Configuration, config, &mut desc); + self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, ring, &mut desc).await?; Ok(*desc) } - fn get_bos(&mut self) -> Result<(usb::BosDescriptor, [u8; 4087])> { + async fn fetch_bos_desc(&mut self, port: usize, slot: u8, ring: &mut Ring) -> Result<(usb::BosDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc(usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc); + self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, ring, &mut desc).await?; Ok(*desc) } - fn get_string(&mut self, index: u8) -> Result { + async fn fetch_string_desc(&mut self, port: usize, slot: u8, ring: &mut Ring, index: u8) -> Result { let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; - self.get_desc(usb::DescriptorKind::String, index, &mut sdesc); + self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, ring, &mut sdesc).await?; let len = sdesc.0 as usize; if len > 2 { @@ -165,6 +159,7 @@ impl<'a> Device<'a> { pub struct Xhci { // immutable cap: &'static CapabilityRegs, + page_size: usize, // XXX: It would be really useful to be able to mutably access individual elements of a slice, // without having to wrap every element in a lock (which wouldn't work since they're packed). @@ -183,7 +178,7 @@ pub struct Xhci { base: *const u8, handles: CHashMap, - next_handle: usize, + next_handle: AtomicUsize, port_states: CHashMap, drivers: CHashMap, @@ -191,16 +186,25 @@ pub struct Xhci { interrupt_method: InterruptMethod, pcid_handle: Mutex, - irq_reactor: Option>, + + irq_reactor: Mutex>>, + irq_reactor_sender: Sender, + + // not used, but still stored so that the thread, when created, can get the channel without the + // channel being in a mutex. + irq_reactor_receiver: Receiver, } +unsafe impl Send for Xhci {} +unsafe impl Sync for Xhci {} + struct PortState { slot: u8, cfg_idx: Option, if_idx: Option, input_context: Mutex>, - dev_desc: DevDesc, + dev_desc: Option, endpoint_states: BTreeMap, } @@ -227,6 +231,13 @@ impl Xhci { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; println!(" - CAP {:X}", address); + let page_size = { + let memory_fd = syscall::open("memory:", O_RDONLY)?; + let mut stat = syscall::data::StatVfs::default(); + syscall::fstatvfs(memory_fd, &mut stat)?; + stat.f_bsize as usize + }; + let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; println!(" - OP {:X}", op_base); @@ -276,25 +287,42 @@ impl Xhci { let run = unsafe { &mut *(run_base as *mut RuntimeRegs) }; println!(" - RUNTIME {:X}", run_base); - let mut xhci = Xhci { - base: address as *const u8, - cap, - op, - ports, - dbs, - run, - dev_ctx: DeviceContextList::new(max_slots)?, - cmd: Ring::new(), - primary_event_ring: EventRing::new(), - handles: BTreeMap::new(), - next_handle: 0, - port_states: BTreeMap::new(), + // Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the + // DMA allocation (which is at least a 4k page). + let entries_per_page = page_size / mem::size_of::(); + let cmd = Ring::new(entries_per_page, true)?; - drivers: BTreeMap::new(), + let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded(); + + let mut xhci = Self { + base: address as *const u8, + + cap, + page_size, + + op: Mutex::new(op), + ports: Mutex::new(ports), + dbs: Mutex::new(dbs), + run: Mutex::new(run), + + dev_ctx: DeviceContextList::new(max_slots)?, + scratchpad_buf_arr: None, // initialized in init() + + cmd: Mutex::new(cmd), + primary_event_ring: Mutex::new(EventRing::new()?), + handles: CHashMap::new(), + next_handle: AtomicUsize::new(0), + port_states: CHashMap::new(), + + drivers: CHashMap::new(), scheme_name, interrupt_method, pcid_handle: Mutex::new(pcid_handle), + + irq_reactor: Mutex::new(None), + irq_reactor_sender, + irq_reactor_receiver, }; xhci.init(max_slots); @@ -302,37 +330,37 @@ impl Xhci { Ok(xhci) } - pub fn init(&mut self, max_slots: u8) { + pub fn init(&mut self, max_slots: u8) -> Result<()> { // Set enabled slots println!(" - Set enabled slots to {}", max_slots); - self.op.get_mut().config.write(max_slots as u32); - println!(" - Enabled Slots: {}", self.op.get_mut().config.read() & 0xFF); + self.op.get_mut().unwrap().config.write(max_slots as u32); + println!(" - Enabled Slots: {}", self.op.get_mut().unwrap().config.read() & 0xFF); // Set device context address array pointer let dcbaap = self.dev_ctx.dcbaap(); println!(" - Write DCBAAP: {:X}", dcbaap); - self.op.get_mut().dcbaap.write(dcbaap as u64); + self.op.get_mut().unwrap().dcbaap.write(dcbaap as u64); // Set command ring control register - let crcr = self.cmd.get_mut().register(); + let crcr = self.cmd.get_mut().unwrap().register(); assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR"); println!(" - Write CRCR: {:X}", crcr); - self.op.get_mut().crcr.write(crcr as u64); + self.op.get_mut().unwrap().crcr.write(crcr as u64); // Set event ring segment table registers - println!(" - Interrupter 0: {:X}", self.run.ints.as_ptr() as usize); + println!(" - Interrupter 0: {:X}", self.run.get_mut().unwrap().ints.as_ptr() as usize); { - let int = &mut self.run.get_mut().ints[0]; + let int = &mut self.run.get_mut().unwrap().ints[0]; let erstz = 1; println!(" - Write ERSTZ: {}", erstz); int.erstsz.write(erstz); - let erdp = self.primary_event_ring.get_mut().erdp(); + let erdp = self.primary_event_ring.get_mut().unwrap().erdp() | (!1); println!(" - Write ERDP: {:X}", erdp); int.erdp.write(erdp as u64 | (1 << 3)); - let erstba = self.primary_event_ring.get_mut().erstba(); + let erstba = self.primary_event_ring.get_mut().unwrap().erstba(); println!(" - Write ERSTBA: {:X}", erstba); int.erstba.write(erstba as u64); @@ -343,49 +371,66 @@ impl Xhci { int.iman.writef(1 << 1, true); } - self.op.get_mut().usb_cmd.writef(1 << 2, true); + self.op.get_mut().unwrap().usb_cmd.writef(1 << 2, true); // Setup the scratchpad buffers that are required for the xHC to function. - self.setup_scratchpads(); + self.setup_scratchpads()?; // Set run/stop to 1 println!(" - Start"); - self.op.get_mut().usb_cmd.writef(1, true); + self.op.get_mut().unwrap().usb_cmd.writef(1, true); // Wait until controller is running println!(" - Wait for running"); - while self.op.get_mut().usb_sts.readf(1) { + while self.op.get_mut().unwrap().usb_sts.readf(1) { println!(" - Waiting for XHCI running"); } - println!("IP={}", self.run.get_mut().ints[0].iman.readf(1)); + println!("IP={}", self.run.get_mut().unwrap().ints[0].iman.readf(1)); // Ring command doorbell println!(" - Ring doorbell"); - self.dbs.get_mut()[0].write(0); + self.dbs.get_mut().unwrap()[0].write(0); println!(" - XHCI initialized"); + + if self.cap.cic() { + self.op.lock().unwrap().set_cie(true); + } + + Ok(()) } pub fn setup_scratchpads(&mut self) -> Result<()> { let buf_count = self.cap.max_scratchpad_bufs(); if buf_count == 0 { - return; + return Ok(()); } - self.scratchpad_buf_arr = Some(ScratchpadBufferArray::new(buf_count)?); - self.dev_ctx.dcbaa[0] = self.scratchpad_buf_arr.register(); + let scratchpad_buf_arr = ScratchpadBufferArray::new(buf_count)?; + self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; + self.scratchpad_buf_arr = Some(scratchpad_buf_arr); + + Ok(()) } - pub fn enable_port_slot(&mut self, slot_ty: u8) -> Result { + pub async fn enable_port_slot(&mut self, slot_ty: u8) -> Result { assert_eq!(slot_ty & 0x1F, slot_ty); - let cloned_event_trb = - self.execute_command("ENABLE_SLOT", |cmd, cycle| cmd.enable_slot(slot_ty, cycle))?; - Ok(cloned_event_trb.event_slot()) + let (event_trb, command_trb) = + self.execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)).await; + + self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb); + self.event_handler_finished(); + + Ok(event_trb.event_slot()) } - pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> { - self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.disable_slot(slot, cycle))?; + pub async fn disable_port_slot(&mut self, slot: u8) -> Result<()> { + let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)).await; + + self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb); + self.event_handler_finished(); + Ok(()) } @@ -415,29 +460,19 @@ impl Xhci { .supported_protocol(i as u8) .expect("Failed to find supported protocol information for port") .proto_slot_ty(); - let slot = self.enable_port_slot(slot_ty)?; + let slot = self.enable_port_slot(slot_ty).await?; println!(" - Slot {}", slot); let mut input = Dma::::zeroed()?; let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; - let dev_desc = Self::get_dev_desc_raw( - &mut *self.ports.lock().unwrap(), - &mut *self.run.lock().unwrap(), - &mut *self.cmd.lock().unwrap(), - &mut *self.dbs.lock().unwrap(), - i, - slot, - &mut ring, - )?; - - self.update_default_control_pipe(&mut input, slot, &dev_desc)?; + // TODO: Should the descriptors be cached in PortState, or refetched? let mut port_state = PortState { slot, input_context: Mutex::new(input), - dev_desc, + dev_desc: None, cfg_idx: None, if_idx: None, endpoint_states: std::iter::once(( @@ -450,9 +485,9 @@ impl Xhci { .collect::>(), }; - if self.cap.cic() { - self.op.lock().unwrap().set_cie(true); - } + let dev_desc = self.get_desc(i, slot, &mut ring).await?; + port_state.dev_desc = Some(dev_desc); + self.update_default_control_pipe(&mut input, slot, &dev_desc).await?; /*match self.spawn_drivers(i, &mut port_state) { Ok(()) => (), @@ -466,7 +501,7 @@ impl Xhci { Ok(()) } - pub fn update_default_control_pipe( + pub async fn update_default_control_pipe( &mut self, input_context: &mut Dma, slot_id: u8, @@ -486,9 +521,13 @@ impl Xhci { b |= (new_max_packet_size) << 16; endp_ctx.b.write(b); - self.execute_command("EVALUATE_CONTEXT", |trb, cycle| { + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.evaluate_context(slot_id, input_context.physical(), false, cycle) - })?; + }).await; + + self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb); + self.event_handler_finished(); + Ok(()) } @@ -598,15 +637,16 @@ impl Xhci { pub fn uses_msix(&self) -> bool { if let InterruptMethod::MsiX(_) = self.interrupt_method { true } else { false } } - pub fn msix_info(&self) -> Option<&MsixInfo> { + // TODO: Perhaps use an rwlock? + pub fn msix_info(&self) -> Option> { match self.interrupt_method { - InterruptMethod::MsiX(ref info) => Some(info), + InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), _ => None, } } - pub fn msix_info_mut(&mut self) -> Option<&mut MsixInfo> { + pub fn msix_info_mut(&mut self) -> Option> { match self.interrupt_method { - InterruptMethod::MsiX(ref mut info) => Some(info), + InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), _ => None, } } @@ -614,18 +654,20 @@ impl Xhci { /// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always /// true when using MSI/MSI-X. pub fn received_irq(&mut self) -> bool { + let runtime_regs = self.run.lock().unwrap(); + if self.uses_msi() || self.uses_msix() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. - println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", self.run.ints[0].iman.readf(1), self.run.ints[0].erdp.readf(3)); + println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); println!("MSI-X PB={}", self.msix_info_mut().unwrap().pba(0)); let entry = self.msix_info_mut().unwrap().table_entry_pointer(0); println!("MSI-X entry (addr_lo, addr_hi, msg_data, vec_ctl: {:#0x} {:#0x} {:#0x} {:#0x}", entry.addr_lo.read(), entry.addr_hi.read(), entry.msg_data.read(), entry.vec_ctl.read()); true - } else if self.run.ints[0].iman.readf(1) { + } else if runtime_regs.ints[0].iman.readf(1) { // If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is // a special register to specify whether the IRQ actually came from the xHC. - self.run.ints[0].iman.writef(1, true); + runtime_regs.ints[0].iman.writef(1, true); // The interrupt came from the xHC. true @@ -634,8 +676,6 @@ impl Xhci { false } - } - pub fn on_irq(&mut self) { } fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> { // TODO: There should probably be a way to select alternate interfaces, and not just the @@ -645,12 +685,14 @@ impl Xhci { let ifdesc = &ps .dev_desc + .as_ref().unwrap() .config_descs .first() .ok_or(Error::new(EBADF))? .interface_descs .first() .ok_or(Error::new(EBADF))?; + let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| { @@ -787,6 +829,15 @@ impl Xhci { .find(|speed| speed.psiv() == psiv) } } +pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { + let receiver = hci.irq_reactor_receiver.clone(); + let hci_clone = Arc::clone(&hci); + + *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { + IrqReactor::new(hci_clone, receiver, irq_file).run() + })); +} + #[derive(Deserialize)] struct DriverConfig { name: String, diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index 26d0433277..2e067efce3 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -64,9 +64,10 @@ impl Ring { /// /// # Panics /// Panics if paddr is not a multiple of 16 bytes, i.e. the size of a TRB. + // TODO: Use usize instead of u64. pub fn phys_addr_to_index(&self, paddr: u64) -> Option { let base = self.trbs.physical(); - let offset = paddr.checked_sub(base)?; + let offset = paddr.checked_sub(base as u64)? as usize; assert_eq!(offset % mem::size_of::(), 0, "unaligned TRB physical address"); @@ -79,29 +80,29 @@ impl Ring { Some(index) } pub fn phys_addr_to_entry_ref(&self, paddr: u64) -> Option<&Trb> { - &self.trbs[self.phys_addr_to_index(paddr)] + Some(&self.trbs[self.phys_addr_to_index(paddr)?]) } pub fn phys_addr_to_entry_mut(&self, paddr: u64) -> Option<&mut Trb> { - &mut self.trbs[self.phys_addr_to_index(paddr)] + Some(&mut self.trbs[self.phys_addr_to_index(paddr)?]) } pub fn phys_addr_to_entry(&self, paddr: u64) -> Option { - self.trbs[self.phys_addr_to_index(paddr)].clone() + Some(self.trbs[self.phys_addr_to_index(paddr)?].clone()) } pub(crate) fn start_virt_addr(&self) -> *const Trb { self.trbs.as_ptr() } pub(crate) fn end_virt_addr(&self) -> *const Trb { - unsafe { self.start_virt_addr().offset(self.trbs.len()) } + unsafe { self.start_virt_addr().offset(self.trbs.len() as isize) } } pub fn trb_phys_ptr(&self, trb: &Trb) -> u64 { let trb_virt_pointer = trb as *const Trb; let trbs_base_virt_pointer = self.trbs.as_ptr(); - if trb_virt_pointer < trbs_base_virt_pointer || trb_virt_pointer > trbs_base_virt_pointer + self.trbs.len() * mem::size_of::() { + if (trb_virt_pointer as usize) < (trbs_base_virt_pointer as usize) || (trb_virt_pointer as usize) > (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::() { panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb); } - let trbs_base_phys_ptr = self.trbs.physical(); - let trb_phys_ptr = trb_virt_pointer - trbs_base_phys_ptr; + let trbs_base_phys_ptr = self.trbs.physical() as u64; + let trb_phys_ptr = trb_virt_pointer as u64 - trbs_base_phys_ptr; trb_phys_ptr } /* diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c96d3d9c08..3ecc690cae 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,7 +1,9 @@ use std::convert::TryFrom; use std::io::prelude::*; +use std::sync::atomic; use std::{cmp, io, mem, path, str}; +use futures::executor::block_on; use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; @@ -15,7 +17,7 @@ use syscall::{ }; use super::{port, usb}; -use super::{Device, EndpointState, Xhci}; +use super::{EndpointState, Xhci}; use super::context::{ InputContext, SlotState, StreamContext, StreamContextArray, StreamContextType, @@ -23,6 +25,7 @@ use super::context::{ }; use super::doorbell::Doorbell; use super::extended::ProtocolSpeed; +use super::irq_reactor::RingId; use super::operational::OperationalRegs; use super::ring::Ring; use super::runtime::RuntimeRegs; @@ -139,31 +142,6 @@ impl From for SuperSpeedPlusIsochCmp { } } -impl IfDesc { - fn new( - dev: &mut Device, - desc: usb::InterfaceDescriptor, - endps: impl IntoIterator, - hid_descs: impl IntoIterator, - ) -> Result { - Ok(Self { - alternate_setting: desc.alternate_setting, - class: desc.class, - interface_str: if desc.interface_str > 0 { - Some(dev.get_string(desc.interface_str)?) - } else { - None - }, - kind: desc.kind, - number: desc.number, - protocol: desc.protocol, - sub_class: desc.sub_class, - endpoints: endps.into_iter().collect(), - hid_descs: hid_descs.into_iter().collect(), - }) - } -} - /// Any descriptor that can be stored in the config desc "data" area. #[derive(Debug)] pub enum AnyDescriptor { @@ -210,8 +188,35 @@ impl AnyDescriptor { } impl Xhci { + async fn new_if_desc( + &self, + port_id: usize, + slot: u8, + ring: &mut Ring, + desc: usb::InterfaceDescriptor, + endps: impl IntoIterator, + hid_descs: impl IntoIterator, + ) -> Result { + Ok(IfDesc { + alternate_setting: desc.alternate_setting, + class: desc.class, + interface_str: if desc.interface_str > 0 { + Some(self.fetch_string_desc(port_id, slot, ring, desc.interface_str).await?) + } else { + None + }, + kind: desc.kind, + number: desc.number, + protocol: desc.protocol, + sub_class: desc.sub_class, + endpoints: endps.into_iter().collect(), + hid_descs: hid_descs.into_iter().collect(), + }) + } pub fn execute_command_noreply(&self, f: F) { - let (cmd, cycle) = self.cmd.lock().unwrap(); + let command_ring = self.cmd.lock().unwrap(); + + let (cmd, cycle) = command_ring.next(); f(cmd, cycle); self.dbs.lock().unwrap()[0].write(0); @@ -243,7 +248,7 @@ impl Xhci { (event_trb, command_trb) } - pub fn execute_control_transfer( + pub async fn execute_control_transfer( &mut self, port_num: usize, setup: usb::Setup, @@ -254,62 +259,60 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { - let slot = self.port_state(port_num)?.slot; - let ring = self - .endpoint_state_mut(port_num, 0)? - .ring() - .ok_or(Error::new(EIO))?; + let port_state = self.port_state(port_num)?; + let slot = port_state.slot; + + let future = { + let endpoint_state = port_state + .endpoint_states + .get_mut(&0).ok_or(Error::new(EIO))?; + + let ring = endpoint_state + .ring() + .ok_or(Error::new(EIO))?; - { let (cmd, cycle) = ring.next(); cmd.setup(setup, tk, cycle); - } - if tk != TransferKind::NoData { - loop { - let (trb, cycle) = ring.next(); - match d(trb, cycle) { - ControlFlow::Break => break, - ControlFlow::Continue => continue, + + if tk != TransferKind::NoData { + loop { + let (trb, cycle) = ring.next(); + match d(trb, cycle) { + ControlFlow::Break => break, + ControlFlow::Continue => continue, + } } } - } - { + let (cmd, cycle) = ring.next(); - cmd.status(tk == TransferKind::In, cycle); - } - self.dbs[usize::from(slot)].write(Self::def_control_endp_doorbell()); - let cloned_trb = { - let event = self.cmd.next_event(); - while event.data.read() == 0 { - println!(" - {} Waiting for event", name); - } + let interrupter = 0; + let ioc = true; + let ch = false; + let ent = false; - if event.completion_code() != TrbCompletionCode::Success as u8 - || event.trb_type() != TrbType::Transfer as u8 - { - println!( - "{} CONTROL TRANSFER ERROR, EVENT TRB {:#0x} {:#0x} {:#0}»", - name, - event.data.read(), - event.status.read(), - event.control.read() - ); - } - event.reserved(false); - event.clone() + cmd.status(interrupter, tk == TransferKind::In, ioc, ch, ent, cycle); + self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), cmd) }; - self.run.ints[0].erdp.write(self.cmd.erdp() | (1 << 3)); + self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); - Ok(cloned_trb) + let trbs = future.await; + let event_trb = trbs.event_trb; + let status_trb = trbs.src_trb.unwrap(); + + handle_transfer_event_trb("CONTROL_TRANSFER", &event_trb, &status_trb)?; + + self.event_handler_finished(); + + Ok(event_trb) } /// NOTE: There has to be AT LEAST one successful invocation of `d`, that actually updates the /// TRB (it could be a NO-OP in the worst case). /// The function is also required to set the Interrupt on Completion flag, or this function /// will never complete. pub async fn execute_transfer( - &mut self, + &self, port_num: usize, endp_num: u8, stream_id: u16, @@ -326,7 +329,7 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; let slot = port_state.slot; let endp_state = port_state @@ -353,7 +356,7 @@ impl Xhci { match d(trb, cycle) { ControlFlow::Break => { - break self.next_transfer_event_trb(super::irq_reactor::RingId { slot, endpoint_num: endp_num, stream_id }, &trb); + break self.next_transfer_event_trb(super::irq_reactor::RingId { port: port_num as u8, endpoint_num: endp_num, stream_id }, &trb); } ControlFlow::Continue => continue, } @@ -386,20 +389,20 @@ impl Xhci { Ok(event_trb) } - fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { + async fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { self.execute_control_transfer( port, req, TransferKind::NoData, "DEVICE_REQ_NO_DATA", |_, _| ControlFlow::Break, - )?; + ).await?; Ok(()) } - fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { - self.device_req_no_data(port, usb::Setup::set_configuration(config)) + async fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { + self.device_req_no_data(port, usb::Setup::set_configuration(config)).await } - fn set_interface( + async fn set_interface( &mut self, port: usize, interface_num: u8, @@ -408,7 +411,7 @@ impl Xhci { self.device_req_no_data( port, usb::Setup::set_interface(interface_num, alternate_setting), - ) + ).await } async fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { @@ -419,7 +422,7 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); let slot = self @@ -534,7 +537,7 @@ impl Xhci { let (endp_desc_count, new_context_entries, configuration_value) = { let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let config_desc = port_state.dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; + let config_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; let endpoints = config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; @@ -588,7 +591,7 @@ impl Xhci { let endp_num = endp_idx + 1; let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let dev_desc = &port_state.dev_desc; + let dev_desc = port_state.dev_desc.as_ref().unwrap(); let endpoints = &dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; @@ -731,12 +734,12 @@ impl Xhci { handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; // Tell the device about this configuration. - self.set_configuration(port, configuration_value)?; + self.set_configuration(port, configuration_value).await?; if let (Some(interface_num), Some(alternate_setting)) = (req.interface_desc, req.alternate_setting) { - self.set_interface(port, interface_num, alternate_setting)?; + self.set_interface(port, interface_num, alternate_setting).await?; } Ok(()) @@ -747,28 +750,36 @@ impl Xhci { endp_idx: u8, buf: &mut [u8], ) -> Result<(u8, u32)> { + if buf.is_empty() { + return Err(Error::new(EINVAL)); + } + let dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(buf.len())? }; + + let (completion_code, bytes_transferred) = self.transfer( + port_num, + endp_idx, + Some(dma_buffer), + PortReqDirection::DeviceToHost, + ).await?; + + buf.copy_from_slice(&*dma_buffer.as_ref()); + Ok((completion_code, bytes_transferred)) + } + async fn transfer_write(&mut self, port_num: usize, endp_idx: u8, sbuf: &[u8]) -> Result<(u8, u32)> { + if sbuf.is_empty() { + return Err(Error::new(EINVAL)); + } + let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; + dma_buffer.copy_from_slice(sbuf); + self.transfer( port_num, endp_idx, - if !buf.is_empty() { - DeviceReqData::In(buf) - } else { - DeviceReqData::NoData - }, + Some(dma_buffer), + PortReqDirection::HostToDevice, ).await } - async fn transfer_write(&mut self, port_num: usize, endp_idx: u8, buf: &[u8]) -> Result<(u8, u32)> { - self.transfer( - port_num, - endp_idx, - if !buf.is_empty() { - DeviceReqData::Out(buf) - } else { - DeviceReqData::NoData - }, - ).await - } - const fn def_control_endp_doorbell() -> u32 { + pub const fn def_control_endp_doorbell() -> u32 { 1 } // TODO: Wrap DCIs and driver-level endp_num into distinct types, due to the high chance of @@ -794,39 +805,23 @@ impl Xhci { } // TODO: Rename DeviceReqData to something more general. async fn transfer( - &mut self, + &self, port_num: usize, endp_idx: u8, - mut buf: DeviceReqData, + dma_buf: Option>, + direction: PortReqDirection, ) -> Result<(u8, u32)> { // TODO: Check that only readable enpoints are read, etc. let endp_num = endp_idx + 1; - // TODO: Check that buf has a nonzero size, otherwise (at least for Rust's GlobalAlloc), - // UB. - let dma_buffer = match buf { - DeviceReqData::Out(sbuf) => { - if sbuf.is_empty() { - return Err(Error::new(EINVAL)); - } - let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; - dma_buffer.copy_from_slice(sbuf); - Some(dma_buffer) - } - DeviceReqData::In(ref dbuf) => { - if dbuf.is_empty() { - return Err(Error::new(EINVAL)); - } - Some(unsafe { Dma::<[u8]>::zeroed_unsized(dbuf.len()) }?) - } - DeviceReqData::NoData => None, - }; let port_state = self .port_states .get_mut(&port_num) .ok_or(Error::new(EBADFD))?; + let endp_desc: &EndpDesc = port_state .dev_desc + .as_ref().unwrap() .config_descs .get(0) .ok_or(Error::new(EIO))? @@ -843,7 +838,7 @@ impl Xhci { return Err(Error::new(ENOSYS)); } - if EndpDirection::from(buf.direction()) != endp_desc.direction() { + if EndpDirection::from(direction) != endp_desc.direction() { return Err(Error::new(EBADF)); } @@ -852,23 +847,22 @@ impl Xhci { let (buffer, idt, estimated_td_size) = { let (buffer, idt) = - if buf.len() <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { - buf.map_buf(|sbuf| { + if dma_buf.map(|buf| buf.len()).unwrap_or(0) <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { + dma_buf.map(|sbuf| { let mut bytes = [0u8; 8]; - bytes[..buf.len()].copy_from_slice(&sbuf[..buf.len()]); - // FIXME: little endian, right? + bytes[..sbuf.len()].copy_from_slice(&sbuf); (u64::from_le_bytes(bytes), true) }) .unwrap_or((0, false)) } else { ( - dma_buffer.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, + dma_buf.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, false, ) }; let estimated_td_size = cmp::min( u8::try_from( - div_round_up(buf.len(), max_transfer_size as usize) * mem::size_of::(), + div_round_up(dma_buf.map(|buf| buf.len()).unwrap_or(0), max_transfer_size as usize) * mem::size_of::(), ) .ok() .unwrap_or(0x1F), @@ -879,7 +873,7 @@ impl Xhci { let stream_id = 1u16; - let mut bytes_left = buf.len(); + let mut bytes_left = dma_buf.map(|buf| buf.len()).unwrap_or(0); let event = self.execute_transfer( port_num, @@ -918,162 +912,120 @@ impl Xhci { ).await?; self.event_handler_finished(); - let bytes_transferred = buf.len() as u32 - event.transfer_length(); - - if let DeviceReqData::In(dbuf) = &mut buf { - dbuf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); - } + let bytes_transferred = dma_buf.map(|buf| buf.len() as u32 - event.transfer_length()).unwrap_or(0); Ok((event.completion_code(), bytes_transferred)) } - pub(crate) fn get_dev_desc(&mut self, port_id: usize) -> Result { - let st = self - .port_states - .get_mut(&port_id) - .ok_or(Error::new(ENOENT))?; - let ports = self.ports.lock().unwrap(); - let run = self.run.lock().unwrap(); - let cmd = self.cmd.lock().unwrap(); - let dbs = self.dbs.lock().unwrap(); - - Self::get_dev_desc_raw( - &mut *ports, - &mut *run, - &mut *cmd, - &mut *dbs, - port_id, - st.slot, - st.endpoint_states - .get_mut(&0) - .ok_or(Error::new(EIO))? - .ring() - .ok_or(Error::new(EIO))?, - ) - } - pub(crate) fn get_dev_desc_raw( - ports: &mut [port::Port], - run: &mut RuntimeRegs, - cmd: &mut Ring, - dbs: &mut [Doorbell], + pub async fn get_desc( + &self, port_id: usize, slot: u8, ring: &mut Ring, ) -> Result { - let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; + let port = self.ports.lock().unwrap().get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); } - // TODO: Should the descriptors be stored in PortState? - - run.ints[0].erdp.write(cmd.register() | (1 << 3)); - - let mut dev = Device { - ring, - cmd, - db: &mut dbs[slot as usize], - int: &mut run.ints[0], - }; - - let raw_dd = dev.get_device()?; + let raw_dd = self.fetch_dev_desc(port_id, slot, ring).await?; let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { - Some(dev.get_string(raw_dd.manufacturer_str)?) + Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.manufacturer_str).await?) } else { None }, if raw_dd.product_str > 0 { - Some(dev.get_string(raw_dd.product_str)?) + Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.product_str).await?) } else { None }, if raw_dd.serial_str > 0 { - Some(dev.get_string(raw_dd.serial_str)?) + Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.serial_str).await?) } else { None }, ); - let (bos_desc, bos_data) = dev.get_bos()?; + let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot, ring).await?; let supports_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); let supports_superspeedplus = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus()); - let config_descs = (0..raw_dd.configurations) - .map(|index| -> Result<_> { - let (desc, data) = dev.get_config(index)?; + let mut config_descs = SmallVec::new(); - let extra_length = desc.total_length as usize - mem::size_of_val(&desc); - let data = &data[..extra_length]; + for index in 0..raw_dd.configurations { + let (desc, data) = self.fetch_config_desc(port_id, slot, ring, index).await?; - let mut i = 0; - let mut descriptors = Vec::new(); + let extra_length = desc.total_length as usize - mem::size_of_val(&desc); + let data = &data[..extra_length]; - while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) { - descriptors.push(descriptor); - i += len; - } + let mut i = 0; + let mut descriptors = Vec::new(); - let mut interface_descs = SmallVec::new(); - let mut iter = descriptors.into_iter(); + while let Some((descriptor, len)) = AnyDescriptor::parse(&data[i..]) { + descriptors.push(descriptor); + i += len; + } - while let Some(item) = iter.next() { - if let AnyDescriptor::Interface(idesc) = item { - let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); - let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); + let mut interface_descs = SmallVec::new(); + let mut iter = descriptors.into_iter(); - for _ in 0..idesc.endpoints { + while let Some(item) = iter.next() { + if let AnyDescriptor::Interface(idesc) = item { + let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); + let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); + + for _ in 0..idesc.endpoints { + let next = match iter.next() { + Some(AnyDescriptor::Endpoint(n)) => n, + Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { + hid_descs.push(h.into()); + break; + } + _ => break, + }; + let mut endp = EndpDesc::from(next); + + if supports_superspeed { let next = match iter.next() { - Some(AnyDescriptor::Endpoint(n)) => n, - Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { - hid_descs.push(h.into()); - break; - } + Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, _ => break, }; - let mut endp = EndpDesc::from(next); + endp.ssc = Some(SuperSpeedCmp::from(next)); - if supports_superspeed { + if endp.has_ssp_companion() && supports_superspeedplus { let next = match iter.next() { - Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, + Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => n, _ => break, }; - endp.ssc = Some(SuperSpeedCmp::from(next)); - - if endp.has_ssp_companion() && supports_superspeedplus { - let next = match iter.next() { - Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => n, - _ => break, - }; - endp.sspc = Some(SuperSpeedPlusIsochCmp::from(next)); - } + endp.sspc = Some(SuperSpeedPlusIsochCmp::from(next)); } - endpoints.push(endp); } - - interface_descs.push(IfDesc::new(&mut dev, idesc, endpoints, hid_descs)?); - } else { - // TODO - break; + endpoints.push(endp); } - } - Ok(ConfDesc { - kind: desc.kind, - configuration: if desc.configuration_str > 0 { - Some(dev.get_string(desc.configuration_str)?) - } else { - None - }, - configuration_value: desc.configuration_value, - attributes: desc.attributes, - max_power: desc.max_power, - interface_descs, - }) - }) - .collect::>>()?; + interface_descs.push(self.new_if_desc(port_id, slot, ring, idesc, endpoints, hid_descs).await?); + } else { + // TODO + break; + } + } + + config_descs.push(ConfDesc { + kind: desc.kind, + configuration: if desc.configuration_str > 0 { + Some(self.fetch_string_desc(port_id, slot, ring, desc.configuration_str).await?) + } else { + None + }, + configuration_value: desc.configuration_value, + attributes: desc.attributes, + max_power: desc.max_power, + interface_descs, + }); + }; Ok(DevDesc { kind: raw_dd.kind, @@ -1108,7 +1060,7 @@ impl Xhci { bytes_to_read } - fn port_req_transfer( + async fn port_req_transfer( &mut self, port_num: usize, data_buffer: Option<&mut Dma<[u8]>>, @@ -1129,7 +1081,7 @@ impl Xhci { ); ControlFlow::Break }, - )?; + ).await?; Ok(()) } fn port_req_init_st(&mut self, port_num: usize, req: &PortReq) -> Result { @@ -1169,7 +1121,7 @@ impl Xhci { // FIXME: Make sure there aren't any other PortReq handles, perhaps by storing the state in // PortState? } - fn handle_port_req_write( + async fn handle_port_req_write( &mut self, fd: usize, port_num: usize, @@ -1184,7 +1136,7 @@ impl Xhci { if let PortReqState::TmpSetup(setup) = st { // No need for any additional reads or writes, before completing. - self.port_req_transfer(port_num, None, setup, TransferKind::NoData)?; + self.port_req_transfer(port_num, None, setup, TransferKind::NoData).await?; st = PortReqState::Init; } @@ -1196,7 +1148,7 @@ impl Xhci { } dma_buffer.copy_from_slice(buf); - self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::Out)?; + self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::Out).await?; st = PortReqState::Init; buf.len() @@ -1211,7 +1163,7 @@ impl Xhci { } Ok(bytes_written) } - fn handle_port_req_read( + async fn handle_port_req_read( &mut self, fd: usize, port_num: usize, @@ -1223,7 +1175,7 @@ impl Xhci { if buf.len() != dma_buffer.len() { return Err(Error::new(EINVAL)); } - self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::In)?; + self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::In).await?; buf.copy_from_slice(&dma_buffer); st = PortReqState::Init; @@ -1413,8 +1365,7 @@ impl SchemeMut for Xhci { _ => return Err(Error::new(ENOENT)), }; - let fd = self.next_handle; - self.next_handle += 1; + let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed); self.handles.insert(fd, handle); Ok(fd) @@ -1545,7 +1496,7 @@ impl SchemeMut for Xhci { &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { EndpointHandleTy::Ctl => self.on_read_endp_ctl(port_num, endp_num, buf), - EndpointHandleTy::Data => self.on_read_endp_data(port_num, endp_num, buf), + EndpointHandleTy::Data => block_on(self.on_read_endp_data(port_num, endp_num, buf)), EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), }, &mut Handle::PortState(port_num, ref mut offset) => { @@ -1574,7 +1525,7 @@ impl SchemeMut for Xhci { } &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); - self.handle_port_req_read(fd, port_num, state, buf) + block_on(self.handle_port_req_read(fd, port_num, state, buf)) } } } @@ -1582,17 +1533,17 @@ impl SchemeMut for Xhci { let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { &mut Handle::ConfigureEndpoints(port_num) => { - self.configure_endpoints(port_num, buf)?; + block_on(self.configure_endpoints(port_num, buf))?; Ok(buf.len()) } &mut Handle::Endpoint(port_num, endp_num, ref ep_file_ty) => match ep_file_ty { - EndpointHandleTy::Ctl => self.on_write_endp_ctl(port_num, endp_num, buf), - EndpointHandleTy::Data => self.on_write_endp_data(port_num, endp_num, buf), + EndpointHandleTy::Ctl => block_on(self.on_write_endp_ctl(port_num, endp_num, buf)), + EndpointHandleTy::Data => block_on(self.on_write_endp_data(port_num, endp_num, buf)), EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), }, &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); - self.handle_port_req_write(fd, port_num, state, buf) + block_on(self.handle_port_req_write(fd, port_num, state, buf)) } // TODO: Introduce PortReqState::Waiting, which this write call changes to // PortReqState::ReadyToWrite when all bytes are written. @@ -1608,13 +1559,28 @@ impl SchemeMut for Xhci { } impl Xhci { pub fn get_endp_status(&mut self, port_num: usize, endp_num: u8) -> Result { - let slot = self + let port_state = self .port_states .get(&port_num) - .ok_or(Error::new(EBADFD))? - .slot; + .ok_or(Error::new(EBADFD))?; + + let slot = port_state.slot; + + let endp_desc = port_state + .dev_desc + .as_ref().unwrap() + .config_descs + .get(0) + .ok_or(Error::new(EIO))? + .interface_descs + .get(0) + .ok_or(Error::new(EIO))? + .endpoints + .get(endp_num as usize - 1) + .ok_or(Error::new(EBADFD))?; + let endp_num_xhc = if endp_num != 0 { - Self::endp_num_to_dci(endp_num, self.endp_desc(port_num, endp_num)?) + Self::endp_num_to_dci(endp_num, endp_desc) } else { 1 }; @@ -1664,7 +1630,7 @@ impl Xhci { index: 0, // TODO: interface num length: 0, }, - )?; + ).await?; } Ok(()) } @@ -1676,6 +1642,7 @@ impl Xhci { let endp_desc = port_state .dev_desc + .as_ref().unwrap() .config_descs .get(0) .ok_or(Error::new(EIO))? @@ -1727,6 +1694,7 @@ impl Xhci { .get(&port_num) .ok_or(Error::new(EIO))? .dev_desc + .as_ref().unwrap() .config_descs .first() .ok_or(Error::new(EIO))? @@ -1755,7 +1723,7 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let endp_desc = port_state.dev_desc.config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); let (event_trb, command_trb) = self.execute_command(|trb, cycle| { @@ -1806,7 +1774,7 @@ impl Xhci { // Yield the result directly because no bytes have to be sent or received // beforehand. let (completion_code, bytes_transferred) = - self.transfer(port_num, endp_num - 1, DeviceReqData::NoData).await?; + self.transfer(port_num, endp_num - 1, None, PortReqDirection::DeviceToHost).await?; if bytes_transferred > 0 { return Err(Error::new(EIO)); } @@ -1853,7 +1821,7 @@ impl Xhci { bytes_transferred, } } - pub fn on_write_endp_data( + pub async fn on_write_endp_data( &mut self, port_num: usize, endp_num: u8, @@ -1874,7 +1842,7 @@ impl Xhci { return Err(Error::new(EINVAL)); } let (completion_code, some_bytes_transferred) = - self.transfer_write(port_num, endp_num - 1, buf)?; + self.transfer_write(port_num, endp_num - 1, buf).await?; let result = Self::transfer_result(completion_code, some_bytes_transferred); // To avoid having to read from the Ctl interface file, the client should stop @@ -1937,7 +1905,7 @@ impl Xhci { serde_json::to_writer(&mut cursor, &res).or(Err(Error::new(EIO)))?; Ok(cursor.seek(io::SeekFrom::Current(0)).unwrap() as usize) } - pub fn on_read_endp_data( + pub async fn on_read_endp_data( &mut self, port_num: usize, endp_num: u8, @@ -1962,7 +1930,7 @@ impl Xhci { } let (completion_code, some_bytes_transferred) = - self.transfer_read(port_num, endp_num - 1, buf)?; + self.transfer_read(port_num, endp_num - 1, buf).await?; // Just as with on_write_endp_data, a client issuing multiple reads must always // stop reading if one read returns fewer bytes than expected. @@ -2001,7 +1969,7 @@ impl Xhci { self.run.lock().unwrap().ints[0].erdp.writef(1 << 3, true); } } -fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()> { +pub fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()> { if event_trb.completion_code() == TrbCompletionCode::Success as u8 { Ok(()) } else { @@ -2009,7 +1977,7 @@ fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<() Err(Error::new(EIO)) } } -fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb) -> Result<()> { +pub fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb) -> Result<()> { if event_trb.completion_code() == TrbCompletionCode::Success as u8 || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 { Ok(()) } else { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index c23f543a38..1a91800bbf 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -374,10 +374,10 @@ impl Trb { ); } - pub fn status(&mut self, input: bool, cycle: bool) { + pub fn status(&mut self, interrupter: u16, input: bool, ioc: bool, ch: bool, ent: bool, cycle: bool) { self.set( 0, - 0, + u32::from(interrupter) << 22, ((input as u32) << 16) | ((TrbType::StatusStage as u32) << 10) | (1 << 5) From 078a929bfcc1c6f5b641592d72a927c1327b5b40 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 11:56:56 +0100 Subject: [PATCH 0369/1301] Fix borrow checker errors, except SchemeMut::handle. --- xhcid/src/main.rs | 1 - xhcid/src/xhci/context.rs | 5 +- xhcid/src/xhci/irq_reactor.rs | 71 ++++++----- xhcid/src/xhci/mod.rs | 40 ++++--- xhcid/src/xhci/ring.rs | 5 +- xhcid/src/xhci/scheme.rs | 214 +++++++++++++++++++--------------- 6 files changed, 187 insertions(+), 149 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 4077bdb912..37de0739a4 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -233,7 +233,6 @@ fn main() { event_queue .add(socket_fd, move |_| -> io::Result> { let mut socket = socket_packet.lock().unwrap(); - let mut hci = hci; let mut todo = todo.lock().unwrap(); loop { diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 1093a6e250..45023397cc 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -175,12 +175,11 @@ pub struct ScratchpadBufferArray { pub pages: Vec, } impl ScratchpadBufferArray { - pub fn new(entries: u16) -> Result { + pub fn new(page_size: usize, entries: u16) -> Result { let mut entries = unsafe { Dma::zeroed_unsized(entries as usize)? }; let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result { - // TODO: Get the page size using fstatvfs on the `memory:` scheme. - let pointer = syscall::physalloc(4096)?; + let pointer = unsafe { syscall::physalloc(page_size)? }; assert_eq!(pointer & 0xFFFF_FFFF_FFFF_F000, pointer, "physically allocated pointer (physalloc) wasn't 4k page-aligned"); entry.set_addr(pointer as u64); Ok(pointer) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 977fa56584..7ab7b8f677 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -94,39 +94,44 @@ impl IrqReactor { states: Vec::new(), } } - // TODO: Configure the amount of time to be awaited when no more work can be done. + // TODO: Configure the amount of time wait when no more work can be done (for IRQ-less polling). fn pause(&self) { std::thread::yield_now(); } fn run_polling(mut self) { - loop { + let hci_clone = Arc::clone(&self.hci); + + 'event_loop: loop { self.handle_requests(); - let index = self.hci.primary_event_ring.lock().unwrap().ring.next_index(); + let mut event_ring_guard = hci_clone.primary_event_ring.lock().unwrap(); + + let index = event_ring_guard.ring.next_index(); let mut trb; 'busy_waiting: loop { - trb = self.hci.primary_event_ring.lock().unwrap().ring.trbs[index]; + trb = &event_ring_guard.ring.trbs[index]; if trb.completion_code() == TrbCompletionCode::Invalid as u8 { self.pause(); continue 'busy_waiting; } } - if self.check_event_ring_full(&trb) { continue } - self.acknowledge(trb); + if self.check_event_ring_full(trb.clone()) { continue 'event_loop } + + self.acknowledge(trb.clone()); self.update_erdp(); } } fn run_with_irq_file(mut self) { - let irq_file = self.irq_file.as_mut().expect("Calling IrqReactor::run_with_irq_file without the IRQ file being None"); + let hci_clone = Arc::clone(&self.hci); 'event_loop: loop { self.handle_requests(); let mut buffer = [0u8; 8]; - let bytes_read = irq_file.read(&mut buffer).expect("Failed to read from irq scheme"); + let bytes_read = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); if bytes_read < mem::size_of::() { panic!("wrong number of bytes read from `irq:`: expected {}, got {}", mem::size_of::(), bytes_read); } @@ -135,11 +140,11 @@ impl IrqReactor { continue; } - let _ = irq_file.write(&buffer); + let _ = self.irq_file.as_mut().unwrap().write(&buffer); // TODO: More event rings, probably even with different IRQs. - let event_ring = self.hci.primary_event_ring.lock().unwrap(); + let mut event_ring = hci_clone.primary_event_ring.lock().unwrap(); let mut count = 0; @@ -151,10 +156,10 @@ impl IrqReactor { continue 'event_loop; } else { count += 1 } - if self.check_event_ring_full(trb) { + if self.check_event_ring_full(trb.clone()) { continue 'trb_loop; } - self.acknowledge(*trb); + self.acknowledge(trb.clone()); trb.reserved(false); self.update_erdp(); @@ -196,7 +201,7 @@ impl IrqReactor { // TODO: Validate the command TRB. *state.message.lock().unwrap() = Some(NextEventTrb { src_trb: Some(command_trb.clone()), - event_trb: trb, + event_trb: trb.clone(), }); state.waker.wake(); @@ -215,7 +220,7 @@ impl IrqReactor { let state = self.states.remove(index); *state.message.lock().unwrap() = Some(NextEventTrb { src_trb: Some(src_trb), - event_trb: trb, + event_trb: trb.clone(), }); state.waker.wake(); } else if trb.transfer_event_trb_pointer().is_none() { @@ -266,7 +271,7 @@ impl IrqReactor { } let state = self.states.remove(index); *state.message.lock().unwrap() = Some(NextEventTrb { - event_trb: trb, + event_trb: trb.clone(), src_trb: None, }); state.waker.wake(); @@ -275,7 +280,7 @@ impl IrqReactor { /// Checks if an event TRB is a Host Controller Event, with the completion code Event Ring /// Full. If so, it grows the event ring. The return value is whether the event ring was full, /// and then grown. - fn check_event_ring_full(&mut self, event_trb: &Trb) -> bool { + fn check_event_ring_full(&mut self, event_trb: Trb) -> bool { let had_event_ring_full_error = event_trb.trb_type() == TrbType::HostController as u8 && event_trb.completion_code() == TrbCompletionCode::EventRingFull as u8; if had_event_ring_full_error { @@ -313,23 +318,27 @@ impl Future for EventTrbFuture { type Output = NextEventTrb; fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { - match self.get_mut() { - &mut Self::Pending { ref mut state, ref mut sender } => if let Some(message) = state.message.lock().unwrap().take() { - *self.get_mut() = Self::Finished; + let this = self.get_mut(); - task::Poll::Ready(message) - } else { - sender.send(State { - message: Arc::clone(&state.message), - is_isoch_or_vf: state.is_isoch_or_vf, - kind: state.state_kind, - waker: context.waker().clone(), - }).expect("IRQ reactor thread unexpectedly stopped"); + let message = match this { + &mut Self::Pending { ref state, ref sender } => match state.message.lock().unwrap().take() { + Some(message) => message, - task::Poll::Pending + None => { + sender.send(State { + message: Arc::clone(&state.message), + is_isoch_or_vf: state.is_isoch_or_vf, + kind: state.state_kind, + waker: context.waker().clone(), + }).expect("IRQ reactor thread unexpectedly stopped"); + + return task::Poll::Pending; + } } &mut Self::Finished => panic!("Polling finished EventTrbFuture again."), - } + }; + *this = Self::Finished; + task::Poll::Ready(message) } } @@ -353,8 +362,8 @@ impl Xhci { pub fn with_ring_mut T>(&self, id: RingId, function: F) -> Option { use super::RingOrStreams; - let slot_state = self.port_states.get(&(id.port as usize))?; - let endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?; + let mut slot_state = self.port_states.get_mut(&(id.port as usize))?; + let mut endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?; let ring_ref = match endpoint_state.transfer { RingOrStreams::Ring(ref mut ring) => ring, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index e2da2a887a..4cd98ae907 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -125,25 +125,25 @@ impl Xhci { Ok(()) } - async fn fetch_dev_desc(&mut self, port: usize, slot: u8, ring: &mut Ring) -> Result { + async fn fetch_dev_desc(&self, port: usize, slot: u8, ring: &mut Ring) -> Result { let mut desc = Dma::::zeroed()?; self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, ring, &mut desc).await?; Ok(*desc) } - async fn fetch_config_desc(&mut self, port: usize, slot: u8, ring: &mut Ring, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { + async fn fetch_config_desc(&self, port: usize, slot: u8, ring: &mut Ring, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, ring, &mut desc).await?; Ok(*desc) } - async fn fetch_bos_desc(&mut self, port: usize, slot: u8, ring: &mut Ring) -> Result<(usb::BosDescriptor, [u8; 4087])> { + async fn fetch_bos_desc(&self, port: usize, slot: u8, ring: &mut Ring) -> Result<(usb::BosDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?; self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, ring, &mut desc).await?; Ok(*desc) } - async fn fetch_string_desc(&mut self, port: usize, slot: u8, ring: &mut Ring, index: u8) -> Result { + async fn fetch_string_desc(&self, port: usize, slot: u8, ring: &mut Ring, index: u8) -> Result { let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, ring, &mut sdesc).await?; @@ -407,14 +407,14 @@ impl Xhci { if buf_count == 0 { return Ok(()); } - let scratchpad_buf_arr = ScratchpadBufferArray::new(buf_count)?; + let scratchpad_buf_arr = ScratchpadBufferArray::new(self.page_size,buf_count)?; self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; self.scratchpad_buf_arr = Some(scratchpad_buf_arr); Ok(()) } - pub async fn enable_port_slot(&mut self, slot_ty: u8) -> Result { + pub async fn enable_port_slot(&self, slot_ty: u8) -> Result { assert_eq!(slot_ty & 0x1F, slot_ty); let (event_trb, command_trb) = @@ -425,7 +425,7 @@ impl Xhci { Ok(event_trb.event_slot()) } - pub async fn disable_port_slot(&mut self, slot: u8) -> Result<()> { + pub async fn disable_port_slot(&self, slot: u8) -> Result<()> { let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)).await; self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb); @@ -485,9 +485,18 @@ impl Xhci { .collect::>(), }; - let dev_desc = self.get_desc(i, slot, &mut ring).await?; + let ring = port_state.endpoint_states.get_mut(&0).unwrap().ring().unwrap(); + + let dev_desc = self.get_desc(i, slot, ring).await?; port_state.dev_desc = Some(dev_desc); - self.update_default_control_pipe(&mut input, slot, &dev_desc).await?; + + + { + let mut input = port_state.input_context.lock().unwrap(); + let dev_desc = port_state.dev_desc.as_ref().unwrap(); + + self.update_default_control_pipe(&mut *input, slot, dev_desc).await?; + } /*match self.spawn_drivers(i, &mut port_state) { Ok(()) => (), @@ -502,7 +511,7 @@ impl Xhci { } pub async fn update_default_control_pipe( - &mut self, + &self, input_context: &mut Dma, slot_id: u8, dev_desc: &DevDesc, @@ -644,7 +653,7 @@ impl Xhci { _ => None, } } - pub fn msix_info_mut(&mut self) -> Option> { + pub fn msix_info_mut(&self) -> Option> { match self.interrupt_method { InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), _ => None, @@ -653,15 +662,16 @@ impl Xhci { /// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always /// true when using MSI/MSI-X. - pub fn received_irq(&mut self) -> bool { - let runtime_regs = self.run.lock().unwrap(); + pub fn received_irq(&self) -> bool { + let mut runtime_regs = self.run.lock().unwrap(); if self.uses_msi() || self.uses_msix() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); println!("MSI-X PB={}", self.msix_info_mut().unwrap().pba(0)); - let entry = self.msix_info_mut().unwrap().table_entry_pointer(0); + let mut msix = self.msix_info_mut().unwrap(); + let entry = msix.table_entry_pointer(0); println!("MSI-X entry (addr_lo, addr_hi, msg_data, vec_ctl: {:#0x} {:#0x} {:#0x} {:#0x}", entry.addr_lo.read(), entry.addr_hi.read(), entry.msg_data.read(), entry.vec_ctl.read()); true } else if runtime_regs.ints[0].iman.readf(1) { @@ -677,7 +687,7 @@ impl Xhci { } } - fn spawn_drivers(&mut self, port: usize, ps: &mut PortState) -> Result<()> { + fn spawn_drivers(&self, port: usize, ps: &mut PortState) -> Result<()> { // TODO: There should probably be a way to select alternate interfaces, and not just the // first one. // TODO: Now that there are some good error crates, I don't think errno.h error codes are diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index 2e067efce3..f6e6ee0696 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -82,8 +82,9 @@ impl Ring { pub fn phys_addr_to_entry_ref(&self, paddr: u64) -> Option<&Trb> { Some(&self.trbs[self.phys_addr_to_index(paddr)?]) } - pub fn phys_addr_to_entry_mut(&self, paddr: u64) -> Option<&mut Trb> { - Some(&mut self.trbs[self.phys_addr_to_index(paddr)?]) + pub fn phys_addr_to_entry_mut(&mut self, paddr: u64) -> Option<&mut Trb> { + let index = self.phys_addr_to_index(paddr)?; + Some(&mut self.trbs[index]) } pub fn phys_addr_to_entry(&self, paddr: u64) -> Option { Some(self.trbs[self.phys_addr_to_index(paddr)?].clone()) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 3ecc690cae..28a6fd2b9d 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -214,7 +214,7 @@ impl Xhci { }) } pub fn execute_command_noreply(&self, f: F) { - let command_ring = self.cmd.lock().unwrap(); + let mut command_ring = self.cmd.lock().unwrap(); let (cmd, cycle) = command_ring.next(); f(cmd, cycle); @@ -229,7 +229,7 @@ impl Xhci { f: F, ) -> (Trb, Trb) { let next_event = { - let command_ring = self.cmd.lock().unwrap(); + let mut command_ring = self.cmd.lock().unwrap(); let (cmd, cycle) = command_ring.next(); f(cmd, cycle); @@ -249,7 +249,7 @@ impl Xhci { (event_trb, command_trb) } pub async fn execute_control_transfer( - &mut self, + &self, port_num: usize, setup: usb::Setup, tk: TransferKind, @@ -259,11 +259,11 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { - let port_state = self.port_state(port_num)?; + let mut port_state = self.port_state_mut(port_num)?; let slot = port_state.slot; let future = { - let endpoint_state = port_state + let mut endpoint_state = port_state .endpoint_states .get_mut(&0).ok_or(Error::new(EIO))?; @@ -322,16 +322,16 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { - let port_state = self.port_state_mut(port_num)?; + let mut port_state = self.port_state_mut(port_num)?; let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { (Some(c), Some(i)) => (c, i), _ => return Err(Error::new(EIO)), }; - let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; let slot = port_state.slot; + let endp_state = port_state .endpoint_states .get_mut(&endp_num) @@ -362,6 +362,8 @@ impl Xhci { } }; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + self.dbs.lock().unwrap()[usize::from(slot)].write(Self::endp_doorbell( endp_num, endp_desc, @@ -389,7 +391,7 @@ impl Xhci { Ok(event_trb) } - async fn device_req_no_data(&mut self, port: usize, req: usb::Setup) -> Result<()> { + async fn device_req_no_data(&self, port: usize, req: usb::Setup) -> Result<()> { self.execute_control_transfer( port, req, @@ -399,11 +401,11 @@ impl Xhci { ).await?; Ok(()) } - async fn set_configuration(&mut self, port: usize, config: u8) -> Result<()> { + async fn set_configuration(&self, port: usize, config: u8) -> Result<()> { self.device_req_no_data(port, usb::Setup::set_configuration(config)).await } async fn set_interface( - &mut self, + &self, port: usize, interface_num: u8, alternate_setting: u8, @@ -414,7 +416,7 @@ impl Xhci { ).await } - async fn reset_endpoint(&mut self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { + async fn reset_endpoint(&self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { @@ -519,7 +521,7 @@ impl Xhci { fn port_state_mut(&self, port: usize) -> Result> { self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) } - async fn configure_endpoints(&mut self, port: usize, json_buf: &[u8]) -> Result<()> { + async fn configure_endpoints(&self, port: usize, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; @@ -539,7 +541,7 @@ impl Xhci { let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; let config_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; - let endpoints = config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; + let endpoints = &config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; if endpoints.len() >= 31 { return Err(Error::new(EIO)); @@ -564,7 +566,7 @@ impl Xhci { { let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let input_context = port_state.input_context.lock().unwrap(); + let mut input_context = port_state.input_context.lock().unwrap(); // Configure the slot context as well, which holds the last index of the endp descs. input_context.add_context.write(1); @@ -650,7 +652,7 @@ impl Xhci { assert_eq!(max_error_count & 0x3, max_error_count); assert_ne!(ep_ty, 0); // 0 means invalid. - let port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; + let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; let ring_ptr = if usb_log_max_streams.is_some() { let mut array = StreamContextArray::new(1 << (primary_streams + 1))?; @@ -694,7 +696,7 @@ impl Xhci { assert_eq!(primary_streams & 0x1F, primary_streams); let port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; - let input_context = port_state.input_context.lock().unwrap(); + let mut input_context = port_state.input_context.lock().unwrap(); input_context.add_context.writef(1 << endp_num_xhc, true); let endp_ctx = input_context.device.endpoints.get_mut(endp_num_xhc as usize - 1).ok_or(Error::new(EIO))?; @@ -745,7 +747,7 @@ impl Xhci { Ok(()) } async fn transfer_read( - &mut self, + &self, port_num: usize, endp_idx: u8, buf: &mut [u8], @@ -755,29 +757,30 @@ impl Xhci { } let dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(buf.len())? }; - let (completion_code, bytes_transferred) = self.transfer( + let (completion_code, bytes_transferred, dma_buffer) = self.transfer( port_num, endp_idx, Some(dma_buffer), PortReqDirection::DeviceToHost, ).await?; - buf.copy_from_slice(&*dma_buffer.as_ref()); + buf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); Ok((completion_code, bytes_transferred)) } - async fn transfer_write(&mut self, port_num: usize, endp_idx: u8, sbuf: &[u8]) -> Result<(u8, u32)> { + async fn transfer_write(&self, port_num: usize, endp_idx: u8, sbuf: &[u8]) -> Result<(u8, u32)> { if sbuf.is_empty() { return Err(Error::new(EINVAL)); } let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; dma_buffer.copy_from_slice(sbuf); - self.transfer( + let (completion_code, bytes_transferred, _) = self.transfer( port_num, endp_idx, Some(dma_buffer), PortReqDirection::HostToDevice, - ).await + ).await?; + Ok((completion_code, bytes_transferred)) } pub const fn def_control_endp_doorbell() -> u32 { 1 @@ -810,7 +813,7 @@ impl Xhci { endp_idx: u8, dma_buf: Option>, direction: PortReqDirection, - ) -> Result<(u8, u32)> { + ) -> Result<(u8, u32, Option>)> { // TODO: Check that only readable enpoints are read, etc. let endp_num = endp_idx + 1; @@ -847,8 +850,8 @@ impl Xhci { let (buffer, idt, estimated_td_size) = { let (buffer, idt) = - if dma_buf.map(|buf| buf.len()).unwrap_or(0) <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { - dma_buf.map(|sbuf| { + if dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0) <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { + dma_buf.as_ref().map(|sbuf| { let mut bytes = [0u8; 8]; bytes[..sbuf.len()].copy_from_slice(&sbuf); (u64::from_le_bytes(bytes), true) @@ -862,7 +865,7 @@ impl Xhci { }; let estimated_td_size = cmp::min( u8::try_from( - div_round_up(dma_buf.map(|buf| buf.len()).unwrap_or(0), max_transfer_size as usize) * mem::size_of::(), + div_round_up(dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0), max_transfer_size as usize) * mem::size_of::(), ) .ok() .unwrap_or(0x1F), @@ -873,7 +876,7 @@ impl Xhci { let stream_id = 1u16; - let mut bytes_left = dma_buf.map(|buf| buf.len()).unwrap_or(0); + let mut bytes_left = dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0); let event = self.execute_transfer( port_num, @@ -912,9 +915,9 @@ impl Xhci { ).await?; self.event_handler_finished(); - let bytes_transferred = dma_buf.map(|buf| buf.len() as u32 - event.transfer_length()).unwrap_or(0); + let bytes_transferred = dma_buf.as_ref().map(|buf| buf.len() as u32 - event.transfer_length()).unwrap_or(0); - Ok((event.completion_code(), bytes_transferred)) + Ok((event.completion_code(), bytes_transferred, dma_buf)) } pub async fn get_desc( &self, @@ -922,7 +925,8 @@ impl Xhci { slot: u8, ring: &mut Ring, ) -> Result { - let port = self.ports.lock().unwrap().get(port_id).ok_or(Error::new(ENOENT))?; + let ports = self.ports.lock().unwrap(); + let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); } @@ -1043,7 +1047,7 @@ impl Xhci { config_descs, }) } - fn port_desc_json(&mut self, port_id: usize) -> Result> { + fn port_desc_json(&self, port_id: usize) -> Result> { let dev_desc = &self .port_states .get(&port_id) @@ -1061,7 +1065,7 @@ impl Xhci { bytes_to_read } async fn port_req_transfer( - &mut self, + &self, port_num: usize, data_buffer: Option<&mut Dma<[u8]>>, setup: usb::Setup, @@ -1084,7 +1088,7 @@ impl Xhci { ).await?; Ok(()) } - fn port_req_init_st(&mut self, port_num: usize, req: &PortReq) -> Result { + fn port_req_init_st(&self, port_num: usize, req: &PortReq) -> Result { use usb::setup::*; let direction = ReqDirection::from(req.direction); @@ -1122,7 +1126,7 @@ impl Xhci { // PortState? } async fn handle_port_req_write( - &mut self, + &self, fd: usize, port_num: usize, mut st: PortReqState, @@ -1156,7 +1160,7 @@ impl Xhci { PortReqState::WaitingForDeviceBytes(_, _) => return Err(Error::new(EBADF)), PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), }; - let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { Handle::PortReq(_, ref mut state) => *state = st, _ => unreachable!(), @@ -1164,7 +1168,7 @@ impl Xhci { Ok(bytes_written) } async fn handle_port_req_read( - &mut self, + &self, fd: usize, port_num: usize, mut st: PortReqState, @@ -1188,7 +1192,7 @@ impl Xhci { PortReqState::Tmp | PortReqState::TmpSetup(_) => unreachable!(), }; - let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { Handle::PortReq(_, ref mut state) => *state = st, _ => unreachable!(), @@ -1372,7 +1376,7 @@ impl SchemeMut for Xhci { } fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { - let guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; match &*guard { &Handle::TopLevel(_, ref buf) @@ -1409,7 +1413,7 @@ impl SchemeMut for Xhci { } fn fpath(&mut self, fd: usize, buffer: &mut [u8]) -> Result { - let cursor = io::Cursor::new(buffer); + let mut cursor = io::Cursor::new(buffer); let guard = self.handles.get(&fd).ok_or(Error::new(EBADF))?; match &*guard { @@ -1423,15 +1427,15 @@ impl SchemeMut for Xhci { &Handle::Endpoints(port_num, _, _) => { write!(cursor, "/port{}/endpoints/", port_num).unwrap() } - &Handle::Endpoint(port_num, endp_num, st) => write!( + &Handle::Endpoint(port_num, endp_num, ref st) => write!( cursor, "/port{}/endpoints/{}/{}", port_num, endp_num, match st { - EndpointHandleTy::Root(_, _) => "", - EndpointHandleTy::Ctl => "ctl", - EndpointHandleTy::Data => "data", + &EndpointHandleTy::Root(_, _) => "", + &EndpointHandleTy::Ctl => "ctl", + &EndpointHandleTy::Data => "data", } ) .unwrap(), @@ -1444,7 +1448,7 @@ impl SchemeMut for Xhci { } fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { - let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { // Directories, or fixed files Handle::TopLevel(ref mut offset, ref buf) @@ -1477,7 +1481,7 @@ impl SchemeMut for Xhci { } fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { - let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) @@ -1530,7 +1534,8 @@ impl SchemeMut for Xhci { } } fn write(&mut self, fd: usize, buf: &[u8]) -> Result { - let guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + match &mut *guard { &mut Handle::ConfigureEndpoints(port_num) => { block_on(self.configure_endpoints(port_num, buf))?; @@ -1558,7 +1563,7 @@ impl SchemeMut for Xhci { } } impl Xhci { - pub fn get_endp_status(&mut self, port_num: usize, endp_num: u8) -> Result { + pub fn get_endp_status(&self, port_num: usize, endp_num: u8) -> Result { let port_state = self .port_states .get(&port_num) @@ -1607,7 +1612,7 @@ impl Xhci { }) } pub async fn on_req_reset_device( - &mut self, + &self, port_num: usize, endp_num: u8, clear_feature: bool, @@ -1635,10 +1640,28 @@ impl Xhci { Ok(()) } pub async fn restart_endpoint(&self, port_num: usize, endp_num: u8) -> Result<()> { - let port_state = self + let mut port_state = self .port_states .get_mut(&port_num) .ok_or(Error::new(EBADFD))?; + let slot = port_state.slot; + + let mut endpoint_state = port_state + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADFD))?; + + let (has_streams, ring) = match &mut endpoint_state.transfer { + &mut super::RingOrStreams::Ring(ref mut ring) => (false, ring), + &mut super::RingOrStreams::Streams(ref mut arr) => { + (true, arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?) + } + }; + + let (cmd, cycle) = ring.next(); + cmd.transfer_no_op(0, false, false, false, cycle); + + let deque_ptr_and_cycle = ring.register(); let endp_desc = port_state .dev_desc @@ -1653,39 +1676,22 @@ impl Xhci { .get(endp_num as usize - 1) .ok_or(Error::new(EBADFD))?; - let direction = if endp_num != 0 { - endp_desc.direction() + let doorbell = if endp_num != 0 { + let stream_id = 1u16; + + Self::endp_doorbell( + endp_num, + endp_desc, + if has_streams { stream_id } else { 0 }, + ) } else { - EndpDirection::Bidirectional + Self::def_control_endp_doorbell() }; - let endpoint_state = port_state - .endpoint_states - .get_mut(&endp_num) - .ok_or(Error::new(EBADFD))?; - - let (has_streams, ring) = match &mut endpoint_state.transfer { - &mut super::RingOrStreams::Ring(ref mut ring) => (false, ring), - &mut super::RingOrStreams::Streams(ref mut arr) => { - (true, arr.rings.get_mut(&1).ok_or(Error::new(EBADFD))?) - } - }; - let stream_id = 1u16; - let doorbell = Self::endp_doorbell( - endp_num, - endp_desc, - if has_streams { stream_id } else { 0 }, - ); - - let (cmd, cycle) = ring.next(); - cmd.transfer_no_op(0, false, false, false, cycle); - - let deque_ptr_and_cycle = ring.register(); - let slot = port_state.slot; + self.dbs.lock().unwrap()[slot as usize].write(doorbell); self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle).await?; - self.dbs.lock().unwrap()[slot as usize].write(doorbell); Ok(()) } pub fn endp_direction(&self, port_num: usize, endp_num: u8) -> Result { @@ -1741,19 +1747,22 @@ impl Xhci { handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb) } pub async fn on_write_endp_ctl( - &mut self, + &self, port_num: usize, endp_num: u8, buf: &[u8], ) -> Result { - let ep_if_state = &mut self + let mut port_state = self .port_states .get_mut(&port_num) - .ok_or(Error::new(EBADF))? + .ok_or(Error::new(EBADF))?; + + let ep_if_state = &mut port_state .endpoint_states .get_mut(&endp_num) .ok_or(Error::new(EBADF))? .driver_if_state; + let req = serde_json::from_slice::(buf).or(Err(Error::new(EBADMSG)))?; match req { XhciEndpCtlReq::Status => match ep_if_state { @@ -1773,16 +1782,18 @@ impl Xhci { if direction == XhciEndpCtlDirection::NoData { // Yield the result directly because no bytes have to be sent or received // beforehand. - let (completion_code, bytes_transferred) = + let (completion_code, bytes_transferred, _) = self.transfer(port_num, endp_num - 1, None, PortReqDirection::DeviceToHost).await?; if bytes_transferred > 0 { return Err(Error::new(EIO)); } let result = Self::transfer_result(completion_code, 0); - let new_state = &mut self + + let mut port_state = self .port_states .get_mut(&port_num) - .ok_or(Error::new(EBADF))? + .ok_or(Error::new(EBADF))?; + let new_state = &mut port_state .endpoint_states .get_mut(&endp_num) .ok_or(Error::new(EBADF))? @@ -1822,13 +1833,13 @@ impl Xhci { } } pub async fn on_write_endp_data( - &mut self, + &self, port_num: usize, endp_num: u8, buf: &[u8], ) -> Result { - let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; - let endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + let mut port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; + let mut endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; let ep_if_state = &mut endpoint_state.driver_if_state; @@ -1849,8 +1860,8 @@ impl Xhci { // invoking further data transfer calls if any single transfer returns fewer bytes // than requested. - let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; - let endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + let mut port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; + let mut endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; let ep_if_state = &mut endpoint_state.driver_if_state; if let &mut EndpIfState::WaitingForDataPipe { @@ -1873,15 +1884,17 @@ impl Xhci { } } pub fn on_read_endp_ctl( - &mut self, + &self, port_num: usize, endp_num: u8, buf: &mut [u8], ) -> Result { - let ep_if_state = &mut self + let port_state = &mut self .port_states .get_mut(&port_num) - .ok_or(Error::new(EBADF))? + .ok_or(Error::new(EBADF))?; + + let ep_if_state = &mut port_state .endpoint_states .get_mut(&endp_num) .ok_or(Error::new(EBADF))? @@ -1906,19 +1919,22 @@ impl Xhci { Ok(cursor.seek(io::SeekFrom::Current(0)).unwrap() as usize) } pub async fn on_read_endp_data( - &mut self, + &self, port_num: usize, endp_num: u8, buf: &mut [u8], ) -> Result { - let ep_if_state = &mut self + let mut port_state = self .port_states .get_mut(&port_num) - .ok_or(Error::new(EBADF))? + .ok_or(Error::new(EBADF))?; + + let mut ep_if_state = &mut port_state .endpoint_states .get_mut(&endp_num) .ok_or(Error::new(EBADF))? .driver_if_state; + match ep_if_state { &mut EndpIfState::WaitingForDataPipe { direction: XhciEndpCtlDirection::In, @@ -1937,14 +1953,18 @@ impl Xhci { let result = Self::transfer_result(completion_code, some_bytes_transferred); - let ep_if_state = &mut self + let mut port_state = self .port_states .get_mut(&port_num) - .ok_or(Error::new(EBADF))? + .ok_or(Error::new(EBADF))?; + + let mut ep_state = port_state .endpoint_states .get_mut(&endp_num) - .ok_or(Error::new(EBADF))? - .driver_if_state; + .ok_or(Error::new(EBADF))?; + + let ep_if_state = &mut ep_state.driver_if_state; + if let &mut EndpIfState::WaitingForDataPipe { direction: XhciEndpCtlDirection::In, bytes_to_transfer, From 9e34ed3fbf9140e40765d3f8d5da7ac445fe458a Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 12:03:48 +0100 Subject: [PATCH 0370/1301] It compiles! --- xhcid/src/main.rs | 2 +- xhcid/src/xhci/scheme.rs | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 37de0739a4..50ca1adccf 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -20,7 +20,7 @@ use std::env; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; -use syscall::scheme::SchemeMut; +use syscall::scheme::Scheme; use syscall::io::Io; use crate::xhci::{InterruptMethod, Xhci}; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 28a6fd2b9d..f605de6ee4 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; use syscall::io::{Dma, Io}; -use syscall::scheme::SchemeMut; +use syscall::scheme::Scheme; use syscall::{ Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, ENOTDIR, ENXIO, EOPNOTSUPP, EOVERFLOW, EPERM, EPROTO, ESPIPE, MODE_CHR, MODE_DIR, @@ -1201,8 +1201,8 @@ impl Xhci { } } -impl SchemeMut for Xhci { - fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { +impl Scheme for Xhci { + fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { if uid != 0 { return Err(Error::new(EACCES)); } @@ -1375,7 +1375,7 @@ impl SchemeMut for Xhci { Ok(fd) } - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { + fn fstat(&self, id: usize, stat: &mut Stat) -> Result { let mut guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; match &*guard { @@ -1412,7 +1412,7 @@ impl SchemeMut for Xhci { Ok(0) } - fn fpath(&mut self, fd: usize, buffer: &mut [u8]) -> Result { + fn fpath(&self, fd: usize, buffer: &mut [u8]) -> Result { let mut cursor = io::Cursor::new(buffer); let guard = self.handles.get(&fd).ok_or(Error::new(EBADF))?; @@ -1447,7 +1447,7 @@ impl SchemeMut for Xhci { Ok(src_len) } - fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { + fn seek(&self, fd: usize, pos: usize, whence: usize) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { // Directories, or fixed files @@ -1480,7 +1480,7 @@ impl SchemeMut for Xhci { } } - fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { + fn read(&self, fd: usize, buf: &mut [u8]) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { Handle::TopLevel(ref mut offset, ref src_buf) @@ -1533,7 +1533,7 @@ impl SchemeMut for Xhci { } } } - fn write(&mut self, fd: usize, buf: &[u8]) -> Result { + fn write(&self, fd: usize, buf: &[u8]) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; match &mut *guard { @@ -1555,7 +1555,7 @@ impl SchemeMut for Xhci { _ => return Err(Error::new(EBADF)), } } - fn close(&mut self, fd: usize) -> Result { + fn close(&self, fd: usize) -> Result { if self.handles.remove(&fd).is_none() { return Err(Error::new(EBADF)); } From e58245b280f66cff9e7863c29849ab244dc1ede2 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 12:30:32 +0100 Subject: [PATCH 0371/1301] Use an event queue in the IRQ reactor. --- xhcid/src/xhci/irq_reactor.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 7ab7b8f677..81299046a6 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -5,12 +5,16 @@ use std::io::prelude::*; use std::pin::Pin; use std::sync::{Arc, Mutex}; use std::sync::atomic::{self, AtomicUsize}; -use std::{mem, task, thread}; +use std::{io, mem, task, thread}; + +use std::os::unix::io::AsRawFd; use crossbeam_channel::{Sender, Receiver}; use futures::Stream; use syscall::Io; +use event::EventQueue; + use super::Xhci; use super::ring::Ring; use super::trb::{Trb, TrbCompletionCode, TrbType}; @@ -126,18 +130,26 @@ impl IrqReactor { } fn run_with_irq_file(mut self) { let hci_clone = Arc::clone(&self.hci); + let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); + let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); - 'event_loop: loop { - self.handle_requests(); + event_queue.add(irq_fd, move |_| -> io::Result> { let mut buffer = [0u8; 8]; + let bytes_read = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); + + self.handle_requests(); + if bytes_read < mem::size_of::() { - panic!("wrong number of bytes read from `irq:`: expected {}, got {}", mem::size_of::(), bytes_read); + // continue the loop when the next IRQ arrives + return Ok(None); } + if !self.hci.received_irq() { - continue; + // continue only when an IRQ to this device was received + return Ok(None); } let _ = self.irq_file.as_mut().unwrap().write(&buffer); @@ -153,18 +165,20 @@ impl IrqReactor { if trb.completion_code() == TrbCompletionCode::Invalid as u8 { if count == 0 { println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } - continue 'event_loop; + // no more events were found, continue the loop + return Ok(None); } else { count += 1 } if self.check_event_ring_full(trb.clone()) { - continue 'trb_loop; + return Ok(None); } self.acknowledge(trb.clone()); trb.reserved(false); self.update_erdp(); } - } + }).expect("xhcid: failed to catch irq events"); + event_queue.run().expect("xhcid: failed to run IRQ event queue"); } fn update_erdp(&self) { let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().erdp(); From ddf71d48e60d881de020dee8be6ef221b834f976 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 15:52:39 +0100 Subject: [PATCH 0372/1301] Get the Enable Slot cmd working, asynchronously! This is the first command that actually worked by calling the IRQ reactor and then getting a response. While this may not be that much on its own, it means the async/await model actually works in this context. Now the major problem is getting rid of all the deadlocks, and later remove block_on(future) in the Scheme impl, and instead go async with future spawning instead. --- xhcid/src/xhci/irq_reactor.rs | 51 ++++++++++++++++++++--------------- xhcid/src/xhci/mod.rs | 15 ++++++++--- xhcid/src/xhci/ring.rs | 4 ++- xhcid/src/xhci/scheme.rs | 12 ++++++--- 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 81299046a6..9371bc33c6 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -13,7 +13,7 @@ use crossbeam_channel::{Sender, Receiver}; use futures::Stream; use syscall::Io; -use event::EventQueue; +use event::{Event, EventQueue}; use super::Xhci; use super::ring::Ring; @@ -21,6 +21,7 @@ use super::trb::{Trb, TrbCompletionCode, TrbType}; /// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back /// by the future unless it completed). +#[derive(Debug)] pub struct State { waker: task::Waker, kind: StateKind, @@ -28,6 +29,7 @@ pub struct State { is_isoch_or_vf: bool, } +#[derive(Debug)] pub struct NextEventTrb { pub event_trb: Trb, pub src_trb: Option, @@ -103,11 +105,10 @@ impl IrqReactor { std::thread::yield_now(); } fn run_polling(mut self) { + println!("Running IRQ reactor in polling mode."); let hci_clone = Arc::clone(&self.hci); 'event_loop: loop { - self.handle_requests(); - let mut event_ring_guard = hci_clone.primary_event_ring.lock().unwrap(); let index = event_ring_guard.ring.next_index(); @@ -124,34 +125,32 @@ impl IrqReactor { } if self.check_event_ring_full(trb.clone()) { continue 'event_loop } + self.handle_requests(); self.acknowledge(trb.clone()); self.update_erdp(); } } fn run_with_irq_file(mut self) { + println!("Running IRQ reactor with IRQ file and event queue"); + let hci_clone = Arc::clone(&self.hci); let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); event_queue.add(irq_fd, move |_| -> io::Result> { - + println!("IRQ event queue notified"); let mut buffer = [0u8; 8]; - let bytes_read = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); - - self.handle_requests(); - - if bytes_read < mem::size_of::() { - // continue the loop when the next IRQ arrives - return Ok(None); - } - + let _ = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); if !self.hci.received_irq() { // continue only when an IRQ to this device was received + println!("no interrupt pending"); return Ok(None); } + println!("IRQ reactor received an IRQ"); + let _ = self.irq_file.as_mut().unwrap().write(&buffer); // TODO: More event rings, probably even with different IRQs. @@ -169,15 +168,22 @@ impl IrqReactor { return Ok(None); } else { count += 1 } + println!("Found event TRB: {:?}", trb); + if self.check_event_ring_full(trb.clone()) { + println!("Had to resize event TRB, retrying..."); + hci_clone.event_handler_finished(); return Ok(None); } + + self.handle_requests(); self.acknowledge(trb.clone()); trb.reserved(false); self.update_erdp(); } }).expect("xhcid: failed to catch irq events"); + //event_queue.trigger_all(Event { fd: 0, flags: 0 }).expect("irq reactor failed to trigger events"); event_queue.run().expect("xhcid: failed to run IRQ event queue"); } fn update_erdp(&self) { @@ -185,17 +191,22 @@ impl IrqReactor { let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); + println!("Updated ERDP to {:#0x}", dequeue_pointer); + self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); } fn handle_requests(&mut self) { - self.states.extend(self.receiver.try_iter()); + self.states.extend(self.receiver.try_iter().inspect(|req| println!("Received request: {:?}", req))); } fn acknowledge(&mut self, trb: Trb) { let mut index = 0; loop { + if index >= self.states.len() { return } + match self.states[index].kind { - StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => if trb.completion_trb_pointer() == Some(phys_ptr) { + StateKind::CommandCompletion { phys_ptr } if dbg!(trb.trb_type()) == TrbType::CommandCompletion as u8 => if dbg!(trb.completion_trb_pointer()) == Some(phys_ptr) { + println!("Found matching command completion future"); let state = self.states.remove(index); // Before waking, it's crucial that the command TRB that generated this event @@ -218,6 +229,7 @@ impl IrqReactor { event_trb: trb.clone(), }); + println!("Waking up future with waker: {:?}", state.waker); state.waker.wake(); } else if trb.completion_trb_pointer().is_none() { println!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); @@ -264,9 +276,6 @@ impl IrqReactor { _ => { index += 1; - if index >= self.states.len() { - break; - } continue; } } @@ -405,13 +414,11 @@ impl Xhci { sender: self.irq_reactor_sender.clone(), } } - pub fn next_command_completion_event_trb(&self, trb: &Trb) -> impl Future + Send + Sync + 'static { + pub fn next_command_completion_event_trb(&self, command_ring: &Ring, trb: &Trb) -> impl Future + Send + Sync + 'static { if ! trb.is_command_trb() { panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb) } - - let command_ring = self.cmd.lock().unwrap(); - + dbg!(command_ring.trbs.physical()); EventTrbFuture::Pending { state: FutureState { // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 4cd98ae907..b67e123832 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -356,7 +356,7 @@ impl Xhci { println!(" - Write ERSTZ: {}", erstz); int.erstsz.write(erstz); - let erdp = self.primary_event_ring.get_mut().unwrap().erdp() | (!1); + let erdp = self.primary_event_ring.get_mut().unwrap().erdp(); println!(" - Write ERDP: {:X}", erdp); int.erdp.write(erdp as u64 | (1 << 3)); @@ -368,7 +368,7 @@ impl Xhci { int.imod.write(0); println!(" - Enable interrupts"); - int.iman.writef(1 << 1, true); + int.iman.writef(1 << 1 | 1, true); } self.op.get_mut().unwrap().usb_cmd.writef(1 << 2, true); @@ -395,7 +395,7 @@ impl Xhci { println!(" - XHCI initialized"); if self.cap.cic() { - self.op.lock().unwrap().set_cie(true); + self.op.get_mut().unwrap().set_cie(true); } Ok(()) @@ -441,7 +441,9 @@ impl Xhci { pub async fn probe(&self) -> Result<()> { println!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); - for i in 0..self.ports.lock().unwrap().len() { + let port_count = { self.ports.lock().unwrap().len() }; + + for i in 0..port_count { let (data, state, speed, flags) = { let port = &self.ports.lock().unwrap()[i]; (port.read(), port.state(), port.speed(), port.flags()) @@ -460,6 +462,8 @@ impl Xhci { .supported_protocol(i as u8) .expect("Failed to find supported protocol information for port") .proto_slot_ty(); + + println!("Got slot type: {}", slot_ty); let slot = self.enable_port_slot(slot_ty).await?; println!(" - Slot {}", slot); @@ -843,7 +847,10 @@ pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { let receiver = hci.irq_reactor_receiver.clone(); let hci_clone = Arc::clone(&hci); + println!("About to start IRQ reactor"); + *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { + println!("Started IRQ reactor thread"); IrqReactor::new(hci_clone, receiver, irq_file).run() })); } diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index f6e6ee0696..67cafcf080 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -102,8 +102,10 @@ impl Ring { if (trb_virt_pointer as usize) < (trbs_base_virt_pointer as usize) || (trb_virt_pointer as usize) > (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::() { panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb); } + let trb_offset_from_base = trb_virt_pointer as u64 - trbs_base_virt_pointer as u64; + let trbs_base_phys_ptr = self.trbs.physical() as u64; - let trb_phys_ptr = trb_virt_pointer as u64 - trbs_base_phys_ptr; + let trb_phys_ptr = trbs_base_phys_ptr + trb_offset_from_base; trb_phys_ptr } /* diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index f605de6ee4..c21436677d 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -230,12 +230,16 @@ impl Xhci { ) -> (Trb, Trb) { let next_event = { let mut command_ring = self.cmd.lock().unwrap(); + let (cmd_index, cycle) = (command_ring.next_index(), command_ring.cycle); - let (cmd, cycle) = command_ring.next(); - f(cmd, cycle); + { + let command_trb = &mut command_ring.trbs[cmd_index]; + f(command_trb, cycle); + } // get the future here before awaiting, to destroy the lock before deadlock - self.next_command_completion_event_trb(&cmd) + let command_trb = &command_ring.trbs[cmd_index]; + self.next_command_completion_event_trb(&*command_ring, command_trb) }; self.dbs.lock().unwrap()[0].write(0); @@ -244,7 +248,7 @@ impl Xhci { let event_trb = trbs.event_trb; let command_trb = trbs.src_trb.expect("Command completion event TRBs shall always have a valid pointer to a valid source command TRB"); - assert_eq!(command_trb.trb_type(), TrbType::CommandCompletion as u8, "The IRQ reactor (or the xHC) gave an invalid event TRB"); + assert_eq!(event_trb.trb_type(), TrbType::CommandCompletion as u8, "The IRQ reactor (or the xHC) gave an invalid event TRB"); (event_trb, command_trb) } From f3d2d3e2d1a24a67509f6eb6845a19cb21773f5e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 28 Mar 2020 22:38:22 +0100 Subject: [PATCH 0373/1301] Fix the IRQ reactor when doing subsequent cmds. --- xhcid/src/xhci/irq_reactor.rs | 37 +++++++++++++++++++++++------------ xhcid/src/xhci/mod.rs | 5 ++++- xhcid/src/xhci/scheme.rs | 24 ++++++++++++----------- 3 files changed, 41 insertions(+), 25 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 9371bc33c6..61d7f548a7 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -18,6 +18,7 @@ use event::{Event, EventQueue}; use super::Xhci; use super::ring::Ring; use super::trb::{Trb, TrbCompletionCode, TrbType}; +use super::event::EventRing; /// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back /// by the future unless it completed). @@ -127,7 +128,8 @@ impl IrqReactor { self.handle_requests(); self.acknowledge(trb.clone()); - self.update_erdp(); + + self.update_erdp(&*event_ring_guard); } } fn run_with_irq_file(mut self) { @@ -137,6 +139,8 @@ impl IrqReactor { let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); + let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() }; + event_queue.add(irq_fd, move |_| -> io::Result> { println!("IRQ event queue notified"); let mut buffer = [0u8; 8]; @@ -160,34 +164,36 @@ impl IrqReactor { let mut count = 0; 'trb_loop: loop { - let trb = event_ring.next(); + let event_trb = &mut event_ring.ring.trbs[event_trb_index]; - if trb.completion_code() == TrbCompletionCode::Invalid as u8 { + if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { if count == 0 { println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } // no more events were found, continue the loop return Ok(None); } else { count += 1 } - println!("Found event TRB: {:?}", trb); + println!("Found event TRB: {:?}", event_trb); - if self.check_event_ring_full(trb.clone()) { + if self.check_event_ring_full(event_trb.clone()) { println!("Had to resize event TRB, retrying..."); hci_clone.event_handler_finished(); return Ok(None); } self.handle_requests(); - self.acknowledge(trb.clone()); - trb.reserved(false); + self.acknowledge(event_trb.clone()); - self.update_erdp(); + event_trb.reserved(false); + + self.update_erdp(&*event_ring); + + event_trb_index = event_ring.ring.next_index(); } }).expect("xhcid: failed to catch irq events"); - //event_queue.trigger_all(Event { fd: 0, flags: 0 }).expect("irq reactor failed to trigger events"); event_queue.run().expect("xhcid: failed to run IRQ event queue"); } - fn update_erdp(&self) { - let dequeue_pointer_and_dcs = self.hci.primary_event_ring.lock().unwrap().erdp(); + fn update_erdp(&self, event_ring: &EventRing) { + let dequeue_pointer_and_dcs = event_ring.erdp(); let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); @@ -202,7 +208,7 @@ impl IrqReactor { let mut index = 0; loop { - if index >= self.states.len() { return } + if index >= self.states.len() { break } match self.states[index].kind { StateKind::CommandCompletion { phys_ptr } if dbg!(trb.trb_type()) == TrbType::CommandCompletion as u8 => if dbg!(trb.completion_trb_pointer()) == Some(phys_ptr) { @@ -210,7 +216,7 @@ impl IrqReactor { let state = self.states.remove(index); // Before waking, it's crucial that the command TRB that generated this event - // be fetched before removing this event TRB from the queue. + // is fetched before removing this event TRB from the queue. let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(phys_ptr) { Some(command_trb) => { let t = command_trb.clone(); @@ -231,6 +237,8 @@ impl IrqReactor { println!("Waking up future with waker: {:?}", state.waker); state.waker.wake(); + + return; } else if trb.completion_trb_pointer().is_none() { println!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); continue; @@ -249,6 +257,7 @@ impl IrqReactor { event_trb: trb.clone(), }); state.waker.wake(); + return; } else if trb.transfer_event_trb_pointer().is_none() { // Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full. // @@ -272,6 +281,7 @@ impl IrqReactor { StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => { let state = self.states.remove(index); state.waker.wake(); + return; } _ => { @@ -280,6 +290,7 @@ impl IrqReactor { } } } + println!("Lost event TRB: {:?}", trb); } fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { let mut index = 0; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index b67e123832..b81f0b38bf 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -470,6 +470,7 @@ impl Xhci { let mut input = Dma::::zeroed()?; let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; + println!("Addressed device"); // TODO: Should the descriptors be cached in PortState, or refetched? @@ -538,7 +539,7 @@ impl Xhci { trb.evaluate_context(slot_id, input_context.physical(), false, cycle) }).await; - self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb); + self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; self.event_handler_finished(); Ok(()) @@ -633,9 +634,11 @@ impl Xhci { let input_context_physical = input_context.physical(); + println!("pre_address_device"); let (event_trb, _) = self.execute_command(|trb, cycle| { trb.address_device(slot, input_context_physical, false, cycle) }).await; + println!("post_address_device"); if event_trb.completion_code() != TrbCompletionCode::Success as u8 { println!("Failed to address device at slot {} (port {})", slot, i); diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c21436677d..c722986af7 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -213,17 +213,11 @@ impl Xhci { hid_descs: hid_descs.into_iter().collect(), }) } - pub fn execute_command_noreply(&self, f: F) { - let mut command_ring = self.cmd.lock().unwrap(); - - let (cmd, cycle) = command_ring.next(); - f(cmd, cycle); - - self.dbs.lock().unwrap()[0].write(0); - - // TODO: It's still possible not to reset the TRB, right? - } - + /// Pushes a command TRB to the command ring, rings the doorbell, and then awaits its Command + /// Completion Event. + /// + /// # Locking + /// This function will lock `Xhci::cmd` and `Xhci::dbs`. pub async fn execute_command( &self, f: F, @@ -242,7 +236,9 @@ impl Xhci { self.next_command_completion_event_trb(&*command_ring, command_trb) }; + println!("Ringing doorbell"); self.dbs.lock().unwrap()[0].write(0); + println!("Doorbell rung"); let trbs = next_event.await; let event_trb = trbs.event_trb; @@ -1988,7 +1984,13 @@ impl Xhci { _ => return Err(Error::new(EBADF)), } } + /// Notifies the xHC that the current event handler has finished, so that new interrupts can be + /// sent. This is required after each invocation of `Self::execute_command`. + /// + /// # Locking + /// This function locks `Xhci::run`. pub fn event_handler_finished(&self) { + println!("Event handler finished"); // write 1 to EHB to clear it self.run.lock().unwrap().ints[0].erdp.writef(1 << 3, true); } From 08616920d61a8a99107363d34895a0e395df6fcf Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 29 Mar 2020 13:49:57 +0200 Subject: [PATCH 0374/1301] Get descriptor fetching working. --- xhcid/src/xhci/irq_reactor.rs | 4 +-- xhcid/src/xhci/mod.rs | 51 ++++++++++++++++++++++------------- xhcid/src/xhci/scheme.rs | 41 +++++++++++++++++----------- xhcid/src/xhci/trb.rs | 6 +++-- 4 files changed, 65 insertions(+), 37 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 61d7f548a7..0abc6a2a9b 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -406,7 +406,7 @@ impl Xhci { Some(function(ring_ref)) } - pub fn next_transfer_event_trb(&self, ring_id: RingId, trb: &Trb) -> impl Future + Send + Sync + 'static { + pub fn next_transfer_event_trb(&self, ring_id: RingId, ring: &Ring, trb: &Trb) -> impl Future + Send + Sync + 'static { if ! trb.is_transfer_trb() { panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", trb.trb_type(), trb) } @@ -418,7 +418,7 @@ impl Xhci { is_isoch_or_vf, state_kind: StateKind::Transfer { ring_id, - phys_ptr: self.with_ring(ring_id, |ring| ring.trb_phys_ptr(trb)).unwrap(), + phys_ptr: ring.trb_phys_ptr(trb), }, message: Arc::new(Mutex::new(None)), }, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index b81f0b38bf..8e11e56781 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -12,7 +12,7 @@ use std::{mem, process, slice, sync::atomic, task, thread}; use chashmap::CHashMap; use crossbeam_channel::{Receiver, Sender}; use serde::Deserialize; -use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT}; +use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; use syscall::flag::O_RDONLY; use syscall::io::{Dma, Io}; @@ -93,10 +93,16 @@ impl MsixInfo { impl Xhci { /// Gets descriptors, before the port state is initiated. - async fn get_desc_raw(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, ring: &mut Ring, desc: &mut Dma) -> Result<()> { + async fn get_desc_raw(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, desc: &mut Dma) -> Result<()> { + println!("A"); let len = mem::size_of::(); let future = { + println!("B"); + let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; + let ring = port_state.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().expect("no ring for the default control pipe"); + println!("C"); + let (cmd, cycle) = ring.next(); cmd.setup( usb::Setup::get_descriptor(kind, index, 0, len as u16), @@ -107,45 +113,52 @@ impl Xhci { let (cmd, cycle) = ring.next(); cmd.data(desc.physical(), len as u16, true, cycle); - let (cmd, cycle) = ring.next(); + let last_index = ring.next_index(); + let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle); cmd.status(0, true, true, false, false, cycle); - self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &cmd) + println!("D"); + self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &ring, &ring.trbs[last_index]) }; + println!("E"); self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); + println!("F"); let trbs = future.await; let event_trb = trbs.event_trb; let status_trb = trbs.src_trb.unwrap(); + println!("G"); self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?; + println!("H"); self.event_handler_finished(); + println!("I"); Ok(()) } - async fn fetch_dev_desc(&self, port: usize, slot: u8, ring: &mut Ring) -> Result { + async fn fetch_dev_desc(&self, port: usize, slot: u8) -> Result { let mut desc = Dma::::zeroed()?; - self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, ring, &mut desc).await?; + self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?; Ok(*desc) } - async fn fetch_config_desc(&self, port: usize, slot: u8, ring: &mut Ring, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { + async fn fetch_config_desc(&self, port: usize, slot: u8, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, ring, &mut desc).await?; + self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, &mut desc).await?; Ok(*desc) } - async fn fetch_bos_desc(&self, port: usize, slot: u8, ring: &mut Ring) -> Result<(usb::BosDescriptor, [u8; 4087])> { + async fn fetch_bos_desc(&self, port: usize, slot: u8) -> Result<(usb::BosDescriptor, [u8; 4087])> { let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?; - self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, ring, &mut desc).await?; + self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc).await?; Ok(*desc) } - async fn fetch_string_desc(&self, port: usize, slot: u8, ring: &mut Ring, index: u8) -> Result { + async fn fetch_string_desc(&self, port: usize, slot: u8, index: u8) -> Result { let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; - self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, ring, &mut sdesc).await?; + self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, &mut sdesc).await?; let len = sdesc.0 as usize; if len > 2 { @@ -489,14 +502,16 @@ impl Xhci { )) .collect::>(), }; + self.port_states.insert(i, port_state); - let ring = port_state.endpoint_states.get_mut(&0).unwrap().ring().unwrap(); - - let dev_desc = self.get_desc(i, slot, ring).await?; - port_state.dev_desc = Some(dev_desc); - + println!("pre get desc"); + let dev_desc = self.get_desc(i, slot).await?; + println!("post get desc"); + self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc); { + let mut port_state = self.port_states.get_mut(&i).unwrap(); + let mut input = port_state.input_context.lock().unwrap(); let dev_desc = port_state.dev_desc.as_ref().unwrap(); @@ -508,7 +523,6 @@ impl Xhci { Err(err) => println!("Failed to spawn driver for port {}: `{}`", i, err), }*/ - self.port_states.insert(i, port_state); } } @@ -643,6 +657,7 @@ impl Xhci { if event_trb.completion_code() != TrbCompletionCode::Success as u8 { println!("Failed to address device at slot {} (port {})", slot, i); } + self.event_handler_finished(); Ok(ring) } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c722986af7..3709b18845 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -192,7 +192,6 @@ impl Xhci { &self, port_id: usize, slot: u8, - ring: &mut Ring, desc: usb::InterfaceDescriptor, endps: impl IntoIterator, hid_descs: impl IntoIterator, @@ -201,7 +200,7 @@ impl Xhci { alternate_setting: desc.alternate_setting, class: desc.class, interface_str: if desc.interface_str > 0 { - Some(self.fetch_string_desc(port_id, slot, ring, desc.interface_str).await?) + Some(self.fetch_string_desc(port_id, slot, desc.interface_str).await?) } else { None }, @@ -284,7 +283,8 @@ impl Xhci { } } - let (cmd, cycle) = ring.next(); + let last_index = ring.next_index(); + let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle); let interrupter = 0; let ioc = true; @@ -292,7 +292,7 @@ impl Xhci { let ent = false; cmd.status(interrupter, tk == TransferKind::In, ioc, ch, ent, cycle); - self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), cmd) + self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), ring, &ring.trbs[last_index]) }; self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); @@ -352,11 +352,12 @@ impl Xhci { }; let future = loop { - let (trb, cycle) = ring.next(); + let last_index = ring.next_index(); + let (trb, cycle) = (&mut ring.trbs[last_index], ring.cycle); match d(trb, cycle) { ControlFlow::Break => { - break self.next_transfer_event_trb(super::irq_reactor::RingId { port: port_num as u8, endpoint_num: endp_num, stream_id }, &trb); + break self.next_transfer_event_trb(super::irq_reactor::RingId { port: port_num as u8, endpoint_num: endp_num, stream_id }, ring, &ring.trbs[last_index]); } ControlFlow::Continue => continue, } @@ -923,35 +924,43 @@ impl Xhci { &self, port_id: usize, slot: u8, - ring: &mut Ring, ) -> Result { + println!("Checkpoint 1"); let ports = self.ports.lock().unwrap(); let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); } - let raw_dd = self.fetch_dev_desc(port_id, slot, ring).await?; + println!("Checkpoint 2"); + let raw_dd = self.fetch_dev_desc(port_id, slot).await?; + println!("Checkpoint 3"); let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { - Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.manufacturer_str).await?) + println!("Checkpoint 4a"); + Some(self.fetch_string_desc(port_id, slot, raw_dd.manufacturer_str).await?) } else { None }, if raw_dd.product_str > 0 { - Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.product_str).await?) + println!("Checkpoint 4b"); + Some(self.fetch_string_desc(port_id, slot, raw_dd.product_str).await?) } else { None }, if raw_dd.serial_str > 0 { - Some(self.fetch_string_desc(port_id, slot, ring, raw_dd.serial_str).await?) + println!("Checkpoint 4c"); + Some(self.fetch_string_desc(port_id, slot, raw_dd.serial_str).await?) } else { None }, ); - let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot, ring).await?; + println!("Checkpoint 5"); + let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot).await?; + println!("Checkpoint 6"); + let supports_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); let supports_superspeedplus = @@ -960,7 +969,9 @@ impl Xhci { let mut config_descs = SmallVec::new(); for index in 0..raw_dd.configurations { - let (desc, data) = self.fetch_config_desc(port_id, slot, ring, index).await?; + println!("Checkpoint 7: {}", index); + let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?; + println!("Checkpoint 8: {}", index); let extra_length = desc.total_length as usize - mem::size_of_val(&desc); let data = &data[..extra_length]; @@ -1010,7 +1021,7 @@ impl Xhci { endpoints.push(endp); } - interface_descs.push(self.new_if_desc(port_id, slot, ring, idesc, endpoints, hid_descs).await?); + interface_descs.push(self.new_if_desc(port_id, slot, idesc, endpoints, hid_descs).await?); } else { // TODO break; @@ -1020,7 +1031,7 @@ impl Xhci { config_descs.push(ConfDesc { kind: desc.kind, configuration: if desc.configuration_str > 0 { - Some(self.fetch_string_desc(port_id, slot, ring, desc.configuration_str).await?) + Some(self.fetch_string_desc(port_id, slot, desc.configuration_str).await?) } else { None }, diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 1a91800bbf..a26a28f626 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -378,9 +378,11 @@ impl Trb { self.set( 0, u32::from(interrupter) << 22, - ((input as u32) << 16) + (u32::from(input) << 16) | ((TrbType::StatusStage as u32) << 10) - | (1 << 5) + | (u32::from(ioc) << 5) + | (u32::from(ch) << 4) + | (u32::from(ent) << 1) | (cycle as u32), ); } From ae49a0ba30dbfc8848e3dd97e47dc65ac8988f15 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 4 Apr 2020 11:55:52 +0200 Subject: [PATCH 0375/1301] Update chashmap version. --- Cargo.lock | 269 +++++++++++++++++++++++------------------------ xhcid/Cargo.toml | 2 +- 2 files changed, 132 insertions(+), 139 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2eeb19c3db..d171dc02ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,8 +47,8 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -90,7 +90,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -144,10 +144,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chashmap" version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://gitlab.redox-os.org/redox-os/chashmap.git#da92c702e052cde00db5e409dfb234af71928152" dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -182,10 +182,11 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -206,8 +207,8 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -221,10 +222,10 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -317,9 +318,9 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -363,10 +364,10 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -428,7 +429,7 @@ name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -467,7 +468,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.66" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -480,10 +481,19 @@ name = "lock_api" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lock_api" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.3.9" @@ -517,10 +527,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memoffset" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -540,7 +550,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -559,7 +569,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -573,7 +583,7 @@ version = "0.6.7" source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#22580ca398cdb5ed6f50fb61134e5579e2213999" dependencies = [ "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", ] @@ -594,7 +604,7 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -607,7 +617,7 @@ dependencies = [ "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.2 (git+https://github.com/a8m/pb)", @@ -627,7 +637,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-uni dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -694,8 +704,8 @@ name = "num_cpus" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -725,29 +735,12 @@ dependencies = [ [[package]] name = "owning_ref" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "owning_ref" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "parking_lot" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parking_lot" version = "0.7.1" @@ -758,14 +751,13 @@ dependencies = [ ] [[package]] -name = "parking_lot_core" -version = "0.2.14" +name = "parking_lot" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -773,13 +765,27 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "partitionlib" version = "0.1.0" @@ -795,8 +801,8 @@ name = "pbr" version = "1.0.2" source = "git+https://github.com/a8m/pb#87c29c05486afa7335916c870ea3621ff7ef2966" dependencies = [ - "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -807,7 +813,7 @@ name = "pbr" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -820,11 +826,11 @@ dependencies = [ "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -862,7 +868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -880,22 +886,10 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -904,7 +898,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -959,7 +953,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -971,7 +965,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1047,7 +1041,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1094,7 +1088,7 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1109,7 +1103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "scopeguard" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1125,9 +1119,9 @@ name = "scroll_derive" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1146,7 +1140,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1158,7 +1152,7 @@ version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1176,30 +1170,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.104" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.104" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.47" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1220,7 +1214,7 @@ name = "smallvec" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1256,11 +1250,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1269,7 +1263,7 @@ name = "termion" version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1285,20 +1279,20 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thiserror-impl" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1306,7 +1300,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1457,7 +1451,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", @@ -1471,7 +1465,7 @@ name = "toml" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1558,7 +1552,7 @@ dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] @@ -1678,19 +1672,19 @@ name = "xhcid" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)", + "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "pcid 0.1.0", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1712,15 +1706,15 @@ dependencies = [ "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chashmap 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ff41a3c2c1e39921b9003de14bf0439c7b63a9039637c291e1a64925d8ddfa45" +"checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c" +"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" "checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" "checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -"checksum crossbeam-utils 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4" +"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" @@ -1736,7 +1730,7 @@ dependencies = [ "checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" "checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" "checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" -"checksum hermit-abi 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" +"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" "checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" @@ -1746,15 +1740,16 @@ dependencies = [ "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" +"checksum memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" "checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" "checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" "checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" @@ -1772,12 +1767,11 @@ dependencies = [ "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402" -"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" -"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13" -"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" +"checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" +"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" +"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" "checksum pbr 1.0.2 (git+https://github.com/a8m/pb)" = "" "checksum pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4403eb718d70c03ee279e51737782902c68cca01e870a33b6a2f9dfb50b9cd83" @@ -1786,9 +1780,8 @@ dependencies = [ "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420" "checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" -"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" @@ -1809,10 +1802,10 @@ dependencies = [ "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b" "checksum rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a" -"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +"checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" "checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" +"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" "checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" "checksum scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28" "checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" @@ -1820,9 +1813,9 @@ dependencies = [ "checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" -"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" -"checksum serde_json 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "15913895b61e0be854afd32fd4163fcd2a3df34142cf2cb961b310ce694cbf90" +"checksum serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" +"checksum serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" +"checksum serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" @@ -1831,11 +1824,11 @@ dependencies = [ "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" "checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" +"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "205684fd018ca14432b12cce6ea3d46763311a571c3d294e71ba3f01adcf1aad" -"checksum thiserror-impl 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "57e4d2e50ca050ed44fb58309bdce3efa79948f84f9993ad1978de5eebdce5a7" +"checksum thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e3711fd1c4e75b3eff12ba5c40dba762b6b65c5476e8174c1a664772060c49bf" +"checksum thiserror-impl 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ae2b85ba4c9aa32dd3343bd80eb8d22e9b54b7688c17ea3907f236885353b233" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index e46a79a13b..3b1b2a622b 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -13,7 +13,7 @@ path = "src/lib.rs" [dependencies] bitflags = "1" -chashmap = "2.2.2" +chashmap = { git = "https://gitlab.redox-os.org/redox-os/chashmap.git" } crossbeam-channel = "0.4" futures = "0.3" plain = "0.2" From 80d3affa1c993c56f1978f942e6f40e11ef58719 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 4 Apr 2020 23:43:38 +0200 Subject: [PATCH 0376/1301] Enable xhci logging, powered by redox-log. --- Cargo.lock | 94 +++++++++++++++++++++++++++++------------------ xhcid/Cargo.toml | 3 +- xhcid/src/main.rs | 42 +++++++++++++-------- 3 files changed, 86 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d171dc02ee..9c56aa7049 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,7 +47,7 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -90,7 +90,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -150,6 +150,16 @@ dependencies = [ "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "chrono" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "clap" version = "2.33.0" @@ -317,8 +327,8 @@ name = "futures-macro" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -346,7 +356,7 @@ dependencies = [ "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -364,7 +374,7 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", @@ -704,7 +714,7 @@ name = "num_cpus" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -828,9 +838,9 @@ dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -858,7 +868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-hack" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -868,7 +878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -889,7 +899,7 @@ name = "quote" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1005,6 +1015,15 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox-log" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git#2e887e91e34edc90a2341678781e9271e70bc210" +dependencies = [ + "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_event" version = "0.1.0" @@ -1119,7 +1138,7 @@ name = "scroll_derive" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1170,18 +1189,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.105" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1193,7 +1212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1214,7 +1233,7 @@ name = "smallvec" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1253,7 +1272,7 @@ name = "syn" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1279,18 +1298,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "thiserror-impl 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thiserror-impl" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1465,7 +1484,7 @@ name = "toml" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1552,7 +1571,7 @@ dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] @@ -1676,15 +1695,16 @@ dependencies = [ "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pcid 0.1.0", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1707,6 +1727,7 @@ dependencies = [ "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "" +"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" @@ -1730,7 +1751,7 @@ dependencies = [ "checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" "checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" "checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" -"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" +"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" "checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" @@ -1778,9 +1799,9 @@ dependencies = [ "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro-hack 0.5.14 (registry+https://github.com/rust-lang/crates.io-index)" = "fcfdefadc3d57ca21cf17990a28ef4c0f7c61383a28cb7604cf4a18e6ede1420" +"checksum proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" "checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" -"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" @@ -1794,6 +1815,7 @@ dependencies = [ "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git)" = "" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" @@ -1813,8 +1835,8 @@ dependencies = [ "checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "e707fbbf255b8fc8c3b99abb91e7257a622caeb20a9818cbadbeeede4e0932ff" -"checksum serde_derive 1.0.105 (registry+https://github.com/rust-lang/crates.io-index)" = "ac5d00fc561ba2724df6758a17de23df5914f20e41cb00f94d5b7ae42fffaff8" +"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" +"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" "checksum serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" @@ -1827,8 +1849,8 @@ dependencies = [ "checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e3711fd1c4e75b3eff12ba5c40dba762b6b65c5476e8174c1a664772060c49bf" -"checksum thiserror-impl 1.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "ae2b85ba4c9aa32dd3343bd80eb8d22e9b54b7688c17ea3907f236885353b233" +"checksum thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "f0570dc61221295909abdb95c739f2e74325e14293b2026b0a7e195091ec54ae" +"checksum thiserror-impl 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "227362df41d566be41a28f64401e07a043157c21c14b9785a0d8e256f940a8fd" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 3b1b2a622b..c1ef18ce37 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -18,8 +18,9 @@ crossbeam-channel = "0.4" futures = "0.3" plain = "0.2" lazy_static = "1.4" -spin = "0.4" +log = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git" } redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 50ca1adccf..fedea2b399 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -1,13 +1,6 @@ #[macro_use] extern crate bitflags; -extern crate event; -extern crate plain; -extern crate syscall; -use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo}; -use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; - -use event::{Event, EventQueue}; use std::convert::TryInto; use std::fs::{self, File}; use std::future::Future; @@ -17,6 +10,12 @@ use std::pin::Pin; use std::ptr::NonNull; use std::sync::{Arc, Mutex}; use std::env; + +use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo}; +use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; + +use event::{Event, EventQueue}; +use log::info; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; @@ -81,14 +80,30 @@ async fn handle_packet(hci: Arc, packet: Packet) -> Packet { } fn main() { + let mut args = env::args().skip(1); + + let mut name = args.next().expect("xhcid: no name provided"); + name.push_str("_xhci"); + // Daemonize if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { return; } + match redox_log::RedoxLogger::new("usb", "host", "xhci.log") { + Ok(logger) => match logger.with_stdout_mirror().enable() { + Ok(()) => { + println!("xhcid: enabled logger"); + log::set_max_level(log::LevelFilter::Trace); + } + Err(error) => eprintln!("xhcid: failed to set default logger: {}", error), + } + Err(error) => eprintln!("xhcid: failed to initialize logger: {}", error), + } + let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); - println!("XHCI PCI CONFIG: {:?}", pci_config); + info!("XHCI PCI CONFIG: {:?}", pci_config); let bar = pci_config.func.bars[0]; let irq = pci_config.func.legacy_interrupt_line; @@ -104,7 +119,7 @@ fn main() { }; let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); - println!("XHCI PCI FEATURES: {:?}", all_pci_features); + info!("XHCI PCI FEATURES: {:?}", all_pci_features); let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); @@ -114,12 +129,12 @@ fn main() { if has_msi && !msi_enabled && !has_msix { pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); - println!("Enabled MSI"); + info!("Enabled MSI"); msi_enabled = true; } if has_msix && !msix_enabled { pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); - println!("Enabled MSI-X"); + info!("Enabled MSI-X"); msix_enabled = true; } @@ -197,11 +212,6 @@ fn main() { std::thread::sleep(std::time::Duration::from_millis(300)); - let mut args = env::args().skip(1); - - let mut name = args.next().expect("xhcid: no name provided"); - name.push_str("_xhci"); - print!( "{}", format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq) From 74c77412bf960cd5bc5eb2fe95434ec80f5a0e78 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 5 Apr 2020 00:17:55 +0200 Subject: [PATCH 0377/1301] Replace all calls to [e]println with log macros. --- xhcid/src/xhci/context.rs | 3 +- xhcid/src/xhci/irq_reactor.rs | 33 +++++----- xhcid/src/xhci/mod.rs | 111 ++++++++++++++-------------------- xhcid/src/xhci/scheme.rs | 23 ++----- 4 files changed, 72 insertions(+), 98 deletions(-) diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 45023397cc..e971ad28a7 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -1,5 +1,6 @@ use std::collections::BTreeMap; +use log::debug; use syscall::error::Result; use syscall::io::{Dma, Io, Mmio}; @@ -59,7 +60,7 @@ pub struct InputContext { } impl InputContext { pub fn dump_control(&self) { - println!( + debug!( "INPUT CONTEXT: {} {} [{} {} {} {} {}] {}", self.drop_context.read(), self.add_context.read(), diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 0abc6a2a9b..581e2214d2 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -10,6 +10,7 @@ use std::{io, mem, task, thread}; use std::os::unix::io::AsRawFd; use crossbeam_channel::{Sender, Receiver}; +use log::{debug, error, info, warn, trace}; use futures::Stream; use syscall::Io; @@ -106,7 +107,7 @@ impl IrqReactor { std::thread::yield_now(); } fn run_polling(mut self) { - println!("Running IRQ reactor in polling mode."); + debug!("Running IRQ reactor in polling mode."); let hci_clone = Arc::clone(&self.hci); 'event_loop: loop { @@ -133,7 +134,7 @@ impl IrqReactor { } } fn run_with_irq_file(mut self) { - println!("Running IRQ reactor with IRQ file and event queue"); + debug!("Running IRQ reactor with IRQ file and event queue"); let hci_clone = Arc::clone(&self.hci); let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); @@ -142,18 +143,18 @@ impl IrqReactor { let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() }; event_queue.add(irq_fd, move |_| -> io::Result> { - println!("IRQ event queue notified"); + trace!("IRQ event queue notified"); let mut buffer = [0u8; 8]; let _ = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); if !self.hci.received_irq() { // continue only when an IRQ to this device was received - println!("no interrupt pending"); + trace!("no interrupt pending"); return Ok(None); } - println!("IRQ reactor received an IRQ"); + trace!("IRQ reactor received an IRQ"); let _ = self.irq_file.as_mut().unwrap().write(&buffer); @@ -167,15 +168,15 @@ impl IrqReactor { let event_trb = &mut event_ring.ring.trbs[event_trb_index]; if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { - if count == 0 { println!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } + if count == 0 { warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } // no more events were found, continue the loop return Ok(None); } else { count += 1 } - println!("Found event TRB: {:?}", event_trb); + trace!("Found event TRB: {:?}", event_trb); if self.check_event_ring_full(event_trb.clone()) { - println!("Had to resize event TRB, retrying..."); + info!("Had to resize event TRB, retrying..."); hci_clone.event_handler_finished(); return Ok(None); } @@ -197,12 +198,12 @@ impl IrqReactor { let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); - println!("Updated ERDP to {:#0x}", dequeue_pointer); + debug!("Updated ERDP to {:#0x}", dequeue_pointer); self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); } fn handle_requests(&mut self) { - self.states.extend(self.receiver.try_iter().inspect(|req| println!("Received request: {:?}", req))); + self.states.extend(self.receiver.try_iter().inspect(|req| trace!("Received request: {:?}", req))); } fn acknowledge(&mut self, trb: Trb) { let mut index = 0; @@ -212,7 +213,7 @@ impl IrqReactor { match self.states[index].kind { StateKind::CommandCompletion { phys_ptr } if dbg!(trb.trb_type()) == TrbType::CommandCompletion as u8 => if dbg!(trb.completion_trb_pointer()) == Some(phys_ptr) { - println!("Found matching command completion future"); + trace!("Found matching command completion future"); let state = self.states.remove(index); // Before waking, it's crucial that the command TRB that generated this event @@ -224,7 +225,7 @@ impl IrqReactor { t }, None => { - println!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb); + warn!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb); continue; } }; @@ -235,12 +236,12 @@ impl IrqReactor { event_trb: trb.clone(), }); - println!("Waking up future with waker: {:?}", state.waker); + trace!("Waking up future with waker: {:?}", state.waker); state.waker.wake(); return; } else if trb.completion_trb_pointer().is_none() { - println!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); + warn!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); continue; } else { // The event TRB simply didn't match the current future @@ -290,7 +291,7 @@ impl IrqReactor { } } } - println!("Lost event TRB: {:?}", trb); + warn!("Lost event TRB: {:?}", trb); } fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { let mut index = 0; @@ -325,7 +326,7 @@ impl IrqReactor { /// Grows the event ring fn grow_event_ring(&mut self) { // TODO - println!("TODO: grow event ring"); + error!("TODO: grow event ring"); } pub fn run(mut self) { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 8e11e56781..6656b78fe9 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -11,6 +11,7 @@ use std::{mem, process, slice, sync::atomic, task, thread}; use chashmap::CHashMap; use crossbeam_channel::{Receiver, Sender}; +use log::{debug, error, info, trace, warn}; use serde::Deserialize; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; use syscall::flag::O_RDONLY; @@ -94,14 +95,11 @@ impl MsixInfo { impl Xhci { /// Gets descriptors, before the port state is initiated. async fn get_desc_raw(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, desc: &mut Dma) -> Result<()> { - println!("A"); let len = mem::size_of::(); let future = { - println!("B"); let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; let ring = port_state.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().expect("no ring for the default control pipe"); - println!("C"); let (cmd, cycle) = ring.next(); cmd.setup( @@ -117,24 +115,18 @@ impl Xhci { let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle); cmd.status(0, true, true, false, false, cycle); - println!("D"); self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &ring, &ring.trbs[last_index]) }; - println!("E"); self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); - println!("F"); let trbs = future.await; let event_trb = trbs.event_trb; let status_trb = trbs.src_trb.unwrap(); - println!("G"); self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?; - println!("H"); self.event_handler_finished(); - println!("I"); Ok(()) } @@ -242,7 +234,7 @@ impl EndpointState { impl Xhci { pub fn new(scheme_name: String, address: usize, interrupt_method: InterruptMethod, pcid_handle: PcidServerHandle) -> Result { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; - println!(" - CAP {:X}", address); + debug!("CAP REGS BASE {:X}", address); let page_size = { let memory_fd = syscall::open("memory:", O_RDONLY)?; @@ -253,52 +245,52 @@ impl Xhci { let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; - println!(" - OP {:X}", op_base); + debug!("OP REGS BASE {:X}", op_base); let (max_slots, max_ports) = { - println!(" - Wait for ready"); + debug!("Waiting for xHC becoming ready."); // Wait until controller is ready while op.usb_sts.readf(1 << 11) { - println!(" - Waiting for XHCI ready"); + trace!("Waiting for the xHC to be ready."); } - println!(" - Stop"); + debug!("Stopping the xHC"); // Set run/stop to 0 op.usb_cmd.writef(1, false); - println!(" - Wait for not running"); + debug!("Waiting for the xHC to stop."); // Wait until controller not running while !op.usb_sts.readf(1) { - println!(" - Waiting for XHCI stopped"); + trace!("Waiting for the xHC to stop."); } - println!(" - Reset"); + debug!("Resetting the xHC."); op.usb_cmd.writef(1 << 1, true); while op.usb_sts.readf(1 << 1) { - println!(" - Waiting for XHCI reset"); + trace!("Waiting for the xHC to reset."); } - println!(" - Read max slots"); + debug!("Reading max slots."); let max_slots = cap.max_slots(); let max_ports = cap.max_ports(); - println!(" - Max Slots: {}, Max Ports {}", max_slots, max_ports); + info!("xHC max slots: {}, max ports: {}", max_slots, max_ports); (max_slots, max_ports) }; let port_base = op_base + 0x400; let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut Port, max_ports as usize) }; - println!(" - PORT {:X}", port_base); + debug!("PORT BASE {:X}", port_base); let db_base = address + cap.db_offset.read() as usize; let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut Doorbell, 256) }; - println!(" - DOORBELL {:X}", db_base); + debug!("DOORBELL REGS BASE {:X}", db_base); let run_base = address + cap.rts_offset.read() as usize; let run = unsafe { &mut *(run_base as *mut RuntimeRegs) }; - println!(" - RUNTIME {:X}", run_base); + debug!("RUNTIME REGS BASE {:X}", run_base); // Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the // DMA allocation (which is at least a 4k page). @@ -345,42 +337,42 @@ impl Xhci { pub fn init(&mut self, max_slots: u8) -> Result<()> { // Set enabled slots - println!(" - Set enabled slots to {}", max_slots); + debug!("Setting enabled slots to {}.", max_slots); self.op.get_mut().unwrap().config.write(max_slots as u32); - println!(" - Enabled Slots: {}", self.op.get_mut().unwrap().config.read() & 0xFF); + debug!("Enabled Slots: {}", self.op.get_mut().unwrap().config.read() & 0xFF); // Set device context address array pointer let dcbaap = self.dev_ctx.dcbaap(); - println!(" - Write DCBAAP: {:X}", dcbaap); + debug!("Writing DCBAAP: {:X}", dcbaap); self.op.get_mut().unwrap().dcbaap.write(dcbaap as u64); // Set command ring control register let crcr = self.cmd.get_mut().unwrap().register(); assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR"); - println!(" - Write CRCR: {:X}", crcr); + debug!("Writing CRCR: {:X}", crcr); self.op.get_mut().unwrap().crcr.write(crcr as u64); // Set event ring segment table registers - println!(" - Interrupter 0: {:X}", self.run.get_mut().unwrap().ints.as_ptr() as usize); + debug!("Interrupter 0: {:p}", self.run.get_mut().unwrap().ints.as_ptr()); { let int = &mut self.run.get_mut().unwrap().ints[0]; let erstz = 1; - println!(" - Write ERSTZ: {}", erstz); + debug!("Writing ERSTZ: {}", erstz); int.erstsz.write(erstz); let erdp = self.primary_event_ring.get_mut().unwrap().erdp(); - println!(" - Write ERDP: {:X}", erdp); + debug!("Writing ERDP: {:X}", erdp); int.erdp.write(erdp as u64 | (1 << 3)); let erstba = self.primary_event_ring.get_mut().unwrap().erstba(); - println!(" - Write ERSTBA: {:X}", erstba); + debug!("Writing ERSTBA: {:X}", erstba); int.erstba.write(erstba as u64); - println!(" - Write IMODC and IMODI: {} and {}", 0, 0); + debug!("Writing IMODC and IMODI: {} and {}", 0, 0); int.imod.write(0); - println!(" - Enable interrupts"); + debug!("Enabling Primary Interrupter."); int.iman.writef(1 << 1 | 1, true); } @@ -390,22 +382,20 @@ impl Xhci { self.setup_scratchpads()?; // Set run/stop to 1 - println!(" - Start"); + info!("Starting xHC."); self.op.get_mut().unwrap().usb_cmd.writef(1, true); // Wait until controller is running - println!(" - Wait for running"); + debug!("Waiting for start request to complete."); while self.op.get_mut().unwrap().usb_sts.readf(1) { - println!(" - Waiting for XHCI running"); + trace!("Waiting for XHCI to report running status."); } - println!("IP={}", self.run.get_mut().unwrap().ints[0].iman.readf(1)); - // Ring command doorbell - println!(" - Ring doorbell"); + debug!("Ringing command doorbell."); self.dbs.get_mut().unwrap()[0].write(0); - println!(" - XHCI initialized"); + info!("XHCI initialized."); if self.cap.cic() { self.op.get_mut().unwrap().set_cie(true); @@ -422,6 +412,7 @@ impl Xhci { } let scratchpad_buf_arr = ScratchpadBufferArray::new(self.page_size,buf_count)?; self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; + debug!("Setting up {} scratchpads, at {:#0x}", buf_count, scratchpad_buf_arr.register()); self.scratchpad_buf_arr = Some(scratchpad_buf_arr); Ok(()) @@ -452,7 +443,7 @@ impl Xhci { } pub async fn probe(&self) -> Result<()> { - println!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); + info!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); let port_count = { self.ports.lock().unwrap().len() }; @@ -461,29 +452,26 @@ impl Xhci { let port = &self.ports.lock().unwrap()[i]; (port.read(), port.state(), port.speed(), port.flags()) }; - println!( - " + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", + info!( + "XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags ); if flags.contains(port::PortFlags::PORT_CCS) { - //TODO: Link TRB when running to the end of the ring buffer - - println!(" - Enable slot"); - let slot_ty = self .supported_protocol(i as u8) .expect("Failed to find supported protocol information for port") .proto_slot_ty(); - println!("Got slot type: {}", slot_ty); + debug!("Slot type: {}", slot_ty); + debug!("Enabling slot."); let slot = self.enable_port_slot(slot_ty).await?; - println!(" - Slot {}", slot); + info!("Enabled port {}, which the xHC mapped to {}", i, slot); let mut input = Dma::::zeroed()?; let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; - println!("Addressed device"); + info!("Addressed device"); // TODO: Should the descriptors be cached in PortState, or refetched? @@ -504,9 +492,7 @@ impl Xhci { }; self.port_states.insert(i, port_state); - println!("pre get desc"); let dev_desc = self.get_desc(i, slot).await?; - println!("post get desc"); self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc); { @@ -520,7 +506,7 @@ impl Xhci { /*match self.spawn_drivers(i, &mut port_state) { Ok(()) => (), - Err(err) => println!("Failed to spawn driver for port {}: `{}`", i, err), + Err(err) => error!("Failed to spawn driver for port {}: `{}`", i, err), }*/ } @@ -648,14 +634,14 @@ impl Xhci { let input_context_physical = input_context.physical(); - println!("pre_address_device"); let (event_trb, _) = self.execute_command(|trb, cycle| { trb.address_device(slot, input_context_physical, false, cycle) }).await; - println!("post_address_device"); if event_trb.completion_code() != TrbCompletionCode::Success as u8 { - println!("Failed to address device at slot {} (port {})", slot, i); + error!("Failed to address device at slot {} (port {})", slot, i); + self.event_handler_finished(); + return Err(Error::new(EIO)); } self.event_handler_finished(); @@ -690,13 +676,10 @@ impl Xhci { if self.uses_msi() || self.uses_msix() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. - println!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); - println!("MSI-X PB={}", self.msix_info_mut().unwrap().pba(0)); - let mut msix = self.msix_info_mut().unwrap(); - let entry = msix.table_entry_pointer(0); - println!("MSI-X entry (addr_lo, addr_hi, msg_data, vec_ctl: {:#0x} {:#0x} {:#0x} {:#0x}", entry.addr_lo.read(), entry.addr_hi.read(), entry.msg_data.read(), entry.vec_ctl.read()); + trace!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); true } else if runtime_regs.ints[0].iman.readf(1) { + trace!("Successfully received INTx# interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); // If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is // a special register to specify whether the IRQ actually came from the xHC. runtime_regs.ints[0].iman.writef(1, true); @@ -734,7 +717,7 @@ impl Xhci { .map(|subclass| subclass == ifdesc.sub_class) .unwrap_or(true) }) { - println!("Loading driver \"{}\"", driver.name); + info!("Loading subdriver\"{}\"", driver.name); let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; let if_proto = ifdesc.protocol; @@ -865,10 +848,10 @@ pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { let receiver = hci.irq_reactor_receiver.clone(); let hci_clone = Arc::clone(&hci); - println!("About to start IRQ reactor"); + debug!("About to start IRQ reactor"); *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { - println!("Started IRQ reactor thread"); + info!("Started IRQ reactor thread"); IrqReactor::new(hci_clone, receiver, irq_file).run() })); } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 3709b18845..c39cf56163 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -4,6 +4,7 @@ use std::sync::atomic; use std::{cmp, io, mem, path, str}; use futures::executor::block_on; +use log::{debug, error, info, warn, trace}; use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; @@ -235,9 +236,7 @@ impl Xhci { self.next_command_completion_event_trb(&*command_ring, command_trb) }; - println!("Ringing doorbell"); self.dbs.lock().unwrap()[0].write(0); - println!("Doorbell rung"); let trbs = next_event.await; let event_trb = trbs.event_trb; @@ -381,14 +380,14 @@ impl Xhci { if event_trb.completion_code() != TrbCompletionCode::ShortPacket as u8 && event_trb.transfer_length() != 0 { - println!( + error!( "Event trb didn't yield a short packet, but some bytes were not transferred" ); return Err(Error::new(EIO)); } // TODO: Handle event data - println!("EVENT DATA: {:?}", event_trb.event_data()); + debug!("EVENT DATA: {:?}", event_trb.event_data()); Ok(event_trb) } @@ -925,41 +924,33 @@ impl Xhci { port_id: usize, slot: u8, ) -> Result { - println!("Checkpoint 1"); let ports = self.ports.lock().unwrap(); let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); } - println!("Checkpoint 2"); let raw_dd = self.fetch_dev_desc(port_id, slot).await?; - println!("Checkpoint 3"); let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { - println!("Checkpoint 4a"); Some(self.fetch_string_desc(port_id, slot, raw_dd.manufacturer_str).await?) } else { None }, if raw_dd.product_str > 0 { - println!("Checkpoint 4b"); Some(self.fetch_string_desc(port_id, slot, raw_dd.product_str).await?) } else { None }, if raw_dd.serial_str > 0 { - println!("Checkpoint 4c"); Some(self.fetch_string_desc(port_id, slot, raw_dd.serial_str).await?) } else { None }, ); - println!("Checkpoint 5"); let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot).await?; - println!("Checkpoint 6"); let supports_superspeed = usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); @@ -969,9 +960,7 @@ impl Xhci { let mut config_descs = SmallVec::new(); for index in 0..raw_dd.configurations { - println!("Checkpoint 7: {}", index); let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?; - println!("Checkpoint 8: {}", index); let extra_length = desc.total_length as usize - mem::size_of_val(&desc); let data = &data[..extra_length]; @@ -2001,7 +1990,7 @@ impl Xhci { /// # Locking /// This function locks `Xhci::run`. pub fn event_handler_finished(&self) { - println!("Event handler finished"); + trace!("Event handler finished"); // write 1 to EHB to clear it self.run.lock().unwrap().ints[0].erdp.writef(1 << 3, true); } @@ -2010,7 +1999,7 @@ pub fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Resul if event_trb.completion_code() == TrbCompletionCode::Success as u8 { Ok(()) } else { - println!("{} command (TRB {:?}) failed with event trb {:?}", name, command_trb, event_trb); + error!("{} command (TRB {:?}) failed with event trb {:?}", name, command_trb, event_trb); Err(Error::new(EIO)) } } @@ -2018,7 +2007,7 @@ pub fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb if event_trb.completion_code() == TrbCompletionCode::Success as u8 || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 { Ok(()) } else { - println!("{} transfer (TRB {:?}) failed with event trb {:?}", name, transfer_trb, event_trb); + error!("{} transfer (TRB {:?}) failed with event trb {:?}", name, transfer_trb, event_trb); Err(Error::new(EIO)) } } From f4398854fc34966da9b929b68ba0e727777abc26 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 5 Apr 2020 23:21:24 +0200 Subject: [PATCH 0378/1301] Add trace debug printlns for opening handles. --- xhcid/src/xhci/scheme.rs | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c39cf56163..9289880953 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,7 +1,8 @@ use std::convert::TryFrom; use std::io::prelude::*; +use std::ops::Deref; use std::sync::atomic; -use std::{cmp, io, mem, path, str}; +use std::{cmp, fmt, io, mem, path, str}; use futures::executor::block_on; use log::{debug, error, info, warn, trace}; @@ -53,6 +54,7 @@ pub enum EndpIfState { } /// Subdirs of an endpoint +#[derive(Debug)] pub enum EndpointHandleTy { /// portX/endpoints/Y/data. Allows clients to read and write data associated with ctl requests. Data, @@ -64,7 +66,7 @@ pub enum EndpointHandleTy { Root(usize, Vec), // offset, content } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub enum PortTransferState { /// Ready to read or write to do another transfer Ready, @@ -81,6 +83,7 @@ pub enum PortReqState { Tmp, } +#[derive(Debug)] pub enum Handle { TopLevel(usize, Vec), // offset, contents (ports) Port(usize, usize, Vec), // port, offset, contents @@ -92,6 +95,34 @@ pub enum Handle { ConfigureEndpoints(usize), // port } +#[derive(Clone, Copy)] +struct DmaSliceDbg<'a, T>(&'a Dma<[T]>); + +impl<'a, T> fmt::Debug for DmaSliceDbg<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let DmaSliceDbg(dma) = self; + + f.debug_struct("Dma") + .field("phys_ptr", &(dma.physical() as *const u8)) + .field("virt_ptr", &(dma.deref().as_ptr() as *const u8)) + .field("length", &(dma.len() * mem::size_of::())) + .finish() + } +} + +impl fmt::Debug for PortReqState { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Init => f.debug_struct("PortReqState::Init").finish(), + Self::WaitingForDeviceBytes(ref dma, setup) => f.debug_tuple("PortReqState::WaitingForDeviceBytes").field(&DmaSliceDbg(dma)).field(&setup).finish(), + Self::WaitingForHostBytes(ref dma, setup) => f.debug_tuple("PortReqState::WaitingForHostBytes").field(&DmaSliceDbg(dma)).field(&setup).finish(), + Self::TmpSetup(setup) => f.debug_tuple("PortReqState::TmpSetup").field(&setup).finish(), + Self::Tmp => f.debug_struct("PortReqState::Init").finish(), + } + } +} + + // TODO: Even though the driver interface descriptors are originally intended for JSON, they should suffice... for // now. @@ -1370,6 +1401,9 @@ impl Scheme for Xhci { }; let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed); + + trace!("OPENED {} to FD={}, handle: {:?}", path_str, fd, handle); + self.handles.insert(fd, handle); Ok(fd) From 0e802e208575b2ceab6c6837c4c958f6625dd328 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 6 Apr 2020 00:54:15 +0200 Subject: [PATCH 0379/1301] Fix two deadlocks. --- Cargo.lock | 11 +++++----- xhcid/src/driver_interface.rs | 2 +- xhcid/src/main.rs | 2 +- xhcid/src/xhci/scheme.rs | 38 ++++++++++++++++++++--------------- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9c56aa7049..d93fb99f01 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -839,7 +839,7 @@ dependencies = [ "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1018,10 +1018,11 @@ dependencies = [ [[package]] name = "redox-log" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git#2e887e91e34edc90a2341678781e9271e70bc210" +source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git#08693d48b2d7b56fcb07a1e62e257bacce749cef" dependencies = [ "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1207,7 +1208,7 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1702,7 +1703,7 @@ dependencies = [ "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1837,7 +1838,7 @@ dependencies = [ "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" "checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" -"checksum serde_json 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "78a7a12c167809363ec3bd7329fc0a3369056996de43c4b37ef3cd54a6ce4867" +"checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 1d0968f402..8b560a5cd1 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -14,7 +14,7 @@ use thiserror::Error; pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK}; -#[derive(Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct ConfigureEndpointsReq { /// Index into the configuration descriptors of the device descriptor. pub config_desc: u8, diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index fedea2b399..f8dfd8c520 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -92,7 +92,7 @@ fn main() { match redox_log::RedoxLogger::new("usb", "host", "xhci.log") { Ok(logger) => match logger.with_stdout_mirror().enable() { - Ok(()) => { + Ok(_) => { println!("xhcid: enabled logger"); log::set_max_level(log::LevelFilter::Trace); } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 9289880953..70ea13db4e 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -288,10 +288,10 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { - let mut port_state = self.port_state_mut(port_num)?; - let slot = port_state.slot; + let (future, slot) = { + let mut port_state = self.port_state_mut(port_num)?; + let slot = port_state.slot; - let future = { let mut endpoint_state = port_state .endpoint_states .get_mut(&0).ok_or(Error::new(EIO))?; @@ -322,7 +322,7 @@ impl Xhci { let ent = false; cmd.status(interrupter, tk == TransferKind::In, ioc, ch, ent, cycle); - self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), ring, &ring.trbs[last_index]) + (self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), ring, &ring.trbs[last_index]), slot) }; self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); @@ -423,6 +423,8 @@ impl Xhci { Ok(event_trb) } async fn device_req_no_data(&self, port: usize, req: usb::Setup) -> Result<()> { + trace!("DEVICE_REQ_NO_DATA port {}, req: {:?}", port, req); + self.execute_control_transfer( port, req, @@ -433,6 +435,7 @@ impl Xhci { Ok(()) } async fn set_configuration(&self, port: usize, config: u8) -> Result<()> { + debug!("Setting configuration value {} to port {}", config, port); self.device_req_no_data(port, usb::Setup::set_configuration(config)).await } async fn set_interface( @@ -441,6 +444,7 @@ impl Xhci { interface_num: u8, alternate_setting: u8, ) -> Result<()> { + debug!("Setting interface value {} (alternate setting {}) to port {}", interface_num, alternate_setting, port); self.device_req_no_data( port, usb::Setup::set_interface(interface_num, alternate_setting), @@ -556,6 +560,8 @@ impl Xhci { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; + debug!("Running configure endpoints command, at port {}, request: {:?}", port, req); + if (!self.cap.cic() || !self.op.lock().unwrap().cie()) && (req.config_desc != 0 || req.interface_desc != None || req.alternate_setting != None) { @@ -623,7 +629,7 @@ impl Xhci { for endp_idx in 0..endp_desc_count as u8 { let endp_num = endp_idx + 1; - let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; let dev_desc = port_state.dev_desc.as_ref().unwrap(); let endpoints = &dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; @@ -683,8 +689,6 @@ impl Xhci { assert_eq!(max_error_count & 0x3, max_error_count); assert_ne!(ep_ty, 0); // 0 means invalid. - let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; - let ring_ptr = if usb_log_max_streams.is_some() { let mut array = StreamContextArray::new(1 << (primary_streams + 1))?; @@ -726,7 +730,6 @@ impl Xhci { }; assert_eq!(primary_streams & 0x1F, primary_streams); - let port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; let mut input_context = port_state.input_context.lock().unwrap(); input_context.add_context.writef(1 << endp_num_xhc, true); @@ -755,16 +758,19 @@ impl Xhci { .write(u32::from(avg_trb_len) | (u32::from(max_esit_payload_lo) << 16)); } - let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; - let slot = port_state.slot; - let input_context_physical = port_state.input_context.lock().unwrap().physical(); + { + let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let slot = port_state.slot; + let input_context_physical = port_state.input_context.lock().unwrap().physical(); - let (event_trb, command_trb) = self.execute_command(|trb, cycle| { - trb.configure_endpoint(slot, input_context_physical, cycle) - }).await; - self.event_handler_finished(); + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { + trb.configure_endpoint(slot, input_context_physical, cycle) + }).await; - handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; + self.event_handler_finished(); + + handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; + } // Tell the device about this configuration. self.set_configuration(port, configuration_value).await?; From 57bde84edb0f5ca1b84d444e63c91807597179c1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 6 Apr 2020 13:58:26 +0200 Subject: [PATCH 0380/1301] usbscsid works again, AFAICT. --- xhcid/src/xhci/mod.rs | 6 +++--- xhcid/src/xhci/scheme.rs | 34 ++++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 6656b78fe9..d8f3348f71 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -330,7 +330,7 @@ impl Xhci { irq_reactor_receiver, }; - xhci.init(max_slots); + xhci.init(max_slots)?; Ok(xhci) } @@ -424,7 +424,7 @@ impl Xhci { let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)).await; - self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb); + self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb)?; self.event_handler_finished(); Ok(event_trb.event_slot()) @@ -432,7 +432,7 @@ impl Xhci { pub async fn disable_port_slot(&self, slot: u8) -> Result<()> { let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)).await; - self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb); + self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb)?; self.event_handler_finished(); Ok(()) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 70ea13db4e..039da4431f 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -352,6 +352,7 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { + let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?; let mut port_state = self.port_state_mut(port_num)?; let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { @@ -359,7 +360,6 @@ impl Xhci { _ => return Err(Error::new(EIO)), }; - let slot = port_state.slot; let endp_state = port_state @@ -393,7 +393,7 @@ impl Xhci { } }; - let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(cfg_idx)).ok_or(Error::new(EIO))?.interface_descs.get(usize::from(if_idx)).ok_or(Error::new(EIO))?.endpoints.get(usize::from(endp_idx)).ok_or(Error::new(EBADFD))?; self.dbs.lock().unwrap()[usize::from(slot)].write(Self::endp_doorbell( endp_num, @@ -401,6 +401,7 @@ impl Xhci { if has_streams { stream_id } else { 0 }, )); + drop(port_state); let trbs = future.await; let event_trb = trbs.event_trb; let transfer_trb = trbs.src_trb.unwrap(); @@ -575,7 +576,10 @@ impl Xhci { } let (endp_desc_count, new_context_entries, configuration_value) = { - let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; + port_state.cfg_idx = Some(req.config_desc); + port_state.if_idx = Some(req.interface_desc.unwrap_or(0)); + let config_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; let endpoints = &config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; @@ -811,6 +815,8 @@ impl Xhci { let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; dma_buffer.copy_from_slice(sbuf); + trace!("TRANSFER_WRITE port {} ep {}, buffer at {:p}, size {}, dma buffer {:?}", port_num, endp_idx + 1, sbuf.as_ptr(), sbuf.len(), DmaSliceDbg(&dma_buffer)); + let (completion_code, bytes_transferred, _) = self.transfer( port_num, endp_idx, @@ -854,19 +860,24 @@ impl Xhci { // TODO: Check that only readable enpoints are read, etc. let endp_num = endp_idx + 1; - let port_state = self + let mut port_state = self .port_states .get_mut(&port_num) .ok_or(Error::new(EBADFD))?; + let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { + (Some(c), Some(i)) => (c, i), + _ => return Err(Error::new(EIO)), + }; + let endp_desc: &EndpDesc = port_state .dev_desc .as_ref().unwrap() .config_descs - .get(0) + .get(usize::from(cfg_idx)) .ok_or(Error::new(EIO))? .interface_descs - .get(0) + .get(usize::from(if_idx)) .ok_or(Error::new(EIO))? .endpoints .get(endp_idx as usize) @@ -915,6 +926,8 @@ impl Xhci { let mut bytes_left = dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0); + drop(port_state); + let event = self.execute_transfer( port_num, endp_num, @@ -1489,6 +1502,9 @@ impl Scheme for Xhci { fn seek(&self, fd: usize, pos: usize, whence: usize) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + + trace!("SEEK fd={}, handle={:?}, pos {}, whence {}", fd, guard, pos, whence); + match &mut *guard { // Directories, or fixed files Handle::TopLevel(ref mut offset, ref buf) @@ -1522,6 +1538,7 @@ impl Scheme for Xhci { fn read(&self, fd: usize, buf: &mut [u8]) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + trace!("READ fd={}, handle={:?}, buf=(addr {:p}, length {})", fd, guard, buf.as_ptr(), buf.len()); match &mut *guard { Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) @@ -1569,12 +1586,14 @@ impl Scheme for Xhci { } &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); + drop(guard); // release the lock block_on(self.handle_port_req_read(fd, port_num, state, buf)) } } } fn write(&self, fd: usize, buf: &[u8]) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; + trace!("WRITE fd={}, handle={:?}, buf=(addr {:p}, length {})", fd, guard, buf.as_ptr(), buf.len()); match &mut *guard { &mut Handle::ConfigureEndpoints(port_num) => { @@ -1588,6 +1607,7 @@ impl Scheme for Xhci { }, &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); + drop(guard); // release the lock block_on(self.handle_port_req_write(fd, port_num, state, buf)) } // TODO: Introduce PortReqState::Waiting, which this write call changes to @@ -1892,6 +1912,7 @@ impl Xhci { if buf.len() > total_bytes_to_transfer as usize - bytes_transferred as usize { return Err(Error::new(EINVAL)); } + drop(port_state); let (completion_code, some_bytes_transferred) = self.transfer_write(port_num, endp_num - 1, buf).await?; let result = Self::transfer_result(completion_code, some_bytes_transferred); @@ -1985,6 +2006,7 @@ impl Xhci { return Err(Error::new(EINVAL)); } + drop(port_state); let (completion_code, some_bytes_transferred) = self.transfer_read(port_num, endp_num - 1, buf).await?; From 81afdb2750b5128b92723c129fe3d6867fca2002 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 12 Apr 2020 11:37:10 +0200 Subject: [PATCH 0381/1301] Remove two todo comments. --- pcid/src/main.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 63637cb50b..daef5c699a 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -62,8 +62,6 @@ impl DriverHandler { PcidClientRequest::RequestFeatures => { PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability { PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))), - // TODO: For MSI-X to actually be enabled, MSI also has to be enabled. - // How should this be reported to the subdrivers? PciCapability::MsiX(msix) => Some((PciFeature::MsiX, FeatureStatus::enabled(msix.msix_enabled()))), _ => None, }).collect()) @@ -344,9 +342,6 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, func, }; - // TODO: find a better way to pass the header data down to the - // device driver, making passing the capabilities list etc - // posible. let mut args = args.iter(); if let Some(program) = args.next() { let mut command = Command::new(program); From da188109d49955caa12646890e237d08efce862f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 19 Apr 2020 17:11:08 +0200 Subject: [PATCH 0382/1301] Change the default log level to debug. --- xhcid/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index f8dfd8c520..66a84b2262 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -94,7 +94,7 @@ fn main() { Ok(logger) => match logger.with_stdout_mirror().enable() { Ok(_) => { println!("xhcid: enabled logger"); - log::set_max_level(log::LevelFilter::Trace); + log::set_max_level(log::LevelFilter::Debug); } Err(error) => eprintln!("xhcid: failed to set default logger: {}", error), } From 31d5a95cf9c59437ad41b4e1bc199f38162eea38 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 12 Apr 2020 11:18:20 +0200 Subject: [PATCH 0383/1301] Add MCFG parsing for PCIe. --- Cargo.lock | 2 + pcid/Cargo.toml | 2 + pcid/src/main.rs | 1 + pcid/src/pcie/mod.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+) create mode 100644 pcid/src/pcie/mod.rs diff --git a/Cargo.lock b/Cargo.lock index d93fb99f01..d36db5740f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -837,9 +837,11 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 966d0ebff2..dae6e66cce 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -16,8 +16,10 @@ bincode = "1.2" bitflags = "1" byteorder = "1.2" libc = "0.2" +plain = "0.2" redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } serde = { version = "1", features = ["derive"] } serde_json = "1" +smallvec = "1" thiserror = "1" toml = "0.5" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index daef5c699a..e0d1b76d19 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -21,6 +21,7 @@ use crate::pci::cap::Capability as PciCapability; mod config; mod driver_interface; mod pci; +mod pcie; pub struct DriverHandler { config: config::DriverConfig, diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs new file mode 100644 index 0000000000..57c21a9275 --- /dev/null +++ b/pcid/src/pcie/mod.rs @@ -0,0 +1,91 @@ +use std::{fs, io, mem, slice}; +use smallvec::SmallVec; + +pub const MCFG_NAME: [u8; 4] = *b"MCFG"; + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct Mcfg { + // base sdt fields + name: [u8; 4], + length: u32, + revision: u8, + checksum: u8, + oem_id: [u8; 6], + oem_table_id: [u8; 8], + oem_revision: u32, + creator_id: [u8; 4], + _rsvd: [u8; 8], + + base_addrs: [PcieAlloc; 0], +} +unsafe impl plain::Plain for Mcfg {} + +/// The "Memory Mapped Enhanced Configuration Space Base Address Allocation Structure" (yes, it's +/// called that). + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct PcieAlloc { + pub base_addr: u64, + pub seg_group_num: u16, + pub start_bus: u8, + pub end_bus: u8, + _rsvd: [u8; 4], +} +unsafe impl plain::Plain for PcieAlloc {} + +impl Mcfg { + pub fn base_addr_structs(&self) -> &[PcieAlloc] { + let total_length = mem::size_of::(); + let len = total_length - 44; + // safe because the length cannot be changed arbitrarily + unsafe { slice::from_raw_parts(&self.base_addrs as *const PcieAlloc, len / mem::size_of::()) } + } +} + +pub struct Mcfgs { + tables: SmallVec<[Vec; 2]>, +} +impl Mcfgs { + pub fn tables<'a>(&'a self) -> impl Iterator + 'a { + self.tables.iter().filter_map(|bytes| { + let mcfg = plain::from_bytes::(bytes).ok()?; + if mcfg.length as usize > bytes.len() { + return None; + } + Some(mcfg) + }) + } + + pub fn fetch() -> io::Result { + let table_dir = fs::read_dir("acpi:tables")?; + + let tables = table_dir.map(|table_direntry| -> io::Result> { + let table_direntry = table_direntry?; + let table_path = table_direntry.path(); + + let table_filename = match table_path.file_name() { + Some(n) => n.to_str().ok_or(io::Error::new(io::ErrorKind::InvalidData, "Non-UTF-8 ACPI table filename"))?, + None => return Ok(None), + }; + + if table_filename.starts_with("MCFG") { + Ok(Some(fs::read(table_path)?)) + } else { + Ok(None) + } + }).filter_map(|result_option| result_option.transpose()).collect::, _>>()?; + + Ok(Self { + tables, + }) + } + pub fn at_bus(&self, bus: u8) -> Option<(&Mcfg, &PcieAlloc)> { + self.tables().find_map(|table| { + Some((table, table.base_addr_structs().iter().find(|addr_struct| { + (addr_struct.start_bus..addr_struct.end_bus).contains(&bus) + })?)) + }) + } +} From 14206f0e5c147107630e6e5a46f301c81a161dc8 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 12 Apr 2020 18:32:36 +0200 Subject: [PATCH 0384/1301] Successfully read config space with PCIe MMIO*. *to the extent where all the subdriver appear to function as normal. --- pcid/src/main.rs | 43 +++++++++------ pcid/src/pci/bus.rs | 10 ++-- pcid/src/pci/cap.rs | 10 ++-- pcid/src/pci/dev.rs | 4 +- pcid/src/pci/func.rs | 15 ++--- pcid/src/pci/mod.rs | 64 ++++++++++++++++----- pcid/src/pci/msi.rs | 38 ++++++------- pcid/src/pcie/mod.rs | 129 ++++++++++++++++++++++++++++++++++++++++++- 8 files changed, 239 insertions(+), 74 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index e0d1b76d19..d2369d1707 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,10 +1,5 @@ #![feature(asm)] -extern crate bitflags; -extern crate byteorder; -extern crate syscall; -extern crate toml; - use std::fs::{File, metadata, read_dir}; use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; @@ -15,8 +10,9 @@ use std::{env, io, i64, thread}; use syscall::iopl; use crate::config::Config; -use crate::pci::{Pci, PciBar, PciBus, PciClass, PciDev, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::{CfgAccess, Pci, PciIter, PciBar, PciBus, PciClass, PciDev, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; use crate::pci::cap::Capability as PciCapability; +use crate::pcie::Pcie; mod config; mod driver_interface; @@ -138,7 +134,13 @@ impl DriverHandler { pub struct State { threads: Mutex>>, - pci: Pci, + pci: Arc, + pcie: Option, +} +impl State { + fn preferred_cfg_access(&self) -> &dyn CfgAccess { + self.pcie.as_ref().map(|pcie| pcie as &dyn CfgAccess).unwrap_or(&*self.pci as &dyn CfgAccess) + } } fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, @@ -274,11 +276,11 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, let offset = 0x10 + (i as u8) * 4; - let original = pci.read(bus_num, dev_num, func_num, offset); - pci.write(bus_num, dev_num, func_num, offset, 0xFFFFFFFF); + let original = pci.read(bus_num, dev_num, func_num, offset.into()); + pci.write(bus_num, dev_num, func_num, offset.into(), 0xFFFFFFFF); - let new = pci.read(bus_num, dev_num, func_num, offset); - pci.write(bus_num, dev_num, func_num, offset, original); + let new = pci.read(bus_num, dev_num, func_num, offset.into()); + pci.write(bus_num, dev_num, func_num, offset.into(), original); let masked = if new & 1 == 1 { new & 0xFFFFFFFC @@ -297,7 +299,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, let capabilities = { let bus = PciBus { - pci, + pci: state.preferred_cfg_access(), num: bus_num, }; let dev = PciDev { @@ -445,18 +447,25 @@ fn main() { } } + let pci = Arc::new(Pci::new()); + let state = Arc::new(State { - pci: Pci::new(), + pci: Arc::clone(&pci), + pcie: match Pcie::new(Arc::clone(&pci)) { + Ok(pcie) => Some(pcie), + Err(error) => { + println!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error); + None + } + }, threads: Mutex::new(Vec::new()), }); - let pci = &state.pci; - - unsafe { iopl(3).unwrap() }; + let pci = state.preferred_cfg_access(); print!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV\n"); - 'bus: for bus in pci.buses() { + 'bus: for bus in PciIter::new(pci) { 'dev: for dev in bus.devs() { for func in dev.funcs() { let func_num = func.num; diff --git a/pcid/src/pci/bus.rs b/pcid/src/pci/bus.rs index 388e796e61..7678fad2fc 100644 --- a/pcid/src/pci/bus.rs +++ b/pcid/src/pci/bus.rs @@ -1,7 +1,7 @@ -use super::{Pci, PciDev}; +use super::{Pci, PciDev, CfgAccess}; pub struct PciBus<'pci> { - pub pci: &'pci Pci, + pub pci: &'pci dyn CfgAccess, pub num: u8 } @@ -10,10 +10,10 @@ impl<'pci> PciBus<'pci> { PciBusIter::new(self) } - pub unsafe fn read(&self, dev: u8, func: u8, offset: u8) -> u32 { + pub unsafe fn read(&self, dev: u8, func: u8, offset: u16) -> u32 { self.pci.read(self.num, dev, func, offset) } - pub unsafe fn write(&self, dev: u8, func: u8, offset: u8, value: u32) { + pub unsafe fn write(&self, dev: u8, func: u8, offset: u16, value: u32) { self.pci.write(self.num, dev, func, offset, value) } } @@ -26,7 +26,7 @@ pub struct PciBusIter<'pci> { impl<'pci> PciBusIter<'pci> { pub fn new(bus: &'pci PciBus<'pci>) -> Self { PciBusIter { - bus: bus, + bus, num: 0 } } diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 6159dc0f6a..d808776cec 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -25,7 +25,7 @@ where if self.offset == 0 { return None }; - let first_dword = dbg!(self.reader.read_u32(dbg!(self.offset))); + let first_dword = dbg!(self.reader.read_u32(dbg!(u16::from(self.offset)))); let next = ((first_dword >> 8) & 0xFF) as u8; let offset = self.offset; @@ -135,9 +135,9 @@ impl Capability { } unsafe fn parse_msix(reader: &R, offset: u8) -> Self { Self::MsiX(MsixCapability { - a: reader.read_u32(offset), - b: reader.read_u32(offset + 4), - c: reader.read_u32(offset + 8), + a: reader.read_u32(u16::from(offset)), + b: reader.read_u32(u16::from(offset + 4)), + c: reader.read_u32(u16::from(offset + 8)), }) } unsafe fn parse_pcie(reader: &R, offset: u8) -> Self { @@ -147,7 +147,7 @@ impl Capability { unsafe fn parse(reader: &R, offset: u8) -> Self { assert_eq!(offset & 0xF8, offset, "capability must be dword aligned"); - let dword = reader.read_u32(offset); + let dword = reader.read_u32(u16::from(offset)); let capability_id = (dword & 0xFF) as u8; if capability_id == CapabilityId::Msi as u8 { diff --git a/pcid/src/pci/dev.rs b/pcid/src/pci/dev.rs index 6d021994e5..7cb7aa2926 100644 --- a/pcid/src/pci/dev.rs +++ b/pcid/src/pci/dev.rs @@ -10,10 +10,10 @@ impl<'pci> PciDev<'pci> { PciDevIter::new(self) } - pub unsafe fn read(&self, func: u8, offset: u8) -> u32 { + pub unsafe fn read(&self, func: u8, offset: u16) -> u32 { self.bus.read(self.num, func, offset) } - pub unsafe fn write(&self, func: u8, offset: u8, value: u32) { + pub unsafe fn write(&self, func: u8, offset: u16, value: u32) { self.bus.write(self.num, func, offset, value); } } diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index 0a3be3c874..1b278bd057 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -2,11 +2,8 @@ use byteorder::{LittleEndian, ByteOrder}; use super::PciDev; -// TODO: PCI Express Configuration Space, which uses a flat memory buffer, rather than IN/OUT -// instructions. - pub trait ConfigReader { - unsafe fn read_range(&self, offset: u8, len: u8) -> Vec { + unsafe fn read_range(&self, offset: u16, len: u16) -> Vec { assert!(len > 3 && len % 4 == 0); let mut ret = Vec::with_capacity(len as usize); let results = (offset..offset + len).step_by(4).fold(Vec::new(), |mut acc, offset| { @@ -19,9 +16,9 @@ pub trait ConfigReader { ret } - unsafe fn read_u32(&self, offset: u8) -> u32; + unsafe fn read_u32(&self, offset: u16) -> u32; - unsafe fn read_u8(&self, offset: u8) -> u8 { + unsafe fn read_u8(&self, offset: u16) -> u8 { let dword_offset = (offset / 4) * 4; let dword = self.read_u32(dword_offset); @@ -30,7 +27,7 @@ pub trait ConfigReader { } } pub trait ConfigWriter { - unsafe fn write_u32(&self, offset: u8, value: u32); + unsafe fn write_u32(&self, offset: u16, value: u32); } pub struct PciFunc<'pci> { @@ -39,12 +36,12 @@ pub struct PciFunc<'pci> { } impl<'pci> ConfigReader for PciFunc<'pci> { - unsafe fn read_u32(&self, offset: u8) -> u32 { + unsafe fn read_u32(&self, offset: u16) -> u32 { self.dev.read(self.num, offset) } } impl<'pci> ConfigWriter for PciFunc<'pci> { - unsafe fn write_u32(&self, offset: u8, value: u32) { + unsafe fn write_u32(&self, offset: u16, value: u32) { self.dev.write(self.num, offset, value); } } diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index b3395517eb..bea70cd448 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,4 +1,5 @@ -use std::sync::Mutex; +use std::convert::TryFrom; +use std::sync::{Mutex, Once}; pub use self::bar::PciBar; pub use self::bus::{PciBus, PciBusIter}; @@ -16,14 +17,24 @@ mod func; pub mod header; pub mod msi; +pub trait CfgAccess { + unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32; + unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32; + + unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32); + unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32); +} + pub struct Pci { lock: Mutex<()>, + iopl_once: Once, } impl Pci { pub fn new() -> Self { Self { lock: Mutex::new(()), + iopl_once: Once::new(), } } @@ -31,9 +42,33 @@ impl Pci { PciIter::new(self) } - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 { - let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); + fn set_iopl() { + // make sure that pcid is not granted io port permission unless pcie memory-mapped + // configuration space is not available. + println!("PCI: couldn't find or access PCIe extended configuration, and thus falling back to PCI 3.0 io ports"); + unsafe { syscall::iopl(3).expect("pcid: failed to set iopl to 3"); } + } + fn address(bus: u8, dev: u8, func: u8, offset: u8) -> u32 { + // TODO: Find the part of pcid that uses an unaligned offset! + // + // assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); + // + let offset = offset & 0xFC; + + assert_eq!(dev & 0x1F, dev, "pci device larger than 5 bits"); + assert_eq!(func & 0x7, func, "pci func larger than 3 bits"); + + 0x80000000 | (u32::from(bus) << 16) | (u32::from(dev) << 11) | (u32::from(func) << 8) | u32::from(offset) + } +} +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +impl CfgAccess for Pci { + unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + self.iopl_once.call_once(Self::set_iopl); + + let offset = u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); + let address = Self::address(bus, dev, func, offset); + let value: u32; asm!("mov dx, 0xCF8 out dx, eax @@ -43,15 +78,17 @@ impl Pci { value } - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u8) -> u32 { + unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); self.read_nolock(bus, dev, func, offset) } - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) { - let address = 0x80000000 | ((bus as u32) << 16) | ((dev as u32) << 11) | ((func as u32) << 8) | ((offset as u32) & 0xFC); + unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { + self.iopl_once.call_once(Self::set_iopl); + + let offset = u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); + let address = Self::address(bus, dev, func, offset); + asm!("mov dx, 0xCF8 out dx, eax" : : "{eax}"(address) : "dx" : "intel", "volatile"); @@ -59,22 +96,21 @@ impl Pci { out dx, eax" : : "{eax}"(value) : "dx" : "intel", "volatile"); } - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - pub unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u8, value: u32) { + unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { let _guard = self.lock.lock().unwrap(); self.write_nolock(bus, dev, func, offset, value) } } pub struct PciIter<'pci> { - pci: &'pci Pci, + pci: &'pci dyn CfgAccess, num: u32 } impl<'pci> PciIter<'pci> { - pub fn new(pci: &'pci Pci) -> Self { + pub fn new(pci: &'pci dyn CfgAccess) -> Self { PciIter { - pci: pci, + pci, num: 0 } } diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index d4400257f4..cd1561b755 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -19,7 +19,7 @@ impl MsiCapability { pub const MC_MSI_ENABLED_BIT: u16 = 1; pub unsafe fn parse(reader: &R, offset: u8) -> Self { - let dword = reader.read_u32(offset); + let dword = reader.read_u32(u16::from(offset)); let message_control = (dword >> 16) as u16; @@ -27,34 +27,34 @@ impl MsiCapability { if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { Self::_64BitAddressWithPvm { message_control: dword, - message_address_lo: reader.read_u32(offset + 4), - message_address_hi: reader.read_u32(offset + 8), - message_data: reader.read_u32(offset + 12), - mask_bits: reader.read_u32(offset + 16), - pending_bits: reader.read_u32(offset + 20), + message_address_lo: reader.read_u32(u16::from(offset + 4)), + message_address_hi: reader.read_u32(u16::from(offset + 8)), + message_data: reader.read_u32(u16::from(offset + 12)), + mask_bits: reader.read_u32(u16::from(offset + 16)), + pending_bits: reader.read_u32(u16::from(offset + 20)), } } else { Self::_32BitAddressWithPvm { message_control: dword, - message_address: reader.read_u32(offset + 4), - message_data: reader.read_u32(offset + 8), - mask_bits: reader.read_u32(offset + 12), - pending_bits: reader.read_u32(offset + 16), + message_address: reader.read_u32(u16::from(offset + 4)), + message_data: reader.read_u32(u16::from(offset + 8)), + mask_bits: reader.read_u32(u16::from(offset + 12)), + pending_bits: reader.read_u32(u16::from(offset + 16)), } } } else { if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { Self::_64BitAddress { message_control: dword, - message_address_lo: reader.read_u32(offset + 4), - message_address_hi: reader.read_u32(offset + 8), - message_data: reader.read_u32(offset + 12), + message_address_lo: reader.read_u32(u16::from(offset + 4)), + message_address_hi: reader.read_u32(u16::from(offset + 8)), + message_data: reader.read_u32(u16::from(offset + 12)), } } else { Self::_32BitAddress { message_control: dword, - message_address: reader.read_u32(offset + 4), - message_data: reader.read_u32(offset + 8), + message_address: reader.read_u32(u16::from(offset + 4)), + message_data: reader.read_u32(u16::from(offset + 8)), } } } @@ -81,7 +81,7 @@ impl MsiCapability { } } pub unsafe fn write_message_control(&mut self, writer: &W, offset: u8) { - writer.write_u32(offset, self.message_control_raw()); + writer.write_u32(u16::from(offset), self.message_control_raw()); } pub fn is_pvt_capable(&self) -> bool { self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 @@ -238,17 +238,17 @@ impl MsixCapability { /// Write the first DWORD into configuration space (containing the partially modifiable Message /// Control field). pub unsafe fn write_a(&self, writer: &W, offset: u8) { - writer.write_u32(offset, self.a) + writer.write_u32(u16::from(offset), self.a) } /// Write the second DWORD into configuration space (containing the modifiable table /// offset and the readonly table BIR). pub unsafe fn write_b(&self, writer: &W, offset: u8) { - writer.write_u32(offset + 4, self.a) + writer.write_u32(u16::from(offset + 4), self.a) } /// Write the third DWORD into configuration space (containing the modifiable pending bit array /// offset, and the readonly PBA BIR). pub unsafe fn write_c(&self, writer: &W, offset: u8) { - writer.write_u32(offset + 8, self.a) + writer.write_u32(u16::from(offset + 8), self.a) } /// Write this capability structure back to configuration space. pub unsafe fn write_all(&self, writer: &W, offset: u8) { diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 57c21a9275..27f75a8638 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -1,10 +1,18 @@ -use std::{fs, io, mem, slice}; +use std::{fmt, fs, io, mem, ptr, slice}; +use std::collections::BTreeMap; +use std::sync::{Arc, Mutex}; + +use syscall::flag::PhysmapFlags; +use syscall::io::Dma; + use smallvec::SmallVec; +use crate::pci::{CfgAccess, Pci, PciIter}; + pub const MCFG_NAME: [u8; 4] = *b"MCFG"; #[repr(packed)] -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy)] pub struct Mcfg { // base sdt fields name: [u8; 4], @@ -15,6 +23,7 @@ pub struct Mcfg { oem_table_id: [u8; 8], oem_revision: u32, creator_id: [u8; 4], + creator_revision: u32, _rsvd: [u8; 8], base_addrs: [PcieAlloc; 0], @@ -43,10 +52,27 @@ impl Mcfg { unsafe { slice::from_raw_parts(&self.base_addrs as *const PcieAlloc, len / mem::size_of::()) } } } +impl fmt::Debug for Mcfg { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Mcfg") + .field("name", &"MCFG") + .field("length", &self.length) + .field("revision", &self.revision) + .field("checksum", &self.checksum) + .field("oem_id", &self.oem_id) + .field("oem_table_id", &self.oem_table_id) + .field("oem_revision", &self.oem_revision) + .field("creator_revision", &self.creator_revision) + .field("creator_id", &self.creator_id) + .field("base_addrs", &self.base_addr_structs()) + .finish() + } +} pub struct Mcfgs { tables: SmallVec<[Vec; 2]>, } + impl Mcfgs { pub fn tables<'a>(&'a self) -> impl Iterator + 'a { self.tables.iter().filter_map(|bytes| { @@ -57,6 +83,9 @@ impl Mcfgs { Some(mcfg) }) } + pub fn allocs<'a>(&'a self) -> impl Iterator + 'a { + self.tables().map(|table| table.base_addr_structs().iter()).flatten() + } pub fn fetch() -> io::Result { let table_dir = fs::read_dir("acpi:tables")?; @@ -81,11 +110,105 @@ impl Mcfgs { tables, }) } - pub fn at_bus(&self, bus: u8) -> Option<(&Mcfg, &PcieAlloc)> { + pub fn table_and_alloc_at_bus(&self, bus: u8) -> Option<(&Mcfg, &PcieAlloc)> { self.tables().find_map(|table| { Some((table, table.base_addr_structs().iter().find(|addr_struct| { (addr_struct.start_bus..addr_struct.end_bus).contains(&bus) })?)) }) } + pub fn at_bus(&self, bus: u8) -> Option<&PcieAlloc> { + self.table_and_alloc_at_bus(bus).map(|(_, alloc)| alloc) + } +} + +impl fmt::Debug for Mcfgs { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + struct Tables<'a>(&'a Mcfgs); + impl<'a> fmt::Debug for Tables<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self.0.tables()).finish() + } + } + + f.debug_tuple("Mcfgs").field(&Tables(self)).finish() + } +} + +pub struct Pcie { + lock: Mutex<()>, + mcfgs: Mcfgs, + maps: Mutex>, + fallback: Arc, +} +unsafe impl Send for Pcie {} +unsafe impl Sync for Pcie {} + +impl Pcie { + pub fn new(fallback: Arc) -> io::Result { + let mcfgs = Mcfgs::fetch()?; + + Ok(Self { + lock: Mutex::new(()), + mcfgs, + maps: Mutex::new(BTreeMap::new()), + fallback, + }) + } + fn addr_offset_in_bytes(starting_bus: u8, bus: u8, dev: u8, func: u8, offset: u16) -> usize { + assert_eq!(offset & 0xFFFC, offset, "pcie offset not dword-aligned"); + assert_eq!(offset & 0x0FFF, offset, "pcie offset larger than 4095"); + assert_eq!(dev & 0x1F, dev, "pcie dev number larger than 5 bits"); + assert_eq!(func & 0x7, func, "pcie func number larger than 3 bits"); + + (((bus - starting_bus) as usize) << 20) | ((dev as usize) << 15) | ((func as usize) << 12) | (offset as usize) + } + fn addr_offset_in_dwords(starting_bus: u8, bus: u8, dev: u8, func: u8, offset: u16) -> usize { + Self::addr_offset_in_bytes(starting_bus, bus, dev, func, offset) / mem::size_of::() + } + unsafe fn with_pointer) -> T>(&self, bus: u8, dev: u8, func: u8, offset: u16, f: F) -> T { + let (base_address_phys, starting_bus) = match self.mcfgs.at_bus(bus) { + Some(t) => (t.base_addr, t.start_bus), + None => return f(None), + }; + let mut maps_lock = self.maps.lock().unwrap(); + let virt_pointer = maps_lock.entry((bus, dev, func)).or_insert_with(|| { + syscall::physmap(base_address_phys as usize + Self::addr_offset_in_bytes(starting_bus, bus, dev, func, 0), 4096, PhysmapFlags::PHYSMAP_NO_CACHE | PhysmapFlags::PHYSMAP_WRITE).unwrap_or_else(|error| panic!("failed to physmap pcie configuration space for {:2x}:{:2x}.{:2x}: {:?}", bus, dev, func, error)) as *mut u32 + }); + f(Some(&mut *virt_pointer.offset((offset as usize / mem::size_of::()) as isize))) + } + pub fn buses<'pcie>(&'pcie self) -> PciIter<'pcie> { + PciIter::new(self) + } +} + +impl CfgAccess for Pcie { + unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + self.with_pointer(bus, dev, func, offset, |pointer| match pointer { + Some(address) => ptr::read_volatile::(address), + None => self.fallback.read(bus, dev, func, offset), + }) + } + unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + let _guard = self.lock.lock().unwrap(); + self.read_nolock(bus, dev, func, offset) + } + unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { + self.with_pointer(bus, dev, func, offset, |pointer| match pointer { + Some(address) => ptr::write_volatile::(address, value), + None => { self.fallback.read(bus, dev, func, offset); } + }); + } + unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { + let _guard = self.lock.lock().unwrap(); + self.write_nolock(bus, dev, func, offset, value); + } +} + +impl Drop for Pcie { + fn drop(&mut self) { + for address in self.maps.values() { + let _ = unsafe { syscall::physfree(address, 4096) }; + } + } } From cee5a39cccc4bf8713ef8dde6dcfed0c4e0b119c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 19 Apr 2020 09:29:24 +0200 Subject: [PATCH 0385/1301] Fix pcie memory destructor. --- pcid/src/pcie/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 27f75a8638..453aef8b0c 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -207,8 +207,8 @@ impl CfgAccess for Pcie { impl Drop for Pcie { fn drop(&mut self) { - for address in self.maps.values() { - let _ = unsafe { syscall::physfree(address, 4096) }; + for address in self.maps.lock().unwrap().values().copied() { + let _ = unsafe { syscall::physfree(address as usize, 4096) }; } } } From 255e5fcb68b4ea27358f37616cfea3b98e1a0351 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 19 Apr 2020 14:27:44 -0600 Subject: [PATCH 0386/1301] WIP: ps2d interrupt fixes --- Cargo.lock | 1 - ps2d/Cargo.toml | 1 - ps2d/src/controller.rs | 6 +-- ps2d/src/main.rs | 110 ++++++++++++++++++++++++++++------------- ps2d/src/state.rs | 13 ++--- 5 files changed, 87 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d93fb99f01..396b7553ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -890,7 +890,6 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 34ef208a98..f1da6df454 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -6,5 +6,4 @@ edition = "2018" [dependencies] bitflags = "0.7" orbclient = "0.3.27" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.1" diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 1d758446be..378ecb5764 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -76,9 +76,9 @@ enum MouseCommandData { } pub struct Ps2 { - data: Pio, - status: ReadOnly>, - command: WriteOnly> + pub data: Pio, + pub status: ReadOnly>, + pub command: WriteOnly> } impl Ps2 { diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 3e896a9253..56dce69f8f 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -2,18 +2,15 @@ #[macro_use] extern crate bitflags; -extern crate event; extern crate orbclient; extern crate syscall; use std::{env, process}; -use std::cell::RefCell; -use std::fs::File; -use std::io::{Read, Write, Result}; +use std::fs::{File, OpenOptions}; +use std::io::{Read, Write}; +use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; -use std::sync::Arc; -use event::EventQueue; use syscall::iopl; use crate::state::Ps2d; @@ -41,46 +38,93 @@ fn daemon(input: File) { None => (keymap::us::get_char) }; - let mut key_irq = File::open("irq:1").expect("ps2d: failed to open irq:1"); + let mut event_file = OpenOptions::new() + .read(true) + .write(true) + .custom_flags(syscall::O_NONBLOCK as i32) + .open("event:") + .expect("ps2d: failed to open event:"); - let mut mouse_irq = File::open("irq:12").expect("ps2d: failed to open irq:12"); + let mut key_irq = OpenOptions::new() + .read(true) + .write(true) + .custom_flags(syscall::O_NONBLOCK as i32) + .open("irq:1") + .expect("ps2d: failed to open irq:1"); - let ps2d = Arc::new(RefCell::new(Ps2d::new(input, keymap))); + let mut key_irq_data = [0; 8]; + key_irq.read(&mut key_irq_data).expect("ps2d: failed to read irq:1"); - let mut event_queue = EventQueue::<()>::new().expect("ps2d: failed to create event queue"); + event_file.write(&syscall::Event { + id: key_irq.as_raw_fd() as usize, + flags: syscall::EVENT_READ, + data: 1 + }).expect("ps2d: failed to event irq:1"); + + key_irq.write(&key_irq_data).expect("ps2d: failed to write irq:1"); + + let mut mouse_irq = OpenOptions::new() + .read(true) + .write(true) + .open("irq:12") + .expect("ps2d: failed to open irq:12"); + + let mut mouse_irq_data = [0; 8]; + mouse_irq.read(&mut mouse_irq_data).expect("ps2d: failed to read irq:12"); + + event_file.write(&syscall::Event { + id: mouse_irq.as_raw_fd() as usize, + flags: syscall::EVENT_READ, + data: 1 + }).expect("ps2d: failed to event irq:12"); + + mouse_irq.write(&mouse_irq_data).expect("ps2d: failed to write irq:12"); + + let mut ps2d = Ps2d::new(input, keymap); syscall::setrens(0, 0).expect("ps2d: failed to enter null namespace"); - let key_ps2d = ps2d.clone(); - event_queue.add(key_irq.as_raw_fd(), move |_event| -> Result> { - let mut irq = [0; 8]; - if key_irq.read(&mut irq)? >= irq.len() { - key_ps2d.borrow_mut().irq(); - key_irq.write(&irq)?; + loop { + // There are some gotchas with ps/2 controllers that require this weird + // way of doing things. You read key and mouse data from the same + // place. There is a status register that may show you which the data + // came from, but if it is even implemented it can have a race + // condition causing keyboard data to be read as mouse data. + // + // So, if any IRQ is returned as an event, first we check if a keyboard + // IRQ has happened. If so, we know the next byte is keyboard data. If + // not, we can read mouse data. + + let mut event = syscall::Event::default(); + if event_file.read(&mut event).expect("ps2d: failed to read event file") == 0 { + break; } - Ok(None) - }).expect("ps2d: failed to poll irq:1"); - let mouse_ps2d = ps2d; - event_queue.add(mouse_irq.as_raw_fd(), move |_event| -> Result> { - let mut irq = [0; 8]; - if mouse_irq.read(&mut irq)? >= irq.len() { - mouse_ps2d.borrow_mut().irq(); - mouse_irq.write(&irq)?; + let last_mouse_irq_data = mouse_irq_data; + mouse_irq.read(&mut mouse_irq_data).expect("ps2d: failed to read irq:12"); + let mouse_irq_change = mouse_irq_data != last_mouse_irq_data; + + let last_key_irq_data = key_irq_data; + key_irq.read(&mut key_irq_data).expect("ps2d: failed to read irq:1"); + let key_irq_change = key_irq_data != last_key_irq_data; + + if key_irq_change { + ps2d.irq(true); + key_irq.write(&key_irq_data).expect("ps2d: failed to write irq:1"); + } else if mouse_irq_change { + ps2d.irq(false); + } else { + println!("ps2d: no irq change found"); } - Ok(None) - }).expect("ps2d: failed to poll irq:12"); - event_queue.trigger_all(event::Event { - fd: 0, - flags: 0, - }).expect("ps2d: failed to trigger events"); - - event_queue.run().expect("ps2d: failed to handle events"); + if mouse_irq_change { + mouse_irq.write(&mouse_irq_data).expect("ps2d: failed to write irq:12"); + } + } } fn main() { - match File::open("display:input") { + match OpenOptions::new().write(true).open("display:input") { Ok(input) => { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 13c71c0876..0d33b2db2a 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -4,6 +4,7 @@ use std::io::Write; use std::os::unix::io::AsRawFd; use std::str; use syscall; +use syscall::Io; use crate::controller::Ps2; use crate::vm; @@ -82,13 +83,13 @@ impl char> Ps2d { } } - pub fn irq(&mut self) { - while let Some((keyboard, data)) = self.ps2.next() { - self.handle(keyboard, data); - } + pub fn irq(&mut self, keyboard: bool) { + self.handle(keyboard, self.ps2.data.read()); } pub fn handle(&mut self, keyboard: bool, data: u8) { + println!("{}{:x}", if keyboard { 'k' } else { 'm' }, data); + if keyboard { let (scancode, pressed) = if data >= 0x80 { (data - 0x80, false) @@ -174,7 +175,7 @@ impl char> Ps2d { let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); if ! flags.contains(ALWAYS_ON) { - println!("MOUSE MISALIGN {:X}", self.packets[0]); + panic!("ps2d: mouse misalign {:X}", self.packets[0]); self.packets = [0; 4]; self.packet_i = 0; @@ -227,7 +228,7 @@ impl char> Ps2d { }.to_event()).expect("ps2d: failed to write button event"); } } else { - println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); + panic!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); } self.packets = [0; 4]; From a6dbe788f69e17852ec3f5682eabf21b23ad1790 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 20 Apr 2020 11:23:15 -0600 Subject: [PATCH 0387/1301] Undo some changes --- ps2d/src/controller.rs | 6 +++--- ps2d/src/state.rs | 13 ++++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 378ecb5764..1d758446be 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -76,9 +76,9 @@ enum MouseCommandData { } pub struct Ps2 { - pub data: Pio, - pub status: ReadOnly>, - pub command: WriteOnly> + data: Pio, + status: ReadOnly>, + command: WriteOnly> } impl Ps2 { diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 0d33b2db2a..0ea9d62f03 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -4,7 +4,6 @@ use std::io::Write; use std::os::unix::io::AsRawFd; use std::str; use syscall; -use syscall::Io; use crate::controller::Ps2; use crate::vm; @@ -83,13 +82,13 @@ impl char> Ps2d { } } - pub fn irq(&mut self, keyboard: bool) { - self.handle(keyboard, self.ps2.data.read()); + pub fn irq(&mut self) { + while let Some((keyboard, data)) = self.ps2.next() { + self.handle(keyboard, data); + } } pub fn handle(&mut self, keyboard: bool, data: u8) { - println!("{}{:x}", if keyboard { 'k' } else { 'm' }, data); - if keyboard { let (scancode, pressed) = if data >= 0x80 { (data - 0x80, false) @@ -175,7 +174,7 @@ impl char> Ps2d { let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); if ! flags.contains(ALWAYS_ON) { - panic!("ps2d: mouse misalign {:X}", self.packets[0]); + println!("ps2d: mouse misalign {:X}", self.packets[0]); self.packets = [0; 4]; self.packet_i = 0; @@ -228,7 +227,7 @@ impl char> Ps2d { }.to_event()).expect("ps2d: failed to write button event"); } } else { - panic!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); + println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); } self.packets = [0; 4]; From 9150f7cc8508355f5d74183f4bec8f6ff28aab41 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 20 Apr 2020 11:23:29 -0600 Subject: [PATCH 0388/1301] Use serio: from kernel --- ps2d/src/main.rs | 70 +++++++++++++++++++----------------------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 56dce69f8f..8d00348830 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -41,49 +41,40 @@ fn daemon(input: File) { let mut event_file = OpenOptions::new() .read(true) .write(true) - .custom_flags(syscall::O_NONBLOCK as i32) .open("event:") .expect("ps2d: failed to open event:"); - let mut key_irq = OpenOptions::new() + let mut key_file = OpenOptions::new() .read(true) .write(true) .custom_flags(syscall::O_NONBLOCK as i32) - .open("irq:1") - .expect("ps2d: failed to open irq:1"); - - let mut key_irq_data = [0; 8]; - key_irq.read(&mut key_irq_data).expect("ps2d: failed to read irq:1"); + .open("serio:0") + .expect("ps2d: failed to open serio:0"); event_file.write(&syscall::Event { - id: key_irq.as_raw_fd() as usize, + id: key_file.as_raw_fd() as usize, flags: syscall::EVENT_READ, - data: 1 - }).expect("ps2d: failed to event irq:1"); + data: 0 + }).expect("ps2d: failed to event serio:0"); - key_irq.write(&key_irq_data).expect("ps2d: failed to write irq:1"); - - let mut mouse_irq = OpenOptions::new() + let mut mouse_file = OpenOptions::new() .read(true) .write(true) - .open("irq:12") - .expect("ps2d: failed to open irq:12"); - - let mut mouse_irq_data = [0; 8]; - mouse_irq.read(&mut mouse_irq_data).expect("ps2d: failed to read irq:12"); + .custom_flags(syscall::O_NONBLOCK as i32) + .open("serio:1") + .expect("ps2d: failed to open serio:1"); event_file.write(&syscall::Event { - id: mouse_irq.as_raw_fd() as usize, + id: mouse_file.as_raw_fd() as usize, flags: syscall::EVENT_READ, data: 1 }).expect("ps2d: failed to event irq:12"); - mouse_irq.write(&mouse_irq_data).expect("ps2d: failed to write irq:12"); - let mut ps2d = Ps2d::new(input, keymap); syscall::setrens(0, 0).expect("ps2d: failed to enter null namespace"); + let mut data = [0; 256]; loop { // There are some gotchas with ps/2 controllers that require this weird // way of doing things. You read key and mouse data from the same @@ -91,34 +82,29 @@ fn daemon(input: File) { // came from, but if it is even implemented it can have a race // condition causing keyboard data to be read as mouse data. // - // So, if any IRQ is returned as an event, first we check if a keyboard - // IRQ has happened. If so, we know the next byte is keyboard data. If - // not, we can read mouse data. + // Due to this, we have a kernel driver doing a small amount of work + // to grab bytes and sort them based on the source let mut event = syscall::Event::default(); if event_file.read(&mut event).expect("ps2d: failed to read event file") == 0 { break; } - let last_mouse_irq_data = mouse_irq_data; - mouse_irq.read(&mut mouse_irq_data).expect("ps2d: failed to read irq:12"); - let mouse_irq_change = mouse_irq_data != last_mouse_irq_data; + let (file, keyboard) = match event.data { + 0 => (&mut key_file, true), + 1 => (&mut mouse_file, false), + _ => continue, + }; - let last_key_irq_data = key_irq_data; - key_irq.read(&mut key_irq_data).expect("ps2d: failed to read irq:1"); - let key_irq_change = key_irq_data != last_key_irq_data; - - if key_irq_change { - ps2d.irq(true); - key_irq.write(&key_irq_data).expect("ps2d: failed to write irq:1"); - } else if mouse_irq_change { - ps2d.irq(false); - } else { - println!("ps2d: no irq change found"); - } - - if mouse_irq_change { - mouse_irq.write(&mouse_irq_data).expect("ps2d: failed to write irq:12"); + loop { + let count = match file.read(&mut data) { + Ok(0) => break, + Ok(count) => count, + Err(_) => break, + }; + for i in 0..count { + ps2d.handle(keyboard, data[i]); + } } } } From af039d9507d230812b3083b617d3fede017a462b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 20 Apr 2020 11:24:18 -0600 Subject: [PATCH 0389/1301] Support relative vmmouse mode, and use by default --- ps2d/src/state.rs | 19 +++++++++++-------- ps2d/src/vm.rs | 16 ++++++++++------ 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 0ea9d62f03..bca33b61ec 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -24,6 +24,7 @@ bitflags! { pub struct Ps2d char> { ps2: Ps2, vmmouse: bool, + vmmouse_relative: bool, input: File, width: u32, height: u32, @@ -46,12 +47,14 @@ impl char> Ps2d { let mut ps2 = Ps2::new(); let extra_packet = ps2.init(); - let vmmouse = false; //vm::enable(); + let vmmouse_relative = true; + let vmmouse = vm::enable(vmmouse_relative); let mut ps2d = Ps2d { - ps2: ps2, - vmmouse: vmmouse, - input: input, + ps2, + vmmouse, + vmmouse_relative, + input, width: 0, height: 0, lshift: false, @@ -63,7 +66,7 @@ impl char> Ps2d { mouse_right: false, packets: [0; 4], packet_i: 0, - extra_packet: extra_packet, + extra_packet, get_char: keymap }; @@ -118,17 +121,17 @@ impl char> Ps2d { } if queue_length % 4 != 0 { - println!("queue length not a multiple of 4: {}", queue_length); + println!("ps2d: queue length not a multiple of 4: {}", queue_length); break; } let (status, dx, dy, dz, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; - if status & vm::RELATIVE_PACKET == vm::RELATIVE_PACKET { + if self.vmmouse_relative { if dx != 0 || dy != 0 { self.input.write(&MouseRelativeEvent { dx: dx as i32, - dy: -(dy as i32), + dy: dy as i32, }.to_event()).expect("ps2d: failed to write mouse event"); } } else { diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index a772829aaf..36dc9dce60 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -14,6 +14,7 @@ pub const ABSPOINTER_COMMAND: u32 = 41; pub const CMD_ENABLE: u32 = 0x45414552; pub const CMD_DISABLE: u32 = 0x000000f5; pub const CMD_REQUEST_ABSOLUTE: u32 = 0x53424152; +pub const CMD_REQUEST_RELATIVE: u32 = 0x4c455252; const VERSION: u32 = 0x3442554a; @@ -55,27 +56,30 @@ pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32, u32, u32) { (a, b, c, d, si, di) } -pub fn enable() -> bool { - println!("Enable"); +pub fn enable(relative: bool) -> bool { + println!("ps2d: Enable vmmouse"); unsafe { let _ = cmd(ABSPOINTER_COMMAND, CMD_ENABLE); let (status, _, _, _, _, _) = cmd(ABSPOINTER_STATUS, 0); if (status & 0x0000ffff) == 0 { - println!("No vmmouse"); + println!("ps2d: No vmmouse"); return false; } let (version, _, _, _, _, _) = cmd(ABSPOINTER_DATA, 1); if version != VERSION { - println!("Invalid vmmouse version: {} instead of {}", version, VERSION); + println!("ps2d: Invalid vmmouse version: {} instead of {}", version, VERSION); let _ = cmd(ABSPOINTER_COMMAND, CMD_DISABLE); return false; } - cmd(ABSPOINTER_COMMAND, CMD_REQUEST_ABSOLUTE); - + if relative { + cmd(ABSPOINTER_COMMAND, CMD_REQUEST_RELATIVE); + } else { + cmd(ABSPOINTER_COMMAND, CMD_REQUEST_ABSOLUTE); + } } return true; From 751f5490bda7c427f1adca9ab8bee4a7187586cb Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 20 Apr 2020 13:00:34 -0600 Subject: [PATCH 0390/1301] Disable vmmouse again, for performance --- ps2d/src/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index bca33b61ec..ec6e5d2c15 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -48,7 +48,7 @@ impl char> Ps2d { let extra_packet = ps2.init(); let vmmouse_relative = true; - let vmmouse = vm::enable(vmmouse_relative); + let vmmouse = false; //vm::enable(vmmouse_relative); let mut ps2d = Ps2d { ps2, From afe9c88f377027decafdc4f6f52b5303c15609c0 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 19 Apr 2020 21:09:34 +0200 Subject: [PATCH 0391/1301] Allow every settable MSI field to be set. --- pcid/src/driver_interface.rs | 49 ++++++++++++++++- pcid/src/main.rs | 58 ++++++++++++++++++-- pcid/src/pci/cap.rs | 4 +- pcid/src/pci/msi.rs | 102 +++++++++++++++++++++++++++++++++-- xhcid/src/main.rs | 2 +- 5 files changed, 202 insertions(+), 13 deletions(-) diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface.rs index 28c06ef02a..12a055d666 100644 --- a/pcid/src/driver_interface.rs +++ b/pcid/src/driver_interface.rs @@ -40,7 +40,9 @@ pub struct PciFunction { /// BAR sizes pub bar_sizes: [u32; 6], - /// Legacy IRQ line + /// Legacy IRQ line: It's the responsibility of pcid to make sure that it be mapped in either + /// the I/O APIC or the 8259 PIC, so that the subdriver can map the interrupt vector directly. + /// The vector to map is always this field, plus 32. pub legacy_interrupt_line: u8, /// Legacy interrupt pin (INTx#), none if INTx# interrupts aren't supported at all. @@ -114,6 +116,48 @@ pub enum PcidClientHandleError { } pub type Result = std::result::Result; +// TODO: Remove these "features" and just go strait to the actual thing. + +#[derive(Debug, Serialize, Deserialize)] +pub struct MsiSetFeatureInfo { + /// The Multi Message Enable field of the Message Control in the MSI Capability Structure, + /// is the log2 of the interrupt vectors, minus one. Can only be 0b000..=0b101. + pub multi_message_enable: Option, + + /// The system-specific message address, must be DWORD aligned. + /// + /// The message address contains things like the CPU that will be targeted, at least on + /// x86_64. + pub message_address: Option, + + /// The upper 32 bits of the 64-bit message address. Not guaranteed to exist, and is + /// reserved on x86_64 (currently). + pub message_upper_address: Option, + + /// The message data, containing the actual interrupt vector (lower 8 bits), etc. + /// + /// The spec mentions that the lower N bits can be modified, where N is the multi message + /// enable, which means that the vector set here has to be aligned to that number, and that + /// all vectors in that range have to be allocated. + pub message_data: Option, + + /// A bitmap of the vectors that are masked. This field is not guaranteed (and not likely, + /// at least according to the feature flags I got from QEMU), to exist. + pub mask_bits: Option, +} + +/// Some flags that might be set simultaneously, but separately. +#[derive(Debug, Serialize, Deserialize)] +#[non_exhaustive] +pub enum SetFeatureInfo { + Msi(MsiSetFeatureInfo), + + MsiX { + /// Masks the entire function, and all of its vectors. + function_mask: Option, + }, +} + #[derive(Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum PcidClientRequest { @@ -122,12 +166,14 @@ pub enum PcidClientRequest { EnableFeature(PciFeature), FeatureStatus(PciFeature), FeatureInfo(PciFeature), + SetFeatureInfo(SetFeatureInfo), } #[derive(Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum PcidServerResponseError { NonexistentFeature(PciFeature), + InvalidBitPattern, } #[derive(Debug, Serialize, Deserialize)] @@ -139,6 +185,7 @@ pub enum PcidClientResponse { FeatureStatus(PciFeature, FeatureStatus), Error(PcidServerResponseError), FeatureInfo(PciFeature, PciFeatureInfo), + SetFeatureInfo(PciFeature), } // TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over diff --git a/pcid/src/main.rs b/pcid/src/main.rs index d2369d1707..4459185018 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -29,7 +29,7 @@ pub struct DriverHandler { state: Arc, } -fn with_pci_func_raw T>(pci: &Pci, bus_num: u8, dev_num: u8, func_num: u8, function: F) -> T { +fn with_pci_func_raw T>(pci: &dyn CfgAccess, bus_num: u8, dev_num: u8, func_num: u8, function: F) -> T { let bus = PciBus { pci, num: bus_num, @@ -46,7 +46,7 @@ fn with_pci_func_raw T>(pci: &Pci, bus_num: u8, dev_nu } impl DriverHandler { fn with_pci_func_raw T>(&self, function: F) -> T { - with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, function) + with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, function) } fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse { use driver_interface::*; @@ -70,7 +70,7 @@ impl DriverHandler { None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), }; unsafe { - with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| { + with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { capability.set_enabled(true); capability.write_message_control(func, offset); }); @@ -83,7 +83,7 @@ impl DriverHandler { None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), }; unsafe { - with_pci_func_raw(&self.state.pci, self.bus_num, self.dev_num, self.func_num, |func| { + with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { capability.set_msix_enabled(true); capability.write_a(func, offset); }); @@ -115,6 +115,56 @@ impl DriverHandler { return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)); } }), + PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set { + SetFeatureInfo::Msi(info_to_set) => if let Some((offset, info)) = self.capabilities.iter_mut().find_map(|(offset, capability)| Some((*offset, capability.as_msi_mut()?))) { + if let Some(mme) = info_to_set.multi_message_enable { + if info.multi_message_capable() < mme || mme > 0b101 { + return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern); + } + info.set_multi_message_enable(mme); + + } + if let Some(message_addr) = info_to_set.message_address { + if message_addr & 0b11 != 0 { + return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern); + } + info.set_message_address(message_addr); + } + if let Some(message_addr_upper) = info_to_set.message_upper_address { + info.set_message_upper_address(message_addr_upper); + } + if let Some(message_data) = info_to_set.message_data { + if message_data & ((1 << info.multi_message_enable()) - 1) != 0 { + return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern); + } + info.set_message_data(message_data); + } + if let Some(mask_bits) = info_to_set.mask_bits { + info.set_mask_bits(mask_bits); + } + unsafe { + with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { + info.write_all(func, offset); + }); + } + PcidClientResponse::SetFeatureInfo(PciFeature::Msi) + } else { + return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(PciFeature::Msi)); + } + SetFeatureInfo::MsiX { function_mask } => if let Some((offset, info)) = self.capabilities.iter_mut().find_map(|(offset, capability)| Some((*offset, capability.as_msix_mut()?))) { + if let Some(mask) = function_mask { + info.set_function_mask(mask); + unsafe { + with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { + info.write_a(func, offset); + }); + } + } + PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) + } else { + return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(PciFeature::MsiX)); + } + } } } fn handle_spawn(mut self, pcid_to_client_write: Option, pcid_from_client_read: Option, args: driver_interface::SubdriverArguments) { diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index d808776cec..14714cb7e9 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -48,13 +48,13 @@ pub enum MsiCapability { _32BitAddress { message_control: u32, message_address: u32, - message_data: u32, + message_data: u16, }, _64BitAddress { message_control: u32, message_address_lo: u32, message_address_hi: u32, - message_data: u32, + message_data: u16, }, _32BitAddressWithPvm { message_control: u32, diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index cd1561b755..54e2f386c6 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -48,13 +48,13 @@ impl MsiCapability { message_control: dword, message_address_lo: reader.read_u32(u16::from(offset + 4)), message_address_hi: reader.read_u32(u16::from(offset + 8)), - message_data: reader.read_u32(u16::from(offset + 12)), + message_data: reader.read_u32(u16::from(offset + 12)) as u16, } } else { Self::_32BitAddress { message_control: dword, message_address: reader.read_u32(u16::from(offset + 4)), - message_data: reader.read_u32(u16::from(offset + 8)), + message_data: reader.read_u32(u16::from(offset + 8)) as u16, } } } @@ -80,7 +80,7 @@ impl MsiCapability { | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, } } - pub unsafe fn write_message_control(&mut self, writer: &W, offset: u8) { + pub unsafe fn write_message_control(&self, writer: &W, offset: u8) { writer.write_u32(u16::from(offset), self.message_control_raw()); } pub fn is_pvt_capable(&self) -> bool { @@ -100,14 +100,106 @@ impl MsiCapability { pub fn multi_message_capable(&self) -> u8 { ((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8 } - pub fn multi_message_enabled(&self) -> u8 { + pub fn multi_message_enable(&self) -> u8 { ((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8 } - pub fn set_multi_message_enabled(&mut self, log_mme: u8) { + pub fn set_multi_message_enable(&mut self, log_mme: u8) { let mut new_message_control = self.message_control() & (!Self::MC_MULTI_MESSAGE_ENABLE_MASK); new_message_control |= (u16::from(log_mme) << Self::MC_MULTI_MESSAGE_ENABLE_SHIFT); self.set_message_control(new_message_control); } + + pub fn message_address(&self) -> u32 { + match self { + &Self::_32BitAddress { message_address, .. } | &Self::_32BitAddressWithPvm { message_address, .. } => message_address, + &Self::_64BitAddress { message_address_lo, .. } | &Self::_64BitAddressWithPvm { message_address_lo, .. } => message_address_lo, + } + } + pub fn message_upper_address(&self) -> Option { + match self { + &Self::_64BitAddress { message_address_hi, .. } | &Self::_64BitAddressWithPvm { message_address_hi, .. } => Some(message_address_hi), + &Self::_32BitAddress { .. } | &Self::_32BitAddressWithPvm { .. } => None, + } + } + pub fn message_data(&self) -> u16 { + match self { + &Self::_32BitAddress { message_data, .. } | &Self::_64BitAddress { message_data, .. } => message_data, + &Self::_32BitAddressWithPvm { message_data, .. } | &Self::_64BitAddressWithPvm { message_data, .. } => message_data as u16, + } + } + pub fn mask_bits(&self) -> Option { + match self { + &Self::_32BitAddressWithPvm { mask_bits, .. } | &Self::_64BitAddressWithPvm { mask_bits, .. } => Some(mask_bits), + &Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => None, + } + } + pub fn pending_bits(&self) -> Option { + match self { + &Self::_32BitAddressWithPvm { pending_bits, .. } | &Self::_64BitAddressWithPvm { pending_bits, .. } => Some(pending_bits), + &Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => None, + } + } + pub fn set_message_address(&mut self, message_address: u32) { + assert_eq!(message_address & 0xFFFF_FFFC, message_address, "unaligned message address (this should already be validated)"); + match self { + &mut Self::_32BitAddress { message_address: ref mut addr, .. } | &mut Self::_32BitAddressWithPvm { message_address: ref mut addr, .. } => *addr = message_address, + &mut Self::_64BitAddress { message_address_lo: ref mut addr, .. } | &mut Self::_64BitAddressWithPvm { message_address_lo: ref mut addr, .. } => *addr = message_address, + } + } + pub fn set_message_upper_address(&mut self, message_upper_address: u32) -> Option<()> { + match self { + &mut Self::_64BitAddress { ref mut message_address_hi, .. } | &mut Self::_64BitAddressWithPvm { ref mut message_address_hi, .. } => *message_address_hi = message_upper_address, + &mut Self::_32BitAddress { .. } | &mut Self::_32BitAddressWithPvm { .. } => return None, + } + Some(()) + } + pub fn set_message_data(&mut self, value: u16) { + match self { + &mut Self::_32BitAddress { ref mut message_data, .. } | &mut Self::_64BitAddress { ref mut message_data, .. } => *message_data = value, + &mut Self::_32BitAddressWithPvm { ref mut message_data, .. } | &mut Self::_64BitAddressWithPvm { ref mut message_data, .. } => { + *message_data &= 0xFFFF_0000; + *message_data |= u32::from(value); + } + } + } + pub fn set_mask_bits(&mut self, mask_bits: u32) -> Option<()> { + match self { + &mut Self::_32BitAddressWithPvm { mask_bits: ref mut bits, .. } | &mut Self::_64BitAddressWithPvm { mask_bits: ref mut bits, .. } => *bits = mask_bits, + &mut Self::_32BitAddress { .. } | &mut Self::_64BitAddress { .. } => return None, + } + Some(()) + } + pub unsafe fn write_message_address(&self, writer: &W, offset: u8) { + writer.write_u32(u16::from(offset) + 4, self.message_address()) + } + pub unsafe fn write_message_upper_address(&self, writer: &W, offset: u8) -> Option<()> { + let value = self.message_upper_address()?; + writer.write_u32(u16::from(offset + 8), value); + Some(()) + } + pub unsafe fn write_message_data(&self, writer: &W, offset: u8) { + match self { + &Self::_32BitAddress { message_data, .. } => writer.write_u32(u16::from(offset + 8), message_data.into()), + &Self::_32BitAddressWithPvm { message_data, .. } => writer.write_u32(u16::from(offset + 8), message_data), + &Self::_64BitAddress { message_data, .. } => writer.write_u32(u16::from(offset + 12), message_data.into()), + &Self::_64BitAddressWithPvm { message_data, .. } => writer.write_u32(u16::from(offset + 12), message_data), + } + } + pub unsafe fn write_mask_bits(&self, writer: &W, offset: u8) -> Option<()> { + match self { + &Self::_32BitAddressWithPvm { mask_bits, .. } => writer.write_u32(u16::from(offset + 12), mask_bits), + &Self::_64BitAddressWithPvm { mask_bits, .. } => writer.write_u32(u16::from(offset + 16), mask_bits), + &Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => return None, + } + Some(()) + } + pub unsafe fn write_all(&self, writer: &W, offset: u8) { + self.write_message_control(writer, offset); + self.write_message_address(writer, offset); + self.write_message_upper_address(writer, offset); + self.write_message_data(writer, offset); + self.write_mask_bits(writer, offset); + } } impl MsixCapability { diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 66a84b2262..d475b453c5 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -144,7 +144,7 @@ fn main() { PciFeatureInfo::MsiX(_) => panic!(), }; // use one vector - capability.set_multi_message_enabled(0); + capability.set_multi_message_enable(0); todo!("msi (msix is implemented though)") } else if msix_enabled { From 4f62888bb40b6c936d06d1a1741abf1a177e9e06 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 21 Apr 2020 15:42:29 +0200 Subject: [PATCH 0392/1301] Various fixes. --- pcid/src/driver_interface/irq_helpers.rs | 137 ++++++++++++++++++ .../mod.rs} | 11 +- pcid/src/main.rs | 2 +- xhcid/src/main.rs | 92 +++++------- 4 files changed, 183 insertions(+), 59 deletions(-) create mode 100644 pcid/src/driver_interface/irq_helpers.rs rename pcid/src/{driver_interface.rs => driver_interface/mod.rs} (95%) diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs new file mode 100644 index 0000000000..58d252be7a --- /dev/null +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -0,0 +1,137 @@ +//! IRQ helpers. +//! +//! This module allows easy handling of the `irq:` scheme, and allocating interrupt vectors for use +//! by INTx#, MSI, or MSI-X. + +use std::fs::{self, File}; +use std::io::{self, prelude::*}; +use std::num::NonZeroU8; +use std::ops; + +/// Read the local APIC ID of the bootstrap processor. +pub fn read_bsp_apic_id() -> io::Result { + let mut buffer = [0u8; 8]; + + let mut file = File::open("irq:bsp")?; + let bytes_read = file.read(&mut buffer)?; + + Ok(if bytes_read == 8 { + u64::from_le_bytes(buffer) as u32 + } else if bytes_read == 4 { + u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]) + } else { + panic!("`irq:` scheme responded with {} bytes, expected {}", bytes_read, std::mem::size_of::()); + }) +} + +/// Allocate multiple interrupt vectors, from the IDT of the bootstrap processor, returning the +/// start vector and the IRQ handles. +/// +/// The alignment is a requirement for the allocation range. For example, with an alignment of 8, +/// only ranges that begin with a multiple of eight are accepted. The IRQ handles returned will +/// always correspond to the subsequent IRQ numbers beginning the first value in the return tuple. +/// +/// This function is not actually guaranteed to allocate all of the IRQs specified in `count`, +/// since another process might already have requested that vector. The caller must check that +/// the returned vector have the same length as `count`. In the future this function may perhaps +/// lock the entire directory to prevent this from happening, or maybe find the smallest free range +/// with the minimum alignment, to allow other drivers to obtain their necessary IRQs. +/// +/// Note that this count/alignment restriction is only mandatory for MSI; MSI-X allows for +/// individually allocated vectors that might be spread out, even on multiple CPUs. Thus, multiple +/// invocations with alignment 1 and count 1 are totally acceptable, although allocating in bulk +/// minimizes the initialization overhead, even though it's negligible. +pub fn allocate_aligned_interrupt_vectors(alignment: NonZeroU8, count: u8) -> io::Result)>> { + if count == 0 { return Ok(None) } + + let available_irqs = fs::read_dir("irq:")?; + let mut available_irq_numbers = available_irqs.filter_map(|entry| -> Option> { + let entry = match entry { + Ok(e) => e, + Err(err) => return Some(Err(err)), + }; + + let path = entry.path(); + + let file_name = match path.file_name() { + Some(f) => f, + None => return None, + }; + + let path_str = match file_name.to_str() { + Some(s) => s, + None => return None, + }; + + // note that there might be future subdirectories in the IRQ scheme, such as `cpu-/`, thus no error but just None + match path_str.parse::() { + Ok(p) => Some(Ok(p)), + Err(_) => None, + } + }); + + // TODO: fcntl F_SETLK on `irq:/`? + + let mut handles = Vec::with_capacity(usize::from(count)); + + let mut index = 0; + let mut first = None; + + while let Some(number) = available_irq_numbers.next() { + let number = number?; + + // Skip until a suitable alignment is found. + if number % u8::from(alignment) != 0 { + continue; + } + let first = *first.get_or_insert(number); + let irq_number = first + index; + + // From the point where the range is aligned, we can start to advance until `count` IRQs + // have been allocated. + if index >= count { + break; + } + + // if found, reserve the irq + let irq_handle = match File::create(format!("irq:{}", irq_number)) { + Ok(handle) => handle, + + // return early if the entire range couldn't be allocated + Err(err) if err.kind() == io::ErrorKind::NotFound => break, + + Err(err) => return Err(err), + }; + handles.push(irq_handle); + index += 1; + } + if handles.is_empty() { + return Ok(None); + } + let first = match first { + Some(f) => f, + None => return Ok(None), + }; + + Ok(Some((first + 32, handles))) +} + +/// Allocate at most `count` interrupt vectors, which can start at any offset. Unless MSI is used +/// and an entire aligned range of vectors is needed, this function should be used. +pub fn allocate_interrupt_vectors(count: u8) -> io::Result)>> { + allocate_aligned_interrupt_vectors(NonZeroU8::new(1).unwrap(), count) +} + +/// Allocate a single interrupt vector, returning both the vector number (starting from 32 up to +/// 254), and its IRQ handle which is then reserved. Returns Ok(None) if allocation fails due to +/// no available IRQs. +pub fn allocate_single_interrupt_vector() -> io::Result> { + let (base, mut files) = match allocate_interrupt_vectors(1) { + Ok(Some((base, files))) => (base, files), + Ok(None) => return Ok(None), + Err(err) => return Err(err), + }; + assert_eq!(files.len(), 1); + Ok(Some((base, files.pop().unwrap()))) +} diff --git a/pcid/src/driver_interface.rs b/pcid/src/driver_interface/mod.rs similarity index 95% rename from pcid/src/driver_interface.rs rename to pcid/src/driver_interface/mod.rs index 12a055d666..e301bbe597 100644 --- a/pcid/src/driver_interface.rs +++ b/pcid/src/driver_interface/mod.rs @@ -10,6 +10,8 @@ use thiserror::Error; pub use crate::pci::PciBar; pub use crate::pci::msi; +pub mod irq_helpers; + #[derive(Clone, Copy, Debug, Serialize, Deserialize)] #[repr(u8)] pub enum LegacyInterruptPin { @@ -118,7 +120,7 @@ pub type Result = std::result::Result; // TODO: Remove these "features" and just go strait to the actual thing. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct MsiSetFeatureInfo { /// The Multi Message Enable field of the Message Control in the MSI Capability Structure, /// is the log2 of the interrupt vectors, minus one. Can only be 0b000..=0b101. @@ -273,4 +275,11 @@ impl PcidServerHandle { other => Err(PcidClientHandleError::InvalidResponse(other)), } } + pub fn set_feature_info(&mut self, info: SetFeatureInfo) -> Result<()> { + self.send(&PcidClientRequest::SetFeatureInfo(info))?; + match self.recv()? { + PcidClientResponse::SetFeatureInfo(_) => Ok(()), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 4459185018..f5b0d83ec9 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -195,7 +195,7 @@ impl State { fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, dev_num: u8, func_num: u8, header: PciHeader) { - let pci = &state.pci; + let pci = state.preferred_cfg_access(); let raw_class: u8 = header.class().into(); let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index d475b453c5..8b9c38c026 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -11,7 +11,8 @@ use std::ptr::NonNull; use std::sync::{Arc, Mutex}; use std::env; -use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo}; +use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; +use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector}; use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; use event::{Event, EventQueue}; @@ -32,49 +33,6 @@ pub mod driver_interface; mod usb; mod xhci; -/// Read the local APIC id of the bootstrap processor. -fn read_bsp_apic_id() -> io::Result { - let mut buffer = [0u8; 8]; - - let mut file = File::open("irq:bsp")?; - let bytes_read = file.read(&mut buffer)?; - - Ok(if bytes_read == 8 { - u64::from_le_bytes(buffer) as u32 - } else if bytes_read == 4 { - u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]) - } else { - panic!("`irq:` scheme responded with {} bytes, expected {}", bytes_read, std::mem::size_of::()); - }) -} -/// Allocate an interrupt vector, located at the BSP's IDT. -fn allocate_interrupt_vector() -> io::Result> { - let available_irqs = fs::read_dir("irq:")?; - - for entry in available_irqs { - let entry = entry?; - let path = entry.path(); - - let file_name = match path.file_name() { - Some(f) => f, - None => continue, - }; - - let path_str = match file_name.to_str() { - Some(s) => s, - None => continue, - }; - - if let Ok(irq_number) = path_str.parse::() { - // if found, reserve the irq - let irq_handle = File::create(format!("irq:{}", irq_number))?; - let interrupt_vector = irq_number + 32; - return Ok(Some((interrupt_vector, irq_handle))); - } - } - Ok(None) -} - async fn handle_packet(hci: Arc, packet: Packet) -> Packet { todo!() } @@ -124,29 +82,44 @@ fn main() { let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); - dbg!(has_msi, msi_enabled); - dbg!(has_msix, msix_enabled); - if has_msi && !msi_enabled && !has_msix { - pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); - info!("Enabled MSI"); msi_enabled = true; } if has_msix && !msix_enabled { - pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); - info!("Enabled MSI-X"); msix_enabled = true; } let (mut irq_file, interrupt_method) = if msi_enabled && !msix_enabled { + use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; + let mut capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI capability structure from pcid") { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), }; - // use one vector - capability.set_multi_message_enable(0); + // TODO: Allow allocation of up to 32 vectors. - todo!("msi (msix is implemented though)") + // TODO: Find a way to abstract this away, potantially as a helper module for + // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. + + let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); + let msg_addr = x86_64_msix::message_address(destination_id as u8, false, false, 0b00); + + let (vector, interrupt_handle) = allocate_single_interrupt_vector().expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); + let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + + let set_feature_info = MsiSetFeatureInfo { + multi_message_enable: Some(0), + message_address: Some(msg_addr), + message_upper_address: Some(0), + message_data: Some(msg_data as u16), + mask_bits: None, + }; + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("xhcid: failed to set feature info"); + + pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); + info!("Enabled MSI"); + + (Some(interrupt_handle), InterruptMethod::Msi) } else if msix_enabled { let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), @@ -178,7 +151,7 @@ fn main() { // Allocate one msi vector. - { + let method = { use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; // primary interrupter @@ -192,7 +165,7 @@ fn main() { let dm = false; let addr = x86_64_msix::message_address(destination_id.try_into().expect("xhcid: BSP apic id couldn't fit u8"), rh, dm, 0b00); - let (vector, interrupt_handle) = allocate_interrupt_vector().expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); + let (vector, interrupt_handle) = allocate_single_interrupt_vector().expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); table_entry_pointer.addr_lo.write(addr); @@ -201,7 +174,12 @@ fn main() { table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); (Some(interrupt_handle), InterruptMethod::MsiX(Mutex::new(info))) - } + }; + + pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); + info!("Enabled MSI-X"); + + method } else if pci_config.func.legacy_interrupt_pin.is_some() { // legacy INTx# interrupt pins. (Some(File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file")), InterruptMethod::Intx) From cafee6ad7bcc360585f9bc72c20958ca14c0b215 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 22 Apr 2020 13:43:45 +0200 Subject: [PATCH 0393/1301] Allow per-cpu IRQ allocation. --- pcid/src/driver_interface/irq_helpers.rs | 47 +++++++++++++++++------- xhcid/src/main.rs | 14 ++++--- 2 files changed, 42 insertions(+), 19 deletions(-) diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index 58d252be7a..5d380dba79 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -3,25 +3,45 @@ //! This module allows easy handling of the `irq:` scheme, and allocating interrupt vectors for use //! by INTx#, MSI, or MSI-X. +use std::convert::TryFrom; use std::fs::{self, File}; use std::io::{self, prelude::*}; use std::num::NonZeroU8; use std::ops; /// Read the local APIC ID of the bootstrap processor. -pub fn read_bsp_apic_id() -> io::Result { +pub fn read_bsp_apic_id() -> io::Result { let mut buffer = [0u8; 8]; let mut file = File::open("irq:bsp")?; let bytes_read = file.read(&mut buffer)?; - Ok(if bytes_read == 8 { - u64::from_le_bytes(buffer) as u32 + (if bytes_read == 8 { + usize::try_from(u64::from_le_bytes(buffer)) } else if bytes_read == 4 { - u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]]) + usize::try_from(u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]])) } else { panic!("`irq:` scheme responded with {} bytes, expected {}", bytes_read, std::mem::size_of::()); - }) + }).or(Err(io::Error::new(io::ErrorKind::InvalidData, "bad BSP int size"))) +} + +// TODO: Perhaps read the MADT instead? +/// Obtains an interator over all of the visible CPU ids, for use in IRQ allocation and MSI +/// capability structs or MSI-X tables. +pub fn cpu_ids() -> io::Result> + 'static> { + Ok(fs::read_dir("irq:")? + .filter_map(|entry| -> Option> { match entry { + Ok(e) => { + let path = e.path(); + let file_name = path.file_name()?.to_str()?; + // the file name should be in the format `cpu-` + if ! file_name.starts_with("cpu-") { + return None; + } + u8::from_str_radix(&file_name[4..], 16).map(usize::from).map(Ok).ok() + } + Err(e) => Some(Err(e)), + } })) } /// Allocate multiple interrupt vectors, from the IDT of the bootstrap processor, returning the @@ -41,10 +61,13 @@ pub fn read_bsp_apic_id() -> io::Result { /// individually allocated vectors that might be spread out, even on multiple CPUs. Thus, multiple /// invocations with alignment 1 and count 1 are totally acceptable, although allocating in bulk /// minimizes the initialization overhead, even though it's negligible. -pub fn allocate_aligned_interrupt_vectors(alignment: NonZeroU8, count: u8) -> io::Result)>> { +/// +/// Every interrupt vector will be allocated in the same CPU's IDT, as specified by `cpu_id`. +pub fn allocate_aligned_interrupt_vectors(cpu_id: usize, alignment: NonZeroU8, count: u8) -> io::Result)>> { + let cpu_id = u8::try_from(cpu_id).expect("usize cpu ids not implemented yet"); if count == 0 { return Ok(None) } - let available_irqs = fs::read_dir("irq:")?; + let available_irqs = fs::read_dir(format!("irq:{:02x}", cpu_id))?; let mut available_irq_numbers = available_irqs.filter_map(|entry| -> Option> { let entry = match entry { Ok(e) => e, @@ -63,8 +86,6 @@ pub fn allocate_aligned_interrupt_vectors(alignment: NonZeroU8, count: u8) -> io None => return None, }; - // note that there might be future subdirectories in the IRQ scheme, such as `cpu-/`, thus no error but just None match path_str.parse::() { Ok(p) => Some(Ok(p)), Err(_) => None, @@ -119,15 +140,15 @@ pub fn allocate_aligned_interrupt_vectors(alignment: NonZeroU8, count: u8) -> io /// Allocate at most `count` interrupt vectors, which can start at any offset. Unless MSI is used /// and an entire aligned range of vectors is needed, this function should be used. -pub fn allocate_interrupt_vectors(count: u8) -> io::Result)>> { - allocate_aligned_interrupt_vectors(NonZeroU8::new(1).unwrap(), count) +pub fn allocate_interrupt_vectors(cpu_id: usize, count: u8) -> io::Result)>> { + allocate_aligned_interrupt_vectors(cpu_id, NonZeroU8::new(1).unwrap(), count) } /// Allocate a single interrupt vector, returning both the vector number (starting from 32 up to /// 254), and its IRQ handle which is then reserved. Returns Ok(None) if allocation fails due to /// no available IRQs. -pub fn allocate_single_interrupt_vector() -> io::Result> { - let (base, mut files) = match allocate_interrupt_vectors(1) { +pub fn allocate_single_interrupt_vector(cpu_id: usize) -> io::Result> { + let (base, mut files) = match allocate_interrupt_vectors(cpu_id, 1) { Ok(Some((base, files))) => (base, files), Ok(None) => return Ok(None), Err(err) => return Err(err), diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 8b9c38c026..adcad485f8 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -1,7 +1,7 @@ #[macro_use] extern crate bitflags; -use std::convert::TryInto; +use std::convert::{TryFrom, TryInto}; use std::fs::{self, File}; use std::future::Future; use std::io::{self, Read, Write}; @@ -52,7 +52,7 @@ fn main() { Ok(logger) => match logger.with_stdout_mirror().enable() { Ok(_) => { println!("xhcid: enabled logger"); - log::set_max_level(log::LevelFilter::Debug); + log::set_max_level(log::LevelFilter::Trace); } Err(error) => eprintln!("xhcid: failed to set default logger: {}", error), } @@ -102,9 +102,10 @@ fn main() { // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); - let msg_addr = x86_64_msix::message_address(destination_id as u8, false, false, 0b00); + let lapic_id = u8::try_from(destination_id).expect("CPU id didn't fit inside u8"); + let msg_addr = x86_64_msix::message_address(lapic_id, false, false, 0b00); - let (vector, interrupt_handle) = allocate_single_interrupt_vector().expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); + let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); let set_feature_info = MsiSetFeatureInfo { @@ -161,11 +162,12 @@ fn main() { let table_entry_pointer = info.table_entry_pointer(k); let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); + let lapic_id = u8::try_from(destination_id).expect("xhcid: CPU id couldn't fit inside u8"); let rh = false; let dm = false; - let addr = x86_64_msix::message_address(destination_id.try_into().expect("xhcid: BSP apic id couldn't fit u8"), rh, dm, 0b00); + let addr = x86_64_msix::message_address(lapic_id, rh, dm, 0b00); - let (vector, interrupt_handle) = allocate_single_interrupt_vector().expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); + let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); table_entry_pointer.addr_lo.write(addr); From 85691b8f4ef3b0ef060f80a5ea558222455ca034 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 22 Apr 2020 14:43:06 +0200 Subject: [PATCH 0394/1301] Fix xhcid. --- pcid/src/driver_interface/irq_helpers.rs | 16 +++++++--------- pcid/src/main.rs | 4 +++- xhcid/src/main.rs | 1 - 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index 5d380dba79..da928bf8d2 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -44,7 +44,7 @@ pub fn cpu_ids() -> io::Result> + 'static } })) } -/// Allocate multiple interrupt vectors, from the IDT of the bootstrap processor, returning the +/// Allocate multiple interrupt vectors, from the IDT of the specified processor, returning the /// start vector and the IRQ handles. /// /// The alignment is a requirement for the allocation range. For example, with an alignment of 8, @@ -52,22 +52,20 @@ pub fn cpu_ids() -> io::Result> + 'static /// always correspond to the subsequent IRQ numbers beginning the first value in the return tuple. /// /// This function is not actually guaranteed to allocate all of the IRQs specified in `count`, -/// since another process might already have requested that vector. The caller must check that -/// the returned vector have the same length as `count`. In the future this function may perhaps -/// lock the entire directory to prevent this from happening, or maybe find the smallest free range -/// with the minimum alignment, to allow other drivers to obtain their necessary IRQs. +/// since another process might already have requested one vector in the range. The caller must +/// check that the returned vector have the same length as `count`. In the future this function may +/// perhaps lock the entire directory to prevent this from happening, or maybe find the smallest free +/// range with the minimum alignment, to allow other drivers to obtain their necessary IRQs. /// /// Note that this count/alignment restriction is only mandatory for MSI; MSI-X allows for /// individually allocated vectors that might be spread out, even on multiple CPUs. Thus, multiple /// invocations with alignment 1 and count 1 are totally acceptable, although allocating in bulk /// minimizes the initialization overhead, even though it's negligible. -/// -/// Every interrupt vector will be allocated in the same CPU's IDT, as specified by `cpu_id`. pub fn allocate_aligned_interrupt_vectors(cpu_id: usize, alignment: NonZeroU8, count: u8) -> io::Result)>> { let cpu_id = u8::try_from(cpu_id).expect("usize cpu ids not implemented yet"); if count == 0 { return Ok(None) } - let available_irqs = fs::read_dir(format!("irq:{:02x}", cpu_id))?; + let available_irqs = fs::read_dir(format!("irq:cpu-{:02x}", cpu_id))?; let mut available_irq_numbers = available_irqs.filter_map(|entry| -> Option> { let entry = match entry { Ok(e) => e, @@ -116,7 +114,7 @@ pub fn allocate_aligned_interrupt_vectors(cpu_id: usize, alignment: NonZeroU8, c } // if found, reserve the irq - let irq_handle = match File::create(format!("irq:{}", irq_number)) { + let irq_handle = match File::create(format!("irq:cpu-{:02x}/{}", cpu_id, irq_number)) { Ok(handle) => handle, // return early if the entire range couldn't be allocated diff --git a/pcid/src/main.rs b/pcid/src/main.rs index f5b0d83ec9..34b8efee17 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -189,7 +189,9 @@ pub struct State { } impl State { fn preferred_cfg_access(&self) -> &dyn CfgAccess { - self.pcie.as_ref().map(|pcie| pcie as &dyn CfgAccess).unwrap_or(&*self.pci as &dyn CfgAccess) + // TODO + //self.pcie.as_ref().map(|pcie| pcie as &dyn CfgAccess).unwrap_or(&*self.pci as &dyn CfgAccess) + &*self.pci as &dyn CfgAccess } } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index adcad485f8..081ee09489 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -132,7 +132,6 @@ fn main() { let pba_min_length = crate::xhci::scheme::div_round_up(table_size, 8); let pba_base = capability.pba_base_pointer(pci_config.func.bars); - dbg!(table_size, table_base, table_min_length, pba_base); if !(bar_ptr..bar_ptr + 65536).contains(&(table_base as u32 + table_min_length as u32)) { todo!() From aea6e1b84c9afba333acd8f6d5a5585f69bd9209 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 22 Apr 2020 18:09:56 +0200 Subject: [PATCH 0395/1301] Improve xhcid logging. --- Cargo.lock | 150 +++++++++++++++++++++++----------------------- xhcid/Cargo.toml | 2 +- xhcid/src/main.rs | 51 ++++++++++++---- 3 files changed, 116 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9398d25a36..f4d41629f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,8 +47,8 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -133,7 +133,7 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.50" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -144,10 +144,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chashmap" version = "2.2.2" -source = "git+https://gitlab.redox-os.org/redox-os/chashmap.git#da92c702e052cde00db5e409dfb234af71928152" +source = "git+https://gitlab.redox-os.org/redox-os/chashmap.git#9a36a4df91930628390d70b697800e32b9e7c9bd" dependencies = [ "owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -157,7 +157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -374,10 +374,10 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -395,8 +395,8 @@ dependencies = [ "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -439,7 +439,7 @@ name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -478,7 +478,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.68" +version = "0.2.69" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -497,7 +497,7 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -560,7 +560,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -579,7 +579,7 @@ dependencies = [ "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", @@ -593,7 +593,7 @@ version = "0.6.7" source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#22580ca398cdb5ed6f50fb61134e5579e2213999" dependencies = [ "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", ] @@ -614,7 +614,7 @@ version = "0.2.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -627,7 +627,7 @@ dependencies = [ "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.2 (git+https://github.com/a8m/pb)", @@ -647,7 +647,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-uni dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -669,7 +669,7 @@ version = "0.0.1" source = "git+https://github.com/willem66745/ntpclient-rust#7e3bdf60eb940825789a8da5181025320e3050b0" dependencies = [ "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -711,11 +711,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -762,12 +762,11 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.9.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -775,7 +774,7 @@ name = "parking_lot_core" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -784,15 +783,14 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.6.2" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -812,9 +810,9 @@ version = "1.0.2" source = "git+https://github.com/a8m/pb#87c29c05486afa7335916c870ea3621ff7ef2966" dependencies = [ "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -823,9 +821,9 @@ name = "pbr" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -836,13 +834,13 @@ dependencies = [ "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -909,7 +907,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -964,7 +962,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -976,7 +974,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1019,10 +1017,11 @@ dependencies = [ [[package]] name = "redox-log" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git#08693d48b2d7b56fcb07a1e62e257bacce749cef" +source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0#30f6bf2464c462c32cd215bc0f1eedafa0707a04" dependencies = [ "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1060,9 +1059,9 @@ name = "ring" version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1161,7 +1160,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1173,7 +1172,7 @@ version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1232,7 +1231,7 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1284,7 +1283,7 @@ name = "termion" version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1300,15 +1299,15 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "thiserror-impl 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thiserror-impl" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1318,11 +1317,10 @@ dependencies = [ [[package]] name = "time" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1334,7 +1332,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -1405,7 +1403,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", @@ -1434,7 +1432,7 @@ dependencies = [ "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", ] @@ -1472,7 +1470,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", "mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", @@ -1520,7 +1518,7 @@ name = "unicode-normalization" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1573,7 +1571,7 @@ dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] @@ -1700,13 +1698,13 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pcid 0.1.0", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git)", + "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1726,7 +1724,7 @@ dependencies = [ "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" +"checksum cc 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9384ca4b90c0ea47e19a5c996d6643a3e73dedf9b89c65efb67587e34da1bb" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "" "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" @@ -1753,7 +1751,7 @@ dependencies = [ "checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" "checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" "checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" -"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +"checksum hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8a0d737e0f947a1864e93d33fdef4af8445a00d1ed8dc0c8ddb73139ea6abf15" "checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" "checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" "checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" @@ -1763,10 +1761,10 @@ dependencies = [ "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" +"checksum libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" "checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" -"checksum lock_api 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "79b2de95ecb4691949fea4716ca53cdbcfccb2c612e19644a8bad05edcf9f47b" +"checksum lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" @@ -1787,14 +1785,14 @@ dependencies = [ "checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" "checksum num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" -"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" +"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402" "checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" +"checksum parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" -"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" +"checksum parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" "checksum pbr 1.0.2 (git+https://github.com/a8m/pb)" = "" "checksum pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4403eb718d70c03ee279e51737782902c68cca01e870a33b6a2f9dfb50b9cd83" @@ -1817,7 +1815,7 @@ dependencies = [ "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git)" = "" +"checksum redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)" = "" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" @@ -1842,7 +1840,7 @@ dependencies = [ "checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -"checksum smallvec 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c2fb2ec9bcd216a5b0d0ccf31ab17b5ed1d627960edff65bbe95d3ce221cefc" +"checksum smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05720e22615919e4734f6a99ceae50d00226c3c5aca406e102ebc33298214e0a" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" @@ -1851,9 +1849,9 @@ dependencies = [ "checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "f0570dc61221295909abdb95c739f2e74325e14293b2026b0a7e195091ec54ae" -"checksum thiserror-impl 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "227362df41d566be41a28f64401e07a043157c21c14b9785a0d8e256f940a8fd" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum thiserror 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "54b3d3d2ff68104100ab257bb6bb0cb26c901abe4bd4ba15961f3bf867924012" +"checksum thiserror-impl 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972988113b7715266f91250ddb98070d033c62a011fa0fcc57434a649310dd" +"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" "checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index c1ef18ce37..10072dd3c4 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -20,7 +20,7 @@ plain = "0.2" lazy_static = "1.4" log = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git" } +redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 081ee09489..0f1cf1553b 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -17,6 +17,7 @@ use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; use event::{Event, EventQueue}; use log::info; +use redox_log::{RedoxLogger, OutputBuilder}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; @@ -37,6 +38,45 @@ async fn handle_packet(hci: Arc, packet: Packet) -> Packet { todo!() } +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .build() + ); + + match OutputBuilder::in_redox_logging_scheme("usb", "host", "xhci.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Trace) + .build() + ), + Err(error) => eprintln!("Failed to create xhci.log: {}", error), + } + + match OutputBuilder::in_redox_logging_scheme("usb", "host", "xhci.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Trace) + .with_ansi_escape_codes() + .build() + ), + Err(error) => eprintln!("Failed to create xhci.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("xhcid: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("xhcid: failed to set default logger: {}", error); + None + } + } +} + fn main() { let mut args = env::args().skip(1); @@ -48,16 +88,7 @@ fn main() { return; } - match redox_log::RedoxLogger::new("usb", "host", "xhci.log") { - Ok(logger) => match logger.with_stdout_mirror().enable() { - Ok(_) => { - println!("xhcid: enabled logger"); - log::set_max_level(log::LevelFilter::Trace); - } - Err(error) => eprintln!("xhcid: failed to set default logger: {}", error), - } - Err(error) => eprintln!("xhcid: failed to initialize logger: {}", error), - } + setup_logging(); let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); From fe95c942ac334bd5e45c453f54a76bafa2cd0a5d Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 22 Apr 2020 18:27:43 +0200 Subject: [PATCH 0396/1301] Add pcid logging. --- Cargo.lock | 2 ++ pcid/Cargo.toml | 2 ++ pcid/src/main.rs | 67 +++++++++++++++++++++++++++++++++++++-------- pcid/src/pci/mod.rs | 4 ++- xhcid/src/main.rs | 11 +++++--- 5 files changed, 70 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f4d41629f9..7e3c14e7d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -835,7 +835,9 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index dae6e66cce..71c5682ed4 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -16,7 +16,9 @@ bincode = "1.2" bitflags = "1" byteorder = "1.2" libc = "0.2" +log = "0.4" plain = "0.2" +redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 34b8efee17..f8b02b1c4d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -9,6 +9,9 @@ use std::{env, io, i64, thread}; use syscall::iopl; +use log::{error, info, warn, trace}; +use redox_log::{OutputBuilder, RedoxLogger}; + use crate::config::Config; use crate::pci::{CfgAccess, Pci, PciIter, PciBar, PciBus, PciClass, PciDev, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; use crate::pci::cap::Capability as PciCapability; @@ -245,7 +248,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, string.push('\n'); - print!("{}", string); + info!("{}", string); for driver in config.drivers.iter() { if let Some(class) = driver.class { @@ -364,7 +367,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, }; crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() }; - println!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); + info!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); use driver_interface::LegacyInterruptPin; @@ -376,7 +379,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, 4 => Some(LegacyInterruptPin::IntD), other => { - println!("pcid: invalid interrupt pin: {}", other); + warn!("pcid: invalid interrupt pin: {}", other); None } }; @@ -426,7 +429,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, command.arg(&arg); } - println!("PCID SPAWN {:?}", command); + info!("PCID SPAWN {:?}", command); let (pcid_to_client_write, pcid_from_client_read, envs) = if driver.channel_name.is_some() { let mut fds1 = [0usize; 2]; @@ -459,16 +462,56 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, }); match child.wait() { Ok(_status) => (), - Err(err) => println!("pcid: failed to wait for {:?}: {}", command, err), + Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err), } } - Err(err) => println!("pcid: failed to execute {:?}: {}", command, err) + Err(err) => error!("pcid: failed to execute {:?}: {}", command, err) } } } } } +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_ansi_escape_codes() + .with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build() + ); + + match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Trace) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("pcid: failed to open pcid.log"), + } + match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Trace) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("pcid: failed to open pcid.ansi.log"), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("pcid: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("pcid: failed to set default logger: {}", error); + None + } + } +} + fn main() { let mut config = Config::default(); @@ -499,6 +542,8 @@ fn main() { } } + let _logger_ref = setup_logging(); + let pci = Arc::new(Pci::new()); let state = Arc::new(State { @@ -506,7 +551,7 @@ fn main() { pcie: match Pcie::new(Arc::clone(&pci)) { Ok(pcie) => Some(pcie), Err(error) => { - println!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error); + info!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error); None } }, @@ -515,7 +560,7 @@ fn main() { let pci = state.preferred_cfg_access(); - print!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV\n"); + info!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); 'bus: for bus in PciIter::new(pci) { 'dev: for dev in bus.devs() { @@ -528,16 +573,16 @@ fn main() { Err(PciHeaderError::NoDevice) => { if func_num == 0 { if dev.num == 0 { - // println!("PCI {:>02X}: no bus", bus.num); + trace!("PCI {:>02X}: no bus", bus.num); continue 'bus; } else { - // println!("PCI {:>02X}/{:>02X}: no dev", bus.num, dev.num); + trace!("PCI {:>02X}/{:>02X}: no dev", bus.num, dev.num); continue 'dev; } } }, Err(PciHeaderError::UnknownHeaderType(id)) => { - println!("pcid: unknown header type: {}", id); + warn!("pcid: unknown header type: {}", id); } } } diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index bea70cd448..3307c857c2 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -8,6 +8,8 @@ pub use self::dev::{PciDev, PciDevIter}; pub use self::func::PciFunc; pub use self::header::{PciHeader, PciHeaderError, PciHeaderType}; +use log::info; + mod bar; mod bus; pub mod cap; @@ -45,7 +47,7 @@ impl Pci { fn set_iopl() { // make sure that pcid is not granted io port permission unless pcie memory-mapped // configuration space is not available. - println!("PCI: couldn't find or access PCIe extended configuration, and thus falling back to PCI 3.0 io ports"); + info!("PCI: couldn't find or access PCIe extended configuration, and thus falling back to PCI 3.0 io ports"); unsafe { syscall::iopl(3).expect("pcid: failed to set iopl to 3"); } } fn address(bus: u8, dev: u8, func: u8, offset: u8) -> u32 { diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 0f1cf1553b..5c365aabac 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -44,6 +44,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { OutputBuilder::stderr() .with_filter(log::LevelFilter::Info) // limit global output to important info .with_ansi_escape_codes() + .flush_on_newline(true) .build() ); @@ -51,7 +52,8 @@ fn setup_logging() -> Option<&'static RedoxLogger> { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this b.with_filter(log::LevelFilter::Trace) - .build() + .flush_on_newline(true) + .build() ), Err(error) => eprintln!("Failed to create xhci.log: {}", error), } @@ -59,8 +61,9 @@ fn setup_logging() -> Option<&'static RedoxLogger> { match OutputBuilder::in_redox_logging_scheme("usb", "host", "xhci.ansi.log") { Ok(b) => logger = logger.with_output( b.with_filter(log::LevelFilter::Trace) - .with_ansi_escape_codes() - .build() + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() ), Err(error) => eprintln!("Failed to create xhci.ansi.log: {}", error), } @@ -88,7 +91,7 @@ fn main() { return; } - setup_logging(); + let _logger_ref = setup_logging(); let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); From 07d4ae0e605d1c3ed7a6917c2b1c1481cb4ca6f2 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 22 Apr 2020 18:31:18 +0200 Subject: [PATCH 0397/1301] Recognize the AHCI-specific SATA PCI capability. --- pcid/src/pci/cap.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 14714cb7e9..dfbb6a1feb 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -41,6 +41,7 @@ pub enum CapabilityId { Msi = 0x05, MsiX = 0x11, Pcie = 0x10, + Sata = 0x12, // only on AHCI functions } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] @@ -85,11 +86,12 @@ pub struct MsixCapability { pub c: u32, } -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum Capability { Msi(MsiCapability), MsiX(MsixCapability), Pcie(PcieCapability), + FunctionSpecific(u8, Vec), // TODO: Arrayvec Other(u8), } @@ -156,6 +158,8 @@ impl Capability { Self::parse_msix(reader, offset) } else if capability_id == CapabilityId::Pcie as u8 { Self::parse_pcie(reader, offset) + } else if capability_id == CapabilityId::Sata as u8 { + Self::FunctionSpecific(capability_id, reader.read_range(offset.into(), 8)) } else { Self::Other(capability_id) //panic!("unimplemented or malformed capability id: {}", capability_id) From 7b69d5b9b5f6dc48b01dd4b7cbf790589e5a4acb Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 22 Apr 2020 21:21:39 +0200 Subject: [PATCH 0398/1301] WIP: Use the enhanced pcid IPC. --- Cargo.lock | 10 +- initfs.toml | 5 +- nvmed/Cargo.toml | 5 +- nvmed/src/main.rs | 195 +++++++++++++++---------------- nvmed/src/nvme.rs | 6 +- pcid/src/config.rs | 2 +- pcid/src/driver_interface/mod.rs | 5 + pcid/src/main.rs | 4 +- xhcid/Cargo.toml | 1 + xhcid/src/main.rs | 8 +- 10 files changed, 125 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e3c14e7d4..f27f4203eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -355,7 +355,7 @@ dependencies = [ "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -729,9 +729,11 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "block-io-wrapper 0.1.0", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", + "pcid 0.1.0", + "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -860,7 +862,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pin-utils" -version = "0.1.0-alpha.4" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1799,7 +1801,7 @@ dependencies = [ "checksum pbr 1.0.2 (git+https://github.com/a8m/pb)" = "" "checksum pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4403eb718d70c03ee279e51737782902c68cca01e870a33b6a2f9dfb50b9cd83" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" +"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" "checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" diff --git a/initfs.toml b/initfs.toml index 6861491750..9d95b91f9f 100644 --- a/initfs.toml +++ b/initfs.toml @@ -28,6 +28,7 @@ name = "NVME storage" class = 1 subclass = 8 command = ["nvmed", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ"] +use_channel = true # vboxd [[drivers]] @@ -43,5 +44,5 @@ name = "XHCI" class = 12 subclass = 3 interface = 48 -command = ["xhcid", "$NAME", "$BAR0", "$IRQ"] -channel_name = "pcid-xhcid" +command = ["xhcid"] +use_channel = true diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index b0bbfee4b2..92a180f585 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -5,7 +5,10 @@ edition = "2018" [dependencies] bitflags = "0.7" -spin = "0.4" +log = "0.4" +redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } redox_syscall = "0.1" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } block-io-wrapper = { path = "../block-io-wrapper" } + +pcid = { path = "../pcid" } diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index fb37c0f6b9..7e6178840a 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -1,16 +1,14 @@ -#![feature(asm)] - -extern crate bitflags; -extern crate spin; -extern crate syscall; - use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write}; use std::os::unix::io::{RawFd, FromRawFd}; +use pcid_interface::{PcidServerHandle, PciBar}; + use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, Result, SchemeBlockMut}; +use log::{debug, error, info, warn, trace}; + use self::nvme::Nvme; use self::scheme::DiskScheme; @@ -18,108 +16,109 @@ mod nvme; mod scheme; fn main() { - let mut args = env::args().skip(1); + // Daemonize + if unsafe { syscall::clone(0).unwrap() } != 0 { + return; + } - let mut name = args.next().expect("nvmed: no name provided"); + let mut pcid_handle = PcidServerHandle::connect_default().expect("nvmed: failed to setup channel to pcid"); + let pci_config = pcid_handle.fetch_config().expect("nvmed: failed to fetch config"); + + let bar = match pci_config.func.bars[0] { + PciBar::Memory(mem) => mem, + other => panic!("received a non-memory BAR ({:?})", other), + }; + let bar_size = pci_config.func.bar_sizes[0]; + let irq = pci_config.func.legacy_interrupt_line; + + let mut name = pci_config.func.name(); name.push_str("_nvme"); - let bar_str = args.next().expect("nvmed: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("nvmed: failed to parse address"); + info!("NVME PCI CONFIG: {:?}", pci_config); - let bar_size_str = args.next().expect("nvmed: no address size provided"); - let bar_size = usize::from_str_radix(&bar_size_str, 16).expect("nvmed: failed to parse address size"); + let address = unsafe { + syscall::physmap(bar as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("nvmed: failed to map address") + }; + { + let event_fd = syscall::open("event:", syscall::O_RDWR | syscall::O_CLOEXEC) + .expect("nvmed: failed to open event queue"); + let mut event_file = unsafe { File::from_raw_fd(event_fd as RawFd) }; - let irq_str = args.next().expect("nvmed: no irq provided"); - let irq = irq_str.parse::().expect("nvmed: failed to parse irq"); + let irq_fd = syscall::open( + &format!("irq:{}", irq), + syscall::O_RDWR | syscall::O_NONBLOCK | syscall::O_CLOEXEC + ).expect("nvmed: failed to open irq file"); + syscall::write(event_fd, &syscall::Event { + id: irq_fd, + flags: syscall::EVENT_READ, + data: 0, + }).expect("nvmed: failed to watch irq file events"); + let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; - print!("{}", format!(" + NVME {} on: {:X} size: {} IRQ: {}\n", name, bar, bar_size, irq)); + let scheme_name = format!("disk/{}", name); + let socket_fd = syscall::open( + &format!(":{}", scheme_name), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK | syscall::O_CLOEXEC + ).expect("nvmed: failed to create disk scheme"); + syscall::write(event_fd, &syscall::Event { + id: socket_fd, + flags: syscall::EVENT_READ, + data: 1, + }).expect("nvmed: failed to watch disk scheme events"); + let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { - syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("nvmed: failed to map address") - }; - { - let event_fd = syscall::open("event:", syscall::O_RDWR | syscall::O_CLOEXEC) - .expect("nvmed: failed to open event queue"); - let mut event_file = unsafe { File::from_raw_fd(event_fd as RawFd) }; + syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - let irq_fd = syscall::open( - &format!("irq:{}", irq), - syscall::O_RDWR | syscall::O_NONBLOCK | syscall::O_CLOEXEC - ).expect("nvmed: failed to open irq file"); - syscall::write(event_fd, &syscall::Event { - id: irq_fd, - flags: syscall::EVENT_READ, - data: 0, - }).expect("nvmed: failed to watch irq file events"); - let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; - - let scheme_name = format!("disk/{}", name); - let socket_fd = syscall::open( - &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK | syscall::O_CLOEXEC - ).expect("nvmed: failed to create disk scheme"); - syscall::write(event_fd, &syscall::Event { - id: socket_fd, - flags: syscall::EVENT_READ, - data: 1, - }).expect("nvmed: failed to watch disk scheme events"); - let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - - syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - - let mut nvme = Nvme::new(address).expect("nvmed: failed to allocate driver data"); - let namespaces = unsafe { nvme.init() }; - let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); - let mut todo = Vec::new(); - 'events: loop { - let mut event = Event::default(); - if event_file.read(&mut event).expect("nvmed: failed to read event queue") == 0 { - break; - } - - match event.data { - 0 => { - let mut irq = [0; 8]; - if irq_file.read(&mut irq).expect("nvmed: failed to read irq file") >= irq.len() { - if scheme.irq() { - irq_file.write(&irq).expect("nvmed: failed to write irq file"); - } - } - }, - 1 => loop { - let mut packet = Packet::default(); - match socket_file.read(&mut packet) { - Ok(0) => break 'events, - Ok(_) => (), - Err(err) => match err.kind() { - ErrorKind::WouldBlock => break, - _ => Err(err).expect("nvmed: failed to read disk scheme"), - } - } - todo.push(packet); - }, - unknown => { - panic!("nvmed: unknown event data {}", unknown); - }, - } - - let mut i = 0; - while i < todo.len() { - if let Some(a) = scheme.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket_file.write(&packet).expect("nvmed: failed to write disk scheme"); - } else { - i += 1; - } - } + let mut nvme = Nvme::new(address).expect("nvmed: failed to allocate driver data"); + let namespaces = unsafe { nvme.init() }; + let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); + let mut todo = Vec::new(); + 'events: loop { + let mut event = Event::default(); + if event_file.read(&mut event).expect("nvmed: failed to read event queue") == 0 { + break; } - //TODO: destroy NVMe stuff + match event.data { + 0 => { + let mut irq = [0; 8]; + if irq_file.read(&mut irq).expect("nvmed: failed to read irq file") >= irq.len() { + if scheme.irq() { + irq_file.write(&irq).expect("nvmed: failed to write irq file"); + } + } + }, + 1 => loop { + let mut packet = Packet::default(); + match socket_file.read(&mut packet) { + Ok(0) => break 'events, + Ok(_) => (), + Err(err) => match err.kind() { + ErrorKind::WouldBlock => break, + _ => Err(err).expect("nvmed: failed to read disk scheme"), + } + } + todo.push(packet); + }, + unknown => { + panic!("nvmed: unknown event data {}", unknown); + }, + } + + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket_file.write(&packet).expect("nvmed: failed to write disk scheme"); + } else { + i += 1; + } + } } - unsafe { let _ = syscall::physunmap(address); } + + //TODO: destroy NVMe stuff } + unsafe { let _ = syscall::physunmap(address); } } diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme.rs index 8754ded99b..9b74892f65 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme.rs @@ -259,7 +259,7 @@ impl NvmeCompQueue { if let Some(some) = self.complete() { return some; } else { - unsafe { asm!("pause"); } + unsafe { std::arch::x86_64::_mm_pause() } } } } @@ -324,7 +324,7 @@ impl Nvme { let csts = self.regs.csts.read(); // println!("CSTS: {:X}", csts); if csts & 1 == 1 { - asm!("pause"); + unsafe { std::arch::x86_64::_mm_pause() } } else { break; } @@ -365,7 +365,7 @@ impl Nvme { let csts = self.regs.csts.read(); // println!("CSTS: {:X}", csts); if csts & 1 == 0 { - asm!("pause"); + unsafe { std::arch::x86_64::_mm_pause() } } else { break; } diff --git a/pcid/src/config.rs b/pcid/src/config.rs index 3c79746816..7481955dc6 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -19,5 +19,5 @@ pub struct DriverConfig { pub device: Option, pub device_id_range: Option>, pub command: Option>, - pub channel_name: Option, + pub use_channel: bool, } diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index e301bbe597..3716574c10 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -55,6 +55,11 @@ pub struct PciFunction { /// Device ID pub devid: u16, } +impl PciFunction { + pub fn name(&self) -> String { + format!("pci-{:>02X}.{:>02X}.{:>02X}", self.bus_num, self.dev_num, self.func_num) + } +} #[derive(Clone, Debug, Serialize, Deserialize)] pub struct SubdriverArguments { diff --git a/pcid/src/main.rs b/pcid/src/main.rs index f8b02b1c4d..e039bd1272 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -408,7 +408,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, "$BUS" => format!("{:>02X}", bus_num), "$DEV" => format!("{:>02X}", dev_num), "$FUNC" => format!("{:>02X}", func_num), - "$NAME" => format!("pci-{:>02X}.{:>02X}.{:>02X}", bus_num, dev_num, func_num), + "$NAME" => func.name(), "$BAR0" => format!("{}", bars[0]), "$BAR1" => format!("{}", bars[1]), "$BAR2" => format!("{}", bars[2]), @@ -431,7 +431,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, info!("PCID SPAWN {:?}", command); - let (pcid_to_client_write, pcid_from_client_read, envs) = if driver.channel_name.is_some() { + let (pcid_to_client_write, pcid_from_client_read, envs) = if driver.use_channel { let mut fds1 = [0usize; 2]; let mut fds2 = [0usize; 2]; diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 10072dd3c4..3817f5f8af 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -27,4 +27,5 @@ serde_json = "1" smallvec = { version = "1", features = ["serde"] } thiserror = "1" toml = "0.5" + pcid = { path = "../pcid" } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 5c365aabac..6e8befb546 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -81,11 +81,6 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } fn main() { - let mut args = env::args().skip(1); - - let mut name = args.next().expect("xhcid: no name provided"); - name.push_str("_xhci"); - // Daemonize if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { return; @@ -100,6 +95,9 @@ fn main() { let bar = pci_config.func.bars[0]; let irq = pci_config.func.legacy_interrupt_line; + let mut name = pci_config.func.name(); + name.push_str("_xhci"); + let bar_ptr = match bar { pcid_interface::PciBar::Memory(ptr) => ptr, other => panic!("Expected memory bar, found {}", other), From 4016b0c7b84bd9755d44162f546e63fba9f54abc Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 23 Apr 2020 15:35:44 +0200 Subject: [PATCH 0399/1301] Fix failing pcid config parsing. --- pcid/src/config.rs | 2 +- pcid/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pcid/src/config.rs b/pcid/src/config.rs index 7481955dc6..c74f05842a 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -19,5 +19,5 @@ pub struct DriverConfig { pub device: Option, pub device_id_range: Option>, pub command: Option>, - pub use_channel: bool, + pub use_channel: Option, } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index e039bd1272..fa34f78314 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -431,7 +431,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, info!("PCID SPAWN {:?}", command); - let (pcid_to_client_write, pcid_from_client_read, envs) = if driver.use_channel { + let (pcid_to_client_write, pcid_from_client_read, envs) = if driver.use_channel.unwrap_or(false) { let mut fds1 = [0usize; 2]; let mut fds2 = [0usize; 2]; From e6a46bb6a679d4bd332f6ec6d679c34842e93d13 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 25 Apr 2020 23:02:16 +0200 Subject: [PATCH 0400/1301] Begin with NVME MSI support. --- Cargo.lock | 8 ++ nvmed/Cargo.toml | 2 + nvmed/src/main.rs | 127 ++++++++++++++++++++++-- nvmed/src/nvme/cq_reactor.rs | 153 +++++++++++++++++++++++++++++ nvmed/src/{nvme.rs => nvme/mod.rs} | 124 +++++++++++++++-------- nvmed/src/scheme.rs | 21 ++-- 6 files changed, 379 insertions(+), 56 deletions(-) create mode 100644 nvmed/src/nvme/cq_reactor.rs rename nvmed/src/{nvme.rs => nvme/mod.rs} (81%) diff --git a/Cargo.lock b/Cargo.lock index f27f4203eb..0a006c6d13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,6 +42,11 @@ dependencies = [ "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "atty" version = "0.2.14" @@ -727,8 +732,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "nvmed" version = "0.1.0" dependencies = [ + "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "block-io-wrapper 0.1.0", + "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", "pcid 0.1.0", @@ -1716,6 +1723,7 @@ dependencies = [ "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index 92a180f585..ec8152f9e9 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -4,7 +4,9 @@ version = "0.1.0" edition = "2018" [dependencies] +arrayvec = "0.5" bitflags = "0.7" +crossbeam-channel = "0.4" log = "0.4" redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } redox_syscall = "0.1" diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 7e6178840a..5bec4fca96 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -1,20 +1,127 @@ -use std::{env, usize}; +use std::{env, slice, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write}; +use std::ptr::NonNull; use std::os::unix::io::{RawFd, FromRawFd}; +use std::sync::{Arc, Mutex}; -use pcid_interface::{PcidServerHandle, PciBar}; - +use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle, PciBar}; use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, Result, SchemeBlockMut}; +use syscall::io::Mmio; +use arrayvec::ArrayVec; use log::{debug, error, info, warn, trace}; -use self::nvme::Nvme; +use self::nvme::{InterruptMethod, Nvme}; use self::scheme::DiskScheme; mod nvme; mod scheme; +#[derive(Default)] +pub struct Bar { + ptr: NonNull, + physical: usize, + bar_size: usize, +} +impl Bar { + pub fn allocate(bar: usize, bar_size: usize) -> Result { + Ok(Self { + ptr: NonNull::new(syscall::physmap(bar, bar_size, PHYSMAP_NO_CACHE | PHYSMAP_WRITE)? as *mut u8).expect("Mapping a BAR resulted in a nullptr"), + physical: bar, + bar_size, + }) + } +} + +impl Drop for Bar { + fn drop(&mut self) { + let _ = syscall::physunmap(self.physical); + } +} + +#[derive(Default)] +pub struct AllocatedBars(pub [Mutex>; 6]); + +/// Get the most optimal yet functional interrupt +fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, nvme: &mut Nvme, allocated_bars: &AllocatedBars) -> Result { + + let features = pcid_handle.fetch_all_features().unwrap(); + + let has_msi = features.iter().any(|(feature, _)| feature.is_msi()); + let has_msix = features.iter().any(|(feature, _)| feature.is_msix()); + + // TODO: Allocate more than one vector when possible and useful. + if has_msix { + // Extended message signaled interrupts. + use pcid_interface::msi::MsixTableEntry; + use self::nvme::MsixCfg; + + let mut capability_struct = match pcid_handle.feature_info(PciFeature::MsiX).unwrap() { + PciFeatureInfo::MsiX(msix) => msix, + _ => unreachable!(), + }; + fn bar_base(allocated_bars: &AllocatedBars, function: &PciFunction, bir: u8) -> Result> { + let bir = usize::from(bir); + let bar_guard = allocated_bars.0[bir].lock().unwrap(); + match &mut *bar_guard { + &mut Some(ref bar) => Ok(bar.ptr), + bar_to_set @ &mut None => { + let bar = match function.bars[bir] { + PciBar::Memory(addr) => addr, + other => panic!("Expected memory BAR, found {:?}", other), + }; + let bar_size = function.bar_sizes[bir]; + + let bar = Bar::allocate(bar as usize, bar_size as usize)?; + *bar_to_set = Some(bar); + Ok(bar_to_set.as_ref().unwrap().ptr) + } + } + } + let table_bar_base: *mut u8 = bar_base(allocated_bars, function, capability_struct.table_bir())?.as_ptr(); + let pba_bar_base: *mut u8 = bar_base(allocated_bars, function, capability_struct.pba_bir())?.as_ptr(); + let table_base = unsafe { table_bar_base.offset(capability_struct.table_offset() as isize) }; + let pba_base = unsafe { pba_bar_base.offset(capability_struct.pba_offset() as isize) }; + + let vector_count = capability_struct.table_size(); + let table_entries: &'static mut [MsixTableEntry] = unsafe { slice::from_raw_parts_mut(table_base as *mut MsixTableEntry, vector_count as usize) }; + let pba_entries: &'static mut [Mmio] = unsafe { slice::from_raw_parts_mut(table_base as *mut Mmio, (vector_count as usize + 63) / 64) }; + + // Mask all interrupts in case some earlier driver/os already unmasked them (according to + // the PCI Local Bus spec 3.0, they are masked after system reset). + for table_entry in table_entries { + table_entry.mask(); + } + + pcid_handle.enable_feature(PciFeature::MsiX).unwrap(); + capability_struct.set_msix_enabled(true); // only affects our local mirror of the cap + + // We don't allocate any vectors yet; that's later done when we get into + // submission/completion queues. + + Ok(InterruptMethod::MsiX(MsixCfg { + cap: capability_struct, + table: table_entries, + pba: pba_entries, + })) + } else if has_msi { + // Message signaled interrupts. + let capability_struct = match pcid_handle.feature_info(PciFeature::Msi).unwrap() { + PciFeatureInfo::Msi(msi) => msi, + _ => unreachable!(), + }; + // We don't enable MSI until needed. + Ok(InterruptMethod::Msi(capability_struct)) + } else if function.legacy_interrupt_pin.is_some() { + // INTx# pin based interrupts. + Ok(InterruptMethod::Intx) + } else { + // No interrupts at all + todo!("handling of no interrupts") + } +} + fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } != 0 { @@ -36,10 +143,13 @@ fn main() { info!("NVME PCI CONFIG: {:?}", pci_config); + let allocated_bars = AllocatedBars::default(); + let address = unsafe { syscall::physmap(bar as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("nvmed: failed to map address") }; + *allocated_bars.0[0].lock().unwrap() = Some(Bar { physical: bar as usize, bar_size: bar_size as usize, ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr") }); { let event_fd = syscall::open("event:", syscall::O_RDWR | syscall::O_CLOEXEC) .expect("nvmed: failed to open event queue"); @@ -70,8 +180,12 @@ fn main() { syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - let mut nvme = Nvme::new(address).expect("nvmed: failed to allocate driver data"); - let namespaces = unsafe { nvme.init() }; + let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); + let mut nvme = Nvme::new(address, interrupt_method, pcid_handle, reactor_sender).expect("nvmed: failed to allocate driver data"); + let nvme = Arc::new(nvme); + unsafe { nvme.init() } + nvme::cq_reactor::start_cq_reactor_thread(nvme); + let namespaces = unsafe { nvme.init_with_queues() }; let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); let mut todo = Vec::new(); 'events: loop { @@ -120,5 +234,4 @@ fn main() { //TODO: destroy NVMe stuff } - unsafe { let _ = syscall::physunmap(address); } } diff --git a/nvmed/src/nvme/cq_reactor.rs b/nvmed/src/nvme/cq_reactor.rs new file mode 100644 index 0000000000..f0ea1336de --- /dev/null +++ b/nvmed/src/nvme/cq_reactor.rs @@ -0,0 +1,153 @@ +use std::collections::BTreeMap; +use std::fs::File; +use std::future::Future; +use std::io::prelude::*; +use std::pin::Pin; +use std::sync::{Arc, Mutex}; +use std::{io, task, thread}; +use std::os::unix::io::{FromRawFd, RawFd}; + +use syscall::Result; + +use crossbeam_channel::{Sender, Receiver}; + +use crate::nvme::{InterruptMethod, Nvme, NvmeComp}; + +/// A source of interrupts. The NVME spec splits the definition of MSI into "single msi" and "multi +/// msi". +#[derive(Debug)] +pub enum IntSources { + Intx(File), + SingleMsi(File), + MultiMsi(BTreeMap), + MsiX(BTreeMap), +} + +/// A notification request, sent by the future in order to tell the completion thread that the +/// current task wants a notification when a matching completion queue entry has been seen. +pub enum NotifReq { + RequestCompletion { + queue_id: usize, + waker: task::Waker, + // TODO: Get rid of this allocation + message: Arc>>, + }, +} + +struct PendingReq { + waker: task::Waker, + message: Arc>>, + queue_id: usize, +} +struct CqReactor { + int_sources: Option, + nvme: Arc, + pending_reqs: Vec, + receiver: Receiver, + event_queue: File, +} +impl CqReactor { + fn create_event_queue() -> Result { + use syscall::flag::*; + let fd = syscall::open("event:", O_CLOEXEC | O_RDWR)?; + let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; + todo!() + } + fn new(nvme: Arc, receiver: Receiver) -> Result { + Ok(Self { + int_sources: None, // TODO + nvme, + pending_reqs: Vec::new(), + receiver, + event_queue: Self::create_event_queue()?, + }) + } + fn handle_notif_reqs(&mut self) { + for req in self.receiver.try_iter() { + match req { + NotifReq::RequestCompletion { queue_id, waker, message } => self.pending_reqs.push(PendingReq { + queue_id, + message, + waker, + }), + } + } + } + fn run(mut self) -> ! { + loop { + self.handle_notif_reqs(); + } + } +} + +pub fn start_cq_reactor_thread(nvme: Arc, receiver: Receiver) -> thread::JoinHandle<()> { + // Actually, nothing prevents us from spawning additional threads. the channel is MPMC and + // everything is properly synchronized. I'm not saying this is strictly required, but with + // multiple completion queues it might actually be worth considering. + thread::spawn(move || { + CqReactor::new(nvme, receiver) + .expect("nvmed: failed to setup CQ reactor") + .run() + }) +} + +pub struct CompletionMessage { + cq_entry: NvmeComp, +} + +enum CompletionFuture { + // not really required, but makes futures inert + Init { + sender: Sender, + queue_id: usize, + }, + Pending { + message: Arc>>, + }, + Finished, +} + +// enum not self-referential +impl Unpin for CompletionFuture {} + +impl Future for CompletionFuture { + type Output = NvmeComp; + + fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { + let this = self.get_mut(); + + match this { + &mut Self::Init { sender, queue_id } => { + let message = Arc::new(Mutex::new(None)); + sender.send(NotifReq::RequestCompletion { + queue_id, + waker: context.waker().clone(), + message: Arc::clone(&message), + }); + *this = CompletionFuture::Pending { + message, + }; + task::Poll::Pending + } + &mut Self::Pending { message } => if let Some(value) = message.lock().unwrap().take() { + *this = Self::Finished; + task::Poll::Ready(value.cq_entry) + } else { + // woken up but the reactor hadn't sent the message. + // this is ideally unreachable + task::Poll::Pending + } + &mut Self::Finished => panic!("calling poll() on an already finished CompletionFuture"), + } + } +} + + +impl Nvme { + pub fn completion(&self, cq_id: usize) -> impl Future + '_ { + CompletionFuture::Init { + sender: self.reactor_sender.clone(), + queue_id: cq_id, + } + } +} diff --git a/nvmed/src/nvme.rs b/nvmed/src/nvme/mod.rs similarity index 81% rename from nvmed/src/nvme.rs rename to nvmed/src/nvme/mod.rs index 9b74892f65..aeef71471b 100644 --- a/nvmed/src/nvme.rs +++ b/nvmed/src/nvme/mod.rs @@ -1,8 +1,33 @@ -use std::{ptr, thread}; +use std::ptr; use std::collections::BTreeMap; +use std::sync::{Mutex, RwLock}; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use crossbeam_channel::Sender; + use syscall::io::{Dma, Io, Mmio}; use syscall::error::{Error, Result, EINVAL}; +pub mod cq_reactor; +use self::cq_reactor::{self, NotifReq}; + +use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; +use pcid_interface::PcidServerHandle; + +#[derive(Debug)] +pub enum InterruptMethod { + Intx, + Msi(MsiCapability), + MsiX(MsixCfg), +} + +#[derive(Debug)] +pub struct MsixCfg { + pub cap: MsixCapability, + pub table: &'static mut [MsixTableEntry], + pub pba: &'static mut [Mmio], +} + #[derive(Clone, Copy)] #[repr(packed)] pub struct NvmeCmd { @@ -39,7 +64,7 @@ impl NvmeCmd { Self { opcode: 5, flags: 0, - cid: cid, + cid, nsid: 0, _rsvd: 0, mptr: 0, @@ -272,43 +297,55 @@ pub struct NvmeNamespace { } pub struct Nvme { - regs: &'static mut NvmeRegs, - submission_queues: [NvmeCmdQueue; 2], - pub (crate) completion_queues: [NvmeCompQueue; 2], - buffer: Dma<[u8; 512 * 4096]>, // 2MB of buffer - buffer_prp: Dma<[u64; 512]>, // 4KB of PRP for the buffer + interrupt_method: Mutex, + pcid_interface: Mutex, + regs: Mutex<&'static mut NvmeRegs>, + submission_queues: RwLock>>, + pub (crate) completion_queues: RwLock>>, + buffer: Mutex>, // 2MB of buffer + buffer_prp: Mutex>, // 4KB of PRP for the buffer + reactor_sender: Sender, + next_cid: AtomicUsize, } impl Nvme { - pub fn new(address: usize) -> Result { + pub fn new(address: usize, interrupt_method: InterruptMethod, pcid_interface: PcidServerHandle, reactor_sender: Sender) -> Result { Ok(Nvme { - regs: unsafe { &mut *(address as *mut NvmeRegs) }, - submission_queues: [NvmeCmdQueue::new()?, NvmeCmdQueue::new()?], - completion_queues: [NvmeCompQueue::new()?, NvmeCompQueue::new()?], - buffer: Dma::zeroed()?, - buffer_prp: Dma::zeroed()?, + regs: Mutex::new(unsafe { &mut *(address as *mut NvmeRegs) }), + submission_queues: RwLock::new(vec! [Mutex::new(NvmeCmdQueue::new()?), Mutex::new(NvmeCmdQueue::new()?)]), + completion_queues: RwLock::new(vec! [Mutex::new(NvmeCompQueue::new()?), Mutex::new(NvmeCompQueue::new()?)]), + buffer: Mutex::new(Dma::zeroed()?), + buffer_prp: Mutex::new(Dma::zeroed()?), + next_cid: AtomicUsize::new(0), + interrupt_method: Mutex::new(interrupt_method), + pcid_interface: Mutex::new(pcid_interface), + reactor_sender, }) } + unsafe fn doorbell_write(&self, index: usize, value: u32) { + let mut regs_guard = self.regs.lock().unwrap(); - unsafe fn doorbell(&mut self, index: usize) -> &'static mut Mmio { - let dstrd = ((self.regs.cap.read() >> 32) & 0b1111) as usize; - let addr = (self.regs as *mut _ as usize) + let dstrd = ((regs_guard.cap.read() >> 32) & 0b1111) as usize; + let addr = (regs_guard as *mut u8 as usize) + 0x1000 + index * (4 << dstrd); - &mut *(addr as *mut Mmio) + (&mut *(addr as *mut Mmio)).write(value); } - pub unsafe fn submission_queue_tail(&mut self, qid: u16, tail: u16) { - self.doorbell(2 * (qid as usize)).write(tail as u32); + pub unsafe fn submission_queue_tail(&self, qid: u16, tail: u16) { + self.doorbell_write(2 * (qid as usize), u32::from(tail)); } - pub unsafe fn completion_queue_head(&mut self, qid: u16, head: u16) { - self.doorbell(2 * (qid as usize) + 1).write(head as u32) + pub unsafe fn completion_queue_head(&self, qid: u16, head: u16) { + self.doorbell_write(2 * (qid as usize) + 1, u32::from(head)); } - pub unsafe fn init(&mut self) -> BTreeMap { - for i in 0..self.buffer_prp.len() { - self.buffer_prp[i] = (self.buffer.physical() + i * 4096) as u64; + pub unsafe fn init(&mut self) { + let mut buffer = self.buffer.get_mut().unwrap(); + let mut buffer_prp = self.buffer_prp.get_mut().unwrap(); + + for i in 0..buffer_prp.len() { + buffer_prp[i] = (buffer.physical() + i * 4096) as u64; } // println!(" - CAPS: {:X}", self.regs.cap.read()); @@ -317,11 +354,11 @@ impl Nvme { // println!(" - CSTS: {:X}", self.regs.csts.read()); // println!(" - Disable"); - self.regs.cc.writef(1, false); + self.regs.get_mut().unwrap().cc.writef(1, false); // println!(" - Waiting for not ready"); loop { - let csts = self.regs.csts.read(); + let csts = self.regs.get_mut().unwrap().csts.read(); // println!("CSTS: {:X}", csts); if csts & 1 == 1 { unsafe { std::arch::x86_64::_mm_pause() } @@ -331,38 +368,42 @@ impl Nvme { } // println!(" - Mask all interrupts"); - self.regs.intms.write(0xFFFFFFFF); + self.regs.get_mut().unwrap().intms.write(0xFFFFFFFF); // TODO: Don't mask - for (qid, queue) in self.completion_queues.iter().enumerate() { - let data = &queue.data; + for (qid, queue) in self.completion_queues.get_mut().unwrap().iter().enumerate() { + let data = &queue.get_mut().unwrap().data; // println!(" - completion queue {}: {:X}, {}", qid, data.physical(), data.len()); } - for (qid, queue) in self.submission_queues.iter().enumerate() { - let data = &queue.data; + for (qid, queue) in self.submission_queues.get_mut().unwrap().iter().enumerate() { + let data = &queue.get_mut().unwrap().data; // println!(" - submission queue {}: {:X}, {}", qid, data.physical(), data.len()); } { - let asq = &self.submission_queues[0]; - let acq = &self.completion_queues[0]; - self.regs.aqa.write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1)); - self.regs.asq.write(asq.data.physical() as u64); - self.regs.acq.write(acq.data.physical() as u64); + let regs = self.regs.get_mut().unwrap(); + let submission_queues = self.submission_queues.get_mut().unwrap(); + let completion_queues = self.submission_queues.get_mut().unwrap(); + + let asq = &submission_queues[0].get_mut().unwrap(); + let acq = &completion_queues[0].get_mut().unwrap(); + regs.aqa.write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1)); + regs.asq.write(asq.data.physical() as u64); + regs.acq.write(acq.data.physical() as u64); // Set IOCQES, IOSQES, AMS, MPS, and CSS - let mut cc = self.regs.cc.read(); + let mut cc = regs.cc.read(); cc &= 0xFF00000F; cc |= (4 << 20) | (6 << 16); - self.regs.cc.write(cc); + regs.cc.write(cc); } // println!(" - Enable"); - self.regs.cc.writef(1, true); + self.regs.get_mut().unwrap().cc.writef(1, true); // println!(" - Waiting for ready"); loop { - let csts = self.regs.csts.read(); + let csts = self.regs.get_mut().unwrap().csts.read(); // println!("CSTS: {:X}", csts); if csts & 1 == 0 { unsafe { std::arch::x86_64::_mm_pause() } @@ -370,7 +411,8 @@ impl Nvme { break; } } - + } + pub fn init_with_queues(&self) -> BTreeMap { { //TODO: Use buffer let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index 108518a3e6..40f6f1b68c 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -4,6 +4,8 @@ use std::convert::{TryFrom, TryInto}; use std::fmt::Write; use std::io::prelude::*; use std::io; +use std::sync::Arc; + use syscall::{ Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, EOVERFLOW, Result, Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, @@ -32,13 +34,13 @@ impl AsRef for DiskWrapper { } impl DiskWrapper { - fn pt(disk: &mut NvmeNamespace, nvme: &mut Nvme) -> Option { + fn pt(disk: &mut NvmeNamespace, nvme: &Nvme) -> Option { let bs = match disk.block_size { 512 => LogicalBlockSize::Lb512, 4096 => LogicalBlockSize::Lb4096, _ => return None, }; - struct Device<'a, 'b> { disk: &'a mut NvmeNamespace, nvme: &'a mut Nvme, offset: u64, block_bytes: &'b mut [u8] } + struct Device<'a, 'b> { disk: &'a mut NvmeNamespace, nvme: &'a Nvme, offset: u64, block_bytes: &'b mut [u8] } impl<'a, 'b> Seek for Device<'a, 'b> { fn seek(&mut self, from: io::SeekFrom) -> io::Result { @@ -91,7 +93,7 @@ impl DiskWrapper { partitionlib::get_partitions(&mut Device { disk, nvme, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() } - fn new(mut inner: NvmeNamespace, nvme: &mut Nvme) -> Self { + fn new(mut inner: NvmeNamespace, nvme: &Nvme) -> Self { Self { pt: Self::pt(&mut inner, nvme), inner, @@ -101,17 +103,17 @@ impl DiskWrapper { pub struct DiskScheme { scheme_name: String, - nvme: Nvme, + nvme: Arc, disks: BTreeMap, handles: BTreeMap, next_id: usize } impl DiskScheme { - pub fn new(scheme_name: String, mut nvme: Nvme, disks: BTreeMap) -> DiskScheme { + pub fn new(scheme_name: String, nvme: Arc, disks: BTreeMap) -> DiskScheme { DiskScheme { scheme_name, - disks: disks.into_iter().map(|(k, v)| (k, DiskWrapper::new(v, &mut nvme))).collect(), + disks: disks.into_iter().map(|(k, v)| (k, DiskWrapper::new(v, &nvme))).collect(), nvme, handles: BTreeMap::new(), next_id: 0 @@ -124,8 +126,11 @@ impl DiskScheme { let mut found_completion = false; let nvme = &mut self.nvme; - for qid in 0..nvme.completion_queues.len() { - while let Some((head, entry)) = nvme.completion_queues[qid].complete() { + let completion_queues = nvme.completion_queues.read().unwrap(); + + for qid in 0..completion_queues.len() { + let queue = completion_queues[qid].lock().unwrap(); + while let Some((head, entry)) = queue.complete() { found_completion = true; println!("nvmed: Unhandled completion {:?}", entry); //TODO: Handle errors From d485176bd6c7d0471b4b59f386f86ffa7a8e01a1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 27 Apr 2020 15:59:06 +0200 Subject: [PATCH 0401/1301] Improve startup interrupt initialization. --- nvmed/src/main.rs | 108 ++++++++++++++++++++++++----------- nvmed/src/nvme/cq_reactor.rs | 69 +++++++++++++++------- nvmed/src/nvme/mod.rs | 49 +++++++++++++--- pcid/src/pci/msi.rs | 12 +++- 4 files changed, 172 insertions(+), 66 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 5bec4fca96..2c54919298 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -1,4 +1,6 @@ -use std::{env, slice, usize}; +use std::{slice, usize}; +use std::collections::BTreeMap; +use std::convert::TryInto; use std::fs::File; use std::io::{ErrorKind, Read, Write}; use std::ptr::NonNull; @@ -12,13 +14,13 @@ use syscall::io::Mmio; use arrayvec::ArrayVec; use log::{debug, error, info, warn, trace}; -use self::nvme::{InterruptMethod, Nvme}; +use self::nvme::{InterruptMethod, InterruptSources, Nvme}; use self::scheme::DiskScheme; mod nvme; mod scheme; -#[derive(Default)] +/// A wrapper for a BAR allocation. pub struct Bar { ptr: NonNull, physical: usize, @@ -40,11 +42,15 @@ impl Drop for Bar { } } +/// The PCI BARs that may be allocated. #[derive(Default)] pub struct AllocatedBars(pub [Mutex>; 6]); -/// Get the most optimal yet functional interrupt -fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, nvme: &mut Nvme, allocated_bars: &AllocatedBars) -> Result { +/// Get the most optimal yet functional interrupt mechanism: either (in the order preference): +/// MSI-X, MSI, and INTx# pin. Returns both runtime interrupt structures (MSI/MSI-X capability +/// structures), and the handles to the interrupts. +fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, allocated_bars: &AllocatedBars) -> Result<(InterruptMethod, InterruptSources)> { + use pcid_interface::irq_helpers; let features = pcid_handle.fetch_all_features().unwrap(); @@ -97,25 +103,74 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, nv pcid_handle.enable_feature(PciFeature::MsiX).unwrap(); capability_struct.set_msix_enabled(true); // only affects our local mirror of the cap - // We don't allocate any vectors yet; that's later done when we get into - // submission/completion queues. + let (msix_vector_number, irq_handle) = { + use pcid_interface::msi::x86_64 as msi_x86_64; + use msi_x86_64::DeliveryMode; - Ok(InterruptMethod::MsiX(MsixCfg { + let entry: &mut MsixTableEntry = &mut table_entries[0]; + + let bsp_cpu_id = irq_helpers::read_bsp_apic_id().expect("nvmed: failed to read APIC ID"); + let bsp_lapic_id = bsp_cpu_id.try_into().expect("nvmed: BSP local apic ID couldn't fit inside u8"); + let (vector, irq_handle) = irq_helpers::allocate_single_interrupt_vector(bsp_cpu_id).expect("nvmed: failed to allocate single MSI-X interrupt vector").expect("nvmed: no interrupt vectors left on BSP"); + + let msg_addr = msi_x86_64::message_address(bsp_lapic_id, false, false); + let msg_data = msi_x86_64::message_data_edge_triggered(DeliveryMode::Fixed, vector); + + entry.set_addr_lo(msg_addr); + entry.set_msg_data(msg_data); + entry.unmask(); + + (0, irq_handle) + }; + + let interrupt_method = InterruptMethod::MsiX(MsixCfg { cap: capability_struct, table: table_entries, pba: pba_entries, - })) + }); + let interrupt_sources = InterruptSources::MsiX(std::iter::once((msix_vector_number, irq_handle)).collect()); + + Ok((interrupt_method, interrupt_sources)) } else if has_msi { // Message signaled interrupts. let capability_struct = match pcid_handle.feature_info(PciFeature::Msi).unwrap() { PciFeatureInfo::Msi(msi) => msi, _ => unreachable!(), }; - // We don't enable MSI until needed. - Ok(InterruptMethod::Msi(capability_struct)) + + let (msi_vector_number, irq_handle) = { + use pcid_interface::{MsiSetFeatureInfo, SetFeatureInfo}; + use pcid_interface::msi::x86_64 as msi_x86_64; + use msi_x86_64::DeliveryMode; + + let bsp_cpu_id = irq_helpers::read_bsp_apic_id().expect("nvmed: failed to read BSP APIC ID"); + let bsp_lapic_id = bsp_cpu_id.try_into().expect("nvmed: BSP local apic ID couldn't fit inside u8"); + let (vector, irq_handle) = irq_helpers::allocate_single_interrupt_vector(bsp_cpu_id).expect("nvmed: failed to allocate single MSI interrupt vector").expect("nvmed: no interrupt vectors left on BSP"); + + let msg_addr = msi_x86_64::message_address(bsp_lapic_id, false, false); + let msg_data = msi_x86_64::message_data_edge_triggered(DeliveryMode::Fixed, vector) as u16; + + pcid_handle.set_feature_info(SetFeatureInfo::Msi(MsiSetFeatureInfo { + message_address: Some(msg_addr), + message_upper_address: Some(0), + message_data: Some(msg_data), + multi_message_enable: Some(0), // enable 2^0=1 vectors + mask_bits: None, + })); + + (0, irq_handle) + }; + + let interrupt_method = InterruptMethod::Msi(capability_struct); + let interrupt_sources = InterruptSources::Msi(std::iter::once((msi_vector_number, irq_handle)).collect()); + + pcid_handle.enable_feature(PciFeature::Msi).unwrap(); + + Ok((interrupt_method, interrupt_sources)) } else if function.legacy_interrupt_pin.is_some() { // INTx# pin based interrupts. - Ok(InterruptMethod::Intx) + let irq_handle = File::open(format!("irq:{}", function.legacy_interrupt_line)).expect("nvmed: failed to open INTx# interrupt line"); + Ok((InterruptMethod::Intx, InterruptSources::Intx(irq_handle))) } else { // No interrupts at all todo!("handling of no interrupts") @@ -155,37 +210,30 @@ fn main() { .expect("nvmed: failed to open event queue"); let mut event_file = unsafe { File::from_raw_fd(event_fd as RawFd) }; - let irq_fd = syscall::open( - &format!("irq:{}", irq), - syscall::O_RDWR | syscall::O_NONBLOCK | syscall::O_CLOEXEC - ).expect("nvmed: failed to open irq file"); - syscall::write(event_fd, &syscall::Event { - id: irq_fd, - flags: syscall::EVENT_READ, - data: 0, - }).expect("nvmed: failed to watch irq file events"); - let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; - let scheme_name = format!("disk/{}", name); let socket_fd = syscall::open( &format!(":{}", scheme_name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK | syscall::O_CLOEXEC ).expect("nvmed: failed to create disk scheme"); + syscall::write(event_fd, &syscall::Event { id: socket_fd, flags: syscall::EVENT_READ, - data: 1, + data: 0, }).expect("nvmed: failed to watch disk scheme events"); + let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); + let (interrupt_method, interrupt_sources) = get_int_method(&mut pcid_handle, &pci_config.func, &allocated_bars).expect("nvmed: failed to find a suitable interrupt method"); let mut nvme = Nvme::new(address, interrupt_method, pcid_handle, reactor_sender).expect("nvmed: failed to allocate driver data"); let nvme = Arc::new(nvme); unsafe { nvme.init() } - nvme::cq_reactor::start_cq_reactor_thread(nvme); + nvme::cq_reactor::start_cq_reactor_thread(nvme, interrupt_sources, reactor_receiver); let namespaces = unsafe { nvme.init_with_queues() }; + let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); let mut todo = Vec::new(); 'events: loop { @@ -195,15 +243,7 @@ fn main() { } match event.data { - 0 => { - let mut irq = [0; 8]; - if irq_file.read(&mut irq).expect("nvmed: failed to read irq file") >= irq.len() { - if scheme.irq() { - irq_file.write(&irq).expect("nvmed: failed to write irq file"); - } - } - }, - 1 => loop { + 0 => loop { let mut packet = Packet::default(); match socket_file.read(&mut packet) { Ok(0) => break 'events, diff --git a/nvmed/src/nvme/cq_reactor.rs b/nvmed/src/nvme/cq_reactor.rs index f0ea1336de..59532aa6bf 100644 --- a/nvmed/src/nvme/cq_reactor.rs +++ b/nvmed/src/nvme/cq_reactor.rs @@ -5,23 +5,14 @@ use std::io::prelude::*; use std::pin::Pin; use std::sync::{Arc, Mutex}; use std::{io, task, thread}; -use std::os::unix::io::{FromRawFd, RawFd}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use syscall::Result; +use syscall::data::Event; use crossbeam_channel::{Sender, Receiver}; -use crate::nvme::{InterruptMethod, Nvme, NvmeComp}; - -/// A source of interrupts. The NVME spec splits the definition of MSI into "single msi" and "multi -/// msi". -#[derive(Debug)] -pub enum IntSources { - Intx(File), - SingleMsi(File), - MultiMsi(BTreeMap), - MsiX(BTreeMap), -} +use crate::nvme::{InterruptMethod, InterruptSources, Nvme, NvmeComp}; /// A notification request, sent by the future in order to tell the completion thread that the /// current task wants a notification when a matching completion queue entry has been seen. @@ -40,26 +31,54 @@ struct PendingReq { queue_id: usize, } struct CqReactor { - int_sources: Option, + int_sources: InterruptSources, nvme: Arc, pending_reqs: Vec, receiver: Receiver, event_queue: File, } impl CqReactor { - fn create_event_queue() -> Result { + fn create_event_queue(int_sources: &InterruptSources) -> Result { use syscall::flag::*; let fd = syscall::open("event:", O_CLOEXEC | O_RDWR)?; let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; - todo!() + + let mut msix_iter; + let mut msi_iter; + let mut intx_iter; + + let iter: &mut dyn Iterator = match int_sources { + InterruptSources::MsiX(ref btree) => { + msix_iter = btree.iter().map(|(&n, f)| (n, f)); + &mut msix_iter + } + InterruptSources::Msi(ref btree) => { + msi_iter = btree.iter().map(|(&n, f)| (u16::from(n), f)); + &mut msi_iter + } + InterruptSources::Intx(ref file) => { + intx_iter = std::iter::once((0, file)); + &mut intx_iter + } + }; + for (num, irq_handle) in iter { + if file.write(&Event { + id: irq_handle.as_raw_fd() as usize, + flags: syscall::EVENT_READ, + data: num as usize, + }).unwrap() == 0 { + panic!("Failed to setup event queue for {} {:?}", num, irq_handle); + } + } + Ok(file) } - fn new(nvme: Arc, receiver: Receiver) -> Result { + fn new(nvme: Arc, int_sources: InterruptSources, receiver: Receiver) -> Result { Ok(Self { - int_sources: None, // TODO + event_queue: Self::create_event_queue(&int_sources)?, + int_sources, nvme, pending_reqs: Vec::new(), receiver, - event_queue: Self::create_event_queue()?, }) } fn handle_notif_reqs(&mut self) { @@ -73,19 +92,27 @@ impl CqReactor { } } } + fn block_on_new_irq(&mut self) -> Event { + let mut event = Event::default(); + self.event_queue.read(&mut event); + event + } fn run(mut self) -> ! { loop { self.handle_notif_reqs(); + let event = self.block_on_new_irq(); } } } -pub fn start_cq_reactor_thread(nvme: Arc, receiver: Receiver) -> thread::JoinHandle<()> { +pub fn start_cq_reactor_thread(nvme: Arc, interrupt_sources: InterruptSources, receiver: Receiver) -> thread::JoinHandle<()> { // Actually, nothing prevents us from spawning additional threads. the channel is MPMC and // everything is properly synchronized. I'm not saying this is strictly required, but with - // multiple completion queues it might actually be worth considering. + // multiple completion queues it might actually be worth considering. The IRQ subsystem might + // be improved to lower the latency, but MSI-X allows multiple vectors to point to different + // CPUs, so that the load is balanced across the logical processors. thread::spawn(move || { - CqReactor::new(nvme, receiver) + CqReactor::new(nvme, interrupt_sources, receiver) .expect("nvmed: failed to setup CQ reactor") .run() }) diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index aeef71471b..ac56cb9b78 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -1,7 +1,8 @@ -use std::ptr; use std::collections::BTreeMap; +use std::fs::File; use std::sync::{Mutex, RwLock}; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::ptr; use crossbeam_channel::Sender; @@ -9,19 +10,44 @@ use syscall::io::{Dma, Io, Mmio}; use syscall::error::{Error, Result, EINVAL}; pub mod cq_reactor; -use self::cq_reactor::{self, NotifReq}; +use self::cq_reactor::NotifReq; use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; use pcid_interface::PcidServerHandle; #[derive(Debug)] -pub enum InterruptMethod { - Intx, - Msi(MsiCapability), - MsiX(MsixCfg), +pub enum InterruptSources { + MsiX(BTreeMap), + Msi(BTreeMap), + Intx(File), +} + +pub enum InterruptMethod { + /// INTx# interrupt pins + Intx, + /// Message signaled interrupts + Msi(MsiCapability), + /// Extended message signaled interrupts + MsiX(MsixCfg), +} +impl InterruptMethod { + fn is_intx(&self) -> bool { + if let Self::Intx = self { + true + } else { false } + } + fn is_msi(&self) -> bool { + if let Self::Msi(_) = self { + true + } else { false } + } + fn is_msix(&self) -> bool { + if let Self::MsiX(_) = self { + true + } else { false } + } } -#[derive(Debug)] pub struct MsixCfg { pub cap: MsixCapability, pub table: &'static mut [MsixTableEntry], @@ -307,6 +333,8 @@ pub struct Nvme { reactor_sender: Sender, next_cid: AtomicUsize, } +unsafe impl Send for Nvme {} +unsafe impl Sync for Nvme {} impl Nvme { pub fn new(address: usize, interrupt_method: InterruptMethod, pcid_interface: PcidServerHandle, reactor_sender: Sender) -> Result { @@ -326,7 +354,7 @@ impl Nvme { let mut regs_guard = self.regs.lock().unwrap(); let dstrd = ((regs_guard.cap.read() >> 32) & 0b1111) as usize; - let addr = (regs_guard as *mut u8 as usize) + let addr = ((*regs_guard) as *mut NvmeRegs as usize) + 0x1000 + index * (4 << dstrd); (&mut *(addr as *mut Mmio)).write(value); @@ -368,7 +396,10 @@ impl Nvme { } // println!(" - Mask all interrupts"); - self.regs.get_mut().unwrap().intms.write(0xFFFFFFFF); // TODO: Don't mask + if !self.interrupt_method.get_mut().unwrap().is_msix() { + self.regs.get_mut().unwrap().intms.write(0xFFFFFFFF); + self.regs.get_mut().unwrap().intmc.write(0xFFFFFFFE); + } for (qid, queue) in self.completion_queues.get_mut().unwrap().iter().enumerate() { let data = &queue.get_mut().unwrap().data; diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 54e2f386c6..eb73ab4aa1 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -385,12 +385,11 @@ pub mod x86_64 { } // TODO: should the reserved field be preserved? - pub const fn message_address(destination_id: u8, rh: bool, dm: bool, xx: u8) -> u32 { + pub const fn message_address(destination_id: u8, rh: bool, dm: bool) -> u32 { 0xFEE0_0000u32 | ((destination_id as u32) << 12) | ((rh as u32) << 3) | ((dm as u32) << 2) - | xx as u32 } pub const fn message_data(trigger_mode: TriggerMode, level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 { ((trigger_mode as u32) << 15) @@ -413,12 +412,21 @@ impl MsixTableEntry { pub fn addr_hi(&self) -> u32 { self.addr_hi.read() } + pub fn set_addr_lo(&mut self, value: u32) { + self.addr_lo.write(value); + } + pub fn set_addr_hi(&mut self, value: u32) { + self.addr_hi.write(value); + } pub fn msg_data(&self) -> u32 { self.msg_data.read() } pub fn vec_ctl(&self) -> u32 { self.vec_ctl.read() } + pub fn set_msg_data(&mut self, value: u32) { + self.msg_data.write(value); + } pub fn addr(&self) -> u64 { u64::from(self.addr_lo()) | (u64::from(self.addr_hi()) << 32) } From 6c2f10384101df72d3268f2a09cabe70eef64f0e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 29 Apr 2020 19:35:48 +0200 Subject: [PATCH 0402/1301] WIP: Complete the NVME CQ reactor (doesn't compile yet) --- Cargo.lock | 3 +- nvmed/Cargo.toml | 3 +- nvmed/src/nvme/cq_reactor.rs | 179 +++++++++++++++++++++++------------ nvmed/src/nvme/mod.rs | 84 +++++++++++++--- xhcid/src/main.rs | 4 +- 5 files changed, 200 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a006c6d13..c46545bf26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -740,7 +740,8 @@ dependencies = [ "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", "pcid 0.1.0", "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", + "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index ec8152f9e9..002d88c6e4 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -9,8 +9,9 @@ bitflags = "0.7" crossbeam-channel = "0.4" log = "0.4" redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } -redox_syscall = "0.1" +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +smallvec = "1" block-io-wrapper = { path = "../block-io-wrapper" } pcid = { path = "../pcid" } diff --git a/nvmed/src/nvme/cq_reactor.rs b/nvmed/src/nvme/cq_reactor.rs index 59532aa6bf..2e16b62ce7 100644 --- a/nvmed/src/nvme/cq_reactor.rs +++ b/nvmed/src/nvme/cq_reactor.rs @@ -1,26 +1,34 @@ +//! The Completion Queue Reactor. Functions like any other async/await reactor, but are driven by +//! IRQs triggering wakeups in order to poll NVME completion queues. + use std::collections::BTreeMap; use std::fs::File; use std::future::Future; use std::io::prelude::*; use std::pin::Pin; use std::sync::{Arc, Mutex}; -use std::{io, task, thread}; +use std::{io, mem, task, thread}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use syscall::Result; use syscall::data::Event; +use syscall::flag::EVENT_READ; use crossbeam_channel::{Sender, Receiver}; -use crate::nvme::{InterruptMethod, InterruptSources, Nvme, NvmeComp}; +use crate::nvme::{CqId, CmdId, InterruptMethod, InterruptSources, Nvme, NvmeComp, NvmeCompQueue, SqId}; /// A notification request, sent by the future in order to tell the completion thread that the /// current task wants a notification when a matching completion queue entry has been seen. pub enum NotifReq { RequestCompletion { - queue_id: usize, + cq_id: CqId, + sq_id: SqId, + cmd_id: CmdId, + waker: task::Waker, - // TODO: Get rid of this allocation + + // TODO: Get rid of this allocation, or maybe a thread-local vec for reusing. message: Arc>>, }, } @@ -28,7 +36,9 @@ pub enum NotifReq { struct PendingReq { waker: task::Waker, message: Arc>>, - queue_id: usize, + cq_id: u16, + sq_id: u16, + cmd_id: u16, } struct CqReactor { int_sources: InterruptSources, @@ -43,25 +53,7 @@ impl CqReactor { let fd = syscall::open("event:", O_CLOEXEC | O_RDWR)?; let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; - let mut msix_iter; - let mut msi_iter; - let mut intx_iter; - - let iter: &mut dyn Iterator = match int_sources { - InterruptSources::MsiX(ref btree) => { - msix_iter = btree.iter().map(|(&n, f)| (n, f)); - &mut msix_iter - } - InterruptSources::Msi(ref btree) => { - msi_iter = btree.iter().map(|(&n, f)| (u16::from(n), f)); - &mut msi_iter - } - InterruptSources::Intx(ref file) => { - intx_iter = std::iter::once((0, file)); - &mut intx_iter - } - }; - for (num, irq_handle) in iter { + for (num, irq_handle) in int_sources.iter_mut() { if file.write(&Event { id: irq_handle.as_raw_fd() as usize, flags: syscall::EVENT_READ, @@ -84,23 +76,95 @@ impl CqReactor { fn handle_notif_reqs(&mut self) { for req in self.receiver.try_iter() { match req { - NotifReq::RequestCompletion { queue_id, waker, message } => self.pending_reqs.push(PendingReq { - queue_id, + NotifReq::RequestCompletion { sq_id, cq_id, cmd_id, waker, message } => self.pending_reqs.push(PendingReq { + sq_id, + cq_id, + cmd_id, message, waker, }), } } } - fn block_on_new_irq(&mut self) -> Event { - let mut event = Event::default(); - self.event_queue.read(&mut event); - event + fn poll_completion_queues(&mut self, iv: u16) -> Option<()> { + let ivs_read_guard = self.nvme.cqs_for_ivs.read().unwrap(); + let cqs_read_guard = self.nvme.completion_queues.read().unwrap(); + + let mut entry_count = 0; + + for cq_id in ivs_read_guard.get(&iv)?.iter() { + let completion_queue_guard = cqs_read_guard.get(cq_id)?.lock().unwrap(); + let completion_queue: &mut NvmeCompQueue = &mut *completion_queue_guard; + + let entry = match completion_queue.complete() { + Some((_index, entry)) => entry, + None => continue, + }; + + self.try_notify_futures(cq_id, &entry); + + entry_count += 1; + } + if entry_count == 0 { + + } + + Some(()) } - fn run(mut self) -> ! { + fn try_notify_futures(&mut self, cq_id: CqId, entry: &NvmeComp) -> Option<()> { + let mut i = 0usize; + + let mut futures_notified = 0; + + while i < self.pending_reqs.len() { + let pending_req = &self.pending_reqs[i]; + + if pending_req.cq_id == cq_id && pending_req.sq_id == entry.sq_id && pending_req.cid == entry.cmd_id { + let pending_req_owned = self.pending_reqs.remove(i); + + *pending_req_owned.message.lock().unwrap() = Some(*entry); + pending_req_owned.waker.wake(); + + futures_notified += 1; + } else { + i += 1; + } + } + if futures_notified == 0 { + } + } + + fn run(mut self) { + let mut event = Event::default(); + let mut irq_word = [0u8; 8]; // stores the IRQ count + + const WORD_SIZE: usize = mem::size_of::(); + loop { self.handle_notif_reqs(); - let event = self.block_on_new_irq(); + + // block on getting the next event + if self.event_queue.read(&mut event) == 0 { + // event queue has been destroyed + break; + } + if event.flags & EVENT_READ == 0 { + continue; + } + + let (vector, irq_handle) = match self.int_sources.get_mut().nth(event.id) { + Some(s) => s, + None => continue, + }; + if irq_handle.read(&mut irq_word[..WORD_SIZE]) == 0 { + continue; + } + // acknowledge the interrupt (only necessary for level-triggered INTx# interrups) + if irq_handle.write(&irq_word[..WORD_SIZE]) == 0 { + continue; + } + + self.poll_completion_queues(vector); } } } @@ -108,9 +172,10 @@ impl CqReactor { pub fn start_cq_reactor_thread(nvme: Arc, interrupt_sources: InterruptSources, receiver: Receiver) -> thread::JoinHandle<()> { // Actually, nothing prevents us from spawning additional threads. the channel is MPMC and // everything is properly synchronized. I'm not saying this is strictly required, but with - // multiple completion queues it might actually be worth considering. The IRQ subsystem might - // be improved to lower the latency, but MSI-X allows multiple vectors to point to different - // CPUs, so that the load is balanced across the logical processors. + // multiple completion queues it might actually be worth considering. The (in-kernel) IRQ + // subsystem can have some room for improvement regarding lowering the latency, but MSI-X allows + // multiple vectors to point to different CPUs, so that the load can be balanced across the + // logical processors. thread::spawn(move || { CqReactor::new(nvme, interrupt_sources, receiver) .expect("nvmed: failed to setup CQ reactor") @@ -118,17 +183,17 @@ pub fn start_cq_reactor_thread(nvme: Arc, interrupt_sources: InterruptSour }) } -pub struct CompletionMessage { +struct CompletionMessage { cq_entry: NvmeComp, } enum CompletionFuture { // not really required, but makes futures inert - Init { - sender: Sender, - queue_id: usize, - }, Pending { + sender: Sender, + cq_id: CqId, + cmd_id: CmdId, + sq_id: SqId, message: Arc>>, }, Finished, @@ -144,24 +209,17 @@ impl Future for CompletionFuture { let this = self.get_mut(); match this { - &mut Self::Init { sender, queue_id } => { - let message = Arc::new(Mutex::new(None)); - sender.send(NotifReq::RequestCompletion { - queue_id, - waker: context.waker().clone(), - message: Arc::clone(&message), - }); - *this = CompletionFuture::Pending { - message, - }; - task::Poll::Pending - } - &mut Self::Pending { message } => if let Some(value) = message.lock().unwrap().take() { + &mut Self::Pending { message, cq_id, cmd_id, sq_id, sender } => if let Some(value) = message.lock().unwrap().take() { *this = Self::Finished; task::Poll::Ready(value.cq_entry) } else { - // woken up but the reactor hadn't sent the message. - // this is ideally unreachable + sender.send(NotifReq::RequestCompletion { + cq_id, + sq_id, + cmd_id, + waker: context.waker().clone(), + message: Arc::clone(&message), + }); task::Poll::Pending } &mut Self::Finished => panic!("calling poll() on an already finished CompletionFuture"), @@ -171,10 +229,15 @@ impl Future for CompletionFuture { impl Nvme { - pub fn completion(&self, cq_id: usize) -> impl Future + '_ { - CompletionFuture::Init { + /// Returns a future representing an eventual completion queue event, in `cq_id`, from `sq_id`, + /// with the individual command identified by `cmd_id`. + pub fn completion(&self, sq_id: usize, cmd_id: usize, cq_id: usize) -> impl Future + '_ { + CompletionFuture::Pending { sender: self.reactor_sender.clone(), - queue_id: cq_id, + cq_id, + cmd_id, + sq_id, + message: Arc::new(Mutex::new(None)), } } } diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index ac56cb9b78..0420020022 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -1,10 +1,11 @@ use std::collections::BTreeMap; use std::fs::File; use std::sync::{Mutex, RwLock}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize, AtomicU16, Ordering}; use std::ptr; use crossbeam_channel::Sender; +use smallvec::{smallvec, SmallVec}; use syscall::io::{Dma, Io, Mmio}; use syscall::error::{Error, Result, EINVAL}; @@ -21,9 +22,47 @@ pub enum InterruptSources { Msi(BTreeMap), Intx(File), } +impl InterruptSources { + pub fn iter_mut(&mut self) -> impl Iterator { + use std::collections::btree_map::IterMut as BTreeIterMut; + use std::iter::Once; + enum IterMut<'a> { + Msi(BTreeIterMut<'a, u16, File>), + MsiX(BTreeIterMut<'a, u8, File>), + Intx(Once<&'a mut File>), + } + impl<'a> Iterator for IterMut<'a> { + type Item = (u16, &'a mut File); + + fn next(&mut self) -> Option { + match self { + &mut Self::Msi(ref mut iter) => iter.next().map(|&mut (vector, ref mut handle)| (u16::from(vector), handle)), + &mut Self::MsiX(ref mut iter) => iter.next(), + &mut Self::Intx(ref mut iter) => (0, iter.next()), + } + } + fn size_hint(&self) -> (usize, Option) { + match self { + &Self::Msi(mut iter) => iter.size_hint(), + &Self::MsiX(mut iter) => iter.size_hint(), + &Self::Intx(mut iter) => iter.size_hint(), + } + } + } + + match self { + &mut Self::MsiX(ref mut map) => IterMut::MsiX(map.iter_mut()), + &mut Self::Msi(ref mut map) => IterMut::Msi(map.iter_mut()), + &mut Self::Intx(ref mut single) => IterMut::Intx(false, single), + } + } +} + +/// The way interrupts are sent. Unlike other PCI-based interfaces, like XHCI, it doesn't seem like +/// NVME supports operating with interrupts completely disabled. pub enum InterruptMethod { - /// INTx# interrupt pins + /// Traditional level-triggered, INTx# interrupt pins. Intx, /// Message signaled interrupts Msi(MsiCapability), @@ -85,6 +124,9 @@ pub struct NvmeCmd { cdw15: u32, } +pub struct IoCompletionQueueCreateInfo { +} + impl NvmeCmd { pub fn create_io_completion_queue(cid: u16, qid: u16, ptr: usize, size: u16) -> Self { Self { @@ -108,7 +150,7 @@ impl NvmeCmd { Self { opcode: 1, flags: 0, - cid: cid, + cid, nsid: 0, _rsvd: 0, mptr: 0, @@ -126,8 +168,8 @@ impl NvmeCmd { Self { opcode: 6, flags: 0, - cid: cid, - nsid: nsid, + cid, + nsid, _rsvd: 0, mptr: 0, dptr: [ptr as u64, 0], @@ -316,22 +358,37 @@ impl NvmeCompQueue { } } +#[derive(Debug)] pub struct NvmeNamespace { pub id: u32, pub blocks: u64, pub block_size: u64, } +pub type CqId = u16; +pub type SqId = u16; +pub type CmdId = u16; +pub type AtomicCqId = AtomicU16; +pub type AtomicSqId = AtomicU16; +pub type AtomicCmdId = AtomicU16; + pub struct Nvme { interrupt_method: Mutex, pcid_interface: Mutex, - regs: Mutex<&'static mut NvmeRegs>, - submission_queues: RwLock>>, - pub (crate) completion_queues: RwLock>>, + regs: RwLock<&'static mut NvmeRegs>, + + pub(crate) submission_queues: RwLock>>, + pub(crate) completion_queues: RwLock)>>>, + + // maps interrupt vectors with the completion queues they have + cqs_for_ivs: RwLock>>, + buffer: Mutex>, // 2MB of buffer buffer_prp: Mutex>, // 4KB of PRP for the buffer reactor_sender: Sender, - next_cid: AtomicUsize, + + next_sqid: AtomicSqId, + next_cqid: AtomicCqId, } unsafe impl Send for Nvme {} unsafe impl Sync for Nvme {} @@ -342,12 +399,17 @@ impl Nvme { regs: Mutex::new(unsafe { &mut *(address as *mut NvmeRegs) }), submission_queues: RwLock::new(vec! [Mutex::new(NvmeCmdQueue::new()?), Mutex::new(NvmeCmdQueue::new()?)]), completion_queues: RwLock::new(vec! [Mutex::new(NvmeCompQueue::new()?), Mutex::new(NvmeCompQueue::new()?)]), + // map the zero interrupt vector (which according to the spec shall always point to the + // admin completion queue) to CQID 0 (admin completion queue) + cqs_for_ivs: RwLock::new(std::iter::once((0, smallvec!(0))).collect()), buffer: Mutex::new(Dma::zeroed()?), buffer_prp: Mutex::new(Dma::zeroed()?), - next_cid: AtomicUsize::new(0), interrupt_method: Mutex::new(interrupt_method), pcid_interface: Mutex::new(pcid_interface), reactor_sender, + + next_sqid: AtomicSqId::new(0), + next_cqid: AtomicCqId::new(0), }) } unsafe fn doorbell_write(&self, index: usize, value: u32) { @@ -443,7 +505,7 @@ impl Nvme { } } } - pub fn init_with_queues(&self) -> BTreeMap { + pub async fn init_with_queues(&self) -> BTreeMap { { //TODO: Use buffer let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 6e8befb546..66faca6e95 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -135,7 +135,7 @@ fn main() { let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); let lapic_id = u8::try_from(destination_id).expect("CPU id didn't fit inside u8"); - let msg_addr = x86_64_msix::message_address(lapic_id, false, false, 0b00); + let msg_addr = x86_64_msix::message_address(lapic_id, false, false); let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); @@ -196,7 +196,7 @@ fn main() { let lapic_id = u8::try_from(destination_id).expect("xhcid: CPU id couldn't fit inside u8"); let rh = false; let dm = false; - let addr = x86_64_msix::message_address(lapic_id, rh, dm, 0b00); + let addr = x86_64_msix::message_address(lapic_id, rh, dm); let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); From 737870439a41827219d85e31d45ae012123e3cbd Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 29 Apr 2020 20:36:35 +0200 Subject: [PATCH 0403/1301] Wrap some NVME commands in async (not compiling). --- nvmed/src/nvme/cq_reactor.rs | 8 +- nvmed/src/nvme/mod.rs | 180 +++++++++++++++++------------------ 2 files changed, 92 insertions(+), 96 deletions(-) diff --git a/nvmed/src/nvme/cq_reactor.rs b/nvmed/src/nvme/cq_reactor.rs index 2e16b62ce7..0665c059b2 100644 --- a/nvmed/src/nvme/cq_reactor.rs +++ b/nvmed/src/nvme/cq_reactor.rs @@ -96,11 +96,13 @@ impl CqReactor { let completion_queue_guard = cqs_read_guard.get(cq_id)?.lock().unwrap(); let completion_queue: &mut NvmeCompQueue = &mut *completion_queue_guard; - let entry = match completion_queue.complete() { - Some((_index, entry)) => entry, + let (head, entry) = match completion_queue.complete() { + Some(e) => e, None => continue, }; + self.nvme.completion_queue_head(cq_id, head); + self.try_notify_futures(cq_id, &entry); entry_count += 1; @@ -231,7 +233,7 @@ impl Future for CompletionFuture { impl Nvme { /// Returns a future representing an eventual completion queue event, in `cq_id`, from `sq_id`, /// with the individual command identified by `cmd_id`. - pub fn completion(&self, sq_id: usize, cmd_id: usize, cq_id: usize) -> impl Future + '_ { + pub fn completion(&self, sq_id: SqId, cmd_id: CmdId, cq_id: SqId) -> impl Future + '_ { CompletionFuture::Pending { sender: self.reactor_sender.clone(), cq_id, diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 0420020022..2bff2f2cf2 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -186,7 +186,7 @@ impl NvmeCmd { Self { opcode: 6, flags: 0, - cid: cid, + cid, nsid: 0, _rsvd: 0, mptr: 0, @@ -204,7 +204,7 @@ impl NvmeCmd { Self { opcode: 6, flags: 0, - cid: cid, + cid, nsid: base, _rsvd: 0, mptr: 0, @@ -255,6 +255,23 @@ impl NvmeCmd { } } +#[derive(Clone, Copy)] +#[repr(packed)] +pub struct IdentifyControllerData { + /// PCI vendor ID, always the same as in the PCI function header. + pub vid: u16, + /// PCI subsystem vendor ID. + pub ssvid: u16, + /// ASCII + pub serial_no: [u8; 20], + /// ASCII + pub model_no: [u8; 48], + /// ASCII + pub firmware_rev: [u8; 8], + // TODO: Lots of fields + pub _4k_pad: [u8; 4096 - 72], +} + #[derive(Clone, Copy, Debug)] #[repr(packed)] pub struct NvmeComp { @@ -412,8 +429,12 @@ impl Nvme { next_cqid: AtomicCqId::new(0), }) } + /// Write to a doorbell register. + /// + /// # Locking + /// Locks `regs`. unsafe fn doorbell_write(&self, index: usize, value: u32) { - let mut regs_guard = self.regs.lock().unwrap(); + let mut regs_guard = self.regs.write().unwrap(); let dstrd = ((regs_guard.cap.read() >> 32) & 0b1111) as usize; let addr = ((*regs_guard) as *mut NvmeRegs as usize) @@ -505,97 +526,70 @@ impl Nvme { } } } + pub fn submit_command NvmeCmd>(&self, sq_id: SqId, f: F) -> CmdId { + let sqs_read_guard = self.submission_queues.read().unwrap(); + let sq_lock = sqs_read_guard.get(&sq_id).expect("nvmed: internal error: given SQ for SQ ID not there").lock().unwrap(); + let cmd_id = u16::try_from(sq_lock.i).expect("nvmed: internal error: CQ has more than 2^16 entries"); + let tail = sq_lock.submit(f(cmd_id)); + self.submission_queue_tail(sq_id, tail); + cmd_id + } + pub fn submit_admin_command NvmeCmd>(&self, f: F) -> CmdId { + self.submit_admin_command(0, f) + } + pub async fn admin_queue_completion(&self, cmd_id: CmdId) -> NvmeComp { + self.completion(0, cmd_id, 0).await + } + + /// Returns the serial number, model, and firmware, in that order. + pub async fn identify_controller(&self) { + // TODO: Use same buffer + let data: Dma = Dma::zeroed().unwrap(); + + // println!(" - Attempting to identify controller"); + let cid = self.submit_admin_command(|cid| NvmeCmd::identify_controller( + cid, data.physical() + )); + + // println!(" - Waiting to identify controller"); + let comp = self.admin_queue_completion(cid).await; + + // println!(" - Dumping identify controller"); + + let model_cow = String::from_utf8_lossy(&data.model_no); + let serial_cow = String::from_utf8_lossy(&data.serial_no); + let fw_cow = String::from_utf8_lossy(&data.firmware_rev); + + let model = model_cow.trim(); + let serial = serial_cow.trim(); + let firmware = fw_cow.trim(); + + println!( + " - Model: {} Serial: {} Firmware: {}", + model, + serial, + firmware, + ); + } + pub async fn identify_namespace_list(&self, base: u32) -> Vec { + // TODO: Use buffer + let data: Dma<[u32; 1024]> = Dma::zeroed().unwrap(); + + // println!(" - Attempting to retrieve namespace ID list"); + let cmd_id = self.submit_admin_command(|cid| NvmeCmd::identify_namespace_list( + cid, data.physical(), base + )); + + // println!(" - Waiting to retrieve namespace ID list"); + let comp = self.admin_queue_completion(cmd_id).await; + + // println!(" - Dumping namespace ID list"); + data.iter().copied().take_while(|&nsid| nsid != 0).collect() + } + pub async fn init_with_queues(&self) -> BTreeMap { - { - //TODO: Use buffer - let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); - - // println!(" - Attempting to identify controller"); - { - let qid = 0; - let queue = &mut self.submission_queues[qid]; - let cid = queue.i as u16; - let entry = NvmeCmd::identify_controller( - cid, data.physical() - ); - let tail = queue.submit(entry); - self.submission_queue_tail(qid as u16, tail as u16); - } - - // println!(" - Waiting to identify controller"); - { - let qid = 0; - let queue = &mut self.completion_queues[qid]; - let (head, entry) = queue.complete_spin(); - self.completion_queue_head(qid as u16, head as u16); - } - - // println!(" - Dumping identify controller"); - - let mut serial = String::new(); - for &b in &data[4..24] { - if b == 0 { - break; - } - serial.push(b as char); - } - - let mut model = String::new(); - for &b in &data[24..64] { - if b == 0 { - break; - } - model.push(b as char); - } - - let mut firmware = String::new(); - for &b in &data[64..72] { - if b == 0 { - break; - } - firmware.push(b as char); - } - - println!( - " - Model: {} Serial: {} Firmware: {}", - model.trim(), - serial.trim(), - firmware.trim() - ); - } - - let mut nsids = Vec::new(); - { - //TODO: Use buffer - let data: Dma<[u32; 1024]> = Dma::zeroed().unwrap(); - - // println!(" - Attempting to retrieve namespace ID list"); - { - let qid = 0; - let queue = &mut self.submission_queues[qid]; - let cid = queue.i as u16; - let entry = NvmeCmd::identify_namespace_list( - cid, data.physical(), 0 - ); - let tail = queue.submit(entry); - self.submission_queue_tail(qid as u16, tail as u16); - } - - // println!(" - Waiting to retrieve namespace ID list"); - { - let qid = 0; - let queue = &mut self.completion_queues[qid]; - let (head, entry) = queue.complete_spin(); - self.completion_queue_head(qid as u16, head as u16); - } - - // println!(" - Dumping namespace ID list"); - for &nsid in data.iter() { - if nsid != 0 { - nsids.push(nsid); - } - } - } + self.identify_controller().await; + let nsids = self.identify_namespace_list(0).await; let mut namespaces = BTreeMap::new(); for &nsid in nsids.iter() { From cbeb0070ec644e81b376eeb1755fc7d97a567eee Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 29 Apr 2020 20:44:38 +0200 Subject: [PATCH 0404/1301] WIP: Asyncify namespace identification. --- Cargo.lock | 1 + nvmed/Cargo.toml | 1 + nvmed/src/nvme/mod.rs | 78 +++++++++++++++++++------------------------ 3 files changed, 36 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c46545bf26..e68857c1cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -736,6 +736,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "block-io-wrapper 0.1.0", "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", "pcid 0.1.0", diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index 002d88c6e4..dca9a5dee1 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" arrayvec = "0.5" bitflags = "0.7" crossbeam-channel = "0.4" +futures = "0.3" log = "0.4" redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 2bff2f2cf2..6dc5b47274 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -586,55 +586,45 @@ impl Nvme { // println!(" - Dumping namespace ID list"); data.iter().copied().take_while(|&nsid| nsid != 0).collect() } + pub async fn identify_namespace(&self, nsid: u32) -> NvmeNamespace { + //TODO: Use buffer + let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); + + // println!(" - Attempting to identify namespace {}", nsid); + let cmd_id = self.submit_admin_command(|cid| NvmeCmd::identify_namespace( + cid, data.physical(), nsid + )); + + // println!(" - Waiting to identify namespace {}", nsid); + let comp = self.admin_queue_completion(cmd_id).await; + + // println!(" - Dumping identify namespace"); + + let size = *(data.as_ptr().offset(0) as *const u64); + let capacity = *(data.as_ptr().offset(8) as *const u64); + println!( + " - ID: {} Size: {} Capacity: {}", + nsid, + size, + capacity + ); + + //TODO: Read block size + + NvmeNamespace { + id: nsid, + blocks: size, + block_size: 512, // TODO + } + } pub async fn init_with_queues(&self) -> BTreeMap { - self.identify_controller().await; - let nsids = self.identify_namespace_list(0).await; + let ((), nsids) = futures::join!(self.identify_controller(), self.identify_namespace_list(0)); let mut namespaces = BTreeMap::new(); - for &nsid in nsids.iter() { - //TODO: Use buffer - let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); - // println!(" - Attempting to identify namespace {}", nsid); - { - let qid = 0; - let queue = &mut self.submission_queues[qid]; - let cid = queue.i as u16; - let entry = NvmeCmd::identify_namespace( - cid, data.physical(), nsid - ); - let tail = queue.submit(entry); - self.submission_queue_tail(qid as u16, tail as u16); - } - - // println!(" - Waiting to identify namespace {}", nsid); - { - let qid = 0; - let queue = &mut self.completion_queues[qid]; - let (head, entry) = queue.complete_spin(); - self.completion_queue_head(qid as u16, head as u16); - } - - // println!(" - Dumping identify namespace"); - - - let size = *(data.as_ptr().offset(0) as *const u64); - let capacity = *(data.as_ptr().offset(8) as *const u64); - println!( - " - ID: {} Size: {} Capacity: {}", - nsid, - size, - capacity - ); - - //TODO: Read block size - - namespaces.insert(nsid, NvmeNamespace { - id: nsid, - blocks: size, - block_size: 512, // TODO - }); + for nsid in nsids.iter().copied() { + namespaces.insert(nsid, self.identify_namespace(nsid).await); } for io_qid in 1..self.completion_queues.len() { From 3207f5a0093861864c9bd580b4ff75953bf6c9c2 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 30 Apr 2020 14:48:43 +0200 Subject: [PATCH 0405/1301] WIP: Make I/O completion queue creation async. --- nvmed/src/nvme/mod.rs | 91 ++++++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 35 deletions(-) diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 6dc5b47274..57b39a41cf 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -1,3 +1,4 @@ +use std::convert::TryFrom; use std::collections::BTreeMap; use std::fs::File; use std::sync::{Mutex, RwLock}; @@ -93,7 +94,7 @@ pub struct MsixCfg { pub pba: &'static mut [Mmio], } -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug, Default)] #[repr(packed)] pub struct NvmeCmd { /// Opcode @@ -124,11 +125,12 @@ pub struct NvmeCmd { cdw15: u32, } -pub struct IoCompletionQueueCreateInfo { -} - impl NvmeCmd { - pub fn create_io_completion_queue(cid: u16, qid: u16, ptr: usize, size: u16) -> Self { + pub fn create_io_completion_queue(cid: u16, qid: u16, ptr: usize, size: u16, iv: Option) -> Self { + const DW11_PHYSICALLY_CONTIGUOUS_BIT: u32 = 0x0000_0001; + const DW11_ENABLE_INTERRUPTS_BIT: u32 = 0x0000_0002; + const DW11_INTERRUPT_VECTOR_SHIFT: u8 = 16; + Self { opcode: 5, flags: 0, @@ -138,7 +140,13 @@ impl NvmeCmd { mptr: 0, dptr: [ptr as u64, 0], cdw10: ((size as u32) << 16) | (qid as u32), - cdw11: 1 /* Physically Contiguous */, //TODO: IV, IEN + + cdw11: DW11_PHYSICALLY_CONTIGUOUS_BIT | if let Some(iv) = iv { + // enable interrupts if a vector is present + DW11_ENABLE_INTERRUPTS_BIT + | (u32::from(iv) << DW11_INTERRUPT_VECTOR_SHIFT) + } else { 0 }, + cdw12: 0, cdw13: 0, cdw14: 0, @@ -217,13 +225,21 @@ impl NvmeCmd { cdw15: 0, } } + pub fn get_features(cid: u16, ptr: usize, fid: u8) -> Self { + Self { + opcode: 0xA, + dptr: [ptr as u64, 0], + cdw10: u32::from(fid), // TODO: SEL + .. Default::default() + } + } pub fn io_read(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { Self { opcode: 2, flags: 1 << 6, - cid: cid, - nsid: nsid, + cid, + nsid, _rsvd: 0, mptr: 0, dptr: [ptr0, ptr1], @@ -240,8 +256,8 @@ impl NvmeCmd { Self { opcode: 1, flags: 1 << 6, - cid: cid, - nsid: nsid, + cid, + nsid, _rsvd: 0, mptr: 0, dptr: [ptr0, ptr1], @@ -617,7 +633,32 @@ impl Nvme { block_size: 512, // TODO } } + pub async fn create_io_completion_queue(&self, io_cq_id: CqId, vector: Option) { + let (ptr, len) = { + let mut completion_queues_guard = self.completion_queues.write().unwrap(); + let queue_guard = completion_queues_guard.entry(io_cq_id).or_insert_with(|| { + let queue = NvmeCompQueue::new().expect("nvmed: failed to allocate I/O completion queue"); + let sqs = SmallVec::new(); + Mutex::new((queue, sqs)) + }).get_mut().unwrap(); + + let &(ref queue, _) = &*queue_guard; + (queue.data.physical(), queue.data.len()) + }; + + let len = u16::try_from(len).expect("nvmed: internal error: I/O CQ longer than 2^16 entries"); + let raw_len = len.checked_sub(1).expect("nvmed: internal error: CQID 0 for I/O CQ"); + + let cmd_id = self.submit_admin_command(|cid| NvmeCmd::create_io_completion_queue( + cid, io_cq_id, ptr, raw_len, vector, + )); + let comp = self.admin_queue_completion(cmd_id).await; + + if let Some(vector) = vector { + self.cqs_for_ivs.write().unwrap().entry(vector).or_insert_with(SmallVec::new).push(io_cq_id); + } + } pub async fn init_with_queues(&self) -> BTreeMap { let ((), nsids) = futures::join!(self.identify_controller(), self.identify_namespace_list(0)); @@ -627,32 +668,11 @@ impl Nvme { namespaces.insert(nsid, self.identify_namespace(nsid).await); } - for io_qid in 1..self.completion_queues.len() { - let (ptr, len) = { - let queue = &self.completion_queues[io_qid]; - (queue.data.physical(), queue.data.len()) - }; - - // println!(" - Attempting to create I/O completion queue {}", io_qid); - { - let qid = 0; - let queue = &mut self.submission_queues[qid]; - let cid = queue.i as u16; - let entry = NvmeCmd::create_io_completion_queue( - cid, io_qid as u16, ptr, (len - 1) as u16 - ); - let tail = queue.submit(entry); - self.submission_queue_tail(qid as u16, tail as u16); - } - - // println!(" - Waiting to create I/O completion queue {}", io_qid); - { - let qid = 0; - let queue = &mut self.completion_queues[qid]; - let (head, entry) = queue.complete_spin(); - self.completion_queue_head(qid as u16, head as u16); - } + // TODO: Multiple queues + for io_qid in 1u16..=1 { + self.create_io_completion_queue(io_qid, Some(0)).await; } + /* for io_qid in 1..self.submission_queues.len() { let (ptr, len) = { @@ -681,6 +701,7 @@ impl Nvme { self.completion_queue_head(qid as u16, head as u16); } } + */ // println!(" - Complete"); From 167b994aeadd0e5a779f4706e2384638e85c16e9 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 30 Apr 2020 15:01:35 +0200 Subject: [PATCH 0406/1301] WIP: Asyncify IO SQ creation too. --- nvmed/src/nvme/mod.rs | 56 ++++++++++++++++--------------------------- 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 57b39a41cf..ba9feb33fe 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -659,6 +659,25 @@ impl Nvme { self.cqs_for_ivs.write().unwrap().entry(vector).or_insert_with(SmallVec::new).push(io_cq_id); } } + pub async fn create_io_submission_queue(&self, io_sq_id: SqId, io_cq_id: CqId) { + let (ptr, len) = { + let mut submission_queues_guard = self.submission_queues.write().unwrap(); + + let queue_guard = submission_queues_guard.entry(io_sq_id).or_insert_with(|| { + Mutex::new(NvmeCmdQueue::new().expect("nvmed: failed to allocate I/O completion queue")) + }).get_mut().unwrap(); + (queue_guard.data.physical(), queue_guard.data.len()) + }; + + let len = u16::try_from(len).expect("nvmed: internal error: I/O SQ longer than 2^16 entries"); + let raw_len = len.checked_sub(1).expect("nvmed: internal error: SQID 0 for I/O SQ"); + + let cmd_id = self.submit_admin_command(|cid| NvmeCmd::create_io_submission_queue( + cid, io_sq_id, ptr, raw_len, io_cq_id, + )); + let comp = self.admin_queue_completion(cmd_id).await; + } + pub async fn init_with_queues(&self) -> BTreeMap { let ((), nsids) = futures::join!(self.identify_controller(), self.identify_namespace_list(0)); @@ -669,41 +688,8 @@ impl Nvme { } // TODO: Multiple queues - for io_qid in 1u16..=1 { - self.create_io_completion_queue(io_qid, Some(0)).await; - } - /* - - for io_qid in 1..self.submission_queues.len() { - let (ptr, len) = { - let queue = &self.submission_queues[io_qid]; - (queue.data.physical(), queue.data.len()) - }; - - // println!(" - Attempting to create I/O submission queue {}", io_qid); - { - let qid = 0; - let queue = &mut self.submission_queues[qid]; - let cid = queue.i as u16; - //TODO: Get completion queue ID through smarter mechanism - let entry = NvmeCmd::create_io_submission_queue( - cid, io_qid as u16, ptr, (len - 1) as u16, io_qid as u16 - ); - let tail = queue.submit(entry); - self.submission_queue_tail(qid as u16, tail as u16); - } - - // println!(" - Waiting to create I/O submission queue {}", io_qid); - { - let qid = 0; - let queue = &mut self.completion_queues[qid]; - let (head, entry) = queue.complete_spin(); - self.completion_queue_head(qid as u16, head as u16); - } - } - */ - - // println!(" - Complete"); + self.create_io_completion_queue(1, Some(0)).await; + self.create_io_submission_queue(1, 1).await; namespaces } From c61e88610823b14da064e096b36f42ad7c3bd531 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 1 May 2020 11:57:55 +0200 Subject: [PATCH 0407/1301] Refactor and rustfmt the nvme driver. --- nvmed/src/main.rs | 159 ++++++--- nvmed/src/nvme/cmd.rs | 162 +++++++++ nvmed/src/nvme/cq_reactor.rs | 198 ++++++++--- nvmed/src/nvme/identify.rs | 93 +++++ nvmed/src/nvme/mod.rs | 658 +++++++++++++---------------------- nvmed/src/nvme/queues.rs | 117 +++++++ nvmed/src/scheme.rs | 202 ++++++++--- pcid/src/pci/msi.rs | 7 +- 8 files changed, 1025 insertions(+), 571 deletions(-) create mode 100644 nvmed/src/nvme/cmd.rs create mode 100644 nvmed/src/nvme/identify.rs create mode 100644 nvmed/src/nvme/queues.rs diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 2c54919298..539c70b69d 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -1,18 +1,20 @@ -use std::{slice, usize}; use std::collections::BTreeMap; use std::convert::TryInto; use std::fs::File; use std::io::{ErrorKind, Read, Write}; +use std::os::unix::io::{FromRawFd, RawFd}; use std::ptr::NonNull; -use std::os::unix::io::{RawFd, FromRawFd}; use std::sync::{Arc, Mutex}; +use std::{slice, usize}; -use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle, PciBar}; -use syscall::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Event, Packet, Result, SchemeBlockMut}; -use syscall::io::Mmio; +use pcid_interface::{PciBar, PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; +use syscall::{ + CloneFlags, Event, Mmio, Packet, Result, SchemeBlockMut, EVENT_READ, PHYSMAP_NO_CACHE, + PHYSMAP_WRITE, +}; use arrayvec::ArrayVec; -use log::{debug, error, info, warn, trace}; +use log::{debug, error, info, trace, warn}; use self::nvme::{InterruptMethod, InterruptSources, Nvme}; use self::scheme::DiskScheme; @@ -29,7 +31,10 @@ pub struct Bar { impl Bar { pub fn allocate(bar: usize, bar_size: usize) -> Result { Ok(Self { - ptr: NonNull::new(syscall::physmap(bar, bar_size, PHYSMAP_NO_CACHE | PHYSMAP_WRITE)? as *mut u8).expect("Mapping a BAR resulted in a nullptr"), + ptr: NonNull::new( + syscall::physmap(bar, bar_size, PHYSMAP_NO_CACHE | PHYSMAP_WRITE)? as *mut u8, + ) + .expect("Mapping a BAR resulted in a nullptr"), physical: bar, bar_size, }) @@ -49,7 +54,11 @@ pub struct AllocatedBars(pub [Mutex>; 6]); /// Get the most optimal yet functional interrupt mechanism: either (in the order preference): /// MSI-X, MSI, and INTx# pin. Returns both runtime interrupt structures (MSI/MSI-X capability /// structures), and the handles to the interrupts. -fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, allocated_bars: &AllocatedBars) -> Result<(InterruptMethod, InterruptSources)> { +fn get_int_method( + pcid_handle: &mut PcidServerHandle, + function: &PciFunction, + allocated_bars: &AllocatedBars, +) -> Result<(InterruptMethod, InterruptSources)> { use pcid_interface::irq_helpers; let features = pcid_handle.fetch_all_features().unwrap(); @@ -60,14 +69,18 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, al // TODO: Allocate more than one vector when possible and useful. if has_msix { // Extended message signaled interrupts. - use pcid_interface::msi::MsixTableEntry; use self::nvme::MsixCfg; + use pcid_interface::msi::MsixTableEntry; let mut capability_struct = match pcid_handle.feature_info(PciFeature::MsiX).unwrap() { PciFeatureInfo::MsiX(msix) => msix, _ => unreachable!(), }; - fn bar_base(allocated_bars: &AllocatedBars, function: &PciFunction, bir: u8) -> Result> { + fn bar_base( + allocated_bars: &AllocatedBars, + function: &PciFunction, + bir: u8, + ) -> Result> { let bir = usize::from(bir); let bar_guard = allocated_bars.0[bir].lock().unwrap(); match &mut *bar_guard { @@ -85,14 +98,24 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, al } } } - let table_bar_base: *mut u8 = bar_base(allocated_bars, function, capability_struct.table_bir())?.as_ptr(); - let pba_bar_base: *mut u8 = bar_base(allocated_bars, function, capability_struct.pba_bir())?.as_ptr(); - let table_base = unsafe { table_bar_base.offset(capability_struct.table_offset() as isize) }; + let table_bar_base: *mut u8 = + bar_base(allocated_bars, function, capability_struct.table_bir())?.as_ptr(); + let pba_bar_base: *mut u8 = + bar_base(allocated_bars, function, capability_struct.pba_bir())?.as_ptr(); + let table_base = + unsafe { table_bar_base.offset(capability_struct.table_offset() as isize) }; let pba_base = unsafe { pba_bar_base.offset(capability_struct.pba_offset() as isize) }; let vector_count = capability_struct.table_size(); - let table_entries: &'static mut [MsixTableEntry] = unsafe { slice::from_raw_parts_mut(table_base as *mut MsixTableEntry, vector_count as usize) }; - let pba_entries: &'static mut [Mmio] = unsafe { slice::from_raw_parts_mut(table_base as *mut Mmio, (vector_count as usize + 63) / 64) }; + let table_entries: &'static mut [MsixTableEntry] = unsafe { + slice::from_raw_parts_mut(table_base as *mut MsixTableEntry, vector_count as usize) + }; + let pba_entries: &'static mut [Mmio] = unsafe { + slice::from_raw_parts_mut( + table_base as *mut Mmio, + (vector_count as usize + 63) / 64, + ) + }; // Mask all interrupts in case some earlier driver/os already unmasked them (according to // the PCI Local Bus spec 3.0, they are masked after system reset). @@ -104,21 +127,25 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, al capability_struct.set_msix_enabled(true); // only affects our local mirror of the cap let (msix_vector_number, irq_handle) = { - use pcid_interface::msi::x86_64 as msi_x86_64; use msi_x86_64::DeliveryMode; + use pcid_interface::msi::x86_64 as msi_x86_64; let entry: &mut MsixTableEntry = &mut table_entries[0]; - let bsp_cpu_id = irq_helpers::read_bsp_apic_id().expect("nvmed: failed to read APIC ID"); - let bsp_lapic_id = bsp_cpu_id.try_into().expect("nvmed: BSP local apic ID couldn't fit inside u8"); - let (vector, irq_handle) = irq_helpers::allocate_single_interrupt_vector(bsp_cpu_id).expect("nvmed: failed to allocate single MSI-X interrupt vector").expect("nvmed: no interrupt vectors left on BSP"); + let bsp_cpu_id = + irq_helpers::read_bsp_apic_id().expect("nvmed: failed to read APIC ID"); + let bsp_lapic_id = bsp_cpu_id + .try_into() + .expect("nvmed: BSP local apic ID couldn't fit inside u8"); + let (vector, irq_handle) = irq_helpers::allocate_single_interrupt_vector(bsp_cpu_id) + .expect("nvmed: failed to allocate single MSI-X interrupt vector") + .expect("nvmed: no interrupt vectors left on BSP"); let msg_addr = msi_x86_64::message_address(bsp_lapic_id, false, false); let msg_data = msi_x86_64::message_data_edge_triggered(DeliveryMode::Fixed, vector); entry.set_addr_lo(msg_addr); entry.set_msg_data(msg_data); - entry.unmask(); (0, irq_handle) }; @@ -128,7 +155,8 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, al table: table_entries, pba: pba_entries, }); - let interrupt_sources = InterruptSources::MsiX(std::iter::once((msix_vector_number, irq_handle)).collect()); + let interrupt_sources = + InterruptSources::MsiX(std::iter::once((msix_vector_number, irq_handle)).collect()); Ok((interrupt_method, interrupt_sources)) } else if has_msi { @@ -139,16 +167,22 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, al }; let (msi_vector_number, irq_handle) = { - use pcid_interface::{MsiSetFeatureInfo, SetFeatureInfo}; - use pcid_interface::msi::x86_64 as msi_x86_64; use msi_x86_64::DeliveryMode; + use pcid_interface::msi::x86_64 as msi_x86_64; + use pcid_interface::{MsiSetFeatureInfo, SetFeatureInfo}; - let bsp_cpu_id = irq_helpers::read_bsp_apic_id().expect("nvmed: failed to read BSP APIC ID"); - let bsp_lapic_id = bsp_cpu_id.try_into().expect("nvmed: BSP local apic ID couldn't fit inside u8"); - let (vector, irq_handle) = irq_helpers::allocate_single_interrupt_vector(bsp_cpu_id).expect("nvmed: failed to allocate single MSI interrupt vector").expect("nvmed: no interrupt vectors left on BSP"); + let bsp_cpu_id = + irq_helpers::read_bsp_apic_id().expect("nvmed: failed to read BSP APIC ID"); + let bsp_lapic_id = bsp_cpu_id + .try_into() + .expect("nvmed: BSP local apic ID couldn't fit inside u8"); + let (vector, irq_handle) = irq_helpers::allocate_single_interrupt_vector(bsp_cpu_id) + .expect("nvmed: failed to allocate single MSI interrupt vector") + .expect("nvmed: no interrupt vectors left on BSP"); let msg_addr = msi_x86_64::message_address(bsp_lapic_id, false, false); - let msg_data = msi_x86_64::message_data_edge_triggered(DeliveryMode::Fixed, vector) as u16; + let msg_data = + msi_x86_64::message_data_edge_triggered(DeliveryMode::Fixed, vector) as u16; pcid_handle.set_feature_info(SetFeatureInfo::Msi(MsiSetFeatureInfo { message_address: Some(msg_addr), @@ -162,14 +196,16 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, al }; let interrupt_method = InterruptMethod::Msi(capability_struct); - let interrupt_sources = InterruptSources::Msi(std::iter::once((msi_vector_number, irq_handle)).collect()); + let interrupt_sources = + InterruptSources::Msi(std::iter::once((msi_vector_number, irq_handle)).collect()); pcid_handle.enable_feature(PciFeature::Msi).unwrap(); Ok((interrupt_method, interrupt_sources)) } else if function.legacy_interrupt_pin.is_some() { // INTx# pin based interrupts. - let irq_handle = File::open(format!("irq:{}", function.legacy_interrupt_line)).expect("nvmed: failed to open INTx# interrupt line"); + let irq_handle = File::open(format!("irq:{}", function.legacy_interrupt_line)) + .expect("nvmed: failed to open INTx# interrupt line"); Ok((InterruptMethod::Intx, InterruptSources::Intx(irq_handle))) } else { // No interrupts at all @@ -179,12 +215,15 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, function: &PciFunction, al fn main() { // Daemonize - if unsafe { syscall::clone(0).unwrap() } != 0 { + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { return; } - let mut pcid_handle = PcidServerHandle::connect_default().expect("nvmed: failed to setup channel to pcid"); - let pci_config = pcid_handle.fetch_config().expect("nvmed: failed to fetch config"); + let mut pcid_handle = + PcidServerHandle::connect_default().expect("nvmed: failed to setup channel to pcid"); + let pci_config = pcid_handle + .fetch_config() + .expect("nvmed: failed to fetch config"); let bar = match pci_config.func.bars[0] { PciBar::Memory(mem) => mem, @@ -201,10 +240,18 @@ fn main() { let allocated_bars = AllocatedBars::default(); let address = unsafe { - syscall::physmap(bar as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("nvmed: failed to map address") + syscall::physmap( + bar as usize, + bar_size as usize, + PHYSMAP_WRITE | PHYSMAP_NO_CACHE, + ) + .expect("nvmed: failed to map address") }; - *allocated_bars.0[0].lock().unwrap() = Some(Bar { physical: bar as usize, bar_size: bar_size as usize, ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr") }); + *allocated_bars.0[0].lock().unwrap() = Some(Bar { + physical: bar as usize, + bar_size: bar_size as usize, + ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"), + }); { let event_fd = syscall::open("event:", syscall::O_RDWR | syscall::O_CLOEXEC) .expect("nvmed: failed to open event queue"); @@ -213,32 +260,44 @@ fn main() { let scheme_name = format!("disk/{}", name); let socket_fd = syscall::open( &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK | syscall::O_CLOEXEC - ).expect("nvmed: failed to create disk scheme"); + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK | syscall::O_CLOEXEC, + ) + .expect("nvmed: failed to create disk scheme"); - syscall::write(event_fd, &syscall::Event { - id: socket_fd, - flags: syscall::EVENT_READ, - data: 0, - }).expect("nvmed: failed to watch disk scheme events"); + syscall::write( + event_fd, + &syscall::Event { + id: socket_fd, + flags: syscall::EVENT_READ, + data: 0, + }, + ) + .expect("nvmed: failed to watch disk scheme events"); let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); - let (interrupt_method, interrupt_sources) = get_int_method(&mut pcid_handle, &pci_config.func, &allocated_bars).expect("nvmed: failed to find a suitable interrupt method"); - let mut nvme = Nvme::new(address, interrupt_method, pcid_handle, reactor_sender).expect("nvmed: failed to allocate driver data"); + let (interrupt_method, interrupt_sources) = + get_int_method(&mut pcid_handle, &pci_config.func, &allocated_bars) + .expect("nvmed: failed to find a suitable interrupt method"); + let mut nvme = Nvme::new(address, interrupt_method, pcid_handle, reactor_sender) + .expect("nvmed: failed to allocate driver data"); let nvme = Arc::new(nvme); unsafe { nvme.init() } nvme::cq_reactor::start_cq_reactor_thread(nvme, interrupt_sources, reactor_receiver); - let namespaces = unsafe { nvme.init_with_queues() }; + let namespaces = unsafe { futures::executor::block_on(nvme.init_with_queues()) }; let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); let mut todo = Vec::new(); 'events: loop { let mut event = Event::default(); - if event_file.read(&mut event).expect("nvmed: failed to read event queue") == 0 { + if event_file + .read(&mut event) + .expect("nvmed: failed to read event queue") + == 0 + { break; } @@ -251,13 +310,13 @@ fn main() { Err(err) => match err.kind() { ErrorKind::WouldBlock => break, _ => Err(err).expect("nvmed: failed to read disk scheme"), - } + }, } todo.push(packet); }, unknown => { panic!("nvmed: unknown event data {}", unknown); - }, + } } let mut i = 0; @@ -265,7 +324,9 @@ fn main() { if let Some(a) = scheme.handle(&todo[i]) { let mut packet = todo.remove(i); packet.a = a; - socket_file.write(&packet).expect("nvmed: failed to write disk scheme"); + socket_file + .write(&packet) + .expect("nvmed: failed to write disk scheme"); } else { i += 1; } diff --git a/nvmed/src/nvme/cmd.rs b/nvmed/src/nvme/cmd.rs new file mode 100644 index 0000000000..251fe0da5f --- /dev/null +++ b/nvmed/src/nvme/cmd.rs @@ -0,0 +1,162 @@ +use super::NvmeCmd; + +impl NvmeCmd { + pub fn create_io_completion_queue( + cid: u16, + qid: u16, + ptr: usize, + size: u16, + iv: Option, + ) -> Self { + const DW11_PHYSICALLY_CONTIGUOUS_BIT: u32 = 0x0000_0001; + const DW11_ENABLE_INTERRUPTS_BIT: u32 = 0x0000_0002; + const DW11_INTERRUPT_VECTOR_SHIFT: u8 = 16; + + Self { + opcode: 5, + flags: 0, + cid, + nsid: 0, + _rsvd: 0, + mptr: 0, + dptr: [ptr as u64, 0], + cdw10: ((size as u32) << 16) | (qid as u32), + + cdw11: DW11_PHYSICALLY_CONTIGUOUS_BIT + | if let Some(iv) = iv { + // enable interrupts if a vector is present + DW11_ENABLE_INTERRUPTS_BIT | (u32::from(iv) << DW11_INTERRUPT_VECTOR_SHIFT) + } else { + 0 + }, + + cdw12: 0, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + + pub fn create_io_submission_queue( + cid: u16, + qid: u16, + ptr: usize, + size: u16, + cqid: u16, + ) -> Self { + Self { + opcode: 1, + flags: 0, + cid, + nsid: 0, + _rsvd: 0, + mptr: 0, + dptr: [ptr as u64, 0], + cdw10: ((size as u32) << 16) | (qid as u32), + cdw11: ((cqid as u32) << 16) | 1, /* Physically Contiguous */ + //TODO: QPRIO + cdw12: 0, //TODO: NVMSETID + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + + pub fn identify_namespace(cid: u16, ptr: usize, nsid: u32) -> Self { + Self { + opcode: 6, + flags: 0, + cid, + nsid, + _rsvd: 0, + mptr: 0, + dptr: [ptr as u64, 0], + cdw10: 0, + cdw11: 0, + cdw12: 0, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + + pub fn identify_controller(cid: u16, ptr: usize) -> Self { + Self { + opcode: 6, + flags: 0, + cid, + nsid: 0, + _rsvd: 0, + mptr: 0, + dptr: [ptr as u64, 0], + cdw10: 1, + cdw11: 0, + cdw12: 0, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + + pub fn identify_namespace_list(cid: u16, ptr: usize, base: u32) -> Self { + Self { + opcode: 6, + flags: 0, + cid, + nsid: base, + _rsvd: 0, + mptr: 0, + dptr: [ptr as u64, 0], + cdw10: 2, + cdw11: 0, + cdw12: 0, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + pub fn get_features(cid: u16, ptr: usize, fid: u8) -> Self { + Self { + opcode: 0xA, + dptr: [ptr as u64, 0], + cdw10: u32::from(fid), // TODO: SEL + ..Default::default() + } + } + + pub fn io_read(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { + Self { + opcode: 2, + flags: 1 << 6, + cid, + nsid, + _rsvd: 0, + mptr: 0, + dptr: [ptr0, ptr1], + cdw10: lba as u32, + cdw11: (lba >> 32) as u32, + cdw12: blocks_1 as u32, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } + + pub fn io_write(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { + Self { + opcode: 1, + flags: 1 << 6, + cid, + nsid, + _rsvd: 0, + mptr: 0, + dptr: [ptr0, ptr1], + cdw10: lba as u32, + cdw11: (lba >> 32) as u32, + cdw12: blocks_1 as u32, + cdw13: 0, + cdw14: 0, + cdw15: 0, + } + } +} diff --git a/nvmed/src/nvme/cq_reactor.rs b/nvmed/src/nvme/cq_reactor.rs index 0665c059b2..80cc48e256 100644 --- a/nvmed/src/nvme/cq_reactor.rs +++ b/nvmed/src/nvme/cq_reactor.rs @@ -1,22 +1,25 @@ -//! The Completion Queue Reactor. Functions like any other async/await reactor, but are driven by -//! IRQs triggering wakeups in order to poll NVME completion queues. +//! The Completion Queue Reactor. Functions like any other async/await reactor, but is driven by +//! IRQs triggering wakeups in order to poll NVME completion queues (see `CompletionFuture`). +//! +//! While the reactor is primarily intended to wait for IRQs and then poll completion queues, it +//! can also be used for notifying when a full submission queue can submit a new command (see +//! `AvailableSqEntryFuture`). -use std::collections::BTreeMap; use std::fs::File; use std::future::Future; use std::io::prelude::*; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::pin::Pin; use std::sync::{Arc, Mutex}; -use std::{io, mem, task, thread}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::{mem, task, thread}; -use syscall::Result; use syscall::data::Event; use syscall::flag::EVENT_READ; +use syscall::Result; -use crossbeam_channel::{Sender, Receiver}; +use crossbeam_channel::{Receiver, Sender}; -use crate::nvme::{CqId, CmdId, InterruptMethod, InterruptSources, Nvme, NvmeComp, NvmeCompQueue, SqId}; +use crate::nvme::{CmdId, CqId, InterruptSources, Nvme, NvmeComp, NvmeCompQueue, SqId}; /// A notification request, sent by the future in order to tell the completion thread that the /// current task wants a notification when a matching completion queue entry has been seen. @@ -29,6 +32,7 @@ pub enum NotifReq { waker: task::Waker, // TODO: Get rid of this allocation, or maybe a thread-local vec for reusing. + // TODO: Maybe the `remem` crate. message: Arc>>, }, } @@ -54,17 +58,25 @@ impl CqReactor { let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; for (num, irq_handle) in int_sources.iter_mut() { - if file.write(&Event { - id: irq_handle.as_raw_fd() as usize, - flags: syscall::EVENT_READ, - data: num as usize, - }).unwrap() == 0 { + if file + .write(&Event { + id: irq_handle.as_raw_fd() as usize, + flags: syscall::EVENT_READ, + data: num as usize, + }) + .unwrap() + == 0 + { panic!("Failed to setup event queue for {} {:?}", num, irq_handle); } } Ok(file) } - fn new(nvme: Arc, int_sources: InterruptSources, receiver: Receiver) -> Result { + fn new( + nvme: Arc, + int_sources: InterruptSources, + receiver: Receiver, + ) -> Result { Ok(Self { event_queue: Self::create_event_queue(&int_sources)?, int_sources, @@ -76,7 +88,13 @@ impl CqReactor { fn handle_notif_reqs(&mut self) { for req in self.receiver.try_iter() { match req { - NotifReq::RequestCompletion { sq_id, cq_id, cmd_id, waker, message } => self.pending_reqs.push(PendingReq { + NotifReq::RequestCompletion { + sq_id, + cq_id, + cmd_id, + waker, + message, + } => self.pending_reqs.push(PendingReq { sq_id, cq_id, cmd_id, @@ -92,24 +110,22 @@ impl CqReactor { let mut entry_count = 0; - for cq_id in ivs_read_guard.get(&iv)?.iter() { - let completion_queue_guard = cqs_read_guard.get(cq_id)?.lock().unwrap(); - let completion_queue: &mut NvmeCompQueue = &mut *completion_queue_guard; + for cq_id in ivs_read_guard.get(&iv)?.iter().copied() { + let completion_queue_guard = cqs_read_guard.get(&cq_id)?.lock().unwrap(); + let &mut (ref mut completion_queue, _) = &mut *completion_queue_guard; let (head, entry) = match completion_queue.complete() { Some(e) => e, None => continue, }; - self.nvme.completion_queue_head(cq_id, head); + self.nvme.completion_queue_head(cq_id, head as u16); self.try_notify_futures(cq_id, &entry); entry_count += 1; } - if entry_count == 0 { - - } + if entry_count == 0 {} Some(()) } @@ -121,10 +137,14 @@ impl CqReactor { while i < self.pending_reqs.len() { let pending_req = &self.pending_reqs[i]; - if pending_req.cq_id == cq_id && pending_req.sq_id == entry.sq_id && pending_req.cid == entry.cmd_id { + if pending_req.cq_id == cq_id + && pending_req.sq_id == entry.sq_id + && pending_req.cmd_id == entry.cid + { let pending_req_owned = self.pending_reqs.remove(i); - *pending_req_owned.message.lock().unwrap() = Some(*entry); + *pending_req_owned.message.lock().unwrap() = + Some(CompletionMessage { cq_entry: *entry }); pending_req_owned.waker.wake(); futures_notified += 1; @@ -132,8 +152,8 @@ impl CqReactor { i += 1; } } - if futures_notified == 0 { - } + if futures_notified == 0 {} + Some(()) } fn run(mut self) { @@ -146,32 +166,37 @@ impl CqReactor { self.handle_notif_reqs(); // block on getting the next event - if self.event_queue.read(&mut event) == 0 { + if self.event_queue.read(&mut event).unwrap() == 0 { // event queue has been destroyed break; } - if event.flags & EVENT_READ == 0 { + if event.flags & EVENT_READ != EVENT_READ { continue; } - let (vector, irq_handle) = match self.int_sources.get_mut().nth(event.id) { + let (vector, irq_handle) = match self.int_sources.iter_mut().nth(event.id) { Some(s) => s, None => continue, }; - if irq_handle.read(&mut irq_word[..WORD_SIZE]) == 0 { + if irq_handle.read(&mut irq_word[..WORD_SIZE]).unwrap() == 0 { continue; } // acknowledge the interrupt (only necessary for level-triggered INTx# interrups) - if irq_handle.write(&irq_word[..WORD_SIZE]) == 0 { + if irq_handle.write(&irq_word[..WORD_SIZE]).unwrap() == 0 { continue; } - + self.nvme.set_vector_masked(vector, true); self.poll_completion_queues(vector); + self.nvme.set_vector_masked(vector, false); } } } -pub fn start_cq_reactor_thread(nvme: Arc, interrupt_sources: InterruptSources, receiver: Receiver) -> thread::JoinHandle<()> { +pub fn start_cq_reactor_thread( + nvme: Arc, + interrupt_sources: InterruptSources, + receiver: Receiver, +) -> thread::JoinHandle<()> { // Actually, nothing prevents us from spawning additional threads. the channel is MPMC and // everything is properly synchronized. I'm not saying this is strictly required, but with // multiple completion queues it might actually be worth considering. The (in-kernel) IRQ @@ -189,7 +214,7 @@ struct CompletionMessage { cq_entry: NvmeComp, } -enum CompletionFuture { +enum CompletionFutureState { // not really required, but makes futures inert Pending { sender: Sender, @@ -200,6 +225,9 @@ enum CompletionFuture { }, Finished, } +pub struct CompletionFuture { + state: CompletionFutureState, +} // enum not self-referential impl Unpin for CompletionFuture {} @@ -208,38 +236,96 @@ impl Future for CompletionFuture { type Output = NvmeComp; fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { - let this = self.get_mut(); + let this = &mut self.get_mut().state; match this { - &mut Self::Pending { message, cq_id, cmd_id, sq_id, sender } => if let Some(value) = message.lock().unwrap().take() { - *this = Self::Finished; - task::Poll::Ready(value.cq_entry) - } else { - sender.send(NotifReq::RequestCompletion { - cq_id, - sq_id, - cmd_id, - waker: context.waker().clone(), - message: Arc::clone(&message), - }); - task::Poll::Pending + &mut CompletionFutureState::Pending { + message, + cq_id, + cmd_id, + sq_id, + sender, + } => { + if let Some(value) = message.lock().unwrap().take() { + *this = CompletionFutureState::Finished; + task::Poll::Ready(value.cq_entry) + } else { + sender.send(NotifReq::RequestCompletion { + cq_id, + sq_id, + cmd_id, + waker: context.waker().clone(), + message: Arc::clone(&message), + }); + task::Poll::Pending + } + } + &mut CompletionFutureState::Finished => { + panic!("calling poll() on an already finished CompletionFuture") } - &mut Self::Finished => panic!("calling poll() on an already finished CompletionFuture"), } } } - impl Nvme { /// Returns a future representing an eventual completion queue event, in `cq_id`, from `sq_id`, /// with the individual command identified by `cmd_id`. - pub fn completion(&self, sq_id: SqId, cmd_id: CmdId, cq_id: SqId) -> impl Future + '_ { - CompletionFuture::Pending { - sender: self.reactor_sender.clone(), - cq_id, - cmd_id, - sq_id, - message: Arc::new(Mutex::new(None)), + pub fn completion(&self, sq_id: SqId, cmd_id: CmdId, cq_id: SqId) -> CompletionFuture { + CompletionFuture { + state: CompletionFutureState::Pending { + sender: self.reactor_sender.clone(), + cq_id, + cmd_id, + sq_id, + message: Arc::new(Mutex::new(None)), + }, + } + } + /// Returns a future representing a submission queue becoming non-full. Make sure that the + /// queue doesn't have any additional free entries first though, so that the reactor doesn't + /// have to interfere. + pub fn wait_for_available_submission(&self, sq_id: SqId) -> AvailableSqEntryFuture { + todo!() + } +} + +struct AvailMessage { + cmd_id: CmdId, +} + +enum AvailableSqEntryFutureState { + Pending { + sq_id: SqId, + message: Option>>>, + }, + Finished, +} + +pub struct AvailableSqEntryFuture { + state: AvailableSqEntryFutureState, +} + +impl Unpin for AvailableSqEntryFuture {} + +impl Future for AvailableSqEntryFuture { + type Output = CmdId; + + fn poll(self: Pin<&mut Self>, context: &mut task::Context<'_>) -> task::Poll { + let this = &mut self.get_mut().state; + + match this { + &mut AvailableSqEntryFutureState::Pending { + sq_id, + ref mut message, + } => { + if let Some(message) = message.lock().unwrap().take() { + } else { + task::Poll::Pending + } + } + &mut AvailableSqEntryFutureState::Finished => { + panic!("calling poll() on an already finished AvailableSqEntryFuture") + } } } } diff --git a/nvmed/src/nvme/identify.rs b/nvmed/src/nvme/identify.rs new file mode 100644 index 0000000000..5bae5d76c2 --- /dev/null +++ b/nvmed/src/nvme/identify.rs @@ -0,0 +1,93 @@ +use syscall::Dma; + +use super::{Nvme, NvmeCmd, NvmeNamespace}; + +#[derive(Clone, Copy)] +#[repr(packed)] +pub struct IdentifyControllerData { + /// PCI vendor ID, always the same as in the PCI function header. + pub vid: u16, + /// PCI subsystem vendor ID. + pub ssvid: u16, + /// ASCII + pub serial_no: [u8; 20], + /// ASCII + pub model_no: [u8; 48], + /// ASCII + pub firmware_rev: [u8; 8], + // TODO: Lots of fields + pub _4k_pad: [u8; 4096 - 72], +} +impl Nvme { + /// Returns the serial number, model, and firmware, in that order. + pub async fn identify_controller(&self) { + // TODO: Use same buffer + let data: Dma = Dma::zeroed().unwrap(); + + // println!(" - Attempting to identify controller"); + let cid = self + .submit_admin_command(|cid| NvmeCmd::identify_controller(cid, data.physical())) + .await; + + // println!(" - Waiting to identify controller"); + let comp = self.admin_queue_completion(cid).await; + + // println!(" - Dumping identify controller"); + + let model_cow = String::from_utf8_lossy(&data.model_no); + let serial_cow = String::from_utf8_lossy(&data.serial_no); + let fw_cow = String::from_utf8_lossy(&data.firmware_rev); + + let model = model_cow.trim(); + let serial = serial_cow.trim(); + let firmware = fw_cow.trim(); + + println!( + " - Model: {} Serial: {} Firmware: {}", + model, serial, firmware, + ); + } + pub async fn identify_namespace_list(&self, base: u32) -> Vec { + // TODO: Use buffer + let data: Dma<[u32; 1024]> = Dma::zeroed().unwrap(); + + // println!(" - Attempting to retrieve namespace ID list"); + let cmd_id = self + .submit_admin_command(|cid| { + NvmeCmd::identify_namespace_list(cid, data.physical(), base) + }) + .await; + + // println!(" - Waiting to retrieve namespace ID list"); + let comp = self.admin_queue_completion(cmd_id).await; + + // println!(" - Dumping namespace ID list"); + data.iter().copied().take_while(|&nsid| nsid != 0).collect() + } + pub async fn identify_namespace(&self, nsid: u32) -> NvmeNamespace { + //TODO: Use buffer + let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); + + // println!(" - Attempting to identify namespace {}", nsid); + let cmd_id = self + .submit_admin_command(|cid| NvmeCmd::identify_namespace(cid, data.physical(), nsid)) + .await; + + // println!(" - Waiting to identify namespace {}", nsid); + let comp = self.admin_queue_completion(cmd_id).await; + + // println!(" - Dumping identify namespace"); + + let size = *(data.as_ptr().offset(0) as *const u64); + let capacity = *(data.as_ptr().offset(8) as *const u64); + println!(" - ID: {} Size: {} Capacity: {}", nsid, size, capacity); + + //TODO: Read block size + + NvmeNamespace { + id: nsid, + blocks: size, + block_size: 512, // TODO + } + } +} diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index ba9feb33fe..d9e0c25bc2 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -1,22 +1,28 @@ -use std::convert::TryFrom; use std::collections::BTreeMap; +use std::convert::TryFrom; use std::fs::File; -use std::sync::{Mutex, RwLock}; -use std::sync::atomic::{AtomicUsize, AtomicU16, Ordering}; use std::ptr; +use std::sync::atomic::{AtomicU16, AtomicUsize, Ordering}; +use std::sync::{Mutex, RwLock}; use crossbeam_channel::Sender; use smallvec::{smallvec, SmallVec}; -use syscall::io::{Dma, Io, Mmio}; use syscall::error::{Error, Result, EINVAL}; +use syscall::io::{Dma, Io, Mmio}; +pub mod cmd; pub mod cq_reactor; +pub mod identify; +pub mod queues; + use self::cq_reactor::NotifReq; +pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue}; use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; use pcid_interface::PcidServerHandle; +/// Used in conjunction with `InterruptMethod`, primarily by the CQ reactor. #[derive(Debug)] pub enum InterruptSources { MsiX(BTreeMap), @@ -29,8 +35,8 @@ impl InterruptSources { use std::iter::Once; enum IterMut<'a> { - Msi(BTreeIterMut<'a, u16, File>), - MsiX(BTreeIterMut<'a, u8, File>), + Msi(BTreeIterMut<'a, u8, File>), + MsiX(BTreeIterMut<'a, u16, File>), Intx(Once<&'a mut File>), } impl<'a> Iterator for IterMut<'a> { @@ -38,9 +44,13 @@ impl InterruptSources { fn next(&mut self) -> Option { match self { - &mut Self::Msi(ref mut iter) => iter.next().map(|&mut (vector, ref mut handle)| (u16::from(vector), handle)), - &mut Self::MsiX(ref mut iter) => iter.next(), - &mut Self::Intx(ref mut iter) => (0, iter.next()), + &mut Self::Msi(ref mut iter) => iter + .next() + .map(|(&vector, handle)| (u16::from(vector), handle)), + &mut Self::MsiX(ref mut iter) => { + iter.next().map(|(&vector, handle)| (vector, handle)) + } + &mut Self::Intx(ref mut iter) => iter.next().map(|handle| (0u16, handle)), } } fn size_hint(&self) -> (usize, Option) { @@ -55,7 +65,7 @@ impl InterruptSources { match self { &mut Self::MsiX(ref mut map) => IterMut::MsiX(map.iter_mut()), &mut Self::Msi(ref mut map) => IterMut::Msi(map.iter_mut()), - &mut Self::Intx(ref mut single) => IterMut::Intx(false, single), + &mut Self::Intx(ref mut single) => IterMut::Intx(std::iter::once(single)), } } } @@ -74,17 +84,23 @@ impl InterruptMethod { fn is_intx(&self) -> bool { if let Self::Intx = self { true - } else { false } + } else { + false + } } fn is_msi(&self) -> bool { if let Self::Msi(_) = self { true - } else { false } + } else { + false + } } fn is_msix(&self) -> bool { if let Self::MsiX(_) = self { true - } else { false } + } else { + false + } } } @@ -94,211 +110,6 @@ pub struct MsixCfg { pub pba: &'static mut [Mmio], } -#[derive(Clone, Copy, Debug, Default)] -#[repr(packed)] -pub struct NvmeCmd { - /// Opcode - opcode: u8, - /// Flags - flags: u8, - /// Command ID - cid: u16, - /// Namespace identifier - nsid: u32, - /// Reserved - _rsvd: u64, - /// Metadata pointer - mptr: u64, - /// Data pointer - dptr: [u64; 2], - /// Command dword 10 - cdw10: u32, - /// Command dword 11 - cdw11: u32, - /// Command dword 12 - cdw12: u32, - /// Command dword 13 - cdw13: u32, - /// Command dword 14 - cdw14: u32, - /// Command dword 15 - cdw15: u32, -} - -impl NvmeCmd { - pub fn create_io_completion_queue(cid: u16, qid: u16, ptr: usize, size: u16, iv: Option) -> Self { - const DW11_PHYSICALLY_CONTIGUOUS_BIT: u32 = 0x0000_0001; - const DW11_ENABLE_INTERRUPTS_BIT: u32 = 0x0000_0002; - const DW11_INTERRUPT_VECTOR_SHIFT: u8 = 16; - - Self { - opcode: 5, - flags: 0, - cid, - nsid: 0, - _rsvd: 0, - mptr: 0, - dptr: [ptr as u64, 0], - cdw10: ((size as u32) << 16) | (qid as u32), - - cdw11: DW11_PHYSICALLY_CONTIGUOUS_BIT | if let Some(iv) = iv { - // enable interrupts if a vector is present - DW11_ENABLE_INTERRUPTS_BIT - | (u32::from(iv) << DW11_INTERRUPT_VECTOR_SHIFT) - } else { 0 }, - - cdw12: 0, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - - pub fn create_io_submission_queue(cid: u16, qid: u16, ptr: usize, size: u16, cqid: u16) -> Self { - Self { - opcode: 1, - flags: 0, - cid, - nsid: 0, - _rsvd: 0, - mptr: 0, - dptr: [ptr as u64, 0], - cdw10: ((size as u32) << 16) | (qid as u32), - cdw11: ((cqid as u32) << 16) | 1 /* Physically Contiguous */, //TODO: QPRIO - cdw12: 0, //TODO: NVMSETID - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - - pub fn identify_namespace(cid: u16, ptr: usize, nsid: u32) -> Self { - Self { - opcode: 6, - flags: 0, - cid, - nsid, - _rsvd: 0, - mptr: 0, - dptr: [ptr as u64, 0], - cdw10: 0, - cdw11: 0, - cdw12: 0, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - - pub fn identify_controller(cid: u16, ptr: usize) -> Self { - Self { - opcode: 6, - flags: 0, - cid, - nsid: 0, - _rsvd: 0, - mptr: 0, - dptr: [ptr as u64, 0], - cdw10: 1, - cdw11: 0, - cdw12: 0, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - - pub fn identify_namespace_list(cid: u16, ptr: usize, base: u32) -> Self { - Self { - opcode: 6, - flags: 0, - cid, - nsid: base, - _rsvd: 0, - mptr: 0, - dptr: [ptr as u64, 0], - cdw10: 2, - cdw11: 0, - cdw12: 0, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - pub fn get_features(cid: u16, ptr: usize, fid: u8) -> Self { - Self { - opcode: 0xA, - dptr: [ptr as u64, 0], - cdw10: u32::from(fid), // TODO: SEL - .. Default::default() - } - } - - pub fn io_read(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { - Self { - opcode: 2, - flags: 1 << 6, - cid, - nsid, - _rsvd: 0, - mptr: 0, - dptr: [ptr0, ptr1], - cdw10: lba as u32, - cdw11: (lba >> 32) as u32, - cdw12: blocks_1 as u32, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } - - pub fn io_write(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { - Self { - opcode: 1, - flags: 1 << 6, - cid, - nsid, - _rsvd: 0, - mptr: 0, - dptr: [ptr0, ptr1], - cdw10: lba as u32, - cdw11: (lba >> 32) as u32, - cdw12: blocks_1 as u32, - cdw13: 0, - cdw14: 0, - cdw15: 0, - } - } -} - -#[derive(Clone, Copy)] -#[repr(packed)] -pub struct IdentifyControllerData { - /// PCI vendor ID, always the same as in the PCI function header. - pub vid: u16, - /// PCI subsystem vendor ID. - pub ssvid: u16, - /// ASCII - pub serial_no: [u8; 20], - /// ASCII - pub model_no: [u8; 48], - /// ASCII - pub firmware_rev: [u8; 8], - // TODO: Lots of fields - pub _4k_pad: [u8; 4096 - 72], -} - -#[derive(Clone, Copy, Debug)] -#[repr(packed)] -pub struct NvmeComp { - command_specific: u32, - _rsvd: u32, - sq_head: u16, - sq_id: u16, - cid: u16, - status: u16, -} - #[repr(packed)] pub struct NvmeRegs { /// Controller Capabilities @@ -329,68 +140,6 @@ pub struct NvmeRegs { cmbsz: Mmio, } -pub struct NvmeCmdQueue { - data: Dma<[NvmeCmd; 64]>, - i: usize, -} - -impl NvmeCmdQueue { - fn new() -> Result { - Ok(Self { - data: Dma::zeroed()?, - i: 0, - }) - } - - fn submit(&mut self, entry: NvmeCmd) -> usize { - self.data[self.i] = entry; - self.i = (self.i + 1) % self.data.len(); - self.i - } -} - -pub struct NvmeCompQueue { - data: Dma<[NvmeComp; 256]>, - i: usize, - phase: bool, -} - -impl NvmeCompQueue { - fn new() -> Result { - Ok(Self { - data: Dma::zeroed()?, - i: 0, - phase: true, - }) - } - - pub (crate) fn complete(&mut self) -> Option<(usize, NvmeComp)> { - let entry = unsafe { - ptr::read_volatile(self.data.as_ptr().add(self.i)) - }; - // println!("{:?}", entry); - if ((entry.status & 1) == 1) == self.phase { - self.i = (self.i + 1) % self.data.len(); - if self.i == 0 { - self.phase = ! self.phase; - } - Some((self.i, entry)) - } else { - None - } - } - - fn complete_spin(&mut self) -> (usize, NvmeComp) { - loop { - if let Some(some) = self.complete() { - return some; - } else { - unsafe { std::arch::x86_64::_mm_pause() } - } - } - } -} - #[derive(Debug)] pub struct NvmeNamespace { pub id: u32, @@ -411,13 +160,14 @@ pub struct Nvme { regs: RwLock<&'static mut NvmeRegs>, pub(crate) submission_queues: RwLock>>, - pub(crate) completion_queues: RwLock)>>>, + pub(crate) completion_queues: + RwLock)>>>, // maps interrupt vectors with the completion queues they have cqs_for_ivs: RwLock>>, buffer: Mutex>, // 2MB of buffer - buffer_prp: Mutex>, // 4KB of PRP for the buffer + buffer_prp: Mutex>, // 4KB of PRP for the buffer reactor_sender: Sender, next_sqid: AtomicSqId, @@ -426,12 +176,36 @@ pub struct Nvme { unsafe impl Send for Nvme {} unsafe impl Sync for Nvme {} +/// How to handle full submission queues. +pub enum FullSqHandling { + /// Return an error immediately prior to posting the command. + ErrorDirectly, + + /// Tell the IRQ reactor that we wan't to be notified when a command on the same submission + /// queue has been completed. + Wait, +} + +pub enum Submission { + Nonblocking(Option), // TODO: Add full error + MaybeBlocking(), +} + impl Nvme { - pub fn new(address: usize, interrupt_method: InterruptMethod, pcid_interface: PcidServerHandle, reactor_sender: Sender) -> Result { + pub fn new( + address: usize, + interrupt_method: InterruptMethod, + pcid_interface: PcidServerHandle, + reactor_sender: Sender, + ) -> Result { Ok(Nvme { - regs: Mutex::new(unsafe { &mut *(address as *mut NvmeRegs) }), - submission_queues: RwLock::new(vec! [Mutex::new(NvmeCmdQueue::new()?), Mutex::new(NvmeCmdQueue::new()?)]), - completion_queues: RwLock::new(vec! [Mutex::new(NvmeCompQueue::new()?), Mutex::new(NvmeCompQueue::new()?)]), + regs: RwLock::new(unsafe { &mut *(address as *mut NvmeRegs) }), + submission_queues: RwLock::new( + std::iter::once((0u16, Mutex::new(NvmeCmdQueue::new()?))).collect(), + ), + completion_queues: RwLock::new( + std::iter::once((0u16, Mutex::new((NvmeCompQueue::new()?, smallvec!())))).collect(), + ), // map the zero interrupt vector (which according to the spec shall always point to the // admin completion queue) to CQID 0 (admin completion queue) cqs_for_ivs: RwLock::new(std::iter::once((0, smallvec!(0))).collect()), @@ -453,9 +227,7 @@ impl Nvme { let mut regs_guard = self.regs.write().unwrap(); let dstrd = ((regs_guard.cap.read() >> 32) & 0b1111) as usize; - let addr = ((*regs_guard) as *mut NvmeRegs as usize) - + 0x1000 - + index * (4 << dstrd); + let addr = ((*regs_guard) as *mut NvmeRegs as usize) + 0x1000 + index * (4 << dstrd); (&mut *(addr as *mut Mmio)).write(value); } @@ -494,18 +266,23 @@ impl Nvme { } } - // println!(" - Mask all interrupts"); - if !self.interrupt_method.get_mut().unwrap().is_msix() { - self.regs.get_mut().unwrap().intms.write(0xFFFFFFFF); - self.regs.get_mut().unwrap().intmc.write(0xFFFFFFFE); + match self.interrupt_method.get_mut().unwrap() { + &mut InterruptMethod::Intx | InterruptMethod::Msi(_) => { + self.regs.get_mut().unwrap().intms.write(0xFFFF_FFFF); + self.regs.get_mut().unwrap().intmc.write(0x0000_0001); + } + &mut InterruptMethod::MsiX(ref mut cfg) => { + cfg.table[0].unmask(); + } } - for (qid, queue) in self.completion_queues.get_mut().unwrap().iter().enumerate() { - let data = &queue.get_mut().unwrap().data; + for (qid, queue) in self.completion_queues.get_mut().unwrap().iter() { + let &(ref cq, ref sq_ids) = &*queue.get_mut().unwrap(); + let data = &cq.data; // println!(" - completion queue {}: {:X}, {}", qid, data.physical(), data.len()); } - for (qid, queue) in self.submission_queues.get_mut().unwrap().iter().enumerate() { + for (qid, queue) in self.submission_queues.get_mut().unwrap().iter() { let data = &queue.get_mut().unwrap().data; // println!(" - submission queue {}: {:X}, {}", qid, data.physical(), data.len()); } @@ -515,9 +292,10 @@ impl Nvme { let submission_queues = self.submission_queues.get_mut().unwrap(); let completion_queues = self.submission_queues.get_mut().unwrap(); - let asq = &submission_queues[0].get_mut().unwrap(); - let acq = &completion_queues[0].get_mut().unwrap(); - regs.aqa.write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1)); + let asq = submission_queues.get(&0).unwrap().get_mut().unwrap(); + let acq = completion_queues.get(&0).unwrap().get_mut().unwrap(); + regs.aqa + .write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1)); regs.asq.write(asq.data.physical() as u64); regs.acq.write(acq.data.physical() as u64); @@ -542,144 +320,186 @@ impl Nvme { } } } - pub fn submit_command NvmeCmd>(&self, sq_id: SqId, f: F) -> CmdId { - let sqs_read_guard = self.submission_queues.read().unwrap(); - let sq_lock = sqs_read_guard.get(&sq_id).expect("nvmed: internal error: given SQ for SQ ID not there").lock().unwrap(); - let cmd_id = u16::try_from(sq_lock.i).expect("nvmed: internal error: CQ has more than 2^16 entries"); - let tail = sq_lock.submit(f(cmd_id)); - self.submission_queue_tail(sq_id, tail); - cmd_id + + /// Masks or unmasks multiple vectors. + /// + /// # Panics + /// Will panic if the same vector is called twice with different mask flags. + pub fn set_vectors_masked(&self, vectors: impl IntoIterator) { + let interrupt_method_guard = self.interrupt_method.lock().unwrap(); + + match &mut *interrupt_method_guard { + &mut InterruptMethod::Intx => { + let mut iter = vectors.into_iter(); + let (vector, mask) = match iter.next() { + Some(f) => f, + None => return, + }; + assert_eq!( + iter.next(), + None, + "nvmed: internal error: multiple vectors on INTx#" + ); + assert_eq!(vector, 0, "nvmed: internal error: nonzero vector on INTx#"); + if mask { + self.regs.write().unwrap().intms.write(0x0000_0001); + } else { + self.regs.write().unwrap().intmc.write(0x0000_0001); + } + } + &mut InterruptMethod::Msi(ref mut cap) => { + let mut to_mask = 0x0000_0000; + let mut to_clear = 0x0000_0000; + + for (vector, mask) in vectors { + assert!( + vector < (1 << cap.multi_message_enable()), + "nvmed: internal error: MSI vector out of range" + ); + let vector = vector as u8; + + if mask { + assert_ne!( + to_clear & (1 << vector), + (1 << vector), + "nvmed: internal error: cannot both mask and set" + ); + to_mask |= 1 << vector; + } else { + assert_ne!( + to_mask & (1 << vector), + (1 << vector), + "nvmed: internal error: cannot both mask and set" + ); + to_clear |= 1 << vector; + } + } + + if to_mask != 0 { + self.regs.write().unwrap().intms.write(to_mask); + } + if to_clear != 0 { + self.regs.write().unwrap().intmc.write(to_clear); + } + } + &mut InterruptMethod::MsiX(ref mut cfg) => { + for (vector, mask) in vectors { + cfg.table + .get_mut(vector as usize) + .expect("nvmed: internal error: MSI-X vector out of range") + .set_masked(mask); + } + } + } } - pub fn submit_admin_command NvmeCmd>(&self, f: F) -> CmdId { - self.submit_admin_command(0, f) + pub fn set_vector_masked(&self, vector: u16, masked: bool) { + self.set_vectors_masked(std::iter::once((vector, masked))) + } + + /// Try submitting a new entry to the specified submission queue, or return None if the queue + /// was full. + pub fn try_submit_command NvmeCmd>( + &self, + sq_id: SqId, + full_sq_handling: FullSqHandling, + f: F, + ) -> Option { + let sqs_read_guard = self.submission_queues.read().unwrap(); + let sq_lock = sqs_read_guard + .get(&sq_id) + .expect("nvmed: internal error: given SQ for SQ ID not there") + .lock() + .unwrap(); + let cmd_id = + u16::try_from(sq_lock.i).expect("nvmed: internal error: CQ has more than 2^16 entries"); + let tail = sq_lock.submit(f(cmd_id))?; + let tail = u16::try_from(tail).unwrap(); + self.submission_queue_tail(sq_id, tail); + Some(cmd_id) + } + pub async fn submit_admin_command NvmeCmd>(&self, f: F) -> CmdId { + self.try_submit_command(0, FullSqHandling::Wait, f); + todo!() } pub async fn admin_queue_completion(&self, cmd_id: CmdId) -> NvmeComp { self.completion(0, cmd_id, 0).await } - /// Returns the serial number, model, and firmware, in that order. - pub async fn identify_controller(&self) { - // TODO: Use same buffer - let data: Dma = Dma::zeroed().unwrap(); - - // println!(" - Attempting to identify controller"); - let cid = self.submit_admin_command(|cid| NvmeCmd::identify_controller( - cid, data.physical() - )); - - // println!(" - Waiting to identify controller"); - let comp = self.admin_queue_completion(cid).await; - - // println!(" - Dumping identify controller"); - - let model_cow = String::from_utf8_lossy(&data.model_no); - let serial_cow = String::from_utf8_lossy(&data.serial_no); - let fw_cow = String::from_utf8_lossy(&data.firmware_rev); - - let model = model_cow.trim(); - let serial = serial_cow.trim(); - let firmware = fw_cow.trim(); - - println!( - " - Model: {} Serial: {} Firmware: {}", - model, - serial, - firmware, - ); - } - pub async fn identify_namespace_list(&self, base: u32) -> Vec { - // TODO: Use buffer - let data: Dma<[u32; 1024]> = Dma::zeroed().unwrap(); - - // println!(" - Attempting to retrieve namespace ID list"); - let cmd_id = self.submit_admin_command(|cid| NvmeCmd::identify_namespace_list( - cid, data.physical(), base - )); - - // println!(" - Waiting to retrieve namespace ID list"); - let comp = self.admin_queue_completion(cmd_id).await; - - // println!(" - Dumping namespace ID list"); - data.iter().copied().take_while(|&nsid| nsid != 0).collect() - } - pub async fn identify_namespace(&self, nsid: u32) -> NvmeNamespace { - //TODO: Use buffer - let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); - - // println!(" - Attempting to identify namespace {}", nsid); - let cmd_id = self.submit_admin_command(|cid| NvmeCmd::identify_namespace( - cid, data.physical(), nsid - )); - - // println!(" - Waiting to identify namespace {}", nsid); - let comp = self.admin_queue_completion(cmd_id).await; - - // println!(" - Dumping identify namespace"); - - let size = *(data.as_ptr().offset(0) as *const u64); - let capacity = *(data.as_ptr().offset(8) as *const u64); - println!( - " - ID: {} Size: {} Capacity: {}", - nsid, - size, - capacity - ); - - //TODO: Read block size - - NvmeNamespace { - id: nsid, - blocks: size, - block_size: 512, // TODO - } - } pub async fn create_io_completion_queue(&self, io_cq_id: CqId, vector: Option) { let (ptr, len) = { let mut completion_queues_guard = self.completion_queues.write().unwrap(); - let queue_guard = completion_queues_guard.entry(io_cq_id).or_insert_with(|| { - let queue = NvmeCompQueue::new().expect("nvmed: failed to allocate I/O completion queue"); - let sqs = SmallVec::new(); - Mutex::new((queue, sqs)) - }).get_mut().unwrap(); + let queue_guard = completion_queues_guard + .entry(io_cq_id) + .or_insert_with(|| { + let queue = NvmeCompQueue::new() + .expect("nvmed: failed to allocate I/O completion queue"); + let sqs = SmallVec::new(); + Mutex::new((queue, sqs)) + }) + .get_mut() + .unwrap(); let &(ref queue, _) = &*queue_guard; (queue.data.physical(), queue.data.len()) }; - let len = u16::try_from(len).expect("nvmed: internal error: I/O CQ longer than 2^16 entries"); - let raw_len = len.checked_sub(1).expect("nvmed: internal error: CQID 0 for I/O CQ"); + let len = + u16::try_from(len).expect("nvmed: internal error: I/O CQ longer than 2^16 entries"); + let raw_len = len + .checked_sub(1) + .expect("nvmed: internal error: CQID 0 for I/O CQ"); - let cmd_id = self.submit_admin_command(|cid| NvmeCmd::create_io_completion_queue( - cid, io_cq_id, ptr, raw_len, vector, - )); + let cmd_id = self + .submit_admin_command(|cid| { + NvmeCmd::create_io_completion_queue(cid, io_cq_id, ptr, raw_len, vector) + }) + .await; let comp = self.admin_queue_completion(cmd_id).await; if let Some(vector) = vector { - self.cqs_for_ivs.write().unwrap().entry(vector).or_insert_with(SmallVec::new).push(io_cq_id); + self.cqs_for_ivs + .write() + .unwrap() + .entry(vector) + .or_insert_with(SmallVec::new) + .push(io_cq_id); } } pub async fn create_io_submission_queue(&self, io_sq_id: SqId, io_cq_id: CqId) { let (ptr, len) = { let mut submission_queues_guard = self.submission_queues.write().unwrap(); - let queue_guard = submission_queues_guard.entry(io_sq_id).or_insert_with(|| { - Mutex::new(NvmeCmdQueue::new().expect("nvmed: failed to allocate I/O completion queue")) - }).get_mut().unwrap(); + let queue_guard = submission_queues_guard + .entry(io_sq_id) + .or_insert_with(|| { + Mutex::new( + NvmeCmdQueue::new() + .expect("nvmed: failed to allocate I/O completion queue"), + ) + }) + .get_mut() + .unwrap(); (queue_guard.data.physical(), queue_guard.data.len()) }; - let len = u16::try_from(len).expect("nvmed: internal error: I/O SQ longer than 2^16 entries"); - let raw_len = len.checked_sub(1).expect("nvmed: internal error: SQID 0 for I/O SQ"); + let len = + u16::try_from(len).expect("nvmed: internal error: I/O SQ longer than 2^16 entries"); + let raw_len = len + .checked_sub(1) + .expect("nvmed: internal error: SQID 0 for I/O SQ"); - let cmd_id = self.submit_admin_command(|cid| NvmeCmd::create_io_submission_queue( - cid, io_sq_id, ptr, raw_len, io_cq_id, - )); + let cmd_id = self + .submit_admin_command(|cid| { + NvmeCmd::create_io_submission_queue(cid, io_sq_id, ptr, raw_len, io_cq_id) + }) + .await; let comp = self.admin_queue_completion(cmd_id).await; } pub async fn init_with_queues(&self) -> BTreeMap { - let ((), nsids) = futures::join!(self.identify_controller(), self.identify_namespace_list(0)); + let ((), nsids) = + futures::join!(self.identify_controller(), self.identify_namespace_list(0)); let mut namespaces = BTreeMap::new(); @@ -694,7 +514,13 @@ impl Nvme { namespaces } - unsafe fn namespace_rw(&mut self, nsid: u32, lba: u64, blocks_1: u16, write: bool) -> Result<()> { + unsafe fn namespace_rw( + &mut self, + nsid: u32, + lba: u64, + blocks_1: u16, + write: bool, + ) -> Result<()> { //TODO: Get real block size let block_size = 512; @@ -712,13 +538,9 @@ impl Nvme { let queue = &mut self.submission_queues[qid]; let cid = queue.i as u16; let entry = if write { - NvmeCmd::io_write( - cid, nsid, lba, blocks_1, ptr0, ptr1 - ) + NvmeCmd::io_write(cid, nsid, lba, blocks_1, ptr0, ptr1) } else { - NvmeCmd::io_read( - cid, nsid, lba, blocks_1, ptr0, ptr1 - ) + NvmeCmd::io_read(cid, nsid, lba, blocks_1, ptr0, ptr1) }; let tail = queue.submit(entry); self.submission_queue_tail(qid as u16, tail as u16); @@ -735,7 +557,12 @@ impl Nvme { Ok(()) } - pub unsafe fn namespace_read(&mut self, nsid: u32, mut lba: u64, buf: &mut [u8]) -> Result> { + pub unsafe fn namespace_read( + &mut self, + nsid: u32, + mut lba: u64, + buf: &mut [u8], + ) -> Result> { //TODO: Use interrupts //TODO: Get real block size @@ -757,7 +584,12 @@ impl Nvme { Ok(Some(buf.len())) } - pub unsafe fn namespace_write(&mut self, nsid: u32, mut lba: u64, buf: &[u8]) -> Result> { + pub unsafe fn namespace_write( + &mut self, + nsid: u32, + mut lba: u64, + buf: &[u8], + ) -> Result> { //TODO: Use interrupts //TODO: Get real block size diff --git a/nvmed/src/nvme/queues.rs b/nvmed/src/nvme/queues.rs new file mode 100644 index 0000000000..bdef2e076c --- /dev/null +++ b/nvmed/src/nvme/queues.rs @@ -0,0 +1,117 @@ +use std::ptr; +use syscall::{Dma, Result}; + +/// A submission queue entry. +#[derive(Clone, Copy, Debug, Default)] +#[repr(packed)] +pub struct NvmeCmd { + /// Opcode + pub opcode: u8, + /// Flags + pub flags: u8, + /// Command ID + pub cid: u16, + /// Namespace identifier + pub nsid: u32, + /// Reserved + pub _rsvd: u64, + /// Metadata pointer + pub mptr: u64, + /// Data pointer + pub dptr: [u64; 2], + /// Command dword 10 + pub cdw10: u32, + /// Command dword 11 + pub cdw11: u32, + /// Command dword 12 + pub cdw12: u32, + /// Command dword 13 + pub cdw13: u32, + /// Command dword 14 + pub cdw14: u32, + /// Command dword 15 + pub cdw15: u32, +} + +/// A completion queue entry. +#[derive(Clone, Copy, Debug)] +#[repr(packed)] +pub struct NvmeComp { + pub command_specific: u32, + pub _rsvd: u32, + pub sq_head: u16, + pub sq_id: u16, + pub cid: u16, + pub status: u16, +} + +/// Completion queue +pub struct NvmeCompQueue { + pub data: Dma<[NvmeComp; 256]>, + pub i: usize, + pub phase: bool, +} + +impl NvmeCompQueue { + pub fn new() -> Result { + Ok(Self { + data: Dma::zeroed()?, + i: 0, + phase: true, + }) + } + + /// Get a new completion queue entry, or return None if no entry is available yet. + pub(crate) fn complete(&mut self) -> Option<(usize, NvmeComp)> { + let entry = unsafe { ptr::read_volatile(self.data.as_ptr().add(self.i)) }; + // println!("{:?}", entry); + if ((entry.status & 1) == 1) == self.phase { + self.i = (self.i + 1) % self.data.len(); + if self.i == 0 { + self.phase = !self.phase; + } + Some((self.i, entry)) + } else { + None + } + } + + /// Get a new CQ entry, busy waiting until an entry appears. + fn complete_spin(&mut self) -> (usize, NvmeComp) { + loop { + if let Some(some) = self.complete() { + return some; + } else { + unsafe { std::arch::x86_64::_mm_pause() } + } + } + } +} + +/// Submission queue +pub struct NvmeCmdQueue { + pub data: Dma<[NvmeCmd; 64]>, + pub i: usize, +} + +impl NvmeCmdQueue { + pub(crate) fn new() -> Result { + Ok(Self { + data: Dma::zeroed()?, + i: 0, + }) + } + + /// Add a new submission command entry to the queue. Returns Some(tail) when a vacant entry was + /// found, or None if the queue was full. + pub(crate) fn submit(&mut self, entry: NvmeCmd) -> Option { + // FIXME: Check for full conditions + if true { + self.data[self.i] = entry; + self.i = (self.i + 1) % self.data.len(); + Some(self.i) + } else { + None + } + } +} diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index 40f6f1b68c..1badbcd282 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -1,15 +1,15 @@ use std::collections::BTreeMap; -use std::{cmp, str}; use std::convert::{TryFrom, TryInto}; use std::fmt::Write; -use std::io::prelude::*; use std::io; +use std::io::prelude::*; use std::sync::Arc; +use std::{cmp, str}; use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, EOVERFLOW, Result, - Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; + Error, Io, Result, SchemeBlockMut, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, EOVERFLOW, + MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET, +}; use crate::nvme::{Nvme, NvmeNamespace}; @@ -17,8 +17,8 @@ use partitionlib::{LogicalBlockSize, PartitionTable}; #[derive(Clone)] enum Handle { - List(Vec, usize), // entries, offset - Disk(u32, usize), // disk num, offset + List(Vec, usize), // entries, offset + Disk(u32, usize), // disk num, offset Partition(u32, u32, usize), // disk num, part num, offset } @@ -40,17 +40,29 @@ impl DiskWrapper { 4096 => LogicalBlockSize::Lb4096, _ => return None, }; - struct Device<'a, 'b> { disk: &'a mut NvmeNamespace, nvme: &'a Nvme, offset: u64, block_bytes: &'b mut [u8] } + struct Device<'a, 'b> { + disk: &'a mut NvmeNamespace, + nvme: &'a Nvme, + offset: u64, + block_bytes: &'b mut [u8], + } impl<'a, 'b> Seek for Device<'a, 'b> { fn seek(&mut self, from: io::SeekFrom) -> io::Result { let size_u = self.disk.blocks * self.disk.block_size; - let size = i64::try_from(size_u).or(Err(io::Error::new(io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes")))?; + let size = i64::try_from(size_u).or(Err(io::Error::new( + io::ErrorKind::Other, + "Disk larger than 2^63 - 1 bytes", + )))?; self.offset = match from { io::SeekFrom::Start(new_pos) => cmp::min(size_u, new_pos), - io::SeekFrom::Current(new_pos) => cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64, - io::SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64, + io::SeekFrom::Current(new_pos) => { + cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64 + } + io::SeekFrom::End(new_pos) => { + cmp::max(0, cmp::min(size + new_pos, size)) as u64 + } }; Ok(self.offset) @@ -71,19 +83,30 @@ impl DiskWrapper { } loop { match unsafe { - nvme.namespace_read(disk.id, block, block_bytes).map_err(|err| io::Error::from_raw_os_error(err.errno))? + nvme.namespace_read(disk.id, block, block_bytes) + .map_err(|err| io::Error::from_raw_os_error(err.errno))? } { Some(bytes) => { assert_eq!(bytes, block_bytes.len()); assert_eq!(bytes, blksize as usize); return Ok(()); } - None => { std::thread::yield_now(); continue } - // TODO: Does this driver have (internal) error handling at all? + None => { + std::thread::yield_now(); + continue; + } // TODO: Does this driver have (internal) error handling at all? } } }; - let bytes_read = block_io_wrapper::read(self.offset, blksize.try_into().expect("Unreasonable block size above 2^32 bytes"), buf, self.block_bytes, read_block)?; + let bytes_read = block_io_wrapper::read( + self.offset, + blksize + .try_into() + .expect("Unreasonable block size above 2^32 bytes"), + buf, + self.block_bytes, + read_block, + )?; self.offset += bytes_read as u64; Ok(bytes_read) } @@ -91,7 +114,17 @@ impl DiskWrapper { let mut block_bytes = [0u8; 4096]; - partitionlib::get_partitions(&mut Device { disk, nvme, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() + partitionlib::get_partitions( + &mut Device { + disk, + nvme, + offset: 0, + block_bytes: &mut block_bytes[..bs.into()], + }, + bs, + ) + .ok() + .flatten() } fn new(mut inner: NvmeNamespace, nvme: &Nvme) -> Self { Self { @@ -106,17 +139,24 @@ pub struct DiskScheme { nvme: Arc, disks: BTreeMap, handles: BTreeMap, - next_id: usize + next_id: usize, } impl DiskScheme { - pub fn new(scheme_name: String, nvme: Arc, disks: BTreeMap) -> DiskScheme { + pub fn new( + scheme_name: String, + nvme: Arc, + disks: BTreeMap, + ) -> DiskScheme { DiskScheme { scheme_name, - disks: disks.into_iter().map(|(k, v)| (k, DiskWrapper::new(v, &nvme))).collect(), + disks: disks + .into_iter() + .map(|(k, v)| (k, DiskWrapper::new(v, &nvme))) + .collect(), nvme, handles: BTreeMap::new(), - next_id: 0 + next_id: 0, } } } @@ -134,7 +174,9 @@ impl DiskScheme { found_completion = true; println!("nvmed: Unhandled completion {:?}", entry); //TODO: Handle errors - unsafe { nvme.completion_queue_head(qid as u16, head as u16); } + unsafe { + nvme.completion_queue_head(qid as u16, head as u16); + } } } @@ -145,7 +187,9 @@ impl DiskScheme { impl SchemeBlockMut for DiskScheme { fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { if uid == 0 { - let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_matches('/'); + let path_str = str::from_utf8(path) + .or(Err(Error::new(ENOENT)))? + .trim_matches('/'); if path_str.is_empty() { if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { let mut list = String::new(); @@ -180,10 +224,18 @@ impl SchemeBlockMut for DiskScheme { let part_num = part_num_str.parse::().or(Err(Error::new(ENOENT)))?; if let Some(disk) = self.disks.get(&nsid) { - if disk.pt.as_ref().ok_or(Error::new(ENOENT))?.partitions.get(part_num as usize).is_some() { + if disk + .pt + .as_ref() + .ok_or(Error::new(ENOENT))? + .partitions + .get(part_num as usize) + .is_some() + { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::Partition(nsid, part_num, 0)); + self.handles + .insert(id, Handle::Partition(nsid, part_num, 0)); Ok(Some(id)) } else { Err(Error::new(ENOENT)) @@ -209,7 +261,7 @@ impl SchemeBlockMut for DiskScheme { } fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if ! buf.is_empty() { + if !buf.is_empty() { return Err(Error::new(EINVAL)); } @@ -230,22 +282,36 @@ impl SchemeBlockMut for DiskScheme { stat.st_mode = MODE_DIR; stat.st_size = data.len() as u64; Ok(Some(0)) - }, + } Handle::Disk(number, _) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_blocks = disk.as_ref().blocks; - stat.st_blksize = disk.as_ref().block_size.try_into().expect("Unreasonable block size of over 2^32 bytes"); + stat.st_blksize = disk + .as_ref() + .block_size + .try_into() + .expect("Unreasonable block size of over 2^32 bytes"); stat.st_size = disk.as_ref().blocks * disk.as_ref().block_size; Ok(Some(0)) } Handle::Partition(disk_num, part_num, _) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let part = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = part.size * disk.as_ref().block_size; stat.st_blocks = part.size; - stat.st_blksize = disk.as_ref().block_size.try_into().expect("Unreasonable block size of over 2^32 bytes"); + stat.st_blksize = disk + .as_ref() + .block_size + .try_into() + .expect("Unreasonable block size of over 2^32 bytes"); Ok(Some(0)) } } @@ -307,7 +373,8 @@ impl SchemeBlockMut for DiskScheme { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; if let Some(count) = unsafe { - self.nvme.namespace_read(disk.as_ref().id, (*size as u64)/block_size, buf)? + self.nvme + .namespace_read(disk.as_ref().id, (*size as u64) / block_size, buf)? } { *size += count; Ok(Some(count)) @@ -317,7 +384,13 @@ impl SchemeBlockMut for DiskScheme { } Handle::Partition(disk_num, part_num, ref mut offset) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let part = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; let rel_block = (*offset as u64) / block_size; @@ -327,9 +400,9 @@ impl SchemeBlockMut for DiskScheme { let abs_block = part.start_lba + rel_block; - if let Some(count) = unsafe { - self.nvme.namespace_read(disk.as_ref().id, abs_block, buf)? - } { + if let Some(count) = + unsafe { self.nvme.namespace_read(disk.as_ref().id, abs_block, buf)? } + { *offset += count; Ok(Some(count)) } else { @@ -341,14 +414,13 @@ impl SchemeBlockMut for DiskScheme { fn write(&mut self, id: usize, buf: &[u8]) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_, _) => { - Err(Error::new(EBADF)) - }, + Handle::List(_, _) => Err(Error::new(EBADF)), Handle::Disk(number, ref mut size) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; if let Some(count) = unsafe { - self.nvme.namespace_write(disk.as_ref().id, (*size as u64)/block_size, buf)? + self.nvme + .namespace_write(disk.as_ref().id, (*size as u64) / block_size, buf)? } { *size += count; Ok(Some(count)) @@ -358,7 +430,13 @@ impl SchemeBlockMut for DiskScheme { } Handle::Partition(disk_num, part_num, ref mut offset) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let part = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; let rel_block = (*offset as u64) / block_size; @@ -369,7 +447,8 @@ impl SchemeBlockMut for DiskScheme { let abs_block = part.start_lba + rel_block; if let Some(count) = unsafe { - self.nvme.namespace_write(disk.as_ref().id, abs_block, buf)? + self.nvme + .namespace_write(disk.as_ref().id, abs_block, buf)? } { *offset += count; Ok(Some(count)) @@ -386,9 +465,13 @@ impl SchemeBlockMut for DiskScheme { let len = handle.len() as usize; *size = match whence { SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) + SEEK_CUR => { + cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize + } + SEEK_END => { + cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize + } + _ => return Err(Error::new(EINVAL)), }; Ok(Some(*size)) @@ -398,24 +481,38 @@ impl SchemeBlockMut for DiskScheme { let len = (disk.as_ref().blocks * disk.as_ref().block_size) as usize; *size = match whence { SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) + SEEK_CUR => { + cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize + } + SEEK_END => { + cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize + } + _ => return Err(Error::new(EINVAL)), }; Ok(Some(*size)) } Handle::Partition(disk_num, part_num, ref mut size) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let part = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; let len = (part.size * disk.as_ref().block_size) as usize; *size = match whence { SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) + SEEK_CUR => { + cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize + } + SEEK_END => { + cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize + } + _ => return Err(Error::new(EINVAL)), }; Ok(Some(*size)) @@ -424,6 +521,9 @@ impl SchemeBlockMut for DiskScheme { } fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + self.handles + .remove(&id) + .ok_or(Error::new(EBADF)) + .and(Ok(Some(0))) } } diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index eb73ab4aa1..145f611533 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -432,11 +432,14 @@ impl MsixTableEntry { } pub const VEC_CTL_MASK_BIT: u32 = 1; + pub fn set_masked(&mut self, masked: bool) { + self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, masked) + } pub fn mask(&mut self) { - self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, true) + self.set_masked(true); } pub fn unmask(&mut self) { - self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, false) + self.set_masked(false); } } From 64e9eea9b02607e6f393ac673f1dc51b4485395a Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 1 May 2020 13:14:31 +0200 Subject: [PATCH 0408/1301] Implement asynchronous command __submission__. Note that by writing submission, I'm referring to blocking until a submission queue has more entries available. The command completion handling is already async. --- nvmed/src/nvme/cq_reactor.rs | 182 ++++++++++++++++++++++------------- nvmed/src/nvme/mod.rs | 53 +++++++--- nvmed/src/nvme/queues.rs | 56 ++++++----- 3 files changed, 184 insertions(+), 107 deletions(-) diff --git a/nvmed/src/nvme/cq_reactor.rs b/nvmed/src/nvme/cq_reactor.rs index 80cc48e256..c2e80fa5a5 100644 --- a/nvmed/src/nvme/cq_reactor.rs +++ b/nvmed/src/nvme/cq_reactor.rs @@ -19,7 +19,7 @@ use syscall::Result; use crossbeam_channel::{Receiver, Sender}; -use crate::nvme::{CmdId, CqId, InterruptSources, Nvme, NvmeComp, NvmeCompQueue, SqId}; +use super::{CmdId, CqId, InterruptSources, Nvme, NvmeComp, NvmeCmd, SqId}; /// A notification request, sent by the future in order to tell the completion thread that the /// current task wants a notification when a matching completion queue entry has been seen. @@ -35,14 +35,24 @@ pub enum NotifReq { // TODO: Maybe the `remem` crate. message: Arc>>, }, + RequestAvailSubmission { + sq_id: SqId, + waker: task::Waker, + } } -struct PendingReq { - waker: task::Waker, - message: Arc>>, - cq_id: u16, - sq_id: u16, - cmd_id: u16, +enum PendingReq { + PendingCompletion { + waker: task::Waker, + message: Arc>>, + cq_id: CqId, + sq_id: SqId, + cmd_id: CmdId, + }, + PendingAvailSubmission { + waker: task::Waker, + sq_id: SqId, + }, } struct CqReactor { int_sources: InterruptSources, @@ -94,13 +104,14 @@ impl CqReactor { cmd_id, waker, message, - } => self.pending_reqs.push(PendingReq { + } => self.pending_reqs.push(PendingReq::PendingCompletion { sq_id, cq_id, cmd_id, message, waker, }), + NotifReq::RequestAvailSubmission { sq_id, waker } => self.pending_reqs.push(PendingReq::PendingAvailSubmission { sq_id, waker, }), } } } @@ -119,7 +130,9 @@ impl CqReactor { None => continue, }; - self.nvme.completion_queue_head(cq_id, head as u16); + self.nvme.completion_queue_head(cq_id, head); + + self.nvme.submission_queues.read().unwrap().get(&entry.sq_id).expect("nvmed: internal error: queue returned from controller doesn't exist").lock().unwrap().head = entry.sq_head; self.try_notify_futures(cq_id, &entry); @@ -129,27 +142,54 @@ impl CqReactor { Some(()) } + fn finish_pending_completion(&mut self, req_cq_id: CqId, cq_id: CqId, sq_id: SqId, cmd_id: CmdId, entry: &NvmeComp, i: usize) -> bool { + if req_cq_id == cq_id + && sq_id == entry.sq_id + && cmd_id == entry.cid + { + let (waker, message) = match self.pending_reqs.remove(i) { + PendingReq::PendingCompletion { waker, message, .. } => (waker, message), + _ => unreachable!(), + }; + + *message.lock().unwrap() = Some(CompletionMessage { cq_entry: *entry }); + waker.wake(); + + true + } else { + false + } + } + fn finish_pending_avail_submission(&mut self, sq_id: SqId, entry: &NvmeComp, i: usize) -> bool { + if sq_id == entry.sq_id { + let waker = match self.pending_reqs.remove(i) { + PendingReq::PendingAvailSubmission { waker, .. } => waker, + _ => unreachable!(), + }; + waker.wake(); + + true + } else { + false + } + } fn try_notify_futures(&mut self, cq_id: CqId, entry: &NvmeComp) -> Option<()> { let mut i = 0usize; let mut futures_notified = 0; while i < self.pending_reqs.len() { - let pending_req = &self.pending_reqs[i]; - - if pending_req.cq_id == cq_id - && pending_req.sq_id == entry.sq_id - && pending_req.cmd_id == entry.cid - { - let pending_req_owned = self.pending_reqs.remove(i); - - *pending_req_owned.message.lock().unwrap() = - Some(CompletionMessage { cq_entry: *entry }); - pending_req_owned.waker.wake(); - - futures_notified += 1; - } else { - i += 1; + match &self.pending_reqs[i] { + &PendingReq::PendingCompletion { cq_id: req_cq_id, sq_id, cmd_id, .. } => if self.finish_pending_completion(req_cq_id, cq_id, sq_id, cmd_id, entry, i) { + futures_notified += 1; + } else { + i += 1; + } + &PendingReq::PendingAvailSubmission { sq_id, .. } => if self.finish_pending_avail_submission(sq_id, entry, i) { + futures_notified += 1; + } else { + i += 1; + } } } if futures_notified == 0 {} @@ -284,48 +324,60 @@ impl Nvme { /// Returns a future representing a submission queue becoming non-full. Make sure that the /// queue doesn't have any additional free entries first though, so that the reactor doesn't /// have to interfere. - pub fn wait_for_available_submission(&self, sq_id: SqId) -> AvailableSqEntryFuture { - todo!() - } -} - -struct AvailMessage { - cmd_id: CmdId, -} - -enum AvailableSqEntryFutureState { - Pending { - sq_id: SqId, - message: Option>>>, - }, - Finished, -} - -pub struct AvailableSqEntryFuture { - state: AvailableSqEntryFutureState, -} - -impl Unpin for AvailableSqEntryFuture {} - -impl Future for AvailableSqEntryFuture { - type Output = CmdId; - - fn poll(self: Pin<&mut Self>, context: &mut task::Context<'_>) -> task::Poll { - let this = &mut self.get_mut().state; - - match this { - &mut AvailableSqEntryFutureState::Pending { + pub fn wait_for_available_submission<'a, F: FnOnce(CmdId) -> NvmeCmd>(&'a self, sq_id: SqId, f: F) -> SubmissionFuture<'a, F> { + SubmissionFuture { + state: SubmissionFutureState::Pending { sq_id, - ref mut message, - } => { - if let Some(message) = message.lock().unwrap().take() { - } else { - task::Poll::Pending - } - } - &mut AvailableSqEntryFutureState::Finished => { - panic!("calling poll() on an already finished AvailableSqEntryFuture") - } + cmd_init: f, + nvme: &self, + }, + } + } +} + +pub(crate) enum SubmissionFutureState<'a, F> { + // the queue was known to be full when checked, thus the reactor is asked + Pending { + sq_id: SqId, + cmd_init: F, + nvme: &'a Nvme, + }, + // returned when there was an available submission entry from the beginning + Ready(CmdId), + Finished, +} + +/// A future representing a submission queue eventually becoming non-full. In most cases this +/// future will finish directly, since all entries in the queue have to be occupied for it to block. +pub struct SubmissionFuture<'a, F> { + pub(crate) state: SubmissionFutureState<'a, F>, +} + +impl Unpin for SubmissionFuture<'_, F> {} + +impl NvmeCmd> Future for SubmissionFuture<'_, F> { + type Output = CmdId; + + fn poll(self: Pin<&mut Self>, context: &mut task::Context<'_>) -> task::Poll { + let state = &mut self.get_mut().state; + + match state { + &mut SubmissionFutureState::Pending { sq_id, cmd_init, nvme } => match nvme.try_submit_command(sq_id, cmd_init) { + Ok(cmd_id) => { + *state = SubmissionFutureState::Finished; + task::Poll::Ready(cmd_id) + } + Err(closure) => { + nvme.reactor_sender.send(NotifReq::RequestAvailSubmission { sq_id, waker: context.waker().clone() }); + *state = SubmissionFutureState::Pending { sq_id, cmd_init: closure, nvme }; + task::Poll::Pending + } + } + &mut SubmissionFutureState::Ready(value) => { + *state = SubmissionFutureState::Finished; + task::Poll::Ready(value) + } + &mut SubmissionFutureState::Finished => panic!("calling poll() on an already finished SubmissionFuture"), } } } diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index d9e0c25bc2..362bedf789 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -186,9 +186,9 @@ pub enum FullSqHandling { Wait, } -pub enum Submission { - Nonblocking(Option), // TODO: Add full error - MaybeBlocking(), +pub enum SubmissionBehavior<'a, F: FnOnce(CmdId) -> NvmeCmd> { + Nonblocking(Result), // TODO: Add full error + Future(self::cq_reactor::SubmissionFuture<'a, F>), } impl Nvme { @@ -396,30 +396,51 @@ impl Nvme { self.set_vectors_masked(std::iter::once((vector, masked))) } - /// Try submitting a new entry to the specified submission queue, or return None if the queue - /// was full. - pub fn try_submit_command NvmeCmd>( - &self, - sq_id: SqId, - full_sq_handling: FullSqHandling, - f: F, - ) -> Option { + pub fn submit_command_generic<'a, F: FnOnce(CmdId) -> NvmeCmd>(&'a self, sq_id: SqId, full_sq_handling: FullSqHandling, cmd_init: F) -> SubmissionBehavior<'a, F> { let sqs_read_guard = self.submission_queues.read().unwrap(); let sq_lock = sqs_read_guard .get(&sq_id) .expect("nvmed: internal error: given SQ for SQ ID not there") .lock() .unwrap(); + if sq_lock.is_full() { + match full_sq_handling { + FullSqHandling::ErrorDirectly => return SubmissionBehavior::Nonblocking(Err(cmd_init)), + FullSqHandling::Wait => return SubmissionBehavior::Future(self.wait_for_available_submission(sq_id, cmd_init)), + } + } let cmd_id = - u16::try_from(sq_lock.i).expect("nvmed: internal error: CQ has more than 2^16 entries"); - let tail = sq_lock.submit(f(cmd_id))?; + u16::try_from(sq_lock.tail).expect("nvmed: internal error: CQ has more than 2^16 entries"); + let tail = sq_lock.submit_unchecked(cmd_init(cmd_id)); let tail = u16::try_from(tail).unwrap(); self.submission_queue_tail(sq_id, tail); - Some(cmd_id) + + match full_sq_handling { + FullSqHandling::ErrorDirectly => SubmissionBehavior::Nonblocking(Ok(cmd_id)), + FullSqHandling::Wait => SubmissionBehavior::Future(self::cq_reactor::SubmissionFuture { state: self::cq_reactor::SubmissionFutureState::Ready(cmd_id) }) + } + } + + /// Try submitting a new entry to the specified submission queue, or return None if the queue + /// was full. + pub fn try_submit_command NvmeCmd>( + &self, + sq_id: SqId, + f: F, + ) -> Result { + match self.submit_command_generic(sq_id, FullSqHandling::ErrorDirectly, f) { + SubmissionBehavior::Nonblocking(opt) => opt, + _ => unreachable!(), + } + } + pub async fn submit_command_async NvmeCmd>(&self, sq_id: SqId, f: F) -> CmdId { + match self.submit_command_generic(sq_id, FullSqHandling::Wait, f) { + SubmissionBehavior::Future(future) => future.await, + _ => unreachable!(), + } } pub async fn submit_admin_command NvmeCmd>(&self, f: F) -> CmdId { - self.try_submit_command(0, FullSqHandling::Wait, f); - todo!() + self.submit_command_async(0, f).await } pub async fn admin_queue_completion(&self, cmd_id: CmdId) -> NvmeComp { self.completion(0, cmd_id, 0).await diff --git a/nvmed/src/nvme/queues.rs b/nvmed/src/nvme/queues.rs index bdef2e076c..aca1b49efc 100644 --- a/nvmed/src/nvme/queues.rs +++ b/nvmed/src/nvme/queues.rs @@ -47,37 +47,37 @@ pub struct NvmeComp { /// Completion queue pub struct NvmeCompQueue { - pub data: Dma<[NvmeComp; 256]>, - pub i: usize, + pub data: Dma<[NvmeComp]>, + pub head: u16, pub phase: bool, } impl NvmeCompQueue { pub fn new() -> Result { Ok(Self { - data: Dma::zeroed()?, - i: 0, + data: Dma::zeroed_unsized(256)?, + head: 0, phase: true, }) } /// Get a new completion queue entry, or return None if no entry is available yet. - pub(crate) fn complete(&mut self) -> Option<(usize, NvmeComp)> { - let entry = unsafe { ptr::read_volatile(self.data.as_ptr().add(self.i)) }; + pub(crate) fn complete(&mut self) -> Option<(u16, NvmeComp)> { + let entry = unsafe { ptr::read_volatile(self.data.as_ptr().add(self.head as usize)) }; // println!("{:?}", entry); if ((entry.status & 1) == 1) == self.phase { - self.i = (self.i + 1) % self.data.len(); - if self.i == 0 { + self.head = (self.head + 1) % (self.data.len() as u16); + if self.head == 0 { self.phase = !self.phase; } - Some((self.i, entry)) + Some((self.head, entry)) } else { None } } /// Get a new CQ entry, busy waiting until an entry appears. - fn complete_spin(&mut self) -> (usize, NvmeComp) { + fn complete_spin(&mut self) -> (u16, NvmeComp) { loop { if let Some(some) = self.complete() { return some; @@ -90,28 +90,32 @@ impl NvmeCompQueue { /// Submission queue pub struct NvmeCmdQueue { - pub data: Dma<[NvmeCmd; 64]>, - pub i: usize, + pub data: Dma<[NvmeCmd]>, + pub tail: u16, + pub head: u16, } impl NvmeCmdQueue { - pub(crate) fn new() -> Result { + pub fn new() -> Result { Ok(Self { - data: Dma::zeroed()?, - i: 0, + data: Dma::zeroed_unsized(64)?, + tail: 0, + head: 0, }) } - /// Add a new submission command entry to the queue. Returns Some(tail) when a vacant entry was - /// found, or None if the queue was full. - pub(crate) fn submit(&mut self, entry: NvmeCmd) -> Option { - // FIXME: Check for full conditions - if true { - self.data[self.i] = entry; - self.i = (self.i + 1) % self.data.len(); - Some(self.i) - } else { - None - } + pub fn is_empty(&self) -> bool { + self.head == self.tail + } + pub fn is_full(&self) -> bool { + self.head + 1 == self.tail + } + + /// Add a new submission command entry to the queue. The caller must ensure that the queue have free + /// entries; this can be checked using `is_full`. + pub fn submit_unchecked(&mut self, entry: NvmeCmd) -> u16 { + self.data[self.tail as usize] = entry; + self.tail = (self.tail + 1) % (self.data.len() as u16); + self.tail } } From 1936f05030d299146e0b2de1fbf106a1633f8de4 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 1 May 2020 14:14:47 +0200 Subject: [PATCH 0409/1301] NVME WORKS WITH IRQs --- nvmed/src/main.rs | 14 +++--- nvmed/src/nvme/cq_reactor.rs | 76 +++++++++++++++------------- nvmed/src/nvme/identify.rs | 5 +- nvmed/src/nvme/mod.rs | 96 ++++++++++++++++++------------------ nvmed/src/nvme/queues.rs | 4 +- nvmed/src/scheme.rs | 47 +++--------------- 6 files changed, 107 insertions(+), 135 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 539c70b69d..483c9aafe5 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -32,7 +32,7 @@ impl Bar { pub fn allocate(bar: usize, bar_size: usize) -> Result { Ok(Self { ptr: NonNull::new( - syscall::physmap(bar, bar_size, PHYSMAP_NO_CACHE | PHYSMAP_WRITE)? as *mut u8, + unsafe { syscall::physmap(bar, bar_size, PHYSMAP_NO_CACHE | PHYSMAP_WRITE)? as *mut u8 }, ) .expect("Mapping a BAR resulted in a nullptr"), physical: bar, @@ -43,7 +43,7 @@ impl Bar { impl Drop for Bar { fn drop(&mut self) { - let _ = syscall::physunmap(self.physical); + let _ = unsafe { syscall::physunmap(self.physical) }; } } @@ -82,7 +82,7 @@ fn get_int_method( bir: u8, ) -> Result> { let bir = usize::from(bir); - let bar_guard = allocated_bars.0[bir].lock().unwrap(); + let mut bar_guard = allocated_bars.0[bir].lock().unwrap(); match &mut *bar_guard { &mut Some(ref bar) => Ok(bar.ptr), bar_to_set @ &mut None => { @@ -119,7 +119,7 @@ fn get_int_method( // Mask all interrupts in case some earlier driver/os already unmasked them (according to // the PCI Local Bus spec 3.0, they are masked after system reset). - for table_entry in table_entries { + for table_entry in table_entries.iter_mut() { table_entry.mask(); } @@ -284,10 +284,10 @@ fn main() { .expect("nvmed: failed to find a suitable interrupt method"); let mut nvme = Nvme::new(address, interrupt_method, pcid_handle, reactor_sender) .expect("nvmed: failed to allocate driver data"); - let nvme = Arc::new(nvme); unsafe { nvme.init() } - nvme::cq_reactor::start_cq_reactor_thread(nvme, interrupt_sources, reactor_receiver); - let namespaces = unsafe { futures::executor::block_on(nvme.init_with_queues()) }; + let nvme = Arc::new(nvme); + nvme::cq_reactor::start_cq_reactor_thread(Arc::clone(&nvme), interrupt_sources, reactor_receiver); + let namespaces = futures::executor::block_on(nvme.init_with_queues()); let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); let mut todo = Vec::new(); diff --git a/nvmed/src/nvme/cq_reactor.rs b/nvmed/src/nvme/cq_reactor.rs index c2e80fa5a5..e4dbfefe87 100644 --- a/nvmed/src/nvme/cq_reactor.rs +++ b/nvmed/src/nvme/cq_reactor.rs @@ -62,7 +62,7 @@ struct CqReactor { event_queue: File, } impl CqReactor { - fn create_event_queue(int_sources: &InterruptSources) -> Result { + fn create_event_queue(int_sources: &mut InterruptSources) -> Result { use syscall::flag::*; let fd = syscall::open("event:", O_CLOEXEC | O_RDWR)?; let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; @@ -84,11 +84,11 @@ impl CqReactor { } fn new( nvme: Arc, - int_sources: InterruptSources, + mut int_sources: InterruptSources, receiver: Receiver, ) -> Result { Ok(Self { - event_queue: Self::create_event_queue(&int_sources)?, + event_queue: Self::create_event_queue(&mut int_sources)?, int_sources, nvme, pending_reqs: Vec::new(), @@ -121,8 +121,10 @@ impl CqReactor { let mut entry_count = 0; - for cq_id in ivs_read_guard.get(&iv)?.iter().copied() { - let completion_queue_guard = cqs_read_guard.get(&cq_id)?.lock().unwrap(); + let cq_ids = ivs_read_guard.get(&iv)?; + + for cq_id in cq_ids.iter().copied() { + let mut completion_queue_guard = cqs_read_guard.get(&cq_id)?.lock().unwrap(); let &mut (ref mut completion_queue, _) = &mut *completion_queue_guard; let (head, entry) = match completion_queue.complete() { @@ -130,11 +132,11 @@ impl CqReactor { None => continue, }; - self.nvme.completion_queue_head(cq_id, head); + unsafe { self.nvme.completion_queue_head(cq_id, head) }; - self.nvme.submission_queues.read().unwrap().get(&entry.sq_id).expect("nvmed: internal error: queue returned from controller doesn't exist").lock().unwrap().head = entry.sq_head; + self.nvme.submission_queues.read().unwrap().get(&{entry.sq_id}).expect("nvmed: internal error: queue returned from controller doesn't exist").lock().unwrap().head = entry.sq_head; - self.try_notify_futures(cq_id, &entry); + Self::try_notify_futures(&mut self.pending_reqs, cq_id, &entry); entry_count += 1; } @@ -142,12 +144,12 @@ impl CqReactor { Some(()) } - fn finish_pending_completion(&mut self, req_cq_id: CqId, cq_id: CqId, sq_id: SqId, cmd_id: CmdId, entry: &NvmeComp, i: usize) -> bool { + fn finish_pending_completion(pending_reqs: &mut Vec, req_cq_id: CqId, cq_id: CqId, sq_id: SqId, cmd_id: CmdId, entry: &NvmeComp, i: usize) -> bool { if req_cq_id == cq_id && sq_id == entry.sq_id && cmd_id == entry.cid { - let (waker, message) = match self.pending_reqs.remove(i) { + let (waker, message) = match pending_reqs.remove(i) { PendingReq::PendingCompletion { waker, message, .. } => (waker, message), _ => unreachable!(), }; @@ -160,9 +162,9 @@ impl CqReactor { false } } - fn finish_pending_avail_submission(&mut self, sq_id: SqId, entry: &NvmeComp, i: usize) -> bool { + fn finish_pending_avail_submission(pending_reqs: &mut Vec, sq_id: SqId, entry: &NvmeComp, i: usize) -> bool { if sq_id == entry.sq_id { - let waker = match self.pending_reqs.remove(i) { + let waker = match pending_reqs.remove(i) { PendingReq::PendingAvailSubmission { waker, .. } => waker, _ => unreachable!(), }; @@ -173,19 +175,19 @@ impl CqReactor { false } } - fn try_notify_futures(&mut self, cq_id: CqId, entry: &NvmeComp) -> Option<()> { + fn try_notify_futures(pending_reqs: &mut Vec, cq_id: CqId, entry: &NvmeComp) -> Option<()> { let mut i = 0usize; let mut futures_notified = 0; - while i < self.pending_reqs.len() { - match &self.pending_reqs[i] { - &PendingReq::PendingCompletion { cq_id: req_cq_id, sq_id, cmd_id, .. } => if self.finish_pending_completion(req_cq_id, cq_id, sq_id, cmd_id, entry, i) { + while i < pending_reqs.len() { + match &pending_reqs[i] { + &PendingReq::PendingCompletion { cq_id: req_cq_id, sq_id, cmd_id, .. } => if Self::finish_pending_completion(pending_reqs, req_cq_id, cq_id, sq_id, cmd_id, entry, i) { futures_notified += 1; } else { i += 1; } - &PendingReq::PendingAvailSubmission { sq_id, .. } => if self.finish_pending_avail_submission(sq_id, entry, i) { + &PendingReq::PendingAvailSubmission { sq_id, .. } => if Self::finish_pending_avail_submission(pending_reqs, sq_id, entry, i) { futures_notified += 1; } else { i += 1; @@ -250,7 +252,7 @@ pub fn start_cq_reactor_thread( }) } -struct CompletionMessage { +pub struct CompletionMessage { cq_entry: NvmeComp, } @@ -264,6 +266,7 @@ enum CompletionFutureState { message: Arc>>, }, Finished, + Placeholder, } pub struct CompletionFuture { state: CompletionFutureState, @@ -278,8 +281,8 @@ impl Future for CompletionFuture { fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { let this = &mut self.get_mut().state; - match this { - &mut CompletionFutureState::Pending { + match mem::replace(this, CompletionFutureState::Placeholder) { + CompletionFutureState::Pending { message, cq_id, cmd_id, @@ -288,21 +291,22 @@ impl Future for CompletionFuture { } => { if let Some(value) = message.lock().unwrap().take() { *this = CompletionFutureState::Finished; - task::Poll::Ready(value.cq_entry) - } else { - sender.send(NotifReq::RequestCompletion { - cq_id, - sq_id, - cmd_id, - waker: context.waker().clone(), - message: Arc::clone(&message), - }); - task::Poll::Pending + return task::Poll::Ready(value.cq_entry); } + sender.send(NotifReq::RequestCompletion { + cq_id, + sq_id, + cmd_id, + waker: context.waker().clone(), + message: Arc::clone(&message), + }).expect("reactor dead"); + *this = CompletionFutureState::Pending { message, cq_id, cmd_id, sq_id, sender }; + task::Poll::Pending } - &mut CompletionFutureState::Finished => { + CompletionFutureState::Finished => { panic!("calling poll() on an already finished CompletionFuture") } + CompletionFutureState::Placeholder => unreachable!(), } } } @@ -345,6 +349,7 @@ pub(crate) enum SubmissionFutureState<'a, F> { // returned when there was an available submission entry from the beginning Ready(CmdId), Finished, + Placeholder, } /// A future representing a submission queue eventually becoming non-full. In most cases this @@ -361,8 +366,8 @@ impl NvmeCmd> Future for SubmissionFuture<'_, F> { fn poll(self: Pin<&mut Self>, context: &mut task::Context<'_>) -> task::Poll { let state = &mut self.get_mut().state; - match state { - &mut SubmissionFutureState::Pending { sq_id, cmd_init, nvme } => match nvme.try_submit_command(sq_id, cmd_init) { + match mem::replace(state, SubmissionFutureState::Placeholder) { + SubmissionFutureState::Pending { sq_id, cmd_init, nvme } => match nvme.try_submit_command(sq_id, cmd_init) { Ok(cmd_id) => { *state = SubmissionFutureState::Finished; task::Poll::Ready(cmd_id) @@ -373,11 +378,12 @@ impl NvmeCmd> Future for SubmissionFuture<'_, F> { task::Poll::Pending } } - &mut SubmissionFutureState::Ready(value) => { + SubmissionFutureState::Ready(value) => { *state = SubmissionFutureState::Finished; task::Poll::Ready(value) } - &mut SubmissionFutureState::Finished => panic!("calling poll() on an already finished SubmissionFuture"), + SubmissionFutureState::Finished => panic!("calling poll() on an already finished SubmissionFuture"), + SubmissionFutureState::Placeholder => unreachable!(), } } } diff --git a/nvmed/src/nvme/identify.rs b/nvmed/src/nvme/identify.rs index 5bae5d76c2..4bcb830d22 100644 --- a/nvmed/src/nvme/identify.rs +++ b/nvmed/src/nvme/identify.rs @@ -78,8 +78,9 @@ impl Nvme { // println!(" - Dumping identify namespace"); - let size = *(data.as_ptr().offset(0) as *const u64); - let capacity = *(data.as_ptr().offset(8) as *const u64); + // TODO: Use struct + let size = unsafe { *(data.as_ptr().offset(0) as *const u64) }; + let capacity = unsafe { *(data.as_ptr().offset(8) as *const u64) }; println!(" - ID: {} Size: {} Capacity: {}", nsid, size, capacity); //TODO: Read block size diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 362bedf789..e2c194db96 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -55,9 +55,9 @@ impl InterruptSources { } fn size_hint(&self) -> (usize, Option) { match self { - &Self::Msi(mut iter) => iter.size_hint(), - &Self::MsiX(mut iter) => iter.size_hint(), - &Self::Intx(mut iter) => iter.size_hint(), + &Self::Msi(ref iter) => iter.size_hint(), + &Self::MsiX(ref iter) => iter.size_hint(), + &Self::Intx(ref iter) => iter.size_hint(), } } } @@ -224,10 +224,13 @@ impl Nvme { /// # Locking /// Locks `regs`. unsafe fn doorbell_write(&self, index: usize, value: u32) { - let mut regs_guard = self.regs.write().unwrap(); + use std::ops::DerefMut; - let dstrd = ((regs_guard.cap.read() >> 32) & 0b1111) as usize; - let addr = ((*regs_guard) as *mut NvmeRegs as usize) + 0x1000 + index * (4 << dstrd); + let mut regs_guard = self.regs.write().unwrap(); + let mut regs: &mut NvmeRegs = regs_guard.deref_mut(); + + let dstrd = ((regs.cap.read() >> 32) & 0b1111) as usize; + let addr = (regs as *mut NvmeRegs as usize) + 0x1000 + index * (4 << dstrd); (&mut *(addr as *mut Mmio)).write(value); } @@ -260,7 +263,7 @@ impl Nvme { let csts = self.regs.get_mut().unwrap().csts.read(); // println!("CSTS: {:X}", csts); if csts & 1 == 1 { - unsafe { std::arch::x86_64::_mm_pause() } + std::arch::x86_64::_mm_pause(); } else { break; } @@ -276,13 +279,13 @@ impl Nvme { } } - for (qid, queue) in self.completion_queues.get_mut().unwrap().iter() { + for (qid, queue) in self.completion_queues.get_mut().unwrap().iter_mut() { let &(ref cq, ref sq_ids) = &*queue.get_mut().unwrap(); let data = &cq.data; // println!(" - completion queue {}: {:X}, {}", qid, data.physical(), data.len()); } - for (qid, queue) in self.submission_queues.get_mut().unwrap().iter() { + for (qid, queue) in self.submission_queues.get_mut().unwrap().iter_mut() { let data = &queue.get_mut().unwrap().data; // println!(" - submission queue {}: {:X}, {}", qid, data.physical(), data.len()); } @@ -290,10 +293,10 @@ impl Nvme { { let regs = self.regs.get_mut().unwrap(); let submission_queues = self.submission_queues.get_mut().unwrap(); - let completion_queues = self.submission_queues.get_mut().unwrap(); + let completion_queues = self.completion_queues.get_mut().unwrap(); - let asq = submission_queues.get(&0).unwrap().get_mut().unwrap(); - let acq = completion_queues.get(&0).unwrap().get_mut().unwrap(); + let asq = submission_queues.get_mut(&0).unwrap().get_mut().unwrap(); + let (acq, _) = completion_queues.get_mut(&0).unwrap().get_mut().unwrap(); regs.aqa .write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1)); regs.asq.write(asq.data.physical() as u64); @@ -314,7 +317,7 @@ impl Nvme { let csts = self.regs.get_mut().unwrap().csts.read(); // println!("CSTS: {:X}", csts); if csts & 1 == 0 { - unsafe { std::arch::x86_64::_mm_pause() } + std::arch::x86_64::_mm_pause(); } else { break; } @@ -326,7 +329,7 @@ impl Nvme { /// # Panics /// Will panic if the same vector is called twice with different mask flags. pub fn set_vectors_masked(&self, vectors: impl IntoIterator) { - let interrupt_method_guard = self.interrupt_method.lock().unwrap(); + let mut interrupt_method_guard = self.interrupt_method.lock().unwrap(); match &mut *interrupt_method_guard { &mut InterruptMethod::Intx => { @@ -398,7 +401,7 @@ impl Nvme { pub fn submit_command_generic<'a, F: FnOnce(CmdId) -> NvmeCmd>(&'a self, sq_id: SqId, full_sq_handling: FullSqHandling, cmd_init: F) -> SubmissionBehavior<'a, F> { let sqs_read_guard = self.submission_queues.read().unwrap(); - let sq_lock = sqs_read_guard + let mut sq_lock = sqs_read_guard .get(&sq_id) .expect("nvmed: internal error: given SQ for SQ ID not there") .lock() @@ -413,7 +416,8 @@ impl Nvme { u16::try_from(sq_lock.tail).expect("nvmed: internal error: CQ has more than 2^16 entries"); let tail = sq_lock.submit_unchecked(cmd_init(cmd_id)); let tail = u16::try_from(tail).unwrap(); - self.submission_queue_tail(sq_id, tail); + + unsafe { self.submission_queue_tail(sq_id, tail) }; match full_sq_handling { FullSqHandling::ErrorDirectly => SubmissionBehavior::Nonblocking(Ok(cmd_id)), @@ -535,8 +539,8 @@ impl Nvme { namespaces } - unsafe fn namespace_rw( - &mut self, + async fn namespace_rw( + &self, nsid: u32, lba: u64, blocks_1: u16, @@ -545,59 +549,51 @@ impl Nvme { //TODO: Get real block size let block_size = 512; + let buffer_prp_guard = self.buffer_prp.lock().unwrap(); + let bytes = ((blocks_1 as u64) + 1) * block_size; let (ptr0, ptr1) = if bytes <= 4096 { - (self.buffer_prp[0], 0) + (buffer_prp_guard[0], 0) } else if bytes <= 8192 { - (self.buffer_prp[0], self.buffer_prp[1]) + (buffer_prp_guard[0], buffer_prp_guard[1]) } else { - (self.buffer_prp[0], (self.buffer_prp.physical() + 8) as u64) + (buffer_prp_guard[0], (buffer_prp_guard.physical() + 8) as u64) }; - { - let qid = 1; - let queue = &mut self.submission_queues[qid]; - let cid = queue.i as u16; - let entry = if write { + let cmd_id = self.submit_command_async(1, |cid| { + if write { NvmeCmd::io_write(cid, nsid, lba, blocks_1, ptr0, ptr1) } else { NvmeCmd::io_read(cid, nsid, lba, blocks_1, ptr0, ptr1) - }; - let tail = queue.submit(entry); - self.submission_queue_tail(qid as u16, tail as u16); - } + } + }).await; - { - let qid = 1; - let queue = &mut self.completion_queues[qid]; - let (head, entry) = queue.complete_spin(); - //TODO: Handle errors - self.completion_queue_head(qid as u16, head as u16); - } + let comp = self.completion(1, cmd_id, 1).await; + // TODO: Handle errors Ok(()) } - pub unsafe fn namespace_read( - &mut self, + pub async fn namespace_read( + &self, nsid: u32, mut lba: u64, buf: &mut [u8], ) -> Result> { - //TODO: Use interrupts - //TODO: Get real block size let block_size = 512; - for chunk in buf.chunks_mut(self.buffer.len()) { + let mut buffer_guard = self.buffer.lock().unwrap(); + + for chunk in buf.chunks_mut(buffer_guard.len()) { let blocks = (chunk.len() + block_size - 1) / block_size; assert!(blocks > 0); assert!(blocks <= 0x1_0000); - self.namespace_rw(nsid, lba, (blocks - 1) as u16, false)?; + self.namespace_rw(nsid, lba, (blocks - 1) as u16, false).await?; - chunk.copy_from_slice(&self.buffer[..chunk.len()]); + chunk.copy_from_slice(&buffer_guard[..chunk.len()]); lba += blocks as u64; } @@ -605,8 +601,8 @@ impl Nvme { Ok(Some(buf.len())) } - pub unsafe fn namespace_write( - &mut self, + pub async fn namespace_write( + &self, nsid: u32, mut lba: u64, buf: &[u8], @@ -616,15 +612,17 @@ impl Nvme { //TODO: Get real block size let block_size = 512; - for chunk in buf.chunks(self.buffer.len()) { + let mut buffer_guard = self.buffer.lock().unwrap(); + + for chunk in buf.chunks(buffer_guard.len()) { let blocks = (chunk.len() + block_size - 1) / block_size; assert!(blocks > 0); assert!(blocks <= 0x1_0000); - self.buffer[..chunk.len()].copy_from_slice(chunk); + buffer_guard[..chunk.len()].copy_from_slice(chunk); - self.namespace_rw(nsid, lba, (blocks - 1) as u16, true)?; + self.namespace_rw(nsid, lba, (blocks - 1) as u16, true).await?; lba += blocks as u64; } diff --git a/nvmed/src/nvme/queues.rs b/nvmed/src/nvme/queues.rs index aca1b49efc..cac0001b7f 100644 --- a/nvmed/src/nvme/queues.rs +++ b/nvmed/src/nvme/queues.rs @@ -55,7 +55,7 @@ pub struct NvmeCompQueue { impl NvmeCompQueue { pub fn new() -> Result { Ok(Self { - data: Dma::zeroed_unsized(256)?, + data: unsafe { Dma::zeroed_unsized(256)? }, head: 0, phase: true, }) @@ -98,7 +98,7 @@ pub struct NvmeCmdQueue { impl NvmeCmdQueue { pub fn new() -> Result { Ok(Self { - data: Dma::zeroed_unsized(64)?, + data: unsafe { Dma::zeroed_unsized(64)? }, tail: 0, head: 0, }) diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index 1badbcd282..090fdb67ba 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -82,10 +82,8 @@ impl DiskWrapper { return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); } loop { - match unsafe { - nvme.namespace_read(disk.id, block, block_bytes) - .map_err(|err| io::Error::from_raw_os_error(err.errno))? - } { + match futures::executor::block_on(nvme.namespace_read(disk.id, block, block_bytes)) + .map_err(|err| io::Error::from_raw_os_error(err.errno))? { Some(bytes) => { assert_eq!(bytes, block_bytes.len()); assert_eq!(bytes, blksize as usize); @@ -161,29 +159,6 @@ impl DiskScheme { } } -impl DiskScheme { - pub fn irq(&mut self) -> bool { - let mut found_completion = false; - - let nvme = &mut self.nvme; - let completion_queues = nvme.completion_queues.read().unwrap(); - - for qid in 0..completion_queues.len() { - let queue = completion_queues[qid].lock().unwrap(); - while let Some((head, entry)) = queue.complete() { - found_completion = true; - println!("nvmed: Unhandled completion {:?}", entry); - //TODO: Handle errors - unsafe { - nvme.completion_queue_head(qid as u16, head as u16); - } - } - } - - found_completion - } -} - impl SchemeBlockMut for DiskScheme { fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { if uid == 0 { @@ -372,10 +347,7 @@ impl SchemeBlockMut for DiskScheme { Handle::Disk(number, ref mut size) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; - if let Some(count) = unsafe { - self.nvme - .namespace_read(disk.as_ref().id, (*size as u64) / block_size, buf)? - } { + if let Some(count) = futures::executor::block_on(self.nvme.namespace_read(disk.as_ref().id, (*size as u64) / block_size, buf))? { *size += count; Ok(Some(count)) } else { @@ -400,9 +372,7 @@ impl SchemeBlockMut for DiskScheme { let abs_block = part.start_lba + rel_block; - if let Some(count) = - unsafe { self.nvme.namespace_read(disk.as_ref().id, abs_block, buf)? } - { + if let Some(count) = futures::executor::block_on(self.nvme.namespace_read(disk.as_ref().id, abs_block, buf))? { *offset += count; Ok(Some(count)) } else { @@ -419,8 +389,8 @@ impl SchemeBlockMut for DiskScheme { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; if let Some(count) = unsafe { - self.nvme - .namespace_write(disk.as_ref().id, (*size as u64) / block_size, buf)? + futures::executor::block_on(self.nvme + .namespace_write(disk.as_ref().id, (*size as u64) / block_size, buf))? } { *size += count; Ok(Some(count)) @@ -446,10 +416,7 @@ impl SchemeBlockMut for DiskScheme { let abs_block = part.start_lba + rel_block; - if let Some(count) = unsafe { - self.nvme - .namespace_write(disk.as_ref().id, abs_block, buf)? - } { + if let Some(count) = futures::executor::block_on(self.nvme.namespace_write(disk.as_ref().id, abs_block, buf))? { *offset += count; Ok(Some(count)) } else { From 2db3bf468915a2a8cd736f75ae87e3e696ab7ba4 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 1 May 2020 20:00:24 +0200 Subject: [PATCH 0410/1301] Read real block sizes. --- nvmed/src/main.rs | 57 +++++++++++++-- nvmed/src/nvme/identify.rs | 138 +++++++++++++++++++++++++++++++++++-- nvmed/src/nvme/mod.rs | 49 ++++++------- nvmed/src/scheme.rs | 14 ++-- 4 files changed, 212 insertions(+), 46 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 483c9aafe5..1baf366ad6 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::convert::TryInto; use std::fs::File; use std::io::{ErrorKind, Read, Write}; @@ -9,12 +8,10 @@ use std::{slice, usize}; use pcid_interface::{PciBar, PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; use syscall::{ - CloneFlags, Event, Mmio, Packet, Result, SchemeBlockMut, EVENT_READ, PHYSMAP_NO_CACHE, + CloneFlags, Event, Mmio, Packet, Result, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, }; - -use arrayvec::ArrayVec; -use log::{debug, error, info, trace, warn}; +use redox_log::{OutputBuilder, RedoxLogger}; use self::nvme::{InterruptMethod, InterruptSources, Nvme}; use self::scheme::DiskScheme; @@ -190,7 +187,7 @@ fn get_int_method( message_data: Some(msg_data), multi_message_enable: Some(0), // enable 2^0=1 vectors mask_bits: None, - })); + })).unwrap(); (0, irq_handle) }; @@ -213,12 +210,58 @@ fn get_int_method( } } +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "nvme.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Trace) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("nvmed: failed to create nvme.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "nvme.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Trace) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("nvmed: failed to create nvme.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("nvmed: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("nvmed: failed to set default logger: {}", error); + None + } + } +} + fn main() { // Daemonize if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { return; } + let _logger_ref = setup_logging(); + let mut pcid_handle = PcidServerHandle::connect_default().expect("nvmed: failed to setup channel to pcid"); let pci_config = pcid_handle @@ -235,7 +278,7 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_nvme"); - info!("NVME PCI CONFIG: {:?}", pci_config); + log::info!("NVME PCI CONFIG: {:?}", pci_config); let allocated_bars = AllocatedBars::default(); diff --git a/nvmed/src/nvme/identify.rs b/nvmed/src/nvme/identify.rs index 4bcb830d22..98937ec72f 100644 --- a/nvmed/src/nvme/identify.rs +++ b/nvmed/src/nvme/identify.rs @@ -2,6 +2,7 @@ use syscall::Dma; use super::{Nvme, NvmeCmd, NvmeNamespace}; +/// See NVME spec section 5.15.2.2. #[derive(Clone, Copy)] #[repr(packed)] pub struct IdentifyControllerData { @@ -18,6 +19,129 @@ pub struct IdentifyControllerData { // TODO: Lots of fields pub _4k_pad: [u8; 4096 - 72], } + +/// See NVME spec section 5.15.2.1. +#[derive(Clone, Copy)] +#[repr(packed)] +pub struct IdentifyNamespaceData { + pub nsze: u64, + pub ncap: u64, + pub nuse: u64, + + pub nsfeat: u8, + pub nlbaf: u8, + pub flbas: u8, + pub mc: u8, + + pub dpc: u8, + pub dps: u8, + pub nmic: u8, + pub rescap: u8, + + pub fpi: u8, + pub dlfeat: u8, + pub nawun: u16, + + pub nawupf: u16, + pub nacwu: u16, + pub nabsn: u16, + pub nabo: u16, + + pub nabspf: u16, + pub noiob: u16, + + pub nvmcap: u64, + pub npwg: u16, + pub npwa: u16, + pub npdg: u16, + pub npda: u16, + + pub nows: u16, + pub _rsvd1: [u8; 18], + + pub anagrpid: u32, + pub _rsvd2: [u8; 3], + pub nsattr: u8, + + pub nvmsetid: u16, + pub endgid: u16, + pub nguid: [u8; 16], + pub eui64: u64, + + pub lba_format_support: [LbaFormat; 16], + pub _rsvd3: [u8; 192], + pub vendor_specific: [u8; 3712], +} + +impl IdentifyNamespaceData { + pub fn size_in_blocks(&self) -> u64 { + self.nsze + } + pub fn capacity_in_blocks(&self) -> u64 { + self.ncap + } + /// Guaranteed to be within 0..=15 + pub fn formatted_lba_size_idx(&self) -> usize { + (self.flbas & 0xF) as usize + } + pub fn formatted_lba_size(&self) -> &LbaFormat { + &self.lba_format_support[self.formatted_lba_size_idx()] + } + pub fn has_metadata_after_data(&self) -> bool { + (self.flbas & (1 << 4)) != 0 + } +} + +#[derive(Clone, Copy)] +#[repr(packed)] +pub struct LbaFormat(pub u32); + +#[repr(u8)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum RelativePerformance { + Best = 0b00, + Better, + Good, + Degraded, +} +impl Ord for RelativePerformance { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + // higher performance is better, hence reversed + Ord::cmp(&(*self as u8), &(*other as u8)).reverse() + } +} +impl PartialOrd for RelativePerformance { + fn partial_cmp(&self, other: &Self) -> Option { + Some(Ord::cmp(self, other)) + } +} + +impl LbaFormat { + pub fn relative_performance(&self) -> RelativePerformance { + match ((self.0 >> 24) & 0b11) { + 0b00 => RelativePerformance::Best, + 0b01 => RelativePerformance::Better, + 0b10 => RelativePerformance::Good, + 0b11 => RelativePerformance::Degraded, + _ => unreachable!(), + } + } + pub fn is_available(&self) -> bool { + self.log_lba_data_size() != 0 + } + pub fn log_lba_data_size(&self) -> u8 { + ((self.0 >> 16) & 0xFF) as u8 + } + pub fn lba_data_size(&self) -> Option { + if self.log_lba_data_size() < 9 { return None } + if self.log_lba_data_size() >= 32 { return None } + Some(1u64 << self.log_lba_data_size()) + } + pub fn metadata_size(&self) -> u16 { + (self.0 & 0xFFFF) as u16 + } +} + impl Nvme { /// Returns the serial number, model, and firmware, in that order. pub async fn identify_controller(&self) { @@ -66,7 +190,7 @@ impl Nvme { } pub async fn identify_namespace(&self, nsid: u32) -> NvmeNamespace { //TODO: Use buffer - let data: Dma<[u8; 4096]> = Dma::zeroed().unwrap(); + let data: Dma = Dma::zeroed().unwrap(); // println!(" - Attempting to identify namespace {}", nsid); let cmd_id = self @@ -78,17 +202,17 @@ impl Nvme { // println!(" - Dumping identify namespace"); - // TODO: Use struct - let size = unsafe { *(data.as_ptr().offset(0) as *const u64) }; - let capacity = unsafe { *(data.as_ptr().offset(8) as *const u64) }; - println!(" - ID: {} Size: {} Capacity: {}", nsid, size, capacity); + let size = data.size_in_blocks(); + let capacity = data.capacity_in_blocks(); + log::info!("NSID: {} Size: {} Capacity: {}", nsid, size, capacity); - //TODO: Read block size + let block_size = data.formatted_lba_size().lba_data_size().expect("nvmed: error: size outside 512-2^64 range"); + log::debug!("NVME block size: {}", block_size); NvmeNamespace { id: nsid, blocks: size, - block_size: 512, // TODO + block_size, } } } diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index e2c194db96..96f86e1bd5 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -181,7 +181,7 @@ pub enum FullSqHandling { /// Return an error immediately prior to posting the command. ErrorDirectly, - /// Tell the IRQ reactor that we wan't to be notified when a command on the same submission + /// Tell the IRQ reactor that we want to be notified when a command on the same submission /// queue has been completed. Wait, } @@ -250,18 +250,21 @@ impl Nvme { buffer_prp[i] = (buffer.physical() + i * 4096) as u64; } - // println!(" - CAPS: {:X}", self.regs.cap.read()); - // println!(" - VS: {:X}", self.regs.vs.read()); - // println!(" - CC: {:X}", self.regs.cc.read()); - // println!(" - CSTS: {:X}", self.regs.csts.read()); + { + let regs = self.regs.read().unwrap(); + log::debug!("CAPS: {:X}", regs.cap.read()); + log::debug!("VS: {:X}", regs.vs.read()); + log::debug!("CC: {:X}", regs.cc.read()); + log::debug!("CSTS: {:X}", regs.csts.read()); + } - // println!(" - Disable"); + log::debug!("Disabling controller."); self.regs.get_mut().unwrap().cc.writef(1, false); - // println!(" - Waiting for not ready"); + log::trace!("Waiting for not ready."); loop { let csts = self.regs.get_mut().unwrap().csts.read(); - // println!("CSTS: {:X}", csts); + log::trace!("CSTS: {:X}", csts); if csts & 1 == 1 { std::arch::x86_64::_mm_pause(); } else { @@ -282,12 +285,12 @@ impl Nvme { for (qid, queue) in self.completion_queues.get_mut().unwrap().iter_mut() { let &(ref cq, ref sq_ids) = &*queue.get_mut().unwrap(); let data = &cq.data; - // println!(" - completion queue {}: {:X}, {}", qid, data.physical(), data.len()); + log::debug!("completion queue {}: {:X}, {}, (submission queue ids: {:?}", qid, data.physical(), data.len(), sq_ids); } for (qid, queue) in self.submission_queues.get_mut().unwrap().iter_mut() { let data = &queue.get_mut().unwrap().data; - // println!(" - submission queue {}: {:X}, {}", qid, data.physical(), data.len()); + log::debug!("submission queue {}: {:X}, {}", qid, data.physical(), data.len()); } { @@ -309,13 +312,13 @@ impl Nvme { regs.cc.write(cc); } - // println!(" - Enable"); + log::debug!("Enabling controller."); self.regs.get_mut().unwrap().cc.writef(1, true); - // println!(" - Waiting for ready"); + log::debug!("Waiting for ready"); loop { let csts = self.regs.get_mut().unwrap().csts.read(); - // println!("CSTS: {:X}", csts); + log::debug!("CSTS: {:X}", csts); if csts & 1 == 0 { std::arch::x86_64::_mm_pause(); } else { @@ -541,13 +544,13 @@ impl Nvme { async fn namespace_rw( &self, + namespace: &NvmeNamespace, nsid: u32, lba: u64, blocks_1: u16, write: bool, ) -> Result<()> { - //TODO: Get real block size - let block_size = 512; + let block_size = namespace.block_size; let buffer_prp_guard = self.buffer_prp.lock().unwrap(); @@ -576,14 +579,14 @@ impl Nvme { pub async fn namespace_read( &self, + namespace: &NvmeNamespace, nsid: u32, mut lba: u64, buf: &mut [u8], ) -> Result> { - //TODO: Get real block size - let block_size = 512; + let block_size = namespace.block_size as usize; - let mut buffer_guard = self.buffer.lock().unwrap(); + let buffer_guard = self.buffer.lock().unwrap(); for chunk in buf.chunks_mut(buffer_guard.len()) { let blocks = (chunk.len() + block_size - 1) / block_size; @@ -591,7 +594,7 @@ impl Nvme { assert!(blocks > 0); assert!(blocks <= 0x1_0000); - self.namespace_rw(nsid, lba, (blocks - 1) as u16, false).await?; + self.namespace_rw(namespace, nsid, lba, (blocks - 1) as u16, false).await?; chunk.copy_from_slice(&buffer_guard[..chunk.len()]); @@ -603,14 +606,12 @@ impl Nvme { pub async fn namespace_write( &self, + namespace: &NvmeNamespace, nsid: u32, mut lba: u64, buf: &[u8], ) -> Result> { - //TODO: Use interrupts - - //TODO: Get real block size - let block_size = 512; + let block_size = namespace.block_size as usize; let mut buffer_guard = self.buffer.lock().unwrap(); @@ -622,7 +623,7 @@ impl Nvme { buffer_guard[..chunk.len()].copy_from_slice(chunk); - self.namespace_rw(nsid, lba, (blocks - 1) as u16, true).await?; + self.namespace_rw(namespace, nsid, lba, (blocks - 1) as u16, true).await?; lba += blocks as u64; } diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index 090fdb67ba..aabec0389e 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -82,7 +82,7 @@ impl DiskWrapper { return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); } loop { - match futures::executor::block_on(nvme.namespace_read(disk.id, block, block_bytes)) + match futures::executor::block_on(nvme.namespace_read(disk, disk.id, block, block_bytes)) .map_err(|err| io::Error::from_raw_os_error(err.errno))? { Some(bytes) => { assert_eq!(bytes, block_bytes.len()); @@ -347,7 +347,7 @@ impl SchemeBlockMut for DiskScheme { Handle::Disk(number, ref mut size) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; - if let Some(count) = futures::executor::block_on(self.nvme.namespace_read(disk.as_ref().id, (*size as u64) / block_size, buf))? { + if let Some(count) = futures::executor::block_on(self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, (*size as u64) / block_size, buf))? { *size += count; Ok(Some(count)) } else { @@ -372,7 +372,7 @@ impl SchemeBlockMut for DiskScheme { let abs_block = part.start_lba + rel_block; - if let Some(count) = futures::executor::block_on(self.nvme.namespace_read(disk.as_ref().id, abs_block, buf))? { + if let Some(count) = futures::executor::block_on(self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, abs_block, buf))? { *offset += count; Ok(Some(count)) } else { @@ -388,10 +388,8 @@ impl SchemeBlockMut for DiskScheme { Handle::Disk(number, ref mut size) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; - if let Some(count) = unsafe { - futures::executor::block_on(self.nvme - .namespace_write(disk.as_ref().id, (*size as u64) / block_size, buf))? - } { + if let Some(count) = futures::executor::block_on(self.nvme + .namespace_write(disk.as_ref(), disk.as_ref().id, (*size as u64) / block_size, buf))? { *size += count; Ok(Some(count)) } else { @@ -416,7 +414,7 @@ impl SchemeBlockMut for DiskScheme { let abs_block = part.start_lba + rel_block; - if let Some(count) = futures::executor::block_on(self.nvme.namespace_write(disk.as_ref().id, abs_block, buf))? { + if let Some(count) = futures::executor::block_on(self.nvme.namespace_write(disk.as_ref(), disk.as_ref().id, abs_block, buf))? { *offset += count; Ok(Some(count)) } else { From cea6ce7d7a07364b14ef34108e81c03609130e33 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 2 May 2020 00:05:04 +0200 Subject: [PATCH 0411/1301] Move the setrens to a later position, in nvmed. --- nvmed/src/main.rs | 4 ++-- pcid/src/driver_interface/irq_helpers.rs | 3 +-- pcid/src/pci/cap.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 1baf366ad6..3691cc9a2d 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -319,8 +319,6 @@ fn main() { let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); let (interrupt_method, interrupt_sources) = get_int_method(&mut pcid_handle, &pci_config.func, &allocated_bars) @@ -332,6 +330,8 @@ fn main() { nvme::cq_reactor::start_cq_reactor_thread(Arc::clone(&nvme), interrupt_sources, reactor_receiver); let namespaces = futures::executor::block_on(nvme.init_with_queues()); + syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); let mut todo = Vec::new(); 'events: loop { diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index da928bf8d2..e0d63164e5 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -7,7 +7,6 @@ use std::convert::TryFrom; use std::fs::{self, File}; use std::io::{self, prelude::*}; use std::num::NonZeroU8; -use std::ops; /// Read the local APIC ID of the bootstrap processor. pub fn read_bsp_apic_id() -> io::Result { @@ -60,7 +59,7 @@ pub fn cpu_ids() -> io::Result> + 'static /// Note that this count/alignment restriction is only mandatory for MSI; MSI-X allows for /// individually allocated vectors that might be spread out, even on multiple CPUs. Thus, multiple /// invocations with alignment 1 and count 1 are totally acceptable, although allocating in bulk -/// minimizes the initialization overhead, even though it's negligible. +/// minimizes the initialization overhead. pub fn allocate_aligned_interrupt_vectors(cpu_id: usize, alignment: NonZeroU8, count: u8) -> io::Result)>> { let cpu_id = u8::try_from(cpu_id).expect("usize cpu ids not implemented yet"); if count == 0 { return Ok(None) } diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index dfbb6a1feb..15e2077305 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -25,7 +25,7 @@ where if self.offset == 0 { return None }; - let first_dword = dbg!(self.reader.read_u32(dbg!(u16::from(self.offset)))); + let first_dword = self.reader.read_u32(u16::from(self.offset)); let next = ((first_dword >> 8) & 0xFF) as u8; let offset = self.offset; From 3558397859f6ec470de387bf92a6743bc3c00f65 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 3 May 2020 15:47:09 +0200 Subject: [PATCH 0412/1301] ASYNC COMMAND SUBMISSION WORKS (partially). --- nvmed/src/main.rs | 166 ++++++++++++++-------------- nvmed/src/nvme/cq_reactor.rs | 202 +++++++++++++++++------------------ nvmed/src/nvme/identify.rs | 22 ++-- nvmed/src/nvme/mod.rs | 103 +++++------------- nvmed/src/nvme/queues.rs | 9 +- xhcid/src/main.rs | 8 +- 6 files changed, 232 insertions(+), 278 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 3691cc9a2d..2eb7eec7a2 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -48,7 +48,7 @@ impl Drop for Bar { #[derive(Default)] pub struct AllocatedBars(pub [Mutex>; 6]); -/// Get the most optimal yet functional interrupt mechanism: either (in the order preference): +/// Get the most optimal yet functional interrupt mechanism: either (in the order of preference): /// MSI-X, MSI, and INTx# pin. Returns both runtime interrupt structures (MSI/MSI-X capability /// structures), and the handles to the interrupts. fn get_int_method( @@ -56,6 +56,7 @@ fn get_int_method( function: &PciFunction, allocated_bars: &AllocatedBars, ) -> Result<(InterruptMethod, InterruptSources)> { + log::trace!("Begin get_int_method"); use pcid_interface::irq_helpers; let features = pcid_handle.fetch_all_features().unwrap(); @@ -214,7 +215,14 @@ fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_filter(log::LevelFilter::Trace) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ) + .with_output( + OutputBuilder::with_endpoint(File::open("debug:").unwrap()) + .with_filter(log::LevelFilter::Trace) .with_ansi_escape_codes() .flush_on_newline(true) .build() @@ -295,87 +303,89 @@ fn main() { bar_size: bar_size as usize, ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"), }); - { - let event_fd = syscall::open("event:", syscall::O_RDWR | syscall::O_CLOEXEC) - .expect("nvmed: failed to open event queue"); - let mut event_file = unsafe { File::from_raw_fd(event_fd as RawFd) }; + let event_fd = syscall::open("event:", syscall::O_RDWR | syscall::O_CLOEXEC) + .expect("nvmed: failed to open event queue"); + let mut event_file = unsafe { File::from_raw_fd(event_fd as RawFd) }; - let scheme_name = format!("disk/{}", name); - let socket_fd = syscall::open( - &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK | syscall::O_CLOEXEC, - ) - .expect("nvmed: failed to create disk scheme"); + let scheme_name = format!("disk/{}", name); + let socket_fd = syscall::open( + &format!(":{}", scheme_name), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK | syscall::O_CLOEXEC, + ) + .expect("nvmed: failed to create disk scheme"); - syscall::write( - event_fd, - &syscall::Event { - id: socket_fd, - flags: syscall::EVENT_READ, - data: 0, + syscall::write( + event_fd, + &syscall::Event { + id: socket_fd, + flags: syscall::EVENT_READ, + data: 0, + }, + ) + .expect("nvmed: failed to watch disk scheme events"); + + std::thread::sleep(std::time::Duration::from_millis(1000)); + + let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + + let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); + let (interrupt_method, interrupt_sources) = + get_int_method(&mut pcid_handle, &pci_config.func, &allocated_bars) + .expect("nvmed: failed to find a suitable interrupt method"); + let mut nvme = Nvme::new(address, interrupt_method, pcid_handle, reactor_sender) + .expect("nvmed: failed to allocate driver data"); + unsafe { nvme.init() } + log::debug!("Finished base initialization"); + let nvme = Arc::new(nvme); + let reactor_thread = nvme::cq_reactor::start_cq_reactor_thread(Arc::clone(&nvme), interrupt_sources, reactor_receiver); + let namespaces = futures::executor::block_on(nvme.init_with_queues()); + + syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + + let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); + let mut todo = Vec::new(); + 'events: loop { + let mut event = Event::default(); + if event_file + .read(&mut event) + .expect("nvmed: failed to read event queue") + == 0 + { + break; + } + + match event.data { + 0 => loop { + let mut packet = Packet::default(); + match socket_file.read(&mut packet) { + Ok(0) => break 'events, + Ok(_) => (), + Err(err) => match err.kind() { + ErrorKind::WouldBlock => break, + _ => Err(err).expect("nvmed: failed to read disk scheme"), + }, + } + todo.push(packet); }, - ) - .expect("nvmed: failed to watch disk scheme events"); - - let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - - let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); - let (interrupt_method, interrupt_sources) = - get_int_method(&mut pcid_handle, &pci_config.func, &allocated_bars) - .expect("nvmed: failed to find a suitable interrupt method"); - let mut nvme = Nvme::new(address, interrupt_method, pcid_handle, reactor_sender) - .expect("nvmed: failed to allocate driver data"); - unsafe { nvme.init() } - let nvme = Arc::new(nvme); - nvme::cq_reactor::start_cq_reactor_thread(Arc::clone(&nvme), interrupt_sources, reactor_receiver); - let namespaces = futures::executor::block_on(nvme.init_with_queues()); - - syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - - let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); - let mut todo = Vec::new(); - 'events: loop { - let mut event = Event::default(); - if event_file - .read(&mut event) - .expect("nvmed: failed to read event queue") - == 0 - { - break; - } - - match event.data { - 0 => loop { - let mut packet = Packet::default(); - match socket_file.read(&mut packet) { - Ok(0) => break 'events, - Ok(_) => (), - Err(err) => match err.kind() { - ErrorKind::WouldBlock => break, - _ => Err(err).expect("nvmed: failed to read disk scheme"), - }, - } - todo.push(packet); - }, - unknown => { - panic!("nvmed: unknown event data {}", unknown); - } - } - - let mut i = 0; - while i < todo.len() { - if let Some(a) = scheme.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket_file - .write(&packet) - .expect("nvmed: failed to write disk scheme"); - } else { - i += 1; - } + unknown => { + panic!("nvmed: unknown event data {}", unknown); } } - //TODO: destroy NVMe stuff + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket_file + .write(&packet) + .expect("nvmed: failed to write disk scheme"); + } else { + i += 1; + } + } } + + //TODO: destroy NVMe stuff + reactor_thread.join().expect("nvmed: failed to join reactor thread"); } diff --git a/nvmed/src/nvme/cq_reactor.rs b/nvmed/src/nvme/cq_reactor.rs index e4dbfefe87..f78547bb4b 100644 --- a/nvmed/src/nvme/cq_reactor.rs +++ b/nvmed/src/nvme/cq_reactor.rs @@ -5,6 +5,7 @@ //! can also be used for notifying when a full submission queue can submit a new command (see //! `AvailableSqEntryFuture`). +use std::convert::TryFrom; use std::fs::File; use std::future::Future; use std::io::prelude::*; @@ -14,15 +15,15 @@ use std::sync::{Arc, Mutex}; use std::{mem, task, thread}; use syscall::data::Event; -use syscall::flag::EVENT_READ; use syscall::Result; -use crossbeam_channel::{Receiver, Sender}; +use crossbeam_channel::Receiver; use super::{CmdId, CqId, InterruptSources, Nvme, NvmeComp, NvmeCmd, SqId}; /// A notification request, sent by the future in order to tell the completion thread that the /// current task wants a notification when a matching completion queue entry has been seen. +#[derive(Debug)] pub enum NotifReq { RequestCompletion { cq_id: CqId, @@ -58,6 +59,7 @@ struct CqReactor { int_sources: InterruptSources, nvme: Arc, pending_reqs: Vec, + // used to store commands that may be completed before a completion is requested receiver: Receiver, event_queue: File, } @@ -95,8 +97,20 @@ impl CqReactor { receiver, }) } - fn handle_notif_reqs(&mut self) { - for req in self.receiver.try_iter() { + fn handle_notif_reqs_raw(pending_reqs: &mut Vec, receiver: &Receiver, block_until_first: bool) { + let mut blocking_iter; + let mut nonblocking_iter; + + let iter: &mut dyn Iterator = if block_until_first { + blocking_iter = std::iter::once(receiver.recv().unwrap()).chain(receiver.try_iter()); + &mut blocking_iter + } else { + nonblocking_iter = receiver.try_iter(); + &mut nonblocking_iter + }; + + for req in iter { + log::trace!("Got notif req: {:?}", req); match req { NotifReq::RequestCompletion { sq_id, @@ -104,14 +118,14 @@ impl CqReactor { cmd_id, waker, message, - } => self.pending_reqs.push(PendingReq::PendingCompletion { + } => pending_reqs.push(PendingReq::PendingCompletion { sq_id, cq_id, cmd_id, message, waker, }), - NotifReq::RequestAvailSubmission { sq_id, waker } => self.pending_reqs.push(PendingReq::PendingAvailSubmission { sq_id, waker, }), + NotifReq::RequestAvailSubmission { sq_id, waker } => pending_reqs.push(PendingReq::PendingAvailSubmission { sq_id, waker, }), } } } @@ -127,18 +141,29 @@ impl CqReactor { let mut completion_queue_guard = cqs_read_guard.get(&cq_id)?.lock().unwrap(); let &mut (ref mut completion_queue, _) = &mut *completion_queue_guard; - let (head, entry) = match completion_queue.complete() { - Some(e) => e, - None => continue, - }; + while let Some((head, entry)) = completion_queue.complete() { + unsafe { self.nvme.completion_queue_head(cq_id, head) }; - unsafe { self.nvme.completion_queue_head(cq_id, head) }; + log::trace!("Got completion queue entry (CQID {}): {:?} at {}", cq_id, entry, head); - self.nvme.submission_queues.read().unwrap().get(&{entry.sq_id}).expect("nvmed: internal error: queue returned from controller doesn't exist").lock().unwrap().head = entry.sq_head; + { + let submission_queues_read_lock = self.nvme.submission_queues.read().unwrap(); + // this lock is actually important, since it will block during submission from other + // threads. the lock won't be held for long by the submitters, but it still prevents + // the entry being lost before this reactor is actually able to respond: + let &(ref sq_lock, corresponding_cq_id) = submission_queues_read_lock.get(&{entry.sq_id}).expect("nvmed: internal error: queue returned from controller doesn't exist"); + assert_eq!(cq_id, corresponding_cq_id); + let mut sq_guard = sq_lock.lock().unwrap(); + sq_guard.head = entry.sq_head; + // the channel still has to be polled twice though: + Self::handle_notif_reqs_raw(&mut self.pending_reqs, &self.receiver, false); + } - Self::try_notify_futures(&mut self.pending_reqs, cq_id, &entry); - entry_count += 1; + Self::try_notify_futures(&mut self.pending_reqs, cq_id, &entry); + + entry_count += 1; + } } if entry_count == 0 {} @@ -199,24 +224,24 @@ impl CqReactor { } fn run(mut self) { + log::debug!("Running CQ reactor"); let mut event = Event::default(); let mut irq_word = [0u8; 8]; // stores the IRQ count const WORD_SIZE: usize = mem::size_of::(); loop { - self.handle_notif_reqs(); + let block_until_first = self.pending_reqs.is_empty(); + Self::handle_notif_reqs_raw(&mut self.pending_reqs, &self.receiver, block_until_first); + log::trace!("Handled notif reqs"); // block on getting the next event if self.event_queue.read(&mut event).unwrap() == 0 { // event queue has been destroyed break; } - if event.flags & EVENT_READ != EVENT_READ { - continue; - } - let (vector, irq_handle) = match self.int_sources.iter_mut().nth(event.id) { + let (vector, irq_handle) = match self.int_sources.iter_mut().nth(event.data) { Some(s) => s, None => continue, }; @@ -227,6 +252,7 @@ impl CqReactor { if irq_handle.write(&irq_word[..WORD_SIZE]).unwrap() == 0 { continue; } + log::trace!("NVME IRQ: vector {}", vector); self.nvme.set_vector_masked(vector, true); self.poll_completion_queues(vector); self.nvme.set_vector_masked(vector, false); @@ -252,14 +278,22 @@ pub fn start_cq_reactor_thread( }) } +#[derive(Debug)] pub struct CompletionMessage { cq_entry: NvmeComp, } -enum CompletionFutureState { - // not really required, but makes futures inert - Pending { - sender: Sender, +enum CompletionFutureState<'a, F> { + // the future is in its initial state: the command has not been submitted yet, and no interest + // has been registered. this state will repeat until a free submission queue entry appears to + // it, which it probably will since queues aren't supposed to be nearly always be full. + PendingSubmission { + cmd_init: F, + nvme: &'a Nvme, + sq_id: SqId, + }, + PendingCompletion { + nvme: &'a Nvme, cq_id: CqId, cmd_id: CmdId, sq_id: SqId, @@ -268,39 +302,72 @@ enum CompletionFutureState { Finished, Placeholder, } -pub struct CompletionFuture { - state: CompletionFutureState, +pub struct CompletionFuture<'a, F> { + state: CompletionFutureState<'a, F>, } // enum not self-referential -impl Unpin for CompletionFuture {} +impl Unpin for CompletionFuture<'_, F> {} -impl Future for CompletionFuture { +impl Future for CompletionFuture<'_, F> +where + F: FnOnce(CmdId) -> NvmeCmd, +{ type Output = NvmeComp; fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { let this = &mut self.get_mut().state; match mem::replace(this, CompletionFutureState::Placeholder) { - CompletionFutureState::Pending { + CompletionFutureState::PendingSubmission { cmd_init, nvme, sq_id } => { + let sqs_read_guard = nvme.submission_queues.read().unwrap(); + let &(ref sq_lock, cq_id) = sqs_read_guard + .get(&sq_id) + .expect("nvmed: internal error: given SQ for SQ ID not there"); + let mut sq_guard = sq_lock.lock().unwrap(); + let sq = &mut *sq_guard; + + if sq.is_full() { + // when the CQ reactor gets a new completion queue entry, it'll lock the + // submisson queue it came from. since we're holding the same lock, this + // message will always be sent before the reactor is done with the entry. + nvme.reactor_sender.send(NotifReq::RequestAvailSubmission { sq_id, waker: context.waker().clone() }).unwrap(); + *this = CompletionFutureState::PendingSubmission { cmd_init, nvme, sq_id }; + return task::Poll::Pending; + } + + let cmd_id = + u16::try_from(sq.tail).expect("nvmed: internal error: CQ has more than 2^16 entries"); + let tail = sq.submit_unchecked(cmd_init(cmd_id)); + let tail = u16::try_from(tail).unwrap(); + + // make sure that we register interest before the reactor can get notified + let message = Arc::new(Mutex::new(None)); + *this = CompletionFutureState::PendingCompletion { nvme, cq_id, cmd_id, sq_id, message: Arc::clone(&message), }; + nvme.reactor_sender.send(NotifReq::RequestCompletion { cq_id, sq_id, cmd_id, message, waker: context.waker().clone() }).expect("reactor dead"); + unsafe { nvme.submission_queue_tail(sq_id, tail) }; + task::Poll::Pending + } + CompletionFutureState::PendingCompletion { message, cq_id, cmd_id, sq_id, - sender, + nvme, } => { + println!("{:p}", &mut nvme.completion_queues.read().unwrap().get(&cq_id).unwrap().lock().unwrap().0); if let Some(value) = message.lock().unwrap().take() { *this = CompletionFutureState::Finished; return task::Poll::Ready(value.cq_entry); } - sender.send(NotifReq::RequestCompletion { + nvme.reactor_sender.send(NotifReq::RequestCompletion { cq_id, sq_id, cmd_id, waker: context.waker().clone(), message: Arc::clone(&message), }).expect("reactor dead"); - *this = CompletionFutureState::Pending { message, cq_id, cmd_id, sq_id, sender }; + *this = CompletionFutureState::PendingCompletion { message, cq_id, cmd_id, sq_id, nvme }; task::Poll::Pending } CompletionFutureState::Finished => { @@ -312,78 +379,9 @@ impl Future for CompletionFuture { } impl Nvme { - /// Returns a future representing an eventual completion queue event, in `cq_id`, from `sq_id`, - /// with the individual command identified by `cmd_id`. - pub fn completion(&self, sq_id: SqId, cmd_id: CmdId, cq_id: SqId) -> CompletionFuture { + pub fn submit_and_complete_command NvmeCmd>(&self, sq_id: SqId, cmd_init: F) -> CompletionFuture { CompletionFuture { - state: CompletionFutureState::Pending { - sender: self.reactor_sender.clone(), - cq_id, - cmd_id, - sq_id, - message: Arc::new(Mutex::new(None)), - }, - } - } - /// Returns a future representing a submission queue becoming non-full. Make sure that the - /// queue doesn't have any additional free entries first though, so that the reactor doesn't - /// have to interfere. - pub fn wait_for_available_submission<'a, F: FnOnce(CmdId) -> NvmeCmd>(&'a self, sq_id: SqId, f: F) -> SubmissionFuture<'a, F> { - SubmissionFuture { - state: SubmissionFutureState::Pending { - sq_id, - cmd_init: f, - nvme: &self, - }, - } - } -} - -pub(crate) enum SubmissionFutureState<'a, F> { - // the queue was known to be full when checked, thus the reactor is asked - Pending { - sq_id: SqId, - cmd_init: F, - nvme: &'a Nvme, - }, - // returned when there was an available submission entry from the beginning - Ready(CmdId), - Finished, - Placeholder, -} - -/// A future representing a submission queue eventually becoming non-full. In most cases this -/// future will finish directly, since all entries in the queue have to be occupied for it to block. -pub struct SubmissionFuture<'a, F> { - pub(crate) state: SubmissionFutureState<'a, F>, -} - -impl Unpin for SubmissionFuture<'_, F> {} - -impl NvmeCmd> Future for SubmissionFuture<'_, F> { - type Output = CmdId; - - fn poll(self: Pin<&mut Self>, context: &mut task::Context<'_>) -> task::Poll { - let state = &mut self.get_mut().state; - - match mem::replace(state, SubmissionFutureState::Placeholder) { - SubmissionFutureState::Pending { sq_id, cmd_init, nvme } => match nvme.try_submit_command(sq_id, cmd_init) { - Ok(cmd_id) => { - *state = SubmissionFutureState::Finished; - task::Poll::Ready(cmd_id) - } - Err(closure) => { - nvme.reactor_sender.send(NotifReq::RequestAvailSubmission { sq_id, waker: context.waker().clone() }); - *state = SubmissionFutureState::Pending { sq_id, cmd_init: closure, nvme }; - task::Poll::Pending - } - } - SubmissionFutureState::Ready(value) => { - *state = SubmissionFutureState::Finished; - task::Poll::Ready(value) - } - SubmissionFutureState::Finished => panic!("calling poll() on an already finished SubmissionFuture"), - SubmissionFutureState::Placeholder => unreachable!(), + state: CompletionFutureState::PendingSubmission { cmd_init, nvme: &self, sq_id }, } } } diff --git a/nvmed/src/nvme/identify.rs b/nvmed/src/nvme/identify.rs index 98937ec72f..8dff534a27 100644 --- a/nvmed/src/nvme/identify.rs +++ b/nvmed/src/nvme/identify.rs @@ -149,12 +149,10 @@ impl Nvme { let data: Dma = Dma::zeroed().unwrap(); // println!(" - Attempting to identify controller"); - let cid = self - .submit_admin_command(|cid| NvmeCmd::identify_controller(cid, data.physical())) + let comp = self + .submit_and_complete_admin_command(|cid| NvmeCmd::identify_controller(cid, data.physical())) .await; - - // println!(" - Waiting to identify controller"); - let comp = self.admin_queue_completion(cid).await; + log::trace!("Completion: {:?}", comp); // println!(" - Dumping identify controller"); @@ -176,14 +174,13 @@ impl Nvme { let data: Dma<[u32; 1024]> = Dma::zeroed().unwrap(); // println!(" - Attempting to retrieve namespace ID list"); - let cmd_id = self - .submit_admin_command(|cid| { + let comp = self + .submit_and_complete_admin_command(|cid| { NvmeCmd::identify_namespace_list(cid, data.physical(), base) }) .await; - // println!(" - Waiting to retrieve namespace ID list"); - let comp = self.admin_queue_completion(cmd_id).await; + log::trace!("Completion2: {:?}", comp); // println!(" - Dumping namespace ID list"); data.iter().copied().take_while(|&nsid| nsid != 0).collect() @@ -193,13 +190,10 @@ impl Nvme { let data: Dma = Dma::zeroed().unwrap(); // println!(" - Attempting to identify namespace {}", nsid); - let cmd_id = self - .submit_admin_command(|cid| NvmeCmd::identify_namespace(cid, data.physical(), nsid)) + let comp = self + .submit_and_complete_admin_command(|cid| NvmeCmd::identify_namespace(cid, data.physical(), nsid)) .await; - // println!(" - Waiting to identify namespace {}", nsid); - let comp = self.admin_queue_completion(cmd_id).await; - // println!(" - Dumping identify namespace"); let size = data.size_in_blocks(); diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 96f86e1bd5..f5af0f0c37 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::convert::TryFrom; use std::fs::File; use std::ptr; -use std::sync::atomic::{AtomicU16, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicU16, AtomicU64, AtomicUsize, Ordering}; use std::sync::{Mutex, RwLock}; use crossbeam_channel::Sender; @@ -159,7 +159,7 @@ pub struct Nvme { pcid_interface: Mutex, regs: RwLock<&'static mut NvmeRegs>, - pub(crate) submission_queues: RwLock>>, + pub(crate) submission_queues: RwLock, CqId)>>, pub(crate) completion_queues: RwLock)>>>, @@ -172,6 +172,8 @@ pub struct Nvme { next_sqid: AtomicSqId, next_cqid: AtomicCqId, + + next_avail_submission_epoch: AtomicU64, } unsafe impl Send for Nvme {} unsafe impl Sync for Nvme {} @@ -186,11 +188,6 @@ pub enum FullSqHandling { Wait, } -pub enum SubmissionBehavior<'a, F: FnOnce(CmdId) -> NvmeCmd> { - Nonblocking(Result), // TODO: Add full error - Future(self::cq_reactor::SubmissionFuture<'a, F>), -} - impl Nvme { pub fn new( address: usize, @@ -201,10 +198,10 @@ impl Nvme { Ok(Nvme { regs: RwLock::new(unsafe { &mut *(address as *mut NvmeRegs) }), submission_queues: RwLock::new( - std::iter::once((0u16, Mutex::new(NvmeCmdQueue::new()?))).collect(), + std::iter::once((0u16, (Mutex::new(NvmeCmdQueue::new()?), 0u16))).collect(), ), completion_queues: RwLock::new( - std::iter::once((0u16, Mutex::new((NvmeCompQueue::new()?, smallvec!())))).collect(), + std::iter::once((0u16, Mutex::new((NvmeCompQueue::new()?, smallvec!(0))))).collect(), ), // map the zero interrupt vector (which according to the spec shall always point to the // admin completion queue) to CQID 0 (admin completion queue) @@ -217,6 +214,7 @@ impl Nvme { next_sqid: AtomicSqId::new(0), next_cqid: AtomicCqId::new(0), + next_avail_submission_epoch: AtomicU64::new(0), }) } /// Write to a doorbell register. @@ -288,9 +286,9 @@ impl Nvme { log::debug!("completion queue {}: {:X}, {}, (submission queue ids: {:?}", qid, data.physical(), data.len(), sq_ids); } - for (qid, queue) in self.submission_queues.get_mut().unwrap().iter_mut() { + for (qid, (queue, cq_id)) in self.submission_queues.get_mut().unwrap().iter_mut() { let data = &queue.get_mut().unwrap().data; - log::debug!("submission queue {}: {:X}, {}", qid, data.physical(), data.len()); + log::debug!("submission queue {}: {:X}, {}, attached to CQID: {}", qid, data.physical(), data.len(), cq_id); } { @@ -298,7 +296,7 @@ impl Nvme { let submission_queues = self.submission_queues.get_mut().unwrap(); let completion_queues = self.completion_queues.get_mut().unwrap(); - let asq = submission_queues.get_mut(&0).unwrap().get_mut().unwrap(); + let asq = submission_queues.get_mut(&0).unwrap().0.get_mut().unwrap(); let (acq, _) = completion_queues.get_mut(&0).unwrap().get_mut().unwrap(); regs.aqa .write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1)); @@ -402,55 +400,8 @@ impl Nvme { self.set_vectors_masked(std::iter::once((vector, masked))) } - pub fn submit_command_generic<'a, F: FnOnce(CmdId) -> NvmeCmd>(&'a self, sq_id: SqId, full_sq_handling: FullSqHandling, cmd_init: F) -> SubmissionBehavior<'a, F> { - let sqs_read_guard = self.submission_queues.read().unwrap(); - let mut sq_lock = sqs_read_guard - .get(&sq_id) - .expect("nvmed: internal error: given SQ for SQ ID not there") - .lock() - .unwrap(); - if sq_lock.is_full() { - match full_sq_handling { - FullSqHandling::ErrorDirectly => return SubmissionBehavior::Nonblocking(Err(cmd_init)), - FullSqHandling::Wait => return SubmissionBehavior::Future(self.wait_for_available_submission(sq_id, cmd_init)), - } - } - let cmd_id = - u16::try_from(sq_lock.tail).expect("nvmed: internal error: CQ has more than 2^16 entries"); - let tail = sq_lock.submit_unchecked(cmd_init(cmd_id)); - let tail = u16::try_from(tail).unwrap(); - - unsafe { self.submission_queue_tail(sq_id, tail) }; - - match full_sq_handling { - FullSqHandling::ErrorDirectly => SubmissionBehavior::Nonblocking(Ok(cmd_id)), - FullSqHandling::Wait => SubmissionBehavior::Future(self::cq_reactor::SubmissionFuture { state: self::cq_reactor::SubmissionFutureState::Ready(cmd_id) }) - } - } - - /// Try submitting a new entry to the specified submission queue, or return None if the queue - /// was full. - pub fn try_submit_command NvmeCmd>( - &self, - sq_id: SqId, - f: F, - ) -> Result { - match self.submit_command_generic(sq_id, FullSqHandling::ErrorDirectly, f) { - SubmissionBehavior::Nonblocking(opt) => opt, - _ => unreachable!(), - } - } - pub async fn submit_command_async NvmeCmd>(&self, sq_id: SqId, f: F) -> CmdId { - match self.submit_command_generic(sq_id, FullSqHandling::Wait, f) { - SubmissionBehavior::Future(future) => future.await, - _ => unreachable!(), - } - } - pub async fn submit_admin_command NvmeCmd>(&self, f: F) -> CmdId { - self.submit_command_async(0, f).await - } - pub async fn admin_queue_completion(&self, cmd_id: CmdId) -> NvmeComp { - self.completion(0, cmd_id, 0).await + pub async fn submit_and_complete_admin_command NvmeCmd>(&self, cmd_init: F) -> NvmeComp { + self.submit_and_complete_command(0, cmd_init).await } pub async fn create_io_completion_queue(&self, io_cq_id: CqId, vector: Option) { @@ -478,12 +429,11 @@ impl Nvme { .checked_sub(1) .expect("nvmed: internal error: CQID 0 for I/O CQ"); - let cmd_id = self - .submit_admin_command(|cid| { + let comp = self + .submit_and_complete_admin_command(|cid| { NvmeCmd::create_io_completion_queue(cid, io_cq_id, ptr, raw_len, vector) }) .await; - let comp = self.admin_queue_completion(cmd_id).await; if let Some(vector) = vector { self.cqs_for_ivs @@ -498,17 +448,17 @@ impl Nvme { let (ptr, len) = { let mut submission_queues_guard = self.submission_queues.write().unwrap(); - let queue_guard = submission_queues_guard + let (queue_lock, _) = submission_queues_guard .entry(io_sq_id) .or_insert_with(|| { - Mutex::new( + (Mutex::new( NvmeCmdQueue::new() .expect("nvmed: failed to allocate I/O completion queue"), - ) - }) - .get_mut() - .unwrap(); - (queue_guard.data.physical(), queue_guard.data.len()) + ), io_cq_id) + }); + let queue = queue_lock.get_mut().unwrap(); + + (queue.data.physical(), queue.data.len()) }; let len = @@ -517,17 +467,18 @@ impl Nvme { .checked_sub(1) .expect("nvmed: internal error: SQID 0 for I/O SQ"); - let cmd_id = self - .submit_admin_command(|cid| { + let comp = self + .submit_and_complete_admin_command(|cid| { NvmeCmd::create_io_submission_queue(cid, io_sq_id, ptr, raw_len, io_cq_id) }) .await; - let comp = self.admin_queue_completion(cmd_id).await; } pub async fn init_with_queues(&self) -> BTreeMap { + log::trace!("preinit"); let ((), nsids) = futures::join!(self.identify_controller(), self.identify_namespace_list(0)); + log::debug!("first commands"); let mut namespaces = BTreeMap::new(); @@ -563,15 +514,13 @@ impl Nvme { (buffer_prp_guard[0], (buffer_prp_guard.physical() + 8) as u64) }; - let cmd_id = self.submit_command_async(1, |cid| { + let comp = self.submit_and_complete_command(1, |cid| { if write { NvmeCmd::io_write(cid, nsid, lba, blocks_1, ptr0, ptr1) } else { NvmeCmd::io_read(cid, nsid, lba, blocks_1, ptr0, ptr1) } }).await; - - let comp = self.completion(1, cmd_id, 1).await; // TODO: Handle errors Ok(()) diff --git a/nvmed/src/nvme/queues.rs b/nvmed/src/nvme/queues.rs index cac0001b7f..f6fe72a279 100644 --- a/nvmed/src/nvme/queues.rs +++ b/nvmed/src/nvme/queues.rs @@ -63,10 +63,11 @@ impl NvmeCompQueue { /// Get a new completion queue entry, or return None if no entry is available yet. pub(crate) fn complete(&mut self) -> Option<(u16, NvmeComp)> { + println!("PTR: {:p}", &*self as *const _); let entry = unsafe { ptr::read_volatile(self.data.as_ptr().add(self.head as usize)) }; // println!("{:?}", entry); - if ((entry.status & 1) == 1) == self.phase { - self.head = (self.head + 1) % (self.data.len() as u16); + if ((dbg!(entry.status) & 1) == 1) == dbg!(self.phase) { + self.head = dbg!(self.head + 1) % dbg!(self.data.len() as u16); if self.head == 0 { self.phase = !self.phase; } @@ -108,13 +109,13 @@ impl NvmeCmdQueue { self.head == self.tail } pub fn is_full(&self) -> bool { - self.head + 1 == self.tail + self.head == self.tail + 1 } /// Add a new submission command entry to the queue. The caller must ensure that the queue have free /// entries; this can be checked using `is_full`. pub fn submit_unchecked(&mut self, entry: NvmeCmd) -> u16 { - self.data[self.tail as usize] = entry; + unsafe { ptr::write_volatile(&mut self.data[self.tail as usize] as *mut _, entry) } self.tail = (self.tail + 1) % (self.data.len() as u16); self.tail } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 66faca6e95..f56aacaf4e 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -40,14 +40,15 @@ async fn handle_packet(hci: Arc, packet: Packet) -> Packet { fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() - .with_output( + /*.with_output( OutputBuilder::stderr() .with_filter(log::LevelFilter::Info) // limit global output to important info .with_ansi_escape_codes() .flush_on_newline(true) .build() - ); + )*/; + #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("usb", "host", "xhci.log") { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this @@ -58,6 +59,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { Err(error) => eprintln!("Failed to create xhci.log: {}", error), } + #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("usb", "host", "xhci.ansi.log") { Ok(b) => logger = logger.with_output( b.with_filter(log::LevelFilter::Trace) @@ -221,7 +223,7 @@ fn main() { (None, InterruptMethod::Polling) }; - std::thread::sleep(std::time::Duration::from_millis(300)); + //std::thread::sleep(std::time::Duration::from_millis(300)); print!( "{}", From 938cce8c8c68d7222f242309f79dffc54ee2e774 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 3 May 2020 16:02:23 +0200 Subject: [PATCH 0413/1301] make qemu_nvme works! only cleanup left... --- nvmed/src/nvme/identify.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/nvmed/src/nvme/identify.rs b/nvmed/src/nvme/identify.rs index 8dff534a27..e5c5db5a53 100644 --- a/nvmed/src/nvme/identify.rs +++ b/nvmed/src/nvme/identify.rs @@ -37,32 +37,36 @@ pub struct IdentifyNamespaceData { pub dps: u8, pub nmic: u8, pub rescap: u8, - + // 32 pub fpi: u8, pub dlfeat: u8, pub nawun: u16, pub nawupf: u16, pub nacwu: u16, + // 40 pub nabsn: u16, pub nabo: u16, pub nabspf: u16, pub noiob: u16, - - pub nvmcap: u64, + // 48 + pub nvmcap: u128, + // 64 pub npwg: u16, pub npwa: u16, pub npdg: u16, pub npda: u16, - + // 72 pub nows: u16, pub _rsvd1: [u8; 18], + // 92 pub anagrpid: u32, pub _rsvd2: [u8; 3], pub nsattr: u8, + // 100 pub nvmsetid: u16, pub endgid: u16, pub nguid: [u8; 16], From 07b1fe79fab367f05991428914e38af04c37d710 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 3 May 2020 16:33:56 +0200 Subject: [PATCH 0414/1301] Cleanup, and remove trace log writes for nvmed. --- nvmed/src/main.rs | 15 +++------------ nvmed/src/nvme/cq_reactor.rs | 1 - nvmed/src/nvme/queues.rs | 6 ++---- xhcid/src/main.rs | 6 ++---- xhcid/src/xhci/irq_reactor.rs | 3 +-- 5 files changed, 8 insertions(+), 23 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 2eb7eec7a2..dc5585c37d 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -215,14 +215,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Trace) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ) - .with_output( - OutputBuilder::with_endpoint(File::open("debug:").unwrap()) - .with_filter(log::LevelFilter::Trace) + .with_filter(log::LevelFilter::Info) // limit global output to important info .with_ansi_escape_codes() .flush_on_newline(true) .build() @@ -232,7 +225,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "nvme.log") { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Trace) + b.with_filter(log::LevelFilter::Info) .flush_on_newline(true) .build() ), @@ -242,7 +235,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "nvme.ansi.log") { Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Trace) + b.with_filter(log::LevelFilter::Info) .with_ansi_escape_codes() .flush_on_newline(true) .build() @@ -324,8 +317,6 @@ fn main() { ) .expect("nvmed: failed to watch disk scheme events"); - std::thread::sleep(std::time::Duration::from_millis(1000)); - let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); diff --git a/nvmed/src/nvme/cq_reactor.rs b/nvmed/src/nvme/cq_reactor.rs index f78547bb4b..d327e7056e 100644 --- a/nvmed/src/nvme/cq_reactor.rs +++ b/nvmed/src/nvme/cq_reactor.rs @@ -355,7 +355,6 @@ where sq_id, nvme, } => { - println!("{:p}", &mut nvme.completion_queues.read().unwrap().get(&cq_id).unwrap().lock().unwrap().0); if let Some(value) = message.lock().unwrap().take() { *this = CompletionFutureState::Finished; return task::Poll::Ready(value.cq_entry); diff --git a/nvmed/src/nvme/queues.rs b/nvmed/src/nvme/queues.rs index f6fe72a279..bfc68b1d9f 100644 --- a/nvmed/src/nvme/queues.rs +++ b/nvmed/src/nvme/queues.rs @@ -63,11 +63,9 @@ impl NvmeCompQueue { /// Get a new completion queue entry, or return None if no entry is available yet. pub(crate) fn complete(&mut self) -> Option<(u16, NvmeComp)> { - println!("PTR: {:p}", &*self as *const _); let entry = unsafe { ptr::read_volatile(self.data.as_ptr().add(self.head as usize)) }; - // println!("{:?}", entry); - if ((dbg!(entry.status) & 1) == 1) == dbg!(self.phase) { - self.head = dbg!(self.head + 1) % dbg!(self.data.len() as u16); + if ((entry.status & 1) == 1) == self.phase { + self.head = (self.head + 1) % (self.data.len() as u16); if self.head == 0 { self.phase = !self.phase; } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index f56aacaf4e..db0df15acb 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -40,13 +40,13 @@ async fn handle_packet(hci: Arc, packet: Packet) -> Packet { fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() - /*.with_output( + .with_output( OutputBuilder::stderr() .with_filter(log::LevelFilter::Info) // limit global output to important info .with_ansi_escape_codes() .flush_on_newline(true) .build() - )*/; + ); #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("usb", "host", "xhci.log") { @@ -223,8 +223,6 @@ fn main() { (None, InterruptMethod::Polling) }; - //std::thread::sleep(std::time::Duration::from_millis(300)); - print!( "{}", format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 581e2214d2..2b80883c29 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -212,7 +212,7 @@ impl IrqReactor { if index >= self.states.len() { break } match self.states[index].kind { - StateKind::CommandCompletion { phys_ptr } if dbg!(trb.trb_type()) == TrbType::CommandCompletion as u8 => if dbg!(trb.completion_trb_pointer()) == Some(phys_ptr) { + StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => if trb.completion_trb_pointer() == Some(phys_ptr) { trace!("Found matching command completion future"); let state = self.states.remove(index); @@ -430,7 +430,6 @@ impl Xhci { if ! trb.is_command_trb() { panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb) } - dbg!(command_ring.trbs.physical()); EventTrbFuture::Pending { state: FutureState { // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). From f149620e5ad46233f0eec93e713deeec67646d83 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 20 May 2020 19:49:05 +0200 Subject: [PATCH 0415/1301] Revert "Enable ahcid interrupts" This reverts commit f00a049439483e6b87189ec500587646a70c032b. --- ahcid/src/ahci/disk_ata.rs | 2 +- ahcid/src/ahci/hba.rs | 2 +- ahcid/src/scheme.rs | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index 30c4de7e9d..03d51d838f 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -68,7 +68,7 @@ impl DiskATA { }; //TODO: Go back to interrupt magic - let use_interrupts = true; + let use_interrupts = false; loop { let mut request = match self.request_opt.take() { Some(request) => if address == request.address && total_sectors == request.total_sectors { diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index d0318e54cc..86764ec767 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -116,7 +116,7 @@ impl HbaPort { self.fb[1].write((fb.physical() >> 32) as u32); let is = self.is.read(); self.is.write(is); - self.ie.write(0b10111); + self.ie.write(0 /*TODO: Enable interrupts: 0b10111*/); let serr = self.serr.read(); self.serr.write(serr); diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 0d1f3d9e00..48d0721d61 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -136,7 +136,6 @@ impl DiskScheme { if pi_is & 1 << i > 0 { let port = &mut self.hba_mem.ports[i]; let is = port.is.read(); - //TODO: Handle requests for only this port here port.is.write(is); } } From 146265682ab13fb666d27170a9f9394b571f705e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4ldo2@protonmail.com> Date: Thu, 21 May 2020 12:16:22 +0000 Subject: [PATCH 0416/1301] Improved PCI capability parsing. --- pcid/src/main.rs | 11 ++++--- pcid/src/pci/cap.rs | 68 +++++++++++++++++++++++++++++++++++++----- pcid/src/pci/header.rs | 8 ++++- 3 files changed, 74 insertions(+), 13 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index fa34f78314..1fd195b62f 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -304,17 +304,18 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, // Set IRQ line to 9 if not set let mut irq; + let mut interrupt_pin; + unsafe { let mut data = pci.read(bus_num, dev_num, func_num, 0x3C); irq = (data & 0xFF) as u8; + interrupt_pin = ((data & 0x0000_FF00) >> 8) as u8; if irq == 0xFF { irq = 9; } data = (data & 0xFFFFFF00) | irq as u32; pci.write(bus_num, dev_num, func_num, 0x3C, data); - } - - let interrupt_pin = unsafe { pci.read(bus_num, dev_num, func_num, 0x3B) }; + }; // Find BAR sizes let mut bars = [PciBar::None; 6]; @@ -352,7 +353,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, } } - let capabilities = { + let capabilities = if header.status() & (1 << 4) != 0 { let bus = PciBus { pci: state.preferred_cfg_access(), num: bus_num, @@ -366,6 +367,8 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, num: func_num, }; crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() + } else { + Vec::new() }; info!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 15e2077305..8d5682079d 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -21,7 +21,8 @@ where fn next(&mut self) -> Option { unsafe { - assert_eq!(self.offset & 0xF8, self.offset, "capability must be dword aligned"); + // mask RsvdP bits + self.offset = self.offset & 0xFC; if self.offset == 0 { return None }; @@ -38,10 +39,14 @@ where #[repr(u8)] pub enum CapabilityId { - Msi = 0x05, - MsiX = 0x11, - Pcie = 0x10, - Sata = 0x12, // only on AHCI functions + PwrMgmt = 0x01, + Msi = 0x05, + MsiX = 0x11, + Pcie = 0x10, + + // function specific + + Sata = 0x12, // only on AHCI functions } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] @@ -77,6 +82,27 @@ pub enum MsiCapability { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub struct PcieCapability { + pub pcie_caps: u32, + pub dev_caps: u32, + pub dev_sts_ctl: u32, + pub link_caps: u32, + pub link_sts_ctl: u32, + pub slot_caps: u32, + pub slot_sts_ctl: u32, + pub root_cap_ctl: u32, + pub root_sts: u32, + pub dev_caps2: u32, + pub dev_sts_ctl2: u32, + pub link_caps2: u32, + pub link_sts_ctl2: u32, + pub slot_caps2: u32, + pub slot_sts_ctl2: u32, +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct PwrMgmtCapability { + pub a: u32, + pub b: u32, } #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] @@ -91,6 +117,7 @@ pub enum Capability { Msi(MsiCapability), MsiX(MsixCapability), Pcie(PcieCapability), + PwrMgmt(PwrMgmtCapability), FunctionSpecific(u8, Vec), // TODO: Arrayvec Other(u8), } @@ -142,9 +169,32 @@ impl Capability { c: reader.read_u32(u16::from(offset + 8)), }) } + unsafe fn parse_pwr(reader: &R, offset: u8) -> Self { + Self::PwrMgmt(PwrMgmtCapability { + a: reader.read_u32(u16::from(offset)), + b: reader.read_u32(u16::from(offset + 4)), + }) + } unsafe fn parse_pcie(reader: &R, offset: u8) -> Self { - // TODO - Self::Pcie(PcieCapability {}) + let offset = u16::from(offset); + + Self::Pcie(PcieCapability { + pcie_caps: reader.read_u32(offset), + dev_caps: reader.read_u32(offset + 0x04), + dev_sts_ctl: reader.read_u32(offset + 0x08), + link_caps: reader.read_u32(offset + 0x0C), + link_sts_ctl: reader.read_u32(offset + 0x10), + slot_caps: reader.read_u32(offset + 0x14), + slot_sts_ctl: reader.read_u32(offset + 0x18), + root_cap_ctl: reader.read_u32(offset + 0x1C), + root_sts: reader.read_u32(offset + 0x20), + dev_caps2: reader.read_u32(offset + 0x24), + dev_sts_ctl2: reader.read_u32(offset + 0x28), + link_caps2: reader.read_u32(offset + 0x2C), + link_sts_ctl2: reader.read_u32(offset + 0x30), + slot_caps2: reader.read_u32(offset + 0x34), + slot_sts_ctl2: reader.read_u32(offset + 0x38), + }) } unsafe fn parse(reader: &R, offset: u8) -> Self { assert_eq!(offset & 0xF8, offset, "capability must be dword aligned"); @@ -158,11 +208,13 @@ impl Capability { Self::parse_msix(reader, offset) } else if capability_id == CapabilityId::Pcie as u8 { Self::parse_pcie(reader, offset) + } else if capability_id == CapabilityId::PwrMgmt as u8{ + Self::parse_pwr(reader, offset) } else if capability_id == CapabilityId::Sata as u8 { Self::FunctionSpecific(capability_id, reader.read_range(offset.into(), 8)) } else { + log::warn!("unimplemented or malformed capability id: {}", capability_id); Self::Other(capability_id) - //panic!("unimplemented or malformed capability id: {}", capability_id) } } } diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index 0d8513bb82..14d2a7b6ee 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -264,6 +264,12 @@ impl PciHeader { } } + pub fn status(&self) -> u16 { + match self { + &PciHeader::General { status, .. } | &PciHeader::PciToPci { status, .. } => status, + } + } + pub fn cap_pointer(&self) -> u8 { match self { &PciHeader::General { cap_pointer, .. } | &PciHeader::PciToPci { cap_pointer, .. } => cap_pointer, @@ -273,7 +279,7 @@ impl PciHeader { #[cfg(test)] impl<'a> ConfigReader for &'a [u8] { - unsafe fn read_u32(&self, offset: u8) -> u32 { + unsafe fn read_u32(&self, offset: u16) -> u32 { let offset = offset as usize; assert!(offset < self.len()); LittleEndian::read_u32(&self[offset..offset + 4]) From f3a35af0de8303bb7d2efce5510e2a65b0fde40b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 22 May 2020 09:05:22 -0600 Subject: [PATCH 0417/1301] Move ixgbed in-tree --- .gitmodules | 3 - ixgbed | 1 - ixgbed/Cargo.toml | 9 + ixgbed/LICENSE | 661 +++++++++++++++++++++++++++++++++++++++++++ ixgbed/README.md | 37 +++ ixgbed/config.toml | 6 + ixgbed/src/device.rs | 642 +++++++++++++++++++++++++++++++++++++++++ ixgbed/src/ixgbe.rs | 314 ++++++++++++++++++++ ixgbed/src/main.rs | 203 +++++++++++++ 9 files changed, 1872 insertions(+), 4 deletions(-) delete mode 160000 ixgbed create mode 100644 ixgbed/Cargo.toml create mode 100644 ixgbed/LICENSE create mode 100644 ixgbed/README.md create mode 100644 ixgbed/config.toml create mode 100644 ixgbed/src/device.rs create mode 100644 ixgbed/src/ixgbe.rs create mode 100644 ixgbed/src/main.rs diff --git a/.gitmodules b/.gitmodules index 73ccf1a62a..e69de29bb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "ixgbed"] - path = ixgbed - url = https://github.com/ackxolotl/ixgbed.git diff --git a/ixgbed b/ixgbed deleted file mode 160000 index 97a1efdd22..0000000000 --- a/ixgbed +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 97a1efdd22800be67b6781beecde956927e3975b diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml new file mode 100644 index 0000000000..1ac5938b16 --- /dev/null +++ b/ixgbed/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ixgbed" +version = "1.0.0" + +[dependencies] +bitflags = "1.0" +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox_syscall = "0.1.54" diff --git a/ixgbed/LICENSE b/ixgbed/LICENSE new file mode 100644 index 0000000000..0ad25db4bd --- /dev/null +++ b/ixgbed/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/ixgbed/README.md b/ixgbed/README.md new file mode 100644 index 0000000000..abcd4a2f83 --- /dev/null +++ b/ixgbed/README.md @@ -0,0 +1,37 @@ +# ixgbed (a.k.a. ixy.rs on Redox) + +ixgbed is the Redox port of [ixy.rs](https://github.com/ixy-languages/ixy.rs), a Rust rewrite of the [ixy](https://github.com/emmericp/ixy) userspace network driver. +It is designed to be readable, idiomatic Rust code. +It supports Intel 82599 10GbE NICs (`ixgbe` family). + +## Features + +* first 10 Gbit/s network driver on Redox +* transmitting 250 times faster than e1000 / rtl8168 driver +* MSI-X interrupts (not supported by Redox yet) +* less than 1000 lines of code for the driver +* documented code + +## Build instructions + +See the [Redox README](https://gitlab.redox-os.org/redox-os/redox/blob/master/README.md) for build instructions. + +To run ixgbed on Redox (in case the driver is not shipped with Redox anymore) + +* clone this project into `cookbook/recipes/drivers/source/` +* create an entry for ixgbed in `cookbook/recipes/drivers/source/Cargo.toml` +* check if your ixgbe device is included in `config.toml` +* touch `filesystem.toml` in Redox's root directory, build Redox and run it + +## Usage + +To test the driver's transmit and forwarding capabilities, have a look at [rheinfall](https://github.com/ackxolotl/rheinfall), a simple packet generator / forwarder application. + +## Docs + +ixgbed contains documentation that can be created and viewed by running + +``` +cargo doc --open +``` + diff --git a/ixgbed/config.toml b/ixgbed/config.toml new file mode 100644 index 0000000000..db2d47838a --- /dev/null +++ b/ixgbed/config.toml @@ -0,0 +1,6 @@ +[[drivers]] +name = "Intel 10G NIC" +class = 2 +ids = { 0x8086 = [0x10F7, 0x1514, 0x1517, 0x151C, 0x10F9, 0x10FB, 0x152a, 0x1529, 0x1507, 0x154D, 0x1557, 0x10FC, 0x10F8, 0x154F, 0x1528, 0x154A, 0x1558, 0x1560, 0x1563, 0x15D1, 0x15AA, 0x15AB, 0x15AC, 0x15AD, 0x15AE, 0x15B0, 0x15C2, 0x15C3, 0x15C4, 0x15C6, 0x15C7, 0x15C8, 0x15CE, 0x15E4, 0x15E5, 0x10ED, 0x1515, 0x1565, 0x15A8, 0x15C5] } +command = ["ixgbed", "$NAME", "$BAR0", "$IRQ"] + diff --git a/ixgbed/src/device.rs b/ixgbed/src/device.rs new file mode 100644 index 0000000000..0f532129ec --- /dev/null +++ b/ixgbed/src/device.rs @@ -0,0 +1,642 @@ +use std::collections::BTreeMap; +use std::time::{Duration, Instant}; +use std::{cmp, mem, ptr, slice, thread}; + +use netutils::setcfg; +use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; +use syscall::flag::O_NONBLOCK; +use syscall::io::Dma; +use syscall::scheme::SchemeBlockMut; + +use ixgbe::*; + +pub struct Intel8259x { + base: usize, + size: usize, + receive_buffer: [Dma<[u8; 16384]>; 32], + receive_ring: Dma<[ixgbe_adv_rx_desc; 32]>, + receive_index: usize, + transmit_buffer: [Dma<[u8; 16384]>; 32], + transmit_ring: Dma<[ixgbe_adv_tx_desc; 32]>, + transmit_ring_free: usize, + transmit_index: usize, + transmit_clean_index: usize, + next_id: usize, + pub handles: BTreeMap, +} + +fn wrap_ring(index: usize, ring_size: usize) -> usize { + (index + 1) & (ring_size - 1) +} + +impl SchemeBlockMut for Intel8259x { + fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { + if uid == 0 { + self.next_id += 1; + self.handles.insert(self.next_id, flags); + Ok(Some(self.next_id)) + } else { + Err(Error::new(EACCES)) + } + } + + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { + if !buf.is_empty() { + return Err(Error::new(EINVAL)); + } + + let flags = { + let flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; + *flags + }; + self.next_id += 1; + self.handles.insert(self.next_id, flags); + Ok(Some(self.next_id)) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; + + let desc = unsafe { + &mut *(self.receive_ring.as_ptr().add(self.receive_index) as *mut ixgbe_adv_rx_desc) + }; + + let status = unsafe { desc.wb.upper.status_error }; + + if (status & IXGBE_RXDADV_STAT_DD) != 0 { + if (status & IXGBE_RXDADV_STAT_EOP) == 0 { + panic!("increase buffer size or decrease MTU") + } + + let data = unsafe { + &self.receive_buffer[self.receive_index][..desc.wb.upper.length as usize] + }; + + let i = cmp::min(buf.len(), data.len()); + buf[..i].copy_from_slice(&data[..i]); + + unsafe { + desc.read.pkt_addr = self.receive_buffer[self.receive_index].physical() as u64; + desc.read.hdr_addr = 0; + } + + self.write_reg(IXGBE_RDT(0), self.receive_index as u32); + self.receive_index = wrap_ring(self.receive_index, self.receive_ring.len()); + + return Ok(Some(i)); + } + + if flags & O_NONBLOCK == O_NONBLOCK { + Err(Error::new(EWOULDBLOCK)) + } else { + Ok(None) + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; + + if self.transmit_ring_free == 0 { + loop { + let desc = unsafe { + &*(self.transmit_ring.as_ptr().add(self.transmit_clean_index) + as *const ixgbe_adv_tx_desc) + }; + + if (unsafe { desc.wb.status } & IXGBE_ADVTXD_STAT_DD) != 0 { + self.transmit_clean_index = + wrap_ring(self.transmit_clean_index, self.transmit_ring.len()); + self.transmit_ring_free += 1; + } else if self.transmit_ring_free > 0 { + break; + } + + if self.transmit_ring_free >= self.transmit_ring.len() { + break; + } + } + } + + let desc = unsafe { + &mut *(self.transmit_ring.as_ptr().add(self.transmit_index) as *mut ixgbe_adv_tx_desc) + }; + + let data = unsafe { + slice::from_raw_parts_mut( + self.transmit_buffer[self.transmit_index].as_ptr() as *mut u8, + cmp::min(buf.len(), self.transmit_buffer[self.transmit_index].len()) as usize, + ) + }; + + let i = cmp::min(buf.len(), data.len()); + data[..i].copy_from_slice(&buf[..i]); + + unsafe { + desc.read.cmd_type_len = IXGBE_ADVTXD_DCMD_EOP + | IXGBE_ADVTXD_DCMD_RS + | IXGBE_ADVTXD_DCMD_IFCS + | IXGBE_ADVTXD_DCMD_DEXT + | IXGBE_ADVTXD_DTYP_DATA + | buf.len() as u32; + + desc.read.olinfo_status = (buf.len() as u32) << IXGBE_ADVTXD_PAYLEN_SHIFT; + } + + self.transmit_index = wrap_ring(self.transmit_index, self.transmit_ring.len()); + self.transmit_ring_free -= 1; + + self.write_reg(IXGBE_TDT(0), self.transmit_index as u32); + + Ok(Some(i)) + } + + fn fevent(&mut self, id: usize, _flags: usize) -> Result> { + let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; + Ok(Some(0)) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; + + let scheme_path = b"network:"; + let i = cmp::min(buf.len(), scheme_path.len()); + buf[..i].copy_from_slice(&scheme_path[..i]); + Ok(Some(i)) + } + + fn fsync(&mut self, id: usize) -> Result> { + let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; + Ok(Some(0)) + } + + fn close(&mut self, id: usize) -> Result> { + self.handles.remove(&id).ok_or_else(|| Error::new(EBADF))?; + Ok(Some(0)) + } +} + +impl Intel8259x { + /// Returns an initialized `Intel8259x` on success. + pub fn new(base: usize, size: usize) -> Result { + #[rustfmt::skip] + let mut module = Intel8259x { + base, + size, + receive_buffer: [ + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + ], + receive_ring: Dma::zeroed()?, + transmit_buffer: [ + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, + ], + receive_index: 0, + transmit_ring: Dma::zeroed()?, + transmit_ring_free: 32, + transmit_index: 0, + transmit_clean_index: 0, + next_id: 0, + handles: BTreeMap::new(), + }; + + module.init(); + + Ok(module) + } + + pub fn irq(&self) -> bool { + let icr = self.read_reg(IXGBE_EICR); + icr != 0 + } + + pub fn next_read(&self) -> usize { + let desc = unsafe { + &*(self.receive_ring.as_ptr().add(self.receive_index) as *const ixgbe_adv_rx_desc) + }; + + let status = unsafe { desc.wb.upper.status_error }; + + if (status & IXGBE_RXDADV_STAT_DD) != 0 { + if (status & IXGBE_RXDADV_STAT_EOP) == 0 { + panic!("increase buffer size or decrease MTU") + } + + return unsafe { desc.wb.upper.length as usize }; + } + + 0 + } + + /// Returns the mac address of this device. + pub fn get_mac_addr(&self) -> [u8; 6] { + let low = self.read_reg(IXGBE_RAL(0)); + let high = self.read_reg(IXGBE_RAH(0)); + + [ + (low & 0xff) as u8, + (low >> 8 & 0xff) as u8, + (low >> 16 & 0xff) as u8, + (low >> 24) as u8, + (high & 0xff) as u8, + (high >> 8 & 0xff) as u8, + ] + } + + /// Sets the mac address of this device. + #[allow(dead_code)] + pub fn set_mac_addr(&self, mac: [u8; 6]) { + let low: u32 = u32::from(mac[0]) + + (u32::from(mac[1]) << 8) + + (u32::from(mac[2]) << 16) + + (u32::from(mac[3]) << 24); + let high: u32 = u32::from(mac[4]) + (u32::from(mac[5]) << 8); + + self.write_reg(IXGBE_RAL(0), low); + self.write_reg(IXGBE_RAH(0), high); + } + + /// Returns the register at `self.base` + `register`. + /// + /// # Panics + /// + /// Panics if `self.base` + `register` does not belong to the mapped memory of the PCIe device. + fn read_reg(&self, register: u32) -> u32 { + assert!( + register as usize <= self.size - 4 as usize, + "MMIO access out of bounds" + ); + + unsafe { ptr::read_volatile((self.base + register as usize) as *mut u32) } + } + + /// Sets the register at `self.base` + `register`. + /// + /// # Panics + /// + /// Panics if `self.base` + `register` does not belong to the mapped memory of the PCIe device. + fn write_reg(&self, register: u32, data: u32) -> u32 { + assert!( + register as usize <= self.size - 4 as usize, + "MMIO access out of bounds" + ); + + unsafe { + ptr::write_volatile((self.base + register as usize) as *mut u32, data); + ptr::read_volatile((self.base + register as usize) as *mut u32) + } + } + + fn write_flag(&self, register: u32, flags: u32) { + self.write_reg(register, self.read_reg(register) | flags); + } + + fn clear_flag(&self, register: u32, flags: u32) { + self.write_reg(register, self.read_reg(register) & !flags); + } + + fn wait_clear_reg(&self, register: u32, value: u32) { + loop { + let current = self.read_reg(register); + if (current & value) == 0 { + break; + } + thread::sleep(Duration::from_millis(100)); + } + } + + fn wait_write_reg(&self, register: u32, value: u32) { + loop { + let current = self.read_reg(register); + if (current & value) == value { + break; + } + thread::sleep(Duration::from_millis(100)); + } + } + + /// Resets and initializes an ixgbe device. + fn init(&mut self) { + // section 4.6.3.1 - disable all interrupts + self.write_reg(IXGBE_EIMC, 0x7fff_ffff); + + // section 4.6.3.2 + self.write_reg(IXGBE_CTRL, IXGBE_CTRL_RST_MASK); + self.wait_clear_reg(IXGBE_CTRL, IXGBE_CTRL_RST_MASK); + thread::sleep(Duration::from_millis(10)); + + // section 4.6.3.1 - disable interrupts again after reset + self.write_reg(IXGBE_EIMC, 0x7fff_ffff); + + let mac = self.get_mac_addr(); + + println!( + " - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + ); + + let _ = setcfg( + "mac", + &format!( + "{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + ), + ); + + // section 4.6.3 - wait for EEPROM auto read completion + self.wait_write_reg(IXGBE_EEC, IXGBE_EEC_ARD); + + // section 4.6.3 - wait for dma initialization done + self.wait_write_reg(IXGBE_RDRXCTL, IXGBE_RDRXCTL_DMAIDONE); + + // section 4.6.4 - initialize link (auto negotiation) + self.init_link(); + + // section 4.6.5 - statistical counters + // reset-on-read registers, just read them once + self.reset_stats(); + + // section 4.6.7 - init rx + self.init_rx(); + + // section 4.6.8 - init tx + self.init_tx(); + + // start a single receive queue/ring + self.start_rx_queue(0); + + // start a single transmit queue/ring + self.start_tx_queue(0); + + // section 4.6.3.9 - enable interrupts + self.enable_msix_interrupt(0); + + // enable promisc mode by default to make testing easier + self.set_promisc(true); + + // wait some time for the link to come up + self.wait_for_link(); + } + + /// Resets the stats of this device. + fn reset_stats(&self) { + self.read_reg(IXGBE_GPRC); + self.read_reg(IXGBE_GPTC); + self.read_reg(IXGBE_GORCL); + self.read_reg(IXGBE_GORCH); + self.read_reg(IXGBE_GOTCL); + self.read_reg(IXGBE_GOTCH); + } + + // sections 4.6.7 + /// Initializes the rx queues of this device. + fn init_rx(&mut self) { + // disable rx while re-configuring it + self.clear_flag(IXGBE_RXCTRL, IXGBE_RXCTRL_RXEN); + + // section 4.6.11.3.4 - allocate all queues and traffic to PB0 + self.write_reg(IXGBE_RXPBSIZE(0), IXGBE_RXPBSIZE_128KB); + for i in 1..8 { + self.write_reg(IXGBE_RXPBSIZE(i), 0); + } + + // enable CRC offloading + self.write_flag(IXGBE_HLREG0, IXGBE_HLREG0_RXCRCSTRP); + self.write_flag(IXGBE_RDRXCTL, IXGBE_RDRXCTL_CRCSTRIP); + + // accept broadcast packets + self.write_flag(IXGBE_FCTRL, IXGBE_FCTRL_BAM); + + // configure a single receive queue/ring + let i: u32 = 0; + + // enable advanced rx descriptors + self.write_reg( + IXGBE_SRRCTL(i), + (self.read_reg(IXGBE_SRRCTL(i)) & !IXGBE_SRRCTL_DESCTYPE_MASK) + | IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF, + ); + // let nic drop packets if no rx descriptor is available instead of buffering them + self.write_flag(IXGBE_SRRCTL(i), IXGBE_SRRCTL_DROP_EN); + + self.write_reg(IXGBE_RDBAL(i), self.receive_ring.physical() as u32); + + self.write_reg(IXGBE_RDBAH(i), (self.receive_ring.physical() >> 32) as u32); + self.write_reg( + IXGBE_RDLEN(i), + (self.receive_ring.len() * mem::size_of::()) as u32, + ); + + // set ring to empty at start + self.write_reg(IXGBE_RDH(i), 0); + self.write_reg(IXGBE_RDT(i), 0); + + // last sentence of section 4.6.7 - set some magic bits + self.write_flag(IXGBE_CTRL_EXT, IXGBE_CTRL_EXT_NS_DIS); + + // probably a broken feature, this flag is initialized with 1 but has to be set to 0 + self.clear_flag(IXGBE_DCA_RXCTRL(i), 1 << 12); + + // start rx + self.write_flag(IXGBE_RXCTRL, IXGBE_RXCTRL_RXEN); + } + + // section 4.6.8 + /// Initializes the tx queues of this device. + fn init_tx(&mut self) { + // crc offload and small packet padding + self.write_flag(IXGBE_HLREG0, IXGBE_HLREG0_TXCRCEN | IXGBE_HLREG0_TXPADEN); + + // section 4.6.11.3.4 - set default buffer size allocations + self.write_reg(IXGBE_TXPBSIZE(0), IXGBE_TXPBSIZE_40KB); + for i in 1..8 { + self.write_reg(IXGBE_TXPBSIZE(i), 0); + } + + // required when not using DCB/VTd + self.write_reg(IXGBE_DTXMXSZRQ, 0xffff); + self.clear_flag(IXGBE_RTTDCS, IXGBE_RTTDCS_ARBDIS); + + // configure a single transmit queue/ring + let i: u32 = 0; + + // section 7.1.9 - setup descriptor ring + + self.write_reg(IXGBE_TDBAL(i), self.transmit_ring.physical() as u32); + self.write_reg(IXGBE_TDBAH(i), (self.transmit_ring.physical() >> 32) as u32); + self.write_reg( + IXGBE_TDLEN(i), + (self.transmit_ring.len() * mem::size_of::()) as u32, + ); + + // descriptor writeback magic values, important to get good performance and low PCIe overhead + // see 7.2.3.4.1 and 7.2.3.5 for an explanation of these values and how to find good ones + // we just use the defaults from DPDK here, but this is a potentially interesting point for optimizations + let mut txdctl = self.read_reg(IXGBE_TXDCTL(i)); + // there are no defines for this in ixgbe.rs for some reason + // pthresh: 6:0, hthresh: 14:8, wthresh: 22:16 + txdctl &= !(0x3F | (0x3F << 8) | (0x3F << 16)); + txdctl |= 36 | (8 << 8) | (4 << 16); + + self.write_reg(IXGBE_TXDCTL(i), txdctl); + + // final step: enable DMA + self.write_reg(IXGBE_DMATXCTL, IXGBE_DMATXCTL_TE); + } + + /// Sets the rx queues` descriptors and enables the queues. + /// + /// # Panics + /// Panics if length of `self.receive_ring` is not a power of 2. + fn start_rx_queue(&mut self, queue_id: u16) { + if self.receive_ring.len() & (self.receive_ring.len() - 1) != 0 { + panic!("number of receive queue entries must be a power of 2"); + } + + for i in 0..self.receive_ring.len() { + unsafe { + self.receive_ring[i].read.pkt_addr = self.receive_buffer[i].physical() as u64; + self.receive_ring[i].read.hdr_addr = 0; + } + } + + // enable queue and wait if necessary + self.write_flag(IXGBE_RXDCTL(u32::from(queue_id)), IXGBE_RXDCTL_ENABLE); + self.wait_write_reg(IXGBE_RXDCTL(u32::from(queue_id)), IXGBE_RXDCTL_ENABLE); + + // rx queue starts out full + self.write_reg(IXGBE_RDH(u32::from(queue_id)), 0); + + // was set to 0 before in the init function + self.write_reg( + IXGBE_RDT(u32::from(queue_id)), + (self.receive_ring.len() - 1) as u32, + ); + } + + /// Enables the tx queues. + /// + /// # Panics + /// Panics if length of `self.transmit_ring` is not a power of 2. + fn start_tx_queue(&mut self, queue_id: u16) { + if self.transmit_ring.len() & (self.transmit_ring.len() - 1) != 0 { + panic!("number of receive queue entries must be a power of 2"); + } + + for i in 0..self.transmit_ring.len() { + unsafe { + self.transmit_ring[i].read.buffer_addr = self.transmit_buffer[i].physical() as u64; + } + } + + // tx queue starts out empty + self.write_reg(IXGBE_TDH(u32::from(queue_id)), 0); + self.write_reg(IXGBE_TDT(u32::from(queue_id)), 0); + + // enable queue and wait if necessary + self.write_flag(IXGBE_TXDCTL(u32::from(queue_id)), IXGBE_TXDCTL_ENABLE); + self.wait_write_reg(IXGBE_TXDCTL(u32::from(queue_id)), IXGBE_TXDCTL_ENABLE); + } + + // see section 4.6.4 + /// Initializes the link of this device. + fn init_link(&self) { + // link auto-configuration register should already be set correctly, we're resetting it anyway + self.write_reg( + IXGBE_AUTOC, + (self.read_reg(IXGBE_AUTOC) & !IXGBE_AUTOC_LMS_MASK) | IXGBE_AUTOC_LMS_10G_SERIAL, + ); + self.write_reg( + IXGBE_AUTOC, + (self.read_reg(IXGBE_AUTOC) & !IXGBE_AUTOC_10G_PMA_PMD_MASK) | IXGBE_AUTOC_10G_XAUI, + ); + // negotiate link + self.write_flag(IXGBE_AUTOC, IXGBE_AUTOC_AN_RESTART); + // datasheet wants us to wait for the link here, but we can continue and wait afterwards + } + + /// Waits for the link to come up. + fn wait_for_link(&self) { + println!(" - waiting for link"); + let time = Instant::now(); + let mut speed = self.get_link_speed(); + while speed == 0 && time.elapsed().as_secs() < 10 { + thread::sleep(Duration::from_millis(100)); + speed = self.get_link_speed(); + } + println!(" - link speed is {} Mbit/s", self.get_link_speed()); + } + + /// Enables or disables promisc mode of this device. + fn set_promisc(&self, enabled: bool) { + if enabled { + self.write_flag(IXGBE_FCTRL, IXGBE_FCTRL_MPE | IXGBE_FCTRL_UPE); + } else { + self.clear_flag(IXGBE_FCTRL, IXGBE_FCTRL_MPE | IXGBE_FCTRL_UPE); + } + } + + /// Set the IVAR registers, mapping interrupt causes to vectors. + fn set_ivar(&mut self, direction: i8, queue_id: u16, mut msix_vector: u8) { + let index = ((16 * (queue_id & 1)) as i16 + i16::from(8 * direction)) as u32; + + msix_vector |= IXGBE_IVAR_ALLOC_VAL as u8; + + let mut ivar = self.read_reg(IXGBE_IVAR(u32::from(queue_id >> 1))); + ivar &= !(0xFF << index); + ivar |= u32::from(msix_vector << index); + + self.write_reg(IXGBE_IVAR(u32::from(queue_id >> 1)), ivar); + } + + /// Enable MSI-X interrupt for a queue. + fn enable_msix_interrupt(&mut self, queue_id: u16) { + // Step 1: The software driver associates between interrupt causes and MSI-X vectors and the + //throttling timers EITR[n] by programming the IVAR[n] and IVAR_MISC registers. + self.set_ivar(0, queue_id, queue_id as u8); + + // Step 2: Program SRRCTL[n].RDMTS (per receive queue) if software uses the receive + // descriptor minimum threshold interrupt + + // Step 3: The EIAC[n] registers should be set to auto clear for transmit and receive interrupt + // causes (for best performance). The EIAC bits that control the other and TCP timer + // interrupt causes should be set to 0b (no auto clear). + self.write_reg(IXGBE_EIAC, IXGBE_EICR_RTX_QUEUE); + + // Step 4: Set the auto mask in the EIAM register according to the preferred mode of operation. + + // Step 5: Set the interrupt throttling in EITR[n] and GPIE according to the preferred mode of operation. + + // Step 6: Software enables the required interrupt causes by setting the EIMS register + let mut mask: u32 = self.read_reg(IXGBE_EIMS); + mask |= 1 << queue_id; + + self.write_reg(IXGBE_EIMS, mask); + } + + /// Returns the link speed of this device. + fn get_link_speed(&self) -> u16 { + let speed = self.read_reg(IXGBE_LINKS); + if (speed & IXGBE_LINKS_UP) == 0 { + return 0; + } + match speed & IXGBE_LINKS_SPEED_82599 { + IXGBE_LINKS_SPEED_100_82599 => 100, + IXGBE_LINKS_SPEED_1G_82599 => 1000, + IXGBE_LINKS_SPEED_10G_82599 => 10000, + _ => 0, + } + } +} diff --git a/ixgbed/src/ixgbe.rs b/ixgbed/src/ixgbe.rs new file mode 100644 index 0000000000..c86d9d827b --- /dev/null +++ b/ixgbed/src/ixgbe.rs @@ -0,0 +1,314 @@ +#![allow(non_snake_case)] +#![allow(non_camel_case_types)] +#![allow(non_upper_case_globals)] +#![allow(clippy::unreadable_literal)] + +pub const IXGBE_EIMC: u32 = 0x00888; + +pub const IXGBE_CTRL: u32 = 0x00000; +pub const IXGBE_CTRL_LNK_RST: u32 = 0x00000008; /* Link Reset. Resets everything. */ +pub const IXGBE_CTRL_RST: u32 = 0x04000000; /* Reset (SW) */ +pub const IXGBE_CTRL_RST_MASK: u32 = (IXGBE_CTRL_LNK_RST | IXGBE_CTRL_RST); + +pub const IXGBE_EEC: u32 = 0x10010; +pub const IXGBE_EEC_ARD: u32 = 0x00000200; /* EEPROM Auto Read Done */ + +pub const IXGBE_RDRXCTL: u32 = 0x02F00; +pub const IXGBE_RDRXCTL_DMAIDONE: u32 = 0x00000008; /* DMA init cycle done */ + +pub const IXGBE_AUTOC: u32 = 0x042A0; +pub const IXGBE_AUTOC_LMS_SHIFT: u32 = 13; +pub const IXGBE_AUTOC_LMS_MASK: u32 = (0x7 << IXGBE_AUTOC_LMS_SHIFT); +pub const IXGBE_AUTOC_LMS_10G_SERIAL: u32 = (0x3 << IXGBE_AUTOC_LMS_SHIFT); +pub const IXGBE_AUTOC_10G_PMA_PMD_MASK: u32 = 0x00000180; +pub const IXGBE_AUTOC_10G_PMA_PMD_SHIFT: u32 = 7; +pub const IXGBE_AUTOC_10G_XAUI: u32 = (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT); +pub const IXGBE_AUTOC_AN_RESTART: u32 = 0x00001000; + +pub const IXGBE_GPRC: u32 = 0x04074; +pub const IXGBE_GPTC: u32 = 0x04080; +pub const IXGBE_GORCL: u32 = 0x04088; +pub const IXGBE_GORCH: u32 = 0x0408C; +pub const IXGBE_GOTCL: u32 = 0x04090; +pub const IXGBE_GOTCH: u32 = 0x04094; + +pub const IXGBE_RXCTRL: u32 = 0x03000; +pub const IXGBE_RXCTRL_RXEN: u32 = 0x00000001; /* Enable Receiver */ + +pub fn IXGBE_RXPBSIZE(i: u32) -> u32 { + (0x03C00 + (i * 4)) +} + +pub const IXGBE_RXPBSIZE_128KB: u32 = 0x00020000; /* 128KB Packet Buffer */ +pub const IXGBE_HLREG0: u32 = 0x04240; +pub const IXGBE_HLREG0_RXCRCSTRP: u32 = 0x00000002; /* bit 1 */ +pub const IXGBE_RDRXCTL_CRCSTRIP: u32 = 0x00000002; /* CRC Strip */ + +pub const IXGBE_FCTRL: u32 = 0x05080; +pub const IXGBE_FCTRL_BAM: u32 = 0x00000400; /* Broadcast Accept Mode */ + +pub fn IXGBE_SRRCTL(i: u32) -> u32 { + if i <= 15 { + 0x02100 + (i * 4) + } else if i < 64 { + 0x01014 + (i * 0x40) + } else { + 0x0D014 + ((i - 64) * 0x40) + } +} + +pub const IXGBE_SRRCTL_DESCTYPE_MASK: u32 = 0x0E000000; +pub const IXGBE_SRRCTL_DESCTYPE_ADV_ONEBUF: u32 = 0x02000000; +pub const IXGBE_SRRCTL_DROP_EN: u32 = 0x10000000; + +pub fn IXGBE_RDBAL(i: u32) -> u32 { + if i < 64 { + 0x01000 + (i * 0x40) + } else { + 0x0D000 + ((i - 64) * 0x40) + } +} +pub fn IXGBE_RDBAH(i: u32) -> u32 { + if i < 64 { + 0x01004 + (i * 0x40) + } else { + 0x0D004 + ((i - 64) * 0x40) + } +} +pub fn IXGBE_RDLEN(i: u32) -> u32 { + if i < 64 { + 0x01008 + (i * 0x40) + } else { + 0x0D008 + ((i - 64) * 0x40) + } +} +pub fn IXGBE_RDH(i: u32) -> u32 { + if i < 64 { + 0x01010 + (i * 0x40) + } else { + 0x0D010 + ((i - 64) * 0x40) + } +} +pub fn IXGBE_RDT(i: u32) -> u32 { + if i < 64 { + 0x01018 + (i * 0x40) + } else { + 0x0D018 + ((i - 64) * 0x40) + } +} + +pub const IXGBE_CTRL_EXT: u32 = 0x00018; +pub const IXGBE_CTRL_EXT_NS_DIS: u32 = 0x00010000; /* No Snoop disable */ + +pub fn IXGBE_DCA_RXCTRL(i: u32) -> u32 { + if i <= 15 { + 0x02200 + (i * 4) + } else if i < 64 { + 0x0100C + (i * 0x40) + } else { + 0x0D00C + ((i - 64) * 0x40) + } +} + +pub const IXGBE_HLREG0_TXCRCEN: u32 = 0x00000001; /* bit 0 */ +pub const IXGBE_HLREG0_TXPADEN: u32 = 0x00000400; /* bit 10 */ + +pub fn IXGBE_TXPBSIZE(i: u32) -> u32 { + (0x0CC00 + (i * 4)) +} /* 8 of these */ + +pub const IXGBE_TXPBSIZE_40KB: u32 = 0x0000A000; /* 40KB Packet Buffer */ +pub const IXGBE_DTXMXSZRQ: u32 = 0x08100; +pub const IXGBE_RTTDCS: u32 = 0x04900; +pub const IXGBE_RTTDCS_ARBDIS: u32 = 0x00000040; /* DCB arbiter disable */ + +pub fn IXGBE_TDBAL(i: u32) -> u32 { + (0x06000 + (i * 0x40)) +} /* 32 of them (0-31)*/ +pub fn IXGBE_TDBAH(i: u32) -> u32 { + (0x06004 + (i * 0x40)) +} +pub fn IXGBE_TDLEN(i: u32) -> u32 { + (0x06008 + (i * 0x40)) +} +pub fn IXGBE_TXDCTL(i: u32) -> u32 { + (0x06028 + (i * 0x40)) +} + +pub const IXGBE_DMATXCTL: u32 = 0x04A80; +pub const IXGBE_DMATXCTL_TE: u32 = 0x1; /* Transmit Enable */ + +pub fn IXGBE_RXDCTL(i: u32) -> u32 { + if i < 64 { + 0x01028 + (i * 0x40) + } else { + 0x0D028 + ((i - 64) * 0x40) + } +} +pub const IXGBE_RXDCTL_ENABLE: u32 = 0x02000000; /* Ena specific Rx Queue */ +pub const IXGBE_TXDCTL_ENABLE: u32 = 0x02000000; /* Ena specific Tx Queue */ + +pub fn IXGBE_TDH(i: u32) -> u32 { + (0x06010 + (i * 0x40)) +} +pub fn IXGBE_TDT(i: u32) -> u32 { + (0x06018 + (i * 0x40)) +} + +pub const IXGBE_FCTRL_MPE: u32 = 0x00000100; /* Multicast Promiscuous Ena*/ +pub const IXGBE_FCTRL_UPE: u32 = 0x00000200; /* Unicast Promiscuous Ena */ + +pub const IXGBE_LINKS: u32 = 0x042A4; +pub const IXGBE_LINKS_UP: u32 = 0x40000000; +pub const IXGBE_LINKS_SPEED_82599: u32 = 0x30000000; +pub const IXGBE_LINKS_SPEED_100_82599: u32 = 0x10000000; +pub const IXGBE_LINKS_SPEED_1G_82599: u32 = 0x20000000; +pub const IXGBE_LINKS_SPEED_10G_82599: u32 = 0x30000000; + +pub fn IXGBE_RAL(i: u32) -> u32 { + if i <= 15 { + 0x05400 + (i * 8) + } else { + 0x0A200 + (i * 8) + } +} + +pub fn IXGBE_RAH(i: u32) -> u32 { + if i <= 15 { + 0x05404 + (i * 8) + } else { + 0x0A204 + (i * 8) + } +} + +pub const IXGBE_RXD_STAT_DD: u32 = 0x01; /* Descriptor Done */ +pub const IXGBE_RXD_STAT_EOP: u32 = 0x02; /* End of Packet */ +pub const IXGBE_RXDADV_STAT_DD: u32 = IXGBE_RXD_STAT_DD; /* Done */ +pub const IXGBE_RXDADV_STAT_EOP: u32 = IXGBE_RXD_STAT_EOP; /* End of Packet */ + +pub const IXGBE_ADVTXD_PAYLEN_SHIFT: u32 = 14; /* Adv desc PAYLEN shift */ +pub const IXGBE_TXD_CMD_EOP: u32 = 0x01000000; /* End of Packet */ +pub const IXGBE_ADVTXD_DCMD_EOP: u32 = IXGBE_TXD_CMD_EOP; /* End of Packet */ +pub const IXGBE_TXD_CMD_RS: u32 = 0x08000000; /* Report Status */ +pub const IXGBE_ADVTXD_DCMD_RS: u32 = IXGBE_TXD_CMD_RS; /* Report Status */ +pub const IXGBE_TXD_CMD_IFCS: u32 = 0x02000000; /* Insert FCS (Ethernet CRC) */ +pub const IXGBE_ADVTXD_DCMD_IFCS: u32 = IXGBE_TXD_CMD_IFCS; /* Insert FCS */ +pub const IXGBE_TXD_CMD_DEXT: u32 = 0x20000000; /* Desc extension (0 = legacy) */ +pub const IXGBE_ADVTXD_DTYP_DATA: u32 = 0x00300000; /* Adv Data Descriptor */ +pub const IXGBE_ADVTXD_DCMD_DEXT: u32 = IXGBE_TXD_CMD_DEXT; /* Desc ext 1=Adv */ +pub const IXGBE_TXD_STAT_DD: u32 = 0x00000001; /* Descriptor Done */ +pub const IXGBE_ADVTXD_STAT_DD: u32 = IXGBE_TXD_STAT_DD; /* Descriptor Done */ + +/* Interrupt Registers */ +pub const IXGBE_EICR: u32 = 0x00800; +pub const IXGBE_EIAC: u32 = 0x00810; +pub const IXGBE_EIMS: u32 = 0x00880; +pub const IXGBE_IVAR_ALLOC_VAL: u32 = 0x80; /* Interrupt Allocation valid */ +pub const IXGBE_EICR_RTX_QUEUE: u32 = 0x0000FFFF; /* RTx Queue Interrupt */ + +pub fn IXGBE_IVAR(i: u32) -> u32 { + (0x00900 + (i * 4)) +} /* 24 at 0x900-0x960 */ + +#[derive(Debug, Copy, Clone)] +#[repr(packed)] +pub struct ixgbe_adv_rx_desc_read { + pub pkt_addr: u64, + /* Packet buffer address */ + pub hdr_addr: u64, + /* Header buffer address */ +} + +/* Receive Descriptor - Advanced */ +#[derive(Debug, Copy, Clone)] +#[repr(packed)] +pub struct ixgbe_adv_rx_desc_wb_lower_lo_dword_hs_rss { + pub pkt_info: u16, + /* RSS, Pkt type */ + pub hdr_info: u16, + /* Splithdr, hdrlen */ +} + +#[derive(Copy, Clone)] +#[repr(packed)] +pub union ixgbe_adv_rx_desc_wb_lower_lo_dword { + pub data: u32, + pub hs_rss: ixgbe_adv_rx_desc_wb_lower_lo_dword_hs_rss, +} + +#[derive(Debug, Copy, Clone)] +#[repr(packed)] +pub struct ixgbe_adv_rx_desc_wb_lower_hi_dword_csum_ip { + pub ip_id: u16, + /* IP id */ + pub csum: u16, + /* Packet Checksum */ +} + +#[derive(Copy, Clone)] +#[repr(packed)] +pub union ixgbe_adv_rx_desc_wb_lower_hi_dword { + pub rss: u32, + /* RSS Hash */ + pub csum_ip: ixgbe_adv_rx_desc_wb_lower_hi_dword_csum_ip, +} + +#[derive(Copy, Clone)] +#[repr(packed)] +pub struct ixgbe_adv_rx_desc_wb_lower { + pub lo_dword: ixgbe_adv_rx_desc_wb_lower_lo_dword, + pub hi_dword: ixgbe_adv_rx_desc_wb_lower_hi_dword, +} + +#[derive(Debug, Copy, Clone)] +#[repr(packed)] +pub struct ixgbe_adv_rx_desc_wb_upper { + pub status_error: u32, + /* ext status/error */ + pub length: u16, + /* Packet length */ + pub vlan: u16, + /* VLAN tag */ +} + +#[derive(Copy, Clone)] +#[repr(packed)] +pub struct ixgbe_adv_rx_desc_wb { + pub lower: ixgbe_adv_rx_desc_wb_lower, + pub upper: ixgbe_adv_rx_desc_wb_upper, +} + +#[derive(Copy, Clone)] +#[repr(packed)] +pub union ixgbe_adv_rx_desc { + pub read: ixgbe_adv_rx_desc_read, + pub wb: ixgbe_adv_rx_desc_wb, /* writeback */ + _union_align: [u64; 2], +} + +/* Transmit Descriptor - Advanced */ +#[derive(Debug, Copy, Clone)] +#[repr(packed)] +pub struct ixgbe_adv_tx_desc_read { + pub buffer_addr: u64, + /* Address of descriptor's data buf */ + pub cmd_type_len: u32, + pub olinfo_status: u32, +} + +#[derive(Debug, Copy, Clone)] +#[repr(packed)] +pub struct ixgbe_adv_tx_desc_wb { + pub rsvd: u64, + /* Reserved */ + pub nxtseq_seed: u32, + pub status: u32, +} + +#[derive(Copy, Clone)] +#[repr(packed)] +pub union ixgbe_adv_tx_desc { + pub read: ixgbe_adv_tx_desc_read, + pub wb: ixgbe_adv_tx_desc_wb, + _union_align: [u64; 2], +} diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs new file mode 100644 index 0000000000..d593aa387a --- /dev/null +++ b/ixgbed/src/main.rs @@ -0,0 +1,203 @@ +extern crate event; +extern crate netutils; +extern crate syscall; + +use std::cell::RefCell; +use std::fs::File; +use std::io::{ErrorKind, Read, Result, Write}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::sync::Arc; +use std::{env, thread}; + +use event::EventQueue; +use std::time::Duration; +use syscall::{Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; + +pub mod device; +#[rustfmt::skip] +mod ixgbe; + +const IXGBE_MMIO_SIZE: usize = 512 * 1024; + +fn handle_update( + socket: &mut File, + device: &mut device::Intel8259x, + todo: &mut Vec, +) -> Result { + // Handle any blocked packets + let mut i = 0; + while i < todo.len() { + if let Some(a) = device.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&packet)?; + } else { + i += 1; + } + } + + // Check that the socket is empty + loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => return Ok(true), + Ok(_) => (), + Err(err) => { + if err.kind() == ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } + } + } + + if let Some(a) = device.handle(&packet) { + packet.a = a; + socket.write(&packet)?; + } else { + todo.push(packet); + } + } + + Ok(false) +} + +fn main() { + let mut args = env::args().skip(1); + + let mut name = args.next().expect("ixgbed: no name provided"); + name.push_str("_ixgbe"); + + let bar_str = args.next().expect("ixgbed: no address provided"); + let bar = usize::from_str_radix(&bar_str, 16).expect("ixgbed: failed to parse address"); + + let irq_str = args.next().expect("ixgbed: no irq provided"); + let irq = irq_str.parse::().expect("ixgbed: failed to parse irq"); + + println!(" + IXGBE {} on: {:X} IRQ: {}", name, bar, irq); + + // Daemonize + if unsafe { syscall::clone(0).unwrap() } == 0 { + let socket_fd = syscall::open( + ":network", + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + ) + .expect("ixgbed: failed to create network scheme"); + let socket = Arc::new(RefCell::new(unsafe { + File::from_raw_fd(socket_fd as RawFd) + })); + + let mut irq_file = + File::open(format!("irq:{}", irq)).expect("ixgbed: failed to open IRQ file"); + + let address = unsafe { + syscall::physmap(bar, IXGBE_MMIO_SIZE, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("ixgbed: failed to map address") + }; + { + let device = Arc::new(RefCell::new(unsafe { + device::Intel8259x::new(address, IXGBE_MMIO_SIZE) + .expect("ixgbed: failed to allocate device") + })); + + let mut event_queue = + EventQueue::::new().expect("ixgbed: failed to create event queue"); + + syscall::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); + + let todo = Arc::new(RefCell::new(Vec::::new())); + + let device_irq = device.clone(); + let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + if unsafe { device_irq.borrow().irq() } { + irq_file.write(&irq)?; + + if handle_update( + &mut socket_irq.borrow_mut(), + &mut device_irq.borrow_mut(), + &mut todo_irq.borrow_mut(), + )? { + return Ok(Some(0)); + } + + let next_read = device_irq.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + } + Ok(None) + }, + ) + .expect("ixgbed: failed to catch events on IRQ file"); + + let device_packet = device.clone(); + let socket_packet = socket.clone(); + + event_queue + .add(socket_fd as RawFd, move |_event| -> Result> { + if handle_update( + &mut socket_packet.borrow_mut(), + &mut device_packet.borrow_mut(), + &mut todo.borrow_mut(), + )? { + return Ok(Some(0)); + } + + let next_read = device_packet.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + + Ok(None) + }) + .expect("ixgbed: failed to catch events on scheme file"); + + let send_events = |event_count| { + for (handle_id, _handle) in device.borrow().handles.iter() { + socket + .borrow_mut() + .write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: syscall::flag::EVENT_READ, + d: event_count, + }) + .expect("ixgbed: failed to write event"); + } + }; + + for event_count in event_queue + .trigger_all(event::Event { fd: 0, flags: 0 }) + .expect("ixgbed: failed to trigger events") + { + send_events(event_count); + } + + loop { + let event_count = event_queue.run().expect("ixgbed: failed to handle events"); + if event_count == 0 { + //TODO: Handle todo + break; + } + + send_events(event_count); + } + } + unsafe { + let _ = syscall::physunmap(address); + } + } + + thread::sleep(Duration::from_secs(20)); +} From 713058f18301fe85a4a7cb8803478c8294e2f217 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 22 May 2020 09:06:03 -0600 Subject: [PATCH 0418/1301] Update dependencies, add patches --- .gitmodules | 0 Cargo.lock | 863 +++++++++++----------------------------------------- Cargo.toml | 5 + 3 files changed, 182 insertions(+), 686 deletions(-) delete mode 100644 .gitmodules diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/Cargo.lock b/Cargo.lock index e68857c1cd..50dcc25437 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,8 +52,8 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -67,15 +67,6 @@ name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "base64" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "base64" version = "0.11.0" @@ -95,7 +86,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -127,20 +118,6 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bytes" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cc" -version = "1.0.51" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cfg-if" version = "0.1.10" @@ -167,7 +144,7 @@ dependencies = [ [[package]] name = "clap" -version = "2.33.0" +version = "2.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -176,7 +153,7 @@ dependencies = [ "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -204,37 +181,6 @@ dependencies = [ "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-deque" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-utils" version = "0.7.2" @@ -281,85 +227,84 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" -version = "0.1.29" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "futures" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-channel" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-core" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures-executor" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-io" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures-macro" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures-sink" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures-task" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "futures-util" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -379,44 +324,10 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "httparse" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "hyper" -version = "0.10.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "hyper-rustls" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", - "rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -444,7 +355,7 @@ name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -457,7 +368,7 @@ name = "ixgbed" version = "1.0.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)", + "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -471,35 +382,26 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazycell" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" -version = "0.2.69" +version = "0.2.70" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "linked-hash-map" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "lock_api" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "lock_api" version = "0.3.4" @@ -509,14 +411,6 @@ dependencies = [ "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "log" version = "0.4.8" @@ -540,75 +434,31 @@ name = "memchr" version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "memoffset" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mime" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "mio" -version = "0.6.16" -source = "git+https://gitlab.redox-os.org/redox-os/mio#439a559b2aa734e0970d37b3375889a57a465360" +version = "0.6.14" +source = "git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix#c9a70849ced97387e2607c9c466d23b130ec8901" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "mio" -version = "0.6.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "mio-uds" -version = "0.6.7" -source = "git+https://gitlab.redox-os.org/redox-os/mio-uds#22580ca398cdb5ed6f50fb61134e5579e2213999" -dependencies = [ - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", -] - [[package]] name = "miow" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -616,46 +466,25 @@ dependencies = [ [[package]] name = "net2" version = "0.2.33" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix#be7b855982e63770753a81ffc4bedf66d7f66506" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#85c159fdd8bbdc562afb5041ae40dde566bed538" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#6f81f874f2015d82e811102160808db581f585a5" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix)", + "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", - "pbr 1.0.2 (git+https://github.com/a8m/pb)", - "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "netutils" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#bcdac5927ec65217dfa02497d83e94a29b9b992d" -dependencies = [ - "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", - "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", - "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", - "pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "pbr 1.0.2 (git+https://github.com/jackpot51/pb.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -714,15 +543,6 @@ dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "num_cpus" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "numtoa" version = "0.1.0" @@ -736,15 +556,20 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "block-io-wrapper 0.1.0", "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", "pcid 0.1.0", "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "once_cell" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "orbclient" version = "0.3.27" @@ -762,15 +587,6 @@ dependencies = [ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "parking_lot" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parking_lot" version = "0.10.2" @@ -780,18 +596,6 @@ dependencies = [ "parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "parking_lot_core" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "parking_lot_core" version = "0.7.2" @@ -799,9 +603,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -818,22 +622,10 @@ dependencies = [ [[package]] name = "pbr" version = "1.0.2" -source = "git+https://github.com/a8m/pb#87c29c05486afa7335916c870ea3621ff7ef2966" +source = "git+https://github.com/jackpot51/pb.git#ae1c429f9eb980ac6fe67aebd88db293815d42b0" dependencies = [ "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "pbr" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -845,15 +637,15 @@ dependencies = [ "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -869,6 +661,24 @@ name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "pin-project" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "pin-project-internal 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "pin-utils" version = "0.1.0" @@ -891,7 +701,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.10" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -908,10 +718,10 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.3" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -920,7 +730,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -975,7 +785,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -987,7 +797,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1034,7 +844,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0#30f6 dependencies = [ "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1067,17 +877,6 @@ dependencies = [ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ring" -version = "0.13.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rtl8168d" version = "0.1.0" @@ -1088,50 +887,19 @@ dependencies = [ "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustls" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rusttype" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ryu" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "safemem" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "scopeguard" -version = "0.3.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1144,26 +912,17 @@ name = "scroll" version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll_derive 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "scroll_derive" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "sct" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1173,7 +932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1185,48 +944,35 @@ version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "serde" -version = "1.0.106" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.106" +version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.51" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1236,18 +982,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "0.6.13" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "smallvec" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1283,11 +1021,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.17" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1296,7 +1034,7 @@ name = "termion" version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1312,20 +1050,20 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.15" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "thiserror-impl 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thiserror-impl" -version = "1.0.15" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1333,189 +1071,16 @@ name = "time" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio" -version = "0.1.13" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-fs 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-tcp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-codec" -version = "0.1.1" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-current-thread" -version = "0.1.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-executor" -version = "0.1.5" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-fs" -version = "0.1.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-io" -version = "0.1.10" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-reactor" -version = "0.1.7" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-tcp" -version = "0.1.2" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-threadpool" -version = "0.1.9" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-timer" -version = "0.2.8" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-udp" -version = "0.1.3" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - -[[package]] -name = "tokio-uds" -version = "0.2.4" -source = "git+https://gitlab.redox-os.org/redox-os/tokio#6c1f7a23c50f8deccce3cc111038b9cd4dbd9de7" -dependencies = [ - "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)", - "mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)", - "tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)", - "tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)", -] - [[package]] name = "toml" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "traitobject" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "typeable" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicase" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1531,7 +1096,7 @@ name = "unicode-normalization" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1544,11 +1109,6 @@ name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "untrusted" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "url" version = "1.7.2" @@ -1563,7 +1123,7 @@ dependencies = [ name = "usbctl" version = "0.1.0" dependencies = [ - "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] @@ -1584,7 +1144,7 @@ dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "thiserror 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] @@ -1617,12 +1177,7 @@ dependencies = [ [[package]] name = "vec_map" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "version_check" -version = "0.1.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1643,24 +1198,6 @@ dependencies = [ "utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "webpki" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)", - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "webpki-roots" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "winapi" version = "0.2.8" @@ -1706,7 +1243,7 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)", "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pcid 0.1.0", @@ -1714,10 +1251,10 @@ dependencies = [ "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1730,68 +1267,51 @@ dependencies = [ "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" -"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" "checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" -"checksum cc 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9384ca4b90c0ea47e19a5c996d6643a3e73dedf9b89c65efb67587e34da1bb" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "" "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" -"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" "checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" -"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13" -"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" -"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" -"checksum futures 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5c329ae8753502fb44ae4fc2b622fa2a94652c41e795143765ba0927f92ab780" -"checksum futures-channel 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0c77d04ce8edd9cb903932b608268b3fffec4163dc053b3b402bf47eac1f1a8" -"checksum futures-core 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f25592f769825e89b92358db00d26f965761e094951ac44d3663ef25b7ac464a" -"checksum futures-executor 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f674f3e1bcb15b37284a90cedf55afdba482ab061c407a9c0ebbd0f3109741ba" -"checksum futures-io 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a638959aa96152c7a4cddf50fcb1e3fede0583b27157c26e67d6f99904090dc6" -"checksum futures-macro 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "9a5081aa3de1f7542a794a397cde100ed903b0630152d0973479018fd85423a7" -"checksum futures-sink 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3466821b4bc114d95b087b850a724c6f83115e929bc88f1fa98a3304a944c8a6" -"checksum futures-task 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0a34e53cf6cdcd0178aa573aed466b646eb3db769570841fda0c7ede375a27" -"checksum futures-util 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "22766cf25d64306bedf0384da004d05c9974ab104fcc4528f1236181c18004c5" +"checksum futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" +"checksum futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" +"checksum futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" +"checksum futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" +"checksum futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" +"checksum futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" +"checksum futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" +"checksum futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" +"checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" "checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" -"checksum hermit-abi 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8a0d737e0f947a1864e93d33fdef4af8445a00d1ed8dc0c8ddb73139ea6abf15" -"checksum httparse 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" -"checksum hyper 0.10.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0a0652d9a2609a968c14be1a9ea00bf4b1d64e2e1f53a1b51b6fff3a6e829273" -"checksum hyper-rustls 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "71f7b2e5858ab9e19771dc361159f09ee5031734a6f7471fe0947db0238d92b7" +"checksum hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" "checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)" = "99e85c08494b21a9054e7fe1374a732aeadaff3980b6990b94bfd3a70f690005" -"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" -"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c" +"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" +"checksum libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" +"checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" "checksum lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -"checksum memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" -"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0" -"checksum mio 0.6.16 (git+https://gitlab.redox-os.org/redox-os/mio)" = "" -"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" -"checksum mio-uds 0.6.7 (git+https://gitlab.redox-os.org/redox-os/mio-uds)" = "" +"checksum mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix)" = "" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" -"checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git)" = "" +"checksum net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)" = "" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)" = "" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" @@ -1799,24 +1319,23 @@ dependencies = [ "checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" "checksum num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" -"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" +"checksum once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" "checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402" "checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" "checksum parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" -"checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" -"checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" -"checksum pbr 1.0.2 (git+https://github.com/a8m/pb)" = "" -"checksum pbr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4403eb718d70c03ee279e51737782902c68cca01e870a33b6a2f9dfb50b9cd83" +"checksum pbr 1.0.2 (git+https://github.com/jackpot51/pb.git)" = "" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" +"checksum pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)" = "edc93aeee735e60ecb40cf740eb319ff23eab1c5748abfdb5c180e4ce49f7791" +"checksum pin-project-internal 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)" = "e58db2081ba5b4c93bd6be09c40fd36cb9193a8336c384f3b40012e531aa7e40" "checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" "checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" -"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" -"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +"checksum proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "de40dd4ff82d9c9bab6dae29dbab1167e515f8df9ed17d2987cb6012db206933" +"checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" @@ -1834,68 +1353,40 @@ dependencies = [ "checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustls 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "942b71057b31981152970d57399c25f72e27a6ee0d207a669d8304cabf44705b" "checksum rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a" -"checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" -"checksum safemem 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" -"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" +"checksum ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" "checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" -"checksum scroll_derive 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8584eea9b9ff42825b46faf46a8c24d2cff13ec152fa2a50df788b87c07ee28" -"checksum sct 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cb8f61f9e6eadd062a71c380043d28036304a4706b3c4dd001ff3387ed00745a" +"checksum scroll_derive 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e367622f934864ffa1c704ba2b82280aab856e3d8213c84c5720257eb34b15b9" "checksum sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d051a07231e303f5f719da78cb6f7394f6d5b54f733aef5b0b447804a83edd7b" "checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" -"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" -"checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" +"checksum serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)" = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" +"checksum serde_derive 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)" = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" +"checksum serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)" = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" -"checksum smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05720e22615919e4734f6a99ceae50d00226c3c5aca406e102ebc33298214e0a" +"checksum smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" "checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" +"checksum syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "54b3d3d2ff68104100ab257bb6bb0cb26c901abe4bd4ba15961f3bf867924012" -"checksum thiserror-impl 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972988113b7715266f91250ddb98070d033c62a011fa0fcc57434a649310dd" +"checksum thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "b13f926965ad00595dd129fa12823b04bbf866e9085ab0a5f2b05b850fbfc344" +"checksum thiserror-impl 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "893582086c2f98cde18f906265a65b5030a074b1046c674ae898be6519a7f479" "checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -"checksum tokio 0.1.13 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-codec 0.1.1 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-current-thread 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-executor 0.1.5 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-fs 0.1.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-io 0.1.10 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-reactor 0.1.7 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-tcp 0.1.2 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-threadpool 0.1.9 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-timer 0.2.8 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-udp 0.1.3 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" -"checksum tokio-uds 0.2.4 (git+https://gitlab.redox-os.org/redox-os/tokio)" = "" "checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" -"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" -"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887" -"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" "checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" -"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" -"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" +"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" "checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" -"checksum webpki 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "17d7967316d8411ca3b01821ee6c332bde138ba4363becdb492f12e514daa17f" -"checksum webpki-roots 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85d1f408918fd590908a70d36b7ac388db2edc221470333e4d6e5b598e44cabf" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index 3c1f2a91d1..37e309e500 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,3 +19,8 @@ members = [ "usbhidd", "usbscsid", ] + +[patch.crates-io] +mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } +net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "redox-unix" } +pbr = { git = "https://github.com/jackpot51/pb.git" } From 7ccf8d27b01029de8370e47e3085a32032a0d99b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 28 May 2020 11:54:30 -0600 Subject: [PATCH 0419/1301] Remove pbr patch --- Cargo.lock | 84 +++++++++++++++++++++++++++--------------------------- Cargo.toml | 1 - 2 files changed, 42 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 50dcc25437..6c72bc911e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,7 +53,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -273,10 +273,10 @@ name = "futures-macro" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -306,7 +306,7 @@ dependencies = [ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -327,7 +327,7 @@ name = "hermit-abi" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -355,7 +355,7 @@ name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -394,7 +394,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.70" +version = "0.2.71" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -444,7 +444,7 @@ dependencies = [ "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", @@ -469,7 +469,7 @@ version = "0.2.33" source = "git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix#be7b855982e63770753a81ffc4bedf66d7f66506" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -480,11 +480,11 @@ source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-uni dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix)", "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", - "pbr 1.0.2 (git+https://github.com/jackpot51/pb.git)", + "pbr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -603,7 +603,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -621,11 +621,11 @@ dependencies = [ [[package]] name = "pbr" -version = "1.0.2" -source = "git+https://github.com/jackpot51/pb.git#ae1c429f9eb980ac6fe67aebd88db293815d42b0" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -637,7 +637,7 @@ dependencies = [ "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", @@ -674,9 +674,9 @@ name = "pin-project-internal" version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -691,7 +691,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-hack" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -701,7 +701,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -721,7 +721,7 @@ name = "quote" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -730,7 +730,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -785,7 +785,7 @@ name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -797,7 +797,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -920,9 +920,9 @@ name = "scroll_derive" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -932,7 +932,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -944,7 +944,7 @@ version = "0.32.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -960,9 +960,9 @@ name = "serde_derive" version = "1.0.110" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1021,10 +1021,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.23" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1034,7 +1034,7 @@ name = "termion" version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1061,9 +1061,9 @@ name = "thiserror-impl" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1071,7 +1071,7 @@ name = "time" version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1302,7 +1302,7 @@ dependencies = [ "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" -"checksum libc 0.2.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" +"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" "checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" "checksum lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" @@ -1326,15 +1326,15 @@ dependencies = [ "checksum parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" "checksum parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" -"checksum pbr 1.0.2 (git+https://github.com/jackpot51/pb.git)" = "" +"checksum pbr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74333e3d1d8bced07fd0b8599304825684bcdb4a1fcc6fa6a470e6e08cefd254" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)" = "edc93aeee735e60ecb40cf740eb319ff23eab1c5748abfdb5c180e4ce49f7791" "checksum pin-project-internal 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)" = "e58db2081ba5b4c93bd6be09c40fd36cb9193a8336c384f3b40012e531aa7e40" "checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro-hack 0.5.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d659fe7c6d27f25e9d80a1a094c223f5246f6a6596453e09d7229bf42750b63" +"checksum proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" "checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" -"checksum proc-macro2 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "de40dd4ff82d9c9bab6dae29dbab1167e515f8df9ed17d2987cb6012db206933" +"checksum proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101" "checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" @@ -1370,7 +1370,7 @@ dependencies = [ "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" "checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum syn 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269" +"checksum syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "ef781e621ee763a2a40721a8861ec519cb76966aee03bb5d00adb6a31dc1c1de" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "b13f926965ad00595dd129fa12823b04bbf866e9085ab0a5f2b05b850fbfc344" diff --git a/Cargo.toml b/Cargo.toml index 37e309e500..dd766edf78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,4 +23,3 @@ members = [ [patch.crates-io] mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "redox-unix" } -pbr = { git = "https://github.com/jackpot51/pb.git" } From 6bd4bb814fff1cd980263bbb3880351f1ea8cbfa Mon Sep 17 00:00:00 2001 From: 4lDO2 <4ldo2@protonmail.com> Date: Thu, 18 Jun 2020 19:17:20 +0000 Subject: [PATCH 0420/1301] Support xHCs that only support 32-bit physical addresses. --- Cargo.lock | 164 +++++++++++++++++----------------- nvmed/src/nvme/identify.rs | 6 +- nvmed/src/nvme/mod.rs | 4 +- xhcid/src/xhci/capability.rs | 6 ++ xhcid/src/xhci/context.rs | 19 ++-- xhcid/src/xhci/event.rs | 7 +- xhcid/src/xhci/irq_reactor.rs | 8 +- xhcid/src/xhci/mod.rs | 44 ++++++--- xhcid/src/xhci/ring.rs | 28 +++--- xhcid/src/xhci/scheme.rs | 12 +-- 10 files changed, 163 insertions(+), 135 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6c72bc911e..e293e0c3cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,7 +52,7 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -86,7 +86,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -137,8 +137,8 @@ name = "chrono" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -274,9 +274,9 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -304,17 +304,17 @@ dependencies = [ "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)", "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "gpt" version = "0.6.3" -source = "git+https://gitlab.redox-os.org/redox-os/gpt#de8270848edf07b68b7e0d73d6efcb15b2e1f090" +source = "git+https://gitlab.redox-os.org/redox-os/gpt#4d800981c5dfae60ae183dbddaa3e026f80a5e5c" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -324,7 +324,7 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", @@ -360,7 +360,7 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -476,7 +476,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#6f81f874f2015d82e811102160808db581f585a5" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#a66c155fa4bb248151100c2ac861a913df7c75cd" dependencies = [ "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", @@ -511,33 +511,33 @@ name = "num" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-iter 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-iter" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -642,10 +642,10 @@ dependencies = [ "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -663,20 +663,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "pin-project" -version = "0.4.17" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "pin-project-internal 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)", + "pin-project-internal 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "pin-project-internal" -version = "0.4.17" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -696,12 +696,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro-nested" -version = "0.1.4" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -718,10 +718,10 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -859,7 +859,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.1.56" -source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#8d0015be8693a81c2a4459f3c09fb47b98ff07b1" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#783a03dc73495b9a3b0e8a02bf8910cd91874888" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -899,7 +899,7 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -920,9 +920,9 @@ name = "scroll_derive" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -949,30 +949,30 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.110" +version = "1.0.112" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.110" +version = "1.0.112" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.53" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -985,7 +985,7 @@ name = "smallvec" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1021,11 +1021,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.27" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1050,20 +1050,20 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "thiserror-impl 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thiserror-impl" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1080,7 +1080,7 @@ name = "toml" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1144,7 +1144,7 @@ dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] @@ -1251,10 +1251,10 @@ dependencies = [ "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1295,10 +1295,10 @@ dependencies = [ "checksum futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" "checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" "checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" -"checksum hermit-abi 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "91780f809e750b0a89f5544be56617ff6b1227ee485bcb06ebe10cdf89bd3b71" +"checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" +"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" @@ -1316,9 +1316,9 @@ dependencies = [ "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" "checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" -"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" -"checksum num-iter 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "dfb0800a0291891dd9f4fe7bd9c19384f98f7fbe0cd0f39a2c6b88b9868bbc00" -"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +"checksum num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" +"checksum num-iter 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f" +"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" "checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402" @@ -1328,14 +1328,14 @@ dependencies = [ "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" "checksum pbr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74333e3d1d8bced07fd0b8599304825684bcdb4a1fcc6fa6a470e6e08cefd254" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum pin-project 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)" = "edc93aeee735e60ecb40cf740eb319ff23eab1c5748abfdb5c180e4ce49f7791" -"checksum pin-project-internal 0.4.17 (registry+https://github.com/rust-lang/crates.io-index)" = "e58db2081ba5b4c93bd6be09c40fd36cb9193a8336c384f3b40012e531aa7e40" +"checksum pin-project 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)" = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17" +"checksum pin-project-internal 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7" "checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" "checksum proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" -"checksum proc-macro-nested 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8e946095f9d3ed29ec38de908c22f95d9ac008e424c7bcae54c75a79c527c694" -"checksum proc-macro2 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "1502d12e458c49a4c9cbff560d0fe0060c252bc29799ed94ca2ed4bb665a0101" -"checksum quote 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" +"checksum proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" +"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" "checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" @@ -1354,15 +1354,15 @@ dependencies = [ "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a" -"checksum ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" +"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" "checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" "checksum scroll_derive 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e367622f934864ffa1c704ba2b82280aab856e3d8213c84c5720257eb34b15b9" "checksum sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d051a07231e303f5f719da78cb6f7394f6d5b54f733aef5b0b447804a83edd7b" "checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" -"checksum serde 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)" = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" -"checksum serde_derive 1.0.110 (registry+https://github.com/rust-lang/crates.io-index)" = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" -"checksum serde_json 1.0.53 (registry+https://github.com/rust-lang/crates.io-index)" = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" +"checksum serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243" +"checksum serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57" +"checksum serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" @@ -1370,11 +1370,11 @@ dependencies = [ "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" "checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum syn 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "ef781e621ee763a2a40721a8861ec519cb76966aee03bb5d00adb6a31dc1c1de" +"checksum syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "b13f926965ad00595dd129fa12823b04bbf866e9085ab0a5f2b05b850fbfc344" -"checksum thiserror-impl 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "893582086c2f98cde18f906265a65b5030a074b1046c674ae898be6519a7f479" +"checksum thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" +"checksum thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" "checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" "checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" diff --git a/nvmed/src/nvme/identify.rs b/nvmed/src/nvme/identify.rs index e5c5db5a53..94c0a39595 100644 --- a/nvmed/src/nvme/identify.rs +++ b/nvmed/src/nvme/identify.rs @@ -150,7 +150,7 @@ impl Nvme { /// Returns the serial number, model, and firmware, in that order. pub async fn identify_controller(&self) { // TODO: Use same buffer - let data: Dma = Dma::zeroed().unwrap(); + let data: Dma = unsafe { Dma::zeroed().unwrap().assume_init() }; // println!(" - Attempting to identify controller"); let comp = self @@ -175,7 +175,7 @@ impl Nvme { } pub async fn identify_namespace_list(&self, base: u32) -> Vec { // TODO: Use buffer - let data: Dma<[u32; 1024]> = Dma::zeroed().unwrap(); + let data: Dma<[u32; 1024]> = unsafe { Dma::zeroed().unwrap().assume_init() }; // println!(" - Attempting to retrieve namespace ID list"); let comp = self @@ -191,7 +191,7 @@ impl Nvme { } pub async fn identify_namespace(&self, nsid: u32) -> NvmeNamespace { //TODO: Use buffer - let data: Dma = Dma::zeroed().unwrap(); + let data: Dma = unsafe { Dma::zeroed().unwrap().assume_init() }; // println!(" - Attempting to identify namespace {}", nsid); let comp = self diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index f5af0f0c37..b80a633513 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -206,8 +206,8 @@ impl Nvme { // map the zero interrupt vector (which according to the spec shall always point to the // admin completion queue) to CQID 0 (admin completion queue) cqs_for_ivs: RwLock::new(std::iter::once((0, smallvec!(0))).collect()), - buffer: Mutex::new(Dma::zeroed()?), - buffer_prp: Mutex::new(Dma::zeroed()?), + buffer: Mutex::new(unsafe { Dma::zeroed()?.assume_init() }), + buffer_prp: Mutex::new(unsafe { Dma::zeroed()?.assume_init() }), interrupt_method: Mutex::new(interrupt_method), pcid_interface: Mutex::new(pcid_interface), reactor_sender, diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index 4ec7b10a15..5479be88fb 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -14,6 +14,8 @@ pub struct CapabilityRegs { pub hcc_params2: Mmio, } +pub const HCC_PARAMS1_AC64_BIT: u32 = 1 << HCC_PARAMS1_AC64_SHIFT; +pub const HCC_PARAMS1_AC64_SHIFT: u8 = 0; pub const HCC_PARAMS1_MAXPSASIZE_MASK: u32 = 0xF000; // 15:12 pub const HCC_PARAMS1_MAXPSASIZE_SHIFT: u8 = 12; pub const HCC_PARAMS1_XECP_MASK: u32 = 0xFFFF_0000; @@ -35,6 +37,10 @@ pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK: u32 = 0x03E0_0000; pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT: u8 = 21; impl CapabilityRegs { + pub fn ac64(&self) -> bool { + self.hcc_params1.readf(HCC_PARAMS1_AC64_BIT) + } + pub fn lec(&self) -> bool { self.hcc_params2.readf(HCC_PARAMS2_LEC_BIT) } diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index e971ad28a7..e6f56427e6 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -4,6 +4,7 @@ use log::debug; use syscall::error::Result; use syscall::io::{Dma, Io, Mmio}; +use super::Xhci; use super::ring::Ring; #[repr(packed)] @@ -80,13 +81,13 @@ pub struct DeviceContextList { } impl DeviceContextList { - pub fn new(max_slots: u8) -> Result { - let mut dcbaa = Dma::<[u64; 256]>::zeroed()?; + pub fn new(ac64: bool, max_slots: u8) -> Result { + let mut dcbaa = unsafe { Xhci::alloc_dma_zeroed_raw::<[u64; 256]>(ac64)? }; let mut contexts = vec![]; // Create device context buffers for each slot for i in 0..max_slots as usize { - let context: Dma = Dma::zeroed()?; + let context: Dma = unsafe { Xhci::alloc_dma_zeroed_raw(ac64) }?; dcbaa[i] = context.physical() as u64; contexts.push(context); } @@ -130,19 +131,19 @@ pub struct StreamContextArray { } impl StreamContextArray { - pub fn new(count: usize) -> Result { + pub fn new(ac64: bool, count: usize) -> Result { unsafe { Ok(Self { - contexts: Dma::zeroed_unsized(count)?, + contexts: Xhci::alloc_dma_zeroed_unsized_raw(ac64, count)?, rings: BTreeMap::new(), }) } } - pub fn add_ring(&mut self, stream_id: u16, link: bool) -> Result<()> { + pub fn add_ring(&mut self, ac64: bool, stream_id: u16, link: bool) -> Result<()> { // NOTE: stream_id 0 is reserved assert_ne!(stream_id, 0); - let ring = Ring::new(16, link)?; + let ring = Ring::new(ac64, 16, link)?; let pointer = ring.register(); let sct = StreamContextType::PrimaryRing; @@ -176,8 +177,8 @@ pub struct ScratchpadBufferArray { pub pages: Vec, } impl ScratchpadBufferArray { - pub fn new(page_size: usize, entries: u16) -> Result { - let mut entries = unsafe { Dma::zeroed_unsized(entries as usize)? }; + pub fn new(ac64: bool, page_size: usize, entries: u16) -> Result { + let mut entries = unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? }; let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result { let pointer = unsafe { syscall::physalloc(page_size)? }; diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index b3e0af0e35..7ee17d6957 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -1,6 +1,7 @@ use syscall::error::Result; use syscall::io::{Dma, Io, Mmio}; +use super::Xhci; use super::ring::Ring; use super::trb::Trb; @@ -19,10 +20,10 @@ pub struct EventRing { } impl EventRing { - pub fn new() -> Result { + pub fn new(ac64: bool) -> Result { let mut ring = EventRing { - ste: unsafe { Dma::zeroed_unsized(1)? }, - ring: Ring::new(256, false)?, + ste: unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, 1)? }, + ring: Ring::new(ac64, 256, false)?, }; ring.ste[0].address.write(ring.ring.trbs.physical() as u64); diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 2b80883c29..9989da87e5 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -218,7 +218,7 @@ impl IrqReactor { // Before waking, it's crucial that the command TRB that generated this event // is fetched before removing this event TRB from the queue. - let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(phys_ptr) { + let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(self.hci.cap.ac64(), phys_ptr) { Some(command_trb) => { let t = command_trb.clone(); command_trb.reserved(false); @@ -379,7 +379,7 @@ impl Future for EventTrbFuture { impl Xhci { pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option { - self.with_ring(id, |ring| ring.phys_addr_to_entry(paddr)).flatten() + self.with_ring(id, |ring| ring.phys_addr_to_entry(self.cap.ac64(), paddr)).flatten() } pub fn with_ring T>(&self, id: RingId, function: F) -> Option { use super::RingOrStreams; @@ -419,7 +419,7 @@ impl Xhci { is_isoch_or_vf, state_kind: StateKind::Transfer { ring_id, - phys_ptr: ring.trb_phys_ptr(trb), + phys_ptr: ring.trb_phys_ptr(self.cap.ac64(), trb), }, message: Arc::new(Mutex::new(None)), }, @@ -435,7 +435,7 @@ impl Xhci { // This is only possible for transfers if they are isochronous, or for Force Event TRBs (virtualization). is_isoch_or_vf: false, state_kind: StateKind::CommandCompletion { - phys_ptr: command_ring.trb_phys_ptr(trb), + phys_ptr: command_ring.trb_phys_ptr(self.cap.ac64(), trb), }, message: Arc::new(Mutex::new(None)), }, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index d8f3348f71..3fc5d75a46 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -14,8 +14,8 @@ use crossbeam_channel::{Receiver, Sender}; use log::{debug, error, info, trace, warn}; use serde::Deserialize; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; -use syscall::flag::O_RDONLY; -use syscall::io::{Dma, Io}; +use syscall::flag::{O_RDONLY, PhysallocFlags}; +use syscall::io::{Dma, Io, PhysBox}; use crate::usb; @@ -131,25 +131,25 @@ impl Xhci { } async fn fetch_dev_desc(&self, port: usize, slot: u8) -> Result { - let mut desc = Dma::::zeroed()?; + let mut desc = unsafe { self.alloc_dma_zeroed::()? }; self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?; Ok(*desc) } async fn fetch_config_desc(&self, port: usize, slot: u8, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { - let mut desc = Dma::<(usb::ConfigDescriptor, [u8; 4087])>::zeroed()?; + let mut desc = unsafe { self.alloc_dma_zeroed::<(usb::ConfigDescriptor, [u8; 4087])>()? }; self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, &mut desc).await?; Ok(*desc) } async fn fetch_bos_desc(&self, port: usize, slot: u8) -> Result<(usb::BosDescriptor, [u8; 4087])> { - let mut desc = Dma::<(usb::BosDescriptor, [u8; 4087])>::zeroed()?; + let mut desc = unsafe { self.alloc_dma_zeroed::<(usb::BosDescriptor, [u8; 4087])>()? }; self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc).await?; Ok(*desc) } async fn fetch_string_desc(&self, port: usize, slot: u8, index: u8) -> Result { - let mut sdesc = Dma::<(u8, u8, [u16; 127])>::zeroed()?; + let mut sdesc = unsafe { self.alloc_dma_zeroed::<(u8, u8, [u16; 127])>()? }; self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, &mut sdesc).await?; let len = sdesc.0 as usize; @@ -295,7 +295,7 @@ impl Xhci { // Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the // DMA allocation (which is at least a 4k page). let entries_per_page = page_size / mem::size_of::(); - let cmd = Ring::new(entries_per_page, true)?; + let cmd = Ring::new(cap.ac64(), entries_per_page, true)?; let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded(); @@ -310,11 +310,11 @@ impl Xhci { dbs: Mutex::new(dbs), run: Mutex::new(run), - dev_ctx: DeviceContextList::new(max_slots)?, + dev_ctx: DeviceContextList::new(cap.ac64(), max_slots)?, scratchpad_buf_arr: None, // initialized in init() cmd: Mutex::new(cmd), - primary_event_ring: Mutex::new(EventRing::new()?), + primary_event_ring: Mutex::new(EventRing::new(cap.ac64())?), handles: CHashMap::new(), next_handle: AtomicUsize::new(0), port_states: CHashMap::new(), @@ -410,7 +410,7 @@ impl Xhci { if buf_count == 0 { return Ok(()); } - let scratchpad_buf_arr = ScratchpadBufferArray::new(self.page_size,buf_count)?; + let scratchpad_buf_arr = ScratchpadBufferArray::new(self.cap.ac64(), self.page_size,buf_count)?; self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; debug!("Setting up {} scratchpads, at {:#0x}", buf_count, scratchpad_buf_arr.register()); self.scratchpad_buf_arr = Some(scratchpad_buf_arr); @@ -441,6 +441,26 @@ impl Xhci { pub fn slot_state(&self, slot: usize) -> u8 { self.dev_ctx.contexts[slot].slot.state() } + pub unsafe fn alloc_phys(ac64: bool, byte_count: usize) -> Result { + let flags = if ac64 { + PhysallocFlags::SPACE_64 + } else { + PhysallocFlags::SPACE_32 + }; + PhysBox::new_with_flags(byte_count, flags) + } + pub unsafe fn alloc_dma_zeroed_raw(ac64: bool) -> Result> { + Ok(Dma::from_physbox_zeroed(Self::alloc_phys(ac64, mem::size_of::())?)?.assume_init()) + } + pub unsafe fn alloc_dma_zeroed(&self) -> Result> { + Self::alloc_dma_zeroed_raw(self.cap.ac64()) + } + pub unsafe fn alloc_dma_zeroed_unsized_raw(ac64: bool, count: usize) -> Result> { + Ok(Dma::from_physbox_zeroed_unsized(Self::alloc_phys(ac64, mem::size_of::() * count)?, count)?.assume_init()) + } + pub unsafe fn alloc_dma_zeroed_unsized(&self, count: usize) -> Result> { + Self::alloc_dma_zeroed_unsized_raw(self.cap.ac64(), count) + } pub async fn probe(&self) -> Result<()> { info!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); @@ -469,7 +489,7 @@ impl Xhci { info!("Enabled port {}, which the xHC mapped to {}", i, slot); - let mut input = Dma::::zeroed()?; + let mut input = unsafe { self.alloc_dma_zeroed::()? }; let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; info!("Addressed device"); @@ -553,7 +573,7 @@ impl Xhci { slot: u8, speed: u8, ) -> Result { - let mut ring = Ring::new(16, true)?; + let mut ring = Ring::new(self.cap.ac64(), 16, true)?; { input_context.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit). diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index 67cafcf080..8326217858 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -3,6 +3,7 @@ use std::mem; use syscall::error::Result; use syscall::io::Dma; +use super::Xhci; use super::trb::Trb; pub struct Ring { @@ -13,10 +14,10 @@ pub struct Ring { } impl Ring { - pub fn new(length: usize, link: bool) -> Result { + pub fn new(ac64: bool, length: usize, link: bool) -> Result { Ok(Ring { - link: link, - trbs: unsafe { Dma::zeroed_unsized(length)? }, + link, + trbs: unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, length)? }, i: 0, cycle: link, }) @@ -64,9 +65,8 @@ impl Ring { /// /// # Panics /// Panics if paddr is not a multiple of 16 bytes, i.e. the size of a TRB. - // TODO: Use usize instead of u64. - pub fn phys_addr_to_index(&self, paddr: u64) -> Option { - let base = self.trbs.physical(); + pub fn phys_addr_to_index(&self, ac64: bool, paddr: u64) -> Option { + let base = self.trbs.physical() & if ac64 { 0xFFFF_FFFF_FFFF_FFFF } else { 0xFFFF_FFFF }; let offset = paddr.checked_sub(base as u64)? as usize; assert_eq!(offset % mem::size_of::(), 0, "unaligned TRB physical address"); @@ -79,15 +79,15 @@ impl Ring { Some(index) } - pub fn phys_addr_to_entry_ref(&self, paddr: u64) -> Option<&Trb> { - Some(&self.trbs[self.phys_addr_to_index(paddr)?]) + pub fn phys_addr_to_entry_ref(&self, ac64: bool, paddr: u64) -> Option<&Trb> { + Some(&self.trbs[self.phys_addr_to_index(ac64, paddr)?]) } - pub fn phys_addr_to_entry_mut(&mut self, paddr: u64) -> Option<&mut Trb> { - let index = self.phys_addr_to_index(paddr)?; + pub fn phys_addr_to_entry_mut(&mut self, ac64: bool, paddr: u64) -> Option<&mut Trb> { + let index = self.phys_addr_to_index(ac64, paddr)?; Some(&mut self.trbs[index]) } - pub fn phys_addr_to_entry(&self, paddr: u64) -> Option { - Some(self.trbs[self.phys_addr_to_index(paddr)?].clone()) + pub fn phys_addr_to_entry(&self, ac64: bool, paddr: u64) -> Option { + Some(self.trbs[self.phys_addr_to_index(ac64, paddr)?].clone()) } pub(crate) fn start_virt_addr(&self) -> *const Trb { self.trbs.as_ptr() @@ -95,7 +95,7 @@ impl Ring { pub(crate) fn end_virt_addr(&self) -> *const Trb { unsafe { self.start_virt_addr().offset(self.trbs.len() as isize) } } - pub fn trb_phys_ptr(&self, trb: &Trb) -> u64 { + pub fn trb_phys_ptr(&self, ac64: bool, trb: &Trb) -> u64 { let trb_virt_pointer = trb as *const Trb; let trbs_base_virt_pointer = self.trbs.as_ptr(); @@ -104,7 +104,7 @@ impl Ring { } let trb_offset_from_base = trb_virt_pointer as u64 - trbs_base_virt_pointer as u64; - let trbs_base_phys_ptr = self.trbs.physical() as u64; + let trbs_base_phys_ptr = (self.trbs.physical() as u64) & if ac64 { 0xFFFF_FFFF_FFFF_FFFF } else { 0xFFFF_FFFF }; let trb_phys_ptr = trbs_base_phys_ptr + trb_offset_from_base; trb_phys_ptr } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 039da4431f..8370414a85 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -694,10 +694,10 @@ impl Xhci { assert_ne!(ep_ty, 0); // 0 means invalid. let ring_ptr = if usb_log_max_streams.is_some() { - let mut array = StreamContextArray::new(1 << (primary_streams + 1))?; + let mut array = StreamContextArray::new(self.cap.ac64(), 1 << (primary_streams + 1))?; // TODO: Use as many stream rings as needed. - array.add_ring(1, true)?; + array.add_ring(self.cap.ac64(), 1, true)?; let array_ptr = array.register(); assert_eq!( @@ -715,7 +715,7 @@ impl Xhci { array_ptr } else { - let ring = Ring::new(16, true)?; + let ring = Ring::new(self.cap.ac64(), 16, true)?; let ring_ptr = ring.register(); assert_eq!( @@ -796,7 +796,7 @@ impl Xhci { if buf.is_empty() { return Err(Error::new(EINVAL)); } - let dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(buf.len())? }; + let dma_buffer = unsafe { self.alloc_dma_zeroed_unsized(buf.len())? }; let (completion_code, bytes_transferred, dma_buffer) = self.transfer( port_num, @@ -812,7 +812,7 @@ impl Xhci { if sbuf.is_empty() { return Err(Error::new(EINVAL)); } - let mut dma_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(sbuf.len()) }?; + let mut dma_buffer = unsafe { self.alloc_dma_zeroed_unsized(sbuf.len()) }?; dma_buffer.copy_from_slice(sbuf); trace!("TRANSFER_WRITE port {} ep {}, buffer at {:p}, size {}, dma buffer {:?}", port_num, endp_idx + 1, sbuf.as_ptr(), sbuf.len(), DmaSliceDbg(&dma_buffer)); @@ -1163,7 +1163,7 @@ impl Xhci { // TODO: Reuse buffers, or something. // TODO: Validate the size. // TODO: Sizes above 65536, *perhaps*. - let data_buffer = unsafe { Dma::<[u8]>::zeroed_unsized(req.length as usize)? }; + let data_buffer = unsafe { self.alloc_dma_zeroed_unsized(req.length as usize)? }; assert_eq!(data_buffer.len(), req.length as usize); Ok(match transfer_kind { From 00b8ad9fc2c2108e49fffb8d3acfd6105f8ef7bc Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Tue, 14 Jul 2020 12:56:44 +0000 Subject: [PATCH 0421/1301] Remove unnecessary unsafe declarations. The removed unsafe statements were identified by rustc as unneeded during compilation. Signed-off-by: Wren Turkal --- ihdad/src/hda/device.rs | 17 +++++++---------- ihdad/src/hda/stream.rs | 8 +++----- ihdad/src/main.rs | 2 +- ixgbed/src/device.rs | 14 +++----------- ixgbed/src/main.rs | 6 +++--- 5 files changed, 17 insertions(+), 30 deletions(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 78a8e61062..92c3685b17 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -153,26 +153,23 @@ impl IntelHDA { pub unsafe fn new(base: usize, vend_prod:u32) -> Result { let regs = &mut *(base as *mut Regs); - let buff_desc_phys = unsafe { + let buff_desc_phys = syscall::physalloc(0x1000) - .expect("Could not allocate physical memory for buffer descriptor list.") - }; + .expect("Could not allocate physical memory for buffer descriptor list."); - let buff_desc_virt = unsafe { + let buff_desc_virt = syscall::physmap(buff_desc_phys, 0x1000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("ihdad: failed to map address for buffer descriptor list.") - }; + .expect("ihdad: failed to map address for buffer descriptor list."); print!("Virt: {:016X}, Phys: {:016X}\n", buff_desc_virt, buff_desc_phys); let buff_desc = &mut *(buff_desc_virt as *mut [BufferDescriptorListEntry;256]); - let cmd_buff_address = unsafe { + let cmd_buff_address = syscall::physalloc(0x1000) - .expect("Could not allocate physical memory for CORB and RIRB.") - }; + .expect("Could not allocate physical memory for CORB and RIRB."); - let cmd_buff_virt = unsafe { syscall::physmap(cmd_buff_address, 0x1000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("ihdad: failed to map address for CORB/RIRB buff") }; + let cmd_buff_virt = syscall::physmap(cmd_buff_address, 0x1000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("ihdad: failed to map address for CORB/RIRB buff"); print!("Virt: {:016X}, Phys: {:016X}\n", cmd_buff_virt, cmd_buff_address); let mut module = IntelHDA { diff --git a/ihdad/src/hda/stream.rs b/ihdad/src/hda/stream.rs index 0f46da305a..4a77314b62 100644 --- a/ihdad/src/hda/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -209,12 +209,10 @@ pub struct OutputStream { impl OutputStream { pub fn new(block_count: usize, block_length: usize, regs: &'static mut StreamDescriptorRegs) -> OutputStream { - unsafe { - OutputStream { - buff: StreamBuffer::new(block_length, block_count).unwrap(), + OutputStream { + buff: StreamBuffer::new(block_length, block_count).unwrap(), - desc_regs: regs, - } + desc_regs: regs, } } diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 3fe24d8713..6e7543cb4e 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -77,7 +77,7 @@ fn main() { let mut irq = [0; 8]; irq_file.read(&mut irq)?; - if unsafe { device_irq.borrow_mut().irq() } { + if device_irq.borrow_mut().irq() { irq_file.write(&mut irq)?; let mut todo = todo_irq.borrow_mut(); diff --git a/ixgbed/src/device.rs b/ixgbed/src/device.rs index 0f532129ec..94e9e59c32 100644 --- a/ixgbed/src/device.rs +++ b/ixgbed/src/device.rs @@ -75,10 +75,8 @@ impl SchemeBlockMut for Intel8259x { let i = cmp::min(buf.len(), data.len()); buf[..i].copy_from_slice(&data[..i]); - unsafe { desc.read.pkt_addr = self.receive_buffer[self.receive_index].physical() as u64; desc.read.hdr_addr = 0; - } self.write_reg(IXGBE_RDT(0), self.receive_index as u32); self.receive_index = wrap_ring(self.receive_index, self.receive_ring.len()); @@ -131,7 +129,6 @@ impl SchemeBlockMut for Intel8259x { let i = cmp::min(buf.len(), data.len()); data[..i].copy_from_slice(&buf[..i]); - unsafe { desc.read.cmd_type_len = IXGBE_ADVTXD_DCMD_EOP | IXGBE_ADVTXD_DCMD_RS | IXGBE_ADVTXD_DCMD_IFCS @@ -140,7 +137,6 @@ impl SchemeBlockMut for Intel8259x { | buf.len() as u32; desc.read.olinfo_status = (buf.len() as u32) << IXGBE_ADVTXD_PAYLEN_SHIFT; - } self.transmit_index = wrap_ring(self.transmit_index, self.transmit_ring.len()); self.transmit_ring_free -= 1; @@ -506,10 +502,8 @@ impl Intel8259x { } for i in 0..self.receive_ring.len() { - unsafe { - self.receive_ring[i].read.pkt_addr = self.receive_buffer[i].physical() as u64; - self.receive_ring[i].read.hdr_addr = 0; - } + self.receive_ring[i].read.pkt_addr = self.receive_buffer[i].physical() as u64; + self.receive_ring[i].read.hdr_addr = 0; } // enable queue and wait if necessary @@ -536,9 +530,7 @@ impl Intel8259x { } for i in 0..self.transmit_ring.len() { - unsafe { - self.transmit_ring[i].read.buffer_addr = self.transmit_buffer[i].physical() as u64; - } + self.transmit_ring[i].read.buffer_addr = self.transmit_buffer[i].physical() as u64; } // tx queue starts out empty diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index d593aa387a..f3ff909a34 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -95,10 +95,10 @@ fn main() { .expect("ixgbed: failed to map address") }; { - let device = Arc::new(RefCell::new(unsafe { + let device = Arc::new(RefCell::new( device::Intel8259x::new(address, IXGBE_MMIO_SIZE) .expect("ixgbed: failed to allocate device") - })); + )); let mut event_queue = EventQueue::::new().expect("ixgbed: failed to create event queue"); @@ -116,7 +116,7 @@ fn main() { move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; - if unsafe { device_irq.borrow().irq() } { + if device_irq.borrow().irq() { irq_file.write(&irq)?; if handle_update( From 24aa9192cb64b6c591c79f1c247690da38e721f2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Jul 2020 22:23:34 -0600 Subject: [PATCH 0422/1301] pcid: Fix extra newlines in log --- pcid/src/main.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 1fd195b62f..249f75a6a2 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -246,8 +246,6 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, } } - string.push('\n'); - info!("{}", string); for driver in config.drivers.iter() { From bbec25fa3b31b87faa7ba123123869837701a20b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Jul 2020 22:24:12 -0600 Subject: [PATCH 0423/1301] ps2d: better error logging --- ps2d/src/controller.rs | 55 +++++++++++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 1d758446be..6866c6f7b0 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -200,6 +200,8 @@ impl Ps2 { } pub fn init(&mut self) -> bool { + let mut b = 0; + // Clear remaining data self.flush_read("init start"); @@ -233,12 +235,14 @@ impl Ps2 { self.flush_read("enable"); // Reset keyboard - if self.keyboard_command(KeyboardCommand::Reset) == 0xFA { - if self.read() != 0xAA { - println!("ps2d: keyboard failed self test"); + b = self.keyboard_command(KeyboardCommand::Reset); + if b == 0xFA { + b = self.read(); + if b != 0xAA { + println!("ps2d: keyboard failed self test: {:02X}", b); } } else { - println!("ps2d: keyboard failed to reset"); + println!("ps2d: keyboard failed to reset: {:02X}", b); } // Clear remaining data @@ -246,52 +250,63 @@ impl Ps2 { // Set scancode set to 2 let scancode_set = 2; - if self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set) != 0xFA { - println!("ps2d: keyboard failed to set scancode set {}", scancode_set); + b = self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set); + if b != 0xFA { + println!("ps2d: keyboard failed to set scancode set {}: {:02X}", scancode_set, b); } // Enable data reporting - if self.keyboard_command(KeyboardCommand::EnableReporting) != 0xFA { - println!("ps2d: keyboard failed to enable reporting"); + b = self.keyboard_command(KeyboardCommand::EnableReporting); + if b != 0xFA { + println!("ps2d: keyboard failed to enable reporting: {:02X}", b); } // Reset mouse and set up scroll - if self.mouse_command(MouseCommand::Reset) == 0xFA { - let a = self.read(); - let b = self.read(); - if a != 0xAA || b != 0x00 { - println!("ps2d: mouse failed self test"); + b = self.mouse_command(MouseCommand::Reset); + if b == 0xFA { + b = self.read(); + if b != 0xAA { + println!("ps2d: mouse failed self test 1: {:02X}", b); + } + + b = self.read(); + if b != 0x00 { + println!("ps2d: mouse failed self test 2: {:02X}", b); } } else { - println!("ps2d: mouse failed to reset"); + println!("ps2d: mouse failed to reset: {:02X}", b); } // Clear remaining data self.flush_read("mouse defaults"); // Enable extra packet on mouse + //TODO: show error return values if self.mouse_command_data(MouseCommandData::SetSampleRate, 200) != 0xFA || self.mouse_command_data(MouseCommandData::SetSampleRate, 100) != 0xFA || self.mouse_command_data(MouseCommandData::SetSampleRate, 80) != 0xFA { println!("ps2d: mouse failed to enable extra packet"); } - let mouse_extra = if self.mouse_command(MouseCommand::GetDeviceId) == 0xFA { + b = self.mouse_command(MouseCommand::GetDeviceId); + let mouse_extra = if b == 0xFA { self.read() == 3 } else { - println!("ps2d: mouse failed to get device id"); + println!("ps2d: mouse failed to get device id: {:02X}", b); false }; // Set sample rate to maximum let sample_rate = 200; - if self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate) != 0xFA { - println!("ps2d: mouse failed to set sample rate to {}", sample_rate); + b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate); + if b != 0xFA { + println!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b); } // Enable data reporting - if self.mouse_command(MouseCommand::EnableReporting) != 0xFA { - println!("ps2d: mouse failed to enable reporting"); + b = self.mouse_command(MouseCommand::EnableReporting); + if b != 0xFA { + println!("ps2d: mouse failed to enable reporting: {:02X}", b); } // Enable clocks and interrupts From b99671d8bbe94753a90ba15a4587223e6e3240af Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 16 Jul 2020 16:33:29 -0600 Subject: [PATCH 0424/1301] Wait for vesad to create display: before continuing --- vesad/src/main.rs | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 9bcb62d251..e9fe865b86 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -1,13 +1,13 @@ -#![deny(warnings)] #![feature(allocator_api)] #![feature(asm)] extern crate orbclient; extern crate syscall; -use std::env; +use std::{env, process}; use std::fs::File; use std::io::{Read, Write}; +use std::os::unix::io::{RawFd, FromRawFd}; use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE}; use crate::mode_info::VBEModeInfo; @@ -49,7 +49,24 @@ fn main() { if physbaseptr > 0 { // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { + let mut pipes = [0; 2]; + syscall::pipe2(&mut pipes, 0).unwrap(); + let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; + let mut write = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; + let pid = unsafe { syscall::clone(0).unwrap() }; + if pid != 0 { + drop(write); + + let mut res = [0]; + if read.read(&mut res).unwrap() == res.len() { + process::exit(res[0] as i32); + } else { + eprintln!("vesad: daemon pipe EOF"); + process::exit(1); + } + } else { + drop(read); + let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); let size = width * height; @@ -62,6 +79,9 @@ fn main() { syscall::setrens(0, 0).expect("vesad: failed to enter null namespace"); + write.write(&[0]).unwrap(); + drop(write); + let mut blocked = Vec::new(); loop { let mut packet = Packet::default(); From a16604fc2cb78238317ed80a780c51875e321d51 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 19 Jul 2020 21:04:10 -0600 Subject: [PATCH 0425/1301] e1000d and rtl8168d will use pipe to wait for network: before continuing --- e1000d/src/main.rs | 24 ++++++++++++++++++++++-- rtl8168d/src/main.rs | 24 ++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index dd4800371e..a1f94334ad 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -5,7 +5,7 @@ extern crate netutils; extern crate syscall; use std::cell::RefCell; -use std::env; +use std::{env, process}; use std::fs::File; use std::io::{ErrorKind, Read, Result, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; @@ -77,7 +77,24 @@ fn main() { println!(" + E1000 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { + let mut pipes = [0; 2]; + syscall::pipe2(&mut pipes, 0).unwrap(); + let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; + let mut write = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; + let pid = unsafe { syscall::clone(0).unwrap() }; + if pid != 0 { + drop(write); + + let mut res = [0]; + if read.read(&mut res).unwrap() == res.len() { + process::exit(res[0] as i32); + } else { + eprintln!("e1000d: daemon pipe EOF"); + process::exit(1); + } + } else { + drop(read); + let socket_fd = syscall::open( ":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, @@ -107,6 +124,9 @@ fn main() { syscall::setrens(0, 0).expect("e1000d: failed to enter null namespace"); + write.write(&[0]).unwrap(); + drop(write); + let todo = Arc::new(RefCell::new(Vec::::new())); let device_irq = device.clone(); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 6b5e676f13..277c968807 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -5,7 +5,7 @@ extern crate netutils; extern crate syscall; use std::cell::RefCell; -use std::env; +use std::{env, process}; use std::fs::File; use std::io::{ErrorKind, Read, Result, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; @@ -77,7 +77,24 @@ fn main() { println!(" + RTL8168 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { + let mut pipes = [0; 2]; + syscall::pipe2(&mut pipes, 0).unwrap(); + let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; + let mut write = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; + let pid = unsafe { syscall::clone(0).unwrap() }; + if pid != 0 { + drop(write); + + let mut res = [0]; + if read.read(&mut res).unwrap() == res.len() { + process::exit(res[0] as i32); + } else { + eprintln!("rtl8168d: daemon pipe EOF"); + process::exit(1); + } + } else { + drop(read); + let socket_fd = syscall::open( ":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, @@ -107,6 +124,9 @@ fn main() { syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); + write.write(&[0]).unwrap(); + drop(write); + let todo = Arc::new(RefCell::new(Vec::::new())); let device_irq = device.clone(); From 5dfd5f7e7cc16d0edb746b957b8c5496500a6e86 Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Mon, 27 Jul 2020 22:49:39 -0700 Subject: [PATCH 0426/1301] Fixed PCI bus scan to scan bus 0xFF. Previously, the PCI bus scan was skipping bus 0xFF. Now it does not. I used a match expression to make sure that all cases are accounted for. I also changed the PCI dev scan and PCI func scan to use a match expression in a similar way to make sure all cases are account. While this is functionally the same as before, the match expression will not allow unhandled cases and should be easier to read and make it harder to introduce bugs. Signed-off-by: Wren Turkal --- pcid/src/pci/bus.rs | 21 +++++++++++---------- pcid/src/pci/dev.rs | 21 +++++++++++---------- pcid/src/pci/mod.rs | 23 ++++++++++++----------- 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/pcid/src/pci/bus.rs b/pcid/src/pci/bus.rs index 7678fad2fc..4c2a931f3f 100644 --- a/pcid/src/pci/bus.rs +++ b/pcid/src/pci/bus.rs @@ -20,7 +20,7 @@ impl<'pci> PciBus<'pci> { pub struct PciBusIter<'pci> { bus: &'pci PciBus<'pci>, - num: u32 + num: u8 } impl<'pci> PciBusIter<'pci> { @@ -35,15 +35,16 @@ impl<'pci> PciBusIter<'pci> { impl<'pci> Iterator for PciBusIter<'pci> { type Item = PciDev<'pci>; fn next(&mut self) -> Option { - if self.num < 32 { - let dev = PciDev { - bus: self.bus, - num: self.num as u8 - }; - self.num += 1; - Some(dev) - } else { - None + match self.num { + dev_num if dev_num < 32 => { + let dev = PciDev { + bus: self.bus, + num: self.num + }; + self.num += 1; + Some(dev) + }, + _ => None, } } } diff --git a/pcid/src/pci/dev.rs b/pcid/src/pci/dev.rs index 7cb7aa2926..ca2e505bb4 100644 --- a/pcid/src/pci/dev.rs +++ b/pcid/src/pci/dev.rs @@ -20,7 +20,7 @@ impl<'pci> PciDev<'pci> { pub struct PciDevIter<'pci> { dev: &'pci PciDev<'pci>, - num: u32 + num: u8 } impl<'pci> PciDevIter<'pci> { @@ -35,15 +35,16 @@ impl<'pci> PciDevIter<'pci> { impl<'pci> Iterator for PciDevIter<'pci> { type Item = PciFunc<'pci>; fn next(&mut self) -> Option { - if self.num < 8 { - let func = PciFunc { - dev: self.dev, - num: self.num as u8 - }; - self.num += 1; - Some(func) - } else { - None + match self.num { + func_num if func_num < 8 => { + let func = PciFunc { + dev: self.dev, + num: self.num + }; + self.num += 1; + Some(func) + }, + _ => None, } } } diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 3307c857c2..6bc80ebb0e 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -106,14 +106,14 @@ impl CfgAccess for Pci { pub struct PciIter<'pci> { pci: &'pci dyn CfgAccess, - num: u32 + num: Option } impl<'pci> PciIter<'pci> { pub fn new(pci: &'pci dyn CfgAccess) -> Self { PciIter { pci, - num: 0 + num: Some(0) } } } @@ -121,15 +121,16 @@ impl<'pci> PciIter<'pci> { impl<'pci> Iterator for PciIter<'pci> { type Item = PciBus<'pci>; fn next(&mut self) -> Option { - if self.num < 255 { /* TODO: Do not ignore 0xFF bus */ - let bus = PciBus { - pci: self.pci, - num: self.num as u8 - }; - self.num += 1; - Some(bus) - } else { - None + match self.num { + Some(bus_num) => { + let bus = PciBus { + pci: self.pci, + num: bus_num + }; + self.num = bus_num.checked_add(1); + Some(bus) + }, + None => None, } } } From 5db50db7a96b257ec50c5fd2a212aa6b5008b62f Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Fri, 31 Jul 2020 21:21:09 -0700 Subject: [PATCH 0427/1301] Fix buggy assertion in pcid capability parser. The pcid capability parsing code has an assertion that checks for dword alignment. Unfortunately, the check was previously checking for alignment to qwords. This fixes that. I found this issue by using qemu to emulate adding different pci devices. I managed to come across a device that had a capability aligned on dword, but not qword. That exposed the bug. Signed-off-by: Wren Turkal --- pcid/src/pci/cap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 8d5682079d..2e4f946a70 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -197,7 +197,7 @@ impl Capability { }) } unsafe fn parse(reader: &R, offset: u8) -> Self { - assert_eq!(offset & 0xF8, offset, "capability must be dword aligned"); + assert_eq!(offset & 0xFC, offset, "capability must be dword aligned"); let dword = reader.read_u32(u16::from(offset)); let capability_id = (dword & 0xFF) as u8; From 3323a143af7b8b48454533d7b40c48a8071d63fc Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Fri, 31 Jul 2020 21:58:28 -0700 Subject: [PATCH 0428/1301] Ignore all target directories. When working in an IDE like vscode, it uses rust infrastructure to check the code, which results in "target" folders in the base of the crates I am working on. For example, if I am working on pcid code, I get a "target" folder in the pcid folder. This change causes git to ignore all those target directories. Signed-off-by: Wren Turkal --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b83d22266a..2f7896d1d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -/target/ +target/ From 39fea644031aa945dbc462ac808227de08f54a92 Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Sat, 1 Aug 2020 00:40:30 -0700 Subject: [PATCH 0429/1301] Add pci vendor specific capability. Signed-off-by: Wren Turkal --- pcid/src/pci/cap.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 8d5682079d..24a1e805a9 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -43,9 +43,9 @@ pub enum CapabilityId { Msi = 0x05, MsiX = 0x11, Pcie = 0x10, + Vendor = 0x09, // function specific - Sata = 0x12, // only on AHCI functions } @@ -112,12 +112,18 @@ pub struct MsixCapability { pub c: u32, } +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] +pub struct VendorSpecificCapability { + pub data: Vec, +} + #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum Capability { Msi(MsiCapability), MsiX(MsixCapability), Pcie(PcieCapability), PwrMgmt(PwrMgmtCapability), + Vendor(VendorSpecificCapability), FunctionSpecific(u8, Vec), // TODO: Arrayvec Other(u8), } @@ -175,6 +181,16 @@ impl Capability { b: reader.read_u32(u16::from(offset + 4)), }) } + unsafe fn parse_vendor(reader: &R, offset: u8) -> Self { + log::info!("Vendor specific offset: {}", offset); + log::info!("Vendor specific next: {}", reader.read_u8((offset+1).into())); + let length = reader.read_u8(u16::from(offset+2)); + log::info!("Vendor specific cap len: {}", length); + let mut raw_data = reader.read_range(offset.into(), length.into()); + Self::Vendor(VendorSpecificCapability { + data: raw_data.drain(3..).collect(), + }) + } unsafe fn parse_pcie(reader: &R, offset: u8) -> Self { let offset = u16::from(offset); @@ -210,6 +226,8 @@ impl Capability { Self::parse_pcie(reader, offset) } else if capability_id == CapabilityId::PwrMgmt as u8{ Self::parse_pwr(reader, offset) + } else if capability_id == CapabilityId::Vendor as u8 { + Self::parse_vendor(reader, offset) } else if capability_id == CapabilityId::Sata as u8 { Self::FunctionSpecific(capability_id, reader.read_range(offset.into(), 8)) } else { From 65982d5e028eb285fb8de5c8a0b0958656c10c2f Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Sat, 1 Aug 2020 18:16:31 +0000 Subject: [PATCH 0430/1301] Add more structure cli to pcid. This change adds a structopt commandline interface to the pcid tool. This add some help for the arguments that pcid takes. Signed-off-by: Wren Turkal --- Cargo.lock | 111 +++++++++++++++++++++++++++++++++++++++++++++++ pcid/Cargo.toml | 2 + pcid/src/main.rs | 31 ++++++++++--- 3 files changed, 137 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e293e0c3cf..b50721cc2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,6 +322,14 @@ dependencies = [ "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "hermit-abi" version = "0.1.14" @@ -619,6 +627,30 @@ dependencies = [ "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "paw" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "paw-attributes 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "paw-raw 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "paw-attributes" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "paw-raw" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "pbr" version = "1.0.3" @@ -639,12 +671,14 @@ dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "paw 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -689,6 +723,30 @@ name = "plain" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "proc-macro-error" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro-hack" version = "0.5.16" @@ -1019,6 +1077,28 @@ name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "structopt" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "structopt-derive" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "syn" version = "1.0.31" @@ -1029,6 +1109,16 @@ dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "syn-mid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termion" version = "1.5.5" @@ -1099,6 +1189,11 @@ dependencies = [ "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-width" version = "0.1.7" @@ -1180,6 +1275,11 @@ name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vesad" version = "0.1.0" @@ -1295,6 +1395,7 @@ dependencies = [ "checksum futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" "checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" "checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" @@ -1326,12 +1427,17 @@ dependencies = [ "checksum parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" "checksum parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" +"checksum paw 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09c0fc9b564dbc3dc2ed7c92c0c144f4de340aa94514ce2b446065417c4084e9" +"checksum paw-attributes 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" +"checksum paw-raw 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" "checksum pbr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74333e3d1d8bced07fd0b8599304825684bcdb4a1fcc6fa6a470e6e08cefd254" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pin-project 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)" = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17" "checksum pin-project-internal 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7" "checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" "checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +"checksum proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880" +"checksum proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50" "checksum proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" "checksum proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" "checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" @@ -1370,7 +1476,10 @@ dependencies = [ "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" "checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" "checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum structopt 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "de2f5e239ee807089b62adce73e48c625e0ed80df02c7ab3f068f5db5281065c" +"checksum structopt-derive 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "510413f9de616762a4fbeab62509bf15c729603b72d7cd71280fbca431b1c118" "checksum syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" +"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" @@ -1379,6 +1488,7 @@ dependencies = [ "checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" +"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" @@ -1386,6 +1496,7 @@ dependencies = [ "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" "checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" "checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" "checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 71c5682ed4..bb65204eae 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -17,11 +17,13 @@ bitflags = "1" byteorder = "1.2" libc = "0.2" log = "0.4" +paw = "1.0" plain = "0.2" redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = "1" +structopt = { version = "0.3", default-features = false, features = [ "paw" ] } thiserror = "1" toml = "0.5" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 249f75a6a2..527bcc0281 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -9,6 +9,7 @@ use std::{env, io, i64, thread}; use syscall::iopl; +use structopt::StructOpt; use log::{error, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; @@ -22,6 +23,18 @@ mod driver_interface; mod pci; mod pcie; +#[derive(StructOpt)] +#[structopt(about)] +struct Args { + #[structopt(short, long, + help="Increase logging level once for each arg.", parse(from_occurrences))] + verbose: u8, + + #[structopt( + help="A path to a pcid config file or a directory that contains pcid config files.")] + config_path: Option, +} + pub struct DriverHandler { config: config::DriverConfig, bus_num: u8, @@ -473,12 +486,17 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, } } -fn setup_logging() -> Option<&'static RedoxLogger> { +fn setup_logging(verbosity: u8) -> Option<&'static RedoxLogger> { + let log_level = match verbosity { + 0 => log::LevelFilter::Info, + 1 => log::LevelFilter::Debug, + _ => log::LevelFilter::Trace, + }; let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() .with_ansi_escape_codes() - .with_filter(log::LevelFilter::Info) + .with_filter(log_level) .flush_on_newline(true) .build() ); @@ -513,11 +531,11 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } } -fn main() { +#[paw::main] +fn main(args: Args) { let mut config = Config::default(); - let mut args = env::args().skip(1); - if let Some(config_path) = args.next() { + if let Some(config_path) = args.config_path { if metadata(&config_path).unwrap().is_file() { if let Ok(mut config_file) = File::open(&config_path) { let mut config_data = String::new(); @@ -538,12 +556,11 @@ fn main() { } } } - config = toml::from_str(&config_data).unwrap_or(Config::default()); } } - let _logger_ref = setup_logging(); + let _logger_ref = setup_logging(args.verbose); let pci = Arc::new(Pci::new()); From dadc0c6c10581bace76795fdc61e35d9b558b60f Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Sat, 1 Aug 2020 12:48:06 -0700 Subject: [PATCH 0431/1301] Remove unused imports. Signed-off-by: Wren Turkal --- pcid/src/driver_interface/mod.rs | 2 +- pcid/src/main.rs | 4 +--- pcid/src/pci/bus.rs | 2 +- pcid/src/pcie/mod.rs | 1 - 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 3716574c10..0b0a5c1009 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -1,4 +1,4 @@ -use std::fs::{File, OpenOptions}; +use std::fs::File; use std::io::prelude::*; use std::{env, io}; diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 527bcc0281..b66e9ea3fd 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -5,9 +5,7 @@ use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; use std::process::Command; use std::sync::{Arc, Mutex}; -use std::{env, io, i64, thread}; - -use syscall::iopl; +use std::{i64, thread}; use structopt::StructOpt; use log::{error, info, warn, trace}; diff --git a/pcid/src/pci/bus.rs b/pcid/src/pci/bus.rs index 4c2a931f3f..0211c6d4ac 100644 --- a/pcid/src/pci/bus.rs +++ b/pcid/src/pci/bus.rs @@ -1,4 +1,4 @@ -use super::{Pci, PciDev, CfgAccess}; +use super::{PciDev, CfgAccess}; pub struct PciBus<'pci> { pub pci: &'pci dyn CfgAccess, diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 453aef8b0c..6536c954f8 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -3,7 +3,6 @@ use std::collections::BTreeMap; use std::sync::{Arc, Mutex}; use syscall::flag::PhysmapFlags; -use syscall::io::Dma; use smallvec::SmallVec; From 6018b6fc491e41ac9ea3577b4b70384f950dfa4f Mon Sep 17 00:00:00 2001 From: Wren Turkal Date: Sat, 1 Aug 2020 16:52:47 -0700 Subject: [PATCH 0432/1301] Fix lint issues from rustc. Signed-off-by: Wren Turkal --- ahcid/src/scheme.rs | 2 +- e1000d/src/device.rs | 2 +- pcid/src/pci/msi.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 48d0721d61..5d5e13f85a 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; use std::{cmp, str}; -use std::convert::{TryFrom, TryInto}; +use std::convert::{TryFrom}; use std::fmt::Write; use std::io::prelude::*; use std::io::SeekFrom; diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index bded679c9e..ef1c11cc8a 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,5 +1,5 @@ use std::collections::BTreeMap; -use std::{cmp, mem, ptr, slice, thread}; +use std::{cmp, mem, ptr, slice}; use netutils::setcfg; use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 145f611533..c8256389f5 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -105,7 +105,7 @@ impl MsiCapability { } pub fn set_multi_message_enable(&mut self, log_mme: u8) { let mut new_message_control = self.message_control() & (!Self::MC_MULTI_MESSAGE_ENABLE_MASK); - new_message_control |= (u16::from(log_mme) << Self::MC_MULTI_MESSAGE_ENABLE_SHIFT); + new_message_control |= u16::from(log_mme) << Self::MC_MULTI_MESSAGE_ENABLE_SHIFT; self.set_message_control(new_message_control); } From be101621cce424712ecd304de4096b2167857158 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 2 Aug 2020 15:25:03 -0600 Subject: [PATCH 0433/1301] Update to newer syscall --- Cargo.lock | 60 ++++++++++++++++++++-------------------- ahcid/src/ahci/hba.rs | 8 +++--- ahcid/src/main.rs | 2 +- alxd/src/main.rs | 2 +- e1000d/src/main.rs | 2 +- ihdad/src/main.rs | 2 +- nvmed/src/scheme.rs | 32 ++++++++++----------- pcid/src/lib.rs | 2 +- pcid/src/main.rs | 2 +- pcid/src/pci/mod.rs | 6 ++-- ps2d/src/main.rs | 2 +- ps2d/src/vm.rs | 2 +- rtl8168d/src/device.rs | 6 ++-- rtl8168d/src/main.rs | 2 +- usbscsid/src/scheme.rs | 18 ++++++------ vesad/src/display.rs | 12 ++++---- vesad/src/main.rs | 2 +- vesad/src/primitive.rs | 8 +++--- xhcid/src/xhci/scheme.rs | 22 ++++++++------- 19 files changed, 96 insertions(+), 96 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b50721cc2c..a92ac6aefb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ dependencies = [ "block-io-wrapper 0.1.0", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -18,7 +18,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -77,7 +77,7 @@ name = "bgad" version = "0.1.0" dependencies = [ "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -198,7 +198,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -354,7 +354,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -378,7 +378,7 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -494,7 +494,7 @@ dependencies = [ "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", "pbr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -569,7 +569,7 @@ dependencies = [ "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", "pcid 0.1.0", "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", - "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", + "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -583,7 +583,7 @@ name = "orbclient" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -612,7 +612,7 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -674,7 +674,7 @@ dependencies = [ "paw 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", - "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", + "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -687,7 +687,7 @@ dependencies = [ name = "pcspkrd" version = "0.1.0" dependencies = [ - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -771,7 +771,7 @@ version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -911,28 +911,28 @@ name = "redox_event" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/event.git#c31e3d3d5f44d60ff9fec2b1ee58b982e72c0d77" dependencies = [ - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.56" -source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#783a03dc73495b9a3b0e8a02bf8910cd91874888" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_syscall" +version = "0.2.0" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#a0ea09ceb3380b1d1e878bb18886e13742d34e8a" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "redox_syscall" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -942,7 +942,7 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1126,7 +1126,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1238,7 +1238,7 @@ version = "0.1.0" dependencies = [ "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", + "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] @@ -1267,7 +1267,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1286,7 +1286,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1350,7 +1350,7 @@ dependencies = [ "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", + "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1456,8 +1456,8 @@ dependencies = [ "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)" = "" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" -"checksum redox_syscall 0.1.56 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +"checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a" "checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 86764ec767..6fb268bc8b 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -75,7 +75,7 @@ impl HbaPort { pub fn start(&mut self) { while self.cmd.readf(HBA_PORT_CMD_CR) { - unsafe { asm!("pause"); } + unsafe { llvm_asm!("pause"); } } self.cmd.writef(HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST, true); @@ -85,7 +85,7 @@ impl HbaPort { self.cmd.writef(HBA_PORT_CMD_ST, false); while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { - unsafe { asm!("pause"); } + unsafe { llvm_asm!("pause"); } } self.cmd.writef(HBA_PORT_CMD_FRE, false); @@ -305,7 +305,7 @@ impl HbaPort { } while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - unsafe { asm!("pause"); } + unsafe { llvm_asm!("pause"); } } self.ci.writef(1 << slot, true); @@ -325,7 +325,7 @@ impl HbaPort { pub fn ata_stop(&mut self, slot: u32) -> Result<()> { while self.ata_running(slot) { - unsafe { asm!("pause"); } + unsafe { llvm_asm!("pause"); } } self.stop(); diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 513cf81a57..2b98e6d663 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -1,4 +1,4 @@ -#![feature(asm)] +#![feature(llvm_asm)] extern crate syscall; extern crate byteorder; diff --git a/alxd/src/main.rs b/alxd/src/main.rs index 4d0ac6c88b..0165894474 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] #![allow(non_upper_case_globals)] #![allow(unused_parens)] -#![feature(asm)] +#![feature(llvm_asm)] #![feature(concat_idents)] extern crate event; diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index a1f94334ad..e622201062 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -1,4 +1,4 @@ -#![feature(asm)] +#![feature(llvm_asm)] extern crate event; extern crate netutils; diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 6e7543cb4e..77e0cdfdf5 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -1,5 +1,5 @@ //#![deny(warnings)] -#![feature(asm)] +#![feature(llvm_asm)] extern crate bitflags; extern crate spin; diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index aabec0389e..4bedc114b3 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -424,38 +424,38 @@ impl SchemeBlockMut for DiskScheme { } } - fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result> { + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(ref mut handle, ref mut size) => { - let len = handle.len() as usize; + let len = handle.len() as isize; *size = match whence { SEEK_SET => cmp::min(len, pos), SEEK_CUR => { - cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize + cmp::max(0, cmp::min(len, *size as isize + pos)) } SEEK_END => { - cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize + cmp::max(0, cmp::min(len, len + pos)) } _ => return Err(Error::new(EINVAL)), - }; + } as usize; - Ok(Some(*size)) + Ok(Some(*size as isize)) } Handle::Disk(number, ref mut size) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let len = (disk.as_ref().blocks * disk.as_ref().block_size) as usize; + let len = (disk.as_ref().blocks * disk.as_ref().block_size) as isize; *size = match whence { SEEK_SET => cmp::min(len, pos), SEEK_CUR => { - cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize + cmp::max(0, cmp::min(len, *size as isize + pos)) } SEEK_END => { - cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize + cmp::max(0, cmp::min(len, len + pos)) } _ => return Err(Error::new(EINVAL)), - }; + } as usize; - Ok(Some(*size)) + Ok(Some(*size as isize)) } Handle::Partition(disk_num, part_num, ref mut size) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; @@ -467,20 +467,20 @@ impl SchemeBlockMut for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))?; - let len = (part.size * disk.as_ref().block_size) as usize; + let len = (part.size * disk.as_ref().block_size) as isize; *size = match whence { SEEK_SET => cmp::min(len, pos), SEEK_CUR => { - cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize + cmp::max(0, cmp::min(len, *size as isize + pos)) } SEEK_END => { - cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize + cmp::max(0, cmp::min(len, len + pos)) } _ => return Err(Error::new(EINVAL)), - }; + } as usize; - Ok(Some(*size)) + Ok(Some(*size as isize)) } } } diff --git a/pcid/src/lib.rs b/pcid/src/lib.rs index e03e5bfccf..bddde59abe 100644 --- a/pcid/src/lib.rs +++ b/pcid/src/lib.rs @@ -1,6 +1,6 @@ //! Interface to `pcid`. -#![feature(asm)] +#![feature(llvm_asm)] mod driver_interface; mod pci; diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 527bcc0281..09b0960ef4 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,4 +1,4 @@ -#![feature(asm)] +#![feature(llvm_asm)] use std::fs::{File, metadata, read_dir}; use std::io::prelude::*; diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 6bc80ebb0e..371b01580d 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -72,7 +72,7 @@ impl CfgAccess for Pci { let address = Self::address(bus, dev, func, offset); let value: u32; - asm!("mov dx, 0xCF8 + llvm_asm!("mov dx, 0xCF8 out dx, eax mov dx, 0xCFC in eax, dx" @@ -91,10 +91,10 @@ impl CfgAccess for Pci { let offset = u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); let address = Self::address(bus, dev, func, offset); - asm!("mov dx, 0xCF8 + llvm_asm!("mov dx, 0xCF8 out dx, eax" : : "{eax}"(address) : "dx" : "intel", "volatile"); - asm!("mov dx, 0xCFC + llvm_asm!("mov dx, 0xCFC out dx, eax" : : "{eax}"(value) : "dx" : "intel", "volatile"); } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 8d00348830..0b3ae6a484 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -1,4 +1,4 @@ -#![feature(asm)] +#![feature(llvm_asm)] #[macro_use] extern crate bitflags; diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index 36dc9dce60..be4b0ab443 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -33,7 +33,7 @@ pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32, u32, u32) { let si: u32; let di: u32; - asm!( + llvm_asm!( "in eax, dx" : "={eax}"(a), diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index a1b19c44c4..3245cbeeb3 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -163,7 +163,7 @@ impl SchemeBlockMut for Rtl8168 { self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet while self.regs.tppoll.readf(1 << 6) { - unsafe { asm!("pause"); } + unsafe { llvm_asm!("pause"); } } self.transmit_i += 1; @@ -171,7 +171,7 @@ impl SchemeBlockMut for Rtl8168 { return Ok(Some(i)); } - unsafe { asm!("pause"); } + unsafe { llvm_asm!("pause"); } } } @@ -293,7 +293,7 @@ impl Rtl8168 { println!(" - Reset"); self.regs.cmd.writef(1 << 4, true); while self.regs.cmd.readf(1 << 4) { - asm!("pause"); + llvm_asm!("pause"); } // Set up rx buffers diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 277c968807..0d143ab0b1 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -1,4 +1,4 @@ -#![feature(asm)] +#![feature(llvm_asm)] extern crate event; extern crate netutils; diff --git a/usbscsid/src/scheme.rs b/usbscsid/src/scheme.rs index 6b12fbcbee..f41291aa57 100644 --- a/usbscsid/src/scheme.rs +++ b/usbscsid/src/scheme.rs @@ -87,27 +87,27 @@ impl<'a> SchemeMut for ScsiScheme<'a> { buf[..min].copy_from_slice(&path[..min]); Ok(min) } - fn seek(&mut self, fd: usize, pos: usize, whence: usize) -> Result { + fn seek(&mut self, fd: usize, pos: isize, whence: usize) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { Handle::Disk(ref mut offset) => { - let len = self.scsi.get_disk_size() as usize; + let len = self.scsi.get_disk_size() as isize; *offset = match whence { SEEK_SET => cmp::max(0, cmp::min(pos, len)), - SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, len)), + SEEK_CUR => cmp::max(0, cmp::min(*offset as isize + pos, len)), SEEK_END => cmp::max(0, cmp::min(len + pos, len)), _ => return Err(Error::new(EINVAL)), - }; - Ok(*offset) + } as usize; + Ok(*offset as isize) } Handle::List(ref mut offset) => { - let len = LIST_CONTENTS.len(); + let len = LIST_CONTENTS.len() as isize; *offset = match whence { SEEK_SET => cmp::max(0, cmp::min(pos, len)), - SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, len)), + SEEK_CUR => cmp::max(0, cmp::min(*offset as isize + pos, len)), SEEK_END => cmp::max(0, cmp::min(len + pos, len)), _ => return Err(Error::new(EINVAL)), - }; - Ok(*offset) + } as usize; + Ok(*offset as isize) } } } diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 1b4f2cb8bb..a41456e087 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -1,11 +1,11 @@ #[cfg(feature="rusttype")] extern crate rusttype; -use std::alloc::{Alloc, Global, Layout}; +use std::alloc::{AllocInit, AllocRef, Global, Layout}; use std::{cmp, slice}; use std::ptr::NonNull; -use crate::primitive::{fast_set32, fast_set64, fast_copy}; +use crate::primitive::{fast_set32, fast_copy}; #[cfg(feature="rusttype")] use self::rusttype::{Font, FontCollection, Scale, point}; @@ -42,8 +42,7 @@ impl Display { #[cfg(not(feature="rusttype"))] pub fn new(width: usize, height: usize, onscreen: usize) -> Display { let size = width * height; - let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap().as_ptr() }; - unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; + let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096), AllocInit::Zeroed).unwrap().ptr.as_ptr() }; Display { width: width, height: height, @@ -55,8 +54,7 @@ impl Display { #[cfg(feature="rusttype")] pub fn new(width: usize, height: usize, onscreen: usize) -> Display { let size = width * height; - let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap().as_ptr() }; - unsafe { fast_set64(offscreen as *mut u64, 0, size/2) }; + let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096), AllocInit::Zeroed).unwrap().ptr.as_ptr() }; Display { width: width, height: height, @@ -74,7 +72,7 @@ impl Display { println!("Resize display to {}, {}", width, height); let size = width * height; - let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096)).unwrap().as_ptr() }; + let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096), AllocInit::Zeroed).unwrap().ptr.as_ptr() }; { let mut old_ptr = self.offscreen.as_ptr(); diff --git a/vesad/src/main.rs b/vesad/src/main.rs index e9fe865b86..1b78fe7765 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -1,5 +1,5 @@ #![feature(allocator_api)] -#![feature(asm)] +#![feature(llvm_asm)] extern crate orbclient; extern crate syscall; diff --git a/vesad/src/primitive.rs b/vesad/src/primitive.rs index 16c2536a24..519fd3ac94 100644 --- a/vesad/src/primitive.rs +++ b/vesad/src/primitive.rs @@ -2,7 +2,7 @@ #[inline(always)] #[cold] pub unsafe fn fast_copy(dst: *mut u8, src: *const u8, len: usize) { - asm!("cld + llvm_asm!("cld rep movsb" : : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len) @@ -14,7 +14,7 @@ pub unsafe fn fast_copy(dst: *mut u8, src: *const u8, len: usize) { #[inline(always)] #[cold] pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) { - asm!("cld + llvm_asm!("cld rep movsq" : : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len) @@ -26,7 +26,7 @@ pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) { #[inline(always)] #[cold] pub unsafe fn fast_set32(dst: *mut u32, src: u32, len: usize) { - asm!("cld + llvm_asm!("cld rep stosd" : : "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len) @@ -38,7 +38,7 @@ pub unsafe fn fast_set32(dst: *mut u32, src: u32, len: usize) { #[inline(always)] #[cold] pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) { - asm!("cld + llvm_asm!("cld rep stosq" : : "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 8370414a85..9804efd830 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1500,7 +1500,7 @@ impl Scheme for Xhci { Ok(src_len) } - fn seek(&self, fd: usize, pos: usize, whence: usize) -> Result { + fn seek(&self, fd: usize, pos: isize, whence: usize) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; trace!("SEEK fd={}, handle={:?}, pos {}, whence {}", fd, guard, pos, whence); @@ -1512,22 +1512,24 @@ impl Scheme for Xhci { | Handle::PortDesc(_, ref mut offset, ref buf) | Handle::Endpoints(_, ref mut offset, ref buf) | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref buf)) => { + let max = buf.len() as isize; *offset = match whence { - SEEK_SET => cmp::max(0, cmp::min(pos, buf.len())), - SEEK_CUR => cmp::max(0, cmp::min(*offset + pos, buf.len())), - SEEK_END => cmp::max(0, cmp::min(buf.len() + pos, buf.len())), + SEEK_SET => cmp::max(0, cmp::min(pos, max)), + SEEK_CUR => cmp::max(0, cmp::min(*offset as isize + pos, max)), + SEEK_END => cmp::max(0, cmp::min(max + pos, max)), _ => return Err(Error::new(EINVAL)), - }; - Ok(*offset) + } as usize; + Ok(*offset as isize) } Handle::PortState(_, ref mut offset) => { match whence { - SEEK_SET => *offset = pos, - SEEK_CUR => *offset = pos, - SEEK_END => *offset = pos, + //TODO: checks for invalid pos + SEEK_SET => *offset = pos as usize, + SEEK_CUR => *offset = pos as usize, + SEEK_END => *offset = pos as usize, _ => return Err(Error::new(EINVAL)), }; - Ok(*offset) + Ok(*offset as isize) } // Write-once configure or transfer Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) | Handle::PortReq(_, _) => { From 321f708d0f79bf84bb669bcf25db5a33cd303ac2 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 17 Aug 2020 14:39:17 +0200 Subject: [PATCH 0434/1301] vesad: Update redox_syscall --- Cargo.lock | 11 ++++++++++- vesad/Cargo.toml | 2 +- vesad/src/main.rs | 8 ++++---- vesad/src/scheme.rs | 16 ++++++++-------- vesad/src/screen/graphic.rs | 8 ++++---- vesad/src/screen/mod.rs | 2 +- vesad/src/screen/text.rs | 2 +- 7 files changed, 29 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a92ac6aefb..926cbdf962 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -919,6 +919,14 @@ name = "redox_syscall" version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "redox_syscall" +version = "0.2.0" +source = "git+https://gitlab.redox-os.org/redox-os/syscall?rev=4115e0f43547449ce56f7d7749732813e9505955#4115e0f43547449ce56f7d7749732813e9505955" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_syscall" version = "0.2.0" @@ -1286,7 +1294,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall?rev=4115e0f43547449ce56f7d7749732813e9505955)", "rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1458,6 +1466,7 @@ dependencies = [ "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" "checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" +"checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall?rev=4115e0f43547449ce56f7d7749732813e9505955)" = "" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a" "checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 6223c0672e..83620be64e 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" orbclient = "0.3.27" ransid = "0.4" rusttype = { version = "0.2", optional = true } -redox_syscall = "0.1" +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall", rev = "4115e0f43547449ce56f7d7749732813e9505955" } [features] default = [] diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 1b78fe7765..28c6cc5f66 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -38,7 +38,7 @@ fn main() { let physbaseptr; { - let mode_info = unsafe { &*(physmap(0x5200, 4096, 0).expect("vesad: failed to map VBE info") as *const VBEModeInfo) }; + let mode_info = unsafe { &*(physmap(0x5200, 4096, syscall::PhysmapFlags::empty()).expect("vesad: failed to map VBE info") as *const VBEModeInfo) }; width = mode_info.xresolution as usize; height = mode_info.yresolution as usize; @@ -53,7 +53,7 @@ fn main() { syscall::pipe2(&mut pipes, 0).unwrap(); let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; let mut write = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; - let pid = unsafe { syscall::clone(0).unwrap() }; + let pid = unsafe { syscall::clone(syscall::CloneFlags::empty()).unwrap() }; if pid != 0 { drop(write); @@ -113,7 +113,7 @@ fn main() { } for (handle_id, handle) in scheme.handles.iter_mut() { - if handle.events & EVENT_READ == 0 { + if handle.events.contains(EVENT_READ) { continue; } @@ -135,7 +135,7 @@ fn main() { gid: 0, a: syscall::number::SYS_FEVENT, b: *handle_id, - c: EVENT_READ, + c: EVENT_READ.bits(), d: count }; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 46eff7639a..17b392f56e 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::{mem, slice, str}; use orbclient::{Event, EventOption}; -use syscall::{Result, Error, EACCES, EBADF, EINVAL, ENOENT, O_NONBLOCK, Map, SchemeMut}; +use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut}; use crate::display::Display; use crate::screen::{Screen, GraphicScreen, TextScreen}; @@ -17,7 +17,7 @@ pub enum HandleKind { pub struct Handle { pub kind: HandleKind, pub flags: usize, - pub events: usize, + pub events: EventFlags, pub notified_read: bool } @@ -81,7 +81,7 @@ impl SchemeMut for DisplayScheme { self.handles.insert(id, Handle { kind: HandleKind::Input, flags: flags, - events: 0, + events: EventFlags::empty(), notified_read: false }); @@ -106,7 +106,7 @@ impl SchemeMut for DisplayScheme { self.handles.insert(id, Handle { kind: HandleKind::Screen(screen_i), flags: flags, - events: 0, + events: EventFlags::empty(), notified_read: false }); @@ -132,14 +132,14 @@ impl SchemeMut for DisplayScheme { Ok(new_id) } - fn fevent(&mut self, id: usize, flags: usize) -> Result { + fn fevent(&mut self, id: usize, flags: syscall::EventFlags) -> Result { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; handle.notified_read = false; if let HandleKind::Screen(_screen_i) = handle.kind { handle.events = flags; - Ok(0) + Ok(syscall::EventFlags::empty()) } else { Err(Error::new(EBADF)) } @@ -274,12 +274,12 @@ impl SchemeMut for DisplayScheme { } } - fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result { + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(screen_i) = handle.kind { if let Some(screen) = self.screens.get_mut(&screen_i) { - return screen.seek(pos, whence); + return screen.seek(pos, whence).map(|pos| pos as isize); } } diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 0cb6739594..1f5ac5ea3f 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -91,13 +91,13 @@ impl Screen for GraphicScreen { Ok(size * 4) } - fn seek(&mut self, pos: usize, whence: usize) -> Result { + fn seek(&mut self, pos: isize, whence: usize) -> Result { let size = self.display.offscreen.len(); self.seek = match whence { - SEEK_SET => cmp::min(size, pos/4), - SEEK_CUR => cmp::max(0, cmp::min(size as isize, self.seek as isize + (pos/4) as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(size as isize, size as isize + (pos/4) as isize)) as usize, + SEEK_SET => cmp::min(size, (pos/4) as usize), + SEEK_CUR => cmp::max(0, cmp::min(size as isize, self.seek as isize + (pos/4))) as usize, + SEEK_END => cmp::max(0, cmp::min(size as isize, size as isize + (pos/4))) as usize, _ => return Err(Error::new(EINVAL)) }; diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs index 9983728e5b..a37778ee8f 100644 --- a/vesad/src/screen/mod.rs +++ b/vesad/src/screen/mod.rs @@ -24,7 +24,7 @@ pub trait Screen { fn write(&mut self, buf: &[u8], sync: bool) -> Result; - fn seek(&mut self, pos: usize, whence: usize) -> Result; + fn seek(&mut self, pos: isize, whence: usize) -> Result; fn sync(&mut self); diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 38b7a2976f..9035cb4fad 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -209,7 +209,7 @@ impl Screen for TextScreen { Ok(buf.len()) } - fn seek(&mut self, _pos: usize, _whence: usize) -> Result { + fn seek(&mut self, _pos: isize, _whence: usize) -> Result { Ok(0) } From ac64d091860d6bd5c95c3d7d301aa835f46db142 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 17 Aug 2020 16:28:02 +0200 Subject: [PATCH 0435/1301] vesad: Provide legacy fmap implementation --- Cargo.lock | 203 +++++++++++++++++++++++++++++++++++--------- Cargo.toml | 1 + vesad/src/scheme.rs | 10 ++- 3 files changed, 174 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 926cbdf962..788a4fb4dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,10 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "adler" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ahcid" version = "0.1.0" @@ -11,6 +16,14 @@ dependencies = [ "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "aho-corasick" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "alxd" version = "0.1.0" @@ -76,7 +89,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.28", "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -118,6 +131,11 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cc" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.10" @@ -164,6 +182,14 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cmake" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crc" version = "1.8.1" @@ -172,6 +198,14 @@ dependencies = [ "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-channel" version = "0.4.2" @@ -201,11 +235,41 @@ dependencies = [ "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "encoding_rs" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "extra" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#0b50f3f2127fa62b1fe74090feffbae357266eac" +[[package]] +name = "filetime" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "flate2" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "miniz_oxide 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -442,6 +506,14 @@ name = "memchr" version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "miniz_oxide" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "mio" version = "0.6.14" @@ -514,16 +586,6 @@ dependencies = [ "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "num" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-iter 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-integer" version = "0.1.43" @@ -533,16 +595,6 @@ dependencies = [ "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "num-iter" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-traits" version = "0.2.12" @@ -580,11 +632,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "orbclient" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "0.3.28" dependencies = [ - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall?rev=4115e0f43547449ce56f7d7749732813e9505955)", + "sdl2 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -770,7 +821,7 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.28", "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -943,6 +994,22 @@ dependencies = [ "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "1.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rtl8168d" version = "0.1.0" @@ -993,24 +1060,27 @@ dependencies = [ [[package]] name = "sdl2" -version = "0.32.2" +version = "0.34.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "sdl2-sys" -version = "0.32.6" +version = "0.34.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "tar 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)", + "unidiff 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "version-compare 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1127,6 +1197,17 @@ dependencies = [ "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tar" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "filetime 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termion" version = "1.5.5" @@ -1164,6 +1245,14 @@ dependencies = [ "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "time" version = "0.1.43" @@ -1212,6 +1301,16 @@ name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unidiff" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "encoding_rs 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "url" version = "1.7.2" @@ -1235,7 +1334,7 @@ name = "usbhidd" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.28", "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] @@ -1273,7 +1372,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.28", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1283,6 +1382,11 @@ name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "version-compare" +version = "0.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "version_check" version = "0.9.2" @@ -1292,7 +1396,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.28", "ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall?rev=4115e0f43547449ce56f7d7749732813e9505955)", "rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1344,6 +1448,14 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "xattr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "xhcid" version = "0.1.0" @@ -1367,6 +1479,8 @@ dependencies = [ ] [metadata] +"checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" +"checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" "checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" @@ -1381,15 +1495,21 @@ dependencies = [ "checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" "checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +"checksum cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "" "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum cmake 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb" "checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +"checksum encoding_rs 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "e8ac63f94732332f44fe654443c46f6375d1939684c17b0afb6cb56b0456e171" "checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" +"checksum filetime 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" +"checksum flate2 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" @@ -1418,19 +1538,17 @@ dependencies = [ "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +"checksum miniz_oxide 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" "checksum mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix)" = "" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)" = "" "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)" = "" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" -"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" "checksum num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" -"checksum num-iter 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e6b7c748f995c4c29c5f5ae0248536e04a5739927c74ec0fa564805094b9f" "checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" -"checksum orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b18f57ab94fbd058e30aa57f712ec423c0bb7403f8493a6c58eef0c36d9402" "checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" "checksum parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" "checksum parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" @@ -1468,13 +1586,15 @@ dependencies = [ "checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" "checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall?rev=4115e0f43547449ce56f7d7749732813e9505955)" = "" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" +"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" "checksum rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a" "checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" "checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" "checksum scroll_derive 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e367622f934864ffa1c704ba2b82280aab856e3d8213c84c5720257eb34b15b9" -"checksum sdl2 0.32.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d051a07231e303f5f719da78cb6f7394f6d5b54f733aef5b0b447804a83edd7b" -"checksum sdl2-sys 0.32.6 (registry+https://github.com/rust-lang/crates.io-index)" = "34e71125077d297d57e4c1acfe8981b5bdfbf5a20e7b589abfdcb33bf1127f86" +"checksum sdl2 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)" = "29fb006600d16da4f1f1e5c7b398f44af2f1b476ff5f2e555651bd78cf4c18d8" +"checksum sdl2-sys 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed17d6d46b62b7df12134513bcc4f071268963e8c9bc8bf7ad983fbfb2bc3cc" "checksum serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243" "checksum serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57" "checksum serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226" @@ -1489,10 +1609,12 @@ dependencies = [ "checksum structopt-derive 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "510413f9de616762a4fbeab62509bf15c729603b72d7cd71280fbca431b1c118" "checksum syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" "checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" +"checksum tar 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)" = "c8a4c1d0bee3230179544336c15eefb563cf0302955d962e456542323e8c2e8a" "checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" "checksum thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" "checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" @@ -1500,11 +1622,13 @@ dependencies = [ "checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum unidiff 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d8a62719acf1933bfdbeb73a657ecd9ecece70b405125267dd549e2e2edc232c" "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" "checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" "checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" "checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +"checksum version-compare 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" "checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" "checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" @@ -1513,3 +1637,4 @@ dependencies = [ "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" diff --git a/Cargo.toml b/Cargo.toml index dd766edf78..cb5ec5297e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,3 +23,4 @@ members = [ [patch.crates-io] mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "redox-unix" } +orbclient = { path = "/home/user/redox-nix/forks/orbclient", version = "0.3.28" } diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 17b392f56e..60e0701750 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::{mem, slice, str}; use orbclient::{Event, EventOption}; -use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut}; +use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, OldMap, O_NONBLOCK, Result, SchemeMut}; use crate::display::Display; use crate::screen::{Screen, GraphicScreen, TextScreen}; @@ -156,6 +156,14 @@ impl SchemeMut for DisplayScheme { Err(Error::new(EBADF)) } + fn fmap_old(&mut self, id: usize, map: &syscall::OldMap) -> syscall::Result { + self.fmap(id, &Map { + offset: map.offset, + size: map.size, + flags: map.flags, + address: 0, + }) + } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; From 85411f2f91b86a8738f5f10ca8f42c98d0f6f1c3 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Mon, 17 Aug 2020 17:00:12 +0200 Subject: [PATCH 0436/1301] vesad: fix embarassing bug from last commit --- vesad/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 28c6cc5f66..e1249a1a2e 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -113,7 +113,7 @@ fn main() { } for (handle_id, handle) in scheme.handles.iter_mut() { - if handle.events.contains(EVENT_READ) { + if !handle.events.contains(EVENT_READ) { continue; } From ca2b3fa2d4a4b16d85b52afcfe9fac7a58f0bcd4 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Thu, 27 Aug 2020 17:55:01 +0200 Subject: [PATCH 0437/1301] Update to cargo release of redox_syscall --- Cargo.lock | 11 ++++++++++- vesad/Cargo.toml | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 788a4fb4dc..e9019e234d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -986,6 +986,14 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox_syscall" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_termios" version = "0.1.1" @@ -1398,7 +1406,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.28", "ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall?rev=4115e0f43547449ce56f7d7749732813e9505955)", + "redox_syscall 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1585,6 +1593,7 @@ dependencies = [ "checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" "checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" "checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall?rev=4115e0f43547449ce56f7d7749732813e9505955)" = "" +"checksum redox_syscall 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "48b82c2a1e8eb6e1bfde608de2bcbebd4072aa32d056ea48a986990cd5ca0f5a" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 83620be64e..dd2433f889 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" orbclient = "0.3.27" ransid = "0.4" rusttype = { version = "0.2", optional = true } -redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall", rev = "4115e0f43547449ce56f7d7749732813e9505955" } +redox_syscall = "0.2.1" [features] default = [] From c255a869ba17b0cc4d8619b559676e36ebbd34e3 Mon Sep 17 00:00:00 2001 From: jD91mZM2 Date: Thu, 29 Oct 2020 15:57:09 +0100 Subject: [PATCH 0438/1301] Don't use a local dependency lmao --- Cargo.lock | 36 +++++++++++++++++++++--------------- Cargo.toml | 2 +- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e9019e234d..e68091c90e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -89,7 +89,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.28", + "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -633,9 +633,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "orbclient" version = "0.3.28" +source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#d212107f84183a1375de9e958f7e4427fb35dc72" dependencies = [ - "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall?rev=4115e0f43547449ce56f7d7749732813e9505955)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", + "sdl2-sys 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -821,7 +825,7 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.28", + "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -938,6 +942,14 @@ dependencies = [ "vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "raw-window-handle" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -970,14 +982,6 @@ name = "redox_syscall" version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "redox_syscall" -version = "0.2.0" -source = "git+https://gitlab.redox-os.org/redox-os/syscall?rev=4115e0f43547449ce56f7d7749732813e9505955#4115e0f43547449ce56f7d7749732813e9505955" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "redox_syscall" version = "0.2.0" @@ -1074,6 +1078,7 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1342,7 +1347,7 @@ name = "usbhidd" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.28", + "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] @@ -1380,7 +1385,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.28", + "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1404,7 +1409,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.28", + "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", "ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1557,6 +1562,7 @@ dependencies = [ "checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" +"checksum orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)" = "" "checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" "checksum parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" "checksum parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" @@ -1587,12 +1593,12 @@ dependencies = [ "checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045" +"checksum raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)" = "" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" "checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" -"checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall?rev=4115e0f43547449ce56f7d7749732813e9505955)" = "" "checksum redox_syscall 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "48b82c2a1e8eb6e1bfde608de2bcbebd4072aa32d056ea48a986990cd5ca0f5a" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" diff --git a/Cargo.toml b/Cargo.toml index cb5ec5297e..b9af329cd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,4 +23,4 @@ members = [ [patch.crates-io] mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "redox-unix" } -orbclient = { path = "/home/user/redox-nix/forks/orbclient", version = "0.3.28" } +orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.28" } From 00b7674321ecb7a7ff8619f6501618007e71dcc0 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 8 Mar 2021 14:37:38 +0100 Subject: [PATCH 0439/1301] Use correct syscall when dropping PCIe context. --- pcid/src/pcie/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 6536c954f8..8a85929a31 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -207,7 +207,7 @@ impl CfgAccess for Pcie { impl Drop for Pcie { fn drop(&mut self) { for address in self.maps.lock().unwrap().values().copied() { - let _ = unsafe { syscall::physfree(address as usize, 4096) }; + let _ = unsafe { syscall::physunmap(address as usize) }; } } } From be984885bb58a5a1d2aaca05507b3c00ab3ed1cf Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 10 Mar 2021 11:24:27 +0100 Subject: [PATCH 0440/1301] WIP: Move ACPI code from kernel to drivers. --- Cargo.lock | 84 +- Cargo.toml | 1 + acpid/Cargo.toml | 14 + acpid/src/acpi.rs | 443 +++++++ acpid/src/aml/dataobj.rs | 184 +++ acpid/src/aml/mod.rs | 141 +++ acpid/src/aml/namedobj.rs | 1043 ++++++++++++++++ acpid/src/aml/namespace.rs | 486 ++++++++ acpid/src/aml/namespacemodifier.rs | 106 ++ acpid/src/aml/namestring.rs | 223 ++++ acpid/src/aml/parser.rs | 559 +++++++++ acpid/src/aml/parsermacros.rs | 52 + acpid/src/aml/pkglength.rs | 25 + acpid/src/aml/termlist.rs | 172 +++ acpid/src/aml/type1opcode.rs | 479 ++++++++ acpid/src/aml/type2opcode.rs | 1784 ++++++++++++++++++++++++++++ acpid/src/main.rs | 55 + vesad/src/scheme.rs | 5 +- 18 files changed, 5841 insertions(+), 15 deletions(-) create mode 100644 acpid/Cargo.toml create mode 100644 acpid/src/acpi.rs create mode 100644 acpid/src/aml/dataobj.rs create mode 100644 acpid/src/aml/mod.rs create mode 100644 acpid/src/aml/namedobj.rs create mode 100644 acpid/src/aml/namespace.rs create mode 100644 acpid/src/aml/namespacemodifier.rs create mode 100644 acpid/src/aml/namestring.rs create mode 100644 acpid/src/aml/parser.rs create mode 100644 acpid/src/aml/parsermacros.rs create mode 100644 acpid/src/aml/pkglength.rs create mode 100644 acpid/src/aml/termlist.rs create mode 100644 acpid/src/aml/type1opcode.rs create mode 100644 acpid/src/aml/type2opcode.rs create mode 100644 acpid/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index e68091c90e..4322c741b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,16 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "acpid" +version = "0.1.0" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "adler" version = "0.2.3" @@ -141,6 +152,11 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "chashmap" version = "2.2.2" @@ -422,6 +438,14 @@ dependencies = [ "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "iovec" version = "0.1.4" @@ -483,6 +507,14 @@ dependencies = [ "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "log" version = "0.4.8" @@ -622,7 +654,7 @@ dependencies = [ "pcid 0.1.0", "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -637,7 +669,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#d212107f84183a1 dependencies = [ "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", "sdl2-sys 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -659,6 +691,16 @@ dependencies = [ "parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lock_api 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot_core 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "parking_lot_core" version = "0.7.2" @@ -668,7 +710,20 @@ dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -732,7 +787,7 @@ dependencies = [ "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -965,7 +1020,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0#30f6 dependencies = [ "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -992,7 +1047,7 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.1" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1131,7 +1186,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "smallvec" -version = "1.4.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1296,7 +1351,7 @@ name = "unicode-normalization" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1411,7 +1466,7 @@ version = "0.1.0" dependencies = [ "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", "ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1486,7 +1541,7 @@ dependencies = [ "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1510,6 +1565,7 @@ dependencies = [ "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" "checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "" "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" @@ -1539,6 +1595,7 @@ dependencies = [ "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" "checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" @@ -1547,6 +1604,7 @@ dependencies = [ "checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" "checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" "checksum lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" +"checksum lock_api 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" @@ -1565,7 +1623,9 @@ dependencies = [ "checksum orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)" = "" "checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" "checksum parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" +"checksum parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" "checksum parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" +"checksum parking_lot_core 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" "checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" "checksum paw 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09c0fc9b564dbc3dc2ed7c92c0c144f4de340aa94514ce2b446065417c4084e9" "checksum paw-attributes 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" @@ -1599,7 +1659,7 @@ dependencies = [ "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" "checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" -"checksum redox_syscall 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "48b82c2a1e8eb6e1bfde608de2bcbebd4072aa32d056ea48a986990cd5ca0f5a" +"checksum redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" @@ -1614,7 +1674,7 @@ dependencies = [ "checksum serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57" "checksum serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cb5678e1615754284ec264d9bb5b4c27d2018577fd90ac0ceb578591ed5ee4" +"checksum smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" diff --git a/Cargo.toml b/Cargo.toml index b9af329cd3..28ffd6b8a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "acpid", "ahcid", "alxd", "bgad", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml new file mode 100644 index 0000000000..30041ea4fd --- /dev/null +++ b/acpid/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "acpid" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "0.4" +parking_lot = "0.11.1" +plain = "0.2.3" +redox_syscall = "0.2.5" +thiserror = "1" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs new file mode 100644 index 0000000000..10ece8899f --- /dev/null +++ b/acpid/src/acpi.rs @@ -0,0 +1,443 @@ +use std::collections::HashMap; +use std::convert::{TryFrom, TryInto}; +use std::mem; +use std::ops::Deref; +use std::sync::Arc; + +use syscall::flag::PhysmapFlags; + +use thiserror::Error; + +use super::aml::AmlValue; + +#[cfg(target_arch = "x86_64")] +pub const PAGE_SIZE: usize = 4096; + +/// The raw SDT header struct, as defined by the ACPI specification. +#[derive(Copy, Clone, Debug)] +#[repr(packed)] +pub struct SdtHeader { + pub signature: [u8; 4], + pub length: u32, + pub revision: u8, + pub checksum: u8, + pub oem_id: [u8; 6], + pub oem_table_id: [u8; 8], + pub oem_revision: u32, + pub creator_id: u32, + pub creator_revision: u32, +} +unsafe impl plain::Plain for SdtHeader {} + +impl SdtHeader { + pub fn signature(&self) -> SdtSignature { + SdtSignature { + signature: self.signature, + oem_id: self.oem_id, + oem_table_id: self.oem_table_id, + } + } + fn length(&self) -> usize { + self + .length + .try_into() + .expect("expected usize to be at least 32 bits") + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub struct SdtSignature { + pub signature: [u8; 4], + pub oem_id: [u8; 6], + pub oem_table_id: [u8; 8], +} + +#[derive(Debug, Error)] +pub enum TablePhysLoadError { + // TODO: Make syscall::Error implement std::error::Error, when enabling a Cargo feature. + #[error("i/o error: {0}")] + Io(#[from] std::io::Error), + + #[error("invalid SDT: {0}")] + Validity(#[from] InvalidSdtError), +} +#[derive(Debug, Error)] +pub enum InvalidSdtError { + #[error("invalid size")] + InvalidSize, + + #[error("invalid checksum")] + BadChecksum, +} + +struct PhysmapGuard { + virt: *const u8, + size: usize, +} +impl PhysmapGuard { + fn map(page: usize, page_count: usize) -> std::io::Result { + let size = page_count * PAGE_SIZE; + let virt = unsafe { + syscall::call::physmap(page, size, PhysmapFlags::empty()) + .map_err(|error| std::io::Error::from_raw_os_error(error.errno))? + }; + + Ok(Self { + virt: virt as *const u8, + size, + }) + } +} +impl Deref for PhysmapGuard { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + unsafe { + std::slice::from_raw_parts(self.virt as *const u8, self.size) + } + } +} +impl Drop for PhysmapGuard { + fn drop(&mut self) { + unsafe { + syscall::physfree(self.virt as usize, self.size); + } + } +} + +#[derive(Clone)] +pub struct Sdt(Arc<[u8]>); + +impl Sdt { + pub fn new(slice: Arc<[u8]>) -> Result { + let header = match plain::from_bytes::(&slice) { + Ok(header) => header, + Err(plain::Error::TooShort) => return Err(InvalidSdtError::InvalidSize), + Err(plain::Error::BadAlignment) => panic!("plain::from_bytes failed due to alignment, but SdtHeader is #[repr(packed)]!"), + }; + + if header.length() != slice.len() { + return Err(InvalidSdtError::InvalidSize); + } + + let checksum = slice.iter().copied().fold(0_u8, |current_sum, item| current_sum.wrapping_add(item)); + + if checksum != 0 { + return Err(InvalidSdtError::BadChecksum); + } + + Ok(Self(slice)) + } + pub fn load_from_physical(physaddr: usize) -> Result { + let physaddr_start_page = physaddr / PAGE_SIZE * PAGE_SIZE; + let physaddr_page_offset = physaddr % PAGE_SIZE; + + // Begin by reading and validating the header first. The SDT header is always 36 bytes + // long, and can thus span either one or two page table frames. + let needs_extra_page = (PAGE_SIZE - physaddr_page_offset).checked_sub(mem::size_of::()).is_none(); + let page_table_count = 1 + if needs_extra_page { 1 } else { 0 }; + + let pages = PhysmapGuard::map(physaddr_start_page, page_table_count)?; + assert!(pages.len() >= mem::size_of::()); + let sdt_mem = &pages[physaddr_page_offset..]; + + let sdt = plain::from_bytes::(&pages[mem::size_of::()..]) + .expect("either alignment is wrong, or the length is too short, both of which are already checked for"); + + let total_length = sdt.length(); + let base_length = std::cmp::min(total_length, sdt_mem.len()); + let extended_length = total_length - base_length; + + let mut loaded = sdt_mem[..base_length].to_owned(); + loaded.reserve(extended_length); + + const SIMULTANEOUS_PAGE_COUNT: usize = 4; + + let mut left = extended_length; + let mut offset = physaddr_start_page + page_table_count * PAGE_SIZE; + let length_per_iteration = PAGE_SIZE * SIMULTANEOUS_PAGE_COUNT; + + while left > 0 { + let to_copy = std::cmp::min(left, length_per_iteration); + let pages = PhysmapGuard::map(offset, length_per_iteration)?; + + loaded.extend(&pages[..to_copy]); + + left -= to_copy; + offset += to_copy; + } + assert_eq!(offset, loaded.len()); + + Self::new(loaded.into()).map_err(Into::into) + } +} + +impl Deref for Sdt { + type Target = SdtHeader; + + fn deref(&self) -> &Self::Target { + plain::from_bytes::(&self.0) + .expect("expected already validated Sdt to be able to get its header") + } +} + +impl Sdt { + pub fn data(&self) -> &[u8] { + &self.0[mem::size_of::()..] + } +} + +pub struct Dsdt(Sdt); +pub struct Ssdt(Sdt); + +pub struct AcpiContext { + tables: Vec, + dsdt: Option, + fadt: Option, + namespace: Option>, +} +impl AcpiContext { + pub fn dsdt(&self) -> Option<&Dsdt> { + self.dsdt.as_ref() + } + pub fn ssdts(&self) -> impl Iterator + '_ { + self.find_multiple_sdts(*b"SSDT").map(|sdt| Ssdt(sdt.clone())) + } + fn find_single_sdt_pos(&self, signature: [u8; 4]) -> Option { + let count = self.tables.iter().filter(|sdt| sdt.signature == signature).count(); + + if count > 1 { + log::warn!("Expected only a single SDT of signature `{}` ({:?}), but there were {}", String::from_utf8_lossy(&signature), signature, count); + } + + self.tables.iter().position(|sdt| sdt.signature == signature) + } + pub fn find_single_sdt(&self, signature: [u8; 4]) -> Option<&Sdt> { + self.find_single_sdt_pos(signature).map(|pos| &self.tables[pos]) + } + pub fn find_multiple_sdts<'a>(&'a self, signature: [u8; 4]) -> impl Iterator { + self.tables.iter().filter(move |sdt| sdt.signature == signature) + } + pub fn take_single_sdt(&mut self, signature: [u8; 4]) -> Option { + self.find_single_sdt_pos(signature).map(|pos| self.tables[pos].clone()) + } + pub fn namespace(&self) -> Option<&HashMap> { + self.namespace.as_ref() + } + pub fn fadt(&self) -> Option<&Fadt> { + self.fadt.as_ref() + } + pub fn sdt_from_signature(&self, signature: &SdtSignature) -> Option<&Sdt> { + self.tables.iter().find(|sdt| sdt.signature == signature.signature && sdt.oem_id == signature.oem_id && sdt.oem_table_id == signature.oem_table_id) + } + pub fn get_signature_from_index(&self, index: usize) -> Option { + todo!() + } + pub fn get_index_from_signature(&self, signature: &SdtSignature) -> Option { + todo!() + } +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct FadtStruct { + pub header: SdtHeader, + pub firmware_ctrl: u32, + pub dsdt: u32, + + // field used in ACPI 1.0; no longer in use, for compatibility only + reserved: u8, + + pub preferred_power_managament: u8, + pub sci_interrupt: u16, + pub smi_command_port: u32, + pub acpi_enable: u8, + pub acpi_disable: u8, + pub s4_bios_req: u8, + pub pstate_control: u8, + pub pm1a_event_block: u32, + pub pm1b_event_block: u32, + pub pm1a_control_block: u32, + pub pm1b_control_block: u32, + pub pm2_control_block: u32, + pub pm_timer_block: u32, + pub gpe0_block: u32, + pub gpe1_block: u32, + pub pm1_event_length: u8, + pub pm1_control_length: u8, + pub pm2_control_length: u8, + pub pm_timer_length: u8, + pub gpe0_ength: u8, + pub gpe1_length: u8, + pub gpe1_base: u8, + pub c_state_control: u8, + pub worst_c2_latency: u16, + pub worst_c3_latency: u16, + pub flush_size: u16, + pub flush_stride: u16, + pub duty_offset: u8, + pub duty_width: u8, + pub day_alarm: u8, + pub month_alarm: u8, + pub century: u8, + + // reserved in ACPI 1.0; used since ACPI 2.0+ + pub boot_architecture_flags: u16, + + reserved2: u8, + pub flags: u32, +} +unsafe impl plain::Plain for FadtStruct {} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct GenericAddressStructure { + address_space: u8, + bit_width: u8, + bit_offset: u8, + access_size: u8, + address: u64, +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct FadtAcpi2Struct { + // 12 byte structure; see below for details + pub reset_reg: GenericAddressStructure, + + pub reset_value: u8, + reserved3: [u8; 3], + + // 64bit pointers - Available on ACPI 2.0+ + pub x_firmware_control: u64, + pub x_dsdt: u64, + + pub x_pm1a_event_block: GenericAddressStructure, + pub x_pm1b_event_block: GenericAddressStructure, + pub x_pm1a_control_block: GenericAddressStructure, + pub x_pm1b_control_block: GenericAddressStructure, + pub x_pm2_control_block: GenericAddressStructure, + pub x_pm_timer_block: GenericAddressStructure, + pub x_gpe0_block: GenericAddressStructure, + pub x_gpe1_block: GenericAddressStructure, +} +unsafe impl plain::Plain for FadtAcpi2Struct {} + +pub struct Fadt(Sdt); + +impl Fadt { + pub fn acpi_2_struct(&self) -> Option<&FadtAcpi2Struct> { + let bytes = &self.0.0[mem::size_of::()..]; + + match plain::from_bytes::(bytes) { + Ok(fadt2) => Some(fadt2), + Err(plain::Error::TooShort) => None, + Err(plain::Error::BadAlignment) => unreachable!("plain::from_bytes reported bad alignment, but FadtAcpi2Struct is #[repr(packed)]"), + } + } +} + +impl Deref for Fadt { + type Target = FadtStruct; + + fn deref(&self) -> &Self::Target { + plain::from_bytes::(&self.0.0) + .expect("expected FADT struct to already be validated in Deref impl") + } +} + +impl Fadt { + pub fn new(context: &AcpiContext, sdt: Sdt) -> Option { + if sdt.signature != *b"FACP" || sdt.length() < mem::size_of::() { + return None; + } + Some(Fadt(sdt)) + } + + pub fn init(context: &mut AcpiContext) { + let fadt_sdt = context + .take_single_sdt(*b"FACP") + .expect("expected ACPI to always have a FADT"); + + let fadt = match Fadt::new(context, fadt_sdt) { + Some(fadt) => fadt, + None => { + log::error!("Failed to find FADT"); + return; + } + }; + + let dsdt_ptr = match fadt.acpi_2_struct() { + Some(fadt2) => usize::try_from(fadt2.x_dsdt).unwrap_or_else(|_| { + usize::try_from(fadt.dsdt) + .expect("expected any given u32 to fit within usize") + }), + None => usize::try_from(fadt.dsdt) + .expect("expected any given u32 to fit within usize") + }; + + log::info!(" FACP: {:X}", {dsdt_ptr}); + + let dsdt_sdt = match Sdt::load_from_physical(fadt.dsdt as usize) { + Ok(dsdt) => dsdt, + Err(error) => { + log::error!("Failed to load DSDT: {}", error); + return; + } + }; + + context.dsdt = Some(Dsdt(dsdt_sdt)); + + /* + let signature = get_sdt_signature(dsdt_sdt); + if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) { + ptrs.insert(signature, dsdt_sdt); + }*/ + } +} + +pub enum PossibleAmlTables { + Dsdt(Dsdt), + Ssdt(Ssdt), +} +impl PossibleAmlTables { + pub fn try_new(inner: Sdt) -> Option { + match &inner.signature { + b"DSDT" => Some(Self::Dsdt(Dsdt(inner))), + b"SSDT" => Some(Self::Ssdt(Ssdt(inner))), + _ => None, + } + } +} +impl AmlContainingTable for PossibleAmlTables { + fn aml(&self) -> &[u8] { + match self { + Self::Dsdt(dsdt) => dsdt.aml(), + Self::Ssdt(ssdt) => ssdt.aml(), + } + } +} + +pub trait AmlContainingTable { + fn aml(&self) -> &[u8]; +} + +impl AmlContainingTable for &T +where + T: AmlContainingTable, +{ + fn aml(&self) -> &[u8] { + T::aml(*self) + } +} + +impl AmlContainingTable for Dsdt { + fn aml(&self) -> &[u8] { + self.0.data() + } +} +impl AmlContainingTable for Ssdt { + fn aml(&self) -> &[u8] { + self.0.data() + } +} diff --git a/acpid/src/aml/dataobj.rs b/acpid/src/aml/dataobj.rs new file mode 100644 index 0000000000..6e4ab1da73 --- /dev/null +++ b/acpid/src/aml/dataobj.rs @@ -0,0 +1,184 @@ +use super::AmlError; +use super::parser::{ AmlParseType, ParseResult, AmlExecutionContext, ExecutionState }; +use super::namespace::{ AmlValue, ObjectReference }; + +use super::type2opcode::{parse_def_buffer, parse_def_package, parse_def_var_package}; +use super::termlist::parse_term_arg; +use super::namestring::parse_super_name; + +pub fn parse_data_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_computational_data, + parse_def_package, + parse_def_var_package + }; + + Err(AmlError::AmlInvalidOpCode) +} + +pub fn parse_data_ref_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_data_obj, + parse_term_arg + }; + + match parse_super_name(data, ctx) { + Ok(res) => match res.val { + AmlValue::String(s) => Ok(AmlParseType { + val: AmlValue::ObjectReference(ObjectReference::Object(s)), + len: res.len + }), + _ => Ok(res) + }, + Err(e) => Err(e) + } +} + +pub fn parse_arg_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + match data[0] { + 0x68 ..= 0x6E => Ok(AmlParseType { + val: AmlValue::ObjectReference(ObjectReference::ArgObj(data[0] - 0x68)), + len: 1 as usize + }), + _ => Err(AmlError::AmlInvalidOpCode) + } +} + +pub fn parse_local_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + match data[0] { + 0x68 ..= 0x6E => Ok(AmlParseType { + val: AmlValue::ObjectReference(ObjectReference::LocalObj(data[0] - 0x60)), + len: 1 as usize + }), + _ => Err(AmlError::AmlInvalidOpCode) + } +} + +fn parse_computational_data(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + match data[0] { + 0x0A => Ok(AmlParseType { + val: AmlValue::Integer(data[1] as u64), + len: 2 as usize + }), + 0x0B => { + let res = (data[1] as u16) + + ((data[2] as u16) << 8); + + Ok(AmlParseType { + val: AmlValue::Integer(res as u64), + len: 3 as usize + }) + }, + 0x0C => { + let res = (data[1] as u32) + + ((data[2] as u32) << 8) + + ((data[3] as u32) << 16) + + ((data[4] as u32) << 24); + + Ok(AmlParseType { + val: AmlValue::Integer(res as u64), + len: 5 as usize + }) + }, + 0x0D => { + let mut cur_ptr: usize = 1; + let mut cur_string: Vec = vec!(); + + while data[cur_ptr] != 0x00 { + cur_string.push(data[cur_ptr]); + cur_ptr += 1; + } + + match String::from_utf8(cur_string) { + Ok(s) => Ok(AmlParseType { + val: AmlValue::String(s.clone()), + len: s.clone().len() + 2 + }), + Err(_) => Err(AmlError::AmlParseError("String data - invalid string")) + } + }, + 0x0E => { + let res = (data[1] as u64) + + ((data[2] as u64) << 8) + + ((data[3] as u64) << 16) + + ((data[4] as u64) << 24) + + ((data[5] as u64) << 32) + + ((data[6] as u64) << 40) + + ((data[7] as u64) << 48) + + ((data[8] as u64) << 56); + + Ok(AmlParseType { + val: AmlValue::Integer(res as u64), + len: 9 as usize + }) + }, + 0x00 => Ok(AmlParseType { + val: AmlValue::IntegerConstant(0 as u64), + len: 1 as usize + }), + 0x01 => Ok(AmlParseType { + val: AmlValue::IntegerConstant(1 as u64), + len: 1 as usize + }), + 0x5B => if data[1] == 0x30 { + Ok(AmlParseType { + val: AmlValue::IntegerConstant(2017_0630 as u64), + len: 2 as usize + }) + } else { + Err(AmlError::AmlInvalidOpCode) + }, + 0xFF => Ok(AmlParseType { + val: AmlValue::IntegerConstant(0xFFFF_FFFF_FFFF_FFFF), + len: 1 as usize + }), + _ => parse_def_buffer(data, ctx) + } +} diff --git a/acpid/src/aml/mod.rs b/acpid/src/aml/mod.rs new file mode 100644 index 0000000000..903597afe2 --- /dev/null +++ b/acpid/src/aml/mod.rs @@ -0,0 +1,141 @@ +//! # AML +//! +//! Code to parse and execute ACPI Machine Language tables. + +use std::collections::HashMap; + +use syscall::io::{Io, Pio}; + +use crate::acpi::{AcpiContext, AmlContainingTable, Sdt, SdtHeader}; + +#[macro_use] +mod parsermacros; + +mod namespace; +mod termlist; +mod namespacemodifier; +mod pkglength; +mod namestring; +mod namedobj; +mod dataobj; +mod type1opcode; +mod type2opcode; +mod parser; + +use self::parser::AmlExecutionContext; +use self::termlist::parse_term_list; +pub use self::namespace::AmlValue; + +#[derive(Debug)] +pub enum AmlError { + AmlParseError(&'static str), + AmlInvalidOpCode, + AmlValueError, + AmlDeferredLoad, + AmlFatalError(u8, u16, AmlValue), + AmlHardFatal +} + +pub fn parse_aml_table(sdt: impl AmlContainingTable) -> Result, AmlError> { + parse_aml_with_scope(sdt, "\\".to_owned()) +} + +pub fn parse_aml_with_scope(sdt: impl AmlContainingTable, scope: String) -> Result, AmlError> { + let data = sdt.aml(); + let mut ctx = AmlExecutionContext::new(scope); + + parse_term_list(data, &mut ctx)?; + + Ok(ctx.namespace_delta) +} + +pub fn is_aml_table(sdt: &SdtHeader) -> bool { + if &sdt.signature == b"DSDT" || &sdt.signature == b"SSDT" { + true + } else { + false + } +} + +fn init_aml_table(sdt: impl AmlContainingTable) { + match parse_aml_table(sdt) { + Ok(_) => println!(": Parsed"), + Err(AmlError::AmlParseError(e)) => println!(": {}", e), + Err(AmlError::AmlInvalidOpCode) => println!(": Invalid opcode"), + Err(AmlError::AmlValueError) => println!(": Type constraints or value bounds not met"), + Err(AmlError::AmlDeferredLoad) => println!(": Deferred load reached top level"), + Err(AmlError::AmlFatalError(_, _, _)) => { + println!(": Fatal error occurred"); + // TODO + return; + }, + Err(AmlError::AmlHardFatal) => { + println!(": Fatal error occurred"); + // TODO + return; + } + } +} +fn init_namespace(context: &AcpiContext) -> HashMap { + let dsdt = context.dsdt().expect("could not find any DSDT"); + + log::info!("Found DSDT."); + init_aml_table(dsdt); + + let ssdts = context.ssdts(); + + for ssdt in ssdts { + print!("Found SSDT."); + init_aml_table(ssdt); + } + + todo!() +} + +pub fn set_global_s_state(context: &AcpiContext, state: u8) { + if state != 5 { + return + } + let fadt = match context.fadt() { + Some(fadt) => fadt, + None => { + log::error!("Cannot set global S-state due to missing FADT."); + return; + } + }; + + let port = fadt.pm1a_control_block as u16; + let mut val = 1 << 13; + + let namespace = match context.namespace() { + Some(namespace) => namespace, + None => { + log::error!("Cannot set global S-state due to missing ACPI namespace"); + return; + } + }; + + let s5 = match namespace.get("\\_S5") { + Some(s5) => s5, + None => { + log::error!("Cannot set global S-state due to missing \\_S5"); + return; + } + }; + let p = match s5.get_as_package() { + Ok(package) => package, + Err(error) => { + log::error!("Cannot set global S-state due to \\_S5 not being a package: {:?}", error); + return; + } + }; + + let slp_typa = p[0].get_as_integer().expect("SLP_TYPa is not an integer"); + let slp_typb = p[1].get_as_integer().expect("SLP_TYPb is not an integer"); + + log::info!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); + val |= slp_typa as u16; + + log::info!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); + Pio::::new(port).write(val); +} diff --git a/acpid/src/aml/namedobj.rs b/acpid/src/aml/namedobj.rs new file mode 100644 index 0000000000..01e272e492 --- /dev/null +++ b/acpid/src/aml/namedobj.rs @@ -0,0 +1,1043 @@ +use std::collections::BTreeMap; + +use super::AmlError; +use super::parser::{ AmlParseType, ParseResult, AmlParseTypeGeneric, AmlExecutionContext, ExecutionState }; +use super::namespace::{AmlValue, FieldSelector, Method, get_namespace_string, + Accessor, BufferField, FieldUnit, Processor, PowerResource, OperationRegion, + Device, ThermalZone}; +use super::namestring::{parse_name_string, parse_name_seg}; +use super::termlist::{parse_term_arg, parse_object_list}; +use super::pkglength::parse_pkg_length; +use super::type2opcode::parse_def_buffer; + +#[derive(Debug, Copy, Clone)] +pub enum RegionSpace { + SystemMemory, + SystemIO, + PCIConfig, + EmbeddedControl, + SMBus, + SystemCMOS, + PciBarTarget, + IPMI, + GeneralPurposeIO, + GenericSerialBus, + UserDefined(u8) +} + +#[derive(Debug, Clone)] +pub struct FieldFlags { + access_type: AccessType, + lock_rule: bool, + update_rule: UpdateRule +} + +#[derive(Debug, Clone)] +pub enum AccessType { + AnyAcc, + ByteAcc, + WordAcc, + DWordAcc, + QWordAcc, + BufferAcc(AccessAttrib) +} + +#[derive(Debug, Clone)] +pub enum UpdateRule { + Preserve, + WriteAsOnes, + WriteAsZeros +} + +#[derive(Debug, Clone)] +pub struct NamedField { + name: String, + length: usize +} + +#[derive(Debug, Clone)] +pub struct AccessField { + access_type: AccessType, + access_attrib: AccessAttrib +} + +#[derive(Debug, Clone)] +pub enum AccessAttrib { + AttribBytes(u8), + AttribRawBytes(u8), + AttribRawProcessBytes(u8), + AttribQuick, + AttribSendReceive, + AttribByte, + AttribWord, + AttribBlock, + AttribProcessCall, + AttribBlockProcessCall +} + +pub fn parse_named_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_def_bank_field, + parse_def_create_bit_field, + parse_def_create_byte_field, + parse_def_create_word_field, + parse_def_create_dword_field, + parse_def_create_qword_field, + parse_def_create_field, + parse_def_data_region, + parse_def_event, + parse_def_external, + parse_def_device, + parse_def_op_region, + parse_def_field, + parse_def_index_field, + parse_def_method, + parse_def_mutex, + parse_def_power_res, + parse_def_processor, + parse_def_thermal_zone + }; + + Err(AmlError::AmlInvalidOpCode) +} + +fn parse_def_bank_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 3 { + return Err(AmlError::AmlParseError("DefBankField - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x87); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let data = &data[2 + pkg_length_len .. 2 + pkg_length]; + + let region_name = parse_name_string(data, ctx)?; + let bank_name = parse_name_string(&data[2 + pkg_length_len + region_name.len .. 2 + pkg_length], ctx)?; + + let bank_value = parse_term_arg(&data[2 + pkg_length_len + region_name.len .. 2 + pkg_length], ctx)?; + + let flags_raw = data[2 + pkg_length_len + region_name.len + bank_name.len + bank_value.len]; + let mut flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), + _ => return Err(AmlError::AmlParseError("BankField - invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlError::AmlParseError("BankField - invalid update rule")) + } + }; + + let selector = FieldSelector::Bank { + region: region_name.val.get_as_string()?, + bank_register: bank_name.val.get_as_string()?, + bank_selector: Box::new(bank_value.val) + }; + + parse_field_list(&data[3 + pkg_length_len + region_name.len + bank_name.len + bank_value.len .. + 2 + pkg_length], ctx, selector, &mut flags)?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_length + }) +} + +fn parse_def_create_bit_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 2 { + return Err(AmlError::AmlParseError("DefCreateBitField - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x8D); + + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(AmlValue::IntegerConstant(1)) + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + }) +} + +fn parse_def_create_byte_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 2 { + return Err(AmlError::AmlParseError("DefCreateByteField - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x8C); + + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(AmlValue::IntegerConstant(8)) + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + }) +} + +fn parse_def_create_word_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 2 { + return Err(AmlError::AmlParseError("DefCreateWordField - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x8B); + + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(AmlValue::IntegerConstant(16)) + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + }) +} + +fn parse_def_create_dword_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 2 { + return Err(AmlError::AmlParseError("DefCreateDwordField - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x8A); + + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + let _ = ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(AmlValue::IntegerConstant(32)) + })); + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + }) +} + +fn parse_def_create_qword_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 2 { + return Err(AmlError::AmlParseError("DefCreateQwordField - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x8F); + + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(AmlValue::IntegerConstant(64)) + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + }) +} + +fn parse_def_create_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 2 { + return Err(AmlError::AmlParseError("DefCreateField - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x13); + + let source_buf = parse_term_arg(&data[2..], ctx)?; + let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; + let num_bits = parse_term_arg(&data[2 + source_buf.len + bit_index.len..], ctx)?; + let name = parse_name_string(&data[2 + source_buf.len + bit_index.len + num_bits.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + source_buf: Box::new(source_buf.val), + index: Box::new(bit_index.val), + length: Box::new(num_bits.val) + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + source_buf.len + bit_index.len + num_bits.len + }) +} + +fn parse_def_data_region(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 2 { + return Err(AmlError::AmlParseError("DefDataRegion - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + // TODO: Find the actual offset and length, once table mapping is implemented + parser_opcode_extended!(data, 0x88); + + let name = parse_name_string(&data[2..], ctx)?; + let signature = parse_term_arg(&data[2 + name.len..], ctx)?; + let oem_id = parse_term_arg(&data[2 + name.len + signature.len..], ctx)?; + let oem_table_id = parse_term_arg(&data[2 + name.len + signature.len + oem_id.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::OperationRegion(OperationRegion { + region: RegionSpace::SystemMemory, + offset: Box::new(AmlValue::IntegerConstant(0)), + len: Box::new(AmlValue::IntegerConstant(0)), + accessor: Accessor { + read: |_x| 0 as u64, + write: |_x, _y| () + }, + accessed_by: None + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + signature.len + oem_id.len + oem_table_id.len + }) +} + +fn parse_def_event(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 2 { + return Err(AmlError::AmlParseError("DefEvent - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x02); + + let name = parse_name_string(&data[2..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(local_scope_string, AmlValue::Event(0))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + }) +} + +fn parse_def_device(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 2 { + return Err(AmlError::AmlParseError("DefDevice - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + // TODO: How to handle local context deferreds + parser_opcode_extended!(data, 0x82); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); + + parse_object_list(&data[2 + pkg_length_len + name.len .. 2 + pkg_length], &mut local_ctx)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::Device(Device { + obj_list: local_ctx.namespace_delta.clone(), + notify_methods: BTreeMap::new() + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_length + }) +} + +fn parse_def_op_region(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 3 { + return Err(AmlError::AmlParseError("DefOpRegion - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x80); + + let name = parse_name_string(&data[2..], ctx)?; + let region = match data[2 + name.len] { + 0x00 => RegionSpace::SystemMemory, + 0x01 => RegionSpace::SystemIO, + 0x02 => RegionSpace::PCIConfig, + 0x03 => RegionSpace::EmbeddedControl, + 0x04 => RegionSpace::SMBus, + 0x05 => RegionSpace::SystemCMOS, + 0x06 => RegionSpace::PciBarTarget, + 0x07 => RegionSpace::IPMI, + 0x08 => RegionSpace::GeneralPurposeIO, + 0x09 => RegionSpace::GenericSerialBus, + 0x80 ..= 0xFF => RegionSpace::UserDefined(data[2 + name.len]), + _ => return Err(AmlError::AmlParseError("OpRegion - invalid region")) + }; + + let offset = parse_term_arg(&data[3 + name.len..], ctx)?; + let len = parse_term_arg(&data[3 + name.len + offset.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(local_scope_string, AmlValue::OperationRegion(OperationRegion { + region: region, + offset: Box::new(offset.val), + len: Box::new(len.val), + accessor: Accessor { + read: |_x| 0 as u64, + write: |_x, _y| () + }, + accessed_by: None + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 3 + name.len + offset.len + len.len + }) +} + +fn parse_def_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 3 { + return Err(AmlError::AmlParseError("DefField - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x81); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; + + let flags_raw = data[2 + pkg_length_len + name.len]; + let mut flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), + _ => return Err(AmlError::AmlParseError("Field - Invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlError::AmlParseError("Field - Invalid update rule")) + } + }; + + let selector = FieldSelector::Region(name.val.get_as_string()?); + + parse_field_list(&data[3 + pkg_length_len + name.len .. 2 + pkg_length], ctx, selector, &mut flags)?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_length + }) +} + +fn parse_def_index_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 3 { + return Err(AmlError::AmlParseError("DefIndexField - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x86); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; + let idx_name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; + let data_name = parse_name_string(&data[2 + pkg_length_len + idx_name.len .. 2 + pkg_length], ctx)?; + + let flags_raw = data[2 + pkg_length_len + idx_name.len + data_name.len]; + let mut flags = FieldFlags { + access_type: match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), + _ => return Err(AmlError::AmlParseError("IndexField - Invalid access type")) + }, + lock_rule: (flags_raw & 0x10) == 0x10, + update_rule: match (flags_raw & 0x60) >> 5 { + 0 => UpdateRule::Preserve, + 1 => UpdateRule::WriteAsOnes, + 2 => UpdateRule::WriteAsZeros, + _ => return Err(AmlError::AmlParseError("IndexField - Invalid update rule")) + } + }; + + let selector = FieldSelector::Index { + index_selector: idx_name.val.get_as_string()?, + data_selector: data_name.val.get_as_string()? + }; + + parse_field_list(&data[3 + pkg_length_len + idx_name.len + data_name.len .. 2 + pkg_length], + ctx, selector, &mut flags)?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_length + }) +} + +fn parse_field_list(data: &[u8], + ctx: &mut AmlExecutionContext, + selector: FieldSelector, + flags: &mut FieldFlags) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + let mut current_offset: usize = 0; + let mut field_offset: usize = 0; + let mut connection = AmlValue::Uninitialized; + + while current_offset < data.len() { + let res = parse_field_element(&data[current_offset..], ctx, selector.clone(), &mut connection, flags, &mut field_offset)?; + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + current_offset += res.len; + } + + Ok(AmlParseType { + val: AmlValue::None, + len: data.len() + }) +} + +fn parse_field_element(data: &[u8], + ctx: &mut AmlExecutionContext, + selector: FieldSelector, + connection: &mut AmlValue, + flags: &mut FieldFlags, + offset: &mut usize) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + let length = if let Ok(field) = parse_named_field(data, ctx) { + let local_scope_string = get_namespace_string(ctx.scope.clone(), AmlValue::String(field.val.name.clone()))?; + + ctx.add_to_namespace(local_scope_string, AmlValue::FieldUnit(FieldUnit { + selector: selector.clone(), + connection: Box::new(connection.clone()), + flags: flags.clone(), + offset: offset.clone(), + length: field.val.length + }))?; + + *offset += field.val.length; + field.len + } else if let Ok(field) = parse_reserved_field(data, ctx) { + *offset += field.val; + field.len + } else if let Ok(field) = parse_access_field(data, ctx) { + match field.val.access_type { + AccessType::BufferAcc(_) => + flags.access_type = AccessType::BufferAcc(field.val.access_attrib.clone()), + ref a => flags.access_type = a.clone() + } + + field.len + } else if let Ok(field) = parse_connect_field(data, ctx) { + *connection = field.val.clone(); + field.len + } else { + return Err(AmlError::AmlInvalidOpCode); + }; + + Ok(AmlParseType { + val: AmlValue::None, + len: length + }) +} + +fn parse_named_field(data: &[u8], _ctx: &mut AmlExecutionContext) -> Result, AmlError> { + if data.len() < 4 { + return Err(AmlError::AmlParseError("NamedField - data truncated")) + } + + let (name_seg, name_seg_len) = parse_name_seg(&data[0..4])?; + let name = match String::from_utf8(name_seg) { + Ok(s) => s, + Err(_) => return Err(AmlError::AmlParseError("NamedField - invalid name")) + }; + let (length, length_len) = parse_pkg_length(&data[4..])?; + + Ok(AmlParseTypeGeneric { + val: NamedField { name, length }, + len: name_seg_len + length_len + }) +} + +fn parse_reserved_field(data: &[u8], _ctx: &mut AmlExecutionContext) -> Result, AmlError> { + if data.len() < 1 { + return Err(AmlError::AmlParseError("ReservedField - data truncated")) + } + + parser_opcode!(data, 0x00); + + let (length, length_len) = parse_pkg_length(&data[1..])?; + Ok(AmlParseTypeGeneric { + val: length, + len: 1 + length_len + }) +} + +fn parse_access_field(data: &[u8], _ctx: &mut AmlExecutionContext) -> Result, AmlError> { + if data.len() < 3 { + return Err(AmlError::AmlParseError("AccessField - data truncated")) + } + + parser_opcode!(data, 0x01, 0x03); + + let flags_raw = data[1]; + let access_type = match flags_raw & 0x0F { + 0 => AccessType::AnyAcc, + 1 => AccessType::ByteAcc, + 2 => AccessType::WordAcc, + 3 => AccessType::DWordAcc, + 4 => AccessType::QWordAcc, + 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), + _ => return Err(AmlError::AmlParseError("AccessField - Invalid access type")) + }; + + let access_attrib = match (flags_raw & 0xC0) >> 6 { + 0 => match data[2] { + 0x02 => AccessAttrib::AttribQuick, + 0x04 => AccessAttrib::AttribSendReceive, + 0x06 => AccessAttrib::AttribByte, + 0x08 => AccessAttrib::AttribWord, + 0x0A => AccessAttrib::AttribBlock, + 0x0B => AccessAttrib::AttribBytes(data[3]), + 0x0C => AccessAttrib::AttribProcessCall, + 0x0D => AccessAttrib::AttribBlockProcessCall, + 0x0E => AccessAttrib::AttribRawBytes(data[3]), + 0x0F => AccessAttrib::AttribRawProcessBytes(data[3]), + _ => return Err(AmlError::AmlParseError("AccessField - Invalid access attrib")) + }, + 1 => AccessAttrib::AttribBytes(data[2]), + 2 => AccessAttrib::AttribRawBytes(data[2]), + 3 => AccessAttrib::AttribRawProcessBytes(data[2]), + _ => return Err(AmlError::AmlParseError("AccessField - Invalid access attrib")) + // This should never happen but the compiler bitches if I don't cover this + }; + + Ok(AmlParseTypeGeneric { + val: AccessField { access_type, access_attrib }, + len: if data[0] == 0x01 { + 3 as usize + } else { + 4 as usize + } + }) +} + +fn parse_connect_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 1 { + return Err(AmlError::AmlParseError("ConnectField - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x02); + + if let Ok(e) = parse_def_buffer(&data[1..], ctx) { + Ok(AmlParseType { + val: e.val, + len: e.len + 1 + }) + } else { + let name = parse_name_string(&data[1..], ctx)?; + Ok(AmlParseType { + val: AmlValue::Alias(name.val.get_as_string()?), + len: name.len + 1 + }) + } +} + +fn parse_def_method(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 1 { + return Err(AmlError::AmlParseError("DefMethod - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x14); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[1..])?; + let name = parse_name_string(&data[1 + pkg_len_len..], ctx)?; + let flags = data[1 + pkg_len_len + name.len]; + + let arg_count = flags & 0x07; + let serialized = (flags & 0x08) == 0x08; + let sync_level = flags & 0xF0 >> 4; + + let term_list = &data[2 + pkg_len_len + name.len .. 1 + pkg_len]; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(local_scope_string, AmlValue::Method(Method { + arg_count, + serialized, + sync_level, + term_list: term_list.to_vec() + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + pkg_len + }) +} + +fn parse_def_mutex(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 1 { + return Err(AmlError::AmlParseError("DefMutex - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x01); + + let name = parse_name_string(&data[2 ..], ctx)?; + let flags = data[2 + name.len]; + let sync_level = flags & 0x0F; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(local_scope_string, AmlValue::Mutex((sync_level, None)))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 3 + name.len + }) +} + +fn parse_def_power_res(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 5 { + return Err(AmlError::AmlParseError("DefPowerRes - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + // TODO: How to handle local context deferreds + parser_opcode_extended!(data, 0x84); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let name = parse_name_string(&data[2 + pkg_len_len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + let system_level = data[2 + pkg_len_len + name.len]; + let resource_order: u16 = (data[3 + pkg_len_len + name.len] as u16) + + ((data[4 + pkg_len_len + name.len] as u16) << 8); + + let mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); + parse_object_list(&data[5 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::PowerResource(PowerResource { + system_level, + resource_order, + obj_list: local_ctx.namespace_delta.clone() + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_len + }) +} + +fn parse_def_processor(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 8 { + return Err(AmlError::AmlParseError("DefProcessor - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x83); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let name = parse_name_string(&data[2 + pkg_len_len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + let proc_id = data[2 + pkg_len_len + name.len]; + let p_blk_addr: u32 = (data[3 + pkg_len_len + name.len] as u32) + + ((data[4 + pkg_len_len + name.len] as u32) << 8) + + ((data[5 + pkg_len_len + name.len] as u32) << 16) + + ((data[6 + pkg_len_len + name.len] as u32) << 24); + let p_blk_len = data[7 + pkg_len_len + name.len]; + + let mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); + parse_object_list(&data[8 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::Processor(Processor { + proc_id: proc_id, + p_blk: if p_blk_len > 0 { Some(p_blk_addr) } else { None }, + obj_list: local_ctx.namespace_delta.clone(), + notify_methods: BTreeMap::new() + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_len + }) +} + +fn parse_def_thermal_zone(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 2 { + return Err(AmlError::AmlParseError("DefThermalZone - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x85); + + let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; + let name = parse_name_string(&data[2 + pkg_len_len .. 2 + pkg_len], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + let mut local_ctx = AmlExecutionContext::new(ctx.acpi_context(), local_scope_string.clone()); + parse_object_list(&data[2 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::ThermalZone(ThermalZone { + obj_list: local_ctx.namespace_delta.clone(), + notify_methods: BTreeMap::new() + }))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + pkg_len + }) +} + +fn parse_def_external(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { + if data.len() < 2 { + return Err(AmlError::AmlParseError("DefExternal - data truncated")) + } + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x15); + + let object_name = parse_name_string(&data[1..], ctx)?; + let object_type = data[1 + object_name.len]; + let argument_count = data[2 + object_name.len]; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), object_name.val)?; + + let obj = match object_type { + 8 => AmlValue::Method(Method { + arg_count: argument_count, + serialized: false, + sync_level: 0, + term_list: vec!() + }), + _ => AmlValue::Uninitialized + }; + + ctx.add_to_namespace(local_scope_string, obj)?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 3 + object_name.len + }) +} diff --git a/acpid/src/aml/namespace.rs b/acpid/src/aml/namespace.rs new file mode 100644 index 0000000000..9b3e12b2ba --- /dev/null +++ b/acpid/src/aml/namespace.rs @@ -0,0 +1,486 @@ +use std::collections::BTreeMap; + +use core::fmt::Debug; +use core::str::FromStr; + +use super::termlist::parse_term_list; +use super::namedobj::{ RegionSpace, FieldFlags }; +use super::parser::{AmlExecutionContext, ExecutionState}; +use super::AmlError; + +use crate::acpi::{AcpiContext, SdtSignature}; + +#[derive(Clone, Debug)] +pub enum FieldSelector { + Region(String), + Bank { + region: String, + bank_register: String, + bank_selector: Box + }, + Index { + index_selector: String, + data_selector: String + } +} + +#[derive(Clone, Debug)] +pub enum ObjectReference { + ArgObj(u8), + LocalObj(u8), + Object(String), + Index(Box, Box) +} + +#[derive(Clone, Debug)] +pub struct Method { + pub arg_count: u8, + pub serialized: bool, + pub sync_level: u8, + pub term_list: Vec +} + +#[derive(Clone, Debug)] +pub struct BufferField { + pub source_buf: Box, + pub index: Box, + pub length: Box +} + +#[derive(Clone, Debug)] +pub struct FieldUnit { + pub selector: FieldSelector, + pub connection: Box, + pub flags: FieldFlags, + pub offset: usize, + pub length: usize +} + +#[derive(Clone, Debug)] +pub struct Device { + pub obj_list: Vec, + pub notify_methods: BTreeMap> +} + +#[derive(Clone, Debug)] +pub struct ThermalZone { + pub obj_list: Vec, + pub notify_methods: BTreeMap> +} + +#[derive(Clone, Debug)] +pub struct Processor { + pub proc_id: u8, + pub p_blk: Option, + pub obj_list: Vec, + pub notify_methods: BTreeMap> +} + +#[derive(Clone, Debug)] +pub struct OperationRegion { + pub region: RegionSpace, + pub offset: Box, + pub len: Box, + pub accessor: Accessor, + pub accessed_by: Option +} + +#[derive(Clone, Debug)] +pub struct PowerResource { + pub system_level: u8, + pub resource_order: u16, + pub obj_list: Vec +} + +#[derive(Debug)] +pub struct Accessor { + pub read: fn(usize) -> u64, + pub write: fn(usize, u64) +} + +impl Clone for Accessor { + fn clone(&self) -> Accessor { + Accessor { + read: (*self).read, + write: (*self).write + } + } +} + +#[derive(Clone, Debug)] +pub enum AmlValue { + None, + Uninitialized, + Alias(String), + Buffer(Vec), + BufferField(BufferField), + DDBHandle((Vec, SdtSignature)), + DebugObject, + Device(Device), + Event(u64), + FieldUnit(FieldUnit), + Integer(u64), + IntegerConstant(u64), + Method(Method), + Mutex((u8, Option)), + ObjectReference(ObjectReference), + OperationRegion(OperationRegion), + Package(Vec), + String(String), + PowerResource(PowerResource), + Processor(Processor), + RawDataBuffer(Vec), + ThermalZone(ThermalZone) +} + +impl AmlValue { + pub fn get_type_string(&self) -> String { + match *self { + AmlValue::Uninitialized => String::from_str("[Uninitialized Object]").unwrap(), + AmlValue::Integer(_) => String::from_str("[Integer]").unwrap(), + AmlValue::String(_) => String::from_str("[String]").unwrap(), + AmlValue::Buffer(_) => String::from_str("[Buffer]").unwrap(), + AmlValue::Package(_) => String::from_str("[Package]").unwrap(), + AmlValue::FieldUnit(_) => String::from_str("[Field]").unwrap(), + AmlValue::Device(_) => String::from_str("[Device]").unwrap(), + AmlValue::Event(_) => String::from_str("[Event]").unwrap(), + AmlValue::Method(_) => String::from_str("[Control Method]").unwrap(), + AmlValue::Mutex(_) => String::from_str("[Mutex]").unwrap(), + AmlValue::OperationRegion(_) => String::from_str("[Operation Region]").unwrap(), + AmlValue::PowerResource(_) => String::from_str("[Power Resource]").unwrap(), + AmlValue::Processor(_) => String::from_str("[Processor]").unwrap(), + AmlValue::ThermalZone(_) => String::from_str("[Thermal Zone]").unwrap(), + AmlValue::BufferField(_) => String::from_str("[Buffer Field]").unwrap(), + AmlValue::DDBHandle(_) => String::from_str("[DDB Handle]").unwrap(), + AmlValue::DebugObject => String::from_str("[Debug Object]").unwrap(), + _ => String::new() + } + } + + pub fn get_as_type(&self, t: AmlValue) -> Result { + match t { + AmlValue::None => Ok(AmlValue::None), + AmlValue::Uninitialized => Ok(self.clone()), + AmlValue::Alias(_) => match *self { + AmlValue::Alias(_) => Ok(self.clone()), + _ => Err(AmlError::AmlValueError) + }, + AmlValue::Buffer(_) => Ok(AmlValue::Buffer(self.get_as_buffer()?)), + AmlValue::BufferField(_) => Ok(AmlValue::BufferField(self.get_as_buffer_field()?)), + AmlValue::DDBHandle(_) => Ok(AmlValue::DDBHandle(self.get_as_ddb_handle()?)), + AmlValue::DebugObject => match *self { + AmlValue::DebugObject => Ok(self.clone()), + _ => Err(AmlError::AmlValueError) + }, + AmlValue::Device(_) => Ok(AmlValue::Device(self.get_as_device()?)), + AmlValue::Event(_) => Ok(AmlValue::Event(self.get_as_event()?)), + AmlValue::FieldUnit(_) => Ok(AmlValue::FieldUnit(self.get_as_field_unit()?)), + AmlValue::Integer(_) => Ok(AmlValue::Integer(self.get_as_integer()?)), + AmlValue::IntegerConstant(_) => Ok(AmlValue::IntegerConstant(self.get_as_integer_constant()?)), + AmlValue::Method(_) => Ok(AmlValue::Method(self.get_as_method()?)), + AmlValue::Mutex(_) => Ok(AmlValue::Mutex(self.get_as_mutex()?)), + AmlValue::ObjectReference(_) => Ok(AmlValue::ObjectReference(self.get_as_object_reference()?)), + AmlValue::OperationRegion(_) => match *self { + AmlValue::OperationRegion(_) => Ok(self.clone()), + _ => Err(AmlError::AmlValueError) + }, + AmlValue::Package(_) => Ok(AmlValue::Package(self.get_as_package()?)), + AmlValue::String(_) => Ok(AmlValue::String(self.get_as_string()?)), + AmlValue::PowerResource(_) => Ok(AmlValue::PowerResource(self.get_as_power_resource()?)), + AmlValue::Processor(_) => Ok(AmlValue::Processor(self.get_as_processor()?)), + AmlValue::RawDataBuffer(_) => Ok(AmlValue::RawDataBuffer(self.get_as_raw_data_buffer()?)), + AmlValue::ThermalZone(_) => Ok(AmlValue::ThermalZone(self.get_as_thermal_zone()?)) + } + } + + pub fn get_as_buffer(&self) -> Result, AmlError> { + match *self { + AmlValue::Buffer(ref b) => Ok(b.clone()), + AmlValue::Integer(ref i) => { + let mut v: Vec = vec!(); + let mut i = i.clone(); + + while i != 0 { + v.push((i & 0xFF) as u8); + i >>= 8; + } + + while v.len() < 8 { + v.push(0); + } + + Ok(v) + }, + AmlValue::String(ref s) => { + Ok(s.clone().into_bytes()) + }, + AmlValue::BufferField(ref b) => { + let buf = b.source_buf.get_as_buffer()?; + let idx = b.index.get_as_integer()? as usize; + let len = b.length.get_as_integer()? as usize; + + if idx + len > buf.len() { + return Err(AmlError::AmlValueError); + } + + Ok(buf[idx .. idx + len].to_vec()) + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_buffer_field(&self) -> Result { + match *self { + AmlValue::BufferField(ref b) => Ok(b.clone()), + _ => { + let raw_buf = self.get_as_buffer()?; + let buf = Box::new(AmlValue::Buffer(raw_buf.clone())); + let idx = Box::new(AmlValue::IntegerConstant(0)); + let len = Box::new(AmlValue::Integer(raw_buf.len() as u64)); + + Ok(BufferField { + source_buf: buf, + index: idx, + length: len + }) + } + } + } + + pub fn get_as_ddb_handle(&self, acpi_ctx: &AcpiContext) -> Result<(Vec, SdtSignature), AmlError> { + match *self { + AmlValue::DDBHandle(ref v) => Ok(v.clone()), + AmlValue::Integer(i) => if let Some(sig) = acpi_ctx.get_signature_from_index(i as usize) { + Ok((vec!(), sig)) + } else { + Err(AmlError::AmlValueError) + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_device(&self) -> Result { + match *self { + AmlValue::Device(ref s) => Ok(s.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_event(&self) -> Result { + match *self { + AmlValue::Event(ref e) => Ok(e.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_field_unit(&self) -> Result { + match *self { + AmlValue::FieldUnit(ref e) => Ok(e.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_integer(&self, acpi_ctx: &AcpiContext) -> Result { + match *self { + AmlValue::IntegerConstant(ref i) => Ok(i.clone()), + AmlValue::Integer(ref i) => Ok(i.clone()), + AmlValue::Buffer(ref b) => { + let mut b = b.clone(); + if b.len() > 8 { + return Err(AmlError::AmlValueError); + } + + let mut i: u64 = 0; + + while b.len() > 0 { + i <<= 8; + i += b.pop().expect("Won't happen") as u64; + } + + Ok(i) + }, + AmlValue::BufferField(_) => { + let mut b = self.get_as_buffer()?; + if b.len() > 8 { + return Err(AmlError::AmlValueError); + } + + let mut i: u64 = 0; + + while b.len() > 0 { + i <<= 8; + i += b.pop().expect("Won't happen") as u64; + } + + Ok(i) + }, + AmlValue::DDBHandle(ref v) => if let Some(idx) = acpi_ctx.get_index_from_signature(&v.1) { + Ok(idx as u64) + } else { + Err(AmlError::AmlValueError) + }, + AmlValue::String(ref s) => { + let s = s.clone()[0..8].to_string().to_uppercase(); + let mut i: u64 = 0; + + for c in s.chars() { + if !c.is_digit(16) { + break; + } + + i <<= 8; + i += c.to_digit(16).unwrap() as u64; + } + + Ok(i) + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_integer_constant(&self) -> Result { + match *self { + AmlValue::IntegerConstant(ref i) => Ok(i.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_method(&self) -> Result { + match *self { + AmlValue::Method(ref m) => Ok(m.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_mutex(&self) -> Result<(u8, Option), AmlError> { + match *self { + AmlValue::Mutex(ref m) => Ok(m.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_object_reference(&self) -> Result { + match *self { + AmlValue::ObjectReference(ref m) => Ok(m.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + /* + pub fn get_as_operation_region(&self) -> Result { + match *self { + AmlValue::OperationRegion(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) + } + } + */ + + pub fn get_as_package(&self) -> Result, AmlError> { + match *self { + AmlValue::Package(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_string(&self) -> Result { + match *self { + AmlValue::String(ref s) => Ok(s.clone()), + AmlValue::Integer(ref i) => Ok(format!("{:X}", i)), + AmlValue::IntegerConstant(ref i) => Ok(format!("{:X}", i)), + AmlValue::Buffer(ref b) => Ok(String::from_utf8(b.clone()).expect("Invalid UTF-8")), + AmlValue::BufferField(_) => { + let b = self.get_as_buffer()?; + Ok(String::from_utf8(b).expect("Invalid UTF-8")) + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_power_resource(&self) -> Result { + match *self { + AmlValue::PowerResource(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_processor(&self) -> Result { + match *self { + AmlValue::Processor(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_raw_data_buffer(&self) -> Result, AmlError> { + match *self { + AmlValue::RawDataBuffer(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_as_thermal_zone(&self) -> Result { + match *self { + AmlValue::ThermalZone(ref p) => Ok(p.clone()), + _ => Err(AmlError::AmlValueError) + } + } +} + +impl Method { + pub fn execute(&self, scope: String, parameters: Vec) -> AmlValue { + let mut ctx = AmlExecutionContext::new(scope); + ctx.init_arg_vars(parameters); + + let _ = parse_term_list(&self.term_list[..], &mut ctx); + ctx.clean_namespace(); + + match ctx.state { + ExecutionState::RETURN(v) => v, + _ => AmlValue::IntegerConstant(0) + } + } +} + +pub fn get_namespace_string(current: String, modifier_v: AmlValue) -> Result { + let mut modifier = modifier_v.get_as_string()?; + + if current.len() == 0 { + return Ok(modifier); + } + + if modifier.len() == 0 { + return Ok(current); + } + + if modifier.starts_with("\\") { + return Ok(modifier); + } + + let mut namespace = current.clone(); + + if modifier.starts_with("^") { + while modifier.starts_with("^") { + modifier = modifier[1..].to_string(); + + if namespace.ends_with("\\") { + return Err(AmlError::AmlValueError); + } + + loop { + if namespace.ends_with(".") { + namespace.pop(); + break; + } + + if namespace.pop() == None { + return Err(AmlError::AmlValueError); + } + } + } + } + + if !namespace.ends_with("\\") { + namespace.push('.'); + } + + Ok(namespace + &modifier) +} diff --git a/acpid/src/aml/namespacemodifier.rs b/acpid/src/aml/namespacemodifier.rs new file mode 100644 index 0000000000..77fa1406b0 --- /dev/null +++ b/acpid/src/aml/namespacemodifier.rs @@ -0,0 +1,106 @@ +use super::AmlError; +use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; +use super::namespace::{AmlValue, get_namespace_string}; +use super::pkglength::parse_pkg_length; +use super::namestring::parse_name_string; +use super::termlist::parse_term_list; +use super::dataobj::parse_data_ref_obj; + +pub fn parse_namespace_modifier(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_alias_op, + parse_scope_op, + parse_name_op + }; + + Err(AmlError::AmlInvalidOpCode) +} + +fn parse_alias_op(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x06); + + let source_name = parse_name_string(&data[1..], ctx)?; + let alias_name = parse_name_string(&data[1 + source_name.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), source_name.val)?; + let local_alias_string = get_namespace_string(ctx.scope.clone(), alias_name.val)?; + + ctx.add_to_namespace(local_scope_string, AmlValue::Alias(local_alias_string))?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + source_name.len + alias_name.len + }) +} + +fn parse_name_op(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x08); + + let name = parse_name_string(&data[1..], ctx)?; + let data_ref_obj = parse_data_ref_obj(&data[1 + name.len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + + ctx.add_to_namespace(local_scope_string, data_ref_obj.val)?; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + name.len + data_ref_obj.len + }) +} + +fn parse_scope_op(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x10); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let name = parse_name_string(&data[1 + pkg_length_len..], ctx)?; + + let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val.clone())?; + let containing_scope_string = ctx.scope.clone(); + + ctx.scope = local_scope_string; + parse_term_list(&data[1 + pkg_length_len + name.len .. 1 + pkg_length], ctx)?; + ctx.scope = containing_scope_string; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + pkg_length + }) +} diff --git a/acpid/src/aml/namestring.rs b/acpid/src/aml/namestring.rs new file mode 100644 index 0000000000..dd3eb88a33 --- /dev/null +++ b/acpid/src/aml/namestring.rs @@ -0,0 +1,223 @@ +use super::AmlError; +use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; +use super::namespace::AmlValue; +use super::dataobj::{parse_arg_obj, parse_local_obj}; +use super::type2opcode::parse_type6_opcode; + +pub fn parse_name_string(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + let mut characters: Vec = vec!(); + let mut starting_index: usize = 0; + + if data[0] == 0x5C { + characters.push(data[0]); + starting_index = 1; + } else if data[0] == 0x5E { + while data[starting_index] == 0x5E { + characters.push(data[starting_index]); + starting_index += 1; + } + } + + let sel = |data| { + parser_selector_simple! { + data, + parse_dual_name_path, + parse_multi_name_path, + parse_null_name, + parse_name_seg + }; + + Err(AmlError::AmlInvalidOpCode) + }; + let (mut chr, len) = sel(&data[starting_index..])?; + characters.append(&mut chr); + + let name_string = String::from_utf8(characters); + + match name_string { + Ok(s) => Ok(AmlParseType { + val: AmlValue::String(s.clone()), + len: len + starting_index + }), + Err(_) => Err(AmlError::AmlParseError("Namestring - Name is invalid")) + } +} + +fn parse_null_name(data: &[u8]) -> Result<(Vec, usize), AmlError> { + parser_opcode!(data, 0x00); + Ok((vec!(), 1 )) +} + +pub fn parse_name_seg(data: &[u8]) -> Result<(Vec, usize), AmlError> { + match data[0] { + 0x41 ..= 0x5A | 0x5F => (), + _ => return Err(AmlError::AmlInvalidOpCode) + } + + match data[1] { + 0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (), + _ => return Err(AmlError::AmlInvalidOpCode) + } + + match data[2] { + 0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (), + _ => return Err(AmlError::AmlInvalidOpCode) + } + + match data[3] { + 0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (), + _ => return Err(AmlError::AmlInvalidOpCode) + } + + let mut name_seg = vec!(data[0], data[1], data[2], data[3]); + while *(name_seg.last().unwrap()) == 0x5F { + name_seg.pop(); + } + + Ok((name_seg, 4)) +} + +fn parse_dual_name_path(data: &[u8]) -> Result<(Vec, usize), AmlError> { + parser_opcode!(data, 0x2E); + + let mut characters: Vec = vec!(); + let mut dual_len: usize = 1; + + match parse_name_seg(&data[1..5]) { + Ok((mut v, len)) => { + characters.append(&mut v); + dual_len += len; + }, + Err(e) => return Err(e) + } + + characters.push(0x2E); + + match parse_name_seg(&data[5..9]) { + Ok((mut v, len)) => { + characters.append(&mut v); + dual_len += len; + }, + Err(e) => return Err(e) + } + + Ok((characters, dual_len)) +} + +fn parse_multi_name_path(data: &[u8]) -> Result<(Vec, usize), AmlError> { + parser_opcode!(data, 0x2F); + + let seg_count = data[1]; + if seg_count == 0x00 { + return Err(AmlError::AmlParseError("MultiName Path - can't have zero name segments")); + } + + let mut current_seg = 0; + let mut characters: Vec = vec!(); + let mut multi_len: usize = 2; + + while current_seg < seg_count { + match parse_name_seg(&data[(current_seg as usize * 4) + 2 ..]) { + Ok((mut v, len)) => { + characters.append(&mut v); + multi_len += len; + }, + Err(e) => return Err(e) + } + + characters.push(0x2E); + + current_seg += 1; + } + + characters.pop(); + + Ok((characters, multi_len)) +} + +pub fn parse_super_name(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_simple_name, + parse_type6_opcode, + parse_debug_obj + }; + + Err(AmlError::AmlInvalidOpCode) +} + +fn parse_debug_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x31); + + Ok(AmlParseType { + val: AmlValue::DebugObject, + len: 2 + }) +} + +pub fn parse_simple_name(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_name_string, + parse_arg_obj, + parse_local_obj + }; + + Err(AmlError::AmlInvalidOpCode) +} + +pub fn parse_target(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + if data[0] == 0x00 { + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + }) + } else { + parse_super_name(data, ctx) + } +} diff --git a/acpid/src/aml/parser.rs b/acpid/src/aml/parser.rs new file mode 100644 index 0000000000..aff1aaa158 --- /dev/null +++ b/acpid/src/aml/parser.rs @@ -0,0 +1,559 @@ +use std::string::String; +use std::collections::BTreeMap; +use std::vec::Vec; +use std::boxed::Box; + +use parking_lot::RwLockWriteGuard; + +use super::namespace::{AmlValue, ObjectReference}; +use super::AmlError; + +use crate::acpi::AcpiContext; + +pub type ParseResult = Result; +pub type AmlParseType = AmlParseTypeGeneric; + +pub struct AmlParseTypeGeneric { + pub val: T, + pub len: usize +} + +pub enum ExecutionState { + EXECUTING, + CONTINUE, + BREAK, + RETURN(AmlValue) +} + +pub struct AmlExecutionContext<'a> { + pub scope: String, + pub local_vars: [AmlValue; 8], + pub arg_vars: [AmlValue; 8], + pub state: ExecutionState, + pub namespace_delta: Vec, + pub ctx_id: u64, + pub sync_level: u8, + + pub acpi_context: &'a AcpiContext, +} + +impl<'a> AmlExecutionContext<'a> { + pub fn new(acpi_context: &'a AcpiContext, scope: String) -> AmlExecutionContext<'_> { + let mut idptr = ACPI_TABLE.next_ctx.write(); + let id: u64 = *idptr; + + *idptr += 1; + + AmlExecutionContext { + scope: scope, + local_vars: [AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized], + arg_vars: [AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized, + AmlValue::Uninitialized], + state: ExecutionState::EXECUTING, + namespace_delta: vec!(), + ctx_id: id, + sync_level: 0, + + acpi_context, + } + } + pub fn acpi_context(&self) -> &'a AcpiContext { + self.acpi_context + } + + pub fn wait_for_event(&mut self, event_ptr: AmlValue) -> Result { + let mut namespace_ptr = self.prelock(); + let namespace = match *namespace_ptr { + Some(ref mut n) => n, + None => return Err(AmlError::AmlHardFatal) + }; + + let mutex_idx = match event_ptr { + AmlValue::String(ref s) => s.clone(), + AmlValue::ObjectReference(ref o) => match *o { + ObjectReference::Object(ref s) => s.clone(), + _ => return Err(AmlError::AmlValueError) + }, + _ => return Err(AmlError::AmlValueError) + }; + + let mutex = match namespace.get(&mutex_idx) { + Some(s) => s.clone(), + None => return Err(AmlError::AmlValueError) + }; + + match mutex { + AmlValue::Event(count) => { + if count > 0 { + namespace.insert(mutex_idx, AmlValue::Event(count - 1)); + return Ok(true); + } + }, + _ => return Err(AmlError::AmlValueError) + } + + Ok(false) + } + + pub fn signal_event(&mut self, event_ptr: AmlValue) -> Result<(), AmlError> { + let mut namespace_ptr = self.prelock(); + let namespace = match *namespace_ptr { + Some(ref mut n) => n, + None => return Err(AmlError::AmlHardFatal) + }; + + + let mutex_idx = match event_ptr { + AmlValue::String(ref s) => s.clone(), + AmlValue::ObjectReference(ref o) => match *o { + ObjectReference::Object(ref s) => s.clone(), + _ => return Err(AmlError::AmlValueError) + }, + _ => return Err(AmlError::AmlValueError) + }; + + let mutex = match namespace.get(&mutex_idx) { + Some(s) => s.clone(), + None => return Err(AmlError::AmlValueError) + }; + + match mutex { + AmlValue::Event(count) => { + namespace.insert(mutex_idx, AmlValue::Event(count + 1)); + }, + _ => return Err(AmlError::AmlValueError) + } + + Ok(()) + } + + pub fn release_mutex(&mut self, mutex_ptr: AmlValue) -> Result<(), AmlError> { + let id = self.ctx_id; + + let mut namespace_ptr = self.prelock(); + let namespace = match *namespace_ptr { + Some(ref mut n) => n, + None => return Err(AmlError::AmlHardFatal) + }; + + let mutex_idx = match mutex_ptr { + AmlValue::String(ref s) => s.clone(), + AmlValue::ObjectReference(ref o) => match *o { + ObjectReference::Object(ref s) => s.clone(), + _ => return Err(AmlError::AmlValueError) + }, + _ => return Err(AmlError::AmlValueError) + }; + + let mutex = match namespace.get(&mutex_idx) { + Some(s) => s.clone(), + None => return Err(AmlError::AmlValueError) + }; + + match mutex { + AmlValue::Mutex((sync_level, owner)) => { + if let Some(o) = owner { + if o == id { + if sync_level == self.sync_level { + namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, None))); + return Ok(()); + } else { + return Err(AmlError::AmlValueError); + } + } else { + return Err(AmlError::AmlHardFatal); + } + } + }, + AmlValue::OperationRegion(ref region) => { + if let Some(o) = region.accessed_by { + if o == id { + let mut new_region = region.clone(); + new_region.accessed_by = None; + + namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region)); + return Ok(()); + } else { + return Err(AmlError::AmlHardFatal); + } + } + }, + _ => return Err(AmlError::AmlValueError) + } + + Ok(()) + } + + pub fn acquire_mutex(&mut self, mutex_ptr: AmlValue) -> Result { + let id = self.ctx_id; + + let mut namespace_ptr = self.prelock(); + let namespace = match *namespace_ptr { + Some(ref mut n) => n, + None => return Err(AmlError::AmlHardFatal) + }; + let mutex_idx = match mutex_ptr { + AmlValue::String(ref s) => s.clone(), + AmlValue::ObjectReference(ref o) => match *o { + ObjectReference::Object(ref s) => s.clone(), + _ => return Err(AmlError::AmlValueError) + }, + _ => return Err(AmlError::AmlValueError) + }; + + let mutex = match namespace.get(&mutex_idx) { + Some(s) => s.clone(), + None => return Err(AmlError::AmlValueError) + }; + + match mutex { + AmlValue::Mutex((sync_level, owner)) => { + if owner == None { + if sync_level < self.sync_level { + return Err(AmlError::AmlValueError); + } + + namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, Some(id)))); + self.sync_level = sync_level; + + return Ok(true); + } + }, + AmlValue::OperationRegion(ref o) => { + if o.accessed_by == None { + let mut new_region = o.clone(); + new_region.accessed_by = Some(id); + + namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region)); + return Ok(true); + } + }, + _ => return Err(AmlError::AmlValueError) + } + + Ok(false) + } + + pub fn add_to_namespace(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { + let mut namespace = ACPI_TABLE.namespace.write(); + + if let Some(ref mut namespace) = *namespace { + if let Some(obj) = namespace.get(&name) { + match *obj { + AmlValue::Uninitialized => (), + AmlValue::Method(ref m) => { + if m.term_list.len() != 0 { + return Err(AmlError::AmlValueError); + } + }, + _ => return Err(AmlError::AmlValueError) + } + } + + self.namespace_delta.push(name.clone()); + namespace.insert(name, value); + + Ok(()) + } else { + Err(AmlError::AmlValueError) + } + } + + pub fn clean_namespace(&mut self) { + let mut namespace = ACPI_TABLE.namespace.write(); + + if let Some(ref mut namespace) = *namespace { + for k in &self.namespace_delta { + namespace.remove(k); + } + } + } + + pub fn init_arg_vars(&mut self, parameters: Vec) { + if parameters.len() > 8 { + return; + } + + let mut cur = 0; + while cur < parameters.len() { + self.arg_vars[cur] = parameters[cur].clone(); + cur += 1; + } + } + + pub fn prelock(&mut self) -> RwLockWriteGuard<'static, Option>> { + ACPI_TABLE.namespace.write() + } + + fn modify_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> { + self.local_vars[local] = value.get_as_type(self.local_vars[local].clone())?; + Ok(()) + } + + fn modify_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { + if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { + let coercion_obj = { + let obj = namespace.get(&name); + + if let Some(o) = obj { + o.clone() + } else { + AmlValue::Uninitialized + } + }; + + namespace.insert(name, value.get_as_type(coercion_obj)?); + Ok(()) + } else { + Err(AmlError::AmlHardFatal) + } + } + + fn modify_index_final(&mut self, name: String, value: AmlValue, indices: Vec) -> Result<(), AmlError> { + if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { + let mut obj = if let Some(s) = namespace.get(&name) { + s.clone() + } else { + return Err(AmlError::AmlValueError); + }; + + obj = self.modify_index_core(obj, value, indices)?; + + namespace.insert(name, obj); + Ok(()) + } else { + Err(AmlError::AmlValueError) + } + } + + fn modify_index_core(&mut self, obj: AmlValue, value: AmlValue, indices: Vec) -> Result { + match obj { + AmlValue::String(ref string) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + let mut bytes = string.clone().into_bytes(); + bytes[indices[0] as usize] = value.get_as_integer()? as u8; + + let string = String::from_utf8(bytes).unwrap(); + + Ok(AmlValue::String(string)) + }, + AmlValue::Buffer(ref b) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + let mut b = b.clone(); + b[indices[0] as usize] = value.get_as_integer()? as u8; + + Ok(AmlValue::Buffer(b)) + }, + AmlValue::BufferField(ref b) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + let mut idx = indices[0]; + idx += b.index.get_as_integer()?; + + let _ = self.modify(AmlValue::ObjectReference(ObjectReference::Index(b.source_buf.clone(), Box::new(AmlValue::Integer(idx.clone())))), value); + + Ok(AmlValue::BufferField(b.clone())) + }, + AmlValue::Package(ref p) => { + if indices.len() == 0 { + return Err(AmlError::AmlValueError); + } + + let mut p = p.clone(); + + if indices.len() == 1 { + p[indices[0] as usize] = value; + } else { + p[indices[0] as usize] = self.modify_index_core(p[indices[0] as usize].clone(), value, indices[1..].to_vec())?; + } + + Ok(AmlValue::Package(p)) + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn modify_index(&mut self, name: AmlValue, value: AmlValue, indices: Vec) -> Result<(), AmlError>{ + match name { + AmlValue::ObjectReference(r) => match r { + ObjectReference::Object(s) => self.modify_index_final(s, value, indices), + ObjectReference::Index(c, v) => { + let mut indices = indices.clone(); + indices.push(v.get_as_integer()?); + + self.modify_index(*c, value, indices) + }, + ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), + ObjectReference::LocalObj(i) => { + let v = self.local_vars[i as usize].clone(); + self.local_vars[i as usize] = self.modify_index_core(v, value, indices)?; + + Ok(()) + } + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn modify(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { + match name { + AmlValue::ObjectReference(r) => match r { + ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), + ObjectReference::LocalObj(i) => self.modify_local_obj(i as usize, value), + ObjectReference::Object(s) => self.modify_object(s, value), + ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?)) + }, + AmlValue::String(s) => self.modify_object(s, value), + _ => Err(AmlError::AmlValueError) + } + } + + fn copy_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> { + self.local_vars[local] = value; + Ok(()) + } + + fn copy_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { + if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { + namespace.insert(name, value); + Ok(()) + } else { + Err(AmlError::AmlHardFatal) + } + } + + pub fn copy(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { + match name { + AmlValue::ObjectReference(r) => match r { + ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), + ObjectReference::LocalObj(i) => self.copy_local_obj(i as usize, value), + ObjectReference::Object(s) => self.copy_object(s, value), + ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?)) + }, + AmlValue::String(s) => self.copy_object(s, value), + _ => Err(AmlError::AmlValueError) + } + } + + fn get_index_final(&self, name: String, indices: Vec) -> Result { + if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { + let obj = if let Some(s) = namespace.get(&name) { + s.clone() + } else { + return Err(AmlError::AmlValueError); + }; + + self.get_index_core(obj, indices) + } else { + Err(AmlError::AmlValueError) + } + } + + fn get_index_core(&self, obj: AmlValue, indices: Vec) -> Result { + match obj { + AmlValue::String(ref string) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + let bytes = string.clone().into_bytes(); + Ok(AmlValue::Integer(bytes[indices[0] as usize] as u64)) + }, + AmlValue::Buffer(ref b) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + Ok(AmlValue::Integer(b[indices[0] as usize] as u64)) + }, + AmlValue::BufferField(ref b) => { + if indices.len() != 1 { + return Err(AmlError::AmlValueError); + } + + let mut idx = indices[0]; + idx += b.index.get_as_integer()?; + + Ok(AmlValue::Integer(b.source_buf.get_as_buffer()?[idx as usize] as u64)) + }, + AmlValue::Package(ref p) => { + if indices.len() == 0 { + return Err(AmlError::AmlValueError); + } + + if indices.len() == 1 { + Ok(p[indices[0] as usize].clone()) + } else { + self.get_index_core(p[indices[0] as usize].clone(), indices[1..].to_vec()) + } + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get_index(&self, name: AmlValue, indices: Vec) -> Result{ + match name { + AmlValue::ObjectReference(r) => match r { + ObjectReference::Object(s) => self.get_index_final(s, indices), + ObjectReference::Index(c, v) => { + let mut indices = indices.clone(); + indices.push(v.get_as_integer()?); + + self.get_index(*c, indices) + }, + ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), + ObjectReference::LocalObj(i) => { + let v = self.local_vars[i as usize].clone(); + self.get_index_core(v, indices) + } + }, + _ => Err(AmlError::AmlValueError) + } + } + + pub fn get(&self, name: AmlValue) -> Result { + Ok(match name { + AmlValue::ObjectReference(r) => match r { + ObjectReference::ArgObj(i) => self.arg_vars[i as usize].clone(), + ObjectReference::LocalObj(i) => self.local_vars[i as usize].clone(), + ObjectReference::Object(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { + if let Some(o) = namespace.get(s) { + o.clone() + } else { + AmlValue::None + } + } else { AmlValue::None }, + ObjectReference::Index(c, v) => self.get_index(*c, vec!(v.get_as_integer()?))?, + }, + AmlValue::String(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { + if let Some(o) = namespace.get(s) { + o.clone() + } else { + AmlValue::None + } + } else { AmlValue::None }, + _ => AmlValue::None + }) + } +} diff --git a/acpid/src/aml/parsermacros.rs b/acpid/src/aml/parsermacros.rs new file mode 100644 index 0000000000..31a23386ff --- /dev/null +++ b/acpid/src/aml/parsermacros.rs @@ -0,0 +1,52 @@ +#[macro_export] +macro_rules! parser_selector { + {$data:expr, $ctx:expr, $func:expr} => { + match $func($data, $ctx) { + Ok(res) => return Ok(res), + Err(AmlError::AmlInvalidOpCode) => (), + Err(e) => return Err(e) + } + }; + {$data:expr, $ctx:expr, $func:expr, $($funcs:expr),+} => { + parser_selector! {$data, $ctx, $func}; + parser_selector! {$data, $ctx, $($funcs),*}; + }; +} + +#[macro_export] +macro_rules! parser_selector_simple { + {$data:expr, $func:expr} => { + match $func($data) { + Ok(res) => return Ok(res), + Err(AmlError::AmlInvalidOpCode) => (), + Err(e) => return Err(e) + } + }; + {$data:expr, $func:expr, $($funcs:expr),+} => { + parser_selector_simple! {$data, $func}; + parser_selector_simple! {$data, $($funcs),*}; + }; +} + +#[macro_export] +macro_rules! parser_opcode { + ($data:expr, $opcode:expr) => { + if $data[0] != $opcode { + return Err(AmlError::AmlInvalidOpCode); + } + }; + ($data:expr, $opcode:expr, $alternate_opcode:expr) => { + if $data[0] != $opcode && $data[0] != $alternate_opcode { + return Err(AmlError::AmlInvalidOpCode); + } + }; +} + +#[macro_export] +macro_rules! parser_opcode_extended { + ($data:expr, $opcode:expr) => { + if $data[0] != 0x5B || $data[1] != $opcode { + return Err(AmlError::AmlInvalidOpCode); + } + }; +} diff --git a/acpid/src/aml/pkglength.rs b/acpid/src/aml/pkglength.rs new file mode 100644 index 0000000000..7b511f9b44 --- /dev/null +++ b/acpid/src/aml/pkglength.rs @@ -0,0 +1,25 @@ +use super::AmlError; + +pub fn parse_pkg_length(data: &[u8]) -> Result<(usize, usize), AmlError> { + let lead_byte = data[0]; + let count_bytes: usize = (lead_byte >> 6) as usize; + + if count_bytes == 0 { + return Ok(((lead_byte & 0x3F) as usize, 1 as usize)); + } + + let upper_two = (lead_byte >> 4) & 0x03; + if upper_two != 0 { + return Err(AmlError::AmlParseError("Invalid package length")); + } + + let mut current_byte = 0; + let mut pkg_len: usize = (lead_byte & 0x0F) as usize; + + while current_byte < count_bytes { + pkg_len += (data[1 + current_byte] as u32 * 16 * (256 as u32).pow(current_byte as u32)) as usize; + current_byte += 1; + } + + Ok((pkg_len, count_bytes + 1)) +} diff --git a/acpid/src/aml/termlist.rs b/acpid/src/aml/termlist.rs new file mode 100644 index 0000000000..c382a7c5c0 --- /dev/null +++ b/acpid/src/aml/termlist.rs @@ -0,0 +1,172 @@ +use super::AmlError; +use super::parser::{ AmlParseType, ParseResult, AmlExecutionContext, ExecutionState }; +use super::namespace::{AmlValue, get_namespace_string}; +use super::namespacemodifier::parse_namespace_modifier; +use super::namedobj::parse_named_obj; +use super::dataobj::{parse_data_obj, parse_arg_obj, parse_local_obj}; +use super::type1opcode::parse_type1_opcode; +use super::type2opcode::parse_type2_opcode; +use super::namestring::parse_name_string; + +pub fn parse_term_list(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + let mut current_offset: usize = 0; + + while current_offset < data.len() { + let res = parse_term_obj(&data[current_offset..], ctx)?; + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: data.len() + }) + } + + current_offset += res.len; + } + + Ok(AmlParseType { + val: AmlValue::None, + len: data.len() + }) +} + +pub fn parse_term_arg(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_local_obj, + parse_data_obj, + parse_arg_obj, + parse_type2_opcode + }; + + Err(AmlError::AmlInvalidOpCode) +} + +pub fn parse_object_list(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + let mut current_offset: usize = 0; + + while current_offset < data.len() { + let res = parse_object(&data[current_offset..], ctx)?; + + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: data.len() + }) + } + + current_offset += res.len; + } + + Ok(AmlParseType { + val: AmlValue::None, + len: data.len() + }) +} + +fn parse_object(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_namespace_modifier, + parse_named_obj + }; + + Err(AmlError::AmlInvalidOpCode) +} + +pub fn parse_method_invocation(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + let name = parse_name_string(data, ctx)?; + let method = ctx.get(name.val.clone())?; + + let method = match method { + AmlValue::None => return Err(AmlError::AmlDeferredLoad), + _ => method.get_as_method()? + }; + + let mut cur = 0; + let mut params: Vec = vec!(); + + let mut current_offset = name.len; + + while cur < method.arg_count { + let res = parse_term_arg(&data[current_offset..], ctx)?; + + current_offset += res.len; + cur += 1; + + params.push(res.val); + } + + Ok(AmlParseType { + val: method.execute(get_namespace_string(ctx.scope.clone(), name.val)?, params), + len: current_offset + }) +} + +fn parse_term_obj(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_namespace_modifier, + parse_named_obj, + parse_type1_opcode, + parse_type2_opcode + }; + + Err(AmlError::AmlInvalidOpCode) +} diff --git a/acpid/src/aml/type1opcode.rs b/acpid/src/aml/type1opcode.rs new file mode 100644 index 0000000000..fe5b8256ba --- /dev/null +++ b/acpid/src/aml/type1opcode.rs @@ -0,0 +1,479 @@ +use std::mem; + +use super::AmlError; +use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; +use super::namespace::AmlValue; +use super::pkglength::parse_pkg_length; +use super::termlist::{parse_term_arg, parse_term_list}; +use super::namestring::{parse_name_string, parse_super_name}; + +use crate::monotonic; + +use crate::acpi::{PossibleAmlTables, SdtHeader}; +use super::{parse_aml_table, is_aml_table}; + +pub fn parse_type1_opcode(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_def_break, + parse_def_breakpoint, + parse_def_continue, + parse_def_noop, + parse_def_fatal, + parse_def_if_else, + parse_def_load, + parse_def_notify, + parse_def_release, + parse_def_reset, + parse_def_signal, + parse_def_sleep, + parse_def_stall, + parse_def_return, + parse_def_unload, + parse_def_while + }; + + Err(AmlError::AmlInvalidOpCode) +} + +fn parse_def_break(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0xA5); + ctx.state = ExecutionState::BREAK; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 as usize + }) +} + +fn parse_def_breakpoint(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0xCC); + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 as usize + }) +} + +fn parse_def_continue(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x9F); + ctx.state = ExecutionState::CONTINUE; + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 as usize + }) +} + +fn parse_def_noop(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0xA3); + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 as usize + }) +} + +fn parse_def_fatal(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x32); + + let fatal_type = data[2]; + let fatal_code: u16 = (data[3] as u16) + ((data[4] as u16) << 8); + let fatal_arg = parse_term_arg(&data[5..], ctx)?; + + Err(AmlError::AmlFatalError(fatal_type, fatal_code, fatal_arg.val)) +} + +fn parse_def_load(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x20); + + let name = parse_name_string(&data[2..], ctx)?; + let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?; + + let tbl = ctx.get(name.val)?.get_as_buffer()?; + // TODO + let sdt = plain::from_bytes::(&tbl[..mem::size_of::()]).unwrap(); + + let table = match ctx.acpi_context().sdt_from_signature(&sdt.signature()) { + Some(table) => table, + None => return Err(AmlError::AmlValueError), + }; + + if let Some(aml_sdt) = PossibleAmlTables::try_new(table.clone()) { + let delta = parse_aml_table(aml_sdt)?; + let _ = ctx.modify(ddb_handle_object.val, AmlValue::DDBHandle((delta, sdt.signature()))); + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + name.len + ddb_handle_object.len + }) + } else { + Err(AmlError::AmlValueError) + } +} + +fn parse_def_notify(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x86); + + let object = parse_super_name(&data[1..], ctx)?; + let value = parse_term_arg(&data[1 + object.len..], ctx)?; + + let number = value.val.get_as_integer()? as u8; + + match ctx.get(object.val)? { + AmlValue::Device(d) => { + if let Some(methods) = d.notify_methods.get(&number) { + for method in methods { + method(); + } + } + }, + AmlValue::Processor(d) => { + if let Some(methods) = d.notify_methods.get(&number) { + for method in methods { + method(); + } + } + }, + AmlValue::ThermalZone(d) => { + if let Some(methods) = d.notify_methods.get(&number) { + for method in methods { + method(); + } + } + }, + _ => return Err(AmlError::AmlValueError) + } + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + object.len + value.len + }) +} + +fn parse_def_release(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x27); + + let obj = parse_super_name(&data[2..], ctx)?; + let _ = ctx.release_mutex(obj.val); + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + obj.len + }) +} + +fn parse_def_reset(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x26); + + let object = parse_super_name(&data[2..], ctx)?; + ctx.get(object.val.clone())?.get_as_event()?; + + let _ = ctx.modify(object.val.clone(), AmlValue::Event(0)); + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + object.len + }) +} + +fn parse_def_signal(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x24); + let object = parse_super_name(&data[2..], ctx)?; + + ctx.signal_event(object.val)?; + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + object.len + }) +} + +fn parse_def_sleep(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x22); + + let time = parse_term_arg(&data[2..], ctx)?; + let timeout = time.val.get_as_integer()?; + + let (seconds, nanoseconds) = monotonic(); + let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); + + loop { + let (seconds, nanoseconds) = monotonic(); + let current_time_ns = nanoseconds + (seconds * 1_000_000_000); + + if current_time_ns - starting_time_ns > timeout as u64 * 1_000_000 { + break; + } + } + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + time.len + }) +} + +fn parse_def_stall(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x21); + + let time = parse_term_arg(&data[2..], ctx)?; + let timeout = time.val.get_as_integer()?; + + let (seconds, nanoseconds) = monotonic(); + let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); + + loop { + let (seconds, nanoseconds) = monotonic(); + let current_time_ns = nanoseconds + (seconds * 1_000_000_000); + + if current_time_ns - starting_time_ns > timeout as u64 * 1000 { + break; + } + } + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + time.len + }) +} + +fn parse_def_unload(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x2A); + + let object = parse_super_name(&data[2..], ctx)?; + + let delta = ctx.get(object.val)?.get_as_ddb_handle()?; + let mut namespace = ctx.prelock(); + + if let Some(ref mut ns) = *namespace { + for o in delta.0 { + ns.remove(&o); + } + } + + Ok(AmlParseType { + val: AmlValue::None, + len: 2 + object.len + }) +} + +fn parse_def_if_else(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0xA0); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let if_condition = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?; + + let (else_length, else_length_len) = if data.len() > 1 + pkg_length && data[1 + pkg_length] == 0xA1 { + parse_pkg_length(&data[2 + pkg_length..])? + } else { + (0 as usize, 0 as usize) + }; + + if if_condition.val.get_as_integer()? > 0 { + parse_term_list(&data[1 + pkg_length_len + if_condition.len .. 1 + pkg_length], ctx)?; + } else if else_length > 0 { + parse_term_list(&data[2 + pkg_length + else_length_len .. 2 + pkg_length + else_length], ctx)?; + } + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + pkg_length + if else_length > 0 { 1 + else_length } else { 0 } + }) +} + +fn parse_def_while(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0xA2); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + + loop { + let predicate = parse_term_arg(&data[1 + pkg_length_len..], ctx)?; + if predicate.val.get_as_integer()? == 0 { + break; + } + + parse_term_list(&data[1 + pkg_length_len + predicate.len .. 1 + pkg_length], ctx)?; + + match ctx.state { + ExecutionState::EXECUTING => (), + ExecutionState::BREAK => { + ctx.state = ExecutionState::EXECUTING; + break; + }, + ExecutionState::CONTINUE => ctx.state = ExecutionState::EXECUTING, + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + } + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + pkg_length + }) +} + +fn parse_def_return(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0xA4); + + let arg_object = parse_term_arg(&data[1..], ctx)?; + ctx.state = ExecutionState::RETURN(arg_object.val); + + Ok(AmlParseType { + val: AmlValue::None, + len: 1 + arg_object.len + }) +} diff --git a/acpid/src/aml/type2opcode.rs b/acpid/src/aml/type2opcode.rs new file mode 100644 index 0000000000..846d44a658 --- /dev/null +++ b/acpid/src/aml/type2opcode.rs @@ -0,0 +1,1784 @@ +use std::convert::TryFrom; + +use super::{AmlError, parse_aml_with_scope}; +use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; +use super::namespace::{AmlValue, ObjectReference}; +use super::pkglength::parse_pkg_length; +use super::termlist::{parse_term_arg, parse_method_invocation}; +use super::namestring::{parse_super_name, parse_target, parse_name_string, parse_simple_name}; +use super::dataobj::parse_data_ref_obj; + +use crate::monotonic; +use crate::acpi::{PossibleAmlTables, SdtSignature}; + +#[derive(Debug, Clone)] +pub enum MatchOpcode { + MTR, + MEQ, + MLE, + MLT, + MGE, + MGT +} + +pub fn parse_type2_opcode(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_def_increment, + parse_def_acquire, + parse_def_wait, + parse_def_land, + parse_def_lequal, + parse_def_lgreater, + parse_def_lless, + parse_def_lnot, + parse_def_lor, + parse_def_size_of, + parse_def_store, + parse_def_subtract, + parse_def_to_buffer, + parse_def_to_hex_string, + parse_def_to_bcd, + parse_def_to_decimal_string, + parse_def_to_integer, + parse_def_to_string, + parse_def_add, + parse_def_xor, + parse_def_shift_left, + parse_def_shift_right, + parse_def_mod, + parse_def_and, + parse_def_or, + parse_def_concat_res, + parse_def_concat, + parse_def_cond_ref_of, + parse_def_copy_object, + parse_def_decrement, + parse_def_divide, + parse_def_find_set_left_bit, + parse_def_find_set_right_bit, + parse_def_from_bcd, + parse_def_load_table, + parse_def_match, + parse_def_mid, + parse_def_multiply, + parse_def_nand, + parse_def_nor, + parse_def_not, + parse_def_timer, + parse_def_buffer, + parse_def_package, + parse_def_var_package, + parse_def_object_type, + parse_def_deref_of, + parse_def_ref_of, + parse_def_index, + parse_method_invocation + }; + + Err(AmlError::AmlInvalidOpCode) +} + +pub fn parse_type6_opcode(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_selector! { + data, ctx, + parse_def_deref_of, + parse_def_ref_of, + parse_def_index, + parse_method_invocation + }; + + Err(AmlError::AmlInvalidOpCode) +} + +pub fn parse_def_object_type(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x8E); + parser_selector! { + data, ctx, + parse_super_name, + parse_def_ref_of, + parse_def_deref_of, + parse_def_index + } + + Err(AmlError::AmlInvalidOpCode) +} + +pub fn parse_def_package(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + // TODO: Handle deferred loads in here + parser_opcode!(data, 0x12); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let numelements = data[1 + pkg_length_len] as usize; + let mut elements = parse_package_elements_list(&data[2 + pkg_length_len .. 1 + pkg_length], ctx)?.val.get_as_package()?; + + if elements.len() > numelements { + elements = elements[0 .. numelements].to_vec(); + } else if numelements > elements.len() { + for _ in 0..numelements - elements.len() { + elements.push(AmlValue::Uninitialized); + } + } + + Ok(AmlParseType { + val: AmlValue::Package(elements), + len: 1 + pkg_length + }) +} + +pub fn parse_def_var_package(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + // TODO: Handle deferred loads in here + parser_opcode!(data, 0x13); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let num_elements = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?; + let mut elements = parse_package_elements_list(&data[1 + pkg_length_len + num_elements.len .. + 1 + pkg_length], ctx)?.val.get_as_package()?; + + let numelements = num_elements.val.get_as_integer()? as usize; + + if elements.len() > numelements { + elements = elements[0 .. numelements].to_vec(); + } else if numelements > elements.len() { + for _ in 0..numelements - elements.len() { + elements.push(AmlValue::Uninitialized); + } + } + + Ok(AmlParseType { + val: AmlValue::Package(elements), + len: 1 + pkg_length + }) +} + +fn parse_package_elements_list(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + let mut current_offset: usize = 0; + let mut elements: Vec = vec!(); + + while current_offset < data.len() { + let dro = if let Ok(e) = parse_data_ref_obj(&data[current_offset..], ctx) { + e + } else { + let d = parse_name_string(&data[current_offset..], ctx)?; + AmlParseType { + val: AmlValue::ObjectReference(ObjectReference::Object(d.val.get_as_string()?)), + len: d.len + } + }; + + elements.push(dro.val); + current_offset += dro.len; + } + + Ok(AmlParseType { + val: AmlValue::Package(elements), + len: data.len() + }) +} + +pub fn parse_def_buffer(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x11); + + let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; + let buffer_size = parse_term_arg(&data[1 + pkg_length_len..], ctx)?; + let mut byte_list = data[1 + pkg_length_len + buffer_size.len .. 1 + pkg_length].to_vec().clone(); + + byte_list.truncate(buffer_size.val.get_as_integer()? as usize); + + Ok(AmlParseType { + val: AmlValue::Buffer(byte_list), + len: 1 + pkg_length + }) +} + +fn parse_def_ref_of(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x71); + + let obj = parse_super_name(&data[1..], ctx)?; + let res = match obj.val { + AmlValue::String(ref s) => { + match ctx.get(AmlValue::String(s.clone()))? { + AmlValue::None => return Err(AmlError::AmlValueError), + _ => ObjectReference::Object(s.clone()) + } + }, + AmlValue::ObjectReference(ref o) => o.clone(), + _ => return Err(AmlError::AmlValueError) + }; + + Ok(AmlParseType { + val: AmlValue::ObjectReference(res), + len: 1 + obj.len + }) +} + +fn parse_def_deref_of(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x83); + + let obj = parse_term_arg(&data[1..], ctx)?; + let res = ctx.get(obj.val)?; + + match res { + AmlValue::None => Err(AmlError::AmlValueError), + _ => Ok(AmlParseType { + val: res, + len: 1 + obj.len + }) + } +} + +fn parse_def_acquire(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x23); + + let obj = parse_super_name(&data[1..], ctx)?; + let timeout = (data[2 + obj.len] as u16) + ((data[3 + obj.len] as u16) << 8); + + let (seconds, nanoseconds) = monotonic(); + let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); + + loop { + match ctx.acquire_mutex(obj.val.clone()) { + Err(e) => return Err(e), + Ok(b) => if b { + return Ok(AmlParseType { + val: AmlValue::Integer(0), + len: 4 + obj.len + }); + } else if timeout == 0xFFFF { + // TODO: How long should be sleep be? + let _ = syscall::sched_yield(); + } else { + let (seconds, nanoseconds) = monotonic(); + let current_time_ns = nanoseconds + (seconds * 1_000_000_000); + + if current_time_ns - starting_time_ns > timeout as u64 * 1_000_000 { + return Ok(AmlParseType { + val: AmlValue::Integer(1), + len: 4 + obj.len + }); + } + } + } + } +} + +fn parse_def_increment(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x75); + + let obj = parse_super_name(&data[1..], ctx)?; + + let _namespace = ctx.prelock(); + let value = AmlValue::Integer(ctx.get(obj.val.clone())?.get_as_integer()? + 1); + let _ = ctx.modify(obj.val, value.clone()); + + Ok(AmlParseType { + val: value, + len: 1 + obj.len + }) +} + +fn parse_def_index(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x88); + + let obj = parse_term_arg(&data[1..], ctx)?; + let idx = parse_term_arg(&data[1 + obj.len..], ctx)?; + let target = parse_target(&data[1 + obj.len + idx.len..], ctx)?; + + let reference = AmlValue::ObjectReference(ObjectReference::Index(Box::new(obj.val), Box::new(idx.val))); + let _ = ctx.modify(target.val, reference.clone()); + + Ok(AmlParseType { + val: reference, + len: 1 + obj.len + idx.len + target.len + }) +} + +fn parse_def_land(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x90); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + + let result = if lhs.val.get_as_integer()? > 0 && rhs.val.get_as_integer()? > 0 { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + lhs.len + rhs.len + }) +} + +fn parse_def_lequal(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x93); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + + let result = if lhs.val.get_as_integer()? == rhs.val.get_as_integer()? { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + lhs.len + rhs.len + }) +} + +fn parse_def_lgreater(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x94); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + + let result = if lhs.val.get_as_integer()? > rhs.val.get_as_integer()? { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + lhs.len + rhs.len + }) +} + +fn parse_def_lless(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x95); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + + let result = if lhs.val.get_as_integer()? < rhs.val.get_as_integer()? { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + lhs.len + rhs.len + }) +} + +fn parse_def_lnot(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x92); + + let operand = parse_term_arg(&data[1..], ctx)?; + let result = if operand.val.get_as_integer()? == 0 { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + operand.len + }) +} + +fn parse_def_lor(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x91); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + + let result = if lhs.val.get_as_integer()? > 0 || rhs.val.get_as_integer()? > 0 { 1 } else { 0 }; + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(result), + len: 1 + lhs.len + rhs.len + }) +} + +fn parse_def_to_hex_string(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x98); + + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + + let res = match operand.val { + AmlValue::Integer(_) => { + let result: String = format!("{:X}", operand.val.get_as_integer()?); + AmlValue::String(result) + }, + AmlValue::String(s) => AmlValue::String(s), + AmlValue::Buffer(_) => { + let mut string: String = String::new(); + + for b in operand.val.get_as_buffer()? { + string.push_str(&format!("{:X}", b)); + } + + AmlValue::String(string) + }, + _ => return Err(AmlError::AmlValueError) + }; + + let _ = ctx.modify(target.val, res.clone()); + + Ok(AmlParseType { + val: res, + len: 1 + operand.len + target.len + }) +} + +fn parse_def_to_buffer(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x96); + + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + + let res = AmlValue::Buffer(operand.val.get_as_buffer()?); + let _ = ctx.modify(target.val, res.clone()); + + Ok(AmlParseType { + val: res, + len: 1 + operand.len + target.len + }) +} + +fn parse_def_to_bcd(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x29); + + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + + let mut i = operand.val.get_as_integer()?; + let mut result = 0; + + while i != 0 { + result <<= 4; + result += i % 10; + i /= 10; + } + + let result = AmlValue::Integer(result); + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + operand.len + target.len + }) +} + +fn parse_def_to_decimal_string(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x97); + + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + let res = match operand.val { + AmlValue::Integer(_) => { + let result: String = format!("{}", operand.val.get_as_integer()?); + AmlValue::String(result) + }, + AmlValue::String(s) => AmlValue::String(s), + AmlValue::Buffer(_) => { + let mut string: String = String::new(); + + for b in operand.val.get_as_buffer()? { + string.push_str(&format!("{}", b)); + } + + AmlValue::String(string) + }, + _ => return Err(AmlError::AmlValueError) + }; + + let _ = ctx.modify(target.val, res.clone()); + + Ok(AmlParseType { + val: res, + len: 1 + operand.len + target.len + }) +} + +fn parse_def_to_integer(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x99); + + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + + let res = AmlValue::Integer(operand.val.get_as_integer()?); + + let _ = ctx.modify(target.val, res.clone()); + + Ok(AmlParseType { + val: res, + len: 1 + operand.len + target.len + }) +} + +fn parse_def_to_string(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x9C); + + let operand = parse_term_arg(&data[1..], ctx)?; + let length = parse_term_arg(&data[1 + operand.len..], ctx)?; + let target = parse_target(&data[1 + operand.len + length.len..], ctx)?; + + let buf = operand.val.get_as_buffer()?; + let mut string = match String::from_utf8(buf) { + Ok(s) => s, + Err(_) => return Err(AmlError::AmlValueError) + }; + + string.truncate(length.val.get_as_integer()? as usize); + let res = AmlValue::String(string); + + let _ = ctx.modify(target.val, res.clone()); + + Ok(AmlParseType { + val: res, + len: 1 + operand.len + length.len + target.len + }) +} + +fn parse_def_subtract(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x74); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? - rhs.val.get_as_integer()?); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_size_of(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x87); + + let name = parse_super_name(&data[1..], ctx)?; + let obj = ctx.get(name.val)?; + + let res = match obj { + AmlValue::Buffer(ref v) => v.len(), + AmlValue::String(ref s) => s.len(), + AmlValue::Package(ref p) => p.len(), + _ => return Err(AmlError::AmlValueError) + }; + + Ok(AmlParseType { + val: AmlValue::Integer(res as u64), + len: 1 + name.len + }) +} + +fn parse_def_store(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x70); + + let operand = parse_term_arg(&data[1..], ctx)?; + let target = parse_super_name(&data[1 + operand.len..], ctx)?; + + let _ = ctx.modify(target.val.clone(), operand.val); + + Ok(AmlParseType { + val: target.val, + len: 1 + operand.len + target.len + }) +} + +fn parse_def_or(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x7D); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? | rhs.val.get_as_integer()?); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_shift_left(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x79); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? >> rhs.val.get_as_integer()?); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_shift_right(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x7A); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? << rhs.val.get_as_integer()?); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_add(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x72); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? + rhs.val.get_as_integer()?); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_and(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x7B); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? & rhs.val.get_as_integer()?); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_xor(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x7F); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? ^ rhs.val.get_as_integer()?); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_concat_res(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x84); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let mut buf1 = lhs.val.get_as_buffer()?.clone(); + let mut buf2 = rhs.val.get_as_buffer()?.clone(); + + if buf1.len() == 1 || buf2.len() == 1 { + return Err(AmlError::AmlValueError); + } + + if buf1.len() >= 2 && buf1[buf1.len() - 2] == 0x79 { + buf1 = buf1[0..buf1.len() - 2].to_vec(); + } + + if buf2.len() >= 2 && buf2[buf2.len() - 2] == 0x79 { + buf2 = buf2[0..buf2.len() - 2].to_vec(); + } + + buf1.append(&mut buf2); + buf1.push(0x79); + + let mut checksum: u8 = 0; + let loopbuf = buf1.clone(); + for b in loopbuf { + checksum += b; + } + + checksum = (!checksum) + 1; + buf1.push(checksum); + + let res = AmlValue::Buffer(buf1); + ctx.modify(target.val, res.clone())?; + + Ok(AmlParseType { + val: res, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_wait(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x25); + + let obj = parse_super_name(&data[2..], ctx)?; + let timeout_obj = parse_term_arg(&data[2 + obj.len..], ctx)?; + + let timeout = timeout_obj.val.get_as_integer()?; + + let (seconds, nanoseconds) = monotonic(); + let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); + + loop { + match ctx.wait_for_event(obj.val.clone()) { + Err(e) => return Err(e), + Ok(b) => if b { + return Ok(AmlParseType { + val: AmlValue::Integer(0), + len: 2 + obj.len + timeout_obj.len + }) + } else if timeout >= 0xFFFF { + let _ = syscall::sched_yield(); + } else { + let (seconds, nanoseconds) = crate::monotonic(); + let current_time_ns = nanoseconds + (seconds * 1_000_000_000); + + if current_time_ns - starting_time_ns > timeout as u64 * 1_000_000 { + return Ok(AmlParseType { + val: AmlValue::Integer(1), + len: 2 + obj.len + timeout_obj.len + }); + } + } + } + } +} + +fn parse_def_cond_ref_of(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x12); + + let obj = parse_super_name(&data[2..], ctx)?; + let target = parse_target(&data[2 + obj.len..], ctx)?; + + let res = match obj.val { + AmlValue::String(ref s) => { + match ctx.get(AmlValue::String(s.clone()))? { + AmlValue::None => return Ok(AmlParseType { + val: AmlValue::Integer(0), + len: 1 + obj.len + target.len + }), + _ => ObjectReference::Object(s.clone()) + } + }, + AmlValue::ObjectReference(ref o) => o.clone(), + _ => return Err(AmlError::AmlValueError) + }; + + let _ = ctx.modify(target.val, AmlValue::ObjectReference(res)); + + Ok(AmlParseType { + val: AmlValue::Integer(1), + len: 1 + obj.len + target.len + }) +} + +fn parse_def_copy_object(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + // TODO: Compute the result + // TODO: Store the result + parser_opcode!(data, 0x9D); + + let source = parse_term_arg(&data[1..], ctx)?; + let destination = parse_simple_name(&data[1 + source.len..], ctx)?; + + ctx.copy(destination.val, source.val.clone())?; + + Ok(AmlParseType { + val: source.val, + len: 1 + source.len + destination.len + }) +} + +fn parse_def_concat(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x73); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = match lhs.val { + AmlValue::Integer(_i) => { + let j = AmlValue::Integer(rhs.val.get_as_integer()?); + + let mut first = lhs.val.get_as_buffer()?.clone(); + let mut second = j.get_as_buffer()?.clone(); + + first.append(&mut second); + + AmlValue::Buffer(first) + }, + AmlValue::String(s) => { + let t = if let Ok(t) = rhs.val.get_as_string() { + t + } else { + rhs.val.get_type_string() + }; + + AmlValue::String(format!("{}{}", s, t)) + }, + AmlValue::Buffer(b) => { + let mut b = b.clone(); + let mut c = if let Ok(c) = rhs.val.get_as_buffer() { + c.clone() + } else { + AmlValue::String(rhs.val.get_type_string()).get_as_buffer()?.clone() + }; + + b.append(&mut c); + + AmlValue::Buffer(b) + }, + _ => { + let first = lhs.val.get_type_string(); + let second = if let Ok(second) = rhs.val.get_as_string() { + second + } else { + rhs.val.get_type_string() + }; + + AmlValue::String(format!("{}{}", first, second)) + } + }; + + ctx.modify(target.val, result.clone())?; + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_decrement(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x76); + + let obj = parse_super_name(&data[1..], ctx)?; + + let _namespace = ctx.prelock(); + let value = AmlValue::Integer(ctx.get(obj.val.clone())?.get_as_integer()? - 1); + let _ = ctx.modify(obj.val, value.clone()); + + Ok(AmlParseType { + val: value, + len: 1 + obj.len + }) +} + +fn parse_def_divide(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x78); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target_remainder = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + let target_quotient = parse_target(&data[1 + lhs.len + rhs.len + target_remainder.len..], ctx)?; + + let numerator = lhs.val.get_as_integer()?; + let denominator = rhs.val.get_as_integer()?; + + let remainder = numerator % denominator; + let quotient = (numerator - remainder) / denominator; + + let _ = ctx.modify(target_remainder.val, AmlValue::Integer(remainder)); + let _ = ctx.modify(target_quotient.val, AmlValue::Integer(quotient)); + + Ok(AmlParseType { + val: AmlValue::Integer(quotient), + len: 1 + lhs.len + rhs.len + target_remainder.len + target_quotient.len + }) +} + +fn parse_def_find_set_left_bit(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x81); + + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + + let mut first_bit = 32; + let mut test = operand.val.get_as_integer()?; + + while first_bit > 0{ + if test & 0x8000_0000_0000_0000 > 0 { + break; + } + + test <<= 1; + first_bit -= 1; + } + + let result = AmlValue::Integer(first_bit); + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + operand.len + target.len + }) +} + +fn parse_def_find_set_right_bit(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x82); + + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + + let mut first_bit = 1; + let mut test = operand.val.get_as_integer()?; + + while first_bit <= 32 { + if test & 1 > 0 { + break; + } + + test >>= 1; + first_bit += 1; + } + + if first_bit == 33 { + first_bit = 0; + } + + let result = AmlValue::Integer(first_bit); + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + operand.len + target.len + }) +} + +fn parse_def_load_table(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + // TODO: Clean up + parser_opcode_extended!(data, 0x1F); + + let signature = parse_term_arg(&data[2..], ctx)?; + let oem_id = parse_term_arg(&data[2 + signature.len..], ctx)?; + let oem_table_id = parse_term_arg(&data[2 + signature.len + oem_id.len..], ctx)?; + let root_path = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len..], ctx)?; + let parameter_path = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len + root_path.len..], ctx)?; + let parameter_data = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len + root_path.len + parameter_path.len..], ctx)?; + + let signature = { + <[u8; 4]>::try_from(&*signature.val.get_as_buffer()?) + .expect("expected 'load table' def to have a signature that is 4 bytes long") + }; + let oem_id = { + <[u8; 6]>::try_from(&*oem_id.val.get_as_buffer()?) + .expect("expected 'load table' def to have an OEM ID that is 6 bytes long") + }; + let oem_table_id = { + <[u8; 8]>::try_from(&*oem_table_id.val.get_as_buffer()?) + .expect("expected 'load table' def to have an OEM table ID that is 8 bytes long") + }; + + let sdt_signature = SdtSignature { + signature, + oem_id, + oem_table_id, + }; + + let parse_len = 2 + signature.len() + oem_id.len() + oem_table_id.len() + root_path.len + parameter_path.len + parameter_data.len; + + let sdt = ctx.acpi_context().sdt_from_signature(&sdt_signature); + + Ok(if let Some(sdt) = sdt.and_then(|sdt| PossibleAmlTables::try_new(sdt.clone())) { + let hdl = parse_aml_with_scope(sdt, root_path.val.get_as_string()?)?; + let _ = ctx.modify(parameter_path.val, parameter_data.val); + + AmlParseType { + val: AmlValue::DDBHandle((hdl, sdt_signature)), + len: parse_len, + } + } else { + AmlParseType { + val: AmlValue::IntegerConstant(0), + len: parse_len, + } + }) +} + +fn parse_def_match(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x28); + + let search_pkg = parse_term_arg(&data[1..], ctx)?; + + let first_operation = match data[1 + search_pkg.len] { + 0 => MatchOpcode::MTR, + 1 => MatchOpcode::MEQ, + 2 => MatchOpcode::MLE, + 3 => MatchOpcode::MLT, + 4 => MatchOpcode::MGE, + 5 => MatchOpcode::MGT, + _ => return Err(AmlError::AmlParseError("DefMatch - Invalid Opcode")) + }; + let first_operand = parse_term_arg(&data[2 + search_pkg.len..], ctx)?; + + let second_operation = match data[2 + search_pkg.len + first_operand.len] { + 0 => MatchOpcode::MTR, + 1 => MatchOpcode::MEQ, + 2 => MatchOpcode::MLE, + 3 => MatchOpcode::MLT, + 4 => MatchOpcode::MGE, + 5 => MatchOpcode::MGT, + _ => return Err(AmlError::AmlParseError("DefMatch - Invalid Opcode")) + }; + let second_operand = parse_term_arg(&data[3 + search_pkg.len + first_operand.len..], ctx)?; + + let start_index = parse_term_arg(&data[3 + search_pkg.len + first_operand.len + second_operand.len..], ctx)?; + + let pkg = search_pkg.val.get_as_package()?; + let mut idx = start_index.val.get_as_integer()? as usize; + + match first_operand.val { + AmlValue::Integer(i) => { + let j = second_operand.val.get_as_integer()?; + + while idx < pkg.len() { + let val = if let Ok(v) = pkg[idx].get_as_integer() { v } else { idx += 1; continue; }; + idx += 1; + + match first_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != i { continue }, + MatchOpcode::MLE => if val > i { continue }, + MatchOpcode::MLT => if val >= i { continue }, + MatchOpcode::MGE => if val < i { continue }, + MatchOpcode::MGT => if val <= i { continue } + } + + match second_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != j { continue }, + MatchOpcode::MLE => if val > j { continue }, + MatchOpcode::MLT => if val >= j { continue }, + MatchOpcode::MGE => if val < j { continue }, + MatchOpcode::MGT => if val <= j { continue } + } + + return Ok(AmlParseType { + val: AmlValue::Integer(idx as u64), + len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len + }) + } + }, + AmlValue::String(i) => { + let j = second_operand.val.get_as_string()?; + + while idx < pkg.len() { + let val = if let Ok(v) = pkg[idx].get_as_string() { v } else { idx += 1; continue; }; + idx += 1; + + match first_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != i { continue }, + MatchOpcode::MLE => if val > i { continue }, + MatchOpcode::MLT => if val >= i { continue }, + MatchOpcode::MGE => if val < i { continue }, + MatchOpcode::MGT => if val <= i { continue } + } + + match second_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != j { continue }, + MatchOpcode::MLE => if val > j { continue }, + MatchOpcode::MLT => if val >= j { continue }, + MatchOpcode::MGE => if val < j { continue }, + MatchOpcode::MGT => if val <= j { continue } + } + + return Ok(AmlParseType { + val: AmlValue::Integer(idx as u64), + len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len + }) + } + }, + _ => { + let i = first_operand.val.get_as_buffer()?; + let j = second_operand.val.get_as_buffer()?; + + while idx < pkg.len() { + let val = if let Ok(v) = pkg[idx].get_as_buffer() { v } else { idx += 1; continue; }; + idx += 1; + + match first_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != i { continue }, + MatchOpcode::MLE => if val > i { continue }, + MatchOpcode::MLT => if val >= i { continue }, + MatchOpcode::MGE => if val < i { continue }, + MatchOpcode::MGT => if val <= i { continue } + } + + match second_operation { + MatchOpcode::MTR => (), + MatchOpcode::MEQ => if val != j { continue }, + MatchOpcode::MLE => if val > j { continue }, + MatchOpcode::MLT => if val >= j { continue }, + MatchOpcode::MGE => if val < j { continue }, + MatchOpcode::MGT => if val <= j { continue } + } + + return Ok(AmlParseType { + val: AmlValue::Integer(idx as u64), + len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len + }) + } + } + } + + Ok(AmlParseType { + val: AmlValue::IntegerConstant(0xFFFF_FFFF_FFFF_FFFF), + len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len + }) +} + +fn parse_def_from_bcd(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x28); + + let operand = parse_term_arg(&data[2..], ctx)?; + let target = parse_target(&data[2 + operand.len..], ctx)?; + + let mut i = operand.val.get_as_integer()?; + let mut result = 0; + + while i != 0 { + if i & 0x0F > 10 { + return Err(AmlError::AmlValueError); + } + + result *= 10; + result += i & 0x0F; + i >>= 4; + } + + let result = AmlValue::Integer(result); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 2 + operand.len + target.len + }) +} + +fn parse_def_mid(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x9E); + + let source = parse_term_arg(&data[1..], ctx)?; + let index = parse_term_arg(&data[1 + source.len..], ctx)?; + let length = parse_term_arg(&data[1 + source.len + index.len..], ctx)?; + let target = parse_target(&data[1 + source.len + index.len + length.len..], ctx)?; + + let idx = index.val.get_as_integer()? as usize; + let mut len = length.val.get_as_integer()? as usize; + + let result = match source.val { + AmlValue::String(s) => { + if idx > s.len() { + AmlValue::String(String::new()) + } else { + let mut res = s.clone().split_off(idx); + + if len < res.len() { + res.split_off(len); + } + + AmlValue::String(res) + } + }, + _ => { + // If it isn't a string already, treat it as a buffer. Must perform that check first, + // as Mid can operate on both strings and buffers, but a string can be cast as a buffer + // implicitly. + // Additionally, any type that can be converted to a buffer can also be converted to a + // string, so no information is lost + let b = source.val.get_as_buffer()?; + + if idx > b.len() { + AmlValue::Buffer(vec!()) + } else { + if idx + len > b.len() { + len = b.len() - idx; + } + + AmlValue::Buffer(b[idx .. idx + len].to_vec()) + } + } + }; + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + source.len + index.len + length.len + target.len + }) +} + +fn parse_def_mod(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x85); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + if rhs.val.get_as_integer()? == 0 { + return Err(AmlError::AmlValueError); + } + + let result = AmlValue::Integer(lhs.val.get_as_integer()? % rhs.val.get_as_integer()?); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_multiply(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + // TODO: Handle overflow + parser_opcode!(data, 0x77); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(lhs.val.get_as_integer()? * rhs.val.get_as_integer()?); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_nand(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x7C); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(!(lhs.val.get_as_integer()? & rhs.val.get_as_integer()?)); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_nor(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x7E); + + let lhs = parse_term_arg(&data[1..], ctx)?; + let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; + let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; + + let result = AmlValue::Integer(!(lhs.val.get_as_integer()? | rhs.val.get_as_integer()?)); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + lhs.len + rhs.len + target.len + }) +} + +fn parse_def_not(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode!(data, 0x80); + + let operand = parse_term_arg(&data[1..], ctx)?; + let target = parse_target(&data[1 + operand.len..], ctx)?; + + let result = AmlValue::Integer(!operand.val.get_as_integer()?); + + let _ = ctx.modify(target.val, result.clone()); + + Ok(AmlParseType { + val: result, + len: 1 + operand.len + target.len + }) +} + +fn parse_def_timer(data: &[u8], + ctx: &mut AmlExecutionContext) -> ParseResult { + match ctx.state { + ExecutionState::EXECUTING => (), + _ => return Ok(AmlParseType { + val: AmlValue::None, + len: 0 + }) + } + + parser_opcode_extended!(data, 0x33); + + let (seconds, nanoseconds) = monotonic(); + let monotonic_ns = nanoseconds + (seconds * 1_000_000_000); + + Ok(AmlParseType { + val: AmlValue::Integer(monotonic_ns), + len: 2 as usize + }) +} diff --git a/acpid/src/main.rs b/acpid/src/main.rs new file mode 100644 index 0000000000..54ebe96d1b --- /dev/null +++ b/acpid/src/main.rs @@ -0,0 +1,55 @@ +use std::convert::TryFrom; +use std::mem; +use std::sync::Arc; + +mod acpi; +mod aml; + +// TODO: Perhaps use the acpi and aml crates? + +fn monotonic() -> (u64, u64) { + use syscall::call::clock_gettime; + use syscall::data::TimeSpec; + use syscall::flag::CLOCK_MONOTONIC; + + let mut timespec = TimeSpec::default(); + + clock_gettime(CLOCK_MONOTONIC, &mut timespec) + .expect("failed to fetch monotonic time"); + + (timespec.tv_sec as u64, timespec.tv_nsec as u64) +} + + +fn main() { + let rxsdt_raw_data: Arc<[u8]> = std::fs::read("kernel/acpi:") + .expect("acpid: failed to read `kernel/acpi:`") + .into(); + + let sdt = self::acpi::Sdt::new(rxsdt_raw_data) + .expect("acpid: failed to parse [RX]SDT"); + + let mut thirty_two_bit; + let mut sixty_four_bit; + + let physaddrs_iter = match &sdt.signature { + b"RSDT" => { + thirty_two_bit = sdt.data().chunks(mem::size_of::()) + // TODO: With const generics, the compiler has some way of doing this for static sizes. + .map(|chunk| <[u8; mem::size_of::()]>::try_from(chunk).unwrap()) + .map(|chunk| u32::from_le_bytes(chunk)) + .map(u64::from); + + &mut thirty_two_bit as &mut dyn Iterator + } + b"XSDT" => { + sixty_four_bit = sdt.data().chunks(mem::size_of::()) + .map(|chunk| <[u8; mem::size_of::()]>::try_from(chunk).unwrap()) + .map(|chunk| u64::from_le_bytes(chunk)); + + &mut sixty_four_bit as &mut dyn Iterator + }, + _ => panic!("acpid: expected [RX]SDT from kernel to be either of those"), + }; + +} diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 60e0701750..b16f7cf456 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -72,8 +72,8 @@ impl DisplayScheme { } impl SchemeMut for DisplayScheme { - fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { - if path == b"input" { + fn open(&mut self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result { + if path_str == "input" { if uid == 0 { let id = self.next_id; self.next_id += 1; @@ -90,7 +90,6 @@ impl SchemeMut for DisplayScheme { Err(Error::new(EACCES)) } } else { - let path_str = str::from_utf8(path).unwrap_or("").trim_matches('/'); let mut parts = path_str.split('/'); let screen_i = parts.next().unwrap_or("").parse::().unwrap_or(0); if self.screens.contains_key(&screen_i) { From df4a6aee81dff45552f02434406ac394513421eb Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 10 Mar 2021 12:13:28 +0100 Subject: [PATCH 0441/1301] Remove global variables, make it compile. --- acpid/src/acpi.rs | 11 +- acpid/src/aml/mod.rs | 24 ++-- acpid/src/aml/namedobj.rs | 90 ++++++------- acpid/src/aml/namespace.rs | 40 +++--- acpid/src/aml/namespacemodifier.rs | 12 +- acpid/src/aml/parser.rs | 129 +++++++++--------- acpid/src/aml/termlist.rs | 4 +- acpid/src/aml/type1opcode.rs | 30 ++--- acpid/src/aml/type2opcode.rs | 208 ++++++++++++++--------------- 9 files changed, 276 insertions(+), 272 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 10ece8899f..40082226e3 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -6,6 +6,7 @@ use std::sync::Arc; use syscall::flag::PhysmapFlags; +use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use thiserror::Error; use super::aml::AmlValue; @@ -194,7 +195,8 @@ pub struct AcpiContext { tables: Vec, dsdt: Option, fadt: Option, - namespace: Option>, + namespace: RwLock>>, + pub next_ctx: RwLock, } impl AcpiContext { pub fn dsdt(&self) -> Option<&Dsdt> { @@ -221,8 +223,11 @@ impl AcpiContext { pub fn take_single_sdt(&mut self, signature: [u8; 4]) -> Option { self.find_single_sdt_pos(signature).map(|pos| self.tables[pos].clone()) } - pub fn namespace(&self) -> Option<&HashMap> { - self.namespace.as_ref() + pub fn namespace(&self) -> RwLockReadGuard<'_, Option>> { + self.namespace.read() + } + pub fn namespace_mut(&self) -> RwLockWriteGuard<'_, Option>> { + self.namespace.write() } pub fn fadt(&self) -> Option<&Fadt> { self.fadt.as_ref() diff --git a/acpid/src/aml/mod.rs b/acpid/src/aml/mod.rs index 903597afe2..c56cc1dbcc 100644 --- a/acpid/src/aml/mod.rs +++ b/acpid/src/aml/mod.rs @@ -36,13 +36,13 @@ pub enum AmlError { AmlHardFatal } -pub fn parse_aml_table(sdt: impl AmlContainingTable) -> Result, AmlError> { - parse_aml_with_scope(sdt, "\\".to_owned()) +pub fn parse_aml_table(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable) -> Result, AmlError> { + parse_aml_with_scope(acpi_ctx, sdt, "\\".to_owned()) } -pub fn parse_aml_with_scope(sdt: impl AmlContainingTable, scope: String) -> Result, AmlError> { +pub fn parse_aml_with_scope(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable, scope: String) -> Result, AmlError> { let data = sdt.aml(); - let mut ctx = AmlExecutionContext::new(scope); + let mut ctx = AmlExecutionContext::new(acpi_ctx, scope); parse_term_list(data, &mut ctx)?; @@ -57,8 +57,8 @@ pub fn is_aml_table(sdt: &SdtHeader) -> bool { } } -fn init_aml_table(sdt: impl AmlContainingTable) { - match parse_aml_table(sdt) { +fn init_aml_table(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable) { + match parse_aml_table(acpi_ctx, sdt) { Ok(_) => println!(": Parsed"), Err(AmlError::AmlParseError(e)) => println!(": {}", e), Err(AmlError::AmlInvalidOpCode) => println!(": Invalid opcode"), @@ -80,13 +80,13 @@ fn init_namespace(context: &AcpiContext) -> HashMap { let dsdt = context.dsdt().expect("could not find any DSDT"); log::info!("Found DSDT."); - init_aml_table(dsdt); + init_aml_table(context, dsdt); let ssdts = context.ssdts(); for ssdt in ssdts { print!("Found SSDT."); - init_aml_table(ssdt); + init_aml_table(context, ssdt); } todo!() @@ -107,7 +107,9 @@ pub fn set_global_s_state(context: &AcpiContext, state: u8) { let port = fadt.pm1a_control_block as u16; let mut val = 1 << 13; - let namespace = match context.namespace() { + let namespace_guard = context.namespace(); + + let namespace = match &*namespace_guard { Some(namespace) => namespace, None => { log::error!("Cannot set global S-state due to missing ACPI namespace"); @@ -130,8 +132,8 @@ pub fn set_global_s_state(context: &AcpiContext, state: u8) { } }; - let slp_typa = p[0].get_as_integer().expect("SLP_TYPa is not an integer"); - let slp_typb = p[1].get_as_integer().expect("SLP_TYPb is not an integer"); + let slp_typa = p[0].get_as_integer(context).expect("SLP_TYPa is not an integer"); + let slp_typb = p[1].get_as_integer(context).expect("SLP_TYPb is not an integer"); log::info!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); val |= slp_typa as u16; diff --git a/acpid/src/aml/namedobj.rs b/acpid/src/aml/namedobj.rs index 01e272e492..40659b2c77 100644 --- a/acpid/src/aml/namedobj.rs +++ b/acpid/src/aml/namedobj.rs @@ -155,8 +155,8 @@ fn parse_def_bank_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResu }; let selector = FieldSelector::Bank { - region: region_name.val.get_as_string()?, - bank_register: bank_name.val.get_as_string()?, + region: region_name.val.get_as_string(ctx.acpi_context())?, + bank_register: bank_name.val.get_as_string(ctx.acpi_context())?, bank_selector: Box::new(bank_value.val) }; @@ -188,9 +188,9 @@ fn parse_def_create_bit_field(data: &[u8], ctx: &mut AmlExecutionContext) -> Par let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { source_buf: Box::new(source_buf.val), index: Box::new(bit_index.val), length: Box::new(AmlValue::IntegerConstant(1)) @@ -221,9 +221,9 @@ fn parse_def_create_byte_field(data: &[u8], ctx: &mut AmlExecutionContext) -> Pa let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { source_buf: Box::new(source_buf.val), index: Box::new(bit_index.val), length: Box::new(AmlValue::IntegerConstant(8)) @@ -254,9 +254,9 @@ fn parse_def_create_word_field(data: &[u8], ctx: &mut AmlExecutionContext) -> Pa let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { source_buf: Box::new(source_buf.val), index: Box::new(bit_index.val), length: Box::new(AmlValue::IntegerConstant(16)) @@ -287,9 +287,9 @@ fn parse_def_create_dword_field(data: &[u8], ctx: &mut AmlExecutionContext) -> P let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - let _ = ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + let _ = ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { source_buf: Box::new(source_buf.val), index: Box::new(bit_index.val), length: Box::new(AmlValue::IntegerConstant(32)) @@ -320,9 +320,9 @@ fn parse_def_create_qword_field(data: &[u8], ctx: &mut AmlExecutionContext) -> P let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { source_buf: Box::new(source_buf.val), index: Box::new(bit_index.val), length: Box::new(AmlValue::IntegerConstant(64)) @@ -354,9 +354,9 @@ fn parse_def_create_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseRe let num_bits = parse_term_arg(&data[2 + source_buf.len + bit_index.len..], ctx)?; let name = parse_name_string(&data[2 + source_buf.len + bit_index.len + num_bits.len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::BufferField(BufferField { + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { source_buf: Box::new(source_buf.val), index: Box::new(bit_index.val), length: Box::new(num_bits.val) @@ -389,9 +389,9 @@ fn parse_def_data_region(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseRes let oem_id = parse_term_arg(&data[2 + name.len + signature.len..], ctx)?; let oem_table_id = parse_term_arg(&data[2 + name.len + signature.len + oem_id.len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::OperationRegion(OperationRegion { + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::OperationRegion(OperationRegion { region: RegionSpace::SystemMemory, offset: Box::new(AmlValue::IntegerConstant(0)), len: Box::new(AmlValue::IntegerConstant(0)), @@ -425,8 +425,8 @@ fn parse_def_event(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { let name = parse_name_string(&data[2..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::Event(0))?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Event(0))?; Ok(AmlParseType { val: AmlValue::None, @@ -453,12 +453,12 @@ fn parse_def_device(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; let name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - let mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; + let mut local_ctx = AmlExecutionContext::new(ctx.acpi_context(), local_scope_string.clone()); parse_object_list(&data[2 + pkg_length_len + name.len .. 2 + pkg_length], &mut local_ctx)?; - ctx.add_to_namespace(local_scope_string, AmlValue::Device(Device { + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Device(Device { obj_list: local_ctx.namespace_delta.clone(), notify_methods: BTreeMap::new() }))?; @@ -503,9 +503,9 @@ fn parse_def_op_region(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResul let offset = parse_term_arg(&data[3 + name.len..], ctx)?; let len = parse_term_arg(&data[3 + name.len + offset.len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::OperationRegion(OperationRegion { - region: region, + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::OperationRegion(OperationRegion { + region, offset: Box::new(offset.val), len: Box::new(len.val), accessor: Accessor { @@ -559,7 +559,7 @@ fn parse_def_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { } }; - let selector = FieldSelector::Region(name.val.get_as_string()?); + let selector = FieldSelector::Region(name.val.get_as_string(ctx.acpi_context())?); parse_field_list(&data[3 + pkg_length_len + name.len .. 2 + pkg_length], ctx, selector, &mut flags)?; @@ -609,8 +609,8 @@ fn parse_def_index_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseRes }; let selector = FieldSelector::Index { - index_selector: idx_name.val.get_as_string()?, - data_selector: data_name.val.get_as_string()? + index_selector: idx_name.val.get_as_string(ctx.acpi_context())?, + data_selector: data_name.val.get_as_string(ctx.acpi_context())? }; parse_field_list(&data[3 + pkg_length_len + idx_name.len + data_name.len .. 2 + pkg_length], @@ -673,9 +673,9 @@ fn parse_field_element(data: &[u8], } let length = if let Ok(field) = parse_named_field(data, ctx) { - let local_scope_string = get_namespace_string(ctx.scope.clone(), AmlValue::String(field.val.name.clone()))?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), AmlValue::String(field.val.name.clone()))?; - ctx.add_to_namespace(local_scope_string, AmlValue::FieldUnit(FieldUnit { + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::FieldUnit(FieldUnit { selector: selector.clone(), connection: Box::new(connection.clone()), flags: flags.clone(), @@ -813,7 +813,7 @@ fn parse_connect_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResul } else { let name = parse_name_string(&data[1..], ctx)?; Ok(AmlParseType { - val: AmlValue::Alias(name.val.get_as_string()?), + val: AmlValue::Alias(name.val.get_as_string(ctx.acpi_context())?), len: name.len + 1 }) } @@ -844,8 +844,8 @@ fn parse_def_method(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { let term_list = &data[2 + pkg_len_len + name.len .. 1 + pkg_len]; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::Method(Method { + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Method(Method { arg_count, serialized, sync_level, @@ -877,8 +877,8 @@ fn parse_def_mutex(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { let flags = data[2 + name.len]; let sync_level = flags & 0x0F; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::Mutex((sync_level, None)))?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Mutex((sync_level, None)))?; Ok(AmlParseType { val: AmlValue::None, @@ -905,16 +905,16 @@ fn parse_def_power_res(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResul let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; let name = parse_name_string(&data[2 + pkg_len_len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; let system_level = data[2 + pkg_len_len + name.len]; let resource_order: u16 = (data[3 + pkg_len_len + name.len] as u16) + ((data[4 + pkg_len_len + name.len] as u16) << 8); - let mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); + let mut local_ctx = AmlExecutionContext::new(ctx.acpi_context(), local_scope_string.clone()); parse_object_list(&data[5 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; - ctx.add_to_namespace(local_scope_string, AmlValue::PowerResource(PowerResource { + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::PowerResource(PowerResource { system_level, resource_order, obj_list: local_ctx.namespace_delta.clone() @@ -944,7 +944,7 @@ fn parse_def_processor(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResul let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; let name = parse_name_string(&data[2 + pkg_len_len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; let proc_id = data[2 + pkg_len_len + name.len]; let p_blk_addr: u32 = (data[3 + pkg_len_len + name.len] as u32) + @@ -953,11 +953,11 @@ fn parse_def_processor(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResul ((data[6 + pkg_len_len + name.len] as u32) << 24); let p_blk_len = data[7 + pkg_len_len + name.len]; - let mut local_ctx = AmlExecutionContext::new(local_scope_string.clone()); + let mut local_ctx = AmlExecutionContext::new(ctx.acpi_context(), local_scope_string.clone()); parse_object_list(&data[8 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; - ctx.add_to_namespace(local_scope_string, AmlValue::Processor(Processor { - proc_id: proc_id, + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Processor(Processor { + proc_id, p_blk: if p_blk_len > 0 { Some(p_blk_addr) } else { None }, obj_list: local_ctx.namespace_delta.clone(), notify_methods: BTreeMap::new() @@ -987,12 +987,12 @@ fn parse_def_thermal_zone(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseRe let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; let name = parse_name_string(&data[2 + pkg_len_len .. 2 + pkg_len], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; let mut local_ctx = AmlExecutionContext::new(ctx.acpi_context(), local_scope_string.clone()); parse_object_list(&data[2 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; - ctx.add_to_namespace(local_scope_string, AmlValue::ThermalZone(ThermalZone { + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::ThermalZone(ThermalZone { obj_list: local_ctx.namespace_delta.clone(), notify_methods: BTreeMap::new() }))?; @@ -1022,7 +1022,7 @@ fn parse_def_external(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult let object_type = data[1 + object_name.len]; let argument_count = data[2 + object_name.len]; - let local_scope_string = get_namespace_string(ctx.scope.clone(), object_name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), object_name.val)?; let obj = match object_type { 8 => AmlValue::Method(Method { @@ -1034,7 +1034,7 @@ fn parse_def_external(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult _ => AmlValue::Uninitialized }; - ctx.add_to_namespace(local_scope_string, obj)?; + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, obj)?; Ok(AmlParseType { val: AmlValue::None, diff --git a/acpid/src/aml/namespace.rs b/acpid/src/aml/namespace.rs index 9b3e12b2ba..94938dcce9 100644 --- a/acpid/src/aml/namespace.rs +++ b/acpid/src/aml/namespace.rs @@ -157,7 +157,7 @@ impl AmlValue { } } - pub fn get_as_type(&self, t: AmlValue) -> Result { + pub fn get_as_type(&self, ctx: &AcpiContext, t: AmlValue) -> Result { match t { AmlValue::None => Ok(AmlValue::None), AmlValue::Uninitialized => Ok(self.clone()), @@ -165,9 +165,9 @@ impl AmlValue { AmlValue::Alias(_) => Ok(self.clone()), _ => Err(AmlError::AmlValueError) }, - AmlValue::Buffer(_) => Ok(AmlValue::Buffer(self.get_as_buffer()?)), - AmlValue::BufferField(_) => Ok(AmlValue::BufferField(self.get_as_buffer_field()?)), - AmlValue::DDBHandle(_) => Ok(AmlValue::DDBHandle(self.get_as_ddb_handle()?)), + AmlValue::Buffer(_) => Ok(AmlValue::Buffer(self.get_as_buffer(ctx)?)), + AmlValue::BufferField(_) => Ok(AmlValue::BufferField(self.get_as_buffer_field(ctx)?)), + AmlValue::DDBHandle(_) => Ok(AmlValue::DDBHandle(self.get_as_ddb_handle(ctx)?)), AmlValue::DebugObject => match *self { AmlValue::DebugObject => Ok(self.clone()), _ => Err(AmlError::AmlValueError) @@ -175,7 +175,7 @@ impl AmlValue { AmlValue::Device(_) => Ok(AmlValue::Device(self.get_as_device()?)), AmlValue::Event(_) => Ok(AmlValue::Event(self.get_as_event()?)), AmlValue::FieldUnit(_) => Ok(AmlValue::FieldUnit(self.get_as_field_unit()?)), - AmlValue::Integer(_) => Ok(AmlValue::Integer(self.get_as_integer()?)), + AmlValue::Integer(_) => Ok(AmlValue::Integer(self.get_as_integer(ctx)?)), AmlValue::IntegerConstant(_) => Ok(AmlValue::IntegerConstant(self.get_as_integer_constant()?)), AmlValue::Method(_) => Ok(AmlValue::Method(self.get_as_method()?)), AmlValue::Mutex(_) => Ok(AmlValue::Mutex(self.get_as_mutex()?)), @@ -185,7 +185,7 @@ impl AmlValue { _ => Err(AmlError::AmlValueError) }, AmlValue::Package(_) => Ok(AmlValue::Package(self.get_as_package()?)), - AmlValue::String(_) => Ok(AmlValue::String(self.get_as_string()?)), + AmlValue::String(_) => Ok(AmlValue::String(self.get_as_string(ctx)?)), AmlValue::PowerResource(_) => Ok(AmlValue::PowerResource(self.get_as_power_resource()?)), AmlValue::Processor(_) => Ok(AmlValue::Processor(self.get_as_processor()?)), AmlValue::RawDataBuffer(_) => Ok(AmlValue::RawDataBuffer(self.get_as_raw_data_buffer()?)), @@ -193,7 +193,7 @@ impl AmlValue { } } - pub fn get_as_buffer(&self) -> Result, AmlError> { + pub fn get_as_buffer(&self, ctx: &AcpiContext) -> Result, AmlError> { match *self { AmlValue::Buffer(ref b) => Ok(b.clone()), AmlValue::Integer(ref i) => { @@ -215,9 +215,9 @@ impl AmlValue { Ok(s.clone().into_bytes()) }, AmlValue::BufferField(ref b) => { - let buf = b.source_buf.get_as_buffer()?; - let idx = b.index.get_as_integer()? as usize; - let len = b.length.get_as_integer()? as usize; + let buf = b.source_buf.get_as_buffer(ctx)?; + let idx = b.index.get_as_integer(ctx)? as usize; + let len = b.length.get_as_integer(ctx)? as usize; if idx + len > buf.len() { return Err(AmlError::AmlValueError); @@ -229,11 +229,11 @@ impl AmlValue { } } - pub fn get_as_buffer_field(&self) -> Result { + pub fn get_as_buffer_field(&self, acpi_ctx: &AcpiContext) -> Result { match *self { AmlValue::BufferField(ref b) => Ok(b.clone()), _ => { - let raw_buf = self.get_as_buffer()?; + let raw_buf = self.get_as_buffer(acpi_ctx)?; let buf = Box::new(AmlValue::Buffer(raw_buf.clone())); let idx = Box::new(AmlValue::IntegerConstant(0)); let len = Box::new(AmlValue::Integer(raw_buf.len() as u64)); @@ -300,7 +300,7 @@ impl AmlValue { Ok(i) }, AmlValue::BufferField(_) => { - let mut b = self.get_as_buffer()?; + let mut b = self.get_as_buffer(acpi_ctx)?; if b.len() > 8 { return Err(AmlError::AmlValueError); } @@ -382,14 +382,14 @@ impl AmlValue { } } - pub fn get_as_string(&self) -> Result { + pub fn get_as_string(&self, ctx: &AcpiContext) -> Result { match *self { AmlValue::String(ref s) => Ok(s.clone()), AmlValue::Integer(ref i) => Ok(format!("{:X}", i)), AmlValue::IntegerConstant(ref i) => Ok(format!("{:X}", i)), AmlValue::Buffer(ref b) => Ok(String::from_utf8(b.clone()).expect("Invalid UTF-8")), AmlValue::BufferField(_) => { - let b = self.get_as_buffer()?; + let b = self.get_as_buffer(ctx)?; Ok(String::from_utf8(b).expect("Invalid UTF-8")) }, _ => Err(AmlError::AmlValueError) @@ -426,12 +426,12 @@ impl AmlValue { } impl Method { - pub fn execute(&self, scope: String, parameters: Vec) -> AmlValue { - let mut ctx = AmlExecutionContext::new(scope); + pub fn execute(&self, acpi_ctx: &AcpiContext, scope: String, parameters: Vec) -> AmlValue { + let mut ctx = AmlExecutionContext::new(acpi_ctx, scope); ctx.init_arg_vars(parameters); let _ = parse_term_list(&self.term_list[..], &mut ctx); - ctx.clean_namespace(); + ctx.clean_namespace(acpi_ctx); match ctx.state { ExecutionState::RETURN(v) => v, @@ -440,8 +440,8 @@ impl Method { } } -pub fn get_namespace_string(current: String, modifier_v: AmlValue) -> Result { - let mut modifier = modifier_v.get_as_string()?; +pub fn get_namespace_string(ctx: &AcpiContext, current: String, modifier_v: AmlValue) -> Result { + let mut modifier = modifier_v.get_as_string(ctx)?; if current.len() == 0 { return Ok(modifier); diff --git a/acpid/src/aml/namespacemodifier.rs b/acpid/src/aml/namespacemodifier.rs index 77fa1406b0..3c3a31465c 100644 --- a/acpid/src/aml/namespacemodifier.rs +++ b/acpid/src/aml/namespacemodifier.rs @@ -41,10 +41,10 @@ fn parse_alias_op(data: &[u8], let source_name = parse_name_string(&data[1..], ctx)?; let alias_name = parse_name_string(&data[1 + source_name.len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), source_name.val)?; - let local_alias_string = get_namespace_string(ctx.scope.clone(), alias_name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), source_name.val)?; + let local_alias_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), alias_name.val)?; - ctx.add_to_namespace(local_scope_string, AmlValue::Alias(local_alias_string))?; + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Alias(local_alias_string))?; Ok(AmlParseType { val: AmlValue::None, @@ -67,9 +67,9 @@ fn parse_name_op(data: &[u8], let name = parse_name_string(&data[1..], ctx)?; let data_ref_obj = parse_data_ref_obj(&data[1 + name.len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val)?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(local_scope_string, data_ref_obj.val)?; + ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, data_ref_obj.val)?; Ok(AmlParseType { val: AmlValue::None, @@ -92,7 +92,7 @@ fn parse_scope_op(data: &[u8], let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; let name = parse_name_string(&data[1 + pkg_length_len..], ctx)?; - let local_scope_string = get_namespace_string(ctx.scope.clone(), name.val.clone())?; + let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val.clone())?; let containing_scope_string = ctx.scope.clone(); ctx.scope = local_scope_string; diff --git a/acpid/src/aml/parser.rs b/acpid/src/aml/parser.rs index aff1aaa158..be0a349f2e 100644 --- a/acpid/src/aml/parser.rs +++ b/acpid/src/aml/parser.rs @@ -1,7 +1,4 @@ -use std::string::String; -use std::collections::BTreeMap; -use std::vec::Vec; -use std::boxed::Box; +use std::collections::HashMap; use parking_lot::RwLockWriteGuard; @@ -39,13 +36,13 @@ pub struct AmlExecutionContext<'a> { impl<'a> AmlExecutionContext<'a> { pub fn new(acpi_context: &'a AcpiContext, scope: String) -> AmlExecutionContext<'_> { - let mut idptr = ACPI_TABLE.next_ctx.write(); + let mut idptr = acpi_context.next_ctx.write(); let id: u64 = *idptr; *idptr += 1; AmlExecutionContext { - scope: scope, + scope, local_vars: [AmlValue::Uninitialized, AmlValue::Uninitialized, AmlValue::Uninitialized, @@ -74,8 +71,8 @@ impl<'a> AmlExecutionContext<'a> { self.acpi_context } - pub fn wait_for_event(&mut self, event_ptr: AmlValue) -> Result { - let mut namespace_ptr = self.prelock(); + pub fn wait_for_event(&mut self, ctx: &AcpiContext, event_ptr: AmlValue) -> Result { + let mut namespace_ptr = self.prelock(ctx); let namespace = match *namespace_ptr { Some(ref mut n) => n, None => return Err(AmlError::AmlHardFatal) @@ -108,8 +105,8 @@ impl<'a> AmlExecutionContext<'a> { Ok(false) } - pub fn signal_event(&mut self, event_ptr: AmlValue) -> Result<(), AmlError> { - let mut namespace_ptr = self.prelock(); + pub fn signal_event(&mut self, ctx: &AcpiContext, event_ptr: AmlValue) -> Result<(), AmlError> { + let mut namespace_ptr = self.prelock(ctx); let namespace = match *namespace_ptr { Some(ref mut n) => n, None => return Err(AmlError::AmlHardFatal) @@ -140,10 +137,10 @@ impl<'a> AmlExecutionContext<'a> { Ok(()) } - pub fn release_mutex(&mut self, mutex_ptr: AmlValue) -> Result<(), AmlError> { + pub fn release_mutex(&mut self, ctx: &AcpiContext, mutex_ptr: AmlValue) -> Result<(), AmlError> { let id = self.ctx_id; - let mut namespace_ptr = self.prelock(); + let mut namespace_ptr = self.prelock(ctx); let namespace = match *namespace_ptr { Some(ref mut n) => n, None => return Err(AmlError::AmlHardFatal) @@ -197,10 +194,10 @@ impl<'a> AmlExecutionContext<'a> { Ok(()) } - pub fn acquire_mutex(&mut self, mutex_ptr: AmlValue) -> Result { + pub fn acquire_mutex(&mut self, ctx: &AcpiContext, mutex_ptr: AmlValue) -> Result { let id = self.ctx_id; - let mut namespace_ptr = self.prelock(); + let mut namespace_ptr = self.prelock(ctx); let namespace = match *namespace_ptr { Some(ref mut n) => n, None => return Err(AmlError::AmlHardFatal) @@ -247,8 +244,8 @@ impl<'a> AmlExecutionContext<'a> { Ok(false) } - pub fn add_to_namespace(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { - let mut namespace = ACPI_TABLE.namespace.write(); + pub fn add_to_namespace(&mut self, ctx: &AcpiContext, name: String, value: AmlValue) -> Result<(), AmlError> { + let mut namespace = ctx.namespace_mut(); if let Some(ref mut namespace) = *namespace { if let Some(obj) = namespace.get(&name) { @@ -272,8 +269,8 @@ impl<'a> AmlExecutionContext<'a> { } } - pub fn clean_namespace(&mut self) { - let mut namespace = ACPI_TABLE.namespace.write(); + pub fn clean_namespace(&mut self, ctx: &AcpiContext) { + let mut namespace = ctx.namespace_mut(); if let Some(ref mut namespace) = *namespace { for k in &self.namespace_delta { @@ -294,17 +291,17 @@ impl<'a> AmlExecutionContext<'a> { } } - pub fn prelock(&mut self) -> RwLockWriteGuard<'static, Option>> { - ACPI_TABLE.namespace.write() + pub fn prelock<'ctx>(&mut self, ctx: &'ctx AcpiContext) -> RwLockWriteGuard<'ctx, Option>> { + ctx.namespace_mut() } - fn modify_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> { - self.local_vars[local] = value.get_as_type(self.local_vars[local].clone())?; + fn modify_local_obj(&mut self, ctx: &AcpiContext, local: usize, value: AmlValue) -> Result<(), AmlError> { + self.local_vars[local] = value.get_as_type(ctx, self.local_vars[local].clone())?; Ok(()) } - fn modify_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { - if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { + fn modify_object(&mut self, ctx: &AcpiContext, name: String, value: AmlValue) -> Result<(), AmlError> { + if let Some(ref mut namespace) = *ctx.namespace_mut() { let coercion_obj = { let obj = namespace.get(&name); @@ -315,22 +312,22 @@ impl<'a> AmlExecutionContext<'a> { } }; - namespace.insert(name, value.get_as_type(coercion_obj)?); + namespace.insert(name, value.get_as_type(ctx, coercion_obj)?); Ok(()) } else { Err(AmlError::AmlHardFatal) } } - fn modify_index_final(&mut self, name: String, value: AmlValue, indices: Vec) -> Result<(), AmlError> { - if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { + fn modify_index_final(&mut self, ctx: &AcpiContext, name: String, value: AmlValue, indices: Vec) -> Result<(), AmlError> { + if let Some(ref mut namespace) = *ctx.namespace_mut() { let mut obj = if let Some(s) = namespace.get(&name) { s.clone() } else { return Err(AmlError::AmlValueError); }; - obj = self.modify_index_core(obj, value, indices)?; + obj = self.modify_index_core(ctx, obj, value, indices)?; namespace.insert(name, obj); Ok(()) @@ -339,7 +336,7 @@ impl<'a> AmlExecutionContext<'a> { } } - fn modify_index_core(&mut self, obj: AmlValue, value: AmlValue, indices: Vec) -> Result { + fn modify_index_core(&mut self, ctx: &AcpiContext, obj: AmlValue, value: AmlValue, indices: Vec) -> Result { match obj { AmlValue::String(ref string) => { if indices.len() != 1 { @@ -347,7 +344,7 @@ impl<'a> AmlExecutionContext<'a> { } let mut bytes = string.clone().into_bytes(); - bytes[indices[0] as usize] = value.get_as_integer()? as u8; + bytes[indices[0] as usize] = value.get_as_integer(ctx)? as u8; let string = String::from_utf8(bytes).unwrap(); @@ -359,7 +356,7 @@ impl<'a> AmlExecutionContext<'a> { } let mut b = b.clone(); - b[indices[0] as usize] = value.get_as_integer()? as u8; + b[indices[0] as usize] = value.get_as_integer(ctx)? as u8; Ok(AmlValue::Buffer(b)) }, @@ -369,9 +366,9 @@ impl<'a> AmlExecutionContext<'a> { } let mut idx = indices[0]; - idx += b.index.get_as_integer()?; + idx += b.index.get_as_integer(ctx)?; - let _ = self.modify(AmlValue::ObjectReference(ObjectReference::Index(b.source_buf.clone(), Box::new(AmlValue::Integer(idx.clone())))), value); + let _ = self.modify(ctx, AmlValue::ObjectReference(ObjectReference::Index(b.source_buf.clone(), Box::new(AmlValue::Integer(idx.clone())))), value); Ok(AmlValue::BufferField(b.clone())) }, @@ -385,7 +382,7 @@ impl<'a> AmlExecutionContext<'a> { if indices.len() == 1 { p[indices[0] as usize] = value; } else { - p[indices[0] as usize] = self.modify_index_core(p[indices[0] as usize].clone(), value, indices[1..].to_vec())?; + p[indices[0] as usize] = self.modify_index_core(ctx, p[indices[0] as usize].clone(), value, indices[1..].to_vec())?; } Ok(AmlValue::Package(p)) @@ -394,20 +391,20 @@ impl<'a> AmlExecutionContext<'a> { } } - pub fn modify_index(&mut self, name: AmlValue, value: AmlValue, indices: Vec) -> Result<(), AmlError>{ + pub fn modify_index(&mut self, ctx: &AcpiContext, name: AmlValue, value: AmlValue, indices: Vec) -> Result<(), AmlError>{ match name { AmlValue::ObjectReference(r) => match r { - ObjectReference::Object(s) => self.modify_index_final(s, value, indices), + ObjectReference::Object(s) => self.modify_index_final(ctx, s, value, indices), ObjectReference::Index(c, v) => { let mut indices = indices.clone(); - indices.push(v.get_as_integer()?); + indices.push(v.get_as_integer(ctx)?); - self.modify_index(*c, value, indices) + self.modify_index(ctx, *c, value, indices) }, ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), ObjectReference::LocalObj(i) => { let v = self.local_vars[i as usize].clone(); - self.local_vars[i as usize] = self.modify_index_core(v, value, indices)?; + self.local_vars[i as usize] = self.modify_index_core(ctx, v, value, indices)?; Ok(()) } @@ -416,15 +413,15 @@ impl<'a> AmlExecutionContext<'a> { } } - pub fn modify(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { + pub fn modify(&mut self, ctx: &AcpiContext, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { match name { AmlValue::ObjectReference(r) => match r { ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), - ObjectReference::LocalObj(i) => self.modify_local_obj(i as usize, value), - ObjectReference::Object(s) => self.modify_object(s, value), - ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?)) + ObjectReference::LocalObj(i) => self.modify_local_obj(ctx, i as usize, value), + ObjectReference::Object(s) => self.modify_object(ctx, s, value), + ObjectReference::Index(c, v) => self.modify_index(ctx, *c, value, vec!(v.get_as_integer(ctx)?)) }, - AmlValue::String(s) => self.modify_object(s, value), + AmlValue::String(s) => self.modify_object(ctx, s, value), _ => Err(AmlError::AmlValueError) } } @@ -434,8 +431,8 @@ impl<'a> AmlExecutionContext<'a> { Ok(()) } - fn copy_object(&mut self, name: String, value: AmlValue) -> Result<(), AmlError> { - if let Some(ref mut namespace) = *ACPI_TABLE.namespace.write() { + fn copy_object(&mut self, ctx: &AcpiContext, name: String, value: AmlValue) -> Result<(), AmlError> { + if let Some(ref mut namespace) = *ctx.namespace_mut() { namespace.insert(name, value); Ok(()) } else { @@ -443,34 +440,34 @@ impl<'a> AmlExecutionContext<'a> { } } - pub fn copy(&mut self, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { + pub fn copy(&mut self, ctx: &AcpiContext, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { match name { AmlValue::ObjectReference(r) => match r { ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), ObjectReference::LocalObj(i) => self.copy_local_obj(i as usize, value), - ObjectReference::Object(s) => self.copy_object(s, value), - ObjectReference::Index(c, v) => self.modify_index(*c, value, vec!(v.get_as_integer()?)) + ObjectReference::Object(s) => self.copy_object(ctx, s, value), + ObjectReference::Index(c, v) => self.modify_index(ctx, *c, value, vec!(v.get_as_integer(ctx)?)) }, - AmlValue::String(s) => self.copy_object(s, value), + AmlValue::String(s) => self.copy_object(ctx, s, value), _ => Err(AmlError::AmlValueError) } } - fn get_index_final(&self, name: String, indices: Vec) -> Result { - if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { + fn get_index_final(&self, ctx: &AcpiContext, name: String, indices: Vec) -> Result { + if let Some(ref namespace) = *ctx.namespace() { let obj = if let Some(s) = namespace.get(&name) { s.clone() } else { return Err(AmlError::AmlValueError); }; - self.get_index_core(obj, indices) + self.get_index_core(ctx, obj, indices) } else { Err(AmlError::AmlValueError) } } - fn get_index_core(&self, obj: AmlValue, indices: Vec) -> Result { + fn get_index_core(&self, ctx: &AcpiContext, obj: AmlValue, indices: Vec) -> Result { match obj { AmlValue::String(ref string) => { if indices.len() != 1 { @@ -493,9 +490,9 @@ impl<'a> AmlExecutionContext<'a> { } let mut idx = indices[0]; - idx += b.index.get_as_integer()?; + idx += b.index.get_as_integer(ctx)?; - Ok(AmlValue::Integer(b.source_buf.get_as_buffer()?[idx as usize] as u64)) + Ok(AmlValue::Integer(b.source_buf.get_as_buffer(ctx, )?[idx as usize] as u64)) }, AmlValue::Package(ref p) => { if indices.len() == 0 { @@ -505,48 +502,48 @@ impl<'a> AmlExecutionContext<'a> { if indices.len() == 1 { Ok(p[indices[0] as usize].clone()) } else { - self.get_index_core(p[indices[0] as usize].clone(), indices[1..].to_vec()) + self.get_index_core(ctx, p[indices[0] as usize].clone(), indices[1..].to_vec()) } }, _ => Err(AmlError::AmlValueError) } } - pub fn get_index(&self, name: AmlValue, indices: Vec) -> Result{ + pub fn get_index(&self, ctx: &AcpiContext, name: AmlValue, indices: Vec) -> Result{ match name { AmlValue::ObjectReference(r) => match r { - ObjectReference::Object(s) => self.get_index_final(s, indices), + ObjectReference::Object(s) => self.get_index_final(ctx, s, indices), ObjectReference::Index(c, v) => { let mut indices = indices.clone(); - indices.push(v.get_as_integer()?); + indices.push(v.get_as_integer(ctx)?); - self.get_index(*c, indices) + self.get_index(ctx, *c, indices) }, ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), ObjectReference::LocalObj(i) => { let v = self.local_vars[i as usize].clone(); - self.get_index_core(v, indices) + self.get_index_core(ctx, v, indices) } }, _ => Err(AmlError::AmlValueError) } } - pub fn get(&self, name: AmlValue) -> Result { + pub fn get(&self, ctx: &AcpiContext, name: AmlValue) -> Result { Ok(match name { AmlValue::ObjectReference(r) => match r { ObjectReference::ArgObj(i) => self.arg_vars[i as usize].clone(), ObjectReference::LocalObj(i) => self.local_vars[i as usize].clone(), - ObjectReference::Object(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { + ObjectReference::Object(ref s) => if let Some(ref namespace) = *ctx.namespace() { if let Some(o) = namespace.get(s) { o.clone() } else { AmlValue::None } } else { AmlValue::None }, - ObjectReference::Index(c, v) => self.get_index(*c, vec!(v.get_as_integer()?))?, + ObjectReference::Index(c, v) => self.get_index(ctx, *c, vec!(v.get_as_integer(ctx)?))?, }, - AmlValue::String(ref s) => if let Some(ref namespace) = *ACPI_TABLE.namespace.read() { + AmlValue::String(ref s) => if let Some(ref namespace) = *ctx.namespace() { if let Some(o) = namespace.get(s) { o.clone() } else { diff --git a/acpid/src/aml/termlist.rs b/acpid/src/aml/termlist.rs index c382a7c5c0..036036f1eb 100644 --- a/acpid/src/aml/termlist.rs +++ b/acpid/src/aml/termlist.rs @@ -123,7 +123,7 @@ pub fn parse_method_invocation(data: &[u8], } let name = parse_name_string(data, ctx)?; - let method = ctx.get(name.val.clone())?; + let method = ctx.get(ctx.acpi_context(), name.val.clone())?; let method = match method { AmlValue::None => return Err(AmlError::AmlDeferredLoad), @@ -145,7 +145,7 @@ pub fn parse_method_invocation(data: &[u8], } Ok(AmlParseType { - val: method.execute(get_namespace_string(ctx.scope.clone(), name.val)?, params), + val: method.execute(ctx.acpi_context(), get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?, params), len: current_offset }) } diff --git a/acpid/src/aml/type1opcode.rs b/acpid/src/aml/type1opcode.rs index fe5b8256ba..cd61a78d71 100644 --- a/acpid/src/aml/type1opcode.rs +++ b/acpid/src/aml/type1opcode.rs @@ -153,7 +153,7 @@ fn parse_def_load(data: &[u8], let name = parse_name_string(&data[2..], ctx)?; let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?; - let tbl = ctx.get(name.val)?.get_as_buffer()?; + let tbl = ctx.get(ctx.acpi_context(), name.val)?.get_as_buffer(ctx.acpi_context())?; // TODO let sdt = plain::from_bytes::(&tbl[..mem::size_of::()]).unwrap(); @@ -163,8 +163,8 @@ fn parse_def_load(data: &[u8], }; if let Some(aml_sdt) = PossibleAmlTables::try_new(table.clone()) { - let delta = parse_aml_table(aml_sdt)?; - let _ = ctx.modify(ddb_handle_object.val, AmlValue::DDBHandle((delta, sdt.signature()))); + let delta = parse_aml_table(ctx.acpi_context(), aml_sdt)?; + let _ = ctx.modify(ctx.acpi_context(), ddb_handle_object.val, AmlValue::DDBHandle((delta, sdt.signature()))); Ok(AmlParseType { val: AmlValue::None, @@ -190,9 +190,9 @@ fn parse_def_notify(data: &[u8], let object = parse_super_name(&data[1..], ctx)?; let value = parse_term_arg(&data[1 + object.len..], ctx)?; - let number = value.val.get_as_integer()? as u8; + let number = value.val.get_as_integer(ctx.acpi_context())? as u8; - match ctx.get(object.val)? { + match ctx.get(ctx.acpi_context(), object.val)? { AmlValue::Device(d) => { if let Some(methods) = d.notify_methods.get(&number) { for method in methods { @@ -236,7 +236,7 @@ fn parse_def_release(data: &[u8], parser_opcode_extended!(data, 0x27); let obj = parse_super_name(&data[2..], ctx)?; - let _ = ctx.release_mutex(obj.val); + let _ = ctx.release_mutex(ctx.acpi_context(), obj.val); Ok(AmlParseType { val: AmlValue::None, @@ -257,9 +257,9 @@ fn parse_def_reset(data: &[u8], parser_opcode_extended!(data, 0x26); let object = parse_super_name(&data[2..], ctx)?; - ctx.get(object.val.clone())?.get_as_event()?; + ctx.get(ctx.acpi_context(), object.val.clone())?.get_as_event()?; - let _ = ctx.modify(object.val.clone(), AmlValue::Event(0)); + let _ = ctx.modify(ctx.acpi_context(), object.val.clone(), AmlValue::Event(0)); Ok(AmlParseType { val: AmlValue::None, @@ -280,7 +280,7 @@ fn parse_def_signal(data: &[u8], parser_opcode_extended!(data, 0x24); let object = parse_super_name(&data[2..], ctx)?; - ctx.signal_event(object.val)?; + ctx.signal_event(ctx.acpi_context(), object.val)?; Ok(AmlParseType { val: AmlValue::None, len: 2 + object.len @@ -300,7 +300,7 @@ fn parse_def_sleep(data: &[u8], parser_opcode_extended!(data, 0x22); let time = parse_term_arg(&data[2..], ctx)?; - let timeout = time.val.get_as_integer()?; + let timeout = time.val.get_as_integer(ctx.acpi_context())?; let (seconds, nanoseconds) = monotonic(); let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); @@ -333,7 +333,7 @@ fn parse_def_stall(data: &[u8], parser_opcode_extended!(data, 0x21); let time = parse_term_arg(&data[2..], ctx)?; - let timeout = time.val.get_as_integer()?; + let timeout = time.val.get_as_integer(ctx.acpi_context())?; let (seconds, nanoseconds) = monotonic(); let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); @@ -367,8 +367,8 @@ fn parse_def_unload(data: &[u8], let object = parse_super_name(&data[2..], ctx)?; - let delta = ctx.get(object.val)?.get_as_ddb_handle()?; - let mut namespace = ctx.prelock(); + let delta = ctx.get(ctx.acpi_context(), object.val)?.get_as_ddb_handle(ctx.acpi_context())?; + let mut namespace = ctx.prelock(ctx.acpi_context()); if let Some(ref mut ns) = *namespace { for o in delta.0 { @@ -403,7 +403,7 @@ fn parse_def_if_else(data: &[u8], (0 as usize, 0 as usize) }; - if if_condition.val.get_as_integer()? > 0 { + if if_condition.val.get_as_integer(ctx.acpi_context())? > 0 { parse_term_list(&data[1 + pkg_length_len + if_condition.len .. 1 + pkg_length], ctx)?; } else if else_length > 0 { parse_term_list(&data[2 + pkg_length + else_length_len .. 2 + pkg_length + else_length], ctx)?; @@ -431,7 +431,7 @@ fn parse_def_while(data: &[u8], loop { let predicate = parse_term_arg(&data[1 + pkg_length_len..], ctx)?; - if predicate.val.get_as_integer()? == 0 { + if predicate.val.get_as_integer(ctx.acpi_context())? == 0 { break; } diff --git a/acpid/src/aml/type2opcode.rs b/acpid/src/aml/type2opcode.rs index 846d44a658..ec137cdeb3 100644 --- a/acpid/src/aml/type2opcode.rs +++ b/acpid/src/aml/type2opcode.rs @@ -180,7 +180,7 @@ pub fn parse_def_var_package(data: &[u8], let mut elements = parse_package_elements_list(&data[1 + pkg_length_len + num_elements.len .. 1 + pkg_length], ctx)?.val.get_as_package()?; - let numelements = num_elements.val.get_as_integer()? as usize; + let numelements = num_elements.val.get_as_integer(ctx.acpi_context())? as usize; if elements.len() > numelements { elements = elements[0 .. numelements].to_vec(); @@ -215,7 +215,7 @@ fn parse_package_elements_list(data: &[u8], } else { let d = parse_name_string(&data[current_offset..], ctx)?; AmlParseType { - val: AmlValue::ObjectReference(ObjectReference::Object(d.val.get_as_string()?)), + val: AmlValue::ObjectReference(ObjectReference::Object(d.val.get_as_string(ctx.acpi_context())?)), len: d.len } }; @@ -246,7 +246,7 @@ pub fn parse_def_buffer(data: &[u8], let buffer_size = parse_term_arg(&data[1 + pkg_length_len..], ctx)?; let mut byte_list = data[1 + pkg_length_len + buffer_size.len .. 1 + pkg_length].to_vec().clone(); - byte_list.truncate(buffer_size.val.get_as_integer()? as usize); + byte_list.truncate(buffer_size.val.get_as_integer(ctx.acpi_context())? as usize); Ok(AmlParseType { val: AmlValue::Buffer(byte_list), @@ -269,7 +269,7 @@ fn parse_def_ref_of(data: &[u8], let obj = parse_super_name(&data[1..], ctx)?; let res = match obj.val { AmlValue::String(ref s) => { - match ctx.get(AmlValue::String(s.clone()))? { + match ctx.get(ctx.acpi_context(), AmlValue::String(s.clone()))? { AmlValue::None => return Err(AmlError::AmlValueError), _ => ObjectReference::Object(s.clone()) } @@ -297,7 +297,7 @@ fn parse_def_deref_of(data: &[u8], parser_opcode!(data, 0x83); let obj = parse_term_arg(&data[1..], ctx)?; - let res = ctx.get(obj.val)?; + let res = ctx.get(ctx.acpi_context(), obj.val)?; match res { AmlValue::None => Err(AmlError::AmlValueError), @@ -327,7 +327,7 @@ fn parse_def_acquire(data: &[u8], let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); loop { - match ctx.acquire_mutex(obj.val.clone()) { + match ctx.acquire_mutex(ctx.acpi_context(), obj.val.clone()) { Err(e) => return Err(e), Ok(b) => if b { return Ok(AmlParseType { @@ -366,9 +366,9 @@ fn parse_def_increment(data: &[u8], let obj = parse_super_name(&data[1..], ctx)?; - let _namespace = ctx.prelock(); - let value = AmlValue::Integer(ctx.get(obj.val.clone())?.get_as_integer()? + 1); - let _ = ctx.modify(obj.val, value.clone()); + let _namespace = ctx.prelock(ctx.acpi_context()); + let value = AmlValue::Integer(ctx.get(ctx.acpi_context(), obj.val.clone())?.get_as_integer(ctx.acpi_context())? + 1); + let _ = ctx.modify(ctx.acpi_context(), obj.val, value.clone()); Ok(AmlParseType { val: value, @@ -393,7 +393,7 @@ fn parse_def_index(data: &[u8], let target = parse_target(&data[1 + obj.len + idx.len..], ctx)?; let reference = AmlValue::ObjectReference(ObjectReference::Index(Box::new(obj.val), Box::new(idx.val))); - let _ = ctx.modify(target.val, reference.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, reference.clone()); Ok(AmlParseType { val: reference, @@ -416,7 +416,7 @@ fn parse_def_land(data: &[u8], let lhs = parse_term_arg(&data[1..], ctx)?; let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let result = if lhs.val.get_as_integer()? > 0 && rhs.val.get_as_integer()? > 0 { 1 } else { 0 }; + let result = if lhs.val.get_as_integer(ctx.acpi_context())? > 0 && rhs.val.get_as_integer(ctx.acpi_context())? > 0 { 1 } else { 0 }; Ok(AmlParseType { val: AmlValue::IntegerConstant(result), @@ -439,7 +439,7 @@ fn parse_def_lequal(data: &[u8], let lhs = parse_term_arg(&data[1..], ctx)?; let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let result = if lhs.val.get_as_integer()? == rhs.val.get_as_integer()? { 1 } else { 0 }; + let result = if lhs.val.get_as_integer(ctx.acpi_context())? == rhs.val.get_as_integer(ctx.acpi_context())? { 1 } else { 0 }; Ok(AmlParseType { val: AmlValue::IntegerConstant(result), @@ -462,7 +462,7 @@ fn parse_def_lgreater(data: &[u8], let lhs = parse_term_arg(&data[1..], ctx)?; let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let result = if lhs.val.get_as_integer()? > rhs.val.get_as_integer()? { 1 } else { 0 }; + let result = if lhs.val.get_as_integer(ctx.acpi_context())? > rhs.val.get_as_integer(ctx.acpi_context())? { 1 } else { 0 }; Ok(AmlParseType { val: AmlValue::IntegerConstant(result), @@ -485,7 +485,7 @@ fn parse_def_lless(data: &[u8], let lhs = parse_term_arg(&data[1..], ctx)?; let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let result = if lhs.val.get_as_integer()? < rhs.val.get_as_integer()? { 1 } else { 0 }; + let result = if lhs.val.get_as_integer(ctx.acpi_context())? < rhs.val.get_as_integer(ctx.acpi_context())? { 1 } else { 0 }; Ok(AmlParseType { val: AmlValue::IntegerConstant(result), @@ -506,7 +506,7 @@ fn parse_def_lnot(data: &[u8], parser_opcode!(data, 0x92); let operand = parse_term_arg(&data[1..], ctx)?; - let result = if operand.val.get_as_integer()? == 0 { 1 } else { 0 }; + let result = if operand.val.get_as_integer(ctx.acpi_context())? == 0 { 1 } else { 0 }; Ok(AmlParseType { val: AmlValue::IntegerConstant(result), @@ -529,7 +529,7 @@ fn parse_def_lor(data: &[u8], let lhs = parse_term_arg(&data[1..], ctx)?; let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let result = if lhs.val.get_as_integer()? > 0 || rhs.val.get_as_integer()? > 0 { 1 } else { 0 }; + let result = if lhs.val.get_as_integer(ctx.acpi_context())? > 0 || rhs.val.get_as_integer(ctx.acpi_context())? > 0 { 1 } else { 0 }; Ok(AmlParseType { val: AmlValue::IntegerConstant(result), @@ -554,14 +554,14 @@ fn parse_def_to_hex_string(data: &[u8], let res = match operand.val { AmlValue::Integer(_) => { - let result: String = format!("{:X}", operand.val.get_as_integer()?); + let result: String = format!("{:X}", operand.val.get_as_integer(ctx.acpi_context())?); AmlValue::String(result) }, AmlValue::String(s) => AmlValue::String(s), AmlValue::Buffer(_) => { let mut string: String = String::new(); - for b in operand.val.get_as_buffer()? { + for b in operand.val.get_as_buffer(ctx.acpi_context())? { string.push_str(&format!("{:X}", b)); } @@ -570,7 +570,7 @@ fn parse_def_to_hex_string(data: &[u8], _ => return Err(AmlError::AmlValueError) }; - let _ = ctx.modify(target.val, res.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, res.clone()); Ok(AmlParseType { val: res, @@ -593,8 +593,8 @@ fn parse_def_to_buffer(data: &[u8], let operand = parse_term_arg(&data[2..], ctx)?; let target = parse_target(&data[2 + operand.len..], ctx)?; - let res = AmlValue::Buffer(operand.val.get_as_buffer()?); - let _ = ctx.modify(target.val, res.clone()); + let res = AmlValue::Buffer(operand.val.get_as_buffer(ctx.acpi_context())?); + let _ = ctx.modify(ctx.acpi_context(), target.val, res.clone()); Ok(AmlParseType { val: res, @@ -617,7 +617,7 @@ fn parse_def_to_bcd(data: &[u8], let operand = parse_term_arg(&data[2..], ctx)?; let target = parse_target(&data[2 + operand.len..], ctx)?; - let mut i = operand.val.get_as_integer()?; + let mut i = operand.val.get_as_integer(ctx.acpi_context())?; let mut result = 0; while i != 0 { @@ -627,7 +627,7 @@ fn parse_def_to_bcd(data: &[u8], } let result = AmlValue::Integer(result); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -651,14 +651,14 @@ fn parse_def_to_decimal_string(data: &[u8], let target = parse_target(&data[2 + operand.len..], ctx)?; let res = match operand.val { AmlValue::Integer(_) => { - let result: String = format!("{}", operand.val.get_as_integer()?); + let result: String = format!("{}", operand.val.get_as_integer(ctx.acpi_context())?); AmlValue::String(result) }, AmlValue::String(s) => AmlValue::String(s), AmlValue::Buffer(_) => { let mut string: String = String::new(); - for b in operand.val.get_as_buffer()? { + for b in operand.val.get_as_buffer(ctx.acpi_context())? { string.push_str(&format!("{}", b)); } @@ -667,7 +667,7 @@ fn parse_def_to_decimal_string(data: &[u8], _ => return Err(AmlError::AmlValueError) }; - let _ = ctx.modify(target.val, res.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, res.clone()); Ok(AmlParseType { val: res, @@ -690,9 +690,9 @@ fn parse_def_to_integer(data: &[u8], let operand = parse_term_arg(&data[2..], ctx)?; let target = parse_target(&data[2 + operand.len..], ctx)?; - let res = AmlValue::Integer(operand.val.get_as_integer()?); + let res = AmlValue::Integer(operand.val.get_as_integer(ctx.acpi_context())?); - let _ = ctx.modify(target.val, res.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, res.clone()); Ok(AmlParseType { val: res, @@ -716,16 +716,16 @@ fn parse_def_to_string(data: &[u8], let length = parse_term_arg(&data[1 + operand.len..], ctx)?; let target = parse_target(&data[1 + operand.len + length.len..], ctx)?; - let buf = operand.val.get_as_buffer()?; + let buf = operand.val.get_as_buffer(ctx.acpi_context())?; let mut string = match String::from_utf8(buf) { Ok(s) => s, Err(_) => return Err(AmlError::AmlValueError) }; - string.truncate(length.val.get_as_integer()? as usize); + string.truncate(length.val.get_as_integer(ctx.acpi_context())? as usize); let res = AmlValue::String(string); - let _ = ctx.modify(target.val, res.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, res.clone()); Ok(AmlParseType { val: res, @@ -749,9 +749,9 @@ fn parse_def_subtract(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let result = AmlValue::Integer(lhs.val.get_as_integer()? - rhs.val.get_as_integer()?); + let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? - rhs.val.get_as_integer(ctx.acpi_context())?); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -772,7 +772,7 @@ fn parse_def_size_of(data: &[u8], parser_opcode!(data, 0x87); let name = parse_super_name(&data[1..], ctx)?; - let obj = ctx.get(name.val)?; + let obj = ctx.get(ctx.acpi_context(), name.val)?; let res = match obj { AmlValue::Buffer(ref v) => v.len(), @@ -802,7 +802,7 @@ fn parse_def_store(data: &[u8], let operand = parse_term_arg(&data[1..], ctx)?; let target = parse_super_name(&data[1 + operand.len..], ctx)?; - let _ = ctx.modify(target.val.clone(), operand.val); + let _ = ctx.modify(ctx.acpi_context(), target.val.clone(), operand.val); Ok(AmlParseType { val: target.val, @@ -826,9 +826,9 @@ fn parse_def_or(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let result = AmlValue::Integer(lhs.val.get_as_integer()? | rhs.val.get_as_integer()?); + let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? | rhs.val.get_as_integer(ctx.acpi_context())?); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -852,9 +852,9 @@ fn parse_def_shift_left(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let result = AmlValue::Integer(lhs.val.get_as_integer()? >> rhs.val.get_as_integer()?); + let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? >> rhs.val.get_as_integer(ctx.acpi_context())?); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -878,9 +878,9 @@ fn parse_def_shift_right(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let result = AmlValue::Integer(lhs.val.get_as_integer()? << rhs.val.get_as_integer()?); + let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? << rhs.val.get_as_integer(ctx.acpi_context())?); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -904,9 +904,9 @@ fn parse_def_add(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let result = AmlValue::Integer(lhs.val.get_as_integer()? + rhs.val.get_as_integer()?); + let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? + rhs.val.get_as_integer(ctx.acpi_context())?); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -930,9 +930,9 @@ fn parse_def_and(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let result = AmlValue::Integer(lhs.val.get_as_integer()? & rhs.val.get_as_integer()?); + let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? & rhs.val.get_as_integer(ctx.acpi_context())?); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -956,9 +956,9 @@ fn parse_def_xor(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let result = AmlValue::Integer(lhs.val.get_as_integer()? ^ rhs.val.get_as_integer()?); + let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? ^ rhs.val.get_as_integer(ctx.acpi_context())?); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -982,8 +982,8 @@ fn parse_def_concat_res(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let mut buf1 = lhs.val.get_as_buffer()?.clone(); - let mut buf2 = rhs.val.get_as_buffer()?.clone(); + let mut buf1 = lhs.val.get_as_buffer(ctx.acpi_context())?.clone(); + let mut buf2 = rhs.val.get_as_buffer(ctx.acpi_context())?.clone(); if buf1.len() == 1 || buf2.len() == 1 { return Err(AmlError::AmlValueError); @@ -1010,7 +1010,7 @@ fn parse_def_concat_res(data: &[u8], buf1.push(checksum); let res = AmlValue::Buffer(buf1); - ctx.modify(target.val, res.clone())?; + ctx.modify(ctx.acpi_context(), target.val, res.clone())?; Ok(AmlParseType { val: res, @@ -1033,13 +1033,13 @@ fn parse_def_wait(data: &[u8], let obj = parse_super_name(&data[2..], ctx)?; let timeout_obj = parse_term_arg(&data[2 + obj.len..], ctx)?; - let timeout = timeout_obj.val.get_as_integer()?; + let timeout = timeout_obj.val.get_as_integer(ctx.acpi_context())?; let (seconds, nanoseconds) = monotonic(); let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); loop { - match ctx.wait_for_event(obj.val.clone()) { + match ctx.wait_for_event(ctx.acpi_context(), obj.val.clone()) { Err(e) => return Err(e), Ok(b) => if b { return Ok(AmlParseType { @@ -1080,7 +1080,7 @@ fn parse_def_cond_ref_of(data: &[u8], let res = match obj.val { AmlValue::String(ref s) => { - match ctx.get(AmlValue::String(s.clone()))? { + match ctx.get(ctx.acpi_context(), AmlValue::String(s.clone()))? { AmlValue::None => return Ok(AmlParseType { val: AmlValue::Integer(0), len: 1 + obj.len + target.len @@ -1092,7 +1092,7 @@ fn parse_def_cond_ref_of(data: &[u8], _ => return Err(AmlError::AmlValueError) }; - let _ = ctx.modify(target.val, AmlValue::ObjectReference(res)); + let _ = ctx.modify(ctx.acpi_context(), target.val, AmlValue::ObjectReference(res)); Ok(AmlParseType { val: AmlValue::Integer(1), @@ -1117,7 +1117,7 @@ fn parse_def_copy_object(data: &[u8], let source = parse_term_arg(&data[1..], ctx)?; let destination = parse_simple_name(&data[1 + source.len..], ctx)?; - ctx.copy(destination.val, source.val.clone())?; + ctx.copy(ctx.acpi_context(), destination.val, source.val.clone())?; Ok(AmlParseType { val: source.val, @@ -1143,17 +1143,17 @@ fn parse_def_concat(data: &[u8], let result = match lhs.val { AmlValue::Integer(_i) => { - let j = AmlValue::Integer(rhs.val.get_as_integer()?); + let j = AmlValue::Integer(rhs.val.get_as_integer(ctx.acpi_context())?); - let mut first = lhs.val.get_as_buffer()?.clone(); - let mut second = j.get_as_buffer()?.clone(); + let mut first = lhs.val.get_as_buffer(ctx.acpi_context())?.clone(); + let mut second = j.get_as_buffer(ctx.acpi_context())?.clone(); first.append(&mut second); AmlValue::Buffer(first) }, AmlValue::String(s) => { - let t = if let Ok(t) = rhs.val.get_as_string() { + let t = if let Ok(t) = rhs.val.get_as_string(ctx.acpi_context()) { t } else { rhs.val.get_type_string() @@ -1163,10 +1163,10 @@ fn parse_def_concat(data: &[u8], }, AmlValue::Buffer(b) => { let mut b = b.clone(); - let mut c = if let Ok(c) = rhs.val.get_as_buffer() { + let mut c = if let Ok(c) = rhs.val.get_as_buffer(ctx.acpi_context()) { c.clone() } else { - AmlValue::String(rhs.val.get_type_string()).get_as_buffer()?.clone() + AmlValue::String(rhs.val.get_type_string()).get_as_buffer(ctx.acpi_context())?.clone() }; b.append(&mut c); @@ -1175,7 +1175,7 @@ fn parse_def_concat(data: &[u8], }, _ => { let first = lhs.val.get_type_string(); - let second = if let Ok(second) = rhs.val.get_as_string() { + let second = if let Ok(second) = rhs.val.get_as_string(ctx.acpi_context()) { second } else { rhs.val.get_type_string() @@ -1185,7 +1185,7 @@ fn parse_def_concat(data: &[u8], } }; - ctx.modify(target.val, result.clone())?; + ctx.modify(ctx.acpi_context(), target.val, result.clone())?; Ok(AmlParseType { val: result, @@ -1207,9 +1207,9 @@ fn parse_def_decrement(data: &[u8], let obj = parse_super_name(&data[1..], ctx)?; - let _namespace = ctx.prelock(); - let value = AmlValue::Integer(ctx.get(obj.val.clone())?.get_as_integer()? - 1); - let _ = ctx.modify(obj.val, value.clone()); + let _namespace = ctx.prelock(ctx.acpi_context()); + let value = AmlValue::Integer(ctx.get(ctx.acpi_context(), obj.val.clone())?.get_as_integer(ctx.acpi_context())? - 1); + let _ = ctx.modify(ctx.acpi_context(), obj.val, value.clone()); Ok(AmlParseType { val: value, @@ -1234,14 +1234,14 @@ fn parse_def_divide(data: &[u8], let target_remainder = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; let target_quotient = parse_target(&data[1 + lhs.len + rhs.len + target_remainder.len..], ctx)?; - let numerator = lhs.val.get_as_integer()?; - let denominator = rhs.val.get_as_integer()?; + let numerator = lhs.val.get_as_integer(ctx.acpi_context())?; + let denominator = rhs.val.get_as_integer(ctx.acpi_context())?; let remainder = numerator % denominator; let quotient = (numerator - remainder) / denominator; - let _ = ctx.modify(target_remainder.val, AmlValue::Integer(remainder)); - let _ = ctx.modify(target_quotient.val, AmlValue::Integer(quotient)); + let _ = ctx.modify(ctx.acpi_context(), target_remainder.val, AmlValue::Integer(remainder)); + let _ = ctx.modify(ctx.acpi_context(), target_quotient.val, AmlValue::Integer(quotient)); Ok(AmlParseType { val: AmlValue::Integer(quotient), @@ -1265,7 +1265,7 @@ fn parse_def_find_set_left_bit(data: &[u8], let target = parse_target(&data[2 + operand.len..], ctx)?; let mut first_bit = 32; - let mut test = operand.val.get_as_integer()?; + let mut test = operand.val.get_as_integer(ctx.acpi_context())?; while first_bit > 0{ if test & 0x8000_0000_0000_0000 > 0 { @@ -1277,7 +1277,7 @@ fn parse_def_find_set_left_bit(data: &[u8], } let result = AmlValue::Integer(first_bit); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -1301,7 +1301,7 @@ fn parse_def_find_set_right_bit(data: &[u8], let target = parse_target(&data[2 + operand.len..], ctx)?; let mut first_bit = 1; - let mut test = operand.val.get_as_integer()?; + let mut test = operand.val.get_as_integer(ctx.acpi_context())?; while first_bit <= 32 { if test & 1 > 0 { @@ -1317,7 +1317,7 @@ fn parse_def_find_set_right_bit(data: &[u8], } let result = AmlValue::Integer(first_bit); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -1346,15 +1346,15 @@ fn parse_def_load_table(data: &[u8], let parameter_data = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len + root_path.len + parameter_path.len..], ctx)?; let signature = { - <[u8; 4]>::try_from(&*signature.val.get_as_buffer()?) + <[u8; 4]>::try_from(&*signature.val.get_as_buffer(ctx.acpi_context())?) .expect("expected 'load table' def to have a signature that is 4 bytes long") }; let oem_id = { - <[u8; 6]>::try_from(&*oem_id.val.get_as_buffer()?) + <[u8; 6]>::try_from(&*oem_id.val.get_as_buffer(ctx.acpi_context())?) .expect("expected 'load table' def to have an OEM ID that is 6 bytes long") }; let oem_table_id = { - <[u8; 8]>::try_from(&*oem_table_id.val.get_as_buffer()?) + <[u8; 8]>::try_from(&*oem_table_id.val.get_as_buffer(ctx.acpi_context())?) .expect("expected 'load table' def to have an OEM table ID that is 8 bytes long") }; @@ -1369,8 +1369,8 @@ fn parse_def_load_table(data: &[u8], let sdt = ctx.acpi_context().sdt_from_signature(&sdt_signature); Ok(if let Some(sdt) = sdt.and_then(|sdt| PossibleAmlTables::try_new(sdt.clone())) { - let hdl = parse_aml_with_scope(sdt, root_path.val.get_as_string()?)?; - let _ = ctx.modify(parameter_path.val, parameter_data.val); + let hdl = parse_aml_with_scope(ctx.acpi_context(), sdt, root_path.val.get_as_string(ctx.acpi_context())?)?; + let _ = ctx.modify(ctx.acpi_context(), parameter_path.val, parameter_data.val); AmlParseType { val: AmlValue::DDBHandle((hdl, sdt_signature)), @@ -1423,14 +1423,14 @@ fn parse_def_match(data: &[u8], let start_index = parse_term_arg(&data[3 + search_pkg.len + first_operand.len + second_operand.len..], ctx)?; let pkg = search_pkg.val.get_as_package()?; - let mut idx = start_index.val.get_as_integer()? as usize; + let mut idx = start_index.val.get_as_integer(ctx.acpi_context())? as usize; match first_operand.val { AmlValue::Integer(i) => { - let j = second_operand.val.get_as_integer()?; + let j = second_operand.val.get_as_integer(ctx.acpi_context())?; while idx < pkg.len() { - let val = if let Ok(v) = pkg[idx].get_as_integer() { v } else { idx += 1; continue; }; + let val = if let Ok(v) = pkg[idx].get_as_integer(ctx.acpi_context()) { v } else { idx += 1; continue; }; idx += 1; match first_operation { @@ -1458,10 +1458,10 @@ fn parse_def_match(data: &[u8], } }, AmlValue::String(i) => { - let j = second_operand.val.get_as_string()?; + let j = second_operand.val.get_as_string(ctx.acpi_context())?; while idx < pkg.len() { - let val = if let Ok(v) = pkg[idx].get_as_string() { v } else { idx += 1; continue; }; + let val = if let Ok(v) = pkg[idx].get_as_string(ctx.acpi_context()) { v } else { idx += 1; continue; }; idx += 1; match first_operation { @@ -1489,11 +1489,11 @@ fn parse_def_match(data: &[u8], } }, _ => { - let i = first_operand.val.get_as_buffer()?; - let j = second_operand.val.get_as_buffer()?; + let i = first_operand.val.get_as_buffer(ctx.acpi_context())?; + let j = second_operand.val.get_as_buffer(ctx.acpi_context())?; while idx < pkg.len() { - let val = if let Ok(v) = pkg[idx].get_as_buffer() { v } else { idx += 1; continue; }; + let val = if let Ok(v) = pkg[idx].get_as_buffer(ctx.acpi_context()) { v } else { idx += 1; continue; }; idx += 1; match first_operation { @@ -1543,7 +1543,7 @@ fn parse_def_from_bcd(data: &[u8], let operand = parse_term_arg(&data[2..], ctx)?; let target = parse_target(&data[2 + operand.len..], ctx)?; - let mut i = operand.val.get_as_integer()?; + let mut i = operand.val.get_as_integer(ctx.acpi_context())?; let mut result = 0; while i != 0 { @@ -1558,7 +1558,7 @@ fn parse_def_from_bcd(data: &[u8], let result = AmlValue::Integer(result); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -1583,8 +1583,8 @@ fn parse_def_mid(data: &[u8], let length = parse_term_arg(&data[1 + source.len + index.len..], ctx)?; let target = parse_target(&data[1 + source.len + index.len + length.len..], ctx)?; - let idx = index.val.get_as_integer()? as usize; - let mut len = length.val.get_as_integer()? as usize; + let idx = index.val.get_as_integer(ctx.acpi_context())? as usize; + let mut len = length.val.get_as_integer(ctx.acpi_context())? as usize; let result = match source.val { AmlValue::String(s) => { @@ -1606,7 +1606,7 @@ fn parse_def_mid(data: &[u8], // implicitly. // Additionally, any type that can be converted to a buffer can also be converted to a // string, so no information is lost - let b = source.val.get_as_buffer()?; + let b = source.val.get_as_buffer(ctx.acpi_context())?; if idx > b.len() { AmlValue::Buffer(vec!()) @@ -1620,7 +1620,7 @@ fn parse_def_mid(data: &[u8], } }; - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -1644,13 +1644,13 @@ fn parse_def_mod(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - if rhs.val.get_as_integer()? == 0 { + if rhs.val.get_as_integer(ctx.acpi_context())? == 0 { return Err(AmlError::AmlValueError); } - let result = AmlValue::Integer(lhs.val.get_as_integer()? % rhs.val.get_as_integer()?); + let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? % rhs.val.get_as_integer(ctx.acpi_context())?); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -1675,9 +1675,9 @@ fn parse_def_multiply(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let result = AmlValue::Integer(lhs.val.get_as_integer()? * rhs.val.get_as_integer()?); + let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? * rhs.val.get_as_integer(ctx.acpi_context())?); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -1701,9 +1701,9 @@ fn parse_def_nand(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let result = AmlValue::Integer(!(lhs.val.get_as_integer()? & rhs.val.get_as_integer()?)); + let result = AmlValue::Integer(!(lhs.val.get_as_integer(ctx.acpi_context())? & rhs.val.get_as_integer(ctx.acpi_context())?)); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -1727,9 +1727,9 @@ fn parse_def_nor(data: &[u8], let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let result = AmlValue::Integer(!(lhs.val.get_as_integer()? | rhs.val.get_as_integer()?)); + let result = AmlValue::Integer(!(lhs.val.get_as_integer(ctx.acpi_context())? | rhs.val.get_as_integer(ctx.acpi_context())?)); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, @@ -1752,9 +1752,9 @@ fn parse_def_not(data: &[u8], let operand = parse_term_arg(&data[1..], ctx)?; let target = parse_target(&data[1 + operand.len..], ctx)?; - let result = AmlValue::Integer(!operand.val.get_as_integer()?); + let result = AmlValue::Integer(!operand.val.get_as_integer(ctx.acpi_context())?); - let _ = ctx.modify(target.val, result.clone()); + let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); Ok(AmlParseType { val: result, From 5d661eab5959e79fc43e2fe28a936d20be08d098 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 10 Mar 2021 14:37:06 +0100 Subject: [PATCH 0442/1301] Successfully load physical SDTs, and handle kstop* Well, while it does now wait for the kstop pipe, that is not to say that it actually performs the ACPI shutdown... yet. --- Cargo.lock | 13 +++++ acpid/Cargo.toml | 1 + acpid/src/acpi.rs | 20 ++++++-- acpid/src/aml/mod.rs | 6 ++- acpid/src/main.rs | 110 +++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 141 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4322c741b9..ec0ff080d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox-log 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1024,6 +1025,17 @@ dependencies = [ "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox-log" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "redox_event" version = "0.1.0" @@ -1656,6 +1668,7 @@ dependencies = [ "checksum raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)" = "" +"checksum redox-log 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf6d33a003a5c0b94ec11f10c7c797303f236592964ddb1bfb93e1b438a1557" "checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" "checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" "checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 30041ea4fd..3b990a92cf 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -10,5 +10,6 @@ edition = "2018" log = "0.4" parking_lot = "0.11.1" plain = "0.2.3" +redox-log = "0.1.1" redox_syscall = "0.2.5" thiserror = "1" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 40082226e3..0ff6a50732 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,8 +1,8 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::mem; use std::ops::Deref; use std::sync::Arc; +use std::{fmt, mem}; use syscall::flag::PhysmapFlags; @@ -142,7 +142,7 @@ impl Sdt { assert!(pages.len() >= mem::size_of::()); let sdt_mem = &pages[physaddr_page_offset..]; - let sdt = plain::from_bytes::(&pages[mem::size_of::()..]) + let sdt = plain::from_bytes::(&sdt_mem[..mem::size_of::()]) .expect("either alignment is wrong, or the length is too short, both of which are already checked for"); let total_length = sdt.length(); @@ -156,18 +156,19 @@ impl Sdt { let mut left = extended_length; let mut offset = physaddr_start_page + page_table_count * PAGE_SIZE; + let length_per_iteration = PAGE_SIZE * SIMULTANEOUS_PAGE_COUNT; while left > 0 { let to_copy = std::cmp::min(left, length_per_iteration); - let pages = PhysmapGuard::map(offset, length_per_iteration)?; + let additional_pages = PhysmapGuard::map(offset, length_per_iteration)?; - loaded.extend(&pages[..to_copy]); + loaded.extend(&additional_pages[..to_copy]); left -= to_copy; offset += to_copy; } - assert_eq!(offset, loaded.len()); + assert_eq!(left, 0); Self::new(loaded.into()).map_err(Into::into) } @@ -188,6 +189,15 @@ impl Sdt { } } +impl fmt::Debug for Sdt { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Sdt") + .field("header", &*self as &SdtHeader) + .field("extra_len", &self.data().len()) + .finish() + } +} + pub struct Dsdt(Sdt); pub struct Ssdt(Sdt); diff --git a/acpid/src/aml/mod.rs b/acpid/src/aml/mod.rs index c56cc1dbcc..fa808729f7 100644 --- a/acpid/src/aml/mod.rs +++ b/acpid/src/aml/mod.rs @@ -94,7 +94,7 @@ fn init_namespace(context: &AcpiContext) -> HashMap { pub fn set_global_s_state(context: &AcpiContext, state: u8) { if state != 5 { - return + return; } let fadt = match context.fadt() { Some(fadt) => fadt, @@ -140,4 +140,8 @@ pub fn set_global_s_state(context: &AcpiContext, state: u8) { log::info!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); Pio::::new(port).write(val); + + loop { + core::hint::spin_loop(); + } } diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 54ebe96d1b..8a4baeeeea 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -1,7 +1,17 @@ -use std::convert::TryFrom; +#![feature(renamed_spin_loop)] + +use std::convert::{TryFrom, TryInto}; +use std::io::prelude::*; +use std::fs::{File, OpenOptions}; use std::mem; +use std::os::unix::io::AsRawFd; use std::sync::Arc; +use redox_log::RedoxLogger; + +use syscall::data::Event; +use syscall::flag::EventFlags; + mod acpi; mod aml; @@ -20,10 +30,57 @@ fn monotonic() -> (u64, u64) { (timespec.tv_sec as u64, timespec.tv_nsec as u64) } +fn setup_logging() -> Option<&'static RedoxLogger> { + use redox_log::OutputBuilder; + + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Trace) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Trace) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("Failed to create xhci.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Trace) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("Failed to create acpid.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("acpid: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("acpid: failed to set default logger: {}", error); + None + } + } +} fn main() { - let rxsdt_raw_data: Arc<[u8]> = std::fs::read("kernel/acpi:") - .expect("acpid: failed to read `kernel/acpi:`") + setup_logging(); + + let rxsdt_raw_data: Arc<[u8]> = std::fs::read("kernel/acpi:rxsdt") + .expect("acpid: failed to read `kernel/acpi:rxsdt`") .into(); let sdt = self::acpi::Sdt::new(rxsdt_raw_data) @@ -52,4 +109,51 @@ fn main() { _ => panic!("acpid: expected [RX]SDT from kernel to be either of those"), }; + for physaddr in physaddrs_iter { + let physaddr: usize = physaddr + .try_into() + .expect("expected ACPI addresses to be compatible with the current word size"); + + log::info!("TABLE AT {:#>08X}", physaddr); + + let sdt = self::acpi::Sdt::load_from_physical(physaddr) + .expect("failed to load physical SDT"); + dbg!(sdt); + } + + // TODO: I/O permission bitmap + unsafe { syscall::iopl(3) }.expect("acpid: failed to set I/O privilege level to Ring 3"); + + let shutdown_pipe = File::open("kernel/acpi:kstop") + .expect("acpid: failed to open `kernel/acpi:kstop`"); + + let mut event_queue = OpenOptions::new() + .write(true) + .read(true) + .create(false) + .open("event:") + .expect("acpid: failed to open event queue"); + + syscall::setrens(0, 0).expect("acpid: failed to enter null namespace"); + + event_queue.write_all(&Event { + id: shutdown_pipe.as_raw_fd() as usize, + flags: EventFlags::EVENT_READ, + data: 0, + }).expect("acpid: failed to register shutdown pipe for event queue"); + + loop { + let mut event = Event::default(); + event_queue.read_exact(&mut event).expect("acpid: failed to read from event queue"); + + if event.flags.contains(EventFlags::EVENT_READ) && event.id == shutdown_pipe.as_raw_fd() as usize { + break; + } + } + + drop(shutdown_pipe); + drop(event_queue); + + aml::set_global_s_state(todo!(), 5); + unreachable!(); } From 7de9816c5042bc0c930530a13faa60becfcac946 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 10 Mar 2021 18:06:30 +0100 Subject: [PATCH 0443/1301] Basic ACPI init code, daemonize. --- acpid/src/acpi.rs | 27 +++++++++++- acpid/src/main.rs | 101 ++++++++++++++++++++++++++++++++++++-------- acpid/src/scheme.rs | 37 ++++++++++++++++ 3 files changed, 146 insertions(+), 19 deletions(-) create mode 100644 acpid/src/scheme.rs diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 0ff6a50732..4a697a6fc3 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -101,7 +101,7 @@ impl Deref for PhysmapGuard { impl Drop for PhysmapGuard { fn drop(&mut self) { unsafe { - syscall::physfree(self.virt as usize, self.size); + let _ = syscall::physunmap(self.virt as usize); } } } @@ -209,6 +209,31 @@ pub struct AcpiContext { pub next_ctx: RwLock, } impl AcpiContext { + pub fn init(rxsdt_physaddrs: impl Iterator) -> Self { + let tables = rxsdt_physaddrs.map(|physaddr| { + let physaddr: usize = physaddr + .try_into() + .expect("expected ACPI addresses to be compatible with the current word size"); + + log::info!("TABLE AT {:#>08X}", physaddr); + + Sdt::load_from_physical(physaddr) + .expect("failed to load physical SDT") + }).collect::>(); + + let mut this = Self { + tables, + dsdt: None, + fadt: None, + namespace: RwLock::new(None), + next_ctx: RwLock::new(0), + }; + + Fadt::init(&mut this); + + this + } + pub fn dsdt(&self) -> Option<&Dsdt> { self.dsdt.as_ref() } diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 8a4baeeeea..2efa91161e 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -4,16 +4,18 @@ use std::convert::{TryFrom, TryInto}; use std::io::prelude::*; use std::fs::{File, OpenOptions}; use std::mem; -use std::os::unix::io::AsRawFd; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use redox_log::RedoxLogger; +use syscall::scheme::Scheme; -use syscall::data::Event; +use syscall::data::{Event, Packet}; use syscall::flag::EventFlags; mod acpi; mod aml; +mod scheme; // TODO: Perhaps use the acpi and aml crates? @@ -77,6 +79,41 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } fn main() { + let mut pipes = [0; 2]; + syscall::pipe2(&mut pipes, 0).expect("acpid: failed to create synchronization pipe"); + let [read_part, write_part] = pipes; + + let mut read_part = unsafe { File::from_raw_fd(read_part as RawFd) }; + let mut write_part = unsafe { File::from_raw_fd(write_part as RawFd) }; + + let pid = unsafe { syscall::clone(syscall::CloneFlags::empty()).expect("failed to daemonize acpid") }; + + if pid != 0 { + drop(write_part); + + let mut res = [0]; + let bytes_read = read_part.read(&mut res).expect("acpid: failed to read from sync pipe"); + + let exit_code = if bytes_read == res.len() { + res[0] + } else { + 1 + }; + drop(read_part); + std::process::exit(exit_code.into()); + } + drop(read_part); + + let mut scheme_socket = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .open(":acpi") + .expect("acpid: failed to open scheme socket"); + + let _ = write_part.write(&[0]).expect("acpid: failed to write to sync pipe"); + drop(write_part); + setup_logging(); let rxsdt_raw_data: Arc<[u8]> = std::fs::read("kernel/acpi:rxsdt") @@ -109,17 +146,7 @@ fn main() { _ => panic!("acpid: expected [RX]SDT from kernel to be either of those"), }; - for physaddr in physaddrs_iter { - let physaddr: usize = physaddr - .try_into() - .expect("expected ACPI addresses to be compatible with the current word size"); - - log::info!("TABLE AT {:#>08X}", physaddr); - - let sdt = self::acpi::Sdt::load_from_physical(physaddr) - .expect("failed to load physical SDT"); - dbg!(sdt); - } + let acpi_context = self::acpi::AcpiContext::init(physaddrs_iter); // TODO: I/O permission bitmap unsafe { syscall::iopl(3) }.expect("acpid: failed to set I/O privilege level to Ring 3"); @@ -136,24 +163,62 @@ fn main() { syscall::setrens(0, 0).expect("acpid: failed to enter null namespace"); - event_queue.write_all(&Event { + let _ = event_queue.write(&Event { id: shutdown_pipe.as_raw_fd() as usize, flags: EventFlags::EVENT_READ, data: 0, }).expect("acpid: failed to register shutdown pipe for event queue"); + let _ = event_queue.write(&Event { + id: scheme_socket.as_raw_fd() as usize, + flags: EventFlags::EVENT_READ, + data: 1, + }).expect("acpid: failed to register scheme socket for event queue"); + + let scheme = self::scheme::AcpiScheme::new(&acpi_context); + + let mut event = Event::default(); + let mut packet = Packet::default(); + loop { - let mut event = Event::default(); - event_queue.read_exact(&mut event).expect("acpid: failed to read from event queue"); + let _ = event_queue.read(&mut event).expect("acpid: failed to read from event queue"); if event.flags.contains(EventFlags::EVENT_READ) && event.id == shutdown_pipe.as_raw_fd() as usize { break; } + if !event.flags.contains(EventFlags::EVENT_NONE) || event.id != scheme_socket.as_raw_fd() as usize { + continue; + } + + let bytes_read = scheme_socket.read(&mut packet).expect("acpid: failed to read from scheme socket"); + + if bytes_read == 0 { + log::info!("Terminating acpid driver, without shutting down the main system."); + return; + } + + if bytes_read < mem::size_of::() { + log::error!("Scheme socket read less than a single packet."); + } + + scheme.handle(&mut packet); + + let bytes_written = scheme_socket.write(&packet).expect("acpid: failed to write to scheme socket"); + + if bytes_written == 0 { + log::info!("Terminating acpid driver, without shutting down the main system."); + return; + } + + if bytes_written < mem::size_of::() { + log::error!("Scheme socket read less than a single packet."); + } } drop(shutdown_pipe); drop(event_queue); - aml::set_global_s_state(todo!(), 5); - unreachable!(); + aml::set_global_s_state(&acpi_context, 5); + + unreachable!("System should have shut down before this is entered"); } diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs new file mode 100644 index 0000000000..ac2bff38c2 --- /dev/null +++ b/acpid/src/scheme.rs @@ -0,0 +1,37 @@ +use syscall::error::{EBADF, ENOENT}; +use syscall::error::{Error, Result}; +use syscall::scheme::Scheme; + +use crate::acpi::AcpiContext; + +pub struct AcpiScheme<'acpi> { + ctx: &'acpi AcpiContext, +} + +impl<'acpi> AcpiScheme<'acpi> { + pub fn new(ctx: &'acpi AcpiContext) -> Self { + Self { + ctx, + } + } +} + +const ALLOWED_TABLE_SIGNATURES: [[u8; 4]; 1] = [*b"MCFG"]; + +impl Scheme for AcpiScheme<'_> { + fn open(&self, path: &str, flags: usize, uid: u32, gid: u32) -> Result { + Err(Error::new(ENOENT)) + } + fn seek(&self, id: usize, pos: isize, whence: usize) -> Result { + Err(Error::new(EBADF)) + } + fn read(&self, id: usize, buf: &mut [u8]) -> Result { + Err(Error::new(EBADF)) + } + fn write(&self, id: usize, buf: &[u8]) -> Result { + Err(Error::new(EBADF)) + } + fn close(&self, id: usize) -> Result { + Err(Error::new(EBADF)) + } +} From 20e6384cca5218bd411fbe3c59dcbc2a9f4532dd Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 10 Mar 2021 20:50:16 +0100 Subject: [PATCH 0444/1301] WIP: Implement the userspace ACPI scheme. --- acpid/src/acpi.rs | 8 +- acpid/src/main.rs | 9 +- acpid/src/scheme.rs | 282 ++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 274 insertions(+), 25 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 4a697a6fc3..ddf3061229 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -38,7 +38,7 @@ impl SdtHeader { oem_table_id: self.oem_table_id, } } - fn length(&self) -> usize { + pub fn length(&self) -> usize { self .length .try_into() @@ -172,6 +172,9 @@ impl Sdt { Self::new(loaded.into()).map_err(Into::into) } + pub fn as_slice(&self) -> &[u8] { + &self.0 + } } impl Deref for Sdt { @@ -276,6 +279,9 @@ impl AcpiContext { pub fn get_index_from_signature(&self, signature: &SdtSignature) -> Option { todo!() } + pub fn tables(&self) -> &[Sdt] { + &self.tables + } } #[repr(packed)] diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 2efa91161e..3d34315b6a 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -1,4 +1,4 @@ -#![feature(renamed_spin_loop)] +#![feature(renamed_spin_loop, seek_convenience)] use std::convert::{TryFrom, TryInto}; use std::io::prelude::*; @@ -8,7 +8,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use redox_log::RedoxLogger; -use syscall::scheme::Scheme; +use syscall::scheme::SchemeMut; use syscall::data::{Event, Packet}; use syscall::flag::EventFlags; @@ -97,6 +97,7 @@ fn main() { let exit_code = if bytes_read == res.len() { res[0] } else { + eprintln!("acpid: daemon pipe EOF"); 1 }; drop(read_part); @@ -175,7 +176,7 @@ fn main() { data: 1, }).expect("acpid: failed to register scheme socket for event queue"); - let scheme = self::scheme::AcpiScheme::new(&acpi_context); + let mut scheme = self::scheme::AcpiScheme::new(&acpi_context); let mut event = Event::default(); let mut packet = Packet::default(); @@ -186,7 +187,7 @@ fn main() { if event.flags.contains(EventFlags::EVENT_READ) && event.id == shutdown_pipe.as_raw_fd() as usize { break; } - if !event.flags.contains(EventFlags::EVENT_NONE) || event.id != scheme_socket.as_raw_fd() as usize { + if !event.flags.contains(EventFlags::EVENT_READ) || event.id != scheme_socket.as_raw_fd() as usize { continue; } diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index ac2bff38c2..2587a1c949 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -1,37 +1,279 @@ -use syscall::error::{EBADF, ENOENT}; -use syscall::error::{Error, Result}; -use syscall::scheme::Scheme; +use std::collections::BTreeMap; +use std::convert::{TryFrom, TryInto}; -use crate::acpi::AcpiContext; +use syscall::data::Stat; +use syscall::error::{EBADF, EBADFD, EINVAL, EISDIR, ENOENT, ENOTDIR, EOVERFLOW}; +use syscall::error::{Error, Result}; +use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDONLY, O_STAT, O_SYMLINK}; +use syscall::flag::{MODE_FILE, MODE_DIR, SEEK_CUR, SEEK_END, SEEK_SET}; +use syscall::scheme::SchemeMut; + +use crate::acpi::{AcpiContext, SdtSignature}; pub struct AcpiScheme<'acpi> { ctx: &'acpi AcpiContext, + handles: BTreeMap, + next_fd: usize, +} + +struct Handle { + offset: usize, + kind: HandleKind, + stat: bool, +} +enum HandleKind { + TopLevel, + Tables, + Table(SdtSignature), +} + +impl HandleKind { + fn is_dir(&self) -> bool { + match self { + Self::TopLevel => true, + Self::Tables => true, + Self::Table(_) => false, + } + } + fn len(&self, acpi_ctx: &AcpiContext) -> Result { + Ok(match self { + Self::TopLevel => TOPLEVEL_CONTENTS.len(), + Self::Tables => acpi_ctx.tables().len().checked_mul(TABLE_DENTRY_LENGTH).unwrap_or(usize::max_value()), + Self::Table(signature) => acpi_ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.length(), + }) + } } impl<'acpi> AcpiScheme<'acpi> { pub fn new(ctx: &'acpi AcpiContext) -> Self { Self { ctx, + handles: BTreeMap::new(), + next_fd: 0, } } } -const ALLOWED_TABLE_SIGNATURES: [[u8; 4]; 1] = [*b"MCFG"]; +const TOPLEVEL_CONTENTS: &[u8] = b"tables\n"; -impl Scheme for AcpiScheme<'_> { - fn open(&self, path: &str, flags: usize, uid: u32, gid: u32) -> Result { - Err(Error::new(ENOENT)) - } - fn seek(&self, id: usize, pos: isize, whence: usize) -> Result { - Err(Error::new(EBADF)) - } - fn read(&self, id: usize, buf: &mut [u8]) -> Result { - Err(Error::new(EBADF)) - } - fn write(&self, id: usize, buf: &[u8]) -> Result { - Err(Error::new(EBADF)) - } - fn close(&self, id: usize) -> Result { - Err(Error::new(EBADF)) +const TABLE_DENTRY_LENGTH: usize = 35; + +fn parse_hex_digit(hex: u8) -> Option { + let hex = hex.to_ascii_lowercase(); + + if hex >= b'a' && hex <= b'f' { + Some(hex - b'a') + } else if hex >= b'0' && hex <= b'9' { + Some(hex - b'0') + } else { + None + } +} + +fn parse_hex_2digit(hex: &[u8]) -> Option { + parse_hex_digit(hex[0]).and_then(|least_significant| Some(least_significant | (parse_hex_digit(hex[1])? << 4))) +} + +fn parse_oem_id(hex: [u8; 12]) -> Option<[u8; 6]> { + Some([ + parse_hex_2digit(&hex[0..2])?, + parse_hex_2digit(&hex[2..4])?, + parse_hex_2digit(&hex[4..6])?, + parse_hex_2digit(&hex[6..8])?, + parse_hex_2digit(&hex[8..10])?, + parse_hex_2digit(&hex[10..12])?, + ]) +} +fn parse_oem_table_id(hex: [u8; 16]) -> Option<[u8; 8]> { + Some([ + parse_hex_2digit(&hex[0..2])?, + parse_hex_2digit(&hex[2..4])?, + parse_hex_2digit(&hex[4..6])?, + parse_hex_2digit(&hex[6..8])?, + parse_hex_2digit(&hex[8..10])?, + parse_hex_2digit(&hex[10..12])?, + parse_hex_2digit(&hex[12..14])?, + parse_hex_2digit(&hex[14..16])?, + ]) +} + +fn parse_table(table: &[u8]) -> Option { + let signature_part = table.get(..4)?; + let first_hyphen = table.get(5)?; + let oem_id_part = table.get(5..17)?; + let second_hyphen = table.get(17)?; + let oem_table_part = table.get(18..34)?; + + if *first_hyphen != b'-' { + return None; + } + if *second_hyphen != b'-' { + return None; + } + + if table.len() > 20 { + return None; + } + + Some(SdtSignature { + signature: <[u8; 4]>::try_from(signature_part).expect("expected 4-byte slice to be convertible into [u8; 4]"), + oem_id: { + let hex = <[u8; 12]>::try_from(oem_id_part).expect("expected 12-byte slice to be convertible into [u8; 12]"); + parse_oem_id(hex)? + }, + oem_table_id: { + let hex = <[u8; 16]>::try_from(oem_table_part).expect("expected 16-byte slice to be convertible into [u8; 16]"); + parse_oem_table_id(hex)? + }, + }) +} + +impl SchemeMut for AcpiScheme<'_> { + fn open(&mut self, path: &str, flags: usize, _uid: u32, _gid: u32) -> Result { + let path = path.trim_start_matches('/'); + + let flag_stat = flags & O_STAT == O_STAT; + let flag_dir = flags & O_DIRECTORY == O_DIRECTORY; + + // TODO: arrayvec + let components = path.split('/').collect::>(); + + let kind = match &*components { + [] => HandleKind::TopLevel, + ["tables"] => HandleKind::Tables, + + ["tables", table] => { + let signature = parse_table(table.as_bytes()).ok_or(Error::new(ENOENT))?; + HandleKind::Table(signature) + } + + _ => return Err(Error::new(ENOENT)), + }; + + if kind.is_dir() && !flag_dir && !flag_stat { + return Err(Error::new(EISDIR)); + } else if flag_dir && !flag_stat { + return Err(Error::new(ENOTDIR)); + } + + if flags & O_ACCMODE != O_RDONLY && !flag_stat { + return Err(Error::new(EINVAL)); + } + + if flags & O_SYMLINK == O_SYMLINK && !flag_stat { + return Err(Error::new(EINVAL)); + } + + let fd = self.next_fd; + self.next_fd += 1; + + self.handles.insert(fd, Handle { + offset: 0, + stat: flag_stat, + kind, + }); + + Ok(fd) + } + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + stat.st_size = handle.kind.len(self.ctx)?.try_into().unwrap_or(u64::max_value()); + + if handle.kind.is_dir() { + stat.st_mode = MODE_DIR; + } else { + stat.st_mode = MODE_FILE; + } + + Ok(0) + } + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let file_len = handle.kind.len(self.ctx)?; + + let new_offset = match whence { + SEEK_SET => pos as usize, + SEEK_CUR => if pos < 0 { + handle.offset.checked_sub((-pos) as usize).ok_or(Error::new(EINVAL))? + } else { + handle.offset.saturating_add(pos as usize) + }, + SEEK_END => if pos < 0 { + file_len.checked_sub((-pos) as usize).ok_or(Error::new(EINVAL))? + } else { + file_len + } + + _ => return Err(Error::new(EINVAL)), + }; + + handle.offset = new_offset; + Ok(new_offset as isize) + } + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let src_buf = match handle.kind { + HandleKind::TopLevel => TOPLEVEL_CONTENTS, + HandleKind::Table(ref signature) => self.ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.as_slice(), + + HandleKind::Tables => { + use std::io::prelude::*; + + let tables_to_skip = handle.offset / TABLE_DENTRY_LENGTH; + let tables_to_fill = (buf.len() + TABLE_DENTRY_LENGTH - 1) / TABLE_DENTRY_LENGTH; + + let bytes_to_skip = handle.offset % TABLE_DENTRY_LENGTH; + + let mut src_buf = [0_u8; TABLE_DENTRY_LENGTH]; + let mut bytes_written = 0; + + for table in self.ctx.tables().iter().skip(tables_to_skip).take(tables_to_fill) { + let mut cursor = std::io::Cursor::new(&mut src_buf[..]); + cursor.write_all(&table.signature).unwrap(); + cursor.write_all(&[b'-']).unwrap(); + // TODO: Treat these IDs as strings? + for byte in table.oem_id.iter() { + write!(cursor, "{:>02X}", byte).unwrap(); + } + cursor.write_all(&[b'-']).unwrap(); + for byte in table.oem_table_id.iter() { + write!(cursor, "{:>02X}", byte).unwrap(); + } + + let src_buf = &src_buf[bytes_to_skip..]; + let dst_buf = &mut buf[bytes_written..]; + let to_copy = std::cmp::min(src_buf.len(), dst_buf.len()); + dst_buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); + bytes_written += to_copy; + } + + handle.offset = handle.offset.checked_add(bytes_written).ok_or(Error::new(EOVERFLOW))?; + + return Ok(bytes_written); + } + }; + + let offset = std::cmp::min(src_buf.len(), handle.offset); + let src_buf = &src_buf[offset..]; + + let to_copy = std::cmp::min(src_buf.len(), buf.len()); + buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); + + handle.offset += to_copy; + + Ok(to_copy) + } + fn write(&mut self, _id: usize, _buf: &[u8]) -> Result { + Err(Error::new(EBADF)) + } + fn close(&mut self, id: usize) -> Result { + if self.handles.remove(&id).is_none() { + return Err(Error::new(EBADF)); + } + + Ok(0) } } From 0feb8685a61324d269bc7a4b68c62aea94a5c12a Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 11 Mar 2021 08:31:43 +0100 Subject: [PATCH 0445/1301] Fix the acpi scheme freeze. --- acpid/src/main.rs | 82 ++++++++++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 3d34315b6a..83ea52b090 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -1,9 +1,10 @@ #![feature(renamed_spin_loop, seek_convenience)] -use std::convert::{TryFrom, TryInto}; -use std::io::prelude::*; +use std::convert::TryFrom; +use std::io::{self, prelude::*}; use std::fs::{File, OpenOptions}; use std::mem; +use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; @@ -11,7 +12,7 @@ use redox_log::RedoxLogger; use syscall::scheme::SchemeMut; use syscall::data::{Event, Packet}; -use syscall::flag::EventFlags; +use syscall::flag::{EventFlags, O_NONBLOCK}; mod acpi; mod aml; @@ -109,6 +110,7 @@ fn main() { .write(true) .read(true) .create(true) + .custom_flags(O_NONBLOCK as i32) .open(":acpi") .expect("acpid: failed to open scheme socket"); @@ -181,38 +183,58 @@ fn main() { let mut event = Event::default(); let mut packet = Packet::default(); - loop { + 'events: loop { + 'packets: loop { + let bytes_read = 'eintr1: loop { + match scheme_socket.read(&mut packet) { + Ok(0) => { + log::info!("Terminating acpid driver, without shutting down the main system."); + return; + } + Ok(n) => break 'eintr1 n, + Err(error) if error.kind() == io::ErrorKind::Interrupted => continue 'eintr1, + Err(error) if error.kind() == io::ErrorKind::WouldBlock => break 'packets, + Err(other) => { + log::error!("failed to read from scheme socket: {}", other); + return; + } + } + }; + + if bytes_read < mem::size_of::() { + log::error!("Scheme socket read less than a single packet."); + } + + scheme.handle(&mut packet); + + let bytes_written = 'eintr2: loop { + match scheme_socket.write(&packet) { + Ok(0) => { + log::info!("Terminating acpid driver, without shutting down the main system."); + return; + } + Ok(n) => break 'eintr2 n, + Err(error) if error.kind() == io::ErrorKind::Interrupted => continue 'eintr2, + Err(error) if error.kind() == io::ErrorKind::WouldBlock => break 'packets, + Err(other) => { + log::error!("failed to read from scheme socket: {}", other); + return; + } + } + }; + + if bytes_written < mem::size_of::() { + log::error!("Scheme socket read less than a single packet."); + } + } + let _ = event_queue.read(&mut event).expect("acpid: failed to read from event queue"); if event.flags.contains(EventFlags::EVENT_READ) && event.id == shutdown_pipe.as_raw_fd() as usize { - break; + break 'events; } if !event.flags.contains(EventFlags::EVENT_READ) || event.id != scheme_socket.as_raw_fd() as usize { - continue; - } - - let bytes_read = scheme_socket.read(&mut packet).expect("acpid: failed to read from scheme socket"); - - if bytes_read == 0 { - log::info!("Terminating acpid driver, without shutting down the main system."); - return; - } - - if bytes_read < mem::size_of::() { - log::error!("Scheme socket read less than a single packet."); - } - - scheme.handle(&mut packet); - - let bytes_written = scheme_socket.write(&packet).expect("acpid: failed to write to scheme socket"); - - if bytes_written == 0 { - log::info!("Terminating acpid driver, without shutting down the main system."); - return; - } - - if bytes_written < mem::size_of::() { - log::error!("Scheme socket read less than a single packet."); + continue 'events; } } From 5fc0f0fa4ec3ffc5307f75aa51ad6152437d2b52 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 11 Mar 2021 12:48:34 +0100 Subject: [PATCH 0446/1301] Successfully parse the namespace. --- acpid/src/acpi.rs | 70 +++++++++++++++++++++++++++--------- acpid/src/aml/mod.rs | 32 ++++++----------- acpid/src/aml/namespace.rs | 3 +- acpid/src/aml/parser.rs | 1 + acpid/src/aml/type1opcode.rs | 20 +++++------ acpid/src/aml/type2opcode.rs | 8 ++--- acpid/src/scheme.rs | 28 ++++++++++----- 7 files changed, 98 insertions(+), 64 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index ddf3061229..4d08cfe919 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,7 +1,7 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::convert::{TryFrom, TryInto}; use std::ops::Deref; -use std::sync::Arc; +use std::sync::{Arc, atomic::{self, AtomicUsize}}; use std::{fmt, mem}; use syscall::flag::PhysmapFlags; @@ -46,13 +46,19 @@ impl SdtHeader { } } -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct SdtSignature { pub signature: [u8; 4], pub oem_id: [u8; 6], pub oem_table_id: [u8; 8], } +impl fmt::Display for SdtSignature { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}-{}-{}", String::from_utf8_lossy(&self.signature), String::from_utf8_lossy(&self.oem_id), String::from_utf8_lossy(&self.oem_table_id)) + } +} + #[derive(Debug, Error)] pub enum TablePhysLoadError { // TODO: Make syscall::Error implement std::error::Error, when enabling a Cargo feature. @@ -208,7 +214,17 @@ pub struct AcpiContext { tables: Vec, dsdt: Option, fadt: Option, + + // TODO: Remove Option. This is not kernel code, and not static, but we still need to replace + // every match where namespace{,_mut}() are used. namespace: RwLock>>, + + // TODO: The kernel ACPI code seemed to use load_table quite ubiquitously, however ACPI 5.1 + // states that DDBHandles can only be obtained when loading XSDT-pointed tables. So, we'll + // generate an index only for those. + + sdt_order: RwLock>>, + pub next_ctx: RwLock, } impl AcpiContext { @@ -228,12 +244,20 @@ impl AcpiContext { tables, dsdt: None, fadt: None, - namespace: RwLock::new(None), + namespace: RwLock::new(Some(HashMap::new())), next_ctx: RwLock::new(0), + + sdt_order: RwLock::new(Vec::new()), }; + for table in &this.tables { + this.new_index(&table.signature()); + } + Fadt::init(&mut this); + crate::aml::init_namespace(&this); + this } @@ -252,9 +276,6 @@ impl AcpiContext { self.tables.iter().position(|sdt| sdt.signature == signature) } - pub fn find_single_sdt(&self, signature: [u8; 4]) -> Option<&Sdt> { - self.find_single_sdt_pos(signature).map(|pos| &self.tables[pos]) - } pub fn find_multiple_sdts<'a>(&'a self, signature: [u8; 4]) -> impl Iterator { self.tables.iter().filter(move |sdt| sdt.signature == signature) } @@ -274,14 +295,17 @@ impl AcpiContext { self.tables.iter().find(|sdt| sdt.signature == signature.signature && sdt.oem_id == signature.oem_id && sdt.oem_table_id == signature.oem_table_id) } pub fn get_signature_from_index(&self, index: usize) -> Option { - todo!() + self.sdt_order.read().get(index).copied().flatten() } pub fn get_index_from_signature(&self, signature: &SdtSignature) -> Option { - todo!() + self.sdt_order.read().iter().rposition(|sig| sig.map_or(false, |sig| &sig == signature)) } pub fn tables(&self) -> &[Sdt] { &self.tables } + pub fn new_index(&self, signature: &SdtSignature) { + self.sdt_order.write().push(Some(*signature)); + } } #[repr(packed)] @@ -393,7 +417,7 @@ impl Deref for Fadt { } impl Fadt { - pub fn new(context: &AcpiContext, sdt: Sdt) -> Option { + pub fn new(sdt: Sdt) -> Option { if sdt.signature != *b"FACP" || sdt.length() < mem::size_of::() { return None; } @@ -405,7 +429,7 @@ impl Fadt { .take_single_sdt(*b"FACP") .expect("expected ACPI to always have a FADT"); - let fadt = match Fadt::new(context, fadt_sdt) { + let fadt = match Fadt::new(fadt_sdt) { Some(fadt) => fadt, None => { log::error!("Failed to find FADT"); @@ -432,13 +456,9 @@ impl Fadt { } }; - context.dsdt = Some(Dsdt(dsdt_sdt)); + context.dsdt = Some(Dsdt(dsdt_sdt.clone())); - /* - let signature = get_sdt_signature(dsdt_sdt); - if let Some(ref mut ptrs) = *(SDT_POINTERS.write()) { - ptrs.insert(signature, dsdt_sdt); - }*/ + context.tables.push(dsdt_sdt); } } @@ -462,10 +482,17 @@ impl AmlContainingTable for PossibleAmlTables { Self::Ssdt(ssdt) => ssdt.aml(), } } + fn header(&self) -> &SdtHeader { + match self { + Self::Dsdt(dsdt) => dsdt.header(), + Self::Ssdt(ssdt) => ssdt.header(), + } + } } pub trait AmlContainingTable { fn aml(&self) -> &[u8]; + fn header(&self) -> &SdtHeader; } impl AmlContainingTable for &T @@ -475,15 +502,24 @@ where fn aml(&self) -> &[u8] { T::aml(*self) } + fn header(&self) -> &SdtHeader { + T::header(*self) + } } impl AmlContainingTable for Dsdt { fn aml(&self) -> &[u8] { self.0.data() } + fn header(&self) -> &SdtHeader { + &*self.0 + } } impl AmlContainingTable for Ssdt { fn aml(&self) -> &[u8] { self.0.data() } + fn header(&self) -> &SdtHeader { + &*self.0 + } } diff --git a/acpid/src/aml/mod.rs b/acpid/src/aml/mod.rs index fa808729f7..b48797e493 100644 --- a/acpid/src/aml/mod.rs +++ b/acpid/src/aml/mod.rs @@ -49,34 +49,24 @@ pub fn parse_aml_with_scope(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable Ok(ctx.namespace_delta) } -pub fn is_aml_table(sdt: &SdtHeader) -> bool { - if &sdt.signature == b"DSDT" || &sdt.signature == b"SSDT" { - true - } else { - false - } -} - fn init_aml_table(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable) { - match parse_aml_table(acpi_ctx, sdt) { - Ok(_) => println!(": Parsed"), - Err(AmlError::AmlParseError(e)) => println!(": {}", e), - Err(AmlError::AmlInvalidOpCode) => println!(": Invalid opcode"), - Err(AmlError::AmlValueError) => println!(": Type constraints or value bounds not met"), - Err(AmlError::AmlDeferredLoad) => println!(": Deferred load reached top level"), - Err(AmlError::AmlFatalError(_, _, _)) => { - println!(": Fatal error occurred"); - // TODO + match parse_aml_table(acpi_ctx, &sdt) { + Ok(_) => log::info!("Table {} parsed successfully", sdt.header().signature()), + Err(AmlError::AmlParseError(e)) => log::error!("Table {} got parse error: {}", sdt.header().signature(), e), + Err(AmlError::AmlInvalidOpCode) => log::error!("Table {} got invalid opcode", sdt.header().signature()), + Err(AmlError::AmlValueError) => log::error!("For table {}: type constraints or value bounds not met", sdt.header().signature()), + Err(AmlError::AmlDeferredLoad) => log::error!("For table {}: deferred load reached top level", sdt.header().signature()), + Err(AmlError::AmlFatalError(ty, code, val)) => { + log::error!("Fatal error occurred for table {}: type={}, code={}, val={:?}", sdt.header().signature(), ty, code, val); return; }, Err(AmlError::AmlHardFatal) => { - println!(": Fatal error occurred"); - // TODO + log::error!("Hard fatal error occurred for table {}", sdt.header().signature()); return; } } } -fn init_namespace(context: &AcpiContext) -> HashMap { +pub fn init_namespace(context: &AcpiContext) { let dsdt = context.dsdt().expect("could not find any DSDT"); log::info!("Found DSDT."); @@ -88,8 +78,6 @@ fn init_namespace(context: &AcpiContext) -> HashMap { print!("Found SSDT."); init_aml_table(context, ssdt); } - - todo!() } pub fn set_global_s_state(context: &AcpiContext, state: u8) { diff --git a/acpid/src/aml/namespace.rs b/acpid/src/aml/namespace.rs index 94938dcce9..600a253a56 100644 --- a/acpid/src/aml/namespace.rs +++ b/acpid/src/aml/namespace.rs @@ -253,9 +253,10 @@ impl AmlValue { AmlValue::Integer(i) => if let Some(sig) = acpi_ctx.get_signature_from_index(i as usize) { Ok((vec!(), sig)) } else { + log::error!("AmlValueError in get_as_ddb_handle integer"); Err(AmlError::AmlValueError) }, - _ => Err(AmlError::AmlValueError) + _ => { log::error!("AmlValueError in get_as_ddb_handle other"); Err(AmlError::AmlValueError) } } } diff --git a/acpid/src/aml/parser.rs b/acpid/src/aml/parser.rs index be0a349f2e..704aee5d8c 100644 --- a/acpid/src/aml/parser.rs +++ b/acpid/src/aml/parser.rs @@ -10,6 +10,7 @@ use crate::acpi::AcpiContext; pub type ParseResult = Result; pub type AmlParseType = AmlParseTypeGeneric; +#[derive(Debug)] pub struct AmlParseTypeGeneric { pub val: T, pub len: usize diff --git a/acpid/src/aml/type1opcode.rs b/acpid/src/aml/type1opcode.rs index cd61a78d71..b89d939cb3 100644 --- a/acpid/src/aml/type1opcode.rs +++ b/acpid/src/aml/type1opcode.rs @@ -1,5 +1,3 @@ -use std::mem; - use super::AmlError; use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; use super::namespace::AmlValue; @@ -9,8 +7,8 @@ use super::namestring::{parse_name_string, parse_super_name}; use crate::monotonic; -use crate::acpi::{PossibleAmlTables, SdtHeader}; -use super::{parse_aml_table, is_aml_table}; +use crate::acpi::PossibleAmlTables; +use super::parse_aml_table; pub fn parse_type1_opcode(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { @@ -154,23 +152,23 @@ fn parse_def_load(data: &[u8], let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?; let tbl = ctx.get(ctx.acpi_context(), name.val)?.get_as_buffer(ctx.acpi_context())?; - // TODO - let sdt = plain::from_bytes::(&tbl[..mem::size_of::()]).unwrap(); - let table = match ctx.acpi_context().sdt_from_signature(&sdt.signature()) { - Some(table) => table, - None => return Err(AmlError::AmlValueError), - }; + let table = crate::acpi::Sdt::new(tbl.into()).map_err(|error| { + log::error!("Failed to parse def_load ACPI table: {}", error); + AmlError::AmlValueError + })?; if let Some(aml_sdt) = PossibleAmlTables::try_new(table.clone()) { + ctx.acpi_context().new_index(&table.signature()); let delta = parse_aml_table(ctx.acpi_context(), aml_sdt)?; - let _ = ctx.modify(ctx.acpi_context(), ddb_handle_object.val, AmlValue::DDBHandle((delta, sdt.signature()))); + let _ = ctx.modify(ctx.acpi_context(), ddb_handle_object.val, AmlValue::DDBHandle((delta, table.signature()))); Ok(AmlParseType { val: AmlValue::None, len: 2 + name.len + ddb_handle_object.len }) } else { + log::error!("Loaded table is not for AML"); Err(AmlError::AmlValueError) } } diff --git a/acpid/src/aml/type2opcode.rs b/acpid/src/aml/type2opcode.rs index ec137cdeb3..60d02bb717 100644 --- a/acpid/src/aml/type2opcode.rs +++ b/acpid/src/aml/type2opcode.rs @@ -1346,15 +1346,15 @@ fn parse_def_load_table(data: &[u8], let parameter_data = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len + root_path.len + parameter_path.len..], ctx)?; let signature = { - <[u8; 4]>::try_from(&*signature.val.get_as_buffer(ctx.acpi_context())?) + <[u8; 4]>::try_from(&*signature.val.get_as_string(ctx.acpi_context())?.as_bytes()) .expect("expected 'load table' def to have a signature that is 4 bytes long") }; let oem_id = { - <[u8; 6]>::try_from(&*oem_id.val.get_as_buffer(ctx.acpi_context())?) + <[u8; 6]>::try_from(&*oem_id.val.get_as_string(ctx.acpi_context())?.as_bytes()) .expect("expected 'load table' def to have an OEM ID that is 6 bytes long") }; let oem_table_id = { - <[u8; 8]>::try_from(&*oem_table_id.val.get_as_buffer(ctx.acpi_context())?) + <[u8; 8]>::try_from(&*oem_table_id.val.get_as_string(ctx.acpi_context())?.as_bytes()) .expect("expected 'load table' def to have an OEM table ID that is 8 bytes long") }; @@ -1594,7 +1594,7 @@ fn parse_def_mid(data: &[u8], let mut res = s.clone().split_off(idx); if len < res.len() { - res.split_off(len); + res.truncate(len); } AmlValue::String(res) diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index 2587a1c949..3aeafc41ec 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -62,7 +62,7 @@ fn parse_hex_digit(hex: u8) -> Option { let hex = hex.to_ascii_lowercase(); if hex >= b'a' && hex <= b'f' { - Some(hex - b'a') + Some(hex - b'a' + 10) } else if hex >= b'0' && hex <= b'9' { Some(hex - b'0') } else { @@ -71,7 +71,7 @@ fn parse_hex_digit(hex: u8) -> Option { } fn parse_hex_2digit(hex: &[u8]) -> Option { - parse_hex_digit(hex[0]).and_then(|least_significant| Some(least_significant | (parse_hex_digit(hex[1])? << 4))) + parse_hex_digit(hex[0]).and_then(|most_significant| Some((most_significant << 4) | parse_hex_digit(hex[1])?)) } fn parse_oem_id(hex: [u8; 12]) -> Option<[u8; 6]> { @@ -99,7 +99,7 @@ fn parse_oem_table_id(hex: [u8; 16]) -> Option<[u8; 8]> { fn parse_table(table: &[u8]) -> Option { let signature_part = table.get(..4)?; - let first_hyphen = table.get(5)?; + let first_hyphen = table.get(4)?; let oem_id_part = table.get(5..17)?; let second_hyphen = table.get(17)?; let oem_table_part = table.get(18..34)?; @@ -111,7 +111,7 @@ fn parse_table(table: &[u8]) -> Option { return None; } - if table.len() > 20 { + if table.len() > 34 { return None; } @@ -139,7 +139,7 @@ impl SchemeMut for AcpiScheme<'_> { let components = path.split('/').collect::>(); let kind = match &*components { - [] => HandleKind::TopLevel, + [""] => HandleKind::TopLevel, ["tables"] => HandleKind::Tables, ["tables", table] => { @@ -152,7 +152,7 @@ impl SchemeMut for AcpiScheme<'_> { if kind.is_dir() && !flag_dir && !flag_stat { return Err(Error::new(EISDIR)); - } else if flag_dir && !flag_stat { + } else if !kind.is_dir() && flag_dir && !flag_stat { return Err(Error::new(ENOTDIR)); } @@ -191,6 +191,10 @@ impl SchemeMut for AcpiScheme<'_> { fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + if handle.stat { + return Err(Error::new(EBADF)); + } + let file_len = handle.kind.len(self.ctx)?; let new_offset = match whence { @@ -215,6 +219,10 @@ impl SchemeMut for AcpiScheme<'_> { fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + if handle.stat { + return Err(Error::new(EBADF)); + } + let src_buf = match handle.kind { HandleKind::TopLevel => TOPLEVEL_CONTENTS, HandleKind::Table(ref signature) => self.ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.as_slice(), @@ -223,14 +231,14 @@ impl SchemeMut for AcpiScheme<'_> { use std::io::prelude::*; let tables_to_skip = handle.offset / TABLE_DENTRY_LENGTH; - let tables_to_fill = (buf.len() + TABLE_DENTRY_LENGTH - 1) / TABLE_DENTRY_LENGTH; + let max_tables_to_fill = (buf.len() + TABLE_DENTRY_LENGTH - 1) / TABLE_DENTRY_LENGTH; - let bytes_to_skip = handle.offset % TABLE_DENTRY_LENGTH; + let mut bytes_to_skip = handle.offset % TABLE_DENTRY_LENGTH; let mut src_buf = [0_u8; TABLE_DENTRY_LENGTH]; let mut bytes_written = 0; - for table in self.ctx.tables().iter().skip(tables_to_skip).take(tables_to_fill) { + for table in self.ctx.tables().iter().skip(tables_to_skip).take(max_tables_to_fill) { let mut cursor = std::io::Cursor::new(&mut src_buf[..]); cursor.write_all(&table.signature).unwrap(); cursor.write_all(&[b'-']).unwrap(); @@ -242,12 +250,14 @@ impl SchemeMut for AcpiScheme<'_> { for byte in table.oem_table_id.iter() { write!(cursor, "{:>02X}", byte).unwrap(); } + cursor.write_all(&[b'\n']).unwrap(); let src_buf = &src_buf[bytes_to_skip..]; let dst_buf = &mut buf[bytes_written..]; let to_copy = std::cmp::min(src_buf.len(), dst_buf.len()); dst_buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); bytes_written += to_copy; + bytes_to_skip = 0; } handle.offset = handle.offset.checked_add(bytes_written).ok_or(Error::new(EOVERFLOW))?; From 3989477669b025cb989977c4d167f14c5fd19df8 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 11 Mar 2021 17:50:17 +0100 Subject: [PATCH 0447/1301] Also open a file descriptor in `debug:`. This is to allow the shutdown logs to reach serial output before the system shuts down, which is especially useful on QEMU. --- acpid/src/acpi.rs | 2 ++ acpid/src/aml/namespace.rs | 3 +++ acpid/src/main.rs | 8 ++++++++ 3 files changed, 13 insertions(+) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 4d08cfe919..7e24025997 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -393,6 +393,7 @@ pub struct FadtAcpi2Struct { } unsafe impl plain::Plain for FadtAcpi2Struct {} +#[derive(Clone)] pub struct Fadt(Sdt); impl Fadt { @@ -456,6 +457,7 @@ impl Fadt { } }; + context.fadt = Some(fadt.clone()); context.dsdt = Some(Dsdt(dsdt_sdt.clone())); context.tables.push(dsdt_sdt); diff --git a/acpid/src/aml/namespace.rs b/acpid/src/aml/namespace.rs index 600a253a56..4dfd18516f 100644 --- a/acpid/src/aml/namespace.rs +++ b/acpid/src/aml/namespace.rs @@ -129,7 +129,10 @@ pub enum AmlValue { String(String), PowerResource(PowerResource), Processor(Processor), + + #[allow(dead_code)] RawDataBuffer(Vec), + ThermalZone(ThermalZone) } diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 83ea52b090..bc1e10afc5 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -36,6 +36,7 @@ fn monotonic() -> (u64, u64) { fn setup_logging() -> Option<&'static RedoxLogger> { use redox_log::OutputBuilder; + #[allow(unused_mut)] let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() @@ -45,6 +46,12 @@ fn setup_logging() -> Option<&'static RedoxLogger> { .build() ); + #[cfg(target_os = "redox")] + match File::open("debug:") { + Ok(d) => logger = logger.with_output(OutputBuilder::with_endpoint(d).flush_on_newline(true).with_filter(log::LevelFilter::Info).build()), + Err(error) => eprintln!("Failed to open `debug:` scheme: {}", error), + } + #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.log") { Ok(b) => logger = logger.with_output( @@ -231,6 +238,7 @@ fn main() { let _ = event_queue.read(&mut event).expect("acpid: failed to read from event queue"); if event.flags.contains(EventFlags::EVENT_READ) && event.id == shutdown_pipe.as_raw_fd() as usize { + log::info!("Received shutdown request from kernel."); break 'events; } if !event.flags.contains(EventFlags::EVENT_READ) || event.id != scheme_socket.as_raw_fd() as usize { From 391f7c41844f944cd3d009b4f592b6a0f3f80edc Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 12 Mar 2021 23:45:16 +0100 Subject: [PATCH 0448/1301] WIP: Improve acpid logging. --- acpid/src/acpi.rs | 16 ++++++++++------ acpid/src/aml/parser.rs | 4 ++-- acpid/src/main.rs | 5 +++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 7e24025997..5b1c24c52b 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,4 +1,4 @@ -use std::collections::{BTreeMap, HashMap}; +use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::ops::Deref; use std::sync::{Arc, atomic::{self, AtomicUsize}}; @@ -217,7 +217,7 @@ pub struct AcpiContext { // TODO: Remove Option. This is not kernel code, and not static, but we still need to replace // every match where namespace{,_mut}() are used. - namespace: RwLock>>, + namespace: RwLock>>, // TODO: The kernel ACPI code seemed to use load_table quite ubiquitously, however ACPI 5.1 // states that DDBHandles can only be obtained when loading XSDT-pointed tables. So, we'll @@ -234,7 +234,7 @@ impl AcpiContext { .try_into() .expect("expected ACPI addresses to be compatible with the current word size"); - log::info!("TABLE AT {:#>08X}", physaddr); + log::debug!("TABLE AT {:#>08X}", physaddr); Sdt::load_from_physical(physaddr) .expect("failed to load physical SDT") @@ -244,7 +244,7 @@ impl AcpiContext { tables, dsdt: None, fadt: None, - namespace: RwLock::new(Some(HashMap::new())), + namespace: RwLock::new(Some(BTreeMap::new())), next_ctx: RwLock::new(0), sdt_order: RwLock::new(Vec::new()), @@ -258,6 +258,10 @@ impl AcpiContext { crate::aml::init_namespace(&this); + for (path, _) in this.namespace.get_mut().as_mut().unwrap().iter() { + log::trace!("ACPI NS: {}", path); + } + this } @@ -282,10 +286,10 @@ impl AcpiContext { pub fn take_single_sdt(&mut self, signature: [u8; 4]) -> Option { self.find_single_sdt_pos(signature).map(|pos| self.tables[pos].clone()) } - pub fn namespace(&self) -> RwLockReadGuard<'_, Option>> { + pub fn namespace(&self) -> RwLockReadGuard<'_, Option>> { self.namespace.read() } - pub fn namespace_mut(&self) -> RwLockWriteGuard<'_, Option>> { + pub fn namespace_mut(&self) -> RwLockWriteGuard<'_, Option>> { self.namespace.write() } pub fn fadt(&self) -> Option<&Fadt> { diff --git a/acpid/src/aml/parser.rs b/acpid/src/aml/parser.rs index 704aee5d8c..3902453ebe 100644 --- a/acpid/src/aml/parser.rs +++ b/acpid/src/aml/parser.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::BTreeMap; use parking_lot::RwLockWriteGuard; @@ -292,7 +292,7 @@ impl<'a> AmlExecutionContext<'a> { } } - pub fn prelock<'ctx>(&mut self, ctx: &'ctx AcpiContext) -> RwLockWriteGuard<'ctx, Option>> { + pub fn prelock<'ctx>(&mut self, ctx: &'ctx AcpiContext) -> RwLockWriteGuard<'ctx, Option>> { ctx.namespace_mut() } diff --git a/acpid/src/main.rs b/acpid/src/main.rs index bc1e10afc5..f353f081a1 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -40,7 +40,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Trace) // limit global output to important info + .with_filter(log::LevelFilter::Info) // limit global output to important info .with_ansi_escape_codes() .flush_on_newline(true) .build() @@ -48,7 +48,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { #[cfg(target_os = "redox")] match File::open("debug:") { - Ok(d) => logger = logger.with_output(OutputBuilder::with_endpoint(d).flush_on_newline(true).with_filter(log::LevelFilter::Info).build()), + Ok(d) => logger = logger.with_output(OutputBuilder::with_endpoint(d).flush_on_newline(true).with_ansi_escape_codes().with_filter(log::LevelFilter::Info).build()), Err(error) => eprintln!("Failed to open `debug:` scheme: {}", error), } @@ -58,6 +58,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { // TODO: Add a configuration file for this b.with_filter(log::LevelFilter::Trace) .flush_on_newline(true) + .with_ansi_escape_codes() .build() ), Err(error) => eprintln!("Failed to create xhci.log: {}", error), From c6efa649be0329047976a775d2c49a127b287ac3 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 13 Mar 2021 12:34:56 +0100 Subject: [PATCH 0449/1301] Add DMAR parsing. In the future, this will probably be moved into its own driver, probably called `intelvtdd` or `intelvfiod`. This is because `acpid` already provides an interface to read from ACPI tables, which `pcid` has used for quite long (when that scheme was provided by the kernel). AMD implements IOMMU as a PCI function, so letting these be separate drivers would certainly be beneficial. The same thing might apply for HPET or MADT, which are the only ACPI tables still parsed in the kernel. --- Cargo.lock | 13 + acpid/Cargo.toml | 2 + acpid/src/acpi.rs | 8 +- acpid/src/acpi/dmar/drhd.rs | 119 +++++++++ acpid/src/acpi/dmar/mod.rs | 520 ++++++++++++++++++++++++++++++++++++ 5 files changed, 660 insertions(+), 2 deletions(-) create mode 100644 acpid/src/acpi/dmar/drhd.rs create mode 100644 acpid/src/acpi/dmar/mod.rs diff --git a/Cargo.lock b/Cargo.lock index ec0ff080d9..e973ca2001 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,8 @@ name = "acpid" version = "0.1.0" dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox-log 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -619,6 +621,16 @@ dependencies = [ "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-integer" version = "0.1.43" @@ -1628,6 +1640,7 @@ dependencies = [ "checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)" = "" "checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" +"checksum num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" "checksum num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" "checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" "checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 3b990a92cf..dc52205604 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -8,6 +8,8 @@ edition = "2018" [dependencies] log = "0.4" +num-derive = "0.3" +num-traits = "0.2" parking_lot = "0.11.1" plain = "0.2.3" redox-log = "0.1.1" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 5b1c24c52b..d2cdd9c295 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::ops::Deref; -use std::sync::{Arc, atomic::{self, AtomicUsize}}; +use std::sync::Arc; use std::{fmt, mem}; use syscall::flag::PhysmapFlags; @@ -11,6 +11,9 @@ use thiserror::Error; use super::aml::AmlValue; +pub mod dmar; +use self::dmar::Dmar; + #[cfg(target_arch = "x86_64")] pub const PAGE_SIZE: usize = 4096; @@ -255,6 +258,7 @@ impl AcpiContext { } Fadt::init(&mut this); + Dmar::init(&this); crate::aml::init_namespace(&this); @@ -283,7 +287,7 @@ impl AcpiContext { pub fn find_multiple_sdts<'a>(&'a self, signature: [u8; 4]) -> impl Iterator { self.tables.iter().filter(move |sdt| sdt.signature == signature) } - pub fn take_single_sdt(&mut self, signature: [u8; 4]) -> Option { + pub fn take_single_sdt(&self, signature: [u8; 4]) -> Option { self.find_single_sdt_pos(signature).map(|pos| self.tables[pos].clone()) } pub fn namespace(&self) -> RwLockReadGuard<'_, Option>> { diff --git a/acpid/src/acpi/dmar/drhd.rs b/acpid/src/acpi/dmar/drhd.rs new file mode 100644 index 0000000000..ee6254f636 --- /dev/null +++ b/acpid/src/acpi/dmar/drhd.rs @@ -0,0 +1,119 @@ +use std::ops::{Deref, DerefMut}; + +use syscall::io::Mmio; + +// TODO: Only wrap with Mmio where there are hardware-registers. (Some of these structs seem to be +// ring buffer entries, which are not to be treated the same way). + +pub struct DrhdPage { + virt: *mut Drhd, +} +impl DrhdPage { + pub fn map(base_phys: usize) -> syscall::Result { + assert_eq!(base_phys % crate::acpi::PAGE_SIZE, 0, "DRHD registers must be page-aligned"); + + // TODO: Uncachable? Can reads have side-effects? + let virt = unsafe { + syscall::physmap(base_phys, crate::acpi::PAGE_SIZE, syscall::PhysmapFlags::PHYSMAP_WRITE)? + } as *mut Drhd; + + Ok(Self { virt }) + } +} +impl Deref for DrhdPage { + type Target = Drhd; + + fn deref(&self) -> &Self::Target { + unsafe { &*self.virt } + } +} +impl DerefMut for DrhdPage { + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { &mut *self.virt } + } +} +impl Drop for DrhdPage { + fn drop(&mut self) { + unsafe { + let _ = syscall::physunmap(self.virt as usize); + } + } +} + +#[repr(packed)] +pub struct DrhdFault { + pub sts: Mmio, + pub ctrl: Mmio, + pub data: Mmio, + pub addr: [Mmio; 2], + _rsv: [Mmio; 2], + pub log: Mmio, +} + +#[repr(packed)] +pub struct DrhdProtectedMemory { + pub en: Mmio, + pub low_base: Mmio, + pub low_limit: Mmio, + pub high_base: Mmio, + pub high_limit: Mmio, +} + +#[repr(packed)] +pub struct DrhdInvalidation { + pub queue_head: Mmio, + pub queue_tail: Mmio, + pub queue_addr: Mmio, + _rsv: Mmio, + pub cmpl_sts: Mmio, + pub cmpl_ctrl: Mmio, + pub cmpl_data: Mmio, + pub cmpl_addr: [Mmio; 2], +} + +#[repr(packed)] +pub struct DrhdPageRequest { + pub queue_head: Mmio, + pub queue_tail: Mmio, + pub queue_addr: Mmio, + _rsv: Mmio, + pub sts: Mmio, + pub ctrl: Mmio, + pub data: Mmio, + pub addr: [Mmio; 2], +} + +#[repr(packed)] +pub struct DrhdMtrrVariable { + pub base: Mmio, + pub mask: Mmio, +} + +#[repr(packed)] +pub struct DrhdMtrr { + pub cap: Mmio, + pub def_type: Mmio, + pub fixed: [Mmio; 11], + pub variable: [DrhdMtrrVariable; 10], +} + +#[repr(packed)] +pub struct Drhd { + pub version: Mmio, + _rsv: Mmio, + pub cap: Mmio, + pub ext_cap: Mmio, + pub gl_cmd: Mmio, + pub gl_sts: Mmio, + pub root_table: Mmio, + pub ctx_cmd: Mmio, + _rsv1: Mmio, + pub fault: DrhdFault, + _rsv2: Mmio, + pub pm: DrhdProtectedMemory, + pub invl: DrhdInvalidation, + _rsv3: Mmio, + pub intr_table: Mmio, + pub page_req: DrhdPageRequest, + pub mtrr: DrhdMtrr, +} diff --git a/acpid/src/acpi/dmar/mod.rs b/acpid/src/acpi/dmar/mod.rs new file mode 100644 index 0000000000..6d59c25e99 --- /dev/null +++ b/acpid/src/acpi/dmar/mod.rs @@ -0,0 +1,520 @@ +//! DMA Remapping Table -- `DMAR`. This is Intel's implementation of IOMMU functionality, known as +//! VT-d. +//! +//! Too understand what all of these structs mean, refer to the "Intel(R) Virtualization +//! Technology for Directed I/O" specification. + +// TODO: Move this code to a separate driver as well? + +use std::convert::TryFrom; +use std::ops::Deref; +use std::{fmt, mem}; + +use syscall::io::Io as _; + +use num_derive::FromPrimitive; +use num_traits::FromPrimitive; + +use self::drhd::DrhdPage; +use crate::acpi::{AcpiContext, Sdt, SdtHeader}; + +pub mod drhd; + +#[repr(packed)] +pub struct DmarStruct { + pub sdt_header: SdtHeader, + pub host_addr_width: u8, + pub flags: u8, + pub _rsvd: [u8; 10], + + // This header is followed by N remapping structures. +} +unsafe impl plain::Plain for DmarStruct {} + +/// The DMA Remapping Table +#[derive(Debug)] +pub struct Dmar(Sdt); + +impl Dmar { + fn remmapping_structs_area(&self) -> &[u8] { + &self.0.as_slice()[mem::size_of::()..] + } +} + +impl Deref for Dmar { + type Target = DmarStruct; + + fn deref(&self) -> &Self::Target { + plain::from_bytes(self.0.as_slice()) + .expect("expected Dmar struct to already have checked the length, and alignment issues should be impossible due to #[repr(packed)]") + } +} + +impl Dmar { + // TODO: Again, perhaps put this code into a different driver, and read the table the regular + // way via the acpi scheme? + pub fn init(acpi_ctx: &AcpiContext) { + let dmar_sdt = match acpi_ctx.take_single_sdt(*b"DMAR") { + Some(dmar_sdt) => dmar_sdt, + None => { + log::warn!("Unable to find `DMAR` ACPI table."); + return; + } + }; + let dmar = match Dmar::new(dmar_sdt) { + Some(dmar) => dmar, + None => { + log::error!("Failed to parse DMAR table, possibly malformed."); + return; + } + }; + + log::info!("Found DMAR: {}: {}", dmar.host_addr_width, dmar.flags); + log::debug!("DMAR: {:?}", dmar); + + for dmar_entry in dmar.iter() { + log::debug!("DMAR entry: {:?}", dmar_entry); + match dmar_entry { + DmarEntry::Drhd(dmar_drhd) => { + let drhd = dmar_drhd.map(); + + log::debug!("VER: {:X}", drhd.version.read()); + log::debug!("CAP: {:X}", drhd.cap.read()); + log::debug!("EXT_CAP: {:X}", drhd.ext_cap.read()); + log::debug!("GCMD: {:X}", drhd.gl_cmd.read()); + log::debug!("GSTS: {:X}", drhd.gl_sts.read()); + log::debug!("RT: {:X}", drhd.root_table.read()); + }, + _ => () + } + } + } + + fn new(sdt: Sdt) -> Option { + assert_eq!(sdt.signature, *b"DMAR", "signature already checked against `DMAR`"); + if sdt.length() < mem::size_of::() { + log::error!("The DMAR table was too small ({} B < {} B).", sdt.length(), mem::size_of::()); + return None; + } + // No need to check alignment for #[repr(packed)] structs. + + Some(Dmar(sdt)) + } + + pub fn iter(&self) -> DmarIter<'_> { + DmarIter(DmarRawIter { bytes: self.remmapping_structs_area() }) + } +} + +/// DMAR DMA Remapping Hardware Unit Definition +#[derive(Clone, Copy, Debug)] +#[repr(packed)] +pub struct DmarDrhdHeader { + pub kind: u16, + pub length: u16, + + pub flags: u8, + pub _rsv: u8, + pub segment: u16, + pub base: u64, +} +unsafe impl plain::Plain for DmarDrhdHeader {} + +#[derive(Clone, Copy, Debug)] +#[repr(packed)] +pub struct DeviceScopeHeader { + pub ty: u8, + pub len: u8, + pub _rsvd: u16, + pub enumeration_id: u8, + pub start_bus_num: u8, + + // The variable-sized path comes after. +} +unsafe impl plain::Plain for DeviceScopeHeader {} + +pub struct DeviceScope(Box<[u8]>); + +impl DeviceScope { + pub fn try_new(raw: &[u8]) -> Option { + // TODO: Check ty. + + let header_bytes = match raw.get(..mem::size_of::()) { + Some(bytes) => bytes, + None => return None, + }; + let header = plain::from_bytes::(header_bytes) + .expect("length already checked, and alignment 1 (#[repr(packed)] should suffice"); + + let len = usize::from(header.len); + + if len > raw.len() { + log::warn!("Device scope smaller than len field."); + return None; + } + + Some(Self(raw.into())) + } +} + +impl fmt::Debug for DeviceScope { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DeviceScope") + .field("header", &*self as &DeviceScopeHeader) + .field("path", &self.path()) + .finish() + } +} + +impl Deref for DeviceScope { + type Target = DeviceScopeHeader; + + fn deref(&self) -> &Self::Target { + plain::from_bytes(&self.0) + .expect("expected length to be sufficient, and alignment (due to #[repr(packed)]") + } +} +impl DeviceScope { + pub fn path(&self) -> &[u8] { + &self.0[mem::size_of::()..] + } +} + +pub struct DmarDrhd(Box<[u8]>); + +impl DmarDrhd { + pub fn try_new(raw: &[u8]) -> Option { + if raw.len() < mem::size_of::() { + return None; + } + + Some(Self(raw.into())) + } + pub fn device_scope_area(&self) -> &[u8] { + &self.0[mem::size_of::()..] + } + pub fn map(&self) -> DrhdPage { + let base = usize::try_from(self.base).expect("expected u64 to fit within usize"); + + DrhdPage::map(base) + .expect("failed to map DRHD registers") + } +} +impl Deref for DmarDrhd { + type Target = DmarDrhdHeader; + + fn deref(&self) -> &Self::Target { + plain::from_bytes::(&self.0[..mem::size_of::()]) + .expect("length is already checked, and alignment 1 (#[repr(packed)] should suffice") + } +} +impl fmt::Debug for DmarDrhd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DmarDrhd") + .field("header", &*self as &DmarDrhd) + // TODO: print out device scopes + .finish() + } +} + +/// DMAR Reserved Memory Region Reporting +#[derive(Clone, Copy, Debug)] +#[repr(packed)] +pub struct DmarRmrrHeader { + pub kind: u16, + pub length: u16, + pub _rsv: u16, + pub segment: u16, + pub base: u64, + pub limit: u64, + + // The device scopes come after. +} +unsafe impl plain::Plain for DmarRmrrHeader {} + +pub struct DmarRmrr(Box<[u8]>); + +impl DmarRmrr { + pub fn try_new(raw: &[u8]) -> Option { + if raw.len() < mem::size_of::() { + return None; + } + + Some(Self(raw.into())) + } +} +impl Deref for DmarRmrr { + type Target = DmarRmrrHeader; + + fn deref(&self) -> &Self::Target { + plain::from_bytes(&self.0[..mem::size_of::()]) + .expect("length already checked, and with #[repr(packed)] alignment should be okay") + } +} +impl fmt::Debug for DmarRmrr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DmarRmrr") + .field("header", &*self as &DmarRmrrHeader) + // TODO: print out device scopes + .finish() + } +} + +/// DMAR Root Port ATS Capability Reporting +#[derive(Clone, Copy, Debug)] +#[repr(packed)] +pub struct DmarAtsrHeader { + kind: u16, + length: u16, + flags: u8, + _rsv: u8, + segment: u16, + + // The device scopes come after. +} +unsafe impl plain::Plain for DmarAtsrHeader {} + +pub struct DmarAtsr(Box<[u8]>); + +impl DmarAtsr { + pub fn try_new(raw: &[u8]) -> Option { + if raw.len() < mem::size_of::() { + return None; + } + + Some(Self(raw.into())) + } +} +impl Deref for DmarAtsr { + type Target = DmarAtsrHeader; + + fn deref(&self) -> &Self::Target { + plain::from_bytes(&self.0[..mem::size_of::()]) + .expect("length already checked, and with #[repr(packed)] alignment should be okay") + } +} +impl fmt::Debug for DmarAtsr { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DmarAtsr") + .field("header", &*self as &DmarAtsrHeader) + // TODO: print out device scopes + .finish() + } +} + +/// DMAR Remapping Hardware Static Affinity +#[derive(Clone, Copy, Debug)] +#[repr(packed)] +pub struct DmarRhsa { + pub kind: u16, + pub length: u16, + + pub _rsv: u32, + pub base: u64, + pub domain: u32, +} +unsafe impl plain::Plain for DmarRhsa {} +impl DmarRhsa { + pub fn try_new(raw: &[u8]) -> Option { + let bytes = raw.get(..mem::size_of::())?; + + let this = plain::from_bytes(bytes) + .expect("length is already checked, and alignment 1 should suffice (#[repr(packed)])"); + + Some(*this) + } +} + +/// DMAR ACPI Name-space Device Declaration +#[derive(Clone, Copy, Debug)] +#[repr(packed)] +pub struct DmarAnddHeader { + pub kind: u16, + pub length: u16, + + pub _rsv: [u8; 3], + pub acpi_dev: u8, + + // The device scopes come after. +} +unsafe impl plain::Plain for DmarAnddHeader {} + +pub struct DmarAndd(Box<[u8]>); + +impl DmarAndd { + pub fn try_new(raw: &[u8]) -> Option { + if raw.len() < mem::size_of::() { + return None; + } + + Some(Self(raw.into())) + } +} +impl Deref for DmarAndd { + type Target = DmarAnddHeader; + + fn deref(&self) -> &Self::Target { + plain::from_bytes(&self.0[..mem::size_of::()]) + .expect("length already checked, and with #[repr(packed)] alignment should be okay") + } +} +impl fmt::Debug for DmarAndd { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DmarAndd") + .field("header", &*self as &DmarAnddHeader) + // TODO: print out device scopes + .finish() + } +} + +/// DMAR ACPI Name-space Device Declaration +#[derive(Clone, Copy, Debug)] +#[repr(packed)] +pub struct DmarSatcHeader { + pub kind: u16, + pub length: u16, + + pub flags: u8, + pub _rsvd: u8, + pub seg_num: u16, + + // The device scopes come after. +} +unsafe impl plain::Plain for DmarSatcHeader {} + +pub struct DmarSatc(Box<[u8]>); + +impl DmarSatc { + pub fn try_new(raw: &[u8]) -> Option { + if raw.len() < mem::size_of::() { + return None; + } + + Some(Self(raw.into())) + } +} + +impl Deref for DmarSatc { + type Target = DmarSatcHeader; + + fn deref(&self) -> &Self::Target { + plain::from_bytes(&self.0[..mem::size_of::()]) + .expect("length already checked, and with #[repr(packed)] alignment should be okay") + } +} +impl fmt::Debug for DmarSatc { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("DmarSatc") + .field("header", &*self as &DmarSatcHeader) + // TODO: print out device scopes + .finish() + } +} + +/// The list of different "Remapping Structure Types". +/// +/// Refer to section 8.2 in the VTIO spec (as of revision 3.2). +#[derive(Clone, Copy, Debug, FromPrimitive)] +#[repr(u16)] +pub enum EntryType { + Drhd = 0, + Rmrr = 1, + Atsr = 2, + Rhsa = 3, + Andd = 4, + Satc = 5, +} + +/// DMAR Entries +#[derive(Debug)] +pub enum DmarEntry { + Drhd(DmarDrhd), + Rmrr(DmarRmrr), + Atsr(DmarAtsr), + Rhsa(DmarRhsa), + Andd(DmarAndd), + + // TODO: "SoC Integrated Address Translation Cache Reporting Structure". + Satc(DmarSatc), + + TooShort(EntryType), + Unknown(u16), +} + +struct DmarRawIter<'sdt> { + bytes: &'sdt [u8], +} + +impl<'sdt> Iterator for DmarRawIter<'sdt> { + type Item = (u16, &'sdt [u8]); + + fn next(&mut self) -> Option { + let type_bytes = match self.bytes.get(..2) { + Some(bytes) => bytes, + None => { + if !self.bytes.is_empty() { + log::warn!("DMAR table ended between two entries."); + } + return None; + } + }; + let len_bytes = match self.bytes.get(2..4) { + Some(bytes) => bytes, + None => { + log::warn!("DMAR table ended between two entries."); + return None; + } + }; + let remainder = &self.bytes[4..]; + + let type_bytes = <[u8; 2]>::try_from(type_bytes).expect("expected a 2-byte slice to be convertible to [u8; 2]"); + let len_bytes = <[u8; 2]>::try_from(type_bytes).expect("expected a 2-byte slice to be convertible to [u8; 2]"); + + let ty = u16::from_ne_bytes(type_bytes); + let len = u16::from_ne_bytes(len_bytes); + + let len = usize::try_from(len).expect("expected u16 to fit within usize"); + + if len > remainder.len() { + log::warn!("DMAR remapping structure length was smaller than the remaining length of the table."); + return None; + } + + let (current, residue) = self.bytes.split_at(len); + self.bytes = residue; + + Some((ty, current)) + } +} + +pub struct DmarIter<'sdt>(DmarRawIter<'sdt>); + +impl Iterator for DmarIter<'_> { + type Item = DmarEntry; + fn next(&mut self) -> Option { + let (raw_type, raw) = self.0.next()?; + + // NOTE: If any of these entries look incorrect, we should simply continue the iterator, + // and instead print a warning. + + let entry_type = match EntryType::from_u16(raw_type) { + Some(ty) => ty, + None => { + log::warn!("Encountered invalid entry type {} (length {})", raw_type, raw.len()); + return Some(DmarEntry::Unknown(raw_type)); + } + }; + + let item_opt = match entry_type { + EntryType::Drhd => DmarDrhd::try_new(raw).map(DmarEntry::Drhd), + EntryType::Rmrr => DmarRmrr::try_new(raw).map(DmarEntry::Rmrr), + EntryType::Atsr => DmarAtsr::try_new(raw).map(DmarEntry::Atsr), + EntryType::Rhsa => DmarRhsa::try_new(raw).map(DmarEntry::Rhsa), + EntryType::Andd => DmarAndd::try_new(raw).map(DmarEntry::Andd), + EntryType::Satc => DmarSatc::try_new(raw).map(DmarEntry::Satc), + }; + let item = item_opt.unwrap_or(DmarEntry::TooShort(entry_type)); + + Some(item) + } +} From 641feb01b1b0f6376c06aa3eb4454231dcf891e1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 13 Mar 2021 12:40:26 +0100 Subject: [PATCH 0450/1301] Print parsed tables only with debug verbosity. --- acpid/src/acpi.rs | 2 +- acpid/src/aml/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index d2cdd9c295..f798567873 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -455,7 +455,7 @@ impl Fadt { .expect("expected any given u32 to fit within usize") }; - log::info!(" FACP: {:X}", {dsdt_ptr}); + log::debug!("FACP at {:X}", {dsdt_ptr}); let dsdt_sdt = match Sdt::load_from_physical(fadt.dsdt as usize) { Ok(dsdt) => dsdt, diff --git a/acpid/src/aml/mod.rs b/acpid/src/aml/mod.rs index b48797e493..91d90be619 100644 --- a/acpid/src/aml/mod.rs +++ b/acpid/src/aml/mod.rs @@ -51,7 +51,7 @@ pub fn parse_aml_with_scope(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable fn init_aml_table(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable) { match parse_aml_table(acpi_ctx, &sdt) { - Ok(_) => log::info!("Table {} parsed successfully", sdt.header().signature()), + Ok(_) => log::debug!("Table {} parsed successfully", sdt.header().signature()), Err(AmlError::AmlParseError(e)) => log::error!("Table {} got parse error: {}", sdt.header().signature(), e), Err(AmlError::AmlInvalidOpCode) => log::error!("Table {} got invalid opcode", sdt.header().signature()), Err(AmlError::AmlValueError) => log::error!("For table {}: type constraints or value bounds not met", sdt.header().signature()), @@ -69,7 +69,7 @@ fn init_aml_table(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable) { pub fn init_namespace(context: &AcpiContext) { let dsdt = context.dsdt().expect("could not find any DSDT"); - log::info!("Found DSDT."); + log::debug!("Found DSDT."); init_aml_table(context, dsdt); let ssdts = context.ssdts(); From 5a279d40812f5cdbd25c017af20b1d37fcb17a5e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 1 Jun 2021 21:37:52 -0600 Subject: [PATCH 0451/1301] Use redox-log in ahcid --- Cargo.lock | 2 + ahcid/Cargo.toml | 2 + ahcid/src/ahci/hba.rs | 17 +-- ahcid/src/ahci/mod.rs | 7 +- ahcid/src/main.rs | 236 +++++++++++++++++++++++++----------------- 5 files changed, 160 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e973ca2001..10b62efca9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,7 +26,9 @@ dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "block-io-wrapper 0.1.0", "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", + "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index 458d8cac56..bddad85151 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -6,6 +6,8 @@ edition = "2018" [dependencies] bitflags = "1.2" byteorder = "1.2" +log = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } redox_syscall = "0.1" block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 6fb268bc8b..b4f416d8ed 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -1,3 +1,4 @@ +use log::{error, info, trace}; use std::mem::size_of; use std::ops::DerefMut; use std::{ptr, u32}; @@ -127,7 +128,7 @@ impl HbaPort { // Power on and spin up device self.cmd.writef(1 << 2 | 1 << 1, true); - print!("{}", format!(" - AHCI init {:X}\n", self.cmd.read())); + info!(" - AHCI init {:X}", self.cmd.read()); } pub unsafe fn identify(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { @@ -208,8 +209,8 @@ impl HbaPort { 48 }; - print!("{}", format!(" + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB\n", - serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048)); + info!(" + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", + serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048); Some(sectors * 512) } else { @@ -218,7 +219,7 @@ impl HbaPort { } pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Option { - // print!("{}", format!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}\n", (self as *mut HbaPort) as usize, block, sectors, write)); + trace!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}", (self as *mut HbaPort) as usize, block, sectors, write); assert!(sectors > 0 && sectors < 256); @@ -331,10 +332,10 @@ impl HbaPort { self.stop(); if self.is.read() & HBA_PORT_IS_ERR != 0 { - print!("{}", format!("ERROR IS {:X} IE {:X} CMD {:X} TFD {:X}\nSSTS {:X} SCTL {:X} SERR {:X} SACT {:X}\nCI {:X} SNTF {:X} FBS {:X}\n", + error!("ERROR IS {:X} IE {:X} CMD {:X} TFD {:X}\nSSTS {:X} SCTL {:X} SERR {:X} SACT {:X}\nCI {:X} SNTF {:X} FBS {:X}", self.is.read(), self.ie.read(), self.cmd.read(), self.tfd.read(), self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(), - self.ci.read(), self.sntf.read(), self.fbs.read())); + self.ci.read(), self.sntf.read(), self.fbs.read()); self.is.write(u32::MAX); Err(Error::new(EIO)) } else { @@ -371,9 +372,9 @@ impl HbaMem { */ self.ghc.write(1 << 31 | 1 << 1); - print!("{}", format!(" - AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}", + info!(" - AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}", self.cap.read(), self.ghc.read(), self.is.read(), self.pi.read(), - self.vs.read(), self.cap2.read(), self.bohc.read())); + self.vs.read(), self.cap2.read(), self.bohc.read()); } } diff --git a/ahcid/src/ahci/mod.rs b/ahcid/src/ahci/mod.rs index b72aa59ac5..2036189d24 100644 --- a/ahcid/src/ahci/mod.rs +++ b/ahcid/src/ahci/mod.rs @@ -1,3 +1,4 @@ +use log::{error, info}; use syscall::io::Io; use syscall::error::Result; @@ -27,14 +28,14 @@ pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec .filter_map(|i| { let port = unsafe { &mut *hba_mem.ports.as_mut_ptr().add(i) }; let port_type = port.probe(); - print!("{}", format!("{}-{}: {:?}\n", name, i, port_type)); + info!("{}-{}: {:?}", name, i, port_type); let disk: Option> = match port_type { HbaPortType::SATA => { match DiskATA::new(i, port) { Ok(disk) => Some(Box::new(disk)), Err(err) => { - print!("{}", format!("{}: {}\n", i, err)); + error!("{}: {}", i, err); None } } @@ -43,7 +44,7 @@ pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec match DiskATAPI::new(i, port) { Ok(disk) => Some(Box::new(disk)), Err(err) => { - print!("{}", format!("{}: {}\n", i, err)); + error!("{}: {}", i, err); None } } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 2b98e6d663..31459c208d 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -3,6 +3,8 @@ extern crate syscall; extern crate byteorder; +use log::{error, info}; +use redox_log::{OutputBuilder, RedoxLogger}; use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write}; @@ -14,6 +16,50 @@ use crate::scheme::DiskScheme; pub mod ahci; pub mod scheme; +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "ahci.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("ahcid: failed to create ahci.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "ahci.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("ahcid: failed to create ahci.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("ahcid: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("ahcid: failed to set default logger: {}", error); + None + } + } +} + fn main() { let mut args = env::args().skip(1); @@ -29,120 +75,124 @@ fn main() { let irq_str = args.next().expect("ahcid: no irq provided"); let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); - print!("{}", format!(" + AHCI {} on: {:X} size: {} IRQ: {}\n", name, bar, bar_size, irq)); - // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { - let address = unsafe { - syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("ahcid: failed to map address") - }; - { - let scheme_name = format!("disk/{}", name); - let socket_fd = syscall::open( - &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK - ).expect("ahcid: failed to create disk scheme"); - let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + if unsafe { syscall::clone(0).unwrap() } != 0 { + return; + } - let irq_fd = syscall::open( - &format!("irq:{}", irq), - syscall::O_RDWR | syscall::O_NONBLOCK - ).expect("ahcid: failed to open irq file"); - let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; + let _logger_ref = setup_logging(); - let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); + info!(" + AHCI {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); - syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace"); + let address = unsafe { + syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("ahcid: failed to map address") + }; + { + let scheme_name = format!("disk/{}", name); + let socket_fd = syscall::open( + &format!(":{}", scheme_name), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK + ).expect("ahcid: failed to create disk scheme"); + let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - event_file.write(&Event { - id: socket_fd, - flags: EVENT_READ, - data: 0 - }).expect("ahcid: failed to event disk scheme"); + let irq_fd = syscall::open( + &format!("irq:{}", irq), + syscall::O_RDWR | syscall::O_NONBLOCK + ).expect("ahcid: failed to open irq file"); + let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; - event_file.write(&Event { - id: irq_fd, - flags: EVENT_READ, - data: 0 - }).expect("ahcid: failed to event irq scheme"); + let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); - let (hba_mem, disks) = ahci::disks(address, &name); - let mut scheme = DiskScheme::new(scheme_name, hba_mem, disks); + syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace"); - let mut mounted = true; - let mut todo = Vec::new(); - while mounted { - let mut event = Event::default(); - if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 { - break; - } - if event.id == socket_fd { - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => { - mounted = false; - break; - }, - Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { - break; - } else { - panic!("ahcid: failed to read disk scheme: {}", err); - } - } + event_file.write(&Event { + id: socket_fd, + flags: EVENT_READ, + data: 0 + }).expect("ahcid: failed to event disk scheme"); - if let Some(a) = scheme.handle(&packet) { - packet.a = a; - socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + event_file.write(&Event { + id: irq_fd, + flags: EVENT_READ, + data: 0 + }).expect("ahcid: failed to event irq scheme"); + + let (hba_mem, disks) = ahci::disks(address, &name); + let mut scheme = DiskScheme::new(scheme_name, hba_mem, disks); + + let mut mounted = true; + let mut todo = Vec::new(); + while mounted { + let mut event = Event::default(); + if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 { + break; + } + if event.id == socket_fd { + loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => { + mounted = false; + break; + }, + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; } else { - todo.push(packet); + panic!("ahcid: failed to read disk scheme: {}", err); } } - } else if event.id == irq_fd { - let mut irq = [0; 8]; - if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() { - if scheme.irq() { - irq_file.write(&irq).expect("ahcid: failed to write irq file"); - // Handle todos in order to finish previous packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(a) = scheme.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); - } else { - i += 1; - } + if let Some(a) = scheme.handle(&packet) { + packet.a = a; + socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + } else { + todo.push(packet); + } + } + } else if event.id == irq_fd { + let mut irq = [0; 8]; + if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() { + if scheme.irq() { + irq_file.write(&irq).expect("ahcid: failed to write irq file"); + + // Handle todos in order to finish previous packets if possible + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + } else { + i += 1; } } } + } + } else { + error!("Unknown event {}", event.id); + } + + // Handle todos to start new packets if possible + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&packet).expect("ahcid: failed to write disk scheme"); } else { - println!("Unknown event {}", event.id); + i += 1; } + } - // Handle todos to start new packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(a) = scheme.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet).expect("ahcid: failed to write disk scheme"); - } else { - i += 1; - } - } - - if ! mounted { - for mut packet in todo.drain(..) { - packet.a = Error::mux(Err(Error::new(ENODEV))); - socket.write(&packet).expect("ahcid: failed to write disk scheme"); - } + if ! mounted { + for mut packet in todo.drain(..) { + packet.a = Error::mux(Err(Error::new(ENODEV))); + socket.write(&packet).expect("ahcid: failed to write disk scheme"); } } } - unsafe { let _ = syscall::physunmap(address); } } + unsafe { let _ = syscall::physunmap(address); } } From 7a2b3d765640a4a24ffb813f4b3f11d9775c4f3c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 17 Jun 2021 18:18:27 +0200 Subject: [PATCH 0452/1301] Update dependencies. --- Cargo.lock | 1487 ++++++++++++++++++---------------- Cargo.toml | 2 +- acpid/Cargo.toml | 2 +- acpid/src/main.rs | 2 - ahcid/Cargo.toml | 4 +- ahcid/src/ahci/disk_ata.rs | 26 +- ahcid/src/ahci/disk_atapi.rs | 36 +- ahcid/src/main.rs | 13 +- ahcid/src/scheme.rs | 14 +- alxd/Cargo.toml | 4 +- alxd/src/device/mod.rs | 37 +- alxd/src/main.rs | 10 +- bgad/Cargo.toml | 2 +- bgad/src/main.rs | 6 +- bgad/src/scheme.rs | 2 +- e1000d/Cargo.toml | 4 +- e1000d/src/device.rs | 35 +- e1000d/src/main.rs | 8 +- ihdad/Cargo.toml | 7 +- ihdad/src/hda/device.rs | 7 +- ihdad/src/main.rs | 10 +- ixgbed/Cargo.toml | 2 +- ixgbed/src/device.rs | 43 +- ixgbed/src/main.rs | 8 +- nvmed/Cargo.toml | 6 +- nvmed/src/scheme.rs | 5 +- pcid/Cargo.toml | 4 +- pcspkrd/Cargo.toml | 2 +- pcspkrd/src/main.rs | 6 +- pcspkrd/src/scheme.rs | 2 +- ps2d/Cargo.toml | 4 +- ps2d/src/controller.rs | 66 +- ps2d/src/main.rs | 5 +- ps2d/src/state.rs | 36 +- rtl8168d/Cargo.toml | 4 +- rtl8168d/src/device.rs | 54 +- rtl8168d/src/main.rs | 8 +- usbscsid/Cargo.toml | 2 +- usbscsid/src/scheme.rs | 5 +- vboxd/Cargo.toml | 2 +- vboxd/src/main.rs | 21 +- vesad/Cargo.toml | 2 +- vesad/src/display.rs | 38 +- xhcid/Cargo.toml | 6 +- xhcid/src/main.rs | 4 +- xhcid/src/xhci/scheme.rs | 5 +- 46 files changed, 1059 insertions(+), 999 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 10b62efca9..c9d724edf6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,58 +4,61 @@ name = "acpid" version = "0.1.0" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox-log 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "num-derive", + "num-traits", + "parking_lot 0.11.1", + "plain", + "redox-log", + "redox_syscall", + "thiserror", ] [[package]] name = "adler" -version = "0.2.3" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahcid" version = "0.1.0" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "block-io-wrapper 0.1.0", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", - "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "block-io-wrapper", + "byteorder 1.4.3", + "log", + "partitionlib", + "redox-log", + "redox_syscall", ] [[package]] name = "aho-corasick" -version = "0.7.13" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] name = "alxd" version = "0.1.0" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", - "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "netutils", + "redox_event", + "redox_syscall", ] [[package]] name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9", ] [[package]] @@ -67,66 +70,68 @@ source = "git+https://gitlab.redox-os.org/redox-os/arg-parser.git#1c434b55f3e1a0 name = "arrayvec" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" dependencies = [ - "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop", ] [[package]] name = "arrayvec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi 0.3.9", ] [[package]] name = "autocfg" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" [[package]] name = "bgad" version = "0.1.0" dependencies = [ - "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient", + "redox_syscall", ] [[package]] name = "bincode" -version = "1.2.1" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] -[[package]] -name = "bitflags" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "block-io-wrapper" @@ -134,266 +139,323 @@ version = "0.1.0" [[package]] name = "build_const" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" + +[[package]] +name = "bumpalo" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" [[package]] name = "byteorder" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.58" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chashmap" version = "2.2.2" -source = "git+https://gitlab.redox-os.org/redox-os/chashmap.git#9a36a4df91930628390d70b697800e32b9e7c9bd" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff41a3c2c1e39921b9003de14bf0439c7b63a9039637c291e1a64925d8ddfa45" dependencies = [ - "owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref", + "parking_lot 0.4.8", ] [[package]] name = "chrono" -version = "0.4.11" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ - "num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "num-integer", + "num-traits", + "time", + "winapi 0.3.9", ] [[package]] name = "clap" -version = "2.33.1" +version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ - "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", ] [[package]] name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", ] [[package]] name = "cmake" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855" dependencies = [ - "cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)", + "cc", ] [[package]] name = "crc" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" dependencies = [ - "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "build_const", ] [[package]] name = "crc32fast" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] name = "crossbeam-channel" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" dependencies = [ - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2", + "maybe-uninit", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils 0.8.5", ] [[package]] name = "crossbeam-utils" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1", + "cfg-if 0.1.10", + "lazy_static", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +dependencies = [ + "cfg-if 1.0.0", + "lazy_static", ] [[package]] name = "e1000d" version = "0.1.0" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", - "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "netutils", + "redox_event", + "redox_syscall", ] [[package]] name = "encoding_rs" -version = "0.8.23" +version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] name = "extra" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#0b50f3f2127fa62b1fe74090feffbae357266eac" +source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#cf213969493db8667052a591e32a1e26d43c4234" [[package]] name = "filetime" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "winapi 0.3.9", ] [[package]] name = "flate2" -version = "1.0.16" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "miniz_oxide 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "crc32fast", + "libc", + "miniz_oxide", ] [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" [[package]] name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "fuchsia-zircon-sys", ] [[package]] name = "fuchsia-zircon-sys" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.5" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" dependencies = [ - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", ] [[package]] name = "futures-channel" -version = "0.3.5" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "futures-sink", ] [[package]] name = "futures-core" -version = "0.3.5" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" [[package]] name = "futures-executor" -version = "0.3.5" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" dependencies = [ - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "futures-core", + "futures-task", + "futures-util", ] [[package]] name = "futures-io" -version = "0.3.5" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" [[package]] name = "futures-macro" -version = "0.3.5" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" dependencies = [ - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "futures-sink" -version = "0.3.5" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" [[package]] name = "futures-task" -version = "0.3.5" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" [[package]] name = "futures-util" -version = "0.3.5" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" dependencies = [ - "futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-project 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)", - "pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "proc-macro-hack", + "proc-macro-nested", + "slab", ] [[package]] @@ -401,154 +463,172 @@ name = "gpt" version = "0.6.3" source = "git+https://gitlab.redox-os.org/redox-os/gpt#4d800981c5dfae60ae183dbddaa3e026f80a5e5c" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "crc", + "log", + "uuid", ] [[package]] name = "heck" -version = "0.3.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ - "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation", ] [[package]] name = "hermit-abi" -version = "0.1.14" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "idna" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", + "unicode-bidi", + "unicode-normalization", ] [[package]] name = "ihdad" version = "0.1.0" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "redox_event", + "redox_syscall", + "spin", ] [[package]] name = "instant" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "itoa" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "ixgbed" version = "1.0.0" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", - "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "netutils", + "redox_event", + "redox_syscall", +] + +[[package]] +name = "js-sys" +version = "0.3.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" +dependencies = [ + "wasm-bindgen", ] [[package]] name = "kernel32-sys" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "lazycell" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" [[package]] name = "libc" -version = "0.2.71" +version = "0.2.97" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" [[package]] name = "linked-hash-map" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "lock_api" -version = "0.3.4" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" dependencies = [ - "owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "lock_api" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard", ] [[package]] name = "log" -version = "0.4.8" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", ] [[package]] name = "matches" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "maybe-uninit" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" [[package]] name = "miniz_oxide" -version = "0.4.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ - "adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "adler", + "autocfg 1.0.1", ] [[package]] @@ -556,190 +636,196 @@ name = "mio" version = "0.6.14" source = "git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix#c9a70849ced97387e2607c9c466d23b130ec8901" dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", - "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "lazycell", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", ] [[package]] name = "miow" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", ] [[package]] name = "net2" -version = "0.2.33" -source = "git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix#be7b855982e63770753a81ffc4bedf66d7f66506" +version = "0.2.37" +source = "git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=master#db0604dcb0a355e6b2fa5bcaad8f175bd6aeb5aa" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "libc", + "winapi 0.3.9", ] [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#a66c155fa4bb248151100c2ac861a913df7c75cd" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#c5d6d20900fd4da9cbf1f3ec04bd752c3d5d3e04" dependencies = [ - "arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)", - "extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix)", - "net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)", - "ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)", - "pbr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "arg_parser", + "extra", + "libc", + "mio", + "net2", + "ntpclient", + "pbr", + "redox_event", + "redox_syscall", + "redox_termios", + "termion", + "url", ] [[package]] name = "nodrop" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" [[package]] name = "ntpclient" version = "0.0.1" source = "git+https://github.com/willem66745/ntpclient-rust#7e3bdf60eb940825789a8da5181025320e3050b0" dependencies = [ - "byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 0.5.3", + "time", ] [[package]] name = "num-derive" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "num-integer" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1", + "num-traits", ] [[package]] name = "num-traits" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1", ] [[package]] name = "numtoa" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" [[package]] name = "nvmed" version = "0.1.0" dependencies = [ - "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "block-io-wrapper 0.1.0", - "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)", - "pcid 0.1.0", - "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", - "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.5.2", + "bitflags", + "block-io-wrapper", + "crossbeam-channel 0.4.4", + "futures", + "log", + "partitionlib", + "pcid", + "redox-log", + "redox_syscall", + "smallvec 1.6.1", ] -[[package]] -name = "once_cell" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "orbclient" -version = "0.3.28" -source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#d212107f84183a1375de9e958f7e4427fb35dc72" +version = "0.3.31" +source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#8ef4433da9871d6f6e8c11d0b863f737144d19f1" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2-sys 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "raw-window-handle", + "redox_syscall", + "sdl2", + "sdl2-sys", + "wasm-bindgen", + "web-sys", ] [[package]] name = "owning_ref" -version = "0.4.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" dependencies = [ - "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stable_deref_trait", ] [[package]] name = "parking_lot" -version = "0.10.2" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" dependencies = [ - "lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "owning_ref", + "parking_lot_core 0.2.14", ] [[package]] name = "parking_lot" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" dependencies = [ - "instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "lock_api 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "parking_lot_core 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)", + "instant", + "lock_api", + "parking_lot_core 0.8.3", ] [[package]] name = "parking_lot_core" -version = "0.7.2" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand 0.4.6", + "smallvec 0.6.14", + "winapi 0.3.9", ] [[package]] name = "parking_lot_core" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" dependencies = [ - "cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall", + "smallvec 1.6.1", + "winapi 0.3.9", ] [[package]] @@ -747,997 +833,960 @@ name = "partitionlib" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/partitionlib.git#1c12e0d93f7a16f7a209abdcf318388e850a73c7" dependencies = [ - "gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)", - "scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", + "gpt", + "scroll", + "uuid", ] [[package]] name = "paw" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c0fc9b564dbc3dc2ed7c92c0c144f4de340aa94514ce2b446065417c4084e9" dependencies = [ - "paw-attributes 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "paw-raw 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "paw-attributes", + "paw-raw", ] [[package]] name = "paw-attributes" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "paw-raw" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" [[package]] name = "pbr" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff5751d87f7c00ae6403eb1fcbba229b9c76c9a30de8c1cf87182177b168cea2" dependencies = [ - "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.5.1", + "libc", + "time", + "winapi 0.3.9", ] [[package]] name = "pcid" version = "0.1.0" dependencies = [ - "bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "paw 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", - "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bincode", + "bitflags", + "byteorder 1.4.3", + "libc", + "log", + "paw", + "plain", + "redox-log", + "redox_syscall", + "serde", + "serde_json", + "smallvec 1.6.1", + "structopt", + "thiserror", + "toml", ] [[package]] name = "pcspkrd" version = "0.1.0" dependencies = [ - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall", ] [[package]] name = "percent-encoding" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] -name = "pin-project" -version = "0.4.22" +name = "pin-project-lite" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "pin-project-internal 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "pin-project-internal" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", -] +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "plain" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "proc-macro-error" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ - "proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", ] [[package]] name = "proc-macro-error-attr" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", - "syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "version_check", ] [[package]] name = "proc-macro-hack" -version = "0.5.16" +version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro-nested" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" [[package]] name = "proc-macro2" -version = "1.0.18" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "ps2d" version = "0.1.0" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "orbclient", + "redox_syscall", ] [[package]] name = "quote" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi 0.3.9", ] [[package]] name = "rand" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7", + "libc", + "rand_chacha", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi 0.3.9", ] [[package]] name = "rand_chacha" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7", + "rand_core 0.3.1", ] [[package]] name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2", ] [[package]] name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" [[package]] name = "rand_hc" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "rand_isaac" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "rand_jitter" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "rand_core 0.4.2", + "winapi 0.3.9", ] [[package]] name = "rand_os" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi 0.3.9", ] [[package]] name = "rand_pcg" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7", + "rand_core 0.4.2", ] [[package]] name = "rand_xorshift" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "ransid" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log", + "vte", ] [[package]] name = "raw-window-handle" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "rdrand" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox-log" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0#30f6bf2464c462c32cd215bc0f1eedafa0707a04" -dependencies = [ - "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1", ] [[package]] name = "redox-log" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf6d33a003a5c0b94ec11f10c7c797303f236592964ddb1bfb93e1b438a1557" dependencies = [ - "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono", + "log", + "smallvec 1.6.1", + "termion", ] [[package]] name = "redox_event" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/event.git#c31e3d3d5f44d60ff9fec2b1ee58b982e72c0d77" +source = "git+https://gitlab.redox-os.org/redox-os/event.git#228eb0719c4424357012c6aad71cf26976048990" dependencies = [ - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall", ] [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_syscall" -version = "0.2.0" -source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#a0ea09ceb3380b1d1e878bb18886e13742d34e8a" +checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "redox_syscall" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", ] [[package]] name = "redox_termios" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" dependencies = [ - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall", ] [[package]] name = "regex" -version = "1.3.9" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ - "aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr", + "regex-syntax", ] [[package]] name = "regex-syntax" -version = "0.6.18" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rtl8168d" version = "0.1.0" dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)", - "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "netutils", + "redox_event", + "redox_syscall", ] [[package]] name = "rusttype" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a" dependencies = [ - "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12", + "linked-hash-map", + "stb_truetype 0.2.8", ] [[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "scroll" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda28d4b4830b807a8b43f7b0e6b5df875311b3e7621d84577188c175b6ec1ec" dependencies = [ - "scroll_derive 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "scroll_derive", ] [[package]] name = "scroll_derive" -version = "0.10.2" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "sdl2" -version = "0.34.2" +version = "0.34.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deecbc3fa9460acff5a1e563e05cb5f31bba0aa0c214bb49a43db8159176d54b" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "sdl2-sys 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "lazy_static", + "libc", + "raw-window-handle", + "sdl2-sys", ] [[package]] name = "sdl2-sys" -version = "0.34.2" +version = "0.34.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a29aa21f175b5a41a6e26da572d5e5d1ee5660d35f9f9d0913e8a802098f74" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)", - "unidiff 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "version-compare 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10", + "cmake", + "flate2", + "libc", + "tar", + "unidiff", + "version-compare", ] [[package]] name = "serde" -version = "1.0.112" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" dependencies = [ - "serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.112" +version = "1.0.126" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "serde_json" -version = "1.0.55" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ - "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] name = "slab" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" + +[[package]] +name = "smallvec" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97fcaeba89edba30f044a10c6a3cc39df9c3f17d7cd829dd1446cab35f890e0" +dependencies = [ + "maybe-uninit", +] [[package]] name = "smallvec" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" dependencies = [ - "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "serde", ] [[package]] name = "spin" -version = "0.4.10" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b87bbf98cb81332a56c1ee8929845836f85e8ddd693157c30d76660196014478" +dependencies = [ + "lock_api", +] [[package]] name = "stable_deref_trait" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stb_truetype" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" dependencies = [ - "stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stb_truetype 0.3.1", ] [[package]] name = "stb_truetype" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.4.3", ] [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" dependencies = [ - "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "structopt-derive 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "clap", + "lazy_static", + "paw", + "structopt-derive", ] [[package]] name = "structopt-derive" -version = "0.4.8" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" dependencies = [ - "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "syn" -version = "1.0.31" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn-mid" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] name = "tar" -version = "0.4.29" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d779dc6aeff029314570f666ec83f19df7280bb36ef338442cfa8c604021b80" dependencies = [ - "filetime 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime", + "libc", + "xattr", ] [[package]] name = "termion" -version = "1.5.5" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "numtoa", + "redox_syscall", + "redox_termios", ] [[package]] name = "textwrap" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", ] [[package]] name = "thiserror" -version = "1.0.20" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" dependencies = [ - "thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.20" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", + "wasi", + "winapi 0.3.9", ] [[package]] -name = "toml" -version = "0.5.6" +name = "tinyvec" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" dependencies = [ - "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", ] [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" dependencies = [ - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "matches", ] [[package]] name = "unicode-normalization" -version = "0.1.12" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ - "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" [[package]] name = "unicode-width" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "unidiff" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a62719acf1933bfdbeb73a657ecd9ecece70b405125267dd549e2e2edc232c" dependencies = [ - "encoding_rs 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "encoding_rs", + "lazy_static", + "regex", ] [[package]] name = "url" version = "1.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" dependencies = [ - "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "idna", + "matches", + "percent-encoding", ] [[package]] name = "usbctl" version = "0.1.0" dependencies = [ - "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", - "xhcid 0.1.0", + "clap", + "xhcid", ] [[package]] name = "usbhidd" version = "0.1.0" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", - "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "xhcid 0.1.0", + "bitflags", + "orbclient", + "ux", + "xhcid", ] [[package]] name = "usbscsid" version = "0.1.0" dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", - "xhcid 0.1.0", + "base64", + "plain", + "redox_syscall", + "thiserror", + "xhcid", ] [[package]] name = "utf8parse" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" [[package]] name = "uuid" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" dependencies = [ - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5", ] [[package]] name = "ux" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" [[package]] name = "vboxd" version = "0.1.0" dependencies = [ - "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", - "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient", + "redox_event", + "redox_syscall", ] [[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version-compare" version = "0.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" [[package]] name = "version_check" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "vesad" version = "0.1.0" dependencies = [ - "orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)", - "ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient", + "ransid", + "redox_syscall", + "rusttype", ] [[package]] name = "vte" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" dependencies = [ - "utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8parse", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" + +[[package]] +name = "web-sys" +version = "0.3.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" +dependencies = [ + "js-sys", + "wasm-bindgen", ] [[package]] name = "winapi" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-build" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "ws2_32-sys" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" dependencies = [ - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8", + "winapi-build", ] [[package]] name = "xattr" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "xhcid" version = "0.1.0" dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)", - "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "pcid 0.1.0", - "plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)", - "redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)", - "redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)", - "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags", + "chashmap", + "crossbeam-channel 0.4.4", + "futures", + "lazy_static", + "log", + "pcid", + "plain", + "redox-log", + "redox_event", + "redox_syscall", + "serde", + "serde_json", + "smallvec 1.6.1", + "thiserror", + "toml", ] - -[metadata] -"checksum adler 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" -"checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" -"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum arg_parser 0.1.0 (git+https://gitlab.redox-os.org/redox-os/arg-parser.git)" = "" -"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" -"checksum bincode 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5753e2a71534719bf3f4e57006c3a4f0d2c672a4b676eec84161f763eca87dbf" -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39092a32794787acd8525ee150305ff051b0aa6cc2abaf193924f5ab05425f39" -"checksum byteorder 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" -"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum cc 1.0.58 (registry+https://github.com/rust-lang/crates.io-index)" = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum cfg-if 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -"checksum chashmap 2.2.2 (git+https://gitlab.redox-os.org/redox-os/chashmap.git)" = "" -"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" -"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum cmake 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "0e56268c17a6248366d66d4a47a3381369d068cce8409bb1716ed77ea32163bb" -"checksum crc 1.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" -"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" -"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" -"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum encoding_rs 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "e8ac63f94732332f44fe654443c46f6375d1939684c17b0afb6cb56b0456e171" -"checksum extra 0.1.0 (git+https://gitlab.redox-os.org/redox-os/libextra.git)" = "" -"checksum filetime 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" -"checksum flate2 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "68c90b0fc46cf89d227cc78b40e494ff81287a92dd07631e5af0d06fe3cf885e" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1e05b85ec287aac0dc34db7d4a569323df697f9c55b99b15d6b4ef8cde49f613" -"checksum futures-channel 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f366ad74c28cca6ba456d95e6422883cfb4b252a83bed929c83abfdbbf2967d5" -"checksum futures-core 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "59f5fff90fd5d971f936ad674802482ba441b6f09ba5e15fd8b39145582ca399" -"checksum futures-executor 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "10d6bb888be1153d3abeb9006b11b02cf5e9b209fda28693c31ae1e4e012e314" -"checksum futures-io 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "de27142b013a8e869c14957e6d2edeef89e97c289e69d042ee3a49acd8b51789" -"checksum futures-macro 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" -"checksum futures-sink 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3f2032893cb734c7a05d85ce0cc8b8c4075278e93b24b66f9de99d6eb0fa8acc" -"checksum futures-task 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bdb66b5f09e22019b1ab0830f7785bcea8e7a42148683f99214f73f8ec21a626" -"checksum futures-util 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8764574ff08b701a084482c3c7031349104b07ac897393010494beaa18ce32c6" -"checksum gpt 0.6.3 (git+https://gitlab.redox-os.org/redox-os/gpt)" = "" -"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" -"checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" -"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -"checksum instant 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" -"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" -"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" -"checksum linked-hash-map 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" -"checksum lock_api 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c4da24a77a3d8a6d4862d95f72e6fdb9c09a643ecdb402d754004a557f2bec75" -"checksum lock_api 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" -"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" -"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -"checksum miniz_oxide 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f" -"checksum mio 0.6.14 (git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix)" = "" -"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" -"checksum net2 0.2.33 (git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=redox-unix)" = "" -"checksum netutils 0.1.0 (git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix)" = "" -"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" -"checksum ntpclient 0.0.1 (git+https://github.com/willem66745/ntpclient-rust)" = "" -"checksum num-derive 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" -"checksum num-integer 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" -"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" -"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" -"checksum once_cell 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0b631f7e854af39a1739f401cf34a8a013dfe09eac4fa4dba91e9768bd28168d" -"checksum orbclient 0.3.28 (git+https://gitlab.redox-os.org/redox-os/orbclient.git)" = "" -"checksum owning_ref 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6ff55baddef9e4ad00f88b6c743a2a8062d4c6ade126c2a528644b8e444d52ce" -"checksum parking_lot 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e" -"checksum parking_lot 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" -"checksum parking_lot_core 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3" -"checksum parking_lot_core 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" -"checksum partitionlib 0.1.0 (git+https://gitlab.redox-os.org/redox-os/partitionlib.git)" = "" -"checksum paw 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "09c0fc9b564dbc3dc2ed7c92c0c144f4de340aa94514ce2b446065417c4084e9" -"checksum paw-attributes 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" -"checksum paw-raw 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" -"checksum pbr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74333e3d1d8bced07fd0b8599304825684bcdb4a1fcc6fa6a470e6e08cefd254" -"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" -"checksum pin-project 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)" = "12e3a6cdbfe94a5e4572812a0201f8c0ed98c1c452c7b8563ce2276988ef9c17" -"checksum pin-project-internal 0.4.22 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0ffd45cf79d88737d7cc85bfd5d2894bee1139b356e616fe85dc389c61aaf7" -"checksum pin-utils 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" -"checksum plain 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -"checksum proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880" -"checksum proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50" -"checksum proc-macro-hack 0.5.16 (registry+https://github.com/rust-lang/crates.io-index)" = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" -"checksum proc-macro-nested 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eba180dafb9038b050a4c280019bbedf9f2467b61e5d892dcad585bb57aadc5a" -"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" -"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum ransid 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045" -"checksum raw-window-handle 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum redox-log 0.1.0 (git+https://gitlab.redox-os.org/redox-os/redox-log.git?tag=v0.1.0)" = "" -"checksum redox-log 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf6d33a003a5c0b94ec11f10c7c797303f236592964ddb1bfb93e1b438a1557" -"checksum redox_event 0.1.0 (git+https://gitlab.redox-os.org/redox-os/event.git)" = "" -"checksum redox_syscall 0.1.57 (registry+https://github.com/rust-lang/crates.io-index)" = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" -"checksum redox_syscall 0.2.0 (git+https://gitlab.redox-os.org/redox-os/syscall.git)" = "" -"checksum redox_syscall 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" -"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" -"checksum rusttype 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a" -"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -"checksum scroll 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb2332cb595d33f7edd5700f4cbf94892e680c7f0ae56adab58a35190b66cb1" -"checksum scroll_derive 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e367622f934864ffa1c704ba2b82280aab856e3d8213c84c5720257eb34b15b9" -"checksum sdl2 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)" = "29fb006600d16da4f1f1e5c7b398f44af2f1b476ff5f2e555651bd78cf4c18d8" -"checksum sdl2-sys 0.34.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ed17d6d46b62b7df12134513bcc4f071268963e8c9bc8bf7ad983fbfb2bc3cc" -"checksum serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243" -"checksum serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57" -"checksum serde_json 1.0.55 (registry+https://github.com/rust-lang/crates.io-index)" = "ec2c5d7e739bc07a3e73381a39d61fdb5f671c60c1df26a130690665803d8226" -"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" -"checksum smallvec 1.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" -"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" -"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" -"checksum stb_truetype 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" -"checksum stb_truetype 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" -"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -"checksum structopt 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "de2f5e239ee807089b62adce73e48c625e0ed80df02c7ab3f068f5db5281065c" -"checksum structopt-derive 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "510413f9de616762a4fbeab62509bf15c729603b72d7cd71280fbca431b1c118" -"checksum syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" -"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" -"checksum tar 0.4.29 (registry+https://github.com/rust-lang/crates.io-index)" = "c8a4c1d0bee3230179544336c15eefb563cf0302955d962e456542323e8c2e8a" -"checksum termion 1.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c22cec9d8978d906be5ac94bceb5a010d885c626c4c8855721a4dbd20e3ac905" -"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -"checksum thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "7dfdd070ccd8ccb78f4ad66bf1982dc37f620ef696c6b5028fe2ed83dd3d0d08" -"checksum thiserror-impl 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)" = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" -"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" -"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5479532badd04e128284890390c1e876ef7a993d0570b3597ae43dfa1d59afa4" -"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" -"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum unidiff 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d8a62719acf1933bfdbeb73a657ecd9ecece70b405125267dd549e2e2edc232c" -"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -"checksum utf8parse 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" -"checksum uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" -"checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" -"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" -"checksum version-compare 0.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" -"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" -"checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -"checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" diff --git a/Cargo.toml b/Cargo.toml index 28ffd6b8a9..8078a99e90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,5 +23,5 @@ members = [ [patch.crates-io] mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } -net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "redox-unix" } +net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.28" } diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index dc52205604..12e879c397 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -13,5 +13,5 @@ num-traits = "0.2" parking_lot = "0.11.1" plain = "0.2.3" redox-log = "0.1.1" -redox_syscall = "0.2.5" +redox_syscall = "0.2.9" thiserror = "1" diff --git a/acpid/src/main.rs b/acpid/src/main.rs index f353f081a1..d58343413b 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -1,5 +1,3 @@ -#![feature(renamed_spin_loop, seek_convenience)] - use std::convert::TryFrom; use std::io::{self, prelude::*}; use std::fs::{File, OpenOptions}; diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index bddad85151..d39ade6572 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -8,6 +8,6 @@ bitflags = "1.2" byteorder = "1.2" log = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } -redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } -redox_syscall = "0.1" +redox-log = "0.1" +redox_syscall = "0.2.9" block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index 03d51d838f..ca118a50cb 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -1,3 +1,4 @@ +use std::convert::TryInto; use std::ptr; use syscall::io::Dma; @@ -31,19 +32,16 @@ pub struct DiskATA { impl DiskATA { pub fn new(id: usize, port: &'static mut HbaPort) -> Result { - let mut clb = Dma::zeroed()?; - let mut ctbas = [ - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - ]; - let mut fb = Dma::zeroed()?; - let buf = Dma::zeroed()?; + let mut clb = unsafe { Dma::zeroed()?.assume_init() }; + + let mut ctbas: [_; 32] = (0..32) + .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .collect::>>()? + .try_into() + .unwrap_or_else(|_| unreachable!()); + + let mut fb = unsafe { Dma::zeroed()?.assume_init() }; + let buf = unsafe { Dma::zeroed()?.assume_init() }; port.init(&mut clb, &mut ctbas, &mut fb); @@ -55,7 +53,7 @@ impl DiskATA { size: size, request_opt: None, clb: clb, - ctbas: ctbas, + ctbas, _fb: fb, buf: buf }) diff --git a/ahcid/src/ahci/disk_atapi.rs b/ahcid/src/ahci/disk_atapi.rs index 3a140195d7..c414b8480f 100644 --- a/ahcid/src/ahci/disk_atapi.rs +++ b/ahcid/src/ahci/disk_atapi.rs @@ -1,5 +1,6 @@ #![allow(dead_code)] +use std::convert::TryInto; use std::ptr; use byteorder::{ByteOrder, BigEndian}; @@ -27,32 +28,29 @@ pub struct DiskATAPI { impl DiskATAPI { pub fn new(id: usize, port: &'static mut HbaPort) -> Result { - let mut clb = Dma::zeroed()?; - let mut ctbas = [ - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - ]; - let mut fb = Dma::zeroed()?; - let buf = Dma::zeroed()?; + let mut clb = unsafe { Dma::zeroed()?.assume_init() }; + + let mut ctbas: [_; 32] = (0..32) + .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .collect::>>()? + .try_into() + .unwrap_or_else(|_| unreachable!()); + + let mut fb = unsafe { Dma::zeroed()?.assume_init() }; + let buf = unsafe { Dma::zeroed()?.assume_init() }; port.init(&mut clb, &mut ctbas, &mut fb); let size = unsafe { port.identify_packet(&mut clb, &mut ctbas).unwrap_or(0) }; Ok(DiskATAPI { - id: id, - port: port, - size: size, - clb: clb, - ctbas: ctbas, + id, + port, + size, + clb, + ctbas, _fb: fb, - buf: buf + buf, }) } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 31459c208d..eefdce1ba0 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -3,13 +3,18 @@ extern crate syscall; extern crate byteorder; -use log::{error, info}; -use redox_log::{OutputBuilder, RedoxLogger}; use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write}; use std::os::unix::io::{FromRawFd, RawFd}; -use syscall::{ENODEV, EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Error, Event, Packet, SchemeBlockMut}; + +use syscall::error::{Error, ENODEV}; +use syscall::data::{Event, Packet}; +use syscall::flag::{CloneFlags, EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::scheme::SchemeBlockMut; + +use log::{error, info}; +use redox_log::{OutputBuilder, RedoxLogger}; use crate::scheme::DiskScheme; @@ -76,7 +81,7 @@ fn main() { let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); // Daemonize - if unsafe { syscall::clone(0).unwrap() } != 0 { + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { return; } diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index 5d5e13f85a..da51c0c301 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -148,9 +148,9 @@ impl DiskScheme { } impl SchemeBlockMut for DiskScheme { - fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { + fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { if uid == 0 { - let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?.trim_matches('/'); + let path_str = path.trim_matches('/'); if path_str.is_empty() { if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { let mut list = String::new(); @@ -390,7 +390,9 @@ impl SchemeBlockMut for DiskScheme { } } - fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result> { + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { + let pos = pos as usize; + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(ref mut handle, ref mut size) => { let len = handle.len() as usize; @@ -401,7 +403,7 @@ impl SchemeBlockMut for DiskScheme { _ => return Err(Error::new(EINVAL)) }; - Ok(Some(*size)) + Ok(Some(*size as isize)) }, Handle::Disk(number, ref mut size) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; @@ -413,7 +415,7 @@ impl SchemeBlockMut for DiskScheme { _ => return Err(Error::new(EINVAL)) }; - Ok(Some(*size)) + Ok(Some(*size as isize)) } Handle::Partition(disk_num, part_num, ref mut position) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; @@ -426,7 +428,7 @@ impl SchemeBlockMut for DiskScheme { SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, _ => return Err(Error::new(EINVAL)), }; - Ok(Some(*position as usize)) + Ok(Some(*position as isize)) } } } diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml index f4466be864..08d67ee31e 100644 --- a/alxd/Cargo.toml +++ b/alxd/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "0.7" +bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.1" +redox_syscall = "0.2.9" diff --git a/alxd/src/device/mod.rs b/alxd/src/device/mod.rs index 143f1e48a4..b92a12fb92 100644 --- a/alxd/src/device/mod.rs +++ b/alxd/src/device/mod.rs @@ -1,8 +1,9 @@ use std::{ptr, thread, time}; +use std::convert::TryInto; use netutils::setcfg; use syscall::error::{Error, EACCES, EINVAL, EIO, EWOULDBLOCK, Result}; -use syscall::flag::O_NONBLOCK; +use syscall::flag::{EventFlags, O_NONBLOCK}; use syscall::io::{Dma, Io, Mmio}; use syscall::scheme; @@ -275,6 +276,14 @@ pub struct Alx { tpd_ring: [Dma<[Tpd; 16]>; 4], } +fn dma_array() -> Result<[Dma; N]> { + Ok((0..N) + .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .collect::>>()? + .try_into() + .unwrap_or_else(|_| unreachable!())) +} + impl Alx { pub unsafe fn new(base: usize) -> Result { let mut module = Alx { @@ -325,21 +334,11 @@ impl Alx { hib_patch: false, is_fpga: false, - rfd_buffer: [ - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()? - ], - rfd_ring: Dma::zeroed()?, - rrd_ring: Dma::zeroed()?, - tpd_buffer: [ - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()? - ], - tpd_ring: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?] + rfd_buffer: dma_array()?, + rfd_ring: Dma::zeroed()?.assume_init(), + rrd_ring: Dma::zeroed()?.assume_init(), + tpd_buffer: dma_array()?, + tpd_ring: dma_array()?, }; module.init()?; @@ -1789,7 +1788,7 @@ impl Alx { } impl scheme::SchemeMut for Alx { - fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result { if uid == 0 { Ok(flags) } else { @@ -1886,8 +1885,8 @@ impl scheme::SchemeMut for Alx { Ok(0) } - fn fevent(&mut self, _id: usize, _flags: usize) -> Result { - Ok(0) + fn fevent(&mut self, _id: usize, _flags: EventFlags) -> Result { + Ok(EventFlags::empty()) } fn fsync(&mut self, _id: usize) -> Result { diff --git a/alxd/src/main.rs b/alxd/src/main.rs index 0165894474..77c342f808 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -16,7 +16,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, SchemeMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{CloneFlags, EventFlags, Packet, SchemeMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -36,7 +36,7 @@ fn main() { print!("{}", format!(" + ALX {} on: {:X}, IRQ: {}\n", name, bar, irq)); // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("alxd: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); @@ -112,7 +112,7 @@ fn main() { for event_count in event_queue.trigger_all(event::Event { fd: 0, - flags: 0, + flags: EventFlags::empty(), }).expect("alxd: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, @@ -121,7 +121,7 @@ fn main() { gid: 0, a: syscall::number::SYS_FEVENT, b: 0, - c: syscall::flag::EVENT_READ, + c: syscall::flag::EVENT_READ.bits(), d: event_count }).expect("alxd: failed to write event"); } @@ -136,7 +136,7 @@ fn main() { gid: 0, a: syscall::number::SYS_FEVENT, b: 0, - c: syscall::flag::EVENT_READ, + c: syscall::flag::EVENT_READ.bits(), d: event_count }).expect("alxd: failed to write event"); } diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml index d7611f9d8a..6f93cf78e3 100644 --- a/bgad/Cargo.toml +++ b/bgad/Cargo.toml @@ -5,4 +5,4 @@ edition = "2018" [dependencies] orbclient = "0.3.27" -redox_syscall = "0.1" +redox_syscall = "0.2.9" diff --git a/bgad/src/main.rs b/bgad/src/main.rs index d2ff217f30..47ad94ae74 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -6,8 +6,10 @@ extern crate syscall; use std::env; use std::fs::File; use std::io::{Read, Write}; -use syscall::iopl; + +use syscall::call::iopl; use syscall::data::Packet; +use syscall::flag::CloneFlags; use syscall::scheme::SchemeMut; use crate::bga::Bga; @@ -28,7 +30,7 @@ fn main() { print!("{}", format!(" + BGA {} on: {:X}\n", name, bar)); // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { unsafe { iopl(3).unwrap() }; let mut socket = File::create(":bga").expect("bgad: failed to create bga scheme"); diff --git a/bgad/src/scheme.rs b/bgad/src/scheme.rs index 635d581017..061de83c03 100644 --- a/bgad/src/scheme.rs +++ b/bgad/src/scheme.rs @@ -12,7 +12,7 @@ pub struct BgaScheme { } impl SchemeMut for BgaScheme { - fn open(&mut self, _path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result { + fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result { if uid == 0 { Ok(0) } else { diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index bdd4a8844a..a7f17d77d5 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "0.7" +bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.1" +redox_syscall = "0.2.9" diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index ef1c11cc8a..c5b6902bbb 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,9 +1,11 @@ use std::collections::BTreeMap; +use std::convert::TryInto; use std::{cmp, mem, ptr, slice}; use netutils::setcfg; + use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; -use syscall::flag::O_NONBLOCK; +use syscall::flag::{EventFlags, O_NONBLOCK}; use syscall::io::Dma; use syscall::scheme::SchemeBlockMut; @@ -113,7 +115,7 @@ fn wrap_ring(index: usize, ring_size: usize) -> usize { } impl SchemeBlockMut for Intel8254x { - fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { + fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { if uid == 0 { self.next_id += 1; self.handles.insert(self.next_id, flags); @@ -218,9 +220,9 @@ impl SchemeBlockMut for Intel8254x { Ok(Some(i)) } - fn fevent(&mut self, id: usize, _flags: usize) -> Result> { + fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) + Ok(Some(EventFlags::empty())) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { @@ -246,26 +248,23 @@ impl SchemeBlockMut for Intel8254x { } } +fn dma_array() -> Result<[Dma; N]> { + Ok((0..N) + .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .collect::>>()? + .try_into() + .unwrap_or_else(|_| unreachable!())) +} impl Intel8254x { pub unsafe fn new(base: usize) -> Result { #[rustfmt::skip] let mut module = Intel8254x { base: base, - receive_buffer: [ - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - ], - receive_ring: Dma::zeroed()?, - transmit_buffer: [ - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - ], + receive_buffer: dma_array()?, + receive_ring: Dma::zeroed()?.assume_init(), + transmit_buffer: dma_array()?, receive_index: 0, - transmit_ring: Dma::zeroed()?, + transmit_ring: Dma::zeroed()?.assume_init(), transmit_ring_free: 16, transmit_index: 0, transmit_clean_index: 0, diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index e622201062..0a75a51a05 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -12,7 +12,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{CloneFlags, EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; pub mod device; @@ -81,7 +81,7 @@ fn main() { syscall::pipe2(&mut pipes, 0).unwrap(); let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; let mut write = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; - let pid = unsafe { syscall::clone(0).unwrap() }; + let pid = unsafe { syscall::clone(CloneFlags::empty()).unwrap() }; if pid != 0 { drop(write); @@ -191,7 +191,7 @@ fn main() { gid: 0, a: syscall::number::SYS_FEVENT, b: *handle_id, - c: syscall::flag::EVENT_READ, + c: syscall::flag::EVENT_READ.bits(), d: event_count, }) .expect("e1000d: failed to write event"); @@ -199,7 +199,7 @@ fn main() { }; for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: 0 }) + .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) .expect("e1000d: failed to trigger events") { send_events(event_count); diff --git a/ihdad/Cargo.toml b/ihdad/Cargo.toml index ec6d85b871..4b910a2fec 100755 --- a/ihdad/Cargo.toml +++ b/ihdad/Cargo.toml @@ -4,8 +4,7 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "0.7" -spin = "0.4" +bitflags = "1" +spin = "0.9" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.1" - +redox_syscall = "0.2.9" diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 92c3685b17..5d77f859c6 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -866,7 +866,7 @@ impl Drop for IntelHDA { } impl SchemeBlockMut for IntelHDA { - fn open(&mut self, _path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result> { + fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { //let path: Vec<&str>; /* match str::from_utf8(_path) { @@ -901,7 +901,8 @@ impl SchemeBlockMut for IntelHDA { self.write_to_output(index, buf) } - fn seek(&mut self, id: usize, pos: usize, whence: usize) -> Result> { + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { + let pos = pos as usize; let mut handles = self.handles.lock(); match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::StrBuf(ref mut strbuf, ref mut size) => { @@ -912,7 +913,7 @@ impl SchemeBlockMut for IntelHDA { SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, _ => return Err(Error::new(EINVAL)) }; - Ok(Some(*size)) + Ok(Some(*size as isize)) }, _ => Err(Error::new(EINVAL)), diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 77e0cdfdf5..6223e4c1be 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -10,7 +10,7 @@ use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Packet, SchemeBlockMut}; +use syscall::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; @@ -49,7 +49,7 @@ fn main() { print!("{}", format!(" + ihda {} on: {:X} size: {} IRQ: {}\n", name, bar, bar_size, irq)); // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { let address = unsafe { syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("ihdad: failed to map address") @@ -136,7 +136,7 @@ fn main() { for event_count in event_queue.trigger_all(event::Event { fd: 0, - flags: 0, + flags: EventFlags::empty(), }).expect("IHDA: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, @@ -145,7 +145,7 @@ fn main() { gid: 0, a: syscall::number::SYS_FEVENT, b: 0, - c: syscall::flag::EVENT_READ, + c: syscall::flag::EVENT_READ.bits(), d: event_count }).expect("IHDA: failed to write event"); } @@ -167,7 +167,7 @@ fn main() { gid: 0, a: syscall::number::SYS_FEVENT, b: 0, - c: syscall::flag::EVENT_READ, + c: syscall::flag::EVENT_READ.bits(), d: event_count }).expect("IHDA: failed to write event"); } diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml index 1ac5938b16..3784e2373c 100644 --- a/ixgbed/Cargo.toml +++ b/ixgbed/Cargo.toml @@ -6,4 +6,4 @@ version = "1.0.0" bitflags = "1.0" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.1.54" +redox_syscall = "0.2.9" diff --git a/ixgbed/src/device.rs b/ixgbed/src/device.rs index 94e9e59c32..70452bc81a 100644 --- a/ixgbed/src/device.rs +++ b/ixgbed/src/device.rs @@ -1,10 +1,11 @@ use std::collections::BTreeMap; +use std::convert::TryInto; use std::time::{Duration, Instant}; use std::{cmp, mem, ptr, slice, thread}; use netutils::setcfg; use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; -use syscall::flag::O_NONBLOCK; +use syscall::flag::{EventFlags, O_NONBLOCK}; use syscall::io::Dma; use syscall::scheme::SchemeBlockMut; @@ -30,7 +31,7 @@ fn wrap_ring(index: usize, ring_size: usize) -> usize { } impl SchemeBlockMut for Intel8259x { - fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { + fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { if uid == 0 { self.next_id += 1; self.handles.insert(self.next_id, flags); @@ -146,9 +147,9 @@ impl SchemeBlockMut for Intel8259x { Ok(Some(i)) } - fn fevent(&mut self, id: usize, _flags: usize) -> Result> { + fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - Ok(Some(0)) + Ok(Some(EventFlags::empty())) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { @@ -178,29 +179,19 @@ impl Intel8259x { let mut module = Intel8259x { base, size, - receive_buffer: [ - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - ], - receive_ring: Dma::zeroed()?, - transmit_buffer: [ - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - ], + receive_buffer: (0..32) + .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .collect::>>()? + .try_into() + .unwrap_or_else(|_| unreachable!()), + receive_ring: unsafe { Dma::zeroed()?.assume_init() }, + transmit_buffer: (0..32) + .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .collect::>>()? + .try_into() + .unwrap_or_else(|_| unreachable!()), receive_index: 0, - transmit_ring: Dma::zeroed()?, + transmit_ring: unsafe { Dma::zeroed()?.assume_init() }, transmit_ring_free: 32, transmit_index: 0, transmit_clean_index: 0, diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index f3ff909a34..0f1b1ea3dd 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -11,7 +11,7 @@ use std::{env, thread}; use event::EventQueue; use std::time::Duration; -use syscall::{Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{CloneFlags, EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; pub mod device; #[rustfmt::skip] @@ -77,7 +77,7 @@ fn main() { println!(" + IXGBE {} on: {:X} IRQ: {}", name, bar, irq); // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { let socket_fd = syscall::open( ":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, @@ -170,7 +170,7 @@ fn main() { gid: 0, a: syscall::number::SYS_FEVENT, b: *handle_id, - c: syscall::flag::EVENT_READ, + c: syscall::flag::EVENT_READ.bits(), d: event_count, }) .expect("ixgbed: failed to write event"); @@ -178,7 +178,7 @@ fn main() { }; for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: 0 }) + .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) .expect("ixgbed: failed to trigger events") { send_events(event_count); diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index dca9a5dee1..c5ce4a641f 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -5,12 +5,12 @@ edition = "2018" [dependencies] arrayvec = "0.5" -bitflags = "0.7" +bitflags = "1" crossbeam-channel = "0.4" futures = "0.3" log = "0.4" -redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } -redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } +redox-log = "0.1" +redox_syscall = "0.2.9" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } smallvec = "1" block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index 4bedc114b3..ca78ab8633 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -160,10 +160,9 @@ impl DiskScheme { } impl SchemeBlockMut for DiskScheme { - fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { + fn open(&mut self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result> { if uid == 0 { - let path_str = str::from_utf8(path) - .or(Err(Error::new(ENOENT)))? + let path_str = path_str .trim_matches('/'); if path_str.is_empty() { if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index bb65204eae..e6259a0fac 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -19,8 +19,8 @@ libc = "0.2" log = "0.4" paw = "1.0" plain = "0.2" -redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } -redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } +redox-log = "0.1" +redox_syscall = "0.2.9" serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = "1" diff --git a/pcspkrd/Cargo.toml b/pcspkrd/Cargo.toml index ba42a0de19..649b11350f 100644 --- a/pcspkrd/Cargo.toml +++ b/pcspkrd/Cargo.toml @@ -5,4 +5,4 @@ authors = ["Tibor Nagy "] edition = "2018" [dependencies] -redox_syscall = "0.1" +redox_syscall = "0.2.9" diff --git a/pcspkrd/src/main.rs b/pcspkrd/src/main.rs index f84de4e024..f5692c0dcb 100644 --- a/pcspkrd/src/main.rs +++ b/pcspkrd/src/main.rs @@ -3,8 +3,10 @@ mod scheme; use std::fs::File; use std::io::{Read, Write}; + +use syscall::call::iopl; use syscall::data::Packet; -use syscall::iopl; +use syscall::flag::CloneFlags; use syscall::scheme::SchemeMut; use self::pcspkr::Pcspkr; @@ -12,7 +14,7 @@ use self::scheme::PcspkrScheme; fn main() { // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { unsafe { iopl(3).unwrap() }; let mut socket = File::create(":pcspkr").expect("pcspkrd: failed to create pcspkr scheme"); diff --git a/pcspkrd/src/scheme.rs b/pcspkrd/src/scheme.rs index 647e585881..4a24228f22 100644 --- a/pcspkrd/src/scheme.rs +++ b/pcspkrd/src/scheme.rs @@ -12,7 +12,7 @@ pub struct PcspkrScheme { } impl SchemeMut for PcspkrScheme { - fn open(&mut self, _path: &[u8], flags: usize, _uid: u32, _gid: u32) -> Result { + fn open(&mut self, _path: &str, flags: usize, _uid: u32, _gid: u32) -> Result { if (flags & O_ACCMODE == 0) && (flags & O_STAT == O_STAT) { Ok(0) } else if flags & O_ACCMODE == O_WRONLY { diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index f1da6df454..27e3b5e582 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "0.7" +bitflags = "1" orbclient = "0.3.27" -redox_syscall = "0.1" +redox_syscall = "0.2.9" diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 6866c6f7b0..a10660010a 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -1,32 +1,32 @@ use syscall::io::{Io, Pio, ReadOnly, WriteOnly}; bitflags! { - flags StatusFlags: u8 { - const OUTPUT_FULL = 1, - const INPUT_FULL = 1 << 1, - const SYSTEM = 1 << 2, - const COMMAND = 1 << 3, + pub struct StatusFlags: u8 { + const OUTPUT_FULL = 1; + const INPUT_FULL = 1 << 1; + const SYSTEM = 1 << 2; + const COMMAND = 1 << 3; // Chipset specific - const KEYBOARD_LOCK = 1 << 4, + const KEYBOARD_LOCK = 1 << 4; // Chipset specific - const SECOND_OUTPUT_FULL = 1 << 5, - const TIME_OUT = 1 << 6, - const PARITY = 1 << 7 + const SECOND_OUTPUT_FULL = 1 << 5; + const TIME_OUT = 1 << 6; + const PARITY = 1 << 7; } } bitflags! { - flags ConfigFlags: u8 { - const FIRST_INTERRUPT = 1, - const SECOND_INTERRUPT = 1 << 1, - const POST_PASSED = 1 << 2, + pub struct ConfigFlags: u8 { + const FIRST_INTERRUPT = 1; + const SECOND_INTERRUPT = 1 << 1; + const POST_PASSED = 1 << 2; // 1 << 3 should be zero - const CONFIG_RESERVED_3 = 1 << 3, - const FIRST_DISABLED = 1 << 4, - const SECOND_DISABLED = 1 << 5, - const FIRST_TRANSLATE = 1 << 6, + const CONFIG_RESERVED_3 = 1 << 3; + const FIRST_DISABLED = 1 << 4; + const SECOND_DISABLED = 1 << 5; + const FIRST_TRANSLATE = 1 << 6; // 1 << 7 should be zero - const CONFIG_RESERVED_7 = 1 << 7, + const CONFIG_RESERVED_7 = 1 << 7; } } @@ -95,15 +95,15 @@ impl Ps2 { } fn wait_write(&mut self) { - while self.status().contains(INPUT_FULL) {} + while self.status().contains(StatusFlags::INPUT_FULL) {} } fn wait_read(&mut self) { - while ! self.status().contains(OUTPUT_FULL) {} + while ! self.status().contains(StatusFlags::OUTPUT_FULL) {} } fn flush_read(&mut self, message: &str) { - while self.status().contains(OUTPUT_FULL) { + while self.status().contains(StatusFlags::OUTPUT_FULL) { print!("ps2d: flush {}: {:X}\n", message, self.data.read()); } } @@ -191,9 +191,9 @@ impl Ps2 { pub fn next(&mut self) -> Option<(bool, u8)> { let status = self.status(); - if status.contains(OUTPUT_FULL) { + if status.contains(StatusFlags::OUTPUT_FULL) { let data = self.data.read(); - Some((! status.contains(SECOND_OUTPUT_FULL), data)) + Some((! status.contains(StatusFlags::SECOND_OUTPUT_FULL), data)) } else { None } @@ -215,11 +215,11 @@ impl Ps2 { // Disable clocks, disable interrupts, and disable translate { let mut config = self.config(); - config.insert(FIRST_DISABLED); - config.insert(SECOND_DISABLED); - config.remove(FIRST_TRANSLATE); - config.remove(FIRST_INTERRUPT); - config.remove(SECOND_INTERRUPT); + config.insert(ConfigFlags::FIRST_DISABLED); + config.insert(ConfigFlags::SECOND_DISABLED); + config.remove(ConfigFlags::FIRST_TRANSLATE); + config.remove(ConfigFlags::FIRST_INTERRUPT); + config.remove(ConfigFlags::SECOND_INTERRUPT); self.set_config(config); } @@ -312,11 +312,11 @@ impl Ps2 { // Enable clocks and interrupts { let mut config = self.config(); - config.remove(FIRST_DISABLED); - config.remove(SECOND_DISABLED); - config.insert(FIRST_TRANSLATE); - config.insert(FIRST_INTERRUPT); - config.insert(SECOND_INTERRUPT); + config.remove(ConfigFlags::FIRST_DISABLED); + config.remove(ConfigFlags::SECOND_DISABLED); + config.insert(ConfigFlags::FIRST_TRANSLATE); + config.insert(ConfigFlags::FIRST_INTERRUPT); + config.insert(ConfigFlags::SECOND_INTERRUPT); self.set_config(config); } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 0b3ae6a484..58dd4d38b2 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -11,7 +11,8 @@ use std::io::{Read, Write}; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; -use syscall::iopl; +use syscall::call::iopl; +use syscall::flag::CloneFlags; use crate::state::Ps2d; @@ -113,7 +114,7 @@ fn main() { match OpenOptions::new().write(true).open("display:input") { Ok(input) => { // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { daemon(input); } }, diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index ec6e5d2c15..6671dc7ed8 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -1,23 +1,23 @@ -use orbclient::{KeyEvent, MouseEvent, MouseRelativeEvent, ButtonEvent, ScrollEvent}; use std::fs::File; use std::io::Write; use std::os::unix::io::AsRawFd; use std::str; -use syscall; + +use orbclient::{KeyEvent, MouseEvent, MouseRelativeEvent, ButtonEvent, ScrollEvent}; use crate::controller::Ps2; use crate::vm; bitflags! { - flags MousePacketFlags: u8 { - const LEFT_BUTTON = 1, - const RIGHT_BUTTON = 1 << 1, - const MIDDLE_BUTTON = 1 << 2, - const ALWAYS_ON = 1 << 3, - const X_SIGN = 1 << 4, - const Y_SIGN = 1 << 5, - const X_OVERFLOW = 1 << 6, - const Y_OVERFLOW = 1 << 7 + pub struct MousePacketFlags: u8 { + const LEFT_BUTTON = 1; + const RIGHT_BUTTON = 1 << 1; + const MIDDLE_BUTTON = 1 << 2; + const ALWAYS_ON = 1 << 3; + const X_SIGN = 1 << 4; + const Y_SIGN = 1 << 5; + const X_OVERFLOW = 1 << 6; + const Y_OVERFLOW = 1 << 7; } } @@ -176,20 +176,20 @@ impl char> Ps2d { self.packet_i += 1; let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); - if ! flags.contains(ALWAYS_ON) { + if ! flags.contains(MousePacketFlags::ALWAYS_ON) { println!("ps2d: mouse misalign {:X}", self.packets[0]); self.packets = [0; 4]; self.packet_i = 0; } else if self.packet_i >= self.packets.len() || (!self.extra_packet && self.packet_i >= 3) { - if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) { + if ! flags.contains(MousePacketFlags::X_OVERFLOW) && ! flags.contains(MousePacketFlags::Y_OVERFLOW) { let mut dx = self.packets[1] as i32; - if flags.contains(X_SIGN) { + if flags.contains(MousePacketFlags::X_SIGN) { dx -= 0x100; } let mut dy = -(self.packets[2] as i32); - if flags.contains(Y_SIGN) { + if flags.contains(MousePacketFlags::Y_SIGN) { dy += 0x100; } @@ -216,9 +216,9 @@ impl char> Ps2d { }.to_event()).expect("ps2d: failed to write scroll event"); } - let left = flags.contains(LEFT_BUTTON); - let middle = flags.contains(MIDDLE_BUTTON); - let right = flags.contains(RIGHT_BUTTON); + let left = flags.contains(MousePacketFlags::LEFT_BUTTON); + let middle = flags.contains(MousePacketFlags::MIDDLE_BUTTON); + let right = flags.contains(MousePacketFlags::RIGHT_BUTTON); if left != self.mouse_left || middle != self.mouse_middle || right != self.mouse_right { self.mouse_left = left; self.mouse_middle = middle; diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index 0ad6373cb3..f5232dca04 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "0.7" +bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.1" +redox_syscall = "0.2.9" diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 3245cbeeb3..0773f012e7 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -2,11 +2,12 @@ // See https://people.freebsd.org/~wpaul/RealTek/rtl8169spec-121.pdf use std::mem; +use std::convert::TryInto; use std::collections::BTreeMap; use netutils::setcfg; use syscall::error::{Error, EACCES, EBADF, EINVAL, EWOULDBLOCK, Result}; -use syscall::flag::O_NONBLOCK; +use syscall::flag::{EventFlags, O_NONBLOCK}; use syscall::io::{Dma, Mmio, Io, ReadOnly}; use syscall::scheme::SchemeBlockMut; @@ -83,7 +84,7 @@ pub struct Rtl8168 { } impl SchemeBlockMut for Rtl8168 { - fn open(&mut self, _path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result> { + fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { if uid == 0 { self.next_id += 1; self.handles.insert(self.next_id, flags); @@ -163,7 +164,7 @@ impl SchemeBlockMut for Rtl8168 { self.regs.tppoll.writef(1 << 6, true); //Notify of normal priority packet while self.regs.tppoll.readf(1 << 6) { - unsafe { llvm_asm!("pause"); } + std::hint::spin_loop(); } self.transmit_i += 1; @@ -171,13 +172,13 @@ impl SchemeBlockMut for Rtl8168 { return Ok(Some(i)); } - unsafe { llvm_asm!("pause"); } + std::hint::spin_loop(); } } - fn fevent(&mut self, id: usize, _flags: usize) -> Result> { + fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) + Ok(Some(EventFlags::empty())) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { @@ -220,34 +221,25 @@ impl Rtl8168 { let mut module = Rtl8168 { regs: regs, - receive_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], - receive_ring: Dma::zeroed()?, + receive_buffer: (0..64) + .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) + .collect::>>()? + .try_into() + .unwrap_or_else(|_| unreachable!()), + + receive_ring: Dma::zeroed()?.assume_init(), receive_i: 0, - transmit_buffer: [Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, - Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?, Dma::zeroed()?], - transmit_ring: Dma::zeroed()?, + transmit_buffer: (0..16) + .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) + .collect::>>()? + .try_into() + .unwrap_or_else(|_| unreachable!()), + transmit_ring: Dma::zeroed()?.assume_init(), transmit_i: 0, - transmit_buffer_h: [Dma::zeroed()?], - transmit_ring_h: Dma::zeroed()?, + transmit_buffer_h: [Dma::zeroed()?.assume_init()], + transmit_ring_h: Dma::zeroed()?.assume_init(), next_id: 0, - handles: BTreeMap::new() + handles: BTreeMap::new(), }; module.init(); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 0d143ab0b1..b632089a2f 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -12,7 +12,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{CloneFlags, EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; pub mod device; @@ -81,7 +81,7 @@ fn main() { syscall::pipe2(&mut pipes, 0).unwrap(); let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; let mut write = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; - let pid = unsafe { syscall::clone(0).unwrap() }; + let pid = unsafe { syscall::clone(CloneFlags::empty()).unwrap() }; if pid != 0 { drop(write); @@ -192,7 +192,7 @@ fn main() { gid: 0, a: syscall::number::SYS_FEVENT, b: *handle_id, - c: syscall::flag::EVENT_READ, + c: syscall::flag::EVENT_READ.bits(), d: event_count, }) .expect("rtl8168d: failed to write event"); @@ -200,7 +200,7 @@ fn main() { }; for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: 0 }) + .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) .expect("rtl8168d: failed to trigger events") { send_events(event_count); diff --git a/usbscsid/Cargo.toml b/usbscsid/Cargo.toml index ed2808e70f..22a25a1955 100644 --- a/usbscsid/Cargo.toml +++ b/usbscsid/Cargo.toml @@ -10,6 +10,6 @@ license = "MIT" [dependencies] base64 = "0.11" # Only for debugging plain = "0.2" -redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } +redox_syscall = "0.2.9" thiserror = "1" xhcid = { path = "../xhcid" } diff --git a/usbscsid/src/scheme.rs b/usbscsid/src/scheme.rs index f41291aa57..1ec7b20638 100644 --- a/usbscsid/src/scheme.rs +++ b/usbscsid/src/scheme.rs @@ -39,15 +39,14 @@ impl<'a> ScsiScheme<'a> { } impl<'a> SchemeMut for ScsiScheme<'a> { - fn open(&mut self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + fn open(&mut self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result { if uid != 0 { return Err(Error::new(EACCES)); } if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { return Err(Error::new(EACCES)); } - let path_str = str::from_utf8(path) - .or(Err(Error::new(ENOENT)))? + let path_str = path_str .trim_start_matches('/'); let handle = if path_str.is_empty() { // List diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index bab0ee130a..454e60723b 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -6,4 +6,4 @@ edition = "2018" [dependencies] orbclient = "0.3.27" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.1" +redox_syscall = "0.2.9" diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 74ee1612b4..2cd7cd8e65 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -9,9 +9,10 @@ use std::{env, mem}; use std::os::unix::io::AsRawFd; use std::fs::File; use std::io::{Result, Read, Write}; -use syscall::flag::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; + +use syscall::call::iopl; +use syscall::flag::{CloneFlags, EventFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::io::{Dma, Io, Mmio, Pio}; -use syscall::iopl; use crate::bga::Bga; @@ -60,7 +61,7 @@ impl VboxGetMouse { fn request() -> u32 { 1 } fn new() -> syscall::Result> { - let mut packet = Dma::::zeroed()?; + let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; packet.header.size.write(mem::size_of::() as u32); packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); @@ -83,7 +84,7 @@ impl VboxSetMouse { fn request() -> u32 { 2 } fn new() -> syscall::Result> { - let mut packet = Dma::::zeroed()?; + let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; packet.header.size.write(mem::size_of::() as u32); packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); @@ -104,7 +105,7 @@ impl VboxAckEvents { fn request() -> u32 { 41 } fn new() -> syscall::Result> { - let mut packet = Dma::::zeroed()?; + let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; packet.header.size.write(mem::size_of::() as u32); packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); @@ -125,7 +126,7 @@ impl VboxGuestCaps { fn request() -> u32 { 55 } fn new() -> syscall::Result> { - let mut packet = Dma::::zeroed()?; + let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; packet.header.size.write(mem::size_of::() as u32); packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); @@ -148,7 +149,7 @@ impl VboxDisplayChange { fn request() -> u32 { 51 } fn new() -> syscall::Result> { - let mut packet = Dma::::zeroed()?; + let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; packet.header.size.write(mem::size_of::() as u32); packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); @@ -170,7 +171,7 @@ impl VboxGuestInfo { fn request() -> u32 { 50 } fn new() -> syscall::Result> { - let mut packet = Dma::::zeroed()?; + let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; packet.header.size.write(mem::size_of::() as u32); packet.header.version.write(VBOX_REQUEST_HEADER_VERSION); @@ -198,7 +199,7 @@ fn main() { print!("{}", format!(" + VirtualBox {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1, irq)); // Daemonize - if unsafe { syscall::clone(0).unwrap() } == 0 { + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { unsafe { iopl(3).expect("vboxd: failed to get I/O permission"); }; let mut width = 0; @@ -288,7 +289,7 @@ fn main() { event_queue.trigger_all(event::Event { fd: 0, - flags: 0 + flags: EventFlags::empty() }).expect("vboxd: failed to trigger events"); event_queue.run().expect("vboxd: failed to run event loop"); diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index dd2433f889..3e52d37652 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" orbclient = "0.3.27" ransid = "0.4" rusttype = { version = "0.2", optional = true } -redox_syscall = "0.2.1" +redox_syscall = "0.2.9" [features] default = [] diff --git a/vesad/src/display.rs b/vesad/src/display.rs index a41456e087..f109184d25 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -1,7 +1,7 @@ #[cfg(feature="rusttype")] extern crate rusttype; -use std::alloc::{AllocInit, AllocRef, Global, Layout}; +use std::alloc::{Allocator, Global, Layout}; use std::{cmp, slice}; use std::ptr::NonNull; @@ -42,7 +42,13 @@ impl Display { #[cfg(not(feature="rusttype"))] pub fn new(width: usize, height: usize, onscreen: usize) -> Display { let size = width * height; - let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096), AllocInit::Zeroed).unwrap().ptr.as_ptr() }; + + let offscreen = unsafe { + Global + .allocate_zeroed(Layout::from_size_align_unchecked(size * 4, 4096)) + .expect("failed to allocate offscreen memory") + .as_ptr() + }; Display { width: width, height: height, @@ -54,7 +60,12 @@ impl Display { #[cfg(feature="rusttype")] pub fn new(width: usize, height: usize, onscreen: usize) -> Display { let size = width * height; - let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096), AllocInit::Zeroed).unwrap().ptr.as_ptr() }; + let offscreen = unsafe { + Global + .allocate_zeroed(Layout::from_size_align_unchecked(size * 4, 4096)) + .expect("failed to allocate offscreen memory") + .as_ptr() + }; Display { width: width, height: height, @@ -72,7 +83,12 @@ impl Display { println!("Resize display to {}, {}", width, height); let size = width * height; - let offscreen = unsafe { Global.alloc(Layout::from_size_align_unchecked(size * 4, 4096), AllocInit::Zeroed).unwrap().ptr.as_ptr() }; + let offscreen = unsafe { + Global + .allocate_zeroed(Layout::from_size_align_unchecked(size * 4, 4096)) + .expect("failed to allocate offscreen memory when resizing") + .as_ptr() + }; { let mut old_ptr = self.offscreen.as_ptr(); @@ -105,7 +121,7 @@ impl Display { let onscreen = self.onscreen.as_mut_ptr(); self.onscreen = unsafe { slice::from_raw_parts_mut(onscreen, size) }; - unsafe { Global.dealloc(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; + unsafe { Global.deallocate(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; self.offscreen = unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }; } else { println!("Display is already {}, {}", width, height); @@ -273,7 +289,17 @@ impl Display { } impl Drop for Display { + #[cold] fn drop(&mut self) { - unsafe { Global.dealloc(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; + unsafe { + let offscreen = std::mem::replace(&mut self.offscreen, &mut []); + + let layout = Layout::from_size_align(offscreen.len() * 4, 4096).unwrap(); + + Global.deallocate( + NonNull::from(offscreen).cast::(), + layout, + ); + } } } diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 3817f5f8af..ba92d64a50 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -13,15 +13,15 @@ path = "src/lib.rs" [dependencies] bitflags = "1" -chashmap = { git = "https://gitlab.redox-os.org/redox-os/chashmap.git" } +chashmap = "2.2.2" crossbeam-channel = "0.4" futures = "0.3" plain = "0.2" lazy_static = "1.4" log = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git", tag = "v0.1.0" } -redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } +redox-log = "0.1" +redox_syscall = "0.2.9" serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1", features = ["serde"] } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index db0df15acb..50304e4c18 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -20,7 +20,7 @@ use log::info; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; -use syscall::flag::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::flag::{CloneFlags, EventFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::scheme::Scheme; use syscall::io::Io; @@ -278,7 +278,7 @@ fn main() { .expect("xhcid: failed to catch events on scheme file"); event_queue - .trigger_all(Event { fd: 0, flags: 0 }) + .trigger_all(Event { fd: 0, flags: EventFlags::empty() }) .expect("xhcid: failed to trigger events"); event_queue.run().expect("xhcid: failed to handle events"); diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 9804efd830..ba3a74fd9a 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1252,13 +1252,12 @@ impl Xhci { } impl Scheme for Xhci { - fn open(&self, path: &[u8], flags: usize, uid: u32, _gid: u32) -> Result { + fn open(&self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result { if uid != 0 { return Err(Error::new(EACCES)); } - let path_str = str::from_utf8(path) - .or(Err(Error::new(ENOENT)))? + let path_str = path_str .trim_start_matches('/'); let components = path::Path::new(path_str) From 4da3ceb72331d354ede1d3af3751157f3860d2f0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 10 Aug 2021 18:25:44 -0600 Subject: [PATCH 0453/1301] Workaround hang on real hardware --- acpid/src/acpi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index f798567873..697d5d445f 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -258,7 +258,7 @@ impl AcpiContext { } Fadt::init(&mut this); - Dmar::init(&this); + //TODO (hangs on real hardware): Dmar::init(&this); crate::aml::init_namespace(&this); From 36b3af426260cb1bd740426f5fb8a07a5f37e4c5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 1 Dec 2021 16:14:15 -0700 Subject: [PATCH 0454/1301] ihdad logging --- Cargo.lock | 4 +++ ihdad/Cargo.toml | 4 ++- ihdad/src/hda/cmdbuff.rs | 14 +++++----- ihdad/src/hda/device.rs | 58 ++++++++++++++++++++-------------------- ihdad/src/hda/stream.rs | 4 +-- ihdad/src/main.rs | 47 ++++++++++++++++++++++++++++++++ 6 files changed, 92 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c9d724edf6..647200139b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "acpid" version = "0.1.0" @@ -503,6 +505,8 @@ name = "ihdad" version = "0.1.0" dependencies = [ "bitflags", + "log", + "redox-log", "redox_event", "redox_syscall", "spin", diff --git a/ihdad/Cargo.toml b/ihdad/Cargo.toml index 4b910a2fec..e96fae0740 100755 --- a/ihdad/Cargo.toml +++ b/ihdad/Cargo.toml @@ -5,6 +5,8 @@ edition = "2018" [dependencies] bitflags = "1" -spin = "0.9" +log = "0.4" +redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.2.9" +spin = "0.9" diff --git a/ihdad/src/hda/cmdbuff.rs b/ihdad/src/hda/cmdbuff.rs index 730ae1518c..a39998d3fb 100644 --- a/ihdad/src/hda/cmdbuff.rs +++ b/ihdad/src/hda/cmdbuff.rs @@ -147,16 +147,16 @@ impl Corb { self.stop(); // Set CORBRPRST to 1 - print!("CORBRP {:X}\n", self.regs.corbrp.read()); + log::info!("CORBRP {:X}", self.regs.corbrp.read()); self.regs.corbrp.writef(CORBRPRST, true); - print!("CORBRP {:X}\n", self.regs.corbrp.read()); - print!("Here!\n"); + log::info!("CORBRP {:X}", self.regs.corbrp.read()); + log::info!("Here!"); // Wait for it to become 1 while !self.regs.corbrp.readf(CORBRPRST) { self.regs.corbrp.writef(CORBRPRST, true); } - print!("Here!!\n"); + log::info!("Here!!"); // Clear the bit again self.regs.corbrp.write(0); @@ -168,7 +168,7 @@ impl Corb { } self.regs.corbrp.write(0); } - print!("Here!!!\n"); + log::info!("Here!!!"); } } @@ -183,7 +183,7 @@ impl Corb { self.regs.corbwp.write(write_pos as u16); - print!("Corb: {:08X}\n", cmd); + log::info!("Corb: {:08X}", cmd); } } @@ -285,7 +285,7 @@ impl Rirb { res = *self.rirb_base.offset(read_pos as isize); } self.rirb_rp = read_pos; - print!("Rirb: {:08X}\n", res); + log::info!("Rirb: {:08X}", res); res } } diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 5d77f859c6..f84f7c1e87 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -161,7 +161,7 @@ impl IntelHDA { syscall::physmap(buff_desc_phys, 0x1000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("ihdad: failed to map address for buffer descriptor list."); - print!("Virt: {:016X}, Phys: {:016X}\n", buff_desc_virt, buff_desc_phys); + log::info!("Virt: {:016X}, Phys: {:016X}", buff_desc_virt, buff_desc_phys); let buff_desc = &mut *(buff_desc_virt as *mut [BufferDescriptorListEntry;256]); @@ -171,7 +171,7 @@ impl IntelHDA { let cmd_buff_virt = syscall::physmap(cmd_buff_address, 0x1000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("ihdad: failed to map address for CORB/RIRB buff"); - print!("Virt: {:016X}, Phys: {:016X}\n", cmd_buff_virt, cmd_buff_address); + log::info!("Virt: {:016X}, Phys: {:016X}", cmd_buff_virt, cmd_buff_address); let mut module = IntelHDA { vend_prod: vend_prod, base: base, @@ -209,7 +209,7 @@ impl IntelHDA { module.enumerate(); module.configure(); - print!("IHDA: Initialization finished.\n"); + log::info!("IHDA: Initialization finished."); Ok(module) } @@ -345,7 +345,7 @@ impl IntelHDA { let root = self.read_node((codec,0)); - // print!("{}\n", root); + // log::info!("{}", root); let root_count = root.subnode_count; let root_start = root.subnode_start; @@ -353,7 +353,7 @@ impl IntelHDA { //FIXME: So basically the way this is set up is to only support one codec and hopes the first one is an audio for i in 0..root_count { let afg = self.read_node((codec, root_start + i)); - // print!("{}\n", afg); + // log::info!("{}", afg); let afg_count = afg.subnode_count; let afg_start = afg.subnode_start; @@ -373,13 +373,13 @@ impl IntelHDA { self.input_pins.push(widget.addr); } - print!("{:02X}{:02X} {}\n", widget.addr().0, widget.addr().1, config); + log::info!("{:02X}{:02X} {}", widget.addr().0, widget.addr().1, config); }, _ => {}, } - print!("{}\n", widget); + log::info!("{}", widget); self.widget_map.insert(widget.addr(), widget); } } @@ -473,14 +473,14 @@ impl IntelHDA { pub fn configure(&mut self) { let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); - //print!("Best pin: {:01X}:{:02X}\n", outpin.0, outpin.1); + //log::info!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); let path = self.find_path_to_dac(outpin).unwrap(); let dac = *path.last().unwrap(); let pin = *path.first().unwrap(); - //print!("Path to DAC: {:?}\n", path); + //log::info!("Path to DAC: {:?}", path); // Pin enable self.cmd.cmd12(pin, 0x707, 0x40); @@ -492,8 +492,8 @@ impl IntelHDA { self.update_sound_buffers(); - //print!("Supported Formats: {:08X}\n", self.get_supported_formats((0,0x1))); - //print!("Capabilities: {:08X}\n", self.get_capabilities(path[0])); + //log::info!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); + //log::info!("Capabilities: {:08X}", self.get_capabilities(path[0])); let output = self.get_output_stream_descriptor(0).unwrap(); @@ -525,10 +525,10 @@ impl IntelHDA { let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); - print!("Best pin: {:01X}:{:02X}\n", outpin.0, outpin.1); + log::info!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); let path = self.find_path_to_dac(outpin).unwrap(); - print!("Path to DAC: {:?}\n", path); + log::info!("Path to DAC: {:?}", path); // Pin enable self.cmd.cmd12((0,0xC), 0x707, 0x40); @@ -542,8 +542,8 @@ impl IntelHDA { self.update_sound_buffers(); - print!("Supported Formats: {:08X}\n", self.get_supported_formats((0,0x1))); - print!("Capabilities: {:08X}\n", self.get_capabilities((0,0x1))); + log::info!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); + log::info!("Capabilities: {:08X}", self.get_capabilities((0,0x1))); let output = self.get_output_stream_descriptor(0).unwrap(); @@ -616,7 +616,7 @@ impl IntelHDA { } let statests = self.regs.statests.read(); - print!("Statests: {:04X}\n", statests); + log::info!("Statests: {:04X}", statests); for i in 0..15 { if (statests >> i) & 0x1 == 1 { @@ -648,12 +648,12 @@ impl IntelHDA { } pub fn info(&self) { - print!("Intel HD Audio Version {}.{}\n", self.regs.vmaj.read(), self.regs.vmin.read()); - print!("IHDA: Input Streams: {}\n", self.num_input_streams()); - print!("IHDA: Output Streams: {}\n", self.num_output_streams()); - print!("IHDA: Bidirectional Streams: {}\n", self.num_bidirectional_streams()); - print!("IHDA: Serial Data Outputs: {}\n", self.num_serial_data_out()); - print!("IHDA: 64-Bit: {}\n", self.regs.gcap.read() & 1 == 1); + log::info!("Intel HD Audio Version {}.{}", self.regs.vmaj.read(), self.regs.vmin.read()); + log::info!("IHDA: Input Streams: {}", self.num_input_streams()); + log::info!("IHDA: Output Streams: {}", self.num_output_streams()); + log::info!("IHDA: Bidirectional Streams: {}", self.num_bidirectional_streams()); + log::info!("IHDA: Serial Data Outputs: {}", self.num_serial_data_out()); + log::info!("IHDA: 64-Bit: {}", self.regs.gcap.read() & 1 == 1); } fn get_input_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { @@ -750,7 +750,7 @@ impl IntelHDA { open_block = open_block - 1; } - //print!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}\n", output.status(), output.link_position(), output.control()); + //log::info!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}", output.status(), output.link_position(), output.control()); if open_block == os.current_block() { Ok(None) @@ -806,13 +806,13 @@ impl IntelHDA { } fn validate_path(&mut self, path: &Vec<&str>) -> bool { - print!("Path: {:?}\n", path); + log::info!("Path: {:?}", path); let mut it = path.iter(); match it.next() { Some(card_str) if (*card_str).starts_with("card") => { match usize::from_str_radix(&(*card_str)[4..], 10) { Ok(card_num) => { - print!("Card# {}\n", card_num); + log::info!("Card# {}", card_num); match it.next() { Some(codec_str) if (*codec_str).starts_with("codec#") => { match usize::from_str_radix(&(*codec_str)[6..], 10) { @@ -828,7 +828,7 @@ impl IntelHDA { Some(pcmout_str) if (*pcmout_str).starts_with("pcmout") => { match usize::from_str_radix(&(*pcmout_str)[6..], 10) { Ok(pcmout_num) => { - print!("pcmout {}\n", pcmout_num); + log::info!("pcmout {}", pcmout_num); true }, _ => false, @@ -837,7 +837,7 @@ impl IntelHDA { Some(pcmin_str) if (*pcmin_str).starts_with("pcmin") => { match usize::from_str_radix(&(*pcmin_str)[6..], 10) { Ok(pcmin_num) => { - print!("pcmin {}\n", pcmin_num); + log::info!("pcmin {}", pcmin_num); true }, _ => false, @@ -860,7 +860,7 @@ impl IntelHDA { impl Drop for IntelHDA { fn drop(&mut self) { - print!("IHDA: Deallocating IHDA driver.\n"); + log::info!("IHDA: Deallocating IHDA driver."); } } @@ -896,7 +896,7 @@ impl SchemeBlockMut for IntelHDA { 0 }; - //print!("Int count: {}\n", self.int_counter); + //log::info!("Int count: {}", self.int_counter); self.write_to_output(index, buf) } diff --git a/ihdad/src/hda/stream.rs b/ihdad/src/hda/stream.rs index 4a77314b62..cf9cb90ada 100644 --- a/ihdad/src/hda/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -354,7 +354,7 @@ impl StreamBuffer { let len = min(self.block_size(), buf.len()); - //print!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}\n", self.phys(), self.addr(), self.current_block() * self.block_size(), len); + //log::info!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}", self.phys(), self.addr(), self.current_block() * self.block_size(), len); unsafe { copy_nonoverlapping(buf.as_ptr(), (self.addr() + self.current_block() * self.block_size()) as * mut u8, len); } @@ -369,7 +369,7 @@ impl StreamBuffer { impl Drop for StreamBuffer { fn drop(&mut self) { unsafe { - print!("IHDA: Deallocating buffer.\n"); + log::info!("IHDA: Deallocating buffer."); if syscall::physunmap(self.addr).is_ok() { let _ = syscall::physfree(self.phys, self.block_len * self.block_cnt); } diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 6223e4c1be..2a0ac274bb 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -15,6 +15,7 @@ use std::cell::RefCell; use std::sync::Arc; use event::EventQueue; +use redox_log::{OutputBuilder, RedoxLogger}; pub mod hda; @@ -25,6 +26,50 @@ pub mod hda; 82801H ICH8 8086:284B */ +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "ihda.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("ihdad: failed to create ihda.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "ihda.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("ihdad: failed to create ihda.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("ihdad: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("ihdad: failed to set default logger: {}", error); + None + } + } +} + fn main() { let mut args = env::args().skip(1); @@ -50,6 +95,8 @@ fn main() { // Daemonize if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { + let _logger_ref = setup_logging(); + let address = unsafe { syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("ihdad: failed to map address") From 5e3248ce26f0736f2f5a28e9a6cd625ee13e6296 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 5 Feb 2022 19:57:11 -0700 Subject: [PATCH 0455/1301] Get vesad framebuffer from env --- vesad/src/main.rs | 30 ++++++++++++++++-------------- vesad/src/mode_info.rs | 37 ------------------------------------- 2 files changed, 16 insertions(+), 51 deletions(-) delete mode 100644 vesad/src/mode_info.rs diff --git a/vesad/src/main.rs b/vesad/src/main.rs index e1249a1a2e..8962a80dcc 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -10,12 +10,10 @@ use std::io::{Read, Write}; use std::os::unix::io::{RawFd, FromRawFd}; use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE}; -use crate::mode_info::VBEModeInfo; use crate::primitive::fast_set64; use crate::scheme::{DisplayScheme, HandleKind}; pub mod display; -pub mod mode_info; pub mod primitive; pub mod scheme; pub mod screen; @@ -33,19 +31,23 @@ fn main() { } } - let width; - let height; - let physbaseptr; + let width = usize::from_str_radix( + &env::var("FRAMEBUFFER_WIDTH") + .expect("FRAMEBUFFER_WIDTH not set"), + 16 + ).expect("failed to parse FRAMEBUFFER_WIDTH"); + let height = usize::from_str_radix( + &env::var("FRAMEBUFFER_HEIGHT") + .expect("FRAMEBUFFER_HEIGHT not set"), + 16 + ).expect("failed to parse FRAMEBUFFER_HEIGHT"); + let physbaseptr = usize::from_str_radix( + &env::var("FRAMEBUFFER_ADDR") + .expect("FRAMEBUFFER_ADDR not set"), + 16 + ).expect("failed to parse FRAMEBUFFER_ADDR"); - { - let mode_info = unsafe { &*(physmap(0x5200, 4096, syscall::PhysmapFlags::empty()).expect("vesad: failed to map VBE info") as *const VBEModeInfo) }; - - width = mode_info.xresolution as usize; - height = mode_info.yresolution as usize; - physbaseptr = mode_info.physbaseptr as usize; - - unsafe { let _ = physunmap(mode_info as *const _ as usize); } - } + println!("vesad: {}x{} at 0x{:X}", width, height, physbaseptr); if physbaseptr > 0 { // Daemonize diff --git a/vesad/src/mode_info.rs b/vesad/src/mode_info.rs deleted file mode 100644 index 7d59af6452..0000000000 --- a/vesad/src/mode_info.rs +++ /dev/null @@ -1,37 +0,0 @@ -/// The info of the VBE mode -#[derive(Copy, Clone, Default, Debug)] -#[repr(packed)] -pub struct VBEModeInfo { - attributes: u16, - win_a: u8, - win_b: u8, - granularity: u16, - winsize: u16, - segment_a: u16, - segment_b: u16, - winfuncptr: u32, - bytesperscanline: u16, - pub xresolution: u16, - pub yresolution: u16, - xcharsize: u8, - ycharsize: u8, - numberofplanes: u8, - bitsperpixel: u8, - numberofbanks: u8, - memorymodel: u8, - banksize: u8, - numberofimagepages: u8, - unused: u8, - redmasksize: u8, - redfieldposition: u8, - greenmasksize: u8, - greenfieldposition: u8, - bluemasksize: u8, - bluefieldposition: u8, - rsvdmasksize: u8, - rsvdfieldposition: u8, - directcolormodeinfo: u8, - pub physbaseptr: u32, - offscreenmemoryoffset: u32, - offscreenmemsize: u16, -} From 4a8059302f739087e8663e6f22ebbdcad69ad19a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 11 Feb 2022 08:53:41 -0700 Subject: [PATCH 0456/1301] Disable ihdad, it causes issues on real hardware --- ihdad/config.toml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/ihdad/config.toml b/ihdad/config.toml index 11fc35efb1..98bb72d5ef 100644 --- a/ihdad/config.toml +++ b/ihdad/config.toml @@ -1,5 +1,6 @@ -[[drivers]] -name = "Intel HD Audio" -class = 4 -subclass = 3 -command = ["ihdad", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ", "$VENID", "$DEVID"] +# Disabled - causes issues on real hardware +# [[drivers]] +# name = "Intel HD Audio" +# class = 4 +# subclass = 3 +# command = ["ihdad", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ", "$VENID", "$DEVID"] From 5e42b0697ecd9bc58a88ac2433ee9883b952dcd1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 11 Feb 2022 09:23:48 -0700 Subject: [PATCH 0457/1301] Skip parsing vendor caps with length 0 --- pcid/src/pci/cap.rs | 10 ++++++++-- pcid/src/pci/func.rs | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index cef9108e35..43003fb9a5 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -186,9 +186,15 @@ impl Capability { log::info!("Vendor specific next: {}", reader.read_u8((offset+1).into())); let length = reader.read_u8(u16::from(offset+2)); log::info!("Vendor specific cap len: {}", length); - let mut raw_data = reader.read_range(offset.into(), length.into()); + let data = if length > 0 { + let mut raw_data = reader.read_range(offset.into(), length.into()); + raw_data.drain(3..).collect() + } else { + log::warn!("Vendor specific capability is invalid"); + Vec::new() + }; Self::Vendor(VendorSpecificCapability { - data: raw_data.drain(3..).collect(), + data }) } unsafe fn parse_pcie(reader: &R, offset: u8) -> Self { diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index 1b278bd057..fbdda1cfc6 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -4,7 +4,7 @@ use super::PciDev; pub trait ConfigReader { unsafe fn read_range(&self, offset: u16, len: u16) -> Vec { - assert!(len > 3 && len % 4 == 0); + assert!(len > 3 && len % 4 == 0, "invalid range length: {}", len); let mut ret = Vec::with_capacity(len as usize); let results = (offset..offset + len).step_by(4).fold(Vec::new(), |mut acc, offset| { let val = self.read_u32(offset); From b9d6ca7db5e19c0a28b6a1decc748f52ca354b58 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 11 Feb 2022 10:41:56 -0700 Subject: [PATCH 0458/1301] nvmed: panic if BAR is 0 --- initfs.toml | 2 +- nvmed/src/main.rs | 5 ++++- nvmed/src/nvme/queues.rs | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/initfs.toml b/initfs.toml index 9d95b91f9f..e7663cb8c3 100644 --- a/initfs.toml +++ b/initfs.toml @@ -27,7 +27,7 @@ command = ["bgad", "$NAME", "$BAR0"] name = "NVME storage" class = 1 subclass = 8 -command = ["nvmed", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ"] +command = ["nvmed"] use_channel = true # vboxd diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index dc5585c37d..5cc55d21a3 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -270,7 +270,10 @@ fn main() { .expect("nvmed: failed to fetch config"); let bar = match pci_config.func.bars[0] { - PciBar::Memory(mem) => mem, + PciBar::Memory(mem) => match mem { + 0 => panic!("BAR is mapped to address 0"), + _ => mem, + }, other => panic!("received a non-memory BAR ({:?})", other), }; let bar_size = pci_config.func.bar_sizes[0]; diff --git a/nvmed/src/nvme/queues.rs b/nvmed/src/nvme/queues.rs index bfc68b1d9f..19783095a6 100644 --- a/nvmed/src/nvme/queues.rs +++ b/nvmed/src/nvme/queues.rs @@ -77,6 +77,7 @@ impl NvmeCompQueue { /// Get a new CQ entry, busy waiting until an entry appears. fn complete_spin(&mut self) -> (u16, NvmeComp) { + log::debug!("Waiting for new CQ entry"); loop { if let Some(some) = self.complete() { return some; From 33ef3a326260a0e6fc2bbb69e7c4a7ce46905a0c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 11 Feb 2022 10:42:05 -0700 Subject: [PATCH 0459/1301] xhcid: panic if BAR is 0 --- xhcid/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 50304e4c18..f64af404af 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -101,7 +101,10 @@ fn main() { name.push_str("_xhci"); let bar_ptr = match bar { - pcid_interface::PciBar::Memory(ptr) => ptr, + pcid_interface::PciBar::Memory(ptr) => match ptr { + 0 => panic!("BAR is mapped to address 0"), + _ => ptr, + }, other => panic!("Expected memory bar, found {}", other), }; From 544f1cbebc30c3384645acb7178ca0d03a4b9d05 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 11 Feb 2022 10:44:38 -0700 Subject: [PATCH 0460/1301] nvmed,xhcid: print BAR number --- nvmed/src/main.rs | 7 +++++-- xhcid/src/main.rs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 5cc55d21a3..87c1fa9498 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -85,7 +85,10 @@ fn get_int_method( &mut Some(ref bar) => Ok(bar.ptr), bar_to_set @ &mut None => { let bar = match function.bars[bir] { - PciBar::Memory(addr) => addr, + PciBar::Memory(addr) => match addr { + 0 => panic!("BAR {} is mapped to address 0", bir), + _ => addr, + }, other => panic!("Expected memory BAR, found {:?}", other), }; let bar_size = function.bar_sizes[bir]; @@ -271,7 +274,7 @@ fn main() { let bar = match pci_config.func.bars[0] { PciBar::Memory(mem) => match mem { - 0 => panic!("BAR is mapped to address 0"), + 0 => panic!("BAR 0 is mapped to address 0"), _ => mem, }, other => panic!("received a non-memory BAR ({:?})", other), diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index f64af404af..26c57fc349 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -102,7 +102,7 @@ fn main() { let bar_ptr = match bar { pcid_interface::PciBar::Memory(ptr) => match ptr { - 0 => panic!("BAR is mapped to address 0"), + 0 => panic!("BAR 0 is mapped to address 0"), _ => ptr, }, other => panic!("Expected memory bar, found {}", other), From a1d8b814285f717e3b9d81fc89b828a7b9d9462d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 11 Feb 2022 11:00:50 -0700 Subject: [PATCH 0461/1301] Increase NVME debug level --- nvmed/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 87c1fa9498..5554e75691 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -218,7 +218,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_filter(log::LevelFilter::Debug) // limit global output to important info .with_ansi_escape_codes() .flush_on_newline(true) .build() From 88a6eb17e9ae6880244608266719ede69e798b7e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 11 Feb 2022 14:26:21 -0700 Subject: [PATCH 0462/1301] Make nvmed less async, reduces hangs --- nvmed/src/main.rs | 2 +- nvmed/src/nvme/cq_reactor.rs | 12 ++------- nvmed/src/nvme/identify.rs | 15 +++++------ nvmed/src/nvme/mod.rs | 49 +++++++++++++++++++++--------------- nvmed/src/scheme.rs | 12 ++++----- 5 files changed, 44 insertions(+), 46 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 5554e75691..6393be65e1 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -335,7 +335,7 @@ fn main() { log::debug!("Finished base initialization"); let nvme = Arc::new(nvme); let reactor_thread = nvme::cq_reactor::start_cq_reactor_thread(Arc::clone(&nvme), interrupt_sources, reactor_receiver); - let namespaces = futures::executor::block_on(nvme.init_with_queues()); + let namespaces = nvme.init_with_queues(); syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); diff --git a/nvmed/src/nvme/cq_reactor.rs b/nvmed/src/nvme/cq_reactor.rs index d327e7056e..0e817ff4c0 100644 --- a/nvmed/src/nvme/cq_reactor.rs +++ b/nvmed/src/nvme/cq_reactor.rs @@ -283,7 +283,7 @@ pub struct CompletionMessage { cq_entry: NvmeComp, } -enum CompletionFutureState<'a, F> { +pub enum CompletionFutureState<'a, F> { // the future is in its initial state: the command has not been submitted yet, and no interest // has been registered. this state will repeat until a free submission queue entry appears to // it, which it probably will since queues aren't supposed to be nearly always be full. @@ -303,7 +303,7 @@ enum CompletionFutureState<'a, F> { Placeholder, } pub struct CompletionFuture<'a, F> { - state: CompletionFutureState<'a, F>, + pub state: CompletionFutureState<'a, F>, } // enum not self-referential @@ -376,11 +376,3 @@ where } } } - -impl Nvme { - pub fn submit_and_complete_command NvmeCmd>(&self, sq_id: SqId, cmd_init: F) -> CompletionFuture { - CompletionFuture { - state: CompletionFutureState::PendingSubmission { cmd_init, nvme: &self, sq_id }, - } - } -} diff --git a/nvmed/src/nvme/identify.rs b/nvmed/src/nvme/identify.rs index 94c0a39595..ea504663d4 100644 --- a/nvmed/src/nvme/identify.rs +++ b/nvmed/src/nvme/identify.rs @@ -148,14 +148,13 @@ impl LbaFormat { impl Nvme { /// Returns the serial number, model, and firmware, in that order. - pub async fn identify_controller(&self) { + pub fn identify_controller(&self) { // TODO: Use same buffer let data: Dma = unsafe { Dma::zeroed().unwrap().assume_init() }; // println!(" - Attempting to identify controller"); let comp = self - .submit_and_complete_admin_command(|cid| NvmeCmd::identify_controller(cid, data.physical())) - .await; + .submit_and_complete_admin_command(|cid| NvmeCmd::identify_controller(cid, data.physical())); log::trace!("Completion: {:?}", comp); // println!(" - Dumping identify controller"); @@ -173,7 +172,7 @@ impl Nvme { model, serial, firmware, ); } - pub async fn identify_namespace_list(&self, base: u32) -> Vec { + pub fn identify_namespace_list(&self, base: u32) -> Vec { // TODO: Use buffer let data: Dma<[u32; 1024]> = unsafe { Dma::zeroed().unwrap().assume_init() }; @@ -181,22 +180,20 @@ impl Nvme { let comp = self .submit_and_complete_admin_command(|cid| { NvmeCmd::identify_namespace_list(cid, data.physical(), base) - }) - .await; + }); log::trace!("Completion2: {:?}", comp); // println!(" - Dumping namespace ID list"); data.iter().copied().take_while(|&nsid| nsid != 0).collect() } - pub async fn identify_namespace(&self, nsid: u32) -> NvmeNamespace { + pub fn identify_namespace(&self, nsid: u32) -> NvmeNamespace { //TODO: Use buffer let data: Dma = unsafe { Dma::zeroed().unwrap().assume_init() }; // println!(" - Attempting to identify namespace {}", nsid); let comp = self - .submit_and_complete_admin_command(|cid| NvmeCmd::identify_namespace(cid, data.physical(), nsid)) - .await; + .submit_and_complete_admin_command(|cid| NvmeCmd::identify_namespace(cid, data.physical(), nsid)); // println!(" - Dumping identify namespace"); diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index b80a633513..9934f8a357 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -400,11 +400,20 @@ impl Nvme { self.set_vectors_masked(std::iter::once((vector, masked))) } - pub async fn submit_and_complete_admin_command NvmeCmd>(&self, cmd_init: F) -> NvmeComp { - self.submit_and_complete_command(0, cmd_init).await + pub fn submit_and_complete_command NvmeCmd>(&self, sq_id: SqId, cmd_init: F) -> NvmeComp { + use crate::nvme::cq_reactor::{CompletionFuture, CompletionFutureState}; + futures::executor::block_on( + CompletionFuture { + state: CompletionFutureState::PendingSubmission { cmd_init, nvme: &self, sq_id }, + } + ) } - pub async fn create_io_completion_queue(&self, io_cq_id: CqId, vector: Option) { + pub fn submit_and_complete_admin_command NvmeCmd>(&self, cmd_init: F) -> NvmeComp { + self.submit_and_complete_command(0, cmd_init) + } + + pub fn create_io_completion_queue(&self, io_cq_id: CqId, vector: Option) { let (ptr, len) = { let mut completion_queues_guard = self.completion_queues.write().unwrap(); @@ -432,8 +441,7 @@ impl Nvme { let comp = self .submit_and_complete_admin_command(|cid| { NvmeCmd::create_io_completion_queue(cid, io_cq_id, ptr, raw_len, vector) - }) - .await; + }); if let Some(vector) = vector { self.cqs_for_ivs @@ -444,7 +452,7 @@ impl Nvme { .push(io_cq_id); } } - pub async fn create_io_submission_queue(&self, io_sq_id: SqId, io_cq_id: CqId) { + pub fn create_io_submission_queue(&self, io_sq_id: SqId, io_cq_id: CqId) { let (ptr, len) = { let mut submission_queues_guard = self.submission_queues.write().unwrap(); @@ -470,30 +478,31 @@ impl Nvme { let comp = self .submit_and_complete_admin_command(|cid| { NvmeCmd::create_io_submission_queue(cid, io_sq_id, ptr, raw_len, io_cq_id) - }) - .await; + }); } - pub async fn init_with_queues(&self) -> BTreeMap { + pub fn init_with_queues(&self) -> BTreeMap { log::trace!("preinit"); - let ((), nsids) = - futures::join!(self.identify_controller(), self.identify_namespace_list(0)); + + self.identify_controller(); + let nsids = self.identify_namespace_list(0); + log::debug!("first commands"); let mut namespaces = BTreeMap::new(); for nsid in nsids.iter().copied() { - namespaces.insert(nsid, self.identify_namespace(nsid).await); + namespaces.insert(nsid, self.identify_namespace(nsid)); } // TODO: Multiple queues - self.create_io_completion_queue(1, Some(0)).await; - self.create_io_submission_queue(1, 1).await; + self.create_io_completion_queue(1, Some(0)); + self.create_io_submission_queue(1, 1); namespaces } - async fn namespace_rw( + fn namespace_rw( &self, namespace: &NvmeNamespace, nsid: u32, @@ -520,13 +529,13 @@ impl Nvme { } else { NvmeCmd::io_read(cid, nsid, lba, blocks_1, ptr0, ptr1) } - }).await; + }); // TODO: Handle errors Ok(()) } - pub async fn namespace_read( + pub fn namespace_read( &self, namespace: &NvmeNamespace, nsid: u32, @@ -543,7 +552,7 @@ impl Nvme { assert!(blocks > 0); assert!(blocks <= 0x1_0000); - self.namespace_rw(namespace, nsid, lba, (blocks - 1) as u16, false).await?; + self.namespace_rw(namespace, nsid, lba, (blocks - 1) as u16, false)?; chunk.copy_from_slice(&buffer_guard[..chunk.len()]); @@ -553,7 +562,7 @@ impl Nvme { Ok(Some(buf.len())) } - pub async fn namespace_write( + pub fn namespace_write( &self, namespace: &NvmeNamespace, nsid: u32, @@ -572,7 +581,7 @@ impl Nvme { buffer_guard[..chunk.len()].copy_from_slice(chunk); - self.namespace_rw(namespace, nsid, lba, (blocks - 1) as u16, true).await?; + self.namespace_rw(namespace, nsid, lba, (blocks - 1) as u16, true)?; lba += blocks as u64; } diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index ca78ab8633..55a491ab7f 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -82,7 +82,7 @@ impl DiskWrapper { return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); } loop { - match futures::executor::block_on(nvme.namespace_read(disk, disk.id, block, block_bytes)) + match nvme.namespace_read(disk, disk.id, block, block_bytes) .map_err(|err| io::Error::from_raw_os_error(err.errno))? { Some(bytes) => { assert_eq!(bytes, block_bytes.len()); @@ -346,7 +346,7 @@ impl SchemeBlockMut for DiskScheme { Handle::Disk(number, ref mut size) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; - if let Some(count) = futures::executor::block_on(self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, (*size as u64) / block_size, buf))? { + if let Some(count) = self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, (*size as u64) / block_size, buf)? { *size += count; Ok(Some(count)) } else { @@ -371,7 +371,7 @@ impl SchemeBlockMut for DiskScheme { let abs_block = part.start_lba + rel_block; - if let Some(count) = futures::executor::block_on(self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, abs_block, buf))? { + if let Some(count) = self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, abs_block, buf)? { *offset += count; Ok(Some(count)) } else { @@ -387,8 +387,8 @@ impl SchemeBlockMut for DiskScheme { Handle::Disk(number, ref mut size) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; - if let Some(count) = futures::executor::block_on(self.nvme - .namespace_write(disk.as_ref(), disk.as_ref().id, (*size as u64) / block_size, buf))? { + if let Some(count) = self.nvme + .namespace_write(disk.as_ref(), disk.as_ref().id, (*size as u64) / block_size, buf)? { *size += count; Ok(Some(count)) } else { @@ -413,7 +413,7 @@ impl SchemeBlockMut for DiskScheme { let abs_block = part.start_lba + rel_block; - if let Some(count) = futures::executor::block_on(self.nvme.namespace_write(disk.as_ref(), disk.as_ref().id, abs_block, buf))? { + if let Some(count) = self.nvme.namespace_write(disk.as_ref(), disk.as_ref().id, abs_block, buf)? { *offset += count; Ok(Some(count)) } else { From 0cd3a6b797a7450128d44aaa54e1949e91233ad0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 14 Feb 2022 09:38:31 -0700 Subject: [PATCH 0463/1301] Fix scheme name for xhcid and launch drivers --- xhcid/src/main.rs | 5 +++-- xhcid/src/xhci/mod.rs | 13 +++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 26c57fc349..30c30049f5 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -231,8 +231,9 @@ fn main() { format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq) ); + let scheme_name = format!("usb/{}", name); let socket_fd = syscall::open( - format!(":usb/{}", name), + format!(":{}", scheme_name), syscall::O_RDWR | syscall::O_CREAT, ) .expect("xhcid: failed to create usb scheme"); @@ -240,7 +241,7 @@ fn main() { File::from_raw_fd(socket_fd as RawFd) })); - let hci = Arc::new(Xhci::new(name, address, interrupt_method, pcid_handle).expect("xhcid: failed to allocate device")); + let hci = Arc::new(Xhci::new(scheme_name, address, interrupt_method, pcid_handle).expect("xhcid: failed to allocate device")); xhci::start_irq_reactor(&hci, irq_file); futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe"); diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 3fc5d75a46..083cd281bc 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -524,11 +524,10 @@ impl Xhci { self.update_default_control_pipe(&mut *input, slot, dev_desc).await?; } - /*match self.spawn_drivers(i, &mut port_state) { + match self.spawn_drivers(i) { Ok(()) => (), Err(err) => error!("Failed to spawn driver for port {}: `{}`", i, err), - }*/ - + } } } @@ -712,15 +711,17 @@ impl Xhci { } } - fn spawn_drivers(&self, port: usize, ps: &mut PortState) -> Result<()> { + fn spawn_drivers(&self, port: usize) -> Result<()> { // TODO: There should probably be a way to select alternate interfaces, and not just the // first one. // TODO: Now that there are some good error crates, I don't think errno.h error codes are // suitable here. + let ps = self.port_states.get(&port).unwrap(); + let ifdesc = &ps .dev_desc - .as_ref().unwrap() + .as_ref().ok_or(Error::new(EBADF))? .config_descs .first() .ok_or(Error::new(EBADF))? @@ -737,7 +738,7 @@ impl Xhci { .map(|subclass| subclass == ifdesc.sub_class) .unwrap_or(true) }) { - info!("Loading subdriver\"{}\"", driver.name); + info!("Loading subdriver \"{}\"", driver.name); let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; let if_proto = ifdesc.protocol; From d40a908cfdb9e3dde54ab856cb533cc51a4390f1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 14 Feb 2022 09:38:40 -0700 Subject: [PATCH 0464/1301] Add logging to usbhidd --- Cargo.lock | 2 ++ usbhidd/Cargo.toml | 2 ++ usbhidd/src/main.rs | 55 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 647200139b..86820f3928 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1567,7 +1567,9 @@ name = "usbhidd" version = "0.1.0" dependencies = [ "bitflags", + "log", "orbclient", + "redox-log", "ux", "xhcid", ] diff --git a/usbhidd/Cargo.toml b/usbhidd/Cargo.toml index 7595756e7c..4cf1d27770 100644 --- a/usbhidd/Cargo.toml +++ b/usbhidd/Cargo.toml @@ -9,6 +9,8 @@ license = "MIT" [dependencies] bitflags = "1.2" +log = "0.4" orbclient = "0.3.27" +redox-log = "0.1" ux = "0.1" xhcid = { path = "../xhcid" } diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index f862989fab..884fa9da23 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -3,6 +3,7 @@ use std::fs::File; use bitflags::bitflags; use orbclient::KeyEvent as OrbKeyEvent; +use redox_log::{OutputBuilder, RedoxLogger}; use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle}; mod report_desc; @@ -60,7 +61,53 @@ impl<'a> BinaryView<'a> { } } +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("usb", "device", "hid.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Trace) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("Failed to create hid.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("usb", "device", "hid.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Trace) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("Failed to create hid.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("usbhidd: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("usbhidd: failed to set default logger: {}", error); + None + } + } +} + fn main() { + let _logger_ref = setup_logging(); + let mut args = env::args().skip(1); const USAGE: &'static str = "usbhidd "; @@ -73,7 +120,7 @@ fn main() { .expect("Expected integer as input of port"); let protocol = args.next().expect(USAGE); - println!( + log::info!( "USB HID driver spawned with scheme `{}`, port {}, protocol {}", scheme, port, protocol ); @@ -104,14 +151,14 @@ fn main() { let report_desc = ReportIter::new(ReportFlatIter::new(&report_desc_bytes)).collect::>(); for item in &report_desc { - println!("{:?}", item); + log::info!("{:?}", item); } handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0, interface_desc: None, alternate_setting: None }).expect("Failed to configure endpoints"); let (mut global_state, mut local_state, mut stack) = (GlobalItemsState::default(), LocalItemsState::default(), Vec::new()); - let (_, application_collection, application_global_state, application_local_state) = report_desc.iter().filter_map(|item: &ReportIterItem| + let (_, application_collection, application_global_state, application_local_state) = report_desc.iter().filter_map(|item: &ReportIterItem| match item { &ReportIterItem::Item(ref item) => { report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); @@ -250,7 +297,7 @@ mod tests { #[test] fn binary_view() { // 0000 1000 1100 0111 - // E S + // E S let view = super::BinaryView::new(&[0xC7, 0x08], 3, 11); assert_eq!(view.get(0), Some(false)); assert_eq!(view.get(2), Some(false)); From 07a2c5d590ffebc22d6ed24d286226ab47e999c2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 14 Feb 2022 10:12:12 -0700 Subject: [PATCH 0465/1301] Do not require display:input in usbhidd yet --- usbhidd/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 884fa9da23..7715e5ce02 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -221,7 +221,7 @@ fn main() { let report_ty = ReportTy::Input; let report_id = 0; - let orbital_socket = File::open("display:input").expect("Failed to open orbital input socket"); + //TODO let orbital_socket = File::open("display:input").expect("Failed to open orbital input socket"); let mut pressed_keys = Vec::::new(); let mut last_pressed_keys = pressed_keys.clone(); From 88fc91dfb7a8961ceb1f1c25d2cd9291ce23f2dc Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Feb 2022 11:21:47 -0700 Subject: [PATCH 0466/1301] Only create acpi scheme after tables are found and parsed --- acpid/src/main.rs | 70 ++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 38 deletions(-) diff --git a/acpid/src/main.rs b/acpid/src/main.rs index d58343413b..6ae7d32035 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -85,44 +85,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } } -fn main() { - let mut pipes = [0; 2]; - syscall::pipe2(&mut pipes, 0).expect("acpid: failed to create synchronization pipe"); - let [read_part, write_part] = pipes; - - let mut read_part = unsafe { File::from_raw_fd(read_part as RawFd) }; - let mut write_part = unsafe { File::from_raw_fd(write_part as RawFd) }; - - let pid = unsafe { syscall::clone(syscall::CloneFlags::empty()).expect("failed to daemonize acpid") }; - - if pid != 0 { - drop(write_part); - - let mut res = [0]; - let bytes_read = read_part.read(&mut res).expect("acpid: failed to read from sync pipe"); - - let exit_code = if bytes_read == res.len() { - res[0] - } else { - eprintln!("acpid: daemon pipe EOF"); - 1 - }; - drop(read_part); - std::process::exit(exit_code.into()); - } - drop(read_part); - - let mut scheme_socket = OpenOptions::new() - .write(true) - .read(true) - .create(true) - .custom_flags(O_NONBLOCK as i32) - .open(":acpi") - .expect("acpid: failed to open scheme socket"); - - let _ = write_part.write(&[0]).expect("acpid: failed to write to sync pipe"); - drop(write_part); - +fn daemon(mut write_part: File) { setup_logging(); let rxsdt_raw_data: Arc<[u8]> = std::fs::read("kernel/acpi:rxsdt") @@ -170,6 +133,17 @@ fn main() { .open("event:") .expect("acpid: failed to open event queue"); + let mut scheme_socket = OpenOptions::new() + .write(true) + .read(true) + .create(true) + .custom_flags(O_NONBLOCK as i32) + .open(":acpi") + .expect("acpid: failed to open scheme socket"); + + write_part.write_all(&[0]).expect("acpid: failed to write to sync pipe"); + drop(write_part); + syscall::setrens(0, 0).expect("acpid: failed to enter null namespace"); let _ = event_queue.write(&Event { @@ -252,3 +226,23 @@ fn main() { unreachable!("System should have shut down before this is entered"); } + +fn main() { + let mut pipes = [0; 2]; + syscall::pipe2(&mut pipes, 0).expect("acpid: failed to create synchronization pipe"); + + let mut read_part = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; + let mut write_part = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; + + if unsafe { syscall::clone(syscall::CloneFlags::empty()).expect("failed to daemonize acpid") } == 0 { + drop(read_part); + daemon(write_part); + } else { + drop(write_part); + + let mut res = [0]; + let bytes_read = read_part.read_exact(&mut res).expect("acpid: failed to read from sync pipe"); + + std::process::exit(res[0].into()); + } +} From d31133956dd28c8bc87eea80edb88a4181c98796 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Feb 2022 14:02:58 -0700 Subject: [PATCH 0467/1301] Remove debug: logging from acpid, logd now handles that --- acpid/src/main.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 6ae7d32035..ebc105dcc6 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -44,12 +44,6 @@ fn setup_logging() -> Option<&'static RedoxLogger> { .build() ); - #[cfg(target_os = "redox")] - match File::open("debug:") { - Ok(d) => logger = logger.with_output(OutputBuilder::with_endpoint(d).flush_on_newline(true).with_ansi_escape_codes().with_filter(log::LevelFilter::Info).build()), - Err(error) => eprintln!("Failed to open `debug:` scheme: {}", error), - } - #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.log") { Ok(b) => logger = logger.with_output( From 0a617abb3613adf86c513af1886832c49642999a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Feb 2022 14:10:41 -0700 Subject: [PATCH 0468/1301] Disable xhcid --- initfs.toml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/initfs.toml b/initfs.toml index e7663cb8c3..6f693e2d3f 100644 --- a/initfs.toml +++ b/initfs.toml @@ -38,11 +38,12 @@ vendor = 33006 device = 51966 command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] -# xhcid -[[drivers]] -name = "XHCI" -class = 12 -subclass = 3 -interface = 48 -command = ["xhcid"] -use_channel = true +# Disabled until issues are fixed +# # xhcid +# [[drivers]] +# name = "XHCI" +# class = 12 +# subclass = 3 +# interface = 48 +# command = ["xhcid"] +# use_channel = true From ac9218844741a0dc0ae16b5141517bbd035ce541 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Feb 2022 14:17:34 -0700 Subject: [PATCH 0469/1301] Move bgad and vboxd out of initfs --- bgad/config.toml | 13 +++++++++++++ initfs.toml | 23 ----------------------- vboxd/config.toml | 6 ++++++ 3 files changed, 19 insertions(+), 23 deletions(-) create mode 100644 bgad/config.toml create mode 100644 vboxd/config.toml diff --git a/bgad/config.toml b/bgad/config.toml new file mode 100644 index 0000000000..184aacc0d4 --- /dev/null +++ b/bgad/config.toml @@ -0,0 +1,13 @@ +[[drivers]] +name = "QEMU Graphics Array" +class = 3 +vendor = 4660 +device = 4369 +command = ["bgad", "$NAME", "$BAR0"] + +[[drivers]] +name = "VirtualBox Graphics Array" +class = 3 +vendor = 33006 +device = 48879 +command = ["bgad", "$NAME", "$BAR0"] diff --git a/initfs.toml b/initfs.toml index 6f693e2d3f..be5c786ceb 100644 --- a/initfs.toml +++ b/initfs.toml @@ -7,21 +7,6 @@ class = 1 subclass = 6 command = ["ahcid", "$NAME", "$BAR5", "$BARSIZE5", "$IRQ"] -# bgad -[[drivers]] -name = "QEMU Graphics Array" -class = 3 -vendor = 4660 -device = 4369 -command = ["bgad", "$NAME", "$BAR0"] - -[[drivers]] -name = "VirtualBox Graphics Array" -class = 3 -vendor = 33006 -device = 48879 -command = ["bgad", "$NAME", "$BAR0"] - # nvmed [[drivers]] name = "NVME storage" @@ -30,14 +15,6 @@ subclass = 8 command = ["nvmed"] use_channel = true -# vboxd -[[drivers]] -name = "VirtualBox Guest Device" -class = 8 -vendor = 33006 -device = 51966 -command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] - # Disabled until issues are fixed # # xhcid # [[drivers]] diff --git a/vboxd/config.toml b/vboxd/config.toml new file mode 100644 index 0000000000..c97272fb3d --- /dev/null +++ b/vboxd/config.toml @@ -0,0 +1,6 @@ +[[drivers]] +name = "VirtualBox Guest Device" +class = 8 +vendor = 33006 +device = 51966 +command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] From 64b49f10a0529a8a218323908b96571e00703730 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Feb 2022 14:23:47 -0700 Subject: [PATCH 0470/1301] Fix vesad rusttype feature --- vesad/res/DejaVu-Fonts-License.txt | 97 +++++++++++++++++++++++ vesad/res/DejaVuSansMono-Bold.ttf | Bin 0 -> 318392 bytes vesad/res/DejaVuSansMono-BoldOblique.ttf | Bin 0 -> 239876 bytes vesad/res/DejaVuSansMono-Oblique.ttf | Bin 0 -> 245948 bytes vesad/res/DejaVuSansMono.ttf | Bin 0 -> 335068 bytes vesad/src/display.rs | 8 +- 6 files changed, 101 insertions(+), 4 deletions(-) create mode 100644 vesad/res/DejaVu-Fonts-License.txt create mode 100644 vesad/res/DejaVuSansMono-Bold.ttf create mode 100644 vesad/res/DejaVuSansMono-BoldOblique.ttf create mode 100644 vesad/res/DejaVuSansMono-Oblique.ttf create mode 100644 vesad/res/DejaVuSansMono.ttf diff --git a/vesad/res/DejaVu-Fonts-License.txt b/vesad/res/DejaVu-Fonts-License.txt new file mode 100644 index 0000000000..69399804ca --- /dev/null +++ b/vesad/res/DejaVu-Fonts-License.txt @@ -0,0 +1,97 @@ +Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. +Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) + +Bitstream Vera Fonts Copyright +------------------------------ + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is +a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute the +Font Software, including without limitation the rights to use, copy, merge, +publish, distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to the +following conditions: + +The above copyright and trademark notices and this permission notice shall +be included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular +the designs of glyphs or characters in the Fonts may be modified and +additional glyphs or characters may be added to the Fonts, only if the fonts +are renamed to names not containing either the words "Bitstream" or the word +"Vera". + +This License becomes null and void to the extent applicable to Fonts or Font +Software that has been modified and is distributed under the "Bitstream +Vera" names. + +The Font Software may be sold as part of a larger software package but no +copy of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, +TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME +FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING +ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE +FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font Software +without prior written authorization from the Gnome Foundation or Bitstream +Inc., respectively. For further information, contact: fonts at gnome dot +org. + +Arev Fonts Copyright +------------------------------ + +Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and +associated documentation files (the "Font Software"), to reproduce +and distribute the modifications to the Bitstream Vera Font Software, +including without limitation the rights to use, copy, merge, publish, +distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to +the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Tavmjong Bah" or the word "Arev". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Tavmjong Bah Arev" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the name of Tavmjong Bah shall not +be used in advertising or otherwise to promote the sale, use or other +dealings in this Font Software without prior written authorization +from Tavmjong Bah. For further information, contact: tavmjong @ free +. fr. \ No newline at end of file diff --git a/vesad/res/DejaVuSansMono-Bold.ttf b/vesad/res/DejaVuSansMono-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9c716794f70b10900beded00f5422deb832f01b1 GIT binary patch literal 318392 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 literal 0 HcmV?d00001 diff --git a/vesad/res/DejaVuSansMono-BoldOblique.ttf b/vesad/res/DejaVuSansMono-BoldOblique.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d6536a5cc256583c156c6e284348ef066c740f13 GIT binary patch literal 239876 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 z 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 z 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‹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 z%0A1R*n{$iq2}O<05MdXEnx&ki3Q=jSm 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

-pCqx20`dygKCZxo*{4ns8&=5wcS4zJ-~4SO=_a=L-V zf-xnqSVQ{durNLWmg4n%GLe3)hZ)`>GNcfAq|Z^U7WYkk+lQ*=w2u`s9aav{i*p;@ zE!^*=TE^xUI@Bh*{O@sM3gP#RcL$-to}+q*zN z5Pi@hlXRTS_T|~wta~DK5R$G=9u@CZ5-{KrlYZCB3-r8KMO0F-ec!E~u6uH9EHa~t zlb0;|qsW2ruN{4>6YWG!WQyn^}}`RqG+Ds32R+yRJ>DB2&M~6Ukkn56d^`4tB~g!Hf^l*pR9Gj(ACY?n zYBC`4ffYyyVqsvrm5#d%-R@zPH_~PEESL4CQ~1?&ml-<}mp=dgZU0pp$7dBCd}2vr z%^Zmvn_pd-%)k9w6Y+q*Y5e2o{p;9XRsz$q)DFXedZ*|Urzem4q?2+ShrvsbqMwAL zA8Lu1dh9pKg`Zi)XRSKR0?yX4)pciQxjZ)}***dzP`WgRNpG18L>ilC80KUZe)hFk z56~!eI`9a8#aT^fd{IoDol%P2sfbPr0)BY8?k4<*9Cc}^&%haz%7I0CU=b5oq>1_q zX1KHWA443h5wKgc(}W)d0zV3hXbt|vcs?=hgCKE#fLKFNEsYb^f|Sc>*I4z%=n0?P z_<8kxz{?uvh1iQY85Ok1jRjod?O=B763)PDGY)6q`0yIw9l_7DEcCMl{oqU$wmImM z;F-?2K96=RNK$~CwG!Qgwi49D#?@#^&n8d4bNpE^pJmNbwy}5VPi(d!z^^ML(m#10 z79g*X-Z6e&zjkAzRKYXsE{xlIi3+7)u8_s3W()cX7GoBB17B%q%-E-l-lodS94Cn_ z53UjJ&A`0A$1}F{wv708AQ&C{QtT*mPSE3zR$4cze{5^wPW_ahY@fG%DLrj^ z9p}fmHt`9-2N;g)J?OjROc?kr@E&agKNX9o$-xr)6y|c4ARQVytoxAs;hXeRk>)?v z+5O||TiCU0?3rCv{USn-#6 zok7YpV8kJg&aj*z+hGQCgb!e>OTwSb+WnF{vn+EBivM}Nj<@k6R@=5&vA0*Q^_1&9KQrQomEZzvwixs4bXMH{1@Qa= z#)JI}d>|ATNFLB>|F*9HZkx8Rz+`|zbqMny9TU3)b0B*k&MyTUg#R{14-4HPyK$FB z*?7lHowaCUJ;=bNMT?(Wa5`K1>R^9~agUxe-MjkqmS#VQkT!OA8-sQH3T^(Pj0M}B z$cgwTUv6^*Vdd>N88iJhkA@J2wO_;>X#MS!IXrq11oSU2^2a6v3{)m0sn(FnS@1aR`F+0`{$vaU7oe-;YTRkarME$CT6wC7^aD6 zF*e`&{L`eQ~q4|J| zvxdDYntp{)_h7%&Ez7C>Yo_KwFA0y8@xoU1XuKWmGT$G?Xn$0i`|&R$?P!VCl4PQM z$OJeA)&zv6h_rbmA18)F9Dw!$=^0LF2%N}(5HO$3nLjVy*r1oHEqtiovY%p}4Qpx?Q`XRN@#rpg_)V`~nm0Gpr5(|VJ)Y%p*)X#5_to525E zf6~K3dNOqL_}K1OzW}Dz85`y6FG-G#i%oK-sP8Gxn6fc1N!1tgtVXPxwaCquoMaye zyDWl1{8_TU0!4oc(4%DP;vbCXZpsO@P9Ey?8UJRm)4(;%hxb{}UfS-A{L4J*DSz3+ z*D@}CVe4Avn-CHaoOEwo(P!~e%ovoV;|1jhTja&{zi%m-3`^j@?yoP~=5Xk|=jPlq zLweds_D^)txLZZkJV~@?9N=LKoxvWo2U0)7X%RUW!X_eo43R;aFqGU5=~D(p7J>+^ zZP~7gd}~p!U6fIa&Fb;ZkofHG#r*ZYcShAary>vCsv=jnTiza3i8rPVmM`+l5vgSn z{dhOtG<{O1!-Sv?#wk4~}Aqq(CH~B5~Y&>I2yG8I@ zI+0WOt)q$G>a_ktdZo;E9wgm9H)qI}RAW@?5B_Y~ZoVwhDLV*G$Ir7j$FV(a$vmI= z;_{-aoXCG2_s4qBbx~7VJs)&F2kXSz-^ZBlqQC!v*T%Ca_Plj?aPweR^cH`0_H(7H zvzxPf^BdB;Y!feF$Hh;jF;TKV!S}LJCyaN|hpE;K>cO{DA5;ffjk8wbwNUOrBZ;)i z8;$c?Z?x`|mf^P?*7h-uQa_f%9`3;_XhXb1wW;N4#A_8lL)`B;2Ud}1ijtd=+Q#l@ zr2HY}B{W>YoZx7~YGsETt>^ft*x=&HL(iu81P+;%uUD5t3B35*Ieul~cPgF z16tX|gYz5vrN|$7Z0Ae1&+^#edgT^-mRY;Pj5NXZgIjzM|IL+GYZkRV09#66B=ioy74fch89*^FZW_^bU+4w~(7&_&gBSn_m&w_2{K@ z>pM;1(KJ9qf%)nQc)ttDte^sdPJsg>M2m^DFC>Lt&5oBc)s^SE^7|k0oOAajON2_P zzrNoGsFv0=J@CqYG=N)F$i>%3REfT&THKLK$Ym@7y?5I_yeC ze+$%>d|9+x)JLtm(F#Wlo>pX-9vIfVf4kDQ46H`8_)k)mq7OSY zB#7wyOEx$-PG5MRe{;Q+hW~C){^v*A%Z83DHF9eE5I;`l8LZ`K@R4NLu)r-d86{;T zhD;#_k8xyu!03<(tl~zb@s_vb!J>2cfqfy*>|yGf0*7S2o3|b4c45x7QW~S`_gsVi15VbCm-%%Z}D!@S82IyYVl|DBzR)a^Za$Z`ZfM>pJHS6r~@9%ow@c*d*<|E z4g{oe5HCC}##cLt#y5$^hjF}ywOEO@z&NN@2;h!`D4>nv&H*MJY%-cc?|7~7Kp}6d zsX=|dPM#dqLn0*)Z{sabLk?B2?S{g&i4UnJe+Y>d&zWq>xI;E&seLEra|r9HBMU|_1yW&iBCrT$ z)jRPcV&x=kXw}jWA9Ow0rH|#gbKeqgDt#$b;Y|aiq*9mN&xi5*+b_E=<6E~YjB3#& z!Km01rcEvS{1AOoO)m@D9l=6mL8s8sMGr6#5jF{$DZThXpa$KIbJCnE$wRIHtb#td$m=W53iuO1j0#-QFKkmCc?06HcOCqBztPrC6h&~n5CQ@S{B_S zanXWr^7R=j`t}Y<^&2ryu|~G=K6NvHhW+f`ytyrTd9Sj7-MeUvn?Mt3j6R|tnwU&F zAj;Qt#FvUB`GM^4D3aqb)U*do(>*IPDQx_>7hdr@GA%sLJ5lc+wt{`nJ>WUVFZUhv zE&o+y#Y<^o7A^i^kP{a0^TOT*8$xG$7s&~a*}R^qezBUZgUxGl_wtrZuYb0CVMSqN zdu01U`|o34kc|JowEwuAKdL`OlEnW(*1t$%R%dy?{bxQ4_UgNk)jdsTlf8`W6v1MWLYNdrKKa|45tn*|@s_hQuymIeOZWd{?A^kB zS*mn5=^! zCKE`TG>&47qd^&m(uP8GNo$jjwvOQ*V;~fiu;T!R zQd8SI1uc9y+uu?k)^@9@-$(5r;#xT-OgZt|E_UxV<9w^Pecq0FIR?M2%;QMf^2;w< zlCZXm0I%52xQ??;Q^`d6`w75x+h2_LZ%9w@Pp*H;Uc7ERqagcI<9yjoI&XYWN-$;- zj(iCilFw_}v?<_A=KAY-g|VOesfl=Tq2b;}6shv}Uy% z&RG=NDSXJy2P;Udsd(7aDV^GF^rhi&CZAj$?^&uZpv|}}A|)|rYwYe^Ys(CF4;1-^ z`7mXy=40cKP%lr@5ge`GVDytCr&gx`Ke;?1?6}-Jt;N5CM zJB<52Xg<*lLMY+IL#K$Hh&}3(i@gg=^ji1RBRZ4%KEd65N6g#0Zl;-{$TR*%?iZSA z3z`RADHe2vbl-m@_@XmGXr$TQ|C!)_9%CjvQr+KZeu$X_b<9oJZCyYQJI|_v8p)Ru z7cKl+@U1?XMu;I|YCsqh}J76G!z2BrQf6cVx>G@5-SK^)Gd4+Z2 z`FsugD$8KkA6lBaC)Gd^SeTd09{BkRc)B64S6>dV_gPB6TOyCM^8;@`W ze(Yb1JY*pU=l>Tj%`zCn|_OC(WIa8f%Tw^A9Pke70UxXOn z+mD{>Dh+ z?J3VIv1rQt@E-bC_fXAH9@KDaq zO!G?;?c+VbRoLA+jR$XuewFs80Io{=xypUh^N7KdmG;-0oJk$Nh#* z?a!y@u{U28GSA0k?GWU^i45;{RNR6b^l*fQ11w>cM>wAJQ#!WxuO7*#Pto=5-B?Ubq|KC8g$~CbDHupi8=(7#CxbHd3+?IYF_H@7CZ0)D0-Cx)d%MlvWebu5Y`esN^$oM;zfn-r`ww@adBE}* z)DST9M|CEGWCw4JmRHUE5 zU)}HFz2O_XIr`h~3hSPoHv9BEwavp*k;C(2os*};(h zVUawrg{P}+=AD||z5DD_^Pt<34p)x$UBxU#p#we5D+5Ljv~7(;6N=QcRm0g7MtA-E zl8Yt$zmxZj_Vn_uSbwH!+WvA+@0?lIEFAsM%!~532pLh#x=2&e5qm9T>7}*nE-p$- zTXb<9-@sl-nKC#rdCbavD@P{-he3mAeMpWmO~q7d!8A=I`I^!(i$O2yUo0UgnkO1@ z@zF&1Xqs0)^EAH{uu~a;A5UTZNKUeqO{+z0PfIJ7ArZFTQ#ue!lp{b_DHdu-HDDQW zk-anT^z1ZcY53|E<272H*!~;0Q3P zS3Bm8tgIXt$|mUBvNJFFCB!dkSXooz;vuI_-M45=Uk}KI`UTBzfAU;)u)J{O(d~=I z_UzKa^7h6JU$Xb5Nehopi;bOje4(@Rkvp5RvNqjOaN~RQzgOYsB*T;1q0?WLR_ogi zL$=73UG;50wzRkA*rl!tN{!Ow z$4x#wr>$B(*!0=P+`P?SG$kJ6Ur#wOBQ2q_`NyL(Q{C&2PHVf-JT=qZyXTYw=HqD~ z_(>{1jQK6VPr-c{_ksS(FbVzj8U^ctC@D_z+ZS`@1NprtG@YGRwR^aWm)F!SFHUA% z_|@WB17iHG0)`b2smbeVJzjvDXRW)qI4x)0N9)#pvLUY}Yev()P1AcN4xW;Nf}!{i z_GGLb>0lm@uLbFjFd>U=ZGAEF5w@?n2o-j4`V#}E(UxXEe`!WUV*+|C2ni<~MXMH& z!`?uW^n>DDt$e-<%E#<;wS3@@*YiahDEF}Ln;RZ>#b;X28p zZ6ES zo|rkOa#&VyU}njLS?Pv3Q%Vg%qkj_X^d#14xw1~M3y?2JC!$Z7ksu#7tqW+#qKj*= zWTT3Q%*6ibb&(wl7V9FdGbWhViY>fPI{*2UglvM$QKu0E&<^+KDia5>NXJtzy`Y!uchdsh_Y< z%^RLr5P#ew(R;$p={eK;dV2RBwmYMj^q4@{wLS4(G>Ahq8GfA4~J-N;XmA^M!@ z6kbOpi9ipB3Lu@1*aMa8RR1)U|Gb}d^KbjTM|q~Zja_|RW_{YL-z+-D(zmxQD;s8| zbBN52Wcz*%$a{cPLY`#n?3G74^O9@Nx}asKSF^KEmhcO?Wwd)Y{HqDG?A_TRA| zqOtBogDGyegD;tQQi}WxTdsexxr6VSB?rNfpq{nuGSgkNut4lc;8ZI1^={0s8``#& z{eh?nXq7fMfeuy^@sWSD){TdweXC&qd>UbV4Kow#RSS*neVOXj3p z<8i%IkTpIh($a0>?RD-~9Y?M@K7QQJaUqV@alK3848>8F?4?nMm-O$y^hkNn8AIZt z2UTWdR`dyJ3GX{Jws!iA`eBC+cCIOCQo^UlwPpKkl|Pu99-Qry3lB_B>1Mq z#>(BM?prwe5f?r=GsNG2Zqrje3lpXUN9pSm=4P=gVK;4pBcok%mQ_ht+m20(kDYdG zk*n*`pEqUo-twPk4*a@vfYjB)vBlH(+J_Ug)|T1<5bZ(bK|ki9CIqw^&<_&|lMkdK zyUEW8!H{GpP>gGxq&A?giP=6p^%$>Zs;TX7iggY}eqo|BvWA)wz4AR2#!Uwg0v`iYdPOiRy!cp!Q#BN$He_#HSK(DOc#$A&Y!fi z4j8KGOIALc-07Q3!@Di{WJhuFj!%}f4VO0$+*~`5z$J;iLPWR1=+uJ=mnEy{mKLu=>8vVJ@-L>K0)>to>=g z?0=JUfe!zRoO|t^|546;c#7Ir6=6R?_a__!-!>Bx(p7}e%R)@bhuA<+PC7OhoMVN$ zLHmc45i?~$n_V&H;b@aiygIju&7?Q8!ATc;J>qt2E^_{jo)>n=C@@nun^9PL52A;e z8;UVUVa&By<8*4@JmlnP3$x-8Xx=JXU!+GBvSajBJI~%zvwPNzFm$o@%qXjvI=-Zv zi=F+TWiQlJ?;h@Lf7Qx5207u!jDh748bI2VtquZz> zO9z-KdqVMyjP9edgIiFiD#x#^X)?+A;Aeo%M&OAK7o>hbbYx%WO7{bd7OfXq011M} zNFIb(N?E$pP)A@-bP_Rcwi;;F2^ktpnng>=jzS~T`AS+z=uXneev=1ui?#?U$$6z; zrTA2u%WGEb?4wRDTzX-p`z!7%cJ-B$iV1V>-}@GyCbXXhXKaOn2Ryz1LW;Hs`8@TE#gOStIUnG zu~A2}r=`uK_SR-)*X|oxzOSxV7q4(1e)ibCd&lHwy5>~On~)bCnlrIyMnyjiiEI|Y z3(yM0R*?ZfR$1bD5nvVuFWC&h7}SqO7!nGA3C>1D&j}_N(yU}(nWYF^QmCSgVXMbE z#O93e9gsU@Y+B|1L1i@ zIv41z(1}R~H}M#f^FtHJie?g@0_-3fGOt~(Ll^8CYRKv}zbwq&DskXsLwNu65cvR$ z^Ysq*c2HY5M)nGeOOP7(seh?{ZfUWrT~Pnp!i2J{5SQ4zWPcwA?_lTf%y6Vt@_&u` z-;H_M!M6agfFA*HZg;medg)zv^)D>&nYjQLo=Ix|R{e>(oa_wbPopSlWQig#br|`G zK#Pxxg-WSs$Ucvqm6ts@*xF}7^L#gZ3%kAp!y_W*H_wl8bnKVg)j7g-{-GO(oT92S zx6I7x9X;daCaKZ5u&&9cTYBaCO3z2F9F;fw^zV(ST7>i?^}3u$4uMG)70}OQ-JL+xo<*BiwZzFV2aAtFI@JN1d_2AM$TR&-7_38G);=xUAG3ZWxgcn}Ffv`QAM+B}DO!F{X zoDlB@wcTud|x<8^8e>6lI(F|I_RZkh%Y=Lj>g zj(`otx)4xA7B8|fDGL%Z=Cjrz(iLxG%oN{(=}V93qtC24qtAY6=Fxg&2(5&(mGNV0 z^e1C%^XPFmJHf@3PRx{*e*_momj4YZ{7$nsyypHVs61G?;W3z`fEM<`_$|qw&@=(P z>}(8VF&On+Z{v!+QZN<1Th}J=){F}{n<6>z5iVd{3IqqPJhM`P-bty&t8G^&JTUf? zPSI4`D%W+wgZ37{^?9sI1bNmeav#|`VT^!0C-x;QGzxttF@dNX@`~XR$Pe-X$1a&O z3j5cO?B#UnG>d4}N0pA8kY2HMsHe+#?}}sqE$6#V)U6c8}8FzFFPfU-wLo z4YJT`JmaL8ioG*>gb!Ue9xTJErF(vqW6|~-E7mPNToD%9Z&J?z)p^0ZhktHuu`>ib z-=r`sv!t>GZGIOpv!hrnrZ^L^Siz7 zTey$j^ycsT%N*Q2$1mGaberiGH!u(5K6@5jUNCTOS$BIYJB>bM`+&Ja)79lI@m13* z!soufb;yvd@6TO%X>Fn1b4)*G>s90FqRmx3dsb~ON~oGz5uP<;E73EiLTW$cd=+bh z1yPdu;TT3SAEEyFyw=Zr22NjkR9}CFe|V-k`^A|@=V2`$ZlXOQ)&KdsR0sm_t&j(B z>ZZ;TaqoE#1g%8gJuTXf6}l0rIuI0z!Uz$W*dhstj6?&R&5%%u1OX;M&@z$z2YHeM z-O}6&#zZs6ajgN~14m6uD_fB3YwR7a7bLNS8R}r&a&;(-nGSXDI@B$ixcM5RfZ4BV&!ZX5@Ux(YgC_B#cgcnnksEr6?AhWrRRP&q=il6sU&yp@kr zl4tVFnwd$pC#D9w*0k#N{fAG<7+&Ao&cSEqpbg$vvv(djYs_%4Pb!Mdt1gVU@v?Is zxNb_$RIRgCv(?fny#KUptAQ&{&omxsj?78)G0b>!=tdT?X5Gj=vwA+94RimRr{!!0CU8$Z&@m(51LC_bn zo@O8p%XE$vYPLh^kPu6@_3@Ovyo@#BnW45it3h+N?ASK1q>GJnMn&Ji{{8!U&x#l~ zW3FNH(-VT7Y)k5!;0=;{*}~J^ah+F8W>Eap>bVP+E?=3QR^BVfDL6S`d{j=Ncgm#g zWAiqzZ(J~=9H&i?uf={6c_jv6*2qBu`uClBBW$E9qJLt1niTN|o5+nem}wWekzv+X zV(ZvtZ{zvEZXtG-*6F3w<}EcuO(=}Cv(C+$IX*b4z{eu|WH-H6(hF&X5FmsAfdoPc9YW|Wbm>Kuj({`~Q4ugIAc&%3!$z}#3i|Br`JRxS ze7~8yn`}V;-}nEX57?ZXojG&nv^g_#CbQCH$n}k=*}HDmkRJAu=pG1D>KTz7W8(wKr_(Lq-oc-Mis!#ezbj`>*l zXE7~;)IH>LDeDs%5yL}1k6vZr;W6_M(GL%e{=1Mb^IL1km-UUX2o}hZg?!MZ4A9Yn zIgDp_jfks?bHmCggdPEM$pozA(cHGm1ey^R&>)o6^ za~g&3`)uF1a{iS1O1yHWR;~Aq%Fq>TC=1NY&NHM8?pM)wP;yFr-@I6#lrfKN@lUQy z(&rZySM-bSSDC$d<;GsQ4F!7eRSSEnhppimU>;pqLOzx^;+Z9ROoFgFXI#GwmxYM@ zLVBK@-Pl@yr!La_Hsz6s0JGVzY-;~>cUKZwD}ItZcuui-n$&P~WMlFCV`KVnSUe+R z{nF%#vsYD>EgGHdd}a4@pzADN>~s>${BdP3U(vQg_7az0 zpgWER&>ga)AcuuEtG565!;RckU|cb1e;>w$l`Qg%7IzHcwdgM2*Xg!o;89u-oV3_} zc%H={Yr?flxR)-e(m83@cEXwaX3o2$D%epgEaDzHuyvGq7#0Sp<93Y^u9_EidTt90 zG#N0)YS09UwuupWILBk`>dpx99otocH9EZanKd{B|Ax|1X$RNa@(`vUYp^(8CdVyd z5J%`hyQ-YKAybK z1DE@Fa_HAOasn+%9Fw*5$0YlxGBI5kfFK4 zZvkdk%?p~D0W-}n1mr$3a@5BD9{zr#*FH0P%nHF&UAKJ2bJg`LmanBRt#52xukcx4 zUDI#dC#zOm-_o}RMb?g8zd@^SpnLGra%T;)h!YUFPxKY&VRcSJ5qYOFEytNxRCt6p zObf!U2sef-yMW9T(O{XR^y0xe&n_JC9lq_u)&1J~^_nxXZ|K9m>BR%n9~<%T&@dO* zs`-aTKV7rxWP{qgC3F5#SC{dEhlh|pqw%p}Yewb^g^RClAAkZ;2ZGY75?iCoQv$`< zn5rp-rBiyFXi4eHH^?>;)u*(epZWISH4TaF9~4aA3vw~9O86uTWGQkxXRn3?i)$UQgR+2upI68T&I7$kKqPe{_70T90#q>&n*cX-2u8 zlUn{)qcnuDg**QTMx8@c@*s`JARP*f-V&*qryzGZATPz57Bt> zXWej{7Z-|A;40KxQZw#=cQ9zFX(;Q08~G4Ju#G(jCy|Ckg?Dl>Q3t20q=ZyF$VspJ z6zbJ+B=u{eU(sVq+myt*Cyt+Wj>*J(2fDi%YLlyjQ{t0vn+$K`$)N_V8bxW`NxUh9 zh;g4TY)$R+;dMgjO?t)rvH%W0FN$rw)a1Ycr?4Rzv1{KrNmx!;uscV6Bu~)q%c>tB zwq}zkfHotlU}Gp6wE;w$jD*cO#ze+>w|z!Njh>zK<~vs^++J4AdOB`>@nWKiy?U8A z6gavS6gs+!2d7Rq|6yKF|N7N3iB6w%$`NBn->rgv98}iB0PVti9Di^ zmIp2G)$2&kr;MJlxEpaoS`2#F?xPJoB8W&q&rI4};BNRcoowDT@hU;1)I;E6*adQn z!0ibQQQCt(wBSGJy$Iq@7hfWmvcu_A`rQc+_t&3mji0?GGOl>f_}qbXKV29fP5Kkf z@1A=4<+S1?_fm1Pm1z2d`}+b}Ha`!7c>2nMK^apGzz*zR#?h)S85 zrqG}So=Oa5DuH_}p=qi3iHvD=c4>7XS9X}_CHj`Jngm7~zxm#@&_p6{yhhaFd%n-h z%X?A`ep3`L&?^5g-grY;_xfx>nDuu1>*%KxYs`JpUhn}~Q8pwwI!QH>5F9_l9b~yT zRAOZRPfN6zE`j9Q2p1`yljD{eGl2LSBR{?u(OUT15@Sf{;$^=TKHj!FD$Q&6uhxko zcZu;9t$Ovw2g0LxhT$f>6@8-ploL<_T_SwKju1pm0M*|^ZqgEPN z6}(htM7{9(IAK;)@POeOia%MugoNJsAiCKQe8^}xvC*(*HBnCY?67MicEP{ToBe64 zc(B#{*$WrG63SG<+2e$a8u{_WyPqh+9%lzw1iKvY{0VNyO^^wrtjX*JAy|Jd%bHZ2 z)nFMg$O9J;by^77T;SwZSm@wJ?}S{srVpoABO;F+4{c6pM^VLN`;U1x_R~%)phxL5 z#hHIzk<>y#p$P5n_3TrZZhmy_v`|h7x!1l(TsTe?N130ePeCl2Nc?uh4p%|X%dj~L zmMgVOWMd_1O!GCEdsGJ$z3>mB8UgR>Dh(vB)i*E4m97eyGjuG9Apa{o>dT)Z7iP`c z7P7l-cRoFFEa#!?;3i7NN*Zw{|K5ZJh0UvrpH_l-l zAhHun%!fc{!FE>9$PR|usvfv3;oC~bM1A^9nCa^ujY0HTy^(~GtPDi6HPo2~ia)iQ zKe+L#@zkp*mcE6)fB0>JgOexB6|{g5^kYOnKf<^FeLtOQNUpMenj%?0w|@u=rqAk3 zte+mAw0$!0Z~J+Rn53qATX{EVUDxrmqDtWh8TYm;?{2Xawh|wON`K7V;EXGubQ7|T z%(f$BXN;Cv0LG)#2onJ4iug9O1+t0tH$MzLWj}-{?EQ(iAT$nYS+*cAD{yAihu2J| zA5jr@^lIO%wk-c?Exv<))knO4T+q8a=B&(fH#{{Wc)|$ru1;t43keDhAXa_3_a`YU zukN#581cnxuY1$UnM;?VwB%c>6^g~=ZTrLT<8gbhs?_{pV}@LqOqKhq%GmtbgRgga zj2Dm5g3Ku4e;inntqqryy743C3c|=*MtpV-R!RyKd^S){@fwPxnl~&0WR(5L{Ln!e>oVo`!DFhdU|BTA@I%- zvLb3A9T;IhQ;1u_Sfl*s)QSAGO}FjI+XXt`)l-Udiu^s=dQ+heJ~gQ?i}ww_(7DPdC(7%|8PGT%r(H`2hX*g zV}8&rhXg;n0e*1&iIC9q^L-2zX%Fi*ZhgQHiZ|Mg{}(?P1NxqY4RqqW$Tst#NY(2! zYP}AzEM8+kNpWV7Et0}YHxmz88yR_iLUlAfWBxrSL+~W2>(;LMkRJB-BNNHZ@)DXz z51saj_~2%Qn_t2DPe?6%bpZS0{w+x-p`Xq@O@vju5h8A&+X*>77dGtuO05wkN4c#G z0DapzeOP&R^PiFvQHB}SD4q*z0h@wK<7#F`)OvVxl?ir)sCW#a<0O(71)*$00{!D# z<*K5(>Vr9b{^BEqt~7si7yjZifmD;{ zuMm_RUrB=m;TSnge45J}wUe{{!W^d|U$C9W62aX1!G(z690J%dBRq*W3#?J;2Ubt7 zQ<1Pd-@GjS@d@M%`J>0w3>xwaz3U%w`-aJ>+GimNiX0eD-=_b{C)KU3jK%i{zGy#yUhL?dG+m&8E-_ajDA*3QtZUsC9;#kX*RPLhG-C7WBP3D>4V%75ix=$ zLqLU#O`n!-Er!Npa*ivaZ@ll;tOf1^T@=B_6y}tSSol(irvby|_y7P8w5n znY6fi(lzvyo2HX<*<_n5Y5&*u1aVveNQ~l}j&G&krEPXf zj0Cp}>@a_D3z#*m)`(;nV7q<+fJOhR2L-hyuh4dfz-@Jou2ZM`p^JeBreu&>HTHE0= zdyV^s!Uqq+su$eEx~X5k#Udwm%^b+%?#|oj%8TUkJI}$K^7N@8#I? z9yBXt>13-0=GNuuSMmUpRp*c8O3hae{wV6C%E}^tk-M355~$;wyXG1qKm9S%wP%lX z5)qOybYl>Gm7WXMkphxM`pf1vG~hBe7D+19=6&;;djcuVIC7PcYb6ner%7lkN!v-t z_Qwze;D3T0bV$)lx(4pDjD!uPEY1mIVuE!J%D;QVADfJbf-Kr@rQQ?t6MGxy`wpp2 z2&HdQr}$*D`=MTgdp0$%-u(ND!I=X-aB&42ujKYI|4M(DTIU;m^D0WJOxR3TTm1z6 zOQ08`ioR(dG=WI*^bta4R}CAP+LxZEQw7p8Y(C1yUlGXAVw{Qt?c+O)(hrEA@%}k} zX0eiq*zxC^OkgvUT~Nsd26r_XtBLRk3uo%a2)jtX1nt9@c3-7m1J3EJs`QX-rKfZs3Z~DzAImP7`i@@Y~!CXW$ic}Ry z^!8HhN~Q{W>T&O=+rP$mMC$TMpu0oq{*QKhs6+)GFJC< z%q(g;Vt4@bN=<$$uZh5EiDa0=;**&1#K&vF}`W{unXv}lt$tg#I73L zU!WSx-diC`y^6a81jK3Fa1i%U66Qk#bFu}aAZ6#!TpxlMkG@E^D#Kn{fTVv8eTAN1 z@X~9Rw(dwjp)KT^y4q5*N8oaa+@436ZF}CmKk_v{fl?{h5bfUP%<`p5)~aAbU$<7R z6tcpJ{{xlea@0>z_mNup>8HG1E3Jsp|DIaj_Ww*Vc{}o_$gcJ+WLKjHCO13HNn%#V zaXX1|M1r|XWtD+hh|KL9vm3(p#lHCkTMwczdtA|T!J$V+<(Bz-|NHbJLf@M_#KS#w z_luQ7R!_ge+cTNhiOX>Fi?3-}dkFVfb_(K{$TwdY0Kqo-GTPqTQwsh)(5t*u?fspX z%Q6?2#k)Q7mgX6cM|;wNo2KPB4w*eYcW%#uT2f43#3==)i+Q+JzY21$<#I0j*su`h ze&vLmUT4PzJxN;S@#^G82Q@vAAENh9yM8CqZS88j0-e$Rm~U1tjzudS>({R;jvYXx zqJhs4a=p5~fgXdr-~=PqWw*?)OLsb+MJ@|#a}7@AaFc}fGI|1Un4`x?yp=oR9US7L z92|rb*Qd7Cco|=9gCJFW_W1CjZ%_G&R>sH0CX7WQsrltYq>x^|*!+tf!HdAZ3b&Ot zuqSLE&mbh6=y^g}LwB(8^^|T(hgCZC%kY%M+|fu(w$WnyDz7ZKUNncVYneiOf6Q06Br zaa5#fKy~S-5x!3>E$ZjH&3|?r{qi-x+Zv||pWc0jjtz+S-V_i#DkoO0ZfNrMD$SJM zK;<9r#f0SNUR{taxwtnit_xi@enfhYOhRIcH|!Pa2b1xm6H$kQWJx#0M^r)Z8+KS1 zqv{J%xlEt3{I5l>i@e7FR89a4H zD}32!2vI{cQ^{7tN0$x8k1n?bR8$8j&Yn2&265l80lb+DZHSTP*s)9?tf>bJj~PQy zwG7J@R_qG3r;_lax8$jnLWk1?y2917@obZa^C!e3-+t|F`;*E#5=efg9waxn*Vqw_ z19OwEl0FfkTe4~{hezuJCxuV?If~8sF!ZHWvQt6G&scg>BWr8h3(5z%5eaplSaBZ- z&mDsfNja8g(PbLEyy7pe9H%-djGL_rAf9i!U8TR2cw8qAg3f%COzhi8o~&Nw?mEoJ zbB;dT$+5&Ic2RKXh6eg=UP)!nHzIvxQ1PFjBbpABG9*u&en~={E00>uUQl91rr6LC zhqG$jdL66D=tfwDM*J=eRU|#N`b?seVunx$+Shf65ID~uo_XF+A#PLKCzE7m^e9f1sn@IHh95w5at6!;*MSEH{~VaKfz8Q-}zX-EkN&7JKbT zs>ncS4=X%3BVnNMq)#oW5r$-I`y3&GYWUKF^e>+nDKlzOwx>o=Zs}o0{;@H=3kVE!WqWDpd z=+&qGlbdju`7hAD0DOh-RNOC12*~f}E-&vT{#r@PXp>XGzSD>NRDTg=+!BXZevDED zJmcqBN;V5*u(OWNB;g4e>&H!7X40SeRoI_kI{A56SV{vYWjhZwq)L?&epoj9vsROm}zj0g{TV$IKyhJ%-kQ9XL5 zl$c^jE&VPj>-{>d;Y2u=RctL$3q5efI@K5ZXgDov)db9QH>s1AAc|PDzyoBPWbsTD z&5bmLuJp*eB5iTV!-6TqF?fR1{-*17k^WKac8$2(?>ro7zvXH2UusWk$_F7oppAPB zw@CVa6PdVUfHsu=RNB8+);CxR_R9QH(i?-<3s)jS)+726SQRnpMaZ9yRZ1qPz-GY1 zKvuEh6PrueTT_t6L=P?DGpj-{#H~i6bjYQM{<81STyOVb`u>Kf2KpAg>ZzIp0feb}=Ug#uCR0i)qW{{|p62=vz0=ce+~!T{VdMkSEEwp4 zH&8M!xIFW7x~F%=r3>5cR1GFS&}WcpLfZrBAe{RU*y{WrI!>1AW&~1v&D{>Y7`S?yI;{aCz!i^ou$yox z$-)=(#~dwrRyZqMiWt|wM^&@?2G2pbv_8jOv(4!-r+MDa;zRTdp3eM|&YR)n_)KE2 z`XMf^XY4wLk3)I*7Yq7~I=PeVIy^lmiN`l~Lm&fd@W!P-r@~?**_?BRLs<;WK7s~j zgjjuDW~fDT1MNv?t4EQyUX9i!D*yO4$oVDb4DvWx<49jte?WgNbN>o)Kl2qMD~1XV z^CA0zPm`@VxLQlUiAgqB*OmN1S61cz%>2b5&`_zkhltICNN$|>tero z?s|Bd!%U%9UU=%BRJVxUo1>E)mb^04QCmmmHYIxuX&@+vRmkCQ-#h>aTR;=X_)ibobBl*(gxe%~4ydnfO;7 zEuvFg3^Si@32^*{*yTBYk?Ys*YPj&{J?SX9fu|cx7o{igzLAlnWfVL=c)`PQ;g?8R zPSW)iZ@9Y73yR;U)<{ymDfG?Ykhik6)#sQ&uPNGFmSb&g(T)M0fDA|Z5 z1{`KunD|Q{8c*jqzNGq`n37M?0;huxndV=0q{&Z3KlBx!QlmVOIw~4A3nV)^v=9B{KvMkKhaY=AuV~CYp>po#e)O?yc*b9mfd@ZWT;rnn)h32w zkw4=I6BlOGS%GP09bqmcaU{*Ai#=XF^{VSF;!tY;su=K1?lxy~iAd3gg1(Jy< zdToNVO4>Psqv2paS>n6ee2Kv5U;v1N`a*dttj z?DJ7srXsxPxcO9%h_Q1oQ614{m9~=Yjg5DU2HdOGR!s5o7M_gK)zQ1N%F+)L9BO8K zkHFY|f?Q!&H_WR0vK%p8V|C3#*nhT>j28@alK4>rt)|1B{kA{7*~{S`Aw`)1*ix3n zv%xNr&jq<;lBw$kdMtjb5bicLC1>eKGJ9%N*c)UR3Ew!D==bKOH1sGMkd})F@6HI@ zWLkRRtj$-D0i-Z^M4G~Ri0)F;AbY%qODC7RtEIc0w}~B$Rjn?|m)>=9YasPYQr!nX zLR4zkxVP7A4T*9dIkHDc)}AcqsERF#{;oJ}_m=od+~~1y_7}W9{ysIeiu^>zjDetj zQ$DQtk7voDW1r;2E`6H5MN+cDd(peAO7rQT^uudpT{#M*5X8@eq|@SmSR7+xpS(kJ zi2<81ES3&SLYkc^C|jfdT!v?R#yXw0|DCAf;DTD~D3>e5KX%k}ar7Z# zN=P^9PZRRXA0tTbp8bh*=-tl>Qm=n6I53^$@7_I%n9jtllssE%ybvt=OI*U?`T;H& zu%70I36f{yI}@3$9z;ibj3O7$$7s_XCan!u?NZsd4v5}S^686y+WMn^InmSZpV9x6 zy0w2xKBERQu6&SSPsk#oj}L48KyQfDFZ+^AIDh^|Y`QtFU;b}&S$XDvK${BoNdwya zS!B*vGl-nni2yhagPhvpu3Ty2Av$xd$oPuWcdPU1YsX1)p4)rw?v(auKK@eynL-*x zk4HYZ5SbQKaw$HwpLnD4R9wLHWEiYKgFHTdj8V=3qV5kaN>E3@1ehH}29;cCTon zZDes|$hwEx+}(yngv|^L@ze}8#(DnBIlAQW29I-bN)ODkMmZ9eP;qp% zx`|x88lataoGx+yg#Ovv?S1T%D$MuDz+OWH-)TZ+yI0@5pXrR=Szn>;p=g_84kB1y znB^d>GGJgW+sFsF&x1=r!R-{2Qa)8tM0Yof#2@w4j(qWedYfDN9wr|Slh#F~YwORG ziJDO~if+}sqJ5c!lz3bc=)a_oNZ$GL?-dQ|oiyUIK_3^k;A8p)l39DJ8sTV2T~(uT zbnjmYX|65$mdmga^HYHFr`Q#CYL3-&d3R+4R64#)@rLTKDMX?IlLddGAs}_g4<xBF4au=6!@uG|Zx4;xA z8g1c?_~Q^7OCNIcUA}ODtMe7&m7`oSO$w%$QItG(Qwm8p&`Un#;QR=@98{3kd;Xe1 zV@q-pKOm$aC}_>%4Kuww_slxc`Yru^;j_!K7xdQZSZMn`CQTjYIcg zSmWQPGT{hwTr$V^ba}y{XlRim3BDI-KjtC-hnD**$FK5VwKQ0oEIbtO(DDFsV6yTc zIXFkszaVXtjBV07MevK#ih1;7GBC54L=l(A-X7S{v*hCCTl9&P=pXh(8)gdY$a0J7~oBDc97{)7+XLH3WQEctVoxNYZTXfgRc3J;ip~3k=Mv9O%AY-Mf{IgWsDqXDU<2__ldC=QrXdsP$Vc4YzY;-VL4FL^% z5X)n!YvY?)x0X2$Wt)!NN$ZnTJWB&X5Cw$_`A3!bN*`uWoX&z8mn0|U_dA1j60g2X z*W1%s4i)4LF@U}iuORB5Xi^1zUb5@J&A;)unw}K}s_fH30-xIDM0SS}$M86^blsmm zUi%Nz|I+DWwJB$V5iKA$gAiLf4Eh2sp4<{utHV%+B$TJ&kQC&Vpar?;TKrqjM9p9hn-EhSZ#36!iRD4N1A{F1# z-vq@e`Ya)#kz};6mk{^J1k$&|7=3N?-s3^<`g(8sP;3nJd+eHz*CUXjY+5UQ4;hN& z=N8$iDFaAN!=?kH0ofS7L`_nK%7GepH+)9f?_rwdUnfdOE9pB6B)7nU^tpiNL$^4l z3@6Q@IZh1$l)7NgKH>Rr_ra(B?bgv(HL;>hS8l(226>c@YuQTYt@}oFNHY!~r|J3B z@VT3Xzj_q^Le^~DNX)r?=rOX_5HRHsT@tB(h|jwL`kn-OVKeozMOL%jQ11H#YpN9o zADH6Ht|krSN)i3d|E9H0Wn?I+^|7COQm1@E%q9&a&?%BWLSIO6APQ2JsR}!qMhB7f zq%1P6dCbDlpgE7Fd*+iKzr?41w4^uvDc1BJi7*D2gw<6{;%g{^8heAJNm4k^Zt%sL zO|M`iI0S}*7%U_3R5uR=NW@bUB_a}4rv2%*a}I-Oo*=wXq>Z-!4`7Ke^`V(`x|2xF zZ+mLCkocI$*EZ$8_;GAJO&|1Cxc(*VYfmAD_zcY59_YXkDOApbBNpI`HynpVcPzF} zVlu}TjbTjS090^B>2*(3#M&^*zkh9}{P7B7_O73Pt;`o)8%4V$GiQ!{dklLV(}aJEE8sUYEc-y%@=Z{MfJ#kj zCOd-SM!dO9akWeoRv&OmyK=xeFZ6})5x^F^2fc1Td`g&O?JPy;(U^4l6*(TCMJi7A z6Z-CcB|LcIi;2dmpvE8f+3d0R%i_R3=moX$Sj86hC{u_Mw>9xp6I691M8u(KGIvs;Z|N>xWf`j2=3yhR&X)^L$oN`sU{iTfW=b z+2@eIi*rqRc2x9+NqtA8B&$6_o(gbv9a492;%3aTBdwBNz@E4RX233tKZAg4>3S@o zlEe)(;w*hQP~3!LXM6F&)YP_^HVLnOtZzSSKJzao%VNi6oGp77jS*P)gIdN5xIF=mqjh9 z9^5r&J@fL54(?1{UOD@vlF{Rf$dQWRbib0y)>dI;NkQ}@<0h=o^{(z&oU*y0W>aY2 zf!wzKTZofRV!YV(!-FMwyVoFJME%q9Wc`JRQETy_y%2|*8~ly>D>rUjfiM08d^#b- z@!dlH_8YGofd&1Ebow5RJ)M3ba`f6YFGdR3=cFIt3T_bpBJVTGPEf>)L)aZD<{J57 zJ65WT-Drj&3AfDUp}4mFxR>wFC(SEDrD36m2NrpSprl{hgei+xwY4Q4Za#XL&zD_I z2UUck20XI^{_L$C+&jk(D0!e=S2EDFEjt$G?1-YjBr^L3E?`=*(cDFKck)p|t+^oH)$beng?Xl4SoGt3 zSGUQx%?owHqF?5@x=z7IJxYo;q(-~AA;%svwtU6p!zsm8nTIpV%Q6lf(l_Q-jDnqi zQrIajQ{2QSNAxP9Y_-N<0*8cy*NO9l?F*Lr(NmL_D(2Avf?NCP8#h>NxL?>Q>G2&m z##!7CXUi*oK?pvbc%ubLul_jx70oM|x774V#Ajn$$o?K5zEZ8YS^wX9`hNYDD`HVS zdl?Pfyo3G^p)E&b(Aml#wFr19ZN$qCogc&W`~^D5Ie&r|y0#e(aTkP%{o-lMov8Q+MT4(1G z=|29=Etp(^({R{AgM2puW|X}YW9b#|osg4zc7(e1*_*xKy=yC7BY(g4@;>3Owa-^( zR82O|5WYDwJ+th}TVfHD6=HV}V|okiIpGJ~pJV^Ai)dt*5UZwD@nollj?5&d)#i&< zj&yzRs^xnk1dA8r*QbeB_n9xM$%~nEq=xK_r~TB5o9(CTNgTMz`on7zYs7aHKl9u! zx8v|Nyi|d;5+wYy>ddsPp6}ca3~q^vIC8Y2N5v8k^(`a^*x3Gsv3+BqQLdBD9%3+%)vX0&SiypQ3wqOi zy;~JG@towq_S1NerU@ z5+6qIdC01wlU|aHRm#d*N_%^gsREob@T;!tbc&!-uNz3 zoj4o9X7JJ04divT`31#Ivp?s(-6gcI0uDRPz+d7uXhZ{!A(9D4s{V6i-}Lq7hU)dx z(R>X#(tcX_ik6TU%t(nd+P+8ocko?g=Pci4UtGJlZQ0y?dtX>K2fb7Y&){3nnBgM2 z<0Em7Yg>5BL%g$Z?lPLQci)_4q?G?I4<6vz0zC?cSWfP_cww z>|d_&NGKgTxyoNRcOeDIX!9J}T!=P3vAfGGVK6aZSC}=Vu^IxKo`g-Y86njxOLT=f zbBbE`5#^3~O843HW{=f%O|DY$5Xt0}JM`-h2Pf0V#G;9neu4d)NEN+W)=T3aSIFjp zb;y-9WE1q4XEnwSV9Sf}dXjmqm79KT3845oV|4@<3J( z4RTYGN&Lu#lbi*WOL1yi-vAd6r^&4&eKV30rWO{AGK4vZpJ6lQ&Fo}XJ^tsKoF$~2 z&8-tc^*Wv2P~@J5zJftl4*KG@mCi~%Dl)6%RE1yN8g{N`(if4WDq$|bA-cC zxL>Io=oCl<=sc_lLUe)+eK|<57y-drasbf=FBoi*3E5;IE)<^bRpuX+l%F>AAs@y3 zJ}sWHbBi0My>e)WN+4BbsSAp|isq(IU#t?Z+B>@SjEGB{ImSDRZXcSGKD2V;(h!A{ zV|-Fzz$j0zy1r_*|3QqPLE%u!E!B^t@>CEg-*f5Pb?mVa0(&DQPW+; z)S`wJK8gi>TC@rCt0oLldY{_1LsDc8&0Lu0-E&U*z~(@W_+f6YyQ?8}Mw53G89g*T zWoQp?pRp6&y|qypL4jjDy<%enV{46k|ME z9%}J0jn8cz=%RmdVO|Yg=^S&o+0Qxl@D%CgO7r?Yaq;V_5;M0Qi>KeDM<)!OJ2NdR zao8NpgJ|~&`udZP{cqxQ1%_!g&HtZq`T>XF%0e%VS7KOt9^K+7iBVz6g>Fvt8cBC{ z%ub0OqW3iRk14Em3mVj;Z^PELaT z_rk$^o!S&#QW{&8l;akipbKd5_KA&(iSFBT%A5ozAGfGDAMarrO_;$DR#WCx!cJ%l z+y_0U6k)5wz*DXe7P;a>luPG8xGWRP?g0xGDK&w?p?SF}HM*d%LebQeH)dLLO#G_K zoN7<^=`T+gzDkNuUYuQ0nv@v7IJc-5`7|!RrK#`U?7WirxIW?-)~^WuzT4R^4~8wa zjW2sx0=RQ_nU-SdBQ&K|2L^}a<)sV^3O4i{U)J(+i$_FL?wIDJsJPb3oI2_Cg!rUZ zl%z~bNLZ9t*vp<2wQs{DPajvcFRP#sLM)Il^m|kh4BL%N6%II928-1#Yo z#y|R8-_$-49)W&Iy0{T6l!sl46gD7c3*u`s{#Y^}t8K7>b*`NI~UEcef#h9@^~w_tRqy5MewlAp`Sy)-~dNrVexom;ayXIs5-ckAR(` zgNSv4u=mYuuZ=E1G8M96lWEJnPh3!vO^8qI9~f*X$sN9|l=KNXyfbNJyiaUn;;=D3 zZef#p4sTA3iCa>f+u-HVBK(*XmpDJGpx2r81r-rnR=By1_VF9sl%J3|YfR<#%-o)- z@dLQLcE%h@n`(4#h|kuFz{U?`VWP&7Dyv?zIH82)hMCRTYh)r)>;eFrAgw%W|*Q&9V&d!0l_!R#>_~aB66qgjxXWYth z&i=&_aXqB>j1k#MLA|qZUtmm9flFv`>3q74j7iONHs}f$(`~}E)DS}?WHpLBB_0GF z%wJo}^dOA121201(lg?p9ko8InigqVGD_VB+8ayzPV(&Cva-c9YDVdV97#{7Oq^NU zvxIC24G7B}(?E9%(}ty{jm*S3QRrkWbn|DRKeYWk#%?e32oO^iFaF@BxiM4~K`-va#d17V%#LU#lr209t z_G$D8Nl!WN`*50{;HYE)R2sY%)mc3Z`p1vZEsESQ!8C$hCr=Tb+& zVq!vTUQsU$l@viv*DB8Q-Bi9%<4tq>#mzW-vN26~%7l{u^sio$n2@(vy=L49g`(GK z^=Xsh{P8M!)FaS2ET~^jfveG^&W#7CW_|UxQLyO_tJmo<`T`_@;U?!n}4^T57)%FF0Ca_mQwmG~+HOi?%Jf2R2Fg z$g&zdj1pGTUS8x>{b*OIW&)k+Eu8Zni@RW+`-EL%vU1h#@kLEd{uKr<-{CkE#M=BF zJop^EXX|h4+<{K(BBA?7i#H`Ss8`&8AkV6CeY{+v6O*BweLP*`Vv_i2OdU?L z=F|C)D%{Nf61>f8ah{yyBB0tNj!~9lwYz!Zfu?sOf}7b^IzGWH1Sd zV+$UnTs+2M*JK#h8D*$@^AK`UvYqaV9n>Dl#xQj#jF!cxu@j8kgrRy2k4upsd8KlB zY<&8Zk=s9NHvf=H9RJ&IcZIQZch%{**jr%sw^10cAT(^_dAZJ>5 z8bQtrSe^-#jt0~9S!AMr`y_udF^g`{ktxOW;Q(<{0DZVvXxdNTTECv8>?dQ_ug3$| zglxhYnFu@^h8z}A;uU2#0jojFz9r6{pb#2sS$Nl{V9-^CuVkD!`M^8DFAUB|_mScc ztTA4s*8|8Gw^*#V`uc}+t*;gcw&Sy zalaw}elrEVz>>*(L2Tm|muPr&Wl1*UFur^vgN+S)52;D~(3T-Y@D7cuQ;}YI105ZP zyQqVGk{tEZrXEO5NQm-`hPF)UUE%AX6Q%Nbk4xSkBnv+{=_JvxU1t<}#AyR_hD5|} ztF3i#(lq!uBX2#;6p|Myi6ffa)#E^4BzSNLzFE&BF{b?%TWO6yK?!OSs!VC7B=0nD z6u^dqknIp`hA38+#Kpv~A2fSWd`$etYNsGqm9yUOCCyWVmKU5*@AXLxn2O_2W0yNA zmNXoyuH4Wgzi?J_@yg7co+2S$@w()s_$hr8lIXWij!&;EEI+X!G@aWM#Ks#C8_V(G z|2iJ~sj5Kqd~HwaF9xndkQX1*% zK6JF3`*4jmGtFLQ$mko7iU7K3SGS?AE>&r+t|_IMILOLQaX0uRXDhMnMDmtZVPd8o z0xIs-F3HMrarw>t_gO8o&S+k8^qDk6hHxl)0=6R1P7Zw3!?060h=Wxl zPeq|2>^aB^gxo#(T)VCDbq|s?eY1A6=!2^Ddo&LtoDhYbb>#Ib^S|nxCT3>U78fI& zvc`!nSffXv#rQOnMK`cQ_Ll98B}~MgIbT&UYW1SMOY49ZU+2V{s>ywWPi=}Do#35b zA31ECCvguSUo@}Q*}rW8NfAHEe0Ek#aztYNoX6L0L~Q8mJ7k2SI3;OaWnB8g=h%26 z$&>I=uH2X0XXNENX~NRywC^H) zQqxCfVhk9Q5xjm9ycXFVHpXYOY%`|sfUEOzA)FQWlD$F)M9`u3PR9_ShWDBKY4R#lM?`5arn zBg={{+04VL#Esf-jq*2*-)g^&x#PjwiV^>9p}MN-64L<@Rcf9R_i;XGdCUeL5Vi-1 zlnYpmpCC0Tu#1g(SQRlA9HFlrl6;TMUfHs;Su@KwBG;w4s6wMHyMfADJmwb+LRNW0TNBsZU>_d3a=Rhi6~(KzzC}&|9BY z+mNL})|RJF&tinf)6+vk-Grc~Qu}!?pj~lc zptml41QTmRNQu*kOlG^}_Aw{oP}qUa{HZ_|&LRUmX|y89{8>Gt!R~j^z+#VV{9rMr z>6&p#dcB)S`gn~di?~TvssAZ%IzP6^CT_}ZWO37oD7T32aZ~$R!UHEl9KpNSJAI&K zjoY=JvG9sV@PeJ+s2aW2J0V`Py4Evlc-oLe*ZwvA90D_o$7+R*vnJH0)(8uRr>Boj ziOZ(T$joScNa1*9_8@0N(9aC?!`5_VMc-g(c(NWu@ zBsp1IIdJ7b&*+BqAvzD2LU+Mg;hf;32^rw;;v(!UC2=tYUNI@Db!<%q8VW*FG zrA{e9T1WrdRR8FxEG8>|L7uLGj_&#LWlx@+Ja-NIOA$m>oK^?eI1^WD6p0ArR*VnMmomKxy=xe5Q^nNp% zPD}R+YF+K1%t%F0b!z{F%)Qms)hYcGvi1xRvr`(wf|K;w^gR#vq>$|FXhuU2IVL{G zeRMQCmyG>kW=61kEmOi=5i^XP(FEKy1eygJC~l?!t#U*mY~Jcg_Gz~SkBDUim5&YD z>Pd%bw*-!jXFpd?ZWtYB$n8Ob%i9Ji{>G%zqby-mbvL+bfvJbTe-h$8)td)14~@ zK@_Z{$Kl#HvqVfhyu_oP(MgFJHSr0K_J00@j5DHw6`JD@Wn?)Ejt=U=O`1K;CLc$8 zN0%Nmvil__I0~A8F~%m7ze2Nbao!}!Ji^<_$=fF`)Kjar_lXLM*LV#a?I5b61N~hf z9r}#0xR8X5z#v~=B!>b#ygco-kwJJXvbMpU%dZ{9cs|4&Kx>H_83;>usxuux&R3Lp zFPu9`GdU;I>sRl#ZZ(;@OY(pO_p2Mo2EpjcgY zaF}I1DcD^U)<{n9WqvH*sDT@kH{ak$aI2wHq;s)l?Aa;D7qt^}T5`x3{54%WJ*~wv zEhoEtPJECf>hI8P_UgdOVFj7uwmRZR@3230=7x*_|H8;3Q@lb54T$oKNyUjcrgy8M zcWyk>3Gu}y2fDB($W1mYPiv5pMiOzU*uVD#cV*eBt;MH|&=h>@= z)=JOS%{9&L72umvH*ruw2KHqa?if&LL>;-EnPxKY7AtS=Arbq;;OcwmmDfn??8zTX*sA zAa3ktE^+XKwQ`&6)MBr&1Us=Xl8N3LeT|>1i$I^zk|Xq0xlOBG42X`(bmAQdxL!O= zd;{%!@f8uj5r&)DEGR(rgdt;s5Sp~V zOi~JlbYW+pULT02`(X_G>b2hE`r(wUp71%b`vb3xe1^Vs7)zq}KSubxcVTs5c}Aha z|FdT^XXp6D%_^F;!9%KPn&e3;)#M{=*jSsF z0-lREZjJ0+AsaYyG17Wf72w$W!28!&ba4DkoL#BL8}CL|PagPdaG;d6<4qf-^}KzK zFC4bw18$3Ng?rN--SAI!;_v8&Z-q~z)1`B&@$M$aJiB9fPua*c7yTba%7pd5ll@+a zcarU947S7H#qw{P@H_rK*f>5Gq-NMy-j%;I6Jxo}$5JAXMTXOY^~>{i0%I7h#QW%$-^o3#c4faq=!M!SOs24|V)G!kN9+OrjKj-h zxMdubn4cXgyg|~qhOe~p!EP}4bAq?e@Bx?Sh3P>z ze5>vbh921BpR&wjCE9W1?ZYK^wL^5YQG8z+3_5WN)TUpCKbFaZ0=X+D5At{!z6G9Y z3&$PB9o^cu_6xo2*1na_O6Z3zJ;yC{LeIM4AD8>>cn$n?=6u8UDd%T8=i6`K=XP$3 zsu(?XGrHk3`Dgf@HkIGA-L7jTImKcjo-z_*VXR{D$$O78}};@ef<@@1ozU zT+S10+n42&zlV-BEcj_{|1R3O%G>Ao*7i|P0`kw>m+?E>2S07`t$eEn+!o&g@3;$o z+TvUIX2X0A9?~SYuIV=qL3hTMtu9Q5? zf1kwVxEXxJCpI4)Gs!&2F-3m332%5A?fUcaFPHhnupswrJ{W%2e8~80K4g3gzu1`- zX(7j#<u0k{@OV+d@kR-U&o4fK`8W- z<1>4wfTh9wS?nF~cXVstIv>pM*tTzl`+|RSIsK`&lBNe*==lGp)@S_|4Da-sbKH1`1;gHX6_*VI3a%+okg;&v$ z(tDg9B#SXWPgvTo2YjN`0D5Y>!I|B*#Xo7mXK-75E1dOfi*N0h!EN!a@G8vbdw;7( zpbz|>k6MmgkGKZO)YzI!yRZqx&2Iy9CEv&=$z#r+X(hcxId^|JkuJQI>$9zQb z@iY7`KXD54ah8u?#<$8zKeXSVY6f4hAVT{E&~oT0iw_hA>KUP8O;g@*(_v7b1 zfIp+pgZRnrCU|0$-$YC3$J)N)Wwbxe?&$~GXLf+m(`g4R^gw1AC0%wCcUT$~4Sc*D zzf;cY05|aQ%J`P?b}YiUGPoRP+P2^EBKX_AU6faR$BzJI3)9FN6OapN)c# z3woj`;_V}))J1>Cb=bW(dHdjO7yTV~(eGVV3)(@368tZ;i{<=>Hj4MiinH4FTa z9xC21^AmU3c!k3Oc8GfLE#5El$6Wq|!@dlTZ&~nn$oRZ{rC`-7=8t80mD{(%x&N?< zx2$lk|H>~x57TGFRUP~6KCsTCY6RdipIcZK1pMLS<#2htEzTU?6<-qglP><))k9B8 zl_41EU;O)zVm!8MB&)oZ0&crTvd$~VXM9wwxA0MxV~)@GsMsL$@mraXkAlBTxn367 zRl~no)?$t&cCDPBrJ$!=wGZP$WC72%404`@aj|}us#trhA0_ZPpRslWU2MHz>8JVI zw|P4$fZN9Zht)Fv2*7RQ`NOU<9Nr1>{4mfH&c~5&SIy(X5uj(ZG7a!jK8_idetG+R z+*>$)p`8zxAKpG6_g0QSGK7yCZvr)Ti&L$9%|@JO8>d>~&@c9;Df&(1?O5T{0Uyl$ z4lDv@%?juEoSw%l^vLtT@i{$vWO~?XSnv}y(G_adc(sv?;P`nR8~J#hFy0F+P9Tj8 z-);tm_jmXO|A1fE4S!f?`}y7Q)2!_ao$bSJsFj`;e2i!+ZQ_9$9U8EcsagsxC4@fes6*P)6&#V{KInlEDnHuWB!8Kw@!ayv2R`e z0$R`7u|pi7DB|{+;djc3jL+>evkxlB4=f?W=j}83m)p04eW}e}wagVw314mt@9<}E zSw780UHBcEPWTF2IKgPdMK=7WGXHJhGXJgcbhIPOv&?@hd|W47=D#i6mj6~b`juq3 z%zs@vhnwH&gj?-{4DaZKTkQjf)0>^}*%mu2 z!)Ygcxh>poDfqU;hChxL{&c}*{yYem`ST!r85@;o3%BLZgK(KYws0Hy?ADHrd|Khm zzbJ}0KOb*LJ=|p`Enl|^Zd8?XZ`_x_I|kHWzKi>(!CwUxd-7){w(ysKX>8Vz+aK! zSjX1zxX`E^$J$X`_y_o_GMpZ}5C1g_92ZZ!wR6$Z&QL2{@j7dt^}^`snA-`5#@oO- zJzRfedfv3)-w(ee!|jHk9Tr!agiFkJU<5pF{u}r;&W8u_um1xaT7mgx_}nfi5Z_^a z!h7ik|MUSkvkP7H@HmFI!|Y}k{BzES^=MySx5(p#x8(5i_rY(;Xk|$ z%WQ2I5*c(@=bg^hCzN#e`h+a6AlGF1fF1hyamz7rfjhm^?nS+yFnKBGXHs6y&+Tp4 z;hJf@UeA2M^CMk>KUU7q?OXWEkdE=$=`Z8yeEm>Kuk^|viF&P??cR2#VkfhCES~tw@Do-4uijqdm8Zl8FiVsPrD9yO;ZgdL*S9ZxK-pqJ;T>6hcxES zboj?S>9pOG&gP}gbUxoHc48-8k=v8M9(Z{2Yi6_bj(p5#f0OB?=ns%nNME6(Yv{ZD zyDz@8egr+e?V^ssO1g%=$MgNc`p=7=kX|gE}2%tuJ)vJkW?BfC6(!EB-mz8?Xzc_+`Zxn4}>JS(RwJj>HlwI8F8Wy>5-IeeD? z9MU!Pg6BKyD>qMi=VN`AsF}{|Q_|T=3Tzn0laRWdJgKB-c+%ZGiPErzWEvjekWfyc zHA~mf_c{hgPd^pw+&P1YYJG()s)VTJ`3%+Q-rry#(W%X)2wxlG7Qj zlyvv_=JrA-t-9zpGOhm2;abqocX7GL{bhpEm#WTm)DJDkozCHQ(zXj+FWP$2U*mc_ zqwNn}Xe*~P+REu}+JZk}CwTKGo@1H#LnU29@d>oXD8ar3+20`Bo&R9zd|WafVf?8g z8273vo^-k0@bDnt>*7zsAl6q*j|F|@d56n4hNmW3<}Ep$`6cD~!mY>On4f8ZG8}H7 zczExI{9GP#_z%kYJBDyOP;Rf>4$QQ`hph)M<-GI(``$4G?Y&2#i=0o^(~m3Z8hW1R zvgL^6o_nOwiq6)m8vk{=X2go;VW z-*Ds23v>a>M-~NOb^HxcB~V0+V?cDdAq-6Wl?)c_#3;TObv>OfSpWZ1xricv)OT}r zAKqMD7d-zD<iN0}DXh7|7ZLs=B_SPA5N5o@e zH@1t?v+X@d;I4zho9D<9X?Yjej-qgH*y=oCrV5}vkWa{@XMnxoBF2hBZmukpt!v&KJ9qnha}Obj6Ye%b&|ML&P4 z2?+l1n^PdBE+iMftlb4yY#CiidJF2RIgN$m*At0u=Rv7kyOjj*dP<@7Iho=Nzl*?c zfr4K{QASscys=g1`3f^NDj7Y0>ZcLaROLqQ#0{urAizk*>-Bc4^z+VxR9SBsRWG=h&$cP*oG@ChR%j*iQ&Z+`pm1|HyKR{w~h z#bYnwtPeYw+T2z{X2wdJK6&aBX=4mQ^-}%L>-)q}JJ}#7s(b|}y=qNSWuQ7h=%x+` z5JJ>KfS_ZaD3S>KmKW@EuV0AfUR9u9fT*Hd0|s~3hvy9M~Gh+mM8pRZaY;$8qM z2thtRLU#=Q;1eOnT#R-d{()(~`R$Y~7{5QUUk~@nY~tn-4CN8=79LVaIkzh}#w47P zHq|^eNZJ%jW=`QPsZm-siOjex)svQ8GNN3A7G*&UdE}ph;wm zdIe~F_)P}M!WM7rfyTj>L{fNg@uDZ6TD<59dTr4Y2Ny1S@(DI?6q04am*Q-U4i(Yi zD{Usr=v8So-0vMPW6tUUzLaBJ&MPYL3-z;F0DFP6ty%Mhx(XI6ws}z z8Gagy9qRsmzCP@BNEH=Cs`a7%LO}4T55Gazej9v(jcxwURHYXb{ABB-ks>%fM8fwG z@hl((x|+W=?FH?^%=Y|t=@I-P>C$`dH`t1GwD_KS2k>S4=~*=ULhL4;UQ~c9X=6#I zs#mwS^s#Scp0&J{T;ErJ)~S7~f4ERa^RjSbVpMQmd|7!`e34&#Xt@|493P)n9vl^4 zl$3tz%BkP31poB=PwWlUxopy*qtk)=PqyEGlJLYPC+BA9t;9%p5G^G}f>#&l|04ab z^7pfd-L38Y8cIvXj_X_6u;9`8^Y=eCZ$V4tn9|ZQNEx$W|AP7Z_s?IjAIDxx%Noa) z$Vrbqh9v47L-sVfD$2)n%w`_t!o-z#?s2hjW6@};s4i+ug=RI zT$7Vm9nC1`S~_^nAbcB4?ovL83zSB`vX&E}oi2E^HXyKDx7yl(ZruWE8HI+hPeX=u z!_ScY3l-|U=cc7hDTQJfGISN9VV6PH3HX9g`*hX6&q~`x>};0SF@26)#q-Z$pIJ3; zc0j|09rmVb8zV8E)rpPj+qv!bCY~S%)1Fxll7b9`z9TjYk^-B>Wsz?C6@paW)EoMJK)mN>B z=-@K!w=20BL`(FzlTDbOEIsmvNm{5A%^x7*^uOCka}9^n3vll6z)`&}%5cTfd&s6>*5N02FGAf7d-uj2el z1Uq$sxeNT{j%UP9!3E)%Kd{8KCa^Y)j4CyCgDk+0CUOl+?>Y7M=JXi*AFWm(#!R_B&my~n$-N1l*|!M z=5PUyD)o!vdm4Y>2JKM08;J<*Fa3%;0ofhpD(KfNb|HJ4=ydW})Ya8jqpse274A7r z_YJPn4X!d+1DJ=lNWXHOl9hoAgPq95c^EsjUX4cfXmUV$P#PY6mF91tFK+nb(gxJs z@hxcZPxUX@%R4}(kKX{9KEMmBCF0ZavyRaU?P^hzo30lYZ*+-@Sb7qOSdjCic%SHM>w=AYQjRgS*lwr?~HnSHy4a%;sV=vD+UF2bBo#@!e$cl)_h=@c> zHaS+6lUp&MX+>dSVq#uyMa8%kMMctx?6ee9dTgx8)GsF`Ee@Z|@nR9qZH5}-VnYon zN2mTVusSiZv}EJ7g?Cj~Ct6BNT+5>(bE@Xt(KO7O7!~cPnlpDwwKWmAQ%rIX37a*7 zJMIzdGu9JOjm+daNkZHs*9mvrBg7fG$PR&%lI6T?ca&{aU>kZmKy&y#xGIe*WFi znSMSMYG^nW8jae&A^=x6+qwh5jF3r8kq{=qgDGt+Yw->6W_q#4?jPp z=nj~$f8(l-F4vVxsNMljnAyXIf{LmKe$3q*mgm zzU=yD=CNZ7$YN;$PzIl7@xHpu&*{N{(|XS4D!rtH#PaGG8bjKR(z49Bg6O3K2b#@& zdiNjL*l$TjWbU1Xi)(7Kvl|`G9Gm)b!`r?-g+&v~`V?oR8A3xsZjXxUQ#__$QV)NB z1FM^ou?n9Avi;9QIU>wD9l;FrS{8W%oTBiDeDu}p7_O2oOt4z}jqO|9qes6n%by9e z*4vg38Dh!IFRZ+?xKCt6nxnXH&6)~uP-^jniR)|`8N&C4ICEY$wXZdC8yzyKd+4A+ zdwWGj=Qt-7mi0|@Mnv{0o9WsCz8d6drebA7#; z`b!Dw%Z~P6={Ml}KA!fZu$``*Ekc8ElYF8a{ex>=Xc#{i>p518aEm<3hD>N-U}{Qr zW3S$ImE(H#lK$+MU}+k+asIaAK2vK`lHcC5ZcueuIk63$QB_)#o0F6z?CE2%N*MI|78X=37l0j`6Sy8HVN8ng#-7H3WDTiiD-JG;2g z{L!at=JhJ@feVS9nfy#Rs!riD)L_EP>@eX)cat#byD8FlBut(1XTzWPmHR15_)s`1 z+WCBo>?ps>H9@pDu(n1CWAN-zuCJmO4JMr@2g@bA+DJ+oQ0F$P7VDE@wsl8h z;)INhmfci+fDCIL+*&ueZBVOpn3toF87$Tqh6IaM$|KbChy`|;^FxJ42P_+)%O6yi zpQkTbwqRLEYEjXk`J)kAY#~`WWKfn}i7FNqxdd{ZjOqAAj1Yz(-q9zXI7aml%DaTV zAzF4Tt`ghGjn=WYuJPp1%1zr!tfjU5!Bj(cyPnrd32k8o=z2QkqL)t!`@0>eLbslv2 ziN}yyLv;mdD}~{RHHDd1sn-u>-()eVL})Zh+Cxao5oRFYUG6j$ z)@Ot-I6U|}m3$Ow`&pU>Gry9i?$8Nu^L+3#Drxb^x0Y@Jyv{x^LE3u3f_kA#vV559 z*_y$t>I?iPN_Iw{MzGWON<1XWBr$?J$+4)JgO4uly{zQW-hTf&RC-66A$fYqJx}CM zzo+lrz01fyLZoFWWTsBqlucIaq+oI^JDWIZ6mdGT_mr3YAeH=3R!;rymY%&^ntC@- zQB`&97a!5&BA$IV*AqgG8Hi>G!H56?z#?0|VZe&R>WT6n+!q|;%uc}RZQKKd7Yo;9 zgj_|80by@qLSXt`rLnQ`={70N|MvHrtYc0$#m7c0FsE3v77X_FSvkI;iO?tfV(z+l zN8PkaTb6^aOiq!^390I@e7b3Fe=IcOd~VY9og+s4Y|j#lZVNOne%;Rx_plrx!|&g| zvH#D0WiaN?rdlfs{=0@TTFhAX)WOR|?!gT$p7E znlc1<{UK#XhhYFfqGlnQ2sRj zWnupM@_`LwnqBvbjZaOmW%f?&O-e7=fB(`|Pj^4^P(wqD>t2H8TXhGds`v-!NudqI zLu={*B3re3E5iJk^en;xQ^1(A5C09Y!BO3G7!IlN1 zmw`pl6TWDFGup3ZXXbg7?~p`XDqu$NGIs!Q7Jz~U1$SQol9-NbALK|Q?$~b{P7P#a zkzR-{fAf&0nDQaG)pv2<@Y2$yWpnlu?Un`ML5-E>?9e!SR(4LsNME1K(dN=@WArj2YK6v3@Pew3hcRa%|k~+pnYnv_Mu|-IwCa4+?L92%muqS?TF8Y zQOMqm-`E=gDEQl{jwAvekVvYvTTS>hQQa#fQM*!0M&>-AA@w<{axEdfOw}P1rR)2n z@0L3Dn^I7;s? zO0Hckxm@eTfzs`7Y|SpYzc8hC4N+g)pnhMFE=ZqCo5--MA6z?v$YTj)rqp`%19cT_ z+j-J1HSWv7x(wz#tffw#3OgKYK)-_*4nQ8KsumUXH6}z`3~l=8MKKE_#+kH>GzYa#DgpA1s6hbq`b}bPMgSjgApCf!#y(i7A?dG`Mh2ooYXI zio0;(cZQP>ADNR9f0#q}n-2@#wq1ccS9Suz-3RA%2JS2A6pBnDg8%TBtN6+!L3IxF zB4WUsoj;8tmETot?`JJrQNH$aIr+pU;@kmWs-&h;ty;Pq+A^;t8rpLnjQ*SVfaq#L2BGxA4Rr-2rT@uyPT(HC6yBkaGO z>AlR1hg@#CU>>gLZY?Ope8BBB+iVJ(gz&Syb|%8=A8v+8y?X-AKs=B zEL79lDlHi^aK@@B1LwImk$;XFICbR&xNy`eKgo)7j~Z1Nyt30&D^#0MhgI(m&B)?( zcnl7!p4o(WDP|&b8OTP9HBk-O#h+=d?DB9%e;#LqrLp)k+;~K6LyUd-vpd)j5j0v% zB%w^@@PbF=*`&K%m7uAA*pwVU+@6>p7^Ds`CuC%&M#UKXpH5Bi4fNGewSS!69Mmls z!PnGcfNy)Npa0Y0`tHGjK|_s2){>EvHzt|`eEg#$(j$5&^z7lV#u>xYgQ7LsZryC@ zy-X3*w>CSG41Xp(BqT8`GAd_ukJw0~AFeYCbw~-iaJ{b&_3;l5ldL`Ir3a_h&dkrs zsm^fTHDPj2QCygv(rJ-7=0bxZD%@!?MLO+y*4V^|?%n)f>|qy1`x!#xqw}+e+?`Oo zWMaJ(f<>nAgtvHu|o{ff2M~>$r)T zahYi}VQ{S0r+Zp@&)6Uh6&tTsO)Xykaz@s{;f;;XF&PD4Ke1w~CGq5{+07LNTe<~S zjaf3O?2~DSdYa7Pg@qZnnPL}%pG9^eU2OtCM`4sC@+f5{rc6MJYM3YmgP6SLZ)i2l zI7Va~OCoL@Aj8P9cczUDoTVR0eH--?l4|!#-+e##?9)y9ak?4$>2!xniuvKfz5dko zV+f75y!SnhJ=PCgU6+wvJmZbY5*ubuzunLgs_b?ZRSf{u~mHqCtC0{Mi<`DndT(jdx)Bg5SoeWdBwpZhAQG|UReHE6?Jy9` zjB;4|g_viqOUy~8bcp&zp`<&)rS~U>(4V573|-mpmEMx=-zSM`W$3|)ZDYxbuye0i zg_?!b$Mwg;a|>O6un*K{;kk3?7P7;ngv}?=x2|#z5g(fvl!}iRo=M(ST;~KO`1s}X zcOtq9Sg`!K3TM23Kp%bReH%ukK5WCzNuMq2 zIp^Z!_Ro6+$2=VNiNF7Co28O4;gHrhYuxOW1^IuoT7Nk`px45Y>Ap~X7OpAj|50k{ z7w4;r7W(^Dr^CczV`8QB0nYn%2S=pwjB4#A6kgx>T*~<5`kG;`w$~d5tf#b)@+09OJk2D;jUUzEAkmSUk7&kqOUC!}b`4-$Za0 zn-6$oc4pPF7w|Hj5brQuUvI=;DfP_RGZGG)x6W_9{vQ!;7|bKHP>!OUg|*5Qic)NR zaIQp`GbM{hi2|)nXd=F;X|;5qj1qJ8*Rl2EwpFAg+ZTN@Ic?IoSK}^j8de_T`mUOM zMw1FQ{i|Aie&L{{3s(&rZP4drACM-I1&@r{Kd@-R!b(TgLf|~7;~Vi9`agozZt-++ z9QUP#sBpIn)8BAEo@Xc+$(o^ynjRk&;dkL4>5qlgVF+JALKm;fiKxB(y9M)o0}u8w z!nL=;S(LIuUHRdfSEnu_x0465VwU&J%c$}RJR%*MJHGi&9UQli6Qtvucv>Su|1u+@ zFDz)n9h0){=|RWq`UVR^QCqye%K>%;uca-pC^d#VN)wX$h4)D9TaqwnKv?GRv^$p- z6(!Fv>oJIYy1V_wJ%TvpE~_c)?wSdUttQ*DqfTe->|95B|7c^Fdix7`rk>V9IH1Ow za$b&!cxKFcG@e>}&s0cVq7+*J?WdS~C62 zWnt?GLjaG(&e5>gJm3}OJC6^FX@JRpa9Fk+6JAjj>{^RaP2Sx8`np|)dym~4GU~Ra zM@$QkeSgVc$~=}pq5`E?g=4R6T3$NcRY9NYxAL|Z4!|&bvUF_q^_NGC9fx`-i%cZ0 z6oi-U=zoE_Vrlt%WKKvm)B!i-*&(S zF75{mf4+j00rdI3i)I#cHH3wE?Tboh0Ha(`7k)R8vmQYqVE{N4ZR0Ko*vYLafi9-FiAH0$h z6ewMlULa*Oj+8#@T0iQ_DEy9$jas!TiY|=LF#*ne(QE8;KTWXi? z_qW-^k8HNxZHfj?!^Q6QJ8dYKbp_4!)QzSzIXiiP%CwGAvPW zR186|J}yDo;Nzo3Llhzz75pq9n{c#GUfzVnKEoC~{zYn|<4I{>yu1-#|Yw^U@5V+s{-uO`LLjX*-*;*71pan<;~Zv3}zi( z4in5ne1PW!f63A2+neb#YZf28{UPW6+3NG7r6}^v=ne=O*URK9=>w7~#n58ljFBtu z;Vgi|H7eI)tR$VdR_WrZ!?MCwS&a(Yqtjn(=UQ^1}?mN z*}{R&ZwA_j3@K=wUtae#>2s)!ls@&8^kSR7zg|yf4YJn^&Z=g8h25C=a{~GXyH6B0 z9^uYCY#G98rLtmKOigdV{%)V4C#I)AxM$VVtE$<(qK)lhQ9=XpNo7SH$HTplX~o#ppwZYuwm&*yeT zvHEX#?!iy<*?)iT#$R)>OZ}bYKUd2C#dA;j%U#NM;_t?<>+_r8|JCzLGW|53=j0DB z`eUVrJqN27tNt!-5Eiqzp?U`~!i8WmYKw`vZm%$_edFFb>QlqMwCt^8Jb^Vc@Wiv? zK$hPZHaW(T)=KDR63_FH1h`o)*6nTID9qYhN6fs8cOAY2u~{7^tCNTuyfacC_6@a2 zSl+pz9uvF(kWo$}p+(Z?a;{6A7_t(b?Fhmbw1Duopc(_Q3P)Vi8DLg~ZeeJlE^?WD z;B8~iYLL{WUcj-SMl-7$EwnTL!wblHsfM9|vI#Y;%@=P1yqDvzI)*VFE{x%Hbz)@^ zMxDWYERQ_&HJvfXwRx#v&0Ff)JcrJ}vJ%7JD?g@E2eA@}D=}QjLmm>WQq$MGz|tG@ z_aF{CapI3oxa`Talvne$)YKKWQ)f3|lr_z)Xco3}L9em>U2uZn`oVD0^Y#Mf`NoTL;RM1nq>7 zxNuW!L|BBOn=aX8PtC@~9q}n)Q`DFf!%R_8;dZ~kw3zJV97kG4!t|w}2mLBwo*^VC zC?Gl%cgFOHG#aClvh(|fB!}t)0|WBnQu3_PVPWCPcYi@1%0q_`l{cPXa3lJVnPtq^ zix=|>aTyJxn&Ylu&ahWnBs?kon*p1ikdfxdNzRT*3-q&xM@0ccok=|6q#YunuYyX_h__G4IH>+IgHe5^8LSt>AmXkr(9;DmxSgmYUFC1C!Cf33Ub`o>Ke z8U@m1BFURFoqW&Aqi%1e&q8Jz<>q+TH=gpIws?&jXc}xpW9TRt2>)zpabjH20gP7099`o<9(~5}XT25XX~K6%Wxy2L zV^1KobMNh5Yy_GeFkUB^-{X&8xjN!eL6H+VUk z8D?ZUE%mf%OKe7-C8fI|G_+@GW@hhjV?=NWF!a;ujS*fwV2DUevpI4KvK&dt21ARV ze{hJ=5E&k3)P?wB69Ch<`S=1Z3EZ~pN`z#HNDqIR+`HxY{R0qP(J%mILCYMe>?KU= zLY?g`(mQVYz_JbPk(!a2tBVK?2@3F?*@dd2xeK|@pZ5@KaekH)xOd-&wgp9oMl9}1 z=B{n9VEqwy9x-YeL!&!Mi&iLd)6^ZpRVP?_>>w~pg(LdA}5s8^1Mjz@g zXtlZ!oi+w66y$EXCP3q>jWk5|j*JWq_dyO{AH9!{Rx9{K7@{J2M*@&9PR%I2OjiiO zx_DoIf8T%r_`8F3Izvo?H6Vbc^z;o71&?STYPFxGn@$%JXSHBMz8X6d{d|Hf*0>Oz zE;!y#4dYH3GBRD>gATe$zCTW|I^8ppNe?05*5Rb@3huN0-NSDheEW~m402ieHSQ-j z#JwbteUXI}r~7Q^VvXtt*q$rsbZV>MH0p`oh9jlNI5B_=LJ$Jc!ZHKb^+6VVc z`nek!RPj9hP#PvIj&WTftsKU4fDxe{&-aSC=LBX%ZbeO(m?lV9wFqx|aJc?}fIT|s zbMJB{6j0=WP$0#%(0h|mGvW+XXtd!$(sy6dPLRq6<}V)S*X zh0f0Wm*7~%0Q;7kLvPDda!ZS#ZfRix&6UOGd*NyJ6nY=i*XWM+J;dyqB~q zCN2>ED&CcF!tX9hDVx;eqH1i^XE?SJF^BZPM_O{n$54 z#k{PraGNc)PtL~t-kF)U@R(E+)5wLpqATh~PMkEnzF*&Dlqw%EV&wRVBX1jchpkud zvXX_i6x_8EnQmKHQr5elHR@}(Uha)2o9q<5{3fid&cA8|Dd50NsWIU;%*FW|bNZy( zY~f*9^JIkkjT}B{T5Ur~KWk!QVt?T-rjUOfW$nkYN{59EgLlqkx`MBZA6!JyfLU&u|jL*34MPGz1&+>sYpnB047#JAw*Pr$n@R+wcaU*Wy z-JJnO8>?S#1M?-w_{o-@!)@f#6$=@2$-1UDeoSOw$k9*+<&wKKz^xnu;qNkTCazD~ z>EC4-j2Z%#jF@i2czqGZ3A9I#XTevt{SA;r?&{^XT<1(JyEOzY$A_WrdaKjJLD@|O z;$z&u0hk`ogReqI&`7X(d=RXp;`iV<$z9>5F{_l(`35`{%3vO_ct)o;p6wUp2Fk$5 zT&`w-I2vNu%Jeh&?t>!?IUS*(tPrw+&*48RHl

b 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 literal 0 HcmV?d00001 diff --git a/vesad/src/display.rs b/vesad/src/display.rs index f109184d25..8048b04c3f 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -14,13 +14,13 @@ use self::rusttype::{Font, FontCollection, Scale, point}; use orbclient::FONT; #[cfg(feature="rusttype")] -static FONT: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono.ttf"); +static FONT: &'static [u8] = include_bytes!("../res/DejaVuSansMono.ttf"); #[cfg(feature="rusttype")] -static FONT_BOLD: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Bold.ttf"); +static FONT_BOLD: &'static [u8] = include_bytes!("../res/DejaVuSansMono-Bold.ttf"); #[cfg(feature="rusttype")] -static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-BoldOblique.ttf"); +static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../res/DejaVuSansMono-BoldOblique.ttf"); #[cfg(feature="rusttype")] -static FONT_ITALIC: &'static [u8] = include_bytes!("../../../res/fonts/DejaVuSansMono-Oblique.ttf"); +static FONT_ITALIC: &'static [u8] = include_bytes!("../res/DejaVuSansMono-Oblique.ttf"); /// A display pub struct Display { From 0ff0c42ce6b4640079708034313b58c0804d8597 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 1 Mar 2022 20:34:13 -0700 Subject: [PATCH 0471/1301] p2sd: Add timeout handling --- ps2d/Cargo.toml | 2 +- ps2d/src/controller.rs | 192 +++++++++++++++++++++++++---------------- ps2d/src/main.rs | 29 +++---- ps2d/src/state.rs | 15 +++- ps2d/src/vm.rs | 6 +- 5 files changed, 144 insertions(+), 100 deletions(-) diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 27e3b5e582..fa34ed3874 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -6,4 +6,4 @@ edition = "2018" [dependencies] bitflags = "1" orbclient = "0.3.27" -redox_syscall = "0.2.9" +redox_syscall = "0.2.11" diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index a10660010a..3cf5ede5c1 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -1,5 +1,13 @@ use syscall::io::{Io, Pio, ReadOnly, WriteOnly}; +use std::{thread, time}; + +#[derive(Debug)] +pub enum Error { + ReadTimeout, + WriteTimeout, +} + bitflags! { pub struct StatusFlags: u8 { const OUTPUT_FULL = 1; @@ -94,12 +102,30 @@ impl Ps2 { StatusFlags::from_bits_truncate(self.status.read()) } - fn wait_write(&mut self) { - while self.status().contains(StatusFlags::INPUT_FULL) {} + fn wait_write(&mut self) -> Result<(), Error> { + let mut timeout = 100; + while self.status().contains(StatusFlags::INPUT_FULL) && timeout > 0 { + thread::sleep(time::Duration::from_millis(1)); + timeout -= 1; + } + if timeout > 0 { + Ok(()) + } else { + Err(Error::WriteTimeout) + } } - fn wait_read(&mut self) { - while ! self.status().contains(StatusFlags::OUTPUT_FULL) {} + fn wait_read(&mut self) -> Result<(), Error> { + let mut timeout = 100; + while ! self.status().contains(StatusFlags::OUTPUT_FULL) && timeout > 0 { + thread::sleep(time::Duration::from_millis(1)); + timeout -= 1; + } + if timeout > 0 { + Ok(()) + } else { + Err(Error::ReadTimeout) + } } fn flush_read(&mut self, message: &str) { @@ -108,84 +134,86 @@ impl Ps2 { } } - fn command(&mut self, command: Command) { - self.wait_write(); + fn command(&mut self, command: Command) -> Result<(), Error> { + self.wait_write()?; self.command.write(command as u8); + Ok(()) } - fn read(&mut self) -> u8 { - self.wait_read(); - self.data.read() + fn read(&mut self) -> Result { + self.wait_read()?; + Ok(self.data.read()) } - fn write(&mut self, data: u8) { - self.wait_write(); + fn write(&mut self, data: u8) -> Result<(), Error> { + self.wait_write()?; self.data.write(data); + Ok(()) } - fn config(&mut self) -> ConfigFlags { - self.command(Command::ReadConfig); - ConfigFlags::from_bits_truncate(self.read()) + fn config(&mut self) -> Result { + self.command(Command::ReadConfig)?; + self.read().map(ConfigFlags::from_bits_truncate) } - fn set_config(&mut self, config: ConfigFlags) { - self.command(Command::WriteConfig); - self.write(config.bits()); + fn set_config(&mut self, config: ConfigFlags) -> Result<(), Error> { + self.command(Command::WriteConfig)?; + self.write(config.bits()) } - fn keyboard_command_inner(&mut self, command: u8) -> u8 { + fn keyboard_command_inner(&mut self, command: u8) -> Result { let mut ret = 0xFE; for i in 0..4 { - self.write(command as u8); - ret = self.read(); + self.write(command as u8)?; + ret = self.read()?; if ret == 0xFE { - println!("ps2d: retry keyboard command {:X}: {}", command, i); + eprintln!("ps2d: retry keyboard command {:X}: {}", command, i); } else { break; } } - ret + Ok(ret) } - fn keyboard_command(&mut self, command: KeyboardCommand) -> u8 { + fn keyboard_command(&mut self, command: KeyboardCommand) -> Result { self.keyboard_command_inner(command as u8) } - fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> u8 { - let res = self.keyboard_command_inner(command as u8); + fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> Result { + let res = self.keyboard_command_inner(command as u8)?; if res != 0xFA { - return res; + return Ok(res); } self.write(data as u8); self.read() } - fn mouse_command_inner(&mut self, command: u8) -> u8 { + fn mouse_command_inner(&mut self, command: u8) -> Result { let mut ret = 0xFE; for i in 0..4 { - self.command(Command::WriteSecond); - self.write(command as u8); - ret = self.read(); + self.command(Command::WriteSecond)?; + self.write(command as u8)?; + ret = self.read()?; if ret == 0xFE { - println!("ps2d: retry mouse command {:X}: {}", command, i); + eprintln!("ps2d: retry mouse command {:X}: {}", command, i); } else { break; } } - ret + Ok(ret) } - fn mouse_command(&mut self, command: MouseCommand) -> u8 { + fn mouse_command(&mut self, command: MouseCommand) -> Result { self.mouse_command_inner(command as u8) } - fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> u8 { - let res = self.mouse_command_inner(command as u8); + fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> Result { + let res = self.mouse_command_inner(command as u8)?; if res != 0xFA { - return res; + return Ok(res); } - self.command(Command::WriteSecond); - self.write(data as u8); + self.command(Command::WriteSecond)?; + self.write(data as u8)?; self.read() } @@ -199,50 +227,50 @@ impl Ps2 { } } - pub fn init(&mut self) -> bool { + pub fn init(&mut self) -> Result<(), Error> { let mut b = 0; // Clear remaining data self.flush_read("init start"); // Disable devices - self.command(Command::DisableFirst); - self.command(Command::DisableSecond); + self.command(Command::DisableFirst)?; + self.command(Command::DisableSecond)?; // Clear remaining data self.flush_read("disable"); // Disable clocks, disable interrupts, and disable translate { - let mut config = self.config(); + let mut config = self.config()?; config.insert(ConfigFlags::FIRST_DISABLED); config.insert(ConfigFlags::SECOND_DISABLED); config.remove(ConfigFlags::FIRST_TRANSLATE); config.remove(ConfigFlags::FIRST_INTERRUPT); config.remove(ConfigFlags::SECOND_INTERRUPT); - self.set_config(config); + self.set_config(config)?; } // Perform the self test - self.command(Command::TestController); - assert_eq!(self.read(), 0x55); + self.command(Command::TestController)?; + assert_eq!(self.read()?, 0x55); // Enable devices - self.command(Command::EnableFirst); - self.command(Command::EnableSecond); + self.command(Command::EnableFirst)?; + self.command(Command::EnableSecond)?; // Clear remaining data self.flush_read("enable"); // Reset keyboard - b = self.keyboard_command(KeyboardCommand::Reset); + b = self.keyboard_command(KeyboardCommand::Reset)?; if b == 0xFA { - b = self.read(); + b = self.read()?; if b != 0xAA { - println!("ps2d: keyboard failed self test: {:02X}", b); + eprintln!("ps2d: keyboard failed self test: {:02X}", b); } } else { - println!("ps2d: keyboard failed to reset: {:02X}", b); + eprintln!("ps2d: keyboard failed to reset: {:02X}", b); } // Clear remaining data @@ -250,31 +278,43 @@ impl Ps2 { // Set scancode set to 2 let scancode_set = 2; - b = self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set); + b = self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set)?; if b != 0xFA { - println!("ps2d: keyboard failed to set scancode set {}: {:02X}", scancode_set, b); + eprintln!("ps2d: keyboard failed to set scancode set {}: {:02X}", scancode_set, b); } // Enable data reporting - b = self.keyboard_command(KeyboardCommand::EnableReporting); + b = self.keyboard_command(KeyboardCommand::EnableReporting)?; if b != 0xFA { - println!("ps2d: keyboard failed to enable reporting: {:02X}", b); + eprintln!("ps2d: keyboard failed to enable reporting: {:02X}", b); } + // Clear remaining data + self.flush_read("init finish"); + + Ok(()) + } + + pub fn init_mouse(&mut self) -> Result { + let mut b = 0; + + // Clear remaining data + self.flush_read("mouse init start"); + // Reset mouse and set up scroll - b = self.mouse_command(MouseCommand::Reset); + b = self.mouse_command(MouseCommand::Reset)?; if b == 0xFA { - b = self.read(); + b = self.read()?; if b != 0xAA { - println!("ps2d: mouse failed self test 1: {:02X}", b); + eprintln!("ps2d: mouse failed self test 1: {:02X}", b); } - b = self.read(); + b = self.read()?; if b != 0x00 { - println!("ps2d: mouse failed self test 2: {:02X}", b); + eprintln!("ps2d: mouse failed self test 2: {:02X}", b); } } else { - println!("ps2d: mouse failed to reset: {:02X}", b); + eprintln!("ps2d: mouse failed to reset: {:02X}", b); } // Clear remaining data @@ -282,47 +322,47 @@ impl Ps2 { // Enable extra packet on mouse //TODO: show error return values - if self.mouse_command_data(MouseCommandData::SetSampleRate, 200) != 0xFA - || self.mouse_command_data(MouseCommandData::SetSampleRate, 100) != 0xFA - || self.mouse_command_data(MouseCommandData::SetSampleRate, 80) != 0xFA { - println!("ps2d: mouse failed to enable extra packet"); + if self.mouse_command_data(MouseCommandData::SetSampleRate, 200)? != 0xFA + || self.mouse_command_data(MouseCommandData::SetSampleRate, 100)? != 0xFA + || self.mouse_command_data(MouseCommandData::SetSampleRate, 80)? != 0xFA { + eprintln!("ps2d: mouse failed to enable extra packet"); } - b = self.mouse_command(MouseCommand::GetDeviceId); + b = self.mouse_command(MouseCommand::GetDeviceId)?; let mouse_extra = if b == 0xFA { - self.read() == 3 + self.read()? == 3 } else { - println!("ps2d: mouse failed to get device id: {:02X}", b); + eprintln!("ps2d: mouse failed to get device id: {:02X}", b); false }; // Set sample rate to maximum let sample_rate = 200; - b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate); + b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate)?; if b != 0xFA { - println!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b); + eprintln!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b); } // Enable data reporting - b = self.mouse_command(MouseCommand::EnableReporting); + b = self.mouse_command(MouseCommand::EnableReporting)?; if b != 0xFA { - println!("ps2d: mouse failed to enable reporting: {:02X}", b); + eprintln!("ps2d: mouse failed to enable reporting: {:02X}", b); } // Enable clocks and interrupts { - let mut config = self.config(); + let mut config = self.config()?; config.remove(ConfigFlags::FIRST_DISABLED); config.remove(ConfigFlags::SECOND_DISABLED); config.insert(ConfigFlags::FIRST_TRANSLATE); config.insert(ConfigFlags::FIRST_INTERRUPT); config.insert(ConfigFlags::SECOND_INTERRUPT); - self.set_config(config); + self.set_config(config)?; } // Clear remaining data - self.flush_read("init finish"); + self.flush_read("mouse init finish"); - mouse_extra + Ok(mouse_extra) } } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 58dd4d38b2..56bd0a2014 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -12,7 +12,6 @@ use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; use syscall::call::iopl; -use syscall::flag::CloneFlags; use crate::state::Ps2d; @@ -21,7 +20,7 @@ mod keymap; mod state; mod vm; -fn daemon(input: File) { +fn daemon(daemon: syscall::Daemon) -> ! { unsafe { iopl(3).expect("ps2d: failed to get I/O permission"); } @@ -39,6 +38,11 @@ fn daemon(input: File) { None => (keymap::us::get_char) }; + let input = OpenOptions::new() + .write(true) + .open("display:input") + .expect("p2sd: failed to open display:input"); + let mut event_file = OpenOptions::new() .read(true) .write(true) @@ -71,10 +75,12 @@ fn daemon(input: File) { data: 1 }).expect("ps2d: failed to event irq:12"); - let mut ps2d = Ps2d::new(input, keymap); - syscall::setrens(0, 0).expect("ps2d: failed to enter null namespace"); + daemon.ready().expect("p2sd: failed to mark daemon as ready"); + + let mut ps2d = Ps2d::new(input, keymap); + let mut data = [0; 256]; loop { // There are some gotchas with ps/2 controllers that require this weird @@ -108,19 +114,10 @@ fn daemon(input: File) { } } } + + process::exit(0); } fn main() { - match OpenOptions::new().write(true).open("display:input") { - Ok(input) => { - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { - daemon(input); - } - }, - Err(err) => { - println!("ps2d: failed to open display: {}", err); - process::exit(1); - } - } + syscall::Daemon::new(daemon).expect("p2sd: failed to create daemon"); } diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 6671dc7ed8..38bb484457 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -45,7 +45,14 @@ pub struct Ps2d char> { impl char> Ps2d { pub fn new(input: File, keymap: F) -> Self { let mut ps2 = Ps2::new(); - let extra_packet = ps2.init(); + ps2.init().expect("ps2d: failed to initialize"); + let extra_packet = match ps2.init_mouse() { + Ok(ok) => ok, + Err(err) => { + eprintln!("p2sd: failed to initialize mouse: {:?}", err); + false + } + }; let vmmouse_relative = true; let vmmouse = false; //vm::enable(vmmouse_relative); @@ -121,7 +128,7 @@ impl char> Ps2d { } if queue_length % 4 != 0 { - println!("ps2d: queue length not a multiple of 4: {}", queue_length); + eprintln!("ps2d: queue length not a multiple of 4: {}", queue_length); break; } @@ -177,7 +184,7 @@ impl char> Ps2d { let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); if ! flags.contains(MousePacketFlags::ALWAYS_ON) { - println!("ps2d: mouse misalign {:X}", self.packets[0]); + eprintln!("ps2d: mouse misalign {:X}", self.packets[0]); self.packets = [0; 4]; self.packet_i = 0; @@ -230,7 +237,7 @@ impl char> Ps2d { }.to_event()).expect("ps2d: failed to write button event"); } } else { - println!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); + eprintln!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); } self.packets = [0; 4]; diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index be4b0ab443..b067a8f41e 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -57,20 +57,20 @@ pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32, u32, u32) { } pub fn enable(relative: bool) -> bool { - println!("ps2d: Enable vmmouse"); + eprintln!("ps2d: Enable vmmouse"); unsafe { let _ = cmd(ABSPOINTER_COMMAND, CMD_ENABLE); let (status, _, _, _, _, _) = cmd(ABSPOINTER_STATUS, 0); if (status & 0x0000ffff) == 0 { - println!("ps2d: No vmmouse"); + eprintln!("ps2d: No vmmouse"); return false; } let (version, _, _, _, _, _) = cmd(ABSPOINTER_DATA, 1); if version != VERSION { - println!("ps2d: Invalid vmmouse version: {} instead of {}", version, VERSION); + eprintln!("ps2d: Invalid vmmouse version: {} instead of {}", version, VERSION); let _ = cmd(ABSPOINTER_COMMAND, CMD_DISABLE); return false; } From c5a1013bc2a536be9aa5abd71616fd29abea7d09 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 1 Mar 2022 20:34:27 -0700 Subject: [PATCH 0472/1301] rtl8168d: use syscall::Daemon --- Cargo.lock | 4 ++-- rtl8168d/Cargo.toml | 2 +- rtl8168d/src/main.rs | 28 +++++----------------------- 3 files changed, 8 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 86820f3928..c602d8936e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1165,9 +1165,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee" +checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" dependencies = [ "bitflags", ] diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index f5232dca04..c10aace849 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -7,4 +7,4 @@ edition = "2018" bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.9" +redox_syscall = "0.2.11" diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index b632089a2f..e81764aa36 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -74,27 +74,9 @@ fn main() { let irq_str = args.next().expect("rtl8168d: no irq provided"); let irq = irq_str.parse::().expect("rtl8168d: failed to parse irq"); - println!(" + RTL8168 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); - - // Daemonize - let mut pipes = [0; 2]; - syscall::pipe2(&mut pipes, 0).unwrap(); - let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; - let mut write = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; - let pid = unsafe { syscall::clone(CloneFlags::empty()).unwrap() }; - if pid != 0 { - drop(write); - - let mut res = [0]; - if read.read(&mut res).unwrap() == res.len() { - process::exit(res[0] as i32); - } else { - eprintln!("rtl8168d: daemon pipe EOF"); - process::exit(1); - } - } else { - drop(read); + eprintln!(" + RTL8168 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); + syscall::Daemon::new(move |daemon| { let socket_fd = syscall::open( ":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, @@ -124,8 +106,7 @@ fn main() { syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); - write.write(&[0]).unwrap(); - drop(write); + daemon.ready().expect("rtl8168d: failed to mark daemon as ready"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -218,5 +199,6 @@ fn main() { unsafe { let _ = syscall::physunmap(address); } - } + process::exit(0); + }).expect("rtl8168d: failed to create daemon") } From c69ee40684cc107209c9d865fdbc584c5c2c899d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 1 Mar 2022 20:56:08 -0700 Subject: [PATCH 0473/1301] Print out selected keymap --- ps2d/src/main.rs | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 56bd0a2014..d72d9b0d4b 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -25,19 +25,24 @@ fn daemon(daemon: syscall::Daemon) -> ! { iopl(3).expect("ps2d: failed to get I/O permission"); } - let keymap = match env::args().skip(1).next() { + let (keymap, keymap_name): ( + fn(u8, bool) -> char, + &str + ) = match env::args().skip(1).next() { Some(k) => match k.to_lowercase().as_ref() { - "dvorak" => (keymap::dvorak::get_char), - "us" => (keymap::us::get_char), - "gb" => (keymap::gb::get_char), - "azerty" => (keymap::azerty::get_char), - "bepo" => (keymap::bepo::get_char), - "it" => (keymap::it::get_char), - &_ => (keymap::us::get_char) + "dvorak" => (keymap::dvorak::get_char, "dvorak"), + "us" => (keymap::us::get_char, "us"), + "gb" => (keymap::gb::get_char, "gb"), + "azerty" => (keymap::azerty::get_char, "azerty"), + "bepo" => (keymap::bepo::get_char, "bepo"), + "it" => (keymap::it::get_char, "it"), + &_ => (keymap::us::get_char, "us"), }, - None => (keymap::us::get_char) + None => (keymap::us::get_char, "us"), }; + eprintln!("p2sd: using keymap '{}'", keymap_name); + let input = OpenOptions::new() .write(true) .open("display:input") From 397f45e19d26237b69627b3f64798f2e0106ff0a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 1 Mar 2022 21:34:53 -0700 Subject: [PATCH 0474/1301] p2sd: fixes for mouseless systems --- ps2d/src/controller.rs | 160 +++++++++++++++++++++-------------------- ps2d/src/state.rs | 9 +-- 2 files changed, 84 insertions(+), 85 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 3cf5ede5c1..1f825b6e01 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -1,6 +1,6 @@ use syscall::io::{Io, Pio, ReadOnly, WriteOnly}; -use std::{thread, time}; +use std::thread; #[derive(Debug)] pub enum Error { @@ -103,34 +103,32 @@ impl Ps2 { } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 100; - while self.status().contains(StatusFlags::INPUT_FULL) && timeout > 0 { - thread::sleep(time::Duration::from_millis(1)); + let mut timeout = 10_000; + while self.status().contains(StatusFlags::INPUT_FULL) { + if timeout <= 0 { + return Err(Error::WriteTimeout); + } timeout -= 1; + thread::yield_now(); } - if timeout > 0 { - Ok(()) - } else { - Err(Error::WriteTimeout) - } + Ok(()) } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 100; - while ! self.status().contains(StatusFlags::OUTPUT_FULL) && timeout > 0 { - thread::sleep(time::Duration::from_millis(1)); + let mut timeout = 10_000; + while ! self.status().contains(StatusFlags::OUTPUT_FULL) { + if timeout <= 0 { + return Err(Error::ReadTimeout); + } timeout -= 1; + thread::yield_now(); } - if timeout > 0 { - Ok(()) - } else { - Err(Error::ReadTimeout) - } + Ok(()) } fn flush_read(&mut self, message: &str) { while self.status().contains(StatusFlags::OUTPUT_FULL) { - print!("ps2d: flush {}: {:X}\n", message, self.data.read()); + eprintln!("ps2d: flush {}: {:X}", message, self.data.read()); } } @@ -227,7 +225,67 @@ impl Ps2 { } } - pub fn init(&mut self) -> Result<(), Error> { + pub fn init_mouse(&mut self) -> Result { + let mut b = 0; + + // Clear remaining data + self.flush_read("init mouse start"); + + // Reset mouse and set up scroll + b = self.mouse_command(MouseCommand::Reset)?; + if b == 0xFA { + b = self.read()?; + if b != 0xAA { + eprintln!("ps2d: mouse failed self test 1: {:02X}", b); + } + + b = self.read()?; + if b != 0x00 { + eprintln!("ps2d: mouse failed self test 2: {:02X}", b); + } + } else { + eprintln!("ps2d: mouse failed to reset: {:02X}", b); + } + + // Clear remaining data + self.flush_read("mouse defaults"); + + // Enable extra packet on mouse + //TODO: show error return values + if self.mouse_command_data(MouseCommandData::SetSampleRate, 200)? != 0xFA + || self.mouse_command_data(MouseCommandData::SetSampleRate, 100)? != 0xFA + || self.mouse_command_data(MouseCommandData::SetSampleRate, 80)? != 0xFA { + eprintln!("ps2d: mouse failed to enable extra packet"); + } + + b = self.mouse_command(MouseCommand::GetDeviceId)?; + let mouse_extra = if b == 0xFA { + self.read()? == 3 + } else { + eprintln!("ps2d: mouse failed to get device id: {:02X}", b); + false + }; + + // Set sample rate to maximum + let sample_rate = 200; + b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate)?; + if b != 0xFA { + eprintln!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b); + } + + // Enable data reporting + b = self.mouse_command(MouseCommand::EnableReporting)?; + if b != 0xFA { + eprintln!("ps2d: mouse failed to enable reporting: {:02X}", b); + } + + // Clear remaining data + self.flush_read("init mouse finish"); + + Ok(mouse_extra) + } + + pub fn init(&mut self) -> Result { let mut b = 0; // Clear remaining data @@ -289,66 +347,14 @@ impl Ps2 { eprintln!("ps2d: keyboard failed to enable reporting: {:02X}", b); } - // Clear remaining data - self.flush_read("init finish"); - - Ok(()) - } - - pub fn init_mouse(&mut self) -> Result { - let mut b = 0; - - // Clear remaining data - self.flush_read("mouse init start"); - - // Reset mouse and set up scroll - b = self.mouse_command(MouseCommand::Reset)?; - if b == 0xFA { - b = self.read()?; - if b != 0xAA { - eprintln!("ps2d: mouse failed self test 1: {:02X}", b); + let mouse_extra = match self.init_mouse() { + Ok(ok) => ok, + Err(err) => { + eprintln!("p2sd: failed to initialize mouse: {:?}", err); + false } - - b = self.read()?; - if b != 0x00 { - eprintln!("ps2d: mouse failed self test 2: {:02X}", b); - } - } else { - eprintln!("ps2d: mouse failed to reset: {:02X}", b); - } - - // Clear remaining data - self.flush_read("mouse defaults"); - - // Enable extra packet on mouse - //TODO: show error return values - if self.mouse_command_data(MouseCommandData::SetSampleRate, 200)? != 0xFA - || self.mouse_command_data(MouseCommandData::SetSampleRate, 100)? != 0xFA - || self.mouse_command_data(MouseCommandData::SetSampleRate, 80)? != 0xFA { - eprintln!("ps2d: mouse failed to enable extra packet"); - } - - b = self.mouse_command(MouseCommand::GetDeviceId)?; - let mouse_extra = if b == 0xFA { - self.read()? == 3 - } else { - eprintln!("ps2d: mouse failed to get device id: {:02X}", b); - false }; - // Set sample rate to maximum - let sample_rate = 200; - b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate)?; - if b != 0xFA { - eprintln!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b); - } - - // Enable data reporting - b = self.mouse_command(MouseCommand::EnableReporting)?; - if b != 0xFA { - eprintln!("ps2d: mouse failed to enable reporting: {:02X}", b); - } - // Enable clocks and interrupts { let mut config = self.config()?; @@ -361,7 +367,7 @@ impl Ps2 { } // Clear remaining data - self.flush_read("mouse init finish"); + self.flush_read("init finish"); Ok(mouse_extra) } diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 38bb484457..1e174a0e03 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -45,14 +45,7 @@ pub struct Ps2d char> { impl char> Ps2d { pub fn new(input: File, keymap: F) -> Self { let mut ps2 = Ps2::new(); - ps2.init().expect("ps2d: failed to initialize"); - let extra_packet = match ps2.init_mouse() { - Ok(ok) => ok, - Err(err) => { - eprintln!("p2sd: failed to initialize mouse: {:?}", err); - false - } - }; + let extra_packet = ps2.init().expect("ps2d: failed to initialize"); let vmmouse_relative = true; let vmmouse = false; //vm::enable(vmmouse_relative); From 76d46d92363750dc743a26536450144a3dc82cd5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 1 Mar 2022 21:41:55 -0700 Subject: [PATCH 0475/1301] p2sd: disable second port if no mouse found --- ps2d/src/controller.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 1f825b6e01..866f7ac047 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -347,11 +347,11 @@ impl Ps2 { eprintln!("ps2d: keyboard failed to enable reporting: {:02X}", b); } - let mouse_extra = match self.init_mouse() { - Ok(ok) => ok, + let (mouse_found, mouse_extra) = match self.init_mouse() { + Ok(ok) => (true, ok), Err(err) => { eprintln!("p2sd: failed to initialize mouse: {:?}", err); - false + (false, false) } }; @@ -359,10 +359,15 @@ impl Ps2 { { let mut config = self.config()?; config.remove(ConfigFlags::FIRST_DISABLED); - config.remove(ConfigFlags::SECOND_DISABLED); config.insert(ConfigFlags::FIRST_TRANSLATE); config.insert(ConfigFlags::FIRST_INTERRUPT); - config.insert(ConfigFlags::SECOND_INTERRUPT); + if mouse_found { + config.remove(ConfigFlags::SECOND_DISABLED); + config.insert(ConfigFlags::SECOND_INTERRUPT); + } else { + config.insert(ConfigFlags::SECOND_DISABLED); + config.remove(ConfigFlags::SECOND_INTERRUPT); + } self.set_config(config)?; } From 0e6698de6429ce7f6cff99f958dbff38f7c35134 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 1 Mar 2022 21:46:15 -0700 Subject: [PATCH 0476/1301] ps2d: Wait for ps2 initialization before sending daemon ready --- ps2d/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index d72d9b0d4b..848e66fffe 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -82,10 +82,10 @@ fn daemon(daemon: syscall::Daemon) -> ! { syscall::setrens(0, 0).expect("ps2d: failed to enter null namespace"); - daemon.ready().expect("p2sd: failed to mark daemon as ready"); - let mut ps2d = Ps2d::new(input, keymap); + daemon.ready().expect("p2sd: failed to mark daemon as ready"); + let mut data = [0; 256]; loop { // There are some gotchas with ps/2 controllers that require this weird From d426ffacea7b494324b3597039529924248f8ede Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 19 Mar 2022 15:06:29 +0100 Subject: [PATCH 0477/1301] Update toolchain to 2022-03-18. --- Cargo.lock | 438 +++++++++++++++-------------------------- Cargo.toml | 1 + ahcid/src/ahci/hba.rs | 8 +- ahcid/src/main.rs | 2 - alxd/src/main.rs | 1 - e1000d/src/main.rs | 2 - ihdad/src/main.rs | 1 - pcid/src/lib.rs | 2 - pcid/src/main.rs | 2 - pcid/src/pci/mod.rs | 19 +- ps2d/src/main.rs | 4 +- ps2d/src/vm.rs | 64 +++--- rtl8168d/src/device.rs | 2 +- rtl8168d/src/main.rs | 4 +- vesad/src/main.rs | 1 - vesad/src/primitive.rs | 47 ++--- 16 files changed, 231 insertions(+), 367 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c602d8936e..381269b486 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,19 +9,13 @@ dependencies = [ "log", "num-derive", "num-traits", - "parking_lot 0.11.1", + "parking_lot 0.11.2", "plain", "redox-log", "redox_syscall", "thiserror", ] -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "ahcid" version = "0.1.0" @@ -35,15 +29,6 @@ dependencies = [ "redox_syscall", ] -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - [[package]] name = "alxd" version = "0.1.0" @@ -56,9 +41,9 @@ dependencies = [ [[package]] name = "ansi_term" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ "winapi 0.3.9", ] @@ -96,15 +81,18 @@ dependencies = [ [[package]] name = "autocfg" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" +dependencies = [ + "autocfg 1.1.0", +] [[package]] name = "autocfg" -version = "1.0.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" @@ -147,9 +135,9 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "bumpalo" -version = "3.7.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "byteorder" @@ -165,9 +153,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.68" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" [[package]] name = "cfg-if" @@ -206,9 +194,9 @@ dependencies = [ [[package]] name = "clap" -version = "2.33.3" +version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", @@ -230,9 +218,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.45" +version = "0.1.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855" +checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" dependencies = [ "cc", ] @@ -246,15 +234,6 @@ dependencies = [ "build_const", ] -[[package]] -name = "crc32fast" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "crossbeam-channel" version = "0.4.4" @@ -267,12 +246,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.5", + "crossbeam-utils 0.8.8", ] [[package]] @@ -281,21 +260,27 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "cfg-if 0.1.10", "lazy_static", ] [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if 1.0.0", "lazy_static", ] +[[package]] +name = "cty" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" + [[package]] name = "e1000d" version = "0.1.0" @@ -306,44 +291,11 @@ dependencies = [ "redox_syscall", ] -[[package]] -name = "encoding_rs" -version = "0.8.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "extra" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#cf213969493db8667052a591e32a1e26d43c4234" -[[package]] -name = "filetime" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "redox_syscall", - "winapi 0.3.9", -] - -[[package]] -name = "flate2" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" -dependencies = [ - "cfg-if 1.0.0", - "crc32fast", - "libc", - "miniz_oxide", -] - [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -368,9 +320,9 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" [[package]] name = "futures" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7e43a803dae2fa37c1f6a8fe121e1f7bf9548b4dfc0522a42f34145dadfc27" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", @@ -383,9 +335,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e682a68b29a882df0545c143dc3646daefe80ba479bcdede94d5a703de2871e2" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -393,15 +345,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0402f765d8a89a26043b889b26ce3c4679d268fa6bb22cd7c6aad98340e179d1" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-executor" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "badaa6a909fac9e7236d0620a2f57f7664640c56575b71a7552fbd68deafab79" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -410,18 +362,16 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acc499defb3b348f8d8f3f66415835a9131856ff7714bf10dadfc4ec4bdb29a1" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-macro" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c40298486cdf52cc00cd6d6987892ba502c7656a16a4192a9992b1ccedd121" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ - "autocfg 1.0.1", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -429,23 +379,22 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a57bead0ceff0d6dde8f465ecd96c9338121bb7717d3e7b108059531870c4282" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a16bef9fc1a4dddb5bee51c989e3fbba26569cbb0e31f5b303c184e3dd33dae" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-util" -version = "0.3.15" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb5c238d27e2bf94ffdfd27b2c29e3df4a68c4193bb6427384259e2bf191967" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ - "autocfg 1.0.1", "futures-channel", "futures-core", "futures-io", @@ -455,8 +404,6 @@ dependencies = [ "memchr", "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] @@ -482,9 +429,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -514,9 +461,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if 1.0.0", ] @@ -532,9 +479,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "ixgbed" @@ -548,9 +495,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.51" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" dependencies = [ "wasm-bindgen", ] @@ -579,9 +526,9 @@ checksum = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" [[package]] name = "libc" -version = "0.2.97" +version = "0.2.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b8adadd720df158f4d70dfe7ccc6adb0472d7c55ca83445f6a5ab3e36f8fb6" +checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" [[package]] name = "linked-hash-map" @@ -591,9 +538,9 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "lock_api" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ "scopeguard", ] @@ -609,9 +556,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "maybe-uninit" @@ -621,19 +568,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.4.0" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" - -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg 1.0.1", -] +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "mio" @@ -726,7 +663,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", "num-traits", ] @@ -736,7 +673,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.0.1", + "autocfg 1.1.0", ] [[package]] @@ -759,16 +696,16 @@ dependencies = [ "pcid", "redox-log", "redox_syscall", - "smallvec 1.6.1", + "smallvec 1.8.0", ] [[package]] name = "orbclient" -version = "0.3.31" -source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#8ef4433da9871d6f6e8c11d0b863f737144d19f1" +version = "0.3.32" +source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#192dc30edbad43ee8c5348411b162600d43dfaf9" dependencies = [ "libc", - "raw-window-handle", + "raw-window-handle 0.3.4", "redox_syscall", "sdl2", "sdl2-sys", @@ -797,13 +734,13 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core 0.8.3", + "parking_lot_core 0.8.5", ] [[package]] @@ -820,15 +757,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ "cfg-if 1.0.0", "instant", "libc", "redox_syscall", - "smallvec 1.6.1", + "smallvec 1.8.0", "winapi 0.3.9", ] @@ -875,7 +812,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff5751d87f7c00ae6403eb1fcbba229b9c76c9a30de8c1cf87182177b168cea2" dependencies = [ - "crossbeam-channel 0.5.1", + "crossbeam-channel 0.5.4", "libc", "time", "winapi 0.3.9", @@ -896,7 +833,7 @@ dependencies = [ "redox_syscall", "serde", "serde_json", - "smallvec 1.6.1", + "smallvec 1.8.0", "structopt", "thiserror", "toml", @@ -917,9 +854,9 @@ checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] name = "pin-project-lite" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" [[package]] name = "pin-utils" @@ -957,23 +894,11 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" -version = "1.0.27" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] @@ -989,9 +914,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.9" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57" dependencies = [ "proc-macro2", ] @@ -1015,7 +940,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" dependencies = [ - "autocfg 0.1.7", + "autocfg 0.1.8", "libc", "rand_chacha", "rand_core 0.4.2", @@ -1034,7 +959,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" dependencies = [ - "autocfg 0.1.7", + "autocfg 0.1.8", "rand_core 0.3.1", ] @@ -1102,7 +1027,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" dependencies = [ - "autocfg 0.1.7", + "autocfg 0.1.8", "rand_core 0.4.2", ] @@ -1127,11 +1052,21 @@ dependencies = [ [[package]] name = "raw-window-handle" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a441a7a6c80ad6473bd4b74ec1c9a4c951794285bf941c2126f607c72e48211" +checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76" dependencies = [ "libc", + "raw-window-handle 0.4.2", +] + +[[package]] +name = "raw-window-handle" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba75eee94a9d5273a68c9e1e105d9cffe1ef700532325788389e5a83e2522b7" +dependencies = [ + "cty", ] [[package]] @@ -1151,7 +1086,7 @@ checksum = "cbf6d33a003a5c0b94ec11f10c7c797303f236592964ddb1bfb93e1b438a1557" dependencies = [ "chrono", "log", - "smallvec 1.6.1", + "smallvec 1.8.0", "termion", ] @@ -1165,9 +1100,8 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +version = "0.2.12" +source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=update-toolchain-2022#94de991da2a75c45be0b73b18adc26522fb6f4a8" dependencies = [ "bitflags", ] @@ -1181,23 +1115,6 @@ dependencies = [ "redox_syscall", ] -[[package]] -name = "regex" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - [[package]] name = "rtl8168d" version = "0.1.0" @@ -1221,9 +1138,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "scopeguard" @@ -1253,46 +1170,43 @@ dependencies = [ [[package]] name = "sdl2" -version = "0.34.5" +version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deecbc3fa9460acff5a1e563e05cb5f31bba0aa0c214bb49a43db8159176d54b" +checksum = "f7959277b623f1fb9e04aea73686c3ca52f01b2145f8ea16f4ff30d8b7623b1a" dependencies = [ "bitflags", "lazy_static", "libc", - "raw-window-handle", + "raw-window-handle 0.4.2", "sdl2-sys", ] [[package]] name = "sdl2-sys" -version = "0.34.5" +version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a29aa21f175b5a41a6e26da572d5e5d1ee5660d35f9f9d0913e8a802098f74" +checksum = "e3586be2cf6c0a8099a79a12b4084357aa9b3e0b0d7980e3b67aaf7a9d55f9f0" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "cmake", - "flate2", "libc", - "tar", - "unidiff", "version-compare", ] [[package]] name = "serde" -version = "1.0.126" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -1301,9 +1215,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ "itoa", "ryu", @@ -1312,9 +1226,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" +checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "smallvec" @@ -1327,18 +1241,18 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.6.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" dependencies = [ "serde", ] [[package]] name = "spin" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87bbf98cb81332a56c1ee8929845836f85e8ddd693157c30d76660196014478" +checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" dependencies = [ "lock_api", ] @@ -1375,9 +1289,9 @@ checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" [[package]] name = "structopt" -version = "0.3.21" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" +checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" dependencies = [ "clap", "lazy_static", @@ -1387,9 +1301,9 @@ dependencies = [ [[package]] name = "structopt-derive" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" dependencies = [ "heck", "proc-macro-error", @@ -1400,26 +1314,15 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.73" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f71489ff30030d2ae598524f61326b902466f72a0fb1a8564c001cc63425bcc7" +checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] -[[package]] -name = "tar" -version = "0.4.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d779dc6aeff029314570f666ec83f19df7280bb36ef338442cfa8c604021b80" -dependencies = [ - "filetime", - "libc", - "xattr", -] - [[package]] name = "termion" version = "1.5.6" @@ -1443,18 +1346,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.25" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.25" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", @@ -1474,9 +1377,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.2.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" dependencies = [ "tinyvec_macros", ] @@ -1498,12 +1401,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeb8be209bb1c96b7c177c7420d26e04eccacb0eeae6b980e35fcb74678107e0" -dependencies = [ - "matches", -] +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" [[package]] name = "unicode-normalization" @@ -1516,15 +1416,15 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.7.1" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" @@ -1532,17 +1432,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" -[[package]] -name = "unidiff" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a62719acf1933bfdbeb73a657ecd9ecece70b405125267dd549e2e2edc232c" -dependencies = [ - "encoding_rs", - "lazy_static", - "regex", -] - [[package]] name = "url" version = "1.7.2" @@ -1602,9 +1491,9 @@ dependencies = [ [[package]] name = "ux" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" +checksum = "5efdcf885b33bb81bc9336e66cebc10d503288449466c0e43e51250ddc93a3d8" [[package]] name = "vboxd" @@ -1623,15 +1512,15 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version-compare" -version = "0.0.10" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" +checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "vesad" @@ -1660,9 +1549,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.74" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -1670,9 +1559,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.74" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" dependencies = [ "bumpalo", "lazy_static", @@ -1685,9 +1574,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.74" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1695,9 +1584,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.74" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" dependencies = [ "proc-macro2", "quote", @@ -1708,15 +1597,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.74" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" [[package]] name = "web-sys" -version = "0.3.51" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" dependencies = [ "js-sys", "wasm-bindgen", @@ -1766,15 +1655,6 @@ dependencies = [ "winapi-build", ] -[[package]] -name = "xattr" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" -dependencies = [ - "libc", -] - [[package]] name = "xhcid" version = "0.1.0" @@ -1792,7 +1672,7 @@ dependencies = [ "redox_syscall", "serde", "serde_json", - "smallvec 1.6.1", + "smallvec 1.8.0", "thiserror", "toml", ] diff --git a/Cargo.toml b/Cargo.toml index 8078a99e90..c5c315d790 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,4 @@ members = [ mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.28" } +redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "update-toolchain-2022" } diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index b4f416d8ed..1e7f8031db 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -76,7 +76,7 @@ impl HbaPort { pub fn start(&mut self) { while self.cmd.readf(HBA_PORT_CMD_CR) { - unsafe { llvm_asm!("pause"); } + core::hint::spin_loop(); } self.cmd.writef(HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST, true); @@ -86,7 +86,7 @@ impl HbaPort { self.cmd.writef(HBA_PORT_CMD_ST, false); while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { - unsafe { llvm_asm!("pause"); } + core::hint::spin_loop(); } self.cmd.writef(HBA_PORT_CMD_FRE, false); @@ -306,7 +306,7 @@ impl HbaPort { } while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - unsafe { llvm_asm!("pause"); } + core::hint::spin_loop(); } self.ci.writef(1 << slot, true); @@ -326,7 +326,7 @@ impl HbaPort { pub fn ata_stop(&mut self, slot: u32) -> Result<()> { while self.ata_running(slot) { - unsafe { llvm_asm!("pause"); } + core::hint::spin_loop(); } self.stop(); diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index eefdce1ba0..cef16638a2 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -1,5 +1,3 @@ -#![feature(llvm_asm)] - extern crate syscall; extern crate byteorder; diff --git a/alxd/src/main.rs b/alxd/src/main.rs index 77c342f808..7acdd1df7d 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -1,7 +1,6 @@ #![allow(dead_code)] #![allow(non_upper_case_globals)] #![allow(unused_parens)] -#![feature(llvm_asm)] #![feature(concat_idents)] extern crate event; diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 0a75a51a05..49d2a3beea 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -1,5 +1,3 @@ -#![feature(llvm_asm)] - extern crate event; extern crate netutils; extern crate syscall; diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 2a0ac274bb..70b486e1e6 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -1,5 +1,4 @@ //#![deny(warnings)] -#![feature(llvm_asm)] extern crate bitflags; extern crate spin; diff --git a/pcid/src/lib.rs b/pcid/src/lib.rs index bddde59abe..bf750605da 100644 --- a/pcid/src/lib.rs +++ b/pcid/src/lib.rs @@ -1,7 +1,5 @@ //! Interface to `pcid`. -#![feature(llvm_asm)] - mod driver_interface; mod pci; pub use driver_interface::*; diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 9240d4f046..fce37d5b25 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,5 +1,3 @@ -#![feature(llvm_asm)] - use std::fs::{File, metadata, read_dir}; use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 371b01580d..7338552f23 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,6 +1,8 @@ use std::convert::TryFrom; use std::sync::{Mutex, Once}; +use syscall::io::{Io as _, Pio}; + pub use self::bar::PciBar; pub use self::bus::{PciBus, PciBusIter}; pub use self::class::PciClass; @@ -71,13 +73,8 @@ impl CfgAccess for Pci { let offset = u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); let address = Self::address(bus, dev, func, offset); - let value: u32; - llvm_asm!("mov dx, 0xCF8 - out dx, eax - mov dx, 0xCFC - in eax, dx" - : "={eax}"(value) : "{eax}"(address) : "dx" : "intel", "volatile"); - value + Pio::::new(0xCF8).write(address); + Pio::::new(0xCFC).read() } unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { @@ -91,12 +88,8 @@ impl CfgAccess for Pci { let offset = u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); let address = Self::address(bus, dev, func, offset); - llvm_asm!("mov dx, 0xCF8 - out dx, eax" - : : "{eax}"(address) : "dx" : "intel", "volatile"); - llvm_asm!("mov dx, 0xCFC - out dx, eax" - : : "{eax}"(value) : "dx" : "intel", "volatile"); + Pio::::new(0xCF8).write(address); + Pio::::new(0xCFC).write(value); } unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { let _guard = self.lock.lock().unwrap(); diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 848e66fffe..934efb5631 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -1,4 +1,4 @@ -#![feature(llvm_asm)] +#![feature(asm_const)] #[macro_use] extern crate bitflags; @@ -20,7 +20,7 @@ mod keymap; mod state; mod vm; -fn daemon(daemon: syscall::Daemon) -> ! { +fn daemon(daemon: syscall::Daemon) -> core::convert::Infallible { unsafe { iopl(3).expect("ps2d: failed to get I/O permission"); } diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index b067a8f41e..97a014e7d5 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -4,6 +4,8 @@ // As well as the Linux implementation here: // http://elixir.free-electrons.com/linux/v4.1/source/drivers/input/mouse/vmmouse.c +use core::arch::global_asm; + const MAGIC: u32 = 0x564D5868; const PORT: u16 = 0x5658; @@ -24,36 +26,46 @@ pub const LEFT_BUTTON: u32 = 0x20; pub const RIGHT_BUTTON: u32 = 0x10; pub const MIDDLE_BUTTON: u32 = 0x08; +global_asm!(" + .globl cmd_inner +cmd_inner: + mov r8, rdi + + // 2nd argument `cmd` as per sysv64. + mov ecx, esi + // 3rd argument `arg` as per sysv64. + mov ebx, edx + + mov eax, {MAGIC} + mov dx, {PORT} + + in eax, dx + + xchg rdi, r8 + + mov DWORD PTR [rdi + 0x00], eax + mov DWORD PTR [rdi + 0x04], ebx + mov DWORD PTR [rdi + 0x08], ecx + mov DWORD PTR [rdi + 0x0C], edx + mov DWORD PTR [rdi + 0x10], esi + mov DWORD PTR [rdi + 0x14], r8d +", + MAGIC = const MAGIC, + PORT = const PORT, +); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32, u32, u32) { - let a: u32; - let b: u32; - let c: u32; - let d: u32; - let si: u32; - let di: u32; + extern "sysv64" { + fn cmd_inner(array_ptr: *mut u32, cmd: u32, arg: u32); + } - llvm_asm!( - "in eax, dx" - : - "={eax}"(a), - "={ebx}"(b), - "={ecx}"(c), - "={edx}"(d), - "={esi}"(si), - "={edi}"(di) - : - "{eax}"(MAGIC), - "{ebx}"(arg), - "{ecx}"(cmd), - "{dx}"(PORT) - : - "memory" - : - "intel", "volatile" - ); + let mut array = [0_u32; 6]; - (a, b, c, d, si, di) + cmd_inner(array.as_mut_ptr(), cmd, arg); + + let [a, b, c, d, e, f] = array; + (a, b, c, d, e, f) } pub fn enable(relative: bool) -> bool { diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 0773f012e7..6e3d0991dc 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -285,7 +285,7 @@ impl Rtl8168 { println!(" - Reset"); self.regs.cmd.writef(1 << 4, true); while self.regs.cmd.readf(1 << 4) { - llvm_asm!("pause"); + core::hint::spin_loop(); } // Set up rx buffers diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index e81764aa36..d2d3f34ebf 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -1,5 +1,3 @@ -#![feature(llvm_asm)] - extern crate event; extern crate netutils; extern crate syscall; @@ -200,5 +198,5 @@ fn main() { let _ = syscall::physunmap(address); } process::exit(0); - }).expect("rtl8168d: failed to create daemon") + }).expect("rtl8168d: failed to create daemon"); } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 8962a80dcc..4df6644003 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -1,5 +1,4 @@ #![feature(allocator_api)] -#![feature(llvm_asm)] extern crate orbclient; extern crate syscall; diff --git a/vesad/src/primitive.rs b/vesad/src/primitive.rs index 519fd3ac94..3879c4f99b 100644 --- a/vesad/src/primitive.rs +++ b/vesad/src/primitive.rs @@ -1,47 +1,38 @@ +use core::arch::asm; + #[cfg(target_arch = "x86_64")] #[inline(always)] -#[cold] pub unsafe fn fast_copy(dst: *mut u8, src: *const u8, len: usize) { - llvm_asm!("cld - rep movsb" - : - : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len) - : "cc", "memory", "rdi", "rsi", "rcx" - : "intel", "volatile"); + // direction flag must always be cleared, as per the System V ABI + asm!("rep movsb", + inout("rdi") dst as usize => _, inout("rsi") src as usize => _, inout("rcx") len => _, + options(nostack, preserves_flags), + ); } #[cfg(target_arch = "x86_64")] #[inline(always)] -#[cold] pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) { - llvm_asm!("cld - rep movsq" - : - : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len) - : "cc", "memory", "rdi", "rsi", "rcx" - : "intel", "volatile"); + asm!("rep movsq", + inout("rdi") dst as usize => _, inout("rsi") src as usize => _, inout("rcx") len => _, + options(nostack, preserves_flags), + ); } #[cfg(target_arch = "x86_64")] #[inline(always)] -#[cold] pub unsafe fn fast_set32(dst: *mut u32, src: u32, len: usize) { - llvm_asm!("cld - rep stosd" - : - : "{rdi}"(dst as usize), "{eax}"(src), "{rcx}"(len) - : "cc", "memory", "rdi", "rcx" - : "intel", "volatile"); + asm!("rep stosd", + inout("rdi") dst as usize => _, in("eax") src, inout("rcx") len => _, + options(nostack, preserves_flags), + ); } #[cfg(target_arch = "x86_64")] #[inline(always)] -#[cold] pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) { - llvm_asm!("cld - rep stosq" - : - : "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len) - : "cc", "memory", "rdi", "rcx" - : "intel", "volatile"); + asm!("rep stosq", + inout("rdi") dst as usize => _, in("rax") src, inout("rcx") len => _, + options(nostack, preserves_flags), + ); } From 07f10fb4d12ca724ba4bd69279bd91099024e850 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 24 Mar 2022 16:06:00 +0100 Subject: [PATCH 0478/1301] Update redox_syscall to v0.2.12 --- Cargo.lock | 7 ++++--- Cargo.toml | 1 - acpid/Cargo.toml | 2 +- ahcid/Cargo.toml | 2 +- alxd/Cargo.toml | 2 +- bgad/Cargo.toml | 2 +- e1000d/Cargo.toml | 2 +- ihdad/Cargo.toml | 2 +- ixgbed/Cargo.toml | 2 +- nvmed/Cargo.toml | 2 +- pcid/Cargo.toml | 2 +- pcspkrd/Cargo.toml | 2 +- ps2d/Cargo.toml | 2 +- rtl8168d/Cargo.toml | 2 +- usbscsid/Cargo.toml | 2 +- vboxd/Cargo.toml | 2 +- vesad/Cargo.toml | 2 +- xhcid/Cargo.toml | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 381269b486..2477590f78 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -547,9 +547,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.14" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" dependencies = [ "cfg-if 1.0.0", ] @@ -1101,7 +1101,8 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.2.12" -source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=update-toolchain-2022#94de991da2a75c45be0b73b18adc26522fb6f4a8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0" dependencies = [ "bitflags", ] diff --git a/Cargo.toml b/Cargo.toml index c5c315d790..8078a99e90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,4 +25,3 @@ members = [ mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.28" } -redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "update-toolchain-2022" } diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 12e879c397..ecd8ad11b4 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -13,5 +13,5 @@ num-traits = "0.2" parking_lot = "0.11.1" plain = "0.2.3" redox-log = "0.1.1" -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" thiserror = "1" diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index d39ade6572..74f11ce48a 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -9,5 +9,5 @@ byteorder = "1.2" log = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } redox-log = "0.1" -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml index 08d67ee31e..89c08b7ff9 100644 --- a/alxd/Cargo.toml +++ b/alxd/Cargo.toml @@ -7,4 +7,4 @@ edition = "2018" bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml index 6f93cf78e3..8dd06e8520 100644 --- a/bgad/Cargo.toml +++ b/bgad/Cargo.toml @@ -5,4 +5,4 @@ edition = "2018" [dependencies] orbclient = "0.3.27" -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index a7f17d77d5..4a1a005d01 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -7,4 +7,4 @@ edition = "2018" bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" diff --git a/ihdad/Cargo.toml b/ihdad/Cargo.toml index e96fae0740..c38f53e167 100755 --- a/ihdad/Cargo.toml +++ b/ihdad/Cargo.toml @@ -8,5 +8,5 @@ bitflags = "1" log = "0.4" redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" spin = "0.9" diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml index 3784e2373c..5833964c71 100644 --- a/ixgbed/Cargo.toml +++ b/ixgbed/Cargo.toml @@ -6,4 +6,4 @@ version = "1.0.0" bitflags = "1.0" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index c5ce4a641f..fed14c7a00 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -10,7 +10,7 @@ crossbeam-channel = "0.4" futures = "0.3" log = "0.4" redox-log = "0.1" -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } smallvec = "1" block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index e6259a0fac..3be59750c2 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4" paw = "1.0" plain = "0.2" redox-log = "0.1" -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = "1" diff --git a/pcspkrd/Cargo.toml b/pcspkrd/Cargo.toml index 649b11350f..cbe70ea730 100644 --- a/pcspkrd/Cargo.toml +++ b/pcspkrd/Cargo.toml @@ -5,4 +5,4 @@ authors = ["Tibor Nagy "] edition = "2018" [dependencies] -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index fa34ed3874..c9192a3972 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -6,4 +6,4 @@ edition = "2018" [dependencies] bitflags = "1" orbclient = "0.3.27" -redox_syscall = "0.2.11" +redox_syscall = "0.2.12" diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index c10aace849..6687ced3ed 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -7,4 +7,4 @@ edition = "2018" bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.11" +redox_syscall = "0.2.12" diff --git a/usbscsid/Cargo.toml b/usbscsid/Cargo.toml index 22a25a1955..a5a5eff5c3 100644 --- a/usbscsid/Cargo.toml +++ b/usbscsid/Cargo.toml @@ -10,6 +10,6 @@ license = "MIT" [dependencies] base64 = "0.11" # Only for debugging plain = "0.2" -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" thiserror = "1" xhcid = { path = "../xhcid" } diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index 454e60723b..774fe4fca9 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -6,4 +6,4 @@ edition = "2018" [dependencies] orbclient = "0.3.27" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 3e52d37652..49af3ac6b3 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" orbclient = "0.3.27" ransid = "0.4" rusttype = { version = "0.2", optional = true } -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" [features] default = [] diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index ba92d64a50..026d4b0c9e 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -21,7 +21,7 @@ lazy_static = "1.4" log = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox-log = "0.1" -redox_syscall = "0.2.9" +redox_syscall = "0.2.12" serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1", features = ["serde"] } From 8e1f91137efddc04010bad9f63aad1c708e3977d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 1 Apr 2022 18:02:49 -0600 Subject: [PATCH 0479/1301] e1000d: use syscall::Daemon --- e1000d/src/main.rs | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 49d2a3beea..093d567b98 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -72,27 +72,9 @@ fn main() { let irq_str = args.next().expect("e1000d: no irq provided"); let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); - println!(" + E1000 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); - - // Daemonize - let mut pipes = [0; 2]; - syscall::pipe2(&mut pipes, 0).unwrap(); - let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; - let mut write = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; - let pid = unsafe { syscall::clone(CloneFlags::empty()).unwrap() }; - if pid != 0 { - drop(write); - - let mut res = [0]; - if read.read(&mut res).unwrap() == res.len() { - process::exit(res[0] as i32); - } else { - eprintln!("e1000d: daemon pipe EOF"); - process::exit(1); - } - } else { - drop(read); + eprintln!(" + E1000 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); + syscall::Daemon::new(move |daemon| { let socket_fd = syscall::open( ":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, @@ -122,8 +104,7 @@ fn main() { syscall::setrens(0, 0).expect("e1000d: failed to enter null namespace"); - write.write(&[0]).unwrap(); - drop(write); + daemon.ready().expect("e1000d: failed to mark daemon as ready"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -215,5 +196,6 @@ fn main() { unsafe { let _ = syscall::physunmap(address); } - } + process::exit(0); + }).expect("e1000d: failed to create daemon"); } From 220e13c2d62c5613e9cd0564c7fd2f546c5acd7f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 11 Apr 2022 20:28:44 -0600 Subject: [PATCH 0480/1301] Map USB keyboards using us layout --- usbhidd/src/keymap.rs | 478 ++++++++++++++++++++++++++++++++++++++++++ usbhidd/src/main.rs | 186 ++++++++++++++-- 2 files changed, 647 insertions(+), 17 deletions(-) create mode 100644 usbhidd/src/keymap.rs diff --git a/usbhidd/src/keymap.rs b/usbhidd/src/keymap.rs new file mode 100644 index 0000000000..236e7caa07 --- /dev/null +++ b/usbhidd/src/keymap.rs @@ -0,0 +1,478 @@ +pub mod us { + static US: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['1', '!'], + ['2', '@'], + ['3', '#'], + ['4', '$'], + ['5', '%'], + ['6', '^'], + ['7', '&'], + ['8', '*'], + ['9', '('], + ['0', ')'], + ['-', '_'], + ['=', '+'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['q', 'Q'], + ['w', 'W'], + ['e', 'E'], + ['r', 'R'], + ['t', 'T'], + ['y', 'Y'], + ['u', 'U'], + ['i', 'I'], + ['o', 'O'], + ['p', 'P'], + ['[', '{'], + [']', '}'], + ['\n', '\n'], + ['\0', '\0'], + ['a', 'A'], + ['s', 'S'], + ['d', 'D'], + ['f', 'F'], + ['g', 'G'], + ['h', 'H'], + ['j', 'J'], + ['k', 'K'], + ['l', 'L'], + [';', ':'], + ['\'', '"'], + ['`', '~'], + ['\0', '\0'], + ['\\', '|'], + ['z', 'Z'], + ['x', 'X'], + ['c', 'C'], + ['v', 'V'], + ['b', 'B'], + ['n', 'N'], + ['m', 'M'], + [',', '<'], + ['.', '>'], + ['/', '?'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] + ]; + + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = US.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } + } else { + '\0' + } + } +} + +pub mod gb { + static GB: [[char; 2]; 87] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['1', '!'], + ['2', '"'], + ['3', '£'], + ['4', '$'], + ['5', '%'], + ['6', '^'], + ['7', '&'], + ['8', '*'], + ['9', '('], + ['0', ')'], + ['-', '_'], + ['=', '+'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['q', 'Q'], + ['w', 'W'], + ['e', 'E'], + ['r', 'R'], + ['t', 'T'], + ['y', 'Y'], + ['u', 'U'], + ['i', 'I'], + ['o', 'O'], + ['p', 'P'], + ['[', '{'], + [']', '}'], + ['\n', '\n'], + ['\0', '\0'], + ['a', 'A'], + ['s', 'S'], + ['d', 'D'], + ['f', 'F'], + ['g', 'G'], + ['h', 'H'], + ['j', 'J'], + ['k', 'K'], + ['l', 'L'], + [';', ':'], + ['\'', '@'], + ['`', '¬'], + ['\0', '\0'], + ['#', '~'], + ['z', 'Z'], + ['x', 'X'], + ['c', 'C'], + ['v', 'V'], + ['b', 'B'], + ['n', 'N'], + ['m', 'M'], + [',', '<'], + ['.', '>'], + ['/', '?'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + ['\\', '|'], + ]; + + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = GB.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } + } else { + '\0' + } + } +} + +pub mod dvorak { + static DVORAK: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['1', '!'], + ['2', '@'], + ['3', '#'], + ['4', '$'], + ['5', '%'], + ['6', '^'], + ['7', '&'], + ['8', '*'], + ['9', '('], + ['0', ')'], + ['[', '{'], + [']', '}'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['\'', '"'], + [',', '<'], + ['.', '>'], + ['p', 'P'], + ['y', 'Y'], + ['f', 'F'], + ['g', 'G'], + ['c', 'C'], + ['r', 'R'], + ['l', 'L'], + ['/', '?'], + ['=', '+'], + ['\n', '\n'], + ['\0', '\0'], + ['a', 'A'], + ['o', 'O'], + ['e', 'E'], + ['u', 'U'], + ['i', 'I'], + ['d', 'D'], + ['h', 'H'], + ['t', 'T'], + ['n', 'N'], + ['s', 'S'], + ['-', '_'], + ['`', '~'], + ['\0', '\0'], + ['\\', '|'], + [';', ':'], + ['q', 'Q'], + ['j', 'J'], + ['k', 'K'], + ['x', 'X'], + ['b', 'B'], + ['m', 'M'], + ['w', 'W'], + ['v', 'V'], + ['z', 'Z'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] + ]; + + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = DVORAK.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } + } else { + '\0' + } + } +} + +pub mod azerty { + static AZERTY: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['&', '1'], + ['é', '2'], + ['"', '3'], + ['\'', '4'], + ['(', '5'], + ['|', '6'], + ['è', '7'], + ['_', '8'], + ['ç', '9'], + ['à', '0'], + [')', '°'], + ['=', '+'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['a', 'A'], + ['z', 'Z'], + ['e', 'E'], + ['r', 'R'], + ['t', 'T'], + ['y', 'Y'], + ['u', 'U'], + ['i', 'I'], + ['o', 'O'], + ['p', 'P'], + ['^', '¨'], + ['$', '£'], + ['\n', '\n'], + ['\0', '\0'], + ['q', 'Q'], + ['s', 'S'], + ['d', 'D'], + ['f', 'F'], + ['g', 'G'], + ['h', 'H'], + ['j', 'J'], + ['k', 'K'], + ['l', 'L'], + ['m', 'M'], + ['ù', '%'], + ['*', 'µ'], + ['\0', '\0'], + ['ê', 'Ê'], + ['w', 'W'], + ['x', 'X'], + ['c', 'C'], + ['v', 'V'], + ['b', 'B'], + ['n', 'N'], + [',', '?'], + [';', '.'], + [':', '/'], + ['!', '§'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] + ]; + + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = AZERTY.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } + } else { + '\0' + } + } +} + +pub mod bepo { + static BEPO: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['"', '1'], + ['«', '2'], + ['»', '3'], + ['(', '4'], + [')', '5'], + ['@', '6'], + ['+', '7'], + ['-', '8'], + ['/', '9'], + ['*', '0'], + ['=', '°'], + ['%', '`'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['b', 'B'], + ['é', 'É'], + ['p', 'P'], + ['o', 'O'], + ['è', 'È'], + ['^', '!'], + ['v', 'V'], + ['d', 'D'], + ['l', 'L'], + ['j', 'J'], + ['z', 'Z'], + ['w', 'W'], + ['\n', '\n'], + ['\0', '\0'], + ['a', 'A'], + ['u', 'U'], + ['i', 'I'], + ['e', 'E'], + [',', ';'], + ['c', 'C'], + ['t', 'T'], + ['s', 'S'], + ['r', 'R'], + ['n', 'N'], + ['m', 'M'], + ['ç', 'Ç'], + ['\0', '\0'], + ['ê', 'Ê'], + ['à', 'À'], + ['y', 'Y'], + ['x', 'X'], + ['.', ':'], + ['k', 'K'], + ['\'', '?'], + ['q', 'Q'], + ['g', 'G'], + ['h', 'H'], + ['f', 'F'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] + ]; + + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = BEPO.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } + } else { + '\0' + } + } +} + +pub mod it { + static IT: [[char; 2]; 58] = [ + ['\0', '\0'], + ['\x1B', '\x1B'], + ['1', '!'], + ['2', '"'], + ['3', '£'], + ['4', '$'], + ['5', '%'], + ['6', '&'], + ['7', '/'], + ['8', '('], + ['9', ')'], + ['0', '='], + ['?', '\''], + ['ì', '^'], + ['\x7F', '\x7F'], + ['\t', '\t'], + ['q', 'Q'], + ['w', 'W'], + ['e', 'E'], + ['r', 'R'], + ['t', 'T'], + ['y', 'Y'], + ['u', 'U'], + ['i', 'I'], + ['o', 'O'], + ['p', 'P'], + ['è', 'é'], + ['+', '*'], + ['\n', '\n'], + ['\x20', '\x20'], + ['a', 'A'], + ['s', 'S'], + ['d', 'D'], + ['f', 'F'], + ['g', 'G'], + ['h', 'H'], + ['j', 'J'], + ['k', 'K'], + ['l', 'L'], + ['ò', 'ç'], + ['à', '°'], + ['ù', '§'], + ['\0', '\0'], + ['<', '>'], + ['z', 'Z'], + ['x', 'X'], + ['c', 'C'], + ['v', 'V'], + ['b', 'B'], + ['n', 'N'], + ['m', 'M'], + [',', ';'], + ['.', ':'], + ['-', '_'], + ['\0', '\0'], + ['\0', '\0'], + ['\0', '\0'], + [' ', ' '] + ]; + + pub fn get_char(scancode: u8, shift: bool) -> char { + if let Some(c) = IT.get(scancode as usize) { + if shift { + c[1] + } else { + c[0] + } + } else { + '\0' + } + } +} diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 7715e5ce02..408ea516db 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -6,6 +6,7 @@ use orbclient::KeyEvent as OrbKeyEvent; use redox_log::{OutputBuilder, RedoxLogger}; use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle}; +mod keymap; mod report_desc; mod reqs; mod usage_tables; @@ -105,6 +106,144 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } } +fn send_key_event(usage_page: u32, usage: u8, pressed: bool, shift_opt: Option) { + let scancode = match usage_page { + 0x07 => match usage { + 0x04 => orbclient::K_A, + 0x05 => orbclient::K_B, + 0x06 => orbclient::K_C, + 0x07 => orbclient::K_D, + 0x08 => orbclient::K_E, + 0x09 => orbclient::K_F, + 0x0A => orbclient::K_G, + 0x0B => orbclient::K_H, + 0x0C => orbclient::K_I, + 0x0D => orbclient::K_J, + 0x0E => orbclient::K_K, + 0x0F => orbclient::K_L, + 0x10 => orbclient::K_M, + 0x11 => orbclient::K_N, + 0x12 => orbclient::K_O, + 0x13 => orbclient::K_P, + 0x14 => orbclient::K_Q, + 0x15 => orbclient::K_R, + 0x16 => orbclient::K_S, + 0x17 => orbclient::K_T, + 0x18 => orbclient::K_U, + 0x19 => orbclient::K_V, + 0x1A => orbclient::K_W, + 0x1B => orbclient::K_X, + 0x1C => orbclient::K_Y, + 0x1D => orbclient::K_Z, + 0x1E => orbclient::K_1, + 0x1F => orbclient::K_2, + 0x20 => orbclient::K_3, + 0x21 => orbclient::K_4, + 0x22 => orbclient::K_5, + 0x23 => orbclient::K_6, + 0x24 => orbclient::K_7, + 0x25 => orbclient::K_8, + 0x26 => orbclient::K_9, + 0x27 => orbclient::K_0, + 0x28 => orbclient::K_ENTER, + 0x29 => orbclient::K_ESC, + 0x2A => orbclient::K_BKSP, + 0x2B => orbclient::K_TAB, + 0x2C => orbclient::K_SPACE, + 0x2D => orbclient::K_MINUS, + 0x2E => orbclient::K_EQUALS, + 0x2F => orbclient::K_BRACE_OPEN, + 0x30 => orbclient::K_BRACE_CLOSE, + 0x31 => orbclient::K_BACKSLASH, + // 0x32 non-us # and ~ + 0x33 => orbclient::K_SEMICOLON, + 0x34 => orbclient::K_QUOTE, + 0x35 => orbclient::K_TICK, + 0x36 => orbclient::K_COMMA, + 0x37 => orbclient::K_PERIOD, + 0x38 => orbclient::K_SLASH, + 0x39 => orbclient::K_CAPS, + 0x3A => orbclient::K_F1, + 0x3B => orbclient::K_F2, + 0x3C => orbclient::K_F3, + 0x3D => orbclient::K_F4, + 0x3E => orbclient::K_F5, + 0x3F => orbclient::K_F6, + 0x40 => orbclient::K_F7, + 0x41 => orbclient::K_F8, + 0x42 => orbclient::K_F9, + 0x43 => orbclient::K_F10, + 0x44 => orbclient::K_F11, + 0x45 => orbclient::K_F12, + // 0x46 print screen + // 0x47 scroll lock + // 0x48 pause + // 0x49 insert + 0x4A => orbclient::K_HOME, + 0x4B => orbclient::K_PGUP, + 0x4C => orbclient::K_DEL, + 0x4D => orbclient::K_END, + 0x4E => orbclient::K_PGDN, + 0x4F => orbclient::K_RIGHT, + 0x50 => orbclient::K_LEFT, + 0x51 => orbclient::K_DOWN, + 0x52 => orbclient::K_UP, + // 0x53 num lock + // 0x54 num / + // 0x55 num * + // 0x56 num - + // 0x57 num + + // 0x58 num enter + 0x59 => orbclient::K_NUM_1, + 0x5A => orbclient::K_NUM_2, + 0x5B => orbclient::K_NUM_3, + 0x5C => orbclient::K_NUM_4, + 0x5D => orbclient::K_NUM_5, + 0x5E => orbclient::K_NUM_6, + 0x5F => orbclient::K_NUM_7, + 0x60 => orbclient::K_NUM_8, + 0x61 => orbclient::K_NUM_9, + 0x62 => orbclient::K_NUM_0, + // 0x62 num . + // 0x64 non-us \ and | + // 0x64 app + // 0x66 power + // 0x67 num = + // unmapped values + 0xE0 => orbclient::K_CTRL, // TODO: left control + 0xE1 => orbclient::K_LEFT_SHIFT, + 0xE2 => orbclient::K_ALT, + // 0xE3 left super + 0xE4 => orbclient::K_CTRL, // TODO: right control + 0xE5 => orbclient::K_RIGHT_SHIFT, + 0xE6 => orbclient::K_ALT_GR, + // 0xE7 right super + // reserved values + _ => { + println!("unknown usage_page {:#x} usage {:#x}", usage_page, usage); + return; + }, + }, + _ => { + println!("unknown usage_page {:#x}", usage_page); + return; + }, + }; + + //TODO: other keymaps + let character = if let Some(shift) = shift_opt { + keymap::us::get_char(scancode, shift) + } else { + '\0' + }; + + println!("{:#x?}", OrbKeyEvent { + character, + scancode, + pressed, + }); +} + fn main() { let _logger_ref = setup_logging(); @@ -199,6 +338,7 @@ fn main() { None => return None, }; if global_state.usage_page != Some(0x7) { + println!("Unsupported usage page: {:#x?}", global_state.usage_page); return None; } let bit_length = report_size * report_count; @@ -249,24 +389,25 @@ fn main() { // The usages are selectors. } - for report_index in 0..report_count { - } - - /*if input.contains(MainItemFlags::VARIABLE) { + if input.contains(MainItemFlags::VARIABLE) { // The item is a variable. let binary_view = BinaryView::new(&report_buffer, bit_offset as usize, bit_length as usize); if report_count == 8 && report_size == 1 && local_state.usage_min == Some(224) && local_state.usage_max == Some(231) && global_state.logical_min == Some(0) && global_state.logical_max == Some(1) { + let bits = binary_view.read_u8(0).expect("Failed to read array item"); + for bit in 0..8 { + if bits & (1 << bit) > 0 { + pressed_keys.push(0xE0 + bit); + } + } + println!("Report variable {:#x?}", bits); } else { println!("unknown report variable item"); } } else { // The item is an array. - std::mem::swap(&mut pressed_keys, &mut last_pressed_keys); - pressed_keys.clear(); - println!("INPUT FLAGS: {:?}", input); assert_eq!(report_size, 8); for report_index in 0..report_count as usize { @@ -275,19 +416,30 @@ fn main() { if usage != 0 { pressed_keys.push(usage); } - println!("Report index array {}: {}", report_index, usage); + println!("Report index array {}: {:#x}", report_index, usage); } - }*/ - } - for (current, last) in pressed_keys.iter().copied().zip(last_pressed_keys.iter().copied()) { - if current == last { continue } - if current != 0 { - // Keycode current changed state to "pressed". - } else { - // Keycode current changed state to "released". } } - println!(); + + + for usage in last_pressed_keys.iter() { + if ! pressed_keys.contains(usage) { + println!("Released {:#x}", usage); + send_key_event(global_state.usage_page.unwrap_or(0), *usage, false, None); + } + } + + for usage in pressed_keys.iter() { + if ! last_pressed_keys.contains(usage) { + println!("Pressed {:#x}", usage); + send_key_event(global_state.usage_page.unwrap_or(0), *usage, true, Some( + pressed_keys.contains(&0xE1) || pressed_keys.contains(&0xE5) + )); + } + } + + std::mem::swap(&mut pressed_keys, &mut last_pressed_keys); + pressed_keys.clear(); } } } From 84a20ca70631f8936b4af6f4e96dc53a4c51a5fe Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 11 Apr 2022 20:32:50 -0600 Subject: [PATCH 0481/1301] Send events to orbital --- usbhidd/src/main.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 408ea516db..77be9f898b 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -1,5 +1,6 @@ use std::env; use std::fs::File; +use std::io::Write; use bitflags::bitflags; use orbclient::KeyEvent as OrbKeyEvent; @@ -106,7 +107,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } } -fn send_key_event(usage_page: u32, usage: u8, pressed: bool, shift_opt: Option) { +fn send_key_event(orbital_socket: &mut File, usage_page: u32, usage: u8, pressed: bool, shift_opt: Option) { let scancode = match usage_page { 0x07 => match usage { 0x04 => orbclient::K_A, @@ -237,11 +238,18 @@ fn send_key_event(usage_page: u32, usage: u8, pressed: bool, shift_opt: Option (), + Err(err) => { + println!("failed to send key event to orbital: {}", err); + } + } } fn main() { @@ -361,7 +369,7 @@ fn main() { let report_ty = ReportTy::Input; let report_id = 0; - //TODO let orbital_socket = File::open("display:input").expect("Failed to open orbital input socket"); + let mut orbital_socket = File::open("display:input").expect("Failed to open orbital input socket"); let mut pressed_keys = Vec::::new(); let mut last_pressed_keys = pressed_keys.clone(); @@ -425,14 +433,14 @@ fn main() { for usage in last_pressed_keys.iter() { if ! pressed_keys.contains(usage) { println!("Released {:#x}", usage); - send_key_event(global_state.usage_page.unwrap_or(0), *usage, false, None); + send_key_event(&mut orbital_socket, global_state.usage_page.unwrap_or(0), *usage, false, None); } } for usage in pressed_keys.iter() { if ! last_pressed_keys.contains(usage) { println!("Pressed {:#x}", usage); - send_key_event(global_state.usage_page.unwrap_or(0), *usage, true, Some( + send_key_event(&mut orbital_socket, global_state.usage_page.unwrap_or(0), *usage, true, Some( pressed_keys.contains(&0xE1) || pressed_keys.contains(&0xE5) )); } From 8db178114681ba6b8127d5f61b8476a1d8fd1c62 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 12 Apr 2022 20:34:56 -0600 Subject: [PATCH 0482/1301] xhcid: use actual BAR size --- xhcid/src/main.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 30c30049f5..e92f068bd0 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -95,6 +95,7 @@ fn main() { info!("XHCI PCI CONFIG: {:?}", pci_config); let bar = pci_config.func.bars[0]; + let bar_size = pci_config.func.bar_sizes[0]; let irq = pci_config.func.legacy_interrupt_line; let mut name = pci_config.func.name(); @@ -109,7 +110,7 @@ fn main() { }; let address = unsafe { - syscall::physmap(bar_ptr as usize, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("xhcid: failed to map address") }; @@ -170,11 +171,12 @@ fn main() { let pba_base = capability.pba_base_pointer(pci_config.func.bars); - if !(bar_ptr..bar_ptr + 65536).contains(&(table_base as u32 + table_min_length as u32)) { - todo!() + if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u32 + table_min_length as u32)) { + panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); } - if !(bar_ptr..bar_ptr + 65536).contains(&(pba_base as u32 + pba_min_length as u32)) { - todo!() + + if !(bar_ptr..bar_ptr + bar_size).contains(&(pba_base as u32 + pba_min_length as u32)) { + panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size); } let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; From a3a76284cb39d294aee5d11a532e7d5b54e11b66 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 13 Apr 2022 09:05:26 -0600 Subject: [PATCH 0483/1301] xhcid: set logging filter to info --- xhcid/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index e92f068bd0..c8b84180f9 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -52,7 +52,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { match OutputBuilder::in_redox_logging_scheme("usb", "host", "xhci.log") { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Trace) + b.with_filter(log::LevelFilter::Info) .flush_on_newline(true) .build() ), @@ -62,7 +62,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("usb", "host", "xhci.ansi.log") { Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Trace) + b.with_filter(log::LevelFilter::Info) .with_ansi_escape_codes() .flush_on_newline(true) .build() From ed5257e23f81be79aa2438c58435974585d50282 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 13 Apr 2022 17:01:43 -0600 Subject: [PATCH 0484/1301] Enable xhcid and make usbhidd more quiet --- initfs.toml | 10 ---------- usbhidd/src/main.rs | 24 +++++++++++------------ xhcid/{config.toml.unused => config.toml} | 3 ++- 3 files changed, 14 insertions(+), 23 deletions(-) rename xhcid/{config.toml.unused => config.toml} (58%) diff --git a/initfs.toml b/initfs.toml index be5c786ceb..fed4f568c0 100644 --- a/initfs.toml +++ b/initfs.toml @@ -14,13 +14,3 @@ class = 1 subclass = 8 command = ["nvmed"] use_channel = true - -# Disabled until issues are fixed -# # xhcid -# [[drivers]] -# name = "XHCI" -# class = 12 -# subclass = 3 -# interface = 48 -# command = ["xhcid"] -# use_channel = true diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 77be9f898b..72edaeed38 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -77,7 +77,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { match OutputBuilder::in_redox_logging_scheme("usb", "device", "hid.log") { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Trace) + b.with_filter(log::LevelFilter::Info) .flush_on_newline(true) .build() ), @@ -87,7 +87,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("usb", "device", "hid.ansi.log") { Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Trace) + b.with_filter(log::LevelFilter::Info) .with_ansi_escape_codes() .flush_on_newline(true) .build() @@ -221,12 +221,12 @@ fn send_key_event(orbital_socket: &mut File, usage_page: u32, usage: u8, pressed // 0xE7 right super // reserved values _ => { - println!("unknown usage_page {:#x} usage {:#x}", usage_page, usage); + log::warn!("unknown usage_page {:#x} usage {:#x}", usage_page, usage); return; }, }, _ => { - println!("unknown usage_page {:#x}", usage_page); + log::warn!("unknown usage_page {:#x}", usage_page); return; }, }; @@ -247,7 +247,7 @@ fn send_key_event(orbital_socket: &mut File, usage_page: u32, usage: u8, pressed match orbital_socket.write(&key_event.to_event()) { Ok(_) => (), Err(err) => { - println!("failed to send key event to orbital: {}", err); + log::warn!("failed to send key event to orbital: {}", err); } } } @@ -346,7 +346,7 @@ fn main() { None => return None, }; if global_state.usage_page != Some(0x7) { - println!("Unsupported usage page: {:#x?}", global_state.usage_page); + log::warn!("Unsupported usage page: {:#x?}", global_state.usage_page); return None; } let bit_length = report_size * report_count; @@ -409,14 +409,14 @@ fn main() { pressed_keys.push(0xE0 + bit); } } - println!("Report variable {:#x?}", bits); + log::trace!("Report variable {:#x?}", bits); } else { - println!("unknown report variable item"); + log::warn!("unknown report variable item"); } } else { // The item is an array. - println!("INPUT FLAGS: {:?}", input); + log::trace!("INPUT FLAGS: {:?}", input); assert_eq!(report_size, 8); for report_index in 0..report_count as usize { let binary_view = BinaryView::new(&report_buffer, bit_offset as usize + report_index * report_size as usize, report_size as usize); @@ -424,7 +424,7 @@ fn main() { if usage != 0 { pressed_keys.push(usage); } - println!("Report index array {}: {:#x}", report_index, usage); + log::trace!("Report index array {}: {:#x}", report_index, usage); } } } @@ -432,14 +432,14 @@ fn main() { for usage in last_pressed_keys.iter() { if ! pressed_keys.contains(usage) { - println!("Released {:#x}", usage); + log::debug!("Released {:#x}", usage); send_key_event(&mut orbital_socket, global_state.usage_page.unwrap_or(0), *usage, false, None); } } for usage in pressed_keys.iter() { if ! last_pressed_keys.contains(usage) { - println!("Pressed {:#x}", usage); + log::debug!("Pressed {:#x}", usage); send_key_event(&mut orbital_socket, global_state.usage_page.unwrap_or(0), *usage, true, Some( pressed_keys.contains(&0xE1) || pressed_keys.contains(&0xE5) )); diff --git a/xhcid/config.toml.unused b/xhcid/config.toml similarity index 58% rename from xhcid/config.toml.unused rename to xhcid/config.toml index 6654d5b598..b80bae57a4 100644 --- a/xhcid/config.toml.unused +++ b/xhcid/config.toml @@ -3,4 +3,5 @@ name = "XHCI" class = 12 subclass = 3 interface = 48 -command = ["xhcid", "$NAME", "$BAR0", "$IRQ"] +command = ["xhcid"] +use_channel = true From b4256fdf006162580ae77ac9bbf7943b664bb2f2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 19 Apr 2022 18:03:52 -0600 Subject: [PATCH 0485/1301] Improve ahcid error format --- ahcid/src/ahci/hba.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 1e7f8031db..be469e948a 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -332,10 +332,20 @@ impl HbaPort { self.stop(); if self.is.read() & HBA_PORT_IS_ERR != 0 { - error!("ERROR IS {:X} IE {:X} CMD {:X} TFD {:X}\nSSTS {:X} SCTL {:X} SERR {:X} SACT {:X}\nCI {:X} SNTF {:X} FBS {:X}", - self.is.read(), self.ie.read(), self.cmd.read(), self.tfd.read(), - self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(), - self.ci.read(), self.sntf.read(), self.fbs.read()); + let ( + is, ie, cmd, tfd, + ssts, sctl, serr, sact, + ci, sntf, fbs + ) = ( + self.is.read(), self.ie.read(), self.cmd.read(), self.tfd.read(), + self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(), + self.ci.read(), self.sntf.read(), self.fbs.read() + ); + + error!("IS {:X} IE {:X} CMD {:X} TFD {:X}", is, ie, cmd, tfd); + error!("SSTS {:X} SCTL {:X} SERR {:X} SACT {:X}", ssts, sctl, serr, sact); + error!("CI {:X} SNTF {:X} FBS {:X}", ci, sntf, fbs); + self.is.write(u32::MAX); Err(Error::new(EIO)) } else { From 59d3260722a4981e333a81d6631da55d14e35d30 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 25 Apr 2022 09:11:24 -0600 Subject: [PATCH 0486/1301] Increase ps2d timeouts --- ps2d/src/controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 866f7ac047..a1fe120d7d 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -103,7 +103,7 @@ impl Ps2 { } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 10_000; + let mut timeout = 100_000; while self.status().contains(StatusFlags::INPUT_FULL) { if timeout <= 0 { return Err(Error::WriteTimeout); @@ -115,7 +115,7 @@ impl Ps2 { } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 10_000; + let mut timeout = 100_000; while ! self.status().contains(StatusFlags::OUTPUT_FULL) { if timeout <= 0 { return Err(Error::ReadTimeout); From 0e9e91ddef97f5867ba165df1a66abc2fc1732d0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 27 Apr 2022 15:07:25 -0600 Subject: [PATCH 0487/1301] Improve ps2d retries, fixes a few PS/2 mice --- ps2d/src/controller.rs | 139 +++++++++++++++++++++++++++++------------ 1 file changed, 99 insertions(+), 40 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index a1fe120d7d..c907f814f8 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -1,9 +1,11 @@ use syscall::io::{Io, Pio, ReadOnly, WriteOnly}; -use std::thread; +use std::{fmt, thread}; #[derive(Debug)] pub enum Error { + CommandRetry, + NoMoreTries, ReadTimeout, WriteTimeout, } @@ -38,6 +40,7 @@ bitflags! { } } +#[derive(Clone, Copy, Debug)] #[repr(u8)] #[allow(dead_code)] enum Command { @@ -54,6 +57,7 @@ enum Command { WriteSecond = 0xD4 } +#[derive(Clone, Copy, Debug)] #[repr(u8)] #[allow(dead_code)] enum KeyboardCommand { @@ -63,11 +67,13 @@ enum KeyboardCommand { Reset = 0xFF } +#[derive(Clone, Copy, Debug)] #[repr(u8)] enum KeyboardCommandData { ScancodeSet = 0xF0 } +#[derive(Clone, Copy, Debug)] #[repr(u8)] #[allow(dead_code)] enum MouseCommand { @@ -78,6 +84,7 @@ enum MouseCommand { Reset = 0xFF } +#[derive(Clone, Copy, Debug)] #[repr(u8)] enum MouseCommandData { SetSampleRate = 0xF3, @@ -159,60 +166,86 @@ impl Ps2 { self.write(config.bits()) } - fn keyboard_command_inner(&mut self, command: u8) -> Result { - let mut ret = 0xFE; - for i in 0..4 { - self.write(command as u8)?; - ret = self.read()?; - if ret == 0xFE { - eprintln!("ps2d: retry keyboard command {:X}: {}", command, i); - } else { - break; + fn retry Result>(&mut self, name: fmt::Arguments, retries: usize, f: F) -> Result { + let mut res = Err(Error::NoMoreTries); + for retry in 0..retries { + res = f(self); + match res { + Ok(ok) => { + return Ok(ok); + }, + Err(ref err) => { + eprintln!("ps2d: {}: retry {}/{}: {:?}", name, retry + 1, retries, err); + } } } - Ok(ret) + res + } + + fn keyboard_command_inner(&mut self, command: u8) -> Result { + self.write(command as u8)?; + match self.read()? { + 0xFE => Err(Error::CommandRetry), + value => Ok(value), + } } fn keyboard_command(&mut self, command: KeyboardCommand) -> Result { - self.keyboard_command_inner(command as u8) + self.retry( + format_args!("{:?}", command), + 4, + |x| x.keyboard_command_inner(command as u8) + ) } fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> Result { - let res = self.keyboard_command_inner(command as u8)?; - if res != 0xFA { - return Ok(res); - } - self.write(data as u8); - self.read() + self.retry( + format_args!("{:?} {:#x}", command, data), + 4, + |x| { + let res = x.keyboard_command_inner(command as u8)?; + if res != 0xFA { + //TODO: error? + return Ok(res); + } + x.write(data); + x.read() + } + ) } fn mouse_command_inner(&mut self, command: u8) -> Result { - let mut ret = 0xFE; - for i in 0..4 { - self.command(Command::WriteSecond)?; - self.write(command as u8)?; - ret = self.read()?; - if ret == 0xFE { - eprintln!("ps2d: retry mouse command {:X}: {}", command, i); - } else { - break; - } + self.command(Command::WriteSecond)?; + self.write(command as u8)?; + match self.read()? { + 0xFE => Err(Error::CommandRetry), + value => Ok(value), } - Ok(ret) } fn mouse_command(&mut self, command: MouseCommand) -> Result { - self.mouse_command_inner(command as u8) + self.retry( + format_args!("{:?}", command), + 4, + |x| x.mouse_command_inner(command as u8) + ) } fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> Result { - let res = self.mouse_command_inner(command as u8)?; - if res != 0xFA { - return Ok(res); - } - self.command(Command::WriteSecond)?; - self.write(data as u8)?; - self.read() + self.retry( + format_args!("{:?} {:#x}", command, data), + 4, + |x| { + let res = x.mouse_command_inner(command as u8)?; + if res != 0xFA { + //TODO: error? + return Ok(res); + } + x.command(Command::WriteSecond)?; + x.write(data as u8)?; + x.read() + } + ) } pub fn next(&mut self) -> Option<(bool, u8)> { @@ -226,11 +259,22 @@ impl Ps2 { } pub fn init_mouse(&mut self) -> Result { - let mut b = 0; + let mut b; // Clear remaining data self.flush_read("init mouse start"); + // Wake up mouse by reading device ID + b = self.mouse_command(MouseCommand::GetDeviceId)?; + if b == 0xFA { + b = self.read()?; + } else { + eprintln!("ps2d: failed to get mouse device id: {:02X}", b); + } + + // Clear remaining data + self.flush_read("mouse device id"); + // Reset mouse and set up scroll b = self.mouse_command(MouseCommand::Reset)?; if b == 0xFA { @@ -247,6 +291,15 @@ impl Ps2 { eprintln!("ps2d: mouse failed to reset: {:02X}", b); } + // Clear remaining data + self.flush_read("mouse reset"); + + // Set defaults + b = self.mouse_command(MouseCommand::SetDefaults)?; + if b != 0xFA { + eprintln!("ps2d: mouse failed to set defaults: {:02X}", b); + } + // Clear remaining data self.flush_read("mouse defaults"); @@ -286,7 +339,7 @@ impl Ps2 { } pub fn init(&mut self) -> Result { - let mut b = 0; + let mut b; // Clear remaining data self.flush_read("init start"); @@ -313,12 +366,15 @@ impl Ps2 { self.command(Command::TestController)?; assert_eq!(self.read()?, 0x55); + // Clear remaining data + self.flush_read("test controller"); + // Enable devices self.command(Command::EnableFirst)?; self.command(Command::EnableSecond)?; // Clear remaining data - self.flush_read("enable"); + self.flush_read("init keyboard start"); // Reset keyboard b = self.keyboard_command(KeyboardCommand::Reset)?; @@ -347,6 +403,9 @@ impl Ps2 { eprintln!("ps2d: keyboard failed to enable reporting: {:02X}", b); } + // Clear remaining data + self.flush_read("init keyboard finish"); + let (mouse_found, mouse_extra) = match self.init_mouse() { Ok(ok) => (true, ok), Err(err) => { From 64f40c584b2364912da656ccf9546b64400ea591 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 27 Apr 2022 15:12:52 -0600 Subject: [PATCH 0488/1301] Fix ps2d daemon name in log messages --- ps2d/src/controller.rs | 2 +- ps2d/src/main.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index c907f814f8..fdfcb2495d 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -409,7 +409,7 @@ impl Ps2 { let (mouse_found, mouse_extra) = match self.init_mouse() { Ok(ok) => (true, ok), Err(err) => { - eprintln!("p2sd: failed to initialize mouse: {:?}", err); + eprintln!("ps2d: failed to initialize mouse: {:?}", err); (false, false) } }; diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 934efb5631..880a531f09 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -41,12 +41,12 @@ fn daemon(daemon: syscall::Daemon) -> core::convert::Infallible { None => (keymap::us::get_char, "us"), }; - eprintln!("p2sd: using keymap '{}'", keymap_name); + eprintln!("ps2d: using keymap '{}'", keymap_name); let input = OpenOptions::new() .write(true) .open("display:input") - .expect("p2sd: failed to open display:input"); + .expect("ps2d: failed to open display:input"); let mut event_file = OpenOptions::new() .read(true) @@ -84,7 +84,7 @@ fn daemon(daemon: syscall::Daemon) -> core::convert::Infallible { let mut ps2d = Ps2d::new(input, keymap); - daemon.ready().expect("p2sd: failed to mark daemon as ready"); + daemon.ready().expect("ps2d: failed to mark daemon as ready"); let mut data = [0; 256]; loop { @@ -124,5 +124,5 @@ fn daemon(daemon: syscall::Daemon) -> core::convert::Infallible { } fn main() { - syscall::Daemon::new(daemon).expect("p2sd: failed to create daemon"); + syscall::Daemon::new(daemon).expect("ps2d: failed to create daemon"); } From 2ad84308bf54fdd9bf23e33770927699c74c96bf Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 27 Apr 2022 20:38:41 -0600 Subject: [PATCH 0489/1301] Daemonize ps2d before doing ps2 init --- ps2d/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 880a531f09..947bce2cd1 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -82,10 +82,10 @@ fn daemon(daemon: syscall::Daemon) -> core::convert::Infallible { syscall::setrens(0, 0).expect("ps2d: failed to enter null namespace"); - let mut ps2d = Ps2d::new(input, keymap); - daemon.ready().expect("ps2d: failed to mark daemon as ready"); + let mut ps2d = Ps2d::new(input, keymap); + let mut data = [0; 256]; loop { // There are some gotchas with ps/2 controllers that require this weird From 568203d91bad890d6574ca4b83ad14eba1b014b5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 27 Apr 2022 21:50:32 -0600 Subject: [PATCH 0490/1301] Make ps2d compatible with more laptops --- ps2d/src/controller.rs | 267 ++++++++++++++++++++++++----------------- 1 file changed, 159 insertions(+), 108 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index fdfcb2495d..7eae9e85d3 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -1,6 +1,6 @@ use syscall::io::{Io, Pio, ReadOnly, WriteOnly}; -use std::{fmt, thread}; +use std::{fmt, thread, time}; #[derive(Debug)] pub enum Error { @@ -93,7 +93,7 @@ enum MouseCommandData { pub struct Ps2 { data: Pio, status: ReadOnly>, - command: WriteOnly> + command: WriteOnly>, } impl Ps2 { @@ -110,25 +110,25 @@ impl Ps2 { } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 100_000; + let mut timeout = 100; while self.status().contains(StatusFlags::INPUT_FULL) { if timeout <= 0 { return Err(Error::WriteTimeout); } timeout -= 1; - thread::yield_now(); + thread::sleep(time::Duration::from_millis(1)); } Ok(()) } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 100_000; + let mut timeout = 100; while ! self.status().contains(StatusFlags::OUTPUT_FULL) { if timeout <= 0 { return Err(Error::ReadTimeout); } timeout -= 1; - thread::yield_now(); + thread::sleep(time::Duration::from_millis(1)); } Ok(()) } @@ -167,6 +167,7 @@ impl Ps2 { } fn retry Result>(&mut self, name: fmt::Arguments, retries: usize, f: F) -> Result { + eprintln!("ps2d: {}", name); let mut res = Err(Error::NoMoreTries); for retry in 0..retries { res = f(self); @@ -192,7 +193,7 @@ impl Ps2 { fn keyboard_command(&mut self, command: KeyboardCommand) -> Result { self.retry( - format_args!("{:?}", command), + format_args!("keyboard command {:?}", command), 4, |x| x.keyboard_command_inner(command as u8) ) @@ -200,7 +201,7 @@ impl Ps2 { fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> Result { self.retry( - format_args!("{:?} {:#x}", command, data), + format_args!("keyboard command {:?} {:#x}", command, data), 4, |x| { let res = x.keyboard_command_inner(command as u8)?; @@ -225,7 +226,7 @@ impl Ps2 { fn mouse_command(&mut self, command: MouseCommand) -> Result { self.retry( - format_args!("{:?}", command), + format_args!("mouse command {:?}", command), 4, |x| x.mouse_command_inner(command as u8) ) @@ -233,7 +234,7 @@ impl Ps2 { fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> Result { self.retry( - format_args!("{:?} {:#x}", command, data), + format_args!("mouse command {:?} {:#x}", command, data), 4, |x| { let res = x.mouse_command_inner(command as u8)?; @@ -258,57 +259,111 @@ impl Ps2 { } } + pub fn init_keyboard(&mut self) -> Result<(), Error> { + let mut b; + + { + // Enable first device + self.command(Command::EnableFirst)?; + + // Clear remaining data + self.flush_read("enable first"); + } + + { + // Reset keyboard + b = self.keyboard_command(KeyboardCommand::Reset)?; + if b == 0xFA { + b = self.read()?; + if b != 0xAA { + eprintln!("ps2d: keyboard failed self test: {:02X}", b); + } + } else { + eprintln!("ps2d: keyboard failed to reset: {:02X}", b); + } + + // Clear remaining data + self.flush_read("keyboard defaults"); + } + + { + // Set scancode set to 2 + let scancode_set = 2; + b = self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set)?; + if b != 0xFA { + eprintln!("ps2d: keyboard failed to set scancode set {}: {:02X}", scancode_set, b); + } + + // Clear remaining data + self.flush_read("keyboard scancode"); + } + + Ok(()) + } + pub fn init_mouse(&mut self) -> Result { let mut b; - // Clear remaining data - self.flush_read("init mouse start"); + { + // Enable second device + self.command(Command::EnableSecond)?; - // Wake up mouse by reading device ID - b = self.mouse_command(MouseCommand::GetDeviceId)?; - if b == 0xFA { - b = self.read()?; - } else { - eprintln!("ps2d: failed to get mouse device id: {:02X}", b); + // Clear remaining data + self.flush_read("enable second"); } - // Clear remaining data - self.flush_read("mouse device id"); + self.retry( + format_args!("mouse reset"), + 4, + |x| { + // Reset mouse + let mut b = x.mouse_command(MouseCommand::Reset)?; + if b == 0xFA { + b = x.read()?; + if b != 0xAA { + eprintln!("ps2d: mouse failed self test 1: {:02X}", b); + return Err(Error::CommandRetry); + } - // Reset mouse and set up scroll - b = self.mouse_command(MouseCommand::Reset)?; - if b == 0xFA { - b = self.read()?; - if b != 0xAA { - eprintln!("ps2d: mouse failed self test 1: {:02X}", b); + b = x.read()?; + if b != 0x00 { + eprintln!("ps2d: mouse failed self test 2: {:02X}", b); + return Err(Error::CommandRetry); + } + } else { + eprintln!("ps2d: mouse failed to reset: {:02X}", b); + return Err(Error::CommandRetry); + } + + // Clear remaining data + x.flush_read("mouse reset"); + + Ok(b) + } + )?; + + { + // Set defaults + b = self.mouse_command(MouseCommand::SetDefaults)?; + if b != 0xFA { + eprintln!("ps2d: mouse failed to set defaults: {:02X}", b); } - b = self.read()?; - if b != 0x00 { - eprintln!("ps2d: mouse failed self test 2: {:02X}", b); + // Clear remaining data + self.flush_read("mouse defaults"); + } + + { + // Enable extra packet on mouse + //TODO: show error return values + if self.mouse_command_data(MouseCommandData::SetSampleRate, 200)? != 0xFA + || self.mouse_command_data(MouseCommandData::SetSampleRate, 100)? != 0xFA + || self.mouse_command_data(MouseCommandData::SetSampleRate, 80)? != 0xFA { + eprintln!("ps2d: mouse failed to enable extra packet"); } - } else { - eprintln!("ps2d: mouse failed to reset: {:02X}", b); - } - // Clear remaining data - self.flush_read("mouse reset"); - - // Set defaults - b = self.mouse_command(MouseCommand::SetDefaults)?; - if b != 0xFA { - eprintln!("ps2d: mouse failed to set defaults: {:02X}", b); - } - - // Clear remaining data - self.flush_read("mouse defaults"); - - // Enable extra packet on mouse - //TODO: show error return values - if self.mouse_command_data(MouseCommandData::SetSampleRate, 200)? != 0xFA - || self.mouse_command_data(MouseCommandData::SetSampleRate, 100)? != 0xFA - || self.mouse_command_data(MouseCommandData::SetSampleRate, 80)? != 0xFA { - eprintln!("ps2d: mouse failed to enable extra packet"); + // Clear remaining data + self.flush_read("enable extra mouse packet"); } b = self.mouse_command(MouseCommand::GetDeviceId)?; @@ -319,22 +374,18 @@ impl Ps2 { false }; - // Set sample rate to maximum - let sample_rate = 200; - b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate)?; - if b != 0xFA { - eprintln!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b); - } + { + // Set sample rate to maximum + let sample_rate = 200; + b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate)?; + if b != 0xFA { + eprintln!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b); + } - // Enable data reporting - b = self.mouse_command(MouseCommand::EnableReporting)?; - if b != 0xFA { - eprintln!("ps2d: mouse failed to enable reporting: {:02X}", b); + // Clear remaining data + self.flush_read("set sample rate"); } - // Clear remaining data - self.flush_read("init mouse finish"); - Ok(mouse_extra) } @@ -344,68 +395,44 @@ impl Ps2 { // Clear remaining data self.flush_read("init start"); - // Disable devices - self.command(Command::DisableFirst)?; - self.command(Command::DisableSecond)?; + { + // Disable devices + self.command(Command::DisableFirst)?; + self.command(Command::DisableSecond)?; - // Clear remaining data - self.flush_read("disable"); + // Clear remaining data + self.flush_read("disable"); + } // Disable clocks, disable interrupts, and disable translate { let mut config = self.config()?; + eprintln!("ps2d: config get {:?}", config); config.insert(ConfigFlags::FIRST_DISABLED); config.insert(ConfigFlags::SECOND_DISABLED); config.remove(ConfigFlags::FIRST_TRANSLATE); config.remove(ConfigFlags::FIRST_INTERRUPT); config.remove(ConfigFlags::SECOND_INTERRUPT); + eprintln!("ps2d: config set {:?}", config); self.set_config(config)?; + + // Clear remaining data + self.flush_read("disable interrupts"); } - // Perform the self test - self.command(Command::TestController)?; - assert_eq!(self.read()?, 0x55); + { + // Perform the self test + self.command(Command::TestController)?; + assert_eq!(self.read()?, 0x55); - // Clear remaining data - self.flush_read("test controller"); - - // Enable devices - self.command(Command::EnableFirst)?; - self.command(Command::EnableSecond)?; - - // Clear remaining data - self.flush_read("init keyboard start"); - - // Reset keyboard - b = self.keyboard_command(KeyboardCommand::Reset)?; - if b == 0xFA { - b = self.read()?; - if b != 0xAA { - eprintln!("ps2d: keyboard failed self test: {:02X}", b); - } - } else { - eprintln!("ps2d: keyboard failed to reset: {:02X}", b); + // Clear remaining data + self.flush_read("test controller"); } - // Clear remaining data - self.flush_read("keyboard defaults"); - - // Set scancode set to 2 - let scancode_set = 2; - b = self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set)?; - if b != 0xFA { - eprintln!("ps2d: keyboard failed to set scancode set {}: {:02X}", scancode_set, b); - } - - // Enable data reporting - b = self.keyboard_command(KeyboardCommand::EnableReporting)?; - if b != 0xFA { - eprintln!("ps2d: keyboard failed to enable reporting: {:02X}", b); - } - - // Clear remaining data - self.flush_read("init keyboard finish"); + // Initialize keyboard + self.init_keyboard()?; + // Initialize mouse let (mouse_found, mouse_extra) = match self.init_mouse() { Ok(ok) => (true, ok), Err(err) => { @@ -414,9 +441,32 @@ impl Ps2 { } }; + { + // Enable keyboard data reporting + b = self.keyboard_command(KeyboardCommand::EnableReporting)?; + if b != 0xFA { + eprintln!("ps2d: keyboard failed to enable reporting: {:02X}", b); + } + + // Clear remaining data + self.flush_read("keyboard enable reporting"); + } + + if mouse_found { + // Enable mouse data reporting + b = self.mouse_command(MouseCommand::EnableReporting)?; + if b != 0xFA { + eprintln!("ps2d: mouse failed to enable reporting: {:02X}", b); + } + + // Clear remaining data + self.flush_read("mouse enable reporting"); + } + // Enable clocks and interrupts { let mut config = self.config()?; + eprintln!("ps2d: config get {:?}", config); config.remove(ConfigFlags::FIRST_DISABLED); config.insert(ConfigFlags::FIRST_TRANSLATE); config.insert(ConfigFlags::FIRST_INTERRUPT); @@ -427,6 +477,7 @@ impl Ps2 { config.insert(ConfigFlags::SECOND_DISABLED); config.remove(ConfigFlags::SECOND_INTERRUPT); } + eprintln!("ps2d: config set {:?}", config); self.set_config(config)?; } From 465aaa6d3488b234da52eee3ca6a756ab964bea4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 28 Apr 2022 08:20:20 -0600 Subject: [PATCH 0491/1301] Make config and set_config retry, switch timeouts to spin loops --- ps2d/src/controller.rs | 42 +++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 7eae9e85d3..de4e6180bc 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -1,6 +1,6 @@ use syscall::io::{Io, Pio, ReadOnly, WriteOnly}; -use std::{fmt, thread, time}; +use std::fmt; #[derive(Debug)] pub enum Error { @@ -110,25 +110,23 @@ impl Ps2 { } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 100; + let mut timeout = 100_000; while self.status().contains(StatusFlags::INPUT_FULL) { if timeout <= 0 { return Err(Error::WriteTimeout); } timeout -= 1; - thread::sleep(time::Duration::from_millis(1)); } Ok(()) } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 100; + let mut timeout = 100_000; while ! self.status().contains(StatusFlags::OUTPUT_FULL) { if timeout <= 0 { return Err(Error::ReadTimeout); } timeout -= 1; - thread::sleep(time::Duration::from_millis(1)); } Ok(()) } @@ -156,16 +154,6 @@ impl Ps2 { Ok(()) } - fn config(&mut self) -> Result { - self.command(Command::ReadConfig)?; - self.read().map(ConfigFlags::from_bits_truncate) - } - - fn set_config(&mut self, config: ConfigFlags) -> Result<(), Error> { - self.command(Command::WriteConfig)?; - self.write(config.bits()) - } - fn retry Result>(&mut self, name: fmt::Arguments, retries: usize, f: F) -> Result { eprintln!("ps2d: {}", name); let mut res = Err(Error::NoMoreTries); @@ -183,6 +171,30 @@ impl Ps2 { res } + fn config(&mut self) -> Result { + self.retry( + format_args!("read config"), + 4, + |x| { + x.command(Command::ReadConfig)?; + x.read() + } + ).map(ConfigFlags::from_bits_truncate) + } + + fn set_config(&mut self, config: ConfigFlags) -> Result<(), Error> { + self.retry( + format_args!("write config"), + 4, + |x| { + x.command(Command::WriteConfig)?; + x.write(config.bits())?; + Ok(0) + } + )?; + Ok(()) + } + fn keyboard_command_inner(&mut self, command: u8) -> Result { self.write(command as u8)?; match self.read()? { From aedeb00e5859c940434184254d06b2d32fd66cb0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 2 May 2022 13:37:16 -0600 Subject: [PATCH 0492/1301] ps2d: Fix issue with VirtualBox controller init --- ps2d/src/controller.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index de4e6180bc..b6bd05cf28 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -418,13 +418,11 @@ impl Ps2 { // Disable clocks, disable interrupts, and disable translate { - let mut config = self.config()?; - eprintln!("ps2d: config get {:?}", config); - config.insert(ConfigFlags::FIRST_DISABLED); - config.insert(ConfigFlags::SECOND_DISABLED); - config.remove(ConfigFlags::FIRST_TRANSLATE); - config.remove(ConfigFlags::FIRST_INTERRUPT); - config.remove(ConfigFlags::SECOND_INTERRUPT); + // Since the default config may have interrupts enabled, and the kernel may eat up + // our data in that case, we will write a config without reading the current one + let mut config = ConfigFlags::POST_PASSED | + ConfigFlags::FIRST_DISABLED | + ConfigFlags::SECOND_DISABLED; eprintln!("ps2d: config set {:?}", config); self.set_config(config)?; From fd45fa28184aaa66d72eab4fa5f6c9879a7669a0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 26 Jul 2022 15:21:04 -0600 Subject: [PATCH 0493/1301] Update Cargo.lock --- Cargo.lock | 198 ++++++++++++++++++++++++++++------------------------- 1 file changed, 104 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2477590f78..986e168dba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,9 +135,9 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "bumpalo" -version = "3.9.1" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" [[package]] name = "byteorder" @@ -246,12 +246,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.8", + "crossbeam-utils 0.8.11", ] [[package]] @@ -267,12 +267,12 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.8" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" dependencies = [ "cfg-if 1.0.0", - "lazy_static", + "once_cell", ] [[package]] @@ -479,9 +479,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" [[package]] name = "ixgbed" @@ -495,9 +495,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.56" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" dependencies = [ "wasm-bindgen", ] @@ -526,30 +526,31 @@ checksum = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" [[package]] name = "libc" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "linked-hash-map" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "lock_api" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" dependencies = [ + "autocfg 1.1.0", "scopeguard", ] [[package]] name = "log" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if 1.0.0", ] @@ -568,9 +569,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "mio" @@ -615,7 +616,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#c5d6d20900fd4da9cbf1f3ec04bd752c3d5d3e04" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#55c55eb6452ee886dfd81f1cbb7f9ec45012d95e" dependencies = [ "arg_parser", "extra", @@ -659,9 +660,9 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg 1.1.0", "num-traits", @@ -669,9 +670,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg 1.1.0", ] @@ -696,9 +697,15 @@ dependencies = [ "pcid", "redox-log", "redox_syscall", - "smallvec 1.8.0", + "smallvec 1.9.0", ] +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + [[package]] name = "orbclient" version = "0.3.32" @@ -765,7 +772,7 @@ dependencies = [ "instant", "libc", "redox_syscall", - "smallvec 1.8.0", + "smallvec 1.9.0", "winapi 0.3.9", ] @@ -812,7 +819,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff5751d87f7c00ae6403eb1fcbba229b9c76c9a30de8c1cf87182177b168cea2" dependencies = [ - "crossbeam-channel 0.5.4", + "crossbeam-channel 0.5.6", "libc", "time", "winapi 0.3.9", @@ -833,7 +840,7 @@ dependencies = [ "redox_syscall", "serde", "serde_json", - "smallvec 1.8.0", + "smallvec 1.9.0", "structopt", "thiserror", "toml", @@ -854,9 +861,9 @@ checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" [[package]] name = "pin-utils" @@ -896,11 +903,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -914,9 +921,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.16" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] @@ -1057,14 +1064,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76" dependencies = [ "libc", - "raw-window-handle 0.4.2", + "raw-window-handle 0.4.3", ] [[package]] name = "raw-window-handle" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba75eee94a9d5273a68c9e1e105d9cffe1ef700532325788389e5a83e2522b7" +checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" dependencies = [ "cty", ] @@ -1086,7 +1093,7 @@ checksum = "cbf6d33a003a5c0b94ec11f10c7c797303f236592964ddb1bfb93e1b438a1557" dependencies = [ "chrono", "log", - "smallvec 1.8.0", + "smallvec 1.9.0", "termion", ] @@ -1100,9 +1107,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae183fc1b06c149f0c1793e1eb447c8b04bfe46d48e9e48bfb8d2d7ed64ecf0" +checksum = "534cfe58d6a18cc17120fbf4635d53d14691c1fe4d951064df9bd326178d7d5a" dependencies = [ "bitflags", ] @@ -1139,9 +1146,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" [[package]] name = "scopeguard" @@ -1178,7 +1185,7 @@ dependencies = [ "bitflags", "lazy_static", "libc", - "raw-window-handle 0.4.2", + "raw-window-handle 0.4.3", "sdl2-sys", ] @@ -1196,18 +1203,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.136" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" dependencies = [ "proc-macro2", "quote", @@ -1216,9 +1223,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" dependencies = [ "itoa", "ryu", @@ -1227,9 +1234,12 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg 1.1.0", +] [[package]] name = "smallvec" @@ -1242,18 +1252,18 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" dependencies = [ "serde", ] [[package]] name = "spin" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" dependencies = [ "lock_api", ] @@ -1315,13 +1325,13 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.89" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -1347,18 +1357,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -1378,9 +1388,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -1393,24 +1403,30 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ "serde", ] [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" dependencies = [ "tinyvec", ] @@ -1427,12 +1443,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - [[package]] name = "url" version = "1.7.2" @@ -1550,9 +1560,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.79" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -1560,13 +1570,13 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.79" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", "syn", @@ -1575,9 +1585,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.79" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1585,9 +1595,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.79" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" dependencies = [ "proc-macro2", "quote", @@ -1598,15 +1608,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.79" +version = "0.2.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" +checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" [[package]] name = "web-sys" -version = "0.3.56" +version = "0.3.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" dependencies = [ "js-sys", "wasm-bindgen", @@ -1673,7 +1683,7 @@ dependencies = [ "redox_syscall", "serde", "serde_json", - "smallvec 1.8.0", + "smallvec 1.9.0", "thiserror", "toml", ] From 860821c1504f6d4cd39d45ab40e055daf6f6c276 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 26 Jul 2022 16:01:54 -0600 Subject: [PATCH 0494/1301] Support compilation on more architectures --- Cargo.lock | 4 ++-- acpid/Cargo.toml | 2 +- acpid/src/acpi.rs | 6 ++++++ ahcid/src/ahci/hba.rs | 4 ++-- nvmed/src/main.rs | 10 ++++++++++ nvmed/src/nvme/mod.rs | 16 ++++++++++++++-- nvmed/src/nvme/queues.rs | 2 +- ps2d/src/vm.rs | 10 +++++++++- vesad/src/display.rs | 30 ++++++++++++++++++++--------- vesad/src/main.rs | 6 ++---- vesad/src/primitive.rs | 38 ------------------------------------- vesad/src/screen/graphic.rs | 15 +++++++++++---- 12 files changed, 79 insertions(+), 64 deletions(-) delete mode 100644 vesad/src/primitive.rs diff --git a/Cargo.lock b/Cargo.lock index 986e168dba..0f5f5d06ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1107,9 +1107,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534cfe58d6a18cc17120fbf4635d53d14691c1fe4d951064df9bd326178d7d5a" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index ecd8ad11b4..06fc3c698f 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -13,5 +13,5 @@ num-traits = "0.2" parking_lot = "0.11.1" plain = "0.2.3" redox-log = "0.1.1" -redox_syscall = "0.2.12" +redox_syscall = "0.2.16" thiserror = "1" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 697d5d445f..1fc4260578 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -14,6 +14,12 @@ use super::aml::AmlValue; pub mod dmar; use self::dmar::Dmar; +#[cfg(target_arch = "aarch64")] +pub const PAGE_SIZE: usize = 4096; + +#[cfg(target_arch = "x86")] +pub const PAGE_SIZE: usize = 4096; + #[cfg(target_arch = "x86_64")] pub const PAGE_SIZE: usize = 4096; diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index be469e948a..b798878772 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -112,9 +112,9 @@ impl HbaPort { } self.clb[0].write(clb.physical() as u32); - self.clb[1].write((clb.physical() >> 32) as u32); + self.clb[1].write(((clb.physical() as u64) >> 32) as u32); self.fb[0].write(fb.physical() as u32); - self.fb[1].write((fb.physical() >> 32) as u32); + self.fb[1].write(((fb.physical() as u64) >> 32) as u32); let is = self.is.read(); self.is.write(is); self.ie.write(0 /*TODO: Enable interrupts: 0b10111*/); diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 6393be65e1..34e1e35141 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -51,6 +51,7 @@ pub struct AllocatedBars(pub [Mutex>; 6]); /// Get the most optimal yet functional interrupt mechanism: either (in the order of preference): /// MSI-X, MSI, and INTx# pin. Returns both runtime interrupt structures (MSI/MSI-X capability /// structures), and the handles to the interrupts. +#[cfg(target_arch = "x86_64")] fn get_int_method( pcid_handle: &mut PcidServerHandle, function: &PciFunction, @@ -214,6 +215,15 @@ fn get_int_method( } } +#[cfg(not(target_arch = "x86_64"))] +fn get_int_method( + pcid_handle: &mut PcidServerHandle, + function: &PciFunction, + allocated_bars: &AllocatedBars, +) -> Result<(InterruptMethod, InterruptSources)> { + todo!("handling of interrupts on non-x86_64") +} + fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 9934f8a357..723c65593b 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -22,6 +22,18 @@ pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue}; use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; use pcid_interface::PcidServerHandle; +#[cfg(target_arch = "aarch64")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::x86::__yield(); } + +#[cfg(target_arch = "x86")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::x86::_mm_pause(); } + +#[cfg(target_arch = "x86_64")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::x86_64::_mm_pause(); } + /// Used in conjunction with `InterruptMethod`, primarily by the CQ reactor. #[derive(Debug)] pub enum InterruptSources { @@ -264,7 +276,7 @@ impl Nvme { let csts = self.regs.get_mut().unwrap().csts.read(); log::trace!("CSTS: {:X}", csts); if csts & 1 == 1 { - std::arch::x86_64::_mm_pause(); + pause(); } else { break; } @@ -318,7 +330,7 @@ impl Nvme { let csts = self.regs.get_mut().unwrap().csts.read(); log::debug!("CSTS: {:X}", csts); if csts & 1 == 0 { - std::arch::x86_64::_mm_pause(); + pause(); } else { break; } diff --git a/nvmed/src/nvme/queues.rs b/nvmed/src/nvme/queues.rs index 19783095a6..dfd0e6871f 100644 --- a/nvmed/src/nvme/queues.rs +++ b/nvmed/src/nvme/queues.rs @@ -82,7 +82,7 @@ impl NvmeCompQueue { if let Some(some) = self.complete() { return some; } else { - unsafe { std::arch::x86_64::_mm_pause() } + unsafe { super::pause(); } } } } diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index 97a014e7d5..c04185b480 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -26,6 +26,7 @@ pub const LEFT_BUTTON: u32 = 0x20; pub const RIGHT_BUTTON: u32 = 0x10; pub const MIDDLE_BUTTON: u32 = 0x08; +#[cfg(target_arch = "x86_64")] global_asm!(" .globl cmd_inner cmd_inner: @@ -54,7 +55,7 @@ cmd_inner: PORT = const PORT, ); -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[cfg(target_arch = "x86_64")] pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32, u32, u32) { extern "sysv64" { fn cmd_inner(array_ptr: *mut u32, cmd: u32, arg: u32); @@ -68,6 +69,13 @@ pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32, u32, u32) { (a, b, c, d, e, f) } +//TODO: is it possible to enable this on non-x86_64? +#[cfg(not(target_arch = "x86_64"))] +pub unsafe fn cmd(_cmd: u32, _arg: u32) -> (u32, u32, u32, u32, u32, u32) { + (0, 0, 0, 0, 0, 0) +} + +#[cfg(target_arch = "x86_64")] pub fn enable(relative: bool) -> bool { eprintln!("ps2d: Enable vmmouse"); diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 8048b04c3f..c07e6bcf90 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -2,11 +2,9 @@ extern crate rusttype; use std::alloc::{Allocator, Global, Layout}; -use std::{cmp, slice}; +use std::{cmp, ptr, slice}; use std::ptr::NonNull; -use crate::primitive::{fast_set32, fast_copy}; - #[cfg(feature="rusttype")] use self::rusttype::{Font, FontCollection, Scale, point}; @@ -96,9 +94,17 @@ impl Display { for _y in 0..cmp::min(height, self.height) { unsafe { - fast_copy(new_ptr as *mut u8, old_ptr as *const u8, cmp::min(width, self.width) * 4); + ptr::copy( + old_ptr as *const u8, + new_ptr as *mut u8, + cmp::min(width, self.width) * 4 + ); if width > self.width { - fast_set32(new_ptr.offset(self.width as isize), 0, width - self.width); + ptr::write_bytes( + new_ptr.offset(self.width as isize), + 0, + width - self.width + ); } old_ptr = old_ptr.offset(self.width as isize); new_ptr = new_ptr.offset(width as isize); @@ -108,7 +114,7 @@ impl Display { if height > self.height { for _y in self.height..height { unsafe { - fast_set32(new_ptr, 0, width); + ptr::write_bytes(new_ptr, 0, width); new_ptr = new_ptr.offset(width as isize); } } @@ -145,8 +151,10 @@ impl Display { let mut rows = end_y - start_y; while rows > 0 { - unsafe { - fast_set32(offscreen_ptr as *mut u32, color, len); + for i in 0..len { + unsafe { + *(offscreen_ptr as *mut u32).add(i) = color; + } } offscreen_ptr += stride; rows -= 1; @@ -279,7 +287,11 @@ impl Display { let mut rows = end_y - start_y; while rows > 0 { unsafe { - fast_copy(onscreen_ptr as *mut u8, offscreen_ptr as *const u8, len); + ptr::copy( + offscreen_ptr as *const u8, + onscreen_ptr as *mut u8, + len + ); } offscreen_ptr += stride; onscreen_ptr += stride; diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 4df6644003..ed1bdc0965 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -3,17 +3,15 @@ extern crate orbclient; extern crate syscall; -use std::{env, process}; +use std::{env, process, ptr}; use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::{RawFd, FromRawFd}; use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE}; -use crate::primitive::fast_set64; use crate::scheme::{DisplayScheme, HandleKind}; pub mod display; -pub mod primitive; pub mod scheme; pub mod screen; @@ -74,7 +72,7 @@ fn main() { //TODO: Remap on resize let largest_size = 8 * 1024 * 1024; let onscreen = unsafe { physmap(physbaseptr, largest_size * 4, PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; - unsafe { fast_set64(onscreen as *mut u64, 0, size/2) }; + unsafe { ptr::write_bytes(onscreen as *mut u32, 0, size); } let mut scheme = DisplayScheme::new(width, height, onscreen, &spec); diff --git a/vesad/src/primitive.rs b/vesad/src/primitive.rs deleted file mode 100644 index 3879c4f99b..0000000000 --- a/vesad/src/primitive.rs +++ /dev/null @@ -1,38 +0,0 @@ -use core::arch::asm; - -#[cfg(target_arch = "x86_64")] -#[inline(always)] -pub unsafe fn fast_copy(dst: *mut u8, src: *const u8, len: usize) { - // direction flag must always be cleared, as per the System V ABI - asm!("rep movsb", - inout("rdi") dst as usize => _, inout("rsi") src as usize => _, inout("rcx") len => _, - options(nostack, preserves_flags), - ); -} - -#[cfg(target_arch = "x86_64")] -#[inline(always)] -pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) { - asm!("rep movsq", - inout("rdi") dst as usize => _, inout("rsi") src as usize => _, inout("rcx") len => _, - options(nostack, preserves_flags), - ); -} - -#[cfg(target_arch = "x86_64")] -#[inline(always)] -pub unsafe fn fast_set32(dst: *mut u32, src: u32, len: usize) { - asm!("rep stosd", - inout("rdi") dst as usize => _, in("eax") src, inout("rcx") len => _, - options(nostack, preserves_flags), - ); -} - -#[cfg(target_arch = "x86_64")] -#[inline(always)] -pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) { - asm!("rep stosq", - inout("rdi") dst as usize => _, in("rax") src, inout("rcx") len => _, - options(nostack, preserves_flags), - ); -} diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 1f5ac5ea3f..1dd5df6533 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -1,12 +1,11 @@ use std::collections::VecDeque; -use std::{cmp, mem, slice}; +use std::{cmp, mem, ptr, slice}; use orbclient::{Event, ResizeEvent}; use syscall::error::*; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use crate::display::Display; -use crate::primitive::fast_copy; use crate::screen::Screen; pub struct GraphicScreen { @@ -81,9 +80,17 @@ impl Screen for GraphicScreen { if size > 0 { unsafe { - fast_copy(self.display.offscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4); + ptr::copy( + buf.as_ptr(), + self.display.offscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, + size * 4 + ); if sync { - fast_copy(self.display.onscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4); + ptr::copy( + buf.as_ptr(), + self.display.onscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, + size * 4 + ); } } } From da8ecef8a7d2bc061f1d9ea9c450a75621317eb1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 26 Jul 2022 16:11:45 -0600 Subject: [PATCH 0495/1301] Workarounds for aarch64 support --- acpid/src/aml/mod.rs | 13 +++++++++++-- nvmed/src/main.rs | 2 ++ nvmed/src/nvme/mod.rs | 2 +- pcid/src/pci/mod.rs | 20 ++++++++++++++++++++ 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/acpid/src/aml/mod.rs b/acpid/src/aml/mod.rs index 91d90be619..39f4c1c9e6 100644 --- a/acpid/src/aml/mod.rs +++ b/acpid/src/aml/mod.rs @@ -4,6 +4,7 @@ use std::collections::HashMap; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use syscall::io::{Io, Pio}; use crate::acpi::{AcpiContext, AmlContainingTable, Sdt, SdtHeader}; @@ -126,8 +127,16 @@ pub fn set_global_s_state(context: &AcpiContext, state: u8) { log::info!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); val |= slp_typa as u16; - log::info!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); - Pio::::new(port).write(val); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + log::info!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); + Pio::::new(port).write(val); + } + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + { + log::error!("Cannot shutdown with ACPI outw(0x{:X}, 0x{:X}) on this architecture", port, val); + } loop { core::hint::spin_loop(); diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 34e1e35141..b8368aea42 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -1,3 +1,5 @@ +#![cfg_attr(target_arch = "aarch64", feature(stdsimd))] // Required for yield instruction + use std::convert::TryInto; use std::fs::File; use std::io::{ErrorKind, Read, Write}; diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 723c65593b..901b404cfe 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -24,7 +24,7 @@ use pcid_interface::PcidServerHandle; #[cfg(target_arch = "aarch64")] #[inline(always)] -pub(crate) unsafe fn pause() { std::arch::x86::__yield(); } +pub(crate) unsafe fn pause() { std::arch::aarch64::__yield(); } #[cfg(target_arch = "x86")] #[inline(always)] diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 7338552f23..033693b2c1 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,6 +1,7 @@ use std::convert::TryFrom; use std::sync::{Mutex, Once}; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use syscall::io::{Io as _, Pio}; pub use self::bar::PciBar; @@ -96,6 +97,25 @@ impl CfgAccess for Pci { self.write_nolock(bus, dev, func, offset, value) } } +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +impl CfgAccess for Pci { + unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + todo!("Pci::CfgAccess::read_nolock on this architecture") + } + + unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + let _guard = self.lock.lock().unwrap(); + self.read_nolock(bus, dev, func, offset) + } + + unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { + todo!("Pci::CfgAccess::write_nolock on this architecture") + } + unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { + let _guard = self.lock.lock().unwrap(); + self.write_nolock(bus, dev, func, offset, value) + } +} pub struct PciIter<'pci> { pci: &'pci dyn CfgAccess, From 00de428d6bbbba51d6f926266ee4d29e76b18397 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 26 Jul 2022 17:20:34 -0600 Subject: [PATCH 0496/1301] Workarounds for x86 32-bit --- e1000d/src/device.rs | 4 +- ihdad/src/hda/cmdbuff.rs | 4 +- ihdad/src/hda/stream.rs | 2 +- ixgbed/src/device.rs | 4 +- nvmed/src/main.rs | 11 +++++- rtl8168d/src/device.rs | 6 +-- xhcid/src/main.rs | 83 +++++++++++++++++++++++++-------------- xhcid/src/xhci/context.rs | 2 +- xhcid/src/xhci/ring.rs | 4 +- xhcid/src/xhci/trb.rs | 12 +++--- 10 files changed, 82 insertions(+), 50 deletions(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index c5b6902bbb..cde14975ff 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -364,7 +364,7 @@ impl Intel8254x { self.receive_ring[i].buffer = self.receive_buffer[i].physical() as u64; } - self.write_reg(RDBAH, (self.receive_ring.physical() >> 32) as u32); + self.write_reg(RDBAH, ((self.receive_ring.physical() as u64) >> 32) as u32); self.write_reg(RDBAL, self.receive_ring.physical() as u32); self.write_reg( RDLEN, @@ -378,7 +378,7 @@ impl Intel8254x { self.transmit_ring[i].buffer = self.transmit_buffer[i].physical() as u64; } - self.write_reg(TDBAH, (self.transmit_ring.physical() >> 32) as u32); + self.write_reg(TDBAH, ((self.transmit_ring.physical() as u64) >> 32) as u32); self.write_reg(TDBAL, self.transmit_ring.physical() as u32); self.write_reg( TDLEN, diff --git a/ihdad/src/hda/cmdbuff.rs b/ihdad/src/hda/cmdbuff.rs index a39998d3fb..afbeadaf79 100644 --- a/ihdad/src/hda/cmdbuff.rs +++ b/ihdad/src/hda/cmdbuff.rs @@ -130,7 +130,7 @@ impl Corb { pub fn set_address(&mut self, addr: usize) { self.regs.corblbase.write((addr & 0xFFFFFFFF) as u32); - self.regs.corbubase.write((addr >> 32) as u32); + self.regs.corbubase.write(((addr as u64) >> 32) as u32); } pub fn reset_read_pointer(&mut self) { @@ -268,7 +268,7 @@ impl Rirb { pub fn set_address(&mut self, addr: usize) { self.regs.rirblbase.write((addr & 0xFFFFFFFF) as u32); - self.regs.rirbubase.write((addr >> 32) as u32); + self.regs.rirbubase.write(((addr as u64) >> 32) as u32); } pub fn reset_write_pointer(&mut self) { diff --git a/ihdad/src/hda/stream.rs b/ihdad/src/hda/stream.rs index cf9cb90ada..0b20bd923a 100644 --- a/ihdad/src/hda/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -156,7 +156,7 @@ impl StreamDescriptorRegs { pub fn set_address(&mut self, addr: usize) { self.buff_desc_list_lo.write( (addr & 0xFFFFFFFF) as u32); - self.buff_desc_list_hi.write( ( (addr >> 32) & 0xFFFFFFFF) as u32); + self.buff_desc_list_hi.write( ( ((addr as u64) >> 32) & 0xFFFFFFFF) as u32); } pub fn set_last_valid_index(&mut self, index:u16) { diff --git a/ixgbed/src/device.rs b/ixgbed/src/device.rs index 70452bc81a..c5a8a210b4 100644 --- a/ixgbed/src/device.rs +++ b/ixgbed/src/device.rs @@ -420,7 +420,7 @@ impl Intel8259x { self.write_reg(IXGBE_RDBAL(i), self.receive_ring.physical() as u32); - self.write_reg(IXGBE_RDBAH(i), (self.receive_ring.physical() >> 32) as u32); + self.write_reg(IXGBE_RDBAH(i), ((self.receive_ring.physical() as u64) >> 32) as u32); self.write_reg( IXGBE_RDLEN(i), (self.receive_ring.len() * mem::size_of::()) as u32, @@ -462,7 +462,7 @@ impl Intel8259x { // section 7.1.9 - setup descriptor ring self.write_reg(IXGBE_TDBAL(i), self.transmit_ring.physical() as u32); - self.write_reg(IXGBE_TDBAH(i), (self.transmit_ring.physical() >> 32) as u32); + self.write_reg(IXGBE_TDBAH(i), ((self.transmit_ring.physical() as u64) >> 32) as u32); self.write_reg( IXGBE_TDLEN(i), (self.transmit_ring.len() * mem::size_of::()) as u32, diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index b8368aea42..a8d290768a 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -217,13 +217,22 @@ fn get_int_method( } } +//TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] fn get_int_method( pcid_handle: &mut PcidServerHandle, function: &PciFunction, allocated_bars: &AllocatedBars, ) -> Result<(InterruptMethod, InterruptSources)> { - todo!("handling of interrupts on non-x86_64") + if function.legacy_interrupt_pin.is_some() { + // INTx# pin based interrupts. + let irq_handle = File::open(format!("irq:{}", function.legacy_interrupt_line)) + .expect("nvmed: failed to open INTx# interrupt line"); + Ok((InterruptMethod::Intx, InterruptSources::Intx(irq_handle))) + } else { + // No interrupts at all + todo!("handling of no interrupts") + } } fn setup_logging() -> Option<&'static RedoxLogger> { diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 6e3d0991dc..ff6231c32c 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -333,15 +333,15 @@ impl Rtl8168 { // Set tx low priority buffer address self.regs.tnpds[0].write(self.transmit_ring.physical() as u32); - self.regs.tnpds[1].write((self.transmit_ring.physical() >> 32) as u32); + self.regs.tnpds[1].write(((self.transmit_ring.physical() as u64) >> 32) as u32); // Set tx high priority buffer address self.regs.thpds[0].write(self.transmit_ring_h.physical() as u32); - self.regs.thpds[1].write((self.transmit_ring_h.physical() >> 32) as u32); + self.regs.thpds[1].write(((self.transmit_ring_h.physical() as u64) >> 32) as u32); // Set rx buffer address self.regs.rdsar[0].write(self.receive_ring.physical() as u32); - self.regs.rdsar[1].write((self.receive_ring.physical() >> 32) as u32); + self.regs.rdsar[1].write(((self.receive_ring.physical() as u64) >> 32) as u32); // Disable timer interrupt self.regs.timer_int.write(0); diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index c8b84180f9..5d199d23b6 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -82,38 +82,11 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } } -fn main() { - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { - return; - } - - let _logger_ref = setup_logging(); - - let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); +#[cfg(target_arch = "x86_64")] +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> (Option, InterruptMethod) { let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); - info!("XHCI PCI CONFIG: {:?}", pci_config); - - let bar = pci_config.func.bars[0]; - let bar_size = pci_config.func.bar_sizes[0]; let irq = pci_config.func.legacy_interrupt_line; - let mut name = pci_config.func.name(); - name.push_str("_xhci"); - - let bar_ptr = match bar { - pcid_interface::PciBar::Memory(ptr) => match ptr { - 0 => panic!("BAR 0 is mapped to address 0"), - _ => ptr, - }, - other => panic!("Expected memory bar, found {}", other), - }; - - let address = unsafe { - syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("xhcid: failed to map address") - }; - let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); info!("XHCI PCI FEATURES: {:?}", all_pci_features); @@ -127,7 +100,7 @@ fn main() { msix_enabled = true; } - let (mut irq_file, interrupt_method) = if msi_enabled && !msix_enabled { + if msi_enabled && !msix_enabled { use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; let mut capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI capability structure from pcid") { @@ -226,8 +199,58 @@ fn main() { } else { // no interrupts at all (None, InterruptMethod::Polling) + } +} + +//TODO: MSI on non-x86_64? +#[cfg(not(target_arch = "x86_64"))] +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> (Option, InterruptMethod) { + let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); + let irq = pci_config.func.legacy_interrupt_line; + + if pci_config.func.legacy_interrupt_pin.is_some() { + // legacy INTx# interrupt pins. + (Some(File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file")), InterruptMethod::Intx) + } else { + // no interrupts at all + (None, InterruptMethod::Polling) + } +} + +fn main() { + // Daemonize + if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { + return; + } + + let _logger_ref = setup_logging(); + + let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); + let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); + info!("XHCI PCI CONFIG: {:?}", pci_config); + + let bar = pci_config.func.bars[0]; + let bar_size = pci_config.func.bar_sizes[0]; + let irq = pci_config.func.legacy_interrupt_line; + + let mut name = pci_config.func.name(); + name.push_str("_xhci"); + + let bar_ptr = match bar { + pcid_interface::PciBar::Memory(ptr) => match ptr { + 0 => panic!("BAR 0 is mapped to address 0"), + _ => ptr, + }, + other => panic!("Expected memory bar, found {}", other), }; + let address = unsafe { + syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("xhcid: failed to map address") + }; + + let (mut irq_file, interrupt_method) = get_int_method(&mut pcid_handle); + print!( "{}", format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq) diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index e6f56427e6..c40f000805 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -182,7 +182,7 @@ impl ScratchpadBufferArray { let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result { let pointer = unsafe { syscall::physalloc(page_size)? }; - assert_eq!(pointer & 0xFFFF_FFFF_FFFF_F000, pointer, "physically allocated pointer (physalloc) wasn't 4k page-aligned"); + assert_eq!((pointer as u64) & 0xFFFF_FFFF_FFFF_F000, pointer as u64, "physically allocated pointer (physalloc) wasn't 4k page-aligned"); entry.set_addr(pointer as u64); Ok(pointer) }).collect::, _>>()?; diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index 8326217858..ae7da564b4 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -66,8 +66,8 @@ impl Ring { /// # Panics /// Panics if paddr is not a multiple of 16 bytes, i.e. the size of a TRB. pub fn phys_addr_to_index(&self, ac64: bool, paddr: u64) -> Option { - let base = self.trbs.physical() & if ac64 { 0xFFFF_FFFF_FFFF_FFFF } else { 0xFFFF_FFFF }; - let offset = paddr.checked_sub(base as u64)? as usize; + let base = (self.trbs.physical() as u64) & if ac64 { 0xFFFF_FFFF_FFFF_FFFF } else { 0xFFFF_FFFF }; + let offset = paddr.checked_sub(base)? as usize; assert_eq!(offset % mem::size_of::(), 0, "unaligned TRB physical address"); diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index a26a28f626..66d30437be 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -245,8 +245,8 @@ impl Trb { pub fn address_device(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) { assert_eq!( - input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0, - input_ctx_ptr, + (input_ctx_ptr as u64) & 0xFFFF_FFFF_FFFF_FFF0, + input_ctx_ptr as u64, "unaligned input context ptr" ); self.set( @@ -261,8 +261,8 @@ impl Trb { // Synchronizes the input context endpoints with the device context endpoints, I think. pub fn configure_endpoint(&mut self, slot_id: u8, input_ctx_ptr: usize, cycle: bool) { assert_eq!( - input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0, - input_ctx_ptr, + (input_ctx_ptr as u64) & 0xFFFF_FFFF_FFFF_FFF0, + input_ctx_ptr as u64, "unaligned input context ptr" ); @@ -276,8 +276,8 @@ impl Trb { } pub fn evaluate_context(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) { assert_eq!( - input_ctx_ptr & 0xFFFF_FFFF_FFFF_FFF0, - input_ctx_ptr, + (input_ctx_ptr as u64) & 0xFFFF_FFFF_FFFF_FFF0, + input_ctx_ptr as u64, "unaligned input context ptr" ); self.set( From cb9656d83de4343179195ceee26cdd62bbaff676 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 26 Jul 2022 17:31:02 -0600 Subject: [PATCH 0497/1301] Fix minor issue on x86_64 --- xhcid/src/main.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 5d199d23b6..0918206a6b 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -83,10 +83,21 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } #[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> (Option, InterruptMethod) { +fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option, InterruptMethod) { let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); + + let bar = pci_config.func.bars[0]; + let bar_size = pci_config.func.bar_sizes[0]; let irq = pci_config.func.legacy_interrupt_line; + let bar_ptr = match bar { + pcid_interface::PciBar::Memory(ptr) => match ptr { + 0 => panic!("BAR 0 is mapped to address 0"), + _ => ptr, + }, + other => panic!("Expected memory bar, found {}", other), + }; + let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); info!("XHCI PCI FEATURES: {:?}", all_pci_features); @@ -204,7 +215,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> (Option, Interrup //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> (Option, InterruptMethod) { +fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option, InterruptMethod) { let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); let irq = pci_config.func.legacy_interrupt_line; @@ -249,7 +260,7 @@ fn main() { .expect("xhcid: failed to map address") }; - let (mut irq_file, interrupt_method) = get_int_method(&mut pcid_handle); + let (mut irq_file, interrupt_method) = get_int_method(&mut pcid_handle, address); print!( "{}", From 322af701d6025c13bca4579ff69812ade27f649e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 9 Jun 2022 13:59:07 +0200 Subject: [PATCH 0498/1301] Use aligned addresses in physmap. --- Cargo.lock | 5 ++--- Cargo.toml | 1 + ahcid/Cargo.toml | 2 +- ahcid/src/main.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f5f5d06ef..ebe65ced91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -616,7 +616,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#55c55eb6452ee886dfd81f1cbb7f9ec45012d95e" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#a55df137538fabadea2eff74153ac0b8d3ce3dcf" dependencies = [ "arg_parser", "extra", @@ -1108,8 +1108,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=userspace_fexec#d6af266119e7b4a3b0e9a04c63b3cfcfac94781a" dependencies = [ "bitflags", ] diff --git a/Cargo.toml b/Cargo.toml index 8078a99e90..48733bd4e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,3 +25,4 @@ members = [ mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.28" } +redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "userspace_fexec" } diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index 74f11ce48a..81bfc57ff6 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -9,5 +9,5 @@ byteorder = "1.2" log = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } redox-log = "0.1" -redox_syscall = "0.2.12" +redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "userspace_fexec" } block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index cef16638a2..9a4c75e73b 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -88,7 +88,7 @@ fn main() { info!(" + AHCI {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); let address = unsafe { - syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + syscall::physmap(bar, (bar_size+4095)/4096*4096, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("ahcid: failed to map address") }; { From badd5906d5d279deba144db70ba8de82d1224efe Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 18 Jul 2022 16:14:50 +0200 Subject: [PATCH 0499/1301] Page-align size in physmap. --- xhcid/src/xhci/mod.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 083cd281bc..7d7918fe9e 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -449,14 +449,18 @@ impl Xhci { }; PhysBox::new_with_flags(byte_count, flags) } + fn page_align(size: usize) -> usize { + // TODO: PAGE_SIZE + (size+4095)/4096*4096 + } pub unsafe fn alloc_dma_zeroed_raw(ac64: bool) -> Result> { - Ok(Dma::from_physbox_zeroed(Self::alloc_phys(ac64, mem::size_of::())?)?.assume_init()) + Ok(Dma::from_physbox_zeroed(Self::alloc_phys(ac64, Self::page_align(mem::size_of::()))?)?.assume_init()) } pub unsafe fn alloc_dma_zeroed(&self) -> Result> { Self::alloc_dma_zeroed_raw(self.cap.ac64()) } pub unsafe fn alloc_dma_zeroed_unsized_raw(ac64: bool, count: usize) -> Result> { - Ok(Dma::from_physbox_zeroed_unsized(Self::alloc_phys(ac64, mem::size_of::() * count)?, count)?.assume_init()) + Ok(Dma::from_physbox_zeroed_unsized(Self::alloc_phys(ac64, Self::page_align(mem::size_of::() * count))?, count)?.assume_init()) } pub unsafe fn alloc_dma_zeroed_unsized(&self, count: usize) -> Result> { Self::alloc_dma_zeroed_unsized_raw(self.cap.ac64(), count) From 21e30b733938a5ab1ab607a6c317650b04fb3f90 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 18 Jul 2022 16:15:19 +0200 Subject: [PATCH 0500/1301] Replace syscall::clone() with libc::fork(). --- Cargo.lock | 25 +++++++ acpid/Cargo.toml | 1 + acpid/src/main.rs | 31 ++------ ahcid/Cargo.toml | 1 + ahcid/src/main.rs | 15 ++-- alxd/Cargo.toml | 1 + alxd/src/main.rs | 10 +-- bgad/Cargo.toml | 1 + bgad/src/main.rs | 9 +-- e1000d/Cargo.toml | 1 + e1000d/src/main.rs | 4 +- ihdad/Cargo.toml | 1 + ihdad/src/main.rs | 8 ++- ixgbed/Cargo.toml | 1 + ixgbed/src/main.rs | 10 +-- nvmed/Cargo.toml | 1 + nvmed/src/main.rs | 14 ++-- pcid/src/main.rs | 3 + pcspkrd/Cargo.toml | 1 + pcspkrd/src/main.rs | 11 +-- ps2d/Cargo.toml | 1 + ps2d/src/main.rs | 4 +- rtl8168d/Cargo.toml | 1 + rtl8168d/src/main.rs | 4 +- usbscsid/Cargo.toml | 1 + usbscsid/src/main.rs | 17 ++--- vboxd/Cargo.toml | 1 + vboxd/src/main.rs | 10 ++- vesad/Cargo.toml | 1 + vesad/src/main.rs | 168 ++++++++++++++++++++----------------------- xhcid/Cargo.toml | 1 + xhcid/src/main.rs | 12 ++-- 32 files changed, 200 insertions(+), 170 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ebe65ced91..786227566f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,7 @@ dependencies = [ "num-traits", "parking_lot 0.11.2", "plain", + "redox-daemon", "redox-log", "redox_syscall", "thiserror", @@ -25,6 +26,7 @@ dependencies = [ "byteorder 1.4.3", "log", "partitionlib", + "redox-daemon", "redox-log", "redox_syscall", ] @@ -35,6 +37,7 @@ version = "0.1.0" dependencies = [ "bitflags", "netutils", + "redox-daemon", "redox_event", "redox_syscall", ] @@ -105,6 +108,7 @@ name = "bgad" version = "0.1.0" dependencies = [ "orbclient", + "redox-daemon", "redox_syscall", ] @@ -287,6 +291,7 @@ version = "0.1.0" dependencies = [ "bitflags", "netutils", + "redox-daemon", "redox_event", "redox_syscall", ] @@ -453,6 +458,7 @@ version = "0.1.0" dependencies = [ "bitflags", "log", + "redox-daemon", "redox-log", "redox_event", "redox_syscall", @@ -489,6 +495,7 @@ version = "1.0.0" dependencies = [ "bitflags", "netutils", + "redox-daemon", "redox_event", "redox_syscall", ] @@ -695,6 +702,7 @@ dependencies = [ "log", "partitionlib", "pcid", + "redox-daemon", "redox-log", "redox_syscall", "smallvec 1.9.0", @@ -850,6 +858,7 @@ dependencies = [ name = "pcspkrd" version = "0.1.0" dependencies = [ + "redox-daemon", "redox_syscall", ] @@ -916,6 +925,7 @@ version = "0.1.0" dependencies = [ "bitflags", "orbclient", + "redox-daemon", "redox_syscall", ] @@ -1085,6 +1095,16 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "redox-daemon" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e31c834277709c7ff3eb74959fe62be4b45b1189ba9d41fd3744cd3a9c554f" +dependencies = [ + "libc", + "redox_syscall", +] + [[package]] name = "redox-log" version = "0.1.1" @@ -1128,6 +1148,7 @@ version = "0.1.0" dependencies = [ "bitflags", "netutils", + "redox-daemon", "redox_event", "redox_syscall", ] @@ -1479,6 +1500,7 @@ version = "0.1.0" dependencies = [ "base64", "plain", + "redox-daemon", "redox_syscall", "thiserror", "xhcid", @@ -1510,6 +1532,7 @@ name = "vboxd" version = "0.1.0" dependencies = [ "orbclient", + "redox-daemon", "redox_event", "redox_syscall", ] @@ -1538,6 +1561,7 @@ version = "0.1.0" dependencies = [ "orbclient", "ransid", + "redox-daemon", "redox_syscall", "rusttype", ] @@ -1677,6 +1701,7 @@ dependencies = [ "log", "pcid", "plain", + "redox-daemon", "redox-log", "redox_event", "redox_syscall", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 06fc3c698f..0cdb909538 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -12,6 +12,7 @@ num-derive = "0.3" num-traits = "0.2" parking_lot = "0.11.1" plain = "0.2.3" +redox-daemon = "0.1" redox-log = "0.1.1" redox_syscall = "0.2.16" thiserror = "1" diff --git a/acpid/src/main.rs b/acpid/src/main.rs index ebc105dcc6..0247bb6fac 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -79,7 +79,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } } -fn daemon(mut write_part: File) { +fn daemon(daemon: redox_daemon::Daemon) -> ! { setup_logging(); let rxsdt_raw_data: Arc<[u8]> = std::fs::read("kernel/acpi:rxsdt") @@ -135,8 +135,7 @@ fn daemon(mut write_part: File) { .open(":acpi") .expect("acpid: failed to open scheme socket"); - write_part.write_all(&[0]).expect("acpid: failed to write to sync pipe"); - drop(write_part); + daemon.ready().expect("acpid: failed to notify parent"); syscall::setrens(0, 0).expect("acpid: failed to enter null namespace"); @@ -163,14 +162,14 @@ fn daemon(mut write_part: File) { match scheme_socket.read(&mut packet) { Ok(0) => { log::info!("Terminating acpid driver, without shutting down the main system."); - return; + break 'events; } Ok(n) => break 'eintr1 n, Err(error) if error.kind() == io::ErrorKind::Interrupted => continue 'eintr1, Err(error) if error.kind() == io::ErrorKind::WouldBlock => break 'packets, Err(other) => { log::error!("failed to read from scheme socket: {}", other); - return; + break 'events; } } }; @@ -185,14 +184,14 @@ fn daemon(mut write_part: File) { match scheme_socket.write(&packet) { Ok(0) => { log::info!("Terminating acpid driver, without shutting down the main system."); - return; + break 'events; } Ok(n) => break 'eintr2 n, Err(error) if error.kind() == io::ErrorKind::Interrupted => continue 'eintr2, Err(error) if error.kind() == io::ErrorKind::WouldBlock => break 'packets, Err(other) => { log::error!("failed to read from scheme socket: {}", other); - return; + break 'events; } } }; @@ -222,21 +221,5 @@ fn daemon(mut write_part: File) { } fn main() { - let mut pipes = [0; 2]; - syscall::pipe2(&mut pipes, 0).expect("acpid: failed to create synchronization pipe"); - - let mut read_part = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; - let mut write_part = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; - - if unsafe { syscall::clone(syscall::CloneFlags::empty()).expect("failed to daemonize acpid") } == 0 { - drop(read_part); - daemon(write_part); - } else { - drop(write_part); - - let mut res = [0]; - let bytes_read = read_part.read_exact(&mut res).expect("acpid: failed to read from sync pipe"); - - std::process::exit(res[0].into()); - } + redox_daemon::Daemon::new(daemon).expect("acpid: failed to daemonize"); } diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index 81bfc57ff6..f8eaa7afde 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -8,6 +8,7 @@ bitflags = "1.2" byteorder = "1.2" log = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +redox-daemon = "0.1" redox-log = "0.1" redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "userspace_fexec" } block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 9a4c75e73b..6690684c3e 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -8,7 +8,7 @@ use std::os::unix::io::{FromRawFd, RawFd}; use syscall::error::{Error, ENODEV}; use syscall::data::{Event, Packet}; -use syscall::flag::{CloneFlags, EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::flag::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::scheme::SchemeBlockMut; use log::{error, info}; @@ -64,6 +64,10 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } fn main() { + redox_daemon::Daemon::new(daemon).expect("ahcid: failed to daemonize"); +} + +fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut args = env::args().skip(1); let mut name = args.next().expect("ahcid: no name provided"); @@ -78,11 +82,6 @@ fn main() { let irq_str = args.next().expect("ahcid: no irq provided"); let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { - return; - } - let _logger_ref = setup_logging(); info!(" + AHCI {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); @@ -109,6 +108,8 @@ fn main() { syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace"); + daemon.ready().expect("ahcid: failed to notify parent"); + event_file.write(&Event { id: socket_fd, flags: EVENT_READ, @@ -198,4 +199,6 @@ fn main() { } } unsafe { let _ = syscall::physunmap(address); } + + std::process::exit(0); } diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml index 89c08b7ff9..4064bea456 100644 --- a/alxd/Cargo.toml +++ b/alxd/Cargo.toml @@ -8,3 +8,4 @@ bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.2.12" +redox-daemon = "0.1" diff --git a/alxd/src/main.rs b/alxd/src/main.rs index 7acdd1df7d..f0877eacd4 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -15,7 +15,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{CloneFlags, EventFlags, Packet, SchemeMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{EventFlags, Packet, SchemeMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -35,11 +35,12 @@ fn main() { print!("{}", format!(" + ALX {} on: {:X}, IRQ: {}\n", name, bar, irq)); // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 - { + redox_daemon::Daemon::new(move |daemon| { let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("alxd: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + daemon.ready().expect("alxd: failed to signal readiness"); + let mut irq_file = File::open(format!("irq:{}", irq)).expect("alxd: failed to open IRQ file"); let address = unsafe { syscall::physmap(bar, 128*1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("alxd: failed to map address") }; @@ -141,5 +142,6 @@ fn main() { } } unsafe { let _ = syscall::physunmap(address); } - } + std::process::exit(0); + }).expect("alxd: failed to daemonize"); } diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml index 8dd06e8520..f4ef93efa3 100644 --- a/bgad/Cargo.toml +++ b/bgad/Cargo.toml @@ -5,4 +5,5 @@ edition = "2018" [dependencies] orbclient = "0.3.27" +redox-daemon = "0.1" redox_syscall = "0.2.12" diff --git a/bgad/src/main.rs b/bgad/src/main.rs index 47ad94ae74..f441acf75e 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -9,7 +9,6 @@ use std::io::{Read, Write}; use syscall::call::iopl; use syscall::data::Packet; -use syscall::flag::CloneFlags; use syscall::scheme::SchemeMut; use crate::bga::Bga; @@ -29,8 +28,7 @@ fn main() { print!("{}", format!(" + BGA {} on: {:X}\n", name, bar)); - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { + redox_daemon::Daemon::new(move |daemon| { unsafe { iopl(3).unwrap() }; let mut socket = File::create(":bga").expect("bgad: failed to create bga scheme"); @@ -45,6 +43,8 @@ fn main() { syscall::setrens(0, 0).expect("bgad: failed to enter null namespace"); + daemon.ready().expect("bgad: failed to notify parent"); + loop { let mut packet = Packet::default(); if socket.read(&mut packet).expect("bgad: failed to read events from bga scheme") == 0 { @@ -53,5 +53,6 @@ fn main() { scheme.handle(&mut packet); socket.write(&packet).expect("bgad: failed to write responses to bga scheme"); } - } + std::process::exit(0); + }).expect("bgad: failed to daemonize"); } diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 4a1a005d01..4d558ff412 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -6,5 +6,6 @@ edition = "2018" [dependencies] bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } +redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.2.12" diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 093d567b98..67f8a4012a 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -10,7 +10,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{CloneFlags, EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; pub mod device; @@ -74,7 +74,7 @@ fn main() { eprintln!(" + E1000 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); - syscall::Daemon::new(move |daemon| { + redox_daemon::Daemon::new(move |daemon| { let socket_fd = syscall::open( ":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, diff --git a/ihdad/Cargo.toml b/ihdad/Cargo.toml index c38f53e167..b43f31e321 100755 --- a/ihdad/Cargo.toml +++ b/ihdad/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] bitflags = "1" log = "0.4" +redox-daemon = "0.1" redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.2.12" diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 70b486e1e6..13df709e70 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -9,7 +9,7 @@ use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use syscall::{CloneFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Packet, SchemeBlockMut, EventFlags}; +use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; @@ -93,7 +93,7 @@ fn main() { print!("{}", format!(" + ihda {} on: {:X} size: {} IRQ: {}\n", name, bar, bar_size, irq)); // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { + redox_daemon::Daemon::new(move |daemon| { let _logger_ref = setup_logging(); let address = unsafe { @@ -108,6 +108,7 @@ fn main() { let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); let socket_fd = syscall::open(":hda", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + daemon.ready().expect("IHDA: failed to signal readiness"); let mut event_queue = EventQueue::::new().expect("IHDA: Could not create event queue."); @@ -220,5 +221,6 @@ fn main() { } unsafe { let _ = syscall::physunmap(address); } - } + std::process::exit(0); + }).expect("IHDA: failed to daemonize"); } diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml index 5833964c71..73a9a39d47 100644 --- a/ixgbed/Cargo.toml +++ b/ixgbed/Cargo.toml @@ -7,3 +7,4 @@ bitflags = "1.0" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.2.12" +redox-daemon = "0.1" diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index 0f1b1ea3dd..ae8be8d5b7 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -11,7 +11,7 @@ use std::{env, thread}; use event::EventQueue; use std::time::Duration; -use syscall::{CloneFlags, EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; pub mod device; #[rustfmt::skip] @@ -76,8 +76,7 @@ fn main() { println!(" + IXGBE {} on: {:X} IRQ: {}", name, bar, irq); - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { + redox_daemon::Daemon::new(move |daemon| { let socket_fd = syscall::open( ":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, @@ -87,6 +86,8 @@ fn main() { File::from_raw_fd(socket_fd as RawFd) })); + daemon.ready().expect("ixgbed: failed to signal readiness"); + let mut irq_file = File::open(format!("irq:{}", irq)).expect("ixgbed: failed to open IRQ file"); @@ -197,7 +198,8 @@ fn main() { unsafe { let _ = syscall::physunmap(address); } - } + std::process::exit(0); + }).expect("ixgbed: failed to daemonize"); thread::sleep(Duration::from_secs(20)); } diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index fed14c7a00..1ce0b956b7 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -9,6 +9,7 @@ bitflags = "1" crossbeam-channel = "0.4" futures = "0.3" log = "0.4" +redox-daemon = "0.1" redox-log = "0.1" redox_syscall = "0.2.12" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index a8d290768a..9151a9791a 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -10,7 +10,7 @@ use std::{slice, usize}; use pcid_interface::{PciBar, PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; use syscall::{ - CloneFlags, Event, Mmio, Packet, Result, SchemeBlockMut, PHYSMAP_NO_CACHE, + Event, Mmio, Packet, Result, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE, }; use redox_log::{OutputBuilder, RedoxLogger}; @@ -280,11 +280,9 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } fn main() { - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { - return; - } - + redox_daemon::Daemon::new(daemon).expect("nvmed: failed to daemonize"); +} +fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(); let mut pcid_handle = @@ -334,6 +332,8 @@ fn main() { ) .expect("nvmed: failed to create disk scheme"); + daemon.ready().expect("nvmed: failed to signal readiness"); + syscall::write( event_fd, &syscall::Event { @@ -406,4 +406,6 @@ fn main() { //TODO: destroy NVMe stuff reactor_thread.join().expect("nvmed: failed to join reactor thread"); + + std::process::exit(0); } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index fce37d5b25..daff50513a 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -468,6 +468,9 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, capabilities, }; let thread = thread::spawn(move || { + // RFLAGS are no longer kept in the relibc clone() implementation. + unsafe { syscall::iopl(3).expect("pcid: failed to set IOPL"); } + driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); }); match child.wait() { diff --git a/pcspkrd/Cargo.toml b/pcspkrd/Cargo.toml index cbe70ea730..1d7b6ce8d9 100644 --- a/pcspkrd/Cargo.toml +++ b/pcspkrd/Cargo.toml @@ -6,3 +6,4 @@ edition = "2018" [dependencies] redox_syscall = "0.2.12" +redox-daemon = "0.1" diff --git a/pcspkrd/src/main.rs b/pcspkrd/src/main.rs index f5692c0dcb..7f9bfc1e40 100644 --- a/pcspkrd/src/main.rs +++ b/pcspkrd/src/main.rs @@ -6,24 +6,25 @@ use std::io::{Read, Write}; use syscall::call::iopl; use syscall::data::Packet; -use syscall::flag::CloneFlags; use syscall::scheme::SchemeMut; +use redox_daemon::Daemon; + use self::pcspkr::Pcspkr; use self::scheme::PcspkrScheme; fn main() { - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { + Daemon::new(move |daemon| { unsafe { iopl(3).unwrap() }; let mut socket = File::create(":pcspkr").expect("pcspkrd: failed to create pcspkr scheme"); + daemon.ready().expect("failed to notify parent"); let pcspkr = Pcspkr::new(); println!(" + pcspkr"); let mut scheme = PcspkrScheme { - pcspkr: pcspkr, + pcspkr, handle: None, next_id: 0, }; @@ -40,5 +41,5 @@ fn main() { .write(&packet) .expect("pcspkrd: failed to write responses to pcspkr scheme"); } - } + }).expect("pcspkrd: failed to daemonize"); } diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index c9192a3972..b6af7bbd37 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" bitflags = "1" orbclient = "0.3.27" redox_syscall = "0.2.12" +redox-daemon = "0.1" diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 947bce2cd1..5a845e415f 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -20,7 +20,7 @@ mod keymap; mod state; mod vm; -fn daemon(daemon: syscall::Daemon) -> core::convert::Infallible { +fn daemon(daemon: redox_daemon::Daemon) -> ! { unsafe { iopl(3).expect("ps2d: failed to get I/O permission"); } @@ -124,5 +124,5 @@ fn daemon(daemon: syscall::Daemon) -> core::convert::Infallible { } fn main() { - syscall::Daemon::new(daemon).expect("ps2d: failed to create daemon"); + redox_daemon::Daemon::new(daemon).expect("ps2d: failed to create daemon"); } diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index 6687ced3ed..f0c3c47b5a 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -8,3 +8,4 @@ bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.2.12" +redox-daemon = "0.1" diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index d2d3f34ebf..d8e40a40c6 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -10,7 +10,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{CloneFlags, EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; pub mod device; @@ -74,7 +74,7 @@ fn main() { eprintln!(" + RTL8168 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); - syscall::Daemon::new(move |daemon| { + redox_daemon::Daemon::new(move |daemon| { let socket_fd = syscall::open( ":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, diff --git a/usbscsid/Cargo.toml b/usbscsid/Cargo.toml index a5a5eff5c3..1cc137ecad 100644 --- a/usbscsid/Cargo.toml +++ b/usbscsid/Cargo.toml @@ -10,6 +10,7 @@ license = "MIT" [dependencies] base64 = "0.11" # Only for debugging plain = "0.2" +redox-daemon = "0.1" redox_syscall = "0.2.12" thiserror = "1" xhcid = { path = "../xhcid" } diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index 601512b558..05d37942f0 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -3,7 +3,7 @@ use std::fs::File; use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; -use syscall::{CloneFlags, Packet, SchemeMut}; +use syscall::{Packet, SchemeMut}; use xhcid_interface::{ConfigureEndpointsReq, DeviceReqData, XhciClientHandle}; pub mod protocol; @@ -36,16 +36,15 @@ fn main() { scheme, port, protocol ); - // Daemonize so that xhcid can continue to do other useful work (until proper IRQs, - // async-await, and multithreading :D) - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { - return; - } - + redox_daemon::Daemon::new(move |d| daemon(d, scheme, port, protocol)).expect("usbscsid: failed to daemonize"); +} +fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u8) -> ! { let disk_scheme_name = format!(":disk/{}-{}_scsi", scheme, port); // TODO: Use eventfds. - let handle = XhciClientHandle::new(scheme, port); + let handle = XhciClientHandle::new(scheme.to_owned(), port); + + daemon.ready().expect("usbscsid: failed to signal rediness"); let desc = handle .get_standard_descs() @@ -111,4 +110,6 @@ fn main() { .write(&packet) .expect("scsid: failed to write packet"); } + + std::process::exit(0); } diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index 774fe4fca9..43cea1e68d 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" orbclient = "0.3.27" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.2.12" +redox-daemon = "0.1" diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 2cd7cd8e65..0ed4a1975d 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -11,7 +11,7 @@ use std::fs::File; use std::io::{Result, Read, Write}; use syscall::call::iopl; -use syscall::flag::{CloneFlags, EventFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::flag::{EventFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::io::{Dma, Io, Mmio, Pio}; use crate::bga::Bga; @@ -199,7 +199,9 @@ fn main() { print!("{}", format!(" + VirtualBox {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1, irq)); // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 { + redox_daemon::Daemon::new(move |daemon| { + daemon.ready().expect("failed to signal readiness"); + unsafe { iopl(3).expect("vboxd: failed to get I/O permission"); }; let mut width = 0; @@ -295,5 +297,7 @@ fn main() { event_queue.run().expect("vboxd: failed to run event loop"); } unsafe { let _ = syscall::physunmap(address); } - } + + std::process::exit(0); + }).expect("vboxd: failed to daemonize"); } diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 49af3ac6b3..8f4b457d3c 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -8,6 +8,7 @@ orbclient = "0.3.27" ransid = "0.4" rusttype = { version = "0.2", optional = true } redox_syscall = "0.2.12" +redox-daemon = "0.1" [features] default = [] diff --git a/vesad/src/main.rs b/vesad/src/main.rs index ed1bdc0965..fa3778cce6 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -46,105 +46,89 @@ fn main() { println!("vesad: {}x{} at 0x{:X}", width, height, physbaseptr); - if physbaseptr > 0 { - // Daemonize - let mut pipes = [0; 2]; - syscall::pipe2(&mut pipes, 0).unwrap(); - let mut read = unsafe { File::from_raw_fd(pipes[0] as RawFd) }; - let mut write = unsafe { File::from_raw_fd(pipes[1] as RawFd) }; - let pid = unsafe { syscall::clone(syscall::CloneFlags::empty()).unwrap() }; - if pid != 0 { - drop(write); + if physbaseptr == 0 { + return; + } + redox_daemon::Daemon::new(|daemon| inner(daemon, width, height, physbaseptr, &spec)).expect("failed to create daemon"); +} +fn inner(daemon: redox_daemon::Daemon, width: usize, height: usize, physbaseptr: usize, spec: &[bool]) -> ! { + let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); - let mut res = [0]; - if read.read(&mut res).unwrap() == res.len() { - process::exit(res[0] as i32); - } else { - eprintln!("vesad: daemon pipe EOF"); - process::exit(1); - } + let size = width * height; + //TODO: Remap on resize + let largest_size = 8 * 1024 * 1024; + let onscreen = unsafe { physmap(physbaseptr, largest_size * 4, PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; + unsafe { ptr::write_bytes(onscreen as *mut u32, 0, size); } + + let mut scheme = DisplayScheme::new(width, height, onscreen, &spec); + + syscall::setrens(0, 0).expect("vesad: failed to enter null namespace"); + + daemon.ready().expect("failed to notify parent"); + + let mut blocked = Vec::new(); + loop { + let mut packet = Packet::default(); + if socket.read(&mut packet).expect("vesad: failed to read display scheme") == 0 { + //TODO: Handle blocked + break; + } + + // If it is a read packet, and there is no data, block it. Otherwise, handle packet + if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.can_read(packet.b).is_none() { + blocked.push(packet); } else { - drop(read); + scheme.handle(&mut packet); + socket.write(&packet).expect("vesad: failed to write display scheme"); + } - let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); - - let size = width * height; - //TODO: Remap on resize - let largest_size = 8 * 1024 * 1024; - let onscreen = unsafe { physmap(physbaseptr, largest_size * 4, PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; - unsafe { ptr::write_bytes(onscreen as *mut u32, 0, size); } - - let mut scheme = DisplayScheme::new(width, height, onscreen, &spec); - - syscall::setrens(0, 0).expect("vesad: failed to enter null namespace"); - - write.write(&[0]).unwrap(); - drop(write); - - let mut blocked = Vec::new(); - loop { - let mut packet = Packet::default(); - if socket.read(&mut packet).expect("vesad: failed to read display scheme") == 0 { - //TODO: Handle blocked - break; - } - - // If it is a read packet, and there is no data, block it. Otherwise, handle packet - if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.can_read(packet.b).is_none() { - blocked.push(packet); - } else { + // If there are blocked readers, and data is available, handle them + { + let mut i = 0; + while i < blocked.len() { + if scheme.can_read(blocked[i].b).is_some() { + let mut packet = blocked.remove(i); scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); - } - - // If there are blocked readers, and data is available, handle them - { - let mut i = 0; - while i < blocked.len() { - if scheme.can_read(blocked[i].b).is_some() { - let mut packet = blocked.remove(i); - scheme.handle(&mut packet); - socket.write(&packet).expect("vesad: failed to write display scheme"); - } else { - i += 1; - } - } - } - - for (handle_id, handle) in scheme.handles.iter_mut() { - if !handle.events.contains(EVENT_READ) { - continue; - } - - // Can't use scheme.can_read() because we borrow handles as mutable. - // (and because it'd treat O_NONBLOCK sockets differently) - let count = if let HandleKind::Screen(screen_i) = handle.kind { - scheme.screens.get(&screen_i) - .and_then(|screen| screen.can_read()) - .unwrap_or(0) - } else { 0 }; - - if count > 0 { - if !handle.notified_read { - handle.notified_read = true; - let event_packet = Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: EVENT_READ.bits(), - d: count - }; - - socket.write(&event_packet).expect("vesad: failed to write display event"); - } - } else { - handle.notified_read = false; - } + } else { + i += 1; } } } + + for (handle_id, handle) in scheme.handles.iter_mut() { + if !handle.events.contains(EVENT_READ) { + continue; + } + + // Can't use scheme.can_read() because we borrow handles as mutable. + // (and because it'd treat O_NONBLOCK sockets differently) + let count = if let HandleKind::Screen(screen_i) = handle.kind { + scheme.screens.get(&screen_i) + .and_then(|screen| screen.can_read()) + .unwrap_or(0) + } else { 0 }; + + if count > 0 { + if !handle.notified_read { + handle.notified_read = true; + let event_packet = Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: EVENT_READ.bits(), + d: count + }; + + socket.write(&event_packet).expect("vesad: failed to write display event"); + } + } else { + handle.notified_read = false; + } + } } + std::process::exit(0); } diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 026d4b0c9e..d9112921c3 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -19,6 +19,7 @@ futures = "0.3" plain = "0.2" lazy_static = "1.4" log = "0.4" +redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox-log = "0.1" redox_syscall = "0.2.12" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 0918206a6b..82073e4741 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -20,7 +20,7 @@ use log::info; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; -use syscall::flag::{CloneFlags, EventFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::flag::{EventFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::scheme::Scheme; use syscall::io::Io; @@ -229,11 +229,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option } fn main() { - // Daemonize - if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 { - return; - } + redox_daemon::Daemon::new(daemon).expect("xhcid: failed to daemonize"); +} +fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(); let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); @@ -286,6 +285,8 @@ fn main() { syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); + daemon.ready().expect("xhcid: failed to notify parent"); + let todo = Arc::new(Mutex::new(Vec::::new())); let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); @@ -326,4 +327,5 @@ fn main() { unsafe { let _ = syscall::physunmap(address); } + std::process::exit(0); } From af873f76262709bac6642604ea211e7b24b9e65c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 27 Jul 2022 17:50:32 +0200 Subject: [PATCH 0501/1301] Update redox_syscall dependency. --- Cargo.lock | 63 ++++++++++++++++++++++++++------------------- Cargo.toml | 1 - acpid/Cargo.toml | 2 +- ahcid/Cargo.toml | 2 +- alxd/Cargo.toml | 2 +- bgad/Cargo.toml | 2 +- e1000d/Cargo.toml | 2 +- ihdad/Cargo.toml | 2 +- ixgbed/Cargo.toml | 2 +- nvmed/Cargo.toml | 2 +- pcid/Cargo.toml | 2 +- pcspkrd/Cargo.toml | 2 +- ps2d/Cargo.toml | 2 +- rtl8168d/Cargo.toml | 2 +- usbscsid/Cargo.toml | 2 +- vboxd/Cargo.toml | 2 +- vesad/Cargo.toml | 2 +- xhcid/Cargo.toml | 2 +- 18 files changed, 53 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 786227566f..3400b3bcc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ dependencies = [ "plain", "redox-daemon", "redox-log", - "redox_syscall", + "redox_syscall 0.3.0", "thiserror", ] @@ -28,7 +28,7 @@ dependencies = [ "partitionlib", "redox-daemon", "redox-log", - "redox_syscall", + "redox_syscall 0.3.0", ] [[package]] @@ -39,7 +39,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall", + "redox_syscall 0.3.0", ] [[package]] @@ -109,7 +109,7 @@ version = "0.1.0" dependencies = [ "orbclient", "redox-daemon", - "redox_syscall", + "redox_syscall 0.3.0", ] [[package]] @@ -293,7 +293,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall", + "redox_syscall 0.3.0", ] [[package]] @@ -461,7 +461,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall", + "redox_syscall 0.3.0", "spin", ] @@ -497,7 +497,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall", + "redox_syscall 0.3.0", ] [[package]] @@ -623,7 +623,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#a55df137538fabadea2eff74153ac0b8d3ce3dcf" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#34d1ec9c2e9f7904b57547ca16d4c3145c109880" dependencies = [ "arg_parser", "extra", @@ -632,8 +632,9 @@ dependencies = [ "net2", "ntpclient", "pbr", + "redox-daemon", "redox_event", - "redox_syscall", + "redox_syscall 0.2.16", "redox_termios", "termion", "url", @@ -704,7 +705,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall", + "redox_syscall 0.3.0", "smallvec 1.9.0", ] @@ -721,7 +722,7 @@ source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#192dc30edbad43e dependencies = [ "libc", "raw-window-handle 0.3.4", - "redox_syscall", + "redox_syscall 0.2.16", "sdl2", "sdl2-sys", "wasm-bindgen", @@ -779,7 +780,7 @@ dependencies = [ "cfg-if 1.0.0", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec 1.9.0", "winapi 0.3.9", ] @@ -845,7 +846,7 @@ dependencies = [ "paw", "plain", "redox-log", - "redox_syscall", + "redox_syscall 0.3.0", "serde", "serde_json", "smallvec 1.9.0", @@ -859,7 +860,7 @@ name = "pcspkrd" version = "0.1.0" dependencies = [ "redox-daemon", - "redox_syscall", + "redox_syscall 0.3.0", ] [[package]] @@ -926,7 +927,7 @@ dependencies = [ "bitflags", "orbclient", "redox-daemon", - "redox_syscall", + "redox_syscall 0.3.0", ] [[package]] @@ -1102,7 +1103,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21e31c834277709c7ff3eb74959fe62be4b45b1189ba9d41fd3744cd3a9c554f" dependencies = [ "libc", - "redox_syscall", + "redox_syscall 0.2.16", ] [[package]] @@ -1120,15 +1121,25 @@ dependencies = [ [[package]] name = "redox_event" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/event.git#228eb0719c4424357012c6aad71cf26976048990" +source = "git+https://gitlab.redox-os.org/redox-os/event.git#f7db3d25ca5e282c12ded12bf6c720087b570132" dependencies = [ - "redox_syscall", + "redox_syscall 0.3.0", ] [[package]] name = "redox_syscall" version = "0.2.16" -source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=userspace_fexec#d6af266119e7b4a3b0e9a04c63b3cfcfac94781a" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8ce969b6629faa6f60a71f84022b0217e5ca8bcaeb6d11654506a55ebf8fed" dependencies = [ "bitflags", ] @@ -1139,7 +1150,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" dependencies = [ - "redox_syscall", + "redox_syscall 0.2.16", ] [[package]] @@ -1150,7 +1161,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall", + "redox_syscall 0.3.0", ] [[package]] @@ -1362,7 +1373,7 @@ checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" dependencies = [ "libc", "numtoa", - "redox_syscall", + "redox_syscall 0.2.16", "redox_termios", ] @@ -1501,7 +1512,7 @@ dependencies = [ "base64", "plain", "redox-daemon", - "redox_syscall", + "redox_syscall 0.3.0", "thiserror", "xhcid", ] @@ -1534,7 +1545,7 @@ dependencies = [ "orbclient", "redox-daemon", "redox_event", - "redox_syscall", + "redox_syscall 0.3.0", ] [[package]] @@ -1562,7 +1573,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox_syscall", + "redox_syscall 0.3.0", "rusttype", ] @@ -1704,7 +1715,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall", + "redox_syscall 0.3.0", "serde", "serde_json", "smallvec 1.9.0", diff --git a/Cargo.toml b/Cargo.toml index 48733bd4e9..8078a99e90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,4 +25,3 @@ members = [ mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.28" } -redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "userspace_fexec" } diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 0cdb909538..ccabe47a7b 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -14,5 +14,5 @@ parking_lot = "0.11.1" plain = "0.2.3" redox-daemon = "0.1" redox-log = "0.1.1" -redox_syscall = "0.2.16" +redox_syscall = "0.3" thiserror = "1" diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index f8eaa7afde..bb62d6da12 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -10,5 +10,5 @@ log = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "userspace_fexec" } +redox_syscall = "0.3" block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml index 4064bea456..4d1a83dce0 100644 --- a/alxd/Cargo.toml +++ b/alxd/Cargo.toml @@ -7,5 +7,5 @@ edition = "2018" bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.12" +redox_syscall = "0.3" redox-daemon = "0.1" diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml index f4ef93efa3..b5ff6b4d6b 100644 --- a/bgad/Cargo.toml +++ b/bgad/Cargo.toml @@ -6,4 +6,4 @@ edition = "2018" [dependencies] orbclient = "0.3.27" redox-daemon = "0.1" -redox_syscall = "0.2.12" +redox_syscall = "0.3" diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 4d558ff412..c7d5abaacd 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -8,4 +8,4 @@ bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.12" +redox_syscall = "0.3" diff --git a/ihdad/Cargo.toml b/ihdad/Cargo.toml index b43f31e321..f30d2fae70 100755 --- a/ihdad/Cargo.toml +++ b/ihdad/Cargo.toml @@ -9,5 +9,5 @@ log = "0.4" redox-daemon = "0.1" redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.12" +redox_syscall = "0.3" spin = "0.9" diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml index 73a9a39d47..1884d76457 100644 --- a/ixgbed/Cargo.toml +++ b/ixgbed/Cargo.toml @@ -6,5 +6,5 @@ version = "1.0.0" bitflags = "1.0" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.12" +redox_syscall = "0.3" redox-daemon = "0.1" diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index 1ce0b956b7..af7288f810 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -11,7 +11,7 @@ futures = "0.3" log = "0.4" redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.2.12" +redox_syscall = "0.3" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } smallvec = "1" block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 3be59750c2..20276cb043 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4" paw = "1.0" plain = "0.2" redox-log = "0.1" -redox_syscall = "0.2.12" +redox_syscall = "0.3" serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = "1" diff --git a/pcspkrd/Cargo.toml b/pcspkrd/Cargo.toml index 1d7b6ce8d9..7d2adf41d6 100644 --- a/pcspkrd/Cargo.toml +++ b/pcspkrd/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Tibor Nagy "] edition = "2018" [dependencies] -redox_syscall = "0.2.12" +redox_syscall = "0.3" redox-daemon = "0.1" diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index b6af7bbd37..ce05723671 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" [dependencies] bitflags = "1" orbclient = "0.3.27" -redox_syscall = "0.2.12" +redox_syscall = "0.3" redox-daemon = "0.1" diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index f0c3c47b5a..0bd706fa07 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -7,5 +7,5 @@ edition = "2018" bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.12" +redox_syscall = "0.3" redox-daemon = "0.1" diff --git a/usbscsid/Cargo.toml b/usbscsid/Cargo.toml index 1cc137ecad..a1ed05126f 100644 --- a/usbscsid/Cargo.toml +++ b/usbscsid/Cargo.toml @@ -11,6 +11,6 @@ license = "MIT" base64 = "0.11" # Only for debugging plain = "0.2" redox-daemon = "0.1" -redox_syscall = "0.2.12" +redox_syscall = "0.3" thiserror = "1" xhcid = { path = "../xhcid" } diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index 43cea1e68d..601f88ece6 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" [dependencies] orbclient = "0.3.27" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.2.12" +redox_syscall = "0.3" redox-daemon = "0.1" diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 8f4b457d3c..a77d65c2e6 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" orbclient = "0.3.27" ransid = "0.4" rusttype = { version = "0.2", optional = true } -redox_syscall = "0.2.12" +redox_syscall = "0.3" redox-daemon = "0.1" [features] diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index d9112921c3..a8d6a799f5 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -22,7 +22,7 @@ log = "0.4" redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox-log = "0.1" -redox_syscall = "0.2.12" +redox_syscall = "0.3" serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1", features = ["serde"] } From 7c1707c7de8be3584fc5f740fd63037d7acaa6b9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 23 Aug 2022 07:58:24 -0600 Subject: [PATCH 0502/1301] Ignore some ps2 init errors to improve compatibility --- ps2d/src/controller.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index b6bd05cf28..3fbe16ea1a 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -286,7 +286,7 @@ impl Ps2 { // Reset keyboard b = self.keyboard_command(KeyboardCommand::Reset)?; if b == 0xFA { - b = self.read()?; + b = self.read().unwrap_or(0); if b != 0xAA { eprintln!("ps2d: keyboard failed self test: {:02X}", b); } @@ -334,17 +334,17 @@ impl Ps2 { b = x.read()?; if b != 0xAA { eprintln!("ps2d: mouse failed self test 1: {:02X}", b); - return Err(Error::CommandRetry); + //return Err(Error::CommandRetry); } b = x.read()?; if b != 0x00 { eprintln!("ps2d: mouse failed self test 2: {:02X}", b); - return Err(Error::CommandRetry); + //return Err(Error::CommandRetry); } } else { eprintln!("ps2d: mouse failed to reset: {:02X}", b); - return Err(Error::CommandRetry); + //return Err(Error::CommandRetry); } // Clear remaining data From 8bbf1d8f5be1aec220b8471cc900465990d28da2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 27 Aug 2022 08:18:19 -0600 Subject: [PATCH 0503/1301] Fix typo in xhcid --- xhcid/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 82073e4741..e08891e4a9 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -114,7 +114,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option if msi_enabled && !msix_enabled { use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; - let mut capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI capability structure from pcid") { + let mut capability = match pcid_handle.feature_info(PciFeature::Msi).expect("xhcid: failed to retrieve the MSI capability structure from pcid") { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), }; From 86b065d724649ccd6f2d58bc6864753709d60da8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 27 Aug 2022 08:33:53 -0600 Subject: [PATCH 0504/1301] Allow boot to continue if HCI probe does not return --- xhcid/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index e08891e4a9..8e126abf58 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -276,6 +276,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { File::from_raw_fd(socket_fd as RawFd) })); + daemon.ready().expect("xhcid: failed to notify parent"); + let hci = Arc::new(Xhci::new(scheme_name, address, interrupt_method, pcid_handle).expect("xhcid: failed to allocate device")); xhci::start_irq_reactor(&hci, irq_file); futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe"); @@ -285,8 +287,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); - daemon.ready().expect("xhcid: failed to notify parent"); - let todo = Arc::new(Mutex::new(Vec::::new())); let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); From 83e7da750dd72ba754cf8df75d57b1316abe51ff Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 27 Aug 2022 17:16:15 -0600 Subject: [PATCH 0505/1301] Read actual BGA resolution when updating display resolution --- bgad/src/main.rs | 2 ++ bgad/src/scheme.rs | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/bgad/src/main.rs b/bgad/src/main.rs index f441acf75e..2d5387aeae 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -41,6 +41,8 @@ fn main() { display: File::open("display:input").ok() }; + scheme.update_size(); + syscall::setrens(0, 0).expect("bgad: failed to enter null namespace"); daemon.ready().expect("bgad: failed to notify parent"); diff --git a/bgad/src/scheme.rs b/bgad/src/scheme.rs index 061de83c03..3ae8c48e9d 100644 --- a/bgad/src/scheme.rs +++ b/bgad/src/scheme.rs @@ -11,6 +11,17 @@ pub struct BgaScheme { pub display: Option, } +impl BgaScheme { + pub fn update_size(&mut self) { + if let Some(ref mut display) = self.display { + let _ = display.write(&orbclient::ResizeEvent { + width: self.bga.width() as u32, + height: self.bga.height() as u32, + }.to_event()); + } + } +} + impl SchemeMut for BgaScheme { fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result { if uid == 0 { @@ -58,12 +69,7 @@ impl SchemeMut for BgaScheme { self.bga.set_size(width, height); - if let Some(ref mut display) = self.display { - let _ = display.write(&orbclient::ResizeEvent { - width: width as u32, - height: height as u32, - }.to_event()); - } + self.update_size(); Ok(buf.len()) } From 50338d9b24521b774bd5af2bc4eb59a18eb102e6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 30 Aug 2022 09:56:12 -0600 Subject: [PATCH 0506/1301] Remove unnecessary event queue from nvmed --- nvmed/src/main.rs | 54 ++++++++++++----------------------------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 9151a9791a..936587a6f1 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -321,31 +321,17 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { bar_size: bar_size as usize, ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"), }); - let event_fd = syscall::open("event:", syscall::O_RDWR | syscall::O_CLOEXEC) - .expect("nvmed: failed to open event queue"); - let mut event_file = unsafe { File::from_raw_fd(event_fd as RawFd) }; let scheme_name = format!("disk/{}", name); let socket_fd = syscall::open( &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK | syscall::O_CLOEXEC, + syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, ) .expect("nvmed: failed to create disk scheme"); + let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; daemon.ready().expect("nvmed: failed to signal readiness"); - syscall::write( - event_fd, - &syscall::Event { - id: socket_fd, - flags: syscall::EVENT_READ, - data: 0, - }, - ) - .expect("nvmed: failed to watch disk scheme events"); - - let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); let (interrupt_method, interrupt_sources) = get_int_method(&mut pcid_handle, &pci_config.func, &allocated_bars) @@ -362,32 +348,18 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); let mut todo = Vec::new(); - 'events: loop { - let mut event = Event::default(); - if event_file - .read(&mut event) - .expect("nvmed: failed to read event queue") - == 0 - { - break; - } - - match event.data { - 0 => loop { - let mut packet = Packet::default(); - match socket_file.read(&mut packet) { - Ok(0) => break 'events, - Ok(_) => (), - Err(err) => match err.kind() { - ErrorKind::WouldBlock => break, - _ => Err(err).expect("nvmed: failed to read disk scheme"), - }, - } - todo.push(packet); - }, - unknown => { - panic!("nvmed: unknown event data {}", unknown); + 'running: loop { + loop { + let mut packet = Packet::default(); + match socket_file.read(&mut packet) { + Ok(0) => break 'running, + Ok(_) => (), + Err(err) => match err.kind() { + ErrorKind::WouldBlock => break, + _ => Err(err).expect("nvmed: failed to read disk scheme"), + }, } + todo.push(packet); } let mut i = 0; From 3379a64258accbd09173fbe2cc2c04cff88a3f56 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 30 Aug 2022 10:15:26 -0600 Subject: [PATCH 0507/1301] Fix for last nvmed commit --- nvmed/src/main.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 936587a6f1..f966e1394a 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -348,18 +348,19 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); let mut todo = Vec::new(); - 'running: loop { - loop { - let mut packet = Packet::default(); - match socket_file.read(&mut packet) { - Ok(0) => break 'running, - Ok(_) => (), - Err(err) => match err.kind() { - ErrorKind::WouldBlock => break, - _ => Err(err).expect("nvmed: failed to read disk scheme"), - }, - } - todo.push(packet); + loop { + let mut packet = Packet::default(); + match socket_file.read(&mut packet) { + Ok(0) => { + break; + }, + Ok(_) => { + todo.push(packet); + }, + Err(err) => match err.kind() { + ErrorKind::WouldBlock => break, + _ => Err(err).expect("nvmed: failed to read disk scheme"), + }, } let mut i = 0; From b13bcf729a56d8df4348adfc1530acb062e1f9ad Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 30 Aug 2022 10:34:29 -0600 Subject: [PATCH 0508/1301] Update redox-syscall --- Cargo.lock | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3400b3bcc1..3188f1ea10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ dependencies = [ "plain", "redox-daemon", "redox-log", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", "thiserror", ] @@ -28,7 +28,7 @@ dependencies = [ "partitionlib", "redox-daemon", "redox-log", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", ] [[package]] @@ -39,7 +39,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", ] [[package]] @@ -109,7 +109,7 @@ version = "0.1.0" dependencies = [ "orbclient", "redox-daemon", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", ] [[package]] @@ -293,7 +293,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", ] [[package]] @@ -461,7 +461,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", "spin", ] @@ -497,7 +497,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", ] [[package]] @@ -705,7 +705,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", "smallvec 1.9.0", ] @@ -846,7 +846,7 @@ dependencies = [ "paw", "plain", "redox-log", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", "serde", "serde_json", "smallvec 1.9.0", @@ -860,7 +860,7 @@ name = "pcspkrd" version = "0.1.0" dependencies = [ "redox-daemon", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", ] [[package]] @@ -927,7 +927,7 @@ dependencies = [ "bitflags", "orbclient", "redox-daemon", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", ] [[package]] @@ -1123,7 +1123,7 @@ name = "redox_event" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/event.git#f7db3d25ca5e282c12ded12bf6c720087b570132" dependencies = [ - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", ] [[package]] @@ -1137,9 +1137,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.0" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8ce969b6629faa6f60a71f84022b0217e5ca8bcaeb6d11654506a55ebf8fed" +checksum = "4d6316cf50b21ea8976fb567d494235aec14c00acd96d2f4f45147d4d463bff4" dependencies = [ "bitflags", ] @@ -1161,7 +1161,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", ] [[package]] @@ -1512,7 +1512,7 @@ dependencies = [ "base64", "plain", "redox-daemon", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", "thiserror", "xhcid", ] @@ -1545,7 +1545,7 @@ dependencies = [ "orbclient", "redox-daemon", "redox_event", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", ] [[package]] @@ -1573,7 +1573,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", "rusttype", ] @@ -1715,7 +1715,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.0", + "redox_syscall 0.3.3", "serde", "serde_json", "smallvec 1.9.0", From 55526d6ab06eedef70b97d1dcbce867de6433876 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 30 Aug 2022 11:51:00 -0600 Subject: [PATCH 0509/1301] Do not set SGL flag, we only use PRP --- nvmed/src/nvme/cmd.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nvmed/src/nvme/cmd.rs b/nvmed/src/nvme/cmd.rs index 251fe0da5f..b3567d9923 100644 --- a/nvmed/src/nvme/cmd.rs +++ b/nvmed/src/nvme/cmd.rs @@ -127,7 +127,7 @@ impl NvmeCmd { pub fn io_read(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { Self { opcode: 2, - flags: 1 << 6, + flags: 0, cid, nsid, _rsvd: 0, @@ -145,7 +145,7 @@ impl NvmeCmd { pub fn io_write(cid: u16, nsid: u32, lba: u64, blocks_1: u16, ptr0: u64, ptr1: u64) -> Self { Self { opcode: 1, - flags: 1 << 6, + flags: 0, cid, nsid, _rsvd: 0, From efab53910ed993650df2b5efe4e2d3bda61e14cd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 30 Aug 2022 11:59:10 -0600 Subject: [PATCH 0510/1301] Return error on nvme completion status --- nvmed/src/nvme/mod.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 901b404cfe..5d3aae1e20 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -8,7 +8,7 @@ use std::sync::{Mutex, RwLock}; use crossbeam_channel::Sender; use smallvec::{smallvec, SmallVec}; -use syscall::error::{Error, Result, EINVAL}; +use syscall::error::{Error, Result, EINVAL, EIO}; use syscall::io::{Dma, Io, Mmio}; pub mod cmd; @@ -542,9 +542,13 @@ impl Nvme { NvmeCmd::io_read(cid, nsid, lba, blocks_1, ptr0, ptr1) } }); - // TODO: Handle errors - - Ok(()) + let status = comp.status >> 1; + if status == 0 { + Ok(()) + } else { + log::error!("command failed with status {:#x}", status); + Err(Error::new(EIO)) + } } pub fn namespace_read( From e70d6b7ffb7bc8ad8e736ed91b3ea836144d0bfa Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 31 Aug 2022 08:46:41 -0600 Subject: [PATCH 0511/1301] Update to redox_syscall 0.3.4 --- Cargo.lock | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3188f1ea10..51d1e927a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ dependencies = [ "plain", "redox-daemon", "redox-log", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", "thiserror", ] @@ -28,7 +28,7 @@ dependencies = [ "partitionlib", "redox-daemon", "redox-log", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", ] [[package]] @@ -39,7 +39,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", ] [[package]] @@ -109,7 +109,7 @@ version = "0.1.0" dependencies = [ "orbclient", "redox-daemon", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", ] [[package]] @@ -293,7 +293,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", ] [[package]] @@ -461,7 +461,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", "spin", ] @@ -497,7 +497,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", ] [[package]] @@ -705,7 +705,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", "smallvec 1.9.0", ] @@ -846,7 +846,7 @@ dependencies = [ "paw", "plain", "redox-log", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", "serde", "serde_json", "smallvec 1.9.0", @@ -860,7 +860,7 @@ name = "pcspkrd" version = "0.1.0" dependencies = [ "redox-daemon", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", ] [[package]] @@ -927,7 +927,7 @@ dependencies = [ "bitflags", "orbclient", "redox-daemon", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", ] [[package]] @@ -1123,7 +1123,7 @@ name = "redox_event" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/event.git#f7db3d25ca5e282c12ded12bf6c720087b570132" dependencies = [ - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", ] [[package]] @@ -1137,9 +1137,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d6316cf50b21ea8976fb567d494235aec14c00acd96d2f4f45147d4d463bff4" +checksum = "fb02a9aee8e8c7ad8d86890f1e16b49e0bbbffc9961ff3788c31d57c98bcbf03" dependencies = [ "bitflags", ] @@ -1161,7 +1161,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", ] [[package]] @@ -1512,7 +1512,7 @@ dependencies = [ "base64", "plain", "redox-daemon", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", "thiserror", "xhcid", ] @@ -1545,7 +1545,7 @@ dependencies = [ "orbclient", "redox-daemon", "redox_event", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", ] [[package]] @@ -1573,7 +1573,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", "rusttype", ] @@ -1715,7 +1715,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.3", + "redox_syscall 0.3.4", "serde", "serde_json", "smallvec 1.9.0", From 0e85c01ea3363ad5d3b30b12d2634a9cae6504d0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 31 Aug 2022 08:46:53 -0600 Subject: [PATCH 0512/1301] Implement 64-bit BARs --- nvmed/src/main.rs | 12 +++++++++-- pcid/src/pci/bar.rs | 19 ++++++++++++++--- pcid/src/pci/header.rs | 47 +++++++++++++++++++++++++++++------------- pcid/src/pci/msi.rs | 30 ++++++++++++++++++++------- xhcid/src/main.rs | 12 +++++++++-- 5 files changed, 91 insertions(+), 29 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index f966e1394a..f1b37f3c48 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -88,7 +88,11 @@ fn get_int_method( &mut Some(ref bar) => Ok(bar.ptr), bar_to_set @ &mut None => { let bar = match function.bars[bir] { - PciBar::Memory(addr) => match addr { + PciBar::Memory32(addr) => match addr { + 0 => panic!("BAR {} is mapped to address 0", bir), + _ => addr as u64, + }, + PciBar::Memory64(addr) => match addr { 0 => panic!("BAR {} is mapped to address 0", bir), _ => addr, }, @@ -292,7 +296,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("nvmed: failed to fetch config"); let bar = match pci_config.func.bars[0] { - PciBar::Memory(mem) => match mem { + PciBar::Memory32(mem) => match mem { + 0 => panic!("BAR 0 is mapped to address 0"), + _ => mem as u64, + }, + PciBar::Memory64(mem) => match mem { 0 => panic!("BAR 0 is mapped to address 0"), _ => mem, }, diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index 1ff92f9739..2698818f58 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -5,7 +5,8 @@ use serde::{Serialize, Deserialize}; #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum PciBar { None, - Memory(u32), + Memory32(u32), + Memory64(u64), Port(u16) } @@ -23,7 +24,18 @@ impl From for PciBar { if bar & 0xFFFFFFFC == 0 { PciBar::None } else if bar & 1 == 0 { - PciBar::Memory(bar & 0xFFFFFFF0) + match (bar >> 1) & 3 { + 0 => { + PciBar::Memory32(bar & 0xFFFFFFF0) + }, + 2 => { + PciBar::Memory64((bar & 0xFFFFFFF0) as u64) + }, + other => { + log::warn!("unsupported PCI memory type {}", other); + PciBar::None + }, + } } else { PciBar::Port((bar & 0xFFFC) as u16) } @@ -33,7 +45,8 @@ impl From for PciBar { impl fmt::Display for PciBar { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &PciBar::Memory(address) => write!(f, "{:>08X}", address), + &PciBar::Memory32(address) => write!(f, "{:>08X}", address), + &PciBar::Memory64(address) => write!(f, "{:>016X}", address), &PciBar::Port(address) => write!(f, "{:>04X}", address), &PciBar::None => write!(f, "None") } diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index 14d2a7b6ee..8fef60b9d0 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -91,6 +91,33 @@ pub enum PciHeader { } impl PciHeader { + fn get_bars(bytes: &[u8], bars: &mut [PciBar]) { + let mut i = 0; + while i < bars.len() { + let offset = i * 4; + let bar_bytes = match bytes.get(offset..offset + 4) { + Some(some) => some, + None => continue, + }; + + match PciBar::from(LittleEndian::read_u32(bar_bytes)) { + PciBar::Memory64(mut addr) => { + let high_bytes = match bytes.get(offset + 4..offset + 8) { + Some(some) => some, + None => continue, + }; + addr |= (LittleEndian::read_u32(high_bytes) as u64) << 32; + bars[i] = PciBar::Memory64(addr); + i += 2; + }, + bar => { + bars[i] = bar; + i += 1; + } + } + } + } + /// Parse the bytes found in the Configuration Space of the PCI device into /// a more usable PciHeader. pub fn from_reader(reader: T) -> Result { @@ -112,14 +139,8 @@ impl PciHeader { match header_type & PciHeaderType::HEADER_TYPE { PciHeaderType::GENERAL => { let bytes = unsafe { reader.read_range(16, 48) }; - let bars = [ - PciBar::from(LittleEndian::read_u32(&bytes[0..4])), - PciBar::from(LittleEndian::read_u32(&bytes[4..8])), - PciBar::from(LittleEndian::read_u32(&bytes[8..12])), - PciBar::from(LittleEndian::read_u32(&bytes[12..16])), - PciBar::from(LittleEndian::read_u32(&bytes[16..20])), - PciBar::from(LittleEndian::read_u32(&bytes[20..24])), - ]; + let mut bars = [PciBar::None; 6]; + Self::get_bars(&bytes, &mut bars); let cardbus_cis_ptr = LittleEndian::read_u32(&bytes[24..28]); let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]); let subsystem_id = LittleEndian::read_u16(&bytes[30..32]); @@ -139,10 +160,8 @@ impl PciHeader { }, PciHeaderType::PCITOPCI => { let bytes = unsafe { reader.read_range(16, 48) }; - let bars = [ - PciBar::from(LittleEndian::read_u32(&bytes[0..4])), - PciBar::from(LittleEndian::read_u32(&bytes[4..8])), - ]; + let mut bars = [PciBar::None; 2]; + Self::get_bars(&bytes, &mut bars); let primary_bus_num = bytes[8]; let secondary_bus_num = bytes[9]; let subordinate_bus_num = bytes[10]; @@ -323,10 +342,10 @@ mod test { assert_eq!(header.class(), PciClass::Network); assert_eq!(header.subclass(), 0); assert_eq!(header.bars().len(), 6); - assert_eq!(header.get_bar(0), PciBar::Memory(0xf7500000)); + assert_eq!(header.get_bar(0), PciBar::Memory32(0xf7500000)); assert_eq!(header.get_bar(1), PciBar::None); assert_eq!(header.get_bar(2), PciBar::Port(0xb000)); - assert_eq!(header.get_bar(3), PciBar::Memory(0xf7580000)); + assert_eq!(header.get_bar(3), PciBar::Memory32(0xf7580000)); assert_eq!(header.get_bar(4), PciBar::None); assert_eq!(header.get_bar(5), PciBar::None); assert_eq!(header.interrupt_line(), 10); diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index c8256389f5..fc8a25f4a3 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -291,10 +291,17 @@ impl MsixCapability { } let base = bars[usize::from(self.table_bir())]; - if let PciBar::Memory(ptr) = base { - ptr as usize + self.table_offset() as usize - } else { - panic!("MSI-X Table BIR referenced a non-memory BAR: {:?}", base); + //TODO: ensure type conversions are safe + match base { + PciBar::Memory32(ptr) => { + ptr as usize + self.table_offset() as usize + }, + PciBar::Memory64(ptr) => { + ptr as usize + self.table_offset() as usize + }, + _ => { + panic!("MSI-X Table BIR referenced a non-memory BAR: {:?}", base); + } } } pub fn table_pointer(&self, bars: [PciBar; 6], k: u16) -> usize { @@ -307,10 +314,17 @@ impl MsixCapability { } let base = bars[usize::from(self.pba_bir())]; - if let PciBar::Memory(ptr) = base { - ptr as usize + self.pba_offset() as usize - } else { - panic!("MSI-X PBA BIR referenced a non-memory BAR: {:?}", base); + //TODO: ensure type conversions are safe + match base { + PciBar::Memory32(ptr) => { + ptr as usize + self.pba_offset() as usize + }, + PciBar::Memory64(ptr) => { + ptr as usize + self.pba_offset() as usize + }, + _ => { + panic!("MSI-X PBA BIR referenced a non-memory BAR: {:?}", base); + } } } pub fn pba_pointer_dword(&self, bars: [PciBar; 6], k: u16) -> usize { diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 8e126abf58..b097aa2942 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -91,7 +91,11 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option let irq = pci_config.func.legacy_interrupt_line; let bar_ptr = match bar { - pcid_interface::PciBar::Memory(ptr) => match ptr { + pcid_interface::PciBar::Memory32(ptr) => match ptr { + 0 => panic!("BAR 0 is mapped to address 0"), + _ => ptr as u64, + }, + pcid_interface::PciBar::Memory64(ptr) => match ptr { 0 => panic!("BAR 0 is mapped to address 0"), _ => ptr, }, @@ -247,7 +251,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { name.push_str("_xhci"); let bar_ptr = match bar { - pcid_interface::PciBar::Memory(ptr) => match ptr { + pcid_interface::PciBar::Memory32(ptr) => match ptr { + 0 => panic!("BAR 0 is mapped to address 0"), + _ => ptr as u64, + }, + pcid_interface::PciBar::Memory64(ptr) => match ptr { 0 => panic!("BAR 0 is mapped to address 0"), _ => ptr, }, From 4bca3e55d306dfaf501aec0d47b651306a1ba832 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 31 Aug 2022 08:49:39 -0600 Subject: [PATCH 0513/1301] Fix xhcid compilation --- pcid/src/main.rs | 1 + xhcid/src/main.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index daff50513a..31f997afae 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -325,6 +325,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, }; // Find BAR sizes + //TODO: support 64-bit BAR sizes? let mut bars = [PciBar::None; 6]; let mut bar_sizes = [0; 6]; unsafe { diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index b097aa2942..6a8fc31ce9 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -87,7 +87,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); let bar = pci_config.func.bars[0]; - let bar_size = pci_config.func.bar_sizes[0]; + let bar_size = pci_config.func.bar_sizes[0] as u64; let irq = pci_config.func.legacy_interrupt_line; let bar_ptr = match bar { @@ -159,11 +159,11 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option let pba_base = capability.pba_base_pointer(pci_config.func.bars); - if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u32 + table_min_length as u32)) { + if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u64 + table_min_length as u64)) { panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); } - if !(bar_ptr..bar_ptr + bar_size).contains(&(pba_base as u32 + pba_min_length as u32)) { + if !(bar_ptr..bar_ptr + bar_size).contains(&(pba_base as u64 + pba_min_length as u64)) { panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size); } From fe13ea390a5f848b04dbfc472d86b698b4bef73f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 31 Aug 2022 10:53:21 -0600 Subject: [PATCH 0514/1301] Add feature for nvmed to not use reactor thread --- nvmed/Cargo.toml | 4 +++ nvmed/src/main.rs | 2 ++ nvmed/src/nvme/cq_reactor.rs | 2 +- nvmed/src/nvme/mod.rs | 64 ++++++++++++++++++++++++++++++++++++ nvmed/src/nvme/queues.rs | 16 +++++++-- 5 files changed, 84 insertions(+), 4 deletions(-) diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index af7288f810..f219f0100d 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -17,3 +17,7 @@ smallvec = "1" block-io-wrapper = { path = "../block-io-wrapper" } pcid = { path = "../pcid" } + +[features] +default = [] +async = [] diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index f1b37f3c48..6d11e209bb 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -349,6 +349,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { unsafe { nvme.init() } log::debug!("Finished base initialization"); let nvme = Arc::new(nvme); + #[cfg(feature = "async")] let reactor_thread = nvme::cq_reactor::start_cq_reactor_thread(Arc::clone(&nvme), interrupt_sources, reactor_receiver); let namespaces = nvme.init_with_queues(); @@ -386,6 +387,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } //TODO: destroy NVMe stuff + #[cfg(feature = "async")] reactor_thread.join().expect("nvmed: failed to join reactor thread"); std::process::exit(0); diff --git a/nvmed/src/nvme/cq_reactor.rs b/nvmed/src/nvme/cq_reactor.rs index 0e817ff4c0..5926684974 100644 --- a/nvmed/src/nvme/cq_reactor.rs +++ b/nvmed/src/nvme/cq_reactor.rs @@ -141,7 +141,7 @@ impl CqReactor { let mut completion_queue_guard = cqs_read_guard.get(&cq_id)?.lock().unwrap(); let &mut (ref mut completion_queue, _) = &mut *completion_queue_guard; - while let Some((head, entry)) = completion_queue.complete() { + while let Some((head, entry)) = completion_queue.complete(None) { unsafe { self.nvme.completion_queue_head(cq_id, head) }; log::trace!("Got completion queue entry (CQID {}): {:?} at {}", cq_id, entry, head); diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 5d3aae1e20..f21f478545 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -412,6 +412,70 @@ impl Nvme { self.set_vectors_masked(std::iter::once((vector, masked))) } + #[cfg(not(feature = "async"))] + pub fn submit_and_complete_command NvmeCmd>(&self, sq_id: SqId, cmd_init: F) -> NvmeComp { + // Submit command + let cmd = { + let sqs_read_guard = self.submission_queues.read().unwrap(); + let &(ref sq_lock, cq_id) = sqs_read_guard + .get(&sq_id) + .expect("nvmed: internal error: given SQ for SQ ID not there"); + let mut sq_guard = sq_lock.lock().unwrap(); + let sq = &mut *sq_guard; + + assert!(!sq.is_full()); + + let cmd_id = + u16::try_from(sq.tail).expect("nvmed: internal error: CQ has more than 2^16 entries"); + let cmd = cmd_init(cmd_id); + log::trace!("Sent submission queue entry (SQID {}): {:?} at {}", sq_id, cmd, cmd_id); + let tail = sq.submit_unchecked(cmd); + let tail = u16::try_from(tail).unwrap(); + + // make sure that we register interest before the reactor can get notified + unsafe { self.submission_queue_tail(sq_id, tail) }; + + cmd + }; + + // Read completion + loop { + for (cq_id, completion_queue_lock) in self.completion_queues.read().unwrap().iter() { + if *cq_id != sq_id { + // Currently, CQ and SQ IDs have to match + continue; + } + + let mut completion_queue_guard = completion_queue_lock.lock().unwrap(); + let &mut (ref mut completion_queue, _) = &mut *completion_queue_guard; + + while let Some((head, entry)) = completion_queue.complete(Some((sq_id, cmd))) { + unsafe { self.completion_queue_head(*cq_id, head) }; + + log::trace!("Got completion queue entry (CQID {}): {:?} at {}", cq_id, entry, head); + + assert_eq!(sq_id, entry.sq_id); + assert_eq!(cmd.cid, entry.cid); + + { + let submission_queues_read_lock = self.submission_queues.read().unwrap(); + // this lock is actually important, since it will block during submission from other + // threads. the lock won't be held for long by the submitters, but it still prevents + // the entry being lost before this reactor is actually able to respond: + let &(ref sq_lock, corresponding_cq_id) = submission_queues_read_lock.get(&{entry.sq_id}).expect("nvmed: internal error: queue returned from controller doesn't exist"); + assert_eq!(*cq_id, corresponding_cq_id); + let mut sq_guard = sq_lock.lock().unwrap(); + sq_guard.head = entry.sq_head; + } + + return entry; + } + } + unsafe { pause(); } + } + } + + #[cfg(feature = "async")] pub fn submit_and_complete_command NvmeCmd>(&self, sq_id: SqId, cmd_init: F) -> NvmeComp { use crate::nvme::cq_reactor::{CompletionFuture, CompletionFutureState}; futures::executor::block_on( diff --git a/nvmed/src/nvme/queues.rs b/nvmed/src/nvme/queues.rs index dfd0e6871f..7e06373efa 100644 --- a/nvmed/src/nvme/queues.rs +++ b/nvmed/src/nvme/queues.rs @@ -62,8 +62,18 @@ impl NvmeCompQueue { } /// Get a new completion queue entry, or return None if no entry is available yet. - pub(crate) fn complete(&mut self) -> Option<(u16, NvmeComp)> { + pub(crate) fn complete(&mut self, cmd_opt: Option<(u16, NvmeCmd)>) -> Option<(u16, NvmeComp)> { let entry = unsafe { ptr::read_volatile(self.data.as_ptr().add(self.head as usize)) }; + + //HACK FOR SOMETIMES RETURNING INVALID DATA ON QEMU! + if let Some((sq_id, cmd)) = cmd_opt { + if entry.sq_id != sq_id + || entry.cid != cmd.cid + { + return None; + } + } + if ((entry.status & 1) == 1) == self.phase { self.head = (self.head + 1) % (self.data.len() as u16); if self.head == 0 { @@ -76,10 +86,10 @@ impl NvmeCompQueue { } /// Get a new CQ entry, busy waiting until an entry appears. - fn complete_spin(&mut self) -> (u16, NvmeComp) { + fn complete_spin(&mut self, cmd_opt: Option<(u16, NvmeCmd)>) -> (u16, NvmeComp) { log::debug!("Waiting for new CQ entry"); loop { - if let Some(some) = self.complete() { + if let Some(some) = self.complete(cmd_opt) { return some; } else { unsafe { super::pause(); } From c848aba481825f458fbf25e59eb0a5a34fd44844 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 31 Aug 2022 17:44:59 -0600 Subject: [PATCH 0515/1301] USB HID report debug --- usbhidd/src/main.rs | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 72edaeed38..b28149d01d 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -305,7 +305,8 @@ fn main() { let (mut global_state, mut local_state, mut stack) = (GlobalItemsState::default(), LocalItemsState::default(), Vec::new()); - let (_, application_collection, application_global_state, application_local_state) = report_desc.iter().filter_map(|item: &ReportIterItem| + let (_, application_collection, application_global_state, application_local_state) = report_desc.iter().filter_map(|item: &ReportIterItem| { + println!("1: {:?}", item); match item { &ReportIterItem::Item(ref item) => { report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); @@ -317,26 +318,36 @@ fn main() { Some((n, collection, global_state, lc_state)) } } - ).find(|&(n, _, _, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection"); + }).find(|&(n, _, _, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection"); // Get all main items, and their global item options. { - let items = application_collection.iter().filter_map(ReportIterItem::as_item).filter_map(|item| match item { - ReportItem::Global(_) => { - report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); - None + let items = application_collection.iter().filter_map(|item| { + println!("2: {:?}", item); + match item { + ReportIterItem::Item(ref item) => match item { + ReportItem::Global(_) => { + report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); + None + } + ReportItem::Main(m) => { + let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default()); + Some((global_state, lc_state, m)) + } + ReportItem::Local(_) => { + report_desc::update_local_state(&mut local_state, item); + None + }, + }, + //TODO + _ => { + None + } } - ReportItem::Main(m) => { - let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default()); - Some((global_state, lc_state, m)) - } - ReportItem::Local(_) => { - report_desc::update_local_state(&mut local_state, item); - None - }, }); let mut bit_offset = 0; let inputs = items.filter_map(|(global_state, local_state, item)| { + println!("3: {:?}", item); let report_size = match global_state.report_size { Some(s) => s, None => return None, From 83779b1b5bf73e5f99a82f5057d6b92b5ac80437 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 31 Aug 2022 18:44:18 -0600 Subject: [PATCH 0516/1301] Implement simple usb mouse driver --- usbhidd/src/main.rs | 143 ++++++++++++++++++++++++++++++++------------ 1 file changed, 106 insertions(+), 37 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index b28149d01d..b3a9e1b177 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -1,3 +1,4 @@ +use std::collections::VecDeque; use std::env; use std::fs::File; use std::io::Write; @@ -306,7 +307,7 @@ fn main() { let (mut global_state, mut local_state, mut stack) = (GlobalItemsState::default(), LocalItemsState::default(), Vec::new()); let (_, application_collection, application_global_state, application_local_state) = report_desc.iter().filter_map(|item: &ReportIterItem| { - println!("1: {:?}", item); + log::trace!("1: {:?}", item); match item { &ReportIterItem::Item(ref item) => { report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); @@ -322,32 +323,35 @@ fn main() { // Get all main items, and their global item options. { - let items = application_collection.iter().filter_map(|item| { - println!("2: {:?}", item); - match item { - ReportIterItem::Item(ref item) => match item { - ReportItem::Global(_) => { - report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); - None - } - ReportItem::Main(m) => { - let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default()); - Some((global_state, lc_state, m)) - } - ReportItem::Local(_) => { - report_desc::update_local_state(&mut local_state, item); - None + let mut collections = VecDeque::new(); + collections.push_back(application_collection); + let mut items = Vec::new(); + while let Some(collection) = collections.pop_front() { + for item in collection { + log::trace!("2: {:?}", item); + match item { + ReportIterItem::Item(item) => match item { + ReportItem::Global(_) => { + report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); + } + ReportItem::Main(m) => { + let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default()); + items.push((global_state, lc_state, m)); + } + ReportItem::Local(_) => { + report_desc::update_local_state(&mut local_state, item); + }, + }, + //TODO: does local state need to be different for inner collections? + ReportIterItem::Collection(_, collection) => { + collections.push_back(collection); }, - }, - //TODO - _ => { - None } } - }); + } let mut bit_offset = 0; - let inputs = items.filter_map(|(global_state, local_state, item)| { - println!("3: {:?}", item); + let inputs = items.iter().filter_map(|(global_state, local_state, item)| { + log::trace!("3: {:?}", item); let report_size = match global_state.report_size { Some(s) => s, None => return None, @@ -356,17 +360,24 @@ fn main() { Some(c) => c, None => return None, }; - if global_state.usage_page != Some(0x7) { - log::warn!("Unsupported usage page: {:#x?}", global_state.usage_page); - return None; - } + let bit_length = report_size * report_count; let offset = bit_offset; bit_offset += bit_length; + match global_state.usage_page { + Some(1) => (), + Some(7) => (), + Some(9) => (), + _ => { + log::warn!("Unsupported usage page: {:?}", global_state.usage_page); + return None; + } + } + if let &MainItem::Input(flags) = item { - Some((bit_length, offset, global_state, local_state, MainItemFlags::from_bits_truncate(flags))) + Some((bit_length, offset, global_state, local_state, MainItemFlags::from_bits_truncate(*flags))) } else { None } @@ -384,6 +395,7 @@ fn main() { let mut pressed_keys = Vec::::new(); let mut last_pressed_keys = pressed_keys.clone(); + let mut last_buttons = (false, false, false); loop { std::thread::sleep(std::time::Duration::from_millis(10)); @@ -413,7 +425,7 @@ fn main() { let binary_view = BinaryView::new(&report_buffer, bit_offset as usize, bit_length as usize); - if report_count == 8 && report_size == 1 && local_state.usage_min == Some(224) && local_state.usage_max == Some(231) && global_state.logical_min == Some(0) && global_state.logical_max == Some(1) { + if report_count == 8 && report_size == 1 && global_state.usage_page == Some(7) && local_state.usage_min == Some(224) && local_state.usage_max == Some(231) && global_state.logical_min == Some(0) && global_state.logical_max == Some(1) { let bits = binary_view.read_u8(0).expect("Failed to read array item"); for bit in 0..8 { if bits & (1 << bit) > 0 { @@ -421,21 +433,78 @@ fn main() { } } log::trace!("Report variable {:#x?}", bits); + } else if report_count == 3 && report_size == 8 && global_state.usage_page == Some(1) { + //TODO: Make this less hard-coded + let vx = binary_view.read_u8(0).expect("Failed to read array item") as i8; + let vy = binary_view.read_u8(8).expect("Failed to read array item") as i8; + let vz = binary_view.read_u8(16).expect("Failed to read array item") as i8; + log::trace!("Mouse {}, {}, {}", vx, vy, vz); + if vx != 0 || vy != 0 { + let mouse_event = orbclient::event::MouseRelativeEvent { + dx: vx as i32, + dy: vy as i32, + }; + + match orbital_socket.write(&mouse_event.to_event()) { + Ok(_) => (), + Err(err) => { + log::warn!("failed to send mouse event to orbital: {}", err); + } + } + } + if vz != 0 { + let scroll_event = orbclient::event::ScrollEvent { + x: vz as i32, + y: 0, + }; + + match orbital_socket.write(&scroll_event.to_event()) { + Ok(_) => (), + Err(err) => { + log::warn!("failed to send scroll event to orbital: {}", err); + } + } + } + } else if report_count == 3 && report_size == 1 && global_state.usage_page == Some(9) { + //TODO: Make this less hard-coded + let left = binary_view.get(0).expect("Failed to read array item"); + let right = binary_view.get(1).expect("Failed to read array item"); + let middle = binary_view.get(2).expect("Failed to read array item"); + log::trace!("Left {}, Right {}, Middle {}", left, right, middle); + if last_buttons != (left, right, middle) { + last_buttons = (left, right, middle); + + let button_event = orbclient::event::ButtonEvent { + left, + right, + middle, + }; + + match orbital_socket.write(&button_event.to_event()) { + Ok(_) => (), + Err(err) => { + log::warn!("failed to send button event to orbital: {}", err); + } + } + } } else { - log::warn!("unknown report variable item"); + log::trace!("Unknown report variable item: size {} count {} at {}", report_size, report_count, bit_offset); } } else { // The item is an array. log::trace!("INPUT FLAGS: {:?}", input); - assert_eq!(report_size, 8); - for report_index in 0..report_count as usize { - let binary_view = BinaryView::new(&report_buffer, bit_offset as usize + report_index * report_size as usize, report_size as usize); - let usage = binary_view.read_u8(0).expect("Failed to read array item"); - if usage != 0 { - pressed_keys.push(usage); + if report_size == 8 { + for report_index in 0..report_count as usize { + let binary_view = BinaryView::new(&report_buffer, bit_offset as usize + report_index * report_size as usize, report_size as usize); + let usage = binary_view.read_u8(0).expect("Failed to read array item"); + if usage != 0 { + pressed_keys.push(usage); + } + log::trace!("Report index array {}: {:#x}", report_index, usage); } - log::trace!("Report index array {}: {:#x}", report_index, usage); + } else { + log::trace!("Unknown report array item: size {} count {} at {}", report_size, report_count, bit_offset); } } } From ecb53b977daf35b51be5e224dcf5f383b3674b07 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 31 Aug 2022 21:15:13 -0600 Subject: [PATCH 0517/1301] QEMU USB touchscreen support --- Cargo.lock | 1 + usbhidd/Cargo.toml | 1 + usbhidd/src/main.rs | 80 +++++++++++++++++++++++++++++++++------------ 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 51d1e927a2..d39c4a73a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1501,6 +1501,7 @@ dependencies = [ "log", "orbclient", "redox-log", + "redox_syscall 0.3.4", "ux", "xhcid", ] diff --git a/usbhidd/Cargo.toml b/usbhidd/Cargo.toml index 4cf1d27770..77b9adfdb5 100644 --- a/usbhidd/Cargo.toml +++ b/usbhidd/Cargo.toml @@ -12,5 +12,6 @@ bitflags = "1.2" log = "0.4" orbclient = "0.3.27" redox-log = "0.1" +redox_syscall = "0.3" ux = "0.1" xhcid = { path = "../xhcid" } diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index b3a9e1b177..2e2c7e409e 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -2,6 +2,7 @@ use std::collections::VecDeque; use std::env; use std::fs::File; use std::io::Write; +use std::os::unix::io::AsRawFd; use bitflags::bitflags; use orbclient::KeyEvent as OrbKeyEvent; @@ -108,7 +109,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } } -fn send_key_event(orbital_socket: &mut File, usage_page: u32, usage: u8, pressed: bool, shift_opt: Option) { +fn send_key_event(display: &mut File, usage_page: u32, usage: u8, pressed: bool, shift_opt: Option) { let scancode = match usage_page { 0x07 => match usage { 0x04 => orbclient::K_A, @@ -215,7 +216,7 @@ fn send_key_event(orbital_socket: &mut File, usage_page: u32, usage: u8, pressed 0xE0 => orbclient::K_CTRL, // TODO: left control 0xE1 => orbclient::K_LEFT_SHIFT, 0xE2 => orbclient::K_ALT, - // 0xE3 left super + 0xE3 => 0x5B, // left super 0xE4 => orbclient::K_CTRL, // TODO: right control 0xE5 => orbclient::K_RIGHT_SHIFT, 0xE6 => orbclient::K_ALT_GR, @@ -245,7 +246,7 @@ fn send_key_event(orbital_socket: &mut File, usage_page: u32, usage: u8, pressed pressed, }; - match orbital_socket.write(&key_event.to_event()) { + match display.write(&key_event.to_event()) { Ok(_) => (), Err(err) => { log::warn!("failed to send key event to orbital: {}", err); @@ -391,7 +392,20 @@ fn main() { let report_ty = ReportTy::Input; let report_id = 0; - let mut orbital_socket = File::open("display:input").expect("Failed to open orbital input socket"); + let mut display = File::open("display:input").expect("Failed to open orbital input socket"); + + //TODO: get dynamically + let mut display_width = 0; + let mut display_height = 0; + { + let mut buf = [0; 4096]; + if let Ok(count) = syscall::fpath(display.as_raw_fd() as usize, &mut buf) { + let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; + let res = path.split(":").nth(1).unwrap_or(""); + display_width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); + display_height = res.split("/").nth(2).unwrap_or("").parse::().unwrap_or(0); + } + } let mut pressed_keys = Vec::::new(); let mut last_pressed_keys = pressed_keys.clone(); @@ -433,32 +447,58 @@ fn main() { } } log::trace!("Report variable {:#x?}", bits); - } else if report_count == 3 && report_size == 8 && global_state.usage_page == Some(1) { + } else if report_count == 2 && report_size == 16 && global_state.usage_page == Some(1) { //TODO: Make this less hard-coded - let vx = binary_view.read_u8(0).expect("Failed to read array item") as i8; - let vy = binary_view.read_u8(8).expect("Failed to read array item") as i8; - let vz = binary_view.read_u8(16).expect("Failed to read array item") as i8; - log::trace!("Mouse {}, {}, {}", vx, vy, vz); - if vx != 0 || vy != 0 { - let mouse_event = orbclient::event::MouseRelativeEvent { - dx: vx as i32, - dy: vy as i32, + let raw_x = + binary_view.read_u8(0).expect("Failed to read array item") as u16 | + (binary_view.read_u8(8).expect("Failed to read array item") as u16) << 8; + let raw_y = + binary_view.read_u8(16).expect("Failed to read array item") as u16 | + (binary_view.read_u8(24).expect("Failed to read array item") as u16) << 8; + + let x = ((raw_x as u32) * display_width) / 32767; + let y = ((raw_y as u32) * display_height) / 32767; + + log::trace!("Touchscreen {}, {} => {}, {}", raw_x, raw_y, x, y); + if x != 0 || y != 0 { + let mouse_event = orbclient::event::MouseEvent { + x: x as i32, + y: y as i32, }; - match orbital_socket.write(&mouse_event.to_event()) { + match display.write(&mouse_event.to_event()) { Ok(_) => (), Err(err) => { log::warn!("failed to send mouse event to orbital: {}", err); } } } - if vz != 0 { + } else if report_count == 3 && report_size == 8 && global_state.usage_page == Some(1) { + //TODO: Make this less hard-coded + let dx = binary_view.read_u8(0).expect("Failed to read array item") as i8; + let dy = binary_view.read_u8(8).expect("Failed to read array item") as i8; + let dz = binary_view.read_u8(16).expect("Failed to read array item") as i8; + log::trace!("Mouse {}, {}, {}", dx, dy, dz); + if dx != 0 || dy != 0 { + let mouse_event = orbclient::event::MouseRelativeEvent { + dx: dx as i32, + dy: dy as i32, + }; + + match display.write(&mouse_event.to_event()) { + Ok(_) => (), + Err(err) => { + log::warn!("failed to send mouse event to orbital: {}", err); + } + } + } + if dz != 0 { let scroll_event = orbclient::event::ScrollEvent { - x: vz as i32, + x: dz as i32, y: 0, }; - match orbital_socket.write(&scroll_event.to_event()) { + match display.write(&scroll_event.to_event()) { Ok(_) => (), Err(err) => { log::warn!("failed to send scroll event to orbital: {}", err); @@ -480,7 +520,7 @@ fn main() { middle, }; - match orbital_socket.write(&button_event.to_event()) { + match display.write(&button_event.to_event()) { Ok(_) => (), Err(err) => { log::warn!("failed to send button event to orbital: {}", err); @@ -513,14 +553,14 @@ fn main() { for usage in last_pressed_keys.iter() { if ! pressed_keys.contains(usage) { log::debug!("Released {:#x}", usage); - send_key_event(&mut orbital_socket, global_state.usage_page.unwrap_or(0), *usage, false, None); + send_key_event(&mut display, global_state.usage_page.unwrap_or(0), *usage, false, None); } } for usage in pressed_keys.iter() { if ! last_pressed_keys.contains(usage) { log::debug!("Pressed {:#x}", usage); - send_key_event(&mut orbital_socket, global_state.usage_page.unwrap_or(0), *usage, true, Some( + send_key_event(&mut display, global_state.usage_page.unwrap_or(0), *usage, true, Some( pressed_keys.contains(&0xE1) || pressed_keys.contains(&0xE5) )); } From c68aaac16cc4bdd33b274e43d806be268347bdeb Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 1 Sep 2022 08:01:24 -0600 Subject: [PATCH 0518/1301] Improvements for USB keyboard --- usbhidd/src/main.rs | 68 ++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 35 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 2e2c7e409e..045bb8316d 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -353,31 +353,21 @@ fn main() { let mut bit_offset = 0; let inputs = items.iter().filter_map(|(global_state, local_state, item)| { log::trace!("3: {:?}", item); - let report_size = match global_state.report_size { - Some(s) => s, - None => return None, - }; - let report_count = match global_state.report_count { - Some(c) => c, - None => return None, - }; - - let bit_length = report_size * report_count; - - let offset = bit_offset; - bit_offset += bit_length; - - match global_state.usage_page { - Some(1) => (), - Some(7) => (), - Some(9) => (), - _ => { - log::warn!("Unsupported usage page: {:?}", global_state.usage_page); - return None; - } - } if let &MainItem::Input(flags) = item { + let report_size = match global_state.report_size { + Some(s) => s, + None => return None, + }; + let report_count = match global_state.report_count { + Some(c) => c, + None => return None, + }; + + let bit_length = report_size * report_count; + let offset = bit_offset; + bit_offset += bit_length; + Some((bit_length, offset, global_state, local_state, MainItemFlags::from_bits_truncate(*flags))) } else { None @@ -407,7 +397,7 @@ fn main() { } } - let mut pressed_keys = Vec::::new(); + let mut pressed_keys = Vec::<(u32, u8)>::new(); let mut last_pressed_keys = pressed_keys.clone(); let mut last_buttons = (false, false, false); @@ -425,6 +415,14 @@ fn main() { let report_size = global_state.report_size.unwrap(); let report_count = global_state.report_count.unwrap(); + log::trace!( + "size {} count {} at {} length {}", + report_size, + report_count, + bit_offset, + bit_length + ); + // TODO: For now, the dynamic value usages cannot overlap with selector usages... // for now. @@ -443,7 +441,7 @@ fn main() { let bits = binary_view.read_u8(0).expect("Failed to read array item"); for bit in 0..8 { if bits & (1 << bit) > 0 { - pressed_keys.push(0xE0 + bit); + pressed_keys.push((0x07, 0xE0 + bit)); } } log::trace!("Report variable {:#x?}", bits); @@ -539,7 +537,7 @@ fn main() { let binary_view = BinaryView::new(&report_buffer, bit_offset as usize + report_index * report_size as usize, report_size as usize); let usage = binary_view.read_u8(0).expect("Failed to read array item"); if usage != 0 { - pressed_keys.push(usage); + pressed_keys.push((global_state.usage_page.unwrap_or(0), usage)); } log::trace!("Report index array {}: {:#x}", report_index, usage); } @@ -550,18 +548,18 @@ fn main() { } - for usage in last_pressed_keys.iter() { - if ! pressed_keys.contains(usage) { - log::debug!("Released {:#x}", usage); - send_key_event(&mut display, global_state.usage_page.unwrap_or(0), *usage, false, None); + for &(usage_page, usage) in last_pressed_keys.iter() { + if ! pressed_keys.contains(&(usage_page, usage)) { + log::debug!("Released {:#x},{:#x}", usage_page, usage); + send_key_event(&mut display, usage_page, usage, false, None); } } - for usage in pressed_keys.iter() { - if ! last_pressed_keys.contains(usage) { - log::debug!("Pressed {:#x}", usage); - send_key_event(&mut display, global_state.usage_page.unwrap_or(0), *usage, true, Some( - pressed_keys.contains(&0xE1) || pressed_keys.contains(&0xE5) + for &(usage_page, usage) in pressed_keys.iter() { + if ! last_pressed_keys.contains(&(usage_page, usage)) { + log::debug!("Pressed {:#x},{:#x}", usage_page, usage); + send_key_event(&mut display, usage_page, usage, true, Some( + pressed_keys.contains(&(0x07, 0xE1)) || pressed_keys.contains(&(0x07, 0xE5)) )); } } From 988cb5c0664aa94f9703ca2c6031086dc6a22587 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 2 Sep 2022 11:24:35 -0600 Subject: [PATCH 0519/1301] xhcid: fix polling mode --- xhcid/src/xhci/irq_reactor.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 9989da87e5..3a073eca39 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -122,9 +122,11 @@ impl IrqReactor { if trb.completion_code() == TrbCompletionCode::Invalid as u8 { self.pause(); - continue 'busy_waiting; + } else { + break; } } + if self.check_event_ring_full(trb.clone()) { continue 'event_loop } self.handle_requests(); From fc8ef508a5c47baa59b1d60d206de26fbe8260a5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 2 Sep 2022 11:32:38 -0600 Subject: [PATCH 0520/1301] xhcid: Make polling mode code match normal irq code --- xhcid/src/xhci/irq_reactor.rs | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 3a073eca39..6a2250dbba 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -110,29 +110,35 @@ impl IrqReactor { debug!("Running IRQ reactor in polling mode."); let hci_clone = Arc::clone(&self.hci); - 'event_loop: loop { - let mut event_ring_guard = hci_clone.primary_event_ring.lock().unwrap(); + let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() }; - let index = event_ring_guard.ring.next_index(); + 'trb_loop: loop { + self.pause(); - let mut trb; + let mut event_ring = hci_clone.primary_event_ring.lock().unwrap(); - 'busy_waiting: loop { - trb = &event_ring_guard.ring.trbs[index]; + let event_trb = &mut event_ring.ring.trbs[event_trb_index]; - if trb.completion_code() == TrbCompletionCode::Invalid as u8 { - self.pause(); - } else { - break; - } + if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { + continue 'trb_loop; } - if self.check_event_ring_full(trb.clone()) { continue 'event_loop } + trace!("Found event TRB: {:?}", event_trb); + + if self.check_event_ring_full(event_trb.clone()) { + info!("Had to resize event TRB, retrying..."); + hci_clone.event_handler_finished(); + continue 'trb_loop; + } self.handle_requests(); - self.acknowledge(trb.clone()); + self.acknowledge(event_trb.clone()); - self.update_erdp(&*event_ring_guard); + event_trb.reserved(false); + + self.update_erdp(&*event_ring); + + event_trb_index = event_ring.ring.next_index(); } } fn run_with_irq_file(mut self) { From 3ed83c74cf75a3f0720f35397aedab237d74dff1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 7 Sep 2022 12:01:15 -0600 Subject: [PATCH 0521/1301] Workaround for real hardware prp issue --- nvmed/src/nvme/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index f21f478545..c76673541e 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -599,18 +599,20 @@ impl Nvme { (buffer_prp_guard[0], (buffer_prp_guard.physical() + 8) as u64) }; + let mut cmd = NvmeCmd::default(); let comp = self.submit_and_complete_command(1, |cid| { - if write { + cmd = if write { NvmeCmd::io_write(cid, nsid, lba, blocks_1, ptr0, ptr1) } else { NvmeCmd::io_read(cid, nsid, lba, blocks_1, ptr0, ptr1) - } + }; + cmd.clone() }); let status = comp.status >> 1; if status == 0 { Ok(()) } else { - log::error!("command failed with status {:#x}", status); + log::error!("command {:#x?} failed with status {:#x}", cmd, status); Err(Error::new(EIO)) } } @@ -626,7 +628,7 @@ impl Nvme { let buffer_guard = self.buffer.lock().unwrap(); - for chunk in buf.chunks_mut(buffer_guard.len()) { + for chunk in buf.chunks_mut(/*TODO: buffer_guard.len()*/ 8192) { let blocks = (chunk.len() + block_size - 1) / block_size; assert!(blocks > 0); @@ -653,7 +655,7 @@ impl Nvme { let mut buffer_guard = self.buffer.lock().unwrap(); - for chunk in buf.chunks(buffer_guard.len()) { + for chunk in buf.chunks(/*TODO: buffer_guard.len()*/ 8192) { let blocks = (chunk.len() + block_size - 1) / block_size; assert!(blocks > 0); From e2a8255547a9fa7be888d4e3ad3ca41532c90291 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 7 Sep 2022 12:15:41 -0600 Subject: [PATCH 0522/1301] Allow reading PCI header through pcid socket --- pcid/src/driver_interface/mod.rs | 11 ++++++++++- pcid/src/main.rs | 3 +++ pcid/src/pci/class.rs | 4 +++- pcid/src/pci/header.rs | 6 ++++-- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 0b0a5c1009..aedbf86f77 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -7,7 +7,7 @@ use std::os::unix::io::{FromRawFd, RawFd}; use serde::{Serialize, Deserialize, de::DeserializeOwned}; use thiserror::Error; -pub use crate::pci::PciBar; +pub use crate::pci::{PciBar, PciHeader}; pub use crate::pci::msi; pub mod irq_helpers; @@ -169,6 +169,7 @@ pub enum SetFeatureInfo { #[non_exhaustive] pub enum PcidClientRequest { RequestConfig, + RequestHeader, RequestFeatures, EnableFeature(PciFeature), FeatureStatus(PciFeature), @@ -187,6 +188,7 @@ pub enum PcidServerResponseError { #[non_exhaustive] pub enum PcidClientResponse { Config(SubdriverArguments), + Header(PciHeader), AllFeatures(Vec<(PciFeature, FeatureStatus)>), FeatureEnabled(PciFeature), FeatureStatus(PciFeature, FeatureStatus), @@ -252,6 +254,13 @@ impl PcidServerHandle { other => Err(PcidClientHandleError::InvalidResponse(other)), } } + pub fn fetch_header(&mut self) -> Result { + self.send(&PcidClientRequest::RequestHeader)?; + match self.recv()? { + PcidClientResponse::Header(a) => Ok(a), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } pub fn fetch_all_features(&mut self) -> Result> { self.send(&PcidClientRequest::RequestFeatures)?; match self.recv()? { diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 31f997afae..3dee0e8963 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -68,6 +68,9 @@ impl DriverHandler { PcidClientRequest::RequestConfig => { PcidClientResponse::Config(args.clone()) } + PcidClientRequest::RequestHeader => { + PcidClientResponse::Header(self.header.clone()) + } PcidClientRequest::RequestFeatures => { PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability { PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))), diff --git a/pcid/src/pci/class.rs b/pcid/src/pci/class.rs index 98c503c2b3..042c354df0 100644 --- a/pcid/src/pci/class.rs +++ b/pcid/src/pci/class.rs @@ -1,4 +1,6 @@ -#[derive(Clone, Copy, Debug, PartialEq)] +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum PciClass { Legacy, Storage, diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index 8fef60b9d0..6139c45bb9 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -1,9 +1,10 @@ +use bitflags::bitflags; use byteorder::{LittleEndian, ByteOrder}; +use serde::{Serialize, Deserialize}; use super::func::ConfigReader; use super::class::PciClass; use super::bar::PciBar; -use bitflags::bitflags; #[derive(Debug, PartialEq)] pub enum PciHeaderError { @@ -13,6 +14,7 @@ pub enum PciHeaderError { bitflags! { /// Flags found in the status register of a PCI device + #[derive(Serialize, Deserialize)] pub struct PciHeaderType: u8 { /// A general PCI device (Type 0x01). const GENERAL = 0b00000000; @@ -27,7 +29,7 @@ bitflags! { } } -#[derive(Clone, Copy, Debug, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum PciHeader { General { vendor_id: u16, From 41217ad6fa4c1ee51fd0793a1fe1a3919ff006a6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 7 Sep 2022 12:16:16 -0600 Subject: [PATCH 0523/1301] Add ided stub --- Cargo.lock | 11 +++++++++ Cargo.toml | 1 + ided/.gitignore | 1 + ided/Cargo.toml | 11 +++++++++ ided/src/main.rs | 63 ++++++++++++++++++++++++++++++++++++++++++++++++ initfs.toml | 8 ++++++ 6 files changed, 95 insertions(+) create mode 100644 ided/.gitignore create mode 100644 ided/Cargo.toml create mode 100644 ided/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index d39c4a73a4..272f63687b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -441,6 +441,17 @@ dependencies = [ "libc", ] +[[package]] +name = "ided" +version = "0.1.0" +dependencies = [ + "log", + "pcid", + "redox-daemon", + "redox-log", + "redox_syscall 0.3.4", +] + [[package]] name = "idna" version = "0.1.5" diff --git a/Cargo.toml b/Cargo.toml index 8078a99e90..fb901ff23b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "bgad", "block-io-wrapper", "e1000d", + "ided", "ihdad", "ixgbed", "nvmed", diff --git a/ided/.gitignore b/ided/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/ided/.gitignore @@ -0,0 +1 @@ +/target diff --git a/ided/Cargo.toml b/ided/Cargo.toml new file mode 100644 index 0000000000..d62d829374 --- /dev/null +++ b/ided/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ided" +version = "0.1.0" +edition = "2018" + +[dependencies] +log = "0.4" +pcid = { path = "../pcid" } +redox-daemon = "0.1" +redox-log = "0.1" +redox_syscall = "0.3" diff --git a/ided/src/main.rs b/ided/src/main.rs new file mode 100644 index 0000000000..6391ce4f6b --- /dev/null +++ b/ided/src/main.rs @@ -0,0 +1,63 @@ +use pcid_interface::PcidServerHandle; + +use log::{error, info}; +use redox_log::{OutputBuilder, RedoxLogger}; + +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "ide.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("ided: failed to create ide.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "ide.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("ided: failed to create ide.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("ided: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("ided: failed to set default logger: {}", error); + None + } + } +} + +fn main() { + redox_daemon::Daemon::new(daemon).expect("ided: failed to daemonize"); +} + +fn daemon(daemon: redox_daemon::Daemon) -> ! { + let _logger_ref = setup_logging(); + + let mut pcid_handle = + PcidServerHandle::connect_default().expect("ided: failed to setup channel to pcid"); + + println!("IDE {:#x?}", pcid_handle.fetch_header()); + + std::process::exit(0); +} diff --git a/initfs.toml b/initfs.toml index fed4f568c0..1c1c6015fd 100644 --- a/initfs.toml +++ b/initfs.toml @@ -7,6 +7,14 @@ class = 1 subclass = 6 command = ["ahcid", "$NAME", "$BAR5", "$BARSIZE5", "$IRQ"] +# ided +[[drivers]] +name = "IDE storage" +class = 1 +subclass = 1 +command = ["ided"] +use_channel = true + # nvmed [[drivers]] name = "NVME storage" From 08a1595f54db2ead5bfac78ce2fa399b5144e5bd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 7 Sep 2022 15:28:04 -0600 Subject: [PATCH 0524/1301] Implement ided using PIO and code from ahci --- Cargo.lock | 2 + ided/Cargo.toml | 2 + ided/src/ata.rs | 16 ++ ided/src/ide.rs | 224 ++++++++++++++++++++++++ ided/src/main.rs | 325 ++++++++++++++++++++++++++++++++-- ided/src/scheme.rs | 426 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 985 insertions(+), 10 deletions(-) create mode 100644 ided/src/ata.rs create mode 100644 ided/src/ide.rs create mode 100644 ided/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index 272f63687b..13813dde0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -445,7 +445,9 @@ dependencies = [ name = "ided" version = "0.1.0" dependencies = [ + "block-io-wrapper", "log", + "partitionlib", "pcid", "redox-daemon", "redox-log", diff --git a/ided/Cargo.toml b/ided/Cargo.toml index d62d829374..27052da67e 100644 --- a/ided/Cargo.toml +++ b/ided/Cargo.toml @@ -4,7 +4,9 @@ version = "0.1.0" edition = "2018" [dependencies] +block-io-wrapper = { path = "../block-io-wrapper" } log = "0.4" +partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } pcid = { path = "../pcid" } redox-daemon = "0.1" redox-log = "0.1" diff --git a/ided/src/ata.rs b/ided/src/ata.rs new file mode 100644 index 0000000000..6cd72310d5 --- /dev/null +++ b/ided/src/ata.rs @@ -0,0 +1,16 @@ +#[repr(u8)] +pub enum AtaCommand { + ReadPio = 0x20, + ReadPioExt = 0x24, + ReadDma = 0xC8, + ReadDmaExt = 0x25, + WritePio = 0x30, + WritePioExt = 0x34, + WriteDma = 0xCA, + WriteDmaExt = 0x35, + CacheFlush = 0xE7, + CacheFlushExt = 0xEA, + Packet = 0xA0, + IdentifyPacket = 0xA1, + Identify = 0xEC, +} diff --git a/ided/src/ide.rs b/ided/src/ide.rs new file mode 100644 index 0000000000..73fdbeff37 --- /dev/null +++ b/ided/src/ide.rs @@ -0,0 +1,224 @@ +use std::{ + sync::{Arc, Mutex}, + thread, +}; +use syscall::{ + error::{Error, Result, EIO}, + io::{Io, Pio, ReadOnly, WriteOnly}, +}; + +use crate::ata::AtaCommand; + +pub struct Channel { + pub data8: Pio, + pub data32: Pio, + pub error: ReadOnly>, + pub features: WriteOnly>, + pub sector_count: Pio, + pub lba_0: Pio, + pub lba_1: Pio, + pub lba_2: Pio, + pub device_select: Pio, + pub status: ReadOnly>, + pub command: WriteOnly>, + pub alt_status: ReadOnly>, + pub control: WriteOnly>, +} + +impl Channel { + pub fn new(base: u16, control_base: u16) -> Self { + Self { + data8: Pio::new(base + 0), + data32: Pio::new(base + 0), + error: ReadOnly::new(Pio::new(base + 1)), + features: WriteOnly::new(Pio::new(base + 1)), + sector_count: Pio::new(base + 2), + lba_0: Pio::new(base + 3), + lba_1: Pio::new(base + 4), + lba_2: Pio::new(base + 5), + device_select: Pio::new(base + 6), + status: ReadOnly::new(Pio::new(base + 7)), + command: WriteOnly::new(Pio::new(base + 7)), + alt_status: ReadOnly::new(Pio::new(control_base + 2)), + control: WriteOnly::new(Pio::new(control_base + 2)), + } + } + + pub fn primary_compat() -> Self { + Self::new(0x1F0, 0x3F6) + } + + pub fn secondary_compat() -> Self { + Self::new(0x170, 0x376) + } + + fn polling(&mut self, check: bool) -> Result<()> { + /* + #define ATA_SR_BSY 0x80 // Busy + #define ATA_SR_DRDY 0x40 // Drive ready + #define ATA_SR_DF 0x20 // Drive write fault + #define ATA_SR_DSC 0x10 // Drive seek complete + #define ATA_SR_DRQ 0x08 // Data request ready + #define ATA_SR_CORR 0x04 // Corrected data + #define ATA_SR_IDX 0x02 // Index + #define ATA_SR_ERR 0x01 // Error + */ + + for _ in 0..4 { + // Doing this 4 times creates a 400ns delay + self.alt_status.read(); + } + + while self.status.readf(0x80) { + thread::yield_now(); + } + + if check { + let status = self.status.read(); + + if status & 0x01 != 0 { + log::error!("IDE error"); + return Err(Error::new(EIO)); + } + + if status & 0x20 != 0 { + log::error!("IDE device write fault"); + return Err(Error::new(EIO)); + } + + if status & 0x08 == 0 { + log::error!("IDE data not ready"); + return Err(Error::new(EIO)); + } + } + + Ok(()) + } +} + +pub trait Disk { + fn id(&self) -> usize; + fn size(&mut self) -> u64; + fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result>; + fn write(&mut self, block: u64, buffer: &[u8]) -> Result>; + fn block_length(&mut self) -> Result; +} + +pub struct AtaDisk { + pub chan: Arc>, + pub chan_i: usize, + pub dev: u8, + pub size: u64, +} + +impl Disk for AtaDisk { + fn id(&self) -> usize { + self.chan_i << 1 | self.dev as usize + } + + fn size(&mut self) -> u64 { + self.size + } + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result> { + //TODO: support other LBA modes + assert!(block < 0x1_0000_0000_0000); + + let sectors = buffer.len() / 512; + assert!(sectors < 0x1_0000); + + let mut chan = self.chan.lock().unwrap(); + + // Select drive + chan.device_select.write(0xE0 | (self.dev << 4)); + + // Set high sector count and LBA + //TODO: only if LBA mode is 48-bit + chan.control.writef(0x80, true); + chan.sector_count.write((sectors >> 8) as u8); + chan.lba_0.write((block >> 24) as u8); + chan.lba_1.write((block >> 32) as u8); + chan.lba_2.write((block >> 40) as u8); + chan.control.writef(0x80, false); + + // Set low sector count and LBA + chan.sector_count.write(sectors as u8); + chan.lba_0.write(block as u8); + chan.lba_1.write((block >> 8) as u8); + chan.lba_2.write((block >> 16) as u8); + + // Send command + //TODO: use DMA + chan.command.write(AtaCommand::ReadPioExt as u8); + + // Read data + for sector in 0..sectors { + chan.polling(true)?; + + for i in 0..128 { + let data = chan.data32.read(); + buffer[sector * 512 + i * 4 + 0] = (data >> 0) as u8; + buffer[sector * 512 + i * 4 + 1] = (data >> 8) as u8; + buffer[sector * 512 + i * 4 + 2] = (data >> 16) as u8; + buffer[sector * 512 + i * 4 + 3] = (data >> 24) as u8; + } + } + + Ok(Some(sectors * 512)) + } + + fn write(&mut self, block: u64, buffer: &[u8]) -> Result> { + //TODO: support other LBA modes + assert!(block < 0x1_0000_0000_0000); + + let sectors = buffer.len() / 512; + assert!(sectors < 0x1_0000); + + let mut chan = self.chan.lock().unwrap(); + + // Select drive + chan.device_select.write(0xE0 | (self.dev << 4)); + + // Set high sector count and LBA + //TODO: only if LBA mode is 48-bit + chan.control.writef(0x80, true); + chan.sector_count.write((sectors >> 8) as u8); + chan.lba_0.write((block >> 24) as u8); + chan.lba_1.write((block >> 32) as u8); + chan.lba_2.write((block >> 40) as u8); + chan.control.writef(0x80, false); + + // Set low sector count and LBA + chan.sector_count.write(sectors as u8); + chan.lba_0.write(block as u8); + chan.lba_1.write((block >> 8) as u8); + chan.lba_2.write((block >> 16) as u8); + + // Send command + //TODO: use DMA + chan.command.write(AtaCommand::WritePioExt as u8); + + // Write data + for sector in 0..sectors { + chan.polling(false)?; + + for i in 0..128 { + chan.data32.write( + ((buffer[sector * 512 + i * 4 + 0] as u32) << 0) | + ((buffer[sector * 512 + i * 4 + 1] as u32) << 8) | + ((buffer[sector * 512 + i * 4 + 2] as u32) << 16) | + ((buffer[sector * 512 + i * 4 + 3] as u32) << 24) + ); + } + } + + chan.command.write(AtaCommand::CacheFlushExt as u8); + chan.polling(false)?; + + Ok(Some(sectors * 512)) + } + + fn block_length(&mut self) -> Result { + Ok(512) + } +} diff --git a/ided/src/main.rs b/ided/src/main.rs index 6391ce4f6b..315beb5cad 100644 --- a/ided/src/main.rs +++ b/ided/src/main.rs @@ -1,9 +1,33 @@ -use pcid_interface::PcidServerHandle; - use log::{error, info}; +use pcid_interface::PcidServerHandle; use redox_log::{OutputBuilder, RedoxLogger}; +use std::{ + fs::File, + io::{ErrorKind, Read, Write}, + os::unix::io::{FromRawFd, RawFd}, + sync::{Arc, Mutex}, + thread::sleep, + time::Duration, +}; +use syscall::{ + data::{Event, Packet}, + error::{Error, ENODEV}, + flag::{EVENT_READ}, + io::Io, + scheme::SchemeBlockMut, +}; -fn setup_logging() -> Option<&'static RedoxLogger> { +use crate::{ + ata::AtaCommand, + ide::{AtaDisk, Channel, Disk}, + scheme::DiskScheme, +}; + +pub mod ata; +pub mod ide; +pub mod scheme; + +fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() @@ -14,25 +38,25 @@ fn setup_logging() -> Option<&'static RedoxLogger> { ); #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "ide.log") { + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.log", name)) { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this b.with_filter(log::LevelFilter::Info) .flush_on_newline(true) .build() ), - Err(error) => eprintln!("ided: failed to create ide.log: {}", error), + Err(error) => eprintln!("ided: failed to create log: {}", error), } #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "ide.ansi.log") { + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.ansi.log", name)) { Ok(b) => logger = logger.with_output( b.with_filter(log::LevelFilter::Info) .with_ansi_escape_codes() .flush_on_newline(true) .build() ), - Err(error) => eprintln!("ided: failed to create ide.ansi.log: {}", error), + Err(error) => eprintln!("ided: failed to create ansi log: {}", error), } match logger.enable() { @@ -52,12 +76,293 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let _logger_ref = setup_logging(); - let mut pcid_handle = PcidServerHandle::connect_default().expect("ided: failed to setup channel to pcid"); - println!("IDE {:#x?}", pcid_handle.fetch_header()); + let pci_config = pcid_handle.fetch_config().expect("ided: failed to fetch config"); + let mut name = pci_config.func.name(); + name.push_str("_ide"); + + let _logger_ref = setup_logging(&name); + + info!("IDE {:?}", pci_config); + + let pci_header = pcid_handle.fetch_header().expect("ided: failed to fetch PCI header"); + let (primary, primary_irq) = if pci_header.interface() & 1 != 0 { + panic!("TODO: IDE primary channel is PCI native"); + } else { + (Channel::primary_compat(), 14) + }; + let (secondary, secondary_irq) = if pci_header.interface() & 1 != 0 { + panic!("TODO: IDE secondary channel is PCI native"); + } else { + (Channel::secondary_compat(), 15) + }; + + unsafe { syscall::iopl(3).expect("ided: failed to get I/O privilege") }; + + //TODO: move this to ide.rs? + let chans = vec![ + Arc::new(Mutex::new(primary)), + Arc::new(Mutex::new(secondary)), + ]; + let mut disks: Vec> = Vec::new(); + for (chan_i, chan_lock) in chans.iter().enumerate() { + let mut chan = chan_lock.lock().unwrap(); + + println!(" - channel {}", chan_i); + + // Disable IRQs + chan.control.write(2); + + for dev in 0..=1 { + println!(" - device {}", dev); + + // Select device + chan.device_select.write(0xA0 | (dev << 4)); + sleep(Duration::from_millis(1)); + + // ATA identify command + chan.command.write(AtaCommand::Identify as u8); + sleep(Duration::from_millis(1)); + + // Check if device exists + if chan.status.read() == 0 { + println!(" not found"); + continue; + } + + // Poll for status + let error = loop { + let status = chan.status.read(); + if status & 1 != 0 { + // Error + break true; + } + if status & 0x80 == 0 && status & 0x08 != 0 { + // Not busy and data ready + break false; + } + }; + + //TODO: probe ATAPI + if error { + println!(" error"); + continue; + } + + // Read and print identity + { + let mut dest = [0u16; 256]; + for chunk in dest.chunks_mut(2) { + let data = chan.data32.read(); + chunk[0] = data as u16; + chunk[1] = (data >> 16) as u16; + } + + let mut serial = String::new(); + for word in 10..20 { + let d = dest[word]; + let a = ((d >> 8) as u8) as char; + if a != '\0' { + serial.push(a); + } + let b = (d as u8) as char; + if b != '\0' { + serial.push(b); + } + } + + let mut firmware = String::new(); + for word in 23..27 { + let d = dest[word]; + let a = ((d >> 8) as u8) as char; + if a != '\0' { + firmware.push(a); + } + let b = (d as u8) as char; + if b != '\0' { + firmware.push(b); + } + } + + let mut model = String::new(); + for word in 27..47 { + let d = dest[word]; + let a = ((d >> 8) as u8) as char; + if a != '\0' { + model.push(a); + } + let b = (d as u8) as char; + if b != '\0' { + model.push(b); + } + } + + let mut sectors = (dest[100] as u64) | + ((dest[101] as u64) << 16) | + ((dest[102] as u64) << 32) | + ((dest[103] as u64) << 48); + + let lba_bits = if sectors == 0 { + sectors = (dest[60] as u64) | ((dest[61] as u64) << 16); + 28 + } else { + 48 + }; + + println!(" Serial: {}", serial.trim()); + println!(" Firmware: {}", firmware.trim()); + println!(" Model: {}", model.trim()); + println!(" {}-bit LBA", lba_bits); + println!(" Size: {} MB", sectors / 2048); + + disks.push(Box::new(AtaDisk { + chan: chan_lock.clone(), + chan_i, + dev, + size: sectors * 512, + })); + } + } + } + + let scheme_name = format!("disk/{}", name); + let socket_fd = syscall::open( + &format!(":{}", scheme_name), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK + ).expect("ided: failed to create disk scheme"); + let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + + let primary_irq_fd = syscall::open( + &format!("irq:{}", primary_irq), + syscall::O_RDWR | syscall::O_NONBLOCK + ).expect("ided: failed to open irq file"); + let mut primary_irq_file = unsafe { File::from_raw_fd(primary_irq_fd as RawFd) }; + + let secondary_irq_fd = syscall::open( + &format!("irq:{}", secondary_irq), + syscall::O_RDWR | syscall::O_NONBLOCK + ).expect("ided: failed to open irq file"); + let mut secondary_irq_file = unsafe { File::from_raw_fd(secondary_irq_fd as RawFd) }; + + let mut event_file = File::open("event:").expect("ided: failed to open event file"); + + syscall::setrens(0, 0).expect("ided: failed to enter null namespace"); + + daemon.ready().expect("ided: failed to notify parent"); + + event_file.write(&Event { + id: socket_fd, + flags: EVENT_READ, + data: 0 + }).expect("ided: failed to event disk scheme"); + + event_file.write(&Event { + id: primary_irq_fd, + flags: EVENT_READ, + data: 0 + }).expect("ided: failed to event irq scheme"); + + event_file.write(&Event { + id: secondary_irq_fd, + flags: EVENT_READ, + data: 0 + }).expect("ided: failed to event irq scheme"); + + let mut scheme = DiskScheme::new(scheme_name, chans, disks); + + let mut mounted = true; + let mut todo = Vec::new(); + while mounted { + let mut event = Event::default(); + if event_file.read(&mut event).expect("ided: failed to read event file") == 0 { + break; + } + if event.id == socket_fd { + loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => { + mounted = false; + break; + }, + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; + } else { + panic!("ided: failed to read disk scheme: {}", err); + } + } + + if let Some(a) = scheme.handle(&packet) { + packet.a = a; + socket.write(&mut packet).expect("ided: failed to write disk scheme"); + } else { + todo.push(packet); + } + } + } else if event.id == primary_irq_fd { + let mut irq = [0; 8]; + if primary_irq_file.read(&mut irq).expect("ided: failed to read irq file") >= irq.len() { + if scheme.irq(0) { + primary_irq_file.write(&irq).expect("ided: failed to write irq file"); + + // Handle todos in order to finish previous packets if possible + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&mut packet).expect("ided: failed to write disk scheme"); + } else { + i += 1; + } + } + } + } + } else if event.id == secondary_irq_fd { + let mut irq = [0; 8]; + if secondary_irq_file.read(&mut irq).expect("ided: failed to read irq file") >= irq.len() { + if scheme.irq(1) { + secondary_irq_file.write(&irq).expect("ided: failed to write irq file"); + + // Handle todos in order to finish previous packets if possible + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&mut packet).expect("ided: failed to write disk scheme"); + } else { + i += 1; + } + } + } + } + } else { + error!("Unknown event {}", event.id); + } + + // Handle todos to start new packets if possible + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&packet).expect("ided: failed to write disk scheme"); + } else { + i += 1; + } + } + + if ! mounted { + for mut packet in todo.drain(..) { + packet.a = Error::mux(Err(Error::new(ENODEV))); + socket.write(&packet).expect("ided: failed to write disk scheme"); + } + } + } std::process::exit(0); } diff --git a/ided/src/scheme.rs b/ided/src/scheme.rs new file mode 100644 index 0000000000..e88fb46e0c --- /dev/null +++ b/ided/src/scheme.rs @@ -0,0 +1,426 @@ +use std::collections::BTreeMap; +use std::{cmp, str}; +use std::convert::{TryFrom}; +use std::fmt::Write; +use std::io::prelude::*; +use std::io::SeekFrom; +use std::io; +use std::sync::{Arc, Mutex}; + +use syscall::{ + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, EOVERFLOW, Result, + Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, + O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; + +use crate::ide::{Channel, Disk}; + +use partitionlib::{LogicalBlockSize, PartitionTable}; + +#[derive(Clone)] +enum Handle { + List(Vec, usize), // Dir contents buffer, position + Disk(usize, usize), // Disk index, position + Partition(usize, u32, usize), // Disk index, partition index, position +} + +pub struct DiskWrapper { + disk: Box, + pt: Option, +} + +impl DiskWrapper { + fn pt(disk: &mut dyn Disk) -> Option { + let bs = match disk.block_length() { + Ok(512) => LogicalBlockSize::Lb512, + Ok(4096) => LogicalBlockSize::Lb4096, + _ => return None, + }; + struct Device<'a, 'b> { disk: &'a mut dyn Disk, offset: u64, block_bytes: &'b mut [u8] } + + impl<'a, 'b> Seek for Device<'a, 'b> { + fn seek(&mut self, from: SeekFrom) -> io::Result { + let size = i64::try_from(self.disk.size()).or(Err(io::Error::new(io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes")))?; + + self.offset = match from { + SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos), + SeekFrom::Current(new_pos) => cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64, + SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64, + }; + + Ok(self.offset) + } + } + // TODO: Perhaps this impl should be used in the rest of the scheme. + impl<'a, 'b> Read for Device<'a, 'b> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?; + let size_in_blocks = self.disk.size() / u64::from(blksize); + + let disk = &mut self.disk; + + let read_block = |block: u64, block_bytes: &mut [u8]| { + if block >= size_in_blocks { + return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); + } + loop { + match disk.read(block, block_bytes) { + Ok(Some(bytes)) => { + assert_eq!(bytes, block_bytes.len()); + assert_eq!(bytes, blksize as usize); + return Ok(()); + } + Ok(None) => { std::thread::yield_now(); continue } + Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), + } + } + }; + let bytes_read = block_io_wrapper::read(self.offset, blksize, buf, self.block_bytes, read_block)?; + + self.offset += bytes_read as u64; + Ok(bytes_read) + } + } + + let mut block_bytes = [0u8; 4096]; + + partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() + } + fn new(mut disk: Box) -> Self { + Self { + pt: Self::pt(&mut *disk), + disk, + } + } +} + +impl std::ops::Deref for DiskWrapper { + type Target = dyn Disk; + + fn deref(&self) -> &Self::Target { + &*self.disk + } +} +impl std::ops::DerefMut for DiskWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.disk + } +} + +pub struct DiskScheme { + scheme_name: String, + chans: Box<[Arc>]>, + disks: Box<[DiskWrapper]>, + handles: BTreeMap, + next_id: usize +} + +impl DiskScheme { + pub fn new(scheme_name: String, chans: Vec>>, disks: Vec>) -> DiskScheme { + DiskScheme { + scheme_name: scheme_name, + chans: chans.into_boxed_slice(), + disks: disks.into_iter().map(DiskWrapper::new).collect::>().into_boxed_slice(), + handles: BTreeMap::new(), + next_id: 0 + } + } +} + +impl DiskScheme { + pub fn irq(&mut self, chan_i: usize) -> bool { + let mut chan = self.chans[chan_i].lock().unwrap(); + //TODO: check chan for irq + true + } +} + +impl SchemeBlockMut for DiskScheme { + fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { + if uid == 0 { + let path_str = path.trim_matches('/'); + if path_str.is_empty() { + if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { + let mut list = String::new(); + + for (disk_index, disk) in self.disks.iter().enumerate() { + write!(list, "{}\n", disk_index).unwrap(); + + if disk.pt.is_none() { + continue + } + for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { + write!(list, "{}p{}\n", disk_index, part_index).unwrap(); + } + } + + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle::List(list.into_bytes(), 0)); + Ok(Some(id)) + } else { + Err(Error::new(EISDIR)) + } + } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { + let disk_id_str = &path_str[..p_pos]; + if p_pos + 1 >= path_str.len() { + return Err(Error::new(ENOENT)); + } + let part_id_str = &path_str[p_pos + 1..]; + let i = disk_id_str.parse::().or(Err(Error::new(ENOENT)))?; + let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; + + if let Some(disk) = self.disks.get(i) { + if disk.pt.is_none() || disk.pt.as_ref().unwrap().partitions.get(p as usize).is_none() { + return Err(Error::new(ENOENT)); + } + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, Handle::Partition(i, p, 0)); + + Ok(Some(id)) + } else { + Err(Error::new(ENOENT)) + } + } else { + let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; + + if self.disks.get(i).is_some() { + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle::Disk(i, 0)); + Ok(Some(id)) + } else { + Err(Error::new(ENOENT)) + } + } + } else { + Err(Error::new(EACCES)) + } + } + + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { + if ! buf.is_empty() { + return Err(Error::new(EINVAL)); + } + + let new_handle = { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + handle.clone() + }; + + let new_id = self.next_id; + self.next_id += 1; + self.handles.insert(new_id, new_handle); + Ok(Some(new_id)) + } + + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + match *self.handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref data, _) => { + stat.st_mode = MODE_DIR; + stat.st_size = data.len() as u64; + Ok(Some(0)) + }, + Handle::Disk(number, _) => { + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + stat.st_mode = MODE_FILE; + stat.st_size = disk.size(); + stat.st_blksize = disk.block_length()?; + Ok(Some(0)) + } + Handle::Partition(disk_id, part_num, _) => { + let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; + let size = { + let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; + let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + partition.size + }; + + stat.st_mode = MODE_FILE; // TODO: Block device? + stat.st_size = size * u64::from(disk.block_length()?); + stat.st_blksize = disk.block_length()?; + stat.st_blocks = size; + Ok(Some(0)) + } + } + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let mut i = 0; + + let scheme_name = self.scheme_name.as_bytes(); + let mut j = 0; + while i < buf.len() && j < scheme_name.len() { + buf[i] = scheme_name[j]; + i += 1; + j += 1; + } + + if i < buf.len() { + buf[i] = b':'; + i += 1; + } + + match *handle { + Handle::List(_, _) => (), + Handle::Disk(number, _) => { + let number_str = format!("{}", number); + let number_bytes = number_str.as_bytes(); + j = 0; + while i < buf.len() && j < number_bytes.len() { + buf[i] = number_bytes[j]; + i += 1; + j += 1; + } + } + Handle::Partition(disk_num, part_num, _) => { + let path = format!("{}p{}", disk_num, part_num); + let path_bytes = path.as_bytes(); + j = 0; + while i < buf.len() && j < path_bytes.len() { + buf[i] = path_bytes[j]; + i += 1; + j += 1; + } + } + } + + Ok(Some(i)) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref handle, ref mut size) => { + let count = (&handle[*size..]).read(buf).unwrap(); + *size += count; + Ok(Some(count)) + }, + Handle::Disk(number, ref mut size) => { + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + let blk_len = disk.block_length()?; + if let Some(count) = disk.read((*size as u64)/(blk_len as u64), buf)? { + *size += count; + Ok(Some(count)) + } else { + Ok(None) + } + } + Handle::Partition(disk_num, part_num, ref mut position) => { + let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; + let blksize = disk.block_length()?; + + // validate that we're actually reading within the bounds of the partition + let rel_block = *position as u64 / blksize as u64; + + let abs_block = { + let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; + let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + + let abs_block = partition.start_lba + rel_block; + if rel_block >= partition.size { + return Err(Error::new(EOVERFLOW)); + } + abs_block + }; + + if let Some(count) = disk.read(abs_block, buf)? { + Ok(Some(count)) + } else { + Ok(None) + } + } + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(_, _) => { + Err(Error::new(EBADF)) + }, + Handle::Disk(number, ref mut size) => { + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + let blk_len = disk.block_length()?; + if let Some(count) = disk.write((*size as u64)/(blk_len as u64), buf)? { + *size += count; + Ok(Some(count)) + } else { + Ok(None) + } + } + Handle::Partition(disk_num, part_num, ref mut position) => { + let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; + let blksize = disk.block_length()?; + + // validate that we're actually reading within the bounds of the partition + let rel_block = *position as u64 / blksize as u64; + + let abs_block = { + let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; + let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + + let abs_block = partition.start_lba + rel_block; + if rel_block >= partition.size { + return Err(Error::new(EOVERFLOW)); + } + abs_block + }; + + if let Some(count) = disk.write(abs_block, buf)? { + Ok(Some(count)) + } else { + Ok(None) + } + } + } + } + + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { + let pos = pos as usize; + + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref mut handle, ref mut size) => { + let len = handle.len() as usize; + *size = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(Some(*size as isize)) + }, + Handle::Disk(number, ref mut size) => { + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + let len = disk.size() as usize; + *size = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(Some(*size as isize)) + } + Handle::Partition(disk_num, part_num, ref mut position) => { + let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; + let block_count = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?.size; + let len = u64::from(disk.block_length()?) * block_count; + + *position = match whence { + SEEK_SET => cmp::min(len as usize, pos) as usize, // Why isn't pos u64? + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *position as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)), + }; + Ok(Some(*position as isize)) + } + } + } + + fn close(&mut self, id: usize) -> Result> { + self.handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + } +} From a7848cc079c7738fb2833edd7c53db258e6ec4e8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 7 Sep 2022 15:47:08 -0600 Subject: [PATCH 0525/1301] Fix control base register --- ided/src/ide.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ided/src/ide.rs b/ided/src/ide.rs index 73fdbeff37..f5e82589c2 100644 --- a/ided/src/ide.rs +++ b/ided/src/ide.rs @@ -39,8 +39,8 @@ impl Channel { device_select: Pio::new(base + 6), status: ReadOnly::new(Pio::new(base + 7)), command: WriteOnly::new(Pio::new(base + 7)), - alt_status: ReadOnly::new(Pio::new(control_base + 2)), - control: WriteOnly::new(Pio::new(control_base + 2)), + alt_status: ReadOnly::new(Pio::new(control_base)), + control: WriteOnly::new(Pio::new(control_base)), } } From 4fe7733cadd5e8dbbaea719255a929e66124753f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 7 Sep 2022 16:14:56 -0600 Subject: [PATCH 0526/1301] ided: Use pause instruction instead of yield_now when waiting for status --- ided/src/ide.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ided/src/ide.rs b/ided/src/ide.rs index f5e82589c2..73fbe20d3b 100644 --- a/ided/src/ide.rs +++ b/ided/src/ide.rs @@ -1,6 +1,5 @@ use std::{ sync::{Arc, Mutex}, - thread, }; use syscall::{ error::{Error, Result, EIO}, @@ -9,6 +8,18 @@ use syscall::{ use crate::ata::AtaCommand; +#[cfg(target_arch = "aarch64")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::aarch64::__yield(); } + +#[cfg(target_arch = "x86")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::x86::_mm_pause(); } + +#[cfg(target_arch = "x86_64")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::x86_64::_mm_pause(); } + pub struct Channel { pub data8: Pio, pub data32: Pio, @@ -70,7 +81,7 @@ impl Channel { } while self.status.readf(0x80) { - thread::yield_now(); + unsafe { pause(); } } if check { From 09465d3640df8a3581183535c4e1bf1bd66cf729 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 7 Sep 2022 16:23:57 -0600 Subject: [PATCH 0527/1301] ided: Do I/O in 64 KiB chunks --- ided/src/ide.rs | 158 ++++++++++++++++++++++++++---------------------- 1 file changed, 86 insertions(+), 72 deletions(-) diff --git a/ided/src/ide.rs b/ided/src/ide.rs index 73fbe20d3b..2dd012cc73 100644 --- a/ided/src/ide.rs +++ b/ided/src/ide.rs @@ -131,102 +131,116 @@ impl Disk for AtaDisk { self.size } - fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result> { - //TODO: support other LBA modes - assert!(block < 0x1_0000_0000_0000); + fn read(&mut self, start_block: u64, buffer: &mut [u8]) -> Result> { + let mut count = 0; + for chunk in buffer.chunks_mut(65536) { + let block = start_block + (count as u64) / 512; - let sectors = buffer.len() / 512; - assert!(sectors < 0x1_0000); + //TODO: support other LBA modes + assert!(block < 0x1_0000_0000_0000); - let mut chan = self.chan.lock().unwrap(); + let sectors = chunk.len() / 512; + assert!(sectors < 0x1_0000); - // Select drive - chan.device_select.write(0xE0 | (self.dev << 4)); + let mut chan = self.chan.lock().unwrap(); - // Set high sector count and LBA - //TODO: only if LBA mode is 48-bit - chan.control.writef(0x80, true); - chan.sector_count.write((sectors >> 8) as u8); - chan.lba_0.write((block >> 24) as u8); - chan.lba_1.write((block >> 32) as u8); - chan.lba_2.write((block >> 40) as u8); - chan.control.writef(0x80, false); + // Select drive + chan.device_select.write(0xE0 | (self.dev << 4)); - // Set low sector count and LBA - chan.sector_count.write(sectors as u8); - chan.lba_0.write(block as u8); - chan.lba_1.write((block >> 8) as u8); - chan.lba_2.write((block >> 16) as u8); + // Set high sector count and LBA + //TODO: only if LBA mode is 48-bit + chan.control.writef(0x80, true); + chan.sector_count.write((sectors >> 8) as u8); + chan.lba_0.write((block >> 24) as u8); + chan.lba_1.write((block >> 32) as u8); + chan.lba_2.write((block >> 40) as u8); + chan.control.writef(0x80, false); - // Send command - //TODO: use DMA - chan.command.write(AtaCommand::ReadPioExt as u8); + // Set low sector count and LBA + chan.sector_count.write(sectors as u8); + chan.lba_0.write(block as u8); + chan.lba_1.write((block >> 8) as u8); + chan.lba_2.write((block >> 16) as u8); - // Read data - for sector in 0..sectors { - chan.polling(true)?; + // Send command + //TODO: use DMA + chan.command.write(AtaCommand::ReadPioExt as u8); - for i in 0..128 { - let data = chan.data32.read(); - buffer[sector * 512 + i * 4 + 0] = (data >> 0) as u8; - buffer[sector * 512 + i * 4 + 1] = (data >> 8) as u8; - buffer[sector * 512 + i * 4 + 2] = (data >> 16) as u8; - buffer[sector * 512 + i * 4 + 3] = (data >> 24) as u8; + // Read data + for sector in 0..sectors { + chan.polling(true)?; + + for i in 0..128 { + let data = chan.data32.read(); + chunk[sector * 512 + i * 4 + 0] = (data >> 0) as u8; + chunk[sector * 512 + i * 4 + 1] = (data >> 8) as u8; + chunk[sector * 512 + i * 4 + 2] = (data >> 16) as u8; + chunk[sector * 512 + i * 4 + 3] = (data >> 24) as u8; + } } + + count += chunk.len(); } - Ok(Some(sectors * 512)) + Ok(Some(count)) } - fn write(&mut self, block: u64, buffer: &[u8]) -> Result> { - //TODO: support other LBA modes - assert!(block < 0x1_0000_0000_0000); + fn write(&mut self, start_block: u64, buffer: &[u8]) -> Result> { + let mut count = 0; + for chunk in buffer.chunks(65536) { + let block = start_block + (count as u64) / 512; - let sectors = buffer.len() / 512; - assert!(sectors < 0x1_0000); + //TODO: support other LBA modes + assert!(block < 0x1_0000_0000_0000); - let mut chan = self.chan.lock().unwrap(); + let sectors = chunk.len() / 512; + assert!(sectors < 0x1_0000); - // Select drive - chan.device_select.write(0xE0 | (self.dev << 4)); + let mut chan = self.chan.lock().unwrap(); - // Set high sector count and LBA - //TODO: only if LBA mode is 48-bit - chan.control.writef(0x80, true); - chan.sector_count.write((sectors >> 8) as u8); - chan.lba_0.write((block >> 24) as u8); - chan.lba_1.write((block >> 32) as u8); - chan.lba_2.write((block >> 40) as u8); - chan.control.writef(0x80, false); + // Select drive + chan.device_select.write(0xE0 | (self.dev << 4)); - // Set low sector count and LBA - chan.sector_count.write(sectors as u8); - chan.lba_0.write(block as u8); - chan.lba_1.write((block >> 8) as u8); - chan.lba_2.write((block >> 16) as u8); + // Set high sector count and LBA + //TODO: only if LBA mode is 48-bit + chan.control.writef(0x80, true); + chan.sector_count.write((sectors >> 8) as u8); + chan.lba_0.write((block >> 24) as u8); + chan.lba_1.write((block >> 32) as u8); + chan.lba_2.write((block >> 40) as u8); + chan.control.writef(0x80, false); - // Send command - //TODO: use DMA - chan.command.write(AtaCommand::WritePioExt as u8); + // Set low sector count and LBA + chan.sector_count.write(sectors as u8); + chan.lba_0.write(block as u8); + chan.lba_1.write((block >> 8) as u8); + chan.lba_2.write((block >> 16) as u8); - // Write data - for sector in 0..sectors { + // Send command + //TODO: use DMA + chan.command.write(AtaCommand::WritePioExt as u8); + + // Write data + for sector in 0..sectors { + chan.polling(false)?; + + for i in 0..128 { + chan.data32.write( + ((chunk[sector * 512 + i * 4 + 0] as u32) << 0) | + ((chunk[sector * 512 + i * 4 + 1] as u32) << 8) | + ((chunk[sector * 512 + i * 4 + 2] as u32) << 16) | + ((chunk[sector * 512 + i * 4 + 3] as u32) << 24) + ); + } + } + + chan.command.write(AtaCommand::CacheFlushExt as u8); chan.polling(false)?; - for i in 0..128 { - chan.data32.write( - ((buffer[sector * 512 + i * 4 + 0] as u32) << 0) | - ((buffer[sector * 512 + i * 4 + 1] as u32) << 8) | - ((buffer[sector * 512 + i * 4 + 2] as u32) << 16) | - ((buffer[sector * 512 + i * 4 + 3] as u32) << 24) - ); - } + count += chunk.len(); } - chan.command.write(AtaCommand::CacheFlushExt as u8); - chan.polling(false)?; - - Ok(Some(sectors * 512)) + Ok(Some(count)) } fn block_length(&mut self) -> Result { From 2751d7d7925405d31053fadb268083b37996741a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 7 Sep 2022 20:37:11 -0600 Subject: [PATCH 0528/1301] ahcid: Use pause instead of yield --- ahcid/src/ahci/disk_ata.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index ca118a50cb..15620c315a 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -7,6 +7,18 @@ use syscall::error::Result; use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; use super::Disk; +#[cfg(target_arch = "aarch64")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::aarch64::__yield(); } + +#[cfg(target_arch = "x86")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::x86::_mm_pause(); } + +#[cfg(target_arch = "x86_64")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::x86_64::_mm_pause(); } + enum BufferKind<'a> { Read(&'a mut [u8]), Write(&'a [u8]), @@ -97,7 +109,7 @@ impl DiskATA { if use_interrupts { return Ok(None); } else { - ::std::thread::yield_now(); + unsafe { pause(); } continue; } } @@ -132,7 +144,7 @@ impl DiskATA { if use_interrupts { return Ok(None); } else { - ::std::thread::yield_now(); + unsafe { pause(); } continue; } } else { From 49ba91b0ee655b4f7eb015133a52e13657eb6dc7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 8 Sep 2022 09:55:06 -0600 Subject: [PATCH 0529/1301] Improvements to ps2 mouse init --- ps2d/src/controller.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 3fbe16ea1a..0f54d3329a 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -110,7 +110,7 @@ impl Ps2 { } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 100_000; + let mut timeout = 1_000; while self.status().contains(StatusFlags::INPUT_FULL) { if timeout <= 0 { return Err(Error::WriteTimeout); @@ -121,7 +121,7 @@ impl Ps2 { } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 100_000; + let mut timeout = 1_000; while ! self.status().contains(StatusFlags::OUTPUT_FULL) { if timeout <= 0 { return Err(Error::ReadTimeout); @@ -132,8 +132,12 @@ impl Ps2 { } fn flush_read(&mut self, message: &str) { - while self.status().contains(StatusFlags::OUTPUT_FULL) { - eprintln!("ps2d: flush {}: {:X}", message, self.data.read()); + let mut timeout = 1_000; + while timeout > 0 { + if self.status().contains(StatusFlags::OUTPUT_FULL) { + eprintln!("ps2d: flush {}: {:X}", message, self.data.read()); + } + timeout -= 1; } } @@ -328,27 +332,30 @@ impl Ps2 { format_args!("mouse reset"), 4, |x| { + // Clear remaining data + x.flush_read("mouse before reset"); + // Reset mouse let mut b = x.mouse_command(MouseCommand::Reset)?; if b == 0xFA { b = x.read()?; if b != 0xAA { eprintln!("ps2d: mouse failed self test 1: {:02X}", b); - //return Err(Error::CommandRetry); + return Err(Error::CommandRetry); } b = x.read()?; if b != 0x00 { eprintln!("ps2d: mouse failed self test 2: {:02X}", b); - //return Err(Error::CommandRetry); + return Err(Error::CommandRetry); } } else { eprintln!("ps2d: mouse failed to reset: {:02X}", b); - //return Err(Error::CommandRetry); + return Err(Error::CommandRetry); } // Clear remaining data - x.flush_read("mouse reset"); + x.flush_read("mouse after reset"); Ok(b) } @@ -386,6 +393,9 @@ impl Ps2 { false }; + // Clear remaining data + self.flush_read("get device id"); + { // Set sample rate to maximum let sample_rate = 200; From a0300e2d9cdefc15b7490ad59a6c5347b0b417ec Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 8 Sep 2022 10:08:12 -0600 Subject: [PATCH 0530/1301] ps2d: Use thread::yield_now to ensure delays are acceptable --- ps2d/src/controller.rs | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 0f54d3329a..5659feb230 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -109,26 +109,28 @@ impl Ps2 { StatusFlags::from_bits_truncate(self.status.read()) } - fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 1_000; - while self.status().contains(StatusFlags::INPUT_FULL) { - if timeout <= 0 { - return Err(Error::WriteTimeout); - } - timeout -= 1; - } - Ok(()) - } - fn wait_read(&mut self) -> Result<(), Error> { let mut timeout = 1_000; - while ! self.status().contains(StatusFlags::OUTPUT_FULL) { - if timeout <= 0 { - return Err(Error::ReadTimeout); + while timeout > 0 { + if self.status().contains(StatusFlags::OUTPUT_FULL) { + return Ok(()); } + std::thread::yield_now(); timeout -= 1; } - Ok(()) + Err(Error::ReadTimeout) + } + + fn wait_write(&mut self) -> Result<(), Error> { + let mut timeout = 1_000; + while timeout > 0 { + if ! self.status().contains(StatusFlags::INPUT_FULL) { + return Ok(()); + } + std::thread::yield_now(); + timeout -= 1; + } + Err(Error::WriteTimeout) } fn flush_read(&mut self, message: &str) { @@ -137,6 +139,7 @@ impl Ps2 { if self.status().contains(StatusFlags::OUTPUT_FULL) { eprintln!("ps2d: flush {}: {:X}", message, self.data.read()); } + std::thread::yield_now(); timeout -= 1; } } From 80c60f01117baf72a8390a873dae2fa933356967 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 8 Sep 2022 10:40:03 -0600 Subject: [PATCH 0531/1301] ps2d: Set resolution and scaling instead of using defaults --- ps2d/src/controller.rs | 55 ++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 5659feb230..72cf748ec4 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -77,6 +77,8 @@ enum KeyboardCommandData { #[repr(u8)] #[allow(dead_code)] enum MouseCommand { + SetScaling1To1 = 0xE6, + SetScaling2To1 = 0xE7, GetDeviceId = 0xF2, EnableReporting = 0xF4, SetDefaultsDisable = 0xF5, @@ -87,6 +89,7 @@ enum MouseCommand { #[derive(Clone, Copy, Debug)] #[repr(u8)] enum MouseCommandData { + SetResolution = 0xE8, SetSampleRate = 0xF3, } @@ -105,41 +108,45 @@ impl Ps2 { } } + fn delay() { + std::thread::sleep(std::time::Duration::from_millis(10)); + } + fn status(&mut self) -> StatusFlags { StatusFlags::from_bits_truncate(self.status.read()) } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 1_000; + let mut timeout = 10; while timeout > 0 { if self.status().contains(StatusFlags::OUTPUT_FULL) { return Ok(()); } - std::thread::yield_now(); + Self::delay(); timeout -= 1; } Err(Error::ReadTimeout) } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 1_000; + let mut timeout = 10; while timeout > 0 { if ! self.status().contains(StatusFlags::INPUT_FULL) { return Ok(()); } - std::thread::yield_now(); + Self::delay(); timeout -= 1; } Err(Error::WriteTimeout) } fn flush_read(&mut self, message: &str) { - let mut timeout = 1_000; + let mut timeout = 10; while timeout > 0 { - if self.status().contains(StatusFlags::OUTPUT_FULL) { + while self.status().contains(StatusFlags::OUTPUT_FULL) { eprintln!("ps2d: flush {}: {:X}", message, self.data.read()); } - std::thread::yield_now(); + Self::delay(); timeout -= 1; } } @@ -364,17 +371,6 @@ impl Ps2 { } )?; - { - // Set defaults - b = self.mouse_command(MouseCommand::SetDefaults)?; - if b != 0xFA { - eprintln!("ps2d: mouse failed to set defaults: {:02X}", b); - } - - // Clear remaining data - self.flush_read("mouse defaults"); - } - { // Enable extra packet on mouse //TODO: show error return values @@ -399,6 +395,29 @@ impl Ps2 { // Clear remaining data self.flush_read("get device id"); + { + // Set resolution to maximum + let resolution = 3; + b = self.mouse_command_data(MouseCommandData::SetResolution, resolution)?; + if b != 0xFA { + eprintln!("ps2d: mouse failed to set resolution to {}: {:02X}", resolution, b); + } + + // Clear remaining data + self.flush_read("set sample rate"); + } + + { + // Set scaling to 1:1 + b = self.mouse_command(MouseCommand::SetScaling1To1)?; + if b != 0xFA { + eprintln!("ps2d: mouse failed to set scaling: {:02X}", b); + } + + // Clear remaining data + self.flush_read("set sample rate"); + } + { // Set sample rate to maximum let sample_rate = 200; From 303b5ae6b8d2a6ea52550cf384629d7c9d5908a4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 8 Sep 2022 18:19:47 -0600 Subject: [PATCH 0532/1301] ps2d: Improve timing and control over device scanning --- ps2d/src/controller.rs | 108 +++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 32 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 72cf748ec4..75f7266085 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -2,6 +2,18 @@ use syscall::io::{Io, Pio, ReadOnly, WriteOnly}; use std::fmt; +#[cfg(target_arch = "aarch64")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::aarch64::__yield(); } + +#[cfg(target_arch = "x86")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::x86::_mm_pause(); } + +#[cfg(target_arch = "x86_64")] +#[inline(always)] +pub(crate) unsafe fn pause() { std::arch::x86_64::_mm_pause(); } + #[derive(Debug)] pub enum Error { CommandRetry, @@ -79,6 +91,7 @@ enum KeyboardCommandData { enum MouseCommand { SetScaling1To1 = 0xE6, SetScaling2To1 = 0xE7, + StatusRequest = 0xE9, GetDeviceId = 0xF2, EnableReporting = 0xF4, SetDefaultsDisable = 0xF5, @@ -108,45 +121,41 @@ impl Ps2 { } } - fn delay() { - std::thread::sleep(std::time::Duration::from_millis(10)); - } - fn status(&mut self) -> StatusFlags { StatusFlags::from_bits_truncate(self.status.read()) } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 10; + let mut timeout = 100_000; while timeout > 0 { if self.status().contains(StatusFlags::OUTPUT_FULL) { return Ok(()); } - Self::delay(); + unsafe { pause(); } timeout -= 1; } Err(Error::ReadTimeout) } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 10; + let mut timeout = 100_000; while timeout > 0 { if ! self.status().contains(StatusFlags::INPUT_FULL) { return Ok(()); } - Self::delay(); + unsafe { pause(); } timeout -= 1; } Err(Error::WriteTimeout) } fn flush_read(&mut self, message: &str) { - let mut timeout = 10; + let mut timeout = 100; while timeout > 0 { while self.status().contains(StatusFlags::OUTPUT_FULL) { eprintln!("ps2d: flush {}: {:X}", message, self.data.read()); } - Self::delay(); + unsafe { pause(); } timeout -= 1; } } @@ -210,7 +219,7 @@ impl Ps2 { } fn keyboard_command_inner(&mut self, command: u8) -> Result { - self.write(command as u8)?; + self.write(command)?; match self.read()? { 0xFE => Err(Error::CommandRetry), value => Ok(value), @@ -243,7 +252,7 @@ impl Ps2 { fn mouse_command_inner(&mut self, command: u8) -> Result { self.command(Command::WriteSecond)?; - self.write(command as u8)?; + self.write(command)?; match self.read()? { 0xFE => Err(Error::CommandRetry), value => Ok(value), @@ -309,9 +318,29 @@ impl Ps2 { } // Clear remaining data - self.flush_read("keyboard defaults"); + self.flush_read("keyboard reset"); } + self.retry( + format_args!("keyboard defaults"), + 4, + |x| { + x.flush_read("keyboard before defaults"); + + // Set defaults and disable scanning + let b = x.keyboard_command(KeyboardCommand::SetDefaultsDisable)?; + if b != 0xFA { + eprintln!("ps2d: keyboard failed to set defaults: {:02X}", b); + return Err(Error::CommandRetry); + } + + // Clear remaining data + x.flush_read("keyboard after defaults"); + + Ok(b) + } + )?; + { // Set scancode set to 2 let scancode_set = 2; @@ -371,6 +400,17 @@ impl Ps2 { } )?; + { + // Set defaults + b = self.mouse_command(MouseCommand::SetDefaults)?; + if b != 0xFA { + eprintln!("ps2d: mouse failed to set defaults: {:02X}", b); + } + + // Clear remaining data + self.flush_read("mouse defaults"); + } + { // Enable extra packet on mouse //TODO: show error return values @@ -430,12 +470,23 @@ impl Ps2 { self.flush_read("set sample rate"); } + { + b = self.mouse_command(MouseCommand::StatusRequest)?; + if b != 0xFA { + eprintln!("ps2d: mouse failed to request status: {:02X}", b); + } else { + let a = self.read()?; + let b = self.read()?; + let c = self.read()?; + + eprintln!("ps2d: mouse status {:#x} resolution {:#x} sample rate {:#x}", a, b, c); + } + } + Ok(mouse_extra) } pub fn init(&mut self) -> Result { - let mut b; - // Clear remaining data self.flush_read("init start"); @@ -449,10 +500,11 @@ impl Ps2 { } // Disable clocks, disable interrupts, and disable translate + let mut config; { // Since the default config may have interrupts enabled, and the kernel may eat up // our data in that case, we will write a config without reading the current one - let mut config = ConfigFlags::POST_PASSED | + config = ConfigFlags::POST_PASSED | ConfigFlags::FIRST_DISABLED | ConfigFlags::SECOND_DISABLED; eprintln!("ps2d: config set {:?}", config); @@ -485,30 +537,22 @@ impl Ps2 { { // Enable keyboard data reporting - b = self.keyboard_command(KeyboardCommand::EnableReporting)?; - if b != 0xFA { - eprintln!("ps2d: keyboard failed to enable reporting: {:02X}", b); - } - - // Clear remaining data - self.flush_read("keyboard enable reporting"); + // Use inner function to prevent retries + self.keyboard_command_inner(KeyboardCommand::EnableReporting as u8)?; + // Response is ignored since scanning is now on + //TODO: fix by using interrupts? } if mouse_found { // Enable mouse data reporting - b = self.mouse_command(MouseCommand::EnableReporting)?; - if b != 0xFA { - eprintln!("ps2d: mouse failed to enable reporting: {:02X}", b); - } - - // Clear remaining data - self.flush_read("mouse enable reporting"); + // Use inner function to prevent retries + self.mouse_command_inner(MouseCommand::EnableReporting as u8)?; + // Response is ignored since scanning is now on + //TODO: fix by using interrupts? } // Enable clocks and interrupts { - let mut config = self.config()?; - eprintln!("ps2d: config get {:?}", config); config.remove(ConfigFlags::FIRST_DISABLED); config.insert(ConfigFlags::FIRST_TRANSLATE); config.insert(ConfigFlags::FIRST_INTERRUPT); From efc5cc712d7427242f0bd149d2fcbf8c345bae38 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 9 Sep 2022 08:38:52 -0600 Subject: [PATCH 0533/1301] Disable xhcid until it works on real hardware --- xhcid/config.toml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/xhcid/config.toml b/xhcid/config.toml index b80bae57a4..5244252bc1 100644 --- a/xhcid/config.toml +++ b/xhcid/config.toml @@ -1,7 +1,8 @@ -[[drivers]] -name = "XHCI" -class = 12 -subclass = 3 -interface = 48 -command = ["xhcid"] -use_channel = true +# Disabled - causes issues on real hardware +# [[drivers]] +# name = "XHCI" +# class = 12 +# subclass = 3 +# interface = 48 +# command = ["xhcid"] +# use_channel = true From ae66182c4ec3b3a42aec36560e387618e402ef51 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 9 Sep 2022 08:51:02 -0600 Subject: [PATCH 0534/1301] Name disk driver log files based on scheme name --- ahcid/src/main.rs | 12 ++++++------ ided/src/main.rs | 3 ++- nvmed/src/main.rs | 22 +++++++++++----------- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 6690684c3e..3da29c3d48 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -19,7 +19,7 @@ use crate::scheme::DiskScheme; pub mod ahci; pub mod scheme; -fn setup_logging() -> Option<&'static RedoxLogger> { +fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() @@ -30,25 +30,25 @@ fn setup_logging() -> Option<&'static RedoxLogger> { ); #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "ahci.log") { + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.log", name)) { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this b.with_filter(log::LevelFilter::Info) .flush_on_newline(true) .build() ), - Err(error) => eprintln!("ahcid: failed to create ahci.log: {}", error), + Err(error) => eprintln!("ahcid: failed to create log: {}", error), } #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "ahci.ansi.log") { + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.ansi.log", name)) { Ok(b) => logger = logger.with_output( b.with_filter(log::LevelFilter::Info) .with_ansi_escape_codes() .flush_on_newline(true) .build() ), - Err(error) => eprintln!("ahcid: failed to create ahci.ansi.log: {}", error), + Err(error) => eprintln!("ahcid: failed to create ansi log: {}", error), } match logger.enable() { @@ -82,7 +82,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let irq_str = args.next().expect("ahcid: no irq provided"); let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); - let _logger_ref = setup_logging(); + let _logger_ref = setup_logging(&name); info!(" + AHCI {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); diff --git a/ided/src/main.rs b/ided/src/main.rs index 315beb5cad..8ad04133da 100644 --- a/ided/src/main.rs +++ b/ided/src/main.rs @@ -80,12 +80,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { PcidServerHandle::connect_default().expect("ided: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("ided: failed to fetch config"); + let mut name = pci_config.func.name(); name.push_str("_ide"); let _logger_ref = setup_logging(&name); - info!("IDE {:?}", pci_config); + info!("IDE PCI CONFIG: {:?}", pci_config); let pci_header = pcid_handle.fetch_header().expect("ided: failed to fetch PCI header"); let (primary, primary_irq) = if pci_header.interface() & 1 != 0 { diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 6d11e209bb..12342367cf 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -239,36 +239,36 @@ fn get_int_method( } } -fn setup_logging() -> Option<&'static RedoxLogger> { +fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Debug) // limit global output to important info + .with_filter(log::LevelFilter::Info) // limit global output to important info .with_ansi_escape_codes() .flush_on_newline(true) .build() ); #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "nvme.log") { + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.log", name)) { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this b.with_filter(log::LevelFilter::Info) .flush_on_newline(true) .build() ), - Err(error) => eprintln!("nvmed: failed to create nvme.log: {}", error), + Err(error) => eprintln!("nvmed: failed to create log: {}", error), } #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "nvme.ansi.log") { + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.ansi.log", name)) { Ok(b) => logger = logger.with_output( b.with_filter(log::LevelFilter::Info) .with_ansi_escape_codes() .flush_on_newline(true) .build() ), - Err(error) => eprintln!("nvmed: failed to create nvme.ansi.log: {}", error), + Err(error) => eprintln!("nvmed: failed to create ansi log: {}", error), } match logger.enable() { @@ -287,14 +287,17 @@ fn main() { redox_daemon::Daemon::new(daemon).expect("nvmed: failed to daemonize"); } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let _logger_ref = setup_logging(); - let mut pcid_handle = PcidServerHandle::connect_default().expect("nvmed: failed to setup channel to pcid"); let pci_config = pcid_handle .fetch_config() .expect("nvmed: failed to fetch config"); + let mut name = pci_config.func.name(); + name.push_str("_nvme"); + + let _logger_ref = setup_logging(&name); + let bar = match pci_config.func.bars[0] { PciBar::Memory32(mem) => match mem { 0 => panic!("BAR 0 is mapped to address 0"), @@ -309,9 +312,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let bar_size = pci_config.func.bar_sizes[0]; let irq = pci_config.func.legacy_interrupt_line; - let mut name = pci_config.func.name(); - name.push_str("_nvme"); - log::info!("NVME PCI CONFIG: {:?}", pci_config); let allocated_bars = AllocatedBars::default(); From 4d05737b63aed9e4429ea8c33eb397c4d765379f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 9 Sep 2022 09:29:10 -0600 Subject: [PATCH 0535/1301] ps2d: Increase timeouts --- ps2d/src/controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 75f7266085..8ab469af9f 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -126,7 +126,7 @@ impl Ps2 { } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 100_000; + let mut timeout = 1_000_000; while timeout > 0 { if self.status().contains(StatusFlags::OUTPUT_FULL) { return Ok(()); @@ -138,7 +138,7 @@ impl Ps2 { } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 100_000; + let mut timeout = 1_000_000; while timeout > 0 { if ! self.status().contains(StatusFlags::INPUT_FULL) { return Ok(()); From 91bb118d73489fb4acbe328b41dcd3fb95f16c58 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 10 Sep 2022 15:43:01 -0600 Subject: [PATCH 0536/1301] ided: support 28-bit LBA --- ided/src/ide.rs | 53 +++++++++++++++++++++++++++++++----------------- ided/src/main.rs | 1 + 2 files changed, 35 insertions(+), 19 deletions(-) diff --git a/ided/src/ide.rs b/ided/src/ide.rs index 2dd012cc73..a537d04d67 100644 --- a/ided/src/ide.rs +++ b/ided/src/ide.rs @@ -120,6 +120,7 @@ pub struct AtaDisk { pub chan_i: usize, pub dev: u8, pub size: u64, + pub lba_48: bool, } impl Disk for AtaDisk { @@ -147,14 +148,15 @@ impl Disk for AtaDisk { // Select drive chan.device_select.write(0xE0 | (self.dev << 4)); - // Set high sector count and LBA - //TODO: only if LBA mode is 48-bit - chan.control.writef(0x80, true); - chan.sector_count.write((sectors >> 8) as u8); - chan.lba_0.write((block >> 24) as u8); - chan.lba_1.write((block >> 32) as u8); - chan.lba_2.write((block >> 40) as u8); - chan.control.writef(0x80, false); + if self.lba_48 { + // Set high sector count and LBA + chan.control.writef(0x80, true); + chan.sector_count.write((sectors >> 8) as u8); + chan.lba_0.write((block >> 24) as u8); + chan.lba_1.write((block >> 32) as u8); + chan.lba_2.write((block >> 40) as u8); + chan.control.writef(0x80, false); + } // Set low sector count and LBA chan.sector_count.write(sectors as u8); @@ -164,7 +166,11 @@ impl Disk for AtaDisk { // Send command //TODO: use DMA - chan.command.write(AtaCommand::ReadPioExt as u8); + chan.command.write(if self.lba_48 { + AtaCommand::ReadPioExt as u8 + } else { + AtaCommand::ReadPio as u8 + }); // Read data for sector in 0..sectors { @@ -201,14 +207,15 @@ impl Disk for AtaDisk { // Select drive chan.device_select.write(0xE0 | (self.dev << 4)); - // Set high sector count and LBA - //TODO: only if LBA mode is 48-bit - chan.control.writef(0x80, true); - chan.sector_count.write((sectors >> 8) as u8); - chan.lba_0.write((block >> 24) as u8); - chan.lba_1.write((block >> 32) as u8); - chan.lba_2.write((block >> 40) as u8); - chan.control.writef(0x80, false); + if self.lba_48 { + // Set high sector count and LBA + chan.control.writef(0x80, true); + chan.sector_count.write((sectors >> 8) as u8); + chan.lba_0.write((block >> 24) as u8); + chan.lba_1.write((block >> 32) as u8); + chan.lba_2.write((block >> 40) as u8); + chan.control.writef(0x80, false); + } // Set low sector count and LBA chan.sector_count.write(sectors as u8); @@ -218,7 +225,11 @@ impl Disk for AtaDisk { // Send command //TODO: use DMA - chan.command.write(AtaCommand::WritePioExt as u8); + chan.command.write(if self.lba_48 { + AtaCommand::WritePioExt as u8 + } else { + AtaCommand::WritePio as u8 + }); // Write data for sector in 0..sectors { @@ -234,7 +245,11 @@ impl Disk for AtaDisk { } } - chan.command.write(AtaCommand::CacheFlushExt as u8); + chan.command.write(if self.lba_48 { + AtaCommand::CacheFlushExt as u8 + } else { + AtaCommand::CacheFlush as u8 + }); chan.polling(false)?; count += chunk.len(); diff --git a/ided/src/main.rs b/ided/src/main.rs index 8ad04133da..9cd6a6b616 100644 --- a/ided/src/main.rs +++ b/ided/src/main.rs @@ -223,6 +223,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { chan_i, dev, size: sectors * 512, + lba_48: lba_bits == 48, })); } } From a6bafa17b0b1acf9909046e5f5430d8c796f4cb2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 12 Sep 2022 21:47:16 -0600 Subject: [PATCH 0537/1301] Add pcid methods to read/write pci config region --- pcid/src/driver_interface/mod.rs | 18 ++++++++++++++++++ pcid/src/main.rs | 17 +++++++++++++++++ pcid/src/pci/mod.rs | 2 +- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index aedbf86f77..cc6dad2392 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -175,6 +175,8 @@ pub enum PcidClientRequest { FeatureStatus(PciFeature), FeatureInfo(PciFeature), SetFeatureInfo(SetFeatureInfo), + ReadConfig(u16), + WriteConfig(u16, u32), } #[derive(Debug, Serialize, Deserialize)] @@ -195,6 +197,8 @@ pub enum PcidClientResponse { Error(PcidServerResponseError), FeatureInfo(PciFeature, PciFeatureInfo), SetFeatureInfo(PciFeature), + ReadConfig(u32), + WriteConfig, } // TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over @@ -296,4 +300,18 @@ impl PcidServerHandle { other => Err(PcidClientHandleError::InvalidResponse(other)), } } + pub unsafe fn read_config(&mut self, offset: u16) -> Result { + self.send(&PcidClientRequest::ReadConfig(offset))?; + match self.recv()? { + PcidClientResponse::ReadConfig(value) => Ok(value), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } + pub unsafe fn write_config(&mut self, offset: u16, value: u32) -> Result<()> { + self.send(&PcidClientRequest::WriteConfig(offset, value))?; + match self.recv()? { + PcidClientResponse::WriteConfig => Ok(()), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 3dee0e8963..a298739c6d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -12,6 +12,7 @@ use redox_log::{OutputBuilder, RedoxLogger}; use crate::config::Config; use crate::pci::{CfgAccess, Pci, PciIter, PciBar, PciBus, PciClass, PciDev, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; use crate::pci::cap::Capability as PciCapability; +use crate::pci::func::{ConfigReader, ConfigWriter}; use crate::pcie::Pcie; mod config; @@ -180,6 +181,22 @@ impl DriverHandler { return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(PciFeature::MsiX)); } } + PcidClientRequest::ReadConfig(offset) => { + let value = unsafe { + with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { + func.read_u32(offset) + }) + }; + return PcidClientResponse::ReadConfig(value); + }, + PcidClientRequest::WriteConfig(offset, value) => { + unsafe { + with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { + func.write_u32(offset, value); + }); + } + return PcidClientResponse::WriteConfig; + } } } fn handle_spawn(mut self, pcid_to_client_write: Option, pcid_from_client_read: Option, args: driver_interface::SubdriverArguments) { diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 033693b2c1..e1a18b472f 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -18,7 +18,7 @@ mod bus; pub mod cap; mod class; mod dev; -mod func; +pub mod func; pub mod header; pub mod msi; From b8cb9d0e037e0a04a5006b33b9ad0904915b7589 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 12 Sep 2022 21:48:14 -0600 Subject: [PATCH 0538/1301] ided: DMA support --- ided/src/ide.rs | 225 ++++++++++++++++++++++++++++++++++++----------- ided/src/main.rs | 11 ++- 2 files changed, 181 insertions(+), 55 deletions(-) diff --git a/ided/src/ide.rs b/ided/src/ide.rs index a537d04d67..413cf85dc7 100644 --- a/ided/src/ide.rs +++ b/ided/src/ide.rs @@ -1,9 +1,10 @@ use std::{ + convert::TryInto, sync::{Arc, Mutex}, }; use syscall::{ error::{Error, Result, EIO}, - io::{Io, Pio, ReadOnly, WriteOnly}, + io::{Dma, Io, Pio, PhysBox, ReadOnly, WriteOnly}, }; use crate::ata::AtaCommand; @@ -20,6 +21,13 @@ pub(crate) unsafe fn pause() { std::arch::x86::_mm_pause(); } #[inline(always)] pub(crate) unsafe fn pause() { std::arch::x86_64::_mm_pause(); } +#[repr(packed)] +struct PrdtEntry { + phys: u32, + size: u16, + flags: u16, +} + pub struct Channel { pub data8: Pio, pub data32: Pio, @@ -34,11 +42,16 @@ pub struct Channel { pub command: WriteOnly>, pub alt_status: ReadOnly>, pub control: WriteOnly>, + pub busmaster_command: Pio, + pub busmaster_status: Pio, + pub busmaster_prdt: Pio, + prdt: Dma<[PrdtEntry; 16]>, + buf: Dma<[u8; 16 * 4096]>, } impl Channel { - pub fn new(base: u16, control_base: u16) -> Self { - Self { + pub fn new(base: u16, control_base: u16, busmaster_base: u16) -> Result { + let mut chan = Self { data8: Pio::new(base + 0), data32: Pio::new(base + 0), error: ReadOnly::new(Pio::new(base + 1)), @@ -52,18 +65,63 @@ impl Channel { command: WriteOnly::new(Pio::new(base + 7)), alt_status: ReadOnly::new(Pio::new(control_base)), control: WriteOnly::new(Pio::new(control_base)), + busmaster_command: Pio::new(busmaster_base), + busmaster_status: Pio::new(busmaster_base + 2), + busmaster_prdt: Pio::new(busmaster_base + 4), + prdt: unsafe { + Dma::from_physbox_zeroed( + //TODO: PhysBox::new_in_32bit_space(4096)? + PhysBox::new(4096)? + )?.assume_init() + }, + buf: unsafe { + Dma::from_physbox_zeroed( + //TODO: PhysBox::new_in_32bit_space(16 * 4096)? + PhysBox::new(16 * 4096)? + )?.assume_init() + }, + }; + + for i in 0..chan.prdt.len() { + chan.prdt[i] = PrdtEntry { + phys: (chan.buf.physical() + i * 4096).try_into().unwrap(), + size: 4096, + flags: if i + 1 == chan.prdt.len() { + 1 << 15 // End of table + } else { + 0 + }, + }; } + + Ok(chan) } - pub fn primary_compat() -> Self { - Self::new(0x1F0, 0x3F6) + pub fn primary_compat(busmaster_base: u16) -> Result { + Self::new(0x1F0, 0x3F6, busmaster_base) } - pub fn secondary_compat() -> Self { - Self::new(0x170, 0x376) + pub fn secondary_compat(busmaster_base: u16) -> Result { + Self::new(0x170, 0x376, busmaster_base) } - fn polling(&mut self, check: bool) -> Result<()> { + fn check_status(&mut self) -> Result { + let status = self.status.read(); + + if status & 0x01 != 0 { + log::error!("IDE error: {:#x}", self.error.read()); + return Err(Error::new(EIO)); + } + + if status & 0x20 != 0 { + log::error!("IDE device write fault"); + return Err(Error::new(EIO)); + } + + Ok(status) + } + + fn polling(&mut self, read: bool) -> Result<()> { /* #define ATA_SR_BSY 0x80 // Busy #define ATA_SR_DRDY 0x40 // Drive ready @@ -80,26 +138,16 @@ impl Channel { self.alt_status.read(); } - while self.status.readf(0x80) { - unsafe { pause(); } - } - - if check { - let status = self.status.read(); - - if status & 0x01 != 0 { - log::error!("IDE error"); - return Err(Error::new(EIO)); - } - - if status & 0x20 != 0 { - log::error!("IDE device write fault"); - return Err(Error::new(EIO)); - } - - if status & 0x08 == 0 { - log::error!("IDE data not ready"); - return Err(Error::new(EIO)); + loop { + let status = self.check_status()?; + if status & 0x80 != 0 { + unsafe { pause(); } + } else { + if read && status & 0x08 == 0 { + log::error!("IDE data not ready"); + return Err(Error::new(EIO)); + } + break; } } @@ -120,6 +168,7 @@ pub struct AtaDisk { pub chan_i: usize, pub dev: u8, pub size: u64, + pub dma: bool, pub lba_48: bool, } @@ -145,6 +194,18 @@ impl Disk for AtaDisk { let mut chan = self.chan.lock().unwrap(); + if self.dma { + // Stop bus master + chan.busmaster_command.writef(1, false); + // Set PRDT + let prdt = chan.prdt.physical(); + chan.busmaster_prdt.write(prdt.try_into().unwrap()); + // Set to read + chan.busmaster_command.writef(1 << 3, true); + // Clear interrupt and error bits + chan.busmaster_status.write(0b110); + } + // Select drive chan.device_select.write(0xE0 | (self.dev << 4)); @@ -165,23 +226,46 @@ impl Disk for AtaDisk { chan.lba_2.write((block >> 16) as u8); // Send command - //TODO: use DMA - chan.command.write(if self.lba_48 { - AtaCommand::ReadPioExt as u8 + chan.command.write(if self.dma { + if self.lba_48 { + AtaCommand::ReadDmaExt as u8 + } else { + AtaCommand::ReadDma as u8 + } } else { - AtaCommand::ReadPio as u8 + if self.lba_48 { + AtaCommand::ReadPioExt as u8 + } else { + AtaCommand::ReadPio as u8 + } }); // Read data - for sector in 0..sectors { - chan.polling(true)?; + if self.dma { + // Start bus master + chan.busmaster_command.writef(1, true); - for i in 0..128 { - let data = chan.data32.read(); - chunk[sector * 512 + i * 4 + 0] = (data >> 0) as u8; - chunk[sector * 512 + i * 4 + 1] = (data >> 8) as u8; - chunk[sector * 512 + i * 4 + 2] = (data >> 16) as u8; - chunk[sector * 512 + i * 4 + 3] = (data >> 24) as u8; + // Wait for transaction to finish + chan.polling(false)?; + + //TODO: use bus master status + + // Stop bus master + chan.busmaster_command.writef(1, false); + + // Read buffer + chunk.copy_from_slice(&chan.buf[..chunk.len()]); + } else { + for sector in 0..sectors { + chan.polling(true)?; + + for i in 0..128 { + let data = chan.data32.read(); + chunk[sector * 512 + i * 4 + 0] = (data >> 0) as u8; + chunk[sector * 512 + i * 4 + 1] = (data >> 8) as u8; + chunk[sector * 512 + i * 4 + 2] = (data >> 16) as u8; + chunk[sector * 512 + i * 4 + 3] = (data >> 24) as u8; + } } } @@ -204,6 +288,21 @@ impl Disk for AtaDisk { let mut chan = self.chan.lock().unwrap(); + if self.dma { + // Stop bus master + chan.busmaster_command.writef(1, false); + // Set PRDT + let prdt = chan.prdt.physical(); + chan.busmaster_prdt.write(prdt.try_into().unwrap()); + // Set to write + chan.busmaster_command.writef(1 << 3, false); + // Clear interrupt and error bits + chan.busmaster_status.write(0b110); + + // Write buffer + chan.buf[..chunk.len()].copy_from_slice(chunk); + } + // Select drive chan.device_select.write(0xE0 | (self.dev << 4)); @@ -224,24 +323,46 @@ impl Disk for AtaDisk { chan.lba_2.write((block >> 16) as u8); // Send command - //TODO: use DMA - chan.command.write(if self.lba_48 { - AtaCommand::WritePioExt as u8 + chan.command.write(if self.dma { + if self.lba_48 { + AtaCommand::WriteDmaExt as u8 + } else { + AtaCommand::WriteDma as u8 + } } else { - AtaCommand::WritePio as u8 + if self.lba_48 { + AtaCommand::WritePioExt as u8 + } else { + AtaCommand::WritePio as u8 + } }); // Write data - for sector in 0..sectors { + if self.dma { + // Start bus master + chan.busmaster_command.writef(1, true); + + // Wait for transaction to finish chan.polling(false)?; - for i in 0..128 { - chan.data32.write( - ((chunk[sector * 512 + i * 4 + 0] as u32) << 0) | - ((chunk[sector * 512 + i * 4 + 1] as u32) << 8) | - ((chunk[sector * 512 + i * 4 + 2] as u32) << 16) | - ((chunk[sector * 512 + i * 4 + 3] as u32) << 24) - ); + //TODO: use bus master status + + // Stop bus master + chan.busmaster_command.writef(1, false); + + chan.check_status()?; + } else { + for sector in 0..sectors { + chan.polling(false)?; + + for i in 0..128 { + chan.data32.write( + ((chunk[sector * 512 + i * 4 + 0] as u32) << 0) | + ((chunk[sector * 512 + i * 4 + 1] as u32) << 8) | + ((chunk[sector * 512 + i * 4 + 2] as u32) << 16) | + ((chunk[sector * 512 + i * 4 + 3] as u32) << 24) + ); + } } } diff --git a/ided/src/main.rs b/ided/src/main.rs index 9cd6a6b616..0e3c9f333b 100644 --- a/ided/src/main.rs +++ b/ided/src/main.rs @@ -1,5 +1,5 @@ use log::{error, info}; -use pcid_interface::PcidServerHandle; +use pcid_interface::{PciBar, PcidServerHandle}; use redox_log::{OutputBuilder, RedoxLogger}; use std::{ fs::File, @@ -89,15 +89,19 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { info!("IDE PCI CONFIG: {:?}", pci_config); let pci_header = pcid_handle.fetch_header().expect("ided: failed to fetch PCI header"); + let busmaster_base = match pci_header.get_bar(4) { + PciBar::Port(port) => port, + other => panic!("TODO: IDE busmaster BAR {:#x?}", other), + }; let (primary, primary_irq) = if pci_header.interface() & 1 != 0 { panic!("TODO: IDE primary channel is PCI native"); } else { - (Channel::primary_compat(), 14) + (Channel::primary_compat(busmaster_base).unwrap(), 14) }; let (secondary, secondary_irq) = if pci_header.interface() & 1 != 0 { panic!("TODO: IDE secondary channel is PCI native"); } else { - (Channel::secondary_compat(), 15) + (Channel::secondary_compat(busmaster_base + 8).unwrap(), 15) }; unsafe { syscall::iopl(3).expect("ided: failed to get I/O privilege") }; @@ -223,6 +227,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { chan_i, dev, size: sectors * 512, + dma: true, //TODO: detect! lba_48: lba_bits == 48, })); } From 2462857e2dfd02a4ea81368463d5f457cdafa4fd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 13 Sep 2022 14:38:50 -0600 Subject: [PATCH 0539/1301] ided: Improvements to DMA code, fixes some virtualbox issues --- ided/src/ide.rs | 96 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 23 deletions(-) diff --git a/ided/src/ide.rs b/ided/src/ide.rs index 413cf85dc7..2b0a4a76bd 100644 --- a/ided/src/ide.rs +++ b/ided/src/ide.rs @@ -45,8 +45,8 @@ pub struct Channel { pub busmaster_command: Pio, pub busmaster_status: Pio, pub busmaster_prdt: Pio, - prdt: Dma<[PrdtEntry; 16]>, - buf: Dma<[u8; 16 * 4096]>, + prdt: Dma<[PrdtEntry; 128]>, + buf: Dma<[u8; 128 * 512]>, } impl Channel { @@ -71,29 +71,17 @@ impl Channel { prdt: unsafe { Dma::from_physbox_zeroed( //TODO: PhysBox::new_in_32bit_space(4096)? - PhysBox::new(4096)? + PhysBox::new(4096 /* 128 * 8 page aligned */)? )?.assume_init() }, buf: unsafe { Dma::from_physbox_zeroed( //TODO: PhysBox::new_in_32bit_space(16 * 4096)? - PhysBox::new(16 * 4096)? + PhysBox::new(128 * 512)? )?.assume_init() }, }; - for i in 0..chan.prdt.len() { - chan.prdt[i] = PrdtEntry { - phys: (chan.buf.physical() + i * 4096).try_into().unwrap(), - size: 4096, - flags: if i + 1 == chan.prdt.len() { - 1 << 15 // End of table - } else { - 0 - }, - }; - } - Ok(chan) } @@ -189,14 +177,26 @@ impl Disk for AtaDisk { //TODO: support other LBA modes assert!(block < 0x1_0000_0000_0000); - let sectors = chunk.len() / 512; - assert!(sectors < 0x1_0000); + let sectors = (chunk.len() + 511) / 512; + assert!(sectors <= 128); let mut chan = self.chan.lock().unwrap(); if self.dma { // Stop bus master chan.busmaster_command.writef(1, false); + // Make PRDT EOT match chunk size + for i in 0..sectors { + chan.prdt[i] = PrdtEntry { + phys: (chan.buf.physical() + i * 512).try_into().unwrap(), + size: 512, + flags: if i + 1 == sectors { + 1 << 15 // End of table + } else { + 0 + }, + }; + } // Set PRDT let prdt = chan.prdt.physical(); chan.busmaster_prdt.write(prdt.try_into().unwrap()); @@ -207,6 +207,7 @@ impl Disk for AtaDisk { } // Select drive + //TODO: upper part of LBA 28 chan.device_select.write(0xE0 | (self.dev << 4)); if self.lba_48 { @@ -248,11 +249,30 @@ impl Disk for AtaDisk { // Wait for transaction to finish chan.polling(false)?; - //TODO: use bus master status + // Wait for bus master to finish + let error = loop { + let status = chan.busmaster_status.read(); + if status & 1 << 1 != 0 { + // Break with error status + break true; + } + if status & 1 == 0 { + // Break when not busy and no error + break false; + } + }; // Stop bus master chan.busmaster_command.writef(1, false); + // Clear bus master error and interrupt + chan.busmaster_status.write(0b110); + + if error { + log::error!("IDE bus master error"); + return Err(Error::new(EIO)); + } + // Read buffer chunk.copy_from_slice(&chan.buf[..chunk.len()]); } else { @@ -283,14 +303,26 @@ impl Disk for AtaDisk { //TODO: support other LBA modes assert!(block < 0x1_0000_0000_0000); - let sectors = chunk.len() / 512; - assert!(sectors < 0x1_0000); + let sectors = (chunk.len() + 511) / 512; + assert!(sectors <= 128); let mut chan = self.chan.lock().unwrap(); if self.dma { // Stop bus master chan.busmaster_command.writef(1, false); + // Make PRDT EOT match chunk size + for i in 0..sectors { + chan.prdt[i] = PrdtEntry { + phys: (chan.buf.physical() + i * 512).try_into().unwrap(), + size: 512, + flags: if i + 1 == sectors { + 1 << 15 // End of table + } else { + 0 + }, + }; + } // Set PRDT let prdt = chan.prdt.physical(); chan.busmaster_prdt.write(prdt.try_into().unwrap()); @@ -304,6 +336,7 @@ impl Disk for AtaDisk { } // Select drive + //TODO: upper part of LBA 28 chan.device_select.write(0xE0 | (self.dev << 4)); if self.lba_48 { @@ -345,12 +378,29 @@ impl Disk for AtaDisk { // Wait for transaction to finish chan.polling(false)?; - //TODO: use bus master status + // Wait for bus master to finish + let error = loop { + let status = chan.busmaster_status.read(); + if status & 1 << 1 != 0 { + // Break with error status + break true; + } + if status & 1 == 0 { + // Break when not busy and no error + break false; + } + }; // Stop bus master chan.busmaster_command.writef(1, false); - chan.check_status()?; + // Clear bus master error and interrupt + chan.busmaster_status.write(0b110); + + if error { + log::error!("IDE bus master error"); + return Err(Error::new(EIO)); + } } else { for sector in 0..sectors { chan.polling(false)?; From 14be75f29f92e7dedd6c14443546fa1ebee855da Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 14 Sep 2022 08:33:48 -0600 Subject: [PATCH 0540/1301] ided: Add trace logs for IDE read/write --- ided/src/ide.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ided/src/ide.rs b/ided/src/ide.rs index 2b0a4a76bd..7cadcae91e 100644 --- a/ided/src/ide.rs +++ b/ided/src/ide.rs @@ -180,6 +180,8 @@ impl Disk for AtaDisk { let sectors = (chunk.len() + 511) / 512; assert!(sectors <= 128); + log::trace!("IDE read chan {} dev {} block {:#x} count {:#x}", self.chan_i, self.dev, block, sectors); + let mut chan = self.chan.lock().unwrap(); if self.dma { @@ -306,6 +308,8 @@ impl Disk for AtaDisk { let sectors = (chunk.len() + 511) / 512; assert!(sectors <= 128); + log::trace!("IDE write chan {} dev {} block {:#x} count {:#x}", self.chan_i, self.dev, block, sectors); + let mut chan = self.chan.lock().unwrap(); if self.dma { From cbcf133518980689b1601abe8e1c93892ba16d79 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 16 Sep 2022 13:28:04 -0600 Subject: [PATCH 0541/1301] vesad: use framebuffer stride --- vesad/src/display.rs | 25 +++------ vesad/src/main.rs | 21 ++++---- vesad/src/scheme.rs | 100 ++++++++++++++++++++++++++++-------- vesad/src/screen/graphic.rs | 17 ++---- vesad/src/screen/mod.rs | 6 +-- vesad/src/screen/text.rs | 14 ++--- 6 files changed, 110 insertions(+), 73 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index c07e6bcf90..fe04c500ce 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -24,7 +24,6 @@ static FONT_ITALIC: &'static [u8] = include_bytes!("../res/DejaVuSansMono-Obliqu pub struct Display { pub width: usize, pub height: usize, - pub onscreen: &'static mut [u32], pub offscreen: &'static mut [u32], #[cfg(feature="rusttype")] pub font: Font<'static>, @@ -38,7 +37,7 @@ pub struct Display { impl Display { #[cfg(not(feature="rusttype"))] - pub fn new(width: usize, height: usize, onscreen: usize) -> Display { + pub fn new(width: usize, height: usize) -> Display { let size = width * height; let offscreen = unsafe { @@ -50,13 +49,12 @@ impl Display { Display { width: width, height: height, - onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } } } #[cfg(feature="rusttype")] - pub fn new(width: usize, height: usize, onscreen: usize) -> Display { + pub fn new(width: usize, height: usize) -> Display { let size = width * height; let offscreen = unsafe { Global @@ -67,7 +65,6 @@ impl Display { Display { width: width, height: height, - onscreen: unsafe { slice::from_raw_parts_mut(onscreen as *mut u32, size) }, offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }, font: FontCollection::from_bytes(FONT).into_font().unwrap(), font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(), @@ -124,9 +121,6 @@ impl Display { self.width = width; self.height = height; - let onscreen = self.onscreen.as_mut_ptr(); - self.onscreen = unsafe { slice::from_raw_parts_mut(onscreen, size) }; - unsafe { Global.deallocate(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; self.offscreen = unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }; } else { @@ -268,7 +262,7 @@ impl Display { } /// Copy from offscreen to onscreen - pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize) { + pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize, onscreen: &mut [u32], stride: usize) { let start_y = cmp::min(self.height, y); let end_y = cmp::min(self.height, y + h); @@ -276,13 +270,10 @@ impl Display { let len = (cmp::min(self.width, x + w) - start_x) * 4; let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; - let mut onscreen_ptr = self.onscreen.as_mut_ptr() as usize; + let mut onscreen_ptr = onscreen.as_mut_ptr() as usize; - let stride = self.width * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - onscreen_ptr += offset; + offscreen_ptr += (y * self.width + start_x) * 4; + onscreen_ptr += (y * stride + start_x) * 4; let mut rows = end_y - start_y; while rows > 0 { @@ -293,8 +284,8 @@ impl Display { len ); } - offscreen_ptr += stride; - onscreen_ptr += stride; + offscreen_ptr += self.width * 4; + onscreen_ptr += stride * 4; rows -= 1; } } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index fa3778cce6..87b1ef6b90 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -7,7 +7,7 @@ use std::{env, process, ptr}; use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::{RawFd, FromRawFd}; -use syscall::{physmap, physunmap, Packet, SchemeMut, EVENT_READ, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE}; +use syscall::{Packet, SchemeMut, EVENT_READ}; use crate::scheme::{DisplayScheme, HandleKind}; @@ -43,24 +43,23 @@ fn main() { .expect("FRAMEBUFFER_ADDR not set"), 16 ).expect("failed to parse FRAMEBUFFER_ADDR"); + let stride = usize::from_str_radix( + &env::var("FRAMEBUFFER_STRIDE") + .expect("FRAMEBUFFER_STRIDE not set"), + 16 + ).expect("failed to parse FRAMEBUFFER_STRIDE"); - println!("vesad: {}x{} at 0x{:X}", width, height, physbaseptr); + println!("vesad: {}x{} stride {} at 0x{:X}", width, height, stride, physbaseptr); if physbaseptr == 0 { return; } - redox_daemon::Daemon::new(|daemon| inner(daemon, width, height, physbaseptr, &spec)).expect("failed to create daemon"); + redox_daemon::Daemon::new(|daemon| inner(daemon, width, height, physbaseptr, stride, &spec)).expect("failed to create daemon"); } -fn inner(daemon: redox_daemon::Daemon, width: usize, height: usize, physbaseptr: usize, spec: &[bool]) -> ! { +fn inner(daemon: redox_daemon::Daemon, width: usize, height: usize, physbaseptr: usize, stride: usize, spec: &[bool]) -> ! { let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); - let size = width * height; - //TODO: Remap on resize - let largest_size = 8 * 1024 * 1024; - let onscreen = unsafe { physmap(physbaseptr, largest_size * 4, PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE).expect("vesad: failed to map VBE LFB") }; - unsafe { ptr::write_bytes(onscreen as *mut u32, 0, size); } - - let mut scheme = DisplayScheme::new(width, height, onscreen, &spec); + let mut scheme = DisplayScheme::new(width, height, physbaseptr, stride, &spec); syscall::setrens(0, 0).expect("vesad: failed to enter null namespace"); diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index b16f7cf456..f08f2782fd 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,8 +1,8 @@ use std::collections::BTreeMap; -use std::{mem, slice, str}; +use std::{mem, ptr, slice, str}; use orbclient::{Event, EventOption}; -use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, OldMap, O_NONBLOCK, Result, SchemeMut}; +use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, OldMap, O_NONBLOCK, physmap, physunmap, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, Result, SchemeMut}; use crate::display::Display; use crate::screen::{Screen, GraphicScreen, TextScreen}; @@ -24,6 +24,9 @@ pub struct Handle { pub struct DisplayScheme { width: usize, height: usize, + physbaseptr: usize, + onscreen: &'static mut [u32], + stride: usize, active: usize, pub screens: BTreeMap>, next_id: usize, @@ -31,24 +34,42 @@ pub struct DisplayScheme { } impl DisplayScheme { - pub fn new(width: usize, height: usize, onscreen: usize, spec: &[bool]) -> DisplayScheme { + pub fn new(width: usize, height: usize, physbaseptr: usize, stride: usize, spec: &[bool]) -> DisplayScheme { + let onscreen = unsafe { + let size = stride * height; + let onscreen_ptr = physmap( + physbaseptr, + size * 4, + PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE + ).expect("vesad: failed to map framebuffer") as *mut u32; + ptr::write_bytes(onscreen_ptr, 0, size); + + slice::from_raw_parts_mut( + onscreen_ptr, + size + ) + }; + let mut screens: BTreeMap> = BTreeMap::new(); let mut screen_i = 1; for &screen_type in spec.iter() { if screen_type { - screens.insert(screen_i, Box::new(GraphicScreen::new(Display::new(width, height, onscreen)))); + screens.insert(screen_i, Box::new(GraphicScreen::new(Display::new(width, height)))); } else { - screens.insert(screen_i, Box::new(TextScreen::new(Display::new(width, height, onscreen)))); + screens.insert(screen_i, Box::new(TextScreen::new(Display::new(width, height)))); } screen_i += 1; } DisplayScheme { - width: width, - height: height, + width, + height, + physbaseptr, + onscreen, + stride, active: 1, - screens: screens, + screens, next_id: 0, handles: BTreeMap::new(), } @@ -69,6 +90,44 @@ impl DisplayScheme { Some(0) } + + fn resize(&mut self, width: usize, height: usize, stride: usize) { + println!("Resizing to {}, {} stride {}", width, height, stride); + + // Unmap old onscreen + unsafe { + physunmap(self.onscreen.as_mut_ptr() as usize).expect("vesad: failed to unmap framebuffer"); + } + + // Map new onscreen + self.onscreen = unsafe { + let size = stride * height; + let onscreen_ptr = physmap( + self.physbaseptr, + size * 4, + PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE + ).expect("vesad: failed to map framebuffer") as *mut u32; + ptr::write_bytes(onscreen_ptr, 0, size); + + slice::from_raw_parts_mut( + onscreen_ptr, + size + ) + }; + + // Update size + self.width = width; + self.height = height; + self.stride = stride; + + // Resize screens + for (screen_i, screen) in self.screens.iter_mut() { + screen.resize(width, height); + if *screen_i == self.active { + screen.redraw(self.onscreen, self.stride); + } + } + } } impl SchemeMut for DisplayScheme { @@ -195,7 +254,7 @@ impl SchemeMut for DisplayScheme { if let HandleKind::Screen(screen_i) = handle.kind { if let Some(screen) = self.screens.get_mut(&screen_i) { if screen_i == self.active { - screen.sync(); + screen.sync(self.onscreen, self.stride); } return Ok(0); } @@ -224,7 +283,7 @@ impl SchemeMut for DisplayScheme { let new_active = (buf[0] - 0xF4) as usize + 1; if let Some(screen) = self.screens.get_mut(&new_active) { self.active = new_active; - screen.redraw(); + screen.redraw(self.onscreen, self.stride); } Ok(1) } else { @@ -246,15 +305,10 @@ impl SchemeMut for DisplayScheme { _ => () }, EventOption::Resize(resize_event) => { - println!("Resizing to {}, {}", resize_event.width, resize_event.height); - self.width = resize_event.width as usize; - self.height = resize_event.height as usize; - for (screen_i, screen) in self.screens.iter_mut() { - screen.resize(resize_event.width as usize, resize_event.height as usize); - if *screen_i == self.active { - screen.redraw(); - } - } + let width = resize_event.width as usize; + let height = resize_event.height as usize; + let stride = width; //TODO: get stride somehow + self.resize(width, height, stride); }, _ => () }; @@ -262,7 +316,7 @@ impl SchemeMut for DisplayScheme { if let Some(new_active) = new_active_opt { if let Some(screen) = self.screens.get_mut(&new_active) { self.active = new_active; - screen.redraw(); + screen.redraw(self.onscreen, self.stride); } } else { if let Some(screen) = self.screens.get_mut(&self.active) { @@ -274,7 +328,11 @@ impl SchemeMut for DisplayScheme { Ok(events.len() * mem::size_of::()) }, HandleKind::Screen(screen_i) => if let Some(screen) = self.screens.get_mut(&screen_i) { - screen.write(buf, screen_i == self.active) + let count = screen.write(buf)?; + if screen_i == self.active { + screen.sync(self.onscreen, self.stride); + } + Ok(count) } else { Err(Error::new(EBADF)) } diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 1dd5df6533..3c4763e467 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -75,7 +75,7 @@ impl Screen for GraphicScreen { } } - fn write(&mut self, buf: &[u8], sync: bool) -> Result { + fn write(&mut self, buf: &[u8]) -> Result { let size = cmp::max(0, cmp::min(self.display.offscreen.len() as isize - self.seek as isize, (buf.len()/4) as isize)) as usize; if size > 0 { @@ -85,13 +85,6 @@ impl Screen for GraphicScreen { self.display.offscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, size * 4 ); - if sync { - ptr::copy( - buf.as_ptr(), - self.display.onscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, - size * 4 - ); - } } } @@ -111,13 +104,13 @@ impl Screen for GraphicScreen { Ok(self.seek * 4) } - fn sync(&mut self) { - self.redraw(); + fn sync(&mut self, onscreen: &mut [u32], stride: usize) { + self.redraw(onscreen, stride); } - fn redraw(&mut self) { + fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { let width = self.display.width; let height = self.display.height; - self.display.sync(0, 0, width, height); + self.display.sync(0, 0, width, height, onscreen, stride); } } diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs index a37778ee8f..e254e1c4fe 100644 --- a/vesad/src/screen/mod.rs +++ b/vesad/src/screen/mod.rs @@ -22,11 +22,11 @@ pub trait Screen { fn can_read(&self) -> Option; - fn write(&mut self, buf: &[u8], sync: bool) -> Result; + fn write(&mut self, buf: &[u8]) -> Result; fn seek(&mut self, pos: isize, whence: usize) -> Result; - fn sync(&mut self); + fn sync(&mut self, onscreen: &mut [u32], stride: usize); - fn redraw(&mut self); + fn redraw(&mut self, onscreen: &mut [u32], stride: usize); } diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 9035cb4fad..834aca6cf2 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -132,7 +132,7 @@ impl Screen for TextScreen { } } - fn write(&mut self, buf: &[u8], sync: bool) -> Result { + fn write(&mut self, buf: &[u8]) -> Result { if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { let x = self.console.state.x; let y = self.console.state.y; @@ -202,10 +202,6 @@ impl Screen for TextScreen { self.changed.insert(y); } - if sync { - self.sync(); - } - Ok(buf.len()) } @@ -213,18 +209,18 @@ impl Screen for TextScreen { Ok(0) } - fn sync(&mut self) { + fn sync(&mut self, onscreen: &mut [u32], stride: usize) { let width = self.display.width; for change in self.changed.iter() { - self.display.sync(0, change * 16, width, 16); + self.display.sync(0, change * 16, width, 16, onscreen, stride); } self.changed.clear(); } - fn redraw(&mut self) { + fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { let width = self.display.width; let height = self.display.height; - self.display.sync(0, 0, width, height); + self.display.sync(0, 0, width, height, onscreen, stride); self.changed.clear(); } } From c651590cbd2e8e83749462a7e877b6b7bf9e99cb Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 21 Sep 2022 15:57:09 -0600 Subject: [PATCH 0542/1301] Fix booting on systems which always return 0xFF from ps2 ports --- ps2d/src/controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 8ab469af9f..e5972b5de1 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -152,7 +152,7 @@ impl Ps2 { fn flush_read(&mut self, message: &str) { let mut timeout = 100; while timeout > 0 { - while self.status().contains(StatusFlags::OUTPUT_FULL) { + if self.status().contains(StatusFlags::OUTPUT_FULL) { eprintln!("ps2d: flush {}: {:X}", message, self.data.read()); } unsafe { pause(); } From a4a3c4f7e8868b2b7bee8a72abb672065a7254f5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 25 Sep 2022 16:46:13 -0600 Subject: [PATCH 0543/1301] vesad: Support multiple displays --- vesad/src/display.rs | 8 +- vesad/src/framebuffer.rs | 62 +++++++++ vesad/src/main.rs | 56 ++++++-- vesad/src/scheme.rs | 271 +++++++++++++++++++++++---------------- 4 files changed, 275 insertions(+), 122 deletions(-) create mode 100644 vesad/src/framebuffer.rs diff --git a/vesad/src/display.rs b/vesad/src/display.rs index fe04c500ce..2af08415a5 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -47,8 +47,8 @@ impl Display { .as_ptr() }; Display { - width: width, - height: height, + width, + height, offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } } } @@ -63,8 +63,8 @@ impl Display { .as_ptr() }; Display { - width: width, - height: height, + width, + height, offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }, font: FontCollection::from_bytes(FONT).into_font().unwrap(), font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(), diff --git a/vesad/src/framebuffer.rs b/vesad/src/framebuffer.rs new file mode 100644 index 0000000000..f3b879210e --- /dev/null +++ b/vesad/src/framebuffer.rs @@ -0,0 +1,62 @@ +use std::{ + ptr, + slice +}; + +pub struct FrameBuffer { + pub phys: usize, + pub width: usize, + pub height: usize, + pub stride: usize, +} + +impl FrameBuffer { + pub fn new(phys: usize, width: usize, height: usize, stride: usize) -> Self { + Self { + phys, + width, + height, + stride, + } + } + + pub fn parse(var: &str) -> Option { + fn parse_number(part: &str) -> Option { + let (start, radix) = if part.starts_with("0x") { + (2, 16) + } else { + (0, 10) + }; + match usize::from_str_radix(&part[start..], radix) { + Ok(ok) => Some(ok), + Err(err) => { + eprintln!("vesad: failed to parse '{}': {}", part, err); + None + } + } + } + + let mut parts = var.split(','); + let phys = parse_number(parts.next()?)?; + let width = parse_number(parts.next()?)?; + let height = parse_number(parts.next()?)?; + let stride = parse_number(parts.next()?)?; + Some(Self::new(phys, width, height, stride)) + } + + pub unsafe fn map(&mut self) -> syscall::Result<&'static mut [u32]> { + let size = self.stride * self.height; + let virt = syscall::physmap( + self.phys, + size * 4, + syscall::PHYSMAP_WRITE | syscall::PHYSMAP_WRITE_COMBINE + )? as *mut u32; + //TODO: should we clear the framebuffer here? + ptr::write_bytes(virt, 0, size); + + Ok(slice::from_raw_parts_mut( + virt, + size + )) + } +} diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 87b1ef6b90..e2bb636c60 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -9,9 +9,13 @@ use std::io::{Read, Write}; use std::os::unix::io::{RawFd, FromRawFd}; use syscall::{Packet, SchemeMut, EVENT_READ}; -use crate::scheme::{DisplayScheme, HandleKind}; +use crate::{ + framebuffer::FrameBuffer, + scheme::{DisplayScheme, HandleKind} +}; pub mod display; +pub mod framebuffer; pub mod scheme; pub mod screen; @@ -24,7 +28,7 @@ fn main() { } else if arg == "G" { spec.push(true); } else { - println!("vesad: unknown screen type: {}", arg); + eprintln!("vesad: unknown screen type: {}", arg); } } @@ -38,7 +42,7 @@ fn main() { .expect("FRAMEBUFFER_HEIGHT not set"), 16 ).expect("failed to parse FRAMEBUFFER_HEIGHT"); - let physbaseptr = usize::from_str_radix( + let phys = usize::from_str_radix( &env::var("FRAMEBUFFER_ADDR") .expect("FRAMEBUFFER_ADDR not set"), 16 @@ -49,17 +53,48 @@ fn main() { 16 ).expect("failed to parse FRAMEBUFFER_STRIDE"); - println!("vesad: {}x{} stride {} at 0x{:X}", width, height, stride, physbaseptr); + println!("vesad: {}x{} stride {} at 0x{:X}", width, height, stride, phys); - if physbaseptr == 0 { + if phys == 0 { return; } - redox_daemon::Daemon::new(|daemon| inner(daemon, width, height, physbaseptr, stride, &spec)).expect("failed to create daemon"); + + let mut framebuffers = vec![FrameBuffer::new( + phys, + width, + height, + stride, + )]; + + //TODO: ideal maximum number of outputs? + for i in 1..1024 { + match env::var(&format!("FRAMEBUFFER{}", i)) { + Ok(var) => match FrameBuffer::parse(&var) { + Some(fb) => { + println!( + "vesad: framebuffer {}: {}x{} stride {} at 0x{:X}", + i, + fb.width, + fb.height, + fb.stride, + fb.phys + ); + framebuffers.push(fb); + }, + None => { + eprintln!("vesad: framebuffer {}: failed to parse '{}'", i, var); + }, + }, + Err(_err) => break, + }; + } + + redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers, &spec)).expect("failed to create daemon"); } -fn inner(daemon: redox_daemon::Daemon, width: usize, height: usize, physbaseptr: usize, stride: usize, spec: &[bool]) -> ! { +fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[bool]) -> ! { let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); - let mut scheme = DisplayScheme::new(width, height, physbaseptr, stride, &spec); + let mut scheme = DisplayScheme::new(framebuffers, &spec); syscall::setrens(0, 0).expect("vesad: failed to enter null namespace"); @@ -102,8 +137,9 @@ fn inner(daemon: redox_daemon::Daemon, width: usize, height: usize, physbaseptr: // Can't use scheme.can_read() because we borrow handles as mutable. // (and because it'd treat O_NONBLOCK sockets differently) - let count = if let HandleKind::Screen(screen_i) = handle.kind { - scheme.screens.get(&screen_i) + let count = if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + scheme.vts.get(&vt_i) + .and_then(|screens| screens.get(&screen_i)) .and_then(|screen| screen.can_read()) .unwrap_or(0) } else { 0 }; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index f08f2782fd..08a88e8c2a 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,16 +1,26 @@ use std::collections::BTreeMap; +use std::convert::TryInto; use std::{mem, ptr, slice, str}; use orbclient::{Event, EventOption}; use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, OldMap, O_NONBLOCK, physmap, physunmap, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, Result, SchemeMut}; -use crate::display::Display; -use crate::screen::{Screen, GraphicScreen, TextScreen}; +use crate::{ + display::Display, + framebuffer::FrameBuffer, + screen::{Screen, GraphicScreen, TextScreen}, +}; + +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +pub struct VtIndex(usize); + +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +pub struct ScreenIndex(usize); #[derive(Clone)] pub enum HandleKind { Input, - Screen(usize), + Screen(VtIndex, ScreenIndex), } #[derive(Clone)] @@ -22,54 +32,45 @@ pub struct Handle { } pub struct DisplayScheme { - width: usize, - height: usize, - physbaseptr: usize, - onscreen: &'static mut [u32], - stride: usize, - active: usize, - pub screens: BTreeMap>, + framebuffers: Vec, + onscreens: Vec<&'static mut [u32]>, + active: VtIndex, + pub vts: BTreeMap>>, next_id: usize, pub handles: BTreeMap, } impl DisplayScheme { - pub fn new(width: usize, height: usize, physbaseptr: usize, stride: usize, spec: &[bool]) -> DisplayScheme { - let onscreen = unsafe { - let size = stride * height; - let onscreen_ptr = physmap( - physbaseptr, - size * 4, - PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE - ).expect("vesad: failed to map framebuffer") as *mut u32; - ptr::write_bytes(onscreen_ptr, 0, size); + pub fn new(mut framebuffers: Vec, spec: &[bool]) -> DisplayScheme { + let mut onscreens = Vec::new(); + for fb in framebuffers.iter_mut() { + onscreens.push(unsafe { + fb.map().expect("vesad: failed to map framebuffer") + }); + } - slice::from_raw_parts_mut( - onscreen_ptr, - size - ) - }; + let mut vts = BTreeMap::>>::new(); - let mut screens: BTreeMap> = BTreeMap::new(); - - let mut screen_i = 1; - for &screen_type in spec.iter() { - if screen_type { - screens.insert(screen_i, Box::new(GraphicScreen::new(Display::new(width, height)))); - } else { - screens.insert(screen_i, Box::new(TextScreen::new(Display::new(width, height)))); + let mut vt_i = 1; + for &vt_type in spec.iter() { + let mut screens = BTreeMap::>::new(); + for fb_i in 0..framebuffers.len() { + let fb = &framebuffers[fb_i]; + screens.insert(ScreenIndex(fb_i), if vt_type { + Box::new(GraphicScreen::new(Display::new(fb.width, fb.height))) + } else { + Box::new(TextScreen::new(Display::new(fb.width, fb.height))) + }); } - screen_i += 1; + vts.insert(VtIndex(vt_i), screens); + vt_i += 1; } DisplayScheme { - width, - height, - physbaseptr, - onscreen, - stride, - active: 1, - screens, + framebuffers, + onscreens, + active: VtIndex(1), + vts, next_id: 0, handles: BTreeMap::new(), } @@ -77,13 +78,15 @@ impl DisplayScheme { pub fn can_read(&self, id: usize) -> Option { if let Some(handle) = self.handles.get(&id) { - if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(screen) = self.screens.get(&screen_i) { - screen.can_read().or(if handle.flags & O_NONBLOCK == O_NONBLOCK { - Some(0) - } else { - None - }); + if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + if let Some(screens) = self.vts.get(&vt_i) { + if let Some(screen) = screens.get(&screen_i) { + screen.can_read().or(if handle.flags & O_NONBLOCK == O_NONBLOCK { + Some(0) + } else { + None + }); + } } } } @@ -92,18 +95,20 @@ impl DisplayScheme { } fn resize(&mut self, width: usize, height: usize, stride: usize) { - println!("Resizing to {}, {} stride {}", width, height, stride); + //TODO: support resizing other outputs? + let fb_i = 0; + println!("Resizing framebuffer {} to {}, {} stride {}", fb_i, width, height, stride); // Unmap old onscreen unsafe { - physunmap(self.onscreen.as_mut_ptr() as usize).expect("vesad: failed to unmap framebuffer"); + physunmap(self.onscreens[fb_i].as_mut_ptr() as usize).expect("vesad: failed to unmap framebuffer"); } // Map new onscreen - self.onscreen = unsafe { + self.onscreens[fb_i] = unsafe { let size = stride * height; let onscreen_ptr = physmap( - self.physbaseptr, + self.framebuffers[fb_i].phys, size * 4, PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE ).expect("vesad: failed to map framebuffer") as *mut u32; @@ -116,15 +121,19 @@ impl DisplayScheme { }; // Update size - self.width = width; - self.height = height; - self.stride = stride; + self.framebuffers[fb_i].width = width; + self.framebuffers[fb_i].height = height; + self.framebuffers[fb_i].stride = stride; // Resize screens - for (screen_i, screen) in self.screens.iter_mut() { - screen.resize(width, height); - if *screen_i == self.active { - screen.redraw(self.onscreen, self.stride); + for (vt_i, screens) in self.vts.iter_mut() { + for (screen_i, screen) in screens.iter_mut() { + if screen_i.0 == fb_i { + screen.resize(width, height); + if *vt_i == self.active { + screen.redraw(self.onscreens[fb_i], self.framebuffers[fb_i].stride); + } + } } } } @@ -150,25 +159,35 @@ impl SchemeMut for DisplayScheme { } } else { let mut parts = path_str.split('/'); - let screen_i = parts.next().unwrap_or("").parse::().unwrap_or(0); - if self.screens.contains_key(&screen_i) { - for cmd in parts { - if cmd == "activate" { - self.active = screen_i; + let mut vt_screen = parts.next().unwrap_or("").split('.'); + let vt_i = VtIndex( + vt_screen.next().unwrap_or("").parse::().unwrap_or(1) + ); + let screen_i = ScreenIndex( + vt_screen.next().unwrap_or("").parse::().unwrap_or(0) + ); + if let Some(screens) = self.vts.get(&vt_i) { + if screens.contains_key(&screen_i) { + for cmd in parts { + if cmd == "activate" { + self.active = vt_i; + } } + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert(id, Handle { + kind: HandleKind::Screen(vt_i, screen_i), + flags: flags, + events: EventFlags::empty(), + notified_read: false + }); + + Ok(id) + } else { + Err(Error::new(ENOENT)) } - - let id = self.next_id; - self.next_id += 1; - - self.handles.insert(id, Handle { - kind: HandleKind::Screen(screen_i), - flags: flags, - events: EventFlags::empty(), - notified_read: false - }); - - Ok(id) } else { Err(Error::new(ENOENT)) } @@ -195,7 +214,7 @@ impl SchemeMut for DisplayScheme { handle.notified_read = false; - if let HandleKind::Screen(_screen_i) = handle.kind { + if let HandleKind::Screen(_vt_i, _screen_i) = handle.kind { handle.events = flags; Ok(syscall::EventFlags::empty()) } else { @@ -206,9 +225,11 @@ impl SchemeMut for DisplayScheme { fn fmap(&mut self, id: usize, map: &Map) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(screen) = self.screens.get(&screen_i) { - return screen.map(map.offset, map.size); + if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + if let Some(screens) = self.vts.get(&vt_i) { + if let Some(screen) = screens.get(&screen_i) { + return screen.map(map.offset, map.size); + } } } @@ -228,10 +249,15 @@ impl SchemeMut for DisplayScheme { let path_str = match handle.kind { HandleKind::Input => { - format!("display:input/{}/{}", self.width, self.height) + //TODO: allow inputs associated with other framebuffers? + format!("display:input/{}/{}", self.framebuffers[0].width, self.framebuffers[0].height) }, - HandleKind::Screen(screen_i) => if let Some(screen) = self.screens.get(&screen_i) { - format!("display:{}/{}/{}", screen_i, screen.width(), screen.height()) + HandleKind::Screen(vt_i, screen_i) => if let Some(screens) = self.vts.get(&vt_i) { + if let Some(screen) = screens.get(&screen_i) { + format!("display:{}.{}/{}/{}", vt_i.0, screen_i.0, screen.width(), screen.height()) + } else { + return Err(Error::new(EBADF)); + } } else { return Err(Error::new(EBADF)); } @@ -251,12 +277,17 @@ impl SchemeMut for DisplayScheme { fn fsync(&mut self, id: usize) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(screen) = self.screens.get_mut(&screen_i) { - if screen_i == self.active { - screen.sync(self.onscreen, self.stride); + if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { + if vt_i == self.active { + screen.sync( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); + } + return Ok(0); } - return Ok(0); } } @@ -266,9 +297,11 @@ impl SchemeMut for DisplayScheme { fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(screen) = self.screens.get_mut(&screen_i) { - return screen.read(buf); + if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { + return screen.read(buf); + } } } @@ -280,10 +313,15 @@ impl SchemeMut for DisplayScheme { match handle.kind { HandleKind::Input => if buf.len() == 1 && buf[0] >= 0xF4 { - let new_active = (buf[0] - 0xF4) as usize + 1; - if let Some(screen) = self.screens.get_mut(&new_active) { + let new_active = VtIndex((buf[0] - 0xF4) as usize + 1); + if let Some(screens) = self.vts.get_mut(&new_active) { self.active = new_active; - screen.redraw(self.onscreen, self.stride); + for (screen_i, screen) in screens.iter_mut() { + screen.redraw( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); + } } Ok(1) } else { @@ -294,13 +332,13 @@ impl SchemeMut for DisplayScheme { match event.to_option() { EventOption::Key(key_event) => match key_event.scancode { f @ 0x3B ..= 0x44 => { // F1 through F10 - new_active_opt = Some((f - 0x3A) as usize); + new_active_opt = Some(VtIndex((f - 0x3A) as usize)); }, 0x57 => { // F11 - new_active_opt = Some(11); + new_active_opt = Some(VtIndex(11)); }, 0x58 => { // F12 - new_active_opt = Some(12); + new_active_opt = Some(VtIndex(12)); }, _ => () }, @@ -314,25 +352,40 @@ impl SchemeMut for DisplayScheme { }; if let Some(new_active) = new_active_opt { - if let Some(screen) = self.screens.get_mut(&new_active) { + if let Some(screens) = self.vts.get_mut(&new_active) { self.active = new_active; - screen.redraw(self.onscreen, self.stride); + for (screen_i, screen) in screens.iter_mut() { + screen.redraw( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); + } } } else { - if let Some(screen) = self.screens.get_mut(&self.active) { - screen.input(event); + if let Some(screens) = self.vts.get_mut(&self.active) { + //TODO: send input to other screens? Don't want extra events + if let Some(screen) = screens.get_mut(&ScreenIndex(0)) { + screen.input(event); + } } } } Ok(events.len() * mem::size_of::()) }, - HandleKind::Screen(screen_i) => if let Some(screen) = self.screens.get_mut(&screen_i) { - let count = screen.write(buf)?; - if screen_i == self.active { - screen.sync(self.onscreen, self.stride); + HandleKind::Screen(vt_i, screen_i) => if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { + let count = screen.write(buf)?; + if vt_i == self.active { + screen.sync( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); + } + Ok(count) + } else { + Err(Error::new(EBADF)) } - Ok(count) } else { Err(Error::new(EBADF)) } @@ -342,9 +395,11 @@ impl SchemeMut for DisplayScheme { fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(screen_i) = handle.kind { - if let Some(screen) = self.screens.get_mut(&screen_i) { - return screen.seek(pos, whence).map(|pos| pos as isize); + if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { + return screen.seek(pos, whence).map(|pos| pos as isize); + } } } From 08542ae288ad16134ab0ec71e418ba755ccdc1ea Mon Sep 17 00:00:00 2001 From: Robin Randhawa Date: Mon, 26 Sep 2022 17:17:32 +0100 Subject: [PATCH 0544/1301] aarch64: The use of yield needs the stdsimd feature apparently --- ahcid/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 3da29c3d48..c19c60106d 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -1,3 +1,5 @@ +#![cfg_attr(target_arch = "aarch64", feature(stdsimd))] // Required for yield instruction + extern crate syscall; extern crate byteorder; From 766020195bc24c0adcb54a21966ebdd55e59b276 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 26 Sep 2022 11:07:41 -0600 Subject: [PATCH 0545/1301] Note when there is a missing USB driver --- xhcid/src/xhci/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 7d7918fe9e..368557d030 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -762,6 +762,7 @@ impl Xhci { .or(Err(Error::new(ENOENT)))?; self.drivers.insert(port, process); } else { + warn!("No driver for USB class {}.{}", ifdesc.class, ifdesc.sub_class); return Err(Error::new(ENOENT)); } From 39df471bc246b767f7b6c9220e25f82119a592cf Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 2 Nov 2022 14:36:53 -0600 Subject: [PATCH 0546/1301] Enable LTO --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index fb901ff23b..9ddcd94a99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,9 @@ members = [ "usbscsid", ] +[profile.release] +lto = "fat" + [patch.crates-io] mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } From c8ca7940d451cfb3caec9d0e68336f53f4eb2a60 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 15 Nov 2022 09:02:25 -0700 Subject: [PATCH 0547/1301] ihdad: increase buffers to 4 to eliminate stuttering (mostly) --- ihdad/src/hda/device.rs | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index f84f7c1e87..74cd77d033 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -54,7 +54,7 @@ const IRV: u16 = 1 << 1; const COMMAND_BUFFER_OFFSET: usize = 0x40; -const NUM_SUB_BUFFS: usize = 2; +const NUM_SUB_BUFFS: usize = 4; const SUB_BUFF_SIZE: usize = 2048; enum Handle { @@ -461,13 +461,11 @@ impl IntelHDA { let o = self.output_streams.get_mut(0).unwrap(); - self.buff_desc[0].set_address(o.phys()); - self.buff_desc[0].set_length(o.block_size() as u32); - self.buff_desc[0].set_interrupt_on_complete(true); - - self.buff_desc[1].set_address(o.phys() + o.block_size()); - self.buff_desc[1].set_length(o.block_size() as u32); - self.buff_desc[1].set_interrupt_on_complete(true); + for i in 0..NUM_SUB_BUFFS { + self.buff_desc[i].set_address(o.phys() + o.block_size() * i); + self.buff_desc[i].set_length(o.block_size() as u32); + self.buff_desc[i].set_interrupt_on_complete(true); + } } pub fn configure(&mut self) { @@ -500,9 +498,9 @@ impl IntelHDA { output.set_address(self.buff_desc_phys); output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); - output.set_cyclic_buffer_length(0x8000); // number of bytes + output.set_cyclic_buffer_length((NUM_SUB_BUFFS * SUB_BUFF_SIZE) as u32); // number of bytes output.set_stream_number(1); - output.set_last_valid_index(1); + output.set_last_valid_index((NUM_SUB_BUFFS - 1) as u16); output.set_interrupt_on_completion(true); @@ -550,9 +548,9 @@ impl IntelHDA { output.set_address(self.buff_desc_phys); output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); - output.set_cyclic_buffer_length(0x8000); + output.set_cyclic_buffer_length((NUM_SUB_BUFFS * SUB_BUFF_SIZE) as u32); output.set_stream_number(1); - output.set_last_valid_index(1); + output.set_last_valid_index((NUM_SUB_BUFFS - 1) as u16); output.set_interrupt_on_completion(true); @@ -744,10 +742,9 @@ impl IntelHDA { //let sample_size:usize = output.sample_size(); let mut open_block = (output.link_position() as usize) / os.block_size(); - if open_block == 0 { - open_block = 1; - } else { - open_block = open_block - 1; + open_block += NUM_SUB_BUFFS / 2; + while open_block >= NUM_SUB_BUFFS { + open_block -= NUM_SUB_BUFFS; } //log::info!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}", output.status(), output.link_position(), output.control()); From 0fe60a00fcd36362afd96da6aa6f4d1e0740d5e1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 15 Nov 2022 10:58:00 -0700 Subject: [PATCH 0548/1301] ihdad: improve logging --- ihdad/src/hda/device.rs | 15 ++++++--------- ihdad/src/hda/node.rs | 4 ++-- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 74cd77d033..fd9630ea85 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -205,7 +205,7 @@ impl IntelHDA { module.init(); - // module.info(); + module.info(); module.enumerate(); module.configure(); @@ -372,9 +372,6 @@ impl IntelHDA { } else if config.is_input() { self.input_pins.push(widget.addr); } - - log::info!("{:02X}{:02X} {}", widget.addr().0, widget.addr().1, config); - }, _ => {}, } @@ -471,14 +468,14 @@ impl IntelHDA { pub fn configure(&mut self) { let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); - //log::info!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); + log::info!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); let path = self.find_path_to_dac(outpin).unwrap(); let dac = *path.last().unwrap(); let pin = *path.first().unwrap(); - //log::info!("Path to DAC: {:?}", path); + log::info!("Path to DAC: {:X?}", path); // Pin enable self.cmd.cmd12(pin, 0x707, 0x40); @@ -490,8 +487,8 @@ impl IntelHDA { self.update_sound_buffers(); - //log::info!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); - //log::info!("Capabilities: {:08X}", self.get_capabilities(path[0])); + log::info!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); + log::info!("Capabilities: {:08X}", self.get_capabilities(path[0])); let output = self.get_output_stream_descriptor(0).unwrap(); @@ -526,7 +523,7 @@ impl IntelHDA { log::info!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); let path = self.find_path_to_dac(outpin).unwrap(); - log::info!("Path to DAC: {:?}", path); + log::info!("Path to DAC: {:X?}", path); // Pin enable self.cmd.cmd12((0,0xC), 0x707, 0x40); diff --git a/ihdad/src/hda/node.rs b/ihdad/src/hda/node.rs index 69e6c7e137..b659c3b4ce 100644 --- a/ihdad/src/hda/node.rs +++ b/ihdad/src/hda/node.rs @@ -87,7 +87,7 @@ impl fmt::Display for HDANode { match self.widget_type() { HDAWidgetType::PinComplex => write!( f, - "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {:X}: {:?}.", + "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {:X}: {:X?}.", self.addr.0, self.addr.1, self.widget_type(), @@ -95,7 +95,7 @@ impl fmt::Display for HDANode { self.conn_list_len, self.connections ), - _ => write!(f, "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {:X}: {:?}.", self.addr.0, self.addr.1, self.widget_type(), self.conn_list_len, self.connections), + _ => write!(f, "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {:X}: {:X?}.", self.addr.0, self.addr.1, self.widget_type(), self.conn_list_len, self.connections), } } else { write!(f, "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", self.addr.0, self.addr.1, self.function_group_type, self.subnode_count) From c63fe7f2d65db44bf2f295fc945563c61b2a6747 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 15 Nov 2022 11:07:37 -0700 Subject: [PATCH 0549/1301] ihdad: attempt to enable headphone jacks --- ihdad/src/hda/device.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index fd9630ea85..3d6a0351e5 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -396,7 +396,7 @@ impl IntelHDA { let widget = self.widget_map.get(&out).unwrap(); let cd = widget.configuration_default(); - if cd.sequence() == 0 && cd.default_device() == DefaultDevice::Speaker { + if cd.sequence() == 0 && cd.default_device() == DefaultDevice::HPOut { return Some(out); } } @@ -477,8 +477,8 @@ impl IntelHDA { log::info!("Path to DAC: {:X?}", path); - // Pin enable - self.cmd.cmd12(pin, 0x707, 0x40); + // Pin enable (0x80 = headphone amp enable, 0x40 = output enable) + self.cmd.cmd12(pin, 0x707, 0xC0); // EAPD enable self.cmd.cmd12(pin, 0x70C, 2); @@ -504,7 +504,7 @@ impl IntelHDA { self.set_power_state(dac, 0); // Power state 0 is fully on self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2); - + // Get converter format self.cmd.cmd12(dac, 0xA00, 0); // Unmute and set gain for pin complex and DAC From c993b0ef408bd2da011804a9e24efe6155186be0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 15 Nov 2022 11:07:48 -0700 Subject: [PATCH 0550/1301] ihdad: Turn on by default --- ihdad/config.toml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/ihdad/config.toml b/ihdad/config.toml index 98bb72d5ef..11fc35efb1 100644 --- a/ihdad/config.toml +++ b/ihdad/config.toml @@ -1,6 +1,5 @@ -# Disabled - causes issues on real hardware -# [[drivers]] -# name = "Intel HD Audio" -# class = 4 -# subclass = 3 -# command = ["ihdad", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ", "$VENID", "$DEVID"] +[[drivers]] +name = "Intel HD Audio" +class = 4 +subclass = 3 +command = ["ihdad", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ", "$VENID", "$DEVID"] From 2cdfb46a7100cadf5d8be7b79b6f326885d82bab Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 15 Nov 2022 12:43:22 -0700 Subject: [PATCH 0551/1301] Use audiohw: instead of hda: --- ihdad/src/hda/device.rs | 2 +- ihdad/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 3d6a0351e5..07e6d92cc5 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -919,7 +919,7 @@ impl SchemeBlockMut for IntelHDA { let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; let mut i = 0; - let scheme_path = b"hda:"; + let scheme_path = b"audiohw:"; while i < buf.len() && i < scheme_path.len() { buf[i] = scheme_path[i]; i += 1; diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 13df709e70..bc8f23df7e 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -106,7 +106,7 @@ fn main() { let vend_prod:u32 = ((vend as u32) << 16) | (prod as u32); let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); - let socket_fd = syscall::open(":hda", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create hda scheme"); + let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); daemon.ready().expect("IHDA: failed to signal readiness"); From d7ca6eeeedcd438d1d2a0768aed41fbd3c244a90 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 15 Nov 2022 13:37:31 -0700 Subject: [PATCH 0552/1301] ac97: add stub driver for AC97 --- Cargo.lock | 13 +++ Cargo.toml | 1 + ac97d/Cargo.toml | 13 +++ ac97d/config.toml | 5 ++ ac97d/src/device.rs | 196 ++++++++++++++++++++++++++++++++++++++++++ ac97d/src/main.rs | 205 ++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 433 insertions(+) create mode 100644 ac97d/Cargo.toml create mode 100644 ac97d/config.toml create mode 100644 ac97d/src/device.rs create mode 100644 ac97d/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 13813dde0d..e448276b87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,19 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ac97d" +version = "0.1.0" +dependencies = [ + "bitflags", + "log", + "redox-daemon", + "redox-log", + "redox_event", + "redox_syscall 0.3.4", + "spin", +] + [[package]] name = "acpid" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 9ddcd94a99..8533a87637 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [workspace] members = [ + "ac97d", "acpid", "ahcid", "alxd", diff --git a/ac97d/Cargo.toml b/ac97d/Cargo.toml new file mode 100644 index 0000000000..249ea0ed03 --- /dev/null +++ b/ac97d/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ac97d" +version = "0.1.0" +edition = "2018" + +[dependencies] +bitflags = "1" +log = "0.4" +redox-daemon = "0.1" +redox-log = "0.1" +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox_syscall = "0.3" +spin = "0.9" diff --git a/ac97d/config.toml b/ac97d/config.toml new file mode 100644 index 0000000000..7bafbb4975 --- /dev/null +++ b/ac97d/config.toml @@ -0,0 +1,5 @@ +[[drivers]] +name = "AC97 Audio" +class = 4 +subclass = 1 +command = ["ac97d", "$NAME", "$BAR0", "$BAR1", "$IRQ"] diff --git a/ac97d/src/device.rs b/ac97d/src/device.rs new file mode 100644 index 0000000000..0ba70e9ca9 --- /dev/null +++ b/ac97d/src/device.rs @@ -0,0 +1,196 @@ +#![allow(dead_code)] + +use std::cmp; +use std::collections::HashMap; +use std::str; +use std::collections::BTreeMap; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; +use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; +use syscall::io::{Pio, Io}; +use syscall::scheme::SchemeBlockMut; + +use spin::Mutex; + +const NUM_SUB_BUFFS: usize = 4; +const SUB_BUFF_SIZE: usize = 2048; + +enum Handle { + Todo, +} + +#[repr(packed)] +#[allow(dead_code)] +struct MixerRegs { + /* 0x00 */ reset: Pio, + /* 0x02 */ master_volume: Pio, + /* 0x04 */ aux_out_volume: Pio, + /* 0x06 */ mono_volume: Pio, + /* 0x08 */ master_tone: Pio, + /* 0x0A */ pc_beep_volume: Pio, + /* 0x0C */ phone_volume: Pio, + /* 0x0E */ mic_volume: Pio, + /* 0x10 */ line_in_volume: Pio, + /* 0x12 */ cd_volume: Pio, + /* 0x14 */ video_volume: Pio, + /* 0x16 */ aux_in_volume: Pio, + /* 0x18 */ pcm_out_volume: Pio, + /* 0x1A */ record_select: Pio, + /* 0x1C */ record_gain: Pio, + /* 0x1E */ record_gain_mic: Pio, + /* 0x20 */ general_purpose: Pio, + /* 0x22 */ control_3d: Pio, + /* 0x24 */ audio_int_paging: Pio, + /* 0x26 */ powerdown: Pio, + //TODO: extended registers +} + +impl MixerRegs { + fn new(bar0: u16) -> Self { + Self { + reset: Pio::new(bar0 + 0x00), + master_volume: Pio::new(bar0 + 0x02), + aux_out_volume: Pio::new(bar0 + 0x04), + mono_volume: Pio::new(bar0 + 0x06), + master_tone: Pio::new(bar0 + 0x08), + pc_beep_volume: Pio::new(bar0 + 0x0A), + phone_volume: Pio::new(bar0 + 0x0C), + mic_volume: Pio::new(bar0 + 0x0E), + line_in_volume: Pio::new(bar0 + 0x10), + cd_volume: Pio::new(bar0 + 0x12), + video_volume: Pio::new(bar0 + 0x14), + aux_in_volume: Pio::new(bar0 + 0x16), + pcm_out_volume: Pio::new(bar0 + 0x18), + record_select: Pio::new(bar0 + 0x1A), + record_gain: Pio::new(bar0 + 0x1C), + record_gain_mic: Pio::new(bar0 + 0x1E), + general_purpose: Pio::new(bar0 + 0x20), + control_3d: Pio::new(bar0 + 0x22), + audio_int_paging: Pio::new(bar0 + 0x24), + powerdown: Pio::new(bar0 + 0x26), + } + } +} + +#[repr(packed)] +#[allow(dead_code)] +struct BusBoxRegs { + /// Buffer descriptor list base address + /* 0x00 */ bdbar: Pio, + /// Current index value + /* 0x04 */ civ: Pio, + /// Last valid index + /* 0x05 */ lvi: Pio, + /// Status + /* 0x06 */ sr: Pio, + /// Position in current buffer + /* 0x08 */ picb: Pio, + /// Prefetched index value + /* 0x0A */ piv: Pio, + /// Control + /* 0x0B */ cr: Pio, +} + +impl BusBoxRegs { + fn new(base: u16) -> Self { + Self { + bdbar: Pio::new(base + 0x00), + civ: Pio::new(base + 0x04), + lvi: Pio::new(base + 0x05), + sr: Pio::new(base + 0x06), + picb: Pio::new(base + 0x08), + piv: Pio::new(base + 0x0A), + cr: Pio::new(base + 0x0B), + } + } +} + +#[repr(packed)] +#[allow(dead_code)] +struct BusRegs { + /// PCM in register box + /* 0x00 */ pi: BusBoxRegs, + /// PCM out register box + /* 0x10 */ po: BusBoxRegs, + /// Microphone register box + /* 0x20 */ mc: BusBoxRegs, +} + +impl BusRegs { + fn new(bar1: u16) -> Self { + Self { + pi: BusBoxRegs::new(bar1 + 0x00), + po: BusBoxRegs::new(bar1 + 0x10), + mc: BusBoxRegs::new(bar1 + 0x20), + } + } +} + +pub struct Ac97 { + mixer: MixerRegs, + bus: BusRegs, + handles: Mutex>, + next_id: AtomicUsize, +} + +impl Ac97 { + pub unsafe fn new(bar0: u16, bar1: u16) -> Result { + let mut module = Ac97 { + mixer: MixerRegs::new(bar0), + bus: BusRegs::new(bar1), + handles: Mutex::new(BTreeMap::new()), + next_id: AtomicUsize::new(0), + }; + + //TODO: init + + Ok(module) + } + + pub fn irq(&mut self) -> bool { + //TODO + false + } +} + +impl SchemeBlockMut for Ac97 { + fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { + if uid == 0 { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, Handle::Todo); + Ok(Some(id)) + } else { + Err(Error::new(EACCES)) + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + let index = { + let mut handles = self.handles.lock(); + let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + 0 + }; + + Ok(Some(buf.len())) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let mut handles = self.handles.lock(); + let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let mut i = 0; + let scheme_path = b"audiohw:"; + while i < buf.len() && i < scheme_path.len() { + buf[i] = scheme_path[i]; + i += 1; + } + Ok(Some(i)) + } + + fn close(&mut self, id: usize) -> Result> { + let mut handles = self.handles.lock(); + handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + } +} diff --git a/ac97d/src/main.rs b/ac97d/src/main.rs new file mode 100644 index 0000000000..1be4ff1423 --- /dev/null +++ b/ac97d/src/main.rs @@ -0,0 +1,205 @@ +//#![deny(warnings)] + +extern crate bitflags; +extern crate spin; +extern crate syscall; +extern crate event; + +use std::{env, usize}; +use std::fs::File; +use std::io::{ErrorKind, Read, Write, Result}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Packet, SchemeBlockMut, EventFlags}; +use std::cell::RefCell; +use std::sync::Arc; + +use event::EventQueue; +use redox_log::{OutputBuilder, RedoxLogger}; + +pub mod device; + +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "ac97.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("ac97d: failed to create ac97.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "ac97.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("ac97d: failed to create ac97.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("ac97d: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("ac97d: failed to set default logger: {}", error); + None + } + } +} + +fn main() { + let mut args = env::args().skip(1); + + let mut name = args.next().expect("ac97: no name provided"); + name.push_str("_ac97"); + + let bar0_str = args.next().expect("ac97: no address provided"); + let bar0 = u16::from_str_radix(&bar0_str, 16).expect("ac97: failed to parse address"); + + let bar1_str = args.next().expect("ac97: no address provided"); + let bar1 = u16::from_str_radix(&bar1_str, 16).expect("ac97: failed to parse address"); + + let irq_str = args.next().expect("ac97: no irq provided"); + let irq = irq_str.parse::().expect("ac97: failed to parse irq"); + + print!("{}", format!(" + ac97 {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1, irq)); + + // Daemonize + redox_daemon::Daemon::new(move |daemon| { + let _logger_ref = setup_logging(); + + let mut irq_file = File::open(format!("irq:{}", irq)).expect("ac97d: failed to open IRQ file"); + + let device = Arc::new(RefCell::new(unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") })); + let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ac97d: failed to create hda scheme"); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + + daemon.ready().expect("ac97d: failed to signal readiness"); + + let mut event_queue = EventQueue::::new().expect("ac97d: Could not create event queue."); + + syscall::setrens(0, 0).expect("ac97d: failed to enter null namespace"); + + let todo = Arc::new(RefCell::new(Vec::::new())); + + let todo_irq = todo.clone(); + let device_irq = device.clone(); + let socket_irq = socket.clone(); + + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + + if device_irq.borrow_mut().irq() { + irq_file.write(&mut irq)?; + + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + if let Some(a) = device_irq.borrow_mut().handle(&mut todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket_irq.borrow_mut().write(&packet)?; + } else { + i += 1; + } + } + + /* + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + } + Ok(None) + }).expect("ac97d: failed to catch events on IRQ file"); + let socket_fd = socket.borrow().as_raw_fd(); + let socket_packet = socket.clone(); + event_queue.add(socket_fd, move |_event| -> Result> { + loop { + let mut packet = Packet::default(); + match socket_packet.borrow_mut().read(&mut packet) { + Ok(0) => return Ok(Some(0)), + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } + } + + if let Some(a) = device.borrow_mut().handle(&mut packet) { + packet.a = a; + socket_packet.borrow_mut().write(&packet)?; + } else { + todo.borrow_mut().push(packet); + } + } + + /* + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + + Ok(None) + }).expect("ac97d: failed to catch events on IRQ file"); + + for event_count in event_queue.trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }).expect("ac97d: failed to trigger events") { + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ.bits(), + d: event_count + }).expect("ac97d: failed to write event"); + } + + loop { + { + //device_loop.borrow_mut().handle_interrupts(); + } + let event_count = event_queue.run().expect("ac97d: failed to handle events"); + if event_count == 0 { + //TODO: Handle todo + break; + } + + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ.bits(), + d: event_count + }).expect("ac97d: failed to write event"); + } + + std::process::exit(0); + }).expect("ac97d: failed to daemonize"); +} From 2564997cac9123868c05bf7d563cbad4b0ee3265 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 15 Nov 2022 14:52:18 -0700 Subject: [PATCH 0553/1301] ac97: make driver work --- ac97d/src/device.rs | 143 ++++++++++++++++++++++++++++++++++++++------ ac97d/src/main.rs | 4 +- 2 files changed, 127 insertions(+), 20 deletions(-) diff --git a/ac97d/src/device.rs b/ac97d/src/device.rs index 0ba70e9ca9..6dccdc7f39 100644 --- a/ac97d/src/device.rs +++ b/ac97d/src/device.rs @@ -1,27 +1,22 @@ #![allow(dead_code)] -use std::cmp; -use std::collections::HashMap; -use std::str; +use std::mem; use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; -use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; -use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; -use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; -use syscall::io::{Pio, Io}; +use syscall::error::{Error, EACCES, EBADF, Result, EINVAL, ENOENT}; +use syscall::io::{Dma, PhysBox, Mmio, Pio, Io}; use syscall::scheme::SchemeBlockMut; use spin::Mutex; -const NUM_SUB_BUFFS: usize = 4; +const NUM_SUB_BUFFS: usize = 32; const SUB_BUFF_SIZE: usize = 2048; enum Handle { Todo, } -#[repr(packed)] #[allow(dead_code)] struct MixerRegs { /* 0x00 */ reset: Pio, @@ -44,7 +39,9 @@ struct MixerRegs { /* 0x22 */ control_3d: Pio, /* 0x24 */ audio_int_paging: Pio, /* 0x26 */ powerdown: Pio, - //TODO: extended registers + /* 0x28 */ extended_id: Pio, + /* 0x2A */ extended_ctrl: Pio, + /* 0x2C */ vra_pcm_front: Pio, } impl MixerRegs { @@ -70,11 +67,13 @@ impl MixerRegs { control_3d: Pio::new(bar0 + 0x22), audio_int_paging: Pio::new(bar0 + 0x24), powerdown: Pio::new(bar0 + 0x26), + extended_id: Pio::new(bar0 + 0x28), + extended_ctrl: Pio::new(bar0 + 0x2A), + vra_pcm_front: Pio::new(bar0 + 0x2C), } } } -#[repr(packed)] #[allow(dead_code)] struct BusBoxRegs { /// Buffer descriptor list base address @@ -107,7 +106,6 @@ impl BusBoxRegs { } } -#[repr(packed)] #[allow(dead_code)] struct BusRegs { /// PCM in register box @@ -128,30 +126,120 @@ impl BusRegs { } } +#[repr(packed)] +pub struct BufferDescriptor { + /* 0x00 */ addr: Mmio, + /* 0x04 */ samples: Mmio, + /* 0x06 */ flags: Mmio, +} + pub struct Ac97 { mixer: MixerRegs, bus: BusRegs, + bdl: Dma<[BufferDescriptor; NUM_SUB_BUFFS]>, + buf: Dma<[u8; NUM_SUB_BUFFS * SUB_BUFF_SIZE]>, handles: Mutex>, next_id: AtomicUsize, } impl Ac97 { pub unsafe fn new(bar0: u16, bar1: u16) -> Result { + let round_page = |size: usize| -> usize { + let page_size = 4096; + let pages = (size + (page_size - 1)) / page_size; + pages * page_size + }; + let bdl_size = round_page(NUM_SUB_BUFFS * mem::size_of::()); + let buf_size = round_page(NUM_SUB_BUFFS * SUB_BUFF_SIZE); + let mut module = Ac97 { mixer: MixerRegs::new(bar0), bus: BusRegs::new(bar1), + bdl: Dma::from_physbox_zeroed( + //TODO: PhysBox::new_in_32bit_space(bdl_size)? + PhysBox::new(bdl_size)? + )?.assume_init(), + buf: Dma::from_physbox_zeroed( + //TODO: PhysBox::new_in_32bit_space(buf_size)? + PhysBox::new(buf_size)? + )?.assume_init(), handles: Mutex::new(BTreeMap::new()), next_id: AtomicUsize::new(0), }; - //TODO: init + module.init()?; Ok(module) } + fn init(&mut self) -> Result<()> { + //TODO: support other sample rates, or just the default of 48000 Hz + { + // Check if VRA is supported + if ! self.mixer.extended_id.readf(1 << 0) { + println!("ac97d: VRA not supported and is currently required"); + return Err(Error::new(ENOENT)); + } + + // Enable VRA + self.mixer.extended_ctrl.writef(1 << 0, true); + + // Attempt to set sample rate for PCM front to 44100 Hz + let desired_sample_rate = 44100; + self.mixer.vra_pcm_front.write(desired_sample_rate); + + // Read back real sample rate + let real_sample_rate = self.mixer.vra_pcm_front.read(); + println!("ac97d: set sample rate to {}", real_sample_rate); + + // Error if we cannot set the sample rate as desired + if real_sample_rate != desired_sample_rate { + println!("ac97d: sample rate is {} but only {} is supported", real_sample_rate, desired_sample_rate); + return Err(Error::new(ENOENT)); + } + } + + // Ensure PCM out is stopped + self.bus.po.cr.writef(1, false); + + // Reset PCM out + self.bus.po.cr.writef(1 << 1, true); + while self.bus.po.cr.readf(1 << 1) { + // Spinning on resetting PCM out + //TODO: relax + } + + // Initialize BDL for PCM out + for i in 0..NUM_SUB_BUFFS { + self.bdl[i].addr.write((self.buf.physical() + i * SUB_BUFF_SIZE) as u32); + self.bdl[i].samples.write((SUB_BUFF_SIZE / 2 /* Each sample is i16 or 2 bytes */) as u16); + self.bdl[i].flags.write(1 << 15 /* Interrupt on completion */); + } + self.bus.po.bdbar.write(self.bdl.physical() as u32); + + // Enable interrupt on completion + self.bus.po.cr.writef(1 << 4, true); + + // Start bus master + self.bus.po.cr.writef(1 << 0, true); + + // Set master volume to 0 db (loudest output, DANGER!) + self.mixer.master_volume.write(0); + + // Set PCM output volume to 0 db (medium) + self.mixer.pcm_out_volume.write(0x808); + + Ok(()) + } + pub fn irq(&mut self) -> bool { - //TODO - false + let ints = self.bus.po.sr.read() & 0b11100; + if ints != 0 { + self.bus.po.sr.write(ints); + true + } else { + false + } } } @@ -167,13 +255,30 @@ impl SchemeBlockMut for Ac97 { } fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let index = { + { let mut handles = self.handles.lock(); let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - 0 - }; + } - Ok(Some(buf.len())) + if buf.len() != SUB_BUFF_SIZE { + return Err(Error::new(EINVAL)); + } + + let civ = self.bus.po.civ.read() as usize; + let mut lvi = self.bus.po.lvi.read() as usize; + if lvi == (civ + 1) % NUM_SUB_BUFFS { + // Block if we already are 1 buffer ahead + Ok(None) + } else { + // Fill next buffer + lvi = (lvi + 1) % NUM_SUB_BUFFS; + for i in 0..SUB_BUFF_SIZE { + self.buf[lvi * SUB_BUFF_SIZE + i] = buf[i]; + } + self.bus.po.lvi.write(lvi as u8); + + Ok(Some(SUB_BUFF_SIZE)) + } } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { diff --git a/ac97d/src/main.rs b/ac97d/src/main.rs index 1be4ff1423..6c65e75ad5 100644 --- a/ac97d/src/main.rs +++ b/ac97d/src/main.rs @@ -9,7 +9,7 @@ use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Packet, SchemeBlockMut, EventFlags}; +use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; @@ -82,6 +82,8 @@ fn main() { // Daemonize redox_daemon::Daemon::new(move |daemon| { let _logger_ref = setup_logging(); + + unsafe { syscall::iopl(3) }.expect("ac97d: failed to set I/O privilege level to Ring 3"); let mut irq_file = File::open(format!("irq:{}", irq)).expect("ac97d: failed to open IRQ file"); From 304dcad78bd65c922d0656a24d5e3857c6a6affc Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 16 Nov 2022 14:56:11 -0700 Subject: [PATCH 0554/1301] ihda: Use default connection for finding dac --- ihdad/src/hda/device.rs | 26 +++++++------------------- ihdad/src/hda/node.rs | 26 +++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 07e6d92cc5..a137623bf5 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -268,13 +268,13 @@ impl IntelHDA { temp = self.cmd.cmd12(addr, 0xF00, 0x09); node.capabilities = temp as u32; - temp = self.cmd.cmd12(addr, 0xF00, 0x0E); node.conn_list_len = (temp & 0xFF) as u8; node.connections = self.node_get_connection_list(&node); + node.connection_default = self.cmd.cmd12(addr, 0xF01, 0x00) as u8; node.config_default = self.cmd.cmd12(addr, 0xF1C, 0x00) as u32; @@ -408,24 +408,12 @@ impl IntelHDA { pub fn find_path_to_dac(&self, addr: WidgetAddr) -> Option>{ let widget = self.widget_map.get(&addr).unwrap(); if widget.widget_type() == HDAWidgetType::AudioOutput { - return Some(vec![addr]); - }else{ - if widget.connections.len() == 0 { - return None; - }else{ - // TODO: do more than just first widget - - let res = self.find_path_to_dac(widget.connections[0]); - match res { - Some(p) => { - let mut ret = p.clone(); - ret.insert(0, addr); - Some(ret) - }, - None => {None}, - } - } - + Some(vec![addr]) + } else { + let connection = widget.connections.get(widget.connection_default as usize)?; + let mut path = self.find_path_to_dac(*connection)?; + path.insert(0, addr); + Some(path) } } diff --git a/ihdad/src/hda/node.rs b/ihdad/src/hda/node.rs index b659c3b4ce..4c1238c50a 100644 --- a/ihdad/src/hda/node.rs +++ b/ihdad/src/hda/node.rs @@ -32,6 +32,8 @@ pub struct HDANode { pub connections: Vec, + pub connection_default: u8, + pub is_widget: bool, pub config_default: u32, @@ -54,6 +56,7 @@ impl HDANode { config_default: 0, is_widget: false, connections: Vec::::new(), + connection_default: 0, } } @@ -87,18 +90,35 @@ impl fmt::Display for HDANode { match self.widget_type() { HDAWidgetType::PinComplex => write!( f, - "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {:X}: {:X?}.", + "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {}/{}: {:X?}.", self.addr.0, self.addr.1, self.widget_type(), self.device_default().unwrap(), + self.connection_default, + self.conn_list_len, + self.connections + ), + _ => write!( + f, + "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {}/{}: {:X?}.", + self.addr.0, + self.addr.1, + self.widget_type(), + self.connection_default, self.conn_list_len, self.connections ), - _ => write!(f, "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {:X}: {:X?}.", self.addr.0, self.addr.1, self.widget_type(), self.conn_list_len, self.connections), } } else { - write!(f, "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", self.addr.0, self.addr.1, self.function_group_type, self.subnode_count) + write!( + f, + "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", + self.addr.0, + self.addr.1, + self.function_group_type, + self.subnode_count + ) } } } From 7c3f177ec03908cc1173753b1509018319b606f7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 18 Nov 2022 14:25:34 -0700 Subject: [PATCH 0555/1301] ihda: Set correct intctl based on number of streams --- ihdad/src/hda/device.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index a137623bf5..189a10ea07 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -233,8 +233,8 @@ impl IntelHDA { // TODO: provide a function to enable certain interrupts // This just enables the first output stream interupt and the global interrupt - // TODO: No magic numbers! Bad Schemm. - self.regs.intctl.write((1 << 31) | /* (1 << 30) |*/ (1 << 4)); + let iss = self.num_input_streams(); + self.regs.intctl.write((1 << 31) | /* (1 << 30) |*/ (1 << iss)); } pub fn irq(&mut self) -> bool { From aadf2ec9dca1163a45fadb05db27e1b6dedc792b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 18 Nov 2022 14:36:28 -0700 Subject: [PATCH 0556/1301] ihda: Add 1ms polling --- ihdad/src/main.rs | 53 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 12 deletions(-) diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index bc8f23df7e..30d1ffcbcd 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -101,25 +101,54 @@ fn main() { .expect("ihdad: failed to map address") }; { - let mut irq_file = File::open(format!("irq:{}", irq)).expect("IHDA: failed to open IRQ file"); + let mut time_file = File::open(format!("time:{}", syscall::CLOCK_MONOTONIC)).expect("ihdad: failed to open time file"); + + let mut irq_file = File::open(format!("irq:{}", irq)).expect("ihdad: failed to open IRQ file"); let vend_prod:u32 = ((vend as u32) << 16) | (prod as u32); let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); - let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("IHDA: failed to create hda scheme"); + let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ihdad: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); - daemon.ready().expect("IHDA: failed to signal readiness"); + daemon.ready().expect("ihdad: failed to signal readiness"); - let mut event_queue = EventQueue::::new().expect("IHDA: Could not create event queue."); + let mut event_queue = EventQueue::::new().expect("ihdad: Could not create event queue."); syscall::setrens(0, 0).expect("ihdad: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); + let todo_time = todo.clone(); + let device_time = device.clone(); + let socket_time = socket.clone(); + event_queue.add(time_file.as_raw_fd(), move |_event| -> Result> { + let mut todo = todo_time.borrow_mut(); + let mut i = 0; + while i < todo.len() { + if let Some(a) = device_time.borrow_mut().handle(&mut todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket_time.borrow_mut().write(&packet)?; + } else { + i += 1; + } + } + + let mut time = syscall::TimeSpec::default(); + time_file.read(&mut time)?; + time.tv_nsec += 1_000_000; // 1 ms + while time.tv_nsec >= 1_000_000_000 { + time.tv_sec += 1; + time.tv_nsec -= 1_000_000_000; + } + time_file.write(&time)?; + + Ok(None) + }).expect("ihdad: failed to catch events on time file"); + let todo_irq = todo.clone(); let device_irq = device.clone(); let socket_irq = socket.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; @@ -147,7 +176,7 @@ fn main() { */ } Ok(None) - }).expect("IHDA: failed to catch events on IRQ file"); + }).expect("ihdad: failed to catch events on IRQ file"); let socket_fd = socket.borrow().as_raw_fd(); let socket_packet = socket.clone(); event_queue.add(socket_fd, move |_event| -> Result> { @@ -179,12 +208,12 @@ fn main() { */ Ok(None) - }).expect("IHDA: failed to catch events on IRQ file"); + }).expect("ihdad: failed to catch events on IRQ file"); for event_count in event_queue.trigger_all(event::Event { fd: 0, flags: EventFlags::empty(), - }).expect("IHDA: failed to trigger events") { + }).expect("ihdad: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, pid: 0, @@ -194,14 +223,14 @@ fn main() { b: 0, c: syscall::flag::EVENT_READ.bits(), d: event_count - }).expect("IHDA: failed to write event"); + }).expect("ihdad: failed to write event"); } loop { { //device_loop.borrow_mut().handle_interrupts(); } - let event_count = event_queue.run().expect("IHDA: failed to handle events"); + let event_count = event_queue.run().expect("ihdad: failed to handle events"); if event_count == 0 { //TODO: Handle todo break; @@ -216,11 +245,11 @@ fn main() { b: 0, c: syscall::flag::EVENT_READ.bits(), d: event_count - }).expect("IHDA: failed to write event"); + }).expect("ihdad: failed to write event"); } } unsafe { let _ = syscall::physunmap(address); } std::process::exit(0); - }).expect("IHDA: failed to daemonize"); + }).expect("ihdad: failed to daemonize"); } From 4dc0cba1594e2e86b4a6426c87276b802ac82fd8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 18 Nov 2022 14:37:11 -0700 Subject: [PATCH 0557/1301] ihda: Improvements to configure, add codec file --- ihdad/src/hda/device.rs | 113 +++++++++++++++++++++++++++++++++------- 1 file changed, 94 insertions(+), 19 deletions(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 189a10ea07..834ce6b062 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -2,6 +2,7 @@ use std::cmp; use std::collections::HashMap; +use std::fmt::Write; use std::str; use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -345,7 +346,7 @@ impl IntelHDA { let root = self.read_node((codec,0)); - // log::info!("{}", root); + log::info!("{}", root); let root_count = root.subnode_count; let root_start = root.subnode_start; @@ -353,12 +354,11 @@ impl IntelHDA { //FIXME: So basically the way this is set up is to only support one codec and hopes the first one is an audio for i in 0..root_count { let afg = self.read_node((codec, root_start + i)); - // log::info!("{}", afg); + log::info!("{}", afg); let afg_count = afg.subnode_count; let afg_start = afg.subnode_start; for j in 0..afg_count { - let mut widget = self.read_node((codec, afg_start + j)); widget.is_widget = true; match widget.widget_type() { @@ -465,12 +465,18 @@ impl IntelHDA { log::info!("Path to DAC: {:X?}", path); + // Set power state 0 (on) for all widgets in path + for &addr in &path { + self.set_power_state(addr, 0); + } + // Pin enable (0x80 = headphone amp enable, 0x40 = output enable) self.cmd.cmd12(pin, 0x707, 0xC0); // EAPD enable self.cmd.cmd12(pin, 0x70C, 2); + // Set DAC stream and channel self.set_stream_channel(dac, 1, 0); self.update_sound_buffers(); @@ -478,29 +484,67 @@ impl IntelHDA { log::info!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); log::info!("Capabilities: {:08X}", self.get_capabilities(path[0])); + // Create output stream let output = self.get_output_stream_descriptor(0).unwrap(); - output.set_address(self.buff_desc_phys); - output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); output.set_cyclic_buffer_length((NUM_SUB_BUFFS * SUB_BUFF_SIZE) as u32); // number of bytes output.set_stream_number(1); output.set_last_valid_index((NUM_SUB_BUFFS - 1) as u16); output.set_interrupt_on_completion(true); - - self.set_power_state(dac, 0); // Power state 0 is fully on + // Set DAC converter format self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2); - // Get converter format + // Get DAC converter format + //TODO: should validate? self.cmd.cmd12(dac, 0xA00, 0); - // Unmute and set gain for pin complex and DAC - self.set_amplifier_gain_mute(dac, true, true, true, true, 0, false, 0x7f); - self.set_amplifier_gain_mute(pin, true, true, true, true, 0, false, 0x7f); + // Unmute and set gain to 0db for input and output amplifiers on all widgets in path + for &addr in &path { + // Read widget capabilities + let caps = self.cmd.cmd12(addr, 0xF00, 0x09); + + //TODO: do we need to set any other indexes? + let left = true; + let right = true; + let index = 0; + let mute = false; + + // Check for input amp + if (caps & (1 << 1)) != 0 { + // Read input capabilities + let in_caps = self.cmd.cmd12(addr, 0xF00, 0x0D); + let in_gain = (in_caps & 0x7f) as u8; + // Set input gain + let output = false; + let input = true; + self.set_amplifier_gain_mute(addr, output, input, left, right, index, mute, in_gain); + log::info!("Set {:X?} input gain to 0x{:X}", addr, in_gain); + } + + // Check for output amp + if (caps & (1 << 2)) != 0 { + // Read output capabilities + let out_caps = self.cmd.cmd12(addr, 0xF00, 0x12); + let out_gain = (out_caps & 0x7f) as u8; + // Set output gain + let output = true; + let input = false; + self.set_amplifier_gain_mute(addr, output, input, left, right, index, mute, out_gain); + log::info!("Set {:X?} output gain to 0x{:X}", addr, out_gain); + } + } + + //TODO: implement hda-verb? output.run(); + log::info!("Waiting for output 0 to start running..."); + while output.control() & (1 << 1) == 0 { + //TODO: relax + } + eprintln!("Output 0 CONTROL {:#X} STATUS {:#X} POS {:#X}", output.control(), output.status(), output.link_position()); } /* @@ -557,6 +601,16 @@ impl IntelHDA { */ + pub fn dump_codec(&self, codec:u8) -> String { + let mut string = String::new(); + + for (_, widget) in self.widget_map.iter() { + let _ = writeln!(string, "{}", widget); + } + + string + } + // BEEP!! pub fn beep(&mut self, div:u8) { let addr = self.beep_addr; @@ -716,8 +770,6 @@ impl IntelHDA { payload |= (gain as u16) & 0x7F; self.cmd.cmd4(addr, 0x3, payload); - - } pub fn write_to_output(&mut self, index:u8, buf: &[u8]) -> Result> { @@ -761,8 +813,8 @@ impl IntelHDA { } pub fn handle_stream_interrupts(&mut self, sis: u32) { - let oss = self.num_output_streams(); let iss = self.num_input_streams(); + let oss = self.num_output_streams(); let bss = self.num_bidirectional_streams(); for i in 0..iss { @@ -848,7 +900,7 @@ impl Drop for IntelHDA { } impl SchemeBlockMut for IntelHDA { - fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { + fn open(&mut self, path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { //let path: Vec<&str>; /* match str::from_utf8(_path) { @@ -863,19 +915,42 @@ impl SchemeBlockMut for IntelHDA { // TODO: if uid == 0 { + let handle = match path.trim_matches('/') { + //TODO: allow multiple codecs + "codec" => Handle::StrBuf(self.dump_codec(0).into_bytes(), 0), + _ => Handle::Todo, + }; let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, Handle::Todo); + self.handles.lock().insert(id, handle); Ok(Some(id)) } else { Err(Error::new(EACCES)) } } + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let mut handles = self.handles.lock(); + match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::StrBuf(ref strbuf, ref mut size) => { + let mut i = 0; + while i < buf.len() && *size < strbuf.len() { + buf[i] = strbuf[*size]; + i += 1; + *size += 1; + } + Ok(Some(i)) + }, + _ => Err(Error::new(EBADF)), + } + } + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { let index = { let mut handles = self.handles.lock(); - let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - 0 + match handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::Todo => 0, + _ => return Err(Error::new(EBADF)), + } }; //log::info!("Int count: {}", self.int_counter); @@ -884,7 +959,7 @@ impl SchemeBlockMut for IntelHDA { } fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { - let pos = pos as usize; + let pos = pos as usize; let mut handles = self.handles.lock(); match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::StrBuf(ref mut strbuf, ref mut size) => { From ff205ad65d6336aab43418da4c2d08dfbd536350 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 19 Nov 2022 08:18:51 -0700 Subject: [PATCH 0558/1301] ihda: Enable MSI and use pcid channel --- Cargo.lock | 1 + ihdad/Cargo.toml | 2 + ihdad/config.toml | 3 +- ihdad/src/main.rs | 345 ++++++++++++++++++++++++++-------------------- 4 files changed, 204 insertions(+), 147 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e448276b87..09ed04dbaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -484,6 +484,7 @@ version = "0.1.0" dependencies = [ "bitflags", "log", + "pcid", "redox-daemon", "redox-log", "redox_event", diff --git a/ihdad/Cargo.toml b/ihdad/Cargo.toml index f30d2fae70..7ef0407d69 100755 --- a/ihdad/Cargo.toml +++ b/ihdad/Cargo.toml @@ -11,3 +11,5 @@ redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" spin = "0.9" + +pcid = { path = "../pcid" } diff --git a/ihdad/config.toml b/ihdad/config.toml index 11fc35efb1..b4d8a132d7 100644 --- a/ihdad/config.toml +++ b/ihdad/config.toml @@ -2,4 +2,5 @@ name = "Intel HD Audio" class = 4 subclass = 3 -command = ["ihdad", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ", "$VENID", "$DEVID"] +command = ["ihdad"] +use_channel = true diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 30d1ffcbcd..9ef7efa711 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -5,7 +5,8 @@ extern crate spin; extern crate syscall; extern crate event; -use std::{env, usize}; +use std::convert::TryFrom; +use std::usize; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; @@ -14,6 +15,8 @@ use std::cell::RefCell; use std::sync::Arc; use event::EventQueue; +use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; +use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector}; use redox_log::{OutputBuilder, RedoxLogger}; pub mod hda; @@ -69,187 +72,237 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } } -fn main() { - let mut args = env::args().skip(1); +#[cfg(target_arch = "x86_64")] +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { + let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); - let mut name = args.next().expect("ihda: no name provided"); - name.push_str("_ihda"); + let irq = pci_config.func.legacy_interrupt_line; - let bar_str = args.next().expect("ihda: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("ihda: failed to parse address"); + let all_pci_features = pcid_handle.fetch_all_features().expect("ihdad: failed to fetch pci features"); + log::info!("PCI FEATURES: {:?}", all_pci_features); - let bar_size_str = args.next().expect("ihda: no address size provided"); - let bar_size = usize::from_str_radix(&bar_size_str, 16).expect("ihda: failed to parse address size"); + let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); - let irq_str = args.next().expect("ihda: no irq provided"); - let irq = irq_str.parse::().expect("ihda: failed to parse irq"); + if has_msi && !msi_enabled && !has_msix { + msi_enabled = true; + } + if has_msix && !msix_enabled { + msix_enabled = true; + } - let vend_str = args.next().expect("ihda: no vendor id provided"); - let vend = usize::from_str_radix(&vend_str, 16).expect("ihda: failed to parse vendor id"); + if msi_enabled && !msix_enabled { + use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; - let prod_str = args.next().expect("ihda: no product id provided"); - let prod = usize::from_str_radix(&prod_str, 16).expect("ihda: failed to parse product id"); + let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("ihdad: failed to retrieve the MSI capability structure from pcid") { + PciFeatureInfo::Msi(s) => s, + PciFeatureInfo::MsiX(_) => panic!(), + }; + // TODO: Allow allocation of up to 32 vectors. - print!("{}", format!(" + ihda {} on: {:X} size: {} IRQ: {}\n", name, bar, bar_size, irq)); + // TODO: Find a way to abstract this away, potantially as a helper module for + // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. - // Daemonize - redox_daemon::Daemon::new(move |daemon| { - let _logger_ref = setup_logging(); + let destination_id = read_bsp_apic_id().expect("ihdad: failed to read BSP apic id"); + let lapic_id = u8::try_from(destination_id).expect("CPU id didn't fit inside u8"); + let msg_addr = x86_64_msix::message_address(lapic_id, false, false); - let address = unsafe { - syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("ihdad: failed to map address") - }; - { - let mut time_file = File::open(format!("time:{}", syscall::CLOCK_MONOTONIC)).expect("ihdad: failed to open time file"); + let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("ihdad: failed to allocate interrupt vector").expect("ihdad: no interrupt vectors left"); + let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("ihdad: failed to open IRQ file"); + let set_feature_info = MsiSetFeatureInfo { + multi_message_enable: Some(0), + message_address: Some(msg_addr), + message_upper_address: Some(0), + message_data: Some(msg_data as u16), + mask_bits: None, + }; + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("ihdad: failed to set feature info"); - let vend_prod:u32 = ((vend as u32) << 16) | (prod as u32); + pcid_handle.enable_feature(PciFeature::Msi).expect("ihdad: failed to enable MSI"); + log::info!("Enabled MSI"); - let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); - let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ihdad: failed to create hda scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); - daemon.ready().expect("ihdad: failed to signal readiness"); + Some(interrupt_handle) + } else if pci_config.func.legacy_interrupt_pin.is_some() { + // legacy INTx# interrupt pins. + Some(File::open(format!("irq:{}", irq)).expect("ihdad: failed to open legacy IRQ file")) + } else { + // no interrupts at all + None + } +} - let mut event_queue = EventQueue::::new().expect("ihdad: Could not create event queue."); +//TODO: MSI on non-x86_64? +#[cfg(not(target_arch = "x86_64"))] +fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> Option { + let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); + let irq = pci_config.func.legacy_interrupt_line; - syscall::setrens(0, 0).expect("ihdad: failed to enter null namespace"); + if pci_config.func.legacy_interrupt_pin.is_some() { + // legacy INTx# interrupt pins. + Some(File::open(format!("irq:{}", irq)).expect("ihdad: failed to open legacy IRQ file")) + } else { + // no interrupts at all + None + } +} - let todo = Arc::new(RefCell::new(Vec::::new())); +fn daemon(daemon: redox_daemon::Daemon) -> ! { + let _logger_ref = setup_logging(); - let todo_time = todo.clone(); - let device_time = device.clone(); - let socket_time = socket.clone(); - event_queue.add(time_file.as_raw_fd(), move |_event| -> Result> { - let mut todo = todo_time.borrow_mut(); + let mut pcid_handle = PcidServerHandle::connect_default().expect("rtl8168d: failed to setup channel to pcid"); + + let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); + + let mut name = pci_config.func.name(); + name.push_str("_rtl8168"); + + let bar = pci_config.func.bars[0]; + let bar_size = pci_config.func.bar_sizes[0]; + let bar_ptr = match bar { + pcid_interface::PciBar::Memory32(ptr) => match ptr { + 0 => panic!("BAR 0 is mapped to address 0"), + _ => ptr as u64, + }, + pcid_interface::PciBar::Memory64(ptr) => match ptr { + 0 => panic!("BAR 0 is mapped to address 0"), + _ => ptr, + }, + other => panic!("Expected memory bar, found {}", other), + }; + + eprintln!(" + IHDA {} on: {:#X} size: {}", name, bar_ptr, bar_size); + + let address = unsafe { + syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("ihdad: failed to map address") + }; + + //TODO: MSI-X + let mut irq_file = get_int_method(&mut pcid_handle).expect("rtl8168d: no interrupt file"); + + { + let vend_prod:u32 = ((pci_config.func.venid as u32) << 16) | (pci_config.func.devid as u32); + + let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); + let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ihdad: failed to create hda scheme"); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + daemon.ready().expect("ihdad: failed to signal readiness"); + + let mut event_queue = EventQueue::::new().expect("ihdad: Could not create event queue."); + + syscall::setrens(0, 0).expect("ihdad: failed to enter null namespace"); + + let todo = Arc::new(RefCell::new(Vec::::new())); + + let todo_irq = todo.clone(); + let device_irq = device.clone(); + let socket_irq = socket.clone(); + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + + if device_irq.borrow_mut().irq() { + irq_file.write(&mut irq)?; + + let mut todo = todo_irq.borrow_mut(); let mut i = 0; while i < todo.len() { - if let Some(a) = device_time.borrow_mut().handle(&mut todo[i]) { + if let Some(a) = device_irq.borrow_mut().handle(&mut todo[i]) { let mut packet = todo.remove(i); packet.a = a; - socket_time.borrow_mut().write(&packet)?; + socket_irq.borrow_mut().write(&packet)?; } else { i += 1; } } - let mut time = syscall::TimeSpec::default(); - time_file.read(&mut time)?; - time.tv_nsec += 1_000_000; // 1 ms - while time.tv_nsec >= 1_000_000_000 { - time.tv_sec += 1; - time.tv_nsec -= 1_000_000_000; - } - time_file.write(&time)?; - - Ok(None) - }).expect("ihdad: failed to catch events on time file"); - - let todo_irq = todo.clone(); - let device_irq = device.clone(); - let socket_irq = socket.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - - if device_irq.borrow_mut().irq() { - irq_file.write(&mut irq)?; - - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - if let Some(a) = device_irq.borrow_mut().handle(&mut todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket_irq.borrow_mut().write(&packet)?; - } else { - i += 1; - } - } - - /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - } - Ok(None) - }).expect("ihdad: failed to catch events on IRQ file"); - let socket_fd = socket.borrow().as_raw_fd(); - let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_event| -> Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => return Ok(Some(0)), - Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } - - if let Some(a) = device.borrow_mut().handle(&mut packet) { - packet.a = a; - socket_packet.borrow_mut().write(&packet)?; - } else { - todo.borrow_mut().push(packet); - } - } - /* - let next_read = device.borrow().next_read(); + let next_read = device_irq.next_read(); if next_read > 0 { return Ok(Some(next_read)); } */ - - Ok(None) - }).expect("ihdad: failed to catch events on IRQ file"); - - for event_count in event_queue.trigger_all(event::Event { - fd: 0, - flags: EventFlags::empty(), - }).expect("ihdad: failed to trigger events") { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("ihdad: failed to write event"); } - + Ok(None) + }).expect("ihdad: failed to catch events on IRQ file"); + let socket_fd = socket.borrow().as_raw_fd(); + let socket_packet = socket.clone(); + event_queue.add(socket_fd, move |_event| -> Result> { loop { - { - //device_loop.borrow_mut().handle_interrupts(); - } - let event_count = event_queue.run().expect("ihdad: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; + let mut packet = Packet::default(); + match socket_packet.borrow_mut().read(&mut packet) { + Ok(0) => return Ok(Some(0)), + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } } - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("ihdad: failed to write event"); + if let Some(a) = device.borrow_mut().handle(&mut packet) { + packet.a = a; + socket_packet.borrow_mut().write(&packet)?; + } else { + todo.borrow_mut().push(packet); + } } + + /* + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + + Ok(None) + }).expect("ihdad: failed to catch events on IRQ file"); + + for event_count in event_queue.trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }).expect("ihdad: failed to trigger events") { + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ.bits(), + d: event_count + }).expect("ihdad: failed to write event"); } - unsafe { let _ = syscall::physunmap(address); } + loop { + { + //device_loop.borrow_mut().handle_interrupts(); + } + let event_count = event_queue.run().expect("ihdad: failed to handle events"); + if event_count == 0 { + //TODO: Handle todo + break; + } + + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ.bits(), + d: event_count + }).expect("ihdad: failed to write event"); + } + } + + unsafe { let _ = syscall::physunmap(address); } std::process::exit(0); - }).expect("ihdad: failed to daemonize"); +} + +fn main() { + // Daemonize + redox_daemon::Daemon::new(daemon).expect("ihdad: failed to daemonize"); } From 860dd2ee31c1142552821a42a2c02a1968e4be0b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 19 Nov 2022 08:21:32 -0700 Subject: [PATCH 0559/1301] ihda: Reduce default volume --- ihdad/src/hda/device.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 834ce6b062..dfcb092784 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -515,7 +515,9 @@ impl IntelHDA { if (caps & (1 << 1)) != 0 { // Read input capabilities let in_caps = self.cmd.cmd12(addr, 0xF00, 0x0D); - let in_gain = (in_caps & 0x7f) as u8; + let mut in_gain = (in_caps & 0x7f) as u8; + // Divide gain by two (to try to adjust volume to 50%) + in_gain /= 2; // Set input gain let output = false; let input = true; @@ -527,7 +529,9 @@ impl IntelHDA { if (caps & (1 << 2)) != 0 { // Read output capabilities let out_caps = self.cmd.cmd12(addr, 0xF00, 0x12); - let out_gain = (out_caps & 0x7f) as u8; + let mut out_gain = (out_caps & 0x7f) as u8; + // Divide gain by two (to try to adjust volume to 50%) + out_gain /= 2; // Set output gain let output = true; let input = false; @@ -544,7 +548,7 @@ impl IntelHDA { //TODO: relax } - eprintln!("Output 0 CONTROL {:#X} STATUS {:#X} POS {:#X}", output.control(), output.status(), output.link_position()); + log::info!("Output 0 CONTROL {:#X} STATUS {:#X} POS {:#X}", output.control(), output.status(), output.link_position()); } /* From c57b3c8910e85edb0af18c6534e39fb3a742a834 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 19 Nov 2022 16:18:16 -0700 Subject: [PATCH 0560/1301] rtl8168: enable MSI and MSI-X --- Cargo.lock | 3 + rtl8168d/Cargo.toml | 4 + rtl8168d/config.toml | 3 +- rtl8168d/src/main.rs | 491 ++++++++++++++++++++++++++++++++----------- 4 files changed, 383 insertions(+), 118 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 09ed04dbaf..e91290c178 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1185,8 +1185,11 @@ name = "rtl8168d" version = "0.1.0" dependencies = [ "bitflags", + "log", "netutils", + "pcid", "redox-daemon", + "redox-log", "redox_event", "redox_syscall 0.3.4", ] diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index 0bd706fa07..16579d808b 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -5,7 +5,11 @@ edition = "2018" [dependencies] bitflags = "1" +log = "0.4" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" redox-daemon = "0.1" +redox-log = "0.1" + +pcid = { path = "../pcid" } diff --git a/rtl8168d/config.toml b/rtl8168d/config.toml index a65ba291e3..6fdb0e7b30 100644 --- a/rtl8168d/config.toml +++ b/rtl8168d/config.toml @@ -2,4 +2,5 @@ name = "RTL8168 NIC" class = 2 ids = { 0x10ec = [0x8168, 0x8169] } -command = ["rtl8168d", "$NAME", "$BAR2", "$BARSIZE2", "$IRQ"] +command = ["rtl8168d"] +use_channel = true diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index d8e40a40c6..aa95508967 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -3,17 +3,265 @@ extern crate netutils; extern crate syscall; use std::cell::RefCell; +use std::convert::TryFrom; use std::{env, process}; use std::fs::File; use std::io::{ErrorKind, Read, Result, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::ptr::NonNull; use std::sync::Arc; use event::EventQueue; +use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; +use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector}; +use pcid_interface::msi::{MsixCapability, MsixTableEntry}; +use redox_log::{RedoxLogger, OutputBuilder}; use syscall::{EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::io::Io; pub mod device; +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("usb", "host", "rtl8168.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("Failed to create rtl8168.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("usb", "host", "rtl8168.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("Failed to create rtl8168.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("rtl8168d: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("rtl8168d: failed to set default logger: {}", error); + None + } + } +} + +use std::ops::{Add, Div, Rem}; +pub fn div_round_up(a: T, b: T) -> T +where + T: Add + Div + Rem + PartialEq + From + Copy, +{ + if a % b != T::from(0u8) { + a / b + T::from(1u8) + } else { + a / b + } +} + +pub struct MsixInfo { + pub virt_table_base: NonNull, + pub virt_pba_base: NonNull, + pub capability: MsixCapability, +} + +impl MsixInfo { + pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { + &mut *self.virt_table_base.as_ptr().offset(k as isize) + } + pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { + assert!(k < self.capability.table_size() as usize); + unsafe { self.table_entry_pointer_unchecked(k) } + } + pub unsafe fn pba_pointer_unchecked(&mut self, k: usize) -> &mut u64 { + &mut *self.virt_pba_base.as_ptr().offset(k as isize) + } + pub fn pba_pointer(&mut self, k: usize) -> &mut u64 { + assert!(k < self.capability.table_size() as usize); + unsafe { self.pba_pointer_unchecked(k) } + } + pub fn pba(&mut self, k: usize) -> bool { + let byte = k / 64; + let bit = k % 64; + *self.pba_pointer(byte) & (1 << bit) != 0 + } +} + +#[cfg(target_arch = "x86_64")] +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { + let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); + + let irq = pci_config.func.legacy_interrupt_line; + + let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8168d: failed to fetch pci features"); + log::info!("PCI FEATURES: {:?}", all_pci_features); + + let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + + if has_msi && !msi_enabled && !has_msix { + msi_enabled = true; + } + if has_msix && !msix_enabled { + msix_enabled = true; + } + + if msi_enabled && !msix_enabled { + use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; + + let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("rtl8168d: failed to retrieve the MSI capability structure from pcid") { + PciFeatureInfo::Msi(s) => s, + PciFeatureInfo::MsiX(_) => panic!(), + }; + // TODO: Allow allocation of up to 32 vectors. + + // TODO: Find a way to abstract this away, potantially as a helper module for + // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. + + let destination_id = read_bsp_apic_id().expect("rtl8168d: failed to read BSP apic id"); + let lapic_id = u8::try_from(destination_id).expect("CPU id didn't fit inside u8"); + let msg_addr = x86_64_msix::message_address(lapic_id, false, false); + + let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("rtl8168d: failed to allocate interrupt vector").expect("rtl8168d: no interrupt vectors left"); + let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + + let set_feature_info = MsiSetFeatureInfo { + multi_message_enable: Some(0), + message_address: Some(msg_addr), + message_upper_address: Some(0), + message_data: Some(msg_data as u16), + mask_bits: None, + }; + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("rtl8168d: failed to set feature info"); + + pcid_handle.enable_feature(PciFeature::Msi).expect("rtl8168d: failed to enable MSI"); + log::info!("Enabled MSI"); + + Some(interrupt_handle) + } else if msix_enabled { + let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8168d: failed to retrieve the MSI-X capability structure from pcid") { + PciFeatureInfo::Msi(_) => panic!(), + PciFeatureInfo::MsiX(s) => s, + }; + let table_size = capability.table_size(); + let table_base = capability.table_base_pointer(pci_config.func.bars); + let table_min_length = table_size * 16; + let pba_min_length = div_round_up(table_size, 8); + + let pba_base = capability.pba_base_pointer(pci_config.func.bars); + + let bir = capability.table_bir() as usize; + let bar = pci_config.func.bars[bir]; + let bar_size = pci_config.func.bar_sizes[bir] as u64; + + let bar_ptr = match bar { + pcid_interface::PciBar::Memory32(ptr) => match ptr { + 0 => panic!("BAR {} is mapped to address 0", bir), + _ => ptr as u64, + }, + pcid_interface::PciBar::Memory64(ptr) => match ptr { + 0 => panic!("BAR {} is mapped to address 0", bir), + _ => ptr, + }, + other => panic!("Expected memory bar, found {}", other), + }; + + let address = unsafe { + syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("rtl8168d: failed to map address") + }; + + if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u64 + table_min_length as u64)) { + panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); + } + + if !(bar_ptr..bar_ptr + bar_size).contains(&(pba_base as u64 + pba_min_length as u64)) { + panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size); + } + + let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; + let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; + + let mut info = MsixInfo { + virt_table_base: NonNull::new(virt_table_base).unwrap(), + virt_pba_base: NonNull::new(virt_pba_base).unwrap(), + capability, + }; + + // Allocate one msi vector. + + let method = { + use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; + + // primary interrupter + let k = 0; + + assert_eq!(std::mem::size_of::(), 16); + let table_entry_pointer = info.table_entry_pointer(k); + + let destination_id = read_bsp_apic_id().expect("rtl8168d: failed to read BSP apic id"); + let lapic_id = u8::try_from(destination_id).expect("rtl8168d: CPU id couldn't fit inside u8"); + let rh = false; + let dm = false; + let addr = x86_64_msix::message_address(lapic_id, rh, dm); + + let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("rtl8168d: failed to allocate interrupt vector").expect("rtl8168d: no interrupt vectors left"); + let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + + table_entry_pointer.addr_lo.write(addr); + table_entry_pointer.addr_hi.write(0); + table_entry_pointer.msg_data.write(msg_data); + table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + + Some(interrupt_handle) + }; + + pcid_handle.enable_feature(PciFeature::MsiX).expect("rtl8168d: failed to enable MSI-X"); + log::info!("Enabled MSI-X"); + + method + } else if pci_config.func.legacy_interrupt_pin.is_some() { + // legacy INTx# interrupt pins. + Some(File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open legacy IRQ file")) + } else { + // no interrupts at all + None + } +} + +//TODO: MSI on non-x86_64? +#[cfg(not(target_arch = "x86_64"))] +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { + let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); + let irq = pci_config.func.legacy_interrupt_line; + + if pci_config.func.legacy_interrupt_pin.is_some() { + // legacy INTx# interrupt pins. + Some(File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open legacy IRQ file")) + } else { + // no interrupts at all + None + } +} + fn handle_update( socket: &mut File, device: &mut device::Rtl8168, @@ -57,146 +305,155 @@ fn handle_update( Ok(false) } -fn main() { - let mut args = env::args().skip(1); +fn daemon(daemon: redox_daemon::Daemon) -> ! { + let _logger_ref = setup_logging(); - let mut name = args.next().expect("rtl8168d: no name provided"); + let mut pcid_handle = PcidServerHandle::connect_default().expect("rtl8168d: failed to setup channel to pcid"); + + let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); + + let mut name = pci_config.func.name(); name.push_str("_rtl8168"); - let bar_str = args.next().expect("rtl8168d: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("rtl8168d: failed to parse address"); + let bar = pci_config.func.bars[2]; + let bar_size = pci_config.func.bar_sizes[2]; + let bar_ptr = match bar { + pcid_interface::PciBar::Memory32(ptr) => match ptr { + 0 => panic!("BAR 0 is mapped to address 0"), + _ => ptr as u64, + }, + pcid_interface::PciBar::Memory64(ptr) => match ptr { + 0 => panic!("BAR 0 is mapped to address 0"), + _ => ptr, + }, + other => panic!("Expected memory bar, found {}", other), + }; - let bar_size_str = args.next().expect("rtl8168d: no address size provided"); - let bar_size = usize::from_str_radix(&bar_size_str, 16).expect("rtl8168d: failed to parse address size"); + eprintln!(" + RTL8168 {} on: {:#X} size: {}", name, bar_ptr, bar_size); - let irq_str = args.next().expect("rtl8168d: no irq provided"); - let irq = irq_str.parse::().expect("rtl8168d: failed to parse irq"); + let address = unsafe { + syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("rtl8168d: failed to map address") + }; - eprintln!(" + RTL8168 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); + //TODO: MSI-X + let mut irq_file = get_int_method(&mut pcid_handle).expect("rtl8168d: no interrupt file"); - redox_daemon::Daemon::new(move |daemon| { - let socket_fd = syscall::open( - ":network", - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ) - .expect("rtl8168d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) + let socket_fd = syscall::open( + ":network", + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + ) + .expect("rtl8168d: failed to create network scheme"); + let socket = Arc::new(RefCell::new(unsafe { + File::from_raw_fd(socket_fd as RawFd) + })); + + { + let device = Arc::new(RefCell::new(unsafe { + device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") })); - let irq_fd = syscall::open( - format!("irq:{}", irq), - syscall::O_RDWR | syscall::O_NONBLOCK - ).expect("rtl8168d: failed to open IRQ file"); - let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; + let mut event_queue = + EventQueue::::new().expect("rtl8168d: failed to create event queue"); - let address = unsafe { - syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("rtl8168d: failed to map address") - }; - { - let device = Arc::new(RefCell::new(unsafe { - device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") - })); + syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); - let mut event_queue = - EventQueue::::new().expect("rtl8168d: failed to create event queue"); + daemon.ready().expect("rtl8168d: failed to mark daemon as ready"); - syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); + let todo = Arc::new(RefCell::new(Vec::::new())); - daemon.ready().expect("rtl8168d: failed to mark daemon as ready"); + let device_irq = device.clone(); + let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + //TODO: This may be causing spurious interrupts + if unsafe { device_irq.borrow_mut().irq() } { + irq_file.write(&mut irq)?; - let todo = Arc::new(RefCell::new(Vec::::new())); - - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - //TODO: This may be causing spurious interrupts - if unsafe { device_irq.borrow_mut().irq() } { - irq_file.write(&mut irq)?; - - if handle_update( - &mut socket_irq.borrow_mut(), - &mut device_irq.borrow_mut(), - &mut todo_irq.borrow_mut(), - )? { - return Ok(Some(0)); - } - - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } + if handle_update( + &mut socket_irq.borrow_mut(), + &mut device_irq.borrow_mut(), + &mut todo_irq.borrow_mut(), + )? { + return Ok(Some(0)); } - Ok(None) - }, - ) - .expect("rtl8168d: failed to catch events on IRQ file"); - let device_packet = device.clone(); - let socket_packet = socket.clone(); - event_queue - .add(socket_fd as RawFd, move |_event| -> Result> { - if handle_update( - &mut socket_packet.borrow_mut(), - &mut device_packet.borrow_mut(), - &mut todo.borrow_mut(), - )? { - return Ok(Some(0)); + let next_read = device_irq.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } } - - let next_read = device_packet.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - Ok(None) - }) - .expect("rtl8168d: failed to catch events on scheme file"); + }, + ) + .expect("rtl8168d: failed to catch events on IRQ file"); - let send_events = |event_count| { - for (handle_id, _handle) in device.borrow().handles.iter() { - socket - .borrow_mut() - .write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: syscall::flag::EVENT_READ.bits(), - d: event_count, - }) - .expect("rtl8168d: failed to write event"); + let device_packet = device.clone(); + let socket_packet = socket.clone(); + event_queue + .add(socket_fd as RawFd, move |_event| -> Result> { + if handle_update( + &mut socket_packet.borrow_mut(), + &mut device_packet.borrow_mut(), + &mut todo.borrow_mut(), + )? { + return Ok(Some(0)); } - }; - for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) - .expect("rtl8168d: failed to trigger events") - { - send_events(event_count); - } - - loop { - let event_count = event_queue.run().expect("rtl8168d: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; + let next_read = device_packet.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); } - send_events(event_count); + + Ok(None) + }) + .expect("rtl8168d: failed to catch events on scheme file"); + + let send_events = |event_count| { + for (handle_id, _handle) in device.borrow().handles.iter() { + socket + .borrow_mut() + .write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: syscall::flag::EVENT_READ.bits(), + d: event_count, + }) + .expect("rtl8168d: failed to write event"); } + }; + + for event_count in event_queue + .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) + .expect("rtl8168d: failed to trigger events") + { + send_events(event_count); } - unsafe { - let _ = syscall::physunmap(address); + + loop { + let event_count = event_queue.run().expect("rtl8168d: failed to handle events"); + if event_count == 0 { + //TODO: Handle todo + break; + } + send_events(event_count); } - process::exit(0); - }).expect("rtl8168d: failed to create daemon"); + } + unsafe { + let _ = syscall::physunmap(address); + } + process::exit(0); +} + +fn main() { + redox_daemon::Daemon::new(daemon).expect("rtl8168d: failed to create daemon"); } From 9315af5e41c8f831fc718652052cf468a2678372 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 20 Nov 2022 13:16:51 -0700 Subject: [PATCH 0561/1301] Match ac97 and hda buffering --- ac97d/src/device.rs | 4 ++-- ihdad/src/hda/device.rs | 12 ++++-------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/ac97d/src/device.rs b/ac97d/src/device.rs index 6dccdc7f39..1a6fd0a93b 100644 --- a/ac97d/src/device.rs +++ b/ac97d/src/device.rs @@ -266,8 +266,8 @@ impl SchemeBlockMut for Ac97 { let civ = self.bus.po.civ.read() as usize; let mut lvi = self.bus.po.lvi.read() as usize; - if lvi == (civ + 1) % NUM_SUB_BUFFS { - // Block if we already are 1 buffer ahead + if lvi == (civ + 3) % NUM_SUB_BUFFS { + // Block if we already are 3 buffers ahead Ok(None) } else { // Fill next buffer diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index dfcb092784..d1a81c8f4b 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -55,7 +55,7 @@ const IRV: u16 = 1 << 1; const COMMAND_BUFFER_OFFSET: usize = 0x40; -const NUM_SUB_BUFFS: usize = 4; +const NUM_SUB_BUFFS: usize = 32; const SUB_BUFF_SIZE: usize = 2048; enum Handle { @@ -781,16 +781,12 @@ impl IntelHDA { let os = self.output_streams.get_mut(index as usize).unwrap(); //let sample_size:usize = output.sample_size(); - let mut open_block = (output.link_position() as usize) / os.block_size(); - - open_block += NUM_SUB_BUFFS / 2; - while open_block >= NUM_SUB_BUFFS { - open_block -= NUM_SUB_BUFFS; - } + let open_block = (output.link_position() as usize) / os.block_size(); //log::info!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}", output.status(), output.link_position(), output.control()); - if open_block == os.current_block() { + if os.current_block() == (open_block + 3) % NUM_SUB_BUFFS { + // Block if we already are 3 buffers ahead Ok(None) } else { os.write_block(buf).map(|count| Some(count)) From 7eada2053b3cf33be0f83e4bb9f643fe9e444502 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Nov 2022 09:56:23 -0700 Subject: [PATCH 0562/1301] Adjust volume in audiod instead --- ihdad/src/hda/device.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index d1a81c8f4b..fcbf0b10d8 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -515,9 +515,7 @@ impl IntelHDA { if (caps & (1 << 1)) != 0 { // Read input capabilities let in_caps = self.cmd.cmd12(addr, 0xF00, 0x0D); - let mut in_gain = (in_caps & 0x7f) as u8; - // Divide gain by two (to try to adjust volume to 50%) - in_gain /= 2; + let in_gain = (in_caps & 0x7f) as u8; // Set input gain let output = false; let input = true; @@ -529,9 +527,7 @@ impl IntelHDA { if (caps & (1 << 2)) != 0 { // Read output capabilities let out_caps = self.cmd.cmd12(addr, 0xF00, 0x12); - let mut out_gain = (out_caps & 0x7f) as u8; - // Divide gain by two (to try to adjust volume to 50%) - out_gain /= 2; + let out_gain = (out_caps & 0x7f) as u8; // Set output gain let output = true; let input = false; From 91c40854886502fd327fbc9af7783b6cbf26bf68 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Nov 2022 14:25:52 -0700 Subject: [PATCH 0563/1301] ihda: remove unused HDANode members --- ihdad/src/hda/node.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/ihdad/src/hda/node.rs b/ihdad/src/hda/node.rs index 4c1238c50a..223170b2e8 100644 --- a/ihdad/src/hda/node.rs +++ b/ihdad/src/hda/node.rs @@ -15,21 +15,9 @@ pub struct HDANode { // 0x9 pub capabilities: u32, - // 0xC - pub pin_caps: u32, - - // 0xD - pub in_amp: u32, - // 0xE pub conn_list_len: u8, - // 0x12 - pub out_amp: u32, - - // 0x13 - pub vol_knob: u8, - pub connections: Vec, pub connection_default: u8, @@ -47,10 +35,6 @@ impl HDANode { subnode_start: 0, function_group_type: 0, capabilities: 0, - pin_caps: 0, - in_amp: 0, - out_amp: 0, - vol_knob: 0, conn_list_len: 0, config_default: 0, From 7448cbff2d0223ed9b4fbbd3f2d3e79d7b6e72dd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Nov 2022 14:38:10 -0700 Subject: [PATCH 0564/1301] ihda: Select output based on pin sense and prioritized device type --- ihdad/src/hda/device.rs | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index fcbf0b10d8..9624d75097 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -382,22 +382,36 @@ impl IntelHDA { } } - pub fn find_best_output_pin(&self) -> Option{ + pub fn find_best_output_pin(&mut self) -> Option{ let outs = &self.output_pins; if outs.len() == 0 { None } else if outs.len() == 1 { Some(outs[0]) } else { - // TODO: Somehow find the best. - // Slightly okay is find the speaker with the lowest sequence number. - - for &out in outs { - let widget = self.widget_map.get(&out).unwrap(); - - let cd = widget.configuration_default(); - if cd.sequence() == 0 && cd.default_device() == DefaultDevice::HPOut { - return Some(out); + //TODO: change output based on "unsolicited response" interrupts + // Check for devices in this order: Headphone, Speaker, Line Out + for supported_device in &[ + DefaultDevice::HPOut, + DefaultDevice::LineOut, + DefaultDevice::Speaker, + ] { + for &out in outs { + let widget = self.widget_map.get(&out).unwrap(); + let cd = widget.configuration_default(); + if cd.sequence() == 0 && &cd.default_device() == supported_device { + // Check for jack detect bit + let pin_caps = self.cmd.cmd12(widget.addr, 0xF00, 0x0C); + if pin_caps & (1 << 2) != 0 { + // Check for presence + let pin_sense = self.cmd.cmd12(widget.addr, 0xF09, 0); + if pin_sense & (1 << 31) == 0 { + // Skip if nothing is plugged in + continue; + } + } + return Some(out); + } } } From 336a25d644e15964cca68aec21a76dc09e855573 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Nov 2022 15:52:54 -0700 Subject: [PATCH 0565/1301] ihda: fix compilation on i686 --- ihdad/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 9ef7efa711..cae3eeb330 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -134,7 +134,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> Option { +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); let irq = pci_config.func.legacy_interrupt_line; From 43704e56f0b0d7be6beca470e92cd9d5298575ab Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 22 Nov 2022 12:15:53 -0700 Subject: [PATCH 0566/1301] ps2: Handle extended (prefixed with 0xE0) keycodes --- ps2d/src/state.rs | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 1e174a0e03..507de68cd3 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -28,6 +28,7 @@ pub struct Ps2d char> { input: File, width: u32, height: u32, + extended: bool, lshift: bool, rshift: bool, mouse_x: i32, @@ -57,6 +58,7 @@ impl char> Ps2d { input, width: 0, height: 0, + extended: false, lshift: false, rshift: false, mouse_x: 0, @@ -93,23 +95,32 @@ impl char> Ps2d { pub fn handle(&mut self, keyboard: bool, data: u8) { if keyboard { - let (scancode, pressed) = if data >= 0x80 { - (data - 0x80, false) + if data == 0xE0 { + self.extended = true; } else { - (data, true) - }; + let (mut scancode, pressed) = if data >= 0x80 { + (data - 0x80, false) + } else { + (data, true) + }; - if scancode == 0x2A { - self.lshift = pressed; - } else if scancode == 0x36 { - self.rshift = pressed; + if self.extended { + self.extended = false; + scancode += 0x80; + } + + if scancode == 0x2A { + self.lshift = pressed; + } else if scancode == 0x36 { + self.rshift = pressed; + } + + self.input.write(&KeyEvent { + character: (self.get_char)(scancode, self.lshift || self.rshift), + scancode: scancode, + pressed: pressed + }.to_event()).expect("ps2d: failed to write key event"); } - - self.input.write(&KeyEvent { - character: (self.get_char)(scancode, self.lshift || self.rshift), - scancode: scancode, - pressed: pressed - }.to_event()).expect("ps2d: failed to write key event"); } else if self.vmmouse { for _i in 0..256 { let (status, _, _, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) }; From cd3bfc04fc94e3c3a538b6bc902d9812b950f32d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 22 Nov 2022 13:14:19 -0700 Subject: [PATCH 0567/1301] ps2: Ensure that scancode set is always translated to orbital constants --- ps2d/src/state.rs | 149 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 138 insertions(+), 11 deletions(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 507de68cd3..b10d2812a3 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -98,28 +98,155 @@ impl char> Ps2d { if data == 0xE0 { self.extended = true; } else { - let (mut scancode, pressed) = if data >= 0x80 { + let (ps2_scancode, pressed) = if data >= 0x80 { (data - 0x80, false) } else { (data, true) }; - if self.extended { + let scancode = if self.extended { self.extended = false; - scancode += 0x80; - } + match ps2_scancode { + //TODO: media keys + //TODO: 0x1C => orbclient::K_NUM_ENTER, + //TODO: 0x1D => orbclient::K_RIGHT_CTRL, + //TODO: 0x35 => orbclient::K_NUM_SLASH, + 0x38 => orbclient::K_ALT_GR, + 0x47 => orbclient::K_HOME, + 0x48 => orbclient::K_UP, + 0x49 => orbclient::K_PGUP, + 0x4B => orbclient::K_LEFT, + 0x4D => orbclient::K_RIGHT, + 0x4F => orbclient::K_END, + 0x50 => orbclient::K_DOWN, + 0x51 => orbclient::K_PGDN, + //TODO: 0x52 => orbclient::K_INSERT, + 0x53 => orbclient::K_DEL, + 0x5B => 0x5B, //TODO: orbclient::K_LEFT_SUPER, + //TODO: 0x5C => orbclient::K_RIGHT_SUPER, + //TODO: 0x5D => orbclient::K_APP, + //TODO power keys + /* 0x80 to 0xFF used for press/release detection */ + _ => { + if pressed { + println!("ps2d: unknown extended scancode {:02X}", ps2_scancode); + } + 0 + } + } + } else { + match ps2_scancode { + /* 0x00 unused */ + 0x01 => orbclient::K_ESC, + 0x02 => orbclient::K_1, + 0x03 => orbclient::K_2, + 0x04 => orbclient::K_3, + 0x05 => orbclient::K_4, + 0x06 => orbclient::K_5, + 0x07 => orbclient::K_6, + 0x08 => orbclient::K_7, + 0x09 => orbclient::K_8, + 0x0A => orbclient::K_9, + 0x0B => orbclient::K_0, + 0x0C => orbclient::K_MINUS, + 0x0D => orbclient::K_EQUALS, + 0x0E => orbclient::K_BKSP, + 0x0F => orbclient::K_TAB, + 0x10 => orbclient::K_Q, + 0x11 => orbclient::K_W, + 0x12 => orbclient::K_E, + 0x13 => orbclient::K_R, + 0x14 => orbclient::K_T, + 0x15 => orbclient::K_Y, + 0x16 => orbclient::K_U, + 0x17 => orbclient::K_I, + 0x18 => orbclient::K_O, + 0x19 => orbclient::K_P, + 0x1A => orbclient::K_BRACE_OPEN, + 0x1B => orbclient::K_BRACE_CLOSE, + 0x1C => orbclient::K_ENTER, + 0x1D => orbclient::K_CTRL, + 0x1E => orbclient::K_A, + 0x1F => orbclient::K_S, + 0x20 => orbclient::K_D, + 0x21 => orbclient::K_F, + 0x22 => orbclient::K_G, + 0x23 => orbclient::K_H, + 0x24 => orbclient::K_J, + 0x25 => orbclient::K_K, + 0x26 => orbclient::K_L, + 0x27 => orbclient::K_SEMICOLON, + 0x28 => orbclient::K_QUOTE, + 0x29 => orbclient::K_TICK, + 0x2A => orbclient::K_LEFT_SHIFT, + 0x2B => orbclient::K_BACKSLASH, + 0x2C => orbclient::K_Z, + 0x2D => orbclient::K_X, + 0x2E => orbclient::K_C, + 0x2F => orbclient::K_V, + 0x30 => orbclient::K_B, + 0x31 => orbclient::K_N, + 0x32 => orbclient::K_M, + 0x33 => orbclient::K_COMMA, + 0x34 => orbclient::K_PERIOD, + 0x35 => orbclient::K_SLASH, + 0x36 => orbclient::K_RIGHT_SHIFT, + //TODO: 0x37 => orbclient::K_NUM_ASTERISK, + 0x38 => orbclient::K_ALT, + 0x39 => orbclient::K_SPACE, + 0x3A => orbclient::K_CAPS, + 0x3B => orbclient::K_F1, + 0x3C => orbclient::K_F2, + 0x3D => orbclient::K_F3, + 0x3E => orbclient::K_F4, + 0x3F => orbclient::K_F5, + 0x40 => orbclient::K_F6, + 0x41 => orbclient::K_F7, + 0x42 => orbclient::K_F8, + 0x43 => orbclient::K_F9, + 0x44 => orbclient::K_F10, + //TODO: 0x45 => orbclient::K_NUM_LOCK, + //TODO: 0x46 => orbclient::K_SCROLL_LOCK, + 0x47 => orbclient::K_NUM_7, + 0x48 => orbclient::K_NUM_8, + 0x49 => orbclient::K_NUM_9, + //TODO: 0x4A => orbclient::K_NUM_MINUS, + 0x4B => orbclient::K_NUM_4, + 0x4C => orbclient::K_NUM_5, + 0x4D => orbclient::K_NUM_6, + //TODO: 0x4E => orbclient::K_NUM_PLUS, + 0x4F => orbclient::K_NUM_1, + 0x50 => orbclient::K_NUM_2, + 0x51 => orbclient::K_NUM_3, + 0x52 => orbclient::K_NUM_0, + //TODO: 0x53 => orbclient::K_NUM_PERIOD, + /* 0x54 to 0x56 unused */ + 0x57 => orbclient::K_F11, + 0x58 => orbclient::K_F12, + /* 0x59 to 0x7F unused */ + /* 0x80 to 0xFF used for press/release detection */ + _ => { + if pressed { + println!("ps2d: unknown scancode {:02X}", ps2_scancode); + } + 0 + } + } + }; - if scancode == 0x2A { + if scancode == orbclient::K_LEFT_SHIFT { self.lshift = pressed; - } else if scancode == 0x36 { + } else if scancode == orbclient::K_RIGHT_SHIFT { self.rshift = pressed; } - self.input.write(&KeyEvent { - character: (self.get_char)(scancode, self.lshift || self.rshift), - scancode: scancode, - pressed: pressed - }.to_event()).expect("ps2d: failed to write key event"); + if scancode != 0 { + self.input.write(&KeyEvent { + character: (self.get_char)(ps2_scancode, self.lshift || self.rshift), + scancode, + pressed + }.to_event()).expect("ps2d: failed to write key event"); + } } } else if self.vmmouse { for _i in 0..256 { From 089280a62cae564f06bfa47053040cd53607447e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 22 Nov 2022 13:35:40 -0700 Subject: [PATCH 0568/1301] Pass-through volume keys --- ps2d/src/state.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index b10d2812a3..c23462a7fe 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -110,6 +110,9 @@ impl char> Ps2d { //TODO: media keys //TODO: 0x1C => orbclient::K_NUM_ENTER, //TODO: 0x1D => orbclient::K_RIGHT_CTRL, + 0x20 => 0x80 + 0x20, //TODO: orbclient::K_VOLUME_MUTE, + 0x2E => 0x80 + 0x2E, //TODO: orbclient::K_VOLUME_DOWN, + 0x30 => 0x80 + 0x30, //TODO: orbclient::K_VOLUME_UP, //TODO: 0x35 => orbclient::K_NUM_SLASH, 0x38 => orbclient::K_ALT_GR, 0x47 => orbclient::K_HOME, From fc4a69ccf969611cd5972f7b625df1f94ede14fc Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 23 Nov 2022 11:46:58 -0700 Subject: [PATCH 0569/1301] ihda: Fix copy pasted rtl8168 names --- ihdad/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index cae3eeb330..d7b02dd21a 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -150,12 +150,12 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(); - let mut pcid_handle = PcidServerHandle::connect_default().expect("rtl8168d: failed to setup channel to pcid"); + let mut pcid_handle = PcidServerHandle::connect_default().expect("ihdad: failed to setup channel to pcid"); - let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); + let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); let mut name = pci_config.func.name(); - name.push_str("_rtl8168"); + name.push_str("_ihda"); let bar = pci_config.func.bars[0]; let bar_size = pci_config.func.bar_sizes[0]; @@ -179,7 +179,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { }; //TODO: MSI-X - let mut irq_file = get_int_method(&mut pcid_handle).expect("rtl8168d: no interrupt file"); + let mut irq_file = get_int_method(&mut pcid_handle).expect("ihdad: no interrupt file"); { let vend_prod:u32 = ((pci_config.func.venid as u32) << 16) | (pci_config.func.devid as u32); From d42f626808fb60b4c28752ca050411a05d178e0d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 27 Nov 2022 09:25:03 -0700 Subject: [PATCH 0570/1301] nvmed: Yield instead of spin when waiting for submission queue item --- nvmed/src/nvme/mod.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index c76673541e..8129169afd 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -4,6 +4,7 @@ use std::fs::File; use std::ptr; use std::sync::atomic::{AtomicU16, AtomicU64, AtomicUsize, Ordering}; use std::sync::{Mutex, RwLock}; +use std::thread; use crossbeam_channel::Sender; use smallvec::{smallvec, SmallVec}; @@ -471,7 +472,7 @@ impl Nvme { return entry; } } - unsafe { pause(); } + thread::yield_now(); } } From c3ddedafc4f13025778a95ae77a1b73534eab4d7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 27 Nov 2022 11:45:50 -0700 Subject: [PATCH 0571/1301] ahcid: Yield instead of spin when waiting for interrupt --- ahcid/src/ahci/disk_ata.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index 15620c315a..3d64c0e401 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -1,5 +1,6 @@ use std::convert::TryInto; use std::ptr; +use std::thread; use syscall::io::Dma; use syscall::error::Result; @@ -109,7 +110,7 @@ impl DiskATA { if use_interrupts { return Ok(None); } else { - unsafe { pause(); } + thread::yield_now(); continue; } } @@ -144,7 +145,7 @@ impl DiskATA { if use_interrupts { return Ok(None); } else { - unsafe { pause(); } + thread::yield_now(); continue; } } else { From 43375cbe9dd5c74b0a744113ae9c7a77bc0fbd06 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 27 Nov 2022 16:31:04 -0700 Subject: [PATCH 0572/1301] xhci: Warn on unknown BOS instead of panic --- xhcid/src/usb/bos.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xhcid/src/usb/bos.rs b/xhcid/src/usb/bos.rs index ea6c0cfe23..43f1f05b88 100644 --- a/xhcid/src/usb/bos.rs +++ b/xhcid/src/usb/bos.rs @@ -119,6 +119,7 @@ pub enum BosAnyDevDesc { Usb2Ext(BosUsb2ExtDesc), SuperSpeed(BosSuperSpeedDesc), SuperSpeedPlus(BosSuperSpeedPlusDesc), + Unknown, } impl BosAnyDevDesc { @@ -167,7 +168,8 @@ impl<'a> Iterator for BosAnyDevDescIter<'a> { // TODO return None; } else { - unimplemented!("USB device capability of type: {}", base.cap_ty) + log::warn!("unknown USB device capability of type: {:#x}", base.cap_ty); + Some(BosAnyDevDesc::Unknown) } } } From 2f15288beb5abac5d1285547261ab3d22b2a6a1f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Nov 2022 06:52:20 -0700 Subject: [PATCH 0573/1301] xhci: Perform both port reset and controller reset --- xhcid/src/xhci/mod.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 368557d030..7ba5b208c3 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -336,6 +336,17 @@ impl Xhci { } pub fn init(&mut self, max_slots: u8) -> Result<()> { + // Set run/stop to 0 + debug!("Stopping xHC."); + self.op.get_mut().unwrap().usb_cmd.writef(1, false); + + // Warm reset + debug!("Reset xHC"); + self.op.get_mut().unwrap().usb_cmd.writef(1 << 1, true); + while self.op.get_mut().unwrap().usb_cmd.readf(1 << 1) { + thread::yield_now(); + } + // Set enabled slots debug!("Setting enabled slots to {}.", max_slots); self.op.get_mut().unwrap().config.write(max_slots as u32); @@ -382,7 +393,7 @@ impl Xhci { self.setup_scratchpads()?; // Set run/stop to 1 - info!("Starting xHC."); + debug!("Starting xHC."); self.op.get_mut().unwrap().usb_cmd.writef(1, true); // Wait until controller is running @@ -472,6 +483,17 @@ impl Xhci { let port_count = { self.ports.lock().unwrap().len() }; for i in 0..port_count { + //TODO: only reset if USB 2.0? + debug!("Port reset"); + { + let port = &mut self.ports.lock().unwrap()[i]; + port.portsc.writef(port::PortFlags::PORT_PR.bits(), true); + while port.portsc.readf(port::PortFlags::PORT_PR.bits()) { + //while ! port.flags().contains(port::PortFlags::PORT_PRC) { + std::thread::yield_now(); + } + } + let (data, state, speed, flags) = { let port = &self.ports.lock().unwrap()[i]; (port.read(), port.state(), port.speed(), port.flags()) From 4b54a3d2cdb7f7264128d9b03f615a5e1cd2c2ed Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Nov 2022 06:53:04 -0700 Subject: [PATCH 0574/1301] xhci: Add DescriptorKind derives --- xhcid/src/usb/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 00de50dfce..4c1e57a8f0 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -8,6 +8,7 @@ pub use self::endpoint::{ pub use self::interface::InterfaceDescriptor; pub use self::setup::Setup; +#[derive(Clone, Copy, Debug)] #[repr(u8)] pub enum DescriptorKind { None, From f3e678cb8ab5f958d40c774841cfb00263e7df36 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Nov 2022 06:55:00 -0700 Subject: [PATCH 0575/1301] xhci: Fix deadlock when a stall is recieved --- xhcid/src/xhci/irq_reactor.rs | 137 +++++++++++++++++----------------- 1 file changed, 68 insertions(+), 69 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 6a2250dbba..97f4585fd3 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -181,7 +181,7 @@ impl IrqReactor { return Ok(None); } else { count += 1 } - trace!("Found event TRB: {:?}", event_trb); + trace!("Found event TRB type {}: {:?}", event_trb.trb_type(), event_trb); if self.check_event_ring_full(event_trb.clone()) { info!("Had to resize event TRB, retrying..."); @@ -206,7 +206,7 @@ impl IrqReactor { let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); - debug!("Updated ERDP to {:#0x}", dequeue_pointer); + trace!("Updated ERDP to {:#0x}", dequeue_pointer); self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); } @@ -214,78 +214,78 @@ impl IrqReactor { self.states.extend(self.receiver.try_iter().inspect(|req| trace!("Received request: {:?}", req))); } fn acknowledge(&mut self, trb: Trb) { - let mut index = 0; + //TODO: handle TRBs without an attached state - loop { - if index >= self.states.len() { break } + trace!("ACK TRB {:X?}", trb); + + let mut index = 0; + while index < self.states.len() { + trace!("ACK STATE {}: {:X?}", index, self.states[index].kind); match self.states[index].kind { - StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => if trb.completion_trb_pointer() == Some(phys_ptr) { - trace!("Found matching command completion future"); - let state = self.states.remove(index); - - // Before waking, it's crucial that the command TRB that generated this event - // is fetched before removing this event TRB from the queue. - let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(self.hci.cap.ac64(), phys_ptr) { - Some(command_trb) => { - let t = command_trb.clone(); - command_trb.reserved(false); - t - }, - None => { - warn!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb); - continue; - } - }; - - // TODO: Validate the command TRB. - *state.message.lock().unwrap() = Some(NextEventTrb { - src_trb: Some(command_trb.clone()), - event_trb: trb.clone(), - }); - - trace!("Waking up future with waker: {:?}", state.waker); - state.waker.wake(); - - return; - } else if trb.completion_trb_pointer().is_none() { - warn!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); - continue; - } else { - // The event TRB simply didn't match the current future - continue; - } - - StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => if let Some(src_trb) = trb.transfer_event_trb_pointer().map(|ptr| self.hci.get_transfer_trb(ptr, ring_id)).flatten() { - if trb.transfer_event_trb_pointer() == Some(phys_ptr) { - // Give the source transfer TRB together with the event TRB, to the future. - + StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => { + if trb.completion_trb_pointer() == Some(phys_ptr) { + trace!("Found matching command completion future"); let state = self.states.remove(index); + + // Before waking, it's crucial that the command TRB that generated this event + // is fetched before removing this event TRB from the queue. + let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(self.hci.cap.ac64(), phys_ptr) { + Some(command_trb) => { + let t = command_trb.clone(); + command_trb.reserved(false); + t + }, + None => { + warn!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb); + continue; + } + }; + + // TODO: Validate the command TRB. *state.message.lock().unwrap() = Some(NextEventTrb { - src_trb: Some(src_trb), + src_trb: Some(command_trb.clone()), event_trb: trb.clone(), }); + + trace!("Waking up future with waker: {:?}", state.waker); state.waker.wake(); + return; - } else if trb.transfer_event_trb_pointer().is_none() { - // Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full. - // - // These errors are caused when either an isoch transfer that shall write data, doesn't - // have any data since the ring is empty, or if an isoch receive is impossible due to a - // full ring. The Virtual Function Event Ring Full is only for Virtual Machine - // Managers, and since this isn't implemented yet, they are irrelevant. - // - // The best solution here is to differentiate between isoch transfers (and - // virtual function event rings when virtualization gets implemented), with - // regular commands and transfers, and send the error TRB to all of them, or - // possibly an error code wrapped in a Result. - self.acknowledge_failed_transfer_trbs(trb); - return; - } else { - // The event TRB simply didn't match the current future - continue; + } else if trb.completion_trb_pointer().is_none() { + warn!("Command TRB somehow resulted in an error that only can be caused by transfer TRBs. Ignoring event TRB: {:?}.", trb); } - } else { continue } + } + + StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => { + if let Some(src_trb) = trb.transfer_event_trb_pointer().map(|ptr| self.hci.get_transfer_trb(ptr, ring_id)).flatten() { + if trb.transfer_event_trb_pointer() == Some(phys_ptr) { + // Give the source transfer TRB together with the event TRB, to the future. + + let state = self.states.remove(index); + *state.message.lock().unwrap() = Some(NextEventTrb { + src_trb: Some(src_trb), + event_trb: trb.clone(), + }); + state.waker.wake(); + return; + } else if trb.transfer_event_trb_pointer().is_none() { + // Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full. + // + // These errors are caused when either an isoch transfer that shall write data, doesn't + // have any data since the ring is empty, or if an isoch receive is impossible due to a + // full ring. The Virtual Function Event Ring Full is only for Virtual Machine + // Managers, and since this isn't implemented yet, they are irrelevant. + // + // The best solution here is to differentiate between isoch transfers (and + // virtual function event rings when virtualization gets implemented), with + // regular commands and transfers, and send the error TRB to all of them, or + // possibly an error code wrapped in a Result. + self.acknowledge_failed_transfer_trbs(trb); + return; + } + } + } StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => { let state = self.states.remove(index); @@ -293,13 +293,12 @@ impl IrqReactor { return; } - _ => { - index += 1; - continue; - } + _ => () } + + index += 1; } - warn!("Lost event TRB: {:?}", trb); + warn!("Lost event TRB type {}: {:?}", trb.trb_type(), trb); } fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { let mut index = 0; From 7a8177e15e8430867fae2b5a288eae84990e34f2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Nov 2022 06:56:12 -0700 Subject: [PATCH 0576/1301] xhci: Derive log file name from scheme name --- xhcid/src/main.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 6a8fc31ce9..e042774a51 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -38,7 +38,7 @@ async fn handle_packet(hci: Arc, packet: Packet) -> Packet { todo!() } -fn setup_logging() -> Option<&'static RedoxLogger> { +fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() @@ -49,25 +49,25 @@ fn setup_logging() -> Option<&'static RedoxLogger> { ); #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "host", "xhci.log") { + match OutputBuilder::in_redox_logging_scheme("usb", "host", &format!("{}.log", name)) { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) + b.with_filter(log::LevelFilter::Debug) .flush_on_newline(true) .build() ), - Err(error) => eprintln!("Failed to create xhci.log: {}", error), + Err(error) => eprintln!("Failed to create {}.log: {}", name, error), } #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "host", "xhci.ansi.log") { + match OutputBuilder::in_redox_logging_scheme("usb", "host", &format!("{}.ansi.log", name)) { Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) + b.with_filter(log::LevelFilter::Debug) .with_ansi_escape_codes() .flush_on_newline(true) .build() ), - Err(error) => eprintln!("Failed to create xhci.ansi.log: {}", error), + Err(error) => eprintln!("Failed to create {}.ansi.log: {}", name, error), } match logger.enable() { @@ -237,19 +237,19 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let _logger_ref = setup_logging(); - let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); - info!("XHCI PCI CONFIG: {:?}", pci_config); - - let bar = pci_config.func.bars[0]; - let bar_size = pci_config.func.bar_sizes[0]; - let irq = pci_config.func.legacy_interrupt_line; let mut name = pci_config.func.name(); name.push_str("_xhci"); + let _logger_ref = setup_logging(&name); + + info!("XHCI PCI CONFIG: {:?}", pci_config); + let bar = pci_config.func.bars[0]; + let bar_size = pci_config.func.bar_sizes[0]; + let irq = pci_config.func.legacy_interrupt_line; + let bar_ptr = match bar { pcid_interface::PciBar::Memory32(ptr) => match ptr { 0 => panic!("BAR 0 is mapped to address 0"), From 6187ea09bca07ad10abf13a95d90ff50420ae80f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 2 Dec 2022 08:24:28 -0700 Subject: [PATCH 0577/1301] xhci: port reset outside of async code, assume slot type is 0 if missing --- xhcid/src/xhci/mod.rs | 44 ++++++++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 7ba5b208c3..fb9f12821e 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -412,6 +412,28 @@ impl Xhci { self.op.get_mut().unwrap().set_cie(true); } + + // Reset ports + { + let mut ports = self.ports.lock().unwrap(); + for (i, port) in ports.iter_mut().enumerate() { + //TODO: only reset if USB 2.0? + debug!("XHCI Port {} reset", i); + + let instant = std::time::Instant::now(); + + port.portsc.writef(port::PortFlags::PORT_PR.bits(), true); + while port.portsc.readf(port::PortFlags::PORT_PR.bits()) { + //while ! port.flags().contains(port::PortFlags::PORT_PRC) { + if instant.elapsed().as_secs() >= 1 { + warn!("timeout"); + break; + } + std::thread::yield_now(); + } + } + } + Ok(()) } @@ -483,17 +505,6 @@ impl Xhci { let port_count = { self.ports.lock().unwrap().len() }; for i in 0..port_count { - //TODO: only reset if USB 2.0? - debug!("Port reset"); - { - let port = &mut self.ports.lock().unwrap()[i]; - port.portsc.writef(port::PortFlags::PORT_PR.bits(), true); - while port.portsc.readf(port::PortFlags::PORT_PR.bits()) { - //while ! port.flags().contains(port::PortFlags::PORT_PRC) { - std::thread::yield_now(); - } - } - let (data, state, speed, flags) = { let port = &self.ports.lock().unwrap()[i]; (port.read(), port.state(), port.speed(), port.flags()) @@ -504,10 +515,13 @@ impl Xhci { ); if flags.contains(port::PortFlags::PORT_CCS) { - let slot_ty = self - .supported_protocol(i as u8) - .expect("Failed to find supported protocol information for port") - .proto_slot_ty(); + let slot_ty = match self.supported_protocol(i as u8) { + Some(protocol) => protocol.proto_slot_ty(), + None => { + warn!("Failed to find supported protocol information for port"); + 0 + } + }; debug!("Slot type: {}", slot_ty); debug!("Enabling slot."); From 508a2ee4de0b1e8479a3809599e613237569b238 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 2 Dec 2022 08:24:54 -0700 Subject: [PATCH 0578/1301] xhci: default to debug logging --- xhcid/src/main.rs | 2 +- xhcid/src/xhci/irq_reactor.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index e042774a51..b9c96592bb 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -42,7 +42,7 @@ fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_filter(log::LevelFilter::Debug) // limit global output to important info .with_ansi_escape_codes() .flush_on_newline(true) .build() diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 97f4585fd3..152a05bc9d 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -162,7 +162,7 @@ impl IrqReactor { return Ok(None); } - trace!("IRQ reactor received an IRQ"); + debug!("IRQ reactor received an IRQ"); let _ = self.irq_file.as_mut().unwrap().write(&buffer); From 5874776304df7a6f31700bf3f5c60e80fae15ed8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 2 Dec 2022 08:25:13 -0700 Subject: [PATCH 0579/1301] xhci: temporarily ignore bos descriptors --- xhcid/src/xhci/scheme.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index ba3a74fd9a..1f39d6f82f 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1000,12 +1000,12 @@ impl Xhci { }, ); - let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot).await?; + //TODO let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot).await?; - let supports_superspeed = - usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); - let supports_superspeedplus = - usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus()); + let supports_superspeed = false; + //TODO usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); + let supports_superspeedplus = false; + //TODO usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus()); let mut config_descs = SmallVec::new(); From 970cfd286291dd50888e19435e18fa580e1e15cd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 2 Dec 2022 10:45:11 -0700 Subject: [PATCH 0580/1301] ide: yield instead of spin --- ided/src/ide.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/ided/src/ide.rs b/ided/src/ide.rs index 7cadcae91e..74a5e1c48d 100644 --- a/ided/src/ide.rs +++ b/ided/src/ide.rs @@ -1,6 +1,7 @@ use std::{ convert::TryInto, sync::{Arc, Mutex}, + thread, }; use syscall::{ error::{Error, Result, EIO}, @@ -9,18 +10,6 @@ use syscall::{ use crate::ata::AtaCommand; -#[cfg(target_arch = "aarch64")] -#[inline(always)] -pub(crate) unsafe fn pause() { std::arch::aarch64::__yield(); } - -#[cfg(target_arch = "x86")] -#[inline(always)] -pub(crate) unsafe fn pause() { std::arch::x86::_mm_pause(); } - -#[cfg(target_arch = "x86_64")] -#[inline(always)] -pub(crate) unsafe fn pause() { std::arch::x86_64::_mm_pause(); } - #[repr(packed)] struct PrdtEntry { phys: u32, @@ -129,7 +118,7 @@ impl Channel { loop { let status = self.check_status()?; if status & 0x80 != 0 { - unsafe { pause(); } + thread::yield_now(); } else { if read && status & 0x08 == 0 { log::error!("IDE data not ready"); From debb6789011fbf2380d308804e39b87d65a39487 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 6 Dec 2022 10:35:16 -0700 Subject: [PATCH 0581/1301] ahci: remove pause function --- ahcid/src/ahci/disk_ata.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index 3d64c0e401..b401a9457e 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -8,18 +8,6 @@ use syscall::error::Result; use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; use super::Disk; -#[cfg(target_arch = "aarch64")] -#[inline(always)] -pub(crate) unsafe fn pause() { std::arch::aarch64::__yield(); } - -#[cfg(target_arch = "x86")] -#[inline(always)] -pub(crate) unsafe fn pause() { std::arch::x86::_mm_pause(); } - -#[cfg(target_arch = "x86_64")] -#[inline(always)] -pub(crate) unsafe fn pause() { std::arch::x86_64::_mm_pause(); } - enum BufferKind<'a> { Read(&'a mut [u8]), Write(&'a [u8]), From 163a6b525e81c0057c5e43324072c7a91d9b06e6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 16 Dec 2022 08:27:20 -0700 Subject: [PATCH 0582/1301] vesad: support partial sync --- vesad/src/main.rs | 3 +- vesad/src/scheme.rs | 3 +- vesad/src/screen/graphic.rs | 65 ++++++++++++++++++++----------------- 3 files changed, 38 insertions(+), 33 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index e2bb636c60..3e5cee75c4 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -3,10 +3,9 @@ extern crate orbclient; extern crate syscall; -use std::{env, process, ptr}; +use std::env; use std::fs::File; use std::io::{Read, Write}; -use std::os::unix::io::{RawFd, FromRawFd}; use syscall::{Packet, SchemeMut, EVENT_READ}; use crate::{ diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 08a88e8c2a..a820919344 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,9 +1,8 @@ use std::collections::BTreeMap; -use std::convert::TryInto; use std::{mem, ptr, slice, str}; use orbclient::{Event, EventOption}; -use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, OldMap, O_NONBLOCK, physmap, physunmap, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, Result, SchemeMut}; +use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, physmap, physunmap, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, Result, SchemeMut}; use crate::{ display::Display, diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 3c4763e467..e0bf22ca35 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -1,25 +1,35 @@ use std::collections::VecDeque; -use std::{cmp, mem, ptr, slice}; +use std::convert::TryInto; +use std::{mem, slice}; use orbclient::{Event, ResizeEvent}; use syscall::error::*; -use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use crate::display::Display; use crate::screen::Screen; +// Keep synced with orbital +#[derive(Clone, Copy)] +#[repr(packed)] +struct SyncRect { + x: i32, + y: i32, + w: i32, + h: i32, +} + pub struct GraphicScreen { pub display: Display, - pub seek: usize, pub input: VecDeque, + sync_rects: Vec, } impl GraphicScreen { pub fn new(display: Display) -> GraphicScreen { GraphicScreen { display: display, - seek: 0, input: VecDeque::new(), + sync_rects: Vec::new(), } } } @@ -76,36 +86,33 @@ impl Screen for GraphicScreen { } fn write(&mut self, buf: &[u8]) -> Result { - let size = cmp::max(0, cmp::min(self.display.offscreen.len() as isize - self.seek as isize, (buf.len()/4) as isize)) as usize; - - if size > 0 { - unsafe { - ptr::copy( - buf.as_ptr(), - self.display.offscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, - size * 4 - ); - } - } - - Ok(size * 4) - } - - fn seek(&mut self, pos: isize, whence: usize) -> Result { - let size = self.display.offscreen.len(); - - self.seek = match whence { - SEEK_SET => cmp::min(size, (pos/4) as usize), - SEEK_CUR => cmp::max(0, cmp::min(size as isize, self.seek as isize + (pos/4))) as usize, - SEEK_END => cmp::max(0, cmp::min(size as isize, size as isize + (pos/4))) as usize, - _ => return Err(Error::new(EINVAL)) + let sync_rects = unsafe { + slice::from_raw_parts( + buf.as_ptr() as *const SyncRect, + buf.len() / mem::size_of::() + ) }; - Ok(self.seek * 4) + self.sync_rects.extend_from_slice(sync_rects); + + Ok(sync_rects.len() * mem::size_of::()) + } + + fn seek(&mut self, _pos: isize, _whence: usize) -> Result { + Ok(0) } fn sync(&mut self, onscreen: &mut [u32], stride: usize) { - self.redraw(onscreen, stride); + for sync_rect in self.sync_rects.drain(..) { + self.display.sync( + sync_rect.x.try_into().unwrap_or(0), + sync_rect.y.try_into().unwrap_or(0), + sync_rect.w.try_into().unwrap_or(0), + sync_rect.h.try_into().unwrap_or(0), + onscreen, + stride, + ); + } } fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { From 24022dc37a6c5a5eb0118a373ab7bc298f34b48c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 17 Dec 2022 15:40:40 -0700 Subject: [PATCH 0583/1301] Use Super for screen toggle, allowing apps to use function keys --- vesad/src/scheme.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index a820919344..acfdaa76d6 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -37,6 +37,7 @@ pub struct DisplayScheme { pub vts: BTreeMap>>, next_id: usize, pub handles: BTreeMap, + super_key: bool, } impl DisplayScheme { @@ -72,6 +73,7 @@ impl DisplayScheme { vts, next_id: 0, handles: BTreeMap::new(), + super_key: false, } } @@ -330,15 +332,18 @@ impl SchemeMut for DisplayScheme { let mut new_active_opt = None; match event.to_option() { EventOption::Key(key_event) => match key_event.scancode { - f @ 0x3B ..= 0x44 => { // F1 through F10 + f @ 0x3B ..= 0x44 if self.super_key => { // F1 through F10 new_active_opt = Some(VtIndex((f - 0x3A) as usize)); }, - 0x57 => { // F11 + 0x57 if self.super_key => { // F11 new_active_opt = Some(VtIndex(11)); }, - 0x58 => { // F12 + 0x58 if self.super_key => { // F12 new_active_opt = Some(VtIndex(12)); }, + 0x5B => { // Super + self.super_key = key_event.pressed; + }, _ => () }, EventOption::Resize(resize_event) => { From e0bf7a95f5d9415e488c5f7c64957205767a5732 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 18 Dec 2022 10:59:58 -0700 Subject: [PATCH 0584/1301] ihda: Remove LineOut from supported devices, it breaks some laptops --- ihdad/src/hda/device.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 9624d75097..ec4e03c025 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -393,7 +393,6 @@ impl IntelHDA { // Check for devices in this order: Headphone, Speaker, Line Out for supported_device in &[ DefaultDevice::HPOut, - DefaultDevice::LineOut, DefaultDevice::Speaker, ] { for &out in outs { From ee03583b589bf2a8cc76ba0188f3c35a478108fd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 11 Jan 2023 21:34:33 -0700 Subject: [PATCH 0585/1301] Prevent drives from being opened more than once --- ahcid/src/scheme.rs | 34 +++++++++++++++++++++++++++++----- ided/src/scheme.rs | 34 +++++++++++++++++++++++++++++----- nvmed/src/scheme.rs | 31 +++++++++++++++++++++++++++++-- 3 files changed, 87 insertions(+), 12 deletions(-) diff --git a/ahcid/src/scheme.rs b/ahcid/src/scheme.rs index da51c0c301..77b36972a3 100644 --- a/ahcid/src/scheme.rs +++ b/ahcid/src/scheme.rs @@ -7,7 +7,7 @@ use std::io::SeekFrom; use std::io; use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, EOVERFLOW, Result, + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; @@ -124,9 +124,7 @@ impl DiskScheme { next_id: 0 } } -} -impl DiskScheme { pub fn irq(&mut self) -> bool { let is = self.hba_mem.is.read(); if is > 0 { @@ -145,6 +143,29 @@ impl DiskScheme { false } } + + // Checks if any conflicting handles already exist + fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { + for (_, handle) in self.handles.iter() { + match handle { + Handle::Disk(i, _) => if disk_i == *i { + return Err(Error::new(ENOLCK)); + }, + Handle::Partition(i, p, _) => if disk_i == *i { + match part_i_opt { + Some(part_i) => if part_i == *p { + return Err(Error::new(ENOLCK)); + }, + None => { + return Err(Error::new(ENOLCK)); + } + } + }, + _ => (), + } + } + Ok(()) + } } impl SchemeBlockMut for DiskScheme { @@ -186,11 +207,12 @@ impl SchemeBlockMut for DiskScheme { if disk.pt.is_none() || disk.pt.as_ref().unwrap().partitions.get(p as usize).is_none() { return Err(Error::new(ENOENT)); } + + self.check_locks(i, Some(p))?; + let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::Partition(i, p, 0)); - Ok(Some(id)) } else { Err(Error::new(ENOENT)) @@ -199,6 +221,8 @@ impl SchemeBlockMut for DiskScheme { let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; if self.disks.get(i).is_some() { + self.check_locks(i, None)?; + let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle::Disk(i, 0)); diff --git a/ided/src/scheme.rs b/ided/src/scheme.rs index e88fb46e0c..a5fe20b309 100644 --- a/ided/src/scheme.rs +++ b/ided/src/scheme.rs @@ -8,7 +8,7 @@ use std::io; use std::sync::{Arc, Mutex}; use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, EOVERFLOW, Result, + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; @@ -124,14 +124,35 @@ impl DiskScheme { next_id: 0 } } -} -impl DiskScheme { pub fn irq(&mut self, chan_i: usize) -> bool { let mut chan = self.chans[chan_i].lock().unwrap(); //TODO: check chan for irq true } + + // Checks if any conflicting handles already exist + fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { + for (_, handle) in self.handles.iter() { + match handle { + Handle::Disk(i, _) => if disk_i == *i { + return Err(Error::new(ENOLCK)); + }, + Handle::Partition(i, p, _) => if disk_i == *i { + match part_i_opt { + Some(part_i) => if part_i == *p { + return Err(Error::new(ENOLCK)); + }, + None => { + return Err(Error::new(ENOLCK)); + } + } + }, + _ => (), + } + } + Ok(()) + } } impl SchemeBlockMut for DiskScheme { @@ -173,11 +194,12 @@ impl SchemeBlockMut for DiskScheme { if disk.pt.is_none() || disk.pt.as_ref().unwrap().partitions.get(p as usize).is_none() { return Err(Error::new(ENOENT)); } + + self.check_locks(i, Some(p))?; + let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::Partition(i, p, 0)); - Ok(Some(id)) } else { Err(Error::new(ENOENT)) @@ -186,6 +208,8 @@ impl SchemeBlockMut for DiskScheme { let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; if self.disks.get(i).is_some() { + self.check_locks(i, None)?; + let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle::Disk(i, 0)); diff --git a/nvmed/src/scheme.rs b/nvmed/src/scheme.rs index 55a491ab7f..654044aba0 100644 --- a/nvmed/src/scheme.rs +++ b/nvmed/src/scheme.rs @@ -7,8 +7,8 @@ use std::sync::Arc; use std::{cmp, str}; use syscall::{ - Error, Io, Result, SchemeBlockMut, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, EOVERFLOW, - MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET, + Error, Io, Result, SchemeBlockMut, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, + EOVERFLOW, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET, }; use crate::nvme::{Nvme, NvmeNamespace}; @@ -157,6 +157,29 @@ impl DiskScheme { next_id: 0, } } + + // Checks if any conflicting handles already exist + fn check_locks(&self, disk_i: u32, part_i_opt: Option) -> Result<()> { + for (_, handle) in self.handles.iter() { + match handle { + Handle::Disk(i, _) => if disk_i == *i { + return Err(Error::new(ENOLCK)); + }, + Handle::Partition(i, p, _) => if disk_i == *i { + match part_i_opt { + Some(part_i) => if part_i == *p { + return Err(Error::new(ENOLCK)); + }, + None => { + return Err(Error::new(ENOLCK)); + } + } + }, + _ => (), + } + } + Ok(()) + } } impl SchemeBlockMut for DiskScheme { @@ -206,6 +229,8 @@ impl SchemeBlockMut for DiskScheme { .get(part_num as usize) .is_some() { + self.check_locks(nsid, Some(part_num))?; + let id = self.next_id; self.next_id += 1; self.handles @@ -221,6 +246,8 @@ impl SchemeBlockMut for DiskScheme { let nsid = path_str.parse::().or(Err(Error::new(ENOENT)))?; if self.disks.contains_key(&nsid) { + self.check_locks(nsid, None)?; + let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle::Disk(nsid, 0)); From d74a406dcd02b39f1256de6d038f82ba8328967f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 20 Jan 2023 13:30:41 -0700 Subject: [PATCH 0586/1301] rtl8168d: Allow use of BAR1 for 32-bit systems --- rtl8168d/src/main.rs | 53 ++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index aa95508967..dbfe97aa8b 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -3,7 +3,7 @@ extern crate netutils; extern crate syscall; use std::cell::RefCell; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::{env, process}; use std::fs::File; use std::io::{ErrorKind, Read, Result, Write}; @@ -12,7 +12,7 @@ use std::ptr::NonNull; use std::sync::Arc; use event::EventQueue; -use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; +use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector}; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use redox_log::{RedoxLogger, OutputBuilder}; @@ -305,6 +305,30 @@ fn handle_update( Ok(false) } +fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { + // RTL8168 uses BAR2, RTL8169 uses BAR1, search in that order + for &barnum in &[2, 1] { + match pci_config.func.bars[barnum] { + pcid_interface::PciBar::Memory32(ptr) => match ptr { + 0 => log::warn!("BAR {} is mapped to address 0", barnum), + _ => return Some(( + ptr.try_into().unwrap(), + pci_config.func.bar_sizes[barnum].try_into().unwrap() + )), + }, + pcid_interface::PciBar::Memory64(ptr) => match ptr { + 0 => log::warn!("BAR {} is mapped to address 0", barnum), + _ => return Some(( + ptr.try_into().unwrap(), + pci_config.func.bar_sizes[barnum].try_into().unwrap() + )), + }, + other => log::warn!("BAR {} is {} instead of memory BAR", barnum, other), + } + } + None +} + fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(); @@ -315,30 +339,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_rtl8168"); - let bar = pci_config.func.bars[2]; - let bar_size = pci_config.func.bar_sizes[2]; - let bar_ptr = match bar { - pcid_interface::PciBar::Memory32(ptr) => match ptr { - 0 => panic!("BAR 0 is mapped to address 0"), - _ => ptr as u64, - }, - pcid_interface::PciBar::Memory64(ptr) => match ptr { - 0 => panic!("BAR 0 is mapped to address 0"), - _ => ptr, - }, - other => panic!("Expected memory bar, found {}", other), - }; - - eprintln!(" + RTL8168 {} on: {:#X} size: {}", name, bar_ptr, bar_size); + let (bar_ptr, bar_size) = find_bar(&pci_config).expect("rtl8168d: failed to find BAR"); + log::info!(" + RTL8168 {} on: {:#X} size: {}", name, bar_ptr, bar_size); let address = unsafe { - syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + syscall::physmap(bar_ptr, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("rtl8168d: failed to map address") }; - //TODO: MSI-X - let mut irq_file = get_int_method(&mut pcid_handle).expect("rtl8168d: no interrupt file"); - let socket_fd = syscall::open( ":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, @@ -348,6 +356,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { File::from_raw_fd(socket_fd as RawFd) })); + //TODO: MSI-X + let mut irq_file = get_int_method(&mut pcid_handle).expect("rtl8168d: no interrupt file"); + { let device = Arc::new(RefCell::new(unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") From eb7b811c368c51104ad50e6ebaa725ebc23be57a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 21 Jan 2023 14:24:40 -0700 Subject: [PATCH 0587/1301] Add initial sb16 driver --- Cargo.lock | 18 ++++ Cargo.toml | 1 + sb16d/Cargo.toml | 13 +++ sb16d/src/device.rs | 129 +++++++++++++++++++++++++++ sb16d/src/main.rs | 207 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 368 insertions(+) create mode 100644 sb16d/Cargo.toml create mode 100644 sb16d/src/device.rs create mode 100644 sb16d/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index e91290c178..f3bbc00687 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1211,6 +1211,19 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +[[package]] +name = "sb16d" +version = "0.1.0" +dependencies = [ + "bitflags", + "log", + "redox-daemon", + "redox-log", + "redox_event", + "redox_syscall 0.3.4", + "spin", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -1753,3 +1766,8 @@ dependencies = [ "thiserror", "toml", ] + +[[patch.unused]] +name = "libc" +version = "0.2.137" +source = "git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=rust-2022-03-18#6ba4d1a527c2b53bdd5554cb219a1cd7d315d518" diff --git a/Cargo.toml b/Cargo.toml index 8533a87637..e0d659d3ca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "pcspkrd", "ps2d", "rtl8168d", + "sb16d", "vboxd", "vesad", "xhcid", diff --git a/sb16d/Cargo.toml b/sb16d/Cargo.toml new file mode 100644 index 0000000000..bee3594214 --- /dev/null +++ b/sb16d/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "sb16d" +version = "0.1.0" +edition = "2018" + +[dependencies] +bitflags = "1" +log = "0.4" +redox-daemon = "0.1" +redox-log = "0.1" +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox_syscall = "0.3" +spin = "0.9" diff --git a/sb16d/src/device.rs b/sb16d/src/device.rs new file mode 100644 index 0000000000..cb77b075a9 --- /dev/null +++ b/sb16d/src/device.rs @@ -0,0 +1,129 @@ +#![allow(dead_code)] + +use std::{mem, thread, time}; +use std::collections::BTreeMap; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use syscall::error::{Error, EACCES, EBADF, Result, EINVAL, ENODEV, ENOENT}; +use syscall::io::{Dma, PhysBox, Mmio, Pio, Io, ReadOnly, WriteOnly}; +use syscall::scheme::SchemeBlockMut; + +use spin::Mutex; + +const NUM_SUB_BUFFS: usize = 32; +const SUB_BUFF_SIZE: usize = 2048; + +enum Handle { + Todo, +} + +#[allow(dead_code)] +struct DspRegs { + /* 0x06 */ reset: WriteOnly>, + /* 0x0A */ read_data: ReadOnly>, + /* 0x0C */ write_data: WriteOnly>, + /* 0x0C */ write_status: ReadOnly>, + /* 0x0E */ read_status: ReadOnly>, +} + +impl DspRegs { + fn new(addr: u16) -> Self { + Self { + reset: WriteOnly::new(Pio::new(addr + 0x06)), + read_data: ReadOnly::new(Pio::new(addr + 0x0A)), + write_data: WriteOnly::new(Pio::new(addr + 0x0C)), + write_status: ReadOnly::new(Pio::new(addr + 0x0C)), + read_status: ReadOnly::new(Pio::new(addr + 0x0E)), + } + } +} + +pub struct Sb16 { + dsp: DspRegs, + handles: Mutex>, + next_id: AtomicUsize, +} + +impl Sb16 { + pub unsafe fn new(addr: u16) -> Result { + let mut module = Sb16 { + dsp: DspRegs::new(addr), + handles: Mutex::new(BTreeMap::new()), + next_id: AtomicUsize::new(0), + }; + + module.init()?; + + Ok(module) + } + + fn init(&mut self) -> Result<()> { + // Perform DSP reset + { + // Write 1 to reset port + self.dsp.reset.write(1); + + // Wait 3us + thread::sleep(time::Duration::from_micros(3)); + + // Write 0 to reset port + self.dsp.reset.write(0); + + //TODO: Wait for ready byte (0xAA) using read status + thread::sleep(time::Duration::from_micros(100)); + + let ready = self.dsp.read_data.read(); + if ready != 0xAA { + log::error!("ready byte was 0x{:02X} instead of 0xAA", ready); + return Err(Error::new(ENODEV)); + } + } + + // Read DSP version + { + //TODO + } + + Ok(()) + } + + pub fn irq(&mut self) -> bool { + //TODO + false + } +} + +impl SchemeBlockMut for Sb16 { + fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { + if uid == 0 { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, Handle::Todo); + Ok(Some(id)) + } else { + Err(Error::new(EACCES)) + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + //TODO + Err(Error::new(EBADF)) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let mut handles = self.handles.lock(); + let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let mut i = 0; + let scheme_path = b"audiohw:"; + while i < buf.len() && i < scheme_path.len() { + buf[i] = scheme_path[i]; + i += 1; + } + Ok(Some(i)) + } + + fn close(&mut self, id: usize) -> Result> { + let mut handles = self.handles.lock(); + handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + } +} diff --git a/sb16d/src/main.rs b/sb16d/src/main.rs new file mode 100644 index 0000000000..027eac1a11 --- /dev/null +++ b/sb16d/src/main.rs @@ -0,0 +1,207 @@ +//#![deny(warnings)] + +extern crate bitflags; +extern crate spin; +extern crate syscall; +extern crate event; + +use std::{env, usize}; +use std::fs::File; +use std::io::{ErrorKind, Read, Write, Result}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use syscall::{Packet, SchemeBlockMut, EventFlags}; +use std::cell::RefCell; +use std::sync::Arc; + +use event::EventQueue; +use redox_log::{OutputBuilder, RedoxLogger}; + +pub mod device; + +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "sb16.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("sb16d: failed to create sb16.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "sb16.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("sb16d: failed to create sb16.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("sb16d: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("sb16d: failed to set default logger: {}", error); + None + } + } +} + +fn main() { + let mut args = env::args().skip(1); + + //TODO: add addr to name? + let name = "sb16".to_string(); + + let addr_str = args.next().unwrap_or("220".to_string()); + let addr = u16::from_str_radix(&addr_str, 16).expect("sb16: failed to parse address"); + + let irq_str = args.next().unwrap_or("5".to_string()); + let irq = irq_str.parse::().expect("sb16: failed to parse irq"); + + let dma_str = args.next().unwrap_or("1".to_string()); + let dma = dma_str.parse::().expect("sb16: failed to parse dma"); + + print!("{}", format!(" + sb16 at: ADDR 0x{:X}, IRQ {}, DMA {}\n", addr, irq, dma)); + + // Daemonize + redox_daemon::Daemon::new(move |daemon| { + let _logger_ref = setup_logging(); + + unsafe { syscall::iopl(3) }.expect("sb16d: failed to set I/O privilege level to Ring 3"); + + let mut irq_file = File::open(format!("irq:{}", irq)).expect("sb16d: failed to open IRQ file"); + + let device = Arc::new(RefCell::new(unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") })); + let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("sb16d: failed to create hda scheme"); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + + daemon.ready().expect("sb16d: failed to signal readiness"); + + let mut event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); + + syscall::setrens(0, 0).expect("sb16d: failed to enter null namespace"); + + let todo = Arc::new(RefCell::new(Vec::::new())); + + let todo_irq = todo.clone(); + let device_irq = device.clone(); + let socket_irq = socket.clone(); + + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + + if device_irq.borrow_mut().irq() { + irq_file.write(&mut irq)?; + + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + if let Some(a) = device_irq.borrow_mut().handle(&mut todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket_irq.borrow_mut().write(&packet)?; + } else { + i += 1; + } + } + + /* + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + } + Ok(None) + }).expect("sb16d: failed to catch events on IRQ file"); + let socket_fd = socket.borrow().as_raw_fd(); + let socket_packet = socket.clone(); + event_queue.add(socket_fd, move |_event| -> Result> { + loop { + let mut packet = Packet::default(); + match socket_packet.borrow_mut().read(&mut packet) { + Ok(0) => return Ok(Some(0)), + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } + } + + if let Some(a) = device.borrow_mut().handle(&mut packet) { + packet.a = a; + socket_packet.borrow_mut().write(&packet)?; + } else { + todo.borrow_mut().push(packet); + } + } + + /* + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + + Ok(None) + }).expect("sb16d: failed to catch events on IRQ file"); + + for event_count in event_queue.trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }).expect("sb16d: failed to trigger events") { + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ.bits(), + d: event_count + }).expect("sb16d: failed to write event"); + } + + loop { + { + //device_loop.borrow_mut().handle_interrupts(); + } + let event_count = event_queue.run().expect("sb16d: failed to handle events"); + if event_count == 0 { + //TODO: Handle todo + break; + } + + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ.bits(), + d: event_count + }).expect("sb16d: failed to write event"); + } + + std::process::exit(0); + }).expect("sb16d: failed to daemonize"); +} From c9722c4024b1b95772a05bb11733c5e89dca9bf0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 21 Jan 2023 16:14:04 -0700 Subject: [PATCH 0588/1301] More work on sb16 driver --- sb16d/src/device.rs | 241 ++++++++++++++++++++++++++++++-------------- sb16d/src/main.rs | 223 ++++++++++++++++++++-------------------- 2 files changed, 273 insertions(+), 191 deletions(-) diff --git a/sb16d/src/device.rs b/sb16d/src/device.rs index cb77b075a9..f016cde002 100644 --- a/sb16d/src/device.rs +++ b/sb16d/src/device.rs @@ -14,100 +14,187 @@ const NUM_SUB_BUFFS: usize = 32; const SUB_BUFF_SIZE: usize = 2048; enum Handle { - Todo, + Todo, } #[allow(dead_code)] -struct DspRegs { - /* 0x06 */ reset: WriteOnly>, - /* 0x0A */ read_data: ReadOnly>, - /* 0x0C */ write_data: WriteOnly>, - /* 0x0C */ write_status: ReadOnly>, - /* 0x0E */ read_status: ReadOnly>, -} - -impl DspRegs { - fn new(addr: u16) -> Self { - Self { - reset: WriteOnly::new(Pio::new(addr + 0x06)), - read_data: ReadOnly::new(Pio::new(addr + 0x0A)), - write_data: WriteOnly::new(Pio::new(addr + 0x0C)), - write_status: ReadOnly::new(Pio::new(addr + 0x0C)), - read_status: ReadOnly::new(Pio::new(addr + 0x0E)), - } - } -} - pub struct Sb16 { - dsp: DspRegs, - handles: Mutex>, - next_id: AtomicUsize, + handles: Mutex>, + next_id: AtomicUsize, + pub(crate) irqs: Vec, + dmas: Vec, + // Regs + /* 0x04 */ mixer_addr: WriteOnly>, + /* 0x05 */ mixer_data: Pio, + /* 0x06 */ dsp_reset: WriteOnly>, + /* 0x0A */ dsp_read_data: ReadOnly>, + /* 0x0C */ dsp_write_data: WriteOnly>, + /* 0x0C */ dsp_write_status: ReadOnly>, + /* 0x0E */ dsp_read_status: ReadOnly>, } impl Sb16 { - pub unsafe fn new(addr: u16) -> Result { - let mut module = Sb16 { - dsp: DspRegs::new(addr), - handles: Mutex::new(BTreeMap::new()), - next_id: AtomicUsize::new(0), - }; + pub unsafe fn new(addr: u16) -> Result { + let mut module = Sb16 { + handles: Mutex::new(BTreeMap::new()), + next_id: AtomicUsize::new(0), + irqs: Vec::new(), + dmas: Vec::new(), + // Regs + mixer_addr: WriteOnly::new(Pio::new(addr + 0x04)), + mixer_data: Pio::new(addr + 0x05), + dsp_reset: WriteOnly::new(Pio::new(addr + 0x06)), + dsp_read_data: ReadOnly::new(Pio::new(addr + 0x0A)), + dsp_write_data: WriteOnly::new(Pio::new(addr + 0x0C)), + dsp_write_status: ReadOnly::new(Pio::new(addr + 0x0C)), + dsp_read_status: ReadOnly::new(Pio::new(addr + 0x0E)), + }; - module.init()?; + module.init()?; - Ok(module) - } + Ok(module) + } - fn init(&mut self) -> Result<()> { - // Perform DSP reset - { - // Write 1 to reset port - self.dsp.reset.write(1); + fn mixer_read(&mut self, index: u8) -> u8 { + self.mixer_addr.write(index); + self.mixer_data.read() + } - // Wait 3us - thread::sleep(time::Duration::from_micros(3)); + fn mixer_write(&mut self, index: u8, value: u8) { + self.mixer_addr.write(index); + self.mixer_data.write(value); + } - // Write 0 to reset port - self.dsp.reset.write(0); + fn dsp_read(&mut self) -> Result { + // Bit 7 must be 1 before data can be sent + while ! self.dsp_read_status.readf(1 << 7) { + //TODO: timeout! + std::thread::yield_now(); + } - //TODO: Wait for ready byte (0xAA) using read status - thread::sleep(time::Duration::from_micros(100)); + Ok(self.dsp_read_data.read()) + } - let ready = self.dsp.read_data.read(); - if ready != 0xAA { - log::error!("ready byte was 0x{:02X} instead of 0xAA", ready); - return Err(Error::new(ENODEV)); - } - } + fn dsp_write(&mut self, value: u8) -> Result<()> { + // Bit 7 must be 0 before data can be sent + while self.dsp_write_status.readf(1 << 7) { + //TODO: timeout! + std::thread::yield_now(); + } - // Read DSP version - { - //TODO - } + self.dsp_write_data.write(value); + Ok(()) + } - Ok(()) - } + fn init(&mut self) -> Result<()> { + // Perform DSP reset + { + // Write 1 to reset port + self.dsp_reset.write(1); - pub fn irq(&mut self) -> bool { - //TODO - false - } + // Wait 3us + thread::sleep(time::Duration::from_micros(3)); + + // Write 0 to reset port + self.dsp_reset.write(0); + + //TODO: Wait for ready byte (0xAA) using read status + thread::sleep(time::Duration::from_micros(100)); + + let ready = self.dsp_read()?; + if ready != 0xAA { + log::error!("ready byte was 0x{:02X} instead of 0xAA", ready); + return Err(Error::new(ENODEV)); + } + } + + // Read DSP version + { + self.dsp_write(0xE1)?; + + let major = self.dsp_read()?; + let minor = self.dsp_read()?; + log::info!("DSP version {}.{:02}", major, minor); + + if major != 4 { + log::error!("Unsupported DSP major version {}", major); + return Err(Error::new(ENODEV)); + } + } + + // Get available IRQs and DMAs + { + self.irqs.clear(); + let irq_mask = self.mixer_read(0x80); + if (irq_mask & (1 << 0)) != 0 { + self.irqs.push(2); + } + if (irq_mask & (1 << 1)) != 0 { + self.irqs.push(5); + } + if (irq_mask & (1 << 2)) != 0 { + self.irqs.push(7); + } + if (irq_mask & (1 << 3)) != 0 { + self.irqs.push(10); + } + + self.dmas.clear(); + let dma_mask = self.mixer_read(0x81); + if (dma_mask & (1 << 0)) != 0 { + self.dmas.push(0); + } + if (dma_mask & (1 << 1)) != 0 { + self.dmas.push(1); + } + if (dma_mask & (1 << 3)) != 0 { + self.dmas.push(3); + } + if (dma_mask & (1 << 5)) != 0 { + self.dmas.push(5); + } + if (dma_mask & (1 << 6)) != 0 { + self.dmas.push(6); + } + if (dma_mask & (1 << 7)) != 0 { + self.dmas.push(7); + } + + log::info!("IRQs {:02X?} DMAs {:02X?}", self.irqs, self.dmas); + } + + // Set output sample rate to 44100 Hz (Redox OS standard) + { + let rate = 44100u16; + self.dsp_write(0x41)?; + self.dsp_write((rate >> 8) as u8)?; + self.dsp_write(rate as u8)?; + } + + Ok(()) + } + + pub fn irq(&mut self) -> bool { + //TODO + false + } } impl SchemeBlockMut for Sb16 { - fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, Handle::Todo); - Ok(Some(id)) - } else { - Err(Error::new(EACCES)) - } - } + fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { + if uid == 0 { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, Handle::Todo); + Ok(Some(id)) + } else { + Err(Error::new(EACCES)) + } + } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - //TODO - Err(Error::new(EBADF)) - } + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + //TODO + Err(Error::new(EBADF)) + } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let mut handles = self.handles.lock(); @@ -122,8 +209,8 @@ impl SchemeBlockMut for Sb16 { Ok(Some(i)) } - fn close(&mut self, id: usize) -> Result> { - let mut handles = self.handles.lock(); - handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) - } + fn close(&mut self, id: usize) -> Result> { + let mut handles = self.handles.lock(); + handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + } } diff --git a/sb16d/src/main.rs b/sb16d/src/main.rs index 027eac1a11..5415e2fcb6 100644 --- a/sb16d/src/main.rs +++ b/sb16d/src/main.rs @@ -63,145 +63,140 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } fn main() { - let mut args = env::args().skip(1); + let mut args = env::args().skip(1); - //TODO: add addr to name? - let name = "sb16".to_string(); + let addr_str = args.next().unwrap_or("220".to_string()); + let addr = u16::from_str_radix(&addr_str, 16).expect("sb16: failed to parse address"); - let addr_str = args.next().unwrap_or("220".to_string()); - let addr = u16::from_str_radix(&addr_str, 16).expect("sb16: failed to parse address"); + print!("{}", format!(" + sb16 at 0x{:X}\n", addr)); - let irq_str = args.next().unwrap_or("5".to_string()); - let irq = irq_str.parse::().expect("sb16: failed to parse irq"); - - let dma_str = args.next().unwrap_or("1".to_string()); - let dma = dma_str.parse::().expect("sb16: failed to parse dma"); - - print!("{}", format!(" + sb16 at: ADDR 0x{:X}, IRQ {}, DMA {}\n", addr, irq, dma)); - - // Daemonize + // Daemonize redox_daemon::Daemon::new(move |daemon| { - let _logger_ref = setup_logging(); + let _logger_ref = setup_logging(); unsafe { syscall::iopl(3) }.expect("sb16d: failed to set I/O privilege level to Ring 3"); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("sb16d: failed to open IRQ file"); + let device = Arc::new(RefCell::new(unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") })); + let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("sb16d: failed to create hda scheme"); + let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); - let device = Arc::new(RefCell::new(unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") })); - let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("sb16d: failed to create hda scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + //TODO: error on multiple IRQs? + let mut irq_file = match device.borrow().irqs.first() { + Some(irq) => File::open(format!("irq:{}", irq)).expect("sb16d: failed to open IRQ file"), + None => panic!("sb16d: no IRQs found"), + }; daemon.ready().expect("sb16d: failed to signal readiness"); - let mut event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); + let mut event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); syscall::setrens(0, 0).expect("sb16d: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + let todo = Arc::new(RefCell::new(Vec::::new())); - let todo_irq = todo.clone(); - let device_irq = device.clone(); - let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + let device_irq = device.clone(); + let socket_irq = socket.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; - if device_irq.borrow_mut().irq() { - irq_file.write(&mut irq)?; + if device_irq.borrow_mut().irq() { + irq_file.write(&mut irq)?; - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - if let Some(a) = device_irq.borrow_mut().handle(&mut todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket_irq.borrow_mut().write(&packet)?; - } else { - i += 1; - } - } + let mut todo = todo_irq.borrow_mut(); + let mut i = 0; + while i < todo.len() { + if let Some(a) = device_irq.borrow_mut().handle(&mut todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket_irq.borrow_mut().write(&packet)?; + } else { + i += 1; + } + } - /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - } - Ok(None) - }).expect("sb16d: failed to catch events on IRQ file"); - let socket_fd = socket.borrow().as_raw_fd(); - let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_event| -> Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => return Ok(Some(0)), - Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } + /* + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + } + Ok(None) + }).expect("sb16d: failed to catch events on IRQ file"); + let socket_fd = socket.borrow().as_raw_fd(); + let socket_packet = socket.clone(); + event_queue.add(socket_fd, move |_event| -> Result> { + loop { + let mut packet = Packet::default(); + match socket_packet.borrow_mut().read(&mut packet) { + Ok(0) => return Ok(Some(0)), + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } + } - if let Some(a) = device.borrow_mut().handle(&mut packet) { - packet.a = a; - socket_packet.borrow_mut().write(&packet)?; - } else { - todo.borrow_mut().push(packet); - } - } + if let Some(a) = device.borrow_mut().handle(&mut packet) { + packet.a = a; + socket_packet.borrow_mut().write(&packet)?; + } else { + todo.borrow_mut().push(packet); + } + } - /* - let next_read = device.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ + /* + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ - Ok(None) - }).expect("sb16d: failed to catch events on IRQ file"); + Ok(None) + }).expect("sb16d: failed to catch events on IRQ file"); - for event_count in event_queue.trigger_all(event::Event { - fd: 0, - flags: EventFlags::empty(), - }).expect("sb16d: failed to trigger events") { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("sb16d: failed to write event"); - } + for event_count in event_queue.trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }).expect("sb16d: failed to trigger events") { + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ.bits(), + d: event_count + }).expect("sb16d: failed to write event"); + } - loop { - { - //device_loop.borrow_mut().handle_interrupts(); - } - let event_count = event_queue.run().expect("sb16d: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } + loop { + { + //device_loop.borrow_mut().handle_interrupts(); + } + let event_count = event_queue.run().expect("sb16d: failed to handle events"); + if event_count == 0 { + //TODO: Handle todo + break; + } - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("sb16d: failed to write event"); - } + socket.borrow_mut().write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: 0, + c: syscall::flag::EVENT_READ.bits(), + d: event_count + }).expect("sb16d: failed to write event"); + } std::process::exit(0); - }).expect("sb16d: failed to daemonize"); + }).expect("sb16d: failed to daemonize"); } From f4564d6caf43bf51eb1908d565bb56530d30b852 Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Sun, 22 Jan 2023 19:42:41 -0800 Subject: [PATCH 0589/1301] switch to aml crate, implement acpi:/symbols --- acpid/Cargo.toml | 2 + acpid/src/acpi.rs | 349 +++++- acpid/src/aml/dataobj.rs | 184 --- acpid/src/aml/mod.rs | 144 --- acpid/src/aml/namedobj.rs | 1043 ---------------- acpid/src/aml/namespace.rs | 490 -------- acpid/src/aml/namespacemodifier.rs | 106 -- acpid/src/aml/namestring.rs | 223 ---- acpid/src/aml/parser.rs | 557 --------- acpid/src/aml/parsermacros.rs | 52 - acpid/src/aml/pkglength.rs | 25 - acpid/src/aml/termlist.rs | 172 --- acpid/src/aml/type1opcode.rs | 477 -------- acpid/src/aml/type2opcode.rs | 1784 ---------------------------- acpid/src/main.rs | 19 +- acpid/src/scheme.rs | 68 +- 16 files changed, 401 insertions(+), 5294 deletions(-) delete mode 100644 acpid/src/aml/dataobj.rs delete mode 100644 acpid/src/aml/mod.rs delete mode 100644 acpid/src/aml/namedobj.rs delete mode 100644 acpid/src/aml/namespace.rs delete mode 100644 acpid/src/aml/namespacemodifier.rs delete mode 100644 acpid/src/aml/namestring.rs delete mode 100644 acpid/src/aml/parser.rs delete mode 100644 acpid/src/aml/parsermacros.rs delete mode 100644 acpid/src/aml/pkglength.rs delete mode 100644 acpid/src/aml/termlist.rs delete mode 100644 acpid/src/aml/type1opcode.rs delete mode 100644 acpid/src/aml/type2opcode.rs diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index ccabe47a7b..451f0daeec 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -16,3 +16,5 @@ redox-daemon = "0.1" redox-log = "0.1.1" redox_syscall = "0.3" thiserror = "1" +aml = "0.16.2" +rustc-hash = "1.1.0" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 1fc4260578..b8879f1262 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,4 +1,4 @@ -use std::collections::BTreeMap; +use rustc_hash::FxHashSet; use std::convert::{TryFrom, TryInto}; use std::ops::Deref; use std::sync::Arc; @@ -6,10 +6,13 @@ use std::{fmt, mem}; use syscall::flag::PhysmapFlags; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use syscall::io::{Io, Pio}; + use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use thiserror::Error; -use super::aml::AmlValue; +use aml::{AmlContext, AmlName}; pub mod dmar; use self::dmar::Dmar; @@ -219,14 +222,29 @@ impl fmt::Debug for Sdt { pub struct Dsdt(Sdt); pub struct Ssdt(Sdt); + +#[derive(Debug, Error)] +pub enum SymbolListError { + #[error("Aml Internal Error")] + AmlInternalError, +} + +pub struct AmlSymbols { + pub symbols_str: String, + symbols_hash: FxHashSet, +} + pub struct AcpiContext { tables: Vec, dsdt: Option, fadt: Option, - // TODO: Remove Option. This is not kernel code, and not static, but we still need to replace - // every match where namespace{,_mut}() are used. - namespace: RwLock>>, + // the aml parser + aml_context: RwLock, + + // Use to cache the symbols list, which doesn't change very often + // Set it to None if the ACPI tables change e.g. due to PnP + aml_symbols: RwLock>, // TODO: The kernel ACPI code seemed to use load_table quite ubiquitously, however ACPI 5.1 // states that DDBHandles can only be obtained when loading XSDT-pointed tables. So, we'll @@ -236,6 +254,7 @@ pub struct AcpiContext { pub next_ctx: RwLock, } + impl AcpiContext { pub fn init(rxsdt_physaddrs: impl Iterator) -> Self { let tables = rxsdt_physaddrs.map(|physaddr| { @@ -243,7 +262,7 @@ impl AcpiContext { .try_into() .expect("expected ACPI addresses to be compatible with the current word size"); - log::debug!("TABLE AT {:#>08X}", physaddr); + log::trace!("TABLE AT {:#>08X}", physaddr); Sdt::load_from_physical(physaddr) .expect("failed to load physical SDT") @@ -253,7 +272,10 @@ impl AcpiContext { tables, dsdt: None, fadt: None, - namespace: RwLock::new(Some(BTreeMap::new())), + + aml_context: RwLock::new(AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None)), + aml_symbols: RwLock::new(None), + next_ctx: RwLock::new(0), sdt_order: RwLock::new(Vec::new()), @@ -266,10 +288,28 @@ impl AcpiContext { Fadt::init(&mut this); //TODO (hangs on real hardware): Dmar::init(&this); - crate::aml::init_namespace(&this); + if let Some(mut parser) = this.aml_context.try_write() { + if let Some(dsdt) = this.dsdt() { + match parser.parse_table(dsdt.aml()) { + Ok(_) => log::trace!("Parsed DSDT"), + Err(e) => { + log::error!("DSDT: {:?}", e); + } + } + } else { + log::error!("No DSDT for aml parsing"); + } - for (path, _) in this.namespace.get_mut().as_mut().unwrap().iter() { - log::trace!("ACPI NS: {}", path); + for ssdt in this.ssdts() { + match parser.parse_table(ssdt.aml()) { + Ok(_) => log::trace!("Parsed SSDT"), + Err(e) => { + log::error!("SSDT: {:?}", e); + } + } + } + } else { + log::error!("Failed to obtain aml_context"); } this @@ -296,12 +336,6 @@ impl AcpiContext { pub fn take_single_sdt(&self, signature: [u8; 4]) -> Option { self.find_single_sdt_pos(signature).map(|pos| self.tables[pos].clone()) } - pub fn namespace(&self) -> RwLockReadGuard<'_, Option>> { - self.namespace.read() - } - pub fn namespace_mut(&self) -> RwLockWriteGuard<'_, Option>> { - self.namespace.write() - } pub fn fadt(&self) -> Option<&Fadt> { self.fadt.as_ref() } @@ -320,6 +354,204 @@ impl AcpiContext { pub fn new_index(&self, signature: &SdtSignature) { self.sdt_order.write().push(Some(*signature)); } + fn aml_context(&self) -> RwLockReadGuard<'_, AmlContext>{ + self.aml_context.read() + } + fn aml_context_mut(&self) -> RwLockWriteGuard<'_, AmlContext> { + self.aml_context.write() + } + pub fn aml_lookup(&self, symbol: &str) -> Option { + let aml_name = match AmlName::from_str(symbol) { + Ok(aml_name) => aml_name, + Err(error) => { + log::error!("Lookup failed to convert name to AmlName {}, {:?}", symbol, error); + return None; + } + }; + + // Check the cache first + if let Ok(symbols_option) = self.aml_symbols() { + if let Some(symbols) = symbols_option.as_ref() { + if symbols.symbols_hash.contains(symbol) { + log::trace!("Found symbol in cache, {}", symbol); + return Some(aml_name); + } + } + } + + // Symbol does not exactly match cache, allow lookup using namespace rules + let aml_ctx = self.aml_context(); + let root = aml::AmlName::root(); + if aml_ctx.namespace.get_by_path(&aml_name).is_ok() + || aml_ctx.namespace.search_for_level(&aml_name, &root).is_ok() + { + Some(aml_name) + } else { + log::trace!("Lookup did not find {}", aml_name); + None + } + } + + pub fn aml_symbols(&self) -> Result>, SymbolListError> { + // Some private functions for building the symbol name correctly and efficiently + fn level_name(level_aml_name: &aml::AmlName) -> String { + let mut name = level_aml_name.as_string(); + // remove unnecessary underscores + while let Some(index) = name.find("_.") { + name.remove(index); + } + while name.len() > 0 && &name[name.len() - 1..] == "_" { + name.pop(); + } + name.shrink_to_fit(); + name + } + fn child_symbol(level_name: &str, value_name: &str) -> String { + let mut name = String::with_capacity(level_name.len() + 1 + value_name.len()); + name.push_str(level_name); + name.push('.'); + name.push_str(value_name.trim_end_matches('_')); + name.shrink_to_fit(); + name + } + fn root_symbol(value_name: &str) -> String { + let mut name = String::with_capacity(1 + value_name.len()); + name.push('\\'); + name.push_str(value_name.trim_end_matches('_')); + name.shrink_to_fit(); + name + } + + // return the cached value if it exists + let symbols = self.aml_symbols.read(); + if symbols.is_some() { + return Ok(symbols); + } + // free the read lock + drop(symbols); + + // List has not been initialized, we have to build it + log::trace!("Creating symbols list"); + + let mut symbols_str: String = String::with_capacity(30000); + + let mut symbols_hash: FxHashSet = FxHashSet::default(); + + // Get write lock because traverse requires mut + let mut aml_ctx = self.aml_context_mut(); + + let root = aml::AmlName::root(); + let traverse = aml_ctx.namespace.traverse(| level_aml_name, level | { + let level_is_root = level_aml_name.eq(&root); + let level_name = level_name(level_aml_name); + for (name, _handle) in level.values.iter() { + // Create the name of the symbol as "\levelname.symbolname" + let symbol = if level_is_root { + root_symbol(name.as_str()) + } else { + child_symbol(&level_name, name.as_str()) + }; + symbols_str.push_str(&symbol); + symbols_str.push('\n'); + symbols_hash.insert(symbol); + } + Ok(true) + }); + + match traverse { + Err(error) => { + log::error!("Traverse failed, {:?}", error); + return Err(SymbolListError::AmlInternalError); + } + _ => {} + } + + symbols_str.shrink_to_fit(); + + // Cache the new list + log::trace!("Updating symbols list"); + + let mut write_guarded_symbols = self.aml_symbols.write(); + *write_guarded_symbols = Some(AmlSymbols { symbols_str, symbols_hash }); + + // return the cached value + Ok(RwLockWriteGuard::downgrade(write_guarded_symbols)) + } + + /// Discard any cached symbols list. To be called if the AML namespace changes. + /// The caller must have at least a Read Lock on the aml context to ensure + /// the cached list is not out of sync with the namespace. + pub fn aml_symbols_reset(&self) { + let mut symbols = self.aml_symbols.write(); + *symbols = None; + } + + /// Set Power State + /// See https://uefi.org/sites/default/files/resources/ACPI_6_1.pdf + /// - search for PM1a + /// See https://forum.osdev.org/viewtopic.php?t=16990 for practical details + pub fn set_global_s_state(&self, state: u8) { + if state != 5 { + return; + } + let fadt = match self.fadt() { + Some(fadt) => fadt, + None => { + log::error!("Cannot set global S-state due to missing FADT."); + return; + } + }; + + let port = fadt.pm1a_control_block as u16; + let mut val = 1 << 13; + + let aml_ctx = self.aml_context(); + + let s5_aml_name = match aml::AmlName::from_str("\\_S5") { + Ok(aml_name) => aml_name, + Err(error) => { log::error!("Could not build AmlName for \\_S5, {:?}", error); return; } + }; + + let s5 = match aml_ctx.namespace.get_by_path(&s5_aml_name) { + Ok(s5) => s5, + Err(error) => { log::error!("Cannot set S-state, missing \\_S5, {:?}", error); return; } + }; + + let package = match s5 { + aml::AmlValue::Package(package) => package, + _ => { log::error!("Cannot set S-state, \\_S5 is not a package"); return; } + }; + + let slp_typa = match package[0] { + aml::AmlValue::Integer(i) => i, + _ => { log::error!("typa is not an Integer"); return; } + }; + let slp_typb = match package[1] { + aml::AmlValue::Integer(i) => i, + _ => { log::error!("typb is not an Integer"); return; } + }; + + log::trace!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); + val |= slp_typa as u16; + + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + log::warn!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); + Pio::::new(port).write(val); + } + + // TODO: Handle SLP_TYPb + + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] + { + log::error!("Cannot shutdown with ACPI outw(0x{:X}, 0x{:X}) on this architecture", port, val); + } + + loop { + core::hint::spin_loop(); + } + } + } #[repr(packed)] @@ -539,3 +771,88 @@ impl AmlContainingTable for Ssdt { &*self.0 } } + +struct AmlPhysMemHandler; + +impl aml::Handler for AmlPhysMemHandler { + fn read_u8(&self, _address: usize) -> u8 { + log::error!("read u8 {:X}", _address); + 0 + } + fn read_u16(&self, _address: usize) -> u16 { + log::error!("read u16 {:X}", _address); + 0 + } + fn read_u32(&self, _address: usize) -> u32 { + log::error!("read u32 {:X}", _address); + 0 + } + fn read_u64(&self, _address: usize) -> u64 { + log::error!("read u64 {:X}", _address); + 0 + } + + fn write_u8(&mut self, _address: usize, _value: u8) { + log::error!("write u8 {:X}", _address); + } + fn write_u16(&mut self, _address: usize, _value: u16) { + log::error!("write u16 {:X}", _address); + } + fn write_u32(&mut self, _address: usize, _value: u32) { + log::error!("write u32 {:X}", _address); + } + fn write_u64(&mut self, _address: usize, _value: u64) { + log::error!("write u64 {:X}", _address); + } + + fn read_io_u8(&self, _port: u16) -> u8 { + log::error!("read io u8 {:X}", _port); + + 0 + } + fn read_io_u16(&self, _port: u16) -> u16 { + log::error!("read io u16 {:X}", _port); + + 0 + } + fn read_io_u32(&self, _port: u16) -> u32 { + log::error!("read io u32 {:X}", _port); + + 0 + } + + fn write_io_u8(&self, _port: u16, _value: u8) { + log::error!("write io u8 {:X}", _port); + } + fn write_io_u16(&self, _port: u16, _value: u16) { + log::error!("write io u16 {:X}", _port); + } + fn write_io_u32(&self, _port: u16, _value: u32) { + log::error!("write io u32 {:X}", _port); + } + + fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { + log::error!("read pci u8 {:X}", _device); + + 0 + } + fn read_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u16 { + log::error!("read pci u8 {:X}", _device); + + 0 + } + fn read_pci_u32(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u32 { + log::error!("read pci u8 {:X}", _device); + + 0 + } + fn write_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u8) { + log::error!("write pci u8 {:X}", _device); + } + fn write_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u16) { + log::error!("write pci u8 {:X}", _device); + } + fn write_pci_u32(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u32) { + log::error!("write pci u8 {:X}", _device); + } +} diff --git a/acpid/src/aml/dataobj.rs b/acpid/src/aml/dataobj.rs deleted file mode 100644 index 6e4ab1da73..0000000000 --- a/acpid/src/aml/dataobj.rs +++ /dev/null @@ -1,184 +0,0 @@ -use super::AmlError; -use super::parser::{ AmlParseType, ParseResult, AmlExecutionContext, ExecutionState }; -use super::namespace::{ AmlValue, ObjectReference }; - -use super::type2opcode::{parse_def_buffer, parse_def_package, parse_def_var_package}; -use super::termlist::parse_term_arg; -use super::namestring::parse_super_name; - -pub fn parse_data_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_computational_data, - parse_def_package, - parse_def_var_package - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_data_ref_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_data_obj, - parse_term_arg - }; - - match parse_super_name(data, ctx) { - Ok(res) => match res.val { - AmlValue::String(s) => Ok(AmlParseType { - val: AmlValue::ObjectReference(ObjectReference::Object(s)), - len: res.len - }), - _ => Ok(res) - }, - Err(e) => Err(e) - } -} - -pub fn parse_arg_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - match data[0] { - 0x68 ..= 0x6E => Ok(AmlParseType { - val: AmlValue::ObjectReference(ObjectReference::ArgObj(data[0] - 0x68)), - len: 1 as usize - }), - _ => Err(AmlError::AmlInvalidOpCode) - } -} - -pub fn parse_local_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - match data[0] { - 0x68 ..= 0x6E => Ok(AmlParseType { - val: AmlValue::ObjectReference(ObjectReference::LocalObj(data[0] - 0x60)), - len: 1 as usize - }), - _ => Err(AmlError::AmlInvalidOpCode) - } -} - -fn parse_computational_data(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - match data[0] { - 0x0A => Ok(AmlParseType { - val: AmlValue::Integer(data[1] as u64), - len: 2 as usize - }), - 0x0B => { - let res = (data[1] as u16) + - ((data[2] as u16) << 8); - - Ok(AmlParseType { - val: AmlValue::Integer(res as u64), - len: 3 as usize - }) - }, - 0x0C => { - let res = (data[1] as u32) + - ((data[2] as u32) << 8) + - ((data[3] as u32) << 16) + - ((data[4] as u32) << 24); - - Ok(AmlParseType { - val: AmlValue::Integer(res as u64), - len: 5 as usize - }) - }, - 0x0D => { - let mut cur_ptr: usize = 1; - let mut cur_string: Vec = vec!(); - - while data[cur_ptr] != 0x00 { - cur_string.push(data[cur_ptr]); - cur_ptr += 1; - } - - match String::from_utf8(cur_string) { - Ok(s) => Ok(AmlParseType { - val: AmlValue::String(s.clone()), - len: s.clone().len() + 2 - }), - Err(_) => Err(AmlError::AmlParseError("String data - invalid string")) - } - }, - 0x0E => { - let res = (data[1] as u64) + - ((data[2] as u64) << 8) + - ((data[3] as u64) << 16) + - ((data[4] as u64) << 24) + - ((data[5] as u64) << 32) + - ((data[6] as u64) << 40) + - ((data[7] as u64) << 48) + - ((data[8] as u64) << 56); - - Ok(AmlParseType { - val: AmlValue::Integer(res as u64), - len: 9 as usize - }) - }, - 0x00 => Ok(AmlParseType { - val: AmlValue::IntegerConstant(0 as u64), - len: 1 as usize - }), - 0x01 => Ok(AmlParseType { - val: AmlValue::IntegerConstant(1 as u64), - len: 1 as usize - }), - 0x5B => if data[1] == 0x30 { - Ok(AmlParseType { - val: AmlValue::IntegerConstant(2017_0630 as u64), - len: 2 as usize - }) - } else { - Err(AmlError::AmlInvalidOpCode) - }, - 0xFF => Ok(AmlParseType { - val: AmlValue::IntegerConstant(0xFFFF_FFFF_FFFF_FFFF), - len: 1 as usize - }), - _ => parse_def_buffer(data, ctx) - } -} diff --git a/acpid/src/aml/mod.rs b/acpid/src/aml/mod.rs deleted file mode 100644 index 39f4c1c9e6..0000000000 --- a/acpid/src/aml/mod.rs +++ /dev/null @@ -1,144 +0,0 @@ -//! # AML -//! -//! Code to parse and execute ACPI Machine Language tables. - -use std::collections::HashMap; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use syscall::io::{Io, Pio}; - -use crate::acpi::{AcpiContext, AmlContainingTable, Sdt, SdtHeader}; - -#[macro_use] -mod parsermacros; - -mod namespace; -mod termlist; -mod namespacemodifier; -mod pkglength; -mod namestring; -mod namedobj; -mod dataobj; -mod type1opcode; -mod type2opcode; -mod parser; - -use self::parser::AmlExecutionContext; -use self::termlist::parse_term_list; -pub use self::namespace::AmlValue; - -#[derive(Debug)] -pub enum AmlError { - AmlParseError(&'static str), - AmlInvalidOpCode, - AmlValueError, - AmlDeferredLoad, - AmlFatalError(u8, u16, AmlValue), - AmlHardFatal -} - -pub fn parse_aml_table(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable) -> Result, AmlError> { - parse_aml_with_scope(acpi_ctx, sdt, "\\".to_owned()) -} - -pub fn parse_aml_with_scope(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable, scope: String) -> Result, AmlError> { - let data = sdt.aml(); - let mut ctx = AmlExecutionContext::new(acpi_ctx, scope); - - parse_term_list(data, &mut ctx)?; - - Ok(ctx.namespace_delta) -} - -fn init_aml_table(acpi_ctx: &AcpiContext, sdt: impl AmlContainingTable) { - match parse_aml_table(acpi_ctx, &sdt) { - Ok(_) => log::debug!("Table {} parsed successfully", sdt.header().signature()), - Err(AmlError::AmlParseError(e)) => log::error!("Table {} got parse error: {}", sdt.header().signature(), e), - Err(AmlError::AmlInvalidOpCode) => log::error!("Table {} got invalid opcode", sdt.header().signature()), - Err(AmlError::AmlValueError) => log::error!("For table {}: type constraints or value bounds not met", sdt.header().signature()), - Err(AmlError::AmlDeferredLoad) => log::error!("For table {}: deferred load reached top level", sdt.header().signature()), - Err(AmlError::AmlFatalError(ty, code, val)) => { - log::error!("Fatal error occurred for table {}: type={}, code={}, val={:?}", sdt.header().signature(), ty, code, val); - return; - }, - Err(AmlError::AmlHardFatal) => { - log::error!("Hard fatal error occurred for table {}", sdt.header().signature()); - return; - } - } -} -pub fn init_namespace(context: &AcpiContext) { - let dsdt = context.dsdt().expect("could not find any DSDT"); - - log::debug!("Found DSDT."); - init_aml_table(context, dsdt); - - let ssdts = context.ssdts(); - - for ssdt in ssdts { - print!("Found SSDT."); - init_aml_table(context, ssdt); - } -} - -pub fn set_global_s_state(context: &AcpiContext, state: u8) { - if state != 5 { - return; - } - let fadt = match context.fadt() { - Some(fadt) => fadt, - None => { - log::error!("Cannot set global S-state due to missing FADT."); - return; - } - }; - - let port = fadt.pm1a_control_block as u16; - let mut val = 1 << 13; - - let namespace_guard = context.namespace(); - - let namespace = match &*namespace_guard { - Some(namespace) => namespace, - None => { - log::error!("Cannot set global S-state due to missing ACPI namespace"); - return; - } - }; - - let s5 = match namespace.get("\\_S5") { - Some(s5) => s5, - None => { - log::error!("Cannot set global S-state due to missing \\_S5"); - return; - } - }; - let p = match s5.get_as_package() { - Ok(package) => package, - Err(error) => { - log::error!("Cannot set global S-state due to \\_S5 not being a package: {:?}", error); - return; - } - }; - - let slp_typa = p[0].get_as_integer(context).expect("SLP_TYPa is not an integer"); - let slp_typb = p[1].get_as_integer(context).expect("SLP_TYPb is not an integer"); - - log::info!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); - val |= slp_typa as u16; - - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - log::info!("Shutdown with ACPI outw(0x{:X}, 0x{:X})", port, val); - Pio::::new(port).write(val); - } - - #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] - { - log::error!("Cannot shutdown with ACPI outw(0x{:X}, 0x{:X}) on this architecture", port, val); - } - - loop { - core::hint::spin_loop(); - } -} diff --git a/acpid/src/aml/namedobj.rs b/acpid/src/aml/namedobj.rs deleted file mode 100644 index 40659b2c77..0000000000 --- a/acpid/src/aml/namedobj.rs +++ /dev/null @@ -1,1043 +0,0 @@ -use std::collections::BTreeMap; - -use super::AmlError; -use super::parser::{ AmlParseType, ParseResult, AmlParseTypeGeneric, AmlExecutionContext, ExecutionState }; -use super::namespace::{AmlValue, FieldSelector, Method, get_namespace_string, - Accessor, BufferField, FieldUnit, Processor, PowerResource, OperationRegion, - Device, ThermalZone}; -use super::namestring::{parse_name_string, parse_name_seg}; -use super::termlist::{parse_term_arg, parse_object_list}; -use super::pkglength::parse_pkg_length; -use super::type2opcode::parse_def_buffer; - -#[derive(Debug, Copy, Clone)] -pub enum RegionSpace { - SystemMemory, - SystemIO, - PCIConfig, - EmbeddedControl, - SMBus, - SystemCMOS, - PciBarTarget, - IPMI, - GeneralPurposeIO, - GenericSerialBus, - UserDefined(u8) -} - -#[derive(Debug, Clone)] -pub struct FieldFlags { - access_type: AccessType, - lock_rule: bool, - update_rule: UpdateRule -} - -#[derive(Debug, Clone)] -pub enum AccessType { - AnyAcc, - ByteAcc, - WordAcc, - DWordAcc, - QWordAcc, - BufferAcc(AccessAttrib) -} - -#[derive(Debug, Clone)] -pub enum UpdateRule { - Preserve, - WriteAsOnes, - WriteAsZeros -} - -#[derive(Debug, Clone)] -pub struct NamedField { - name: String, - length: usize -} - -#[derive(Debug, Clone)] -pub struct AccessField { - access_type: AccessType, - access_attrib: AccessAttrib -} - -#[derive(Debug, Clone)] -pub enum AccessAttrib { - AttribBytes(u8), - AttribRawBytes(u8), - AttribRawProcessBytes(u8), - AttribQuick, - AttribSendReceive, - AttribByte, - AttribWord, - AttribBlock, - AttribProcessCall, - AttribBlockProcessCall -} - -pub fn parse_named_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_def_bank_field, - parse_def_create_bit_field, - parse_def_create_byte_field, - parse_def_create_word_field, - parse_def_create_dword_field, - parse_def_create_qword_field, - parse_def_create_field, - parse_def_data_region, - parse_def_event, - parse_def_external, - parse_def_device, - parse_def_op_region, - parse_def_field, - parse_def_index_field, - parse_def_method, - parse_def_mutex, - parse_def_power_res, - parse_def_processor, - parse_def_thermal_zone - }; - - Err(AmlError::AmlInvalidOpCode) -} - -fn parse_def_bank_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 3 { - return Err(AmlError::AmlParseError("DefBankField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x87); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; - let data = &data[2 + pkg_length_len .. 2 + pkg_length]; - - let region_name = parse_name_string(data, ctx)?; - let bank_name = parse_name_string(&data[2 + pkg_length_len + region_name.len .. 2 + pkg_length], ctx)?; - - let bank_value = parse_term_arg(&data[2 + pkg_length_len + region_name.len .. 2 + pkg_length], ctx)?; - - let flags_raw = data[2 + pkg_length_len + region_name.len + bank_name.len + bank_value.len]; - let mut flags = FieldFlags { - access_type: match flags_raw & 0x0F { - 0 => AccessType::AnyAcc, - 1 => AccessType::ByteAcc, - 2 => AccessType::WordAcc, - 3 => AccessType::DWordAcc, - 4 => AccessType::QWordAcc, - 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), - _ => return Err(AmlError::AmlParseError("BankField - invalid access type")) - }, - lock_rule: (flags_raw & 0x10) == 0x10, - update_rule: match (flags_raw & 0x60) >> 5 { - 0 => UpdateRule::Preserve, - 1 => UpdateRule::WriteAsOnes, - 2 => UpdateRule::WriteAsZeros, - _ => return Err(AmlError::AmlParseError("BankField - invalid update rule")) - } - }; - - let selector = FieldSelector::Bank { - region: region_name.val.get_as_string(ctx.acpi_context())?, - bank_register: bank_name.val.get_as_string(ctx.acpi_context())?, - bank_selector: Box::new(bank_value.val) - }; - - parse_field_list(&data[3 + pkg_length_len + region_name.len + bank_name.len + bank_value.len .. - 2 + pkg_length], ctx, selector, &mut flags)?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_length - }) -} - -fn parse_def_create_bit_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateBitField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8D); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(AmlValue::IntegerConstant(1)) - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len - }) -} - -fn parse_def_create_byte_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateByteField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8C); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(AmlValue::IntegerConstant(8)) - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len - }) -} - -fn parse_def_create_word_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateWordField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8B); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(AmlValue::IntegerConstant(16)) - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len - }) -} - -fn parse_def_create_dword_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateDwordField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8A); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - - let _ = ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(AmlValue::IntegerConstant(32)) - })); - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len - }) -} - -fn parse_def_create_qword_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateQwordField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8F); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let name = parse_name_string(&data[1 + source_buf.len + bit_index.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(AmlValue::IntegerConstant(64)) - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len - }) -} - -fn parse_def_create_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefCreateField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x13); - - let source_buf = parse_term_arg(&data[2..], ctx)?; - let bit_index = parse_term_arg(&data[2 + source_buf.len..], ctx)?; - let num_bits = parse_term_arg(&data[2 + source_buf.len + bit_index.len..], ctx)?; - let name = parse_name_string(&data[2 + source_buf.len + bit_index.len + num_bits.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::BufferField(BufferField { - source_buf: Box::new(source_buf.val), - index: Box::new(bit_index.val), - length: Box::new(num_bits.val) - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + source_buf.len + bit_index.len + num_bits.len - }) -} - -fn parse_def_data_region(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefDataRegion - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Find the actual offset and length, once table mapping is implemented - parser_opcode_extended!(data, 0x88); - - let name = parse_name_string(&data[2..], ctx)?; - let signature = parse_term_arg(&data[2 + name.len..], ctx)?; - let oem_id = parse_term_arg(&data[2 + name.len + signature.len..], ctx)?; - let oem_table_id = parse_term_arg(&data[2 + name.len + signature.len + oem_id.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::OperationRegion(OperationRegion { - region: RegionSpace::SystemMemory, - offset: Box::new(AmlValue::IntegerConstant(0)), - len: Box::new(AmlValue::IntegerConstant(0)), - accessor: Accessor { - read: |_x| 0 as u64, - write: |_x, _y| () - }, - accessed_by: None - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + signature.len + oem_id.len + oem_table_id.len - }) -} - -fn parse_def_event(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefEvent - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x02); - - let name = parse_name_string(&data[2..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Event(0))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len - }) -} - -fn parse_def_device(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefDevice - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: How to handle local context deferreds - parser_opcode_extended!(data, 0x82); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; - let name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - let mut local_ctx = AmlExecutionContext::new(ctx.acpi_context(), local_scope_string.clone()); - - parse_object_list(&data[2 + pkg_length_len + name.len .. 2 + pkg_length], &mut local_ctx)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Device(Device { - obj_list: local_ctx.namespace_delta.clone(), - notify_methods: BTreeMap::new() - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_length - }) -} - -fn parse_def_op_region(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 3 { - return Err(AmlError::AmlParseError("DefOpRegion - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x80); - - let name = parse_name_string(&data[2..], ctx)?; - let region = match data[2 + name.len] { - 0x00 => RegionSpace::SystemMemory, - 0x01 => RegionSpace::SystemIO, - 0x02 => RegionSpace::PCIConfig, - 0x03 => RegionSpace::EmbeddedControl, - 0x04 => RegionSpace::SMBus, - 0x05 => RegionSpace::SystemCMOS, - 0x06 => RegionSpace::PciBarTarget, - 0x07 => RegionSpace::IPMI, - 0x08 => RegionSpace::GeneralPurposeIO, - 0x09 => RegionSpace::GenericSerialBus, - 0x80 ..= 0xFF => RegionSpace::UserDefined(data[2 + name.len]), - _ => return Err(AmlError::AmlParseError("OpRegion - invalid region")) - }; - - let offset = parse_term_arg(&data[3 + name.len..], ctx)?; - let len = parse_term_arg(&data[3 + name.len + offset.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::OperationRegion(OperationRegion { - region, - offset: Box::new(offset.val), - len: Box::new(len.val), - accessor: Accessor { - read: |_x| 0 as u64, - write: |_x, _y| () - }, - accessed_by: None - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 3 + name.len + offset.len + len.len - }) -} - -fn parse_def_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 3 { - return Err(AmlError::AmlParseError("DefField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x81); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; - let name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; - - let flags_raw = data[2 + pkg_length_len + name.len]; - let mut flags = FieldFlags { - access_type: match flags_raw & 0x0F { - 0 => AccessType::AnyAcc, - 1 => AccessType::ByteAcc, - 2 => AccessType::WordAcc, - 3 => AccessType::DWordAcc, - 4 => AccessType::QWordAcc, - 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), - _ => return Err(AmlError::AmlParseError("Field - Invalid access type")) - }, - lock_rule: (flags_raw & 0x10) == 0x10, - update_rule: match (flags_raw & 0x60) >> 5 { - 0 => UpdateRule::Preserve, - 1 => UpdateRule::WriteAsOnes, - 2 => UpdateRule::WriteAsZeros, - _ => return Err(AmlError::AmlParseError("Field - Invalid update rule")) - } - }; - - let selector = FieldSelector::Region(name.val.get_as_string(ctx.acpi_context())?); - - parse_field_list(&data[3 + pkg_length_len + name.len .. 2 + pkg_length], ctx, selector, &mut flags)?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_length - }) -} - -fn parse_def_index_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 3 { - return Err(AmlError::AmlParseError("DefIndexField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x86); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[2..])?; - let idx_name = parse_name_string(&data[2 + pkg_length_len .. 2 + pkg_length], ctx)?; - let data_name = parse_name_string(&data[2 + pkg_length_len + idx_name.len .. 2 + pkg_length], ctx)?; - - let flags_raw = data[2 + pkg_length_len + idx_name.len + data_name.len]; - let mut flags = FieldFlags { - access_type: match flags_raw & 0x0F { - 0 => AccessType::AnyAcc, - 1 => AccessType::ByteAcc, - 2 => AccessType::WordAcc, - 3 => AccessType::DWordAcc, - 4 => AccessType::QWordAcc, - 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), - _ => return Err(AmlError::AmlParseError("IndexField - Invalid access type")) - }, - lock_rule: (flags_raw & 0x10) == 0x10, - update_rule: match (flags_raw & 0x60) >> 5 { - 0 => UpdateRule::Preserve, - 1 => UpdateRule::WriteAsOnes, - 2 => UpdateRule::WriteAsZeros, - _ => return Err(AmlError::AmlParseError("IndexField - Invalid update rule")) - } - }; - - let selector = FieldSelector::Index { - index_selector: idx_name.val.get_as_string(ctx.acpi_context())?, - data_selector: data_name.val.get_as_string(ctx.acpi_context())? - }; - - parse_field_list(&data[3 + pkg_length_len + idx_name.len + data_name.len .. 2 + pkg_length], - ctx, selector, &mut flags)?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_length - }) -} - -fn parse_field_list(data: &[u8], - ctx: &mut AmlExecutionContext, - selector: FieldSelector, - flags: &mut FieldFlags) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let mut current_offset: usize = 0; - let mut field_offset: usize = 0; - let mut connection = AmlValue::Uninitialized; - - while current_offset < data.len() { - let res = parse_field_element(&data[current_offset..], ctx, selector.clone(), &mut connection, flags, &mut field_offset)?; - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - current_offset += res.len; - } - - Ok(AmlParseType { - val: AmlValue::None, - len: data.len() - }) -} - -fn parse_field_element(data: &[u8], - ctx: &mut AmlExecutionContext, - selector: FieldSelector, - connection: &mut AmlValue, - flags: &mut FieldFlags, - offset: &mut usize) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let length = if let Ok(field) = parse_named_field(data, ctx) { - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), AmlValue::String(field.val.name.clone()))?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::FieldUnit(FieldUnit { - selector: selector.clone(), - connection: Box::new(connection.clone()), - flags: flags.clone(), - offset: offset.clone(), - length: field.val.length - }))?; - - *offset += field.val.length; - field.len - } else if let Ok(field) = parse_reserved_field(data, ctx) { - *offset += field.val; - field.len - } else if let Ok(field) = parse_access_field(data, ctx) { - match field.val.access_type { - AccessType::BufferAcc(_) => - flags.access_type = AccessType::BufferAcc(field.val.access_attrib.clone()), - ref a => flags.access_type = a.clone() - } - - field.len - } else if let Ok(field) = parse_connect_field(data, ctx) { - *connection = field.val.clone(); - field.len - } else { - return Err(AmlError::AmlInvalidOpCode); - }; - - Ok(AmlParseType { - val: AmlValue::None, - len: length - }) -} - -fn parse_named_field(data: &[u8], _ctx: &mut AmlExecutionContext) -> Result, AmlError> { - if data.len() < 4 { - return Err(AmlError::AmlParseError("NamedField - data truncated")) - } - - let (name_seg, name_seg_len) = parse_name_seg(&data[0..4])?; - let name = match String::from_utf8(name_seg) { - Ok(s) => s, - Err(_) => return Err(AmlError::AmlParseError("NamedField - invalid name")) - }; - let (length, length_len) = parse_pkg_length(&data[4..])?; - - Ok(AmlParseTypeGeneric { - val: NamedField { name, length }, - len: name_seg_len + length_len - }) -} - -fn parse_reserved_field(data: &[u8], _ctx: &mut AmlExecutionContext) -> Result, AmlError> { - if data.len() < 1 { - return Err(AmlError::AmlParseError("ReservedField - data truncated")) - } - - parser_opcode!(data, 0x00); - - let (length, length_len) = parse_pkg_length(&data[1..])?; - Ok(AmlParseTypeGeneric { - val: length, - len: 1 + length_len - }) -} - -fn parse_access_field(data: &[u8], _ctx: &mut AmlExecutionContext) -> Result, AmlError> { - if data.len() < 3 { - return Err(AmlError::AmlParseError("AccessField - data truncated")) - } - - parser_opcode!(data, 0x01, 0x03); - - let flags_raw = data[1]; - let access_type = match flags_raw & 0x0F { - 0 => AccessType::AnyAcc, - 1 => AccessType::ByteAcc, - 2 => AccessType::WordAcc, - 3 => AccessType::DWordAcc, - 4 => AccessType::QWordAcc, - 5 => AccessType::BufferAcc(AccessAttrib::AttribByte), - _ => return Err(AmlError::AmlParseError("AccessField - Invalid access type")) - }; - - let access_attrib = match (flags_raw & 0xC0) >> 6 { - 0 => match data[2] { - 0x02 => AccessAttrib::AttribQuick, - 0x04 => AccessAttrib::AttribSendReceive, - 0x06 => AccessAttrib::AttribByte, - 0x08 => AccessAttrib::AttribWord, - 0x0A => AccessAttrib::AttribBlock, - 0x0B => AccessAttrib::AttribBytes(data[3]), - 0x0C => AccessAttrib::AttribProcessCall, - 0x0D => AccessAttrib::AttribBlockProcessCall, - 0x0E => AccessAttrib::AttribRawBytes(data[3]), - 0x0F => AccessAttrib::AttribRawProcessBytes(data[3]), - _ => return Err(AmlError::AmlParseError("AccessField - Invalid access attrib")) - }, - 1 => AccessAttrib::AttribBytes(data[2]), - 2 => AccessAttrib::AttribRawBytes(data[2]), - 3 => AccessAttrib::AttribRawProcessBytes(data[2]), - _ => return Err(AmlError::AmlParseError("AccessField - Invalid access attrib")) - // This should never happen but the compiler bitches if I don't cover this - }; - - Ok(AmlParseTypeGeneric { - val: AccessField { access_type, access_attrib }, - len: if data[0] == 0x01 { - 3 as usize - } else { - 4 as usize - } - }) -} - -fn parse_connect_field(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 1 { - return Err(AmlError::AmlParseError("ConnectField - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x02); - - if let Ok(e) = parse_def_buffer(&data[1..], ctx) { - Ok(AmlParseType { - val: e.val, - len: e.len + 1 - }) - } else { - let name = parse_name_string(&data[1..], ctx)?; - Ok(AmlParseType { - val: AmlValue::Alias(name.val.get_as_string(ctx.acpi_context())?), - len: name.len + 1 - }) - } -} - -fn parse_def_method(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 1 { - return Err(AmlError::AmlParseError("DefMethod - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x14); - - let (pkg_len, pkg_len_len) = parse_pkg_length(&data[1..])?; - let name = parse_name_string(&data[1 + pkg_len_len..], ctx)?; - let flags = data[1 + pkg_len_len + name.len]; - - let arg_count = flags & 0x07; - let serialized = (flags & 0x08) == 0x08; - let sync_level = flags & 0xF0 >> 4; - - let term_list = &data[2 + pkg_len_len + name.len .. 1 + pkg_len]; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Method(Method { - arg_count, - serialized, - sync_level, - term_list: term_list.to_vec() - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + pkg_len - }) -} - -fn parse_def_mutex(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 1 { - return Err(AmlError::AmlParseError("DefMutex - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x01); - - let name = parse_name_string(&data[2 ..], ctx)?; - let flags = data[2 + name.len]; - let sync_level = flags & 0x0F; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Mutex((sync_level, None)))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 3 + name.len - }) -} - -fn parse_def_power_res(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 5 { - return Err(AmlError::AmlParseError("DefPowerRes - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: How to handle local context deferreds - parser_opcode_extended!(data, 0x84); - - let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; - let name = parse_name_string(&data[2 + pkg_len_len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - - let system_level = data[2 + pkg_len_len + name.len]; - let resource_order: u16 = (data[3 + pkg_len_len + name.len] as u16) + - ((data[4 + pkg_len_len + name.len] as u16) << 8); - - let mut local_ctx = AmlExecutionContext::new(ctx.acpi_context(), local_scope_string.clone()); - parse_object_list(&data[5 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::PowerResource(PowerResource { - system_level, - resource_order, - obj_list: local_ctx.namespace_delta.clone() - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_len - }) -} - -fn parse_def_processor(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 8 { - return Err(AmlError::AmlParseError("DefProcessor - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x83); - - let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; - let name = parse_name_string(&data[2 + pkg_len_len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - - let proc_id = data[2 + pkg_len_len + name.len]; - let p_blk_addr: u32 = (data[3 + pkg_len_len + name.len] as u32) + - ((data[4 + pkg_len_len + name.len] as u32) << 8) + - ((data[5 + pkg_len_len + name.len] as u32) << 16) + - ((data[6 + pkg_len_len + name.len] as u32) << 24); - let p_blk_len = data[7 + pkg_len_len + name.len]; - - let mut local_ctx = AmlExecutionContext::new(ctx.acpi_context(), local_scope_string.clone()); - parse_object_list(&data[8 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Processor(Processor { - proc_id, - p_blk: if p_blk_len > 0 { Some(p_blk_addr) } else { None }, - obj_list: local_ctx.namespace_delta.clone(), - notify_methods: BTreeMap::new() - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_len - }) -} - -fn parse_def_thermal_zone(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefThermalZone - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x85); - - let (pkg_len, pkg_len_len) = parse_pkg_length(&data[2..])?; - let name = parse_name_string(&data[2 + pkg_len_len .. 2 + pkg_len], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - - let mut local_ctx = AmlExecutionContext::new(ctx.acpi_context(), local_scope_string.clone()); - parse_object_list(&data[2 + pkg_len_len + name.len .. 2 + pkg_len], &mut local_ctx)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::ThermalZone(ThermalZone { - obj_list: local_ctx.namespace_delta.clone(), - notify_methods: BTreeMap::new() - }))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + pkg_len - }) -} - -fn parse_def_external(data: &[u8], ctx: &mut AmlExecutionContext) -> ParseResult { - if data.len() < 2 { - return Err(AmlError::AmlParseError("DefExternal - data truncated")) - } - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x15); - - let object_name = parse_name_string(&data[1..], ctx)?; - let object_type = data[1 + object_name.len]; - let argument_count = data[2 + object_name.len]; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), object_name.val)?; - - let obj = match object_type { - 8 => AmlValue::Method(Method { - arg_count: argument_count, - serialized: false, - sync_level: 0, - term_list: vec!() - }), - _ => AmlValue::Uninitialized - }; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, obj)?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 3 + object_name.len - }) -} diff --git a/acpid/src/aml/namespace.rs b/acpid/src/aml/namespace.rs deleted file mode 100644 index 4dfd18516f..0000000000 --- a/acpid/src/aml/namespace.rs +++ /dev/null @@ -1,490 +0,0 @@ -use std::collections::BTreeMap; - -use core::fmt::Debug; -use core::str::FromStr; - -use super::termlist::parse_term_list; -use super::namedobj::{ RegionSpace, FieldFlags }; -use super::parser::{AmlExecutionContext, ExecutionState}; -use super::AmlError; - -use crate::acpi::{AcpiContext, SdtSignature}; - -#[derive(Clone, Debug)] -pub enum FieldSelector { - Region(String), - Bank { - region: String, - bank_register: String, - bank_selector: Box - }, - Index { - index_selector: String, - data_selector: String - } -} - -#[derive(Clone, Debug)] -pub enum ObjectReference { - ArgObj(u8), - LocalObj(u8), - Object(String), - Index(Box, Box) -} - -#[derive(Clone, Debug)] -pub struct Method { - pub arg_count: u8, - pub serialized: bool, - pub sync_level: u8, - pub term_list: Vec -} - -#[derive(Clone, Debug)] -pub struct BufferField { - pub source_buf: Box, - pub index: Box, - pub length: Box -} - -#[derive(Clone, Debug)] -pub struct FieldUnit { - pub selector: FieldSelector, - pub connection: Box, - pub flags: FieldFlags, - pub offset: usize, - pub length: usize -} - -#[derive(Clone, Debug)] -pub struct Device { - pub obj_list: Vec, - pub notify_methods: BTreeMap> -} - -#[derive(Clone, Debug)] -pub struct ThermalZone { - pub obj_list: Vec, - pub notify_methods: BTreeMap> -} - -#[derive(Clone, Debug)] -pub struct Processor { - pub proc_id: u8, - pub p_blk: Option, - pub obj_list: Vec, - pub notify_methods: BTreeMap> -} - -#[derive(Clone, Debug)] -pub struct OperationRegion { - pub region: RegionSpace, - pub offset: Box, - pub len: Box, - pub accessor: Accessor, - pub accessed_by: Option -} - -#[derive(Clone, Debug)] -pub struct PowerResource { - pub system_level: u8, - pub resource_order: u16, - pub obj_list: Vec -} - -#[derive(Debug)] -pub struct Accessor { - pub read: fn(usize) -> u64, - pub write: fn(usize, u64) -} - -impl Clone for Accessor { - fn clone(&self) -> Accessor { - Accessor { - read: (*self).read, - write: (*self).write - } - } -} - -#[derive(Clone, Debug)] -pub enum AmlValue { - None, - Uninitialized, - Alias(String), - Buffer(Vec), - BufferField(BufferField), - DDBHandle((Vec, SdtSignature)), - DebugObject, - Device(Device), - Event(u64), - FieldUnit(FieldUnit), - Integer(u64), - IntegerConstant(u64), - Method(Method), - Mutex((u8, Option)), - ObjectReference(ObjectReference), - OperationRegion(OperationRegion), - Package(Vec), - String(String), - PowerResource(PowerResource), - Processor(Processor), - - #[allow(dead_code)] - RawDataBuffer(Vec), - - ThermalZone(ThermalZone) -} - -impl AmlValue { - pub fn get_type_string(&self) -> String { - match *self { - AmlValue::Uninitialized => String::from_str("[Uninitialized Object]").unwrap(), - AmlValue::Integer(_) => String::from_str("[Integer]").unwrap(), - AmlValue::String(_) => String::from_str("[String]").unwrap(), - AmlValue::Buffer(_) => String::from_str("[Buffer]").unwrap(), - AmlValue::Package(_) => String::from_str("[Package]").unwrap(), - AmlValue::FieldUnit(_) => String::from_str("[Field]").unwrap(), - AmlValue::Device(_) => String::from_str("[Device]").unwrap(), - AmlValue::Event(_) => String::from_str("[Event]").unwrap(), - AmlValue::Method(_) => String::from_str("[Control Method]").unwrap(), - AmlValue::Mutex(_) => String::from_str("[Mutex]").unwrap(), - AmlValue::OperationRegion(_) => String::from_str("[Operation Region]").unwrap(), - AmlValue::PowerResource(_) => String::from_str("[Power Resource]").unwrap(), - AmlValue::Processor(_) => String::from_str("[Processor]").unwrap(), - AmlValue::ThermalZone(_) => String::from_str("[Thermal Zone]").unwrap(), - AmlValue::BufferField(_) => String::from_str("[Buffer Field]").unwrap(), - AmlValue::DDBHandle(_) => String::from_str("[DDB Handle]").unwrap(), - AmlValue::DebugObject => String::from_str("[Debug Object]").unwrap(), - _ => String::new() - } - } - - pub fn get_as_type(&self, ctx: &AcpiContext, t: AmlValue) -> Result { - match t { - AmlValue::None => Ok(AmlValue::None), - AmlValue::Uninitialized => Ok(self.clone()), - AmlValue::Alias(_) => match *self { - AmlValue::Alias(_) => Ok(self.clone()), - _ => Err(AmlError::AmlValueError) - }, - AmlValue::Buffer(_) => Ok(AmlValue::Buffer(self.get_as_buffer(ctx)?)), - AmlValue::BufferField(_) => Ok(AmlValue::BufferField(self.get_as_buffer_field(ctx)?)), - AmlValue::DDBHandle(_) => Ok(AmlValue::DDBHandle(self.get_as_ddb_handle(ctx)?)), - AmlValue::DebugObject => match *self { - AmlValue::DebugObject => Ok(self.clone()), - _ => Err(AmlError::AmlValueError) - }, - AmlValue::Device(_) => Ok(AmlValue::Device(self.get_as_device()?)), - AmlValue::Event(_) => Ok(AmlValue::Event(self.get_as_event()?)), - AmlValue::FieldUnit(_) => Ok(AmlValue::FieldUnit(self.get_as_field_unit()?)), - AmlValue::Integer(_) => Ok(AmlValue::Integer(self.get_as_integer(ctx)?)), - AmlValue::IntegerConstant(_) => Ok(AmlValue::IntegerConstant(self.get_as_integer_constant()?)), - AmlValue::Method(_) => Ok(AmlValue::Method(self.get_as_method()?)), - AmlValue::Mutex(_) => Ok(AmlValue::Mutex(self.get_as_mutex()?)), - AmlValue::ObjectReference(_) => Ok(AmlValue::ObjectReference(self.get_as_object_reference()?)), - AmlValue::OperationRegion(_) => match *self { - AmlValue::OperationRegion(_) => Ok(self.clone()), - _ => Err(AmlError::AmlValueError) - }, - AmlValue::Package(_) => Ok(AmlValue::Package(self.get_as_package()?)), - AmlValue::String(_) => Ok(AmlValue::String(self.get_as_string(ctx)?)), - AmlValue::PowerResource(_) => Ok(AmlValue::PowerResource(self.get_as_power_resource()?)), - AmlValue::Processor(_) => Ok(AmlValue::Processor(self.get_as_processor()?)), - AmlValue::RawDataBuffer(_) => Ok(AmlValue::RawDataBuffer(self.get_as_raw_data_buffer()?)), - AmlValue::ThermalZone(_) => Ok(AmlValue::ThermalZone(self.get_as_thermal_zone()?)) - } - } - - pub fn get_as_buffer(&self, ctx: &AcpiContext) -> Result, AmlError> { - match *self { - AmlValue::Buffer(ref b) => Ok(b.clone()), - AmlValue::Integer(ref i) => { - let mut v: Vec = vec!(); - let mut i = i.clone(); - - while i != 0 { - v.push((i & 0xFF) as u8); - i >>= 8; - } - - while v.len() < 8 { - v.push(0); - } - - Ok(v) - }, - AmlValue::String(ref s) => { - Ok(s.clone().into_bytes()) - }, - AmlValue::BufferField(ref b) => { - let buf = b.source_buf.get_as_buffer(ctx)?; - let idx = b.index.get_as_integer(ctx)? as usize; - let len = b.length.get_as_integer(ctx)? as usize; - - if idx + len > buf.len() { - return Err(AmlError::AmlValueError); - } - - Ok(buf[idx .. idx + len].to_vec()) - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_buffer_field(&self, acpi_ctx: &AcpiContext) -> Result { - match *self { - AmlValue::BufferField(ref b) => Ok(b.clone()), - _ => { - let raw_buf = self.get_as_buffer(acpi_ctx)?; - let buf = Box::new(AmlValue::Buffer(raw_buf.clone())); - let idx = Box::new(AmlValue::IntegerConstant(0)); - let len = Box::new(AmlValue::Integer(raw_buf.len() as u64)); - - Ok(BufferField { - source_buf: buf, - index: idx, - length: len - }) - } - } - } - - pub fn get_as_ddb_handle(&self, acpi_ctx: &AcpiContext) -> Result<(Vec, SdtSignature), AmlError> { - match *self { - AmlValue::DDBHandle(ref v) => Ok(v.clone()), - AmlValue::Integer(i) => if let Some(sig) = acpi_ctx.get_signature_from_index(i as usize) { - Ok((vec!(), sig)) - } else { - log::error!("AmlValueError in get_as_ddb_handle integer"); - Err(AmlError::AmlValueError) - }, - _ => { log::error!("AmlValueError in get_as_ddb_handle other"); Err(AmlError::AmlValueError) } - } - } - - pub fn get_as_device(&self) -> Result { - match *self { - AmlValue::Device(ref s) => Ok(s.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_event(&self) -> Result { - match *self { - AmlValue::Event(ref e) => Ok(e.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_field_unit(&self) -> Result { - match *self { - AmlValue::FieldUnit(ref e) => Ok(e.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_integer(&self, acpi_ctx: &AcpiContext) -> Result { - match *self { - AmlValue::IntegerConstant(ref i) => Ok(i.clone()), - AmlValue::Integer(ref i) => Ok(i.clone()), - AmlValue::Buffer(ref b) => { - let mut b = b.clone(); - if b.len() > 8 { - return Err(AmlError::AmlValueError); - } - - let mut i: u64 = 0; - - while b.len() > 0 { - i <<= 8; - i += b.pop().expect("Won't happen") as u64; - } - - Ok(i) - }, - AmlValue::BufferField(_) => { - let mut b = self.get_as_buffer(acpi_ctx)?; - if b.len() > 8 { - return Err(AmlError::AmlValueError); - } - - let mut i: u64 = 0; - - while b.len() > 0 { - i <<= 8; - i += b.pop().expect("Won't happen") as u64; - } - - Ok(i) - }, - AmlValue::DDBHandle(ref v) => if let Some(idx) = acpi_ctx.get_index_from_signature(&v.1) { - Ok(idx as u64) - } else { - Err(AmlError::AmlValueError) - }, - AmlValue::String(ref s) => { - let s = s.clone()[0..8].to_string().to_uppercase(); - let mut i: u64 = 0; - - for c in s.chars() { - if !c.is_digit(16) { - break; - } - - i <<= 8; - i += c.to_digit(16).unwrap() as u64; - } - - Ok(i) - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_integer_constant(&self) -> Result { - match *self { - AmlValue::IntegerConstant(ref i) => Ok(i.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_method(&self) -> Result { - match *self { - AmlValue::Method(ref m) => Ok(m.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_mutex(&self) -> Result<(u8, Option), AmlError> { - match *self { - AmlValue::Mutex(ref m) => Ok(m.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_object_reference(&self) -> Result { - match *self { - AmlValue::ObjectReference(ref m) => Ok(m.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - /* - pub fn get_as_operation_region(&self) -> Result { - match *self { - AmlValue::OperationRegion(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } - */ - - pub fn get_as_package(&self) -> Result, AmlError> { - match *self { - AmlValue::Package(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_string(&self, ctx: &AcpiContext) -> Result { - match *self { - AmlValue::String(ref s) => Ok(s.clone()), - AmlValue::Integer(ref i) => Ok(format!("{:X}", i)), - AmlValue::IntegerConstant(ref i) => Ok(format!("{:X}", i)), - AmlValue::Buffer(ref b) => Ok(String::from_utf8(b.clone()).expect("Invalid UTF-8")), - AmlValue::BufferField(_) => { - let b = self.get_as_buffer(ctx)?; - Ok(String::from_utf8(b).expect("Invalid UTF-8")) - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_power_resource(&self) -> Result { - match *self { - AmlValue::PowerResource(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_processor(&self) -> Result { - match *self { - AmlValue::Processor(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_raw_data_buffer(&self) -> Result, AmlError> { - match *self { - AmlValue::RawDataBuffer(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_as_thermal_zone(&self) -> Result { - match *self { - AmlValue::ThermalZone(ref p) => Ok(p.clone()), - _ => Err(AmlError::AmlValueError) - } - } -} - -impl Method { - pub fn execute(&self, acpi_ctx: &AcpiContext, scope: String, parameters: Vec) -> AmlValue { - let mut ctx = AmlExecutionContext::new(acpi_ctx, scope); - ctx.init_arg_vars(parameters); - - let _ = parse_term_list(&self.term_list[..], &mut ctx); - ctx.clean_namespace(acpi_ctx); - - match ctx.state { - ExecutionState::RETURN(v) => v, - _ => AmlValue::IntegerConstant(0) - } - } -} - -pub fn get_namespace_string(ctx: &AcpiContext, current: String, modifier_v: AmlValue) -> Result { - let mut modifier = modifier_v.get_as_string(ctx)?; - - if current.len() == 0 { - return Ok(modifier); - } - - if modifier.len() == 0 { - return Ok(current); - } - - if modifier.starts_with("\\") { - return Ok(modifier); - } - - let mut namespace = current.clone(); - - if modifier.starts_with("^") { - while modifier.starts_with("^") { - modifier = modifier[1..].to_string(); - - if namespace.ends_with("\\") { - return Err(AmlError::AmlValueError); - } - - loop { - if namespace.ends_with(".") { - namespace.pop(); - break; - } - - if namespace.pop() == None { - return Err(AmlError::AmlValueError); - } - } - } - } - - if !namespace.ends_with("\\") { - namespace.push('.'); - } - - Ok(namespace + &modifier) -} diff --git a/acpid/src/aml/namespacemodifier.rs b/acpid/src/aml/namespacemodifier.rs deleted file mode 100644 index 3c3a31465c..0000000000 --- a/acpid/src/aml/namespacemodifier.rs +++ /dev/null @@ -1,106 +0,0 @@ -use super::AmlError; -use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; -use super::namespace::{AmlValue, get_namespace_string}; -use super::pkglength::parse_pkg_length; -use super::namestring::parse_name_string; -use super::termlist::parse_term_list; -use super::dataobj::parse_data_ref_obj; - -pub fn parse_namespace_modifier(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_alias_op, - parse_scope_op, - parse_name_op - }; - - Err(AmlError::AmlInvalidOpCode) -} - -fn parse_alias_op(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x06); - - let source_name = parse_name_string(&data[1..], ctx)?; - let alias_name = parse_name_string(&data[1 + source_name.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), source_name.val)?; - let local_alias_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), alias_name.val)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, AmlValue::Alias(local_alias_string))?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + source_name.len + alias_name.len - }) -} - -fn parse_name_op(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x08); - - let name = parse_name_string(&data[1..], ctx)?; - let data_ref_obj = parse_data_ref_obj(&data[1 + name.len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?; - - ctx.add_to_namespace(ctx.acpi_context(), local_scope_string, data_ref_obj.val)?; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + name.len + data_ref_obj.len - }) -} - -fn parse_scope_op(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x10); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - let name = parse_name_string(&data[1 + pkg_length_len..], ctx)?; - - let local_scope_string = get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val.clone())?; - let containing_scope_string = ctx.scope.clone(); - - ctx.scope = local_scope_string; - parse_term_list(&data[1 + pkg_length_len + name.len .. 1 + pkg_length], ctx)?; - ctx.scope = containing_scope_string; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + pkg_length - }) -} diff --git a/acpid/src/aml/namestring.rs b/acpid/src/aml/namestring.rs deleted file mode 100644 index dd3eb88a33..0000000000 --- a/acpid/src/aml/namestring.rs +++ /dev/null @@ -1,223 +0,0 @@ -use super::AmlError; -use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; -use super::namespace::AmlValue; -use super::dataobj::{parse_arg_obj, parse_local_obj}; -use super::type2opcode::parse_type6_opcode; - -pub fn parse_name_string(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let mut characters: Vec = vec!(); - let mut starting_index: usize = 0; - - if data[0] == 0x5C { - characters.push(data[0]); - starting_index = 1; - } else if data[0] == 0x5E { - while data[starting_index] == 0x5E { - characters.push(data[starting_index]); - starting_index += 1; - } - } - - let sel = |data| { - parser_selector_simple! { - data, - parse_dual_name_path, - parse_multi_name_path, - parse_null_name, - parse_name_seg - }; - - Err(AmlError::AmlInvalidOpCode) - }; - let (mut chr, len) = sel(&data[starting_index..])?; - characters.append(&mut chr); - - let name_string = String::from_utf8(characters); - - match name_string { - Ok(s) => Ok(AmlParseType { - val: AmlValue::String(s.clone()), - len: len + starting_index - }), - Err(_) => Err(AmlError::AmlParseError("Namestring - Name is invalid")) - } -} - -fn parse_null_name(data: &[u8]) -> Result<(Vec, usize), AmlError> { - parser_opcode!(data, 0x00); - Ok((vec!(), 1 )) -} - -pub fn parse_name_seg(data: &[u8]) -> Result<(Vec, usize), AmlError> { - match data[0] { - 0x41 ..= 0x5A | 0x5F => (), - _ => return Err(AmlError::AmlInvalidOpCode) - } - - match data[1] { - 0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (), - _ => return Err(AmlError::AmlInvalidOpCode) - } - - match data[2] { - 0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (), - _ => return Err(AmlError::AmlInvalidOpCode) - } - - match data[3] { - 0x30 ..= 0x39 | 0x41 ..= 0x5A | 0x5F => (), - _ => return Err(AmlError::AmlInvalidOpCode) - } - - let mut name_seg = vec!(data[0], data[1], data[2], data[3]); - while *(name_seg.last().unwrap()) == 0x5F { - name_seg.pop(); - } - - Ok((name_seg, 4)) -} - -fn parse_dual_name_path(data: &[u8]) -> Result<(Vec, usize), AmlError> { - parser_opcode!(data, 0x2E); - - let mut characters: Vec = vec!(); - let mut dual_len: usize = 1; - - match parse_name_seg(&data[1..5]) { - Ok((mut v, len)) => { - characters.append(&mut v); - dual_len += len; - }, - Err(e) => return Err(e) - } - - characters.push(0x2E); - - match parse_name_seg(&data[5..9]) { - Ok((mut v, len)) => { - characters.append(&mut v); - dual_len += len; - }, - Err(e) => return Err(e) - } - - Ok((characters, dual_len)) -} - -fn parse_multi_name_path(data: &[u8]) -> Result<(Vec, usize), AmlError> { - parser_opcode!(data, 0x2F); - - let seg_count = data[1]; - if seg_count == 0x00 { - return Err(AmlError::AmlParseError("MultiName Path - can't have zero name segments")); - } - - let mut current_seg = 0; - let mut characters: Vec = vec!(); - let mut multi_len: usize = 2; - - while current_seg < seg_count { - match parse_name_seg(&data[(current_seg as usize * 4) + 2 ..]) { - Ok((mut v, len)) => { - characters.append(&mut v); - multi_len += len; - }, - Err(e) => return Err(e) - } - - characters.push(0x2E); - - current_seg += 1; - } - - characters.pop(); - - Ok((characters, multi_len)) -} - -pub fn parse_super_name(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_simple_name, - parse_type6_opcode, - parse_debug_obj - }; - - Err(AmlError::AmlInvalidOpCode) -} - -fn parse_debug_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x31); - - Ok(AmlParseType { - val: AmlValue::DebugObject, - len: 2 - }) -} - -pub fn parse_simple_name(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_name_string, - parse_arg_obj, - parse_local_obj - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_target(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - if data[0] == 0x00 { - Ok(AmlParseType { - val: AmlValue::None, - len: 1 - }) - } else { - parse_super_name(data, ctx) - } -} diff --git a/acpid/src/aml/parser.rs b/acpid/src/aml/parser.rs deleted file mode 100644 index 3902453ebe..0000000000 --- a/acpid/src/aml/parser.rs +++ /dev/null @@ -1,557 +0,0 @@ -use std::collections::BTreeMap; - -use parking_lot::RwLockWriteGuard; - -use super::namespace::{AmlValue, ObjectReference}; -use super::AmlError; - -use crate::acpi::AcpiContext; - -pub type ParseResult = Result; -pub type AmlParseType = AmlParseTypeGeneric; - -#[derive(Debug)] -pub struct AmlParseTypeGeneric { - pub val: T, - pub len: usize -} - -pub enum ExecutionState { - EXECUTING, - CONTINUE, - BREAK, - RETURN(AmlValue) -} - -pub struct AmlExecutionContext<'a> { - pub scope: String, - pub local_vars: [AmlValue; 8], - pub arg_vars: [AmlValue; 8], - pub state: ExecutionState, - pub namespace_delta: Vec, - pub ctx_id: u64, - pub sync_level: u8, - - pub acpi_context: &'a AcpiContext, -} - -impl<'a> AmlExecutionContext<'a> { - pub fn new(acpi_context: &'a AcpiContext, scope: String) -> AmlExecutionContext<'_> { - let mut idptr = acpi_context.next_ctx.write(); - let id: u64 = *idptr; - - *idptr += 1; - - AmlExecutionContext { - scope, - local_vars: [AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized], - arg_vars: [AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized, - AmlValue::Uninitialized], - state: ExecutionState::EXECUTING, - namespace_delta: vec!(), - ctx_id: id, - sync_level: 0, - - acpi_context, - } - } - pub fn acpi_context(&self) -> &'a AcpiContext { - self.acpi_context - } - - pub fn wait_for_event(&mut self, ctx: &AcpiContext, event_ptr: AmlValue) -> Result { - let mut namespace_ptr = self.prelock(ctx); - let namespace = match *namespace_ptr { - Some(ref mut n) => n, - None => return Err(AmlError::AmlHardFatal) - }; - - let mutex_idx = match event_ptr { - AmlValue::String(ref s) => s.clone(), - AmlValue::ObjectReference(ref o) => match *o { - ObjectReference::Object(ref s) => s.clone(), - _ => return Err(AmlError::AmlValueError) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let mutex = match namespace.get(&mutex_idx) { - Some(s) => s.clone(), - None => return Err(AmlError::AmlValueError) - }; - - match mutex { - AmlValue::Event(count) => { - if count > 0 { - namespace.insert(mutex_idx, AmlValue::Event(count - 1)); - return Ok(true); - } - }, - _ => return Err(AmlError::AmlValueError) - } - - Ok(false) - } - - pub fn signal_event(&mut self, ctx: &AcpiContext, event_ptr: AmlValue) -> Result<(), AmlError> { - let mut namespace_ptr = self.prelock(ctx); - let namespace = match *namespace_ptr { - Some(ref mut n) => n, - None => return Err(AmlError::AmlHardFatal) - }; - - - let mutex_idx = match event_ptr { - AmlValue::String(ref s) => s.clone(), - AmlValue::ObjectReference(ref o) => match *o { - ObjectReference::Object(ref s) => s.clone(), - _ => return Err(AmlError::AmlValueError) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let mutex = match namespace.get(&mutex_idx) { - Some(s) => s.clone(), - None => return Err(AmlError::AmlValueError) - }; - - match mutex { - AmlValue::Event(count) => { - namespace.insert(mutex_idx, AmlValue::Event(count + 1)); - }, - _ => return Err(AmlError::AmlValueError) - } - - Ok(()) - } - - pub fn release_mutex(&mut self, ctx: &AcpiContext, mutex_ptr: AmlValue) -> Result<(), AmlError> { - let id = self.ctx_id; - - let mut namespace_ptr = self.prelock(ctx); - let namespace = match *namespace_ptr { - Some(ref mut n) => n, - None => return Err(AmlError::AmlHardFatal) - }; - - let mutex_idx = match mutex_ptr { - AmlValue::String(ref s) => s.clone(), - AmlValue::ObjectReference(ref o) => match *o { - ObjectReference::Object(ref s) => s.clone(), - _ => return Err(AmlError::AmlValueError) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let mutex = match namespace.get(&mutex_idx) { - Some(s) => s.clone(), - None => return Err(AmlError::AmlValueError) - }; - - match mutex { - AmlValue::Mutex((sync_level, owner)) => { - if let Some(o) = owner { - if o == id { - if sync_level == self.sync_level { - namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, None))); - return Ok(()); - } else { - return Err(AmlError::AmlValueError); - } - } else { - return Err(AmlError::AmlHardFatal); - } - } - }, - AmlValue::OperationRegion(ref region) => { - if let Some(o) = region.accessed_by { - if o == id { - let mut new_region = region.clone(); - new_region.accessed_by = None; - - namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region)); - return Ok(()); - } else { - return Err(AmlError::AmlHardFatal); - } - } - }, - _ => return Err(AmlError::AmlValueError) - } - - Ok(()) - } - - pub fn acquire_mutex(&mut self, ctx: &AcpiContext, mutex_ptr: AmlValue) -> Result { - let id = self.ctx_id; - - let mut namespace_ptr = self.prelock(ctx); - let namespace = match *namespace_ptr { - Some(ref mut n) => n, - None => return Err(AmlError::AmlHardFatal) - }; - let mutex_idx = match mutex_ptr { - AmlValue::String(ref s) => s.clone(), - AmlValue::ObjectReference(ref o) => match *o { - ObjectReference::Object(ref s) => s.clone(), - _ => return Err(AmlError::AmlValueError) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let mutex = match namespace.get(&mutex_idx) { - Some(s) => s.clone(), - None => return Err(AmlError::AmlValueError) - }; - - match mutex { - AmlValue::Mutex((sync_level, owner)) => { - if owner == None { - if sync_level < self.sync_level { - return Err(AmlError::AmlValueError); - } - - namespace.insert(mutex_idx, AmlValue::Mutex((sync_level, Some(id)))); - self.sync_level = sync_level; - - return Ok(true); - } - }, - AmlValue::OperationRegion(ref o) => { - if o.accessed_by == None { - let mut new_region = o.clone(); - new_region.accessed_by = Some(id); - - namespace.insert(mutex_idx, AmlValue::OperationRegion(new_region)); - return Ok(true); - } - }, - _ => return Err(AmlError::AmlValueError) - } - - Ok(false) - } - - pub fn add_to_namespace(&mut self, ctx: &AcpiContext, name: String, value: AmlValue) -> Result<(), AmlError> { - let mut namespace = ctx.namespace_mut(); - - if let Some(ref mut namespace) = *namespace { - if let Some(obj) = namespace.get(&name) { - match *obj { - AmlValue::Uninitialized => (), - AmlValue::Method(ref m) => { - if m.term_list.len() != 0 { - return Err(AmlError::AmlValueError); - } - }, - _ => return Err(AmlError::AmlValueError) - } - } - - self.namespace_delta.push(name.clone()); - namespace.insert(name, value); - - Ok(()) - } else { - Err(AmlError::AmlValueError) - } - } - - pub fn clean_namespace(&mut self, ctx: &AcpiContext) { - let mut namespace = ctx.namespace_mut(); - - if let Some(ref mut namespace) = *namespace { - for k in &self.namespace_delta { - namespace.remove(k); - } - } - } - - pub fn init_arg_vars(&mut self, parameters: Vec) { - if parameters.len() > 8 { - return; - } - - let mut cur = 0; - while cur < parameters.len() { - self.arg_vars[cur] = parameters[cur].clone(); - cur += 1; - } - } - - pub fn prelock<'ctx>(&mut self, ctx: &'ctx AcpiContext) -> RwLockWriteGuard<'ctx, Option>> { - ctx.namespace_mut() - } - - fn modify_local_obj(&mut self, ctx: &AcpiContext, local: usize, value: AmlValue) -> Result<(), AmlError> { - self.local_vars[local] = value.get_as_type(ctx, self.local_vars[local].clone())?; - Ok(()) - } - - fn modify_object(&mut self, ctx: &AcpiContext, name: String, value: AmlValue) -> Result<(), AmlError> { - if let Some(ref mut namespace) = *ctx.namespace_mut() { - let coercion_obj = { - let obj = namespace.get(&name); - - if let Some(o) = obj { - o.clone() - } else { - AmlValue::Uninitialized - } - }; - - namespace.insert(name, value.get_as_type(ctx, coercion_obj)?); - Ok(()) - } else { - Err(AmlError::AmlHardFatal) - } - } - - fn modify_index_final(&mut self, ctx: &AcpiContext, name: String, value: AmlValue, indices: Vec) -> Result<(), AmlError> { - if let Some(ref mut namespace) = *ctx.namespace_mut() { - let mut obj = if let Some(s) = namespace.get(&name) { - s.clone() - } else { - return Err(AmlError::AmlValueError); - }; - - obj = self.modify_index_core(ctx, obj, value, indices)?; - - namespace.insert(name, obj); - Ok(()) - } else { - Err(AmlError::AmlValueError) - } - } - - fn modify_index_core(&mut self, ctx: &AcpiContext, obj: AmlValue, value: AmlValue, indices: Vec) -> Result { - match obj { - AmlValue::String(ref string) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - let mut bytes = string.clone().into_bytes(); - bytes[indices[0] as usize] = value.get_as_integer(ctx)? as u8; - - let string = String::from_utf8(bytes).unwrap(); - - Ok(AmlValue::String(string)) - }, - AmlValue::Buffer(ref b) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - let mut b = b.clone(); - b[indices[0] as usize] = value.get_as_integer(ctx)? as u8; - - Ok(AmlValue::Buffer(b)) - }, - AmlValue::BufferField(ref b) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - let mut idx = indices[0]; - idx += b.index.get_as_integer(ctx)?; - - let _ = self.modify(ctx, AmlValue::ObjectReference(ObjectReference::Index(b.source_buf.clone(), Box::new(AmlValue::Integer(idx.clone())))), value); - - Ok(AmlValue::BufferField(b.clone())) - }, - AmlValue::Package(ref p) => { - if indices.len() == 0 { - return Err(AmlError::AmlValueError); - } - - let mut p = p.clone(); - - if indices.len() == 1 { - p[indices[0] as usize] = value; - } else { - p[indices[0] as usize] = self.modify_index_core(ctx, p[indices[0] as usize].clone(), value, indices[1..].to_vec())?; - } - - Ok(AmlValue::Package(p)) - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn modify_index(&mut self, ctx: &AcpiContext, name: AmlValue, value: AmlValue, indices: Vec) -> Result<(), AmlError>{ - match name { - AmlValue::ObjectReference(r) => match r { - ObjectReference::Object(s) => self.modify_index_final(ctx, s, value, indices), - ObjectReference::Index(c, v) => { - let mut indices = indices.clone(); - indices.push(v.get_as_integer(ctx)?); - - self.modify_index(ctx, *c, value, indices) - }, - ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), - ObjectReference::LocalObj(i) => { - let v = self.local_vars[i as usize].clone(); - self.local_vars[i as usize] = self.modify_index_core(ctx, v, value, indices)?; - - Ok(()) - } - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn modify(&mut self, ctx: &AcpiContext, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { - match name { - AmlValue::ObjectReference(r) => match r { - ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), - ObjectReference::LocalObj(i) => self.modify_local_obj(ctx, i as usize, value), - ObjectReference::Object(s) => self.modify_object(ctx, s, value), - ObjectReference::Index(c, v) => self.modify_index(ctx, *c, value, vec!(v.get_as_integer(ctx)?)) - }, - AmlValue::String(s) => self.modify_object(ctx, s, value), - _ => Err(AmlError::AmlValueError) - } - } - - fn copy_local_obj(&mut self, local: usize, value: AmlValue) -> Result<(), AmlError> { - self.local_vars[local] = value; - Ok(()) - } - - fn copy_object(&mut self, ctx: &AcpiContext, name: String, value: AmlValue) -> Result<(), AmlError> { - if let Some(ref mut namespace) = *ctx.namespace_mut() { - namespace.insert(name, value); - Ok(()) - } else { - Err(AmlError::AmlHardFatal) - } - } - - pub fn copy(&mut self, ctx: &AcpiContext, name: AmlValue, value: AmlValue) -> Result<(), AmlError> { - match name { - AmlValue::ObjectReference(r) => match r { - ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), - ObjectReference::LocalObj(i) => self.copy_local_obj(i as usize, value), - ObjectReference::Object(s) => self.copy_object(ctx, s, value), - ObjectReference::Index(c, v) => self.modify_index(ctx, *c, value, vec!(v.get_as_integer(ctx)?)) - }, - AmlValue::String(s) => self.copy_object(ctx, s, value), - _ => Err(AmlError::AmlValueError) - } - } - - fn get_index_final(&self, ctx: &AcpiContext, name: String, indices: Vec) -> Result { - if let Some(ref namespace) = *ctx.namespace() { - let obj = if let Some(s) = namespace.get(&name) { - s.clone() - } else { - return Err(AmlError::AmlValueError); - }; - - self.get_index_core(ctx, obj, indices) - } else { - Err(AmlError::AmlValueError) - } - } - - fn get_index_core(&self, ctx: &AcpiContext, obj: AmlValue, indices: Vec) -> Result { - match obj { - AmlValue::String(ref string) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - let bytes = string.clone().into_bytes(); - Ok(AmlValue::Integer(bytes[indices[0] as usize] as u64)) - }, - AmlValue::Buffer(ref b) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - Ok(AmlValue::Integer(b[indices[0] as usize] as u64)) - }, - AmlValue::BufferField(ref b) => { - if indices.len() != 1 { - return Err(AmlError::AmlValueError); - } - - let mut idx = indices[0]; - idx += b.index.get_as_integer(ctx)?; - - Ok(AmlValue::Integer(b.source_buf.get_as_buffer(ctx, )?[idx as usize] as u64)) - }, - AmlValue::Package(ref p) => { - if indices.len() == 0 { - return Err(AmlError::AmlValueError); - } - - if indices.len() == 1 { - Ok(p[indices[0] as usize].clone()) - } else { - self.get_index_core(ctx, p[indices[0] as usize].clone(), indices[1..].to_vec()) - } - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get_index(&self, ctx: &AcpiContext, name: AmlValue, indices: Vec) -> Result{ - match name { - AmlValue::ObjectReference(r) => match r { - ObjectReference::Object(s) => self.get_index_final(ctx, s, indices), - ObjectReference::Index(c, v) => { - let mut indices = indices.clone(); - indices.push(v.get_as_integer(ctx)?); - - self.get_index(ctx, *c, indices) - }, - ObjectReference::ArgObj(_) => Err(AmlError::AmlValueError), - ObjectReference::LocalObj(i) => { - let v = self.local_vars[i as usize].clone(); - self.get_index_core(ctx, v, indices) - } - }, - _ => Err(AmlError::AmlValueError) - } - } - - pub fn get(&self, ctx: &AcpiContext, name: AmlValue) -> Result { - Ok(match name { - AmlValue::ObjectReference(r) => match r { - ObjectReference::ArgObj(i) => self.arg_vars[i as usize].clone(), - ObjectReference::LocalObj(i) => self.local_vars[i as usize].clone(), - ObjectReference::Object(ref s) => if let Some(ref namespace) = *ctx.namespace() { - if let Some(o) = namespace.get(s) { - o.clone() - } else { - AmlValue::None - } - } else { AmlValue::None }, - ObjectReference::Index(c, v) => self.get_index(ctx, *c, vec!(v.get_as_integer(ctx)?))?, - }, - AmlValue::String(ref s) => if let Some(ref namespace) = *ctx.namespace() { - if let Some(o) = namespace.get(s) { - o.clone() - } else { - AmlValue::None - } - } else { AmlValue::None }, - _ => AmlValue::None - }) - } -} diff --git a/acpid/src/aml/parsermacros.rs b/acpid/src/aml/parsermacros.rs deleted file mode 100644 index 31a23386ff..0000000000 --- a/acpid/src/aml/parsermacros.rs +++ /dev/null @@ -1,52 +0,0 @@ -#[macro_export] -macro_rules! parser_selector { - {$data:expr, $ctx:expr, $func:expr} => { - match $func($data, $ctx) { - Ok(res) => return Ok(res), - Err(AmlError::AmlInvalidOpCode) => (), - Err(e) => return Err(e) - } - }; - {$data:expr, $ctx:expr, $func:expr, $($funcs:expr),+} => { - parser_selector! {$data, $ctx, $func}; - parser_selector! {$data, $ctx, $($funcs),*}; - }; -} - -#[macro_export] -macro_rules! parser_selector_simple { - {$data:expr, $func:expr} => { - match $func($data) { - Ok(res) => return Ok(res), - Err(AmlError::AmlInvalidOpCode) => (), - Err(e) => return Err(e) - } - }; - {$data:expr, $func:expr, $($funcs:expr),+} => { - parser_selector_simple! {$data, $func}; - parser_selector_simple! {$data, $($funcs),*}; - }; -} - -#[macro_export] -macro_rules! parser_opcode { - ($data:expr, $opcode:expr) => { - if $data[0] != $opcode { - return Err(AmlError::AmlInvalidOpCode); - } - }; - ($data:expr, $opcode:expr, $alternate_opcode:expr) => { - if $data[0] != $opcode && $data[0] != $alternate_opcode { - return Err(AmlError::AmlInvalidOpCode); - } - }; -} - -#[macro_export] -macro_rules! parser_opcode_extended { - ($data:expr, $opcode:expr) => { - if $data[0] != 0x5B || $data[1] != $opcode { - return Err(AmlError::AmlInvalidOpCode); - } - }; -} diff --git a/acpid/src/aml/pkglength.rs b/acpid/src/aml/pkglength.rs deleted file mode 100644 index 7b511f9b44..0000000000 --- a/acpid/src/aml/pkglength.rs +++ /dev/null @@ -1,25 +0,0 @@ -use super::AmlError; - -pub fn parse_pkg_length(data: &[u8]) -> Result<(usize, usize), AmlError> { - let lead_byte = data[0]; - let count_bytes: usize = (lead_byte >> 6) as usize; - - if count_bytes == 0 { - return Ok(((lead_byte & 0x3F) as usize, 1 as usize)); - } - - let upper_two = (lead_byte >> 4) & 0x03; - if upper_two != 0 { - return Err(AmlError::AmlParseError("Invalid package length")); - } - - let mut current_byte = 0; - let mut pkg_len: usize = (lead_byte & 0x0F) as usize; - - while current_byte < count_bytes { - pkg_len += (data[1 + current_byte] as u32 * 16 * (256 as u32).pow(current_byte as u32)) as usize; - current_byte += 1; - } - - Ok((pkg_len, count_bytes + 1)) -} diff --git a/acpid/src/aml/termlist.rs b/acpid/src/aml/termlist.rs deleted file mode 100644 index 036036f1eb..0000000000 --- a/acpid/src/aml/termlist.rs +++ /dev/null @@ -1,172 +0,0 @@ -use super::AmlError; -use super::parser::{ AmlParseType, ParseResult, AmlExecutionContext, ExecutionState }; -use super::namespace::{AmlValue, get_namespace_string}; -use super::namespacemodifier::parse_namespace_modifier; -use super::namedobj::parse_named_obj; -use super::dataobj::{parse_data_obj, parse_arg_obj, parse_local_obj}; -use super::type1opcode::parse_type1_opcode; -use super::type2opcode::parse_type2_opcode; -use super::namestring::parse_name_string; - -pub fn parse_term_list(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let mut current_offset: usize = 0; - - while current_offset < data.len() { - let res = parse_term_obj(&data[current_offset..], ctx)?; - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: data.len() - }) - } - - current_offset += res.len; - } - - Ok(AmlParseType { - val: AmlValue::None, - len: data.len() - }) -} - -pub fn parse_term_arg(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_local_obj, - parse_data_obj, - parse_arg_obj, - parse_type2_opcode - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_object_list(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let mut current_offset: usize = 0; - - while current_offset < data.len() { - let res = parse_object(&data[current_offset..], ctx)?; - - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: data.len() - }) - } - - current_offset += res.len; - } - - Ok(AmlParseType { - val: AmlValue::None, - len: data.len() - }) -} - -fn parse_object(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_namespace_modifier, - parse_named_obj - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_method_invocation(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let name = parse_name_string(data, ctx)?; - let method = ctx.get(ctx.acpi_context(), name.val.clone())?; - - let method = match method { - AmlValue::None => return Err(AmlError::AmlDeferredLoad), - _ => method.get_as_method()? - }; - - let mut cur = 0; - let mut params: Vec = vec!(); - - let mut current_offset = name.len; - - while cur < method.arg_count { - let res = parse_term_arg(&data[current_offset..], ctx)?; - - current_offset += res.len; - cur += 1; - - params.push(res.val); - } - - Ok(AmlParseType { - val: method.execute(ctx.acpi_context(), get_namespace_string(ctx.acpi_context(), ctx.scope.clone(), name.val)?, params), - len: current_offset - }) -} - -fn parse_term_obj(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_namespace_modifier, - parse_named_obj, - parse_type1_opcode, - parse_type2_opcode - }; - - Err(AmlError::AmlInvalidOpCode) -} diff --git a/acpid/src/aml/type1opcode.rs b/acpid/src/aml/type1opcode.rs deleted file mode 100644 index b89d939cb3..0000000000 --- a/acpid/src/aml/type1opcode.rs +++ /dev/null @@ -1,477 +0,0 @@ -use super::AmlError; -use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; -use super::namespace::AmlValue; -use super::pkglength::parse_pkg_length; -use super::termlist::{parse_term_arg, parse_term_list}; -use super::namestring::{parse_name_string, parse_super_name}; - -use crate::monotonic; - -use crate::acpi::PossibleAmlTables; -use super::parse_aml_table; - -pub fn parse_type1_opcode(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_def_break, - parse_def_breakpoint, - parse_def_continue, - parse_def_noop, - parse_def_fatal, - parse_def_if_else, - parse_def_load, - parse_def_notify, - parse_def_release, - parse_def_reset, - parse_def_signal, - parse_def_sleep, - parse_def_stall, - parse_def_return, - parse_def_unload, - parse_def_while - }; - - Err(AmlError::AmlInvalidOpCode) -} - -fn parse_def_break(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xA5); - ctx.state = ExecutionState::BREAK; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 as usize - }) -} - -fn parse_def_breakpoint(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xCC); - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 as usize - }) -} - -fn parse_def_continue(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x9F); - ctx.state = ExecutionState::CONTINUE; - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 as usize - }) -} - -fn parse_def_noop(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xA3); - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 as usize - }) -} - -fn parse_def_fatal(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x32); - - let fatal_type = data[2]; - let fatal_code: u16 = (data[3] as u16) + ((data[4] as u16) << 8); - let fatal_arg = parse_term_arg(&data[5..], ctx)?; - - Err(AmlError::AmlFatalError(fatal_type, fatal_code, fatal_arg.val)) -} - -fn parse_def_load(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x20); - - let name = parse_name_string(&data[2..], ctx)?; - let ddb_handle_object = parse_super_name(&data[2 + name.len..], ctx)?; - - let tbl = ctx.get(ctx.acpi_context(), name.val)?.get_as_buffer(ctx.acpi_context())?; - - let table = crate::acpi::Sdt::new(tbl.into()).map_err(|error| { - log::error!("Failed to parse def_load ACPI table: {}", error); - AmlError::AmlValueError - })?; - - if let Some(aml_sdt) = PossibleAmlTables::try_new(table.clone()) { - ctx.acpi_context().new_index(&table.signature()); - let delta = parse_aml_table(ctx.acpi_context(), aml_sdt)?; - let _ = ctx.modify(ctx.acpi_context(), ddb_handle_object.val, AmlValue::DDBHandle((delta, table.signature()))); - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + name.len + ddb_handle_object.len - }) - } else { - log::error!("Loaded table is not for AML"); - Err(AmlError::AmlValueError) - } -} - -fn parse_def_notify(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x86); - - let object = parse_super_name(&data[1..], ctx)?; - let value = parse_term_arg(&data[1 + object.len..], ctx)?; - - let number = value.val.get_as_integer(ctx.acpi_context())? as u8; - - match ctx.get(ctx.acpi_context(), object.val)? { - AmlValue::Device(d) => { - if let Some(methods) = d.notify_methods.get(&number) { - for method in methods { - method(); - } - } - }, - AmlValue::Processor(d) => { - if let Some(methods) = d.notify_methods.get(&number) { - for method in methods { - method(); - } - } - }, - AmlValue::ThermalZone(d) => { - if let Some(methods) = d.notify_methods.get(&number) { - for method in methods { - method(); - } - } - }, - _ => return Err(AmlError::AmlValueError) - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + object.len + value.len - }) -} - -fn parse_def_release(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x27); - - let obj = parse_super_name(&data[2..], ctx)?; - let _ = ctx.release_mutex(ctx.acpi_context(), obj.val); - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + obj.len - }) -} - -fn parse_def_reset(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x26); - - let object = parse_super_name(&data[2..], ctx)?; - ctx.get(ctx.acpi_context(), object.val.clone())?.get_as_event()?; - - let _ = ctx.modify(ctx.acpi_context(), object.val.clone(), AmlValue::Event(0)); - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + object.len - }) -} - -fn parse_def_signal(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x24); - let object = parse_super_name(&data[2..], ctx)?; - - ctx.signal_event(ctx.acpi_context(), object.val)?; - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + object.len - }) -} - -fn parse_def_sleep(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x22); - - let time = parse_term_arg(&data[2..], ctx)?; - let timeout = time.val.get_as_integer(ctx.acpi_context())?; - - let (seconds, nanoseconds) = monotonic(); - let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); - - loop { - let (seconds, nanoseconds) = monotonic(); - let current_time_ns = nanoseconds + (seconds * 1_000_000_000); - - if current_time_ns - starting_time_ns > timeout as u64 * 1_000_000 { - break; - } - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + time.len - }) -} - -fn parse_def_stall(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x21); - - let time = parse_term_arg(&data[2..], ctx)?; - let timeout = time.val.get_as_integer(ctx.acpi_context())?; - - let (seconds, nanoseconds) = monotonic(); - let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); - - loop { - let (seconds, nanoseconds) = monotonic(); - let current_time_ns = nanoseconds + (seconds * 1_000_000_000); - - if current_time_ns - starting_time_ns > timeout as u64 * 1000 { - break; - } - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + time.len - }) -} - -fn parse_def_unload(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x2A); - - let object = parse_super_name(&data[2..], ctx)?; - - let delta = ctx.get(ctx.acpi_context(), object.val)?.get_as_ddb_handle(ctx.acpi_context())?; - let mut namespace = ctx.prelock(ctx.acpi_context()); - - if let Some(ref mut ns) = *namespace { - for o in delta.0 { - ns.remove(&o); - } - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 2 + object.len - }) -} - -fn parse_def_if_else(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xA0); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - let if_condition = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?; - - let (else_length, else_length_len) = if data.len() > 1 + pkg_length && data[1 + pkg_length] == 0xA1 { - parse_pkg_length(&data[2 + pkg_length..])? - } else { - (0 as usize, 0 as usize) - }; - - if if_condition.val.get_as_integer(ctx.acpi_context())? > 0 { - parse_term_list(&data[1 + pkg_length_len + if_condition.len .. 1 + pkg_length], ctx)?; - } else if else_length > 0 { - parse_term_list(&data[2 + pkg_length + else_length_len .. 2 + pkg_length + else_length], ctx)?; - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + pkg_length + if else_length > 0 { 1 + else_length } else { 0 } - }) -} - -fn parse_def_while(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xA2); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - - loop { - let predicate = parse_term_arg(&data[1 + pkg_length_len..], ctx)?; - if predicate.val.get_as_integer(ctx.acpi_context())? == 0 { - break; - } - - parse_term_list(&data[1 + pkg_length_len + predicate.len .. 1 + pkg_length], ctx)?; - - match ctx.state { - ExecutionState::EXECUTING => (), - ExecutionState::BREAK => { - ctx.state = ExecutionState::EXECUTING; - break; - }, - ExecutionState::CONTINUE => ctx.state = ExecutionState::EXECUTING, - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - } - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + pkg_length - }) -} - -fn parse_def_return(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0xA4); - - let arg_object = parse_term_arg(&data[1..], ctx)?; - ctx.state = ExecutionState::RETURN(arg_object.val); - - Ok(AmlParseType { - val: AmlValue::None, - len: 1 + arg_object.len - }) -} diff --git a/acpid/src/aml/type2opcode.rs b/acpid/src/aml/type2opcode.rs deleted file mode 100644 index 60d02bb717..0000000000 --- a/acpid/src/aml/type2opcode.rs +++ /dev/null @@ -1,1784 +0,0 @@ -use std::convert::TryFrom; - -use super::{AmlError, parse_aml_with_scope}; -use super::parser::{AmlParseType, ParseResult, AmlExecutionContext, ExecutionState}; -use super::namespace::{AmlValue, ObjectReference}; -use super::pkglength::parse_pkg_length; -use super::termlist::{parse_term_arg, parse_method_invocation}; -use super::namestring::{parse_super_name, parse_target, parse_name_string, parse_simple_name}; -use super::dataobj::parse_data_ref_obj; - -use crate::monotonic; -use crate::acpi::{PossibleAmlTables, SdtSignature}; - -#[derive(Debug, Clone)] -pub enum MatchOpcode { - MTR, - MEQ, - MLE, - MLT, - MGE, - MGT -} - -pub fn parse_type2_opcode(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_def_increment, - parse_def_acquire, - parse_def_wait, - parse_def_land, - parse_def_lequal, - parse_def_lgreater, - parse_def_lless, - parse_def_lnot, - parse_def_lor, - parse_def_size_of, - parse_def_store, - parse_def_subtract, - parse_def_to_buffer, - parse_def_to_hex_string, - parse_def_to_bcd, - parse_def_to_decimal_string, - parse_def_to_integer, - parse_def_to_string, - parse_def_add, - parse_def_xor, - parse_def_shift_left, - parse_def_shift_right, - parse_def_mod, - parse_def_and, - parse_def_or, - parse_def_concat_res, - parse_def_concat, - parse_def_cond_ref_of, - parse_def_copy_object, - parse_def_decrement, - parse_def_divide, - parse_def_find_set_left_bit, - parse_def_find_set_right_bit, - parse_def_from_bcd, - parse_def_load_table, - parse_def_match, - parse_def_mid, - parse_def_multiply, - parse_def_nand, - parse_def_nor, - parse_def_not, - parse_def_timer, - parse_def_buffer, - parse_def_package, - parse_def_var_package, - parse_def_object_type, - parse_def_deref_of, - parse_def_ref_of, - parse_def_index, - parse_method_invocation - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_type6_opcode(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_selector! { - data, ctx, - parse_def_deref_of, - parse_def_ref_of, - parse_def_index, - parse_method_invocation - }; - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_def_object_type(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x8E); - parser_selector! { - data, ctx, - parse_super_name, - parse_def_ref_of, - parse_def_deref_of, - parse_def_index - } - - Err(AmlError::AmlInvalidOpCode) -} - -pub fn parse_def_package(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Handle deferred loads in here - parser_opcode!(data, 0x12); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - let numelements = data[1 + pkg_length_len] as usize; - let mut elements = parse_package_elements_list(&data[2 + pkg_length_len .. 1 + pkg_length], ctx)?.val.get_as_package()?; - - if elements.len() > numelements { - elements = elements[0 .. numelements].to_vec(); - } else if numelements > elements.len() { - for _ in 0..numelements - elements.len() { - elements.push(AmlValue::Uninitialized); - } - } - - Ok(AmlParseType { - val: AmlValue::Package(elements), - len: 1 + pkg_length - }) -} - -pub fn parse_def_var_package(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Handle deferred loads in here - parser_opcode!(data, 0x13); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - let num_elements = parse_term_arg(&data[1 + pkg_length_len .. 1 + pkg_length], ctx)?; - let mut elements = parse_package_elements_list(&data[1 + pkg_length_len + num_elements.len .. - 1 + pkg_length], ctx)?.val.get_as_package()?; - - let numelements = num_elements.val.get_as_integer(ctx.acpi_context())? as usize; - - if elements.len() > numelements { - elements = elements[0 .. numelements].to_vec(); - } else if numelements > elements.len() { - for _ in 0..numelements - elements.len() { - elements.push(AmlValue::Uninitialized); - } - } - - Ok(AmlParseType { - val: AmlValue::Package(elements), - len: 1 + pkg_length - }) -} - -fn parse_package_elements_list(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - let mut current_offset: usize = 0; - let mut elements: Vec = vec!(); - - while current_offset < data.len() { - let dro = if let Ok(e) = parse_data_ref_obj(&data[current_offset..], ctx) { - e - } else { - let d = parse_name_string(&data[current_offset..], ctx)?; - AmlParseType { - val: AmlValue::ObjectReference(ObjectReference::Object(d.val.get_as_string(ctx.acpi_context())?)), - len: d.len - } - }; - - elements.push(dro.val); - current_offset += dro.len; - } - - Ok(AmlParseType { - val: AmlValue::Package(elements), - len: data.len() - }) -} - -pub fn parse_def_buffer(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x11); - - let (pkg_length, pkg_length_len) = parse_pkg_length(&data[1..])?; - let buffer_size = parse_term_arg(&data[1 + pkg_length_len..], ctx)?; - let mut byte_list = data[1 + pkg_length_len + buffer_size.len .. 1 + pkg_length].to_vec().clone(); - - byte_list.truncate(buffer_size.val.get_as_integer(ctx.acpi_context())? as usize); - - Ok(AmlParseType { - val: AmlValue::Buffer(byte_list), - len: 1 + pkg_length - }) -} - -fn parse_def_ref_of(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x71); - - let obj = parse_super_name(&data[1..], ctx)?; - let res = match obj.val { - AmlValue::String(ref s) => { - match ctx.get(ctx.acpi_context(), AmlValue::String(s.clone()))? { - AmlValue::None => return Err(AmlError::AmlValueError), - _ => ObjectReference::Object(s.clone()) - } - }, - AmlValue::ObjectReference(ref o) => o.clone(), - _ => return Err(AmlError::AmlValueError) - }; - - Ok(AmlParseType { - val: AmlValue::ObjectReference(res), - len: 1 + obj.len - }) -} - -fn parse_def_deref_of(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x83); - - let obj = parse_term_arg(&data[1..], ctx)?; - let res = ctx.get(ctx.acpi_context(), obj.val)?; - - match res { - AmlValue::None => Err(AmlError::AmlValueError), - _ => Ok(AmlParseType { - val: res, - len: 1 + obj.len - }) - } -} - -fn parse_def_acquire(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x23); - - let obj = parse_super_name(&data[1..], ctx)?; - let timeout = (data[2 + obj.len] as u16) + ((data[3 + obj.len] as u16) << 8); - - let (seconds, nanoseconds) = monotonic(); - let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); - - loop { - match ctx.acquire_mutex(ctx.acpi_context(), obj.val.clone()) { - Err(e) => return Err(e), - Ok(b) => if b { - return Ok(AmlParseType { - val: AmlValue::Integer(0), - len: 4 + obj.len - }); - } else if timeout == 0xFFFF { - // TODO: How long should be sleep be? - let _ = syscall::sched_yield(); - } else { - let (seconds, nanoseconds) = monotonic(); - let current_time_ns = nanoseconds + (seconds * 1_000_000_000); - - if current_time_ns - starting_time_ns > timeout as u64 * 1_000_000 { - return Ok(AmlParseType { - val: AmlValue::Integer(1), - len: 4 + obj.len - }); - } - } - } - } -} - -fn parse_def_increment(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x75); - - let obj = parse_super_name(&data[1..], ctx)?; - - let _namespace = ctx.prelock(ctx.acpi_context()); - let value = AmlValue::Integer(ctx.get(ctx.acpi_context(), obj.val.clone())?.get_as_integer(ctx.acpi_context())? + 1); - let _ = ctx.modify(ctx.acpi_context(), obj.val, value.clone()); - - Ok(AmlParseType { - val: value, - len: 1 + obj.len - }) -} - -fn parse_def_index(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x88); - - let obj = parse_term_arg(&data[1..], ctx)?; - let idx = parse_term_arg(&data[1 + obj.len..], ctx)?; - let target = parse_target(&data[1 + obj.len + idx.len..], ctx)?; - - let reference = AmlValue::ObjectReference(ObjectReference::Index(Box::new(obj.val), Box::new(idx.val))); - let _ = ctx.modify(ctx.acpi_context(), target.val, reference.clone()); - - Ok(AmlParseType { - val: reference, - len: 1 + obj.len + idx.len + target.len - }) -} - -fn parse_def_land(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x90); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - - let result = if lhs.val.get_as_integer(ctx.acpi_context())? > 0 && rhs.val.get_as_integer(ctx.acpi_context())? > 0 { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + lhs.len + rhs.len - }) -} - -fn parse_def_lequal(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x93); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - - let result = if lhs.val.get_as_integer(ctx.acpi_context())? == rhs.val.get_as_integer(ctx.acpi_context())? { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + lhs.len + rhs.len - }) -} - -fn parse_def_lgreater(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x94); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - - let result = if lhs.val.get_as_integer(ctx.acpi_context())? > rhs.val.get_as_integer(ctx.acpi_context())? { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + lhs.len + rhs.len - }) -} - -fn parse_def_lless(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x95); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - - let result = if lhs.val.get_as_integer(ctx.acpi_context())? < rhs.val.get_as_integer(ctx.acpi_context())? { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + lhs.len + rhs.len - }) -} - -fn parse_def_lnot(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x92); - - let operand = parse_term_arg(&data[1..], ctx)?; - let result = if operand.val.get_as_integer(ctx.acpi_context())? == 0 { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + operand.len - }) -} - -fn parse_def_lor(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x91); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - - let result = if lhs.val.get_as_integer(ctx.acpi_context())? > 0 || rhs.val.get_as_integer(ctx.acpi_context())? > 0 { 1 } else { 0 }; - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(result), - len: 1 + lhs.len + rhs.len - }) -} - -fn parse_def_to_hex_string(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x98); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let res = match operand.val { - AmlValue::Integer(_) => { - let result: String = format!("{:X}", operand.val.get_as_integer(ctx.acpi_context())?); - AmlValue::String(result) - }, - AmlValue::String(s) => AmlValue::String(s), - AmlValue::Buffer(_) => { - let mut string: String = String::new(); - - for b in operand.val.get_as_buffer(ctx.acpi_context())? { - string.push_str(&format!("{:X}", b)); - } - - AmlValue::String(string) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let _ = ctx.modify(ctx.acpi_context(), target.val, res.clone()); - - Ok(AmlParseType { - val: res, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_to_buffer(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x96); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let res = AmlValue::Buffer(operand.val.get_as_buffer(ctx.acpi_context())?); - let _ = ctx.modify(ctx.acpi_context(), target.val, res.clone()); - - Ok(AmlParseType { - val: res, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_to_bcd(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x29); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let mut i = operand.val.get_as_integer(ctx.acpi_context())?; - let mut result = 0; - - while i != 0 { - result <<= 4; - result += i % 10; - i /= 10; - } - - let result = AmlValue::Integer(result); - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_to_decimal_string(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x97); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - let res = match operand.val { - AmlValue::Integer(_) => { - let result: String = format!("{}", operand.val.get_as_integer(ctx.acpi_context())?); - AmlValue::String(result) - }, - AmlValue::String(s) => AmlValue::String(s), - AmlValue::Buffer(_) => { - let mut string: String = String::new(); - - for b in operand.val.get_as_buffer(ctx.acpi_context())? { - string.push_str(&format!("{}", b)); - } - - AmlValue::String(string) - }, - _ => return Err(AmlError::AmlValueError) - }; - - let _ = ctx.modify(ctx.acpi_context(), target.val, res.clone()); - - Ok(AmlParseType { - val: res, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_to_integer(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x99); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let res = AmlValue::Integer(operand.val.get_as_integer(ctx.acpi_context())?); - - let _ = ctx.modify(ctx.acpi_context(), target.val, res.clone()); - - Ok(AmlParseType { - val: res, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_to_string(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x9C); - - let operand = parse_term_arg(&data[1..], ctx)?; - let length = parse_term_arg(&data[1 + operand.len..], ctx)?; - let target = parse_target(&data[1 + operand.len + length.len..], ctx)?; - - let buf = operand.val.get_as_buffer(ctx.acpi_context())?; - let mut string = match String::from_utf8(buf) { - Ok(s) => s, - Err(_) => return Err(AmlError::AmlValueError) - }; - - string.truncate(length.val.get_as_integer(ctx.acpi_context())? as usize); - let res = AmlValue::String(string); - - let _ = ctx.modify(ctx.acpi_context(), target.val, res.clone()); - - Ok(AmlParseType { - val: res, - len: 1 + operand.len + length.len + target.len - }) -} - -fn parse_def_subtract(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x74); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? - rhs.val.get_as_integer(ctx.acpi_context())?); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_size_of(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x87); - - let name = parse_super_name(&data[1..], ctx)?; - let obj = ctx.get(ctx.acpi_context(), name.val)?; - - let res = match obj { - AmlValue::Buffer(ref v) => v.len(), - AmlValue::String(ref s) => s.len(), - AmlValue::Package(ref p) => p.len(), - _ => return Err(AmlError::AmlValueError) - }; - - Ok(AmlParseType { - val: AmlValue::Integer(res as u64), - len: 1 + name.len - }) -} - -fn parse_def_store(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x70); - - let operand = parse_term_arg(&data[1..], ctx)?; - let target = parse_super_name(&data[1 + operand.len..], ctx)?; - - let _ = ctx.modify(ctx.acpi_context(), target.val.clone(), operand.val); - - Ok(AmlParseType { - val: target.val, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_or(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7D); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? | rhs.val.get_as_integer(ctx.acpi_context())?); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_shift_left(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x79); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? >> rhs.val.get_as_integer(ctx.acpi_context())?); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_shift_right(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7A); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? << rhs.val.get_as_integer(ctx.acpi_context())?); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_add(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x72); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? + rhs.val.get_as_integer(ctx.acpi_context())?); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_and(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7B); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? & rhs.val.get_as_integer(ctx.acpi_context())?); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_xor(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7F); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? ^ rhs.val.get_as_integer(ctx.acpi_context())?); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_concat_res(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x84); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let mut buf1 = lhs.val.get_as_buffer(ctx.acpi_context())?.clone(); - let mut buf2 = rhs.val.get_as_buffer(ctx.acpi_context())?.clone(); - - if buf1.len() == 1 || buf2.len() == 1 { - return Err(AmlError::AmlValueError); - } - - if buf1.len() >= 2 && buf1[buf1.len() - 2] == 0x79 { - buf1 = buf1[0..buf1.len() - 2].to_vec(); - } - - if buf2.len() >= 2 && buf2[buf2.len() - 2] == 0x79 { - buf2 = buf2[0..buf2.len() - 2].to_vec(); - } - - buf1.append(&mut buf2); - buf1.push(0x79); - - let mut checksum: u8 = 0; - let loopbuf = buf1.clone(); - for b in loopbuf { - checksum += b; - } - - checksum = (!checksum) + 1; - buf1.push(checksum); - - let res = AmlValue::Buffer(buf1); - ctx.modify(ctx.acpi_context(), target.val, res.clone())?; - - Ok(AmlParseType { - val: res, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_wait(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x25); - - let obj = parse_super_name(&data[2..], ctx)?; - let timeout_obj = parse_term_arg(&data[2 + obj.len..], ctx)?; - - let timeout = timeout_obj.val.get_as_integer(ctx.acpi_context())?; - - let (seconds, nanoseconds) = monotonic(); - let starting_time_ns = nanoseconds + (seconds * 1_000_000_000); - - loop { - match ctx.wait_for_event(ctx.acpi_context(), obj.val.clone()) { - Err(e) => return Err(e), - Ok(b) => if b { - return Ok(AmlParseType { - val: AmlValue::Integer(0), - len: 2 + obj.len + timeout_obj.len - }) - } else if timeout >= 0xFFFF { - let _ = syscall::sched_yield(); - } else { - let (seconds, nanoseconds) = crate::monotonic(); - let current_time_ns = nanoseconds + (seconds * 1_000_000_000); - - if current_time_ns - starting_time_ns > timeout as u64 * 1_000_000 { - return Ok(AmlParseType { - val: AmlValue::Integer(1), - len: 2 + obj.len + timeout_obj.len - }); - } - } - } - } -} - -fn parse_def_cond_ref_of(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x12); - - let obj = parse_super_name(&data[2..], ctx)?; - let target = parse_target(&data[2 + obj.len..], ctx)?; - - let res = match obj.val { - AmlValue::String(ref s) => { - match ctx.get(ctx.acpi_context(), AmlValue::String(s.clone()))? { - AmlValue::None => return Ok(AmlParseType { - val: AmlValue::Integer(0), - len: 1 + obj.len + target.len - }), - _ => ObjectReference::Object(s.clone()) - } - }, - AmlValue::ObjectReference(ref o) => o.clone(), - _ => return Err(AmlError::AmlValueError) - }; - - let _ = ctx.modify(ctx.acpi_context(), target.val, AmlValue::ObjectReference(res)); - - Ok(AmlParseType { - val: AmlValue::Integer(1), - len: 1 + obj.len + target.len - }) -} - -fn parse_def_copy_object(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Compute the result - // TODO: Store the result - parser_opcode!(data, 0x9D); - - let source = parse_term_arg(&data[1..], ctx)?; - let destination = parse_simple_name(&data[1 + source.len..], ctx)?; - - ctx.copy(ctx.acpi_context(), destination.val, source.val.clone())?; - - Ok(AmlParseType { - val: source.val, - len: 1 + source.len + destination.len - }) -} - -fn parse_def_concat(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x73); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = match lhs.val { - AmlValue::Integer(_i) => { - let j = AmlValue::Integer(rhs.val.get_as_integer(ctx.acpi_context())?); - - let mut first = lhs.val.get_as_buffer(ctx.acpi_context())?.clone(); - let mut second = j.get_as_buffer(ctx.acpi_context())?.clone(); - - first.append(&mut second); - - AmlValue::Buffer(first) - }, - AmlValue::String(s) => { - let t = if let Ok(t) = rhs.val.get_as_string(ctx.acpi_context()) { - t - } else { - rhs.val.get_type_string() - }; - - AmlValue::String(format!("{}{}", s, t)) - }, - AmlValue::Buffer(b) => { - let mut b = b.clone(); - let mut c = if let Ok(c) = rhs.val.get_as_buffer(ctx.acpi_context()) { - c.clone() - } else { - AmlValue::String(rhs.val.get_type_string()).get_as_buffer(ctx.acpi_context())?.clone() - }; - - b.append(&mut c); - - AmlValue::Buffer(b) - }, - _ => { - let first = lhs.val.get_type_string(); - let second = if let Ok(second) = rhs.val.get_as_string(ctx.acpi_context()) { - second - } else { - rhs.val.get_type_string() - }; - - AmlValue::String(format!("{}{}", first, second)) - } - }; - - ctx.modify(ctx.acpi_context(), target.val, result.clone())?; - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_decrement(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x76); - - let obj = parse_super_name(&data[1..], ctx)?; - - let _namespace = ctx.prelock(ctx.acpi_context()); - let value = AmlValue::Integer(ctx.get(ctx.acpi_context(), obj.val.clone())?.get_as_integer(ctx.acpi_context())? - 1); - let _ = ctx.modify(ctx.acpi_context(), obj.val, value.clone()); - - Ok(AmlParseType { - val: value, - len: 1 + obj.len - }) -} - -fn parse_def_divide(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x78); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target_remainder = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - let target_quotient = parse_target(&data[1 + lhs.len + rhs.len + target_remainder.len..], ctx)?; - - let numerator = lhs.val.get_as_integer(ctx.acpi_context())?; - let denominator = rhs.val.get_as_integer(ctx.acpi_context())?; - - let remainder = numerator % denominator; - let quotient = (numerator - remainder) / denominator; - - let _ = ctx.modify(ctx.acpi_context(), target_remainder.val, AmlValue::Integer(remainder)); - let _ = ctx.modify(ctx.acpi_context(), target_quotient.val, AmlValue::Integer(quotient)); - - Ok(AmlParseType { - val: AmlValue::Integer(quotient), - len: 1 + lhs.len + rhs.len + target_remainder.len + target_quotient.len - }) -} - -fn parse_def_find_set_left_bit(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x81); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let mut first_bit = 32; - let mut test = operand.val.get_as_integer(ctx.acpi_context())?; - - while first_bit > 0{ - if test & 0x8000_0000_0000_0000 > 0 { - break; - } - - test <<= 1; - first_bit -= 1; - } - - let result = AmlValue::Integer(first_bit); - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_find_set_right_bit(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x82); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let mut first_bit = 1; - let mut test = operand.val.get_as_integer(ctx.acpi_context())?; - - while first_bit <= 32 { - if test & 1 > 0 { - break; - } - - test >>= 1; - first_bit += 1; - } - - if first_bit == 33 { - first_bit = 0; - } - - let result = AmlValue::Integer(first_bit); - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_load_table(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Clean up - parser_opcode_extended!(data, 0x1F); - - let signature = parse_term_arg(&data[2..], ctx)?; - let oem_id = parse_term_arg(&data[2 + signature.len..], ctx)?; - let oem_table_id = parse_term_arg(&data[2 + signature.len + oem_id.len..], ctx)?; - let root_path = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len..], ctx)?; - let parameter_path = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len + root_path.len..], ctx)?; - let parameter_data = parse_term_arg(&data[2 + signature.len + oem_id.len + oem_table_id.len + root_path.len + parameter_path.len..], ctx)?; - - let signature = { - <[u8; 4]>::try_from(&*signature.val.get_as_string(ctx.acpi_context())?.as_bytes()) - .expect("expected 'load table' def to have a signature that is 4 bytes long") - }; - let oem_id = { - <[u8; 6]>::try_from(&*oem_id.val.get_as_string(ctx.acpi_context())?.as_bytes()) - .expect("expected 'load table' def to have an OEM ID that is 6 bytes long") - }; - let oem_table_id = { - <[u8; 8]>::try_from(&*oem_table_id.val.get_as_string(ctx.acpi_context())?.as_bytes()) - .expect("expected 'load table' def to have an OEM table ID that is 8 bytes long") - }; - - let sdt_signature = SdtSignature { - signature, - oem_id, - oem_table_id, - }; - - let parse_len = 2 + signature.len() + oem_id.len() + oem_table_id.len() + root_path.len + parameter_path.len + parameter_data.len; - - let sdt = ctx.acpi_context().sdt_from_signature(&sdt_signature); - - Ok(if let Some(sdt) = sdt.and_then(|sdt| PossibleAmlTables::try_new(sdt.clone())) { - let hdl = parse_aml_with_scope(ctx.acpi_context(), sdt, root_path.val.get_as_string(ctx.acpi_context())?)?; - let _ = ctx.modify(ctx.acpi_context(), parameter_path.val, parameter_data.val); - - AmlParseType { - val: AmlValue::DDBHandle((hdl, sdt_signature)), - len: parse_len, - } - } else { - AmlParseType { - val: AmlValue::IntegerConstant(0), - len: parse_len, - } - }) -} - -fn parse_def_match(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x28); - - let search_pkg = parse_term_arg(&data[1..], ctx)?; - - let first_operation = match data[1 + search_pkg.len] { - 0 => MatchOpcode::MTR, - 1 => MatchOpcode::MEQ, - 2 => MatchOpcode::MLE, - 3 => MatchOpcode::MLT, - 4 => MatchOpcode::MGE, - 5 => MatchOpcode::MGT, - _ => return Err(AmlError::AmlParseError("DefMatch - Invalid Opcode")) - }; - let first_operand = parse_term_arg(&data[2 + search_pkg.len..], ctx)?; - - let second_operation = match data[2 + search_pkg.len + first_operand.len] { - 0 => MatchOpcode::MTR, - 1 => MatchOpcode::MEQ, - 2 => MatchOpcode::MLE, - 3 => MatchOpcode::MLT, - 4 => MatchOpcode::MGE, - 5 => MatchOpcode::MGT, - _ => return Err(AmlError::AmlParseError("DefMatch - Invalid Opcode")) - }; - let second_operand = parse_term_arg(&data[3 + search_pkg.len + first_operand.len..], ctx)?; - - let start_index = parse_term_arg(&data[3 + search_pkg.len + first_operand.len + second_operand.len..], ctx)?; - - let pkg = search_pkg.val.get_as_package()?; - let mut idx = start_index.val.get_as_integer(ctx.acpi_context())? as usize; - - match first_operand.val { - AmlValue::Integer(i) => { - let j = second_operand.val.get_as_integer(ctx.acpi_context())?; - - while idx < pkg.len() { - let val = if let Ok(v) = pkg[idx].get_as_integer(ctx.acpi_context()) { v } else { idx += 1; continue; }; - idx += 1; - - match first_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != i { continue }, - MatchOpcode::MLE => if val > i { continue }, - MatchOpcode::MLT => if val >= i { continue }, - MatchOpcode::MGE => if val < i { continue }, - MatchOpcode::MGT => if val <= i { continue } - } - - match second_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != j { continue }, - MatchOpcode::MLE => if val > j { continue }, - MatchOpcode::MLT => if val >= j { continue }, - MatchOpcode::MGE => if val < j { continue }, - MatchOpcode::MGT => if val <= j { continue } - } - - return Ok(AmlParseType { - val: AmlValue::Integer(idx as u64), - len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len - }) - } - }, - AmlValue::String(i) => { - let j = second_operand.val.get_as_string(ctx.acpi_context())?; - - while idx < pkg.len() { - let val = if let Ok(v) = pkg[idx].get_as_string(ctx.acpi_context()) { v } else { idx += 1; continue; }; - idx += 1; - - match first_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != i { continue }, - MatchOpcode::MLE => if val > i { continue }, - MatchOpcode::MLT => if val >= i { continue }, - MatchOpcode::MGE => if val < i { continue }, - MatchOpcode::MGT => if val <= i { continue } - } - - match second_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != j { continue }, - MatchOpcode::MLE => if val > j { continue }, - MatchOpcode::MLT => if val >= j { continue }, - MatchOpcode::MGE => if val < j { continue }, - MatchOpcode::MGT => if val <= j { continue } - } - - return Ok(AmlParseType { - val: AmlValue::Integer(idx as u64), - len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len - }) - } - }, - _ => { - let i = first_operand.val.get_as_buffer(ctx.acpi_context())?; - let j = second_operand.val.get_as_buffer(ctx.acpi_context())?; - - while idx < pkg.len() { - let val = if let Ok(v) = pkg[idx].get_as_buffer(ctx.acpi_context()) { v } else { idx += 1; continue; }; - idx += 1; - - match first_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != i { continue }, - MatchOpcode::MLE => if val > i { continue }, - MatchOpcode::MLT => if val >= i { continue }, - MatchOpcode::MGE => if val < i { continue }, - MatchOpcode::MGT => if val <= i { continue } - } - - match second_operation { - MatchOpcode::MTR => (), - MatchOpcode::MEQ => if val != j { continue }, - MatchOpcode::MLE => if val > j { continue }, - MatchOpcode::MLT => if val >= j { continue }, - MatchOpcode::MGE => if val < j { continue }, - MatchOpcode::MGT => if val <= j { continue } - } - - return Ok(AmlParseType { - val: AmlValue::Integer(idx as u64), - len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len - }) - } - } - } - - Ok(AmlParseType { - val: AmlValue::IntegerConstant(0xFFFF_FFFF_FFFF_FFFF), - len: 3 + search_pkg.len + first_operand.len + second_operand.len + start_index.len - }) -} - -fn parse_def_from_bcd(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x28); - - let operand = parse_term_arg(&data[2..], ctx)?; - let target = parse_target(&data[2 + operand.len..], ctx)?; - - let mut i = operand.val.get_as_integer(ctx.acpi_context())?; - let mut result = 0; - - while i != 0 { - if i & 0x0F > 10 { - return Err(AmlError::AmlValueError); - } - - result *= 10; - result += i & 0x0F; - i >>= 4; - } - - let result = AmlValue::Integer(result); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 2 + operand.len + target.len - }) -} - -fn parse_def_mid(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x9E); - - let source = parse_term_arg(&data[1..], ctx)?; - let index = parse_term_arg(&data[1 + source.len..], ctx)?; - let length = parse_term_arg(&data[1 + source.len + index.len..], ctx)?; - let target = parse_target(&data[1 + source.len + index.len + length.len..], ctx)?; - - let idx = index.val.get_as_integer(ctx.acpi_context())? as usize; - let mut len = length.val.get_as_integer(ctx.acpi_context())? as usize; - - let result = match source.val { - AmlValue::String(s) => { - if idx > s.len() { - AmlValue::String(String::new()) - } else { - let mut res = s.clone().split_off(idx); - - if len < res.len() { - res.truncate(len); - } - - AmlValue::String(res) - } - }, - _ => { - // If it isn't a string already, treat it as a buffer. Must perform that check first, - // as Mid can operate on both strings and buffers, but a string can be cast as a buffer - // implicitly. - // Additionally, any type that can be converted to a buffer can also be converted to a - // string, so no information is lost - let b = source.val.get_as_buffer(ctx.acpi_context())?; - - if idx > b.len() { - AmlValue::Buffer(vec!()) - } else { - if idx + len > b.len() { - len = b.len() - idx; - } - - AmlValue::Buffer(b[idx .. idx + len].to_vec()) - } - } - }; - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + source.len + index.len + length.len + target.len - }) -} - -fn parse_def_mod(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x85); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - if rhs.val.get_as_integer(ctx.acpi_context())? == 0 { - return Err(AmlError::AmlValueError); - } - - let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? % rhs.val.get_as_integer(ctx.acpi_context())?); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_multiply(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - // TODO: Handle overflow - parser_opcode!(data, 0x77); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(lhs.val.get_as_integer(ctx.acpi_context())? * rhs.val.get_as_integer(ctx.acpi_context())?); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_nand(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7C); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(!(lhs.val.get_as_integer(ctx.acpi_context())? & rhs.val.get_as_integer(ctx.acpi_context())?)); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_nor(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x7E); - - let lhs = parse_term_arg(&data[1..], ctx)?; - let rhs = parse_term_arg(&data[1 + lhs.len..], ctx)?; - let target = parse_target(&data[1 + lhs.len + rhs.len..], ctx)?; - - let result = AmlValue::Integer(!(lhs.val.get_as_integer(ctx.acpi_context())? | rhs.val.get_as_integer(ctx.acpi_context())?)); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + lhs.len + rhs.len + target.len - }) -} - -fn parse_def_not(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode!(data, 0x80); - - let operand = parse_term_arg(&data[1..], ctx)?; - let target = parse_target(&data[1 + operand.len..], ctx)?; - - let result = AmlValue::Integer(!operand.val.get_as_integer(ctx.acpi_context())?); - - let _ = ctx.modify(ctx.acpi_context(), target.val, result.clone()); - - Ok(AmlParseType { - val: result, - len: 1 + operand.len + target.len - }) -} - -fn parse_def_timer(data: &[u8], - ctx: &mut AmlExecutionContext) -> ParseResult { - match ctx.state { - ExecutionState::EXECUTING => (), - _ => return Ok(AmlParseType { - val: AmlValue::None, - len: 0 - }) - } - - parser_opcode_extended!(data, 0x33); - - let (seconds, nanoseconds) = monotonic(); - let monotonic_ns = nanoseconds + (seconds * 1_000_000_000); - - Ok(AmlParseType { - val: AmlValue::Integer(monotonic_ns), - len: 2 as usize - }) -} diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 0247bb6fac..34bb3b0626 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -1,3 +1,5 @@ +#![feature(if_let_guard)] + use std::convert::TryFrom; use std::io::{self, prelude::*}; use std::fs::{File, OpenOptions}; @@ -13,11 +15,8 @@ use syscall::data::{Event, Packet}; use syscall::flag::{EventFlags, O_NONBLOCK}; mod acpi; -mod aml; mod scheme; -// TODO: Perhaps use the acpi and aml crates? - fn monotonic() -> (u64, u64) { use syscall::call::clock_gettime; use syscall::data::TimeSpec; @@ -38,8 +37,8 @@ fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() + .with_filter(log::LevelFilter::Warn) // limit global output to important info + // .with_ansi_escape_codes() .flush_on_newline(true) .build() ); @@ -48,9 +47,9 @@ fn setup_logging() -> Option<&'static RedoxLogger> { match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.log") { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Trace) + b.with_filter(log::LevelFilter::Warn) .flush_on_newline(true) - .with_ansi_escape_codes() + // .with_ansi_escape_codes() .build() ), Err(error) => eprintln!("Failed to create xhci.log: {}", error), @@ -59,8 +58,8 @@ fn setup_logging() -> Option<&'static RedoxLogger> { #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.ansi.log") { Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Trace) - .with_ansi_escape_codes() + b.with_filter(log::LevelFilter::Warn) + // .with_ansi_escape_codes() .flush_on_newline(true) .build() ), @@ -215,7 +214,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { drop(shutdown_pipe); drop(event_queue); - aml::set_global_s_state(&acpi_context, 5); + acpi_context.set_global_s_state(5); unreachable!("System should have shut down before this is entered"); } diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index 3aeafc41ec..788f7c92dd 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -1,38 +1,43 @@ use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; +use parking_lot::RwLockReadGuard; use syscall::data::Stat; -use syscall::error::{EBADF, EBADFD, EINVAL, EISDIR, ENOENT, ENOTDIR, EOVERFLOW}; +use syscall::error::{EIO, EBADF, EBADFD, EINVAL, EISDIR, ENOENT, ENOTDIR, EOVERFLOW}; use syscall::error::{Error, Result}; use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDONLY, O_STAT, O_SYMLINK}; use syscall::flag::{MODE_FILE, MODE_DIR, SEEK_CUR, SEEK_END, SEEK_SET}; use syscall::scheme::SchemeMut; -use crate::acpi::{AcpiContext, SdtSignature}; +use crate::acpi::{AcpiContext, SdtSignature, AmlSymbols}; pub struct AcpiScheme<'acpi> { ctx: &'acpi AcpiContext, - handles: BTreeMap, + handles: BTreeMap>, next_fd: usize, } -struct Handle { +struct Handle<'a> { offset: usize, - kind: HandleKind, + kind: HandleKind<'a>, stat: bool, } -enum HandleKind { +enum HandleKind<'a> { TopLevel, Tables, Table(SdtSignature), + Symbols(RwLockReadGuard<'a, Option>), + Symbol(aml::AmlName), } -impl HandleKind { +impl HandleKind<'_> { fn is_dir(&self) -> bool { match self { Self::TopLevel => true, Self::Tables => true, Self::Table(_) => false, + Self::Symbols(_) => true, + Self::Symbol(_) => false, } } fn len(&self, acpi_ctx: &AcpiContext) -> Result { @@ -40,6 +45,13 @@ impl HandleKind { Self::TopLevel => TOPLEVEL_CONTENTS.len(), Self::Tables => acpi_ctx.tables().len().checked_mul(TABLE_DENTRY_LENGTH).unwrap_or(usize::max_value()), Self::Table(signature) => acpi_ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.length(), + Self::Symbols(symbols_option) => { + match symbols_option.as_ref() { + Some(symbols) => symbols.symbols_str.len(), + _ => 0, + } + }, + Self::Symbol(_) => 0, }) } } @@ -54,7 +66,7 @@ impl<'acpi> AcpiScheme<'acpi> { } } -const TOPLEVEL_CONTENTS: &[u8] = b"tables\n"; +const TOPLEVEL_CONTENTS: &[u8] = b"tables\nsymbols\n"; const TABLE_DENTRY_LENGTH: usize = 35; @@ -147,6 +159,20 @@ impl SchemeMut for AcpiScheme<'_> { HandleKind::Table(signature) } + ["symbols"] => if let Ok(symbols_option) = self.ctx.aml_symbols() { + HandleKind::Symbols(symbols_option) + } else { + return Err(Error::new(EIO)) + }, + + ["symbols", symbol] => { + if let Some(symbol) = self.ctx.aml_lookup(symbol) { + HandleKind::Symbol(symbol) + } else { + return Err(Error::new(ENOENT)); + } + } + _ => return Err(Error::new(ENOENT)), }; @@ -177,7 +203,7 @@ impl SchemeMut for AcpiScheme<'_> { } fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - + stat.st_size = handle.kind.len(self.ctx)?.try_into().unwrap_or(u64::max_value()); if handle.kind.is_dir() { @@ -223,7 +249,7 @@ impl SchemeMut for AcpiScheme<'_> { return Err(Error::new(EBADF)); } - let src_buf = match handle.kind { + let src_buf = match &handle.kind { HandleKind::TopLevel => TOPLEVEL_CONTENTS, HandleKind::Table(ref signature) => self.ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.as_slice(), @@ -264,6 +290,26 @@ impl SchemeMut for AcpiScheme<'_> { return Ok(bytes_written); } + + HandleKind::Symbols(symbols_option) => { + match symbols_option.as_ref() { + Some(symbols) => { + let offset = std::cmp::min(symbols.symbols_str.len(), handle.offset); + let src_buf = &symbols.symbols_str.as_bytes()[offset..]; + + let to_copy = std::cmp::min(src_buf.len(), buf.len()); + buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); + + handle.offset = handle.offset.checked_add(to_copy).ok_or(Error::new(EOVERFLOW))?; + + return Ok(to_copy); + } + _ => return Err(Error::new(EIO)), + } + } + + HandleKind::Symbol(_) => b"", + }; let offset = std::cmp::min(src_buf.len(), handle.offset); @@ -272,7 +318,7 @@ impl SchemeMut for AcpiScheme<'_> { let to_copy = std::cmp::min(src_buf.len(), buf.len()); buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); - handle.offset += to_copy; + handle.offset = handle.offset.checked_add(to_copy).ok_or(Error::new(EOVERFLOW))?; Ok(to_copy) } From 9c739d7648f458172ffcb720bc5f17d54353ca2e Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Sat, 28 Jan 2023 22:47:28 -0800 Subject: [PATCH 0590/1301] Add description text in toml format for each symbol in acpi:/symbols --- Cargo.lock | 85 ++++++++++- acpid/src/acpi.rs | 346 ++++++++++++++++++++++++++++---------------- acpid/src/scheme.rs | 43 +++--- 3 files changed, 318 insertions(+), 156 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f3bbc00687..c139b3d136 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,7 @@ dependencies = [ name = "acpid" version = "0.1.0" dependencies = [ + "aml", "log", "num-derive", "num-traits", @@ -27,6 +28,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_syscall 0.3.4", + "rustc-hash", "thiserror", ] @@ -55,6 +57,19 @@ dependencies = [ "redox_syscall 0.3.4", ] +[[package]] +name = "aml" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7450aaee7581251d456c0f283f4c3db13b09a95054572ae77b6d22f77216caf" +dependencies = [ + "bit_field", + "bitvec", + "byteorder 1.4.3", + "log", + "spinning_top", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -134,12 +149,30 @@ dependencies = [ "serde", ] +[[package]] +name = "bit_field" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" + [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "block-io-wrapper" version = "0.1.0" @@ -336,6 +369,12 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + [[package]] name = "futures" version = "0.3.21" @@ -560,9 +599,8 @@ checksum = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" [[package]] name = "libc" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +version = "0.2.137" +source = "git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=rust-2022-03-18#6ba4d1a527c2b53bdd5554cb219a1cd7d315d518" [[package]] name = "linked-hash-map" @@ -966,6 +1004,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + [[package]] name = "rand" version = "0.4.6" @@ -1194,6 +1238,12 @@ dependencies = [ "redox_syscall 0.3.4", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rusttype" version = "0.2.4" @@ -1342,6 +1392,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spinning_top" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c" +dependencies = [ + "lock_api", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -1408,6 +1467,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "termion" version = "1.5.6" @@ -1744,6 +1809,15 @@ dependencies = [ "winapi-build", ] +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + [[package]] name = "xhcid" version = "0.1.0" @@ -1766,8 +1840,3 @@ dependencies = [ "thiserror", "toml", ] - -[[patch.unused]] -name = "libc" -version = "0.2.137" -source = "git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=rust-2022-03-18#6ba4d1a527c2b53bdd5554cb219a1cd7d315d518" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index b8879f1262..5c9e074d55 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,8 +1,9 @@ -use rustc_hash::FxHashSet; +use rustc_hash::FxHashMap; use std::convert::{TryFrom, TryInto}; use std::ops::Deref; use std::sync::Arc; use std::{fmt, mem}; +use std::fmt::Write; use syscall::flag::PhysmapFlags; @@ -12,7 +13,7 @@ use syscall::io::{Io, Pio}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use thiserror::Error; -use aml::{AmlContext, AmlName}; +use aml::{AmlContext, AmlName, AmlHandle, AmlValue}; pub mod dmar; use self::dmar::Dmar; @@ -229,9 +230,147 @@ pub enum SymbolListError { AmlInternalError, } +// Current AML implementation builds the aml_context.namespace at startup, +// but the cache for symbols is lazy-loaded when someone +// reads from the acpi:/symbols scheme. +// If you dynamically add an SDT, you can add to the namespace, but you +// must empty the cache so it is rebuilt. +// If you modify an SDT, you must discard the aml_context and rebuild it. pub struct AmlSymbols { + aml_context: AmlContext, + // k = name, v = description + symbols_cache: FxHashMap, pub symbols_str: String, - symbols_hash: FxHashSet, +} + +impl AmlSymbols { + pub fn to_str(&self) -> &str { + &self.symbols_str + } + + /// Format a value as toml, to use as file contents + pub fn format_value(name: &str, value: &AmlValue, handle_lookup: &AmlHandleLookup) -> String { + let mut value_str = String::with_capacity(256); + let _ = write!(value_str, "[symbol]\nname = \"{}\"\n\n[value]\n", name); + let _ = match value { + AmlValue::Integer(n) => + write!(value_str, "type = \"Integer\"\nvalue = \"{:#x}\"\n", n), + AmlValue::String(s) => + write!(value_str, "type = \"String\"\nvalue = \"{}\"\n", s), + AmlValue::Processor { id, pblk_address, pblk_len } => + write!(value_str, "type = \"Processor\"\nid = \"{}\"\npblk_address = \"{}\"\npblk_len = \"{}\"\n", + id, pblk_address, pblk_len), + AmlValue::Method { flags, code } => + write!(value_str, "type = \"Method\"\nflags = \"{:?}\"\ncode = {}\n", flags, AmlSymbols::code_as_string(code)), + AmlValue::OpRegion { region, offset, length, parent_device } => + write!(value_str, "type = \"OpRegion\"\nregion = \"{:?}\"\noffset = \"{:#x}\"\nlength = \"{:#x}\"\ndevice = \"{}\"\n", + region, offset, length, AmlSymbols::device_option_as_string(parent_device)), + AmlValue::Field { region, flags, offset, length } => + write!(value_str, "type = \"Field\"\nregion = \"{}\"\nflags = \"{:?}\"\noffset = \"{:#x}\"\nlength = \"{:#x}\"\n", + handle_lookup.get_as_str(region), flags, offset, length), + AmlValue::Package(contents) => + write!(value_str, "type = \"Package\"\ncontents = {}\n", + AmlSymbols::contents_as_string(contents)), + AmlValue::Device => write!(value_str, "type = \"Device\"\n"), + AmlValue::Buffer(_) => write!(value_str, "type = \"Buffer\"\n"), + other => + write!(value_str, "type = \"Other\"\ndebug = \"{:.64?}\"\n", other), + }; + + value_str.shrink_to_fit(); + value_str + } + + fn device_option_as_string(device: &Option) -> String { + if let Some(name) = device { + format!("\"{}\"", AmlSymbols::pretty_name(name)) + } else { + "\"None\"".to_string() + } + } + + fn code_as_string(code: &aml::value::MethodCode) -> String { + match code { + aml::value::MethodCode::Aml(bytes) => + if bytes.len() > 15 { + format!("\"AML({:x?}...)\"", &bytes[..15]) + } else { + format!("\"AML({:x?})\"", bytes) + }, + aml::value::MethodCode::Native(_) => format!("(native method)"), + } + } + + fn contents_as_string(contents: &Vec) -> String { + let mut buf = String::with_capacity(128); + let _ = write!(buf, "[ "); + for value in contents { + match value { + AmlValue::Integer(n) => { let _ = write!(buf, "{:x}, ", n); }, + AmlValue::String(s) => { let _ = write!(buf, "\"{}\",", s); } + _ => { let _ = write!(buf, "{:?}", value); }, + } + if buf.len() > 58 { + let _ = write!(buf, "..."); + break; + } + } + let _ = write!(buf, "]"); + buf + } + + /// Remove trailing underscores from each name segment + pub fn pretty_name(level_aml_name: &AmlName) -> String { + let mut name = level_aml_name.as_string(); + // remove unnecessary underscores + while let Some(index) = name.find("_.") { + name.remove(index); + } + while name.len() > 0 && &name[name.len() - 1..] == "_" { + name.pop(); + } + name.shrink_to_fit(); + name + } + + pub fn child_symbol(level_name: &str, value_name: &str) -> String { + format!("{}.{}", level_name, value_name.trim_end_matches('_')) + } + + pub fn root_symbol(value_name: &str) -> String { + format!("\\{}", value_name.trim_end_matches('_')) + } + +} + +pub struct AmlHandleLookup { + map: FxHashMap, +} + +impl AmlHandleLookup { + pub fn new() -> Self { + Self { map: FxHashMap::default() } + } + + fn handle_to_key(&self, handle: &AmlHandle) -> String { + format!("{:?}", handle) + } + + pub fn insert(&mut self, handle: &AmlHandle, name: &String) { + self.map.insert(self.handle_to_key(handle), name.to_owned()); + } + + pub fn get(&self, handle: &AmlHandle) -> Option<&String> { + self.map.get(&self.handle_to_key(handle)) + } + + pub fn get_as_str(&self, handle: &AmlHandle) -> &str { + if let Some(name) = self.get(handle) { + &name[..] + } else { + "Unrecognized" + } + } } pub struct AcpiContext { @@ -239,12 +378,7 @@ pub struct AcpiContext { dsdt: Option, fadt: Option, - // the aml parser - aml_context: RwLock, - - // Use to cache the symbols list, which doesn't change very often - // Set it to None if the ACPI tables change e.g. due to PnP - aml_symbols: RwLock>, + aml_symbols: RwLock, // TODO: The kernel ACPI code seemed to use load_table quite ubiquitously, however ACPI 5.1 // states that DDBHandles can only be obtained when loading XSDT-pointed tables. So, we'll @@ -273,8 +407,12 @@ impl AcpiContext { dsdt: None, fadt: None, - aml_context: RwLock::new(AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None)), - aml_symbols: RwLock::new(None), + // Temporary values + aml_symbols: RwLock::new(AmlSymbols { + aml_context: AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None), + symbols_cache: FxHashMap::default(), + symbols_str: "".to_string(), + }), next_ctx: RwLock::new(0), @@ -287,32 +425,36 @@ impl AcpiContext { Fadt::init(&mut this); //TODO (hangs on real hardware): Dmar::init(&this); + - if let Some(mut parser) = this.aml_context.try_write() { - if let Some(dsdt) = this.dsdt() { - match parser.parse_table(dsdt.aml()) { - Ok(_) => log::trace!("Parsed DSDT"), - Err(e) => { - log::error!("DSDT: {:?}", e); - } - } - } else { - log::error!("No DSDT for aml parsing"); - } + this.aml_symbols.write().aml_context = AcpiContext::build_aml_context(&this); - for ssdt in this.ssdts() { - match parser.parse_table(ssdt.aml()) { - Ok(_) => log::trace!("Parsed SSDT"), - Err(e) => { - log::error!("SSDT: {:?}", e); - } + this + } + + fn build_aml_context(acpi: &AcpiContext) -> AmlContext { + let mut aml_context = AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None); + + if let Some(dsdt) = acpi.dsdt() { + match aml_context.parse_table(dsdt.aml()) { + Ok(_) => log::trace!("Parsed DSDT"), + Err(e) => { + log::error!("DSDT: {:?}", e); } } } else { - log::error!("Failed to obtain aml_context"); + log::error!("No DSDT for aml parsing"); } - this + for ssdt in acpi.ssdts() { + match aml_context.parse_table(ssdt.aml()) { + Ok(_) => log::trace!("Parsed SSDT"), + Err(e) => { + log::error!("SSDT: {:?}", e); + } + } + } + aml_context } pub fn dsdt(&self) -> Option<&Dsdt> { @@ -354,77 +496,22 @@ impl AcpiContext { pub fn new_index(&self, signature: &SdtSignature) { self.sdt_order.write().push(Some(*signature)); } - fn aml_context(&self) -> RwLockReadGuard<'_, AmlContext>{ - self.aml_context.read() - } - fn aml_context_mut(&self) -> RwLockWriteGuard<'_, AmlContext> { - self.aml_context.write() - } - pub fn aml_lookup(&self, symbol: &str) -> Option { - let aml_name = match AmlName::from_str(symbol) { - Ok(aml_name) => aml_name, - Err(error) => { - log::error!("Lookup failed to convert name to AmlName {}, {:?}", symbol, error); - return None; - } - }; - // Check the cache first - if let Ok(symbols_option) = self.aml_symbols() { - if let Some(symbols) = symbols_option.as_ref() { - if symbols.symbols_hash.contains(symbol) { - log::trace!("Found symbol in cache, {}", symbol); - return Some(aml_name); - } + pub fn aml_lookup(&self, symbol: &str) -> Option { + if let Ok(aml_symbols) = self.aml_symbols() { + if let Some(description) = aml_symbols.symbols_cache.get(symbol) { + log::trace!("Found symbol in cache, {}, {}", symbol, description); + return Some(description.to_owned()); } } - - // Symbol does not exactly match cache, allow lookup using namespace rules - let aml_ctx = self.aml_context(); - let root = aml::AmlName::root(); - if aml_ctx.namespace.get_by_path(&aml_name).is_ok() - || aml_ctx.namespace.search_for_level(&aml_name, &root).is_ok() - { - Some(aml_name) - } else { - log::trace!("Lookup did not find {}", aml_name); - None - } + None } - pub fn aml_symbols(&self) -> Result>, SymbolListError> { - // Some private functions for building the symbol name correctly and efficiently - fn level_name(level_aml_name: &aml::AmlName) -> String { - let mut name = level_aml_name.as_string(); - // remove unnecessary underscores - while let Some(index) = name.find("_.") { - name.remove(index); - } - while name.len() > 0 && &name[name.len() - 1..] == "_" { - name.pop(); - } - name.shrink_to_fit(); - name - } - fn child_symbol(level_name: &str, value_name: &str) -> String { - let mut name = String::with_capacity(level_name.len() + 1 + value_name.len()); - name.push_str(level_name); - name.push('.'); - name.push_str(value_name.trim_end_matches('_')); - name.shrink_to_fit(); - name - } - fn root_symbol(value_name: &str) -> String { - let mut name = String::with_capacity(1 + value_name.len()); - name.push('\\'); - name.push_str(value_name.trim_end_matches('_')); - name.shrink_to_fit(); - name - } - + pub fn aml_symbols(&self) -> Result, SymbolListError> { + // return the cached value if it exists let symbols = self.aml_symbols.read(); - if symbols.is_some() { + if !symbols.symbols_cache.is_empty() { return Ok(symbols); } // free the read lock @@ -435,28 +522,28 @@ impl AcpiContext { let mut symbols_str: String = String::with_capacity(30000); - let mut symbols_hash: FxHashSet = FxHashSet::default(); + let mut symbols_list: Vec<(String, AmlHandle)> = Vec::with_capacity(3000); - // Get write lock because traverse requires mut - let mut aml_ctx = self.aml_context_mut(); + let mut aml_symbols = self.aml_symbols.write(); let root = aml::AmlName::root(); - let traverse = aml_ctx.namespace.traverse(| level_aml_name, level | { - let level_is_root = level_aml_name.eq(&root); - let level_name = level_name(level_aml_name); - for (name, _handle) in level.values.iter() { - // Create the name of the symbol as "\levelname.symbolname" - let symbol = if level_is_root { - root_symbol(name.as_str()) - } else { - child_symbol(&level_name, name.as_str()) - }; - symbols_str.push_str(&symbol); - symbols_str.push('\n'); - symbols_hash.insert(symbol); - } - Ok(true) - }); + let traverse = aml_symbols.aml_context.namespace + .traverse(| level_aml_name, level | { + let level_is_root = level_aml_name.eq(&root); + let level_name = AmlSymbols::pretty_name(level_aml_name); + for (name, handle) in level.values.iter() { + // Create the name of the symbol as "\levelname.symbolname" + let symbol = if level_is_root { + AmlSymbols::root_symbol(name.as_str()) + } else { + AmlSymbols::child_symbol(&level_name, name.as_str()) + }; + symbols_str.push_str(&symbol); + symbols_str.push('\n'); + symbols_list.push((symbol, handle.to_owned())); + } + Ok(true) + }); match traverse { Err(error) => { @@ -465,25 +552,40 @@ impl AcpiContext { } _ => {} } + + let mut handle_lookup = AmlHandleLookup::new(); + + for (name, handle) in &symbols_list { + handle_lookup.insert(handle, name); + } + let namespace = &aml_symbols.aml_context.namespace; + + let mut symbols_cache: FxHashMap = FxHashMap::default(); + + for (name, handle) in symbols_list { + if let Ok(value) = namespace.get(handle.to_owned()) { + symbols_cache.insert(name.to_owned(), AmlSymbols::format_value(&name, value, &handle_lookup)); + } + } + symbols_str.shrink_to_fit(); // Cache the new list log::trace!("Updating symbols list"); - let mut write_guarded_symbols = self.aml_symbols.write(); - *write_guarded_symbols = Some(AmlSymbols { symbols_str, symbols_hash }); + aml_symbols.symbols_str = symbols_str; + aml_symbols.symbols_cache = symbols_cache; // return the cached value - Ok(RwLockWriteGuard::downgrade(write_guarded_symbols)) + Ok(RwLockWriteGuard::downgrade(aml_symbols)) } /// Discard any cached symbols list. To be called if the AML namespace changes. - /// The caller must have at least a Read Lock on the aml context to ensure - /// the cached list is not out of sync with the namespace. pub fn aml_symbols_reset(&self) { - let mut symbols = self.aml_symbols.write(); - *symbols = None; + let mut aml_symbols = self.aml_symbols.write(); + aml_symbols.symbols_cache = FxHashMap::default(); + aml_symbols.symbols_str = "".to_string(); } /// Set Power State @@ -505,14 +607,14 @@ impl AcpiContext { let port = fadt.pm1a_control_block as u16; let mut val = 1 << 13; - let aml_ctx = self.aml_context(); + let aml_symbols = self.aml_symbols.read(); let s5_aml_name = match aml::AmlName::from_str("\\_S5") { Ok(aml_name) => aml_name, Err(error) => { log::error!("Could not build AmlName for \\_S5, {:?}", error); return; } }; - let s5 = match aml_ctx.namespace.get_by_path(&s5_aml_name) { + let s5 = match aml_symbols.aml_context.namespace.get_by_path(&s5_aml_name) { Ok(s5) => s5, Err(error) => { log::error!("Cannot set S-state, missing \\_S5, {:?}", error); return; } }; diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index 788f7c92dd..d09b4aee33 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -26,8 +26,8 @@ enum HandleKind<'a> { TopLevel, Tables, Table(SdtSignature), - Symbols(RwLockReadGuard<'a, Option>), - Symbol(aml::AmlName), + Symbols(RwLockReadGuard<'a, AmlSymbols>), + Symbol(String), } impl HandleKind<'_> { @@ -45,13 +45,8 @@ impl HandleKind<'_> { Self::TopLevel => TOPLEVEL_CONTENTS.len(), Self::Tables => acpi_ctx.tables().len().checked_mul(TABLE_DENTRY_LENGTH).unwrap_or(usize::max_value()), Self::Table(signature) => acpi_ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.length(), - Self::Symbols(symbols_option) => { - match symbols_option.as_ref() { - Some(symbols) => symbols.symbols_str.len(), - _ => 0, - } - }, - Self::Symbol(_) => 0, + Self::Symbols(aml_symbols) => aml_symbols.to_str().len(), + Self::Symbol(description) => description.len(), }) } } @@ -159,15 +154,15 @@ impl SchemeMut for AcpiScheme<'_> { HandleKind::Table(signature) } - ["symbols"] => if let Ok(symbols_option) = self.ctx.aml_symbols() { - HandleKind::Symbols(symbols_option) + ["symbols"] => if let Ok(aml_symbols) = self.ctx.aml_symbols() { + HandleKind::Symbols(aml_symbols) } else { return Err(Error::new(EIO)) }, ["symbols", symbol] => { - if let Some(symbol) = self.ctx.aml_lookup(symbol) { - HandleKind::Symbol(symbol) + if let Some(description) = self.ctx.aml_lookup(symbol) { + HandleKind::Symbol(description) } else { return Err(Error::new(ENOENT)); } @@ -291,24 +286,20 @@ impl SchemeMut for AcpiScheme<'_> { return Ok(bytes_written); } - HandleKind::Symbols(symbols_option) => { - match symbols_option.as_ref() { - Some(symbols) => { - let offset = std::cmp::min(symbols.symbols_str.len(), handle.offset); - let src_buf = &symbols.symbols_str.as_bytes()[offset..]; + HandleKind::Symbols(aml_symbols) => { + let symbols = aml_symbols.to_str(); + let offset = std::cmp::min(symbols.len(), handle.offset); + let src_buf = &symbols.as_bytes()[offset..]; - let to_copy = std::cmp::min(src_buf.len(), buf.len()); - buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); + let to_copy = std::cmp::min(src_buf.len(), buf.len()); + buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); - handle.offset = handle.offset.checked_add(to_copy).ok_or(Error::new(EOVERFLOW))?; + handle.offset = handle.offset.checked_add(to_copy).ok_or(Error::new(EOVERFLOW))?; - return Ok(to_copy); - } - _ => return Err(Error::new(EIO)), - } + return Ok(to_copy); } - HandleKind::Symbol(_) => b"", + HandleKind::Symbol(description) => description.as_bytes(), }; From 800c56f15a0743e7bd4b5bbc8bc6473975986cc9 Mon Sep 17 00:00:00 2001 From: Alberto Souza Date: Wed, 8 Feb 2023 18:55:59 +0000 Subject: [PATCH 0591/1301] Add README.md --- README.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000000..216d3a6b54 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# Drivers + +These are the currently implemented devices/hardware interfaces. + +- ac97d - Realtek audio chipsets. +- acpid - ACPI. +- ahcid - SATA. +- alxd - Atheros ethernet (incomplete). +- bgad - Bochs emulator/debugger. +- block-io-wrapper - Library used by other drivers. +- e1000d - Intel Gigabit ethernet. +- ided - IDE. +- ihdad - Intel HD Audio chipsets. +- ixgbed - Intel 10 Gigabit ethernet. +- nvmed - NVMe. +- pcid - PCI. +- pcspkrd - PC speaker +- ps2d - PS/2 +- rtl8168d - Realtek ethernet. +- sb16d - Sound Blaster audio (incomplete). +- vboxd - VirtualBox guest. +- vesad - VESA. +- xhcid - xHCI (incomplete). +- usbctl - USB control (incomplete). +- usbhidd - USB HID (incomplete). +- usbscsid - USB SCSI (incomplete). From 625064004d4c3be7eda451859ec5a77f373226b5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 11 Feb 2023 14:37:22 -0700 Subject: [PATCH 0592/1301] Update for new Rust nightly --- Cargo.lock | 5 +++-- nvmed/src/nvme/mod.rs | 4 ++-- pcid/src/pcie/mod.rs | 8 ++++---- xhcid/src/usb/bos.rs | 3 +-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c139b3d136..e4898776ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -599,8 +599,9 @@ checksum = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" [[package]] name = "libc" -version = "0.2.137" -source = "git+https://gitlab.redox-os.org/redox-os/liblibc.git?branch=rust-2022-03-18#6ba4d1a527c2b53bdd5554cb219a1cd7d315d518" +version = "0.2.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "linked-hash-map" diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 8129169afd..4aa0bac86a 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -455,8 +455,8 @@ impl Nvme { log::trace!("Got completion queue entry (CQID {}): {:?} at {}", cq_id, entry, head); - assert_eq!(sq_id, entry.sq_id); - assert_eq!(cmd.cid, entry.cid); + assert_eq!(sq_id, { entry.sq_id }); + assert_eq!({ cmd.cid }, { entry.cid }); { let submission_queues_read_lock = self.submission_queues.read().unwrap(); diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 8a85929a31..1e1da08a25 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -55,13 +55,13 @@ impl fmt::Debug for Mcfg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Mcfg") .field("name", &"MCFG") - .field("length", &self.length) + .field("length", &{ self.length }) .field("revision", &self.revision) .field("checksum", &self.checksum) .field("oem_id", &self.oem_id) - .field("oem_table_id", &self.oem_table_id) - .field("oem_revision", &self.oem_revision) - .field("creator_revision", &self.creator_revision) + .field("oem_table_id", &{ self.oem_table_id }) + .field("oem_revision", &{ self.oem_revision }) + .field("creator_revision", &{ self.creator_revision }) .field("creator_id", &self.creator_id) .field("base_addrs", &self.base_addr_structs()) .finish() diff --git a/xhcid/src/usb/bos.rs b/xhcid/src/usb/bos.rs index 43f1f05b88..7e843b485a 100644 --- a/xhcid/src/usb/bos.rs +++ b/xhcid/src/usb/bos.rs @@ -44,7 +44,6 @@ pub struct BosSuperSpeedPlusDesc { pub attrs: u32, pub func_supp: u32, pub _rsvd1: u16, - sublink_speed_attr: [u32; 0], } unsafe impl plain::Plain for BosSuperSpeedPlusDesc {} @@ -77,7 +76,7 @@ impl BosSuperSpeedPlusDesc { pub fn sublink_speed_attr(&self) -> &[u32] { unsafe { slice::from_raw_parts( - &self.sublink_speed_attr as *const u32, + (self as *const Self).add(1) as *const u32, self.ssac() as usize + 1, ) } From a86f32e67a0610ad86730875d22fa2827510683d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Feb 2023 11:47:48 -0700 Subject: [PATCH 0593/1301] xhci: Workaround for missing interrupts --- xhcid/src/main.rs | 2 ++ xhcid/src/xhci/irq_reactor.rs | 2 +- xhcid/src/xhci/scheme.rs | 10 ++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index b9c96592bb..62aa36f4c8 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -209,6 +209,8 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option method } else if pci_config.func.legacy_interrupt_pin.is_some() { + info!("Legacy IRQ {}", irq); + // legacy INTx# interrupt pins. (Some(File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file")), InterruptMethod::Intx) } else { diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 152a05bc9d..97f4585fd3 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -162,7 +162,7 @@ impl IrqReactor { return Ok(None); } - debug!("IRQ reactor received an IRQ"); + trace!("IRQ reactor received an IRQ"); let _ = self.irq_file.as_mut().unwrap().write(&buffer); diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 1f39d6f82f..4ac7039375 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -253,6 +253,16 @@ impl Xhci { &self, f: F, ) -> (Trb, Trb) { + { + // If ERDP EHB bit is set, clear it before sending command + //TODO: find out why this bit is set earlier! + let mut run = self.run.lock().unwrap(); + let mut int = &mut run.ints[0]; + if int.erdp.readf(1 << 3) { + int.erdp.writef(1 << 3, true); + } + } + let next_event = { let mut command_ring = self.cmd.lock().unwrap(); let (cmd_index, cycle) = (command_ring.next_index(), command_ring.cycle); From e62b798a8bb9a1473de4c404f43bb03127039bcf Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Feb 2023 13:13:39 -0700 Subject: [PATCH 0594/1301] xhci: Fix status stage TRB direction in get_desc_raw --- xhcid/src/xhci/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index fb9f12821e..b5e278648c 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -113,7 +113,7 @@ impl Xhci { let last_index = ring.next_index(); let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle); - cmd.status(0, true, true, false, false, cycle); + cmd.status(0, false, true, false, false, cycle); self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &ring, &ring.trbs[last_index]) }; From 00720cc95ba80be6310d5c84c68eb6a0f088c629 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Feb 2023 19:17:55 -0700 Subject: [PATCH 0595/1301] ihdad: adjust log levels --- ihdad/src/hda/cmdbuff.rs | 11 ++++------ ihdad/src/hda/device.rs | 46 ++++++++++++++++++++-------------------- ihdad/src/hda/stream.rs | 4 ++-- ihdad/src/main.rs | 2 +- 4 files changed, 30 insertions(+), 33 deletions(-) diff --git a/ihdad/src/hda/cmdbuff.rs b/ihdad/src/hda/cmdbuff.rs index afbeadaf79..36ee9f2237 100644 --- a/ihdad/src/hda/cmdbuff.rs +++ b/ihdad/src/hda/cmdbuff.rs @@ -147,16 +147,14 @@ impl Corb { self.stop(); // Set CORBRPRST to 1 - log::info!("CORBRP {:X}", self.regs.corbrp.read()); + log::trace!("CORBRP {:X}", self.regs.corbrp.read()); self.regs.corbrp.writef(CORBRPRST, true); - log::info!("CORBRP {:X}", self.regs.corbrp.read()); - log::info!("Here!"); + log::trace!("CORBRP {:X}", self.regs.corbrp.read()); // Wait for it to become 1 while !self.regs.corbrp.readf(CORBRPRST) { self.regs.corbrp.writef(CORBRPRST, true); } - log::info!("Here!!"); // Clear the bit again self.regs.corbrp.write(0); @@ -168,7 +166,6 @@ impl Corb { } self.regs.corbrp.write(0); } - log::info!("Here!!!"); } } @@ -183,7 +180,7 @@ impl Corb { self.regs.corbwp.write(write_pos as u16); - log::info!("Corb: {:08X}", cmd); + log::trace!("Corb: {:08X}", cmd); } } @@ -285,7 +282,7 @@ impl Rirb { res = *self.rirb_base.offset(read_pos as isize); } self.rirb_rp = read_pos; - log::info!("Rirb: {:08X}", res); + log::trace!("Rirb: {:08X}", res); res } } diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index ec4e03c025..cc84c8272b 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -162,7 +162,7 @@ impl IntelHDA { syscall::physmap(buff_desc_phys, 0x1000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("ihdad: failed to map address for buffer descriptor list."); - log::info!("Virt: {:016X}, Phys: {:016X}", buff_desc_virt, buff_desc_phys); + log::debug!("Virt: {:016X}, Phys: {:016X}", buff_desc_virt, buff_desc_phys); let buff_desc = &mut *(buff_desc_virt as *mut [BufferDescriptorListEntry;256]); @@ -172,7 +172,7 @@ impl IntelHDA { let cmd_buff_virt = syscall::physmap(cmd_buff_address, 0x1000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("ihdad: failed to map address for CORB/RIRB buff"); - log::info!("Virt: {:016X}, Phys: {:016X}", cmd_buff_virt, cmd_buff_address); + log::debug!("Virt: {:016X}, Phys: {:016X}", cmd_buff_virt, cmd_buff_address); let mut module = IntelHDA { vend_prod: vend_prod, base: base, @@ -346,7 +346,7 @@ impl IntelHDA { let root = self.read_node((codec,0)); - log::info!("{}", root); + log::debug!("{}", root); let root_count = root.subnode_count; let root_start = root.subnode_start; @@ -354,7 +354,7 @@ impl IntelHDA { //FIXME: So basically the way this is set up is to only support one codec and hopes the first one is an audio for i in 0..root_count { let afg = self.read_node((codec, root_start + i)); - log::info!("{}", afg); + log::debug!("{}", afg); let afg_count = afg.subnode_count; let afg_start = afg.subnode_start; @@ -376,7 +376,7 @@ impl IntelHDA { _ => {}, } - log::info!("{}", widget); + log::debug!("{}", widget); self.widget_map.insert(widget.addr(), widget); } } @@ -469,14 +469,14 @@ impl IntelHDA { pub fn configure(&mut self) { let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); - log::info!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); + log::debug!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); let path = self.find_path_to_dac(outpin).unwrap(); let dac = *path.last().unwrap(); let pin = *path.first().unwrap(); - log::info!("Path to DAC: {:X?}", path); + log::debug!("Path to DAC: {:X?}", path); // Set power state 0 (on) for all widgets in path for &addr in &path { @@ -494,8 +494,8 @@ impl IntelHDA { self.update_sound_buffers(); - log::info!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); - log::info!("Capabilities: {:08X}", self.get_capabilities(path[0])); + log::debug!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); + log::debug!("Capabilities: {:08X}", self.get_capabilities(path[0])); // Create output stream let output = self.get_output_stream_descriptor(0).unwrap(); @@ -533,7 +533,7 @@ impl IntelHDA { let output = false; let input = true; self.set_amplifier_gain_mute(addr, output, input, left, right, index, mute, in_gain); - log::info!("Set {:X?} input gain to 0x{:X}", addr, in_gain); + log::debug!("Set {:X?} input gain to 0x{:X}", addr, in_gain); } // Check for output amp @@ -545,19 +545,19 @@ impl IntelHDA { let output = true; let input = false; self.set_amplifier_gain_mute(addr, output, input, left, right, index, mute, out_gain); - log::info!("Set {:X?} output gain to 0x{:X}", addr, out_gain); + log::debug!("Set {:X?} output gain to 0x{:X}", addr, out_gain); } } //TODO: implement hda-verb? output.run(); - log::info!("Waiting for output 0 to start running..."); + log::debug!("Waiting for output 0 to start running..."); while output.control() & (1 << 1) == 0 { //TODO: relax } - log::info!("Output 0 CONTROL {:#X} STATUS {:#X} POS {:#X}", output.control(), output.status(), output.link_position()); + log::debug!("Output 0 CONTROL {:#X} STATUS {:#X} POS {:#X}", output.control(), output.status(), output.link_position()); } /* @@ -565,10 +565,10 @@ impl IntelHDA { let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); - log::info!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); + log::debug!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); let path = self.find_path_to_dac(outpin).unwrap(); - log::info!("Path to DAC: {:X?}", path); + log::debug!("Path to DAC: {:X?}", path); // Pin enable self.cmd.cmd12((0,0xC), 0x707, 0x40); @@ -582,8 +582,8 @@ impl IntelHDA { self.update_sound_buffers(); - log::info!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); - log::info!("Capabilities: {:08X}", self.get_capabilities((0,0x1))); + log::debug!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); + log::debug!("Capabilities: {:08X}", self.get_capabilities((0,0x1))); let output = self.get_output_stream_descriptor(0).unwrap(); @@ -666,7 +666,7 @@ impl IntelHDA { } let statests = self.regs.statests.read(); - log::info!("Statests: {:04X}", statests); + log::debug!("Statests: {:04X}", statests); for i in 0..15 { if (statests >> i) & 0x1 == 1 { @@ -792,7 +792,7 @@ impl IntelHDA { //let sample_size:usize = output.sample_size(); let open_block = (output.link_position() as usize) / os.block_size(); - //log::info!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}", output.status(), output.link_position(), output.control()); + //log::trace!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}", output.status(), output.link_position(), output.control()); if os.current_block() == (open_block + 3) % NUM_SUB_BUFFS { // Block if we already are 3 buffers ahead @@ -849,13 +849,13 @@ impl IntelHDA { } fn validate_path(&mut self, path: &Vec<&str>) -> bool { - log::info!("Path: {:?}", path); + log::debug!("Path: {:?}", path); let mut it = path.iter(); match it.next() { Some(card_str) if (*card_str).starts_with("card") => { match usize::from_str_radix(&(*card_str)[4..], 10) { Ok(card_num) => { - log::info!("Card# {}", card_num); + log::debug!("Card# {}", card_num); match it.next() { Some(codec_str) if (*codec_str).starts_with("codec#") => { match usize::from_str_radix(&(*codec_str)[6..], 10) { @@ -871,7 +871,7 @@ impl IntelHDA { Some(pcmout_str) if (*pcmout_str).starts_with("pcmout") => { match usize::from_str_radix(&(*pcmout_str)[6..], 10) { Ok(pcmout_num) => { - log::info!("pcmout {}", pcmout_num); + log::debug!("pcmout {}", pcmout_num); true }, _ => false, @@ -880,7 +880,7 @@ impl IntelHDA { Some(pcmin_str) if (*pcmin_str).starts_with("pcmin") => { match usize::from_str_radix(&(*pcmin_str)[6..], 10) { Ok(pcmin_num) => { - log::info!("pcmin {}", pcmin_num); + log::debug!("pcmin {}", pcmin_num); true }, _ => false, diff --git a/ihdad/src/hda/stream.rs b/ihdad/src/hda/stream.rs index 0b20bd923a..c6f3753e59 100644 --- a/ihdad/src/hda/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -354,7 +354,7 @@ impl StreamBuffer { let len = min(self.block_size(), buf.len()); - //log::info!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}", self.phys(), self.addr(), self.current_block() * self.block_size(), len); + //log::trace!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}", self.phys(), self.addr(), self.current_block() * self.block_size(), len); unsafe { copy_nonoverlapping(buf.as_ptr(), (self.addr() + self.current_block() * self.block_size()) as * mut u8, len); } @@ -369,7 +369,7 @@ impl StreamBuffer { impl Drop for StreamBuffer { fn drop(&mut self) { unsafe { - log::info!("IHDA: Deallocating buffer."); + log::debug!("IHDA: Deallocating buffer."); if syscall::physunmap(self.addr).is_ok() { let _ = syscall::physfree(self.phys, self.block_len * self.block_cnt); } diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index d7b02dd21a..5cba24fd1e 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -79,7 +79,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { let irq = pci_config.func.legacy_interrupt_line; let all_pci_features = pcid_handle.fetch_all_features().expect("ihdad: failed to fetch pci features"); - log::info!("PCI FEATURES: {:?}", all_pci_features); + log::debug!("PCI FEATURES: {:?}", all_pci_features); let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); From 98a3106749ab54bbfbc2f50eccc56494a71ee6db Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Feb 2023 19:24:50 -0700 Subject: [PATCH 0596/1301] ihda, usbhid, xhci: logging adjustments --- ihdad/src/main.rs | 6 ++++-- usbhidd/src/main.rs | 2 +- xhcid/src/main.rs | 2 +- xhcid/src/xhci/mod.rs | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 5cba24fd1e..1fac624ae0 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -120,10 +120,12 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("ihdad: failed to set feature info"); pcid_handle.enable_feature(PciFeature::Msi).expect("ihdad: failed to enable MSI"); - log::info!("Enabled MSI"); + log::debug!("Enabled MSI"); Some(interrupt_handle) } else if pci_config.func.legacy_interrupt_pin.is_some() { + log::debug!("Legacy IRQ {}", irq); + // legacy INTx# interrupt pins. Some(File::open(format!("irq:{}", irq)).expect("ihdad: failed to open legacy IRQ file")) } else { @@ -171,7 +173,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { other => panic!("Expected memory bar, found {}", other), }; - eprintln!(" + IHDA {} on: {:#X} size: {}", name, bar_ptr, bar_size); + log::info!(" + IHDA {} on: {:#X} size: {}", name, bar_ptr, bar_size); let address = unsafe { syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 045bb8316d..df3f6d60ca 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -300,7 +300,7 @@ fn main() { let report_desc = ReportIter::new(ReportFlatIter::new(&report_desc_bytes)).collect::>(); for item in &report_desc { - log::info!("{:?}", item); + log::debug!("{:?}", item); } handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0, interface_desc: None, alternate_setting: None }).expect("Failed to configure endpoints"); diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 62aa36f4c8..42a378db3d 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -42,7 +42,7 @@ fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Debug) // limit global output to important info + .with_filter(log::LevelFilter::Info) // limit global output to important info .with_ansi_escape_codes() .flush_on_newline(true) .build() diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index b5e278648c..91e850263d 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -531,7 +531,7 @@ impl Xhci { let mut input = unsafe { self.alloc_dma_zeroed::()? }; let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; - info!("Addressed device"); + debug!("Addressed device"); // TODO: Should the descriptors be cached in PortState, or refetched? From 5bbe2e3f4ce0af1b4d8d3e72079b787949bbce54 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Feb 2023 19:30:59 -0700 Subject: [PATCH 0597/1301] ahci, ihda, pci, xhci: logging adjustments --- ahcid/src/ahci/hba.rs | 4 ++-- ihdad/src/hda/device.rs | 10 +++++----- pcid/src/main.rs | 4 ++-- xhcid/config.toml | 15 +++++++-------- xhcid/src/main.rs | 11 +++++------ xhcid/src/xhci/mod.rs | 4 ++-- 6 files changed, 23 insertions(+), 25 deletions(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index b798878772..5e923419c4 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -1,4 +1,4 @@ -use log::{error, info, trace}; +use log::{debug, error, info, trace}; use std::mem::size_of; use std::ops::DerefMut; use std::{ptr, u32}; @@ -128,7 +128,7 @@ impl HbaPort { // Power on and spin up device self.cmd.writef(1 << 2 | 1 << 1, true); - info!(" - AHCI init {:X}", self.cmd.read()); + debug!(" - AHCI init {:X}", self.cmd.read()); } pub unsafe fn identify(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index cc84c8272b..578299793e 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -699,11 +699,11 @@ impl IntelHDA { pub fn info(&self) { log::info!("Intel HD Audio Version {}.{}", self.regs.vmaj.read(), self.regs.vmin.read()); - log::info!("IHDA: Input Streams: {}", self.num_input_streams()); - log::info!("IHDA: Output Streams: {}", self.num_output_streams()); - log::info!("IHDA: Bidirectional Streams: {}", self.num_bidirectional_streams()); - log::info!("IHDA: Serial Data Outputs: {}", self.num_serial_data_out()); - log::info!("IHDA: 64-Bit: {}", self.regs.gcap.read() & 1 == 1); + log::debug!("IHDA: Input Streams: {}", self.num_input_streams()); + log::debug!("IHDA: Output Streams: {}", self.num_output_streams()); + log::debug!("IHDA: Bidirectional Streams: {}", self.num_bidirectional_streams()); + log::debug!("IHDA: Serial Data Outputs: {}", self.num_serial_data_out()); + log::debug!("IHDA: 64-Bit: {}", self.regs.gcap.read() & 1 == 1); } fn get_input_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { diff --git a/pcid/src/main.rs b/pcid/src/main.rs index a298739c6d..2cb52868cc 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -6,7 +6,7 @@ use std::sync::{Arc, Mutex}; use std::{i64, thread}; use structopt::StructOpt; -use log::{error, info, warn, trace}; +use log::{debug, error, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; use crate::config::Config; @@ -398,7 +398,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, } else { Vec::new() }; - info!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); + debug!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); use driver_interface::LegacyInterruptPin; diff --git a/xhcid/config.toml b/xhcid/config.toml index 5244252bc1..b80bae57a4 100644 --- a/xhcid/config.toml +++ b/xhcid/config.toml @@ -1,8 +1,7 @@ -# Disabled - causes issues on real hardware -# [[drivers]] -# name = "XHCI" -# class = 12 -# subclass = 3 -# interface = 48 -# command = ["xhcid"] -# use_channel = true +[[drivers]] +name = "XHCI" +class = 12 +subclass = 3 +interface = 48 +command = ["xhcid"] +use_channel = true diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 42a378db3d..f12b28c2bd 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -16,7 +16,6 @@ use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_ve use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; use event::{Event, EventQueue}; -use log::info; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; @@ -103,7 +102,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option }; let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); - info!("XHCI PCI FEATURES: {:?}", all_pci_features); + log::debug!("XHCI PCI FEATURES: {:?}", all_pci_features); let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); @@ -144,7 +143,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("xhcid: failed to set feature info"); pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); - info!("Enabled MSI"); + log::debug!("Enabled MSI"); (Some(interrupt_handle), InterruptMethod::Msi) } else if msix_enabled { @@ -205,11 +204,11 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option }; pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); - info!("Enabled MSI-X"); + log::debug!("Enabled MSI-X"); method } else if pci_config.func.legacy_interrupt_pin.is_some() { - info!("Legacy IRQ {}", irq); + log::debug!("Legacy IRQ {}", irq); // legacy INTx# interrupt pins. (Some(File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file")), InterruptMethod::Intx) @@ -247,7 +246,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(&name); - info!("XHCI PCI CONFIG: {:?}", pci_config); + log::debug!("XHCI PCI CONFIG: {:?}", pci_config); let bar = pci_config.func.bars[0]; let bar_size = pci_config.func.bar_sizes[0]; let irq = pci_config.func.legacy_interrupt_line; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 91e850263d..4e081c7235 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -500,7 +500,7 @@ impl Xhci { } pub async fn probe(&self) -> Result<()> { - info!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); + debug!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); let port_count = { self.ports.lock().unwrap().len() }; @@ -913,7 +913,7 @@ pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { debug!("About to start IRQ reactor"); *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { - info!("Started IRQ reactor thread"); + debug!("Started IRQ reactor thread"); IrqReactor::new(hci_clone, receiver, irq_file).run() })); } From b6321aa7647e6a2784d9560105d28e7670afa95e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Feb 2023 19:34:05 -0700 Subject: [PATCH 0598/1301] nvme: logging adjustments --- nvmed/src/main.rs | 2 +- nvmed/src/nvme/identify.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 12342367cf..f88a1db9e9 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -312,7 +312,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let bar_size = pci_config.func.bar_sizes[0]; let irq = pci_config.func.legacy_interrupt_line; - log::info!("NVME PCI CONFIG: {:?}", pci_config); + log::debug!("NVME PCI CONFIG: {:?}", pci_config); let allocated_bars = AllocatedBars::default(); diff --git a/nvmed/src/nvme/identify.rs b/nvmed/src/nvme/identify.rs index ea504663d4..4d9f1dfc51 100644 --- a/nvmed/src/nvme/identify.rs +++ b/nvmed/src/nvme/identify.rs @@ -167,7 +167,7 @@ impl Nvme { let serial = serial_cow.trim(); let firmware = fw_cow.trim(); - println!( + log::info!( " - Model: {} Serial: {} Firmware: {}", model, serial, firmware, ); From 6fb6fa34cb5b65d3cd4928658d1ade90369cec2d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Feb 2023 19:36:12 -0700 Subject: [PATCH 0599/1301] ahci: logging adjustments --- ahcid/src/ahci/hba.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 5e923419c4..f2839f8f25 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -382,7 +382,7 @@ impl HbaMem { */ self.ghc.write(1 << 31 | 1 << 1); - info!(" - AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}", + debug!(" - AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}", self.cap.read(), self.ghc.read(), self.is.read(), self.pi.read(), self.vs.read(), self.cap2.read(), self.bohc.read()); } From 96246acca594ca733866e4982874766b68f5f0dc Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 15 Feb 2023 20:05:25 -0700 Subject: [PATCH 0600/1301] pcid: Optimize PCI bus scanning --- pcid/src/main.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 2cb52868cc..98fe46088b 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -600,13 +600,22 @@ fn main(args: Args) { info!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); - 'bus: for bus in PciIter::new(pci) { + let mut bus_nums = vec![0]; + let mut bus_i = 0; + 'bus: while bus_i < bus_nums.len() { + let bus_num = bus_nums[bus_i]; + bus_i += 1; + + let bus = PciBus { pci, num: bus_num }; 'dev: for dev in bus.devs() { for func in dev.funcs() { let func_num = func.num; match PciHeader::from_reader(func) { Ok(header) => { handle_parsed_header(Arc::clone(&state), &config, bus.num, dev.num, func_num, header); + if let PciHeader::PciToPci { secondary_bus_num, .. } = header { + bus_nums.push(secondary_bus_num); + } } Err(PciHeaderError::NoDevice) => { if func_num == 0 { From f0ff668f0c3e6f87c41ddcb4fca6f9ea15c5049d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 16 Feb 2023 07:39:35 -0700 Subject: [PATCH 0601/1301] xhcid: fix direction of status stage in scheme --- xhcid/src/xhci/scheme.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 4ac7039375..6352b0b694 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -327,11 +327,13 @@ impl Xhci { let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle); let interrupter = 0; + // When the data stage is in, the status stage must be out + let input = tk != TransferKind::In; let ioc = true; let ch = false; let ent = false; + cmd.status(interrupter, input, ioc, ch, ent, cycle); - cmd.status(interrupter, tk == TransferKind::In, ioc, ch, ent, cycle); (self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), ring, &ring.trbs[last_index]), slot) }; From afb12dc98b1ecf33f05070834faccabd4145ac0e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 16 Feb 2023 15:28:34 -0700 Subject: [PATCH 0602/1301] xhci: ensure doorbell is rung after irq reactor has state --- xhcid/src/xhci/irq_reactor.rs | 49 ++++++++++++++++++++++----- xhcid/src/xhci/mod.rs | 26 ++++++++++----- xhcid/src/xhci/scheme.rs | 63 +++++++++++++++++++++++++---------- 3 files changed, 105 insertions(+), 33 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 97f4585fd3..602cce288f 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -17,6 +17,7 @@ use syscall::Io; use event::{Event, EventQueue}; use super::Xhci; +use super::doorbell::Doorbell; use super::ring::Ring; use super::trb::{Trb, TrbCompletionCode, TrbType}; use super::event::EventRing; @@ -211,7 +212,7 @@ impl IrqReactor { self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); } fn handle_requests(&mut self) { - self.states.extend(self.receiver.try_iter().inspect(|req| trace!("Received request: {:?}", req))); + self.states.extend(self.receiver.try_iter().inspect(|req| trace!("Received request: {:X?}", req))); } fn acknowledge(&mut self, trb: Trb) { //TODO: handle TRBs without an attached state @@ -298,7 +299,7 @@ impl IrqReactor { index += 1; } - warn!("Lost event TRB type {}: {:?}", trb.trb_type(), trb); + warn!("Lost event TRB type {}, completion code: {}: {:X?}", trb.trb_type(), trb.completion_code(), trb); } fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { let mut index = 0; @@ -351,8 +352,30 @@ struct FutureState { state_kind: StateKind, } +pub struct EventDoorbell { + dbs: Arc>, + index: usize, + data: u32, +} + +impl EventDoorbell { + pub fn new(hci: &Xhci, index: usize, data: u32) -> Self { + Self { + //TODO: simplify this logic, maybe just use a raw pointer? + dbs: hci.dbs.clone(), + index, + data, + } + } + + pub fn ring(self) { + trace!("Ring doorbell {} with data {}", self.index, self.data); + self.dbs.lock().unwrap()[self.index].write(self.data); + } +} + enum EventTrbFuture { - Pending { state: FutureState, sender: Sender, }, + Pending { state: FutureState, sender: Sender, doorbell_opt: Option }, Finished, } @@ -363,10 +386,12 @@ impl Future for EventTrbFuture { let this = self.get_mut(); let message = match this { - &mut Self::Pending { ref state, ref sender } => match state.message.lock().unwrap().take() { + &mut Self::Pending { ref state, ref sender, ref mut doorbell_opt } => match state.message.lock().unwrap().take() { Some(message) => message, None => { + // Register state with IRQ reactor + trace!("Send state {:X?}", state.state_kind); sender.send(State { message: Arc::clone(&state.message), is_isoch_or_vf: state.is_isoch_or_vf, @@ -374,6 +399,11 @@ impl Future for EventTrbFuture { waker: context.waker().clone(), }).expect("IRQ reactor thread unexpectedly stopped"); + // Doorbell must be rung after sending state + if let Some(doorbell) = doorbell_opt.take() { + doorbell.ring(); + } + return task::Poll::Pending; } } @@ -414,26 +444,27 @@ impl Xhci { Some(function(ring_ref)) } - pub fn next_transfer_event_trb(&self, ring_id: RingId, ring: &Ring, trb: &Trb) -> impl Future + Send + Sync + 'static { + pub fn next_transfer_event_trb(&self, ring_id: RingId, ring: &Ring, trb: &Trb, doorbell: EventDoorbell) -> impl Future + Send + Sync + 'static { if ! trb.is_transfer_trb() { panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", trb.trb_type(), trb) } let is_isoch_or_vf = trb.trb_type() == TrbType::Isoch as u8; - + let phys_ptr = ring.trb_phys_ptr(self.cap.ac64(), trb); EventTrbFuture::Pending { state: FutureState { is_isoch_or_vf, state_kind: StateKind::Transfer { ring_id, - phys_ptr: ring.trb_phys_ptr(self.cap.ac64(), trb), + phys_ptr, }, message: Arc::new(Mutex::new(None)), }, sender: self.irq_reactor_sender.clone(), + doorbell_opt: Some(doorbell), } } - pub fn next_command_completion_event_trb(&self, command_ring: &Ring, trb: &Trb) -> impl Future + Send + Sync + 'static { + pub fn next_command_completion_event_trb(&self, command_ring: &Ring, trb: &Trb, doorbell: EventDoorbell) -> impl Future + Send + Sync + 'static { if ! trb.is_command_trb() { panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb) } @@ -447,6 +478,7 @@ impl Xhci { message: Arc::new(Mutex::new(None)), }, sender: self.irq_reactor_sender.clone(), + doorbell_opt: Some(doorbell), } } pub fn next_misc_event_trb(&self, trb_type: TrbType) -> impl Future + Send + Sync + 'static { @@ -468,6 +500,7 @@ impl Xhci { message: Arc::new(Mutex::new(None)), }, sender: self.irq_reactor_sender.clone(), + doorbell_opt: None, } } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 4e081c7235..ef8d103016 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -38,7 +38,7 @@ mod trb; use self::capability::CapabilityRegs; use self::context::{DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray}; use self::doorbell::Doorbell; -use self::irq_reactor::{IrqReactor, NewPendingTrb, RingId}; +use self::irq_reactor::{EventDoorbell, IrqReactor, NewPendingTrb, RingId}; use self::event::EventRing; use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap}; use self::operational::OperationalRegs; @@ -113,13 +113,23 @@ impl Xhci { let last_index = ring.next_index(); let (cmd, cycle) = (&mut ring.trbs[last_index], ring.cycle); - cmd.status(0, false, true, false, false, cycle); - self.next_transfer_event_trb(RingId::default_control_pipe(port as u8), &ring, &ring.trbs[last_index]) + let interrupter = 0; + // When the data stage is in, the status stage must be out + let input = false; + let ioc = true; + let ch = false; + let ent = false; + cmd.status(interrupter, input, ioc, ch, ent, cycle); + + self.next_transfer_event_trb( + RingId::default_control_pipe(port as u8), + &ring, + &ring.trbs[last_index], + EventDoorbell::new(self, usize::from(slot), Self::def_control_endp_doorbell()) + ) }; - self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); - let trbs = future.await; let event_trb = trbs.event_trb; let status_trb = trbs.src_trb.unwrap(); @@ -170,7 +180,7 @@ pub struct Xhci { // without having to wrap every element in a lock (which wouldn't work since they're packed). op: Mutex<&'static mut OperationalRegs>, ports: Mutex<&'static mut [Port]>, - dbs: Mutex<&'static mut [Doorbell]>, + dbs: Arc>, run: Mutex<&'static mut RuntimeRegs>, cmd: Mutex, primary_event_ring: Mutex, @@ -307,7 +317,7 @@ impl Xhci { op: Mutex::new(op), ports: Mutex::new(ports), - dbs: Mutex::new(dbs), + dbs: Arc::new(Mutex::new(dbs)), run: Mutex::new(run), dev_ctx: DeviceContextList::new(cap.ac64(), max_slots)?, @@ -404,7 +414,7 @@ impl Xhci { // Ring command doorbell debug!("Ringing command doorbell."); - self.dbs.get_mut().unwrap()[0].write(0); + self.dbs.lock().unwrap()[0].write(0); info!("XHCI initialized."); diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 6352b0b694..0c0cf893fc 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -27,7 +27,7 @@ use super::context::{ }; use super::doorbell::Doorbell; use super::extended::ProtocolSpeed; -use super::irq_reactor::RingId; +use super::irq_reactor::{EventDoorbell, RingId}; use super::operational::OperationalRegs; use super::ring::Ring; use super::runtime::RuntimeRegs; @@ -274,11 +274,13 @@ impl Xhci { // get the future here before awaiting, to destroy the lock before deadlock let command_trb = &command_ring.trbs[cmd_index]; - self.next_command_completion_event_trb(&*command_ring, command_trb) + self.next_command_completion_event_trb( + &*command_ring, + command_trb, + EventDoorbell::new(self, 0, 0) + ) }; - self.dbs.lock().unwrap()[0].write(0); - let trbs = next_event.await; let event_trb = trbs.event_trb; let command_trb = trbs.src_trb.expect("Command completion event TRBs shall always have a valid pointer to a valid source command TRB"); @@ -298,7 +300,7 @@ impl Xhci { where D: FnMut(&mut Trb, bool) -> ControlFlow, { - let (future, slot) = { + let future = { let mut port_state = self.port_state_mut(port_num)?; let slot = port_state.slot; @@ -334,11 +336,14 @@ impl Xhci { let ent = false; cmd.status(interrupter, input, ioc, ch, ent, cycle); - (self.next_transfer_event_trb(RingId::default_control_pipe(port_num as u8), ring, &ring.trbs[last_index]), slot) + self.next_transfer_event_trb( + RingId::default_control_pipe(port_num as u8), + ring, + &ring.trbs[last_index], + EventDoorbell::new(self, usize::from(slot), Self::def_control_endp_doorbell()) + ) }; - self.dbs.lock().unwrap()[usize::from(slot)].write(Self::def_control_endp_doorbell()); - let trbs = future.await; let event_trb = trbs.event_trb; let status_trb = trbs.src_trb.unwrap(); @@ -374,6 +379,28 @@ impl Xhci { let slot = port_state.slot; + let (doorbell_data_stream, doorbell_data_no_stream) = { + let endp_desc = port_state + .dev_desc.as_ref().unwrap() + .config_descs.get(usize::from(cfg_idx)).ok_or(Error::new(EIO))? + .interface_descs.get(usize::from(if_idx)).ok_or(Error::new(EIO))? + .endpoints.get(usize::from(endp_idx)).ok_or(Error::new(EBADFD))?; + + //TODO: clean this up + ( + Self::endp_doorbell( + endp_num, + endp_desc, + stream_id, + ), + Self::endp_doorbell( + endp_num, + endp_desc, + 0, + ), + ) + }; + let endp_state = port_state .endpoint_states .get_mut(&endp_num) @@ -399,21 +426,23 @@ impl Xhci { match d(trb, cycle) { ControlFlow::Break => { - break self.next_transfer_event_trb(super::irq_reactor::RingId { port: port_num as u8, endpoint_num: endp_num, stream_id }, ring, &ring.trbs[last_index]); + break self.next_transfer_event_trb( + super::irq_reactor::RingId { port: port_num as u8, endpoint_num: endp_num, stream_id }, + ring, + &ring.trbs[last_index], + EventDoorbell::new(self, usize::from(slot), if has_streams { + doorbell_data_stream + } else { + doorbell_data_no_stream + }), + ); } ControlFlow::Continue => continue, } }; - let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(cfg_idx)).ok_or(Error::new(EIO))?.interface_descs.get(usize::from(if_idx)).ok_or(Error::new(EIO))?.endpoints.get(usize::from(endp_idx)).ok_or(Error::new(EBADFD))?; - - self.dbs.lock().unwrap()[usize::from(slot)].write(Self::endp_doorbell( - endp_num, - endp_desc, - if has_streams { stream_id } else { 0 }, - )); - drop(port_state); + let trbs = future.await; let event_trb = trbs.event_trb; let transfer_trb = trbs.src_trb.unwrap(); From 79a9f447d2097149fb249f150a1cb525f6099bbc Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 16 Feb 2023 15:57:28 -0700 Subject: [PATCH 0603/1301] xhci: workaround packet size and protocol speed issues on real hardware --- xhcid/src/xhci/mod.rs | 24 +++++++++++++++--------- xhcid/src/xhci/scheme.rs | 21 +++++++++++++++++---- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index ef8d103016..d3936d51c4 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -604,12 +604,14 @@ impl Xhci { b |= (new_max_packet_size) << 16; endp_ctx.b.write(b); + /*TODO: this causes issues on real hardware, maybe it should only be used on USB 2? let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.evaluate_context(slot_id, input_context.physical(), false, cycle) }).await; self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; self.event_handler_finished(); + */ Ok(()) } @@ -838,7 +840,7 @@ impl Xhci { pub fn supported_protocol_speeds( &self, port: u8, - ) -> Option> { + ) -> impl Iterator { use extended::*; const DEFAULT_SUPP_PROTO_SPEEDS: [ProtocolSpeed; 7] = [ // Full-speed @@ -903,16 +905,20 @@ impl Xhci { ), ]; - let supp_proto = self.supported_protocol(port)?; - - Some(if supp_proto.psic() != 0 { - unsafe { supp_proto.protocol_speeds().iter() } - } else { - DEFAULT_SUPP_PROTO_SPEEDS.iter() - }) + match self.supported_protocol(port) { + Some(supp_proto) => if supp_proto.psic() != 0 { + unsafe { supp_proto.protocol_speeds().iter() } + } else { + DEFAULT_SUPP_PROTO_SPEEDS.iter() + }, + None => { + log::warn!("falling back to default supported protocol speeds for port {}", port); + DEFAULT_SUPP_PROTO_SPEEDS.iter() + } + } } pub fn lookup_psiv(&self, port: u8, psiv: u8) -> Option<&'static ProtocolSpeed> { - self.supported_protocol_speeds(port)? + self.supported_protocol_speeds(port) .find(|speed| speed.psiv() == psiv) } } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 0c0cf893fc..95d2315437 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -626,6 +626,7 @@ impl Xhci { let endpoints = &config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; if endpoints.len() >= 31 { + warn!("endpoints length {} >= 31", endpoints.len()); return Err(Error::new(EIO)); } @@ -644,7 +645,10 @@ impl Xhci { let port_speed_id = self.ports.lock().unwrap()[port].speed(); let speed_id: &ProtocolSpeed = self .lookup_psiv(port as u8, port_speed_id) - .ok_or(Error::new(EIO))?; + .ok_or_else(|| { + warn!("no speed_id"); + Error::new(EIO) + })?; { let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; @@ -677,7 +681,10 @@ impl Xhci { let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; let dev_desc = port_state.dev_desc.as_ref().unwrap(); let endpoints = &dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; - let endp_desc = endpoints.get(endp_idx as usize).ok_or(Error::new(EIO))?; + let endp_desc = endpoints.get(endp_idx as usize).ok_or_else(|| { + warn!("failed to find endpoint {}", endp_idx); + Error::new(EIO) + })?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); @@ -724,7 +731,10 @@ impl Xhci { // driver probably knows better. The spec says that the initial value should be 8 bytes // for control, 1KiB for interrupt and 3KiB for bulk and isoch. let avg_trb_len: u16 = match endp_desc.ty() { - EndpointTy::Ctrl => return Err(Error::new(EIO)), // only endpoint zero is of type control, and is configured separately with the address device command. + EndpointTy::Ctrl => { + warn!("trying to use control endpoint"); + return Err(Error::new(EIO)); // only endpoint zero is of type control, and is configured separately with the address device command. + } EndpointTy::Bulk | EndpointTy::Isoch => 3072, // 3 KiB EndpointTy::Interrupt => 1024, // 1 KiB }; @@ -778,7 +788,10 @@ impl Xhci { let mut input_context = port_state.input_context.lock().unwrap(); input_context.add_context.writef(1 << endp_num_xhc, true); - let endp_ctx = input_context.device.endpoints.get_mut(endp_num_xhc as usize - 1).ok_or(Error::new(EIO))?; + let endp_ctx = input_context.device.endpoints.get_mut(endp_num_xhc as usize - 1).ok_or_else(|| { + warn!("failed to find endpoint {}", endp_num_xhc - 1); + Error::new(EIO) + })?; endp_ctx.a.write( u32::from(mult) << 8 From 6cd802b9b4e53468ad1855a78fb73726cb74f0e8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 2 Mar 2023 12:01:24 -0700 Subject: [PATCH 0604/1301] Make acpid a no-op on i686 until aml crate issue is fixed --- acpid/Cargo.toml | 5 ++++- acpid/src/main.rs | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 451f0daeec..a7facd3c43 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -16,5 +16,8 @@ redox-daemon = "0.1" redox-log = "0.1.1" redox_syscall = "0.3" thiserror = "1" -aml = "0.16.2" rustc-hash = "1.1.0" + +#TODO: https://github.com/rust-osdev/acpi/issues/146 +[target.'cfg(target_arch = "x86_64")'.dependencies] +aml = "0.16.2" diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 34bb3b0626..50d59b06bb 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -14,7 +14,9 @@ use syscall::scheme::SchemeMut; use syscall::data::{Event, Packet}; use syscall::flag::{EventFlags, O_NONBLOCK}; +#[cfg(target_arch = "x86_64")] // TODO: https://github.com/rust-osdev/acpi/issues/146 mod acpi; +#[cfg(target_arch = "x86_64")] // TODO: https://github.com/rust-osdev/acpi/issues/146 mod scheme; fn monotonic() -> (u64, u64) { @@ -78,6 +80,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } } +#[cfg(target_arch = "x86_64")] // TODO: https://github.com/rust-osdev/acpi/issues/146 fn daemon(daemon: redox_daemon::Daemon) -> ! { setup_logging(); @@ -220,5 +223,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } fn main() { + #[cfg(target_arch = "x86_64")] // TODO: https://github.com/rust-osdev/acpi/issues/146 redox_daemon::Daemon::new(daemon).expect("acpid: failed to daemonize"); } From 40334044aaba267935aec1db8fded0b63d2f36a5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 2 Mar 2023 17:54:36 -0700 Subject: [PATCH 0605/1301] Revert "Make acpid a no-op on i686 until aml crate issue is fixed" This reverts commit 6cd802b9b4e53468ad1855a78fb73726cb74f0e8. --- acpid/Cargo.toml | 5 +---- acpid/src/main.rs | 4 ---- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index a7facd3c43..451f0daeec 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -16,8 +16,5 @@ redox-daemon = "0.1" redox-log = "0.1.1" redox_syscall = "0.3" thiserror = "1" -rustc-hash = "1.1.0" - -#TODO: https://github.com/rust-osdev/acpi/issues/146 -[target.'cfg(target_arch = "x86_64")'.dependencies] aml = "0.16.2" +rustc-hash = "1.1.0" diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 50d59b06bb..34bb3b0626 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -14,9 +14,7 @@ use syscall::scheme::SchemeMut; use syscall::data::{Event, Packet}; use syscall::flag::{EventFlags, O_NONBLOCK}; -#[cfg(target_arch = "x86_64")] // TODO: https://github.com/rust-osdev/acpi/issues/146 mod acpi; -#[cfg(target_arch = "x86_64")] // TODO: https://github.com/rust-osdev/acpi/issues/146 mod scheme; fn monotonic() -> (u64, u64) { @@ -80,7 +78,6 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } } -#[cfg(target_arch = "x86_64")] // TODO: https://github.com/rust-osdev/acpi/issues/146 fn daemon(daemon: redox_daemon::Daemon) -> ! { setup_logging(); @@ -223,6 +220,5 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } fn main() { - #[cfg(target_arch = "x86_64")] // TODO: https://github.com/rust-osdev/acpi/issues/146 redox_daemon::Daemon::new(daemon).expect("acpid: failed to daemonize"); } From 9ba13580771690ba2e2eb4c0a123a397b00641a9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 2 Mar 2023 17:56:19 -0700 Subject: [PATCH 0606/1301] Used patched aml --- Cargo.lock | 3 +-- acpid/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e4898776ab..61d110121e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,8 +60,7 @@ dependencies = [ [[package]] name = "aml" version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7450aaee7581251d456c0f283f4c3db13b09a95054572ae77b6d22f77216caf" +source = "git+https://github.com/IsaacWoods/acpi?rev=8aefcb9c1ef1ff92b50e8c484ef6e8bf448670a9#8aefcb9c1ef1ff92b50e8c484ef6e8bf448670a9" dependencies = [ "bit_field", "bitvec", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 451f0daeec..bb14ca64ee 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -16,5 +16,5 @@ redox-daemon = "0.1" redox-log = "0.1.1" redox_syscall = "0.3" thiserror = "1" -aml = "0.16.2" +aml = { git = "https://github.com/IsaacWoods/acpi", rev = "8aefcb9c1ef1ff92b50e8c484ef6e8bf448670a9" } rustc-hash = "1.1.0" From 7d7a706cb313c911d1359250d47d9463d0274c3b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 3 Mar 2023 18:24:17 -0700 Subject: [PATCH 0607/1301] Update aml to 0.16.3 --- Cargo.lock | 5 +++-- acpid/Cargo.toml | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 61d110121e..ef63d408c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,8 +59,9 @@ dependencies = [ [[package]] name = "aml" -version = "0.16.2" -source = "git+https://github.com/IsaacWoods/acpi?rev=8aefcb9c1ef1ff92b50e8c484ef6e8bf448670a9#8aefcb9c1ef1ff92b50e8c484ef6e8bf448670a9" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dcf92e2afd8d6607e435cdc1d8ea76260fa467f6cf821f6af40e88dca15d183" dependencies = [ "bit_field", "bitvec", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index bb14ca64ee..65a7fa9313 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +aml = "0.16.3" log = "0.4" num-derive = "0.3" num-traits = "0.2" @@ -15,6 +16,5 @@ plain = "0.2.3" redox-daemon = "0.1" redox-log = "0.1.1" redox_syscall = "0.3" -thiserror = "1" -aml = { git = "https://github.com/IsaacWoods/acpi", rev = "8aefcb9c1ef1ff92b50e8c484ef6e8bf448670a9" } rustc-hash = "1.1.0" +thiserror = "1" From c26eb11cf19f4777d8a86e9ebcb9f26ce9eadc41 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 7 Mar 2023 19:26:54 -0700 Subject: [PATCH 0608/1301] Support read/write I/O on x86 --- acpid/src/acpi.rs | 132 ++++++++++++++++++++++++++++++++++++---------- acpid/src/main.rs | 9 ++-- 2 files changed, 108 insertions(+), 33 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 5c9e074d55..2d8ecf87ec 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -253,7 +253,7 @@ impl AmlSymbols { let mut value_str = String::with_capacity(256); let _ = write!(value_str, "[symbol]\nname = \"{}\"\n\n[value]\n", name); let _ = match value { - AmlValue::Integer(n) => + AmlValue::Integer(n) => write!(value_str, "type = \"Integer\"\nvalue = \"{:#x}\"\n", n), AmlValue::String(s) => write!(value_str, "type = \"String\"\nvalue = \"{}\"\n", s), @@ -425,7 +425,7 @@ impl AcpiContext { Fadt::init(&mut this); //TODO (hangs on real hardware): Dmar::init(&this); - + this.aml_symbols.write().aml_context = AcpiContext::build_aml_context(&this); @@ -508,7 +508,7 @@ impl AcpiContext { } pub fn aml_symbols(&self) -> Result, SymbolListError> { - + // return the cached value if it exists let symbols = self.aml_symbols.read(); if !symbols.symbols_cache.is_empty() { @@ -558,7 +558,7 @@ impl AcpiContext { for (name, handle) in &symbols_list { handle_lookup.insert(handle, name); } - + let namespace = &aml_symbols.aml_context.namespace; let mut symbols_cache: FxHashMap = FxHashMap::default(); @@ -623,7 +623,7 @@ impl AcpiContext { aml::AmlValue::Package(package) => package, _ => { log::error!("Cannot set S-state, \\_S5 is not a package"); return; } }; - + let slp_typa = match package[0] { aml::AmlValue::Integer(i) => i, _ => { log::error!("typa is not an Integer"); return; } @@ -632,7 +632,7 @@ impl AcpiContext { aml::AmlValue::Integer(i) => i, _ => { log::error!("typb is not an Integer"); return; } }; - + log::trace!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); val |= slp_typa as u16; @@ -876,6 +876,7 @@ impl AmlContainingTable for Ssdt { struct AmlPhysMemHandler; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] impl aml::Handler for AmlPhysMemHandler { fn read_u8(&self, _address: usize) -> u8 { log::error!("read u8 {:X}", _address); @@ -895,42 +896,117 @@ impl aml::Handler for AmlPhysMemHandler { } fn write_u8(&mut self, _address: usize, _value: u8) { - log::error!("write u8 {:X}", _address); + log::error!("write u8 {:X} = {:X}", _address, _value); } fn write_u16(&mut self, _address: usize, _value: u16) { - log::error!("write u16 {:X}", _address); + log::error!("write u16 {:X} = {:X}", _address, _value); } fn write_u32(&mut self, _address: usize, _value: u32) { - log::error!("write u32 {:X}", _address); + log::error!("write u32 {:X} = {:X}", _address, _value); } fn write_u64(&mut self, _address: usize, _value: u64) { - log::error!("write u64 {:X}", _address); + log::error!("write u64 {:X} = {:X}", _address, _value); } - fn read_io_u8(&self, _port: u16) -> u8 { - log::error!("read io u8 {:X}", _port); - - 0 + fn read_io_u8(&self, port: u16) -> u8 { + Pio::::new(port).read() } - fn read_io_u16(&self, _port: u16) -> u16 { - log::error!("read io u16 {:X}", _port); - - 0 + fn read_io_u16(&self, port: u16) -> u16 { + Pio::::new(port).read() } - fn read_io_u32(&self, _port: u16) -> u32 { - log::error!("read io u32 {:X}", _port); - - 0 + fn read_io_u32(&self, port: u16) -> u32 { + Pio::::new(port).read() } - fn write_io_u8(&self, _port: u16, _value: u8) { - log::error!("write io u8 {:X}", _port); + fn write_io_u8(&self, port: u16, value: u8) { + Pio::::new(port).write(value) } - fn write_io_u16(&self, _port: u16, _value: u16) { - log::error!("write io u16 {:X}", _port); + fn write_io_u16(&self, port: u16, value: u16) { + Pio::::new(port).write(value) } - fn write_io_u32(&self, _port: u16, _value: u32) { - log::error!("write io u32 {:X}", _port); + fn write_io_u32(&self, port: u16, value: u32) { + Pio::::new(port).write(value) + } + + fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { + log::error!("read pci u8 {:X}", _device); + + 0 + } + fn read_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u16 { + log::error!("read pci u8 {:X}", _device); + + 0 + } + fn read_pci_u32(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u32 { + log::error!("read pci u8 {:X}", _device); + + 0 + } + fn write_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u8) { + log::error!("write pci u8 {:X}", _device); + } + fn write_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u16) { + log::error!("write pci u8 {:X}", _device); + } + fn write_pci_u32(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u32) { + log::error!("write pci u8 {:X}", _device); + } +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +impl aml::Handler for AmlPhysMemHandler { + fn read_u8(&self, _address: usize) -> u8 { + log::error!("read u8 {:X}", _address); + 0 + } + fn read_u16(&self, _address: usize) -> u16 { + log::error!("read u16 {:X}", _address); + 0 + } + fn read_u32(&self, _address: usize) -> u32 { + log::error!("read u32 {:X}", _address); + 0 + } + fn read_u64(&self, _address: usize) -> u64 { + log::error!("read u64 {:X}", _address); + 0 + } + + fn write_u8(&mut self, _address: usize, _value: u8) { + log::error!("write u8 {:X} = {:X}", _address, _value); + } + fn write_u16(&mut self, _address: usize, _value: u16) { + log::error!("write u16 {:X} = {:X}", _address, _value); + } + fn write_u32(&mut self, _address: usize, _value: u32) { + log::error!("write u32 {:X} = {:X}", _address, _value); + } + fn write_u64(&mut self, _address: usize, _value: u64) { + log::error!("write u64 {:X} = {:X}", _address, _value); + } + + fn read_io_u8(&self, port: u16) -> u8 { + log::error!("read io u8 {:X}", port); + 0 + } + fn read_io_u16(&self, port: u16) -> u16 { + log::error!("read io u16 {:X}", port); + 0 + } + fn read_io_u32(&self, port: u16) -> u32 { + log::error!("read io u32 {:X}", port); + 0 + } + + fn write_io_u8(&self, port: u16, value: u8) { + log::error!("write io u8 {:X} = {:X}", port, value); + } + fn write_io_u16(&self, port: u16, value: u16) { + log::error!("write io u16 {:X} = {:X}", port, value); + } + fn write_io_u32(&self, port: u16, value: u32) { + log::error!("write io u32 {:X} = {:X}", port, value); } fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 34bb3b0626..12bea90e48 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -37,8 +37,8 @@ fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Warn) // limit global output to important info - // .with_ansi_escape_codes() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() .flush_on_newline(true) .build() ); @@ -49,17 +49,16 @@ fn setup_logging() -> Option<&'static RedoxLogger> { // TODO: Add a configuration file for this b.with_filter(log::LevelFilter::Warn) .flush_on_newline(true) - // .with_ansi_escape_codes() .build() ), - Err(error) => eprintln!("Failed to create xhci.log: {}", error), + Err(error) => eprintln!("Failed to create acpid.log: {}", error), } #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.ansi.log") { Ok(b) => logger = logger.with_output( b.with_filter(log::LevelFilter::Warn) - // .with_ansi_escape_codes() + .with_ansi_escape_codes() .flush_on_newline(true) .build() ), From 9333d9acea4f1a330749b4cc525e962262156444 Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Tue, 21 Mar 2023 17:14:50 -0700 Subject: [PATCH 0609/1301] temporarily use forked library for AML --- Cargo.lock | 3 +-- acpid/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef63d408c9..fa39129d36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,8 +60,7 @@ dependencies = [ [[package]] name = "aml" version = "0.16.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dcf92e2afd8d6607e435cdc1d8ea76260fa467f6cf821f6af40e88dca15d183" +source = "git+https://github.com/rw-vanc/acpi.git?branch=cumulative#ac37b03f974ca58f3c024a058224ffd5b77fed31" dependencies = [ "bit_field", "bitvec", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 65a7fa9313..c9829bbf69 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -aml = "0.16.3" +aml = { git = "https://github.com/rw-vanc/acpi.git", branch = "cumulative" } log = "0.4" num-derive = "0.3" num-traits = "0.2" From e1605444a8b1e19fb5591ac689aaf136fe4317e0 Mon Sep 17 00:00:00 2001 From: Ribbon Date: Sun, 26 Mar 2023 23:30:58 +0000 Subject: [PATCH 0610/1301] New section on README. --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 216d3a6b54..22f2e030d7 100644 --- a/README.md +++ b/README.md @@ -24,3 +24,11 @@ These are the currently implemented devices/hardware interfaces. - usbctl - USB control (incomplete). - usbhidd - USB HID (incomplete). - usbscsid - USB SCSI (incomplete). + +## Contributing to Drivers + +If you want to write drivers for Redox, datasheets are preferable, when they are freely available. Be aware that datasheets are often provided under a [Non-Disclosure Agreement](https://en.wikipedia.org/wiki/Non-disclosure_agreement) from hardware vendors, which can affect the ability to create an MIT-licensed driver. + +If you don't have datasheets, we recommend you to do reverse-engineering of available C code of BSD drivers. + +We recommend BSDs drivers because BSD license is compatible with MIT (permissive), that way we can reuse the code in other drivers. From 23be7ed63ca1b858d98bafbc9462fc5bbe0c9325 Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Mon, 27 Mar 2023 20:58:59 -0700 Subject: [PATCH 0611/1301] Add serde with separate library for definitions --- Cargo.lock | 136 +++++++++++--- acpid/Cargo.toml | 3 + acpid/src/acpi.rs | 449 ++++++++++++++++++++++---------------------- acpid/src/scheme.rs | 4 +- amlserde/Cargo.toml | 15 ++ amlserde/src/lib.rs | 295 +++++++++++++++++++++++++++++ 6 files changed, 649 insertions(+), 253 deletions(-) create mode 100644 amlserde/Cargo.toml create mode 100644 amlserde/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index fa39129d36..58740eac28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,6 +20,7 @@ name = "acpid" version = "0.1.0" dependencies = [ "aml", + "amlserde", "log", "num-derive", "num-traits", @@ -29,7 +30,9 @@ dependencies = [ "redox-log", "redox_syscall 0.3.4", "rustc-hash", + "serde_json", "thiserror", + "toml 0.7.3", ] [[package]] @@ -69,6 +72,16 @@ dependencies = [ "spinning_top", ] +[[package]] +name = "amlserde" +version = "0.0.1" +dependencies = [ + "aml", + "rustc-hash", + "serde", + "toml 0.7.3", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -430,7 +443,7 @@ checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -474,6 +487,12 @@ dependencies = [ "uuid", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + [[package]] name = "heck" version = "0.3.3" @@ -530,6 +549,16 @@ dependencies = [ "spin", ] +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg 1.1.0", + "hashbrown", +] + [[package]] name = "instant" version = "0.1.12" @@ -728,7 +757,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -878,7 +907,7 @@ checksum = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -917,7 +946,7 @@ dependencies = [ "smallvec 1.9.0", "structopt", "thiserror", - "toml", + "toml 0.5.9", ] [[package]] @@ -961,7 +990,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.98", "version_check", ] @@ -978,9 +1007,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.42" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" +checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" dependencies = [ "unicode-ident", ] @@ -997,9 +1026,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.20" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -1297,7 +1326,7 @@ checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -1327,35 +1356,44 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.140" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" +checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.140" +version = "1.0.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" +checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.10", ] [[package]] name = "serde_json" -version = "1.0.82" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + [[package]] name = "slab" version = "0.4.7" @@ -1453,7 +1491,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -1467,6 +1505,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tap" version = "1.0.1" @@ -1511,7 +1560,7 @@ checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", ] [[package]] @@ -1549,6 +1598,40 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "unicode-bidi" version = "0.3.8" @@ -1722,7 +1805,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.98", "wasm-bindgen-shared", ] @@ -1744,7 +1827,7 @@ checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.98", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1799,6 +1882,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "winnow" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +dependencies = [ + "memchr", +] + [[package]] name = "ws2_32-sys" version = "0.2.1" @@ -1838,5 +1930,5 @@ dependencies = [ "serde_json", "smallvec 1.9.0", "thiserror", - "toml", + "toml 0.5.9", ] diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index c9829bbf69..3e052af591 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -18,3 +18,6 @@ redox-log = "0.1.1" redox_syscall = "0.3" rustc-hash = "1.1.0" thiserror = "1" +toml = "0.7" +serde_json = "1.0.94" +amlserde = { path = "../amlserde" } \ No newline at end of file diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 2d8ecf87ec..c33dc33fb0 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,3 +1,4 @@ +use amlserde::{AmlHandleLookup, AmlSerde}; use rustc_hash::FxHashMap; use std::convert::{TryFrom, TryInto}; use std::ops::Deref; @@ -13,7 +14,8 @@ use syscall::io::{Io, Pio}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use thiserror::Error; -use aml::{AmlContext, AmlName, AmlHandle, AmlValue}; +use aml::{AmlContext, AmlError, AmlHandle, AmlName, AmlValue}; +use amlserde::pretty_name; pub mod dmar; use self::dmar::Dmar; @@ -68,7 +70,13 @@ pub struct SdtSignature { impl fmt::Display for SdtSignature { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}-{}-{}", String::from_utf8_lossy(&self.signature), String::from_utf8_lossy(&self.oem_id), String::from_utf8_lossy(&self.oem_table_id)) + write!( + f, + "{}-{}-{}", + String::from_utf8_lossy(&self.signature), + String::from_utf8_lossy(&self.oem_id), + String::from_utf8_lossy(&self.oem_table_id) + ) } } @@ -133,14 +141,19 @@ impl Sdt { let header = match plain::from_bytes::(&slice) { Ok(header) => header, Err(plain::Error::TooShort) => return Err(InvalidSdtError::InvalidSize), - Err(plain::Error::BadAlignment) => panic!("plain::from_bytes failed due to alignment, but SdtHeader is #[repr(packed)]!"), + Err(plain::Error::BadAlignment) => panic!( + "plain::from_bytes failed due to alignment, but SdtHeader is #[repr(packed)]!" + ), }; if header.length() != slice.len() { return Err(InvalidSdtError::InvalidSize); } - let checksum = slice.iter().copied().fold(0_u8, |current_sum, item| current_sum.wrapping_add(item)); + let checksum = slice + .iter() + .copied() + .fold(0_u8, |current_sum, item| current_sum.wrapping_add(item)); if checksum != 0 { return Err(InvalidSdtError::BadChecksum); @@ -154,7 +167,9 @@ impl Sdt { // Begin by reading and validating the header first. The SDT header is always 36 bytes // long, and can thus span either one or two page table frames. - let needs_extra_page = (PAGE_SIZE - physaddr_page_offset).checked_sub(mem::size_of::()).is_none(); + let needs_extra_page = (PAGE_SIZE - physaddr_page_offset) + .checked_sub(mem::size_of::()) + .is_none(); let page_table_count = 1 + if needs_extra_page { 1 } else { 0 }; let pages = PhysmapGuard::map(physaddr_start_page, page_table_count)?; @@ -223,13 +238,6 @@ impl fmt::Debug for Sdt { pub struct Dsdt(Sdt); pub struct Ssdt(Sdt); - -#[derive(Debug, Error)] -pub enum SymbolListError { - #[error("Aml Internal Error")] - AmlInternalError, -} - // Current AML implementation builds the aml_context.namespace at startup, // but the cache for symbols is lazy-loaded when someone // reads from the acpi:/symbols scheme. @@ -243,136 +251,6 @@ pub struct AmlSymbols { pub symbols_str: String, } -impl AmlSymbols { - pub fn to_str(&self) -> &str { - &self.symbols_str - } - - /// Format a value as toml, to use as file contents - pub fn format_value(name: &str, value: &AmlValue, handle_lookup: &AmlHandleLookup) -> String { - let mut value_str = String::with_capacity(256); - let _ = write!(value_str, "[symbol]\nname = \"{}\"\n\n[value]\n", name); - let _ = match value { - AmlValue::Integer(n) => - write!(value_str, "type = \"Integer\"\nvalue = \"{:#x}\"\n", n), - AmlValue::String(s) => - write!(value_str, "type = \"String\"\nvalue = \"{}\"\n", s), - AmlValue::Processor { id, pblk_address, pblk_len } => - write!(value_str, "type = \"Processor\"\nid = \"{}\"\npblk_address = \"{}\"\npblk_len = \"{}\"\n", - id, pblk_address, pblk_len), - AmlValue::Method { flags, code } => - write!(value_str, "type = \"Method\"\nflags = \"{:?}\"\ncode = {}\n", flags, AmlSymbols::code_as_string(code)), - AmlValue::OpRegion { region, offset, length, parent_device } => - write!(value_str, "type = \"OpRegion\"\nregion = \"{:?}\"\noffset = \"{:#x}\"\nlength = \"{:#x}\"\ndevice = \"{}\"\n", - region, offset, length, AmlSymbols::device_option_as_string(parent_device)), - AmlValue::Field { region, flags, offset, length } => - write!(value_str, "type = \"Field\"\nregion = \"{}\"\nflags = \"{:?}\"\noffset = \"{:#x}\"\nlength = \"{:#x}\"\n", - handle_lookup.get_as_str(region), flags, offset, length), - AmlValue::Package(contents) => - write!(value_str, "type = \"Package\"\ncontents = {}\n", - AmlSymbols::contents_as_string(contents)), - AmlValue::Device => write!(value_str, "type = \"Device\"\n"), - AmlValue::Buffer(_) => write!(value_str, "type = \"Buffer\"\n"), - other => - write!(value_str, "type = \"Other\"\ndebug = \"{:.64?}\"\n", other), - }; - - value_str.shrink_to_fit(); - value_str - } - - fn device_option_as_string(device: &Option) -> String { - if let Some(name) = device { - format!("\"{}\"", AmlSymbols::pretty_name(name)) - } else { - "\"None\"".to_string() - } - } - - fn code_as_string(code: &aml::value::MethodCode) -> String { - match code { - aml::value::MethodCode::Aml(bytes) => - if bytes.len() > 15 { - format!("\"AML({:x?}...)\"", &bytes[..15]) - } else { - format!("\"AML({:x?})\"", bytes) - }, - aml::value::MethodCode::Native(_) => format!("(native method)"), - } - } - - fn contents_as_string(contents: &Vec) -> String { - let mut buf = String::with_capacity(128); - let _ = write!(buf, "[ "); - for value in contents { - match value { - AmlValue::Integer(n) => { let _ = write!(buf, "{:x}, ", n); }, - AmlValue::String(s) => { let _ = write!(buf, "\"{}\",", s); } - _ => { let _ = write!(buf, "{:?}", value); }, - } - if buf.len() > 58 { - let _ = write!(buf, "..."); - break; - } - } - let _ = write!(buf, "]"); - buf - } - - /// Remove trailing underscores from each name segment - pub fn pretty_name(level_aml_name: &AmlName) -> String { - let mut name = level_aml_name.as_string(); - // remove unnecessary underscores - while let Some(index) = name.find("_.") { - name.remove(index); - } - while name.len() > 0 && &name[name.len() - 1..] == "_" { - name.pop(); - } - name.shrink_to_fit(); - name - } - - pub fn child_symbol(level_name: &str, value_name: &str) -> String { - format!("{}.{}", level_name, value_name.trim_end_matches('_')) - } - - pub fn root_symbol(value_name: &str) -> String { - format!("\\{}", value_name.trim_end_matches('_')) - } - -} - -pub struct AmlHandleLookup { - map: FxHashMap, -} - -impl AmlHandleLookup { - pub fn new() -> Self { - Self { map: FxHashMap::default() } - } - - fn handle_to_key(&self, handle: &AmlHandle) -> String { - format!("{:?}", handle) - } - - pub fn insert(&mut self, handle: &AmlHandle, name: &String) { - self.map.insert(self.handle_to_key(handle), name.to_owned()); - } - - pub fn get(&self, handle: &AmlHandle) -> Option<&String> { - self.map.get(&self.handle_to_key(handle)) - } - - pub fn get_as_str(&self, handle: &AmlHandle) -> &str { - if let Some(name) = self.get(handle) { - &name[..] - } else { - "Unrecognized" - } - } -} - pub struct AcpiContext { tables: Vec, dsdt: Option, @@ -383,7 +261,6 @@ pub struct AcpiContext { // TODO: The kernel ACPI code seemed to use load_table quite ubiquitously, however ACPI 5.1 // states that DDBHandles can only be obtained when loading XSDT-pointed tables. So, we'll // generate an index only for those. - sdt_order: RwLock>>, pub next_ctx: RwLock, @@ -391,16 +268,17 @@ pub struct AcpiContext { impl AcpiContext { pub fn init(rxsdt_physaddrs: impl Iterator) -> Self { - let tables = rxsdt_physaddrs.map(|physaddr| { - let physaddr: usize = physaddr - .try_into() - .expect("expected ACPI addresses to be compatible with the current word size"); + let tables = rxsdt_physaddrs + .map(|physaddr| { + let physaddr: usize = physaddr + .try_into() + .expect("expected ACPI addresses to be compatible with the current word size"); - log::trace!("TABLE AT {:#>08X}", physaddr); + log::trace!("TABLE AT {:#>08X}", physaddr); - Sdt::load_from_physical(physaddr) - .expect("failed to load physical SDT") - }).collect::>(); + Sdt::load_from_physical(physaddr).expect("failed to load physical SDT") + }) + .collect::>(); let mut this = Self { tables, @@ -409,7 +287,10 @@ impl AcpiContext { // Temporary values aml_symbols: RwLock::new(AmlSymbols { - aml_context: AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None), + aml_context: AmlContext::new( + Box::new(AmlPhysMemHandler), + aml::DebugVerbosity::None, + ), symbols_cache: FxHashMap::default(), symbols_str: "".to_string(), }), @@ -426,14 +307,14 @@ impl AcpiContext { Fadt::init(&mut this); //TODO (hangs on real hardware): Dmar::init(&this); - this.aml_symbols.write().aml_context = AcpiContext::build_aml_context(&this); this } fn build_aml_context(acpi: &AcpiContext) -> AmlContext { - let mut aml_context = AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None); + let mut aml_context = + AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None); if let Some(dsdt) = acpi.dsdt() { match aml_context.parse_table(dsdt.aml()) { @@ -461,34 +342,56 @@ impl AcpiContext { self.dsdt.as_ref() } pub fn ssdts(&self) -> impl Iterator + '_ { - self.find_multiple_sdts(*b"SSDT").map(|sdt| Ssdt(sdt.clone())) + self.find_multiple_sdts(*b"SSDT") + .map(|sdt| Ssdt(sdt.clone())) } fn find_single_sdt_pos(&self, signature: [u8; 4]) -> Option { - let count = self.tables.iter().filter(|sdt| sdt.signature == signature).count(); + let count = self + .tables + .iter() + .filter(|sdt| sdt.signature == signature) + .count(); if count > 1 { - log::warn!("Expected only a single SDT of signature `{}` ({:?}), but there were {}", String::from_utf8_lossy(&signature), signature, count); + log::warn!( + "Expected only a single SDT of signature `{}` ({:?}), but there were {}", + String::from_utf8_lossy(&signature), + signature, + count + ); } - self.tables.iter().position(|sdt| sdt.signature == signature) + self.tables + .iter() + .position(|sdt| sdt.signature == signature) } pub fn find_multiple_sdts<'a>(&'a self, signature: [u8; 4]) -> impl Iterator { - self.tables.iter().filter(move |sdt| sdt.signature == signature) + self.tables + .iter() + .filter(move |sdt| sdt.signature == signature) } pub fn take_single_sdt(&self, signature: [u8; 4]) -> Option { - self.find_single_sdt_pos(signature).map(|pos| self.tables[pos].clone()) + self.find_single_sdt_pos(signature) + .map(|pos| self.tables[pos].clone()) } pub fn fadt(&self) -> Option<&Fadt> { self.fadt.as_ref() } pub fn sdt_from_signature(&self, signature: &SdtSignature) -> Option<&Sdt> { - self.tables.iter().find(|sdt| sdt.signature == signature.signature && sdt.oem_id == signature.oem_id && sdt.oem_table_id == signature.oem_table_id) + self.tables.iter().find(|sdt| { + sdt.signature == signature.signature + && sdt.oem_id == signature.oem_id + && sdt.oem_table_id == signature.oem_table_id + }) } pub fn get_signature_from_index(&self, index: usize) -> Option { self.sdt_order.read().get(index).copied().flatten() } pub fn get_index_from_signature(&self, signature: &SdtSignature) -> Option { - self.sdt_order.read().iter().rposition(|sig| sig.map_or(false, |sig| &sig == signature)) + self.sdt_order + .read() + .iter() + .rposition(|sig| sig.map_or(false, |sig| &sig == signature)) } pub fn tables(&self) -> &[Sdt] { &self.tables @@ -507,8 +410,7 @@ impl AcpiContext { None } - pub fn aml_symbols(&self) -> Result, SymbolListError> { - + pub fn aml_symbols(&self) -> Result, AmlError> { // return the cached value if it exists let symbols = self.aml_symbols.read(); if !symbols.symbols_cache.is_empty() { @@ -520,62 +422,57 @@ impl AcpiContext { // List has not been initialized, we have to build it log::trace!("Creating symbols list"); - let mut symbols_str: String = String::with_capacity(30000); - - let mut symbols_list: Vec<(String, AmlHandle)> = Vec::with_capacity(3000); + let mut symbol_list: Vec<(AmlName, String, AmlHandle)> = Vec::with_capacity(5000); let mut aml_symbols = self.aml_symbols.write(); - let root = aml::AmlName::root(); - let traverse = aml_symbols.aml_context.namespace - .traverse(| level_aml_name, level | { - let level_is_root = level_aml_name.eq(&root); - let level_name = AmlSymbols::pretty_name(level_aml_name); - for (name, handle) in level.values.iter() { - // Create the name of the symbol as "\levelname.symbolname" - let symbol = if level_is_root { - AmlSymbols::root_symbol(name.as_str()) + aml_symbols + .aml_context + .namespace + .traverse(|level_aml_name, level| { + for (child_seg, handle) in level.values.iter() { + if let Ok(aml_name) = + AmlName::from_name_seg(child_seg.to_owned()).resolve(level_aml_name) + { + let name = pretty_name(&aml_name); + symbol_list.push((aml_name, name, handle.to_owned())); } else { - AmlSymbols::child_symbol(&level_name, name.as_str()) - }; - symbols_str.push_str(&symbol); - symbols_str.push('\n'); - symbols_list.push((symbol, handle.to_owned())); + log::error!( + "AmlName resolve failed, {:?}:{:?}", + level_aml_name, + child_seg + ); + } } Ok(true) - }); - - match traverse { - Err(error) => { - log::error!("Traverse failed, {:?}", error); - return Err(SymbolListError::AmlInternalError); - } - _ => {} - } + })?; + let mut symbols_str = String::with_capacity(symbol_list.len() * 10); let mut handle_lookup = AmlHandleLookup::new(); - for (name, handle) in &symbols_list { - handle_lookup.insert(handle, name); - } - - let namespace = &aml_symbols.aml_context.namespace; - - let mut symbols_cache: FxHashMap = FxHashMap::default(); - - for (name, handle) in symbols_list { - if let Ok(value) = namespace.get(handle.to_owned()) { - symbols_cache.insert(name.to_owned(), AmlSymbols::format_value(&name, value, &handle_lookup)); - } + for (_aml_name, name, handle) in &symbol_list { + let _ = writeln!(symbols_str, "{}", &name); + handle_lookup.insert(handle.to_owned(), name.to_owned()); } symbols_str.shrink_to_fit(); + let mut symbol_cache: FxHashMap = FxHashMap::default(); + + for (_aml_name, name, handle) in &symbol_list { + if let Some(ser_value) = AmlSerde::from_aml(&aml_symbols.aml_context, &handle_lookup, handle) { + if let Ok(ser_string) = serde_json::to_string_pretty(&ser_value) { + symbol_cache.insert(name.to_owned(), ser_string); + } + } + } + + // Cache the new list log::trace!("Updating symbols list"); aml_symbols.symbols_str = symbols_str; - aml_symbols.symbols_cache = symbols_cache; + aml_symbols.symbols_cache = symbol_cache; // return the cached value Ok(RwLockWriteGuard::downgrade(aml_symbols)) @@ -598,7 +495,7 @@ impl AcpiContext { } let fadt = match self.fadt() { Some(fadt) => fadt, - None => { + None => { log::error!("Cannot set global S-state due to missing FADT."); return; } @@ -611,26 +508,41 @@ impl AcpiContext { let s5_aml_name = match aml::AmlName::from_str("\\_S5") { Ok(aml_name) => aml_name, - Err(error) => { log::error!("Could not build AmlName for \\_S5, {:?}", error); return; } + Err(error) => { + log::error!("Could not build AmlName for \\_S5, {:?}", error); + return; + } }; let s5 = match aml_symbols.aml_context.namespace.get_by_path(&s5_aml_name) { Ok(s5) => s5, - Err(error) => { log::error!("Cannot set S-state, missing \\_S5, {:?}", error); return; } + Err(error) => { + log::error!("Cannot set S-state, missing \\_S5, {:?}", error); + return; + } }; let package = match s5 { aml::AmlValue::Package(package) => package, - _ => { log::error!("Cannot set S-state, \\_S5 is not a package"); return; } + _ => { + log::error!("Cannot set S-state, \\_S5 is not a package"); + return; + } }; let slp_typa = match package[0] { aml::AmlValue::Integer(i) => i, - _ => { log::error!("typa is not an Integer"); return; } + _ => { + log::error!("typa is not an Integer"); + return; + } }; let slp_typb = match package[1] { aml::AmlValue::Integer(i) => i, - _ => { log::error!("typb is not an Integer"); return; } + _ => { + log::error!("typb is not an Integer"); + return; + } }; log::trace!("Shutdown SLP_TYPa {:X}, SLP_TYPb {:X}", slp_typa, slp_typb); @@ -646,14 +558,17 @@ impl AcpiContext { #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] { - log::error!("Cannot shutdown with ACPI outw(0x{:X}, 0x{:X}) on this architecture", port, val); + log::error!( + "Cannot shutdown with ACPI outw(0x{:X}, 0x{:X}) on this architecture", + port, + val + ); } loop { core::hint::spin_loop(); } } - } #[repr(packed)] @@ -746,12 +661,14 @@ pub struct Fadt(Sdt); impl Fadt { pub fn acpi_2_struct(&self) -> Option<&FadtAcpi2Struct> { - let bytes = &self.0.0[mem::size_of::()..]; + let bytes = &self.0 .0[mem::size_of::()..]; match plain::from_bytes::(bytes) { Ok(fadt2) => Some(fadt2), Err(plain::Error::TooShort) => None, - Err(plain::Error::BadAlignment) => unreachable!("plain::from_bytes reported bad alignment, but FadtAcpi2Struct is #[repr(packed)]"), + Err(plain::Error::BadAlignment) => unreachable!( + "plain::from_bytes reported bad alignment, but FadtAcpi2Struct is #[repr(packed)]" + ), } } } @@ -760,7 +677,7 @@ impl Deref for Fadt { type Target = FadtStruct; fn deref(&self) -> &Self::Target { - plain::from_bytes::(&self.0.0) + plain::from_bytes::(&self.0 .0) .expect("expected FADT struct to already be validated in Deref impl") } } @@ -788,14 +705,12 @@ impl Fadt { let dsdt_ptr = match fadt.acpi_2_struct() { Some(fadt2) => usize::try_from(fadt2.x_dsdt).unwrap_or_else(|_| { - usize::try_from(fadt.dsdt) - .expect("expected any given u32 to fit within usize") + usize::try_from(fadt.dsdt).expect("expected any given u32 to fit within usize") }), - None => usize::try_from(fadt.dsdt) - .expect("expected any given u32 to fit within usize") + None => usize::try_from(fadt.dsdt).expect("expected any given u32 to fit within usize"), }; - log::debug!("FACP at {:X}", {dsdt_ptr}); + log::debug!("FACP at {:X}", { dsdt_ptr }); let dsdt_sdt = match Sdt::load_from_physical(fadt.dsdt as usize) { Ok(dsdt) => dsdt, @@ -933,23 +848,61 @@ impl aml::Handler for AmlPhysMemHandler { 0 } - fn read_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u16 { + fn read_pci_u16( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + ) -> u16 { log::error!("read pci u8 {:X}", _device); 0 } - fn read_pci_u32(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u32 { + fn read_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + ) -> u32 { log::error!("read pci u8 {:X}", _device); 0 } - fn write_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u8) { + fn write_pci_u8( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u8, + ) { log::error!("write pci u8 {:X}", _device); } - fn write_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u16) { + fn write_pci_u16( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u16, + ) { log::error!("write pci u8 {:X}", _device); } - fn write_pci_u32(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u32) { + fn write_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u32, + ) { log::error!("write pci u8 {:X}", _device); } } @@ -1014,23 +967,61 @@ impl aml::Handler for AmlPhysMemHandler { 0 } - fn read_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u16 { + fn read_pci_u16( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + ) -> u16 { log::error!("read pci u8 {:X}", _device); 0 } - fn read_pci_u32(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u32 { + fn read_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + ) -> u32 { log::error!("read pci u8 {:X}", _device); 0 } - fn write_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u8) { + fn write_pci_u8( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u8, + ) { log::error!("write pci u8 {:X}", _device); } - fn write_pci_u16(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u16) { + fn write_pci_u16( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u16, + ) { log::error!("write pci u8 {:X}", _device); } - fn write_pci_u32(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16, _value: u32) { + fn write_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u32, + ) { log::error!("write pci u8 {:X}", _device); } } diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index d09b4aee33..99151814f1 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -45,7 +45,7 @@ impl HandleKind<'_> { Self::TopLevel => TOPLEVEL_CONTENTS.len(), Self::Tables => acpi_ctx.tables().len().checked_mul(TABLE_DENTRY_LENGTH).unwrap_or(usize::max_value()), Self::Table(signature) => acpi_ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.length(), - Self::Symbols(aml_symbols) => aml_symbols.to_str().len(), + Self::Symbols(aml_symbols) => aml_symbols.symbols_str.len(), Self::Symbol(description) => description.len(), }) } @@ -287,7 +287,7 @@ impl SchemeMut for AcpiScheme<'_> { } HandleKind::Symbols(aml_symbols) => { - let symbols = aml_symbols.to_str(); + let symbols = &aml_symbols.symbols_str; let offset = std::cmp::min(symbols.len(), handle.offset); let src_buf = &symbols.as_bytes()[offset..]; diff --git a/amlserde/Cargo.toml b/amlserde/Cargo.toml new file mode 100644 index 0000000000..49adbe294e --- /dev/null +++ b/amlserde/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "amlserde" +version = "0.0.1" +authors = ["Ron Williams"] +repository = "https://gitlab.redox-os.org/redox-os/drivers" +description = "Library for serializing AML symbols" +categories = ["hardware-support"] +license = "MIT/Apache-2.0" +edition = "2021" + +[dependencies] +aml = { git = "https://github.com/rw-vanc/acpi.git", branch = "cumulative" } +rustc-hash = "1.1.0" +serde = { version = "1.0", features = ["derive"] } +toml = "0.7.3" diff --git a/amlserde/src/lib.rs b/amlserde/src/lib.rs new file mode 100644 index 0000000000..51417c776f --- /dev/null +++ b/amlserde/src/lib.rs @@ -0,0 +1,295 @@ +use aml::{ + value::{FieldAccessType, FieldUpdateRule, RegionSpace}, + AmlContext, AmlHandle, AmlName, AmlValue, +}; +use rustc_hash::FxHashMap; +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct AmlSerde { + pub name: String, + pub value: AmlSerdeValue, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum AmlSerdeValue { + Boolean(bool), + Integer(u64), + String(String), + OpRegion { + region: AmlSerdeRegionSpace, + offset: u64, + length: u64, + parent_device: Option, + }, + Field { + region: String, + flags: AmlSerdeFieldFlags, + offset: u64, + length: u64, + }, + Device, + Method { + arg_count: u8, + serialize: bool, + sync_level: u8, + }, + Buffer, + BufferField { + offset: u64, + length: u64, + }, + Processor { + id: u8, + pblk_address: u32, + pblk_len: u8, + }, + Mutex { + sync_level: u8, + }, + Package { + contents: Vec, + }, + PowerResource { + system_level: u8, + resource_order: u16, + }, + ThermalZone, + External, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum AmlSerdeRegionSpace { + SystemMemory, + SystemIo, + PciConfig, + EmbeddedControl, + SMBus, + SystemCmos, + PciBarTarget, + IPMI, + GeneralPurposeIo, + GenericSerialBus, + OemDefined(u8), +} + +#[derive(Debug, Serialize, Deserialize)] +pub struct AmlSerdeFieldFlags { + access_type: AmlSerdeFieldAccessType, + lock_rule: bool, + update_rule: AmlSerdeFieldUpdateRule, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum AmlSerdeFieldAccessType { + Any, + Byte, + Word, + DWord, + QWord, + Buffer, +} + +#[derive(Debug, Serialize, Deserialize)] +pub enum AmlSerdeFieldUpdateRule { + Preserve, + WriteAsOnes, + WriteAsZeros, +} + +impl AmlSerde { + pub fn default() -> Self { + Self { + name: "name".to_owned(), + value: AmlSerdeValue::String(String::default()), + } + } + + pub fn from_aml( + aml_context: &AmlContext, + aml_lookup: &AmlHandleLookup, + handle: &AmlHandle, + ) -> Option { + let name = if let Some((name, _handle)) = aml_lookup.get(handle) { + name.to_owned() + } else { + return None; + }; + + let aml_value = if let Ok(aml_value) = aml_context.namespace.get(handle.clone()) { + aml_value + } else { + return None; + }; + + let value = if let Some(value) = AmlSerdeValue::from_aml_value(aml_value, aml_lookup) { + value + } else { + return None; + }; + + Some(AmlSerde { name, value }) + } +} + +impl AmlSerdeValue { + pub fn default() -> Self { + AmlSerdeValue::String("".to_owned()) + } + + fn from_aml_value(aml_value: &AmlValue, aml_lookup: &AmlHandleLookup) -> Option { + Some(match aml_value { + AmlValue::Boolean(b) => AmlSerdeValue::Boolean(b.to_owned()), + + AmlValue::Integer(n) => AmlSerdeValue::Integer(n.to_owned()), + + AmlValue::String(s) => AmlSerdeValue::String(s.to_owned()), + + AmlValue::OpRegion { + region, + offset, + length, + parent_device, + } => AmlSerdeValue::OpRegion { + region: match region { + RegionSpace::SystemMemory => AmlSerdeRegionSpace::SystemMemory, + RegionSpace::SystemIo => AmlSerdeRegionSpace::SystemIo, + RegionSpace::PciConfig => AmlSerdeRegionSpace::PciConfig, + RegionSpace::EmbeddedControl => AmlSerdeRegionSpace::EmbeddedControl, + RegionSpace::SMBus => AmlSerdeRegionSpace::SMBus, + RegionSpace::SystemCmos => AmlSerdeRegionSpace::SystemCmos, + RegionSpace::PciBarTarget => AmlSerdeRegionSpace::PciBarTarget, + RegionSpace::IPMI => AmlSerdeRegionSpace::IPMI, + RegionSpace::GeneralPurposeIo => AmlSerdeRegionSpace::GeneralPurposeIo, + RegionSpace::GenericSerialBus => AmlSerdeRegionSpace::GenericSerialBus, + RegionSpace::OemDefined(n) => AmlSerdeRegionSpace::OemDefined(n.to_owned()), + }, + offset: offset.to_owned(), + length: length.to_owned(), + parent_device: if let Some(parent) = parent_device { + Some(pretty_name(parent)) + } else { + None + }, + }, + + AmlValue::Field { + region, + flags, + offset, + length, + } => AmlSerdeValue::Field { + region: if let Some((region, _handle)) = aml_lookup.get(region) { + region.to_owned() + } else { + return None; + }, + flags: AmlSerdeFieldFlags { + access_type: match flags.access_type() { + Ok(FieldAccessType::Any) => AmlSerdeFieldAccessType::Any, + Ok(FieldAccessType::Byte) => AmlSerdeFieldAccessType::Byte, + Ok(FieldAccessType::Word) => AmlSerdeFieldAccessType::Word, + Ok(FieldAccessType::DWord) => AmlSerdeFieldAccessType::DWord, + Ok(FieldAccessType::QWord) => AmlSerdeFieldAccessType::QWord, + Ok(FieldAccessType::Buffer) => AmlSerdeFieldAccessType::Buffer, + _ => return None, + }, + lock_rule: flags.lock_rule(), + update_rule: match flags.field_update_rule() { + Ok(FieldUpdateRule::Preserve) => AmlSerdeFieldUpdateRule::Preserve, + Ok(FieldUpdateRule::WriteAsOnes) => AmlSerdeFieldUpdateRule::WriteAsOnes, + Ok(FieldUpdateRule::WriteAsZeros) => AmlSerdeFieldUpdateRule::WriteAsZeros, + _ => return None, + }, + }, + offset: offset.to_owned(), + length: length.to_owned(), + }, + + AmlValue::Device => AmlSerdeValue::Device, + + AmlValue::Method { flags, code: _ } => AmlSerdeValue::Method { + arg_count: flags.arg_count(), + serialize: flags.serialize(), + sync_level: flags.sync_level(), + }, + AmlValue::Buffer(_) => AmlSerdeValue::Buffer, + AmlValue::BufferField { + buffer_data: _, + offset, + length, + } => AmlSerdeValue::BufferField { + offset: offset.to_owned(), + length: length.to_owned(), + }, + AmlValue::Processor { + id, + pblk_address, + pblk_len, + } => AmlSerdeValue::Processor { + id: id.to_owned(), + pblk_address: pblk_address.to_owned(), + pblk_len: pblk_len.to_owned(), + }, + AmlValue::Mutex { sync_level } => AmlSerdeValue::Mutex { + sync_level: sync_level.to_owned(), + }, + AmlValue::Package(aml_contents) => AmlSerdeValue::Package { + contents: aml_contents + .iter() + .filter_map(|item| AmlSerdeValue::from_aml_value(item, aml_lookup)) + .collect(), + }, + + AmlValue::PowerResource { + system_level, + resource_order, + } => AmlSerdeValue::PowerResource { + system_level: system_level.to_owned(), + resource_order: resource_order.to_owned(), + }, + AmlValue::ThermalZone => AmlSerdeValue::ThermalZone, + AmlValue::External => AmlSerdeValue::External, + }) + } +} + +pub struct AmlHandleLookup { + map: FxHashMap, +} + +impl AmlHandleLookup { + pub fn new() -> Self { + Self { + map: FxHashMap::default(), + } + } + + fn handle_to_key(&self, handle: &AmlHandle) -> String { + format!("{:?}", handle) + } + + pub fn insert(&mut self, handle: AmlHandle, name: String) { + self.map.insert(self.handle_to_key(&handle), (name, handle)); + } + + pub fn get(&self, handle: &AmlHandle) -> Option<&(String, AmlHandle)> { + self.map.get(&self.handle_to_key(handle)) + } +} + +/// Remove trailing underscores from each name segment +pub fn pretty_name(aml_name: &AmlName) -> String { + let mut name = aml_name.as_string(); + // remove leading slash + name = name.trim_start_matches("\\").to_owned(); + // remove unnecessary underscores + while let Some(index) = name.find("_.") { + name.remove(index); + } + while name.len() > 0 && &name[name.len() - 1..] == "_" { + name.pop(); + } + name.shrink_to_fit(); + name +} From 1baac63934bdff98e5a50752b1925e7126025fb8 Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Wed, 29 Mar 2023 01:41:13 -0700 Subject: [PATCH 0612/1301] clean up aml symbols --- Cargo.lock | 502 ++++++++++++++++++++++++++++++-------------- acpid/Cargo.toml | 1 - acpid/src/acpi.rs | 203 ++++++++++-------- acpid/src/scheme.rs | 4 +- amlserde/src/lib.rs | 90 ++++---- 5 files changed, 522 insertions(+), 278 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 58740eac28..9387e39945 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,7 +11,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", "spin", ] @@ -28,11 +28,10 @@ dependencies = [ "plain", "redox-daemon", "redox-log", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", "rustc-hash", "serde_json", "thiserror", - "toml 0.7.3", ] [[package]] @@ -46,7 +45,7 @@ dependencies = [ "partitionlib", "redox-daemon", "redox-log", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] @@ -57,13 +56,13 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] name = "aml" version = "0.16.3" -source = "git+https://github.com/rw-vanc/acpi.git?branch=cumulative#ac37b03f974ca58f3c024a058224ffd5b77fed31" +source = "git+https://github.com/rw-vanc/acpi.git?branch=cumulative#e4eb93891367e73d3633804002aa050edfbacb6e" dependencies = [ "bit_field", "bitvec", @@ -82,6 +81,15 @@ dependencies = [ "toml 0.7.3", ] +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "ansi_term" version = "0.12.1" @@ -149,7 +157,7 @@ version = "0.1.0" dependencies = [ "orbclient", "redox-daemon", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] @@ -163,9 +171,9 @@ dependencies = [ [[package]] name = "bit_field" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitflags" @@ -197,9 +205,9 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "bumpalo" -version = "3.10.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" [[package]] name = "byteorder" @@ -215,9 +223,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.73" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -243,14 +251,16 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" dependencies = [ - "libc", + "iana-time-zone", + "js-sys", "num-integer", "num-traits", "time", + "wasm-bindgen", "winapi 0.3.9", ] @@ -280,13 +290,29 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.48" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8ad8cef104ac57b68b89df3208164d228503abbdce70f6880ffa3d970e7443a" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" dependencies = [ "cc", ] +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + [[package]] name = "crc" version = "1.8.1" @@ -308,12 +334,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.11", + "crossbeam-utils 0.8.15", ] [[package]] @@ -329,12 +355,11 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.11" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51887d4adc7b564537b15adcfb307936f8075dfcd5f00dde9a9f1d29383682bc" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if 1.0.0", - "once_cell", ] [[package]] @@ -343,6 +368,50 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" +[[package]] +name = "cxx" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" +dependencies = [ + "cc", + "cxxbridge-flags", + "cxxbridge-macro", + "link-cplusplus", +] + +[[package]] +name = "cxx-build" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" +dependencies = [ + "cc", + "codespan-reporting", + "once_cell", + "proc-macro2", + "quote", + "scratch", + "syn 2.0.11", +] + +[[package]] +name = "cxxbridge-flags" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" + +[[package]] +name = "cxxbridge-macro" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.11", +] + [[package]] name = "e1000d" version = "0.1.0" @@ -351,7 +420,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] @@ -389,9 +458,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.21" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" dependencies = [ "futures-channel", "futures-core", @@ -404,9 +473,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" dependencies = [ "futures-core", "futures-sink", @@ -414,15 +483,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" dependencies = [ "futures-core", "futures-task", @@ -431,38 +500,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", ] [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" dependencies = [ "futures-channel", "futures-core", @@ -511,6 +580,30 @@ dependencies = [ "libc", ] +[[package]] +name = "iana-time-zone" +version = "0.1.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +dependencies = [ + "cxx", + "cxx-build", +] + [[package]] name = "ided" version = "0.1.0" @@ -521,7 +614,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] @@ -545,7 +638,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", "spin", ] @@ -579,9 +672,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.2" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "ixgbed" @@ -591,14 +684,14 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] name = "js-sys" -version = "0.3.59" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258451ab10b34f8af53416d1fdab72c22e805f0c92a1136d59470ec0b11138b2" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" dependencies = [ "wasm-bindgen", ] @@ -627,9 +720,18 @@ checksum = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" [[package]] name = "libc" -version = "0.2.139" +version = "0.2.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" + +[[package]] +name = "link-cplusplus" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" +dependencies = [ + "cc", +] [[package]] name = "linked-hash-map" @@ -639,9 +741,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" dependencies = [ "autocfg 1.1.0", "scopeguard", @@ -658,9 +760,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" [[package]] name = "maybe-uninit" @@ -717,7 +819,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#34d1ec9c2e9f7904b57547ca16d4c3145c109880" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#105ed1ea43413a91152b289fbe76e7efc996e933" dependencies = [ "arg_parser", "extra", @@ -757,7 +859,7 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", ] [[package]] @@ -799,21 +901,22 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.3.4", - "smallvec 1.9.0", + "redox_syscall 0.3.5", + "smallvec 1.10.0", ] [[package]] name = "once_cell" -version = "1.13.0" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "orbclient" -version = "0.3.32" -source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#192dc30edbad43ee8c5348411b162600d43dfaf9" +version = "0.3.43" +source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#f5f5d5cc761b61a9ee15a68b086c4967857ba805" dependencies = [ + "cfg-if 1.0.0", "libc", "raw-window-handle 0.3.4", "redox_syscall 0.2.16", @@ -850,7 +953,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", ] [[package]] @@ -867,15 +970,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if 1.0.0", "instant", "libc", "redox_syscall 0.2.16", - "smallvec 1.9.0", + "smallvec 1.10.0", "winapi 0.3.9", ] @@ -907,7 +1010,7 @@ checksum = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", ] [[package]] @@ -918,13 +1021,12 @@ checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" [[package]] name = "pbr" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff5751d87f7c00ae6403eb1fcbba229b9c76c9a30de8c1cf87182177b168cea2" +checksum = "ed5827dfa0d69b6c92493d6c38e633bbaa5937c153d0d7c28bf12313f8c6d514" dependencies = [ - "crossbeam-channel 0.5.6", + "crossbeam-channel 0.5.7", "libc", - "time", "winapi 0.3.9", ] @@ -940,13 +1042,13 @@ dependencies = [ "paw", "plain", "redox-log", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", "serde", "serde_json", - "smallvec 1.9.0", + "smallvec 1.10.0", "structopt", "thiserror", - "toml 0.5.9", + "toml 0.5.11", ] [[package]] @@ -954,7 +1056,7 @@ name = "pcspkrd" version = "0.1.0" dependencies = [ "redox-daemon", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] @@ -990,7 +1092,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", "version_check", ] @@ -1021,7 +1123,7 @@ dependencies = [ "bitflags", "orbclient", "redox-daemon", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] @@ -1160,9 +1262,9 @@ dependencies = [ [[package]] name = "ransid" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22b9af151b0590163dfa64e1c92c0831377d61942df4c19820c704390ebc3045" +checksum = "86e40bb0bbe3ec5efa241ed57fad611b2c1642f1c60550f647201acee2494553" dependencies = [ "log", "vte", @@ -1214,7 +1316,7 @@ checksum = "cbf6d33a003a5c0b94ec11f10c7c797303f236592964ddb1bfb93e1b438a1557" dependencies = [ "chrono", "log", - "smallvec 1.9.0", + "smallvec 1.10.0", "termion", ] @@ -1223,7 +1325,7 @@ name = "redox_event" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/event.git#f7db3d25ca5e282c12ded12bf6c720087b570132" dependencies = [ - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] @@ -1237,9 +1339,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb02a9aee8e8c7ad8d86890f1e16b49e0bbbffc9961ff3788c31d57c98bcbf03" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags", ] @@ -1264,7 +1366,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] @@ -1286,9 +1388,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.10" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "sb16d" @@ -1299,7 +1401,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", "spin", ] @@ -1309,6 +1411,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "scratch" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" + [[package]] name = "scroll" version = "0.10.2" @@ -1326,7 +1434,7 @@ checksum = "aaaae8f38bb311444cfb7f1979af0bc9240d95795f75f9ceddf6a59b79ceffa0" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", ] [[package]] @@ -1356,22 +1464,22 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.158" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9" +checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.158" +version = "1.0.159" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad" +checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn 2.0.10", + "syn 2.0.11", ] [[package]] @@ -1396,9 +1504,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg 1.1.0", ] @@ -1414,27 +1522,27 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" dependencies = [ "serde", ] [[package]] name = "spin" -version = "0.9.4" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" +checksum = "c0959fd6f767df20b231736396e4f602171e00d95205676286e79d4a4eb67bef" dependencies = [ "lock_api", ] [[package]] name = "spinning_top" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c" +checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" dependencies = [ "lock_api", ] @@ -1491,14 +1599,14 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", ] [[package]] name = "syn" -version = "1.0.98" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -1507,9 +1615,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.10" +version = "2.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aad1363ed6d37b84299588d62d3a7d95b5a5c2d9aad5c85609fda12afaa1f40" +checksum = "21e3787bb71465627110e7d87ed4faaa36c1f61042ee67badb9e2ef173accc40" dependencies = [ "proc-macro2", "quote", @@ -1522,6 +1630,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + [[package]] name = "termion" version = "1.5.6" @@ -1545,29 +1662,29 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.31" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.31" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 2.0.11", ] [[package]] name = "time" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", "wasi", @@ -1585,15 +1702,15 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "toml" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] @@ -1634,36 +1751,36 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.2" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" [[package]] name = "unicode-normalization" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" [[package]] name = "unicode-width" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" [[package]] name = "url" @@ -1692,7 +1809,7 @@ dependencies = [ "log", "orbclient", "redox-log", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", "ux", "xhcid", ] @@ -1704,7 +1821,7 @@ dependencies = [ "base64", "plain", "redox-daemon", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", "thiserror", "xhcid", ] @@ -1726,9 +1843,9 @@ dependencies = [ [[package]] name = "ux" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5efdcf885b33bb81bc9336e66cebc10d503288449466c0e43e51250ddc93a3d8" +checksum = "2cb3ff47e36907a6267572c1e398ff32ef78ac5131de8aa272e53846592c207e" [[package]] name = "vboxd" @@ -1737,7 +1854,7 @@ dependencies = [ "orbclient", "redox-daemon", "redox_event", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", ] [[package]] @@ -1748,9 +1865,9 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version-compare" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" [[package]] name = "version_check" @@ -1765,7 +1882,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", "rusttype", ] @@ -1786,9 +1903,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.82" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7652e3f6c4706c8d9cd54832c4a4ccb9b5336e2c3bd154d5cccfbf1c1f5f7d" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -1796,24 +1913,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.82" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662cd44805586bd52971b9586b1df85cdbbd9112e4ef4d8f41559c334dc6ac3f" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.82" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b260f13d3012071dfb1512849c033b1925038373aea48ced3012c09df952c602" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1821,28 +1938,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.82" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be8e654bdd9b79216c2929ab90721aa82faf65c48cdf08bdc4e7f51357b80da" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn 1.0.98", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.82" +version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6598dd0bd3c7d51095ff6531a5b23e02acdc81804e30d8f07afb77b7215a140a" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" [[package]] name = "web-sys" -version = "0.3.59" +version = "0.3.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed055ab27f941423197eb86b2035720b1a3ce40504df082cac2ecc6ed73335a1" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" dependencies = [ "js-sys", "wasm-bindgen", @@ -1876,12 +1993,87 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi 0.3.9", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "winnow" version = "0.4.1" @@ -1925,10 +2117,10 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.4", + "redox_syscall 0.3.5", "serde", "serde_json", - "smallvec 1.9.0", + "smallvec 1.10.0", "thiserror", - "toml 0.5.9", + "toml 0.5.11", ] diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 3e052af591..f093a1e284 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -18,6 +18,5 @@ redox-log = "0.1.1" redox_syscall = "0.3" rustc-hash = "1.1.0" thiserror = "1" -toml = "0.7" serde_json = "1.0.94" amlserde = { path = "../amlserde" } \ No newline at end of file diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index c33dc33fb0..5b72fb1d26 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,10 +1,9 @@ -use amlserde::{AmlHandleLookup, AmlSerde}; use rustc_hash::FxHashMap; use std::convert::{TryFrom, TryInto}; +use std::fmt::Write; use std::ops::Deref; use std::sync::Arc; use std::{fmt, mem}; -use std::fmt::Write; use syscall::flag::PhysmapFlags; @@ -14,8 +13,9 @@ use syscall::io::{Io, Pio}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use thiserror::Error; -use aml::{AmlContext, AmlError, AmlHandle, AmlName, AmlValue}; -use amlserde::pretty_name; +use aml::{AmlContext, AmlError, AmlHandle, AmlName}; +use amlserde::aml_serde_name::aml_to_symbol; +use amlserde::{AmlHandleLookup, AmlSerde}; pub mod dmar; use self::dmar::Dmar; @@ -54,8 +54,7 @@ impl SdtHeader { } } pub fn length(&self) -> usize { - self - .length + self.length .try_into() .expect("expected usize to be at least 32 bits") } @@ -120,9 +119,7 @@ impl Deref for PhysmapGuard { type Target = [u8]; fn deref(&self) -> &Self::Target { - unsafe { - std::slice::from_raw_parts(self.virt as *const u8, self.size) - } + unsafe { std::slice::from_raw_parts(self.virt as *const u8, self.size) } } } impl Drop for PhysmapGuard { @@ -247,8 +244,107 @@ pub struct Ssdt(Sdt); pub struct AmlSymbols { aml_context: AmlContext, // k = name, v = description - symbols_cache: FxHashMap, - pub symbols_str: String, + cache: FxHashMap, + list: String, +} + +impl AmlSymbols { + pub fn new() -> Self { + Self { + aml_context: AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None), + cache: FxHashMap::default(), + list: "".to_string(), + } + } + + pub fn mut_aml_context(&mut self) -> &mut AmlContext { + &mut self.aml_context + } + + pub fn symbols_str(&self) -> &String { + &self.list + } + + pub fn symbols_cache(&self) -> &FxHashMap { + &self.cache + } + + pub fn parse_table(&mut self, aml: &[u8]) -> Result<(), AmlError> { + self.aml_context.parse_table(aml) + } + + pub fn lookup(&self, symbol: &str) -> Option { + if let Some(description) = self.cache.get(symbol) { + log::trace!("Found symbol in cache, {}, {}", symbol, description); + return Some(description.to_owned()); + } + None + } + + pub fn build_cache(&mut self) { + let mut symbol_list: Vec<(AmlName, String, AmlHandle)> = Vec::with_capacity(5000); + + if self + .aml_context + .namespace + .traverse(|level_aml_name, level| { + for (child_seg, handle) in level.values.iter() { + if let Ok(aml_name) = + AmlName::from_name_seg(child_seg.to_owned()).resolve(level_aml_name) + { + let name = aml_to_symbol(&aml_name); + symbol_list.push((aml_name, name, handle.to_owned())); + } else { + log::error!( + "AmlName resolve failed, {:?}:{:?}", + level_aml_name, + child_seg + ); + } + } + Ok(true) + }) + .is_err() + { + log::error!("Namespace traverse failed"); + return; + } + + let mut symbols_str = String::with_capacity(symbol_list.len() * 10); + let mut handle_lookup = AmlHandleLookup::new(); + + for (aml_name, name, handle) in &symbol_list { + let _ = writeln!(symbols_str, "{}", &name); + handle_lookup.insert(handle.to_owned(), aml_name.to_owned()); + } + + symbols_str.shrink_to_fit(); + + let mut symbol_cache: FxHashMap = FxHashMap::default(); + + for (aml_name, name, handle) in &symbol_list { + // create an empty entry, in case something goes wrong with serialization + symbol_cache.insert(name.to_owned(), "".to_owned()); + if let Some(ser_value) = AmlSerde::from_aml( + &mut self.aml_context, + &handle_lookup, + &aml_to_symbol(aml_name), + aml_name, + handle, + ) { + if let Ok(ser_string) = serde_json::to_string_pretty(&ser_value) { + // replace the empty entry + symbol_cache.insert(name.to_owned(), ser_string); + } + } + } + + // Cache the new list + log::trace!("Updating symbols list"); + + self.list = symbols_str; + self.cache = symbol_cache; + } } pub struct AcpiContext { @@ -286,14 +382,7 @@ impl AcpiContext { fadt: None, // Temporary values - aml_symbols: RwLock::new(AmlSymbols { - aml_context: AmlContext::new( - Box::new(AmlPhysMemHandler), - aml::DebugVerbosity::None, - ), - symbols_cache: FxHashMap::default(), - symbols_str: "".to_string(), - }), + aml_symbols: RwLock::new(AmlSymbols::new()), next_ctx: RwLock::new(0), @@ -307,17 +396,16 @@ impl AcpiContext { Fadt::init(&mut this); //TODO (hangs on real hardware): Dmar::init(&this); - this.aml_symbols.write().aml_context = AcpiContext::build_aml_context(&this); + AcpiContext::build_aml_context(&this); this } - fn build_aml_context(acpi: &AcpiContext) -> AmlContext { - let mut aml_context = - AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None); + fn build_aml_context(acpi: &AcpiContext) { + let mut aml_symbols = acpi.aml_symbols.write(); if let Some(dsdt) = acpi.dsdt() { - match aml_context.parse_table(dsdt.aml()) { + match aml_symbols.parse_table(dsdt.aml()) { Ok(_) => log::trace!("Parsed DSDT"), Err(e) => { log::error!("DSDT: {:?}", e); @@ -328,14 +416,13 @@ impl AcpiContext { } for ssdt in acpi.ssdts() { - match aml_context.parse_table(ssdt.aml()) { + match aml_symbols.parse_table(ssdt.aml()) { Ok(_) => log::trace!("Parsed SSDT"), Err(e) => { log::error!("SSDT: {:?}", e); } } } - aml_context } pub fn dsdt(&self) -> Option<&Dsdt> { @@ -402,18 +489,16 @@ impl AcpiContext { pub fn aml_lookup(&self, symbol: &str) -> Option { if let Ok(aml_symbols) = self.aml_symbols() { - if let Some(description) = aml_symbols.symbols_cache.get(symbol) { - log::trace!("Found symbol in cache, {}, {}", symbol, description); - return Some(description.to_owned()); - } + aml_symbols.lookup(symbol) + } else { + None } - None } pub fn aml_symbols(&self) -> Result, AmlError> { // return the cached value if it exists let symbols = self.aml_symbols.read(); - if !symbols.symbols_cache.is_empty() { + if !symbols.symbols_cache().is_empty() { return Ok(symbols); } // free the read lock @@ -422,57 +507,9 @@ impl AcpiContext { // List has not been initialized, we have to build it log::trace!("Creating symbols list"); - let mut symbol_list: Vec<(AmlName, String, AmlHandle)> = Vec::with_capacity(5000); - let mut aml_symbols = self.aml_symbols.write(); - aml_symbols - .aml_context - .namespace - .traverse(|level_aml_name, level| { - for (child_seg, handle) in level.values.iter() { - if let Ok(aml_name) = - AmlName::from_name_seg(child_seg.to_owned()).resolve(level_aml_name) - { - let name = pretty_name(&aml_name); - symbol_list.push((aml_name, name, handle.to_owned())); - } else { - log::error!( - "AmlName resolve failed, {:?}:{:?}", - level_aml_name, - child_seg - ); - } - } - Ok(true) - })?; - - let mut symbols_str = String::with_capacity(symbol_list.len() * 10); - let mut handle_lookup = AmlHandleLookup::new(); - - for (_aml_name, name, handle) in &symbol_list { - let _ = writeln!(symbols_str, "{}", &name); - handle_lookup.insert(handle.to_owned(), name.to_owned()); - } - - symbols_str.shrink_to_fit(); - - let mut symbol_cache: FxHashMap = FxHashMap::default(); - - for (_aml_name, name, handle) in &symbol_list { - if let Some(ser_value) = AmlSerde::from_aml(&aml_symbols.aml_context, &handle_lookup, handle) { - if let Ok(ser_string) = serde_json::to_string_pretty(&ser_value) { - symbol_cache.insert(name.to_owned(), ser_string); - } - } - } - - - // Cache the new list - log::trace!("Updating symbols list"); - - aml_symbols.symbols_str = symbols_str; - aml_symbols.symbols_cache = symbol_cache; + aml_symbols.build_cache(); // return the cached value Ok(RwLockWriteGuard::downgrade(aml_symbols)) @@ -481,8 +518,8 @@ impl AcpiContext { /// Discard any cached symbols list. To be called if the AML namespace changes. pub fn aml_symbols_reset(&self) { let mut aml_symbols = self.aml_symbols.write(); - aml_symbols.symbols_cache = FxHashMap::default(); - aml_symbols.symbols_str = "".to_string(); + aml_symbols.cache = FxHashMap::default(); + aml_symbols.list = "".to_string(); } /// Set Power State diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index 99151814f1..a4d598fbc5 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -45,7 +45,7 @@ impl HandleKind<'_> { Self::TopLevel => TOPLEVEL_CONTENTS.len(), Self::Tables => acpi_ctx.tables().len().checked_mul(TABLE_DENTRY_LENGTH).unwrap_or(usize::max_value()), Self::Table(signature) => acpi_ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.length(), - Self::Symbols(aml_symbols) => aml_symbols.symbols_str.len(), + Self::Symbols(aml_symbols) => aml_symbols.symbols_str().len(), Self::Symbol(description) => description.len(), }) } @@ -287,7 +287,7 @@ impl SchemeMut for AcpiScheme<'_> { } HandleKind::Symbols(aml_symbols) => { - let symbols = &aml_symbols.symbols_str; + let symbols = aml_symbols.symbols_str(); let offset = std::cmp::min(symbols.len(), handle.offset); let src_buf = &symbols.as_bytes()[offset..]; diff --git a/amlserde/src/lib.rs b/amlserde/src/lib.rs index 51417c776f..ae76fee781 100644 --- a/amlserde/src/lib.rs +++ b/amlserde/src/lib.rs @@ -1,7 +1,5 @@ -use aml::{ - value::{FieldAccessType, FieldUpdateRule, RegionSpace}, - AmlContext, AmlHandle, AmlName, AmlValue, -}; +use aml::value::{FieldAccessType, FieldUpdateRule, RegionSpace}; +use aml::{AmlContext, AmlHandle, AmlName, AmlValue}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; @@ -75,9 +73,9 @@ pub enum AmlSerdeRegionSpace { #[derive(Debug, Serialize, Deserialize)] pub struct AmlSerdeFieldFlags { - access_type: AmlSerdeFieldAccessType, - lock_rule: bool, - update_rule: AmlSerdeFieldUpdateRule, + pub access_type: AmlSerdeFieldAccessType, + pub lock_rule: bool, + pub update_rule: AmlSerdeFieldUpdateRule, } #[derive(Debug, Serialize, Deserialize)] @@ -106,16 +104,12 @@ impl AmlSerde { } pub fn from_aml( - aml_context: &AmlContext, + aml_context: &mut AmlContext, aml_lookup: &AmlHandleLookup, + name: &String, + aml_name: &AmlName, handle: &AmlHandle, ) -> Option { - let name = if let Some((name, _handle)) = aml_lookup.get(handle) { - name.to_owned() - } else { - return None; - }; - let aml_value = if let Ok(aml_value) = aml_context.namespace.get(handle.clone()) { aml_value } else { @@ -128,7 +122,10 @@ impl AmlSerde { return None; }; - Some(AmlSerde { name, value }) + Some(AmlSerde { + name: aml_name.to_string(), + value, + }) } } @@ -167,7 +164,7 @@ impl AmlSerdeValue { offset: offset.to_owned(), length: length.to_owned(), parent_device: if let Some(parent) = parent_device { - Some(pretty_name(parent)) + Some(parent.to_string()) } else { None }, @@ -180,7 +177,7 @@ impl AmlSerdeValue { length, } => AmlSerdeValue::Field { region: if let Some((region, _handle)) = aml_lookup.get(region) { - region.to_owned() + region.to_string() } else { return None; }, @@ -254,8 +251,42 @@ impl AmlSerdeValue { } } +pub mod aml_serde_name { + use aml::AmlName; + + /// Add a leading backslash to make the name a valid + /// namespace reference + pub fn to_aml_format(pretty_name: &String) -> String { + format!("\\{}", pretty_name) + } + + /// convert a string from AML namespace style to + /// acpi symbol style + pub fn to_symbol(aml_style_name: &String) -> String { + let mut name = aml_style_name.to_owned(); + + // remove leading slash + name = name.trim_start_matches("\\").to_owned(); + // remove unnecessary underscores + while let Some(index) = name.find("_.") { + name.remove(index); + } + while name.len() > 0 && &name[name.len() - 1..] == "_" { + name.pop(); + } + name.shrink_to_fit(); + name + } + + /// Convert to string and remove + /// trailing underscores from each name segment + pub fn aml_to_symbol(aml_name: &AmlName) -> String { + to_symbol(&aml_name.as_string()) + } +} + pub struct AmlHandleLookup { - map: FxHashMap, + map: FxHashMap, } impl AmlHandleLookup { @@ -269,27 +300,12 @@ impl AmlHandleLookup { format!("{:?}", handle) } - pub fn insert(&mut self, handle: AmlHandle, name: String) { - self.map.insert(self.handle_to_key(&handle), (name, handle)); + pub fn insert(&mut self, handle: AmlHandle, aml_name: AmlName) { + self.map + .insert(self.handle_to_key(&handle), (aml_name, handle)); } - pub fn get(&self, handle: &AmlHandle) -> Option<&(String, AmlHandle)> { + pub fn get(&self, handle: &AmlHandle) -> Option<&(AmlName, AmlHandle)> { self.map.get(&self.handle_to_key(handle)) } } - -/// Remove trailing underscores from each name segment -pub fn pretty_name(aml_name: &AmlName) -> String { - let mut name = aml_name.as_string(); - // remove leading slash - name = name.trim_start_matches("\\").to_owned(); - // remove unnecessary underscores - while let Some(index) = name.find("_.") { - name.remove(index); - } - while name.len() > 0 && &name[name.len() - 1..] == "_" { - name.pop(); - } - name.shrink_to_fit(); - name -} From d682fb7994515014a424385a9d4fb06f145fec39 Mon Sep 17 00:00:00 2001 From: Will Angenent Date: Tue, 4 Apr 2023 18:21:31 +0100 Subject: [PATCH 0613/1301] Update orbclient --- Cargo.lock | 110 ++++++++++++++++++++++++++--------------------------- Cargo.toml | 2 +- 2 files changed, 56 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9387e39945..33d7a1492c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -309,9 +309,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "crc" @@ -392,7 +392,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.11", + "syn 2.0.13", ] [[package]] @@ -409,7 +409,7 @@ checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.13", ] [[package]] @@ -458,9 +458,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -473,9 +473,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -483,15 +483,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -500,38 +500,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.13", ] [[package]] name = "futures-sink" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -582,9 +582,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.54" +version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c17cc76786e99f8d2f055c11159e7f0091c42474dcc3189fbab96072e873e6d" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -720,9 +720,9 @@ checksum = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" [[package]] name = "libc" -version = "0.2.140" +version = "0.2.141" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c" +checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" [[package]] name = "link-cplusplus" @@ -913,8 +913,8 @@ checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" [[package]] name = "orbclient" -version = "0.3.43" -source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#f5f5d5cc761b61a9ee15a68b086c4967857ba805" +version = "0.3.44" +source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#21d152240c4fc290a97d3d7a5adbc35ea495fdf9" dependencies = [ "cfg-if 1.0.0", "libc", @@ -1109,9 +1109,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.54" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e472a104799c74b514a57226160104aa483546de37e839ec50e3c2e41dd87534" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -1479,7 +1479,7 @@ checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.13", ] [[package]] @@ -1531,9 +1531,9 @@ dependencies = [ [[package]] name = "spin" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0959fd6f767df20b231736396e4f602171e00d95205676286e79d4a4eb67bef" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" dependencies = [ "lock_api", ] @@ -1615,9 +1615,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.11" +version = "2.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e3787bb71465627110e7d87ed4faaa36c1f61042ee67badb9e2ef173accc40" +checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" dependencies = [ "proc-macro2", "quote", @@ -1677,7 +1677,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.11", + "syn 2.0.13", ] [[package]] @@ -2010,18 +2010,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.46.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -2034,45 +2034,45 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" diff --git a/Cargo.toml b/Cargo.toml index e0d659d3ca..f68f051017 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,4 +30,4 @@ lto = "fat" [patch.crates-io] mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } -orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.28" } +orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } From 9fb4a8be04e22bf81624c3e8783162749ddd46f9 Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Thu, 13 Apr 2023 19:09:07 -0700 Subject: [PATCH 0614/1301] Add AmlHandler read/write of physaddr --- acpid/src/acpi.rs | 269 +++---------------------- acpid/src/aml_physmem.rs | 417 +++++++++++++++++++++++++++++++++++++++ acpid/src/main.rs | 1 + 3 files changed, 442 insertions(+), 245 deletions(-) create mode 100644 acpid/src/aml_physmem.rs diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 5b72fb1d26..417cd920fa 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -2,7 +2,7 @@ use rustc_hash::FxHashMap; use std::convert::{TryFrom, TryInto}; use std::fmt::Write; use std::ops::Deref; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use std::{fmt, mem}; use syscall::flag::PhysmapFlags; @@ -19,6 +19,7 @@ use amlserde::{AmlHandleLookup, AmlSerde}; pub mod dmar; use self::dmar::Dmar; +use crate::aml_physmem::{AmlPageCache, AmlPhysMemHandler}; #[cfg(target_arch = "aarch64")] pub const PAGE_SIZE: usize = 4096; @@ -244,15 +245,21 @@ pub struct Ssdt(Sdt); pub struct AmlSymbols { aml_context: AmlContext, // k = name, v = description - cache: FxHashMap, + symbol_cache: FxHashMap, + page_cache: Arc>, list: String, } impl AmlSymbols { pub fn new() -> Self { + let page_cache = Arc::new(Mutex::new(AmlPageCache::default())); Self { - aml_context: AmlContext::new(Box::new(AmlPhysMemHandler), aml::DebugVerbosity::None), - cache: FxHashMap::default(), + aml_context: AmlContext::new( + Box::new(AmlPhysMemHandler::new(Arc::clone(&page_cache))), + aml::DebugVerbosity::None, + ), + symbol_cache: FxHashMap::default(), + page_cache, list: "".to_string(), } } @@ -266,7 +273,7 @@ impl AmlSymbols { } pub fn symbols_cache(&self) -> &FxHashMap { - &self.cache + &self.symbol_cache } pub fn parse_table(&mut self, aml: &[u8]) -> Result<(), AmlError> { @@ -274,7 +281,7 @@ impl AmlSymbols { } pub fn lookup(&self, symbol: &str) -> Option { - if let Some(description) = self.cache.get(symbol) { + if let Some(description) = self.symbol_cache.get(symbol) { log::trace!("Found symbol in cache, {}, {}", symbol, description); return Some(description.to_owned()); } @@ -343,7 +350,7 @@ impl AmlSymbols { log::trace!("Updating symbols list"); self.list = symbols_str; - self.cache = symbol_cache; + self.symbol_cache = symbol_cache; } } @@ -423,6 +430,15 @@ impl AcpiContext { } } } + + if let Ok(mut page_cache) = aml_symbols.page_cache.lock() { + page_cache.clear(); + } else { + log::error!("failed to lock AmlPageCache"); + } + + // force drop of page_cache from the previous if let + {} } pub fn dsdt(&self) -> Option<&Dsdt> { @@ -518,7 +534,7 @@ impl AcpiContext { /// Discard any cached symbols list. To be called if the AML namespace changes. pub fn aml_symbols_reset(&self) { let mut aml_symbols = self.aml_symbols.write(); - aml_symbols.cache = FxHashMap::default(); + aml_symbols.symbol_cache = FxHashMap::default(); aml_symbols.list = "".to_string(); } @@ -825,240 +841,3 @@ impl AmlContainingTable for Ssdt { &*self.0 } } - -struct AmlPhysMemHandler; - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -impl aml::Handler for AmlPhysMemHandler { - fn read_u8(&self, _address: usize) -> u8 { - log::error!("read u8 {:X}", _address); - 0 - } - fn read_u16(&self, _address: usize) -> u16 { - log::error!("read u16 {:X}", _address); - 0 - } - fn read_u32(&self, _address: usize) -> u32 { - log::error!("read u32 {:X}", _address); - 0 - } - fn read_u64(&self, _address: usize) -> u64 { - log::error!("read u64 {:X}", _address); - 0 - } - - fn write_u8(&mut self, _address: usize, _value: u8) { - log::error!("write u8 {:X} = {:X}", _address, _value); - } - fn write_u16(&mut self, _address: usize, _value: u16) { - log::error!("write u16 {:X} = {:X}", _address, _value); - } - fn write_u32(&mut self, _address: usize, _value: u32) { - log::error!("write u32 {:X} = {:X}", _address, _value); - } - fn write_u64(&mut self, _address: usize, _value: u64) { - log::error!("write u64 {:X} = {:X}", _address, _value); - } - - fn read_io_u8(&self, port: u16) -> u8 { - Pio::::new(port).read() - } - fn read_io_u16(&self, port: u16) -> u16 { - Pio::::new(port).read() - } - fn read_io_u32(&self, port: u16) -> u32 { - Pio::::new(port).read() - } - - fn write_io_u8(&self, port: u16, value: u8) { - Pio::::new(port).write(value) - } - fn write_io_u16(&self, port: u16, value: u16) { - Pio::::new(port).write(value) - } - fn write_io_u32(&self, port: u16, value: u32) { - Pio::::new(port).write(value) - } - - fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { - log::error!("read pci u8 {:X}", _device); - - 0 - } - fn read_pci_u16( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - ) -> u16 { - log::error!("read pci u8 {:X}", _device); - - 0 - } - fn read_pci_u32( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - ) -> u32 { - log::error!("read pci u8 {:X}", _device); - - 0 - } - fn write_pci_u8( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u8, - ) { - log::error!("write pci u8 {:X}", _device); - } - fn write_pci_u16( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u16, - ) { - log::error!("write pci u8 {:X}", _device); - } - fn write_pci_u32( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u32, - ) { - log::error!("write pci u8 {:X}", _device); - } -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -impl aml::Handler for AmlPhysMemHandler { - fn read_u8(&self, _address: usize) -> u8 { - log::error!("read u8 {:X}", _address); - 0 - } - fn read_u16(&self, _address: usize) -> u16 { - log::error!("read u16 {:X}", _address); - 0 - } - fn read_u32(&self, _address: usize) -> u32 { - log::error!("read u32 {:X}", _address); - 0 - } - fn read_u64(&self, _address: usize) -> u64 { - log::error!("read u64 {:X}", _address); - 0 - } - - fn write_u8(&mut self, _address: usize, _value: u8) { - log::error!("write u8 {:X} = {:X}", _address, _value); - } - fn write_u16(&mut self, _address: usize, _value: u16) { - log::error!("write u16 {:X} = {:X}", _address, _value); - } - fn write_u32(&mut self, _address: usize, _value: u32) { - log::error!("write u32 {:X} = {:X}", _address, _value); - } - fn write_u64(&mut self, _address: usize, _value: u64) { - log::error!("write u64 {:X} = {:X}", _address, _value); - } - - fn read_io_u8(&self, port: u16) -> u8 { - log::error!("read io u8 {:X}", port); - 0 - } - fn read_io_u16(&self, port: u16) -> u16 { - log::error!("read io u16 {:X}", port); - 0 - } - fn read_io_u32(&self, port: u16) -> u32 { - log::error!("read io u32 {:X}", port); - 0 - } - - fn write_io_u8(&self, port: u16, value: u8) { - log::error!("write io u8 {:X} = {:X}", port, value); - } - fn write_io_u16(&self, port: u16, value: u16) { - log::error!("write io u16 {:X} = {:X}", port, value); - } - fn write_io_u32(&self, port: u16, value: u32) { - log::error!("write io u32 {:X} = {:X}", port, value); - } - - fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { - log::error!("read pci u8 {:X}", _device); - - 0 - } - fn read_pci_u16( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - ) -> u16 { - log::error!("read pci u8 {:X}", _device); - - 0 - } - fn read_pci_u32( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - ) -> u32 { - log::error!("read pci u8 {:X}", _device); - - 0 - } - fn write_pci_u8( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u8, - ) { - log::error!("write pci u8 {:X}", _device); - } - fn write_pci_u16( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u16, - ) { - log::error!("write pci u8 {:X}", _device); - } - fn write_pci_u32( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u32, - ) { - log::error!("write pci u8 {:X}", _device); - } -} diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs new file mode 100644 index 0000000000..ffc6798511 --- /dev/null +++ b/acpid/src/aml_physmem.rs @@ -0,0 +1,417 @@ +use num_traits::PrimInt; +use rustc_hash::FxHashMap; +use std::fmt::LowerHex; +use std::mem::size_of; +use std::sync::{Arc, Mutex}; +use syscall::{Io, PhysmapFlags, Pio, PAGE_SIZE}; + +const PAGE_MASK: usize = !(PAGE_SIZE - 1); +const OFFSET_MASK: usize = PAGE_SIZE - 1; + +struct MappedPage { + phys_page: usize, + virt_page: usize, +} + +impl MappedPage { + fn new(phys_page: usize) -> std::io::Result { + let virt_page = unsafe { + syscall::physmap(phys_page, PAGE_SIZE, PhysmapFlags::empty()) + .map_err(|error| std::io::Error::from_raw_os_error(error.errno))? + }; + Ok(Self { + phys_page, + virt_page, + }) + } +} + +impl Drop for MappedPage { + fn drop(&mut self) { + log::trace!("Drop page {:#x}", self.phys_page); + if let Err(e) = unsafe { syscall::physunmap(self.virt_page) } { + log::error!("physunmap: {:?}", e); + } + } +} + +#[derive(Default)] +pub struct AmlPageCache { + page_cache: FxHashMap, +} + +impl AmlPageCache { + /// get a virtual address for the given physical page + fn get_page(&mut self, phys_target: usize) -> std::io::Result<&MappedPage> { + let phys_page = phys_target & PAGE_MASK; + if self.page_cache.contains_key(&phys_page) { + log::trace!("re-using cached page {:#x}", phys_page); + + Ok(self + .page_cache + .get(&phys_page) + .expect("could not get page after contains=true")) + } else { + let mapped_page = MappedPage::new(phys_page)?; + log::trace!("adding page {:#x} to cache", mapped_page.phys_page); + self.page_cache.insert(phys_page, mapped_page); + Ok(self + .page_cache + .get(&phys_page) + .expect("can't find page that was just inserted")) + } + } + + /// The offset into the virtual slice of T that matches the physical target + fn sized_index(phys_target: usize) -> usize { + assert_eq!( + phys_target & !(size_of::() - 1), + phys_target, + "address {} is not aligned", + phys_target + ); + (phys_target & OFFSET_MASK) / size_of::() + } + /// Read from the given physical address + fn read_from_phys(&mut self, phys_target: usize) -> std::io::Result { + let mapped_page = self.get_page(phys_target)?; + let page_as_slice = unsafe { + std::slice::from_raw_parts( + mapped_page.virt_page as *const T, + PAGE_SIZE / size_of::(), + ) + }; + // for debugging only + let _virt_ptr = page_as_slice[Self::sized_index::(phys_target)..].as_ptr() as usize; + + let val = page_as_slice[Self::sized_index::(phys_target)]; + + log::trace!( + "read {:#x}, virt {:#x}, val {:#x}", + phys_target, + _virt_ptr, + val + ); + Ok(val) + } + + /// Write to the given physical address + fn write_to_phys( + &mut self, + phys_target: usize, + val: T, + ) -> std::io::Result<()> { + let mapped_page = self.get_page(phys_target)?; + let page_as_slice = unsafe { + std::slice::from_raw_parts_mut( + mapped_page.virt_page as *mut T, + PAGE_SIZE / size_of::(), + ) + }; + // for debugging only + let _virt_ptr = page_as_slice[Self::sized_index::(phys_target)..].as_ptr() as usize; + + page_as_slice[Self::sized_index::(phys_target)] = val; + + log::trace!( + "write {:#x}, virt {:#x}, val {:#x}", + phys_target, + _virt_ptr, + val + ); + Ok(()) + } + + pub fn clear(&mut self) { + log::trace!("Clear page cache"); + self.page_cache.clear(); + } +} + +pub struct AmlPhysMemHandler { + page_cache: Arc>, +} + +/// Read from a physical address. +/// Generic parameter must be u8, u16, u32 or u64. +impl AmlPhysMemHandler { + pub fn new(page_cache: Arc>) -> Self { + Self { page_cache } + } +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +impl aml::Handler for AmlPhysMemHandler { + fn read_u8(&self, address: usize) -> u8 { + log::trace!("read u8 {:X}", address); + if let Ok(mut page_cache) = self.page_cache.lock() { + if let Ok(value) = page_cache.read_from_phys::(address) { + return value; + } + } + 0 + } + fn read_u16(&self, address: usize) -> u16 { + log::trace!("read u16 {:X}", address); + if let Ok(mut page_cache) = self.page_cache.lock() { + if let Ok(value) = page_cache.read_from_phys::(address) { + return value; + } + } + 0 + } + fn read_u32(&self, address: usize) -> u32 { + log::trace!("read u32 {:X}", address); + if let Ok(mut page_cache) = self.page_cache.lock() { + if let Ok(value) = page_cache.read_from_phys::(address) { + return value; + } + } + 0 + } + fn read_u64(&self, address: usize) -> u64 { + log::trace!("read u64 {:X}", address); + if let Ok(mut page_cache) = self.page_cache.lock() { + if let Ok(value) = page_cache.read_from_phys::(address) { + return value; + } + } + 0 + } + + fn write_u8(&mut self, address: usize, value: u8) { + log::error!("write u8 {:X} = {:X}", address, value); + if let Ok(mut page_cache) = self.page_cache.lock() { + if page_cache.write_to_phys::(address, value).is_err() { + log::error!("failed to get page {:#x}", address); + } + } + } + fn write_u16(&mut self, address: usize, value: u16) { + log::error!("write u16 {:X} = {:X}", address, value); + if let Ok(mut page_cache) = self.page_cache.lock() { + if page_cache.write_to_phys::(address, value).is_err() { + log::error!("failed to get page {:#x}", address); + } + } + } + fn write_u32(&mut self, address: usize, value: u32) { + log::error!("write u32 {:X} = {:X}", address, value); + if let Ok(mut page_cache) = self.page_cache.lock() { + if page_cache.write_to_phys::(address, value).is_err() { + log::error!("failed to get page {:#x}", address); + } + } + } + fn write_u64(&mut self, address: usize, value: u64) { + log::error!("write u64 {:X} = {:X}", address, value); + if let Ok(mut page_cache) = self.page_cache.lock() { + if page_cache.write_to_phys::(address, value).is_err() { + log::error!("failed to get page {:#x}", address); + } + } + } + + // Pio must be enabled via syscall::iopl(3) + fn read_io_u8(&self, port: u16) -> u8 { + Pio::::new(port).read() + } + fn read_io_u16(&self, port: u16) -> u16 { + Pio::::new(port).read() + } + fn read_io_u32(&self, port: u16) -> u32 { + Pio::::new(port).read() + } + + fn write_io_u8(&self, port: u16, value: u8) { + Pio::::new(port).write(value) + } + fn write_io_u16(&self, port: u16, value: u16) { + Pio::::new(port).write(value) + } + fn write_io_u32(&self, port: u16, value: u32) { + Pio::::new(port).write(value) + } + + fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { + log::error!("read pci u8 {:X}", _device); + + 0 + } + fn read_pci_u16( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + ) -> u16 { + log::error!("read pci u16 {:X}", _device); + + 0 + } + fn read_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + ) -> u32 { + log::error!("read pci u32 {:X}", _device); + + 0 + } + fn write_pci_u8( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u8, + ) { + log::error!("write pci u8 {:X}", _device); + } + fn write_pci_u16( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u16, + ) { + log::error!("write pci u16 {:X}", _device); + } + fn write_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u32, + ) { + log::error!("write pci u32 {:X}", _device); + } +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +impl aml::Handler for AmlPhysMemHandler { + fn read_u8(&self, _address: usize) -> u8 { + log::error!("read u8 {:X}", _address); + 0 + } + fn read_u16(&self, _address: usize) -> u16 { + log::error!("read u16 {:X}", _address); + 0 + } + fn read_u32(&self, _address: usize) -> u32 { + log::error!("read u32 {:X}", _address); + 0 + } + fn read_u64(&self, _address: usize) -> u64 { + log::error!("read u64 {:X}", _address); + 0 + } + + fn write_u8(&mut self, _address: usize, _value: u8) { + log::error!("write u8 {:X} = {:X}", _address, _value); + } + fn write_u16(&mut self, _address: usize, _value: u16) { + log::error!("write u16 {:X} = {:X}", _address, _value); + } + fn write_u32(&mut self, _address: usize, _value: u32) { + log::error!("write u32 {:X} = {:X}", _address, _value); + } + fn write_u64(&mut self, _address: usize, _value: u64) { + log::error!("write u64 {:X} = {:X}", _address, _value); + } + + fn read_io_u8(&self, port: u16) -> u8 { + log::error!("read io u8 {:X}", port); + 0 + } + fn read_io_u16(&self, port: u16) -> u16 { + log::error!("read io u16 {:X}", port); + 0 + } + fn read_io_u32(&self, port: u16) -> u32 { + log::error!("read io u32 {:X}", port); + 0 + } + + fn write_io_u8(&self, port: u16, value: u8) { + log::error!("write io u8 {:X} = {:X}", port, value); + } + fn write_io_u16(&self, port: u16, value: u16) { + log::error!("write io u16 {:X} = {:X}", port, value); + } + fn write_io_u32(&self, port: u16, value: u32) { + log::error!("write io u32 {:X} = {:X}", port, value); + } + + fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { + log::error!("read pci u8 {:X}", _device); + + 0 + } + fn read_pci_u16( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + ) -> u16 { + log::error!("read pci u8 {:X}", _device); + + 0 + } + fn read_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + ) -> u32 { + log::error!("read pci u8 {:X}", _device); + + 0 + } + fn write_pci_u8( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u8, + ) { + log::error!("write pci u8 {:X}", _device); + } + fn write_pci_u16( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u16, + ) { + log::error!("write pci u8 {:X}", _device); + } + fn write_pci_u32( + &self, + _segment: u16, + _bus: u8, + _device: u8, + _function: u8, + _offset: u16, + _value: u32, + ) { + log::error!("write pci u8 {:X}", _device); + } +} diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 12bea90e48..d94f762938 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -16,6 +16,7 @@ use syscall::flag::{EventFlags, O_NONBLOCK}; mod acpi; mod scheme; +mod aml_physmem; fn monotonic() -> (u64, u64) { use syscall::call::clock_gettime; From b05402e92b7de7dea51ab44669f43952f806a6eb Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 11 May 2023 20:31:02 -0600 Subject: [PATCH 0615/1301] ided: add timeouts to loops and better debugging --- ided/src/ata.rs | 16 -------------- ided/src/ide.rs | 56 ++++++++++++++++++++++++++++++++++++++---------- ided/src/main.rs | 7 +++--- 3 files changed, 48 insertions(+), 31 deletions(-) delete mode 100644 ided/src/ata.rs diff --git a/ided/src/ata.rs b/ided/src/ata.rs deleted file mode 100644 index 6cd72310d5..0000000000 --- a/ided/src/ata.rs +++ /dev/null @@ -1,16 +0,0 @@ -#[repr(u8)] -pub enum AtaCommand { - ReadPio = 0x20, - ReadPioExt = 0x24, - ReadDma = 0xC8, - ReadDmaExt = 0x25, - WritePio = 0x30, - WritePioExt = 0x34, - WriteDma = 0xCA, - WriteDmaExt = 0x35, - CacheFlush = 0xE7, - CacheFlushExt = 0xEA, - Packet = 0xA0, - IdentifyPacket = 0xA1, - Identify = 0xEC, -} diff --git a/ided/src/ide.rs b/ided/src/ide.rs index 74a5e1c48d..65376e2df5 100644 --- a/ided/src/ide.rs +++ b/ided/src/ide.rs @@ -2,13 +2,31 @@ use std::{ convert::TryInto, sync::{Arc, Mutex}, thread, + time::{Duration, Instant}, }; use syscall::{ error::{Error, Result, EIO}, io::{Dma, Io, Pio, PhysBox, ReadOnly, WriteOnly}, }; -use crate::ata::AtaCommand; +static TIMEOUT: Duration = Duration::new(1, 0); + +#[repr(u8)] +pub enum AtaCommand { + ReadPio = 0x20, + ReadPioExt = 0x24, + ReadDma = 0xC8, + ReadDmaExt = 0x25, + WritePio = 0x30, + WritePioExt = 0x34, + WriteDma = 0xCA, + WriteDmaExt = 0x35, + CacheFlush = 0xE7, + CacheFlushExt = 0xEA, + Packet = 0xA0, + IdentifyPacket = 0xA1, + Identify = 0xEC, +} #[repr(packed)] struct PrdtEntry { @@ -98,7 +116,7 @@ impl Channel { Ok(status) } - fn polling(&mut self, read: bool) -> Result<()> { + fn polling(&mut self, read: bool, line: u32) -> Result<()> { /* #define ATA_SR_BSY 0x80 // Busy #define ATA_SR_DRDY 0x40 // Drive ready @@ -115,17 +133,21 @@ impl Channel { self.alt_status.read(); } + let start = Instant::now(); loop { let status = self.check_status()?; - if status & 0x80 != 0 { - thread::yield_now(); - } else { + if status & 0x80 == 0 { if read && status & 0x08 == 0 { - log::error!("IDE data not ready"); + log::error!("IDE read data not ready"); return Err(Error::new(EIO)); } break; } + if start.elapsed() >= TIMEOUT { + log::error!("line {} polling {} timeout with status 0x{:02X}", line, if read { "read" } else { "write" }, status); + return Err(Error::new(EIO)); + } + thread::yield_now(); } Ok(()) @@ -238,9 +260,10 @@ impl Disk for AtaDisk { chan.busmaster_command.writef(1, true); // Wait for transaction to finish - chan.polling(false)?; + chan.polling(false, line!())?; // Wait for bus master to finish + let start = Instant::now(); let error = loop { let status = chan.busmaster_status.read(); if status & 1 << 1 != 0 { @@ -251,6 +274,11 @@ impl Disk for AtaDisk { // Break when not busy and no error break false; } + if start.elapsed() >= TIMEOUT { + log::error!("busmaster read timeout with status 0x{:02X}", status); + return Err(Error::new(EIO)); + } + thread::yield_now(); }; // Stop bus master @@ -268,7 +296,7 @@ impl Disk for AtaDisk { chunk.copy_from_slice(&chan.buf[..chunk.len()]); } else { for sector in 0..sectors { - chan.polling(true)?; + chan.polling(true, line!())?; for i in 0..128 { let data = chan.data32.read(); @@ -369,9 +397,10 @@ impl Disk for AtaDisk { chan.busmaster_command.writef(1, true); // Wait for transaction to finish - chan.polling(false)?; + chan.polling(false, line!())?; // Wait for bus master to finish + let start = Instant::now(); let error = loop { let status = chan.busmaster_status.read(); if status & 1 << 1 != 0 { @@ -382,6 +411,11 @@ impl Disk for AtaDisk { // Break when not busy and no error break false; } + if start.elapsed() >= TIMEOUT { + log::error!("busmaster write timeout with status 0x{:02X}", status); + return Err(Error::new(EIO)); + } + thread::yield_now(); }; // Stop bus master @@ -396,7 +430,7 @@ impl Disk for AtaDisk { } } else { for sector in 0..sectors { - chan.polling(false)?; + chan.polling(false, line!())?; for i in 0..128 { chan.data32.write( @@ -414,7 +448,7 @@ impl Disk for AtaDisk { } else { AtaCommand::CacheFlush as u8 }); - chan.polling(false)?; + chan.polling(false, line!())?; count += chunk.len(); } diff --git a/ided/src/main.rs b/ided/src/main.rs index 0e3c9f333b..4556084d02 100644 --- a/ided/src/main.rs +++ b/ided/src/main.rs @@ -6,7 +6,7 @@ use std::{ io::{ErrorKind, Read, Write}, os::unix::io::{FromRawFd, RawFd}, sync::{Arc, Mutex}, - thread::sleep, + thread::{self, sleep}, time::Duration, }; use syscall::{ @@ -18,12 +18,10 @@ use syscall::{ }; use crate::{ - ata::AtaCommand, - ide::{AtaDisk, Channel, Disk}, + ide::{AtaCommand, AtaDisk, Channel, Disk}, scheme::DiskScheme, }; -pub mod ata; pub mod ide; pub mod scheme; @@ -148,6 +146,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // Not busy and data ready break false; } + thread::yield_now(); }; //TODO: probe ATAPI From e673b4e3b19c56c4a030cc723a6ee48c2f2871ab Mon Sep 17 00:00:00 2001 From: Noa Date: Wed, 26 May 2021 17:01:36 -0500 Subject: [PATCH 0616/1301] Use the free functions in std::alloc instead of Global as AllocRef --- vesad/src/display.rs | 91 +++++++++++++++++++++++--------------------- vesad/src/main.rs | 2 - 2 files changed, 48 insertions(+), 45 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 2af08415a5..7f5626eaff 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -1,8 +1,8 @@ #[cfg(feature="rusttype")] extern crate rusttype; -use std::alloc::{Allocator, Global, Layout}; -use std::{cmp, ptr, slice}; +use std::alloc::{self, Layout}; +use std::{cmp, ptr}; use std::ptr::NonNull; #[cfg(feature="rusttype")] @@ -20,11 +20,49 @@ static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../res/DejaVuSansMono-B #[cfg(feature="rusttype")] static FONT_ITALIC: &'static [u8] = include_bytes!("../res/DejaVuSansMono-Oblique.ttf"); +pub struct OffscreenBuffer { + ptr: NonNull<[u32]>, +} + +impl OffscreenBuffer { + #[inline] + fn layout(len: usize) -> Layout { + // optimizes to an integer mul + Layout::array::(len).unwrap().align_to(4096).unwrap() + } + + #[inline] + fn new(len: usize) -> Self { + let layout = Self::layout(len); + let ptr = unsafe { alloc::alloc_zeroed(layout) }; + let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len); + let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout)); + OffscreenBuffer { ptr } + } +} +impl Drop for OffscreenBuffer { + fn drop(&mut self) { + let layout = Self::layout(self.ptr.len()); + unsafe { alloc::dealloc(self.ptr.as_ptr().cast(), layout) }; + } +} +impl std::ops::Deref for OffscreenBuffer { + type Target = [u32]; + fn deref(&self) -> &[u32] { + unsafe { self.ptr.as_ref() } + } +} +impl std::ops::DerefMut for OffscreenBuffer { + fn deref_mut(&mut self) -> &mut [u32] { + unsafe { self.ptr.as_mut() } + } +} + /// A display pub struct Display { pub width: usize, pub height: usize, - pub offscreen: &'static mut [u32], + pub offscreen: OffscreenBuffer, #[cfg(feature="rusttype")] pub font: Font<'static>, #[cfg(feature="rusttype")] @@ -39,33 +77,22 @@ impl Display { #[cfg(not(feature="rusttype"))] pub fn new(width: usize, height: usize) -> Display { let size = width * height; - - let offscreen = unsafe { - Global - .allocate_zeroed(Layout::from_size_align_unchecked(size * 4, 4096)) - .expect("failed to allocate offscreen memory") - .as_ptr() - }; + let offscreen = OffscreenBuffer::new(size); Display { width, height, - offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) } + offscreen, } } #[cfg(feature="rusttype")] pub fn new(width: usize, height: usize) -> Display { let size = width * height; - let offscreen = unsafe { - Global - .allocate_zeroed(Layout::from_size_align_unchecked(size * 4, 4096)) - .expect("failed to allocate offscreen memory") - .as_ptr() - }; + let offscreen = OffscreenBuffer::new(size); Display { width, height, - offscreen: unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }, + offscreen, font: FontCollection::from_bytes(FONT).into_font().unwrap(), font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(), font_bold_italic: FontCollection::from_bytes(FONT_BOLD_ITALIC).into_font().unwrap(), @@ -78,16 +105,11 @@ impl Display { println!("Resize display to {}, {}", width, height); let size = width * height; - let offscreen = unsafe { - Global - .allocate_zeroed(Layout::from_size_align_unchecked(size * 4, 4096)) - .expect("failed to allocate offscreen memory when resizing") - .as_ptr() - }; + let mut offscreen = OffscreenBuffer::new(size); { let mut old_ptr = self.offscreen.as_ptr(); - let mut new_ptr = offscreen as *mut u32; + let mut new_ptr = offscreen.as_mut_ptr(); for _y in 0..cmp::min(height, self.height) { unsafe { @@ -121,8 +143,7 @@ impl Display { self.width = width; self.height = height; - unsafe { Global.deallocate(NonNull::new_unchecked(self.offscreen.as_mut_ptr() as *mut u8), Layout::from_size_align_unchecked(self.offscreen.len() * 4, 4096)) }; - self.offscreen = unsafe { slice::from_raw_parts_mut(offscreen as *mut u32, size) }; + self.offscreen = offscreen; } else { println!("Display is already {}, {}", width, height); } @@ -290,19 +311,3 @@ impl Display { } } } - -impl Drop for Display { - #[cold] - fn drop(&mut self) { - unsafe { - let offscreen = std::mem::replace(&mut self.offscreen, &mut []); - - let layout = Layout::from_size_align(offscreen.len() * 4, 4096).unwrap(); - - Global.deallocate( - NonNull::from(offscreen).cast::(), - layout, - ); - } - } -} diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 3e5cee75c4..1fb6a9ef39 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -1,5 +1,3 @@ -#![feature(allocator_api)] - extern crate orbclient; extern crate syscall; From a5a3f3341fb00701c403e34cae5893cdf506b744 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 4 Jun 2023 17:39:02 +0200 Subject: [PATCH 0617/1301] Remove all usages of physunmap. --- acpid/src/acpi.rs | 2 +- acpid/src/acpi/dmar/drhd.rs | 2 +- acpid/src/aml_physmem.rs | 4 ++-- ahcid/src/main.rs | 5 +++-- alxd/src/main.rs | 1 - e1000d/src/main.rs | 3 --- ihdad/src/hda/stream.rs | 17 +++++++++++------ ihdad/src/main.rs | 2 +- ixgbed/src/main.rs | 3 --- nvmed/src/main.rs | 5 +++-- pcid/src/pcie/mod.rs | 5 +++-- rtl8168d/src/main.rs | 3 --- vboxd/src/main.rs | 1 - vesad/src/main.rs | 1 + vesad/src/scheme.rs | 5 +++-- xhcid/src/main.rs | 3 --- 16 files changed, 29 insertions(+), 33 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 417cd920fa..77ed3b9d8f 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -126,7 +126,7 @@ impl Deref for PhysmapGuard { impl Drop for PhysmapGuard { fn drop(&mut self) { unsafe { - let _ = syscall::physunmap(self.virt as usize); + let _ = syscall::funmap(self.virt as usize, self.size); } } } diff --git a/acpid/src/acpi/dmar/drhd.rs b/acpid/src/acpi/dmar/drhd.rs index ee6254f636..67625974d7 100644 --- a/acpid/src/acpi/dmar/drhd.rs +++ b/acpid/src/acpi/dmar/drhd.rs @@ -35,7 +35,7 @@ impl DerefMut for DrhdPage { impl Drop for DrhdPage { fn drop(&mut self) { unsafe { - let _ = syscall::physunmap(self.virt as usize); + let _ = syscall::funmap(self.virt as usize, crate::acpi::PAGE_SIZE); } } } diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index ffc6798511..953b0ac911 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -29,8 +29,8 @@ impl MappedPage { impl Drop for MappedPage { fn drop(&mut self) { log::trace!("Drop page {:#x}", self.phys_page); - if let Err(e) = unsafe { syscall::physunmap(self.virt_page) } { - log::error!("physunmap: {:?}", e); + if let Err(e) = unsafe { syscall::funmap(self.virt_page, PAGE_SIZE) } { + log::error!("funmap (phys): {:?}", e); } } } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index c19c60106d..05ed80fb8a 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -1,4 +1,5 @@ #![cfg_attr(target_arch = "aarch64", feature(stdsimd))] // Required for yield instruction +#![feature(int_roundings)] extern crate syscall; extern crate byteorder; @@ -8,6 +9,7 @@ use std::fs::File; use std::io::{ErrorKind, Read, Write}; use std::os::unix::io::{FromRawFd, RawFd}; +use syscall::PAGE_SIZE; use syscall::error::{Error, ENODEV}; use syscall::data::{Event, Packet}; use syscall::flag::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; @@ -89,7 +91,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { info!(" + AHCI {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); let address = unsafe { - syscall::physmap(bar, (bar_size+4095)/4096*4096, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + syscall::physmap(bar, bar_size.next_multiple_of(PAGE_SIZE), PHYSMAP_WRITE | PHYSMAP_NO_CACHE) .expect("ahcid: failed to map address") }; { @@ -200,7 +202,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } } - unsafe { let _ = syscall::physunmap(address); } std::process::exit(0); } diff --git a/alxd/src/main.rs b/alxd/src/main.rs index f0877eacd4..6f125a855f 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -141,7 +141,6 @@ fn main() { }).expect("alxd: failed to write event"); } } - unsafe { let _ = syscall::physunmap(address); } std::process::exit(0); }).expect("alxd: failed to daemonize"); } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 67f8a4012a..e0353af679 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -193,9 +193,6 @@ fn main() { send_events(event_count); } } - unsafe { - let _ = syscall::physunmap(address); - } process::exit(0); }).expect("e1000d: failed to create daemon"); } diff --git a/ihdad/src/hda/stream.rs b/ihdad/src/hda/stream.rs index c6f3753e59..dbdc3ad79c 100644 --- a/ihdad/src/hda/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -1,4 +1,4 @@ -use syscall::{PHYSMAP_WRITE, PHYSMAP_NO_CACHE}; +use syscall::{PHYSMAP_WRITE, PHYSMAP_NO_CACHE, PAGE_SIZE}; use syscall::error::{Error, EIO, Result}; use syscall::io::{Mmio, Io}; use std::result; @@ -289,8 +289,10 @@ pub struct StreamBuffer { impl StreamBuffer { pub fn new(block_length: usize, block_count: usize) -> result::Result { + let page_aligned_size = (block_length * block_count).next_multiple_of(PAGE_SIZE); + let phys = match unsafe { - syscall::physalloc(block_length * block_count) + syscall::physalloc(page_aligned_size) } { Ok(phys) => phys, Err(_err) => { @@ -299,17 +301,18 @@ impl StreamBuffer { }; let addr = match unsafe { - syscall::physmap(phys, block_length * block_count, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + syscall::physmap(phys, page_aligned_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) } { Ok(addr) => addr, Err(_err) => { unsafe { - syscall::physfree(phys, block_length * block_count); + syscall::physfree(phys, page_aligned_size); } return Err("Could not map physical memory for buffer."); } }; + // TODO: Already zeroed by kernel? unsafe { ptr::write_bytes(addr as *mut u8, 0, block_length * block_count); } @@ -370,8 +373,10 @@ impl Drop for StreamBuffer { fn drop(&mut self) { unsafe { log::debug!("IHDA: Deallocating buffer."); - if syscall::physunmap(self.addr).is_ok() { - let _ = syscall::physfree(self.phys, self.block_len * self.block_cnt); + let page_aligned_size = (self.block_len * self.block_cnt).next_multiple_of(PAGE_SIZE); + + if syscall::funmap(self.addr, page_aligned_size).is_ok() { + let _ = syscall::physfree(self.phys, page_aligned_size); } } } diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 1fac624ae0..f77b2c278e 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -1,4 +1,5 @@ //#![deny(warnings)] +#![feature(int_roundings)] extern crate bitflags; extern crate spin; @@ -300,7 +301,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - unsafe { let _ = syscall::physunmap(address); } std::process::exit(0); } diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index ae8be8d5b7..7bbd3a42fb 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -195,9 +195,6 @@ fn main() { send_events(event_count); } } - unsafe { - let _ = syscall::physunmap(address); - } std::process::exit(0); }).expect("ixgbed: failed to daemonize"); diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index f88a1db9e9..420742704a 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -1,4 +1,5 @@ #![cfg_attr(target_arch = "aarch64", feature(stdsimd))] // Required for yield instruction +#![feature(int_roundings)] use std::convert::TryInto; use std::fs::File; @@ -11,7 +12,7 @@ use std::{slice, usize}; use pcid_interface::{PciBar, PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; use syscall::{ Event, Mmio, Packet, Result, SchemeBlockMut, PHYSMAP_NO_CACHE, - PHYSMAP_WRITE, + PHYSMAP_WRITE, PAGE_SIZE, }; use redox_log::{OutputBuilder, RedoxLogger}; @@ -42,7 +43,7 @@ impl Bar { impl Drop for Bar { fn drop(&mut self) { - let _ = unsafe { syscall::physunmap(self.physical) }; + let _ = unsafe { syscall::funmap(self.physical, self.bar_size.next_multiple_of(PAGE_SIZE)) }; } } diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 1e1da08a25..7c73d84767 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -2,6 +2,7 @@ use std::{fmt, fs, io, mem, ptr, slice}; use std::collections::BTreeMap; use std::sync::{Arc, Mutex}; +use syscall::PAGE_SIZE; use syscall::flag::PhysmapFlags; use smallvec::SmallVec; @@ -172,7 +173,7 @@ impl Pcie { }; let mut maps_lock = self.maps.lock().unwrap(); let virt_pointer = maps_lock.entry((bus, dev, func)).or_insert_with(|| { - syscall::physmap(base_address_phys as usize + Self::addr_offset_in_bytes(starting_bus, bus, dev, func, 0), 4096, PhysmapFlags::PHYSMAP_NO_CACHE | PhysmapFlags::PHYSMAP_WRITE).unwrap_or_else(|error| panic!("failed to physmap pcie configuration space for {:2x}:{:2x}.{:2x}: {:?}", bus, dev, func, error)) as *mut u32 + syscall::physmap(base_address_phys as usize + Self::addr_offset_in_bytes(starting_bus, bus, dev, func, 0), PAGE_SIZE, PhysmapFlags::PHYSMAP_NO_CACHE | PhysmapFlags::PHYSMAP_WRITE).unwrap_or_else(|error| panic!("failed to physmap pcie configuration space for {:2x}:{:2x}.{:2x}: {:?}", bus, dev, func, error)) as *mut u32 }); f(Some(&mut *virt_pointer.offset((offset as usize / mem::size_of::()) as isize))) } @@ -207,7 +208,7 @@ impl CfgAccess for Pcie { impl Drop for Pcie { fn drop(&mut self) { for address in self.maps.lock().unwrap().values().copied() { - let _ = unsafe { syscall::physunmap(address as usize) }; + let _ = unsafe { syscall::funmap(address as usize, PAGE_SIZE) }; } } } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index dbfe97aa8b..dae8c8a62e 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -459,9 +459,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { send_events(event_count); } } - unsafe { - let _ = syscall::physunmap(address); - } process::exit(0); } diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 0ed4a1975d..4ad50c5598 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -296,7 +296,6 @@ fn main() { event_queue.run().expect("vboxd: failed to run event loop"); } - unsafe { let _ = syscall::physunmap(address); } std::process::exit(0); }).expect("vboxd: failed to daemonize"); diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 1fb6a9ef39..10ae4df44a 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -1,3 +1,4 @@ +#![feature(int_roundings)] extern crate orbclient; extern crate syscall; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index acfdaa76d6..d50c12902b 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::{mem, ptr, slice, str}; use orbclient::{Event, EventOption}; -use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, physmap, physunmap, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, Result, SchemeMut}; +use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, physmap, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, Result, SchemeMut, PAGE_SIZE}; use crate::{ display::Display, @@ -102,7 +102,8 @@ impl DisplayScheme { // Unmap old onscreen unsafe { - physunmap(self.onscreens[fb_i].as_mut_ptr() as usize).expect("vesad: failed to unmap framebuffer"); + let slice = mem::take(&mut self.onscreens[fb_i]); + syscall::funmap(slice.as_mut_ptr() as usize, (slice.len() * 4).next_multiple_of(PAGE_SIZE)).expect("vesad: failed to unmap framebuffer"); } // Map new onscreen diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index f12b28c2bd..8ccfd50653 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -333,8 +333,5 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { event_queue.run().expect("xhcid: failed to handle events"); - unsafe { - let _ = syscall::physunmap(address); - } std::process::exit(0); } From 1580cb8c8370a75bf78bd2b5d000b3164136fb17 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 19 Jun 2023 12:02:35 +1000 Subject: [PATCH 0618/1301] virtio: stub! Signed-off-by: Anhad Singh --- .gitignore | 3 ++ Cargo.lock | 71 +++++++++++++++++++++++++++++++------------- Cargo.toml | 2 ++ initfs.toml | 10 +++++++ virtiod/Cargo.toml | 16 ++++++++++ virtiod/src/lib.rs | 34 +++++++++++++++++++++ virtiod/src/main.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 188 insertions(+), 20 deletions(-) create mode 100644 virtiod/Cargo.toml create mode 100644 virtiod/src/lib.rs create mode 100644 virtiod/src/main.rs diff --git a/.gitignore b/.gitignore index 2f7896d1d1..9b0fb7e2e1 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ target/ + +# editor configs: +.vscode diff --git a/Cargo.lock b/Cargo.lock index 33d7a1492c..8d247fb7e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,7 +6,7 @@ version = 3 name = "ac97d" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "log", "redox-daemon", "redox-log", @@ -38,7 +38,7 @@ dependencies = [ name = "ahcid" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "block-io-wrapper", "byteorder 1.4.3", "log", @@ -52,7 +52,7 @@ dependencies = [ name = "alxd" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "netutils", "redox-daemon", "redox_event", @@ -99,6 +99,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + [[package]] name = "arg_parser" version = "0.1.0" @@ -181,6 +187,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitflags" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded" + [[package]] name = "bitvec" version = "1.0.1" @@ -272,7 +284,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.2.1", "strsim", "textwrap", "unicode-width", @@ -285,7 +297,7 @@ version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] @@ -416,7 +428,7 @@ dependencies = [ name = "e1000d" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "netutils", "redox-daemon", "redox_event", @@ -440,7 +452,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags", + "bitflags 1.2.1", "fuchsia-zircon-sys", ] @@ -550,7 +562,7 @@ name = "gpt" version = "0.6.3" source = "git+https://gitlab.redox-os.org/redox-os/gpt#4d800981c5dfae60ae183dbddaa3e026f80a5e5c" dependencies = [ - "bitflags", + "bitflags 1.2.1", "crc", "log", "uuid", @@ -632,7 +644,7 @@ dependencies = [ name = "ihdad" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "log", "pcid", "redox-daemon", @@ -680,7 +692,7 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" name = "ixgbed" version = "1.0.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "netutils", "redox-daemon", "redox_event", @@ -892,7 +904,7 @@ name = "nvmed" version = "0.1.0" dependencies = [ "arrayvec 0.5.2", - "bitflags", + "bitflags 1.2.1", "block-io-wrapper", "crossbeam-channel 0.4.4", "futures", @@ -1035,7 +1047,7 @@ name = "pcid" version = "0.1.0" dependencies = [ "bincode", - "bitflags", + "bitflags 1.2.1", "byteorder 1.4.3", "libc", "log", @@ -1120,7 +1132,7 @@ dependencies = [ name = "ps2d" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "orbclient", "redox-daemon", "redox_syscall 0.3.5", @@ -1334,7 +1346,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] @@ -1343,7 +1355,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] @@ -1359,7 +1371,7 @@ dependencies = [ name = "rtl8168d" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "log", "netutils", "pcid", @@ -1396,7 +1408,7 @@ checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" name = "sb16d" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "log", "redox-daemon", "redox-log", @@ -1443,7 +1455,7 @@ version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7959277b623f1fb9e04aea73686c3ca52f01b2145f8ea16f4ff30d8b7623b1a" dependencies = [ - "bitflags", + "bitflags 1.2.1", "lazy_static", "libc", "raw-window-handle 0.4.3", @@ -1553,6 +1565,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stb_truetype" version = "0.2.8" @@ -1805,7 +1823,7 @@ dependencies = [ name = "usbhidd" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "log", "orbclient", "redox-log", @@ -1886,6 +1904,19 @@ dependencies = [ "rusttype", ] +[[package]] +name = "virtiod" +version = "0.1.0" +dependencies = [ + "anyhow", + "bitflags 2.3.2", + "log", + "pcid", + "redox-daemon", + "redox-log", + "static_assertions", +] + [[package]] name = "vte" version = "0.3.3" @@ -2106,7 +2137,7 @@ dependencies = [ name = "xhcid" version = "0.1.0" dependencies = [ - "bitflags", + "bitflags 1.2.1", "chashmap", "crossbeam-channel 0.4.4", "futures", diff --git a/Cargo.toml b/Cargo.toml index f68f051017..f1fe9a570b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,8 @@ members = [ "usbctl", "usbhidd", "usbscsid", + + "virtiod", ] [profile.release] diff --git a/initfs.toml b/initfs.toml index 1c1c6015fd..d8d3a62644 100644 --- a/initfs.toml +++ b/initfs.toml @@ -22,3 +22,13 @@ class = 1 subclass = 8 command = ["nvmed"] use_channel = true + +# virtiod +[[drivers]] +name = "VirtIO block storage" +class = 1 +subclass = 0 +# VirtIO PCI vendor identifier. +vendor = 6900 +command = ["virtiod"] +use_channel = true diff --git a/virtiod/Cargo.toml b/virtiod/Cargo.toml new file mode 100644 index 0000000000..07246b5ef2 --- /dev/null +++ b/virtiod/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "virtiod" +version = "0.1.0" +edition = "2021" +authors = ["Anhad Singh "] + +[dependencies] +static_assertions = "1.1.0" +bitflags = "2.3.2" +anyhow = "1.0.71" +log = "0.4" + +redox-daemon = "0.1" +redox-log = "0.1" + +pcid = { path = "../pcid" } diff --git a/virtiod/src/lib.rs b/virtiod/src/lib.rs new file mode 100644 index 0000000000..6f32838461 --- /dev/null +++ b/virtiod/src/lib.rs @@ -0,0 +1,34 @@ +//! https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html + +use static_assertions::const_assert_eq; + +bitflags::bitflags! { + #[repr(transparent)] + pub struct DescriptorFlags: u16 { + /// The next field contains linked buffer index. + const NEXT = 1 << 0; + /// The buffer is write-only (otherwise read-only). + const WRITE_ONLY = 1 << 1; + /// The buffer contains a list of buffer descriptors. + const INDIRECT = 1 << 2; + } +} + +#[repr(C)] +struct Descriptor { + /// Address (guest-physical). + address: u64, + /// Size of the descriptor. + size: u32, + flags: DescriptorFlags, + /// Index of next desciptor in chain. + next: u16, +} + +const_assert_eq!(core::mem::size_of::(), 16); + +pub struct VirtQueue {} + +pub struct Transport {} + + diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs new file mode 100644 index 0000000000..c82fae63a3 --- /dev/null +++ b/virtiod/src/main.rs @@ -0,0 +1,72 @@ +use pcid_interface::{PciFeature, PcidServerHandle}; + +pub fn main() -> anyhow::Result<()> { + #[cfg(target_os = "redox")] + setup_logging(); + + redox_daemon::Daemon::new(daemon).expect("virtio-core: failed to daemonize"); +} + +#[cfg(target_os = "redox")] +fn setup_logging() { + use redox_log::{OutputBuilder, RedoxLogger}; + + let mut logger = RedoxLogger::new().with_output( + OutputBuilder::stderr() + // limit global output to important info + .with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ); + + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "virtiod.log") { + Ok(builder) => { + logger = logger.with_output( + builder + .with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build(), + ) + } + Err(err) => eprintln!("virtiod: failed to create log: {}", err), + } + + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "virtiod.ansi.log") { + Ok(builder) => { + logger = logger.with_output( + builder + .with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ) + } + Err(err) => eprintln!("virtiod: failed to create ansi log: {}", err), + } + + logger.enable().unwrap(); + log::info!("virtiod: enabled logger"); +} + +fn daemon(_deamon: redox_daemon::Daemon) -> ! { + let mut pcid_handle = PcidServerHandle::connect_default().unwrap(); + let pci_config = pcid_handle.fetch_config().unwrap(); + + // 0x1001 - virtio-blk + assert_eq!(pci_config.func.devid, 0x1001); + log::info!("virtiod: found `virtio-blk` device"); + + // Get the PCI capabilities. + // for vendor_cap in pcid_handle + // .fetch_all_features() + // .unwrap() + // .iter() + // .filter(|(x, _)| matches!(x, PciFeature::VendorSpecific)) + // { + + // } + // log::info!("{}", x.unwrap() as u8); + + loop {} +} From 7e5a3196c2cbc168f8697da63fd3b1e69938bbe1 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 19 Jun 2023 12:14:49 +1000 Subject: [PATCH 0619/1301] pcid::server_handle: add `get_capabilities` This commit adds the `get_capabilities` function to `PcidServerHandle` which returns all of the `Capability`s (raw representation) of the PCI device. Signed-off-by: Anhad Singh --- pcid/src/driver_interface/mod.rs | 15 ++++++++++++++- pcid/src/main.rs | 3 +++ pcid/src/pci/cap.rs | 4 ++-- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index cc6dad2392..e563c6d06a 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -7,8 +7,9 @@ use std::os::unix::io::{FromRawFd, RawFd}; use serde::{Serialize, Deserialize, de::DeserializeOwned}; use thiserror::Error; -pub use crate::pci::{PciBar, PciHeader}; +pub use crate::pci::cap::Capability; pub use crate::pci::msi; +pub use crate::pci::{PciBar, PciHeader}; pub mod irq_helpers; @@ -171,6 +172,7 @@ pub enum PcidClientRequest { RequestConfig, RequestHeader, RequestFeatures, + RequestCapabilities, EnableFeature(PciFeature), FeatureStatus(PciFeature), FeatureInfo(PciFeature), @@ -189,6 +191,7 @@ pub enum PcidServerResponseError { #[derive(Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum PcidClientResponse { + Capabilities(Vec), Config(SubdriverArguments), Header(PciHeader), AllFeatures(Vec<(PciFeature, FeatureStatus)>), @@ -258,6 +261,16 @@ impl PcidServerHandle { other => Err(PcidClientHandleError::InvalidResponse(other)), } } + + pub fn get_capabilities(&mut self) -> Result> { + self.send(&PcidClientRequest::RequestCapabilities)?; + + match self.recv()? { + PcidClientResponse::Capabilities(a) => Ok(a), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } + pub fn fetch_header(&mut self) -> Result { self.send(&PcidClientRequest::RequestHeader)?; match self.recv()? { diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 98fe46088b..04de72a085 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -66,6 +66,9 @@ impl DriverHandler { use crate::pci::cap::{MsiCapability, MsixCapability}; match request { + PcidClientRequest::RequestCapabilities => { + PcidClientResponse::Capabilities(self.capabilities.iter().map(|(_, capability)| capability.clone()).collect::>()) + } PcidClientRequest::RequestConfig => { PcidClientResponse::Config(args.clone()) } diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 43003fb9a5..02b3301450 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -80,7 +80,7 @@ pub enum MsiCapability { } -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct PcieCapability { pub pcie_caps: u32, pub dev_caps: u32, @@ -117,7 +117,7 @@ pub struct VendorSpecificCapability { pub data: Vec, } -#[derive(Clone, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum Capability { Msi(MsiCapability), MsiX(MsixCapability), From f750d4223d8c6d2641579a5cb8f38e1c701f0852 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 19 Jun 2023 12:19:57 +1000 Subject: [PATCH 0620/1301] virtio: perform the device reset Signed-off-by: Anhad Singh --- Cargo.lock | 2 + virtiod/Cargo.toml | 2 + virtiod/src/lib.rs | 117 +++++++++++++++++++++++++++++++++++- virtiod/src/main.rs | 143 +++++++++++++++++++++++++++++++++++++++----- 4 files changed, 248 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d247fb7e7..7af5c36f26 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1914,7 +1914,9 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", + "redox_syscall 0.3.5", "static_assertions", + "thiserror", ] [[package]] diff --git a/virtiod/Cargo.toml b/virtiod/Cargo.toml index 07246b5ef2..7da66c158d 100644 --- a/virtiod/Cargo.toml +++ b/virtiod/Cargo.toml @@ -9,8 +9,10 @@ static_assertions = "1.1.0" bitflags = "2.3.2" anyhow = "1.0.71" log = "0.4" +thiserror = "1.0.40" redox-daemon = "0.1" redox-log = "0.1" +redox_syscall = "0.3" pcid = { path = "../pcid" } diff --git a/virtiod/src/lib.rs b/virtiod/src/lib.rs index 6f32838461..ee0658c079 100644 --- a/virtiod/src/lib.rs +++ b/virtiod/src/lib.rs @@ -1,7 +1,96 @@ //! https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html +use core::cell::UnsafeCell; use static_assertions::const_assert_eq; +#[derive(Debug, Copy, Clone)] +#[repr(u8)] +pub enum CfgType { + /// Common Configuration. + Common = 1, + /// Notifications. + Notify = 2, + /// ISR Status. + Isr = 3, + /// Device specific configuration. + Device = 4, + /// PCI configuration access. + PciConfig = 5, + /// Shared memory region. + SharedMemory = 8, + /// Vendor-specific data. + Vendor = 9, +} + +const_assert_eq!(core::mem::size_of::(), 1); + +#[derive(Debug, Copy, Clone)] +#[repr(C, packed)] +pub struct PciCapability { + /// Identifies the structure. + pub cfg_type: CfgType, + /// Where to find it. + pub bar: u8, + /// Pad to a full dword. + pub padding: [u8; 3], + /// Offset within the bar. + pub offset: u32, + /// Length of the structure, in bytes. + pub length: u32, +} + +// The size of `PciCapability` is 13 bytes since +// the generic PCI fields are *not* included. +const_assert_eq!(core::mem::size_of::(), 13); + +bitflags::bitflags! { + #[derive(Debug, Copy, Clone, PartialEq)] + #[repr(transparent)] + pub struct DeviceStatusFlags: u8 { + /// Indicates that the guest OS has found the device and recognized it as a + /// valid device. + const ACKNOWLEDGE = 1; + /// Indicates that the guest OS knows how to drive the device. + const DRIVER = 2; + /// Indicates that something went wrong in the guest and it has given up on + /// the device. + const FAILED = 128; + /// Indicates that the driver has acknowledged all the features it understands + /// and feature negotiation is complete. + const FEATURES_OK = 8; + /// Indicates that the driver is set up and ready to drive the device. + const DRIVER_OK = 4; + /// Indicates that the device has experienced an error from which it can’t recover. + const DEVICE_NEEDS_RESET = 64; + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct CommonCfg { + // About the whole device. + pub device_feature_select: VolatileCell, // read-write + pub device_feature: VolatileCell, // read-only for driver + pub driver_feature_select: VolatileCell, // read-write + pub driver_feature: VolatileCell, // read-write + pub msix_config: VolatileCell, // read-write + pub num_queues: VolatileCell, // read-only for driver + pub device_status: VolatileCell, // read-write + pub config_generation: VolatileCell, // read-only for driver + + // About a specific virtqueue. + pub queue_select: VolatileCell, // read-write + pub queue_size: VolatileCell, // read-write + pub queue_msix_vector: VolatileCell, // read-write + pub queue_enable: VolatileCell, // read-write + pub queue_notify_off: VolatileCell, // read-only for driver + pub queue_desc: VolatileCell, // read-write + pub queue_driver: VolatileCell, // read-write + pub queue_device: VolatileCell, // read-write +} + +const_assert_eq!(core::mem::size_of::(), 56); + bitflags::bitflags! { #[repr(transparent)] pub struct DescriptorFlags: u16 { @@ -15,7 +104,7 @@ bitflags::bitflags! { } #[repr(C)] -struct Descriptor { +pub struct Descriptor { /// Address (guest-physical). address: u64, /// Size of the descriptor. @@ -29,6 +118,30 @@ const_assert_eq!(core::mem::size_of::(), 16); pub struct VirtQueue {} -pub struct Transport {} +pub struct StandardTransport {} +impl StandardTransport { + pub fn new() -> Self { + Self {} + } +} +#[derive(Debug)] +#[repr(transparent)] +pub struct VolatileCell { + value: UnsafeCell, +} + +impl VolatileCell { + /// Returns a copy of the contained value. + #[inline] + pub fn get(&self) -> T { + unsafe { core::ptr::read_volatile(self.value.get()) } + } + + /// Sets the contained value. + #[inline] + pub fn set(&self, value: T) { + unsafe { core::ptr::write_volatile(self.value.get(), value) } + } +} diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index c82fae63a3..56ca356d0b 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -1,10 +1,26 @@ -use pcid_interface::{PciFeature, PcidServerHandle}; +use pcid_interface::{Capability, PciBar, PcidServerHandle}; +use thiserror::Error; +use virtiod::*; + +use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; + +// TODO(andypython): +// +// cc 3.1.1 Driver Requirements: Device Initialization +// Reset the device. +// Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. +// Set the DRIVER status bit: the guest OS knows how to drive the device. +// Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. +// Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. +// Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. +// Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. +// Set the DRIVER_OK status bit. At this point the device is “live”. pub fn main() -> anyhow::Result<()> { #[cfg(target_os = "redox")] setup_logging(); - redox_daemon::Daemon::new(daemon).expect("virtio-core: failed to daemonize"); + redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } #[cfg(target_os = "redox")] @@ -49,24 +65,123 @@ fn setup_logging() { log::info!("virtiod: enabled logger"); } -fn daemon(_deamon: redox_daemon::Daemon) -> ! { - let mut pcid_handle = PcidServerHandle::connect_default().unwrap(); - let pci_config = pcid_handle.fetch_config().unwrap(); +#[derive(Debug, Copy, Clone, Error)] +enum Error { + #[error("capability {0:?} not found")] + InCapable(CfgType), + #[error("failed to map memory")] + MapErr, +} + +fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { + let mut pcid_handle = PcidServerHandle::connect_default()?; + let pci_config = pcid_handle.fetch_config()?; + let pci_header = pcid_handle.fetch_header()?; // 0x1001 - virtio-blk assert_eq!(pci_config.func.devid, 0x1001); log::info!("virtiod: found `virtio-blk` device"); - // Get the PCI capabilities. - // for vendor_cap in pcid_handle - // .fetch_all_features() - // .unwrap() - // .iter() - // .filter(|(x, _)| matches!(x, PciFeature::VendorSpecific)) - // { + let mut common_addr = None; + let mut notify_addr = None; + let mut isr_addr = None; + let mut device_addr = None; - // } - // log::info!("{}", x.unwrap() as u8); + for capability in pcid_handle + .get_capabilities()? + .iter() + .filter_map(|capability| { + if let Capability::Vendor(vendor) = capability { + Some(vendor) + } else { + None + } + }) + { + assert!(capability.data.len() >= core::mem::size_of::()); + // SAFETY: We have verified that the length of the data is correct. + let capability = unsafe { &*(capability.data.as_ptr() as *const PciCapability) }; + + match capability.cfg_type { + CfgType::Common | CfgType::Notify | CfgType::Isr | CfgType::Device => {} + _ => continue, + } + + let bar = pci_header.get_bar(capability.bar as usize); + let addr = match bar { + PciBar::Memory32(addr) => addr as usize, + PciBar::Memory64(addr) => addr as usize, + + _ => unreachable!("virtio: unsupported bar type: {bar:?}"), + }; + + let address = unsafe { + syscall::physmap( + addr + capability.offset as usize, + capability.length as usize, + PHYSMAP_WRITE | PHYSMAP_NO_CACHE, + ) + .map_err(|_| Error::MapErr)? + }; + + match capability.cfg_type { + CfgType::Common => { + debug_assert!(common_addr.is_none()); + common_addr = Some(address); + } + + CfgType::Notify => { + debug_assert!(notify_addr.is_none()); + notify_addr = Some(address); + } + + CfgType::Isr => { + debug_assert!(isr_addr.is_none()); + isr_addr = Some(address); + } + + CfgType::Device => { + debug_assert!(device_addr.is_none()); + device_addr = Some(address); + } + + _ => unreachable!(), + } + + log::info!("virtio: {capability:?}"); + } + + let common_addr = common_addr.ok_or(Error::InCapable(CfgType::Common))?; + let notify_addr = notify_addr.ok_or(Error::InCapable(CfgType::Notify))?; + let isr_addr = isr_addr.ok_or(Error::InCapable(CfgType::Isr))?; + let device_addr = device_addr.ok_or(Error::InCapable(CfgType::Device))?; + + let common = unsafe { &mut *(common_addr as *mut CommonCfg) }; + + // Reset the device. + common.device_status.set(DeviceStatusFlags::empty()); + // Upon reset, the device must initialize device status to 0. + assert_eq!(common.device_status.get(), DeviceStatusFlags::empty()); + log::info!("virtio: successfully reseted the device"); + + // XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits + // in `device_status` are required to be done in two steps. + common + .device_status + .set(common.device_status.get() | DeviceStatusFlags::ACKNOWLEDGE); + + common + .device_status + .set(common.device_status.get() | DeviceStatusFlags::DRIVER); + + log::info!("virtio: using standard PCI transport"); + + let _transport = StandardTransport::new(); loop {} } + +fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { + deamon(redox_daemon).unwrap(); + unreachable!(); +} From fe222645711d326882d9b7740c21a28ba6afad47 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 19 Jun 2023 12:22:03 +1000 Subject: [PATCH 0621/1301] misc: include `virtiod` in the README Signed-off-by: Anhad Singh --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 22f2e030d7..6023ec3f00 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ These are the currently implemented devices/hardware interfaces. - usbctl - USB control (incomplete). - usbhidd - USB HID (incomplete). - usbscsid - USB SCSI (incomplete). +- virtiod - VirtIO (incomplete) (`virtio-blk`). ## Contributing to Drivers From 12551d450f7c0d1230fd96c743bb093108c93036 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 19 Jun 2023 15:12:44 +1000 Subject: [PATCH 0622/1301] virtio: enable and allocate MSI-X vector Signed-off-by: Anhad Singh --- virtiod/src/main.rs | 148 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 142 insertions(+), 6 deletions(-) diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index 56ca356d0b..fb5f55de73 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -1,21 +1,43 @@ -use pcid_interface::{Capability, PciBar, PcidServerHandle}; +use core::ptr::NonNull; + +use static_assertions::const_assert_eq; use thiserror::Error; use virtiod::*; -use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use pcid_interface::irq_helpers::{allocate_single_interrupt_vector, read_bsp_apic_id}; +use pcid_interface::msi::x86_64 as x86_64_msix; +use pcid_interface::msi::x86_64::DeliveryMode; +use pcid_interface::msi::{MsixCapability, MsixTableEntry}; +use pcid_interface::*; + +use syscall::{Io, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; // TODO(andypython): // // cc 3.1.1 Driver Requirements: Device Initialization // Reset the device. -// Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. -// Set the DRIVER status bit: the guest OS knows how to drive the device. +// Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. [done] +// Set the DRIVER status bit: the guest OS knows how to drive the device. [done] +// setup interrupts [done] // Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. // Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. // Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. // Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. // Set the DRIVER_OK status bit. At this point the device is “live”. +use std::ops::{Add, Div, Rem}; + +fn div_round_up(a: T, b: T) -> T +where + T: Add + Div + Rem + PartialEq + From + Copy, +{ + if a % b != T::from(0u8) { + a / b + T::from(1u8) + } else { + a / b + } +} + pub fn main() -> anyhow::Result<()> { #[cfg(target_os = "redox")] setup_logging(); @@ -65,12 +87,33 @@ fn setup_logging() { log::info!("virtiod: enabled logger"); } +struct MsixInfo { + pub virt_table_base: NonNull, + pub virt_pba_base: NonNull, + pub capability: MsixCapability, +} + +impl MsixInfo { + pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { + &mut *self.virt_table_base.as_ptr().offset(k as isize) + } + + pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { + assert!(k < self.capability.table_size() as usize); + unsafe { self.table_entry_pointer_unchecked(k) } + } +} + +const_assert_eq!(std::mem::size_of::(), 16); + #[derive(Debug, Copy, Clone, Error)] enum Error { #[error("capability {0:?} not found")] InCapable(CfgType), #[error("failed to map memory")] - MapErr, + Physmap, + #[error("failed to allocate an interrupt vector")] + ExhaustedInt, } fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { @@ -122,7 +165,7 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { capability.length as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE, ) - .map_err(|_| Error::MapErr)? + .map_err(|_| Error::Physmap)? }; match capability.cfg_type { @@ -175,6 +218,99 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { .device_status .set(common.device_status.get() | DeviceStatusFlags::DRIVER); + // Setup interrupts. + let all_pci_features = pcid_handle.fetch_all_features()?; + + let has_msi = all_pci_features.iter().any(|(feature, _)| feature.is_msi()); + let has_msix = all_pci_features + .iter() + .any(|(feature, _)| feature.is_msix()); + + if has_msi { + // TODO(andypython) + todo!() + } else if has_msix { + // Extended message signaled interrupts. + let capability = match pcid_handle.feature_info(PciFeature::MsiX)? { + PciFeatureInfo::MsiX(capability) => capability, + _ => unreachable!(), + }; + + let table_size = capability.table_size(); + let table_base = capability.table_base_pointer(pci_config.func.bars); + let table_min_length = table_size * 16; + let pba_min_length = div_round_up(table_size, 8); + + let pba_base = capability.pba_base_pointer(pci_config.func.bars); + + let bir = capability.table_bir() as usize; + let bar = pci_config.func.bars[bir]; + let bar_size = pci_config.func.bar_sizes[bir] as u64; + + let bar_ptr = match bar { + PciBar::Memory32(ptr) => ptr.into(), + PciBar::Memory64(ptr) => ptr, + _ => unreachable!(), + }; + + let address = unsafe { + syscall::physmap( + bar_ptr as usize, + bar_size as usize, + PHYSMAP_WRITE | PHYSMAP_NO_CACHE, + ) + .map_err(|_| Error::Physmap)? + }; + + // Ensure that the table and PBA are be within the BAR. + { + let bar_range = bar_ptr..bar_ptr + bar_size; + assert!(bar_range.contains(&(table_base as u64 + table_min_length as u64))); + assert!(bar_range.contains(&(pba_base as u64 + pba_min_length as u64))); + } + + let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; + let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; + + let mut info = MsixInfo { + virt_table_base: NonNull::new(virt_table_base).unwrap(), + virt_pba_base: NonNull::new(virt_pba_base).unwrap(), + capability, + }; + + // Allocate the primary MSI vector. + let (vector, interrupt_handle) = { + let k = 0; + let table_entry_pointer = info.table_entry_pointer(k); + + let destination_id = read_bsp_apic_id()?; + let lapic_id = u8::try_from(destination_id).unwrap(); + + let rh = false; + let dm = false; + let addr = x86_64_msix::message_address(lapic_id, rh, dm); + + let (vector, interrupt_handle) = + allocate_single_interrupt_vector(destination_id)?.ok_or(Error::ExhaustedInt)?; + + let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + + table_entry_pointer.addr_lo.write(addr); + table_entry_pointer.addr_hi.write(0); + table_entry_pointer.msg_data.write(msg_data); + table_entry_pointer + .vec_ctl + .writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + + (vector, interrupt_handle) + }; + + pcid_handle.enable_feature(PciFeature::MsiX)?; + log::info!("virtio: using MSI-X (vector={vector}, interrupt_handle={interrupt_handle:?})"); + } else { + unimplemented!() + } + log::info!("virtio: using standard PCI transport"); let _transport = StandardTransport::new(); From 100ff9abd4754c8c5783da1414706d7a17e1ba79 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 19 Jun 2023 16:33:00 +1000 Subject: [PATCH 0623/1301] virtio: add `check_device_feature` and `ack_driver_feature` for `StandardTransport`. Signed-off-by: Anhad Singh --- virtiod/src/lib.rs | 18 +++++++++--------- virtiod/src/main.rs | 22 ++++++++++++++++------ virtiod/src/transport.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 15 deletions(-) create mode 100644 virtiod/src/transport.rs diff --git a/virtiod/src/lib.rs b/virtiod/src/lib.rs index ee0658c079..ee820f957a 100644 --- a/virtiod/src/lib.rs +++ b/virtiod/src/lib.rs @@ -3,6 +3,8 @@ use core::cell::UnsafeCell; use static_assertions::const_assert_eq; +pub mod transport; + #[derive(Debug, Copy, Clone)] #[repr(u8)] pub enum CfgType { @@ -116,16 +118,14 @@ pub struct Descriptor { const_assert_eq!(core::mem::size_of::(), 16); +/// This indicates compliance with the version 1 VirtIO specification. +/// +/// See `6.1 Driver Requirements: Reserved Feature Bits` section of the VirtIO +/// specification for more information. +pub const VIRTIO_F_VERSION_1: u32 = 32; + pub struct VirtQueue {} -pub struct StandardTransport {} - -impl StandardTransport { - pub fn new() -> Self { - Self {} - } -} - #[derive(Debug)] #[repr(transparent)] pub struct VolatileCell { @@ -141,7 +141,7 @@ impl VolatileCell { /// Sets the contained value. #[inline] - pub fn set(&self, value: T) { + pub fn set(&mut self, value: T) { unsafe { core::ptr::write_volatile(self.value.get(), value) } } } diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index fb5f55de73..31761b29f2 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -2,6 +2,8 @@ use core::ptr::NonNull; use static_assertions::const_assert_eq; use thiserror::Error; + +use virtiod::transport::StandardTransport; use virtiod::*; use pcid_interface::irq_helpers::{allocate_single_interrupt_vector, read_bsp_apic_id}; @@ -14,11 +16,14 @@ use syscall::{Io, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; // TODO(andypython): // -// cc 3.1.1 Driver Requirements: Device Initialization -// Reset the device. -// Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. [done] -// Set the DRIVER status bit: the guest OS knows how to drive the device. [done] -// setup interrupts [done] +// cc 3.1.1 Driver Requirements: Device Initialization +// +// ================ Generic ================= +// * Reset the device. [done] +// * Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. [done] +// * Set the DRIVER status bit: the guest OS knows how to drive the device. [done] +// * setup interrupts [done] +// =============== Driver Specific=============== // Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. // Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. // Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. @@ -313,7 +318,12 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { log::info!("virtio: using standard PCI transport"); - let _transport = StandardTransport::new(); + let mut transport = StandardTransport::new(pci_header, common); + + // Check VirtIO version 1 compliance. + assert!(transport.check_device_feature(VIRTIO_F_VERSION_1)); + transport.ack_driver_feature(VIRTIO_F_VERSION_1); + loop {} } diff --git a/virtiod/src/transport.rs b/virtiod/src/transport.rs new file mode 100644 index 0000000000..3141e135b8 --- /dev/null +++ b/virtiod/src/transport.rs @@ -0,0 +1,28 @@ +use pcid_interface::PciHeader; + +use crate::CommonCfg; + +pub struct StandardTransport<'a> { + header: PciHeader, + common: &'a mut CommonCfg, +} + +impl<'a> StandardTransport<'a> { + pub fn new(header: PciHeader, common: &'a mut CommonCfg) -> Self { + Self { header, common } + } + + pub fn check_device_feature(&mut self, feature: u32) -> bool { + self.common.device_feature_select.set(feature >> 5); + (self.common.device_feature.get() & (1 << (feature & 31))) != 0 + } + + pub fn ack_driver_feature(&mut self, feature: u32) { + self.common.driver_feature_select.set(feature >> 5); + + let current = self.common.driver_feature.get(); + self.common + .driver_feature + .set(current | (1 << (feature & 31))); + } +} From 8a7fa569a7b7d71201d8e7f5b79bae91575f484b Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 20 Jun 2023 10:00:08 +1000 Subject: [PATCH 0624/1301] virtiod: ensure the device has MSI-X support According to the virtio sspecification v1.2, MSI-X support is REQUIRED and is the only supported method anyways (i.e, legacy int and MSI wont work). Signed-off-by: Anhad Singh --- virtiod/src/main.rs | 173 ++++++++++++++++++++++---------------------- 1 file changed, 87 insertions(+), 86 deletions(-) diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index 31761b29f2..59e67cb2a6 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -121,6 +121,90 @@ enum Error { ExhaustedInt, } +fn enable_msix(pcid_handle: &mut PcidServerHandle) -> anyhow::Result<()> { + let pci_config = pcid_handle.fetch_config()?; + + // Extended message signaled interrupts. + let capability = match pcid_handle.feature_info(PciFeature::MsiX)? { + PciFeatureInfo::MsiX(capability) => capability, + _ => unreachable!(), + }; + + let table_size = capability.table_size(); + let table_base = capability.table_base_pointer(pci_config.func.bars); + let table_min_length = table_size * 16; + let pba_min_length = div_round_up(table_size, 8); + + let pba_base = capability.pba_base_pointer(pci_config.func.bars); + + let bir = capability.table_bir() as usize; + let bar = pci_config.func.bars[bir]; + let bar_size = pci_config.func.bar_sizes[bir] as u64; + + let bar_ptr = match bar { + PciBar::Memory32(ptr) => ptr.into(), + PciBar::Memory64(ptr) => ptr, + _ => unreachable!(), + }; + + let address = unsafe { + syscall::physmap( + bar_ptr as usize, + bar_size as usize, + PHYSMAP_WRITE | PHYSMAP_NO_CACHE, + ) + .map_err(|_| Error::Physmap)? + }; + + // Ensure that the table and PBA are be within the BAR. + { + let bar_range = bar_ptr..bar_ptr + bar_size; + assert!(bar_range.contains(&(table_base as u64 + table_min_length as u64))); + assert!(bar_range.contains(&(pba_base as u64 + pba_min_length as u64))); + } + + let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; + let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; + + let mut info = MsixInfo { + virt_table_base: NonNull::new(virt_table_base).unwrap(), + virt_pba_base: NonNull::new(virt_pba_base).unwrap(), + capability, + }; + + // Allocate the primary MSI vector. + let (vector, interrupt_handle) = { + let k = 0; + let table_entry_pointer = info.table_entry_pointer(k); + + let destination_id = read_bsp_apic_id()?; + let lapic_id = u8::try_from(destination_id).unwrap(); + + let rh = false; + let dm = false; + let addr = x86_64_msix::message_address(lapic_id, rh, dm); + + let (vector, interrupt_handle) = + allocate_single_interrupt_vector(destination_id)?.ok_or(Error::ExhaustedInt)?; + + let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + + table_entry_pointer.addr_lo.write(addr); + table_entry_pointer.addr_hi.write(0); + table_entry_pointer.msg_data.write(msg_data); + table_entry_pointer + .vec_ctl + .writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + + (vector, interrupt_handle) + }; + + pcid_handle.enable_feature(PciFeature::MsiX)?; + + log::info!("virtio: using MSI-X (vector={vector}, interrupt_handle={interrupt_handle:?})"); + Ok(()) +} + fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut pcid_handle = PcidServerHandle::connect_default()?; let pci_config = pcid_handle.fetch_config()?; @@ -225,96 +309,13 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { // Setup interrupts. let all_pci_features = pcid_handle.fetch_all_features()?; - - let has_msi = all_pci_features.iter().any(|(feature, _)| feature.is_msi()); let has_msix = all_pci_features .iter() .any(|(feature, _)| feature.is_msix()); - if has_msi { - // TODO(andypython) - todo!() - } else if has_msix { - // Extended message signaled interrupts. - let capability = match pcid_handle.feature_info(PciFeature::MsiX)? { - PciFeatureInfo::MsiX(capability) => capability, - _ => unreachable!(), - }; - - let table_size = capability.table_size(); - let table_base = capability.table_base_pointer(pci_config.func.bars); - let table_min_length = table_size * 16; - let pba_min_length = div_round_up(table_size, 8); - - let pba_base = capability.pba_base_pointer(pci_config.func.bars); - - let bir = capability.table_bir() as usize; - let bar = pci_config.func.bars[bir]; - let bar_size = pci_config.func.bar_sizes[bir] as u64; - - let bar_ptr = match bar { - PciBar::Memory32(ptr) => ptr.into(), - PciBar::Memory64(ptr) => ptr, - _ => unreachable!(), - }; - - let address = unsafe { - syscall::physmap( - bar_ptr as usize, - bar_size as usize, - PHYSMAP_WRITE | PHYSMAP_NO_CACHE, - ) - .map_err(|_| Error::Physmap)? - }; - - // Ensure that the table and PBA are be within the BAR. - { - let bar_range = bar_ptr..bar_ptr + bar_size; - assert!(bar_range.contains(&(table_base as u64 + table_min_length as u64))); - assert!(bar_range.contains(&(pba_base as u64 + pba_min_length as u64))); - } - - let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; - let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; - - let mut info = MsixInfo { - virt_table_base: NonNull::new(virt_table_base).unwrap(), - virt_pba_base: NonNull::new(virt_pba_base).unwrap(), - capability, - }; - - // Allocate the primary MSI vector. - let (vector, interrupt_handle) = { - let k = 0; - let table_entry_pointer = info.table_entry_pointer(k); - - let destination_id = read_bsp_apic_id()?; - let lapic_id = u8::try_from(destination_id).unwrap(); - - let rh = false; - let dm = false; - let addr = x86_64_msix::message_address(lapic_id, rh, dm); - - let (vector, interrupt_handle) = - allocate_single_interrupt_vector(destination_id)?.ok_or(Error::ExhaustedInt)?; - - let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); - - table_entry_pointer.addr_lo.write(addr); - table_entry_pointer.addr_hi.write(0); - table_entry_pointer.msg_data.write(msg_data); - table_entry_pointer - .vec_ctl - .writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); - - (vector, interrupt_handle) - }; - - pcid_handle.enable_feature(PciFeature::MsiX)?; - log::info!("virtio: using MSI-X (vector={vector}, interrupt_handle={interrupt_handle:?})"); - } else { - unimplemented!() - } + // According to the virtio specification, the device REQUIRED to support MSI-X. + assert!(has_msix, "virtio: device does not support MSI-X"); + enable_msix(&mut pcid_handle)?; log::info!("virtio: using standard PCI transport"); From 990a9c271688298182e173077203a3d857796759 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 20 Jun 2023 10:14:10 +1000 Subject: [PATCH 0625/1301] virtio::transport: finalize features Signed-off-by: Anhad Singh --- virtiod/VIRTIO.md | 17 +++++++++++++++++ virtiod/src/main.rs | 21 +-------------------- virtiod/src/transport.rs | 18 ++++++++++++++++-- 3 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 virtiod/VIRTIO.md diff --git a/virtiod/VIRTIO.md b/virtiod/VIRTIO.md new file mode 100644 index 0000000000..f5d31f071a --- /dev/null +++ b/virtiod/VIRTIO.md @@ -0,0 +1,17 @@ +## Generic +- [x] Reset the device. +- [x] Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. +- [x] Set the DRIVER status bit: the guest OS knows how to drive the device. +- [x] Setup Interrupts + +## Driver Specific +- [x] Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. +- [x] Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. +- [x] Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. +- [ ] Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. +- [ ] Set the DRIVER_OK status bit. At this point the device is “live”. + +## Drivers +- [ ] `virtio-blk` +- [ ] `virtio-net` +- [ ] `virtio-gpu` diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index 59e67cb2a6..c3f32b42c8 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -14,22 +14,6 @@ use pcid_interface::*; use syscall::{Io, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; -// TODO(andypython): -// -// cc 3.1.1 Driver Requirements: Device Initialization -// -// ================ Generic ================= -// * Reset the device. [done] -// * Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. [done] -// * Set the DRIVER status bit: the guest OS knows how to drive the device. [done] -// * setup interrupts [done] -// =============== Driver Specific=============== -// Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. -// Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. -// Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. -// Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. -// Set the DRIVER_OK status bit. At this point the device is “live”. - use std::ops::{Add, Div, Rem}; fn div_round_up(a: T, b: T) -> T @@ -320,10 +304,7 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { log::info!("virtio: using standard PCI transport"); let mut transport = StandardTransport::new(pci_header, common); - - // Check VirtIO version 1 compliance. - assert!(transport.check_device_feature(VIRTIO_F_VERSION_1)); - transport.ack_driver_feature(VIRTIO_F_VERSION_1); + transport.finalize_features(); loop {} } diff --git a/virtiod/src/transport.rs b/virtiod/src/transport.rs index 3141e135b8..4ee344dd25 100644 --- a/virtiod/src/transport.rs +++ b/virtiod/src/transport.rs @@ -1,7 +1,6 @@ +use crate::*; use pcid_interface::PciHeader; -use crate::CommonCfg; - pub struct StandardTransport<'a> { header: PciHeader, common: &'a mut CommonCfg, @@ -25,4 +24,19 @@ impl<'a> StandardTransport<'a> { .driver_feature .set(current | (1 << (feature & 31))); } + + pub fn finalize_features(&mut self) { + // Check VirtIO version 1 compliance. + assert!(self.check_device_feature(VIRTIO_F_VERSION_1)); + self.ack_driver_feature(VIRTIO_F_VERSION_1); + + self.common + .device_status + .set(self.common.device_status.get() | DeviceStatusFlags::FEATURES_OK); + + // Re-read device status to ensure the `FEATURES_OK` bit is still set: otherwise, + // the device does not support our subset of features and the device is unusable. + let confirm = self.common.device_status.get(); + assert!((confirm & DeviceStatusFlags::FEATURES_OK) == DeviceStatusFlags::FEATURES_OK); + } } From 8fb5e353eae02109ddd9789e27e5b69a367c4783 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 20 Jun 2023 14:14:22 +1000 Subject: [PATCH 0626/1301] virtio::transport: setup queue Signed-off-by: Anhad Singh --- virtiod/src/lib.rs | 78 ++++++++++++++++++++++++++++++---------- virtiod/src/main.rs | 23 +++++------- virtiod/src/transport.rs | 76 +++++++++++++++++++++++++++++++++++++-- virtiod/src/utils.rs | 38 ++++++++++++++++++++ 4 files changed, 180 insertions(+), 35 deletions(-) create mode 100644 virtiod/src/utils.rs diff --git a/virtiod/src/lib.rs b/virtiod/src/lib.rs index ee820f957a..b58688aa46 100644 --- a/virtiod/src/lib.rs +++ b/virtiod/src/lib.rs @@ -1,9 +1,25 @@ //! https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html -use core::cell::UnsafeCell; use static_assertions::const_assert_eq; pub mod transport; +pub mod utils; + +use utils::{IncompleteArrayField, VolatileCell}; + +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum Error { + #[error("capability {0:?} not found")] + InCapable(CfgType), + #[error("failed to map memory")] + Physmap, + #[error("failed to allocate an interrupt vector")] + ExhaustedInt, + #[error("syscall error")] + SyscallError(syscall::Error), +} #[derive(Debug, Copy, Clone)] #[repr(u8)] @@ -124,24 +140,50 @@ const_assert_eq!(core::mem::size_of::(), 16); /// specification for more information. pub const VIRTIO_F_VERSION_1: u32 = 32; -pub struct VirtQueue {} - -#[derive(Debug)] -#[repr(transparent)] -pub struct VolatileCell { - value: UnsafeCell, +// ======== Available Ring ======== +#[repr(C)] +pub struct AvailableRingElement { + pub table_index: VolatileCell, } -impl VolatileCell { - /// Returns a copy of the contained value. - #[inline] - pub fn get(&self) -> T { - unsafe { core::ptr::read_volatile(self.value.get()) } - } +const_assert_eq!(core::mem::size_of::(), 2); - /// Sets the contained value. - #[inline] - pub fn set(&mut self, value: T) { - unsafe { core::ptr::write_volatile(self.value.get(), value) } - } +/// Virtqueue Available Ring +#[repr(C)] +pub struct AvailableRing { + pub flags: VolatileCell, + pub head_index: VolatileCell, + pub elements: IncompleteArrayField, +} + +const_assert_eq!(core::mem::size_of::(), 4); + +#[repr(C)] +pub struct AvailableRingExtra { + pub avail_event: VolatileCell, // Only if `VIRTIO_F_EVENT_IDX` +} + +const_assert_eq!(core::mem::size_of::(), 2); + +// ======== Used Ring ======== +#[repr(C)] +pub struct UsedRingElement { + pub table_index: VolatileCell, + pub written: VolatileCell, +} + +const_assert_eq!(core::mem::size_of::(), 8); + +#[repr(C)] +pub struct UsedRing { + pub flags: VolatileCell, + pub head_index: VolatileCell, + pub elements: IncompleteArrayField, +} + +const_assert_eq!(core::mem::size_of::(), 4); + +#[repr(C)] +pub struct UsedRingExtra { + pub event_index: VolatileCell, } diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index c3f32b42c8..8d877206bc 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -1,7 +1,8 @@ +#![deny(trivial_numeric_casts, unused_allocation)] + use core::ptr::NonNull; use static_assertions::const_assert_eq; -use thiserror::Error; use virtiod::transport::StandardTransport; use virtiod::*; @@ -13,6 +14,7 @@ use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use pcid_interface::*; use syscall::{Io, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use virtiod::utils::VolatileCell; use std::ops::{Add, Div, Rem}; @@ -95,17 +97,7 @@ impl MsixInfo { const_assert_eq!(std::mem::size_of::(), 16); -#[derive(Debug, Copy, Clone, Error)] -enum Error { - #[error("capability {0:?} not found")] - InCapable(CfgType), - #[error("failed to map memory")] - Physmap, - #[error("failed to allocate an interrupt vector")] - ExhaustedInt, -} - -fn enable_msix(pcid_handle: &mut PcidServerHandle) -> anyhow::Result<()> { +fn enable_msix(pcid_handle: &mut PcidServerHandle) -> anyhow::Result { let pci_config = pcid_handle.fetch_config()?; // Extended message signaled interrupts. @@ -186,7 +178,7 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> anyhow::Result<()> { pcid_handle.enable_feature(PciFeature::MsiX)?; log::info!("virtio: using MSI-X (vector={vector}, interrupt_handle={interrupt_handle:?})"); - Ok(()) + Ok(vector) } fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { @@ -282,7 +274,7 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { log::info!("virtio: successfully reseted the device"); // XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits - // in `device_status` are required to be done in two steps. + // in `device_status` is required to be done in two steps. common .device_status .set(common.device_status.get() | DeviceStatusFlags::ACKNOWLEDGE); @@ -299,13 +291,14 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { // According to the virtio specification, the device REQUIRED to support MSI-X. assert!(has_msix, "virtio: device does not support MSI-X"); - enable_msix(&mut pcid_handle)?; + let msix_vector = enable_msix(&mut pcid_handle)?; log::info!("virtio: using standard PCI transport"); let mut transport = StandardTransport::new(pci_header, common); transport.finalize_features(); + let queue = transport.setup_queue(msix_vector.into())?; loop {} } diff --git a/virtiod/src/transport.rs b/virtiod/src/transport.rs index 4ee344dd25..f46c45aa7e 100644 --- a/virtiod/src/transport.rs +++ b/virtiod/src/transport.rs @@ -1,14 +1,26 @@ +use crate::utils::align; use crate::*; + use pcid_interface::PciHeader; +use syscall::{Dma, PhysBox}; + +use core::sync::atomic::{AtomicU16, Ordering}; pub struct StandardTransport<'a> { header: PciHeader, common: &'a mut CommonCfg, + + queue_index: AtomicU16, } impl<'a> StandardTransport<'a> { pub fn new(header: PciHeader, common: &'a mut CommonCfg) -> Self { - Self { header, common } + Self { + header, + common, + + queue_index: AtomicU16::new(0), + } } pub fn check_device_feature(&mut self, feature: u32) -> bool { @@ -34,9 +46,69 @@ impl<'a> StandardTransport<'a> { .device_status .set(self.common.device_status.get() | DeviceStatusFlags::FEATURES_OK); - // Re-read device status to ensure the `FEATURES_OK` bit is still set: otherwise, + // Re-read device status to ensure the `FEATURES_OK` bit is still set: otherwise, // the device does not support our subset of features and the device is unusable. let confirm = self.common.device_status.get(); assert!((confirm & DeviceStatusFlags::FEATURES_OK) == DeviceStatusFlags::FEATURES_OK); } + + pub fn setup_queue(&mut self, vector: u16) -> anyhow::Result<()> { + let queue_index = self.queue_index.fetch_add(1, Ordering::SeqCst); + self.common.queue_select.set(queue_index); + + let queue_size = self.common.queue_size.get() as usize; + let queue_notify_idx = self.common.queue_notify_off.get(); + + assert!(queue_size != 0 && queue_size.is_power_of_two()); + + // Get the queue size in bytes. + // + // Section 2.7 Split Virtqueues of the specfication describe the alignment + // and size of the queues. + const AVAILABLE_ALIGN: usize = 2; + const USED_ALIGN: usize = 4; + + let table_size: usize = align( + (queue_size as usize) * core::mem::size_of::(), + AVAILABLE_ALIGN, + ); + + let available_size = align( + (queue_size as usize * core::mem::size_of::()) + + core::mem::size_of::(), + USED_ALIGN, + ); + + let used_size = (queue_size as usize) * core::mem::size_of::() + + core::mem::size_of::(); + + // Allocate memory for the queue structues. + let table = unsafe { + Dma::<[Descriptor]>::zeroed_unsized(table_size) + .map_err(|err| Error::SyscallError(err))? + }; + + let avaliable = unsafe { + Dma::<[AvailableRing]>::zeroed_unsized(available_size) + .map_err(|err| Error::SyscallError(err))? + }; + + let used = unsafe { + Dma::<[UsedRing]>::zeroed_unsized(used_size).map_err(|err| Error::SyscallError(err))? + }; + + self.common.queue_desc.set(table.physical() as u64); + self.common.queue_driver.set(avaliable.physical() as u64); + self.common.queue_device.set(used.physical() as u64); + + // Set the MSI-X vector. + self.common.queue_msix_vector.set(vector); + assert!(self.common.queue_msix_vector.get() != 0); + + // Enable the queue. + self.common.queue_enable.set(1); + + log::info!("virtio: enabled queue #{queue_index} (size={queue_size})"); + Ok(()) + } } diff --git a/virtiod/src/utils.rs b/virtiod/src/utils.rs new file mode 100644 index 0000000000..3686e77ed9 --- /dev/null +++ b/virtiod/src/utils.rs @@ -0,0 +1,38 @@ +use core::cell::UnsafeCell; +use core::marker::PhantomData; + +use static_assertions::const_assert_eq; + +#[derive(Debug)] +#[repr(transparent)] +pub struct VolatileCell { + value: UnsafeCell, +} + +impl VolatileCell { + /// Returns a copy of the contained value. + #[inline] + pub fn get(&self) -> T { + unsafe { core::ptr::read_volatile(self.value.get()) } + } + + /// Sets the contained value. + #[inline] + pub fn set(&mut self, value: T) { + unsafe { core::ptr::write_volatile(self.value.get(), value) } + } +} + +#[repr(C)] +pub struct IncompleteArrayField(PhantomData, [T; 0]); + +impl IncompleteArrayField { + #[inline] + pub const fn new() -> Self { + IncompleteArrayField(PhantomData, []) + } +} + +pub const fn align(val: usize, align: usize) -> usize { + (val + align) & !align +} From 576302a618ff595346be101d118016069e00f50c Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 20 Jun 2023 14:17:31 +1000 Subject: [PATCH 0627/1301] virtio-blk: get device config * Get the device config for virtio-blk * Log out the # sectors and the block size Signed-off-by: Anhad Singh --- virtiod/src/main.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index 8d877206bc..47fd8dda16 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -181,6 +181,22 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> anyhow::Result { Ok(vector) } +#[repr(C)] +pub struct BlockGeometry { + pub cylinders: VolatileCell, + pub heads: VolatileCell, + pub sectors: VolatileCell, +} + +#[repr(C)] +pub struct BlkDeviceConfig { + pub capacity: VolatileCell, + pub size_max: VolatileCell, + pub seq_max: VolatileCell, + pub geometry: BlockGeometry, + pub blk_size: VolatileCell, +} + fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut pcid_handle = PcidServerHandle::connect_default()?; let pci_config = pcid_handle.fetch_config()?; @@ -266,6 +282,7 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let device_addr = device_addr.ok_or(Error::InCapable(CfgType::Device))?; let common = unsafe { &mut *(common_addr as *mut CommonCfg) }; + let device_space = unsafe { &mut *(device_addr as *mut BlkDeviceConfig) }; // Reset the device. common.device_status.set(DeviceStatusFlags::empty()); @@ -299,6 +316,13 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { transport.finalize_features(); let queue = transport.setup_queue(msix_vector.into())?; + + log::info!( + "virtio-blk: disk size: {} sectors and block size of {} bytes", + device_space.capacity.get(), + device_space.blk_size.get() + ); + loop {} } From c176903905c544970c57b372279685cd42b18db8 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 21 Jun 2023 10:55:53 +1000 Subject: [PATCH 0628/1301] virtio-blk: read and scheme * Minor code cleanup * Able to read/write from the disk * Recycle the descriptors (this is currently done inefficiently, will be fixed in a follow up commit) * Add the disk scheme for virtio-blk with working functionality for seek(), read() and open() * After all of this work, we are successfully able to boot redox from virtio-blk!! :) Signed-off-by: Anhad Singh --- Cargo.lock | 3 + rust-toolchain.toml | 2 + virtiod/Cargo.toml | 3 + virtiod/VIRTIO.md | 9 +- virtiod/src/lib.rs | 96 +++++++- virtiod/src/main.rs | 206 +++++++++++++--- virtiod/src/scheme.rs | 491 +++++++++++++++++++++++++++++++++++++++ virtiod/src/transport.rs | 421 +++++++++++++++++++++++++++------ virtiod/src/utils.rs | 40 +++- 9 files changed, 1159 insertions(+), 112 deletions(-) create mode 100644 rust-toolchain.toml create mode 100644 virtiod/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index 7af5c36f26..b16ea5ef70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1910,10 +1910,13 @@ version = "0.1.0" dependencies = [ "anyhow", "bitflags 2.3.2", + "block-io-wrapper", "log", + "partitionlib", "pcid", "redox-daemon", "redox-log", + "redox_event", "redox_syscall 0.3.5", "static_assertions", "thiserror", diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000000..5d56faf9ae --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly" diff --git a/virtiod/Cargo.toml b/virtiod/Cargo.toml index 7da66c158d..2594590c4b 100644 --- a/virtiod/Cargo.toml +++ b/virtiod/Cargo.toml @@ -14,5 +14,8 @@ thiserror = "1.0.40" redox-daemon = "0.1" redox-log = "0.1" redox_syscall = "0.3" +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +block-io-wrapper = { path = "../block-io-wrapper" } pcid = { path = "../pcid" } diff --git a/virtiod/VIRTIO.md b/virtiod/VIRTIO.md index f5d31f071a..a3c31a10a9 100644 --- a/virtiod/VIRTIO.md +++ b/virtiod/VIRTIO.md @@ -8,10 +8,13 @@ - [x] Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. - [x] Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. - [x] Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. -- [ ] Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. -- [ ] Set the DRIVER_OK status bit. At this point the device is “live”. +- [x] Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. +- [x] Set the DRIVER_OK status bit. At this point the device is “live”. + +## XXX +- [ ] Mark the deamon as ready. ## Drivers -- [ ] `virtio-blk` +- [ ] `virtio-blk` (in-progress) - [ ] `virtio-net` - [ ] `virtio-gpu` diff --git a/virtiod/src/lib.rs b/virtiod/src/lib.rs index b58688aa46..64fff84bb7 100644 --- a/virtiod/src/lib.rs +++ b/virtiod/src/lib.rs @@ -55,11 +55,20 @@ pub struct PciCapability { pub offset: u32, /// Length of the structure, in bytes. pub length: u32, + notify_multiplier: u32, } -// The size of `PciCapability` is 13 bytes since -// the generic PCI fields are *not* included. -const_assert_eq!(core::mem::size_of::(), 13); +// The size of `PciCapability` is 13 bytes since the generic +// PCI fields are *not* included. +const_assert_eq!(core::mem::size_of::(), 17); + +impl PciCapability { + /// ## Safety + /// Undefined if accessed from a capability type other than [`CfgType::Notify`]. + pub unsafe fn notify_multiplier(&self) -> u32 { + self.notify_multiplier + } +} bitflags::bitflags! { #[derive(Debug, Copy, Clone, PartialEq)] @@ -110,26 +119,27 @@ pub struct CommonCfg { const_assert_eq!(core::mem::size_of::(), 56); bitflags::bitflags! { + #[derive(Debug, Copy, Clone)] #[repr(transparent)] pub struct DescriptorFlags: u16 { /// The next field contains linked buffer index. - const NEXT = 1 << 0; + const NEXT = 1 << 0; /// The buffer is write-only (otherwise read-only). const WRITE_ONLY = 1 << 1; /// The buffer contains a list of buffer descriptors. - const INDIRECT = 1 << 2; + const INDIRECT = 1 << 2; } } #[repr(C)] pub struct Descriptor { /// Address (guest-physical). - address: u64, + pub address: u64, /// Size of the descriptor. - size: u32, - flags: DescriptorFlags, + pub size: u32, + pub flags: DescriptorFlags, /// Index of next desciptor in chain. - next: u16, + pub next: u16, } const_assert_eq!(core::mem::size_of::(), 16); @@ -141,6 +151,10 @@ const_assert_eq!(core::mem::size_of::(), 16); pub const VIRTIO_F_VERSION_1: u32 = 32; // ======== Available Ring ======== +// +// XXX: The driver uses the available ring to offer buffers to the +// device. Each ring entry refers to the head of a descriptor +// chain. #[repr(C)] pub struct AvailableRingElement { pub table_index: VolatileCell, @@ -148,7 +162,6 @@ pub struct AvailableRingElement { const_assert_eq!(core::mem::size_of::(), 2); -/// Virtqueue Available Ring #[repr(C)] pub struct AvailableRing { pub flags: VolatileCell, @@ -158,6 +171,16 @@ pub struct AvailableRing { const_assert_eq!(core::mem::size_of::(), 4); +impl Default for AvailableRing { + fn default() -> Self { + Self { + flags: VolatileCell::new(0), + head_index: VolatileCell::new(0), + elements: IncompleteArrayField::new(), + } + } +} + #[repr(C)] pub struct AvailableRingExtra { pub avail_event: VolatileCell, // Only if `VIRTIO_F_EVENT_IDX` @@ -183,7 +206,60 @@ pub struct UsedRing { const_assert_eq!(core::mem::size_of::(), 4); +impl Default for UsedRing { + fn default() -> Self { + Self { + flags: VolatileCell::new(0), + head_index: VolatileCell::new(0), + elements: IncompleteArrayField::new(), + } + } +} + #[repr(C)] pub struct UsedRingExtra { pub event_index: VolatileCell, } + +// ======== Utils ======== +pub struct Buffer { + buffer: usize, + size: usize, + flags: DescriptorFlags, +} + +impl Buffer { + pub fn new(val: &syscall::Dma) -> Self { + Self { + buffer: val.physical(), + size: core::mem::size_of::(), + flags: DescriptorFlags::empty(), + } + } + + pub fn flags(mut self, flags: DescriptorFlags) -> Self { + self.flags = flags; + self + } +} + +pub struct ChainBuilder { + buffers: Vec, +} + +impl ChainBuilder { + pub fn new() -> Self { + Self { + buffers: Vec::new(), + } + } + + pub fn chain(mut self, buffer: Buffer) -> Self { + self.buffers.push(buffer); + self + } + + pub fn build(self) -> Vec { + self.buffers + } +} diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index 47fd8dda16..3599fee16c 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -2,6 +2,12 @@ use core::ptr::NonNull; +use std::fs::File; +use std::io::{self, ErrorKind}; +use std::io::{Read, Write}; +use std::ops::{Add, Div, Rem}; +use std::os::fd::{AsRawFd, FromRawFd, RawFd}; + use static_assertions::const_assert_eq; use virtiod::transport::StandardTransport; @@ -13,10 +19,12 @@ use pcid_interface::msi::x86_64::DeliveryMode; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use pcid_interface::*; -use syscall::{Io, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use event::EventQueue; +use syscall::{Io, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; + use virtiod::utils::VolatileCell; -use std::ops::{Add, Div, Rem}; +mod scheme; fn div_round_up(a: T, b: T) -> T where @@ -42,8 +50,7 @@ fn setup_logging() { let mut logger = RedoxLogger::new().with_output( OutputBuilder::stderr() - // limit global output to important info - .with_filter(log::LevelFilter::Info) + .with_filter(log::LevelFilter::Trace) .with_ansi_escape_codes() .flush_on_newline(true) .build(), @@ -53,7 +60,7 @@ fn setup_logging() { Ok(builder) => { logger = logger.with_output( builder - .with_filter(log::LevelFilter::Info) + .with_filter(log::LevelFilter::Trace) .flush_on_newline(true) .build(), ) @@ -65,7 +72,7 @@ fn setup_logging() { Ok(builder) => { logger = logger.with_output( builder - .with_filter(log::LevelFilter::Info) + .with_filter(log::LevelFilter::Trace) .with_ansi_escape_codes() .flush_on_newline(true) .build(), @@ -86,7 +93,7 @@ struct MsixInfo { impl MsixInfo { pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { - &mut *self.virt_table_base.as_ptr().offset(k as isize) + &mut *self.virt_table_base.as_ptr().add(k) } pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { @@ -97,7 +104,9 @@ impl MsixInfo { const_assert_eq!(std::mem::size_of::(), 16); -fn enable_msix(pcid_handle: &mut PcidServerHandle) -> anyhow::Result { +const MSIX_PRIMARY_VECTOR: u16 = 0; + +fn enable_msix(pcid_handle: &mut PcidServerHandle) -> anyhow::Result { let pci_config = pcid_handle.fetch_config()?; // Extended message signaled interrupts. @@ -149,9 +158,8 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> anyhow::Result { }; // Allocate the primary MSI vector. - let (vector, interrupt_handle) = { - let k = 0; - let table_entry_pointer = info.table_entry_pointer(k); + let interrupt_handle = { + let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize); let destination_id = read_bsp_apic_id()?; let lapic_id = u8::try_from(destination_id).unwrap(); @@ -172,13 +180,13 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> anyhow::Result { .vec_ctl .writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); - (vector, interrupt_handle) + interrupt_handle }; pcid_handle.enable_feature(PciFeature::MsiX)?; - log::info!("virtio: using MSI-X (vector={vector}, interrupt_handle={interrupt_handle:?})"); - Ok(vector) + log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})"); + Ok(interrupt_handle) } #[repr(C)] @@ -189,15 +197,43 @@ pub struct BlockGeometry { } #[repr(C)] -pub struct BlkDeviceConfig { - pub capacity: VolatileCell, +pub struct BlockDeviceConfig { + capacity: VolatileCell, pub size_max: VolatileCell, pub seq_max: VolatileCell, pub geometry: BlockGeometry, - pub blk_size: VolatileCell, + blk_size: VolatileCell, } -fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { +impl BlockDeviceConfig { + /// Returns the capacity of the block device in bytes. + pub fn capacity(&self) -> u64 { + self.capacity.get() + } + + pub fn block_size(&self) -> u32 { + self.blk_size.get() + } +} + +#[repr(u32)] +pub enum BlockRequestTy { + In = 0, + Out = 1, +} + +const_assert_eq!(core::mem::size_of::(), 4); + +#[repr(C)] +pub struct BlockVirtRequest { + pub ty: BlockRequestTy, + pub reserved: u32, + pub sector: u64, +} + +const_assert_eq!(core::mem::size_of::(), 16); + +fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut pcid_handle = PcidServerHandle::connect_default()?; let pci_config = pcid_handle.fetch_config()?; let pci_header = pcid_handle.fetch_header()?; @@ -222,8 +258,6 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } }) { - assert!(capability.data.len() >= core::mem::size_of::()); - // SAFETY: We have verified that the length of the data is correct. let capability = unsafe { &*(capability.data.as_ptr() as *const PciCapability) }; @@ -257,7 +291,11 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { CfgType::Notify => { debug_assert!(notify_addr.is_none()); - notify_addr = Some(address); + + // SAFETY: The capability type is `Notify`, so its safe to access + // the `notify_multiplier` field. + let multiplier = unsafe { capability.notify_multiplier() }; + notify_addr = Some((address, multiplier)); } CfgType::Isr => { @@ -277,12 +315,18 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } let common_addr = common_addr.ok_or(Error::InCapable(CfgType::Common))?; - let notify_addr = notify_addr.ok_or(Error::InCapable(CfgType::Notify))?; + let (notify_addr, notify_multiplier) = notify_addr.ok_or(Error::InCapable(CfgType::Notify))?; let isr_addr = isr_addr.ok_or(Error::InCapable(CfgType::Isr))?; let device_addr = device_addr.ok_or(Error::InCapable(CfgType::Device))?; + assert!( + notify_multiplier != 0, + "virtio: device uses the same Queue Notify addresses for all queues" + ); + let common = unsafe { &mut *(common_addr as *mut CommonCfg) }; - let device_space = unsafe { &mut *(device_addr as *mut BlkDeviceConfig) }; + let device_space = unsafe { &mut *(device_addr as *mut BlockDeviceConfig) }; + let isr = unsafe { &*(isr_addr as *mut VolatileCell) }; // Reset the device. common.device_status.set(DeviceStatusFlags::empty()); @@ -308,14 +352,71 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { // According to the virtio specification, the device REQUIRED to support MSI-X. assert!(has_msix, "virtio: device does not support MSI-X"); - let msix_vector = enable_msix(&mut pcid_handle)?; + let mut irq_handle = enable_msix(&mut pcid_handle)?; log::info!("virtio: using standard PCI transport"); - let mut transport = StandardTransport::new(pci_header, common); + let transport = StandardTransport::new( + pci_header, + common, + notify_addr as *const u8, + notify_multiplier, + ); transport.finalize_features(); - let queue = transport.setup_queue(msix_vector.into())?; + let queue = transport.setup_queue(MSIX_PRIMARY_VECTOR)?; + let queue_copy = queue.clone(); + + std::thread::spawn(move || { + let mut event_queue = EventQueue::::new().unwrap(); + let mut progress_head = 0; + + event_queue + .add( + irq_handle.as_raw_fd(), + move |_| -> Result, io::Error> { + let isr = isr.get() as usize; + + let mut inner = queue_copy.inner.lock().unwrap(); + let used_head = inner.used.head_index(); + + if progress_head == used_head { + return Ok(None); + } + + let used = inner.used.get_element_at((used_head - 1) as usize); + let mut desc_idx = used.table_index.get(); + inner.descriptor_stack.push_back(desc_idx as u16); + + loop { + let desc = &inner.descriptor[desc_idx as usize]; + if !desc.flags.contains(DescriptorFlags::NEXT) { + break; + } + + desc_idx = desc.next.into(); + inner.descriptor_stack.push_back(desc_idx as u16); + } + + progress_head = used_head; + drop(inner); + + let mut buf = [0u8; 8]; + irq_handle.read(&mut buf)?; + // Acknowledge the interrupt. + // irq_handle.write(&buf)?; + Ok(Some(isr)) + }, + ) + .unwrap(); + + loop { + event_queue.run().unwrap(); + } + }); + + // At this point the device is alive! + transport.run_device(); log::info!( "virtio-blk: disk size: {} sectors and block size of {} bytes", @@ -323,7 +424,58 @@ fn deamon(_deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device_space.blk_size.get() ); - loop {} + let mut name = pci_config.func.name(); + name.push_str("_virtio_blk"); + + let scheme_name = format!("disk/{}", name); + + let socket_fd = syscall::open( + &format!(":{}", scheme_name), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, + ) + .map_err(Error::SyscallError)?; + + let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + + let mut scheme = scheme::DiskScheme::new(scheme_name, queue, device_space); + + deamon.ready().expect("virtio: failed to deamonize"); + + loop { + let mut packet = Packet::default(); + socket_file + .read(&mut packet) + .expect("ahcid: failed to read disk scheme"); + let packey = scheme.handle(&mut packet); + packet.a = packey.unwrap(); + socket_file + .write(&mut packet) + .expect("ahcid: failed to read disk scheme"); + } + + // for _ in 0..3 { + // let req = syscall::Dma::new(BlockVirtRequest { + // ty: BlockRequestTy::In, + // reserved: 0, + // sector: 0, + // }) + // .unwrap(); + + // let result = syscall::Dma::new([0u8; 512]).unwrap(); + // let status = syscall::Dma::new(u8::MAX).unwrap(); + + // let chain = ChainBuilder::new() + // .chain(Buffer::new(&req).flags(DescriptorFlags::NEXT)) + // .chain(Buffer::new(&result).flags(DescriptorFlags::WRITE_ONLY | DescriptorFlags::NEXT)) + // .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) + // .build(); + + // queue.send(chain); + + // log::info!("{}", event_queue.run()?); + // log::info!("command status: {}", *status); + // log::info!("data: {:?}", result.as_ref()); + // } } fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { diff --git a/virtiod/src/scheme.rs b/virtiod/src/scheme.rs new file mode 100644 index 0000000000..8bdd0717e0 --- /dev/null +++ b/virtiod/src/scheme.rs @@ -0,0 +1,491 @@ +use std::cmp; +use std::collections::BTreeMap; +use std::io::Read; +use std::io::Result as IoResult; +use std::io::Seek; + +use std::fmt::Write; +use std::sync::Arc; + +use partitionlib::LogicalBlockSize; +use partitionlib::PartitionTable; +use syscall::*; +use virtiod::transport::Queue; +use virtiod::Buffer; +use virtiod::ChainBuilder; +use virtiod::DescriptorFlags; + +use crate::BlockDeviceConfig; +use crate::BlockRequestTy; +use crate::BlockVirtRequest; + +const BLK_SIZE: u64 = 512; + +trait BlkExtension { + /// XXX: Reads only one block despite the size of the output buffer. Use [`BlkExtension::read`] instead. + fn read_block(&self, block: u64, block_bytes: &mut [u8]) -> usize; + fn read(&self, block: u64, block_bytes: &mut [u8]) -> usize { + let sectors = block_bytes.len() / BLK_SIZE as usize; + + (0..sectors) + .map(|i| self.read_block(block + i as u64, &mut block_bytes[i * BLK_SIZE as usize..])) + .sum() + } +} + +impl BlkExtension for Queue<'_> { + fn read_block(&self, block: u64, block_bytes: &mut [u8]) -> usize { + let req = syscall::Dma::new(BlockVirtRequest { + ty: BlockRequestTy::In, + reserved: 0, + sector: block, + }) + .unwrap(); + + let result = syscall::Dma::new([0u8; 512]).unwrap(); + let status = syscall::Dma::new(u8::MAX).unwrap(); + + let chain = ChainBuilder::new() + .chain(Buffer::new(&req).flags(DescriptorFlags::NEXT)) + .chain(Buffer::new(&result).flags(DescriptorFlags::WRITE_ONLY | DescriptorFlags::NEXT)) + .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.send(chain); + + // FIXME: interrupts are for a reason + while *status != 0 { + core::hint::spin_loop(); + } + + let size = core::cmp::min(block_bytes.len(), result.len()); + block_bytes[..size].copy_from_slice(&result.as_slice()[..size]); + std::thread::yield_now(); + + size + } +} + +pub enum Handle { + Partition { + /// Partition Number + number: u32, + /// Offset in bytes + offset: usize, + }, + + List { + entries: Vec, + offset: usize, + }, + + Disk { + offset: usize, + }, +} + +pub struct DiskScheme<'a> { + name: String, + queue: Arc>, + next_id: usize, + cfg: &'a mut BlockDeviceConfig, + handles: BTreeMap, + part_table: Option, +} + +impl<'a> DiskScheme<'a> { + pub fn new(name: String, queue: Arc>, cfg: &'a mut BlockDeviceConfig) -> Self { + let mut this = Self { + name, + queue, + next_id: 0, + cfg, + handles: BTreeMap::new(), + part_table: None, + }; + + struct VirtioShim<'a, 'b> { + scheme: &'b DiskScheme<'a>, + offset: u64, + block_bytes: &'b mut [u8], + } + + impl<'a, 'b> Read for VirtioShim<'a, 'b> { + fn read(&mut self, buf: &mut [u8]) -> IoResult { + let read_block = |block: u64, block_bytes: &mut [u8]| -> Result<(), ()> { + let req = syscall::Dma::new(BlockVirtRequest { + ty: BlockRequestTy::In, + reserved: 0, + sector: block, + }) + .unwrap(); + + let result = syscall::Dma::new([0u8; 512]).unwrap(); + let status = syscall::Dma::new(u8::MAX).unwrap(); + + let chain = ChainBuilder::new() + .chain(Buffer::new(&req).flags(DescriptorFlags::NEXT)) + .chain( + Buffer::new(&result) + .flags(DescriptorFlags::WRITE_ONLY | DescriptorFlags::NEXT), + ) + .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.scheme.queue.send(chain); + + // FIXME: interrupts are for a reason + while *status != 0 { + core::hint::spin_loop(); + } + + let size = core::cmp::min(block_bytes.len(), result.len()); + block_bytes[..size].copy_from_slice(&result.as_slice()[..size]); + + std::thread::yield_now(); + + Ok(()) + }; + + let bytes_read = + block_io_wrapper::read(self.offset, 512, buf, self.block_bytes, read_block) + .unwrap(); + self.offset += bytes_read as u64; + Ok(bytes_read) + } + } + + impl<'a, 'b> Seek for VirtioShim<'a, 'b> { + fn seek(&mut self, from: std::io::SeekFrom) -> IoResult { + let size_u = self.scheme.cfg.capacity.get() * self.scheme.cfg.blk_size.get() as u64; + let size = i64::try_from(size_u).or(Err(std::io::Error::new( + std::io::ErrorKind::Other, + "Disk larger than 2^63 - 1 bytes", + )))?; + + self.offset = match from { + std::io::SeekFrom::Start(new_pos) => std::cmp::min(size_u, new_pos), + std::io::SeekFrom::Current(new_pos) => { + std::cmp::max(0, std::cmp::min(size, self.offset as i64 + new_pos)) as u64 + } + std::io::SeekFrom::End(new_pos) => { + std::cmp::max(0, std::cmp::min(size + new_pos, size)) as u64 + } + }; + + Ok(self.offset) + } + } + + let mut shim = VirtioShim { + scheme: &this, + offset: 0, + block_bytes: &mut [0u8; 4096], + }; + + let part_table = partitionlib::get_partitions(&mut shim, LogicalBlockSize::Lb512) + .unwrap() + .expect("virtiod: no partitions found"); + + this.part_table = Some(part_table); + this + } +} + +impl<'a> SchemeBlockMut for DiskScheme<'a> { + fn open( + &mut self, + path: &str, + flags: usize, + uid: u32, + gid: u32, + ) -> syscall::Result> { + log::info!("virtioo: open: {}", path); + + let path_str = path.trim_matches('/'); + if path_str.is_empty() { + if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { + let mut list = String::new(); + // FIXME: The zero is the disk identifier (look in the nvmed scheme, it set's this + // to the namespace id). + write!(list, "{}\n", 0).unwrap(); + + let part_table = self.part_table.as_ref().unwrap(); + + for part_num in 0..part_table.partitions.len() { + write!(list, "{}p{}\n", 0, part_num).unwrap(); + } + + let id = self.next_id; + self.next_id += 1; + self.handles.insert( + id, + Handle::List { + entries: list.into_bytes(), + offset: 0, + }, + ); + + Ok(Some(id)) + } else { + return Err(syscall::Error::new(EISDIR)); + } + } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { + let _nsid_str = &path_str[..p_pos]; + + if p_pos + 1 >= path_str.len() { + return Err(Error::new(ENOENT)); + } + let part_num_str = &path_str[p_pos + 1..]; + let part_num = part_num_str.parse::().unwrap(); + + let part_table = self.part_table.as_ref().unwrap(); + let _part = part_table.partitions.get(part_num as usize).unwrap(); + + let id = self.next_id; + self.next_id += 1; + self.handles.insert( + id, + Handle::Partition { + number: part_num, + offset: 0, + }, + ); + + Ok(Some(id)) + } else { + let nsid = path_str.parse::().unwrap(); + assert_eq!(nsid, 0); + + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle::Disk { offset: 0 }); + Ok(Some(id)) + } + } + + fn chmod( + &mut self, + path: &str, + mode: u16, + uid: u32, + gid: u32, + ) -> syscall::Result> { + todo!() + } + + fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> syscall::Result> { + todo!() + } + + fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> syscall::Result> { + todo!() + } + + fn dup(&mut self, old_id: usize, buf: &[u8]) -> syscall::Result> { + todo!() + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List { + ref mut entries, + ref mut offset, + } => { + let count = (&entries[*offset..]).read(buf).unwrap(); + *offset += count; + Ok(Some(count)) + } + + Handle::Partition { + number, + ref mut offset, + } => { + let part_table = self.part_table.as_ref().unwrap(); + let part = part_table + .partitions + .get(number as usize) + .ok_or(Error::new(EBADF))?; + + // Get the offset in sectors. + let rel_block = (*offset as u64) / BLK_SIZE; + // if rel_block >= part.size { + // return Err(Error::new(EOVERFLOW)); + // } + + let abs_block = part.start_lba + rel_block; + + let count = self.queue.read(abs_block, buf); + *offset += count; + Ok(Some(count)) + } + + Handle::Disk { ref mut offset } => { + let block_size = self.cfg.block_size(); + + let count = self.queue.read((*offset as u64) / 512, buf); + *offset += count; + Ok(Some(count)) + } + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result> { + // lets assume this worked + Ok(Some(buf.len())) + } + + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> syscall::Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List { + ref entries, + ref mut offset, + } => { + let len = entries.len() as isize; + log::debug!("list: whence={whence:?} pos={pos:?} part_len={len:?}"); + + *offset = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len, *offset as isize + pos)), + SEEK_END => cmp::max(0, cmp::min(len, len + pos)), + _ => return Err(Error::new(EINVAL)), + } as usize; + + Ok(Some(*offset as isize)) + } + + Handle::Partition { + number, + ref mut offset, + } => { + let part_table = self.part_table.as_ref().unwrap(); + let part = part_table + .partitions + .get(number as usize) + .ok_or(Error::new(EBADF))?; + + // Partition size in bytes. + let len = (part.size * BLK_SIZE) as isize; + + log::debug!("part: whence={whence:?} pos={pos:?} part_len={len:?}"); + + *offset = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len, *offset as isize + pos)), + SEEK_END => cmp::max(0, cmp::min(len, len + pos)), + _ => return Err(Error::new(EINVAL)), + } as usize; + + Ok(Some(*offset as isize)) + } + + Handle::Disk { ref mut offset } => { + let len = (self.cfg.capacity() * self.cfg.block_size() as u64) as isize; + + *offset = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len, *offset as isize + pos)), + SEEK_END => cmp::max(0, cmp::min(len, len + pos)), + _ => return Err(Error::new(EINVAL)), + } as usize; + + Ok(Some(*offset as isize)) + } + } + } + + fn fchmod(&mut self, id: usize, mode: u16) -> syscall::Result> { + todo!() + } + + fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> syscall::Result> { + todo!() + } + + fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> syscall::Result> { + todo!() + } + + fn fevent( + &mut self, + id: usize, + flags: syscall::EventFlags, + ) -> syscall::Result> { + todo!() + } + + fn fmap_old(&mut self, id: usize, map: &syscall::OldMap) -> syscall::Result> { + todo!() + } + + fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result> { + if map.flags.contains(syscall::MapFlags::MAP_FIXED) { + return Err(syscall::Error::new(syscall::EINVAL)); + } + self.fmap_old( + id, + &syscall::OldMap { + offset: map.offset, + size: map.size, + flags: map.flags, + }, + ) + } + + fn funmap_old(&mut self, address: usize) -> syscall::Result> { + todo!() + } + + fn funmap(&mut self, address: usize, length: usize) -> syscall::Result> { + todo!() + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result> { + todo!() + } + + fn frename( + &mut self, + id: usize, + path: &str, + uid: u32, + gid: u32, + ) -> syscall::Result> { + todo!() + } + + fn fstat(&mut self, id: usize, stat: &mut syscall::Stat) -> syscall::Result> { + todo!() + } + + fn fstatvfs( + &mut self, + id: usize, + stat: &mut syscall::StatVfs, + ) -> syscall::Result> { + todo!() + } + + fn fsync(&mut self, id: usize) -> syscall::Result> { + todo!() + } + + fn ftruncate(&mut self, id: usize, len: usize) -> syscall::Result> { + todo!() + } + + fn futimens( + &mut self, + id: usize, + times: &[syscall::TimeSpec], + ) -> syscall::Result> { + todo!() + } + + fn close(&mut self, id: usize) -> syscall::Result> { + self.handles + .remove(&id) + .ok_or(Error::new(EBADF)) + .and(Ok(Some(0))) + } +} diff --git a/virtiod/src/transport.rs b/virtiod/src/transport.rs index f46c45aa7e..708389cf0c 100644 --- a/virtiod/src/transport.rs +++ b/virtiod/src/transport.rs @@ -1,114 +1,397 @@ -use crate::utils::align; +use crate::utils::{align, round_up}; use crate::*; use pcid_interface::PciHeader; -use syscall::{Dma, PhysBox}; +use syscall::{Dma, PHYSMAP_WRITE}; -use core::sync::atomic::{AtomicU16, Ordering}; +use core::mem::size_of; +use core::sync::atomic::{fence, AtomicU16, Ordering}; -pub struct StandardTransport<'a> { - header: PciHeader, - common: &'a mut CommonCfg, +use std::collections::VecDeque; +use std::sync::{Arc, Mutex, Weak}; - queue_index: AtomicU16, +/// Returns the queue part sizes in bytes. +/// +/// ## Reference +/// Section 2.7 Split Virtqueues of the specfication v1.2 describes the alignment +/// and size of the queue parts. +/// +/// ## Panics +/// If `queue_size` is not a power of two or is zero. +const fn queue_part_sizes(queue_size: usize) -> (usize, usize, usize) { + assert!(queue_size.is_power_of_two() && queue_size != 0); + + const DESCRIPTOR_ALIGN: usize = 16; + const AVAILABLE_ALIGN: usize = 2; + const USED_ALIGN: usize = 4; + + let queue_size = queue_size as usize; + let desc = size_of::() * queue_size; + + // `avail_header`: Size of the available ring header and the footer. + let avail_header = size_of::() + size_of::(); + let avail = avail_header + size_of::() * queue_size; + + // `used_header`: Size of the used ring header and the footer. + let used_header = size_of::() + size_of::(); + let used = used_header + size_of::() * queue_size; + + ( + align(desc, DESCRIPTOR_ALIGN), + align(avail, AVAILABLE_ALIGN), + align(used, USED_ALIGN), + ) } -impl<'a> StandardTransport<'a> { - pub fn new(header: PciHeader, common: &'a mut CommonCfg) -> Self { - Self { - header, - common, +pub struct QueueInner<'a> { + pub descriptor: Dma<[Descriptor]>, + pub available: Available<'a>, + pub used: Used<'a>, - queue_index: AtomicU16::new(0), + /// Keeps track of unused descriptor indicies. + pub descriptor_stack: VecDeque, + + notification_bell: &'a mut VolatileCell, + head_index: u16, +} + +unsafe impl Sync for QueueInner<'_> {} +unsafe impl Send for QueueInner<'_> {} + +pub struct Queue<'a> { + pub inner: Mutex>, + sref: Weak, +} + +impl<'a> Queue<'a> { + pub fn new( + descriptor: Dma<[Descriptor]>, + available: Available<'a>, + used: Used<'a>, + + notification_bell: &'a mut VolatileCell, + ) -> Arc { + Arc::new_cyclic(|sref| Self { + inner: Mutex::new(QueueInner { + head_index: 0, + descriptor_stack: (0..(descriptor.len() - 1) as u16).rev().collect(), + + descriptor, + available, + used, + + notification_bell, + }), + + sref: sref.clone(), + }) + } + + pub fn send(&self, chain: Vec) { + let mut first_descriptor: Option = None; + let mut last_descriptor: Option = None; + + for buffer in chain.iter() { + let descriptor = self.alloc_descriptor(); + + let mut inner = self.inner.lock().unwrap(); + + if first_descriptor.is_none() { + first_descriptor = Some(descriptor); + } + + inner.descriptor[descriptor].address = buffer.buffer as u64; + inner.descriptor[descriptor].flags = buffer.flags; + inner.descriptor[descriptor].size = buffer.size as u32; + + if let Some(index) = last_descriptor { + inner.descriptor[index].next = descriptor as u16; + } + + last_descriptor = Some(descriptor); + } + + let mut inner = self.inner.lock().unwrap(); + + let last_descriptor = last_descriptor.unwrap(); + let first_descriptor = first_descriptor.unwrap(); + + inner.descriptor[last_descriptor].next = 0; + + fence(Ordering::SeqCst); + let index = inner.head_index as usize; + + inner + .available + .get_element_at(index) + .table_index + .set(first_descriptor as u16); + + fence(Ordering::SeqCst); + inner.available.set_head_idx(index as u16 + 1); + inner.head_index += 1; + + assert_eq!(inner.used.flags(), 0); + inner.notification_bell.set(0); // FIXME: This corresponds to the queue index. + } + + fn alloc_descriptor(&self) -> usize { + if let Some(index) = self.inner.lock().unwrap().descriptor_stack.pop_front() { + index as usize + } else { + panic!("virtio: descriptor exhaustion"); + } + } +} + +pub struct Available<'a> { + addr: usize, + size: usize, + + queue_size: usize, + + ring: &'a mut AvailableRing, +} + +impl<'a> Available<'a> { + pub fn new(queue_size: usize) -> anyhow::Result { + let (_, size, _) = queue_part_sizes(queue_size); + + let size = round_up(size); + let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; + let virt = + unsafe { syscall::physmap(addr, size, PHYSMAP_WRITE) }.map_err(Error::SyscallError)?; + + let ring = unsafe { &mut *(virt as *mut AvailableRing) }; + + Ok(Self { + addr, + size, + ring, + queue_size, + }) + } + + /// ## Panics + /// This function panics if the index is out of bounds. + pub fn get_element_at(&mut self, index: usize) -> &mut AvailableRingElement { + // SAFETY: We have exclusive access to the elements and the number of elements + // is correct; same as the queue size. + unsafe { + self.ring + .elements + .as_mut_slice(self.queue_size) + .get_mut(index % 256) + .expect("virtio::available: index out of bounds") } } - pub fn check_device_feature(&mut self, feature: u32) -> bool { - self.common.device_feature_select.set(feature >> 5); - (self.common.device_feature.get() & (1 << (feature & 31))) != 0 + pub fn set_head_idx(&mut self, index: u16) { + self.ring.head_index.set(index); } - pub fn ack_driver_feature(&mut self, feature: u32) { - self.common.driver_feature_select.set(feature >> 5); + pub fn phys_addr(&self) -> usize { + self.addr + } +} - let current = self.common.driver_feature.get(); - self.common - .driver_feature - .set(current | (1 << (feature & 31))); +impl Drop for Available<'_> { + fn drop(&mut self) { + log::warn!("virtio: dropping 'available' ring at {:#x}", self.addr); + + unsafe { + syscall::physunmap(self.addr).unwrap(); + syscall::physfree(self.addr, self.size).unwrap(); + } + } +} + +pub struct Used<'a> { + addr: usize, + size: usize, + + queue_size: usize, + + ring: &'a mut UsedRing, +} + +impl<'a> Used<'a> { + pub fn new(queue_size: usize) -> anyhow::Result { + let (_, _, size) = queue_part_sizes(queue_size); + + let size = round_up(size); + let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; + let virt = + unsafe { syscall::physmap(addr, size, PHYSMAP_WRITE) }.map_err(Error::SyscallError)?; + + let ring = unsafe { &mut *(virt as *mut UsedRing) }; + + Ok(Self { + addr, + size, + ring, + queue_size, + }) } - pub fn finalize_features(&mut self) { + /// ## Panics + /// This function panics if the index is out of bounds. + pub fn get_element_at(&mut self, index: usize) -> &mut UsedRingElement { + // SAFETY: We have exclusive access to the elements and the number of elements + // is correct; same as the queue size. + unsafe { + self.ring + .elements + .as_mut_slice(self.queue_size) + .get_mut(index % 256) + .expect("virtio::used: index out of bounds") + } + } + + pub fn flags(&self) -> u16 { + self.ring.flags.get() + } + + pub fn head_index(&self) -> u16 { + self.ring.head_index.get() + } + + pub fn phys_addr(&self) -> usize { + self.addr + } +} + +impl Drop for Used<'_> { + fn drop(&mut self) { + log::warn!("virtio: dropping 'used' ring at {:#x}", self.addr); + + unsafe { + syscall::physunmap(self.addr).unwrap(); + syscall::physfree(self.addr, self.size).unwrap(); + } + } +} + +pub struct StandardTransport<'a> { + header: PciHeader, + common: Mutex<&'a mut CommonCfg>, + notify: *const u8, + notify_mul: u32, + + queue_index: AtomicU16, + sref: Weak, +} + +impl<'a> StandardTransport<'a> { + pub fn new( + header: PciHeader, + common: &'a mut CommonCfg, + notify: *const u8, + notify_mul: u32, + ) -> Arc { + Arc::new_cyclic(|sref| Self { + header, + common: Mutex::new(common), + notify, + notify_mul, + + queue_index: AtomicU16::new(0), + sref: sref.clone(), + }) + } + + pub fn sref(&self) -> Arc { + // UNWRAP: The constructor ensures that we are wrapped in our own `Arc`. So this + // unwrap is going to be unreachable. + self.sref.upgrade().unwrap() + } + + pub fn check_device_feature(&self, feature: u32) -> bool { + let mut common = self.common.lock().unwrap(); + + common.device_feature_select.set(feature >> 5); + (common.device_feature.get() & (1 << (feature & 31))) != 0 + } + + pub fn ack_driver_feature(&self, feature: u32) { + let mut common = self.common.lock().unwrap(); + + common.driver_feature_select.set(feature >> 5); + + let current = common.driver_feature.get(); + common.driver_feature.set(current | (1 << (feature & 31))); + } + + pub fn finalize_features(&self) { // Check VirtIO version 1 compliance. assert!(self.check_device_feature(VIRTIO_F_VERSION_1)); self.ack_driver_feature(VIRTIO_F_VERSION_1); - self.common + let mut common = self.common.lock().unwrap(); + + let status = common.device_status.get(); + common .device_status - .set(self.common.device_status.get() | DeviceStatusFlags::FEATURES_OK); + .set(status | DeviceStatusFlags::FEATURES_OK); // Re-read device status to ensure the `FEATURES_OK` bit is still set: otherwise, // the device does not support our subset of features and the device is unusable. - let confirm = self.common.device_status.get(); + let confirm = common.device_status.get(); assert!((confirm & DeviceStatusFlags::FEATURES_OK) == DeviceStatusFlags::FEATURES_OK); } - pub fn setup_queue(&mut self, vector: u16) -> anyhow::Result<()> { + pub fn run_device(&self) { + let mut common = self.common.lock().unwrap(); + + let status = common.device_status.get(); + common + .device_status + .set(status | DeviceStatusFlags::DRIVER_OK); + } + + pub fn setup_queue(&self, vector: u16) -> anyhow::Result>> { + let mut common = self.common.lock().unwrap(); + let queue_index = self.queue_index.fetch_add(1, Ordering::SeqCst); - self.common.queue_select.set(queue_index); + common.queue_select.set(queue_index); - let queue_size = self.common.queue_size.get() as usize; - let queue_notify_idx = self.common.queue_notify_off.get(); + let queue_size = common.queue_size.get() as usize; + let queue_notify_idx = common.queue_notify_off.get(); - assert!(queue_size != 0 && queue_size.is_power_of_two()); - - // Get the queue size in bytes. - // - // Section 2.7 Split Virtqueues of the specfication describe the alignment - // and size of the queues. - const AVAILABLE_ALIGN: usize = 2; - const USED_ALIGN: usize = 4; - - let table_size: usize = align( - (queue_size as usize) * core::mem::size_of::(), - AVAILABLE_ALIGN, - ); - - let available_size = align( - (queue_size as usize * core::mem::size_of::()) - + core::mem::size_of::(), - USED_ALIGN, - ); - - let used_size = (queue_size as usize) * core::mem::size_of::() - + core::mem::size_of::(); + log::info!("notify_idx: {}", queue_notify_idx); // Allocate memory for the queue structues. - let table = unsafe { - Dma::<[Descriptor]>::zeroed_unsized(table_size) - .map_err(|err| Error::SyscallError(err))? + let descriptor = unsafe { + Dma::<[Descriptor]>::zeroed_unsized(queue_size).map_err(Error::SyscallError)? }; - let avaliable = unsafe { - Dma::<[AvailableRing]>::zeroed_unsized(available_size) - .map_err(|err| Error::SyscallError(err))? - }; + let mut avail = Available::new(queue_size)?; + let mut used = Used::new(queue_size)?; - let used = unsafe { - Dma::<[UsedRing]>::zeroed_unsized(used_size).map_err(|err| Error::SyscallError(err))? - }; + for i in 0..queue_size { + // XXX: Fill the `table_index` of the elements with `T::MAX` to help with + // debugging since qemu reports them as illegal values. + avail.get_element_at(i).table_index.set(u16::MAX); + used.get_element_at(i).table_index.set(u32::MAX); + } - self.common.queue_desc.set(table.physical() as u64); - self.common.queue_driver.set(avaliable.physical() as u64); - self.common.queue_device.set(used.physical() as u64); + common.queue_desc.set(descriptor.physical() as u64); + common.queue_driver.set(avail.phys_addr() as u64); + common.queue_device.set(used.phys_addr() as u64); // Set the MSI-X vector. - self.common.queue_msix_vector.set(vector); - assert!(self.common.queue_msix_vector.get() != 0); + common.queue_msix_vector.set(vector); + assert!(common.queue_msix_vector.get() == vector); // Enable the queue. - self.common.queue_enable.set(1); + common.queue_enable.set(1); + + let notification_bell = unsafe { + let offset = self.notify_mul * queue_notify_idx as u32; + &mut *(self.notify.add(offset as usize) as *mut VolatileCell) + }; log::info!("virtio: enabled queue #{queue_index} (size={queue_size})"); - Ok(()) + Ok(Queue::new(descriptor, avail, used, notification_bell)) } } diff --git a/virtiod/src/utils.rs b/virtiod/src/utils.rs index 3686e77ed9..99efef87d6 100644 --- a/virtiod/src/utils.rs +++ b/virtiod/src/utils.rs @@ -1,15 +1,20 @@ use core::cell::UnsafeCell; use core::marker::PhantomData; -use static_assertions::const_assert_eq; - #[derive(Debug)] -#[repr(transparent)] +#[repr(C)] pub struct VolatileCell { value: UnsafeCell, } impl VolatileCell { + #[inline] + pub fn new(value: T) -> Self { + Self { + value: UnsafeCell::new(value), + } + } + /// Returns a copy of the contained value. #[inline] pub fn get(&self) -> T { @@ -23,6 +28,8 @@ impl VolatileCell { } } +unsafe impl Sync for VolatileCell {} + #[repr(C)] pub struct IncompleteArrayField(PhantomData, [T; 0]); @@ -31,8 +38,35 @@ impl IncompleteArrayField { pub const fn new() -> Self { IncompleteArrayField(PhantomData, []) } + + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + core::slice::from_raw_parts(self.as_ptr(), len) + } + + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + core::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } + + #[inline] + pub unsafe fn as_ptr(&self) -> *const T { + self as *const _ as *const T + } + + #[inline] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + self as *mut _ as *mut T + } } pub const fn align(val: usize, align: usize) -> usize { (val + align) & !align } + +// From the syscall crate; the function is private. +// +// TODO(andypython): make it public +pub const fn round_up(x: usize) -> usize { + (x + syscall::PAGE_SIZE - 1) / syscall::PAGE_SIZE * syscall::PAGE_SIZE +} From 65c431756430c9f00b7da7afbc43b5a8fb02a4fc Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Fri, 23 Jun 2023 16:18:14 +1000 Subject: [PATCH 0629/1301] virtiod: refactoring Signed-off-by: Anhad Singh --- virtiod/src/main.rs | 33 ++++---- virtiod/src/scheme.rs | 171 ++++++++++++++------------------------- virtiod/src/transport.rs | 17 +++- 3 files changed, 94 insertions(+), 127 deletions(-) diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index 3599fee16c..c965301fc1 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -3,7 +3,7 @@ use core::ptr::NonNull; use std::fs::File; -use std::io::{self, ErrorKind}; +use std::io; use std::io::{Read, Write}; use std::ops::{Add, Div, Rem}; use std::os::fd::{AsRawFd, FromRawFd, RawFd}; @@ -375,7 +375,8 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { .add( irq_handle.as_raw_fd(), move |_| -> Result, io::Error> { - let isr = isr.get() as usize; + // Read from ISR to acknowledge the interrupt. + let _isr = isr.get() as usize; let mut inner = queue_copy.inner.lock().unwrap(); let used_head = inner.used.head_index(); @@ -384,18 +385,20 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { return Ok(None); } - let used = inner.used.get_element_at((used_head - 1) as usize); - let mut desc_idx = used.table_index.get(); - inner.descriptor_stack.push_back(desc_idx as u16); - - loop { - let desc = &inner.descriptor[desc_idx as usize]; - if !desc.flags.contains(DescriptorFlags::NEXT) { - break; - } - - desc_idx = desc.next.into(); + for i in progress_head..used_head { + let used = inner.used.get_element_at(i as usize); + let mut desc_idx = used.table_index.get(); inner.descriptor_stack.push_back(desc_idx as u16); + + loop { + let desc = &inner.descriptor[desc_idx as usize]; + if !desc.flags.contains(DescriptorFlags::NEXT) { + break; + } + + desc_idx = desc.next.into(); + inner.descriptor_stack.push_back(desc_idx as u16); + } } progress_head = used_head; @@ -405,7 +408,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { irq_handle.read(&mut buf)?; // Acknowledge the interrupt. // irq_handle.write(&buf)?; - Ok(Some(isr)) + Ok(None) }, ) .unwrap(); @@ -437,7 +440,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - let mut scheme = scheme::DiskScheme::new(scheme_name, queue, device_space); + let mut scheme = scheme::DiskScheme::new(queue, device_space); deamon.ready().expect("virtio: failed to deamonize"); diff --git a/virtiod/src/scheme.rs b/virtiod/src/scheme.rs index 8bdd0717e0..ad8b410766 100644 --- a/virtiod/src/scheme.rs +++ b/virtiod/src/scheme.rs @@ -24,6 +24,10 @@ const BLK_SIZE: u64 = 512; trait BlkExtension { /// XXX: Reads only one block despite the size of the output buffer. Use [`BlkExtension::read`] instead. fn read_block(&self, block: u64, block_bytes: &mut [u8]) -> usize; + + /// XXX: Reads only one block despite the size of the output buffer. Use [`BlkExtension::write`] instead. + fn write_block(&self, block: u64, block_bytes: &[u8]) -> usize; + fn read(&self, block: u64, block_bytes: &mut [u8]) -> usize { let sectors = block_bytes.len() / BLK_SIZE as usize; @@ -31,6 +35,14 @@ trait BlkExtension { .map(|i| self.read_block(block + i as u64, &mut block_bytes[i * BLK_SIZE as usize..])) .sum() } + + fn write(&self, block: u64, block_bytes: &[u8]) -> usize { + let sectors = block_bytes.len() / BLK_SIZE as usize; + + (0..sectors) + .map(|i| self.write_block(block + i as u64, &block_bytes[i * BLK_SIZE as usize..])) + .sum() + } } impl BlkExtension for Queue<'_> { @@ -64,6 +76,36 @@ impl BlkExtension for Queue<'_> { size } + + fn write_block(&self, block: u64, block_bytes: &[u8]) -> usize { + let req = syscall::Dma::new(BlockVirtRequest { + ty: BlockRequestTy::Out, + reserved: 0, + sector: block, + }) + .unwrap(); + + let mut result = syscall::Dma::new([0u8; 512]).unwrap(); + result.copy_from_slice(&block_bytes[..512]); + + let status = syscall::Dma::new(u8::MAX).unwrap(); + + let chain = ChainBuilder::new() + .chain(Buffer::new(&req).flags(DescriptorFlags::NEXT)) + .chain(Buffer::new(&result).flags(DescriptorFlags::NEXT)) + .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.send(chain); + + // FIXME: interrupts are for a reason + while *status != 0 { + core::hint::spin_loop(); + } + + std::thread::yield_now(); + block_bytes.len() + } } pub enum Handle { @@ -85,7 +127,6 @@ pub enum Handle { } pub struct DiskScheme<'a> { - name: String, queue: Arc>, next_id: usize, cfg: &'a mut BlockDeviceConfig, @@ -94,9 +135,8 @@ pub struct DiskScheme<'a> { } impl<'a> DiskScheme<'a> { - pub fn new(name: String, queue: Arc>, cfg: &'a mut BlockDeviceConfig) -> Self { + pub fn new(queue: Arc>, cfg: &'a mut BlockDeviceConfig) -> Self { let mut this = Self { - name, queue, next_id: 0, cfg, @@ -197,10 +237,10 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { &mut self, path: &str, flags: usize, - uid: u32, - gid: u32, + _uid: u32, + _gid: u32, ) -> syscall::Result> { - log::info!("virtioo: open: {}", path); + log::info!("virtiod: open: {}", path); let path_str = path.trim_matches('/'); if path_str.is_empty() { @@ -264,28 +304,6 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { } } - fn chmod( - &mut self, - path: &str, - mode: u16, - uid: u32, - gid: u32, - ) -> syscall::Result> { - todo!() - } - - fn rmdir(&mut self, path: &str, uid: u32, gid: u32) -> syscall::Result> { - todo!() - } - - fn unlink(&mut self, path: &str, uid: u32, gid: u32) -> syscall::Result> { - todo!() - } - - fn dup(&mut self, old_id: usize, buf: &[u8]) -> syscall::Result> { - todo!() - } - fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List { @@ -323,7 +341,7 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { Handle::Disk { ref mut offset } => { let block_size = self.cfg.block_size(); - let count = self.queue.read((*offset as u64) / 512, buf); + let count = self.queue.read((*offset as u64) / block_size as u64, buf); *offset += count; Ok(Some(count)) } @@ -331,8 +349,17 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { } fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result> { - // lets assume this worked - Ok(Some(buf.len())) + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::Disk { ref mut offset } => { + let block_size = self.cfg.block_size(); + let count = self.queue.write((*offset as u64) / block_size as u64, buf); + + *offset += count; + Ok(Some(count)) + } + + _ => unimplemented!(), + } } fn seek(&mut self, id: usize, pos: isize, whence: usize) -> syscall::Result> { @@ -394,91 +421,15 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { } } - fn fchmod(&mut self, id: usize, mode: u16) -> syscall::Result> { + fn fpath(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result> { todo!() } - fn fchown(&mut self, id: usize, uid: u32, gid: u32) -> syscall::Result> { + fn fstat(&mut self, _id: usize, _stat: &mut syscall::Stat) -> syscall::Result> { todo!() } - fn fcntl(&mut self, id: usize, cmd: usize, arg: usize) -> syscall::Result> { - todo!() - } - - fn fevent( - &mut self, - id: usize, - flags: syscall::EventFlags, - ) -> syscall::Result> { - todo!() - } - - fn fmap_old(&mut self, id: usize, map: &syscall::OldMap) -> syscall::Result> { - todo!() - } - - fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result> { - if map.flags.contains(syscall::MapFlags::MAP_FIXED) { - return Err(syscall::Error::new(syscall::EINVAL)); - } - self.fmap_old( - id, - &syscall::OldMap { - offset: map.offset, - size: map.size, - flags: map.flags, - }, - ) - } - - fn funmap_old(&mut self, address: usize) -> syscall::Result> { - todo!() - } - - fn funmap(&mut self, address: usize, length: usize) -> syscall::Result> { - todo!() - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result> { - todo!() - } - - fn frename( - &mut self, - id: usize, - path: &str, - uid: u32, - gid: u32, - ) -> syscall::Result> { - todo!() - } - - fn fstat(&mut self, id: usize, stat: &mut syscall::Stat) -> syscall::Result> { - todo!() - } - - fn fstatvfs( - &mut self, - id: usize, - stat: &mut syscall::StatVfs, - ) -> syscall::Result> { - todo!() - } - - fn fsync(&mut self, id: usize) -> syscall::Result> { - todo!() - } - - fn ftruncate(&mut self, id: usize, len: usize) -> syscall::Result> { - todo!() - } - - fn futimens( - &mut self, - id: usize, - times: &[syscall::TimeSpec], - ) -> syscall::Result> { + fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> Result> { todo!() } diff --git a/virtiod/src/transport.rs b/virtiod/src/transport.rs index 708389cf0c..21302b9d53 100644 --- a/virtiod/src/transport.rs +++ b/virtiod/src/transport.rs @@ -136,10 +136,23 @@ impl<'a> Queue<'a> { } fn alloc_descriptor(&self) -> usize { - if let Some(index) = self.inner.lock().unwrap().descriptor_stack.pop_front() { + let mut inner = self.inner.lock().unwrap(); + + if let Some(index) = inner.descriptor_stack.pop_front() { index as usize } else { - panic!("virtio: descriptor exhaustion"); + log::warn!("virtiod: descriptors exhausted, waiting on garabage collector"); + drop(inner); + + // Wait for the garbage collector thread to release some descriptors. + // + // TODO(andypython): Instead of just yielding, we should have a proper notificiation + // mechanism. I am not aware whats the standard way redox applications + // or drivers implement basically a WaitQueue which you can use to wake + // up a thread. The descripts really should NEVER run out, but if they + // do, have a proper way to handle them. + std::thread::yield_now(); + self.alloc_descriptor() } } } From ea1c855cdcde3b44ff9f2bfefde5726f64a3b658 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 26 Jun 2023 09:37:57 +1000 Subject: [PATCH 0630/1301] virtiod: make use of the `int_roundings` feature * Removes the need to define `round_up` and `div_round_up` Signed-off-by: Anhad Singh --- virtiod/src/lib.rs | 2 ++ virtiod/src/main.rs | 15 ++------------- virtiod/src/transport.rs | 6 +++--- virtiod/src/utils.rs | 7 ------- 4 files changed, 7 insertions(+), 23 deletions(-) diff --git a/virtiod/src/lib.rs b/virtiod/src/lib.rs index 64fff84bb7..04f8e74492 100644 --- a/virtiod/src/lib.rs +++ b/virtiod/src/lib.rs @@ -1,5 +1,7 @@ //! https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html +#![feature(int_roundings)] + use static_assertions::const_assert_eq; pub mod transport; diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index c965301fc1..11e1c38543 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -1,11 +1,11 @@ #![deny(trivial_numeric_casts, unused_allocation)] +#![feature(int_roundings)] use core::ptr::NonNull; use std::fs::File; use std::io; use std::io::{Read, Write}; -use std::ops::{Add, Div, Rem}; use std::os::fd::{AsRawFd, FromRawFd, RawFd}; use static_assertions::const_assert_eq; @@ -26,17 +26,6 @@ use virtiod::utils::VolatileCell; mod scheme; -fn div_round_up(a: T, b: T) -> T -where - T: Add + Div + Rem + PartialEq + From + Copy, -{ - if a % b != T::from(0u8) { - a / b + T::from(1u8) - } else { - a / b - } -} - pub fn main() -> anyhow::Result<()> { #[cfg(target_os = "redox")] setup_logging(); @@ -118,7 +107,7 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> anyhow::Result { let table_size = capability.table_size(); let table_base = capability.table_base_pointer(pci_config.func.bars); let table_min_length = table_size * 16; - let pba_min_length = div_round_up(table_size, 8); + let pba_min_length = table_size.div_ceil(8); let pba_base = capability.pba_base_pointer(pci_config.func.bars); diff --git a/virtiod/src/transport.rs b/virtiod/src/transport.rs index 21302b9d53..4ee9753f26 100644 --- a/virtiod/src/transport.rs +++ b/virtiod/src/transport.rs @@ -1,4 +1,4 @@ -use crate::utils::{align, round_up}; +use crate::utils::align; use crate::*; use pcid_interface::PciHeader; @@ -169,8 +169,8 @@ pub struct Available<'a> { impl<'a> Available<'a> { pub fn new(queue_size: usize) -> anyhow::Result { let (_, size, _) = queue_part_sizes(queue_size); + let size = size.next_multiple_of(syscall::PAGE_SIZE); // align to page size - let size = round_up(size); let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; let virt = unsafe { syscall::physmap(addr, size, PHYSMAP_WRITE) }.map_err(Error::SyscallError)?; @@ -231,8 +231,8 @@ pub struct Used<'a> { impl<'a> Used<'a> { pub fn new(queue_size: usize) -> anyhow::Result { let (_, _, size) = queue_part_sizes(queue_size); + let size = size.next_multiple_of(syscall::PAGE_SIZE); // align to page size - let size = round_up(size); let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; let virt = unsafe { syscall::physmap(addr, size, PHYSMAP_WRITE) }.map_err(Error::SyscallError)?; diff --git a/virtiod/src/utils.rs b/virtiod/src/utils.rs index 99efef87d6..be9ccbe876 100644 --- a/virtiod/src/utils.rs +++ b/virtiod/src/utils.rs @@ -63,10 +63,3 @@ impl IncompleteArrayField { pub const fn align(val: usize, align: usize) -> usize { (val + align) & !align } - -// From the syscall crate; the function is private. -// -// TODO(andypython): make it public -pub const fn round_up(x: usize) -> usize { - (x + syscall::PAGE_SIZE - 1) / syscall::PAGE_SIZE * syscall::PAGE_SIZE -} From eee780fa0fe692fdaa6f651bc15eb4e25148caad Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 27 Jun 2023 09:51:16 +1000 Subject: [PATCH 0631/1301] virtiod: split into virtio-core and virtiod Signed-off-by: Anhad Singh --- Cargo.lock | 14 +- virtio-core/Cargo.toml | 14 + virtio-core/src/lib.rs | 9 + virtio-core/src/probe.rs | 271 ++++++++++++++++ virtiod/src/lib.rs => virtio-core/src/spec.rs | 28 +- {virtiod => virtio-core}/src/transport.rs | 42 ++- {virtiod => virtio-core}/src/utils.rs | 0 virtiod/Cargo.toml | 4 +- virtiod/VIRTIO.md | 20 -- virtiod/src/main.rs | 299 ++---------------- virtiod/src/scheme.rs | 12 +- 11 files changed, 378 insertions(+), 335 deletions(-) create mode 100644 virtio-core/Cargo.toml create mode 100644 virtio-core/src/lib.rs create mode 100644 virtio-core/src/probe.rs rename virtiod/src/lib.rs => virtio-core/src/spec.rs (93%) rename {virtiod => virtio-core}/src/transport.rs (92%) rename {virtiod => virtio-core}/src/utils.rs (100%) delete mode 100644 virtiod/VIRTIO.md diff --git a/Cargo.lock b/Cargo.lock index b16ea5ef70..252bb500b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1904,12 +1904,23 @@ dependencies = [ "rusttype", ] +[[package]] +name = "virtio-core" +version = "0.1.0" +dependencies = [ + "bitflags 2.3.2", + "log", + "pcid", + "redox_syscall 0.3.5", + "static_assertions", + "thiserror", +] + [[package]] name = "virtiod" version = "0.1.0" dependencies = [ "anyhow", - "bitflags 2.3.2", "block-io-wrapper", "log", "partitionlib", @@ -1920,6 +1931,7 @@ dependencies = [ "redox_syscall 0.3.5", "static_assertions", "thiserror", + "virtio-core", ] [[package]] diff --git a/virtio-core/Cargo.toml b/virtio-core/Cargo.toml new file mode 100644 index 0000000000..1ffd4a4bb7 --- /dev/null +++ b/virtio-core/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "virtio-core" +version = "0.1.0" +edition = "2021" +authors = ["Anhad Singh "] + +[dependencies] +static_assertions = "1.1.0" +bitflags = "2.3.2" +redox_syscall = "0.3" +log = "0.4" +thiserror = "1.0.40" + +pcid = { path = "../pcid" } diff --git a/virtio-core/src/lib.rs b/virtio-core/src/lib.rs new file mode 100644 index 0000000000..626c2ecf21 --- /dev/null +++ b/virtio-core/src/lib.rs @@ -0,0 +1,9 @@ +#![feature(int_roundings)] + +pub mod spec; +pub mod transport; +pub mod utils; + +mod probe; + +pub use probe::{probe_device, MSIX_PRIMARY_VECTOR, Device}; diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs new file mode 100644 index 0000000000..2f91eabb71 --- /dev/null +++ b/virtio-core/src/probe.rs @@ -0,0 +1,271 @@ +use std::fs::File; +use std::ptr::NonNull; +use std::sync::Arc; + +use pcid_interface::irq_helpers::{allocate_single_interrupt_vector, read_bsp_apic_id}; +use pcid_interface::msi::x86_64 as x86_64_msix; +use pcid_interface::msi::x86_64::DeliveryMode; +use pcid_interface::msi::{MsixCapability, MsixTableEntry}; +use pcid_interface::*; + +use syscall::{Io, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; + +use crate::spec::*; +use crate::transport::{Error, StandardTransport}; +use crate::utils::VolatileCell; + +pub struct Device<'a> { + pub transport: Arc>, + pub device_space: *const u8, + pub irq_handle: File, + pub isr: &'a VolatileCell, +} + +struct MsixInfo { + pub virt_table_base: NonNull, + pub virt_pba_base: NonNull, + pub capability: MsixCapability, +} + +impl MsixInfo { + pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { + &mut *self.virt_table_base.as_ptr().add(k) + } + + pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { + assert!(k < self.capability.table_size() as usize); + unsafe { self.table_entry_pointer_unchecked(k) } + } +} + +static_assertions::const_assert_eq!(std::mem::size_of::(), 16); + +pub const MSIX_PRIMARY_VECTOR: u16 = 0; + +fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { + let pci_config = pcid_handle.fetch_config()?; + + // Extended message signaled interrupts. + let capability = match pcid_handle.feature_info(PciFeature::MsiX)? { + PciFeatureInfo::MsiX(capability) => capability, + _ => unreachable!(), + }; + + let table_size = capability.table_size(); + let table_base = capability.table_base_pointer(pci_config.func.bars); + let table_min_length = table_size * 16; + let pba_min_length = table_size.div_ceil(8); + + let pba_base = capability.pba_base_pointer(pci_config.func.bars); + + let bir = capability.table_bir() as usize; + let bar = pci_config.func.bars[bir]; + let bar_size = pci_config.func.bar_sizes[bir] as u64; + + let bar_ptr = match bar { + PciBar::Memory32(ptr) => ptr.into(), + PciBar::Memory64(ptr) => ptr, + _ => unreachable!(), + }; + + let address = unsafe { + syscall::physmap( + bar_ptr as usize, + bar_size as usize, + PHYSMAP_WRITE | PHYSMAP_NO_CACHE, + )? + }; + + // Ensure that the table and PBA are be within the BAR. + { + let bar_range = bar_ptr..bar_ptr + bar_size; + assert!(bar_range.contains(&(table_base as u64 + table_min_length as u64))); + assert!(bar_range.contains(&(pba_base as u64 + pba_min_length as u64))); + } + + let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; + let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; + + let mut info = MsixInfo { + virt_table_base: NonNull::new(virt_table_base).unwrap(), + virt_pba_base: NonNull::new(virt_pba_base).unwrap(), + capability, + }; + + // Allocate the primary MSI vector. + let interrupt_handle = { + let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize); + + let destination_id = read_bsp_apic_id().expect("virtio_core: `read_bsp_apic_id()` failed"); + let lapic_id = u8::try_from(destination_id).unwrap(); + + let rh = false; + let dm = false; + let addr = x86_64_msix::message_address(lapic_id, rh, dm); + + let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id) + .unwrap() + .expect("virtio_core: interrupt vector exhaustion"); + + let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + + table_entry_pointer.addr_lo.write(addr); + table_entry_pointer.addr_hi.write(0); + table_entry_pointer.msg_data.write(msg_data); + table_entry_pointer + .vec_ctl + .writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + + interrupt_handle + }; + + pcid_handle.enable_feature(PciFeature::MsiX)?; + + log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})"); + Ok(interrupt_handle) +} + +/// VirtIO Device Probe +/// +/// ## Device State +/// After this function, the device has been successfully reseted and is ready for use. +/// +/// The caller is required to do the following: +/// * Negotiate the device and driver supported features (finialize via [`StandardTransport::finalize_features`]) +/// * Create the device specific virtio queues (via [`StandardTransport::setup_queue`]) +/// * Finally start the device (via [`StandardTransport::run_device`]). At this point, the device +/// is alive. +/// +/// ## Panics +/// This function panics if the device is not a virtio device. +pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result, Error> { + let pci_config = pcid_handle.fetch_config()?; + let pci_header = pcid_handle.fetch_header()?; + + assert_eq!( + pci_config.func.venid, 6900, + "virtio_core::probe_device: not a virtio device" + ); + + let mut common_addr = None; + let mut notify_addr = None; + let mut isr_addr = None; + let mut device_addr = None; + + for capability in pcid_handle + .get_capabilities()? + .iter() + .filter_map(|capability| { + if let Capability::Vendor(vendor) = capability { + Some(vendor) + } else { + None + } + }) + { + // SAFETY: We have verified that the length of the data is correct. + let capability = unsafe { &*(capability.data.as_ptr() as *const PciCapability) }; + + match capability.cfg_type { + CfgType::Common | CfgType::Notify | CfgType::Isr | CfgType::Device => {} + _ => continue, + } + + let bar = pci_header.get_bar(capability.bar as usize); + let addr = match bar { + PciBar::Memory32(addr) => addr as usize, + PciBar::Memory64(addr) => addr as usize, + + _ => unreachable!("virtio: unsupported bar type: {bar:?}"), + }; + + let address = unsafe { + syscall::physmap( + addr + capability.offset as usize, + capability.length as usize, + PHYSMAP_WRITE | PHYSMAP_NO_CACHE, + )? + }; + + match capability.cfg_type { + CfgType::Common => { + debug_assert!(common_addr.is_none()); + common_addr = Some(address); + } + + CfgType::Notify => { + debug_assert!(notify_addr.is_none()); + + // SAFETY: The capability type is `Notify`, so its safe to access + // the `notify_multiplier` field. + let multiplier = unsafe { capability.notify_multiplier() }; + notify_addr = Some((address, multiplier)); + } + + CfgType::Isr => { + debug_assert!(isr_addr.is_none()); + isr_addr = Some(address); + } + + CfgType::Device => { + debug_assert!(device_addr.is_none()); + device_addr = Some(address); + } + + _ => unreachable!(), + } + + log::info!("virtio: {capability:?}"); + } + + let common_addr = common_addr.ok_or(Error::InCapable(CfgType::Common))?; + let (notify_addr, notify_multiplier) = notify_addr.ok_or(Error::InCapable(CfgType::Notify))?; + let isr_addr = isr_addr.ok_or(Error::InCapable(CfgType::Isr))?; + let device_addr = device_addr.ok_or(Error::InCapable(CfgType::Device))?; + + assert!( + notify_multiplier != 0, + "virtio-core::device_probe: device uses the same Queue Notify addresses for all queues" + ); + + let common = unsafe { &mut *(common_addr as *mut CommonCfg) }; + let device_space = unsafe { &mut *(device_addr as *mut u8) }; + let isr = unsafe { &*(isr_addr as *mut VolatileCell) }; + + // Reset the device. + common.device_status.set(DeviceStatusFlags::empty()); + // Upon reset, the device must initialize device status to 0. + assert_eq!(common.device_status.get(), DeviceStatusFlags::empty()); + log::info!("virtio: successfully reseted the device"); + + // XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits + // in `device_status` is required to be done in two steps. + common + .device_status + .set(common.device_status.get() | DeviceStatusFlags::ACKNOWLEDGE); + + common + .device_status + .set(common.device_status.get() | DeviceStatusFlags::DRIVER); + + // Setup interrupts. + let all_pci_features = pcid_handle.fetch_all_features()?; + let has_msix = all_pci_features + .iter() + .any(|(feature, _)| feature.is_msix()); + + // According to the virtio specification, the device REQUIRED to support MSI-X. + assert!(has_msix, "virtio: device does not support MSI-X"); + let irq_handle = enable_msix(pcid_handle)?; + + log::info!("virtio: using standard PCI transport"); + + let transport = StandardTransport::new(common, notify_addr as *const u8, notify_multiplier); + + Ok(Device { + transport, + device_space, + irq_handle, + isr, + }) +} diff --git a/virtiod/src/lib.rs b/virtio-core/src/spec.rs similarity index 93% rename from virtiod/src/lib.rs rename to virtio-core/src/spec.rs index 04f8e74492..f494714f14 100644 --- a/virtiod/src/lib.rs +++ b/virtio-core/src/spec.rs @@ -1,28 +1,8 @@ //! https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html -#![feature(int_roundings)] - +use crate::utils::{IncompleteArrayField, VolatileCell}; use static_assertions::const_assert_eq; -pub mod transport; -pub mod utils; - -use utils::{IncompleteArrayField, VolatileCell}; - -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum Error { - #[error("capability {0:?} not found")] - InCapable(CfgType), - #[error("failed to map memory")] - Physmap, - #[error("failed to allocate an interrupt vector")] - ExhaustedInt, - #[error("syscall error")] - SyscallError(syscall::Error), -} - #[derive(Debug, Copy, Clone)] #[repr(u8)] pub enum CfgType { @@ -225,9 +205,9 @@ pub struct UsedRingExtra { // ======== Utils ======== pub struct Buffer { - buffer: usize, - size: usize, - flags: DescriptorFlags, + pub(crate) buffer: usize, + pub(crate) size: usize, + pub(crate) flags: DescriptorFlags, } impl Buffer { diff --git a/virtiod/src/transport.rs b/virtio-core/src/transport.rs similarity index 92% rename from virtiod/src/transport.rs rename to virtio-core/src/transport.rs index 4ee9753f26..529de32ab1 100644 --- a/virtiod/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -1,7 +1,6 @@ -use crate::utils::align; -use crate::*; +use crate::spec::*; +use crate::utils::{align, VolatileCell}; -use pcid_interface::PciHeader; use syscall::{Dma, PHYSMAP_WRITE}; use core::mem::size_of; @@ -10,6 +9,28 @@ use core::sync::atomic::{fence, AtomicU16, Ordering}; use std::collections::VecDeque; use std::sync::{Arc, Mutex, Weak}; +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("syscall failed")] + SyscallError(syscall::Error), + #[error("pcid client handle error")] + PcidClientHandle(pcid_interface::PcidClientHandleError), + #[error("the device is incapable of {0:?}")] + InCapable(CfgType), +} + +impl From for Error { + fn from(value: pcid_interface::PcidClientHandleError) -> Self { + Self::PcidClientHandle(value) + } +} + +impl From for Error { + fn from(value: syscall::Error) -> Self { + Self::SyscallError(value) + } +} + /// Returns the queue part sizes in bytes. /// /// ## Reference @@ -167,7 +188,7 @@ pub struct Available<'a> { } impl<'a> Available<'a> { - pub fn new(queue_size: usize) -> anyhow::Result { + pub fn new(queue_size: usize) -> Result { let (_, size, _) = queue_part_sizes(queue_size); let size = size.next_multiple_of(syscall::PAGE_SIZE); // align to page size @@ -229,7 +250,7 @@ pub struct Used<'a> { } impl<'a> Used<'a> { - pub fn new(queue_size: usize) -> anyhow::Result { + pub fn new(queue_size: usize) -> Result { let (_, _, size) = queue_part_sizes(queue_size); let size = size.next_multiple_of(syscall::PAGE_SIZE); // align to page size @@ -286,7 +307,6 @@ impl Drop for Used<'_> { } pub struct StandardTransport<'a> { - header: PciHeader, common: Mutex<&'a mut CommonCfg>, notify: *const u8, notify_mul: u32, @@ -296,14 +316,8 @@ pub struct StandardTransport<'a> { } impl<'a> StandardTransport<'a> { - pub fn new( - header: PciHeader, - common: &'a mut CommonCfg, - notify: *const u8, - notify_mul: u32, - ) -> Arc { + pub fn new(common: &'a mut CommonCfg, notify: *const u8, notify_mul: u32) -> Arc { Arc::new_cyclic(|sref| Self { - header, common: Mutex::new(common), notify, notify_mul, @@ -362,7 +376,7 @@ impl<'a> StandardTransport<'a> { .set(status | DeviceStatusFlags::DRIVER_OK); } - pub fn setup_queue(&self, vector: u16) -> anyhow::Result>> { + pub fn setup_queue(&self, vector: u16) -> Result>, Error> { let mut common = self.common.lock().unwrap(); let queue_index = self.queue_index.fetch_add(1, Ordering::SeqCst); diff --git a/virtiod/src/utils.rs b/virtio-core/src/utils.rs similarity index 100% rename from virtiod/src/utils.rs rename to virtio-core/src/utils.rs diff --git a/virtiod/Cargo.toml b/virtiod/Cargo.toml index 2594590c4b..74d3adce40 100644 --- a/virtiod/Cargo.toml +++ b/virtiod/Cargo.toml @@ -5,11 +5,10 @@ edition = "2021" authors = ["Anhad Singh "] [dependencies] -static_assertions = "1.1.0" -bitflags = "2.3.2" anyhow = "1.0.71" log = "0.4" thiserror = "1.0.40" +static_assertions = "1.1.0" redox-daemon = "0.1" redox-log = "0.1" @@ -19,3 +18,4 @@ partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } block-io-wrapper = { path = "../block-io-wrapper" } pcid = { path = "../pcid" } +virtio-core = { path = "../virtio-core" } diff --git a/virtiod/VIRTIO.md b/virtiod/VIRTIO.md deleted file mode 100644 index a3c31a10a9..0000000000 --- a/virtiod/VIRTIO.md +++ /dev/null @@ -1,20 +0,0 @@ -## Generic -- [x] Reset the device. -- [x] Set the ACKNOWLEDGE status bit: the guest OS has noticed the device. -- [x] Set the DRIVER status bit: the guest OS knows how to drive the device. -- [x] Setup Interrupts - -## Driver Specific -- [x] Read device feature bits, and write the subset of feature bits understood by the OS and driver to the device. During this step the driver MAY read (but MUST NOT write) the device-specific configuration fields to check that it can support the device before accepting it. -- [x] Set the FEATURES_OK status bit. The driver MUST NOT accept new feature bits after this step. -- [x] Re-read device status to ensure the FEATURES_OK bit is still set: otherwise, the device does not support our subset of features and the device is unusable. -- [x] Perform device-specific setup, including discovery of virtqueues for the device, optional per-bus setup, reading and possibly writing the device’s virtio configuration space, and population of virtqueues. -- [x] Set the DRIVER_OK status bit. At this point the device is “live”. - -## XXX -- [ ] Mark the deamon as ready. - -## Drivers -- [ ] `virtio-blk` (in-progress) -- [ ] `virtio-net` -- [ ] `virtio-gpu` diff --git a/virtiod/src/main.rs b/virtiod/src/main.rs index 11e1c38543..731dc77b96 100644 --- a/virtiod/src/main.rs +++ b/virtiod/src/main.rs @@ -1,8 +1,6 @@ #![deny(trivial_numeric_casts, unused_allocation)] #![feature(int_roundings)] -use core::ptr::NonNull; - use std::fs::File; use std::io; use std::io::{Read, Write}; @@ -10,22 +8,30 @@ use std::os::fd::{AsRawFd, FromRawFd, RawFd}; use static_assertions::const_assert_eq; -use virtiod::transport::StandardTransport; -use virtiod::*; - -use pcid_interface::irq_helpers::{allocate_single_interrupt_vector, read_bsp_apic_id}; -use pcid_interface::msi::x86_64 as x86_64_msix; -use pcid_interface::msi::x86_64::DeliveryMode; -use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use pcid_interface::*; +use virtio_core::spec::*; use event::EventQueue; -use syscall::{Io, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{Packet, SchemeBlockMut}; -use virtiod::utils::VolatileCell; +use virtio_core::utils::VolatileCell; mod scheme; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum Error { + #[error("capability {0:?} not found")] + InCapable(CfgType), + #[error("failed to map memory")] + Physmap, + #[error("failed to allocate an interrupt vector")] + ExhaustedInt, + #[error("syscall error")] + SyscallError(syscall::Error), +} + pub fn main() -> anyhow::Result<()> { #[cfg(target_os = "redox")] setup_logging(); @@ -74,110 +80,6 @@ fn setup_logging() { log::info!("virtiod: enabled logger"); } -struct MsixInfo { - pub virt_table_base: NonNull, - pub virt_pba_base: NonNull, - pub capability: MsixCapability, -} - -impl MsixInfo { - pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { - &mut *self.virt_table_base.as_ptr().add(k) - } - - pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { - assert!(k < self.capability.table_size() as usize); - unsafe { self.table_entry_pointer_unchecked(k) } - } -} - -const_assert_eq!(std::mem::size_of::(), 16); - -const MSIX_PRIMARY_VECTOR: u16 = 0; - -fn enable_msix(pcid_handle: &mut PcidServerHandle) -> anyhow::Result { - let pci_config = pcid_handle.fetch_config()?; - - // Extended message signaled interrupts. - let capability = match pcid_handle.feature_info(PciFeature::MsiX)? { - PciFeatureInfo::MsiX(capability) => capability, - _ => unreachable!(), - }; - - let table_size = capability.table_size(); - let table_base = capability.table_base_pointer(pci_config.func.bars); - let table_min_length = table_size * 16; - let pba_min_length = table_size.div_ceil(8); - - let pba_base = capability.pba_base_pointer(pci_config.func.bars); - - let bir = capability.table_bir() as usize; - let bar = pci_config.func.bars[bir]; - let bar_size = pci_config.func.bar_sizes[bir] as u64; - - let bar_ptr = match bar { - PciBar::Memory32(ptr) => ptr.into(), - PciBar::Memory64(ptr) => ptr, - _ => unreachable!(), - }; - - let address = unsafe { - syscall::physmap( - bar_ptr as usize, - bar_size as usize, - PHYSMAP_WRITE | PHYSMAP_NO_CACHE, - ) - .map_err(|_| Error::Physmap)? - }; - - // Ensure that the table and PBA are be within the BAR. - { - let bar_range = bar_ptr..bar_ptr + bar_size; - assert!(bar_range.contains(&(table_base as u64 + table_min_length as u64))); - assert!(bar_range.contains(&(pba_base as u64 + pba_min_length as u64))); - } - - let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; - let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; - - let mut info = MsixInfo { - virt_table_base: NonNull::new(virt_table_base).unwrap(), - virt_pba_base: NonNull::new(virt_pba_base).unwrap(), - capability, - }; - - // Allocate the primary MSI vector. - let interrupt_handle = { - let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize); - - let destination_id = read_bsp_apic_id()?; - let lapic_id = u8::try_from(destination_id).unwrap(); - - let rh = false; - let dm = false; - let addr = x86_64_msix::message_address(lapic_id, rh, dm); - - let (vector, interrupt_handle) = - allocate_single_interrupt_vector(destination_id)?.ok_or(Error::ExhaustedInt)?; - - let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); - - table_entry_pointer.addr_lo.write(addr); - table_entry_pointer.addr_hi.write(0); - table_entry_pointer.msg_data.write(msg_data); - table_entry_pointer - .vec_ctl - .writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); - - interrupt_handle - }; - - pcid_handle.enable_feature(PciFeature::MsiX)?; - - log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})"); - Ok(interrupt_handle) -} - #[repr(C)] pub struct BlockGeometry { pub cylinders: VolatileCell, @@ -224,148 +126,35 @@ const_assert_eq!(core::mem::size_of::(), 16); fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut pcid_handle = PcidServerHandle::connect_default()?; - let pci_config = pcid_handle.fetch_config()?; - let pci_header = pcid_handle.fetch_header()?; + // Double check that we have the right device. + // // 0x1001 - virtio-blk + let pci_config = pcid_handle.fetch_config()?; + assert_eq!(pci_config.func.devid, 0x1001); log::info!("virtiod: found `virtio-blk` device"); - let mut common_addr = None; - let mut notify_addr = None; - let mut isr_addr = None; - let mut device_addr = None; + let mut device = virtio_core::probe_device(&mut pcid_handle)?; + device.transport.finalize_features(); - for capability in pcid_handle - .get_capabilities()? - .iter() - .filter_map(|capability| { - if let Capability::Vendor(vendor) = capability { - Some(vendor) - } else { - None - } - }) - { - // SAFETY: We have verified that the length of the data is correct. - let capability = unsafe { &*(capability.data.as_ptr() as *const PciCapability) }; - - match capability.cfg_type { - CfgType::Common | CfgType::Notify | CfgType::Isr | CfgType::Device => {} - _ => continue, - } - - let bar = pci_header.get_bar(capability.bar as usize); - let addr = match bar { - PciBar::Memory32(addr) => addr as usize, - PciBar::Memory64(addr) => addr as usize, - - _ => unreachable!("virtio: unsupported bar type: {bar:?}"), - }; - - let address = unsafe { - syscall::physmap( - addr + capability.offset as usize, - capability.length as usize, - PHYSMAP_WRITE | PHYSMAP_NO_CACHE, - ) - .map_err(|_| Error::Physmap)? - }; - - match capability.cfg_type { - CfgType::Common => { - debug_assert!(common_addr.is_none()); - common_addr = Some(address); - } - - CfgType::Notify => { - debug_assert!(notify_addr.is_none()); - - // SAFETY: The capability type is `Notify`, so its safe to access - // the `notify_multiplier` field. - let multiplier = unsafe { capability.notify_multiplier() }; - notify_addr = Some((address, multiplier)); - } - - CfgType::Isr => { - debug_assert!(isr_addr.is_none()); - isr_addr = Some(address); - } - - CfgType::Device => { - debug_assert!(device_addr.is_none()); - device_addr = Some(address); - } - - _ => unreachable!(), - } - - log::info!("virtio: {capability:?}"); - } - - let common_addr = common_addr.ok_or(Error::InCapable(CfgType::Common))?; - let (notify_addr, notify_multiplier) = notify_addr.ok_or(Error::InCapable(CfgType::Notify))?; - let isr_addr = isr_addr.ok_or(Error::InCapable(CfgType::Isr))?; - let device_addr = device_addr.ok_or(Error::InCapable(CfgType::Device))?; - - assert!( - notify_multiplier != 0, - "virtio: device uses the same Queue Notify addresses for all queues" - ); - - let common = unsafe { &mut *(common_addr as *mut CommonCfg) }; - let device_space = unsafe { &mut *(device_addr as *mut BlockDeviceConfig) }; - let isr = unsafe { &*(isr_addr as *mut VolatileCell) }; - - // Reset the device. - common.device_status.set(DeviceStatusFlags::empty()); - // Upon reset, the device must initialize device status to 0. - assert_eq!(common.device_status.get(), DeviceStatusFlags::empty()); - log::info!("virtio: successfully reseted the device"); - - // XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits - // in `device_status` is required to be done in two steps. - common - .device_status - .set(common.device_status.get() | DeviceStatusFlags::ACKNOWLEDGE); - - common - .device_status - .set(common.device_status.get() | DeviceStatusFlags::DRIVER); - - // Setup interrupts. - let all_pci_features = pcid_handle.fetch_all_features()?; - let has_msix = all_pci_features - .iter() - .any(|(feature, _)| feature.is_msix()); - - // According to the virtio specification, the device REQUIRED to support MSI-X. - assert!(has_msix, "virtio: device does not support MSI-X"); - let mut irq_handle = enable_msix(&mut pcid_handle)?; - - log::info!("virtio: using standard PCI transport"); - - let transport = StandardTransport::new( - pci_header, - common, - notify_addr as *const u8, - notify_multiplier, - ); - transport.finalize_features(); - - let queue = transport.setup_queue(MSIX_PRIMARY_VECTOR)?; + let queue = device + .transport + .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR)?; let queue_copy = queue.clone(); + let device_space = unsafe { &mut *(device.device_space as *mut BlockDeviceConfig) }; + std::thread::spawn(move || { let mut event_queue = EventQueue::::new().unwrap(); let mut progress_head = 0; event_queue .add( - irq_handle.as_raw_fd(), + device.irq_handle.as_raw_fd(), move |_| -> Result, io::Error> { // Read from ISR to acknowledge the interrupt. - let _isr = isr.get() as usize; + let _isr = device.isr.get() as usize; let mut inner = queue_copy.inner.lock().unwrap(); let used_head = inner.used.head_index(); @@ -394,7 +183,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { drop(inner); let mut buf = [0u8; 8]; - irq_handle.read(&mut buf)?; + device.irq_handle.read(&mut buf)?; // Acknowledge the interrupt. // irq_handle.write(&buf)?; Ok(None) @@ -408,7 +197,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { }); // At this point the device is alive! - transport.run_device(); + device.transport.run_device(); log::info!( "virtio-blk: disk size: {} sectors and block size of {} bytes", @@ -444,30 +233,6 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { .write(&mut packet) .expect("ahcid: failed to read disk scheme"); } - - // for _ in 0..3 { - // let req = syscall::Dma::new(BlockVirtRequest { - // ty: BlockRequestTy::In, - // reserved: 0, - // sector: 0, - // }) - // .unwrap(); - - // let result = syscall::Dma::new([0u8; 512]).unwrap(); - // let status = syscall::Dma::new(u8::MAX).unwrap(); - - // let chain = ChainBuilder::new() - // .chain(Buffer::new(&req).flags(DescriptorFlags::NEXT)) - // .chain(Buffer::new(&result).flags(DescriptorFlags::WRITE_ONLY | DescriptorFlags::NEXT)) - // .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) - // .build(); - - // queue.send(chain); - - // log::info!("{}", event_queue.run()?); - // log::info!("command status: {}", *status); - // log::info!("data: {:?}", result.as_ref()); - // } } fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { diff --git a/virtiod/src/scheme.rs b/virtiod/src/scheme.rs index ad8b410766..a6247e2c6b 100644 --- a/virtiod/src/scheme.rs +++ b/virtiod/src/scheme.rs @@ -10,10 +10,9 @@ use std::sync::Arc; use partitionlib::LogicalBlockSize; use partitionlib::PartitionTable; use syscall::*; -use virtiod::transport::Queue; -use virtiod::Buffer; -use virtiod::ChainBuilder; -use virtiod::DescriptorFlags; + +use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; +use virtio_core::transport::Queue; use crate::BlockDeviceConfig; use crate::BlockRequestTy; @@ -28,6 +27,8 @@ trait BlkExtension { /// XXX: Reads only one block despite the size of the output buffer. Use [`BlkExtension::write`] instead. fn write_block(&self, block: u64, block_bytes: &[u8]) -> usize; + // FIXME(andypython): The following two methods can be done asynchronously (i.e, send all of the commands at once + // and wait for the result in the end). fn read(&self, block: u64, block_bytes: &mut [u8]) -> usize { let sectors = block_bytes.len() / BLK_SIZE as usize; @@ -72,8 +73,6 @@ impl BlkExtension for Queue<'_> { let size = core::cmp::min(block_bytes.len(), result.len()); block_bytes[..size].copy_from_slice(&result.as_slice()[..size]); - std::thread::yield_now(); - size } @@ -103,7 +102,6 @@ impl BlkExtension for Queue<'_> { core::hint::spin_loop(); } - std::thread::yield_now(); block_bytes.len() } } From 6968a548d95258237ac51c42303a1d258a59a6ac Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 27 Jun 2023 10:26:04 +1000 Subject: [PATCH 0632/1301] virtiod: rename to `virtio-blkd` * Rename to `virtio-blkd` * Start working on `virtio-netd` Signed-off-by: Anhad Singh --- Cargo.lock | 37 +++++++++------ Cargo.toml | 4 +- initfs.toml | 17 +++++-- {virtiod => virtio-blkd}/Cargo.toml | 2 +- {virtiod => virtio-blkd}/src/main.rs | 46 +------------------ {virtiod => virtio-blkd}/src/scheme.rs | 0 virtio-core/Cargo.toml | 2 + virtio-core/src/lib.rs | 2 +- virtio-core/src/probe.rs | 7 +-- virtio-core/src/spec.rs | 1 + virtio-core/src/transport.rs | 27 +++++++---- virtio-core/src/utils.rs | 36 +++++++++++++++ virtio-netd/Cargo.toml | 12 +++++ virtio-netd/src/main.rs | 63 ++++++++++++++++++++++++++ 14 files changed, 179 insertions(+), 77 deletions(-) rename {virtiod => virtio-blkd}/Cargo.toml (96%) rename {virtiod => virtio-blkd}/src/main.rs (80%) rename {virtiod => virtio-blkd}/src/scheme.rs (100%) create mode 100644 virtio-netd/Cargo.toml create mode 100644 virtio-netd/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 252bb500b9..be9d66cebc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1905,19 +1905,7 @@ dependencies = [ ] [[package]] -name = "virtio-core" -version = "0.1.0" -dependencies = [ - "bitflags 2.3.2", - "log", - "pcid", - "redox_syscall 0.3.5", - "static_assertions", - "thiserror", -] - -[[package]] -name = "virtiod" +name = "virtio-blkd" version = "0.1.0" dependencies = [ "anyhow", @@ -1934,6 +1922,29 @@ dependencies = [ "virtio-core", ] +[[package]] +name = "virtio-core" +version = "0.1.0" +dependencies = [ + "bitflags 2.3.2", + "log", + "pcid", + "redox-log", + "redox_syscall 0.3.5", + "static_assertions", + "thiserror", +] + +[[package]] +name = "virtio-netd" +version = "0.1.0" +dependencies = [ + "log", + "pcid", + "redox-daemon", + "virtio-core", +] + [[package]] name = "vte" version = "0.3.3" diff --git a/Cargo.toml b/Cargo.toml index f1fe9a570b..717d492594 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,9 @@ members = [ "usbhidd", "usbscsid", - "virtiod", + "virtio-blkd", + "virtio-netd", + "virtio-core", ] [profile.release] diff --git a/initfs.toml b/initfs.toml index d8d3a62644..067001a19d 100644 --- a/initfs.toml +++ b/initfs.toml @@ -23,12 +23,21 @@ subclass = 8 command = ["nvmed"] use_channel = true -# virtiod +# -------------- virtio -------------- # [[drivers]] -name = "VirtIO block storage" +name = "virtio-blk" class = 1 subclass = 0 -# VirtIO PCI vendor identifier. vendor = 6900 -command = ["virtiod"] +device = 4097 +command = ["virtio-blkd"] +use_channel = true + +[[drivers]] +name = "virtio-net" +class = 2 +subclass = 0 +vendor = 6900 +device = 4096 +command = ["virtio-netd"] use_channel = true diff --git a/virtiod/Cargo.toml b/virtio-blkd/Cargo.toml similarity index 96% rename from virtiod/Cargo.toml rename to virtio-blkd/Cargo.toml index 74d3adce40..0d9e12e5d0 100644 --- a/virtiod/Cargo.toml +++ b/virtio-blkd/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "virtiod" +name = "virtio-blkd" version = "0.1.0" edition = "2021" authors = ["Anhad Singh "] diff --git a/virtiod/src/main.rs b/virtio-blkd/src/main.rs similarity index 80% rename from virtiod/src/main.rs rename to virtio-blkd/src/main.rs index 731dc77b96..7e21dd0ab0 100644 --- a/virtiod/src/main.rs +++ b/virtio-blkd/src/main.rs @@ -34,52 +34,10 @@ pub enum Error { pub fn main() -> anyhow::Result<()> { #[cfg(target_os = "redox")] - setup_logging(); - + virtio_core::utils::setup_logging(log::LevelFilter::Trace, "virtio-blkd"); redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } -#[cfg(target_os = "redox")] -fn setup_logging() { - use redox_log::{OutputBuilder, RedoxLogger}; - - let mut logger = RedoxLogger::new().with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Trace) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ); - - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "virtiod.log") { - Ok(builder) => { - logger = logger.with_output( - builder - .with_filter(log::LevelFilter::Trace) - .flush_on_newline(true) - .build(), - ) - } - Err(err) => eprintln!("virtiod: failed to create log: {}", err), - } - - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", "virtiod.ansi.log") { - Ok(builder) => { - logger = logger.with_output( - builder - .with_filter(log::LevelFilter::Trace) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ) - } - Err(err) => eprintln!("virtiod: failed to create ansi log: {}", err), - } - - logger.enable().unwrap(); - log::info!("virtiod: enabled logger"); -} - #[repr(C)] pub struct BlockGeometry { pub cylinders: VolatileCell, @@ -133,7 +91,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let pci_config = pcid_handle.fetch_config()?; assert_eq!(pci_config.func.devid, 0x1001); - log::info!("virtiod: found `virtio-blk` device"); + log::info!("virtio-blk: initiating startup sequence :^)"); let mut device = virtio_core::probe_device(&mut pcid_handle)?; device.transport.finalize_features(); diff --git a/virtiod/src/scheme.rs b/virtio-blkd/src/scheme.rs similarity index 100% rename from virtiod/src/scheme.rs rename to virtio-blkd/src/scheme.rs diff --git a/virtio-core/Cargo.toml b/virtio-core/Cargo.toml index 1ffd4a4bb7..87467d6bfb 100644 --- a/virtio-core/Cargo.toml +++ b/virtio-core/Cargo.toml @@ -11,4 +11,6 @@ redox_syscall = "0.3" log = "0.4" thiserror = "1.0.40" +redox-log = "0.1" + pcid = { path = "../pcid" } diff --git a/virtio-core/src/lib.rs b/virtio-core/src/lib.rs index 626c2ecf21..5d1d6d0436 100644 --- a/virtio-core/src/lib.rs +++ b/virtio-core/src/lib.rs @@ -6,4 +6,4 @@ pub mod utils; mod probe; -pub use probe::{probe_device, MSIX_PRIMARY_VECTOR, Device}; +pub use probe::{probe_device, Device, MSIX_PRIMARY_VECTOR}; diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 2f91eabb71..34fbc00bed 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -128,11 +128,12 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { /// VirtIO Device Probe /// /// ## Device State -/// After this function, the device has been successfully reseted and is ready for use. +/// After this function, the device will have been successfully reseted and is ready for use. /// /// The caller is required to do the following: /// * Negotiate the device and driver supported features (finialize via [`StandardTransport::finalize_features`]) -/// * Create the device specific virtio queues (via [`StandardTransport::setup_queue`]) +/// * Create the device specific virtio queues (via [`StandardTransport::setup_queue`]). This is *required* to be done +/// before starting the device. /// * Finally start the device (via [`StandardTransport::run_device`]). At this point, the device /// is alive. /// @@ -215,7 +216,7 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result _ => unreachable!(), } - log::info!("virtio: {capability:?}"); + log::trace!("virtio-core::device-probe: {capability:?}"); } let common_addr = common_addr.ok_or(Error::InCapable(CfgType::Common))?; diff --git a/virtio-core/src/spec.rs b/virtio-core/src/spec.rs index f494714f14..6c525c466e 100644 --- a/virtio-core/src/spec.rs +++ b/virtio-core/src/spec.rs @@ -131,6 +131,7 @@ const_assert_eq!(core::mem::size_of::(), 16); /// See `6.1 Driver Requirements: Reserved Feature Bits` section of the VirtIO /// specification for more information. pub const VIRTIO_F_VERSION_1: u32 = 32; +pub const VIRTIO_NET_F_MAC: u32 = 5; // ======== Available Ring ======== // diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 529de32ab1..d4bcfdfd64 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -81,6 +81,7 @@ unsafe impl Send for QueueInner<'_> {} pub struct Queue<'a> { pub inner: Mutex>, + pub queue_index: u16, sref: Weak, } @@ -91,6 +92,7 @@ impl<'a> Queue<'a> { used: Used<'a>, notification_bell: &'a mut VolatileCell, + queue_index: u16, ) -> Arc { Arc::new_cyclic(|sref| Self { inner: Mutex::new(QueueInner { @@ -104,6 +106,7 @@ impl<'a> Queue<'a> { notification_bell, }), + queue_index, sref: sref.clone(), }) } @@ -153,7 +156,7 @@ impl<'a> Queue<'a> { inner.head_index += 1; assert_eq!(inner.used.flags(), 0); - inner.notification_bell.set(0); // FIXME: This corresponds to the queue index. + inner.notification_bell.set(self.queue_index); } fn alloc_descriptor(&self) -> usize { @@ -162,7 +165,7 @@ impl<'a> Queue<'a> { if let Some(index) = inner.descriptor_stack.pop_front() { index as usize } else { - log::warn!("virtiod: descriptors exhausted, waiting on garabage collector"); + log::warn!("virtiod-core: descriptors exhausted, waiting on garabage collector"); drop(inner); // Wait for the garbage collector thread to release some descriptors. @@ -216,7 +219,7 @@ impl<'a> Available<'a> { .elements .as_mut_slice(self.queue_size) .get_mut(index % 256) - .expect("virtio::available: index out of bounds") + .expect("virtio-core::available: index out of bounds") } } @@ -231,7 +234,7 @@ impl<'a> Available<'a> { impl Drop for Available<'_> { fn drop(&mut self) { - log::warn!("virtio: dropping 'available' ring at {:#x}", self.addr); + log::warn!("virtio-core: dropping 'available' ring at {:#x}", self.addr); unsafe { syscall::physunmap(self.addr).unwrap(); @@ -278,7 +281,7 @@ impl<'a> Used<'a> { .elements .as_mut_slice(self.queue_size) .get_mut(index % 256) - .expect("virtio::used: index out of bounds") + .expect("virtio-core::used: index out of bounds") } } @@ -297,7 +300,7 @@ impl<'a> Used<'a> { impl Drop for Used<'_> { fn drop(&mut self) { - log::warn!("virtio: dropping 'used' ring at {:#x}", self.addr); + log::warn!("virtio-core: dropping 'used' ring at {:#x}", self.addr); unsafe { syscall::physunmap(self.addr).unwrap(); @@ -385,8 +388,6 @@ impl<'a> StandardTransport<'a> { let queue_size = common.queue_size.get() as usize; let queue_notify_idx = common.queue_notify_off.get(); - log::info!("notify_idx: {}", queue_notify_idx); - // Allocate memory for the queue structues. let descriptor = unsafe { Dma::<[Descriptor]>::zeroed_unsized(queue_size).map_err(Error::SyscallError)? @@ -418,7 +419,13 @@ impl<'a> StandardTransport<'a> { &mut *(self.notify.add(offset as usize) as *mut VolatileCell) }; - log::info!("virtio: enabled queue #{queue_index} (size={queue_size})"); - Ok(Queue::new(descriptor, avail, used, notification_bell)) + log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})"); + Ok(Queue::new( + descriptor, + avail, + used, + notification_bell, + queue_index, + )) } } diff --git a/virtio-core/src/utils.rs b/virtio-core/src/utils.rs index be9ccbe876..d05b74c41e 100644 --- a/virtio-core/src/utils.rs +++ b/virtio-core/src/utils.rs @@ -63,3 +63,39 @@ impl IncompleteArrayField { pub const fn align(val: usize, align: usize) -> usize { (val + align) & !align } + +#[cfg(target_os = "redox")] +pub fn setup_logging(level: log::LevelFilter, name: &str) { + use redox_log::{OutputBuilder, RedoxLogger}; + + let mut logger = RedoxLogger::new().with_output( + OutputBuilder::stderr() + .with_filter(level) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ); + + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", format!("{name}.log")) { + Ok(builder) => { + logger = logger.with_output(builder.with_filter(level).flush_on_newline(true).build()) + } + Err(err) => eprintln!("virtio-core::utils: failed to create log: {}", err), + } + + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", format!("{name}.ansi.log")) { + Ok(builder) => { + logger = logger.with_output( + builder + .with_filter(level) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ) + } + Err(err) => eprintln!("virtio-core::utils: failed to create ANSI log: {}", err), + } + + logger.enable().unwrap(); + log::info!("virtio-core::utils: enabled logger"); +} diff --git a/virtio-netd/Cargo.toml b/virtio-netd/Cargo.toml new file mode 100644 index 0000000000..1be3271d90 --- /dev/null +++ b/virtio-netd/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "virtio-netd" +version = "0.1.0" +edition = "2021" + +[dependencies] +log = "0.4" + +virtio-core = { path = "../virtio-core" } +pcid = { path = "../pcid" } + +redox-daemon = "0.1" diff --git a/virtio-netd/src/main.rs b/virtio-netd/src/main.rs new file mode 100644 index 0000000000..b0fa791e36 --- /dev/null +++ b/virtio-netd/src/main.rs @@ -0,0 +1,63 @@ +use pcid_interface::PcidServerHandle; + +use virtio_core::spec::VIRTIO_NET_F_MAC; +use virtio_core::transport::Error; + +fn deamon(_deamon: redox_daemon::Daemon) -> Result<(), Error> { + let mut pcid_handle = PcidServerHandle::connect_default()?; + + // Double check that we have the right device. + // + // 0x1000 - virtio-net + let pci_config = pcid_handle.fetch_config()?; + + assert_eq!(pci_config.func.devid, 0x1000); + log::info!("virtio-net: initiating startup sequence :^)"); + + let device = virtio_core::probe_device(&mut pcid_handle)?; + let device_space = device.device_space; + + // Negotiate device features: + if device.transport.check_device_feature(VIRTIO_NET_F_MAC) { + let mac = (0..6) + .map(|i| unsafe { core::ptr::read_volatile(device_space.add(i)) }) + .collect::>(); + + log::info!( + "virtio-net: device MAC is {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", + mac[0], + mac[1], + mac[2], + mac[3], + mac[4], + mac[5] + ); + + device.transport.ack_driver_feature(VIRTIO_NET_F_MAC); + } + + // Allocate the recieve and transmit queues: + // + // TODO(andypython): Should we use the same IRQ vector for both? + let rx_queue = device + .transport + .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR)?; + + let tx_queue = device + .transport + .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR)?; + + device.transport.finalize_features(); + loop {} +} + +fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { + deamon(redox_daemon).unwrap(); + unreachable!(); +} + +pub fn main() { + #[cfg(target_os = "redox")] + virtio_core::utils::setup_logging(log::LevelFilter::Trace, "virtio-netd"); + redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); +} From 97e77e21b6f5e612d17a52f3a0f646c27522e6f1 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 28 Jun 2023 12:58:51 +1000 Subject: [PATCH 0633/1301] virtio-net: scheme :^) Signed-off-by: Anhad Singh --- Cargo.lock | 3 + virtio-blkd/src/main.rs | 7 +- virtio-core/src/spec.rs | 8 ++ virtio-core/src/transport.rs | 7 +- virtio-netd/Cargo.toml | 3 + virtio-netd/src/main.rs | 91 ++++++++++++++++--- virtio-netd/src/scheme.rs | 165 +++++++++++++++++++++++++++++++++++ 7 files changed, 266 insertions(+), 18 deletions(-) create mode 100644 virtio-netd/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index be9d66cebc..0ed00573d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1940,8 +1940,11 @@ name = "virtio-netd" version = "0.1.0" dependencies = [ "log", + "netutils", "pcid", "redox-daemon", + "redox_syscall 0.3.5", + "static_assertions", "virtio-core", ] diff --git a/virtio-blkd/src/main.rs b/virtio-blkd/src/main.rs index 7e21dd0ab0..64497da127 100644 --- a/virtio-blkd/src/main.rs +++ b/virtio-blkd/src/main.rs @@ -175,21 +175,20 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { .map_err(Error::SyscallError)?; let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - let mut scheme = scheme::DiskScheme::new(queue, device_space); - deamon.ready().expect("virtio: failed to deamonize"); + deamon.ready().expect("virtio-blkd: failed to deamonize"); loop { let mut packet = Packet::default(); socket_file .read(&mut packet) - .expect("ahcid: failed to read disk scheme"); + .expect("virtio-blkd: failed to read disk scheme"); let packey = scheme.handle(&mut packet); packet.a = packey.unwrap(); socket_file .write(&mut packet) - .expect("ahcid: failed to read disk scheme"); + .expect("virtio-blkd: failed to read disk scheme"); } } diff --git a/virtio-core/src/spec.rs b/virtio-core/src/spec.rs index 6c525c466e..37dd2b4fad 100644 --- a/virtio-core/src/spec.rs +++ b/virtio-core/src/spec.rs @@ -220,6 +220,14 @@ impl Buffer { } } + pub fn new_unsized(val: &syscall::Dma<[T]>) -> Self { + Self { + buffer: val.physical(), + size: core::mem::size_of::() * val.len(), + flags: DescriptorFlags::empty(), + } + } + pub fn flags(mut self, flags: DescriptorFlags) -> Self { self.flags = flags; self diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index d4bcfdfd64..cbcb7f860d 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -97,7 +97,7 @@ impl<'a> Queue<'a> { Arc::new_cyclic(|sref| Self { inner: Mutex::new(QueueInner { head_index: 0, - descriptor_stack: (0..(descriptor.len() - 1) as u16).rev().collect(), + descriptor_stack: (0..descriptor.len() as u16).collect(), descriptor, available, @@ -179,6 +179,11 @@ impl<'a> Queue<'a> { self.alloc_descriptor() } } + + /// Returns the number of descriptors in the descriptor table of this queue. + pub fn descriptor_len(&self) -> usize { + self.inner.lock().unwrap().descriptor.len() + } } pub struct Available<'a> { diff --git a/virtio-netd/Cargo.toml b/virtio-netd/Cargo.toml index 1be3271d90..8a905d18e8 100644 --- a/virtio-netd/Cargo.toml +++ b/virtio-netd/Cargo.toml @@ -5,8 +5,11 @@ edition = "2021" [dependencies] log = "0.4" +static_assertions = "1.1.0" virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } redox-daemon = "0.1" +redox_syscall = "0.3" +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } diff --git a/virtio-netd/src/main.rs b/virtio-netd/src/main.rs index b0fa791e36..172034c2e2 100644 --- a/virtio-netd/src/main.rs +++ b/virtio-netd/src/main.rs @@ -1,9 +1,35 @@ +mod scheme; + +use std::fs::File; +use std::io::{Read, Write}; +use std::os::fd::{FromRawFd, RawFd}; + use pcid_interface::PcidServerHandle; +use syscall::{Packet, SchemeBlockMut}; + use virtio_core::spec::VIRTIO_NET_F_MAC; use virtio_core::transport::Error; -fn deamon(_deamon: redox_daemon::Daemon) -> Result<(), Error> { +use scheme::NetworkScheme; + +#[derive(Debug)] +#[repr(C)] +pub struct VirtHeader { + pub flags: u8, + pub gso_type: u8, + pub hdr_len: u16, + pub gso_size: u16, + pub csum_start: u16, + pub csum_offset: u16, + pub num_buffers: u16, +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 12); + +const MAX_BUFFER_LEN: usize = 65535; + +fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { let mut pcid_handle = PcidServerHandle::connect_default()?; // Double check that we have the right device. @@ -18,26 +44,32 @@ fn deamon(_deamon: redox_daemon::Daemon) -> Result<(), Error> { let device_space = device.device_space; // Negotiate device features: - if device.transport.check_device_feature(VIRTIO_NET_F_MAC) { + let mac_addr = if device.transport.check_device_feature(VIRTIO_NET_F_MAC) { let mac = (0..6) .map(|i| unsafe { core::ptr::read_volatile(device_space.add(i)) }) .collect::>(); - log::info!( - "virtio-net: device MAC is {:02X}:{:02X}:{:02X}:{:02X}:{:02X}:{:02X}", - mac[0], - mac[1], - mac[2], - mac[3], - mac[4], - mac[5] + let mac_str = format!( + "{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); + log::info!("virtio-net: device MAC is {mac_str}"); + device.transport.ack_driver_feature(VIRTIO_NET_F_MAC); - } + mac_str + } else { + unimplemented!() + }; + + device.transport.finalize_features(); // Allocate the recieve and transmit queues: // + // > Empty buffers are placed in one virtqueue for receiving + // > packets, and outgoing packets are enqueued into another + // > for transmission in that order. + // // TODO(andypython): Should we use the same IRQ vector for both? let rx_queue = device .transport @@ -47,8 +79,41 @@ fn deamon(_deamon: redox_daemon::Daemon) -> Result<(), Error> { .transport .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR)?; - device.transport.finalize_features(); - loop {} + device.transport.run_device(); + + let mut name = pci_config.func.name(); + name.push_str("_virtio_net"); + + // Create the network scheme. + // + // FIXME(andypython): It should be fine to have multiple network devices. + let socket_fd = syscall::open( + &format!(":network"), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, + ) + .map_err(Error::SyscallError)?; + + let mut socket_fd = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + let mut scheme = NetworkScheme::new(rx_queue, tx_queue); + + let _ = netutils::setcfg("mac", &mac_addr); + + deamon.ready().expect("virtio-netd: failed to deamonize"); + + loop { + let mut packet = Packet::default(); + socket_fd + .read(&mut packet) + .expect("virtio-netd: failed to read packet"); + + let result = scheme.handle(&mut packet); + // `packet.a` contains the return value. + packet.a = result.expect("virtio-netd: failed to handle packet"); + + socket_fd + .write(&packet) + .expect("virtio-netd: failed to write packet"); + } } fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { diff --git a/virtio-netd/src/scheme.rs b/virtio-netd/src/scheme.rs new file mode 100644 index 0000000000..19152c19d5 --- /dev/null +++ b/virtio-netd/src/scheme.rs @@ -0,0 +1,165 @@ +use std::collections::BTreeMap; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; + +use syscall::Error as SysError; +use syscall::*; + +use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; +use virtio_core::transport::Queue; + +use crate::{VirtHeader, MAX_BUFFER_LEN}; + +pub struct NetworkScheme<'a> { + /// Reciever Queue. + rx: Arc>, + rx_buffers: Vec>, + + /// Transmiter Queue. + tx: Arc>, + /// File descriptor handles. + handles: BTreeMap, + next_id: AtomicUsize, + + recv_head: u16, +} + +impl<'a> NetworkScheme<'a> { + pub fn new(rx: Arc>, tx: Arc>) -> Self { + // Populate all of the `rx_queue` with buffers to maximize performence. + let mut rx_buffers = vec![]; + for i in 0..(rx.descriptor_len() as usize) { + rx_buffers.push(unsafe { Dma::<[u8]>::zeroed_unsized(MAX_BUFFER_LEN) }.unwrap()); + + let chain = ChainBuilder::new() + .chain(Buffer::new_unsized(&rx_buffers[i]).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + rx.send(chain); + } + + Self { + rx, + rx_buffers, + tx, + + handles: BTreeMap::new(), + next_id: AtomicUsize::new(0), + + recv_head: 0, + } + } + + /// Returns the number of bytes read. Returns `0` if the operation would block. + fn try_recv(&mut self, target: &mut [u8]) -> usize { + let header_size = core::mem::size_of::(); + + let mut queue = self.rx.inner.lock().unwrap(); + + if self.recv_head == queue.used.head_index() { + // The read would block. + return 0; + } + + let idx = queue.used.head_index() as usize; + let element = queue.used.get_element_at(idx - 1); + + let descriptor_idx = element.table_index.get(); + let payload_size = element.written.get() as usize - header_size; + + // XXX: The header and packet are added as one output descriptor to the transmit queue, + // and the device is notified of the new entry (see 5.1.5 Device Initialization). + let buffer = &self.rx_buffers[descriptor_idx as usize]; + // TODO: Check the header. + let _header = unsafe { &*(buffer.as_ptr() as *const VirtHeader) }; + let packet = &buffer[header_size..(header_size + payload_size)]; + + // Copy the packet into the buffer. + target[..payload_size].copy_from_slice(&packet); + + self.recv_head = queue.used.head_index(); + payload_size + } +} + +impl<'a> SchemeBlockMut for NetworkScheme<'a> { + fn open( + &mut self, + _path: &str, + flags: usize, + uid: u32, + _gid: u32, + ) -> syscall::Result> { + if uid != 0 { + return Err(SysError::new(EACCES)); + } + + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.insert(id, flags); + + Ok(Some(id)) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result> { + let flags = *self.handles.get(&id).ok_or(SysError::new(EBADF))?; + let bytes = self.try_recv(buf); + + if bytes != 0 { + // We read some bytes. + Ok(Some(bytes)) + } else if flags & O_NONBLOCK == O_NONBLOCK { + // We are in non-blocking mode. + Err(SysError::new(EWOULDBLOCK)) + } else { + // Block + unimplemented!() + } + } + + fn write(&mut self, id: usize, buffer: &[u8]) -> syscall::Result> { + if self.handles.get(&id).is_none() { + return Err(SysError::new(EBADF)); + } + + let header = unsafe { Dma::::zeroed()?.assume_init() }; + + // TODO: Does the payload actually need to be a DMA buffer? + let mut payload = unsafe { Dma::<[u8]>::zeroed_unsized(buffer.len())? }; + payload.copy_from_slice(buffer); + + let chain = ChainBuilder::new() + .chain(Buffer::new(&header).flags(DescriptorFlags::NEXT)) + .chain(Buffer::new_unsized(&payload)) + .build(); + + self.tx.send(chain); + core::mem::forget(payload); + + Ok(Some(buffer.len())) + } + + fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> syscall::Result> { + unimplemented!() + } + + fn fevent( + &mut self, + id: usize, + _flags: syscall::EventFlags, + ) -> syscall::Result> { + let _flags = self.handles.get(&id).ok_or(SysError::new(EBADF))?; + Ok(Some(syscall::EventFlags::empty())) + } + + fn fpath(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result> { + unimplemented!() + } + + fn fsync(&mut self, _id: usize) -> syscall::Result> { + unimplemented!() + } + + fn close(&mut self, _id: usize) -> syscall::Result> { + unimplemented!() + } +} From 92fd7fc553c65734c83ce743c01d093270695fe0 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 28 Jun 2023 15:06:23 +1000 Subject: [PATCH 0634/1301] virtio-core::ChainBuilder: automagically add the `NEXT` flag Signed-off-by: Anhad Singh --- fmt.sh | 13 +++++++++++++ virtio-blkd/src/scheme.rs | 15 ++++++--------- virtio-core/src/spec.rs | 9 +++++++-- virtio-netd/src/scheme.rs | 2 +- 4 files changed, 27 insertions(+), 12 deletions(-) create mode 100755 fmt.sh diff --git a/fmt.sh b/fmt.sh new file mode 100755 index 0000000000..b0b137080b --- /dev/null +++ b/fmt.sh @@ -0,0 +1,13 @@ +#!/usr/bin/bash + +pushd virtio-core +cargo fmt +popd + +pushd virtio-netd +cargo fmt +popd + +pushd virtio-blkd +cargo fmt +popd diff --git a/virtio-blkd/src/scheme.rs b/virtio-blkd/src/scheme.rs index a6247e2c6b..c71e29d463 100644 --- a/virtio-blkd/src/scheme.rs +++ b/virtio-blkd/src/scheme.rs @@ -59,8 +59,8 @@ impl BlkExtension for Queue<'_> { let status = syscall::Dma::new(u8::MAX).unwrap(); let chain = ChainBuilder::new() - .chain(Buffer::new(&req).flags(DescriptorFlags::NEXT)) - .chain(Buffer::new(&result).flags(DescriptorFlags::WRITE_ONLY | DescriptorFlags::NEXT)) + .chain(Buffer::new(&req)) + .chain(Buffer::new(&result).flags(DescriptorFlags::WRITE_ONLY)) .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) .build(); @@ -90,8 +90,8 @@ impl BlkExtension for Queue<'_> { let status = syscall::Dma::new(u8::MAX).unwrap(); let chain = ChainBuilder::new() - .chain(Buffer::new(&req).flags(DescriptorFlags::NEXT)) - .chain(Buffer::new(&result).flags(DescriptorFlags::NEXT)) + .chain(Buffer::new(&req)) + .chain(Buffer::new(&result)) .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) .build(); @@ -162,11 +162,8 @@ impl<'a> DiskScheme<'a> { let status = syscall::Dma::new(u8::MAX).unwrap(); let chain = ChainBuilder::new() - .chain(Buffer::new(&req).flags(DescriptorFlags::NEXT)) - .chain( - Buffer::new(&result) - .flags(DescriptorFlags::WRITE_ONLY | DescriptorFlags::NEXT), - ) + .chain(Buffer::new(&req)) + .chain(Buffer::new(&result).flags(DescriptorFlags::WRITE_ONLY)) .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) .build(); diff --git a/virtio-core/src/spec.rs b/virtio-core/src/spec.rs index 37dd2b4fad..072314de2b 100644 --- a/virtio-core/src/spec.rs +++ b/virtio-core/src/spec.rs @@ -234,6 +234,7 @@ impl Buffer { } } +/// XXX: The [`DescriptorFlags::NEXT`] flag is set automatically. pub struct ChainBuilder { buffers: Vec, } @@ -245,12 +246,16 @@ impl ChainBuilder { } } - pub fn chain(mut self, buffer: Buffer) -> Self { + pub fn chain(mut self, mut buffer: Buffer) -> Self { + buffer.flags |= DescriptorFlags::NEXT; self.buffers.push(buffer); self } - pub fn build(self) -> Vec { + pub fn build(mut self) -> Vec { + let last_buffer = self.buffers.last_mut().expect("virtio-core: empty chain"); + last_buffer.flags.remove(DescriptorFlags::NEXT); + self.buffers } } diff --git a/virtio-netd/src/scheme.rs b/virtio-netd/src/scheme.rs index 19152c19d5..c3eb8fe4a7 100644 --- a/virtio-netd/src/scheme.rs +++ b/virtio-netd/src/scheme.rs @@ -128,7 +128,7 @@ impl<'a> SchemeBlockMut for NetworkScheme<'a> { payload.copy_from_slice(buffer); let chain = ChainBuilder::new() - .chain(Buffer::new(&header).flags(DescriptorFlags::NEXT)) + .chain(Buffer::new(&header)) .chain(Buffer::new_unsized(&payload)) .build(); From c898e2e01fb0e77749553e9f36a5e37fcf64efc0 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Thu, 29 Jun 2023 14:17:45 +1000 Subject: [PATCH 0635/1301] virtio-core: make `send` async This allows for us to do cool stuff such as `join!(queue.send(read_command), queue.send(write_command), queue.send(read_command_2))` Signed-off-by: Anhad Singh --- Cargo.lock | 16 ++- README.md | 2 +- virtio-blkd/Cargo.toml | 2 +- virtio-blkd/src/main.rs | 62 +-------- virtio-blkd/src/scheme.rs | 84 ++++-------- virtio-core/Cargo.toml | 3 + virtio-core/src/probe.rs | 3 - virtio-core/src/spec.rs | 56 +++++++- virtio-core/src/transport.rs | 245 +++++++++++++++++++++-------------- virtio-netd/Cargo.toml | 1 + virtio-netd/src/main.rs | 4 +- virtio-netd/src/scheme.rs | 22 ++-- 12 files changed, 260 insertions(+), 240 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0ed00573d8..cc75943e6c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -354,6 +354,16 @@ dependencies = [ "crossbeam-utils 0.8.15", ] +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if 1.0.0", + "crossbeam-utils 0.8.15", +] + [[package]] name = "crossbeam-utils" version = "0.7.2" @@ -1910,12 +1920,12 @@ version = "0.1.0" dependencies = [ "anyhow", "block-io-wrapper", + "futures", "log", "partitionlib", "pcid", "redox-daemon", "redox-log", - "redox_event", "redox_syscall 0.3.5", "static_assertions", "thiserror", @@ -1927,9 +1937,12 @@ name = "virtio-core" version = "0.1.0" dependencies = [ "bitflags 2.3.2", + "crossbeam-queue", + "futures", "log", "pcid", "redox-log", + "redox_event", "redox_syscall 0.3.5", "static_assertions", "thiserror", @@ -1939,6 +1952,7 @@ dependencies = [ name = "virtio-netd" version = "0.1.0" dependencies = [ + "futures", "log", "netutils", "pcid", diff --git a/README.md b/README.md index 6023ec3f00..0262ed8d1b 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ These are the currently implemented devices/hardware interfaces. - usbctl - USB control (incomplete). - usbhidd - USB HID (incomplete). - usbscsid - USB SCSI (incomplete). -- virtiod - VirtIO (incomplete) (`virtio-blk`). +- virtio-* - VirtIO (incomplete) (`virtio-blk`, `virtio-net`). ## Contributing to Drivers diff --git a/virtio-blkd/Cargo.toml b/virtio-blkd/Cargo.toml index 0d9e12e5d0..461a0d679a 100644 --- a/virtio-blkd/Cargo.toml +++ b/virtio-blkd/Cargo.toml @@ -9,11 +9,11 @@ anyhow = "1.0.71" log = "0.4" thiserror = "1.0.40" static_assertions = "1.1.0" +futures = { version = "0.3.28", features = ["executor"] } redox-daemon = "0.1" redox-log = "0.1" redox_syscall = "0.3" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/virtio-blkd/src/main.rs b/virtio-blkd/src/main.rs index 64497da127..963156a37b 100644 --- a/virtio-blkd/src/main.rs +++ b/virtio-blkd/src/main.rs @@ -1,17 +1,15 @@ #![deny(trivial_numeric_casts, unused_allocation)] -#![feature(int_roundings)] +#![feature(int_roundings, async_fn_in_trait)] use std::fs::File; -use std::io; use std::io::{Read, Write}; -use std::os::fd::{AsRawFd, FromRawFd, RawFd}; +use std::os::fd::{FromRawFd, RawFd}; use static_assertions::const_assert_eq; use pcid_interface::*; use virtio_core::spec::*; -use event::EventQueue; use syscall::{Packet, SchemeBlockMut}; use virtio_core::utils::VolatileCell; @@ -93,67 +91,15 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { assert_eq!(pci_config.func.devid, 0x1001); log::info!("virtio-blk: initiating startup sequence :^)"); - let mut device = virtio_core::probe_device(&mut pcid_handle)?; + let device = virtio_core::probe_device(&mut pcid_handle)?; device.transport.finalize_features(); let queue = device .transport - .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR)?; - let queue_copy = queue.clone(); + .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR, &device.irq_handle)?; let device_space = unsafe { &mut *(device.device_space as *mut BlockDeviceConfig) }; - std::thread::spawn(move || { - let mut event_queue = EventQueue::::new().unwrap(); - let mut progress_head = 0; - - event_queue - .add( - device.irq_handle.as_raw_fd(), - move |_| -> Result, io::Error> { - // Read from ISR to acknowledge the interrupt. - let _isr = device.isr.get() as usize; - - let mut inner = queue_copy.inner.lock().unwrap(); - let used_head = inner.used.head_index(); - - if progress_head == used_head { - return Ok(None); - } - - for i in progress_head..used_head { - let used = inner.used.get_element_at(i as usize); - let mut desc_idx = used.table_index.get(); - inner.descriptor_stack.push_back(desc_idx as u16); - - loop { - let desc = &inner.descriptor[desc_idx as usize]; - if !desc.flags.contains(DescriptorFlags::NEXT) { - break; - } - - desc_idx = desc.next.into(); - inner.descriptor_stack.push_back(desc_idx as u16); - } - } - - progress_head = used_head; - drop(inner); - - let mut buf = [0u8; 8]; - device.irq_handle.read(&mut buf)?; - // Acknowledge the interrupt. - // irq_handle.write(&buf)?; - Ok(None) - }, - ) - .unwrap(); - - loop { - event_queue.run().unwrap(); - } - }); - // At this point the device is alive! device.transport.run_device(); diff --git a/virtio-blkd/src/scheme.rs b/virtio-blkd/src/scheme.rs index c71e29d463..8a3f6154cb 100644 --- a/virtio-blkd/src/scheme.rs +++ b/virtio-blkd/src/scheme.rs @@ -21,33 +21,12 @@ use crate::BlockVirtRequest; const BLK_SIZE: u64 = 512; trait BlkExtension { - /// XXX: Reads only one block despite the size of the output buffer. Use [`BlkExtension::read`] instead. - fn read_block(&self, block: u64, block_bytes: &mut [u8]) -> usize; - - /// XXX: Reads only one block despite the size of the output buffer. Use [`BlkExtension::write`] instead. - fn write_block(&self, block: u64, block_bytes: &[u8]) -> usize; - - // FIXME(andypython): The following two methods can be done asynchronously (i.e, send all of the commands at once - // and wait for the result in the end). - fn read(&self, block: u64, block_bytes: &mut [u8]) -> usize { - let sectors = block_bytes.len() / BLK_SIZE as usize; - - (0..sectors) - .map(|i| self.read_block(block + i as u64, &mut block_bytes[i * BLK_SIZE as usize..])) - .sum() - } - - fn write(&self, block: u64, block_bytes: &[u8]) -> usize { - let sectors = block_bytes.len() / BLK_SIZE as usize; - - (0..sectors) - .map(|i| self.write_block(block + i as u64, &block_bytes[i * BLK_SIZE as usize..])) - .sum() - } + async fn read(&self, block: u64, target: &mut [u8]) -> usize; + async fn write(&self, block: u64, target: &[u8]) -> usize; } impl BlkExtension for Queue<'_> { - fn read_block(&self, block: u64, block_bytes: &mut [u8]) -> usize { + async fn read(&self, block: u64, target: &mut [u8]) -> usize { let req = syscall::Dma::new(BlockVirtRequest { ty: BlockRequestTy::In, reserved: 0, @@ -55,28 +34,24 @@ impl BlkExtension for Queue<'_> { }) .unwrap(); - let result = syscall::Dma::new([0u8; 512]).unwrap(); + let result = unsafe { syscall::Dma::<[u8]>::zeroed_unsized(target.len()) }.unwrap(); let status = syscall::Dma::new(u8::MAX).unwrap(); let chain = ChainBuilder::new() .chain(Buffer::new(&req)) - .chain(Buffer::new(&result).flags(DescriptorFlags::WRITE_ONLY)) + .chain(Buffer::new_unsized(&result).flags(DescriptorFlags::WRITE_ONLY)) .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) .build(); - self.send(chain); + // XXX: Subtract 1 because the of status byte. + let written = self.send(chain).await as usize - 1; + assert_eq!(*status, 0); - // FIXME: interrupts are for a reason - while *status != 0 { - core::hint::spin_loop(); - } - - let size = core::cmp::min(block_bytes.len(), result.len()); - block_bytes[..size].copy_from_slice(&result.as_slice()[..size]); - size + target[..written].copy_from_slice(&result); + written } - fn write_block(&self, block: u64, block_bytes: &[u8]) -> usize { + async fn write(&self, block: u64, target: &[u8]) -> usize { let req = syscall::Dma::new(BlockVirtRequest { ty: BlockRequestTy::Out, reserved: 0, @@ -84,25 +59,21 @@ impl BlkExtension for Queue<'_> { }) .unwrap(); - let mut result = syscall::Dma::new([0u8; 512]).unwrap(); - result.copy_from_slice(&block_bytes[..512]); + let mut result = unsafe { syscall::Dma::<[u8]>::zeroed_unsized(target.len()) }.unwrap(); + result.copy_from_slice(target.as_ref()); let status = syscall::Dma::new(u8::MAX).unwrap(); let chain = ChainBuilder::new() .chain(Buffer::new(&req)) - .chain(Buffer::new(&result)) + .chain(Buffer::new_sized(&result, target.len())) .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) .build(); - self.send(chain); + self.send(chain).await as usize; + assert_eq!(*status, 0); - // FIXME: interrupts are for a reason - while *status != 0 { - core::hint::spin_loop(); - } - - block_bytes.len() + target.len() } } @@ -167,18 +138,11 @@ impl<'a> DiskScheme<'a> { .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) .build(); - self.scheme.queue.send(chain); - - // FIXME: interrupts are for a reason - while *status != 0 { - core::hint::spin_loop(); - } + futures::executor::block_on(self.scheme.queue.send(chain)); + assert_eq!(*status, 0); let size = core::cmp::min(block_bytes.len(), result.len()); block_bytes[..size].copy_from_slice(&result.as_slice()[..size]); - - std::thread::yield_now(); - Ok(()) }; @@ -328,7 +292,7 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { let abs_block = part.start_lba + rel_block; - let count = self.queue.read(abs_block, buf); + let count = futures::executor::block_on(self.queue.read(abs_block, buf)); *offset += count; Ok(Some(count)) } @@ -336,7 +300,9 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { Handle::Disk { ref mut offset } => { let block_size = self.cfg.block_size(); - let count = self.queue.read((*offset as u64) / block_size as u64, buf); + let count = futures::executor::block_on( + self.queue.read((*offset as u64) / block_size as u64, buf), + ); *offset += count; Ok(Some(count)) } @@ -347,7 +313,9 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::Disk { ref mut offset } => { let block_size = self.cfg.block_size(); - let count = self.queue.write((*offset as u64) / block_size as u64, buf); + let count = futures::executor::block_on( + self.queue.write((*offset as u64) / block_size as u64, buf), + ); *offset += count; Ok(Some(count)) diff --git a/virtio-core/Cargo.toml b/virtio-core/Cargo.toml index 87467d6bfb..9a8c197b5d 100644 --- a/virtio-core/Cargo.toml +++ b/virtio-core/Cargo.toml @@ -10,7 +10,10 @@ bitflags = "2.3.2" redox_syscall = "0.3" log = "0.4" thiserror = "1.0.40" +futures = { version = "0.3.28", features = ["executor"] } +crossbeam-queue = "0.3.8" redox-log = "0.1" +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } pcid = { path = "../pcid" } diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 34fbc00bed..a68ed54541 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -23,7 +23,6 @@ pub struct Device<'a> { struct MsixInfo { pub virt_table_base: NonNull, - pub virt_pba_base: NonNull, pub capability: MsixCapability, } @@ -84,11 +83,9 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { } let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; - let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; let mut info = MsixInfo { virt_table_base: NonNull::new(virt_table_base).unwrap(), - virt_pba_base: NonNull::new(virt_pba_base).unwrap(), capability, }; diff --git a/virtio-core/src/spec.rs b/virtio-core/src/spec.rs index 072314de2b..eb8f12f829 100644 --- a/virtio-core/src/spec.rs +++ b/virtio-core/src/spec.rs @@ -1,5 +1,7 @@ //! https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html +use std::sync::atomic::{AtomicU16, AtomicU32, AtomicU64, Ordering}; + use crate::utils::{IncompleteArrayField, VolatileCell}; use static_assertions::const_assert_eq; @@ -116,16 +118,42 @@ bitflags::bitflags! { #[repr(C)] pub struct Descriptor { /// Address (guest-physical). - pub address: u64, + pub address: AtomicU64, /// Size of the descriptor. - pub size: u32, - pub flags: DescriptorFlags, + pub size: AtomicU32, + flags: AtomicU16, /// Index of next desciptor in chain. - pub next: u16, + pub next: AtomicU16, } const_assert_eq!(core::mem::size_of::(), 16); +impl Descriptor { + pub fn set_addr(&self, addr: u64) { + self.address.store(addr, Ordering::SeqCst) + } + + pub fn set_size(&self, size: u32) { + self.size.store(size, Ordering::SeqCst) + } + + pub fn set_next(&self, next: Option) { + self.next.store(next.unwrap_or_default(), Ordering::SeqCst) + } + + pub fn set_flags(&self, flags: DescriptorFlags) { + self.flags.store(flags.bits(), Ordering::SeqCst) + } + + pub fn next(&self) -> u16 { + self.next.load(Ordering::SeqCst) + } + + pub fn flags(&self) -> DescriptorFlags { + DescriptorFlags::from_bits_truncate(self.flags.load(Ordering::SeqCst)) + } +} + /// This indicates compliance with the version 1 VirtIO specification. /// /// See `6.1 Driver Requirements: Reserved Feature Bits` section of the VirtIO @@ -140,7 +168,13 @@ pub const VIRTIO_NET_F_MAC: u32 = 5; // chain. #[repr(C)] pub struct AvailableRingElement { - pub table_index: VolatileCell, + pub table_index: AtomicU16, +} + +impl AvailableRingElement { + pub fn set_table_index(&self, index: u16) { + self.table_index.store(index, Ordering::SeqCst) + } } const_assert_eq!(core::mem::size_of::(), 2); @@ -148,7 +182,7 @@ const_assert_eq!(core::mem::size_of::(), 2); #[repr(C)] pub struct AvailableRing { pub flags: VolatileCell, - pub head_index: VolatileCell, + pub head_index: AtomicU16, pub elements: IncompleteArrayField, } @@ -158,7 +192,7 @@ impl Default for AvailableRing { fn default() -> Self { Self { flags: VolatileCell::new(0), - head_index: VolatileCell::new(0), + head_index: AtomicU16::new(0), elements: IncompleteArrayField::new(), } } @@ -228,6 +262,14 @@ impl Buffer { } } + pub fn new_sized(val: &syscall::Dma<[T]>, size: usize) -> Self { + Self { + buffer: val.physical(), + size, + flags: DescriptorFlags::empty(), + } + } + pub fn flags(mut self, flags: DescriptorFlags) -> Self { self.flags = flags; self diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index cbcb7f860d..ae94c70316 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -1,13 +1,17 @@ use crate::spec::*; -use crate::utils::{align, VolatileCell}; +use crate::utils::align; +use event::EventQueue; use syscall::{Dma, PHYSMAP_WRITE}; use core::mem::size_of; -use core::sync::atomic::{fence, AtomicU16, Ordering}; +use core::sync::atomic::{AtomicU16, Ordering}; -use std::collections::VecDeque; +use std::fs::File; +use std::future::Future; +use std::os::fd::AsRawFd; use std::sync::{Arc, Mutex, Weak}; +use std::task::{Poll, Waker}; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -64,24 +68,63 @@ const fn queue_part_sizes(queue_size: usize) -> (usize, usize, usize) { ) } -pub struct QueueInner<'a> { - pub descriptor: Dma<[Descriptor]>, - pub available: Available<'a>, - pub used: Used<'a>, - - /// Keeps track of unused descriptor indicies. - pub descriptor_stack: VecDeque, - - notification_bell: &'a mut VolatileCell, - head_index: u16, +pub struct PendingRequest<'a> { + queue: Arc>, + first_descriptor: u32, } -unsafe impl Sync for QueueInner<'_> {} -unsafe impl Send for QueueInner<'_> {} +impl<'a> Future for PendingRequest<'a> { + type Output = u32; + + fn poll(self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { + // XXX: Register the waker before checking the queue to avoid the race condition + // where you lose a notification. + self.queue + .waker + .lock() + .unwrap() + .insert(self.first_descriptor, cx.waker().clone()); + + let used_head = self.queue.used.head_index(); + let used_element = self.queue.used.get_element_at((used_head - 1) as usize); + let written = used_element.written.get(); + + let mut table_index = used_element.table_index.get(); + + if table_index == self.first_descriptor { + // The request has been completed; recycle the descriptors used. + while self.queue.descriptor[table_index as usize] + .flags() + .contains(DescriptorFlags::NEXT) + { + let next_index = self.queue.descriptor[table_index as usize].next(); + self.queue.descriptor_stack.push(table_index as u16); + table_index = next_index.into(); + } + + // Push the last descriptor. + self.queue.descriptor_stack.push(table_index as u16); + self.queue + .waker + .lock() + .unwrap() + .remove(&self.first_descriptor); + return Poll::Ready(written); + } else { + return Poll::Pending; + } + } +} pub struct Queue<'a> { - pub inner: Mutex>, pub queue_index: u16, + pub waker: Mutex>, + pub used: Used<'a>, + pub descriptor: Dma<[Descriptor]>, + pub available: Available<'a>, + + notification_bell: &'a mut AtomicU16, + descriptor_stack: crossbeam_queue::SegQueue, sref: Weak, } @@ -91,101 +134,79 @@ impl<'a> Queue<'a> { available: Available<'a>, used: Used<'a>, - notification_bell: &'a mut VolatileCell, + notification_bell: &'a mut AtomicU16, queue_index: u16, ) -> Arc { + let descriptor_stack = crossbeam_queue::SegQueue::new(); + (0..descriptor.len() as u16).for_each(|i| descriptor_stack.push(i)); + Arc::new_cyclic(|sref| Self { - inner: Mutex::new(QueueInner { - head_index: 0, - descriptor_stack: (0..descriptor.len() as u16).collect(), - - descriptor, - available, - used, - - notification_bell, - }), - + notification_bell, + available, + descriptor, + used, + waker: Mutex::new(std::collections::HashMap::new()), queue_index, + descriptor_stack, sref: sref.clone(), }) } - pub fn send(&self, chain: Vec) { + #[must_use = "The function returns a future that must be awaited to ensure the sent request is completed."] + pub fn send(&self, chain: Vec) -> PendingRequest<'a> { let mut first_descriptor: Option = None; let mut last_descriptor: Option = None; for buffer in chain.iter() { - let descriptor = self.alloc_descriptor(); - - let mut inner = self.inner.lock().unwrap(); + let descriptor = self.descriptor_stack.pop().unwrap() as usize; if first_descriptor.is_none() { first_descriptor = Some(descriptor); } - inner.descriptor[descriptor].address = buffer.buffer as u64; - inner.descriptor[descriptor].flags = buffer.flags; - inner.descriptor[descriptor].size = buffer.size as u32; + self.descriptor[descriptor].set_addr(buffer.buffer as u64); + self.descriptor[descriptor].set_flags(buffer.flags); + self.descriptor[descriptor].set_size(buffer.size as u32); if let Some(index) = last_descriptor { - inner.descriptor[index].next = descriptor as u16; + self.descriptor[index].set_next(Some(descriptor as u16)); } last_descriptor = Some(descriptor); } - let mut inner = self.inner.lock().unwrap(); - let last_descriptor = last_descriptor.unwrap(); let first_descriptor = first_descriptor.unwrap(); - inner.descriptor[last_descriptor].next = 0; + self.descriptor[last_descriptor].set_next(None); - fence(Ordering::SeqCst); - let index = inner.head_index as usize; + let index = self.available.head_index() as usize; - inner - .available + self.available .get_element_at(index) - .table_index - .set(first_descriptor as u16); + .set_table_index(first_descriptor as u16); - fence(Ordering::SeqCst); - inner.available.set_head_idx(index as u16 + 1); - inner.head_index += 1; + self.available.set_head_idx(index as u16 + 1); + self.notification_bell + .store(self.queue_index, Ordering::SeqCst); - assert_eq!(inner.used.flags(), 0); - inner.notification_bell.set(self.queue_index); - } + assert_eq!(self.used.flags(), 0); - fn alloc_descriptor(&self) -> usize { - let mut inner = self.inner.lock().unwrap(); - - if let Some(index) = inner.descriptor_stack.pop_front() { - index as usize - } else { - log::warn!("virtiod-core: descriptors exhausted, waiting on garabage collector"); - drop(inner); - - // Wait for the garbage collector thread to release some descriptors. - // - // TODO(andypython): Instead of just yielding, we should have a proper notificiation - // mechanism. I am not aware whats the standard way redox applications - // or drivers implement basically a WaitQueue which you can use to wake - // up a thread. The descripts really should NEVER run out, but if they - // do, have a proper way to handle them. - std::thread::yield_now(); - self.alloc_descriptor() + PendingRequest { + queue: self.sref.upgrade().unwrap(), + first_descriptor: first_descriptor as u32, } } /// Returns the number of descriptors in the descriptor table of this queue. pub fn descriptor_len(&self) -> usize { - self.inner.lock().unwrap().descriptor.len() + self.descriptor.len() } } +unsafe impl Sync for Queue<'_> {} +unsafe impl Send for Queue<'_> {} + pub struct Available<'a> { addr: usize, size: usize, @@ -216,20 +237,24 @@ impl<'a> Available<'a> { /// ## Panics /// This function panics if the index is out of bounds. - pub fn get_element_at(&mut self, index: usize) -> &mut AvailableRingElement { + pub fn get_element_at(&self, index: usize) -> &AvailableRingElement { // SAFETY: We have exclusive access to the elements and the number of elements // is correct; same as the queue size. unsafe { self.ring .elements - .as_mut_slice(self.queue_size) - .get_mut(index % 256) + .as_slice(self.queue_size) + .get(index % 256) .expect("virtio-core::available: index out of bounds") } } - pub fn set_head_idx(&mut self, index: u16) { - self.ring.head_index.set(index); + pub fn head_index(&self) -> u16 { + self.ring.head_index.load(Ordering::SeqCst) + } + + pub fn set_head_idx(&self, index: u16) { + self.ring.head_index.store(index, Ordering::SeqCst); } pub fn phys_addr(&self) -> usize { @@ -278,7 +303,21 @@ impl<'a> Used<'a> { /// ## Panics /// This function panics if the index is out of bounds. - pub fn get_element_at(&mut self, index: usize) -> &mut UsedRingElement { + pub fn get_element_at(&self, index: usize) -> &UsedRingElement { + // SAFETY: We have exclusive access to the elements and the number of elements + // is correct; same as the queue size. + unsafe { + self.ring + .elements + .as_slice(self.queue_size) + .get(index % 256) + .expect("virtio-core::used: index out of bounds") + } + } + + /// ## Panics + /// This function panics if the index is out of bounds. + pub fn get_mut_element_at(&mut self, index: usize) -> &mut UsedRingElement { // SAFETY: We have exclusive access to the elements and the number of elements // is correct; same as the queue size. unsafe { @@ -320,27 +359,19 @@ pub struct StandardTransport<'a> { notify_mul: u32, queue_index: AtomicU16, - sref: Weak, } impl<'a> StandardTransport<'a> { pub fn new(common: &'a mut CommonCfg, notify: *const u8, notify_mul: u32) -> Arc { - Arc::new_cyclic(|sref| Self { + Arc::new(Self { common: Mutex::new(common), notify, notify_mul, queue_index: AtomicU16::new(0), - sref: sref.clone(), }) } - pub fn sref(&self) -> Arc { - // UNWRAP: The constructor ensures that we are wrapped in our own `Arc`. So this - // unwrap is going to be unreachable. - self.sref.upgrade().unwrap() - } - pub fn check_device_feature(&self, feature: u32) -> bool { let mut common = self.common.lock().unwrap(); @@ -384,7 +415,7 @@ impl<'a> StandardTransport<'a> { .set(status | DeviceStatusFlags::DRIVER_OK); } - pub fn setup_queue(&self, vector: u16) -> Result>, Error> { + pub fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result>, Error> { let mut common = self.common.lock().unwrap(); let queue_index = self.queue_index.fetch_add(1, Ordering::SeqCst); @@ -398,14 +429,17 @@ impl<'a> StandardTransport<'a> { Dma::<[Descriptor]>::zeroed_unsized(queue_size).map_err(Error::SyscallError)? }; - let mut avail = Available::new(queue_size)?; + let avail = Available::new(queue_size)?; let mut used = Used::new(queue_size)?; for i in 0..queue_size { // XXX: Fill the `table_index` of the elements with `T::MAX` to help with // debugging since qemu reports them as illegal values. - avail.get_element_at(i).table_index.set(u16::MAX); - used.get_element_at(i).table_index.set(u32::MAX); + avail + .get_element_at(i) + .table_index + .store(u16::MAX, Ordering::Relaxed); + used.get_mut_element_at(i).table_index.set(u32::MAX); } common.queue_desc.set(descriptor.physical() as u64); @@ -421,16 +455,33 @@ impl<'a> StandardTransport<'a> { let notification_bell = unsafe { let offset = self.notify_mul * queue_notify_idx as u32; - &mut *(self.notify.add(offset as usize) as *mut VolatileCell) + &mut *(self.notify.add(offset as usize) as *mut AtomicU16) }; log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})"); - Ok(Queue::new( - descriptor, - avail, - used, - notification_bell, - queue_index, - )) + + let queue = Queue::new(descriptor, avail, used, notification_bell, queue_index); + + let queue_copy = queue.clone(); + let irq_fd = irq_handle.as_raw_fd(); + + std::thread::spawn(move || { + let mut event_queue = EventQueue::::new().unwrap(); + + event_queue + .add(irq_fd, move |_| -> Result, std::io::Error> { + for (_, task) in queue_copy.waker.lock().unwrap().iter() { + task.wake_by_ref(); + } + Ok(None) + }) + .unwrap(); + + loop { + event_queue.run().unwrap(); + } + }); + + Ok(queue) } } diff --git a/virtio-netd/Cargo.toml b/virtio-netd/Cargo.toml index 8a905d18e8..f4a116f10c 100644 --- a/virtio-netd/Cargo.toml +++ b/virtio-netd/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] log = "0.4" static_assertions = "1.1.0" +futures = { version = "0.3.28", features = ["executor"] } virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } diff --git a/virtio-netd/src/main.rs b/virtio-netd/src/main.rs index 172034c2e2..e6fb3ee842 100644 --- a/virtio-netd/src/main.rs +++ b/virtio-netd/src/main.rs @@ -73,11 +73,11 @@ fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { // TODO(andypython): Should we use the same IRQ vector for both? let rx_queue = device .transport - .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR)?; + .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR, &device.irq_handle)?; let tx_queue = device .transport - .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR)?; + .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR, &device.irq_handle)?; device.transport.run_device(); diff --git a/virtio-netd/src/scheme.rs b/virtio-netd/src/scheme.rs index c3eb8fe4a7..251a501ce0 100644 --- a/virtio-netd/src/scheme.rs +++ b/virtio-netd/src/scheme.rs @@ -35,7 +35,7 @@ impl<'a> NetworkScheme<'a> { .chain(Buffer::new_unsized(&rx_buffers[i]).flags(DescriptorFlags::WRITE_ONLY)) .build(); - rx.send(chain); + let _ = rx.send(chain); } Self { @@ -54,15 +54,13 @@ impl<'a> NetworkScheme<'a> { fn try_recv(&mut self, target: &mut [u8]) -> usize { let header_size = core::mem::size_of::(); - let mut queue = self.rx.inner.lock().unwrap(); - - if self.recv_head == queue.used.head_index() { + if self.recv_head == self.rx.used.head_index() { // The read would block. return 0; } - let idx = queue.used.head_index() as usize; - let element = queue.used.get_element_at(idx - 1); + let idx = self.rx.used.head_index() as usize; + let element = self.rx.used.get_element_at(idx - 1); let descriptor_idx = element.table_index.get(); let payload_size = element.written.get() as usize - header_size; @@ -77,7 +75,7 @@ impl<'a> NetworkScheme<'a> { // Copy the packet into the buffer. target[..payload_size].copy_from_slice(&packet); - self.recv_head = queue.used.head_index(); + self.recv_head = self.rx.used.head_index(); payload_size } } @@ -123,7 +121,6 @@ impl<'a> SchemeBlockMut for NetworkScheme<'a> { let header = unsafe { Dma::::zeroed()?.assume_init() }; - // TODO: Does the payload actually need to be a DMA buffer? let mut payload = unsafe { Dma::<[u8]>::zeroed_unsized(buffer.len())? }; payload.copy_from_slice(buffer); @@ -132,9 +129,7 @@ impl<'a> SchemeBlockMut for NetworkScheme<'a> { .chain(Buffer::new_unsized(&payload)) .build(); - self.tx.send(chain); - core::mem::forget(payload); - + futures::executor::block_on(self.tx.send(chain)); Ok(Some(buffer.len())) } @@ -147,7 +142,10 @@ impl<'a> SchemeBlockMut for NetworkScheme<'a> { id: usize, _flags: syscall::EventFlags, ) -> syscall::Result> { - let _flags = self.handles.get(&id).ok_or(SysError::new(EBADF))?; + if self.handles.get(&id).is_none() { + return Err(SysError::new(EBADF)); + } + Ok(Some(syscall::EventFlags::empty())) } From a720cf6f4491a7e5d9c8ba73c307450dffdfb121 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Thu, 29 Jun 2023 16:36:02 +1000 Subject: [PATCH 0636/1301] virtio-core::probe: make sure the addr is aligned sys_physmap() requires the address to be page aligned. This fixes the panic inside the `virtio-gpu` driver. Signed-off-by: Anhad Singh --- virtio-core/src/probe.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index a68ed54541..f627de9e68 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -12,7 +12,7 @@ use syscall::{Io, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use crate::spec::*; use crate::transport::{Error, StandardTransport}; -use crate::utils::VolatileCell; +use crate::utils::{VolatileCell, align_down}; pub struct Device<'a> { pub transport: Arc>, @@ -178,11 +178,21 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result }; let address = unsafe { - syscall::physmap( - addr + capability.offset as usize, - capability.length as usize, + let addr = addr + capability.offset as usize; + + // XXX: physmap() requires the address to be page aligned. + let aligned_addr = align_down(addr); + let offset = addr - aligned_addr; + + let size = offset + capability.length as usize; + + let addr = syscall::physmap( + aligned_addr, + size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE, - )? + )?; + + addr + offset }; match capability.cfg_type { From 4bbda21f0bcf6c024516dffaccf2d1ad12c23e90 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Thu, 29 Jun 2023 16:37:59 +1000 Subject: [PATCH 0637/1301] drivers: start building `virtio-gpu` Signed-off-by: Anhad Singh --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + README.md | 2 +- initfs.toml | 9 +++++++++ virtio-core/src/utils.rs | 4 ++++ virtio-gpud/Cargo.toml | 13 +++++++++++++ virtio-gpud/src/main.rs | 28 ++++++++++++++++++++++++++++ 7 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 virtio-gpud/Cargo.toml create mode 100644 virtio-gpud/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index cc75943e6c..69722a682a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1948,6 +1948,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "virtio-gpud" +version = "0.1.0" +dependencies = [ + "log", + "pcid", + "redox-daemon", + "virtio-core", +] + [[package]] name = "virtio-netd" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 717d492594..2ccefbc9b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ members = [ "virtio-blkd", "virtio-netd", + "virtio-gpud", "virtio-core", ] diff --git a/README.md b/README.md index 0262ed8d1b..72e8c1788d 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ These are the currently implemented devices/hardware interfaces. - usbctl - USB control (incomplete). - usbhidd - USB HID (incomplete). - usbscsid - USB SCSI (incomplete). -- virtio-* - VirtIO (incomplete) (`virtio-blk`, `virtio-net`). +- virtio-* - VirtIO (incomplete) (`virtio-blk`, `virtio-net`, `virtio-gpu`). ## Contributing to Drivers diff --git a/initfs.toml b/initfs.toml index 067001a19d..631768911d 100644 --- a/initfs.toml +++ b/initfs.toml @@ -41,3 +41,12 @@ vendor = 6900 device = 4096 command = ["virtio-netd"] use_channel = true + +[[drivers]] +name = "virtio-gpu" +class = 3 +subclass = 0 +vendor = 6900 +device = 4176 +command = ["virtio-gpud"] +use_channel = true diff --git a/virtio-core/src/utils.rs b/virtio-core/src/utils.rs index d05b74c41e..85d39e54af 100644 --- a/virtio-core/src/utils.rs +++ b/virtio-core/src/utils.rs @@ -64,6 +64,10 @@ pub const fn align(val: usize, align: usize) -> usize { (val + align) & !align } +pub const fn align_down(addr: usize) -> usize { + addr & !(syscall::PAGE_SIZE - 1) +} + #[cfg(target_os = "redox")] pub fn setup_logging(level: log::LevelFilter, name: &str) { use redox_log::{OutputBuilder, RedoxLogger}; diff --git a/virtio-gpud/Cargo.toml b/virtio-gpud/Cargo.toml new file mode 100644 index 0000000000..17fdf4384a --- /dev/null +++ b/virtio-gpud/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "virtio-gpud" +version = "0.1.0" +edition = "2021" +authors = ["Anhad Singh "] + +[dependencies] +log = "0.4" + +virtio-core = { path = "../virtio-core" } +pcid = { path = "../pcid" } + +redox-daemon = "0.1" diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs new file mode 100644 index 0000000000..140c73ac2c --- /dev/null +++ b/virtio-gpud/src/main.rs @@ -0,0 +1,28 @@ +use pcid_interface::PcidServerHandle; +use virtio_core::transport::Error; + +fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { + let mut pcid_handle = PcidServerHandle::connect_default()?; + + // Double check that we have the right device. + // + // 0x1050 - virtio-gpu + let pci_config = pcid_handle.fetch_config()?; + + assert_eq!(pci_config.func.devid, 0x1050); + log::info!("virtio-gpu: initiating startup sequence :^)"); + + let device = virtio_core::probe_device(&mut pcid_handle)?; + loop {} +} + +fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { + deamon(redox_daemon).unwrap(); + unreachable!(); +} + +pub fn main() { + #[cfg(target_os = "redox")] + virtio_core::utils::setup_logging(log::LevelFilter::Trace, "virtio-gpud"); + redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); +} From 7cc2f4eff7bb94d457e215a8b028d69d9e29cb5e Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 3 Jul 2023 17:12:59 +1000 Subject: [PATCH 0638/1301] virtio-gpu: start working on the scheme Signed-off-by: Anhad Singh --- Cargo.lock | 16 ++- bgad/src/main.rs | 2 +- fmt.sh | 4 + ps2d/src/main.rs | 2 +- usbhidd/src/main.rs | 2 +- vboxd/src/main.rs | 2 +- vesad/src/main.rs | 2 +- virtio-core/src/probe.rs | 8 +- virtio-core/src/transport.rs | 13 +- virtio-core/src/utils.rs | 13 +- virtio-gpud/Cargo.toml | 5 + virtio-gpud/patches/00-init.patch | 45 +++++++ virtio-gpud/patches/01-orbital.patch | 13 ++ virtio-gpud/src/main.rs | 184 ++++++++++++++++++++++++++- virtio-gpud/src/scheme.rs | 108 ++++++++++++++++ 15 files changed, 394 insertions(+), 25 deletions(-) create mode 100644 virtio-gpud/patches/00-init.patch create mode 100644 virtio-gpud/patches/01-orbital.patch create mode 100644 virtio-gpud/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index 69722a682a..fb801dd351 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -773,12 +773,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "matches" @@ -1131,9 +1128,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] @@ -1952,9 +1949,14 @@ dependencies = [ name = "virtio-gpud" version = "0.1.0" dependencies = [ + "anyhow", + "futures", "log", + "orbclient", "pcid", "redox-daemon", + "redox_syscall 0.3.5", + "static_assertions", "virtio-core", ] diff --git a/bgad/src/main.rs b/bgad/src/main.rs index 2d5387aeae..781e68ae8f 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -38,7 +38,7 @@ fn main() { let mut scheme = BgaScheme { bga: bga, - display: File::open("display:input").ok() + display: File::open("display/vesa:input").ok() }; scheme.update_size(); diff --git a/fmt.sh b/fmt.sh index b0b137080b..450e518f26 100755 --- a/fmt.sh +++ b/fmt.sh @@ -11,3 +11,7 @@ popd pushd virtio-blkd cargo fmt popd + +pushd virtio-gpud +cargo fmt +popd diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 5a845e415f..96df72a2b0 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -45,7 +45,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let input = OpenOptions::new() .write(true) - .open("display:input") + .open("display/vesa:input") .expect("ps2d: failed to open display:input"); let mut event_file = OpenOptions::new() diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index df3f6d60ca..bfefd2f798 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -382,7 +382,7 @@ fn main() { let report_ty = ReportTy::Input; let report_id = 0; - let mut display = File::open("display:input").expect("Failed to open orbital input socket"); + let mut display = File::open("display/vesa:input").expect("Failed to open orbital input socket"); //TODO: get dynamically let mut display_width = 0; diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 4ad50c5598..c42c8da424 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -206,7 +206,7 @@ fn main() { let mut width = 0; let mut height = 0; - let mut display_opt = File::open("display:input").ok(); + let mut display_opt = File::open("display/vesa:input").ok(); if let Some(ref display) = display_opt { let mut buf: [u8; 4096] = [0; 4096]; if let Ok(count) = syscall::fpath(display.as_raw_fd() as usize, &mut buf) { diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 10ae4df44a..3d7cf98f4c 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -90,7 +90,7 @@ fn main() { redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers, &spec)).expect("failed to create daemon"); } fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[bool]) -> ! { - let mut socket = File::create(":display").expect("vesad: failed to create display scheme"); + let mut socket = File::create(":display/vesa").expect("vesad: failed to create display scheme"); let mut scheme = DisplayScheme::new(framebuffers, &spec); diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index f627de9e68..58e9466659 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -12,7 +12,7 @@ use syscall::{Io, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use crate::spec::*; use crate::transport::{Error, StandardTransport}; -use crate::utils::{VolatileCell, align_down}; +use crate::utils::{align_down, VolatileCell}; pub struct Device<'a> { pub transport: Arc>, @@ -186,11 +186,7 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result let size = offset + capability.length as usize; - let addr = syscall::physmap( - aligned_addr, - size, - PHYSMAP_WRITE | PHYSMAP_NO_CACHE, - )?; + let addr = syscall::physmap(aligned_addr, size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE)?; addr + offset }; diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index ae94c70316..5bcc693f59 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -86,6 +86,12 @@ impl<'a> Future for PendingRequest<'a> { .insert(self.first_descriptor, cx.waker().clone()); let used_head = self.queue.used.head_index(); + + if used_head == self.queue.used_head.load(Ordering::SeqCst) { + // No new requests have been completed. + return Poll::Pending; + } + let used_element = self.queue.used.get_element_at((used_head - 1) as usize); let written = used_element.written.get(); @@ -109,6 +115,8 @@ impl<'a> Future for PendingRequest<'a> { .lock() .unwrap() .remove(&self.first_descriptor); + + self.queue.used_head.store(used_head, Ordering::SeqCst); return Poll::Ready(written); } else { return Poll::Pending; @@ -122,6 +130,7 @@ pub struct Queue<'a> { pub used: Used<'a>, pub descriptor: Dma<[Descriptor]>, pub available: Available<'a>, + pub used_head: AtomicU16, notification_bell: &'a mut AtomicU16, descriptor_stack: crossbeam_queue::SegQueue, @@ -148,6 +157,7 @@ impl<'a> Queue<'a> { waker: Mutex::new(std::collections::HashMap::new()), queue_index, descriptor_stack, + used_head: AtomicU16::new(0), sref: sref.clone(), }) } @@ -190,8 +200,6 @@ impl<'a> Queue<'a> { self.notification_bell .store(self.queue_index, Ordering::SeqCst); - assert_eq!(self.used.flags(), 0); - PendingRequest { queue: self.sref.upgrade().unwrap(), first_descriptor: first_descriptor as u32, @@ -470,6 +478,7 @@ impl<'a> StandardTransport<'a> { event_queue .add(irq_fd, move |_| -> Result, std::io::Error> { + // Wake up the tasks waiting on the queue. for (_, task) in queue_copy.waker.lock().unwrap().iter() { task.wake_by_ref(); } diff --git a/virtio-core/src/utils.rs b/virtio-core/src/utils.rs index 85d39e54af..6f71dac4ea 100644 --- a/virtio-core/src/utils.rs +++ b/virtio-core/src/utils.rs @@ -1,7 +1,7 @@ use core::cell::UnsafeCell; +use core::fmt::Debug; use core::marker::PhantomData; -#[derive(Debug)] #[repr(C)] pub struct VolatileCell { value: UnsafeCell, @@ -28,6 +28,17 @@ impl VolatileCell { } } +impl Debug for VolatileCell +where + T: Debug + Copy, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("VolatileCell") + .field("value", &self.get()) + .finish() + } +} + unsafe impl Sync for VolatileCell {} #[repr(C)] diff --git a/virtio-gpud/Cargo.toml b/virtio-gpud/Cargo.toml index 17fdf4384a..7a09708fc4 100644 --- a/virtio-gpud/Cargo.toml +++ b/virtio-gpud/Cargo.toml @@ -6,8 +6,13 @@ authors = ["Anhad Singh "] [dependencies] log = "0.4" +static_assertions = "1.1.0" +futures = { version = "0.3.28", features = ["executor"] } +anyhow = "1.0.71" virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } redox-daemon = "0.1" +redox_syscall = "0.3" +orbclient = "0.3.27" diff --git a/virtio-gpud/patches/00-init.patch b/virtio-gpud/patches/00-init.patch new file mode 100644 index 0000000000..dc20be1df6 --- /dev/null +++ b/virtio-gpud/patches/00-init.patch @@ -0,0 +1,45 @@ +diff --git a/src/main.rs b/src/main.rs +index a99488a..ec97fdd 100644 +--- a/src/main.rs ++++ b/src/main.rs +@@ -78,6 +78,40 @@ pub fn run(file: &Path) -> Result<()> { + println!("init: failed to run: no argument"); + }, + "run.d" => if let Some(new_dir) = args.next() { ++ // On startup, the VESA display driver is started which basically makes use of the framebuffer ++ // provided by the firmware. The GPU device are latter started by `pcid` (such as `virtio-gpu`). ++ let mut devices = vec![]; ++ let schemes = std::fs::read_dir(":").unwrap(); ++ ++ for entry in schemes { ++ let path = entry.unwrap().path(); ++ let path_str = path ++ .into_os_string() ++ .into_string() ++ .expect("init: failed to convert path to string"); ++ ++ if path_str.contains("display") { ++ println!("init: found display scheme {}", path_str); ++ devices.push(path_str); ++ } ++ } ++ ++ let device = devices.iter().filter(|d| !d.contains("vesa")).collect::>(); ++ let device = if device.is_empty() { ++ // No GPU available, fallback to VESA display which *should* always be accessible via `display/vesa:`. ++ "vesa" ++ } else { ++ // Parts: ++ // :/display/virtio-gpu ++ // ++ // 1st: ":" ++ // 2nd: "display" ++ // 3rd: "virtio-gpu" (the one we want!) ++ device[0].split("/").nth(2).unwrap() ++ }; ++ ++ std::env::set_var("DISPLAY", &format!("display/{}:3/activate", device)); ++ + let mut entries = vec![]; + match read_dir(&new_dir) { + Ok(list) => for entry_res in list { diff --git a/virtio-gpud/patches/01-orbital.patch b/virtio-gpud/patches/01-orbital.patch new file mode 100644 index 0000000000..493ec66735 --- /dev/null +++ b/virtio-gpud/patches/01-orbital.patch @@ -0,0 +1,13 @@ +diff --git a/src/main.rs b/src/main.rs +index 1cdf9cf..3859ac0 100644 +--- a/src/main.rs ++++ b/src/main.rs +@@ -63,7 +63,7 @@ fn orbital(daemon: Daemon) -> Result<(), String> { + .enable(); + + let mut args = env::args().skip(1); +- let display_path = args.next().ok_or("no display argument")?; ++ let display_path = env::var("DISPLAY").unwrap(); + let login_cmd = args.next().ok_or("no login manager argument")?; + + core::fix_env(&display_path).map_err(|_| "error setting env vars")?; diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index 140c73ac2c..b989fa77d7 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -1,7 +1,154 @@ -use pcid_interface::PcidServerHandle; -use virtio_core::transport::Error; +//! `virtio-gpu` is a virtio based graphics adapter. It can operate in 2D mode and in 3D mode. +//! +//! XXX: 3D mode will offload rendering ops to the host gpu and therefore requires a GPU with 3D support +//! on the host machine. -fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { +#![feature(async_closure)] + +use std::fs::File; +use std::io::{Read, Write}; + +use pcid_interface::PcidServerHandle; + +use syscall::{Packet, SchemeMut}; +use virtio_core::utils::VolatileCell; +use virtio_core::MSIX_PRIMARY_VECTOR; + +mod scheme; + +// const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0; +const VIRTIO_GPU_MAX_SCANOUTS: usize = 16; + +#[repr(C)] +pub struct GpuConfig { + /// Signals pending events to the driver. + pub events_read: VolatileCell, // read-only + /// Clears pending events in the device (write-to-clear). + pub events_clear: VolatileCell, // write-only + + pub min_scanouts: VolatileCell, + pub num_capsets: VolatileCell, +} + +#[derive(Debug, Copy, Clone, PartialEq)] +#[repr(u32)] +pub enum CommandTy { + Undefined = 0, + + // 2D commands + GetDisplayInfo = 0x0100, + ResourceCreate2d, + ResourceUnref, + SetScanout, + ResourceFlush, + TransferToHost2d, + ResourceAttachBacking, + ResourceDetachBacking, + GetCapsetInfo, + GetCapset, + GetEdid, + ResourceAssignUuid, + ResourceCreateBlob, + SetScanoutBlob, + + // 3D commands + CtxCreate = 0x0200, + CtxDestroy, + CtxAttachResource, + CtxDetachResource, + ResourceCreate3d, + TransferToHost3d, + TransferFromHost3d, + Submit3d, + ResourceMapBlob, + ResourceUnmapBlob, + + // cursor commands + UpdateCursor = 0x0300, + MoveCursor, + + // success responses + RespOkNodata = 0x1100, + RespOkDisplayInfo, + RespOkCapsetInfo, + RespOkCapset, + RespOkEdid, + RespOkResourceUuid, + RespOkMapInfo, + + // error responses + RespErrUnspec = 0x1200, + RespErrOutOfMemory, + RespErrInvalidScanoutId, + RespErrInvalidResourceId, + RespErrInvalidContextId, + RespErrInvalidParameter, +} + +static_assertions::const_assert_eq!(core::mem::size_of::(), 4); + +#[derive(Debug)] +#[repr(C)] +pub struct ControlHeader { + pub ty: VolatileCell, + pub flags: VolatileCell, + pub fence_id: VolatileCell, + pub ctx_id: VolatileCell, + pub ring_index: VolatileCell, + padding: [u8; 3], +} + +impl Default for ControlHeader { + fn default() -> Self { + Self { + ty: VolatileCell::new(CommandTy::Undefined), + flags: VolatileCell::new(0), + fence_id: VolatileCell::new(0), + ctx_id: VolatileCell::new(0), + ring_index: VolatileCell::new(0), + padding: [0; 3], + } + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct GpuRect { + pub x: VolatileCell, + pub y: VolatileCell, + pub width: VolatileCell, + pub height: VolatileCell, +} + +#[derive(Debug)] +#[repr(C)] +pub struct DisplayInfo { + pub rect: GpuRect, + pub enabled: VolatileCell, + pub flags: VolatileCell, +} + +#[derive(Debug)] +#[repr(C)] +pub struct GetDisplayInfo { + pub header: ControlHeader, + pub display_info: [DisplayInfo; VIRTIO_GPU_MAX_SCANOUTS], +} + +impl Default for GetDisplayInfo { + fn default() -> Self { + Self { + header: ControlHeader { + ty: VolatileCell::new(CommandTy::GetDisplayInfo), + ..Default::default() + }, + + display_info: unsafe { core::mem::zeroed() }, + } + } +} + +fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut pcid_handle = PcidServerHandle::connect_default()?; // Double check that we have the right device. @@ -13,7 +160,36 @@ fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { log::info!("virtio-gpu: initiating startup sequence :^)"); let device = virtio_core::probe_device(&mut pcid_handle)?; - loop {} + + // Negotiate features. + device.transport.finalize_features(); + + // Queue for sending control commands. + let control_queue = device + .transport + .setup_queue(MSIX_PRIMARY_VECTOR, &device.irq_handle)?; + + // Queue for sending cursor updates. + let cursor_queue = device + .transport + .setup_queue(MSIX_PRIMARY_VECTOR, &device.irq_handle)?; + + device.transport.run_device(); + deamon.ready().unwrap(); + + let mut socket_file = File::create(":display/virtio-gpu")?; + let mut scheme = scheme::Display::new(control_queue, cursor_queue); + + loop { + let mut packet = Packet::default(); + socket_file + .read(&mut packet) + .expect("virtio-gpud: failed to read disk scheme"); + scheme.handle(&mut packet); + socket_file + .write(&packet) + .expect("virtio-gpud: failed to read disk scheme"); + } } fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs new file mode 100644 index 0000000000..7a95d4c4ee --- /dev/null +++ b/virtio-gpud/src/scheme.rs @@ -0,0 +1,108 @@ +use std::{ + collections::BTreeMap, + sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, + }, +}; + +use orbclient::Event; +use syscall::{Dma, Error as SysError, SchemeMut, EINVAL, EPERM}; +use virtio_core::{ + spec::{Buffer, ChainBuilder, DescriptorFlags}, + transport::{Error, Queue}, + utils::VolatileCell, +}; + +use crate::{CommandTy, ControlHeader, GetDisplayInfo}; + +pub enum Handle { + Input(InputHandle), + Screen(ScreenHandle), +} + +pub struct InputHandle {} +pub struct ScreenHandle { + id: usize, +} + +pub struct Display<'a> { + control_queue: Arc>, + cursor_queue: Arc>, + + display_id: usize, + handles: BTreeMap, + next_id: AtomicUsize, +} + +impl<'a> Display<'a> { + pub fn new(control_queue: Arc>, cursor_queue: Arc>) -> Self { + Self { + control_queue, + cursor_queue, + + display_id: 0, + handles: BTreeMap::new(), + next_id: AtomicUsize::new(0), + } + } + + async fn get_display_info(&self) -> Result, Error> { + let header = Dma::new(ControlHeader { + ty: VolatileCell::new(CommandTy::GetDisplayInfo), + ..Default::default() + })?; + + let response = Dma::new(GetDisplayInfo::default())?; + let command = ChainBuilder::new() + .chain(Buffer::new(&header)) + .chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.control_queue.send(command).await; + assert!(response.header.ty.get() == CommandTy::RespOkDisplayInfo); + + Ok(response) + } +} + +impl<'a> SchemeMut for Display<'a> { + fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> syscall::Result { + if path == "input" { + if uid != 0 { + return Err(SysError::new(EPERM)); + } + + let fd = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.insert(fd, Handle::Input(InputHandle {})); + + Ok(fd) + } else { + let mut parts = path.split('/'); + let screen = parts.next().unwrap_or("").split('.'); + dbg!(screen); + + todo!(); + } + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { + todo!() + } + + fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + + match handle { + Handle::Input(_) => todo!(), + Handle::Screen(_) => { + let size = buf.len() / core::mem::size_of::(); + let events = + unsafe { core::slice::from_raw_parts(buf.as_ptr().cast::(), size) }; + + dbg!(events); + todo!() + } + } + } +} From c0950d06867f4451a6fd59153049303857ff57bf Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 4 Jul 2023 13:17:58 +1000 Subject: [PATCH 0639/1301] virtio-gpu: start working on the scheme Signed-off-by: Anhad Singh --- Cargo.lock | 7 ++ virtio-gpud/Cargo.toml | 1 + virtio-gpud/src/main.rs | 190 +++++++++++++++++++++++++++++++++++++- virtio-gpud/src/scheme.rs | 165 +++++++++++++++++++++++++++++---- 4 files changed, 344 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb801dd351..afb50c966b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1011,6 +1011,12 @@ dependencies = [ "uuid", ] +[[package]] +name = "paste" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" + [[package]] name = "paw" version = "1.0.0" @@ -1953,6 +1959,7 @@ dependencies = [ "futures", "log", "orbclient", + "paste", "pcid", "redox-daemon", "redox_syscall 0.3.5", diff --git a/virtio-gpud/Cargo.toml b/virtio-gpud/Cargo.toml index 7a09708fc4..02249c294c 100644 --- a/virtio-gpud/Cargo.toml +++ b/virtio-gpud/Cargo.toml @@ -9,6 +9,7 @@ log = "0.4" static_assertions = "1.1.0" futures = { version = "0.3.28", features = ["executor"] } anyhow = "1.0.71" +paste = "1.0.13" virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index b989fa77d7..1527925b04 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -3,7 +3,7 @@ //! XXX: 3D mode will offload rendering ops to the host gpu and therefore requires a GPU with 3D support //! on the host machine. -#![feature(async_closure)] +#![feature(int_roundings)] use std::fs::File; use std::io::{Read, Write}; @@ -19,6 +19,28 @@ mod scheme; // const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0; const VIRTIO_GPU_MAX_SCANOUTS: usize = 16; +macro_rules! make_getter_setter { + ($($field:ident: $return_ty:ty),*) => { + $( + pub fn $field(&self) -> $return_ty { + self.$field.get() + } + + paste::item! { + pub fn [](&mut self, value: $return_ty) { + self.$field.set(value) + } + } + )* + }; + + (@$field:ident: $return_ty:ty) => { + pub fn $field(&mut self, value: $return_ty) { + self.$field.set(value) + } + }; +} + #[repr(C)] pub struct GpuConfig { /// Signals pending events to the driver. @@ -120,6 +142,28 @@ pub struct GpuRect { pub height: VolatileCell, } +impl GpuRect { + pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self { + Self { + x: VolatileCell::new(x), + y: VolatileCell::new(y), + width: VolatileCell::new(width), + height: VolatileCell::new(height), + } + } + + #[inline] + pub fn width(&self) -> u32 { + self.width.get() + } + + #[inline] + pub fn height(&self) -> u32 { + self.height.get() + } +} + + #[derive(Debug)] #[repr(C)] pub struct DisplayInfo { @@ -148,6 +192,150 @@ impl Default for GetDisplayInfo { } } +#[derive(Debug, Copy, Clone)] +#[repr(u32)] +pub enum ResourceFormat { + Unknown = 0, + + Bgrx = 2, + Xrgb = 4, +} + +#[derive(Debug)] +#[repr(C)] +pub struct ResourceCreate2d { + pub header: ControlHeader, + + resource_id: VolatileCell, + format: VolatileCell, + width: VolatileCell, + height: VolatileCell, +} + +impl ResourceCreate2d { + make_getter_setter!(resource_id: u32, format: ResourceFormat, width: u32, height: u32); +} + +impl Default for ResourceCreate2d { + fn default() -> Self { + Self { + header: ControlHeader { + ty: VolatileCell::new(CommandTy::ResourceCreate2d), + ..Default::default() + }, + + resource_id: VolatileCell::new(0), + format: VolatileCell::new(ResourceFormat::Unknown), + width: VolatileCell::new(0), + height: VolatileCell::new(0), + } + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct MemEntry { + pub address: u64, + pub length: u32, + pub padding: u32 +} + +#[derive(Debug)] +#[repr(C)] +pub struct AttachBacking { + pub header: ControlHeader, + pub resource_id: u32, + pub num_entries: u32 +} + +impl AttachBacking { + pub fn new(resource_id: u32, num_entries: u32) -> Self { + Self { + header: ControlHeader { + ty: VolatileCell::new(CommandTy::ResourceAttachBacking), + ..Default::default() + }, + resource_id, + num_entries + } + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct ResourceFlush { + pub header: ControlHeader, + pub rect: GpuRect, + pub resource_id: u32, + pub padding: u32 +} + +impl ResourceFlush { + pub fn new(resource_id: u32, rect: GpuRect) -> Self { + Self { + header: ControlHeader { + ty: VolatileCell::new(CommandTy::ResourceFlush), + ..Default::default() + }, + + rect, + resource_id, + padding: 0 + } + } +} + +#[repr(C)] +#[derive(Debug)] +pub struct SetScanout { + pub header: ControlHeader, + pub rect: GpuRect, + pub scanout_id: u32, + pub resource_id: u32, +} + +impl SetScanout { + pub fn new(scanout_id: u32, resource_id: u32, rect: GpuRect) -> Self { + Self { + header: ControlHeader { + ty: VolatileCell::new(CommandTy::SetScanout), + ..Default::default() + }, + + rect, + scanout_id, + resource_id, + } + } +} + + +#[derive(Debug)] +#[repr(C)] +pub struct XferToHost2d { + pub header: ControlHeader, + pub rect: GpuRect, + pub offset: u64, + pub resource_id: u32, + pub padding: u32, +} + +impl XferToHost2d { + pub fn new(resource_id: u32, rect: GpuRect) -> Self { + Self { + header: ControlHeader { + ty: VolatileCell::new(CommandTy::TransferToHost2d), + ..Default::default() + }, + + rect, + resource_id, + offset: 0, + padding: 0, + } + } +} + fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut pcid_handle = PcidServerHandle::connect_default()?; diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 7a95d4c4ee..decd2b40f5 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -14,16 +14,12 @@ use virtio_core::{ utils::VolatileCell, }; -use crate::{CommandTy, ControlHeader, GetDisplayInfo}; +use crate::*; pub enum Handle { - Input(InputHandle), - Screen(ScreenHandle), -} - -pub struct InputHandle {} -pub struct ScreenHandle { - id: usize, + Screen { + id: usize + }, } pub struct Display<'a> { @@ -64,29 +60,163 @@ impl<'a> Display<'a> { Ok(response) } + + async fn get_resolution(&self) -> Result<(u32, u32), Error> { + let display_info = self.get_display_info().await?; + + let width = display_info.display_info[self.display_id].rect.width(); + let height = display_info.display_info[self.display_id].rect.height(); + + Ok((width, height)) + } + + async fn get_fpath(&mut self, buffer: &mut [u8]) -> syscall::Result { + let display_info = self.get_display_info().await.unwrap(); + + let width = display_info.display_info[self.display_id].rect.width(); + let height = display_info.display_info[self.display_id].rect.height(); + + let path = format!("display:0.0/{}/{}", width, height); + + // Copy the path into the target buffer. + buffer[..path.len()].copy_from_slice(path.as_bytes()); + Ok(path.len()) + } + + async fn send_request(&mut self, request: Dma) -> Result, Error> { + let header = Dma::new(ControlHeader::default())?; + let command = ChainBuilder::new() + .chain(Buffer::new(&request)) + .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.control_queue.send(command).await; + Ok(header) + } + + async fn flush_resource(&mut self, flush: ResourceFlush) -> Result<(), Error> { + let header = self.send_request(Dma::new(flush)?).await?; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + + Ok(()) + } + + async fn map_screen(&mut self, offset: usize, size: usize) -> Result { + // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. + let (width, height) = self.get_resolution().await?; + let mut request = Dma::new(ResourceCreate2d::default())?; + + request.set_width(width); + request.set_height(height); + request.set_format(ResourceFormat::Bgrx); + request.set_resource_id(1); // FIXME(andypython): dynamically allocate resource identifiers + + self.send_request(request).await?; + + // Allocate a framebuffer from guest ram, and attach it as backing storage to the + // resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. Scatter + // lists are supported, so the framebuffer doesn’t need to be contignous in guest + // physical memory. + let bpp = 32; + let fb_size = (width as usize * height as usize * bpp / 8).next_multiple_of(syscall::PAGE_SIZE); + let mut entries = unsafe { Dma::zeroed_unsized(fb_size / syscall::PAGE_SIZE) }?; + + for i in 0..fb_size / syscall::PAGE_SIZE { + let address = unsafe { syscall::physalloc(syscall::PAGE_SIZE) }? as u64; + let mapped = unsafe {syscall::physmap(address as usize, syscall::PAGE_SIZE, syscall::PhysmapFlags::PHYSMAP_WRITE)}?; + unsafe { + core::ptr::write_bytes(mapped as *mut u8, 69, syscall::PAGE_SIZE); + } + + let entry = MemEntry { + address, + length: syscall::PAGE_SIZE as u32, + padding: 0, + }; + + entries[i]= entry; + } + + let attach_request = Dma::new(AttachBacking::new(1, entries.len() as u32))?; + let header = Dma::new(ControlHeader::default())?; + let command = ChainBuilder::new() + .chain(Buffer::new(&attach_request)) + .chain(Buffer::new_unsized(&entries)) + .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.control_queue.send(command).await; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + + let rect = GpuRect::new(0,0,width,height); + let scanout_request = Dma::new(SetScanout::new(0, 1, rect))?; + let header = self.send_request(scanout_request).await?; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + + let rect = GpuRect::new(0,0,width,height); + let req = Dma::new(XferToHost2d::new(1, rect))?; + let header = self.send_request(req).await?; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + + let rect = GpuRect::new(0,0,width,height); + self.flush_resource(ResourceFlush::new(1, rect)).await?; + todo!() + } } impl<'a> SchemeMut for Display<'a> { - fn open(&mut self, path: &str, flags: usize, uid: u32, gid: u32) -> syscall::Result { + fn open(&mut self, path: &str, _flags: usize, uid: u32, _gid: u32) -> syscall::Result { if path == "input" { if uid != 0 { return Err(SysError::new(EPERM)); } - let fd = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.insert(fd, Handle::Input(InputHandle {})); - - Ok(fd) + unimplemented!("input is only supported via `display/vesa:input`") } else { let mut parts = path.split('/'); - let screen = parts.next().unwrap_or("").split('.'); - dbg!(screen); + let mut screen = parts.next().unwrap_or("").split('.'); - todo!(); + let vt_index = screen.next().unwrap_or("").parse::().unwrap_or(1); + let id = screen.next().unwrap_or("").parse::().unwrap_or(0); + + dbg!(&vt_index, &id); + + let fd = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.insert(fd, Handle::Screen { id }); + + Ok(fd) } } + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + let bytes_copied = match handle { + Handle::Screen { .. } => { + futures::executor::block_on(self.get_fpath(buf))? + } + }; + + Ok(bytes_copied) + } + + fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result { + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + + if let Handle::Screen { .. } = handle { + futures::executor::block_on(self.map_screen(map.offset, map.size)); + } + + unreachable!() + } + fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + let path = match handle { + Handle::Screen { .. } => { + futures::executor::block_on(self.get_fpath(buf))? + } + }; + todo!() } @@ -94,8 +224,7 @@ impl<'a> SchemeMut for Display<'a> { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; match handle { - Handle::Input(_) => todo!(), - Handle::Screen(_) => { + Handle::Screen { .. } => { let size = buf.len() / core::mem::size_of::(); let events = unsafe { core::slice::from_raw_parts(buf.as_ptr().cast::(), size) }; From caa435eae3a2ed9a21431f349e910efad5ae44f6 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 4 Jul 2023 13:21:41 +1000 Subject: [PATCH 0640/1301] virtio_gpud: able to get orbital running :^) Signed-off-by: Anhad Singh --- virtio-gpud/src/main.rs | 20 ++-- virtio-gpud/src/scheme.rs | 190 +++++++++++++++++++++++++------------- 2 files changed, 136 insertions(+), 74 deletions(-) diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index 1527925b04..15fd0509ea 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -163,7 +163,6 @@ impl GpuRect { } } - #[derive(Debug)] #[repr(C)] pub struct DisplayInfo { @@ -234,10 +233,10 @@ impl Default for ResourceCreate2d { #[derive(Debug)] #[repr(C)] -pub struct MemEntry { - pub address: u64, - pub length: u32, - pub padding: u32 +pub struct MemEntry { + pub address: u64, + pub length: u32, + pub padding: u32, } #[derive(Debug)] @@ -245,7 +244,7 @@ pub struct MemEntry { pub struct AttachBacking { pub header: ControlHeader, pub resource_id: u32, - pub num_entries: u32 + pub num_entries: u32, } impl AttachBacking { @@ -256,7 +255,7 @@ impl AttachBacking { ..Default::default() }, resource_id, - num_entries + num_entries, } } } @@ -267,7 +266,7 @@ pub struct ResourceFlush { pub header: ControlHeader, pub rect: GpuRect, pub resource_id: u32, - pub padding: u32 + pub padding: u32, } impl ResourceFlush { @@ -277,10 +276,10 @@ impl ResourceFlush { ty: VolatileCell::new(CommandTy::ResourceFlush), ..Default::default() }, - + rect, resource_id, - padding: 0 + padding: 0, } } } @@ -309,7 +308,6 @@ impl SetScanout { } } - #[derive(Debug)] #[repr(C)] pub struct XferToHost2d { diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index decd2b40f5..0dbec3326f 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -17,9 +17,7 @@ use virtio_core::{ use crate::*; pub enum Handle { - Screen { - id: usize - }, + Screen { id: usize }, } pub struct Display<'a> { @@ -29,6 +27,7 @@ pub struct Display<'a> { display_id: usize, handles: BTreeMap, next_id: AtomicUsize, + mapped: Option, } impl<'a> Display<'a> { @@ -40,6 +39,7 @@ impl<'a> Display<'a> { display_id: 0, handles: BTreeMap::new(), next_id: AtomicUsize::new(0), + mapped: None, } } @@ -76,7 +76,7 @@ impl<'a> Display<'a> { let width = display_info.display_info[self.display_id].rect.width(); let height = display_info.display_info[self.display_id].rect.height(); - let path = format!("display:0.0/{}/{}", width, height); + let path = format!("display:3.0/{}/{}", width, height); // Copy the path into the target buffer. buffer[..path.len()].copy_from_slice(path.as_bytes()); @@ -84,7 +84,7 @@ impl<'a> Display<'a> { } async fn send_request(&mut self, request: Dma) -> Result, Error> { - let header = Dma::new(ControlHeader::default())?; + let header = Dma::new(ControlHeader::default())?; let command = ChainBuilder::new() .chain(Buffer::new(&request)) .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) @@ -95,16 +95,16 @@ impl<'a> Display<'a> { } async fn flush_resource(&mut self, flush: ResourceFlush) -> Result<(), Error> { - let header = self.send_request(Dma::new(flush)?).await?; + let header = self.send_request(Dma::new(flush)?).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); Ok(()) } - async fn map_screen(&mut self, offset: usize, size: usize) -> Result { + async fn map_screen(&mut self, offset: usize) -> Result { // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. let (width, height) = self.get_resolution().await?; - let mut request = Dma::new(ResourceCreate2d::default())?; + let mut request = Dma::new(ResourceCreate2d::default())?; request.set_width(width); request.set_height(height); @@ -113,54 +113,63 @@ impl<'a> Display<'a> { self.send_request(request).await?; - // Allocate a framebuffer from guest ram, and attach it as backing storage to the - // resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. Scatter - // lists are supported, so the framebuffer doesn’t need to be contignous in guest - // physical memory. + // Allocate a framebuffer from guest ram, and attach it as backing storage to the + // resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. Scatter + // lists are supported, so the framebuffer doesn’t need to be contignous in guest + // physical memory. let bpp = 32; - let fb_size = (width as usize * height as usize * bpp / 8).next_multiple_of(syscall::PAGE_SIZE); - let mut entries = unsafe { Dma::zeroed_unsized(fb_size / syscall::PAGE_SIZE) }?; + let fb_size = + (width as usize * height as usize * bpp / 8).next_multiple_of(syscall::PAGE_SIZE); + let address = unsafe { syscall::physalloc(fb_size) }? as u64; + let mapped = unsafe { + syscall::physmap( + address as usize, + fb_size, + syscall::PhysmapFlags::PHYSMAP_WRITE, + ) + }?; - for i in 0..fb_size / syscall::PAGE_SIZE { - let address = unsafe { syscall::physalloc(syscall::PAGE_SIZE) }? as u64; - let mapped = unsafe {syscall::physmap(address as usize, syscall::PAGE_SIZE, syscall::PhysmapFlags::PHYSMAP_WRITE)}?; - unsafe { - core::ptr::write_bytes(mapped as *mut u8, 69, syscall::PAGE_SIZE); - } - - let entry = MemEntry { - address, - length: syscall::PAGE_SIZE as u32, - padding: 0, - }; - - entries[i]= entry; + unsafe { + core::ptr::write_bytes(mapped as *mut u8, 255, fb_size); } - let attach_request = Dma::new(AttachBacking::new(1, entries.len() as u32))?; - let header = Dma::new(ControlHeader::default())?; + let entry = Dma::new(MemEntry { + address, + length: fb_size as u32, + padding: 0, + })?; + + let attach_request = Dma::new(AttachBacking::new(1, 1))?; + let header = Dma::new(ControlHeader::default())?; let command = ChainBuilder::new() .chain(Buffer::new(&attach_request)) - .chain(Buffer::new_unsized(&entries)) + .chain(Buffer::new(&entry)) .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) .build(); self.control_queue.send(command).await; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + self.flush().await?; + self.mapped = Some(mapped); + Ok(mapped + offset) + } - let rect = GpuRect::new(0,0,width,height); + async fn flush(&mut self) -> Result<(), Error> { + let (width, height) = self.get_resolution().await?; + + let rect = GpuRect::new(0, 0, width, height); let scanout_request = Dma::new(SetScanout::new(0, 1, rect))?; let header = self.send_request(scanout_request).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - let rect = GpuRect::new(0,0,width,height); + let rect = GpuRect::new(0, 0, width, height); let req = Dma::new(XferToHost2d::new(1, rect))?; let header = self.send_request(req).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - let rect = GpuRect::new(0,0,width,height); + let rect = GpuRect::new(0, 0, width, height); self.flush_resource(ResourceFlush::new(1, rect)).await?; - todo!() + Ok(()) } } @@ -179,59 +188,114 @@ impl<'a> SchemeMut for Display<'a> { let vt_index = screen.next().unwrap_or("").parse::().unwrap_or(1); let id = screen.next().unwrap_or("").parse::().unwrap_or(0); + if id != self.display_id { + return Err(SysError::new(syscall::ENOENT)); + } + dbg!(&vt_index, &id); let fd = self.next_id.fetch_add(1, Ordering::SeqCst); self.handles.insert(fd, Handle::Screen { id }); - + Ok(fd) } } + fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> syscall::Result { + todo!() + } + + fn fevent( + &mut self, + _id: usize, + _flags: syscall::EventFlags, + ) -> syscall::Result { + log::warn!("fevent is a stub!"); + Ok(syscall::EventFlags::empty()) + } + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; let bytes_copied = match handle { - Handle::Screen { .. } => { - futures::executor::block_on(self.get_fpath(buf))? - } + Handle::Screen { .. } => futures::executor::block_on(self.get_fpath(buf))?, }; Ok(bytes_copied) } + fn fmap_old(&mut self, id: usize, map: &syscall::OldMap) -> syscall::Result { + self.fmap( + id, + &syscall::Map { + offset: map.offset, + size: map.size, + flags: map.flags, + address: 0, + }, + ) + } + fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - if let Handle::Screen { .. } = handle { - futures::executor::block_on(self.map_screen(map.offset, map.size)); - } - - unreachable!() - } - - fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { - let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - let path = match handle { + let a = match handle { Handle::Screen { .. } => { - futures::executor::block_on(self.get_fpath(buf))? + if let Some(mapped) = self.mapped { + // already mapped + mapped + map.offset + } else { + // create the resource + futures::executor::block_on(self.map_screen(map.offset)).unwrap() + } } }; + Ok(a) + } + fn fsync(&mut self, id: usize) -> syscall::Result { + let _handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + futures::executor::block_on(self.flush()).unwrap(); + + Ok(0) + } + + fn read(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result { + // TODO: figure out how to get input lol + log::warn!("virtio_gpu::read is a stub!"); + Ok(0) + } + + fn write(&mut self, _id: usize, buf: &[u8]) -> syscall::Result { + // let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + + // match handle { + // Handle::Screen { .. } => { + // let size = buf.len() / core::mem::size_of::(); + // let events = + // unsafe { core::slice::from_raw_parts(buf.as_ptr().cast::(), size) }; + + // dbg!(events); + // todo!() + // } + // } + + // SAFETY: lmao + unsafe { + core::ptr::copy_nonoverlapping( + buf.as_ptr(), + self.mapped.unwrap() as *mut u8, + buf.len(), + ); + futures::executor::block_on(self.flush()).unwrap(); + } + Ok(buf.len()) + } + + fn seek(&mut self, _id: usize, _pos: isize, _whence: usize) -> syscall::Result { todo!() } - fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { - let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - - match handle { - Handle::Screen { .. } => { - let size = buf.len() / core::mem::size_of::(); - let events = - unsafe { core::slice::from_raw_parts(buf.as_ptr().cast::(), size) }; - - dbg!(events); - todo!() - } - } + fn close(&mut self, _id: usize) -> syscall::Result { + Ok(0) } } From 2f2720263f653425463d3e705156ead5e3a474a9 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 5 Jul 2023 10:52:33 +1000 Subject: [PATCH 0641/1301] drivers: add `inputd` Take out the input coalescing from `vesad` into `inputd`. Signed-off-by: Anhad Singh --- Cargo.lock | 15 ++- Cargo.toml | 1 + fmt.sh | 28 ++--- inputd/Cargo.toml | 12 ++ inputd/src/main.rs | 224 +++++++++++++++++++++++++++++++++++ ps2d/src/main.rs | 4 +- virtio-core/src/transport.rs | 4 +- 7 files changed, 268 insertions(+), 20 deletions(-) create mode 100644 inputd/Cargo.toml create mode 100644 inputd/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index afb50c966b..9960ef6c71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -674,6 +674,17 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inputd" +version = "0.1.0" +dependencies = [ + "anyhow", + "log", + "redox-daemon", + "redox-log", + "redox_syscall 0.3.5", +] + [[package]] name = "instant" version = "0.1.12" @@ -742,9 +753,9 @@ checksum = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" [[package]] name = "libc" -version = "0.2.141" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "link-cplusplus" diff --git a/Cargo.toml b/Cargo.toml index 2ccefbc9b4..b992570d25 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ "usbctl", "usbhidd", "usbscsid", + "inputd", "virtio-blkd", "virtio-netd", diff --git a/fmt.sh b/fmt.sh index 450e518f26..c9f29df18f 100755 --- a/fmt.sh +++ b/fmt.sh @@ -1,17 +1,17 @@ #!/usr/bin/bash -pushd virtio-core -cargo fmt -popd +function fmt() { + for dir in "$@" + do + pushd $dir + printf "\e[1;32mFormatting\e[0m $dir\n" + cargo fmt + popd + done +} -pushd virtio-netd -cargo fmt -popd - -pushd virtio-blkd -cargo fmt -popd - -pushd virtio-gpud -cargo fmt -popd +fmt virtio-core \ + virtio-netd \ + virtio-blkd \ + virtio-gpud \ + inputd diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml new file mode 100644 index 0000000000..75c1a048a5 --- /dev/null +++ b/inputd/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "inputd" +version = "0.1.0" +edition = "2021" +authors = ["Anhad Singh "] + +[dependencies] +anyhow = "1.0.71" +log = "0.4.19" +redox-daemon = "0.1.0" +redox-log = "0.1.1" +redox_syscall = "0.3.5" diff --git a/inputd/src/main.rs b/inputd/src/main.rs new file mode 100644 index 0000000000..f349f6dec8 --- /dev/null +++ b/inputd/src/main.rs @@ -0,0 +1,224 @@ +//! `:input` +//! +//! A seperate scheme is required since all of the input from different input devices is required +//! to be combined into a single stream which is later going to be processed by the "consumer" +//! which usually is Orbital. +//! +//! ## Input Device ("producer") +//! Write events to `input:producer`. +//! +//! ## Input Consumer ("consumer") +//! Read events from `input:consumer`. Optionally, set the `EVENT_READ` flag to be notified when +//! events are available. + +use std::collections::BTreeMap; +use std::fs::File; +use std::io::{Read, Write}; +use std::sync::atomic::{AtomicUsize, Ordering}; + +use syscall::{Error as SysError, EventFlags, Packet, SchemeMut, EINVAL}; + +#[derive(Debug)] +enum Handle { + Producer, + Consumer { + events: EventFlags, + pending: Vec, + notified: bool + }, +} + +impl Handle { + pub fn is_producer(&self) -> bool { + matches!(self, Handle::Producer) + } +} + +struct InputScheme { + handles: BTreeMap, + next_id: AtomicUsize, +} + +impl InputScheme { + pub fn new() -> Self { + Self { + next_id: AtomicUsize::new(0), + handles: BTreeMap::new(), + } + } +} + +impl SchemeMut for InputScheme { + fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { + let handle_ty = match path { + "producer" => Handle::Producer, + "consumer" => Handle::Consumer { + events: EventFlags::empty(), + pending: Vec::new(), + notified: false + }, + + _ => unreachable!("inputd: invalid path {path}"), + }; + + log::info!("inputd: {path} channel has been opened"); + + let fd = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.insert(fd, handle_ty); + + Ok(fd) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + + if let Handle::Consumer { pending, .. } = handle { + let copy = core::cmp::min(pending.len(), buf.len()); + + for (i, byte) in pending.drain(..copy).enumerate() { + buf[i] = byte; + } + + Ok(copy) + } else { + // A producer cannot read from the channel. + unreachable!() + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { + if buf.len() == 1 && buf[0] > 0xf4 { + return Ok(1); + } + + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + assert!(handle.is_producer()); + + for handle in self.handles.values_mut() { + match handle { + Handle::Consumer { + ref mut pending, ref mut notified, .. + } => { + pending.extend_from_slice(buf); + *notified = false; + }, + _ => continue, + } + } + + Ok(buf.len()) + } + + fn fevent( + &mut self, + id: usize, + flags: syscall::EventFlags, + ) -> syscall::Result { + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + + match handle { + Handle::Consumer { ref mut events, ref mut notified, .. } => { + *events = flags; + *notified = false;}, + _ => unreachable!(), + } + + Ok(EventFlags::empty()) + } + + fn close(&mut self, _id: usize) -> syscall::Result { + todo!() + } +} + +fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { + // Create the ":input" scheme. + let mut socket_file = File::create(":input")?; + let mut scheme = InputScheme::new(); + + deamon.ready().unwrap(); + + loop { + let mut should_handle = false; + let mut packet = Packet::default(); + socket_file.read(&mut packet)?; + + // The producer has written to the channel; the consumers should be notified. + if packet.a == syscall::SYS_WRITE { + should_handle = true; + } + + scheme.handle(&mut packet); + socket_file.write(&packet)?; + + if !should_handle { + continue; + } + + for (id, handle) in scheme.handles.iter_mut() { + if let Handle::Consumer { events, pending, ref mut notified } = handle { + if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) { + continue; + } + + // Notify the consumer that we have some events to read. Yum yum. + let mut event_packet = Packet::default(); + event_packet.a = syscall::SYS_FEVENT; + event_packet.b = *id; + event_packet.c = EventFlags::EVENT_READ.bits(); + // Specifies the number of bytes that can be read non-blocking. + event_packet.d = pending.len(); + socket_file.write(&event_packet)?; + + *notified = true; + } + } + } +} + +fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { + deamon(redox_daemon).unwrap(); + unreachable!(); +} + +#[cfg(target_os = "redox")] +pub fn setup_logging(level: log::LevelFilter, name: &str) { + use redox_log::{OutputBuilder, RedoxLogger}; + + let mut logger = RedoxLogger::new().with_output( + OutputBuilder::stderr() + .with_filter(level) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ); + + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", format!("{name}.log")) { + Ok(builder) => { + logger = logger.with_output(builder.with_filter(level).flush_on_newline(true).build()) + } + Err(err) => eprintln!("inputd: failed to create log: {}", err), + } + + match OutputBuilder::in_redox_logging_scheme("disk", "pcie", format!("{name}.ansi.log")) { + Ok(builder) => { + logger = logger.with_output( + builder + .with_filter(level) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ) + } + Err(err) => eprintln!("inputd: failed to create ANSI log: {}", err), + } + + logger.enable().unwrap(); + log::info!("inputd: enabled logger"); +} + +pub fn main() { + #[cfg(target_os = "redox")] + setup_logging(log::LevelFilter::Trace, "inputd"); + redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); +} diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 96df72a2b0..f9cdba3b6b 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -45,8 +45,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let input = OpenOptions::new() .write(true) - .open("display/vesa:input") - .expect("ps2d: failed to open display:input"); + .open("input:producer") + .expect("ps2d: failed to open input:producer"); let mut event_file = OpenOptions::new() .read(true) diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 5bcc693f59..bc56de2149 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -252,7 +252,7 @@ impl<'a> Available<'a> { self.ring .elements .as_slice(self.queue_size) - .get(index % 256) + .get(index % self.queue_size) .expect("virtio-core::available: index out of bounds") } } @@ -318,7 +318,7 @@ impl<'a> Used<'a> { self.ring .elements .as_slice(self.queue_size) - .get(index % 256) + .get(index % self.queue_size) .expect("virtio-core::used: index out of bounds") } } From 07039e8321faaf3cbcea8db879bc14973ac1ce86 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 5 Jul 2023 11:14:06 +1000 Subject: [PATCH 0642/1301] drivers: run `fmt.sh` Signed-off-by: Anhad Singh --- inputd/src/main.rs | 34 +++++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index f349f6dec8..c16cf90325 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -1,12 +1,12 @@ //! `:input` -//! +//! //! A seperate scheme is required since all of the input from different input devices is required //! to be combined into a single stream which is later going to be processed by the "consumer" //! which usually is Orbital. -//! +//! //! ## Input Device ("producer") //! Write events to `input:producer`. -//! +//! //! ## Input Consumer ("consumer") //! Read events from `input:consumer`. Optionally, set the `EVENT_READ` flag to be notified when //! events are available. @@ -24,7 +24,7 @@ enum Handle { Consumer { events: EventFlags, pending: Vec, - notified: bool + notified: bool, }, } @@ -55,7 +55,7 @@ impl SchemeMut for InputScheme { "consumer" => Handle::Consumer { events: EventFlags::empty(), pending: Vec::new(), - notified: false + notified: false, }, _ => unreachable!("inputd: invalid path {path}"), @@ -97,11 +97,13 @@ impl SchemeMut for InputScheme { for handle in self.handles.values_mut() { match handle { Handle::Consumer { - ref mut pending, ref mut notified, .. + ref mut pending, + ref mut notified, + .. } => { pending.extend_from_slice(buf); *notified = false; - }, + } _ => continue, } } @@ -117,9 +119,14 @@ impl SchemeMut for InputScheme { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; match handle { - Handle::Consumer { ref mut events, ref mut notified, .. } => { + Handle::Consumer { + ref mut events, + ref mut notified, + .. + } => { *events = flags; - *notified = false;}, + *notified = false; + } _ => unreachable!(), } @@ -156,7 +163,12 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } for (id, handle) in scheme.handles.iter_mut() { - if let Handle::Consumer { events, pending, ref mut notified } = handle { + if let Handle::Consumer { + events, + pending, + ref mut notified, + } = handle + { if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) { continue; } @@ -167,7 +179,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { event_packet.b = *id; event_packet.c = EventFlags::EVENT_READ.bits(); // Specifies the number of bytes that can be read non-blocking. - event_packet.d = pending.len(); + event_packet.d = pending.len(); socket_file.write(&event_packet)?; *notified = true; From 30146fa81dccce7da5352373a02f34bdec001266 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 5 Jul 2023 13:44:35 +1000 Subject: [PATCH 0643/1301] virtio-gpu: update orbital patch Signed-off-by: Anhad Singh --- virtio-gpud/patches/01-orbital.patch | 45 ++++++++++++++++++++++++++++ virtio-gpud/src/scheme.rs | 1 - 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/virtio-gpud/patches/01-orbital.patch b/virtio-gpud/patches/01-orbital.patch index 493ec66735..0dc1b7c6dd 100644 --- a/virtio-gpud/patches/01-orbital.patch +++ b/virtio-gpud/patches/01-orbital.patch @@ -1,3 +1,48 @@ +diff --git a/src/core/mod.rs b/src/core/mod.rs +index 85337dd..a454579 100644 +--- a/src/core/mod.rs ++++ b/src/core/mod.rs +@@ -160,6 +160,9 @@ pub struct Orbital { + pub todo: Vec, + pub displays: Vec, + pub maps: BTreeMap, ++ ++ /// Handle to "input:consumer" to recieve input events. ++ pub input: File, + } + + impl Orbital { +@@ -259,6 +262,7 @@ impl Orbital { + todo: Vec::new(), + displays, + maps: BTreeMap::new(), ++ input: File::open("input:consumer")?, + }) + } + +@@ -294,6 +298,7 @@ impl Orbital { + + let scheme_fd = self.scheme.as_raw_fd(); + let display_fd = self.displays[0].file.as_raw_fd(); ++ let input_fd = self.input.as_raw_fd(); + + handler.handle_startup(&mut self)?; + +@@ -337,12 +342,12 @@ impl Orbital { + Ok(result) + })?; + +- event_queue.add(display_fd, move |_| -> io::Result> { ++ event_queue.add(input_fd, move |_| -> io::Result> { + let mut me = me2.borrow_mut(); + let me = &mut *me; + let mut events = [Event::new(); 16]; + loop { +- match read_to_slice(&mut me.orb.displays[0].file, &mut events)? { ++ match read_to_slice(&mut me.orb.input, &mut events)? { + 0 => break, + count => { + let events = &mut events[..count]; diff --git a/src/main.rs b/src/main.rs index 1cdf9cf..3859ac0 100644 --- a/src/main.rs diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 0dbec3326f..f7d906cced 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -6,7 +6,6 @@ use std::{ }, }; -use orbclient::Event; use syscall::{Dma, Error as SysError, SchemeMut, EINVAL, EPERM}; use virtio_core::{ spec::{Buffer, ChainBuilder, DescriptorFlags}, From 320fedbd76e254b7c8c34e338a01020889b95b65 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 5 Jul 2023 17:49:08 +1000 Subject: [PATCH 0644/1301] virtio-gpud: get multiple displays to work Signed-off-by: Anhad Singh --- initfs.toml | 1 - virtio-gpud/src/main.rs | 13 ++- virtio-gpud/src/scheme.rs | 228 +++++++++++++++++++------------------- 3 files changed, 124 insertions(+), 118 deletions(-) diff --git a/initfs.toml b/initfs.toml index 631768911d..53e05f3432 100644 --- a/initfs.toml +++ b/initfs.toml @@ -45,7 +45,6 @@ use_channel = true [[drivers]] name = "virtio-gpu" class = 3 -subclass = 0 vendor = 6900 device = 4176 command = ["virtio-gpud"] diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index 15fd0509ea..ce3dc49a53 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -48,10 +48,17 @@ pub struct GpuConfig { /// Clears pending events in the device (write-to-clear). pub events_clear: VolatileCell, // write-only - pub min_scanouts: VolatileCell, + pub num_scanouts: VolatileCell, pub num_capsets: VolatileCell, } +impl GpuConfig { + #[inline] + pub fn num_scanouts(&self) -> u32 { + self.num_scanouts.get() + } +} + #[derive(Debug, Copy, Clone, PartialEq)] #[repr(u32)] pub enum CommandTy { @@ -346,6 +353,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { log::info!("virtio-gpu: initiating startup sequence :^)"); let device = virtio_core::probe_device(&mut pcid_handle)?; + let config = unsafe { &mut *(device.device_space as *mut GpuConfig) }; // Negotiate features. device.transport.finalize_features(); @@ -363,8 +371,9 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device.transport.run_device(); deamon.ready().unwrap(); + let mut socket_file = File::create(":display/virtio-gpu")?; - let mut scheme = scheme::Display::new(control_queue, cursor_queue); + let mut scheme = scheme::Scheme::new(config, control_queue.clone(), cursor_queue.clone())?; loop { let mut packet = Packet::default(); diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index f7d906cced..fea65b1bf7 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -1,12 +1,12 @@ use std::{ collections::BTreeMap, sync::{ - atomic::{AtomicUsize, Ordering}, + atomic::{AtomicUsize, Ordering, AtomicU32}, Arc, }, }; -use syscall::{Dma, Error as SysError, SchemeMut, EINVAL, EPERM}; +use syscall::{Dma, Error as SysError, SchemeMut, EINVAL}; use virtio_core::{ spec::{Buffer, ChainBuilder, DescriptorFlags}, transport::{Error, Queue}, @@ -15,67 +15,41 @@ use virtio_core::{ use crate::*; -pub enum Handle { - Screen { id: usize }, -} +static RESOURCE_ALLOC: AtomicU32 = AtomicU32::new(1); pub struct Display<'a> { control_queue: Arc>, cursor_queue: Arc>, - display_id: usize, - handles: BTreeMap, - next_id: AtomicUsize, mapped: Option, + + width: u32, + height: u32, + + resource_id: u32, + id: usize, } impl<'a> Display<'a> { - pub fn new(control_queue: Arc>, cursor_queue: Arc>) -> Self { + pub fn new(control_queue: Arc>, cursor_queue: Arc>, display_info: & mut DisplayInfo, id: usize) -> Self { + display_info.enabled.set(1); + Self { control_queue, cursor_queue, - display_id: 0, - handles: BTreeMap::new(), - next_id: AtomicUsize::new(0), mapped: None, + + width: 1920, + height: 1080, + + id, + resource_id: RESOURCE_ALLOC.fetch_add(1, Ordering::SeqCst) } } - async fn get_display_info(&self) -> Result, Error> { - let header = Dma::new(ControlHeader { - ty: VolatileCell::new(CommandTy::GetDisplayInfo), - ..Default::default() - })?; - - let response = Dma::new(GetDisplayInfo::default())?; - let command = ChainBuilder::new() - .chain(Buffer::new(&header)) - .chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - self.control_queue.send(command).await; - assert!(response.header.ty.get() == CommandTy::RespOkDisplayInfo); - - Ok(response) - } - - async fn get_resolution(&self) -> Result<(u32, u32), Error> { - let display_info = self.get_display_info().await?; - - let width = display_info.display_info[self.display_id].rect.width(); - let height = display_info.display_info[self.display_id].rect.height(); - - Ok((width, height)) - } - - async fn get_fpath(&mut self, buffer: &mut [u8]) -> syscall::Result { - let display_info = self.get_display_info().await.unwrap(); - - let width = display_info.display_info[self.display_id].rect.width(); - let height = display_info.display_info[self.display_id].rect.height(); - - let path = format!("display:3.0/{}/{}", width, height); + async fn get_fpath(&mut self, buffer: &mut [u8]) -> Result { + let path = format!("display/virtio-gpu:3.0/{}/{}", self.width, self.height); // Copy the path into the target buffer. buffer[..path.len()].copy_from_slice(path.as_bytes()); @@ -101,14 +75,17 @@ impl<'a> Display<'a> { } async fn map_screen(&mut self, offset: usize) -> Result { + if let Some(mapped) = self.mapped { + return Ok(mapped + offset); + } + // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. - let (width, height) = self.get_resolution().await?; let mut request = Dma::new(ResourceCreate2d::default())?; - request.set_width(width); - request.set_height(height); + request.set_width(self.width); + request.set_height(self.height); request.set_format(ResourceFormat::Bgrx); - request.set_resource_id(1); // FIXME(andypython): dynamically allocate resource identifiers + request.set_resource_id(self.resource_id); self.send_request(request).await?; @@ -118,7 +95,7 @@ impl<'a> Display<'a> { // physical memory. let bpp = 32; let fb_size = - (width as usize * height as usize * bpp / 8).next_multiple_of(syscall::PAGE_SIZE); + (self.width as usize * self.height as usize * bpp / 8).next_multiple_of(syscall::PAGE_SIZE); let address = unsafe { syscall::physalloc(fb_size) }? as u64; let mapped = unsafe { syscall::physmap( @@ -138,7 +115,7 @@ impl<'a> Display<'a> { padding: 0, })?; - let attach_request = Dma::new(AttachBacking::new(1, 1))?; + let attach_request = Dma::new(AttachBacking::new(self.resource_id, 1))?; let header = Dma::new(ControlHeader::default())?; let command = ChainBuilder::new() .chain(Buffer::new(&attach_request)) @@ -154,50 +131,96 @@ impl<'a> Display<'a> { } async fn flush(&mut self) -> Result<(), Error> { - let (width, height) = self.get_resolution().await?; - - let rect = GpuRect::new(0, 0, width, height); - let scanout_request = Dma::new(SetScanout::new(0, 1, rect))?; + let rect = GpuRect::new(0, 0, self.width, self.height); + let scanout_request = Dma::new(SetScanout::new(self.id as u32, self.resource_id, rect))?; let header = self.send_request(scanout_request).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - let rect = GpuRect::new(0, 0, width, height); - let req = Dma::new(XferToHost2d::new(1, rect))?; + let rect = GpuRect::new(0, 0, self.width, self.height); + let req = Dma::new(XferToHost2d::new(self.resource_id, rect))?; let header = self.send_request(req).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - let rect = GpuRect::new(0, 0, width, height); - self.flush_resource(ResourceFlush::new(1, rect)).await?; + let rect = GpuRect::new(0, 0, self.width, self.height); + self.flush_resource(ResourceFlush::new(self.resource_id, rect)).await?; Ok(()) } } -impl<'a> SchemeMut for Display<'a> { - fn open(&mut self, path: &str, _flags: usize, uid: u32, _gid: u32) -> syscall::Result { - if path == "input" { - if uid != 0 { - return Err(SysError::new(EPERM)); +pub struct Scheme<'a> { + control_queue: Arc>, + cursor_queue: Arc>, + config: &'a mut GpuConfig, + /// File descriptor allocator. + next_id: AtomicUsize, + handles: BTreeMap> +} + +impl<'a> Scheme<'a> { + pub fn new(config: &'a mut GpuConfig, control_queue: Arc>, cursor_queue: Arc>) -> Result { + Ok( + Self { + control_queue, + cursor_queue, + config, + next_id: AtomicUsize::new(0), + handles: BTreeMap::new() } + ) + } - unimplemented!("input is only supported via `display/vesa:input`") - } else { - let mut parts = path.split('/'); - let mut screen = parts.next().unwrap_or("").split('.'); + async fn open_display(&self, id: usize) -> Result, Error> { + let mut display_info = self.get_display_info().await?; + let displays = &mut display_info.display_info[..self.config.num_scanouts() as usize]; - let vt_index = screen.next().unwrap_or("").parse::().unwrap_or(1); - let id = screen.next().unwrap_or("").parse::().unwrap_or(0); + let display = displays.get_mut (id).ok_or(SysError::new(syscall::ENOENT))?; - if id != self.display_id { - return Err(SysError::new(syscall::ENOENT)); - } - - dbg!(&vt_index, &id); - - let fd = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.insert(fd, Handle::Screen { id }); - - Ok(fd) + log::info!("virtio-gpu: opening display ({}x{}px)", display.rect.width(), display.rect.height()); + let mut d = Display::new(self.control_queue.clone(), self.cursor_queue.clone(), display, id); + + if id != 0 { + d.map_screen(0).await?; } + + Ok( d) + } + + async fn get_display_info(&self) -> Result, Error> { + let header = Dma::new(ControlHeader { + ty: VolatileCell::new(CommandTy::GetDisplayInfo), + ..Default::default() + })?; + + let response = Dma::new(GetDisplayInfo::default())?; + let command = ChainBuilder::new() + .chain(Buffer::new(&header)) + .chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.control_queue.send(command).await; + assert!(response.header.ty.get() == CommandTy::RespOkDisplayInfo); + + Ok(response) + } +} + +impl<'a> SchemeMut for Scheme<'a> { + fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { + dbg!(&path); + + let mut parts = path.split('/'); + let mut screen = parts.next().unwrap_or("").split('.'); + + let vt_index = screen.next().unwrap_or("").parse::().unwrap_or(1); + let id = screen.next().unwrap_or("").parse::().unwrap_or(0); + + dbg!(&vt_index, &id); + + let fd = self.next_id.fetch_add(1, Ordering::SeqCst); + let display = futures::executor::block_on(self.open_display(id)).map_err(|_| SysError::new(syscall::ENOENT))?; + + self.handles.insert(fd, display); + Ok(fd) } fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> syscall::Result { @@ -215,9 +238,7 @@ impl<'a> SchemeMut for Display<'a> { fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - let bytes_copied = match handle { - Handle::Screen { .. } => futures::executor::block_on(self.get_fpath(buf))?, - }; + let bytes_copied = futures::executor::block_on(handle.get_fpath(buf)).unwrap(); Ok(bytes_copied) } @@ -236,25 +257,12 @@ impl<'a> SchemeMut for Display<'a> { fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - - let a = match handle { - Handle::Screen { .. } => { - if let Some(mapped) = self.mapped { - // already mapped - mapped + map.offset - } else { - // create the resource - futures::executor::block_on(self.map_screen(map.offset)).unwrap() - } - } - }; - Ok(a) + Ok(futures::executor::block_on(handle.map_screen(map.offset)).unwrap()) } fn fsync(&mut self, id: usize) -> syscall::Result { - let _handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - futures::executor::block_on(self.flush()).unwrap(); - + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + futures::executor::block_on(handle.flush()).unwrap(); Ok(0) } @@ -264,29 +272,19 @@ impl<'a> SchemeMut for Display<'a> { Ok(0) } - fn write(&mut self, _id: usize, buf: &[u8]) -> syscall::Result { - // let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - - // match handle { - // Handle::Screen { .. } => { - // let size = buf.len() / core::mem::size_of::(); - // let events = - // unsafe { core::slice::from_raw_parts(buf.as_ptr().cast::(), size) }; - - // dbg!(events); - // todo!() - // } - // } + fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; // SAFETY: lmao unsafe { core::ptr::copy_nonoverlapping( buf.as_ptr(), - self.mapped.unwrap() as *mut u8, + handle.mapped.unwrap() as *mut u8, buf.len(), ); - futures::executor::block_on(self.flush()).unwrap(); } + + futures::executor::block_on(handle.flush()).unwrap(); Ok(buf.len()) } From 7e83bd9adffbee6c97db55efc0ff17fc7677bfc5 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 5 Jul 2023 17:50:51 +1000 Subject: [PATCH 0645/1301] virtio-gpud: indicate the reservation of 0 resource_id Signed-off-by: Anhad Singh --- virtio-gpud/src/scheme.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index fea65b1bf7..2dd680fd48 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -15,7 +15,7 @@ use virtio_core::{ use crate::*; -static RESOURCE_ALLOC: AtomicU32 = AtomicU32::new(1); +static RESOURCE_ALLOC: AtomicU32 = AtomicU32::new(1); // XXX: 0 is reserved for whatever that takes `resource_id`. pub struct Display<'a> { control_queue: Arc>, From 2cfd62d194f2a60c49020cb2db498368d20b9957 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Thu, 6 Jul 2023 17:38:44 +1000 Subject: [PATCH 0646/1301] remove patches from virtio-gpu/ Signed-off-by: Anhad Singh --- initfs.toml | 10 ---- virtio-gpud/patches/00-init.patch | 45 -------------- virtio-gpud/patches/01-orbital.patch | 58 ------------------- virtio-gpud/src/main.rs | 18 +++++- virtio-gpud/src/scheme.rs | 87 +++++++++++++++------------- virtio-netd/config.toml | 7 +++ 6 files changed, 71 insertions(+), 154 deletions(-) delete mode 100644 virtio-gpud/patches/00-init.patch delete mode 100644 virtio-gpud/patches/01-orbital.patch create mode 100644 virtio-netd/config.toml diff --git a/initfs.toml b/initfs.toml index 53e05f3432..d648d466ad 100644 --- a/initfs.toml +++ b/initfs.toml @@ -23,7 +23,6 @@ subclass = 8 command = ["nvmed"] use_channel = true -# -------------- virtio -------------- # [[drivers]] name = "virtio-blk" class = 1 @@ -33,15 +32,6 @@ device = 4097 command = ["virtio-blkd"] use_channel = true -[[drivers]] -name = "virtio-net" -class = 2 -subclass = 0 -vendor = 6900 -device = 4096 -command = ["virtio-netd"] -use_channel = true - [[drivers]] name = "virtio-gpu" class = 3 diff --git a/virtio-gpud/patches/00-init.patch b/virtio-gpud/patches/00-init.patch deleted file mode 100644 index dc20be1df6..0000000000 --- a/virtio-gpud/patches/00-init.patch +++ /dev/null @@ -1,45 +0,0 @@ -diff --git a/src/main.rs b/src/main.rs -index a99488a..ec97fdd 100644 ---- a/src/main.rs -+++ b/src/main.rs -@@ -78,6 +78,40 @@ pub fn run(file: &Path) -> Result<()> { - println!("init: failed to run: no argument"); - }, - "run.d" => if let Some(new_dir) = args.next() { -+ // On startup, the VESA display driver is started which basically makes use of the framebuffer -+ // provided by the firmware. The GPU device are latter started by `pcid` (such as `virtio-gpu`). -+ let mut devices = vec![]; -+ let schemes = std::fs::read_dir(":").unwrap(); -+ -+ for entry in schemes { -+ let path = entry.unwrap().path(); -+ let path_str = path -+ .into_os_string() -+ .into_string() -+ .expect("init: failed to convert path to string"); -+ -+ if path_str.contains("display") { -+ println!("init: found display scheme {}", path_str); -+ devices.push(path_str); -+ } -+ } -+ -+ let device = devices.iter().filter(|d| !d.contains("vesa")).collect::>(); -+ let device = if device.is_empty() { -+ // No GPU available, fallback to VESA display which *should* always be accessible via `display/vesa:`. -+ "vesa" -+ } else { -+ // Parts: -+ // :/display/virtio-gpu -+ // -+ // 1st: ":" -+ // 2nd: "display" -+ // 3rd: "virtio-gpu" (the one we want!) -+ device[0].split("/").nth(2).unwrap() -+ }; -+ -+ std::env::set_var("DISPLAY", &format!("display/{}:3/activate", device)); -+ - let mut entries = vec![]; - match read_dir(&new_dir) { - Ok(list) => for entry_res in list { diff --git a/virtio-gpud/patches/01-orbital.patch b/virtio-gpud/patches/01-orbital.patch deleted file mode 100644 index 0dc1b7c6dd..0000000000 --- a/virtio-gpud/patches/01-orbital.patch +++ /dev/null @@ -1,58 +0,0 @@ -diff --git a/src/core/mod.rs b/src/core/mod.rs -index 85337dd..a454579 100644 ---- a/src/core/mod.rs -+++ b/src/core/mod.rs -@@ -160,6 +160,9 @@ pub struct Orbital { - pub todo: Vec, - pub displays: Vec, - pub maps: BTreeMap, -+ -+ /// Handle to "input:consumer" to recieve input events. -+ pub input: File, - } - - impl Orbital { -@@ -259,6 +262,7 @@ impl Orbital { - todo: Vec::new(), - displays, - maps: BTreeMap::new(), -+ input: File::open("input:consumer")?, - }) - } - -@@ -294,6 +298,7 @@ impl Orbital { - - let scheme_fd = self.scheme.as_raw_fd(); - let display_fd = self.displays[0].file.as_raw_fd(); -+ let input_fd = self.input.as_raw_fd(); - - handler.handle_startup(&mut self)?; - -@@ -337,12 +342,12 @@ impl Orbital { - Ok(result) - })?; - -- event_queue.add(display_fd, move |_| -> io::Result> { -+ event_queue.add(input_fd, move |_| -> io::Result> { - let mut me = me2.borrow_mut(); - let me = &mut *me; - let mut events = [Event::new(); 16]; - loop { -- match read_to_slice(&mut me.orb.displays[0].file, &mut events)? { -+ match read_to_slice(&mut me.orb.input, &mut events)? { - 0 => break, - count => { - let events = &mut events[..count]; -diff --git a/src/main.rs b/src/main.rs -index 1cdf9cf..3859ac0 100644 ---- a/src/main.rs -+++ b/src/main.rs -@@ -63,7 +63,7 @@ fn orbital(daemon: Daemon) -> Result<(), String> { - .enable(); - - let mut args = env::args().skip(1); -- let display_path = args.next().ok_or("no display argument")?; -+ let display_path = env::var("DISPLAY").unwrap(); - let login_cmd = args.next().ok_or("no login manager argument")?; - - core::fix_env(&display_path).map_err(|_| "error setting env vars")?; diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index ce3dc49a53..f9671f2485 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -3,6 +3,23 @@ //! XXX: 3D mode will offload rendering ops to the host gpu and therefore requires a GPU with 3D support //! on the host machine. +// Notes for the future: +// +// `virtio-gpu` 2D acceleration is just blitting. 3D acceleration has 2 kinds: +// - virgl - OpenGL +// - venus - Vulkan +// +// The Venus driver requires support for the following from the `virtio-gpu` kernel driver: +// - VIRTGPU_PARAM_3D_FEATURES +// - VIRTGPU_PARAM_CAPSET_QUERY_FIX +// - VIRTGPU_PARAM_RESOURCE_BLOB +// - VIRTGPU_PARAM_HOST_VISIBLE +// - VIRTGPU_PARAM_CROSS_DEVICE +// - VIRTGPU_PARAM_CONTEXT_INIT +// +// cc https://docs.mesa3d.org/drivers/venus.html +// cc https://docs.mesa3d.org/drivers/virgl.html + #![feature(int_roundings)] use std::fs::File; @@ -371,7 +388,6 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device.transport.run_device(); deamon.ready().unwrap(); - let mut socket_file = File::create(":display/virtio-gpu")?; let mut scheme = scheme::Scheme::new(config, control_queue.clone(), cursor_queue.clone())?; diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 2dd680fd48..89c524a517 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -1,17 +1,13 @@ -use std::{ - collections::BTreeMap, - sync::{ - atomic::{AtomicUsize, Ordering, AtomicU32}, - Arc, - }, -}; +use std::collections::BTreeMap; + +use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; +use std::sync::Arc; use syscall::{Dma, Error as SysError, SchemeMut, EINVAL}; -use virtio_core::{ - spec::{Buffer, ChainBuilder, DescriptorFlags}, - transport::{Error, Queue}, - utils::VolatileCell, -}; + +use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; +use virtio_core::transport::{Error, Queue}; +use virtio_core::utils::VolatileCell; use crate::*; @@ -31,9 +27,12 @@ pub struct Display<'a> { } impl<'a> Display<'a> { - pub fn new(control_queue: Arc>, cursor_queue: Arc>, display_info: & mut DisplayInfo, id: usize) -> Self { - display_info.enabled.set(1); - + pub fn new( + control_queue: Arc>, + cursor_queue: Arc>, + _display_info: &mut DisplayInfo, + id: usize, + ) -> Self { Self { control_queue, cursor_queue, @@ -44,7 +43,7 @@ impl<'a> Display<'a> { height: 1080, id, - resource_id: RESOURCE_ALLOC.fetch_add(1, Ordering::SeqCst) + resource_id: RESOURCE_ALLOC.fetch_add(1, Ordering::SeqCst), } } @@ -94,8 +93,8 @@ impl<'a> Display<'a> { // lists are supported, so the framebuffer doesn’t need to be contignous in guest // physical memory. let bpp = 32; - let fb_size = - (self.width as usize * self.height as usize * bpp / 8).next_multiple_of(syscall::PAGE_SIZE); + let fb_size = (self.width as usize * self.height as usize * bpp / 8) + .next_multiple_of(syscall::PAGE_SIZE); let address = unsafe { syscall::physalloc(fb_size) }? as u64; let mapped = unsafe { syscall::physmap( @@ -142,7 +141,8 @@ impl<'a> Display<'a> { assert_eq!(header.ty.get(), CommandTy::RespOkNodata); let rect = GpuRect::new(0, 0, self.width, self.height); - self.flush_resource(ResourceFlush::new(self.resource_id, rect)).await?; + self.flush_resource(ResourceFlush::new(self.resource_id, rect)) + .await?; Ok(()) } } @@ -153,36 +153,42 @@ pub struct Scheme<'a> { config: &'a mut GpuConfig, /// File descriptor allocator. next_id: AtomicUsize, - handles: BTreeMap> + handles: BTreeMap>, } impl<'a> Scheme<'a> { - pub fn new(config: &'a mut GpuConfig, control_queue: Arc>, cursor_queue: Arc>) -> Result { - Ok( - Self { - control_queue, - cursor_queue, - config, - next_id: AtomicUsize::new(0), - handles: BTreeMap::new() - } - ) + pub fn new( + config: &'a mut GpuConfig, + control_queue: Arc>, + cursor_queue: Arc>, + ) -> Result { + Ok(Self { + control_queue, + cursor_queue, + config, + next_id: AtomicUsize::new(0), + handles: BTreeMap::new(), + }) } async fn open_display(&self, id: usize) -> Result, Error> { let mut display_info = self.get_display_info().await?; let displays = &mut display_info.display_info[..self.config.num_scanouts() as usize]; - let display = displays.get_mut (id).ok_or(SysError::new(syscall::ENOENT))?; + let display = displays.get_mut(id).ok_or(SysError::new(syscall::ENOENT))?; - log::info!("virtio-gpu: opening display ({}x{}px)", display.rect.width(), display.rect.height()); - let mut d = Display::new(self.control_queue.clone(), self.cursor_queue.clone(), display, id); - - if id != 0 { - d.map_screen(0).await?; - } + log::info!( + "virtio-gpu: opening display ({}x{}px)", + display.rect.width(), + display.rect.height() + ); - Ok( d) + Ok(Display::new( + self.control_queue.clone(), + self.cursor_queue.clone(), + display, + id, + )) } async fn get_display_info(&self) -> Result, Error> { @@ -207,7 +213,7 @@ impl<'a> Scheme<'a> { impl<'a> SchemeMut for Scheme<'a> { fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { dbg!(&path); - + let mut parts = path.split('/'); let mut screen = parts.next().unwrap_or("").split('.'); @@ -217,7 +223,8 @@ impl<'a> SchemeMut for Scheme<'a> { dbg!(&vt_index, &id); let fd = self.next_id.fetch_add(1, Ordering::SeqCst); - let display = futures::executor::block_on(self.open_display(id)).map_err(|_| SysError::new(syscall::ENOENT))?; + let display = futures::executor::block_on(self.open_display(id)) + .map_err(|_| SysError::new(syscall::ENOENT))?; self.handles.insert(fd, display); Ok(fd) diff --git a/virtio-netd/config.toml b/virtio-netd/config.toml new file mode 100644 index 0000000000..93949ce905 --- /dev/null +++ b/virtio-netd/config.toml @@ -0,0 +1,7 @@ +[[drivers]] +name = "virtio-net" +class = 2 +vendor = 6900 +device = 4096 +command = ["virtio-netd"] +use_channel = true From bfe8536d58d70f7e12ca7a955df78f2fb65b80fd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 6 Jul 2023 10:32:16 -0600 Subject: [PATCH 0647/1301] Add rtl8139 driver --- Cargo.lock | 14 ++ Cargo.toml | 1 + rtl8139d/Cargo.toml | 15 ++ rtl8139d/config.toml | 6 + rtl8139d/src/device.rs | 349 ++++++++++++++++++++++++++++++ rtl8139d/src/main.rs | 469 +++++++++++++++++++++++++++++++++++++++++ rtl8168d/src/device.rs | 6 +- 7 files changed, 859 insertions(+), 1 deletion(-) create mode 100644 rtl8139d/Cargo.toml create mode 100644 rtl8139d/config.toml create mode 100644 rtl8139d/src/device.rs create mode 100644 rtl8139d/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 69722a682a..3965b23e13 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1377,6 +1377,20 @@ dependencies = [ "redox_syscall 0.2.16", ] +[[package]] +name = "rtl8139d" +version = "0.1.0" +dependencies = [ + "bitflags 1.2.1", + "log", + "netutils", + "pcid", + "redox-daemon", + "redox-log", + "redox_event", + "redox_syscall 0.3.5", +] + [[package]] name = "rtl8168d" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 2ccefbc9b4..5182ebc37b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ members = [ "pcid", "pcspkrd", "ps2d", + "rtl8139d", "rtl8168d", "sb16d", "vboxd", diff --git a/rtl8139d/Cargo.toml b/rtl8139d/Cargo.toml new file mode 100644 index 0000000000..48d15ec8ba --- /dev/null +++ b/rtl8139d/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "rtl8139d" +version = "0.1.0" +edition = "2018" + +[dependencies] +bitflags = "1" +log = "0.4" +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox_syscall = "0.3" +redox-daemon = "0.1" +redox-log = "0.1" + +pcid = { path = "../pcid" } diff --git a/rtl8139d/config.toml b/rtl8139d/config.toml new file mode 100644 index 0000000000..92e19426e9 --- /dev/null +++ b/rtl8139d/config.toml @@ -0,0 +1,6 @@ +[[drivers]] +name = "RTL8139 NIC" +class = 2 +ids = { 0x10ec = [0x8139] } +command = ["rtl8139d"] +use_channel = true diff --git a/rtl8139d/src/device.rs b/rtl8139d/src/device.rs new file mode 100644 index 0000000000..0351b8bb95 --- /dev/null +++ b/rtl8139d/src/device.rs @@ -0,0 +1,349 @@ +use std::mem; +use std::convert::TryInto; +use std::collections::BTreeMap; + +use netutils::setcfg; +use syscall::error::{Error, EACCES, EBADF, EINVAL, EIO, EMSGSIZE, EWOULDBLOCK, Result}; +use syscall::flag::{EventFlags, O_NONBLOCK}; +use syscall::io::{Dma, Mmio, Io, ReadOnly}; +use syscall::scheme::SchemeBlockMut; + +const RX_BUFFER_SIZE: usize = 64 * 1024; + +const RXSTS_ROK: u16 = 1 << 0; + +const TSD_TOK: u32 = 1 << 15; +const TSD_OWN: u32 = 1 << 13; +const TSD_SIZE_MASK: u32 = 0x1FFF; + +const CR_RST: u8 = 1 << 4; +const CR_RE: u8 = 1 << 3; +const CR_TE: u8 = 1 << 2; +const CR_BUFE: u8 = 1 << 0; + +const IMR_TOK: u16 = 1 << 2; +const IMR_ROK: u16 = 1 << 0; + +const RCR_RBLEN_8K: u32 = 0b00 << 11; +const RCR_RBLEN_16K: u32 = 0b01 << 11; +const RCR_RBLEN_32K: u32 = 0b10 << 11; +const RCR_RBLEN_64K: u32 = 0b11 << 11; +const RCR_RBLEN_MASK: u32 = 0b11 << 11; +const RCR_AER: u32 = 1 << 5; +const RCR_AR: u32 = 1 << 4; +const RCR_AB: u32 = 1 << 3; +const RCR_AM: u32 = 1 << 2; +const RCR_APM: u32 = 1 << 1; +const RCR_AAP: u32 = 1 << 0; + +#[repr(packed)] +struct Regs { + mac: [Mmio; 2], + mar: [Mmio; 2], + tsd: [Mmio; 4], + tsad: [Mmio; 4], + rbstart: Mmio, + erbcr: ReadOnly>, + ersr: ReadOnly>, + cr: Mmio, + capr: Mmio, + cbr: ReadOnly>, + imr: Mmio, + isr: Mmio, + tcr: Mmio, + rcr: Mmio, + tctr: Mmio, + mpc: Mmio, + cr_9346: Mmio, + config0: Mmio, + config1: Mmio, + rsvd_53: ReadOnly>, + timer_int: Mmio, + msr: Mmio, + config2: Mmio, + config3: Mmio, + rsvd_5b: ReadOnly>, + mulint: Mmio, + rerid: ReadOnly>, + rsvd_5f: ReadOnly>, + tsts: ReadOnly>, + _todo: [ReadOnly>; 158], +} + +impl Regs { + unsafe fn from_base(base: usize) -> &'static mut Self { + assert_eq!(mem::size_of::(), 256); + + let regs = &mut *(base as *mut Regs); + + assert_eq!(®s.mac[0] as *const _ as usize - base, 0x00); + assert_eq!(®s.mac[1] as *const _ as usize - base, 0x04); + assert_eq!(®s.mar[0] as *const _ as usize - base, 0x08); + assert_eq!(®s.mar[1] as *const _ as usize - base, 0x0C); + assert_eq!(®s.tsd[0] as *const _ as usize - base, 0x10); + assert_eq!(®s.tsd[1] as *const _ as usize - base, 0x14); + assert_eq!(®s.tsd[2] as *const _ as usize - base, 0x18); + assert_eq!(®s.tsd[3] as *const _ as usize - base, 0x1C); + assert_eq!(®s.tsad[0] as *const _ as usize - base, 0x20); + assert_eq!(®s.tsad[1] as *const _ as usize - base, 0x24); + assert_eq!(®s.tsad[2] as *const _ as usize - base, 0x28); + assert_eq!(®s.tsad[3] as *const _ as usize - base, 0x2C); + assert_eq!(®s.rbstart as *const _ as usize - base, 0x30); + assert_eq!(®s.erbcr as *const _ as usize - base, 0x34); + assert_eq!(®s.ersr as *const _ as usize - base, 0x36); + assert_eq!(®s.cr as *const _ as usize - base, 0x37); + assert_eq!(®s.capr as *const _ as usize - base, 0x38); + assert_eq!(®s.cbr as *const _ as usize - base, 0x3A); + assert_eq!(®s.imr as *const _ as usize - base, 0x3C); + assert_eq!(®s.isr as *const _ as usize - base, 0x3E); + assert_eq!(®s.tcr as *const _ as usize - base, 0x40); + assert_eq!(®s.rcr as *const _ as usize - base, 0x44); + assert_eq!(®s.tctr as *const _ as usize - base, 0x48); + assert_eq!(®s.mpc as *const _ as usize - base, 0x4C); + assert_eq!(®s.cr_9346 as *const _ as usize - base, 0x50); + assert_eq!(®s.config0 as *const _ as usize - base, 0x51); + assert_eq!(®s.config1 as *const _ as usize - base, 0x52); + assert_eq!(®s.rsvd_53 as *const _ as usize - base, 0x53); + assert_eq!(®s.timer_int as *const _ as usize - base, 0x54); + assert_eq!(®s.msr as *const _ as usize - base, 0x58); + assert_eq!(®s.config2 as *const _ as usize - base, 0x59); + assert_eq!(®s.config3 as *const _ as usize - base, 0x5A); + assert_eq!(®s.rsvd_5b as *const _ as usize - base, 0x5B); + assert_eq!(®s.mulint as *const _ as usize - base, 0x5C); + assert_eq!(®s.rerid as *const _ as usize - base, 0x5E); + assert_eq!(®s.rsvd_5f as *const _ as usize - base, 0x5F); + assert_eq!(®s.tsts as *const _ as usize - base, 0x60); + + regs + } +} + +pub struct Rtl8139 { + regs: &'static mut Regs, + receive_buffer: Dma<[Mmio; RX_BUFFER_SIZE + 16]>, + receive_i: usize, + transmit_buffer: [Dma<[Mmio; 1792]>; 4], + transmit_i: usize, + next_id: usize, + pub handles: BTreeMap +} + +impl SchemeBlockMut for Rtl8139 { + fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { + if uid == 0 { + self.next_id += 1; + self.handles.insert(self.next_id, flags); + Ok(Some(self.next_id)) + } else { + Err(Error::new(EACCES)) + } + } + + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { + if ! buf.is_empty() { + return Err(Error::new(EINVAL)); + } + + let flags = { + let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + *flags + }; + self.next_id += 1; + self.handles.insert(self.next_id, flags); + Ok(Some(self.next_id)) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + if !self.regs.cr.readf(CR_BUFE) { + let rxsts = + (self.rx(0) as u16) | + (self.rx(1) as u16) << 8; + + let size_with_crc = + (self.rx(2) as usize) | + (self.rx(3) as usize) << 8; + + let res = if (rxsts & RXSTS_ROK) == RXSTS_ROK { + let mut i = 0; + while i < buf.len() && i < size_with_crc.saturating_sub(4) { + buf[i] = self.rx(4 + i as u16); + i += 1; + } + Ok(Some(i)) + } else { + //TODO: better error types + eprintln!("rtl8139d: invalid receive status 0x{:X}", rxsts); + Err(Error::new(EIO)) + }; + + self.receive_i = (self.receive_i + 4 + size_with_crc).next_multiple_of(4) % RX_BUFFER_SIZE; + let capr = self.receive_i.wrapping_sub(16) as u16; + self.regs.capr.write(capr); + + res + } else if flags & O_NONBLOCK == O_NONBLOCK { + Err(Error::new(EWOULDBLOCK)) + } else { + Ok(None) + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + loop { + if self.transmit_i >= 4 { + self.transmit_i = 0; + } + + if self.regs.tsd[self.transmit_i].readf(TSD_OWN) { + let data = &mut self.transmit_buffer[self.transmit_i]; + + if buf.len() > data.len() { + return Err(Error::new(EMSGSIZE)); + } + + let mut i = 0; + while i < buf.len() && i < data.len() { + data[i].write(buf[i]); + i += 1; + } + + self.regs.tsad[self.transmit_i].write(data.physical() as u32); + assert_eq!(i as u32, i as u32 & TSD_SIZE_MASK); + self.regs.tsd[self.transmit_i].write(i as u32 & TSD_SIZE_MASK); + + //TODO: wait for TSD_TOK or error + + self.transmit_i += 1; + + return Ok(Some(i)); + } + + std::hint::spin_loop(); + } + } + + fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + Ok(Some(EventFlags::empty())) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let mut i = 0; + let scheme_path = b"network:"; + while i < buf.len() && i < scheme_path.len() { + buf[i] = scheme_path[i]; + i += 1; + } + Ok(Some(i)) + } + + fn fsync(&mut self, id: usize) -> Result> { + let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + Ok(Some(0)) + } + + fn close(&mut self, id: usize) -> Result> { + self.handles.remove(&id).ok_or(Error::new(EBADF))?; + Ok(Some(0)) + } +} + +impl Rtl8139 { + pub unsafe fn new(base: usize) -> Result { + let regs = Regs::from_base(base); + + let mut module = Rtl8139 { + regs: regs, + //TODO: limit to 32-bit + receive_buffer: Dma::zeroed().map(|dma| dma.assume_init())?, + receive_i: 0, + //TODO: limit to 32-bit + transmit_buffer: (0..4) + .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) + .collect::>>()? + .try_into() + .unwrap_or_else(|_| unreachable!()), + transmit_i: 0, + next_id: 0, + handles: BTreeMap::new(), + }; + + module.init(); + + Ok(module) + } + + pub unsafe fn irq(&mut self) -> bool { + // Read and then clear the ISR + let isr = self.regs.isr.read(); + self.regs.isr.write(isr); + let imr = self.regs.imr.read(); + (isr & imr) != 0 + } + + fn rx(&self, offset: u16) -> u8 { + let index = (self.receive_i + offset as usize) % RX_BUFFER_SIZE; + self.receive_buffer[index].read() + } + + pub fn next_read(&self) -> usize { + if !self.regs.cr.readf(CR_BUFE) { + let rxsts = + (self.rx(0) as u16) | + (self.rx(1) as u16) << 8; + + let size_with_crc = + (self.rx(2) as usize) | + (self.rx(3) as usize) << 8; + + if (rxsts & RXSTS_ROK) == RXSTS_ROK { + size_with_crc.saturating_sub(4) + } else { + 0 + } + } else { + 0 + } + } + + pub unsafe fn init(&mut self) { + let mac_low = self.regs.mac[0].read(); + let mac_high = self.regs.mac[1].read(); + let mac = [mac_low as u8, + (mac_low >> 8) as u8, + (mac_low >> 16) as u8, + (mac_low >> 24) as u8, + mac_high as u8, + (mac_high >> 8) as u8]; + println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + + // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value + println!(" - Reset"); + self.regs.cr.writef(CR_RST, true); + while self.regs.cr.readf(CR_RST) { + core::hint::spin_loop(); + } + + // Set up rx buffer + println!(" - Receive buffer"); + self.regs.rbstart.write(self.receive_buffer.physical() as u32); + + println!(" - Interrupt mask"); + self.regs.imr.write(IMR_TOK | IMR_ROK); + + println!(" - Receive configuration"); + self.regs.rcr.write(RCR_RBLEN_64K | RCR_AB | RCR_AM | RCR_APM | RCR_AAP); + + println!(" - Enable RX and TX"); + self.regs.cr.writef(CR_RE | CR_TE, true); + + println!(" - Complete!"); + } +} diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs new file mode 100644 index 0000000000..49edbd9598 --- /dev/null +++ b/rtl8139d/src/main.rs @@ -0,0 +1,469 @@ +#![feature(int_roundings)] + +extern crate event; +extern crate netutils; +extern crate syscall; + +use std::cell::RefCell; +use std::convert::{TryFrom, TryInto}; +use std::{env, process}; +use std::fs::File; +use std::io::{ErrorKind, Read, Result, Write}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::ptr::NonNull; +use std::sync::Arc; + +use event::EventQueue; +use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; +use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector}; +use pcid_interface::msi::{MsixCapability, MsixTableEntry}; +use redox_log::{RedoxLogger, OutputBuilder}; +use syscall::{EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::io::Io; + +pub mod device; + +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("usb", "host", "rtl8139.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("Failed to create rtl8139.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("usb", "host", "rtl8139.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("Failed to create rtl8139.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("rtl8139d: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("rtl8139d: failed to set default logger: {}", error); + None + } + } +} + +use std::ops::{Add, Div, Rem}; +pub fn div_round_up(a: T, b: T) -> T +where + T: Add + Div + Rem + PartialEq + From + Copy, +{ + if a % b != T::from(0u8) { + a / b + T::from(1u8) + } else { + a / b + } +} + +pub struct MsixInfo { + pub virt_table_base: NonNull, + pub virt_pba_base: NonNull, + pub capability: MsixCapability, +} + +impl MsixInfo { + pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { + &mut *self.virt_table_base.as_ptr().offset(k as isize) + } + pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { + assert!(k < self.capability.table_size() as usize); + unsafe { self.table_entry_pointer_unchecked(k) } + } + pub unsafe fn pba_pointer_unchecked(&mut self, k: usize) -> &mut u64 { + &mut *self.virt_pba_base.as_ptr().offset(k as isize) + } + pub fn pba_pointer(&mut self, k: usize) -> &mut u64 { + assert!(k < self.capability.table_size() as usize); + unsafe { self.pba_pointer_unchecked(k) } + } + pub fn pba(&mut self, k: usize) -> bool { + let byte = k / 64; + let bit = k % 64; + *self.pba_pointer(byte) & (1 << bit) != 0 + } +} + +#[cfg(target_arch = "x86_64")] +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { + let pci_config = pcid_handle.fetch_config().expect("rtl8139d: failed to fetch config"); + + let irq = pci_config.func.legacy_interrupt_line; + + let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8139d: failed to fetch pci features"); + log::info!("PCI FEATURES: {:?}", all_pci_features); + + let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + + if has_msi && !msi_enabled && !has_msix { + msi_enabled = true; + } + if has_msix && !msix_enabled { + msix_enabled = true; + } + + if msi_enabled && !msix_enabled { + use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; + + let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("rtl8139d: failed to retrieve the MSI capability structure from pcid") { + PciFeatureInfo::Msi(s) => s, + PciFeatureInfo::MsiX(_) => panic!(), + }; + // TODO: Allow allocation of up to 32 vectors. + + // TODO: Find a way to abstract this away, potantially as a helper module for + // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. + + let destination_id = read_bsp_apic_id().expect("rtl8139d: failed to read BSP apic id"); + let lapic_id = u8::try_from(destination_id).expect("CPU id didn't fit inside u8"); + let msg_addr = x86_64_msix::message_address(lapic_id, false, false); + + let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("rtl8139d: failed to allocate interrupt vector").expect("rtl8139d: no interrupt vectors left"); + let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + + let set_feature_info = MsiSetFeatureInfo { + multi_message_enable: Some(0), + message_address: Some(msg_addr), + message_upper_address: Some(0), + message_data: Some(msg_data as u16), + mask_bits: None, + }; + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("rtl8139d: failed to set feature info"); + + pcid_handle.enable_feature(PciFeature::Msi).expect("rtl8139d: failed to enable MSI"); + log::info!("Enabled MSI"); + + Some(interrupt_handle) + } else if msix_enabled { + let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8139d: failed to retrieve the MSI-X capability structure from pcid") { + PciFeatureInfo::Msi(_) => panic!(), + PciFeatureInfo::MsiX(s) => s, + }; + let table_size = capability.table_size(); + let table_base = capability.table_base_pointer(pci_config.func.bars); + let table_min_length = table_size * 16; + let pba_min_length = div_round_up(table_size, 8); + + let pba_base = capability.pba_base_pointer(pci_config.func.bars); + + let bir = capability.table_bir() as usize; + let bar = pci_config.func.bars[bir]; + let bar_size = pci_config.func.bar_sizes[bir] as u64; + + let bar_ptr = match bar { + pcid_interface::PciBar::Memory32(ptr) => match ptr { + 0 => panic!("BAR {} is mapped to address 0", bir), + _ => ptr as u64, + }, + pcid_interface::PciBar::Memory64(ptr) => match ptr { + 0 => panic!("BAR {} is mapped to address 0", bir), + _ => ptr, + }, + other => panic!("Expected memory bar, found {}", other), + }; + + let address = unsafe { + syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("rtl8139d: failed to map address") + }; + + if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u64 + table_min_length as u64)) { + panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); + } + + if !(bar_ptr..bar_ptr + bar_size).contains(&(pba_base as u64 + pba_min_length as u64)) { + panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size); + } + + let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; + let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; + + let mut info = MsixInfo { + virt_table_base: NonNull::new(virt_table_base).unwrap(), + virt_pba_base: NonNull::new(virt_pba_base).unwrap(), + capability, + }; + + // Allocate one msi vector. + + let method = { + use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; + + // primary interrupter + let k = 0; + + assert_eq!(std::mem::size_of::(), 16); + let table_entry_pointer = info.table_entry_pointer(k); + + let destination_id = read_bsp_apic_id().expect("rtl8139d: failed to read BSP apic id"); + let lapic_id = u8::try_from(destination_id).expect("rtl8139d: CPU id couldn't fit inside u8"); + let rh = false; + let dm = false; + let addr = x86_64_msix::message_address(lapic_id, rh, dm); + + let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("rtl8139d: failed to allocate interrupt vector").expect("rtl8139d: no interrupt vectors left"); + let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + + table_entry_pointer.addr_lo.write(addr); + table_entry_pointer.addr_hi.write(0); + table_entry_pointer.msg_data.write(msg_data); + table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + + Some(interrupt_handle) + }; + + pcid_handle.enable_feature(PciFeature::MsiX).expect("rtl8139d: failed to enable MSI-X"); + log::info!("Enabled MSI-X"); + + method + } else if pci_config.func.legacy_interrupt_pin.is_some() { + // legacy INTx# interrupt pins. + Some(File::open(format!("irq:{}", irq)).expect("rtl8139d: failed to open legacy IRQ file")) + } else { + // no interrupts at all + None + } +} + +//TODO: MSI on non-x86_64? +#[cfg(not(target_arch = "x86_64"))] +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { + let pci_config = pcid_handle.fetch_config().expect("rtl8139d: failed to fetch config"); + let irq = pci_config.func.legacy_interrupt_line; + + if pci_config.func.legacy_interrupt_pin.is_some() { + // legacy INTx# interrupt pins. + Some(File::open(format!("irq:{}", irq)).expect("rtl8139d: failed to open legacy IRQ file")) + } else { + // no interrupts at all + None + } +} + +fn handle_update( + socket: &mut File, + device: &mut device::Rtl8139, + todo: &mut Vec, +) -> Result { + // Handle any blocked packets + let mut i = 0; + while i < todo.len() { + if let Some(a) = device.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&packet)?; + } else { + i += 1; + } + } + + // Check that the socket is empty + loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => return Ok(true), + Ok(_) => (), + Err(err) => { + if err.kind() == ErrorKind::WouldBlock { + break; + } else { + return Err(err); + } + } + } + + if let Some(a) = device.handle(&packet) { + packet.a = a; + socket.write(&packet)?; + } else { + todo.push(packet); + } + } + + Ok(false) +} + +fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { + // RTL8139 uses BAR2, RTL8169 uses BAR1, search in that order + for &barnum in &[2, 1] { + match pci_config.func.bars[barnum] { + pcid_interface::PciBar::Memory32(ptr) => match ptr { + 0 => log::warn!("BAR {} is mapped to address 0", barnum), + _ => return Some(( + ptr.try_into().unwrap(), + pci_config.func.bar_sizes[barnum].try_into().unwrap() + )), + }, + pcid_interface::PciBar::Memory64(ptr) => match ptr { + 0 => log::warn!("BAR {} is mapped to address 0", barnum), + _ => return Some(( + ptr.try_into().unwrap(), + pci_config.func.bar_sizes[barnum].try_into().unwrap() + )), + }, + other => log::warn!("BAR {} is {} instead of memory BAR", barnum, other), + } + } + None +} + +fn daemon(daemon: redox_daemon::Daemon) -> ! { + let _logger_ref = setup_logging(); + + let mut pcid_handle = PcidServerHandle::connect_default().expect("rtl8139d: failed to setup channel to pcid"); + + let pci_config = pcid_handle.fetch_config().expect("rtl8139d: failed to fetch config"); + + let mut name = pci_config.func.name(); + name.push_str("_rtl8139"); + + let (bar_ptr, bar_size) = find_bar(&pci_config).expect("rtl8139d: failed to find BAR"); + log::info!(" + RTL8139 {} on: {:#X} size: {}", name, bar_ptr, bar_size); + + let address = unsafe { + syscall::physmap(bar_ptr, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + .expect("rtl8139d: failed to map address") + }; + + let socket_fd = syscall::open( + ":network", + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + ) + .expect("rtl8139d: failed to create network scheme"); + let socket = Arc::new(RefCell::new(unsafe { + File::from_raw_fd(socket_fd as RawFd) + })); + + //TODO: MSI-X + let mut irq_file = get_int_method(&mut pcid_handle).expect("rtl8139d: no interrupt file"); + + { + let device = Arc::new(RefCell::new(unsafe { + device::Rtl8139::new(address).expect("rtl8139d: failed to allocate device") + })); + + let mut event_queue = + EventQueue::::new().expect("rtl8139d: failed to create event queue"); + + syscall::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); + + daemon.ready().expect("rtl8139d: failed to mark daemon as ready"); + + let todo = Arc::new(RefCell::new(Vec::::new())); + + let device_irq = device.clone(); + let socket_irq = socket.clone(); + let todo_irq = todo.clone(); + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + //TODO: This may be causing spurious interrupts + if unsafe { device_irq.borrow_mut().irq() } { + irq_file.write(&mut irq)?; + + if handle_update( + &mut socket_irq.borrow_mut(), + &mut device_irq.borrow_mut(), + &mut todo_irq.borrow_mut(), + )? { + return Ok(Some(0)); + } + + let next_read = device_irq.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + } + Ok(None) + }, + ) + .expect("rtl8139d: failed to catch events on IRQ file"); + + let device_packet = device.clone(); + let socket_packet = socket.clone(); + event_queue + .add(socket_fd as RawFd, move |_event| -> Result> { + if handle_update( + &mut socket_packet.borrow_mut(), + &mut device_packet.borrow_mut(), + &mut todo.borrow_mut(), + )? { + return Ok(Some(0)); + } + + let next_read = device_packet.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + + Ok(None) + }) + .expect("rtl8139d: failed to catch events on scheme file"); + + let send_events = |event_count| { + for (handle_id, _handle) in device.borrow().handles.iter() { + socket + .borrow_mut() + .write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: syscall::flag::EVENT_READ.bits(), + d: event_count, + }) + .expect("rtl8139d: failed to write event"); + } + }; + + for event_count in event_queue + .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) + .expect("rtl8139d: failed to trigger events") + { + send_events(event_count); + } + + loop { + let event_count = event_queue.run().expect("rtl8139d: failed to handle events"); + if event_count == 0 { + //TODO: Handle todo + break; + } + send_events(event_count); + } + } + process::exit(0); +} + +fn main() { + redox_daemon::Daemon::new(daemon).expect("rtl8139d: failed to create daemon"); +} diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index ff6231c32c..df906089ff 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -6,7 +6,7 @@ use std::convert::TryInto; use std::collections::BTreeMap; use netutils::setcfg; -use syscall::error::{Error, EACCES, EBADF, EINVAL, EWOULDBLOCK, Result}; +use syscall::error::{Error, EACCES, EBADF, EINVAL, EMSGSIZE, EWOULDBLOCK, Result}; use syscall::flag::{EventFlags, O_NONBLOCK}; use syscall::io::{Dma, Mmio, Io, ReadOnly}; use syscall::scheme::SchemeBlockMut; @@ -152,6 +152,10 @@ impl SchemeBlockMut for Rtl8168 { if ! td.ctrl.readf(OWN) { let data = &mut self.transmit_buffer[self.transmit_i]; + if buf.len() > data.len() { + return Err(Error::new(EMSGSIZE)); + } + let mut i = 0; while i < buf.len() && i < data.len() { data[i].write(buf[i]); From 5c4e7b36fad8d3f75ca2363873d8aca6eb3253b5 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Fri, 7 Jul 2023 16:51:27 +1000 Subject: [PATCH 0648/1301] make getty work Signed-off-by: Anhad Singh --- Cargo.lock | 4 + inputd/Cargo.toml | 1 + inputd/src/lib.rs | 25 ++++ inputd/src/main.rs | 116 +++++++++++++++++-- vesad/Cargo.toml | 1 + vesad/src/scheme.rs | 16 ++- virtio-core/src/transport.rs | 5 + virtio-gpud/Cargo.toml | 2 + virtio-gpud/src/main.rs | 101 +++++++++++----- virtio-gpud/src/scheme.rs | 215 ++++++++++++++++++++++++----------- 10 files changed, 375 insertions(+), 111 deletions(-) create mode 100644 inputd/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 9960ef6c71..517d78f2bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -680,6 +680,7 @@ version = "0.1.0" dependencies = [ "anyhow", "log", + "orbclient", "redox-daemon", "redox-log", "redox_syscall 0.3.5", @@ -1921,6 +1922,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" name = "vesad" version = "0.1.0" dependencies = [ + "inputd", "orbclient", "ransid", "redox-daemon", @@ -1968,12 +1970,14 @@ version = "0.1.0" dependencies = [ "anyhow", "futures", + "inputd", "log", "orbclient", "paste", "pcid", "redox-daemon", "redox_syscall 0.3.5", + "spin", "static_assertions", "virtio-core", ] diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index 75c1a048a5..dfc537236e 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -10,3 +10,4 @@ log = "0.4.19" redox-daemon = "0.1.0" redox-log = "0.1.1" redox_syscall = "0.3.5" +orbclient = "0.3.27" diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs new file mode 100644 index 0000000000..9ad4ae5876 --- /dev/null +++ b/inputd/src/lib.rs @@ -0,0 +1,25 @@ +use std::fs::File; +use std::io::{Error, Read}; + +pub struct Handle(File); + +impl Handle { + pub fn new>(device_name: S) -> Result { + let path = format!("input:handle/{}", device_name.into()); + Ok(Self(File::open(path)?)) + } + + // The return value is the display identifier. It will be used to uniquely + // identify the display on activation events. + pub fn register(&mut self) -> Result { + Ok(dbg!(self.0.read(&mut [])?)) + } +} + +#[repr(packed)] +pub struct Damage { + pub x: i32, + pub y: i32, + pub width: i32, + pub height: i32, +} diff --git a/inputd/src/main.rs b/inputd/src/main.rs index c16cf90325..3f78339d2e 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -15,10 +15,11 @@ use std::collections::BTreeMap; use std::fs::File; use std::io::{Read, Write}; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use orbclient::{Event, EventOption}; use syscall::{Error as SysError, EventFlags, Packet, SchemeMut, EINVAL}; -#[derive(Debug)] enum Handle { Producer, Consumer { @@ -26,6 +27,7 @@ enum Handle { pending: Vec, notified: bool, }, + Device(Arc), } impl Handle { @@ -36,27 +38,46 @@ impl Handle { struct InputScheme { handles: BTreeMap, + next_id: AtomicUsize, + next_vt_id: AtomicUsize, + + vts: BTreeMap>, + super_key: bool, + active_vt: Option<(Arc, File)>, } impl InputScheme { pub fn new() -> Self { Self { next_id: AtomicUsize::new(0), + next_vt_id: AtomicUsize::new(1), + handles: BTreeMap::new(), + vts: BTreeMap::new(), + super_key: false, + active_vt: None, } } } impl SchemeMut for InputScheme { fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { - let handle_ty = match path { + let mut path_parts = path.split('/'); + + let command = path_parts.next().ok_or(SysError::new(EINVAL))?; + + let handle_ty = match command { "producer" => Handle::Producer, "consumer" => Handle::Consumer { events: EventFlags::empty(), pending: Vec::new(), notified: false, }, + "handle" => { + let value = path_parts.next().ok_or(SysError::new(EINVAL))?; + Handle::Device(Arc::new(value.to_string())) + } _ => unreachable!("inputd: invalid path {path}"), }; @@ -72,17 +93,24 @@ impl SchemeMut for InputScheme { fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - if let Handle::Consumer { pending, .. } = handle { - let copy = core::cmp::min(pending.len(), buf.len()); + match handle { + Handle::Consumer { pending, .. } => { + let copy = core::cmp::min(pending.len(), buf.len()); - for (i, byte) in pending.drain(..copy).enumerate() { - buf[i] = byte; + for (i, byte) in pending.drain(..copy).enumerate() { + buf[i] = byte; + } + + Ok(copy) } - Ok(copy) - } else { - // A producer cannot read from the channel. - unreachable!() + Handle::Device(device) => { + let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); + self.vts.insert(vt, device.clone()); + Ok(vt) + } + + _ => unreachable!(), } } @@ -91,6 +119,74 @@ impl SchemeMut for InputScheme { return Ok(1); } + let events = unsafe { + core::slice::from_raw_parts( + buf.as_ptr() as *const Event, + buf.len() / core::mem::size_of::(), + ) + }; + + for event in events.iter() { + let mut new_active_opt = None; + match event.to_option() { + EventOption::Key(key_event) => match key_event.scancode { + f @ 0x3B..=0x44 if self.super_key => { + // F1 through F10 + new_active_opt = Some((f - 0x3A) as usize); + } + + 0x57 if self.super_key => { + // F11 + new_active_opt = Some(11); + } + + 0x58 if self.super_key => { + // F12 + new_active_opt = Some(12); + } + + 0x5B => { + // Super + self.super_key = key_event.pressed; + } + + _ => (), + }, + + _ => continue, + } + + if let Some(new_active) = new_active_opt { + if let Some(vt) = self.vts.get(&new_active) { + // Result: display/virtio-gpu:3/acvtivate + let activate = format!("display/{vt}:{new_active}/activate"); + log::info!("inputd: switching to VT #{new_active} ({activate})"); + + let file = File::open(&activate).unwrap(); + // Drop the old active VT first. + // + // TODO(andypython): This can be drastically improved by introducting something + // like ioctl() to the display scheme. + for (vt, device) in self.vts.iter() { + if vt == &new_active { + continue; + } + + let deactivate = format!("display/{device}:{}/deactivate", vt); + let _ = File::open(&deactivate); + + if device.contains("virtio") { + break; + } + } + + self.active_vt = Some((vt.clone(), file)); + } else { + log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); + } + } + } + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; assert!(handle.is_producer()); diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index a77d65c2e6..9b247aabe2 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -9,6 +9,7 @@ ransid = "0.4" rusttype = { version = "0.2", optional = true } redox_syscall = "0.3" redox-daemon = "0.1" +inputd = { path = "../inputd" } [features] default = [] diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index d50c12902b..493eb7888e 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -38,10 +38,13 @@ pub struct DisplayScheme { next_id: usize, pub handles: BTreeMap, super_key: bool, + inputd_handle: inputd::Handle, } impl DisplayScheme { pub fn new(mut framebuffers: Vec, spec: &[bool]) -> DisplayScheme { + let mut inputd_handle = inputd::Handle::new("vesa").unwrap(); + let mut onscreens = Vec::new(); for fb in framebuffers.iter_mut() { onscreens.push(unsafe { @@ -51,7 +54,6 @@ impl DisplayScheme { let mut vts = BTreeMap::>>::new(); - let mut vt_i = 1; for &vt_type in spec.iter() { let mut screens = BTreeMap::>::new(); for fb_i in 0..framebuffers.len() { @@ -62,8 +64,7 @@ impl DisplayScheme { Box::new(TextScreen::new(Display::new(fb.width, fb.height))) }); } - vts.insert(VtIndex(vt_i), screens); - vt_i += 1; + vts.insert(VtIndex(inputd_handle.register().unwrap()), screens); } DisplayScheme { @@ -74,6 +75,7 @@ impl DisplayScheme { next_id: 0, handles: BTreeMap::new(), super_key: false, + inputd_handle } } @@ -168,11 +170,15 @@ impl SchemeMut for DisplayScheme { let screen_i = ScreenIndex( vt_screen.next().unwrap_or("").parse::().unwrap_or(0) ); - if let Some(screens) = self.vts.get(&vt_i) { - if screens.contains_key(&screen_i) { + if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { for cmd in parts { if cmd == "activate" { self.active = vt_i; + screen.redraw( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); } } diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index bc56de2149..a1a913d3fd 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -380,6 +380,11 @@ impl<'a> StandardTransport<'a> { }) } + pub fn reset(&self) { + let mut common = self.common.lock().unwrap(); + common.device_status.set(DeviceStatusFlags::empty()); + } + pub fn check_device_feature(&self, feature: u32) -> bool { let mut common = self.common.lock().unwrap(); diff --git a/virtio-gpud/Cargo.toml b/virtio-gpud/Cargo.toml index 02249c294c..c06c18d87e 100644 --- a/virtio-gpud/Cargo.toml +++ b/virtio-gpud/Cargo.toml @@ -13,7 +13,9 @@ paste = "1.0.13" virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } +inputd = { path = "../inputd" } redox-daemon = "0.1" redox_syscall = "0.3" orbclient = "0.3.27" +spin = "0.9.8" diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index f9671f2485..bbe5675688 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -22,6 +22,7 @@ #![feature(int_roundings)] +use std::cell::UnsafeCell; use std::fs::File; use std::io::{Read, Write}; @@ -144,6 +145,15 @@ pub struct ControlHeader { padding: [u8; 3], } +impl ControlHeader { + pub fn with_ty(ty: CommandTy) -> Self { + Self { + ty: VolatileCell::new(ty), + ..Default::default() + } + } +} + impl Default for ControlHeader { fn default() -> Self { Self { @@ -157,44 +167,41 @@ impl Default for ControlHeader { } } -#[derive(Debug)] +#[derive(Debug, Clone)] #[repr(C)] pub struct GpuRect { - pub x: VolatileCell, - pub y: VolatileCell, - pub width: VolatileCell, - pub height: VolatileCell, + pub x: u32, + pub y: u32, + pub width: u32, + pub height: u32, } impl GpuRect { pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self { Self { - x: VolatileCell::new(x), - y: VolatileCell::new(y), - width: VolatileCell::new(width), - height: VolatileCell::new(height), + x, + y, + width, + height, } } - - #[inline] - pub fn width(&self) -> u32 { - self.width.get() - } - - #[inline] - pub fn height(&self) -> u32 { - self.height.get() - } } #[derive(Debug)] #[repr(C)] pub struct DisplayInfo { - pub rect: GpuRect, + rect: UnsafeCell, pub enabled: VolatileCell, pub flags: VolatileCell, } +impl DisplayInfo { + pub fn rect(&self) -> &GpuRect { + // SAFETY: We never give out mutable references to `self.rect`. + unsafe { &*self.rect.get() } + } +} + #[derive(Debug)] #[repr(C)] pub struct GetDisplayInfo { @@ -274,16 +281,31 @@ pub struct AttachBacking { impl AttachBacking { pub fn new(resource_id: u32, num_entries: u32) -> Self { Self { - header: ControlHeader { - ty: VolatileCell::new(CommandTy::ResourceAttachBacking), - ..Default::default() - }, + header: ControlHeader::with_ty(CommandTy::ResourceAttachBacking), resource_id, num_entries, } } } +#[derive(Debug)] +#[repr(C)] +pub struct DetachBacking { + pub header: ControlHeader, + pub resource_id: u32, + pub padding: u32, +} + +impl DetachBacking { + pub fn new(resource_id: u32) -> Self { + Self { + header: ControlHeader::with_ty(CommandTy::ResourceDetachBacking), + resource_id, + padding: 0, + } + } +} + #[derive(Debug)] #[repr(C)] pub struct ResourceFlush { @@ -296,11 +318,7 @@ pub struct ResourceFlush { impl ResourceFlush { pub fn new(resource_id: u32, rect: GpuRect) -> Self { Self { - header: ControlHeader { - ty: VolatileCell::new(CommandTy::ResourceFlush), - ..Default::default() - }, - + header: ControlHeader::with_ty(CommandTy::ResourceFlush), rect, resource_id, padding: 0, @@ -308,6 +326,24 @@ impl ResourceFlush { } } +#[derive(Debug)] +#[repr(C)] +pub struct ResourceUnref { + pub header: ControlHeader, + pub resource_id: u32, + pub padding: u32, +} + +impl ResourceUnref { + pub fn new(resource_id: u32) -> Self { + Self { + header: ControlHeader::with_ty(CommandTy::ResourceUnref), + resource_id, + padding: 0, + } + } +} + #[repr(C)] #[derive(Debug)] pub struct SetScanout { @@ -389,7 +425,12 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { deamon.ready().unwrap(); let mut socket_file = File::create(":display/virtio-gpu")?; - let mut scheme = scheme::Scheme::new(config, control_queue.clone(), cursor_queue.clone())?; + let mut scheme = futures::executor::block_on(scheme::Scheme::new( + config, + control_queue.clone(), + cursor_queue.clone(), + device.transport.clone(), + ))?; loop { let mut packet = Packet::default(); diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 89c524a517..b0490c8cce 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -1,23 +1,38 @@ use std::collections::BTreeMap; -use std::sync::atomic::{AtomicU32, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; +use inputd::Damage; use syscall::{Dma, Error as SysError, SchemeMut, EINVAL}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; -use virtio_core::transport::{Error, Queue}; +use virtio_core::transport::{Error, Queue, StandardTransport}; use virtio_core::utils::VolatileCell; use crate::*; static RESOURCE_ALLOC: AtomicU32 = AtomicU32::new(1); // XXX: 0 is reserved for whatever that takes `resource_id`. +impl Into for &Damage { + fn into(self) -> GpuRect { + GpuRect { + x: self.x as u32, + y: self.y as u32, + width: self.width as u32, + height: self.height as u32, + } + } +} + pub struct Display<'a> { control_queue: Arc>, cursor_queue: Arc>, + transport: Arc>, - mapped: Option, + // TODO(andypython): Remove the need for the spin crate after the `once_cell` + // API is stabilized. + mapped: spin::Once, width: u32, height: u32, @@ -30,24 +45,25 @@ impl<'a> Display<'a> { pub fn new( control_queue: Arc>, cursor_queue: Arc>, - _display_info: &mut DisplayInfo, + transport: Arc>, id: usize, ) -> Self { Self { control_queue, cursor_queue, - mapped: None, + mapped: spin::Once::new(), width: 1920, height: 1080, + transport, id, resource_id: RESOURCE_ALLOC.fetch_add(1, Ordering::SeqCst), } } - async fn get_fpath(&mut self, buffer: &mut [u8]) -> Result { + async fn get_fpath(&self, buffer: &mut [u8]) -> Result { let path = format!("display/virtio-gpu:3.0/{}/{}", self.width, self.height); // Copy the path into the target buffer. @@ -55,7 +71,7 @@ impl<'a> Display<'a> { Ok(path.len()) } - async fn send_request(&mut self, request: Dma) -> Result, Error> { + async fn send_request(&self, request: Dma) -> Result, Error> { let header = Dma::new(ControlHeader::default())?; let command = ChainBuilder::new() .chain(Buffer::new(&request)) @@ -66,15 +82,15 @@ impl<'a> Display<'a> { Ok(header) } - async fn flush_resource(&mut self, flush: ResourceFlush) -> Result<(), Error> { + async fn flush_resource(&self, flush: ResourceFlush) -> Result<(), Error> { let header = self.send_request(Dma::new(flush)?).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); Ok(()) } - async fn map_screen(&mut self, offset: usize) -> Result { - if let Some(mapped) = self.mapped { + async fn map_screen(&self, offset: usize) -> Result { + if let Some(mapped) = self.mapped.get() { return Ok(mapped + offset); } @@ -124,74 +140,128 @@ impl<'a> Display<'a> { self.control_queue.send(command).await; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - self.flush().await?; - self.mapped = Some(mapped); - Ok(mapped + offset) - } - async fn flush(&mut self) -> Result<(), Error> { - let rect = GpuRect::new(0, 0, self.width, self.height); - let scanout_request = Dma::new(SetScanout::new(self.id as u32, self.resource_id, rect))?; + let scanout_request = Dma::new(SetScanout::new( + self.id as u32, + self.resource_id, + GpuRect::new(0, 0, self.width, self.height), + ))?; let header = self.send_request(scanout_request).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - let rect = GpuRect::new(0, 0, self.width, self.height); - let req = Dma::new(XferToHost2d::new(self.resource_id, rect))?; + self.flush(None).await?; + self.mapped.call_once(|| mapped); + + Ok(mapped + offset) + } + + /// If `damage` is `None`, the entire screen is flushed. + async fn flush(&self, damage: Option<&Damage>) -> Result<(), Error> { + let damage = if let Some(damage) = damage { + damage.into() + } else { + GpuRect { + x: 0, + y: 0, + width: self.width, + height: self.height, + } + }; + + let req = Dma::new(XferToHost2d::new( + self.resource_id, + GpuRect { + x: 0, + y: 0, + width: self.width, + height: self.height, + }, + ))?; let header = self.send_request(req).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - let rect = GpuRect::new(0, 0, self.width, self.height); - self.flush_resource(ResourceFlush::new(self.resource_id, rect)) + self.flush_resource(ResourceFlush::new(self.resource_id, damage.clone())) .await?; Ok(()) } + + /// This detaches any backing pages from the display and unrefs the resource. Also resets the + /// device, which is required to go back to legacy mode. + async fn detach(&self) -> Result<(), Error> { + let request = Dma::new(DetachBacking::new(self.resource_id))?; + let header = self.send_request(request).await?; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + + let request = Dma::new(ResourceUnref::new(self.resource_id))?; + let header = self.send_request(request).await?; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + + // Go back to legacy mode. + self.transport.reset(); + Ok(()) + } } pub struct Scheme<'a> { - control_queue: Arc>, - cursor_queue: Arc>, - config: &'a mut GpuConfig, - /// File descriptor allocator. - next_id: AtomicUsize, - handles: BTreeMap>, + handles: BTreeMap>>, + inputd_handle: inputd::Handle, + displays: Vec>>, } impl<'a> Scheme<'a> { - pub fn new( + pub async fn new( config: &'a mut GpuConfig, control_queue: Arc>, cursor_queue: Arc>, - ) -> Result { - Ok(Self { - control_queue, - cursor_queue, + transport: Arc>, + ) -> Result, Error> { + let displays = Self::probe( + control_queue.clone(), + cursor_queue.clone(), + transport.clone(), config, - next_id: AtomicUsize::new(0), + ) + .await?; + + Ok(Self { handles: BTreeMap::new(), + inputd_handle: inputd::Handle::new("virtio-gpu").unwrap(), + displays, }) } - async fn open_display(&self, id: usize) -> Result, Error> { - let mut display_info = self.get_display_info().await?; - let displays = &mut display_info.display_info[..self.config.num_scanouts() as usize]; + async fn probe( + control_queue: Arc>, + cursor_queue: Arc>, + transport: Arc>, + config: &GpuConfig, + ) -> Result>>, Error> { + let mut display_info = Self::get_display_info(control_queue.clone()).await?; + let displays = &mut display_info.display_info[..config.num_scanouts() as usize]; - let display = displays.get_mut(id).ok_or(SysError::new(syscall::ENOENT))?; + let mut result = vec![]; - log::info!( - "virtio-gpu: opening display ({}x{}px)", - display.rect.width(), - display.rect.height() - ); + for (id, info) in displays.iter().enumerate() { + log::info!( + "virtio-gpu: opening display ({}x{}px)", + info.rect().width, + info.rect().height + ); - Ok(Display::new( - self.control_queue.clone(), - self.cursor_queue.clone(), - display, - id, - )) + let display = Display::new( + control_queue.clone(), + cursor_queue.clone(), + transport.clone(), + id, + ); + + result.push(Arc::new(display)); + } + + Ok(result) } - async fn get_display_info(&self) -> Result, Error> { + async fn get_display_info(control_queue: Arc>) -> Result, Error> { let header = Dma::new(ControlHeader { ty: VolatileCell::new(CommandTy::GetDisplayInfo), ..Default::default() @@ -203,7 +273,7 @@ impl<'a> Scheme<'a> { .chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY)) .build(); - self.control_queue.send(command).await; + control_queue.send(command).await; assert!(response.header.ty.get() == CommandTy::RespOkDisplayInfo); Ok(response) @@ -217,16 +287,30 @@ impl<'a> SchemeMut for Scheme<'a> { let mut parts = path.split('/'); let mut screen = parts.next().unwrap_or("").split('.'); - let vt_index = screen.next().unwrap_or("").parse::().unwrap_or(1); + static YES: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true); + if YES.load(Ordering::SeqCst) { + YES.store(false, Ordering::SeqCst); + } + + let fd = screen.next().unwrap_or("").parse::().unwrap(); + + if path.contains("deactivate") { + log::info!("virtio-gpu: deactivating display at file #{}", fd); + + let handle = self.handles.get(&fd).unwrap(); + futures::executor::block_on(handle.detach()).unwrap(); + + return Ok(0); + } + let id = screen.next().unwrap_or("").parse::().unwrap_or(0); - dbg!(&vt_index, &id); + dbg!(&id); - let fd = self.next_id.fetch_add(1, Ordering::SeqCst); - let display = futures::executor::block_on(self.open_display(id)) - .map_err(|_| SysError::new(syscall::ENOENT))?; + let display = self.displays.get(id).ok_or(SysError::new(EINVAL))?; - self.handles.insert(fd, display); + let fd = self.inputd_handle.register().unwrap(); + self.handles.insert(fd, display.clone()); Ok(fd) } @@ -269,7 +353,7 @@ impl<'a> SchemeMut for Scheme<'a> { fn fsync(&mut self, id: usize) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - futures::executor::block_on(handle.flush()).unwrap(); + futures::executor::block_on(handle.flush(None)).unwrap(); Ok(0) } @@ -281,17 +365,16 @@ impl<'a> SchemeMut for Scheme<'a> { fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + let damages = unsafe { + core::slice::from_raw_parts( + buf.as_ptr() as *const Damage, + buf.len() / core::mem::size_of::(), + ) + }; - // SAFETY: lmao - unsafe { - core::ptr::copy_nonoverlapping( - buf.as_ptr(), - handle.mapped.unwrap() as *mut u8, - buf.len(), - ); + for damage in damages { + futures::executor::block_on(handle.flush(Some(damage))).unwrap(); } - - futures::executor::block_on(handle.flush()).unwrap(); Ok(buf.len()) } From c5729befe5e8afa58ce853f22d060028ad6bddc7 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Fri, 7 Jul 2023 17:03:14 +1000 Subject: [PATCH 0649/1301] inputd: do not reswitch if the same Signed-off-by: Anhad Singh --- inputd/src/main.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 3f78339d2e..a963789c06 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -158,11 +158,17 @@ impl SchemeMut for InputScheme { if let Some(new_active) = new_active_opt { if let Some(vt) = self.vts.get(&new_active) { + // If the VT is already active, don't do anything. + if let Some(current) = self.active_vt.as_ref() { + if vt == ¤t.0 { + continue; + } + } + // Result: display/virtio-gpu:3/acvtivate let activate = format!("display/{vt}:{new_active}/activate"); log::info!("inputd: switching to VT #{new_active} ({activate})"); - let file = File::open(&activate).unwrap(); // Drop the old active VT first. // // TODO(andypython): This can be drastically improved by introducting something @@ -180,6 +186,7 @@ impl SchemeMut for InputScheme { } } + let file = File::open(&activate).unwrap(); self.active_vt = Some((vt.clone(), file)); } else { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); From 2b86dc0bc943acc4bc6baa3a6a629f19adfc599d Mon Sep 17 00:00:00 2001 From: Ribbon Date: Sat, 8 Jul 2023 20:34:30 +0000 Subject: [PATCH 0650/1301] Document new drivers and explain what is missing on incomplete drivers --- README.md | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 72e8c1788d..64beec37aa 100644 --- a/README.md +++ b/README.md @@ -3,28 +3,52 @@ These are the currently implemented devices/hardware interfaces. - ac97d - Realtek audio chipsets. -- acpid - ACPI. +- acpid - ACPI (incomplete). + +Lack of drivers for devices defined in AML. + - ahcid - SATA. - alxd - Atheros ethernet (incomplete). + +Lack of datasheet to finish. + +- amlserde - a library to provide serialization/deserialization of the AML symbol table from ACPI (incomplete). - bgad - Bochs emulator/debugger. - block-io-wrapper - Library used by other drivers. - e1000d - Intel Gigabit ethernet. - ided - IDE. - ihdad - Intel HD Audio chipsets. +- inputd - Multiplexes input from multiple input drivers and provides that to Orbital. - ixgbed - Intel 10 Gigabit ethernet. - nvmed - NVMe. - pcid - PCI. - pcspkrd - PC speaker - ps2d - PS/2 +- rtl8139d - Realtek ethernet. - rtl8168d - Realtek ethernet. - sb16d - Sound Blaster audio (incomplete). + +Still need to determine a way to allocate memory under 16MiB for use in ISA DMA. + +- usbctl - USB control (incomplete). + +Missing class drivers for various classes. + +- usbhidd - USB HID (incomplete). + +Has tons of descriptors that are possible, not all are supported. + +- usbscsid - USB SCSI (incomplete). + +Missing class drivers for various classes. + - vboxd - VirtualBox guest. - vesad - VESA. +- virtio-blkd - VirtIO block device (incomplete). +- virtio-core - VirtIO core. +- virtio-gpud - VirtIO GPU device (incomplete). +- virtio-netd - VirtIO net device (incomplete). - xhcid - xHCI (incomplete). -- usbctl - USB control (incomplete). -- usbhidd - USB HID (incomplete). -- usbscsid - USB SCSI (incomplete). -- virtio-* - VirtIO (incomplete) (`virtio-blk`, `virtio-net`, `virtio-gpu`). ## Contributing to Drivers From 17869bfd7736193ec8ad68c5c4db63dedd5d482f Mon Sep 17 00:00:00 2001 From: Ribbon Date: Sat, 8 Jul 2023 20:47:25 +0000 Subject: [PATCH 0651/1301] Update acpid TODO --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 64beec37aa..3efacbf5a5 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,12 @@ These are the currently implemented devices/hardware interfaces. Lack of drivers for devices defined in AML. +The AML parser does not work on real hardware. + +It don't use any ACPI functionality other than S5 shutdown. + +Needs to implement something like "determine the battery status" on real hardware (hard). + - ahcid - SATA. - alxd - Atheros ethernet (incomplete). From 8e0d4cd2cac560dff20c76a16d5babd592e868c3 Mon Sep 17 00:00:00 2001 From: Ribbon Date: Sat, 8 Jul 2023 20:55:14 +0000 Subject: [PATCH 0652/1301] Improve explanation --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3efacbf5a5..0ffd9ea6a6 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ These are the currently implemented devices/hardware interfaces. - ac97d - Realtek audio chipsets. - acpid - ACPI (incomplete). -Lack of drivers for devices defined in AML. +Lack of drivers for devices controlled using AML. The AML parser does not work on real hardware. -It don't use any ACPI functionality other than S5 shutdown. +It doesn't use any ACPI functionality other than S5 shutdown. Needs to implement something like "determine the battery status" on real hardware (hard). From 12420a1c8c28e4e16f29ea866517babb42831242 Mon Sep 17 00:00:00 2001 From: Ribbon Date: Thu, 13 Jul 2023 13:55:35 +0000 Subject: [PATCH 0653/1301] Add kernel functions and the example driver on README --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 0ffd9ea6a6..bd7b2f809c 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,16 @@ Missing class drivers for various classes. - virtio-netd - VirtIO net device (incomplete). - xhcid - xHCI (incomplete). +## Kernel Functions + +These are the most used kernel functions by Redox drivers. + +- `iopl` - syscall that sets the I/O privilege level. x86 has four privilege rings (0/1/2/3), of which the kernel runs in ring 0 and userspace in ring 3. IOPL can only be changed by the kernel, for obvious security reasons, and therefore the Redox kernel needs root to set it. It is unique for each process. Processes with IOPL=3 can access I/O ports, and the kernel can access them as well. +- `physalloc` - allocates physical memory frames. +- `physfree` - frees memory frames. +- `physmap` - maps physical memory frames to driver-accessible virtual memory pages. +- `irq:` - allows getting events from interrupts. It is used primarily by listening for its file descriptors using the `event:` scheme. + ## Contributing to Drivers If you want to write drivers for Redox, datasheets are preferable, when they are freely available. Be aware that datasheets are often provided under a [Non-Disclosure Agreement](https://en.wikipedia.org/wiki/Non-disclosure_agreement) from hardware vendors, which can affect the ability to create an MIT-licensed driver. @@ -63,3 +73,5 @@ If you want to write drivers for Redox, datasheets are preferable, when they are If you don't have datasheets, we recommend you to do reverse-engineering of available C code of BSD drivers. We recommend BSDs drivers because BSD license is compatible with MIT (permissive), that way we can reuse the code in other drivers. + +You can see this [example](https://gitlab.redox-os.org/redox-os/exampled) driver, read the code of the existent ones or the most close driver type for your device. \ No newline at end of file From 95a84c8cbf34b0bcc0e77ee1ea32816cfa3656c5 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Sat, 15 Jul 2023 16:29:48 +1000 Subject: [PATCH 0654/1301] inputd: fix failure to switch VT after inital switch Signed-off-by: Anhad Singh --- inputd/src/main.rs | 45 ++++++++++++++-------------- vesad/src/scheme.rs | 72 +++++++++++++++++---------------------------- 2 files changed, 49 insertions(+), 68 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index a963789c06..b06a0c247d 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -44,7 +44,7 @@ struct InputScheme { vts: BTreeMap>, super_key: bool, - active_vt: Option<(Arc, File)>, + active_vt: Option<(Arc, File, usize /* VT index */)>, } impl InputScheme { @@ -156,38 +156,37 @@ impl SchemeMut for InputScheme { _ => continue, } + let deactivate = |vt, current| { + // Drop the old active VT first. + // + // TODO(andypython): This can be drastically improved by introducting something + // like ioctl() to the display scheme. + let deactivate = format!("display/{}:{current}/deactivate", vt); + let _ = File::open(&deactivate); + }; + if let Some(new_active) = new_active_opt { if let Some(vt) = self.vts.get(&new_active) { // If the VT is already active, don't do anything. - if let Some(current) = self.active_vt.as_ref() { - if vt == ¤t.0 { + if let Some((vt, _, current)) = self.active_vt.as_ref() { + if new_active == *current { continue; } + + deactivate(vt, *current); + } else { + let id = self.next_vt_id.load(Ordering::SeqCst) - 1; + let vt = self.vts.get(&id).unwrap(); + + deactivate(vt, id); } - + // Result: display/virtio-gpu:3/acvtivate let activate = format!("display/{vt}:{new_active}/activate"); - log::info!("inputd: switching to VT #{new_active} ({activate})"); - - // Drop the old active VT first. - // - // TODO(andypython): This can be drastically improved by introducting something - // like ioctl() to the display scheme. - for (vt, device) in self.vts.iter() { - if vt == &new_active { - continue; - } - - let deactivate = format!("display/{device}:{}/deactivate", vt); - let _ = File::open(&deactivate); - - if device.contains("virtio") { - break; - } - } + log::info!("inputd: switching to VT #{new_active} (`{activate}`)"); let file = File::open(&activate).unwrap(); - self.active_vt = Some((vt.clone(), file)); + self.active_vt = Some((vt.clone(), file, new_active)); } else { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); } diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 493eb7888e..7577ace6fc 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -10,10 +10,10 @@ use crate::{ screen::{Screen, GraphicScreen, TextScreen}, }; -#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)] pub struct VtIndex(usize); -#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd)] +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)] pub struct ScreenIndex(usize); #[derive(Clone)] @@ -144,61 +144,43 @@ impl DisplayScheme { } impl SchemeMut for DisplayScheme { - fn open(&mut self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result { - if path_str == "input" { - if uid == 0 { + fn open(&mut self, path_str: &str, flags: usize, _uid: u32, _gid: u32) -> Result { + let mut parts = path_str.split('/'); + let mut vt_screen = parts.next().unwrap_or("").split('.'); + let vt_i = VtIndex( + vt_screen.next().unwrap_or("").parse::().unwrap_or(1) + ); + let screen_i = ScreenIndex( + vt_screen.next().unwrap_or("").parse::().unwrap_or(0) + ); + if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { + for cmd in parts { + if cmd == "activate" { + self.active = vt_i; + screen.redraw( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); + } + } + let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle { - kind: HandleKind::Input, - flags: flags, + kind: HandleKind::Screen(vt_i, screen_i), + flags, events: EventFlags::empty(), notified_read: false }); Ok(id) - } else { - Err(Error::new(EACCES)) - } - } else { - let mut parts = path_str.split('/'); - let mut vt_screen = parts.next().unwrap_or("").split('.'); - let vt_i = VtIndex( - vt_screen.next().unwrap_or("").parse::().unwrap_or(1) - ); - let screen_i = ScreenIndex( - vt_screen.next().unwrap_or("").parse::().unwrap_or(0) - ); - if let Some(screens) = self.vts.get_mut(&vt_i) { - if let Some(screen) = screens.get_mut(&screen_i) { - for cmd in parts { - if cmd == "activate" { - self.active = vt_i; - screen.redraw( - self.onscreens[screen_i.0], - self.framebuffers[screen_i.0].stride - ); - } - } - - let id = self.next_id; - self.next_id += 1; - - self.handles.insert(id, Handle { - kind: HandleKind::Screen(vt_i, screen_i), - flags: flags, - events: EventFlags::empty(), - notified_read: false - }); - - Ok(id) - } else { - Err(Error::new(ENOENT)) - } } else { Err(Error::new(ENOENT)) } + } else { + Err(Error::new(ENOENT)) } } From 07c3297134248e30eaa4ff09546311503ebad401 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 17 Jul 2023 19:33:25 -0600 Subject: [PATCH 0655/1301] ahcid: Use interrupts --- ahcid/src/ahci/disk_ata.rs | 17 ++--------------- ahcid/src/ahci/hba.rs | 2 +- 2 files changed, 3 insertions(+), 16 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index b401a9457e..adb0fa4045 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -1,6 +1,5 @@ use std::convert::TryInto; use std::ptr; -use std::thread; use syscall::io::Dma; use syscall::error::Result; @@ -66,8 +65,6 @@ impl DiskATA { BufferKind::Write(ref buffer) => (true, buffer.as_ptr() as usize, buffer.len()/512), }; - //TODO: Go back to interrupt magic - let use_interrupts = false; loop { let mut request = match self.request_opt.take() { Some(request) => if address == request.address && total_sectors == request.total_sectors { @@ -95,12 +92,7 @@ impl DiskATA { // Continue waiting for request request.running_opt = Some(running); self.request_opt = Some(request); - if use_interrupts { - return Ok(None); - } else { - thread::yield_now(); - continue; - } + return Ok(None); } self.port.ata_stop(running.0)?; @@ -130,12 +122,7 @@ impl DiskATA { self.request_opt = Some(request); - if use_interrupts { - return Ok(None); - } else { - thread::yield_now(); - continue; - } + return Ok(None); } else { // Done return Ok(Some(request.sector * 512)); diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index f2839f8f25..2bb122ff39 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -117,7 +117,7 @@ impl HbaPort { self.fb[1].write(((fb.physical() as u64) >> 32) as u32); let is = self.is.read(); self.is.write(is); - self.ie.write(0 /*TODO: Enable interrupts: 0b10111*/); + self.ie.write(0b10111); let serr = self.serr.read(); self.serr.write(serr); From 5256a9af471d28142cb0f32b9b352202f0aa2f11 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 17 Jul 2023 19:51:53 -0600 Subject: [PATCH 0656/1301] nvmed: enable async feature --- nvmed/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index f219f0100d..93bc5cf18f 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -19,5 +19,5 @@ block-io-wrapper = { path = "../block-io-wrapper" } pcid = { path = "../pcid" } [features] -default = [] +default = ["async"] async = [] From 094e3ba548059d214f43eac7653d60396b6237f1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Jul 2023 01:13:26 +0200 Subject: [PATCH 0657/1301] Add a crate for driver helpers. --- Cargo.toml | 1 + common/Cargo.toml | 11 +++++++++ common/src/lib.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 common/Cargo.toml create mode 100644 common/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index c7c25c1e42..2c9b8d6e06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "alxd", "bgad", "block-io-wrapper", + "common", "e1000d", "ided", "ihdad", diff --git a/common/Cargo.toml b/common/Cargo.toml new file mode 100644 index 0000000000..7313a2eb95 --- /dev/null +++ b/common/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "common" +version = "0.1.0" +edition = "2021" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +redox_syscall = "0.3" diff --git a/common/src/lib.rs b/common/src/lib.rs new file mode 100644 index 0000000000..85f976f332 --- /dev/null +++ b/common/src/lib.rs @@ -0,0 +1,57 @@ +#![feature(int_roundings)] + +use syscall::PAGE_SIZE; +use syscall::error::{Error, Result, EINVAL}; +use syscall::flag::{MapFlags, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; + +#[derive(Clone, Copy, Debug)] +pub enum MemoryType { + Writeback, + Uncacheable, + WriteCombining, +} +impl Default for MemoryType { + fn default() -> Self { + Self::Writeback + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Prot { + pub read: bool, + pub write: bool, +} +impl Prot { + pub const RO: Self = Self { read: true, write: false }; + pub const WO: Self = Self { read: false, write: true }; + pub const RW: Self = Self { read: true, write: true }; +} + +pub unsafe fn physmap(base_phys: usize, len: usize, Prot { read, write }: Prot, ty: MemoryType) -> Result<*mut ()> { + // TODO: arraystring? + let path = format!("memory:physical@{}", match ty { + MemoryType::Writeback => "wb", + MemoryType::Uncacheable => "uc", + MemoryType::WriteCombining => "wc", + }); + let mode = match (read, write) { + (true, true) => O_RDWR, + (true, false) => O_RDONLY, + (false, true) => O_WRONLY, + (false, false) => return Err(Error::new(EINVAL)), + }; + let mut prot = MapFlags::empty(); + prot.set(MapFlags::PROT_READ, read); + prot.set(MapFlags::PROT_WRITE, write); + + let file = syscall::open(path, O_CLOEXEC | mode)?; + let base = syscall::fmap(file, &syscall::Map { + offset: base_phys, + size: len.next_multiple_of(PAGE_SIZE), + flags: MapFlags::MAP_SHARED | prot, + address: 0, + }); + let _ = syscall::close(file); + + Ok(base? as *mut ()) +} From 6e94a9e2362b7338857454d62c739dc7b594d08b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Jul 2023 01:14:19 +0200 Subject: [PATCH 0658/1301] Remove physmap for disk drivers. --- ahcid/Cargo.toml | 2 ++ ahcid/src/main.rs | 13 ++++++++----- nvmed/Cargo.toml | 3 ++- nvmed/src/main.rs | 18 ++++++++++++------ 4 files changed, 24 insertions(+), 12 deletions(-) diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index bb62d6da12..85704b42a1 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -11,4 +11,6 @@ partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } redox-daemon = "0.1" redox-log = "0.1" redox_syscall = "0.3" + block-io-wrapper = { path = "../block-io-wrapper" } +common = { path = "../common" } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 05ed80fb8a..584f6e1ec2 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -9,10 +9,9 @@ use std::fs::File; use std::io::{ErrorKind, Read, Write}; use std::os::unix::io::{FromRawFd, RawFd}; -use syscall::PAGE_SIZE; use syscall::error::{Error, ENODEV}; use syscall::data::{Event, Packet}; -use syscall::flag::{EVENT_READ, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::flag::EVENT_READ; use syscall::scheme::SchemeBlockMut; use log::{error, info}; @@ -91,8 +90,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { info!(" + AHCI {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); let address = unsafe { - syscall::physmap(bar, bar_size.next_multiple_of(PAGE_SIZE), PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("ahcid: failed to map address") + common::physmap( + bar, + bar_size, + common::Prot { read: true, write: true }, + common::MemoryType::Uncacheable, + ).expect("ahcid: failed to map address") }; { let scheme_name = format!("disk/{}", name); @@ -126,7 +129,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { data: 0 }).expect("ahcid: failed to event irq scheme"); - let (hba_mem, disks) = ahci::disks(address, &name); + let (hba_mem, disks) = ahci::disks(address as usize, &name); let mut scheme = DiskScheme::new(scheme_name, hba_mem, disks); let mut mounted = true; diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index 93bc5cf18f..039cdeac61 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -14,8 +14,9 @@ redox-log = "0.1" redox_syscall = "0.3" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } smallvec = "1" -block-io-wrapper = { path = "../block-io-wrapper" } +block-io-wrapper = { path = "../block-io-wrapper" } +common = { path = "../common" } pcid = { path = "../pcid" } [features] diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 420742704a..65da7182c1 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -11,8 +11,8 @@ use std::{slice, usize}; use pcid_interface::{PciBar, PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; use syscall::{ - Event, Mmio, Packet, Result, SchemeBlockMut, PHYSMAP_NO_CACHE, - PHYSMAP_WRITE, PAGE_SIZE, + Event, Mmio, Packet, Result, SchemeBlockMut, + PAGE_SIZE, }; use redox_log::{OutputBuilder, RedoxLogger}; @@ -32,7 +32,12 @@ impl Bar { pub fn allocate(bar: usize, bar_size: usize) -> Result { Ok(Self { ptr: NonNull::new( - unsafe { syscall::physmap(bar, bar_size, PHYSMAP_NO_CACHE | PHYSMAP_WRITE)? as *mut u8 }, + unsafe { common::physmap( + bar, + bar_size, + common::Prot { read: true, write: true }, + common::MemoryType::Uncacheable, + )? as *mut u8 }, ) .expect("Mapping a BAR resulted in a nullptr"), physical: bar, @@ -318,13 +323,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let allocated_bars = AllocatedBars::default(); let address = unsafe { - syscall::physmap( + common::physmap( bar as usize, bar_size as usize, - PHYSMAP_WRITE | PHYSMAP_NO_CACHE, + common::Prot { read: true, write: true }, + common::MemoryType::Uncacheable, ) .expect("nvmed: failed to map address") - }; + } as usize; *allocated_bars.0[0].lock().unwrap() = Some(Bar { physical: bar as usize, bar_size: bar_size as usize, From e0a0e2a53206681db2ff227ef522512eabe106bf Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Jul 2023 01:14:27 +0200 Subject: [PATCH 0659/1301] Remove physmap in pcid. --- pcid/Cargo.toml | 2 ++ pcid/src/pcie/mod.rs | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 20276cb043..1226f32d9d 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -27,3 +27,5 @@ smallvec = "1" structopt = { version = "0.3", default-features = false, features = [ "paw" ] } thiserror = "1" toml = "0.5" + +common = { path = "../common" } diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 7c73d84767..995f4b7482 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -3,7 +3,6 @@ use std::collections::BTreeMap; use std::sync::{Arc, Mutex}; use syscall::PAGE_SIZE; -use syscall::flag::PhysmapFlags; use smallvec::SmallVec; @@ -173,7 +172,14 @@ impl Pcie { }; let mut maps_lock = self.maps.lock().unwrap(); let virt_pointer = maps_lock.entry((bus, dev, func)).or_insert_with(|| { - syscall::physmap(base_address_phys as usize + Self::addr_offset_in_bytes(starting_bus, bus, dev, func, 0), PAGE_SIZE, PhysmapFlags::PHYSMAP_NO_CACHE | PhysmapFlags::PHYSMAP_WRITE).unwrap_or_else(|error| panic!("failed to physmap pcie configuration space for {:2x}:{:2x}.{:2x}: {:?}", bus, dev, func, error)) as *mut u32 + common::physmap( + base_address_phys as usize + Self::addr_offset_in_bytes(starting_bus, bus, dev, func, 0), + PAGE_SIZE, + common::Prot { read: true, write: true }, + common::MemoryType::Uncacheable, + ).unwrap_or_else(|error| { + panic!("failed to physmap pcie configuration space for {:2x}:{:2x}.{:2x}: {:?}", bus, dev, func, error) + }) as *mut u32 }); f(Some(&mut *virt_pointer.offset((offset as usize / mem::size_of::()) as isize))) } From a0d233030b124172579f5e14c10d4806bd8c04c0 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Jul 2023 01:14:37 +0200 Subject: [PATCH 0660/1301] Remove physmap in vesad. --- vesad/Cargo.toml | 2 ++ vesad/src/framebuffer.rs | 5 +++-- vesad/src/scheme.rs | 7 ++++--- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 9b247aabe2..617aeb6787 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -9,6 +9,8 @@ ransid = "0.4" rusttype = { version = "0.2", optional = true } redox_syscall = "0.3" redox-daemon = "0.1" + +common = { path = "../common" } inputd = { path = "../inputd" } [features] diff --git a/vesad/src/framebuffer.rs b/vesad/src/framebuffer.rs index f3b879210e..28d30907ad 100644 --- a/vesad/src/framebuffer.rs +++ b/vesad/src/framebuffer.rs @@ -46,10 +46,11 @@ impl FrameBuffer { pub unsafe fn map(&mut self) -> syscall::Result<&'static mut [u32]> { let size = self.stride * self.height; - let virt = syscall::physmap( + let virt = common::physmap( self.phys, size * 4, - syscall::PHYSMAP_WRITE | syscall::PHYSMAP_WRITE_COMBINE + common::Prot { read: true, write: true }, + common::MemoryType::WriteCombining, )? as *mut u32; //TODO: should we clear the framebuffer here? ptr::write_bytes(virt, 0, size); diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 7577ace6fc..c6a17b9509 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::{mem, ptr, slice, str}; use orbclient::{Event, EventOption}; -use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, physmap, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, Result, SchemeMut, PAGE_SIZE}; +use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE}; use crate::{ display::Display, @@ -111,10 +111,11 @@ impl DisplayScheme { // Map new onscreen self.onscreens[fb_i] = unsafe { let size = stride * height; - let onscreen_ptr = physmap( + let onscreen_ptr = common::physmap( self.framebuffers[fb_i].phys, size * 4, - PHYSMAP_WRITE | PHYSMAP_WRITE_COMBINE + common::Prot { read: true, write: true }, + common::MemoryType::WriteCombining, ).expect("vesad: failed to map framebuffer") as *mut u32; ptr::write_bytes(onscreen_ptr, 0, size); From 477b1c0adac519c5c66908231ef3d84c6c38c87e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Jul 2023 01:16:07 +0200 Subject: [PATCH 0661/1301] Remove physmap in acpid. --- acpid/Cargo.toml | 4 +++- acpid/src/acpi.rs | 4 +--- acpid/src/acpi/dmar/drhd.rs | 2 +- acpid/src/aml_physmem.rs | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index f093a1e284..6914a81e68 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -19,4 +19,6 @@ redox_syscall = "0.3" rustc-hash = "1.1.0" thiserror = "1" serde_json = "1.0.94" -amlserde = { path = "../amlserde" } \ No newline at end of file + +amlserde = { path = "../amlserde" } +common = { path = "../common" } diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 77ed3b9d8f..bce1f2f6e0 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -5,8 +5,6 @@ use std::ops::Deref; use std::sync::{Arc, Mutex}; use std::{fmt, mem}; -use syscall::flag::PhysmapFlags; - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use syscall::io::{Io, Pio}; @@ -106,7 +104,7 @@ impl PhysmapGuard { fn map(page: usize, page_count: usize) -> std::io::Result { let size = page_count * PAGE_SIZE; let virt = unsafe { - syscall::call::physmap(page, size, PhysmapFlags::empty()) + common::physmap(page, size, common::Prot::RO, common::MemoryType::default()) .map_err(|error| std::io::Error::from_raw_os_error(error.errno))? }; diff --git a/acpid/src/acpi/dmar/drhd.rs b/acpid/src/acpi/dmar/drhd.rs index 67625974d7..091f553e95 100644 --- a/acpid/src/acpi/dmar/drhd.rs +++ b/acpid/src/acpi/dmar/drhd.rs @@ -14,7 +14,7 @@ impl DrhdPage { // TODO: Uncachable? Can reads have side-effects? let virt = unsafe { - syscall::physmap(base_phys, crate::acpi::PAGE_SIZE, syscall::PhysmapFlags::PHYSMAP_WRITE)? + common::physmap(base_phys, crate::acpi::PAGE_SIZE, common::Prot::RO, common::MemoryType::default())? } as *mut Drhd; Ok(Self { virt }) diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 953b0ac911..98d78f1910 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -3,7 +3,7 @@ use rustc_hash::FxHashMap; use std::fmt::LowerHex; use std::mem::size_of; use std::sync::{Arc, Mutex}; -use syscall::{Io, PhysmapFlags, Pio, PAGE_SIZE}; +use syscall::{Io, Pio, PAGE_SIZE}; const PAGE_MASK: usize = !(PAGE_SIZE - 1); const OFFSET_MASK: usize = PAGE_SIZE - 1; @@ -16,9 +16,9 @@ struct MappedPage { impl MappedPage { fn new(phys_page: usize) -> std::io::Result { let virt_page = unsafe { - syscall::physmap(phys_page, PAGE_SIZE, PhysmapFlags::empty()) + common::physmap(phys_page, PAGE_SIZE, common::Prot::RO, common::MemoryType::default()) .map_err(|error| std::io::Error::from_raw_os_error(error.errno))? - }; + } as usize; Ok(Self { phys_page, virt_page, From c63c266400e77d6c2c3fdd9225e62cc6ae87b47a Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Jul 2023 01:16:25 +0200 Subject: [PATCH 0662/1301] Remove physmap in virtio. --- virtio-core/Cargo.toml | 1 + virtio-core/src/probe.rs | 11 ++++++----- virtio-core/src/transport.rs | 13 +++++++------ virtio-gpud/Cargo.toml | 1 + virtio-gpud/src/scheme.rs | 7 ++++--- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/virtio-core/Cargo.toml b/virtio-core/Cargo.toml index 9a8c197b5d..c060fabe78 100644 --- a/virtio-core/Cargo.toml +++ b/virtio-core/Cargo.toml @@ -16,4 +16,5 @@ crossbeam-queue = "0.3.8" redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +common = { path = "../common" } pcid = { path = "../pcid" } diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 58e9466659..c9fad8427e 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -8,7 +8,7 @@ use pcid_interface::msi::x86_64::DeliveryMode; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use pcid_interface::*; -use syscall::{Io, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::Io; use crate::spec::*; use crate::transport::{Error, StandardTransport}; @@ -68,11 +68,12 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { }; let address = unsafe { - syscall::physmap( + common::physmap( bar_ptr as usize, bar_size as usize, - PHYSMAP_WRITE | PHYSMAP_NO_CACHE, - )? + common::Prot::RW, + common::MemoryType::Uncacheable, + )? as usize }; // Ensure that the table and PBA are be within the BAR. @@ -186,7 +187,7 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result let size = offset + capability.length as usize; - let addr = syscall::physmap(aligned_addr, size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE)?; + let addr = common::physmap(aligned_addr, size, common::Prot::RW, common::MemoryType::Uncacheable)? as usize; addr + offset }; diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index a1a913d3fd..2f049a1dab 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -2,7 +2,7 @@ use crate::spec::*; use crate::utils::align; use event::EventQueue; -use syscall::{Dma, PHYSMAP_WRITE}; +use syscall::Dma; use core::mem::size_of; use core::sync::atomic::{AtomicU16, Ordering}; @@ -230,8 +230,9 @@ impl<'a> Available<'a> { let size = size.next_multiple_of(syscall::PAGE_SIZE); // align to page size let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; - let virt = - unsafe { syscall::physmap(addr, size, PHYSMAP_WRITE) }.map_err(Error::SyscallError)?; + let virt = unsafe { + common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) + }.map_err(Error::SyscallError)?; let ring = unsafe { &mut *(virt as *mut AvailableRing) }; @@ -275,7 +276,7 @@ impl Drop for Available<'_> { log::warn!("virtio-core: dropping 'available' ring at {:#x}", self.addr); unsafe { - syscall::physunmap(self.addr).unwrap(); + syscall::funmap(self.addr, self.size).unwrap(); syscall::physfree(self.addr, self.size).unwrap(); } } @@ -297,7 +298,7 @@ impl<'a> Used<'a> { let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; let virt = - unsafe { syscall::physmap(addr, size, PHYSMAP_WRITE) }.map_err(Error::SyscallError)?; + unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) }.map_err(Error::SyscallError)?; let ring = unsafe { &mut *(virt as *mut UsedRing) }; @@ -355,7 +356,7 @@ impl Drop for Used<'_> { log::warn!("virtio-core: dropping 'used' ring at {:#x}", self.addr); unsafe { - syscall::physunmap(self.addr).unwrap(); + syscall::funmap(self.addr, self.size).unwrap(); syscall::physfree(self.addr, self.size).unwrap(); } } diff --git a/virtio-gpud/Cargo.toml b/virtio-gpud/Cargo.toml index c06c18d87e..8979a09873 100644 --- a/virtio-gpud/Cargo.toml +++ b/virtio-gpud/Cargo.toml @@ -11,6 +11,7 @@ futures = { version = "0.3.28", features = ["executor"] } anyhow = "1.0.71" paste = "1.0.13" +common = { path = "../common" } virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } inputd = { path = "../inputd" } diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index b0490c8cce..ed202693e3 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -113,12 +113,13 @@ impl<'a> Display<'a> { .next_multiple_of(syscall::PAGE_SIZE); let address = unsafe { syscall::physalloc(fb_size) }? as u64; let mapped = unsafe { - syscall::physmap( + common::physmap( address as usize, fb_size, - syscall::PhysmapFlags::PHYSMAP_WRITE, + common::Prot::RW, + common::MemoryType::default(), ) - }?; + }? as usize; unsafe { core::ptr::write_bytes(mapped as *mut u8, 255, fb_size); From 8555b8ab3d1af458b0d8d0617f402c39e9fa0b27 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Jul 2023 01:29:21 +0200 Subject: [PATCH 0663/1301] Remove physmap in non-initfs drivers too. --- alxd/Cargo.toml | 2 ++ alxd/src/main.rs | 4 ++-- e1000d/Cargo.toml | 2 ++ e1000d/src/main.rs | 6 +++--- ihdad/Cargo.toml | 1 + ihdad/src/hda/device.rs | 7 +++---- ihdad/src/hda/stream.rs | 6 +++--- ihdad/src/main.rs | 6 +++--- ixgbed/Cargo.toml | 2 ++ ixgbed/src/main.rs | 6 +++--- rtl8139d/Cargo.toml | 1 + rtl8139d/src/main.rs | 10 +++++----- rtl8168d/Cargo.toml | 1 + rtl8168d/src/main.rs | 10 +++++----- vboxd/Cargo.toml | 2 ++ vboxd/src/main.rs | 4 ++-- xhcid/Cargo.toml | 1 + xhcid/src/main.rs | 6 +++--- 18 files changed, 44 insertions(+), 33 deletions(-) diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml index 4d1a83dce0..a9865f295a 100644 --- a/alxd/Cargo.toml +++ b/alxd/Cargo.toml @@ -9,3 +9,5 @@ netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" redox-daemon = "0.1" + +common = { path = "../common" } diff --git a/alxd/src/main.rs b/alxd/src/main.rs index 6f125a855f..4de3005c6e 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -15,7 +15,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{EventFlags, Packet, SchemeMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{EventFlags, Packet, SchemeMut}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -43,7 +43,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("alxd: failed to open IRQ file"); - let address = unsafe { syscall::physmap(bar, 128*1024, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("alxd: failed to map address") }; + let address = unsafe { common::physmap(bar, 128*1024, common::Prot::RW, common::MemoryType::Uncacheable).expect("alxd: failed to map address") as usize }; { let device = Arc::new(RefCell::new(unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") })); diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index c7d5abaacd..2f2470cfbd 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -9,3 +9,5 @@ netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" + +common = { path = "../common" } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index e0353af679..2e2a617c8f 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -10,7 +10,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; -use syscall::{EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{EventFlags, Packet, SchemeBlockMut}; pub mod device; @@ -91,9 +91,9 @@ fn main() { let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; let address = unsafe { - syscall::physmap(bar, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + common::physmap(bar, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) .expect("e1000d: failed to map address") - }; + } as usize; { let device = Arc::new(RefCell::new(unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") diff --git a/ihdad/Cargo.toml b/ihdad/Cargo.toml index 7ef0407d69..084efca393 100755 --- a/ihdad/Cargo.toml +++ b/ihdad/Cargo.toml @@ -12,4 +12,5 @@ redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" spin = "0.9" +common = { path = "../common" } pcid = { path = "../pcid" } diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 578299793e..9778ba1b09 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -7,7 +7,6 @@ use std::str; use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; -use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::io::{Mmio, Io}; @@ -159,8 +158,8 @@ impl IntelHDA { .expect("Could not allocate physical memory for buffer descriptor list."); let buff_desc_virt = - syscall::physmap(buff_desc_phys, 0x1000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("ihdad: failed to map address for buffer descriptor list."); + common::physmap(buff_desc_phys, 0x1000, common::Prot::RW, common::MemoryType::Uncacheable) + .expect("ihdad: failed to map address for buffer descriptor list.") as usize; log::debug!("Virt: {:016X}, Phys: {:016X}", buff_desc_virt, buff_desc_phys); @@ -170,7 +169,7 @@ impl IntelHDA { syscall::physalloc(0x1000) .expect("Could not allocate physical memory for CORB and RIRB."); - let cmd_buff_virt = syscall::physmap(cmd_buff_address, 0x1000, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("ihdad: failed to map address for CORB/RIRB buff"); + let cmd_buff_virt = common::physmap(cmd_buff_address, 0x1000, common::Prot::RW, common::MemoryType::Uncacheable).expect("ihdad: failed to map address for CORB/RIRB buff") as usize; log::debug!("Virt: {:016X}, Phys: {:016X}", cmd_buff_virt, cmd_buff_address); let mut module = IntelHDA { diff --git a/ihdad/src/hda/stream.rs b/ihdad/src/hda/stream.rs index dbdc3ad79c..3f1e383419 100644 --- a/ihdad/src/hda/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -1,4 +1,4 @@ -use syscall::{PHYSMAP_WRITE, PHYSMAP_NO_CACHE, PAGE_SIZE}; +use syscall::PAGE_SIZE; use syscall::error::{Error, EIO, Result}; use syscall::io::{Mmio, Io}; use std::result; @@ -301,9 +301,9 @@ impl StreamBuffer { }; let addr = match unsafe { - syscall::physmap(phys, page_aligned_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) + common::physmap(phys, page_aligned_size, common::Prot::RW, common::MemoryType::Uncacheable) } { - Ok(addr) => addr, + Ok(ptr) => ptr as usize, Err(_err) => { unsafe { syscall::physfree(phys, page_aligned_size); diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index f77b2c278e..6362fcb4e7 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -11,7 +11,7 @@ use std::usize; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use syscall::{PHYSMAP_NO_CACHE, PHYSMAP_WRITE, Packet, SchemeBlockMut, EventFlags}; +use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; @@ -177,8 +177,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::info!(" + IHDA {} on: {:#X} size: {}", name, bar_ptr, bar_size); let address = unsafe { - syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("ihdad: failed to map address") + common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) + .expect("ihdad: failed to map address") as usize }; //TODO: MSI-X diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml index 1884d76457..2df2b871b2 100644 --- a/ixgbed/Cargo.toml +++ b/ixgbed/Cargo.toml @@ -8,3 +8,5 @@ netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" redox-daemon = "0.1" + +common = { path = "../common" } diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index 7bbd3a42fb..b1906fadc8 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -11,7 +11,7 @@ use std::{env, thread}; use event::EventQueue; use std::time::Duration; -use syscall::{EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{EventFlags, Packet, SchemeBlockMut}; pub mod device; #[rustfmt::skip] @@ -92,8 +92,8 @@ fn main() { File::open(format!("irq:{}", irq)).expect("ixgbed: failed to open IRQ file"); let address = unsafe { - syscall::physmap(bar, IXGBE_MMIO_SIZE, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("ixgbed: failed to map address") + common::physmap(bar, IXGBE_MMIO_SIZE, common::Prot::RW, common::MemoryType::Uncacheable) + .expect("ixgbed: failed to map address") as usize }; { let device = Arc::new(RefCell::new( diff --git a/rtl8139d/Cargo.toml b/rtl8139d/Cargo.toml index 48d15ec8ba..9dc4b9d24d 100644 --- a/rtl8139d/Cargo.toml +++ b/rtl8139d/Cargo.toml @@ -12,4 +12,5 @@ redox_syscall = "0.3" redox-daemon = "0.1" redox-log = "0.1" +common = { path = "../common" } pcid = { path = "../pcid" } diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index 49edbd9598..eac441a25f 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -18,7 +18,7 @@ use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeature use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector}; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use redox_log::{RedoxLogger, OutputBuilder}; -use syscall::{EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{EventFlags, Packet, SchemeBlockMut}; use syscall::io::Io; pub mod device; @@ -187,8 +187,8 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { }; let address = unsafe { - syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("rtl8139d: failed to map address") + common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) + .expect("rtl8139d: failed to map address") as usize }; if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u64 + table_min_length as u64)) { @@ -345,8 +345,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::info!(" + RTL8139 {} on: {:#X} size: {}", name, bar_ptr, bar_size); let address = unsafe { - syscall::physmap(bar_ptr, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("rtl8139d: failed to map address") + common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) + .expect("rtl8139d: failed to map address") as usize }; let socket_fd = syscall::open( diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index 16579d808b..9cd8099fe2 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -12,4 +12,5 @@ redox_syscall = "0.3" redox-daemon = "0.1" redox-log = "0.1" +common = { path = "../common" } pcid = { path = "../pcid" } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index dae8c8a62e..2eea0c80f1 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -16,7 +16,7 @@ use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeature use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector}; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use redox_log::{RedoxLogger, OutputBuilder}; -use syscall::{EventFlags, Packet, SchemeBlockMut, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::{EventFlags, Packet, SchemeBlockMut}; use syscall::io::Io; pub mod device; @@ -185,8 +185,8 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { }; let address = unsafe { - syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("rtl8168d: failed to map address") + common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) + .expect("rtl8168d: failed to map address") as usize }; if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u64 + table_min_length as u64)) { @@ -343,8 +343,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::info!(" + RTL8168 {} on: {:#X} size: {}", name, bar_ptr, bar_size); let address = unsafe { - syscall::physmap(bar_ptr, bar_size, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("rtl8168d: failed to map address") + common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) + .expect("rtl8168d: failed to map address") as usize }; let socket_fd = syscall::open( diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index 601f88ece6..bae4b35c82 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -8,3 +8,5 @@ orbclient = "0.3.27" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" redox-daemon = "0.1" + +common = { path = "../common" } diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index c42c8da424..de94f4ba9e 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -11,7 +11,7 @@ use std::fs::File; use std::io::{Result, Read, Write}; use syscall::call::iopl; -use syscall::flag::{EventFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::flag::EventFlags; use syscall::io::{Dma, Io, Mmio, Pio}; use crate::bga::Bga; @@ -220,7 +220,7 @@ fn main() { let mut irq_file = File::open(format!("irq:{}", irq)).expect("vboxd: failed to open IRQ file"); let mut port = Pio::::new(bar0 as u16); - let address = unsafe { syscall::physmap(bar1, 4096, PHYSMAP_WRITE | PHYSMAP_NO_CACHE).expect("vboxd: failed to map address") }; + let address = unsafe { common::physmap(bar1, 4096, common::Prot::RW, common::MemoryType::Uncacheable).expect("vboxd: failed to map address") }; { let vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index a8d6a799f5..db53e8ed36 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -29,4 +29,5 @@ smallvec = { version = "1", features = ["serde"] } thiserror = "1" toml = "0.5" +common = { path = "../common" } pcid = { path = "../pcid" } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 8ccfd50653..decacdd666 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -19,7 +19,7 @@ use event::{Event, EventQueue}; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; -use syscall::flag::{EventFlags, PHYSMAP_NO_CACHE, PHYSMAP_WRITE}; +use syscall::flag::EventFlags; use syscall::scheme::Scheme; use syscall::io::Io; @@ -264,8 +264,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { }; let address = unsafe { - syscall::physmap(bar_ptr as usize, bar_size as usize, PHYSMAP_WRITE | PHYSMAP_NO_CACHE) - .expect("xhcid: failed to map address") + common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) + .expect("xhcid: failed to map address") as usize }; let (mut irq_file, interrupt_method) = get_int_method(&mut pcid_handle, address); From 25b1f7bfeadb35bef01ada4c2e9209bf4e2259a1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 18 Jul 2023 11:08:03 +0200 Subject: [PATCH 0664/1301] Update dependencies. --- Cargo.lock | 372 +++++++++++++++++++---------------------------------- 1 file changed, 129 insertions(+), 243 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a9ffa5805..29f885ada3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,7 @@ version = "0.1.0" dependencies = [ "aml", "amlserde", + "common", "log", "num-derive", "num-traits", @@ -41,6 +42,7 @@ dependencies = [ "bitflags 1.2.1", "block-io-wrapper", "byteorder 1.4.3", + "common", "log", "partitionlib", "redox-daemon", @@ -53,6 +55,7 @@ name = "alxd" version = "0.1.0" dependencies = [ "bitflags 1.2.1", + "common", "netutils", "redox-daemon", "redox_event", @@ -78,9 +81,15 @@ dependencies = [ "aml", "rustc-hash", "serde", - "toml 0.7.3", + "toml 0.7.6", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -101,9 +110,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" [[package]] name = "arg_parser" @@ -189,9 +198,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitflags" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbe3c979c178231552ecba20214a8272df4e09f232a87aef4320cf06539aded" +checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" [[package]] name = "bitvec" @@ -217,9 +226,9 @@ checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byteorder" @@ -263,13 +272,13 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", "js-sys", - "num-integer", "num-traits", "time", "wasm-bindgen", @@ -301,22 +310,10 @@ dependencies = [ ] [[package]] -name = "cmake" -version = "0.1.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" +name = "common" +version = "0.1.0" dependencies = [ - "cc", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", + "redox_syscall 0.3.5", ] [[package]] @@ -346,12 +343,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.15", + "crossbeam-utils 0.8.16", ] [[package]] @@ -361,7 +358,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" dependencies = [ "cfg-if 1.0.0", - "crossbeam-utils 0.8.15", + "crossbeam-utils 0.8.16", ] [[package]] @@ -377,74 +374,31 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - -[[package]] -name = "cxx" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 2.0.13", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.94" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.13", -] - [[package]] name = "e1000d" version = "0.1.0" dependencies = [ "bitflags 1.2.1", + "common", "netutils", "redox-daemon", "redox_event", "redox_syscall 0.3.5", ] +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "extra" version = "0.1.0" @@ -534,7 +488,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.26", ] [[package]] @@ -580,9 +534,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" [[package]] name = "heck" @@ -604,9 +558,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -618,12 +572,11 @@ dependencies = [ [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -655,6 +608,7 @@ name = "ihdad" version = "0.1.0" dependencies = [ "bitflags 1.2.1", + "common", "log", "pcid", "redox-daemon", @@ -666,11 +620,11 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ - "autocfg 1.1.0", + "equivalent", "hashbrown", ] @@ -706,15 +660,16 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "ixgbed" version = "1.0.0" dependencies = [ "bitflags 1.2.1", + "common", "netutils", "redox-daemon", "redox_event", @@ -723,9 +678,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -758,15 +713,6 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" -[[package]] -name = "link-cplusplus" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] - [[package]] name = "linked-hash-map" version = "0.5.6" @@ -775,9 +721,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg 1.1.0", "scopeguard", @@ -893,16 +839,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg 1.1.0", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.15" @@ -925,6 +861,7 @@ dependencies = [ "arrayvec 0.5.2", "bitflags 1.2.1", "block-io-wrapper", + "common", "crossbeam-channel 0.4.4", "futures", "log", @@ -933,28 +870,24 @@ dependencies = [ "redox-daemon", "redox-log", "redox_syscall 0.3.5", - "smallvec 1.10.0", + "smallvec 1.11.0", ] [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "orbclient" -version = "0.3.44" -source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#21d152240c4fc290a97d3d7a5adbc35ea495fdf9" +version = "0.3.45" +source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#def603f25763db3b8222b9cc84983cef5966a561" dependencies = [ - "cfg-if 1.0.0", "libc", - "raw-window-handle 0.3.4", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "sdl2", "sdl2-sys", - "wasm-bindgen", - "web-sys", ] [[package]] @@ -1009,7 +942,7 @@ dependencies = [ "instant", "libc", "redox_syscall 0.2.16", - "smallvec 1.10.0", + "smallvec 1.11.0", "winapi 0.3.9", ] @@ -1025,9 +958,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b27ab7be369122c218afc2079489cdcb4b517c0a3fc386ff11e1fedfcc2b35" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" [[package]] name = "paw" @@ -1062,7 +995,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5827dfa0d69b6c92493d6c38e633bbaa5937c153d0d7c28bf12313f8c6d514" dependencies = [ - "crossbeam-channel 0.5.7", + "crossbeam-channel 0.5.8", "libc", "winapi 0.3.9", ] @@ -1074,6 +1007,7 @@ dependencies = [ "bincode", "bitflags 1.2.1", "byteorder 1.4.3", + "common", "libc", "log", "paw", @@ -1082,7 +1016,7 @@ dependencies = [ "redox_syscall 0.3.5", "serde", "serde_json", - "smallvec 1.10.0", + "smallvec 1.11.0", "structopt", "thiserror", "toml 0.5.11", @@ -1104,9 +1038,9 @@ checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] name = "pin-project-lite" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" +checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" [[package]] name = "pin-utils" @@ -1146,9 +1080,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.63" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" +checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" dependencies = [ "unicode-ident", ] @@ -1165,9 +1099,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.26" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" dependencies = [ "proc-macro2", ] @@ -1307,25 +1241,6 @@ dependencies = [ "vte", ] -[[package]] -name = "raw-window-handle" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28f55143d0548dad60bb4fbdc835a3d7ac6acc3324506450c5fdd6e42903a76" -dependencies = [ - "libc", - "raw-window-handle 0.4.3", -] - -[[package]] -name = "raw-window-handle" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41" -dependencies = [ - "cty", -] - [[package]] name = "rdrand" version = "0.4.0" @@ -1353,7 +1268,7 @@ checksum = "cbf6d33a003a5c0b94ec11f10c7c797303f236592964ddb1bfb93e1b438a1557" dependencies = [ "chrono", "log", - "smallvec 1.10.0", + "smallvec 1.11.0", "termion", ] @@ -1397,6 +1312,7 @@ name = "rtl8139d" version = "0.1.0" dependencies = [ "bitflags 1.2.1", + "common", "log", "netutils", "pcid", @@ -1411,6 +1327,7 @@ name = "rtl8168d" version = "0.1.0" dependencies = [ "bitflags 1.2.1", + "common", "log", "netutils", "pcid", @@ -1439,9 +1356,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.13" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "sb16d" @@ -1458,15 +1375,9 @@ dependencies = [ [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "scratch" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scroll" @@ -1497,7 +1408,6 @@ dependencies = [ "bitflags 1.2.1", "lazy_static", "libc", - "raw-window-handle 0.4.3", "sdl2-sys", ] @@ -1508,36 +1418,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3586be2cf6c0a8099a79a12b4084357aa9b3e0b0d7980e3b67aaf7a9d55f9f0" dependencies = [ "cfg-if 1.0.0", - "cmake", "libc", "version-compare", ] [[package]] name = "serde" -version = "1.0.159" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.26", ] [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" dependencies = [ "itoa", "ryu", @@ -1546,9 +1455,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] @@ -1573,9 +1482,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" dependencies = [ "serde", ] @@ -1672,9 +1581,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.13" +version = "2.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c9da457c5285ac1f936ebd076af6dac17a61cfe7826f2076b4d015cf47bc8ec" +checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" dependencies = [ "proc-macro2", "quote", @@ -1687,15 +1596,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - [[package]] name = "termion" version = "1.5.6" @@ -1719,22 +1619,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.13", + "syn 2.0.26", ] [[package]] @@ -1774,9 +1674,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.3" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ "serde", "serde_spanned", @@ -1786,18 +1686,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.19.8" +version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ "indexmap", "serde", @@ -1814,9 +1714,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" [[package]] name = "unicode-normalization" @@ -1908,6 +1808,7 @@ checksum = "2cb3ff47e36907a6267572c1e398ff32ef78ac5131de8aa272e53846592c207e" name = "vboxd" version = "0.1.0" dependencies = [ + "common", "orbclient", "redox-daemon", "redox_event", @@ -1936,6 +1837,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" name = "vesad" version = "0.1.0" dependencies = [ + "common", "inputd", "orbclient", "ransid", @@ -1966,7 +1868,8 @@ dependencies = [ name = "virtio-core" version = "0.1.0" dependencies = [ - "bitflags 2.3.2", + "bitflags 2.3.3", + "common", "crossbeam-queue", "futures", "log", @@ -1983,6 +1886,7 @@ name = "virtio-gpud" version = "0.1.0" dependencies = [ "anyhow", + "common", "futures", "inputd", "log", @@ -2027,9 +1931,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -2037,24 +1941,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.26", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2062,32 +1966,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.26", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" - -[[package]] -name = "web-sys" -version = "0.3.61" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" -dependencies = [ - "js-sys", - "wasm-bindgen", -] +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "winapi" @@ -2117,15 +2011,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi 0.3.9", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -2143,9 +2028,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.0" +version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -2200,9 +2085,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" dependencies = [ "memchr", ] @@ -2232,6 +2117,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.2.1", "chashmap", + "common", "crossbeam-channel 0.4.4", "futures", "lazy_static", @@ -2244,7 +2130,7 @@ dependencies = [ "redox_syscall 0.3.5", "serde", "serde_json", - "smallvec 1.10.0", + "smallvec 1.11.0", "thiserror", "toml 0.5.11", ] From 2341e3cb16bb8c97bea09b2775bbacb3a5a12121 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 18 Jul 2023 12:24:11 +0200 Subject: [PATCH 0665/1301] Document memory:physical. --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index bd7b2f809c..b8f433684a 100644 --- a/README.md +++ b/README.md @@ -56,14 +56,18 @@ Missing class drivers for various classes. - virtio-netd - VirtIO net device (incomplete). - xhcid - xHCI (incomplete). -## Kernel Functions +## Kernel Interfaces -These are the most used kernel functions by Redox drivers. +These are the most used kernel interfaces by Redox drivers. - `iopl` - syscall that sets the I/O privilege level. x86 has four privilege rings (0/1/2/3), of which the kernel runs in ring 0 and userspace in ring 3. IOPL can only be changed by the kernel, for obvious security reasons, and therefore the Redox kernel needs root to set it. It is unique for each process. Processes with IOPL=3 can access I/O ports, and the kernel can access them as well. - `physalloc` - allocates physical memory frames. - `physfree` - frees memory frames. -- `physmap` - maps physical memory frames to driver-accessible virtual memory pages. +- `memory:physical` - allows mapping physical memory frames to driver-accessible virtual memory pages, with various available memory types: + - `memory:physical`: default memory type (currently writeback) + - `memory:physical@wb` writeback cached memory + - `memory:physical@uc`: uncacheable memory + - `memory:physical@wc`: write-combining memory - `irq:` - allows getting events from interrupts. It is used primarily by listening for its file descriptors using the `event:` scheme. ## Contributing to Drivers @@ -74,4 +78,4 @@ If you don't have datasheets, we recommend you to do reverse-engineering of avai We recommend BSDs drivers because BSD license is compatible with MIT (permissive), that way we can reuse the code in other drivers. -You can see this [example](https://gitlab.redox-os.org/redox-os/exampled) driver, read the code of the existent ones or the most close driver type for your device. \ No newline at end of file +You can see this [example](https://gitlab.redox-os.org/redox-os/exampled) driver, read the code of the existent ones or the most close driver type for your device. From 089e8bac35b6f93c693dd154eb8f81f424f0e835 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 18 Jul 2023 12:43:06 +0200 Subject: [PATCH 0666/1301] Move syscall::Dma to common. --- common/src/dma.rs | 217 ++++++++++++++++++++++++++++++++++++++++++++++ common/src/lib.rs | 2 + 2 files changed, 219 insertions(+) create mode 100644 common/src/dma.rs diff --git a/common/src/dma.rs b/common/src/dma.rs new file mode 100644 index 0000000000..204e9a3a4d --- /dev/null +++ b/common/src/dma.rs @@ -0,0 +1,217 @@ +use std::mem::{self, MaybeUninit}; +use std::ops::{Deref, DerefMut}; +use std::{ptr, slice}; + +use syscall::PAGE_SIZE; + +use syscall::Result; +use syscall::{PartialAllocStrategy, PhysallocFlags}; + +use crate::MemoryType; + +/// An RAII guard of a physical memory allocation. Currently all physically allocated memory are +/// page-aligned and take up at least 4k of space (on x86_64). +#[derive(Debug)] +pub struct PhysBox { + address: usize, + size: usize +} + +fn assert_aligned(x: usize) { + assert_eq!(x % PAGE_SIZE, 0); +} + +const DMA_MEMTY: MemoryType = { + if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { + // aarch64 currently must map DMA memory without caching to ensure coherence + MemoryType::Writeback + } else if cfg!(target_arch = "aarch64") { + // x86 ensures cache coherence with DMA memory + MemoryType::Uncacheable + } else { + panic!("invalid arch") + } +}; + +impl PhysBox { + /// Construct a PhysBox from an address and a size. The address must be page-aligned, and the + /// size must similarly be a multiple of the page size. + /// + /// # Safety + /// This function is unsafe because when dropping, Self has to a valid allocation. + pub unsafe fn from_raw_parts(address: usize, size: usize) -> Self { + assert_aligned(address); + assert_aligned(size); + + Self { + address, + size, + } + } + + /// Retrieve the byte address in physical memory, of this allocation. + pub fn address(&self) -> usize { + self.address + } + + /// Retrieve the size in bytes of the alloc. + pub fn size(&self) -> usize { + self.size + } + + /// Allocate physical memory that must reside in 32-bit space. + pub fn new_in_32bit_space(size: usize) -> Result { + Self::new_with_flags(size, PhysallocFlags::SPACE_32) + } + + pub fn new_with_flags(size: usize, flags: PhysallocFlags) -> Result { + assert!(!flags.contains(PhysallocFlags::PARTIAL_ALLOC)); + assert_aligned(size); + + let address = unsafe { syscall::physalloc2(size, flags.bits())? }; + Ok(unsafe { Self::from_raw_parts(address, size) }) + } + + /// "Partially" allocate physical memory, in the sense that the allocation may be smaller than + /// expected, but still with a minimum limit. This is particularly useful when the physical + /// memory space is fragmented, and a device supports scatter-gather I/O. In that case, the + /// driver can optimistically request e.g. 1 alloc of 1 MiB, with the minimum of 512 KiB. If + /// that first allocation only returns half the size, the driver can do another allocation + /// and then let the device use both buffers. + pub fn new_partial_allocation(size: usize, flags: PhysallocFlags, strategy: Option, mut min: usize) -> Result { + assert_aligned(size); + debug_assert!(!(flags.contains(PhysallocFlags::PARTIAL_ALLOC) && strategy.is_none())); + + let address = unsafe { syscall::physalloc3(size, flags.bits() | strategy.map_or(0, |s| s as usize), &mut min)? }; + Ok(unsafe { Self::from_raw_parts(address, size) }) + } + + pub fn new(size: usize) -> Result { + assert_aligned(size); + + let address = unsafe { syscall::physalloc(size)? }; + Ok(unsafe { Self::from_raw_parts(address, size) }) + } +} + +impl Drop for PhysBox { + fn drop(&mut self) { + let _ = unsafe { syscall::physfree(self.address, self.size) }; + } +} + +pub struct Dma { + phys: PhysBox, + virt: *mut T, +} + +impl Dma { + pub fn from_physbox_uninit(phys: PhysBox) -> Result>> { + Ok(Dma { + virt: unsafe { crate::physmap(phys.address, phys.size, crate::Prot::RW, DMA_MEMTY)? } as *mut MaybeUninit, + phys, + }) + } + pub fn from_physbox_zeroed(phys: PhysBox) -> Result>> { + let this = Self::from_physbox_uninit(phys)?; + unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit, 0, this.phys.size) } + Ok(this) + } + + pub fn from_physbox(phys: PhysBox, value: T) -> Result { + let this = Self::from_physbox_uninit(phys)?; + + Ok(unsafe { + ptr::write(this.virt, MaybeUninit::new(value)); + this.assume_init() + }) + } + + pub fn new(value: T) -> Result { + let phys = PhysBox::new(mem::size_of::().next_multiple_of(PAGE_SIZE))?; + Self::from_physbox(phys, value) + } + pub fn zeroed() -> Result>> { + let phys = PhysBox::new(mem::size_of::().next_multiple_of(PAGE_SIZE))?; + Self::from_physbox_zeroed(phys) + } +} + +impl Dma> { + pub unsafe fn assume_init(self) -> Dma { + let &Dma { phys: PhysBox { address, size }, virt } = &self; + mem::forget(self); + + Dma { + phys: PhysBox { address, size }, + virt: virt as *mut T, + } + } +} +impl Dma { + pub fn physical(&self) -> usize { + self.phys.address() + } + pub fn size(&self) -> usize { + self.phys.size() + } + pub fn phys(&self) -> &PhysBox { + &self.phys + } +} + +impl Dma<[T]> { + pub fn from_physbox_uninit_unsized(phys: PhysBox, len: usize) -> Result]>> { + let max_len = phys.size() / mem::size_of::(); + assert!(len <= max_len); + + Ok(Dma { + virt: unsafe { slice::from_raw_parts_mut(crate::physmap(phys.address, phys.size, crate::Prot::RW, DMA_MEMTY)? as *mut MaybeUninit, len) } as *mut [MaybeUninit], + phys, + }) + } + pub fn from_physbox_zeroed_unsized(phys: PhysBox, len: usize) -> Result]>> { + let this = Self::from_physbox_uninit_unsized(phys, len)?; + unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit, 0, this.phys.size()) } + Ok(this) + } + /// Creates a new DMA buffer with a size only known at runtime. + /// ## Safety + /// * `T` must be properly aligned. + /// * `T` must be valid as zeroed (i.e. no NonNull pointers). + pub unsafe fn zeroed_unsized(count: usize) -> Result { + let phys = PhysBox::new((mem::size_of::() * count).next_multiple_of(PAGE_SIZE))?; + Ok(Self::from_physbox_zeroed_unsized(phys, count)?.assume_init()) + } +} +impl Dma<[MaybeUninit]> { + pub unsafe fn assume_init(self) -> Dma<[T]> { + let &Dma { phys: PhysBox { address, size }, virt } = &self; + mem::forget(self); + + Dma { + phys: PhysBox { address, size }, + virt: virt as *mut [T], + } + } +} + +impl Deref for Dma { + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.virt } + } +} + +impl DerefMut for Dma { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.virt } + } +} + +impl Drop for Dma { + fn drop(&mut self) { + unsafe { ptr::drop_in_place(self.virt) } + let _ = unsafe { syscall::funmap(self.virt as *mut u8 as usize, self.phys.size) }; + } +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 85f976f332..35827a2197 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -4,6 +4,8 @@ use syscall::PAGE_SIZE; use syscall::error::{Error, Result, EINVAL}; use syscall::flag::{MapFlags, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; +pub mod dma; + #[derive(Clone, Copy, Debug)] pub enum MemoryType { Writeback, From 433ea455cce9dba738c50cbcfede7deba17cceeb Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 18 Jul 2023 12:43:39 +0200 Subject: [PATCH 0667/1301] Use common::Dma in ahcid. --- ahcid/src/ahci/disk_ata.rs | 3 ++- ahcid/src/ahci/disk_atapi.rs | 3 ++- ahcid/src/ahci/hba.rs | 4 +++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index adb0fa4045..d9dcef1769 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -1,9 +1,10 @@ use std::convert::TryInto; use std::ptr; -use syscall::io::Dma; use syscall::error::Result; +use common::dma::Dma; + use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; use super::Disk; diff --git a/ahcid/src/ahci/disk_atapi.rs b/ahcid/src/ahci/disk_atapi.rs index c414b8480f..a7abf2e1d6 100644 --- a/ahcid/src/ahci/disk_atapi.rs +++ b/ahcid/src/ahci/disk_atapi.rs @@ -5,9 +5,10 @@ use std::ptr; use byteorder::{ByteOrder, BigEndian}; -use syscall::io::Dma; use syscall::error::{Result, EBADF, Error}; +use common::dma::Dma; + use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; use super::Disk; diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 2bb122ff39..6f9217aa05 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -3,11 +3,13 @@ use std::mem::size_of; use std::ops::DerefMut; use std::{ptr, u32}; -use syscall::io::{Dma, Io, Mmio}; +use syscall::io::{Io, Mmio}; use syscall::error::{Error, Result, EIO}; use super::fis::{FisType, FisRegH2D}; +use common::dma::Dma; + const ATA_CMD_READ_DMA_EXT: u8 = 0x25; const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35; const ATA_CMD_IDENTIFY: u8 = 0xEC; From d9d8d06d330a82a513a94974e0139e148efa1e66 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 18 Jul 2023 12:45:03 +0200 Subject: [PATCH 0668/1301] Use common::Dma in nvmed. --- nvmed/src/nvme/identify.rs | 4 ++-- nvmed/src/nvme/mod.rs | 4 +++- nvmed/src/nvme/queues.rs | 4 +++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/nvmed/src/nvme/identify.rs b/nvmed/src/nvme/identify.rs index 4d9f1dfc51..6f22a1fe40 100644 --- a/nvmed/src/nvme/identify.rs +++ b/nvmed/src/nvme/identify.rs @@ -1,7 +1,7 @@ -use syscall::Dma; - use super::{Nvme, NvmeCmd, NvmeNamespace}; +use common::dma::Dma; + /// See NVME spec section 5.15.2.2. #[derive(Clone, Copy)] #[repr(packed)] diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 4aa0bac86a..7e34801af2 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -10,7 +10,9 @@ use crossbeam_channel::Sender; use smallvec::{smallvec, SmallVec}; use syscall::error::{Error, Result, EINVAL, EIO}; -use syscall::io::{Dma, Io, Mmio}; +use syscall::io::{Io, Mmio}; + +use common::dma::Dma; pub mod cmd; pub mod cq_reactor; diff --git a/nvmed/src/nvme/queues.rs b/nvmed/src/nvme/queues.rs index 7e06373efa..892e220448 100644 --- a/nvmed/src/nvme/queues.rs +++ b/nvmed/src/nvme/queues.rs @@ -1,5 +1,7 @@ use std::ptr; -use syscall::{Dma, Result}; +use syscall::Result; + +use common::dma::Dma; /// A submission queue entry. #[derive(Clone, Copy, Debug, Default)] From e4374ac60dfabfc1bb2543d269db1d1fc7a67a38 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 18 Jul 2023 13:47:15 +0200 Subject: [PATCH 0669/1301] Switch to common::dma::Dma in virtio-*. --- virtio-blkd/Cargo.toml | 1 + virtio-blkd/src/scheme.rs | 19 ++++++++++--------- virtio-core/src/spec.rs | 6 +++--- virtio-core/src/transport.rs | 2 +- virtio-gpud/src/scheme.rs | 3 ++- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/virtio-blkd/Cargo.toml b/virtio-blkd/Cargo.toml index 461a0d679a..2068f8923a 100644 --- a/virtio-blkd/Cargo.toml +++ b/virtio-blkd/Cargo.toml @@ -17,5 +17,6 @@ redox_syscall = "0.3" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } block-io-wrapper = { path = "../block-io-wrapper" } +common = { path = "../common" } pcid = { path = "../pcid" } virtio-core = { path = "../virtio-core" } diff --git a/virtio-blkd/src/scheme.rs b/virtio-blkd/src/scheme.rs index 8a3f6154cb..d94f9a76b4 100644 --- a/virtio-blkd/src/scheme.rs +++ b/virtio-blkd/src/scheme.rs @@ -7,6 +7,7 @@ use std::io::Seek; use std::fmt::Write; use std::sync::Arc; +use common::dma::Dma; use partitionlib::LogicalBlockSize; use partitionlib::PartitionTable; use syscall::*; @@ -27,15 +28,15 @@ trait BlkExtension { impl BlkExtension for Queue<'_> { async fn read(&self, block: u64, target: &mut [u8]) -> usize { - let req = syscall::Dma::new(BlockVirtRequest { + let req = Dma::new(BlockVirtRequest { ty: BlockRequestTy::In, reserved: 0, sector: block, }) .unwrap(); - let result = unsafe { syscall::Dma::<[u8]>::zeroed_unsized(target.len()) }.unwrap(); - let status = syscall::Dma::new(u8::MAX).unwrap(); + let result = unsafe { Dma::<[u8]>::zeroed_unsized(target.len()) }.unwrap(); + let status = Dma::new(u8::MAX).unwrap(); let chain = ChainBuilder::new() .chain(Buffer::new(&req)) @@ -52,17 +53,17 @@ impl BlkExtension for Queue<'_> { } async fn write(&self, block: u64, target: &[u8]) -> usize { - let req = syscall::Dma::new(BlockVirtRequest { + let req = Dma::new(BlockVirtRequest { ty: BlockRequestTy::Out, reserved: 0, sector: block, }) .unwrap(); - let mut result = unsafe { syscall::Dma::<[u8]>::zeroed_unsized(target.len()) }.unwrap(); + let mut result = unsafe { Dma::<[u8]>::zeroed_unsized(target.len()) }.unwrap(); result.copy_from_slice(target.as_ref()); - let status = syscall::Dma::new(u8::MAX).unwrap(); + let status = Dma::new(u8::MAX).unwrap(); let chain = ChainBuilder::new() .chain(Buffer::new(&req)) @@ -122,15 +123,15 @@ impl<'a> DiskScheme<'a> { impl<'a, 'b> Read for VirtioShim<'a, 'b> { fn read(&mut self, buf: &mut [u8]) -> IoResult { let read_block = |block: u64, block_bytes: &mut [u8]| -> Result<(), ()> { - let req = syscall::Dma::new(BlockVirtRequest { + let req = Dma::new(BlockVirtRequest { ty: BlockRequestTy::In, reserved: 0, sector: block, }) .unwrap(); - let result = syscall::Dma::new([0u8; 512]).unwrap(); - let status = syscall::Dma::new(u8::MAX).unwrap(); + let result = Dma::new([0u8; 512]).unwrap(); + let status = Dma::new(u8::MAX).unwrap(); let chain = ChainBuilder::new() .chain(Buffer::new(&req)) diff --git a/virtio-core/src/spec.rs b/virtio-core/src/spec.rs index eb8f12f829..f4a3d79f8c 100644 --- a/virtio-core/src/spec.rs +++ b/virtio-core/src/spec.rs @@ -246,7 +246,7 @@ pub struct Buffer { } impl Buffer { - pub fn new(val: &syscall::Dma) -> Self { + pub fn new(val: &common::dma::Dma) -> Self { Self { buffer: val.physical(), size: core::mem::size_of::(), @@ -254,7 +254,7 @@ impl Buffer { } } - pub fn new_unsized(val: &syscall::Dma<[T]>) -> Self { + pub fn new_unsized(val: &common::dma::Dma<[T]>) -> Self { Self { buffer: val.physical(), size: core::mem::size_of::() * val.len(), @@ -262,7 +262,7 @@ impl Buffer { } } - pub fn new_sized(val: &syscall::Dma<[T]>, size: usize) -> Self { + pub fn new_sized(val: &common::dma::Dma<[T]>, size: usize) -> Self { Self { buffer: val.physical(), size, diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 2f049a1dab..6048d14f34 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -1,8 +1,8 @@ use crate::spec::*; use crate::utils::align; +use common::dma::Dma; use event::EventQueue; -use syscall::Dma; use core::mem::size_of; use core::sync::atomic::{AtomicU16, Ordering}; diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index ed202693e3..4439f647be 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -3,8 +3,9 @@ use std::collections::BTreeMap; use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; +use common::dma::Dma; use inputd::Damage; -use syscall::{Dma, Error as SysError, SchemeMut, EINVAL}; +use syscall::{Error as SysError, SchemeMut, EINVAL}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::{Error, Queue, StandardTransport}; From 44bbb302cf029addcd0e755b49a79f2a64874fc8 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 18 Jul 2023 13:48:38 +0200 Subject: [PATCH 0670/1301] Switch to common::dma::Dma in ided. --- ided/Cargo.toml | 1 + ided/src/ide.rs | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ided/Cargo.toml b/ided/Cargo.toml index 27052da67e..e1dc341aae 100644 --- a/ided/Cargo.toml +++ b/ided/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" [dependencies] block-io-wrapper = { path = "../block-io-wrapper" } +common = { path = "../common" } log = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } pcid = { path = "../pcid" } diff --git a/ided/src/ide.rs b/ided/src/ide.rs index 65376e2df5..dff603f90e 100644 --- a/ided/src/ide.rs +++ b/ided/src/ide.rs @@ -4,11 +4,14 @@ use std::{ thread, time::{Duration, Instant}, }; + use syscall::{ error::{Error, Result, EIO}, - io::{Dma, Io, Pio, PhysBox, ReadOnly, WriteOnly}, + io::{Io, Pio, ReadOnly, WriteOnly}, }; +use common::dma::{Dma, PhysBox}; + static TIMEOUT: Duration = Duration::new(1, 0); #[repr(u8)] From 027728487440e24139df6d0888c0e76df4a48613 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 18 Jul 2023 13:59:44 +0200 Subject: [PATCH 0671/1301] Switch to common::Dma for each non-initfs driver. --- ac97d/Cargo.toml | 1 + ac97d/src/device.rs | 3 ++- alxd/src/device/mod.rs | 6 ++++-- e1000d/src/device.rs | 3 ++- ixgbed/src/device.rs | 5 +++-- ixgbed/src/main.rs | 3 +++ rtl8139d/src/device.rs | 6 ++++-- rtl8168d/src/device.rs | 6 ++++-- sb16d/Cargo.toml | 1 + sb16d/src/device.rs | 3 ++- vboxd/src/main.rs | 4 +++- xhcid/src/xhci/context.rs | 4 +++- xhcid/src/xhci/event.rs | 4 +++- xhcid/src/xhci/mod.rs | 8 +++++--- xhcid/src/xhci/ring.rs | 3 ++- xhcid/src/xhci/scheme.rs | 3 ++- 16 files changed, 44 insertions(+), 19 deletions(-) diff --git a/ac97d/Cargo.toml b/ac97d/Cargo.toml index 249ea0ed03..1657a30cfb 100644 --- a/ac97d/Cargo.toml +++ b/ac97d/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" [dependencies] bitflags = "1" +common = { path = "../common" } log = "0.4" redox-daemon = "0.1" redox-log = "0.1" diff --git a/ac97d/src/device.rs b/ac97d/src/device.rs index 1a6fd0a93b..e40b7e44a0 100644 --- a/ac97d/src/device.rs +++ b/ac97d/src/device.rs @@ -5,9 +5,10 @@ use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; use syscall::error::{Error, EACCES, EBADF, Result, EINVAL, ENOENT}; -use syscall::io::{Dma, PhysBox, Mmio, Pio, Io}; +use syscall::io::{Mmio, Pio, Io}; use syscall::scheme::SchemeBlockMut; +use common::dma::{Dma, PhysBox}; use spin::Mutex; const NUM_SUB_BUFFS: usize = 32; diff --git a/alxd/src/device/mod.rs b/alxd/src/device/mod.rs index b92a12fb92..26395be10a 100644 --- a/alxd/src/device/mod.rs +++ b/alxd/src/device/mod.rs @@ -1,12 +1,14 @@ use std::{ptr, thread, time}; use std::convert::TryInto; -use netutils::setcfg; use syscall::error::{Error, EACCES, EINVAL, EIO, EWOULDBLOCK, Result}; use syscall::flag::{EventFlags, O_NONBLOCK}; -use syscall::io::{Dma, Io, Mmio}; +use syscall::io::{Io, Mmio}; use syscall::scheme; +use common::dma::Dma; +use netutils::setcfg; + use self::regs::*; mod regs; diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index cde14975ff..45186b7695 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -6,9 +6,10 @@ use netutils::setcfg; use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; use syscall::flag::{EventFlags, O_NONBLOCK}; -use syscall::io::Dma; use syscall::scheme::SchemeBlockMut; +use common::dma::Dma; + const CTRL: u32 = 0x00; const CTRL_LRST: u32 = 1 << 3; const CTRL_ASDE: u32 = 1 << 5; diff --git a/ixgbed/src/device.rs b/ixgbed/src/device.rs index c5a8a210b4..2803ccca5f 100644 --- a/ixgbed/src/device.rs +++ b/ixgbed/src/device.rs @@ -3,12 +3,13 @@ use std::convert::TryInto; use std::time::{Duration, Instant}; use std::{cmp, mem, ptr, slice, thread}; -use netutils::setcfg; use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; use syscall::flag::{EventFlags, O_NONBLOCK}; -use syscall::io::Dma; use syscall::scheme::SchemeBlockMut; +use common::dma::Dma; +use netutils::setcfg; + use ixgbe::*; pub struct Intel8259x { diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index b1906fadc8..b192450af0 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -2,6 +2,9 @@ extern crate event; extern crate netutils; extern crate syscall; +// TODO: Migrate to Rust 2018/2021 +extern crate common; + use std::cell::RefCell; use std::fs::File; use std::io::{ErrorKind, Read, Result, Write}; diff --git a/rtl8139d/src/device.rs b/rtl8139d/src/device.rs index 0351b8bb95..f9bbcac38f 100644 --- a/rtl8139d/src/device.rs +++ b/rtl8139d/src/device.rs @@ -2,12 +2,14 @@ use std::mem; use std::convert::TryInto; use std::collections::BTreeMap; -use netutils::setcfg; use syscall::error::{Error, EACCES, EBADF, EINVAL, EIO, EMSGSIZE, EWOULDBLOCK, Result}; use syscall::flag::{EventFlags, O_NONBLOCK}; -use syscall::io::{Dma, Mmio, Io, ReadOnly}; +use syscall::io::{Mmio, Io, ReadOnly}; use syscall::scheme::SchemeBlockMut; +use common::dma::Dma; +use netutils::setcfg; + const RX_BUFFER_SIZE: usize = 64 * 1024; const RXSTS_ROK: u16 = 1 << 0; diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index df906089ff..a32a5199ee 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -5,12 +5,14 @@ use std::mem; use std::convert::TryInto; use std::collections::BTreeMap; -use netutils::setcfg; use syscall::error::{Error, EACCES, EBADF, EINVAL, EMSGSIZE, EWOULDBLOCK, Result}; use syscall::flag::{EventFlags, O_NONBLOCK}; -use syscall::io::{Dma, Mmio, Io, ReadOnly}; +use syscall::io::{Mmio, Io, ReadOnly}; use syscall::scheme::SchemeBlockMut; +use common::dma::Dma; +use netutils::setcfg; + #[repr(packed)] struct Regs { mac: [Mmio; 2], diff --git a/sb16d/Cargo.toml b/sb16d/Cargo.toml index bee3594214..daa3b7659a 100644 --- a/sb16d/Cargo.toml +++ b/sb16d/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" [dependencies] bitflags = "1" +common = { path = "../common" } log = "0.4" redox-daemon = "0.1" redox-log = "0.1" diff --git a/sb16d/src/device.rs b/sb16d/src/device.rs index f016cde002..1e03f877a2 100644 --- a/sb16d/src/device.rs +++ b/sb16d/src/device.rs @@ -5,9 +5,10 @@ use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; use syscall::error::{Error, EACCES, EBADF, Result, EINVAL, ENODEV, ENOENT}; -use syscall::io::{Dma, PhysBox, Mmio, Pio, Io, ReadOnly, WriteOnly}; +use syscall::io::{Mmio, Pio, Io, ReadOnly, WriteOnly}; use syscall::scheme::SchemeBlockMut; +use common::dma::{Dma, PhysBox}; use spin::Mutex; const NUM_SUB_BUFFS: usize = 32; diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index de94f4ba9e..cb3bba6035 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -12,7 +12,9 @@ use std::io::{Result, Read, Write}; use syscall::call::iopl; use syscall::flag::EventFlags; -use syscall::io::{Dma, Io, Mmio, Pio}; +use syscall::io::{Io, Mmio, Pio}; + +use common::dma::Dma; use crate::bga::Bga; diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index c40f000805..d0fa24174a 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -2,7 +2,9 @@ use std::collections::BTreeMap; use log::debug; use syscall::error::Result; -use syscall::io::{Dma, Io, Mmio}; +use syscall::io::{Io, Mmio}; + +use common::dma::Dma; use super::Xhci; use super::ring::Ring; diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index 7ee17d6957..329afc0ed3 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -1,5 +1,7 @@ use syscall::error::Result; -use syscall::io::{Dma, Io, Mmio}; +use syscall::io::{Io, Mmio}; + +use common::dma::Dma; use super::Xhci; use super::ring::Ring; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index d3936d51c4..aa371007d7 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -9,13 +9,15 @@ use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::{mem, process, slice, sync::atomic, task, thread}; +use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; +use syscall::flag::{O_RDONLY, PhysallocFlags}; +use syscall::io::Io; + use chashmap::CHashMap; +use common::dma::{Dma, PhysBox}; use crossbeam_channel::{Receiver, Sender}; use log::{debug, error, info, trace, warn}; use serde::Deserialize; -use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; -use syscall::flag::{O_RDONLY, PhysallocFlags}; -use syscall::io::{Dma, Io, PhysBox}; use crate::usb; diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index ae7da564b4..0bb74f7098 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -1,7 +1,8 @@ use std::mem; use syscall::error::Result; -use syscall::io::Dma; + +use common::dma::Dma; use super::Xhci; use super::trb::Trb; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 95d2315437..71e1610cf7 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -4,12 +4,13 @@ use std::ops::Deref; use std::sync::atomic; use std::{cmp, fmt, io, mem, path, str}; +use common::dma::Dma; use futures::executor::block_on; use log::{debug, error, info, warn, trace}; use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; -use syscall::io::{Dma, Io}; +use syscall::io::Io; use syscall::scheme::Scheme; use syscall::{ Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, From fc7665eb773fca08094a945e3b988c4d3149060c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 18 Jul 2023 14:00:44 +0200 Subject: [PATCH 0672/1301] Update Cargo.lock --- Cargo.lock | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 29f885ada3..0e17d62f53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7,6 +7,7 @@ name = "ac97d" version = "0.1.0" dependencies = [ "bitflags 1.2.1", + "common", "log", "redox-daemon", "redox-log", @@ -584,6 +585,7 @@ name = "ided" version = "0.1.0" dependencies = [ "block-io-wrapper", + "common", "log", "partitionlib", "pcid", @@ -1365,6 +1367,7 @@ name = "sb16d" version = "0.1.0" dependencies = [ "bitflags 1.2.1", + "common", "log", "redox-daemon", "redox-log", @@ -1852,6 +1855,7 @@ version = "0.1.0" dependencies = [ "anyhow", "block-io-wrapper", + "common", "futures", "log", "partitionlib", From e457f0393502bf9edc880112e29a76abe0873df0 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 18 Jul 2023 18:25:32 +1000 Subject: [PATCH 0673/1301] virtio-gpu: handling GPU resets Signed-off-by: Anhad Singh --- Cargo.lock | 1 + inputd/src/lib.rs | 35 +++++- inputd/src/main.rs | 79 ++++++++---- vesad/src/scheme.rs | 93 +++++--------- virtio-core/src/lib.rs | 2 +- virtio-core/src/probe.rs | 50 +++++--- virtio-core/src/transport.rs | 42 ++++++- virtio-gpud/src/main.rs | 24 +++- virtio-gpud/src/scheme.rs | 235 ++++++++++++++++++++++++----------- virtio-netd/Cargo.toml | 1 + virtio-netd/src/scheme.rs | 2 + 11 files changed, 371 insertions(+), 193 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0e17d62f53..a0d8949010 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1908,6 +1908,7 @@ dependencies = [ name = "virtio-netd" version = "0.1.0" dependencies = [ + "common", "futures", "log", "netutils", diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 9ad4ae5876..bd9cb6655d 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -1,11 +1,12 @@ use std::fs::File; use std::io::{Error, Read}; +use std::mem; pub struct Handle(File); impl Handle { pub fn new>(device_name: S) -> Result { - let path = format!("input:handle/{}", device_name.into()); + let path = format!("input:handle/display/{}", device_name.into()); Ok(Self(File::open(path)?)) } @@ -16,6 +17,38 @@ impl Handle { } } +#[derive(Debug, Copy, Clone, PartialEq)] +#[repr(u8)] +pub enum CommandTy { + Unknown = 0, + + Activate, + Deactivate, +} + +#[repr(C)] +pub struct Command { + pub ty: CommandTy, + pub value: usize, +} + +impl Command { + pub fn new(ty: CommandTy, value: usize) -> Self { + Self { ty, value } + } + + /// ## Panics + /// This function panics if the buffer is not `sizeof::()` bytes wide. + pub fn parse<'a>(buffer: &'a [u8]) -> &'a Command { + assert_eq!(buffer.len(), core::mem::size_of::()); + unsafe { &*(buffer.as_ptr() as *const Command) } + } + + pub fn into_bytes(self) -> [u8; mem::size_of::()] { + unsafe { core::mem::transmute(self) } + } +} + #[repr(packed)] pub struct Damage { pub x: i32, diff --git a/inputd/src/main.rs b/inputd/src/main.rs index b06a0c247d..0609cb1491 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -13,10 +13,11 @@ use std::collections::BTreeMap; use std::fs::File; -use std::io::{Read, Write}; +use std::io::{self, Read, Write}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; +use inputd::{Command, CommandTy}; use orbclient::{Event, EventOption}; use syscall::{Error as SysError, EventFlags, Packet, SchemeMut, EINVAL}; @@ -26,6 +27,7 @@ enum Handle { events: EventFlags, pending: Vec, notified: bool, + vt: usize, }, Device(Arc), } @@ -66,17 +68,30 @@ impl SchemeMut for InputScheme { let mut path_parts = path.split('/'); let command = path_parts.next().ok_or(SysError::new(EINVAL))?; + let fd = self.next_id.fetch_add(1, Ordering::SeqCst); let handle_ty = match command { "producer" => Handle::Producer, - "consumer" => Handle::Consumer { - events: EventFlags::empty(), - pending: Vec::new(), - notified: false, - }, + "consumer" => { + let vt = if let Some((_, _, vt)) = self.active_vt { + vt + } else { + // No one is currently set as active, so we assume that the last allocated + // one will be willing to take this consumer. + self.next_vt_id.load(Ordering::SeqCst) - 1 + }; + + dbg!(vt); + Handle::Consumer { + events: EventFlags::empty(), + pending: Vec::new(), + notified: false, + vt, + } + } "handle" => { - let value = path_parts.next().ok_or(SysError::new(EINVAL))?; - Handle::Device(Arc::new(value.to_string())) + let value = path_parts.collect::>().join("/"); + Handle::Device(Arc::new(value)) } _ => unreachable!("inputd: invalid path {path}"), @@ -84,9 +99,7 @@ impl SchemeMut for InputScheme { log::info!("inputd: {path} channel has been opened"); - let fd = self.next_id.fetch_add(1, Ordering::SeqCst); self.handles.insert(fd, handle_ty); - Ok(fd) } @@ -156,36 +169,34 @@ impl SchemeMut for InputScheme { _ => continue, } - let deactivate = |vt, current| { - // Drop the old active VT first. - // - // TODO(andypython): This can be drastically improved by introducting something - // like ioctl() to the display scheme. - let deactivate = format!("display/{}:{current}/deactivate", vt); - let _ = File::open(&deactivate); + let deactivate = |file: &mut File, id: usize| -> io::Result<()> { + let command = Command::new(CommandTy::Deactivate, id).into_bytes(); + file.write(&command)?; + Ok(()) }; if let Some(new_active) = new_active_opt { - if let Some(vt) = self.vts.get(&new_active) { - // If the VT is already active, don't do anything. - if let Some((vt, _, current)) = self.active_vt.as_ref() { + if let Some(vt) = self.vts.get(&new_active).cloned() { + if let Some((_, file, current)) = self.active_vt.as_mut() { + // If the VT is already active, don't do anything. if new_active == *current { continue; } - deactivate(vt, *current); + deactivate(file, *current).unwrap(); } else { let id = self.next_vt_id.load(Ordering::SeqCst) - 1; - let vt = self.vts.get(&id).unwrap(); + let mut vt = File::open(self.vts.get_mut(&id).unwrap().as_ref()).unwrap(); - deactivate(vt, id); + deactivate(&mut vt, id).unwrap(); } - // Result: display/virtio-gpu:3/acvtivate - let activate = format!("display/{vt}:{new_active}/activate"); - log::info!("inputd: switching to VT #{new_active} (`{activate}`)"); + log::info!("inputd: switching to VT #{new_active} (`{vt}`)"); + + let mut file = File::open(vt.as_ref()).unwrap(); + file.write(&Command::new(CommandTy::Activate, new_active).into_bytes()) + .unwrap(); - let file = File::open(&activate).unwrap(); self.active_vt = Some((vt.clone(), file, new_active)); } else { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); @@ -269,12 +280,26 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { events, pending, ref mut notified, + vt, } = handle { if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) { continue; } + let should_notify = if let Some((_, _, active_vt)) = scheme.active_vt { + active_vt == *vt + } else { + let last_allocated = scheme.next_vt_id.load(Ordering::SeqCst) - 1; + last_allocated == *vt + }; + + // The activate VT is not the same as the VT that the consumer is listening to + // for events. + if !should_notify { + continue; + } + // Notify the consumer that we have some events to read. Yum yum. let mut event_packet = Packet::default(); event_packet.a = syscall::SYS_FEVENT; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index c6a17b9509..d334c79a89 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -43,7 +43,7 @@ pub struct DisplayScheme { impl DisplayScheme { pub fn new(mut framebuffers: Vec, spec: &[bool]) -> DisplayScheme { - let mut inputd_handle = inputd::Handle::new("vesa").unwrap(); + let mut inputd_handle = inputd::Handle::new("vesa:handle").unwrap(); let mut onscreens = Vec::new(); for fb in framebuffers.iter_mut() { @@ -146,6 +146,18 @@ impl DisplayScheme { impl SchemeMut for DisplayScheme { fn open(&mut self, path_str: &str, flags: usize, _uid: u32, _gid: u32) -> Result { + if path_str == "handle" { + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle { + kind: HandleKind::Input, + flags, + events: EventFlags::empty(), + notified_read: false + }); + return Ok(id); + } + let mut parts = path_str.split('/'); let mut vt_screen = parts.next().unwrap_or("").split('.'); let vt_i = VtIndex( @@ -156,16 +168,6 @@ impl SchemeMut for DisplayScheme { ); if let Some(screens) = self.vts.get_mut(&vt_i) { if let Some(screen) = screens.get_mut(&screen_i) { - for cmd in parts { - if cmd == "activate" { - self.active = vt_i; - screen.redraw( - self.onscreens[screen_i.0], - self.framebuffers[screen_i.0].stride - ); - } - } - let id = self.next_id; self.next_id += 1; @@ -303,51 +305,14 @@ impl SchemeMut for DisplayScheme { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; match handle.kind { - HandleKind::Input => if buf.len() == 1 && buf[0] >= 0xF4 { - let new_active = VtIndex((buf[0] - 0xF4) as usize + 1); - if let Some(screens) = self.vts.get_mut(&new_active) { - self.active = new_active; - for (screen_i, screen) in screens.iter_mut() { - screen.redraw( - self.onscreens[screen_i.0], - self.framebuffers[screen_i.0].stride - ); - } - } - Ok(1) - } else { - let events = unsafe { slice::from_raw_parts(buf.as_ptr() as *const Event, buf.len()/mem::size_of::()) }; + HandleKind::Input => { + let command = inputd::Command::parse(buf); - for event in events.iter() { - let mut new_active_opt = None; - match event.to_option() { - EventOption::Key(key_event) => match key_event.scancode { - f @ 0x3B ..= 0x44 if self.super_key => { // F1 through F10 - new_active_opt = Some(VtIndex((f - 0x3A) as usize)); - }, - 0x57 if self.super_key => { // F11 - new_active_opt = Some(VtIndex(11)); - }, - 0x58 if self.super_key => { // F12 - new_active_opt = Some(VtIndex(12)); - }, - 0x5B => { // Super - self.super_key = key_event.pressed; - }, - _ => () - }, - EventOption::Resize(resize_event) => { - let width = resize_event.width as usize; - let height = resize_event.height as usize; - let stride = width; //TODO: get stride somehow - self.resize(width, height, stride); - }, - _ => () - }; + match command.ty { + inputd::CommandTy::Activate => { + let vt_i = VtIndex(command.value); - if let Some(new_active) = new_active_opt { - if let Some(screens) = self.vts.get_mut(&new_active) { - self.active = new_active; + if let Some(screens) = self.vts.get_mut(&vt_i) { for (screen_i, screen) in screens.iter_mut() { screen.redraw( self.onscreens[screen_i.0], @@ -355,18 +320,20 @@ impl SchemeMut for DisplayScheme { ); } } - } else { - if let Some(screens) = self.vts.get_mut(&self.active) { - //TODO: send input to other screens? Don't want extra events - if let Some(screen) = screens.get_mut(&ScreenIndex(0)) { - screen.input(event); - } - } - } + + self.active = vt_i; + }, + + inputd::CommandTy::Deactivate => { + // Nothing :) + }, + + _ => unreachable!() } - Ok(events.len() * mem::size_of::()) + Ok(buf.len()) }, + HandleKind::Screen(vt_i, screen_i) => if let Some(screens) = self.vts.get_mut(&vt_i) { if let Some(screen) = screens.get_mut(&screen_i) { let count = screen.write(buf)?; diff --git a/virtio-core/src/lib.rs b/virtio-core/src/lib.rs index 5d1d6d0436..54554679a1 100644 --- a/virtio-core/src/lib.rs +++ b/virtio-core/src/lib.rs @@ -6,4 +6,4 @@ pub mod utils; mod probe; -pub use probe::{probe_device, Device, MSIX_PRIMARY_VECTOR}; +pub use probe::{probe_device, Device, MSIX_PRIMARY_VECTOR, reinit}; diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index c9fad8427e..cdb029a60c 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -11,7 +11,7 @@ use pcid_interface::*; use syscall::Io; use crate::spec::*; -use crate::transport::{Error, StandardTransport}; +use crate::transport::{Error, StandardTransport, Queue}; use crate::utils::{align_down, VolatileCell}; pub struct Device<'a> { @@ -21,6 +21,9 @@ pub struct Device<'a> { pub isr: &'a VolatileCell, } +unsafe impl Send for Device<'_> {} +unsafe impl Sync for Device<'_> {} + struct MsixInfo { pub virt_table_base: NonNull, pub capability: MsixCapability, @@ -237,21 +240,7 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result let device_space = unsafe { &mut *(device_addr as *mut u8) }; let isr = unsafe { &*(isr_addr as *mut VolatileCell) }; - // Reset the device. - common.device_status.set(DeviceStatusFlags::empty()); - // Upon reset, the device must initialize device status to 0. - assert_eq!(common.device_status.get(), DeviceStatusFlags::empty()); - log::info!("virtio: successfully reseted the device"); - - // XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits - // in `device_status` is required to be done in two steps. - common - .device_status - .set(common.device_status.get() | DeviceStatusFlags::ACKNOWLEDGE); - - common - .device_status - .set(common.device_status.get() | DeviceStatusFlags::DRIVER); + let transport = StandardTransport::new(common, notify_addr as *const u8, notify_multiplier); // Setup interrupts. let all_pci_features = pcid_handle.fetch_all_features()?; @@ -265,12 +254,33 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result log::info!("virtio: using standard PCI transport"); - let transport = StandardTransport::new(common, notify_addr as *const u8, notify_multiplier); - - Ok(Device { + let device = Device { transport, device_space, irq_handle, isr, - }) + }; + + device.transport.reset(); + reinit(& device)?; + + Ok(device) +} + +pub fn reinit<'a>(device: & Device<'a>) -> Result<(), Error> { + // XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits + // in `device_status` is required to be done in two steps. + let mut common = device.transport.common.lock().unwrap(); + let old = common.device_status.get(); + + common + .device_status + .set(old | DeviceStatusFlags::ACKNOWLEDGE); + + let old = common.device_status.get(); + common.device_status.set(old | DeviceStatusFlags::DRIVER); + + + + Ok(()) } diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 6048d14f34..7118adbf9d 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -131,6 +131,7 @@ pub struct Queue<'a> { pub descriptor: Dma<[Descriptor]>, pub available: Available<'a>, pub used_head: AtomicU16, + vector: u16, notification_bell: &'a mut AtomicU16, descriptor_stack: crossbeam_queue::SegQueue, @@ -145,6 +146,7 @@ impl<'a> Queue<'a> { notification_bell: &'a mut AtomicU16, queue_index: u16, + vector: u16, ) -> Arc { let descriptor_stack = crossbeam_queue::SegQueue::new(); (0..descriptor.len() as u16).for_each(|i| descriptor_stack.push(i)); @@ -159,9 +161,21 @@ impl<'a> Queue<'a> { descriptor_stack, used_head: AtomicU16::new(0), sref: sref.clone(), + vector }) } + fn reinit(&self) { + self.used_head.store(0, Ordering::SeqCst); + self.available.set_head_idx(0); + + // Drain all of the available descriptors. + while let Some(_) = self.descriptor_stack.pop() {} + + // Refill the descriptor stack. + (0..self.descriptor.len() as u16).for_each(|i| self.descriptor_stack.push(i)); + } + #[must_use = "The function returns a future that must be awaited to ensure the sent request is completed."] pub fn send(&self, chain: Vec) -> PendingRequest<'a> { let mut first_descriptor: Option = None; @@ -363,7 +377,7 @@ impl Drop for Used<'_> { } pub struct StandardTransport<'a> { - common: Mutex<&'a mut CommonCfg>, + pub(crate) common: Mutex<&'a mut CommonCfg>, notify: *const u8, notify_mul: u32, @@ -383,7 +397,12 @@ impl<'a> StandardTransport<'a> { pub fn reset(&self) { let mut common = self.common.lock().unwrap(); + common.device_status.set(DeviceStatusFlags::empty()); + // Upon reset, the device must initialize device status to 0. + assert_eq!(common.device_status.get(), DeviceStatusFlags::empty()); + + log::debug!("virtio: successfully reseted device"); } pub fn check_device_feature(&self, feature: u32) -> bool { @@ -474,7 +493,7 @@ impl<'a> StandardTransport<'a> { log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})"); - let queue = Queue::new(descriptor, avail, used, notification_bell, queue_index); + let queue = Queue::new(descriptor, avail, used, notification_bell, queue_index, vector); let queue_copy = queue.clone(); let irq_fd = irq_handle.as_raw_fd(); @@ -499,4 +518,23 @@ impl<'a> StandardTransport<'a> { Ok(queue) } + + /// Re-initializes a queue; usually done after a device reset. + pub fn reinit_queue(&self, queue: Arc) { + let mut common = self.common.lock().unwrap(); + queue.reinit(); + + common.queue_select.set(queue.queue_index); + + common.queue_desc.set(queue.descriptor.physical() as u64); + common.queue_driver.set(queue.available.phys_addr() as u64); + common.queue_device.set(queue.used.phys_addr() as u64); + + // Set the MSI-X vector. + common.queue_msix_vector.set(queue.vector); + assert!(common.queue_msix_vector.get() == queue.vector); + + // Enable the queue. + common.queue_enable.set(1); + } } diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index bbe5675688..f22ed521da 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -25,10 +25,12 @@ use std::cell::UnsafeCell; use std::fs::File; use std::io::{Read, Write}; +use std::sync::Arc; use pcid_interface::PcidServerHandle; use syscall::{Packet, SchemeMut}; +use virtio_core::transport::{Queue, self}; use virtio_core::utils::VolatileCell; use virtio_core::MSIX_PRIMARY_VECTOR; @@ -356,10 +358,7 @@ pub struct SetScanout { impl SetScanout { pub fn new(scanout_id: u32, resource_id: u32, rect: GpuRect) -> Self { Self { - header: ControlHeader { - ty: VolatileCell::new(CommandTy::SetScanout), - ..Default::default() - }, + header: ControlHeader::with_ty(CommandTy::SetScanout), rect, scanout_id, @@ -394,6 +393,21 @@ impl XferToHost2d { } } +static DEVICE: spin::Once = spin::Once::new(); + +fn reinit(control_queue: Arc, cursor_queue: Arc) -> Result<(), transport::Error> { + let device = DEVICE.get().unwrap(); + + virtio_core::reinit(device)?; + device.transport.finalize_features(); + + device.transport.reinit_queue(control_queue.clone()); + device.transport.reinit_queue(cursor_queue.clone()); + + device.transport.run_device(); + Ok(()) +} + fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut pcid_handle = PcidServerHandle::connect_default()?; @@ -405,7 +419,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { assert_eq!(pci_config.func.devid, 0x1050); log::info!("virtio-gpu: initiating startup sequence :^)"); - let device = virtio_core::probe_device(&mut pcid_handle)?; + let device = DEVICE.try_call_once(|| virtio_core::probe_device(&mut pcid_handle))?; let config = unsafe { &mut *(device.device_space as *mut GpuConfig) }; // Negotiate features. diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 4439f647be..a07b54a8a5 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -1,11 +1,12 @@ use std::collections::BTreeMap; -use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; use std::sync::Arc; -use common::dma::Dma; use inputd::Damage; -use syscall::{Error as SysError, SchemeMut, EINVAL}; + +use common::dma::Dma; +use syscall::{Error as SysError, SchemeMut, EINVAL, EAGAIN}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::{Error, Queue, StandardTransport}; @@ -40,6 +41,8 @@ pub struct Display<'a> { resource_id: u32, id: usize, + + is_reseted: AtomicBool, } impl<'a> Display<'a> { @@ -61,9 +64,27 @@ impl<'a> Display<'a> { id, resource_id: RESOURCE_ALLOC.fetch_add(1, Ordering::SeqCst), + + is_reseted: AtomicBool::new(false), } } + async fn init(&self) -> Result<(), Error> { + if !self.is_reseted.load(Ordering::SeqCst) { + // The device is already initialized. + return Ok(()); + } + + self.is_reseted.store(false, Ordering::SeqCst); + + log::info!("virtio-gpu: initializing GPU after a reset"); + + crate::reinit(self.control_queue.clone(), self.cursor_queue.clone())?; + self.remap_screen().await?; + + Ok(()) + } + async fn get_fpath(&self, buffer: &mut [u8]) -> Result { let path = format!("display/virtio-gpu:3.0/{}/{}", self.width, self.height); @@ -90,29 +111,26 @@ impl<'a> Display<'a> { Ok(()) } + async fn remap_screen(&self) -> Result { + let bpp = 32; + let fb_size = (self.width as usize * self.height as usize * bpp / 8) + .next_multiple_of(syscall::PAGE_SIZE); + + let mapped = *self.mapped.get().unwrap(); + let address = unsafe {syscall::virttophys(mapped)}?; + + self.map_screen_with(0, address, fb_size, mapped).await + } + async fn map_screen(&self, offset: usize) -> Result { if let Some(mapped) = self.mapped.get() { return Ok(mapped + offset); } - // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. - let mut request = Dma::new(ResourceCreate2d::default())?; - - request.set_width(self.width); - request.set_height(self.height); - request.set_format(ResourceFormat::Bgrx); - request.set_resource_id(self.resource_id); - - self.send_request(request).await?; - - // Allocate a framebuffer from guest ram, and attach it as backing storage to the - // resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. Scatter - // lists are supported, so the framebuffer doesn’t need to be contignous in guest - // physical memory. let bpp = 32; let fb_size = (self.width as usize * self.height as usize * bpp / 8) .next_multiple_of(syscall::PAGE_SIZE); - let address = unsafe { syscall::physalloc(fb_size) }? as u64; + let address = unsafe { syscall::physalloc(fb_size) }? ; let mapped = unsafe { common::physmap( address as usize, @@ -126,9 +144,28 @@ impl<'a> Display<'a> { core::ptr::write_bytes(mapped as *mut u8, 255, fb_size); } + self.map_screen_with(offset, address, fb_size, mapped).await + } + + async fn map_screen_with(&self, offset: usize, address: usize, size: usize, mapped: usize) -> Result { + // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. + let mut request = Dma::new(ResourceCreate2d::default())?; + + request.set_width(self.width); + request.set_height(self.height); + request.set_format(ResourceFormat::Bgrx); + request.set_resource_id(self.resource_id); + + self.send_request(request).await?; + + // Use the allocated framebuffer from tthe guest ram, and attach it as backing + // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. + // + // TODO(andypython): Scatter lists are supported, so the framebuffer doesn’t need to be + // contignous in guest physical memory. let entry = Dma::new(MemEntry { - address, - length: fb_size as u32, + address: address as u64, + length: size as u32, padding: 0, })?; @@ -200,12 +237,22 @@ impl<'a> Display<'a> { // Go back to legacy mode. self.transport.reset(); + self.is_reseted.store(true, Ordering::SeqCst); + Ok(()) } } +enum Handle { + Vt(usize /* VT index */), + Input, +} + pub struct Scheme<'a> { - handles: BTreeMap>>, + vts: BTreeMap>>, + handles: BTreeMap, + /// Counter used for file descriptor allocation. + next_id: AtomicUsize, inputd_handle: inputd::Handle, displays: Vec>>, } @@ -225,9 +272,16 @@ impl<'a> Scheme<'a> { ) .await?; + let mut inputd_handle = inputd::Handle::new("virtio-gpu:handle").unwrap(); + + let mut vts = BTreeMap::new(); + vts.insert(inputd_handle.register().unwrap(), displays[0].clone()); + Ok(Self { + vts, handles: BTreeMap::new(), - inputd_handle: inputd::Handle::new("virtio-gpu").unwrap(), + next_id: AtomicUsize::new(0), + inputd_handle, displays, }) } @@ -284,56 +338,42 @@ impl<'a> Scheme<'a> { impl<'a> SchemeMut for Scheme<'a> { fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { - dbg!(&path); + if path == "handle" { + let fd = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.insert(fd, Handle::Input); + + return Ok(fd); + } let mut parts = path.split('/'); let mut screen = parts.next().unwrap_or("").split('.'); - static YES: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(true); - if YES.load(Ordering::SeqCst) { - YES.store(false, Ordering::SeqCst); - } - - let fd = screen.next().unwrap_or("").parse::().unwrap(); - - if path.contains("deactivate") { - log::info!("virtio-gpu: deactivating display at file #{}", fd); - - let handle = self.handles.get(&fd).unwrap(); - futures::executor::block_on(handle.detach()).unwrap(); - - return Ok(0); - } - + let vt = screen.next().unwrap_or("").parse::().unwrap(); let id = screen.next().unwrap_or("").parse::().unwrap_or(0); - dbg!(&id); + dbg!(vt, id); - let display = self.displays.get(id).ok_or(SysError::new(EINVAL))?; + if self.displays.get(id).is_none() { + return Err(SysError::new(EINVAL)); + } - let fd = self.inputd_handle.register().unwrap(); - self.handles.insert(fd, display.clone()); + let fd = self.next_id.fetch_add(1, Ordering::SeqCst); + // FIXME: The +1 is a hack. vesad smh + self.handles.insert(fd, Handle::Vt(vt + 1)); Ok(fd) } - fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> syscall::Result { - todo!() - } - - fn fevent( - &mut self, - _id: usize, - _flags: syscall::EventFlags, - ) -> syscall::Result { - log::warn!("fevent is a stub!"); - Ok(syscall::EventFlags::empty()) - } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { - let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - let bytes_copied = futures::executor::block_on(handle.get_fpath(buf)).unwrap(); + match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { + Handle::Vt(id) => { + let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?; + let bytes_copied = futures::executor::block_on(handle.get_fpath(buf)).unwrap(); - Ok(bytes_copied) + Ok(bytes_copied) + } + + Handle::Input => unreachable!(), + } } fn fmap_old(&mut self, id: usize, map: &syscall::OldMap) -> syscall::Result { @@ -349,14 +389,25 @@ impl<'a> SchemeMut for Scheme<'a> { } fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result { - let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - Ok(futures::executor::block_on(handle.map_screen(map.offset)).unwrap()) + match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { + Handle::Vt(id) => { + let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?; + Ok(futures::executor::block_on(handle.map_screen(map.offset)).unwrap()) + } + _ => unreachable!(), + } } fn fsync(&mut self, id: usize) -> syscall::Result { - let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - futures::executor::block_on(handle.flush(None)).unwrap(); - Ok(0) + match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { + Handle::Vt(id) => { + let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?; + futures::executor::block_on(handle.flush(None)).unwrap(); + Ok(0) + } + + _ => unreachable!(), + } } fn read(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result { @@ -366,18 +417,54 @@ impl<'a> SchemeMut for Scheme<'a> { } fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { - let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - let damages = unsafe { - core::slice::from_raw_parts( - buf.as_ptr() as *const Damage, - buf.len() / core::mem::size_of::(), - ) - }; + match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { + Handle::Vt(id) => { + let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?; - for damage in damages { - futures::executor::block_on(handle.flush(Some(damage))).unwrap(); + // The VT is not active and the device is reseted. Ask them to try + // again later. + if handle.is_reseted.load(Ordering::SeqCst) { + return Err(SysError::new(EAGAIN)); + } + + let damages = unsafe { + core::slice::from_raw_parts( + buf.as_ptr() as *const Damage, + buf.len() / core::mem::size_of::(), + ) + }; + + for damage in damages { + futures::executor::block_on(handle.flush(Some(damage))).unwrap(); + } + + Ok(buf.len()) + } + + Handle::Input => { + let command = inputd::Command::parse(buf); + + match command.ty { + inputd::CommandTy::Activate => { + let vt = command.value; + + let display = self.vts.get(&vt).unwrap(); + futures::executor::block_on(display.init()).unwrap(); + }, + + inputd::CommandTy::Deactivate => { + let vt = command.value; + + let display = self.vts.get(&vt).ok_or(SysError::new(EINVAL))?; + futures::executor::block_on(display.detach()).unwrap(); + } + + _ => unreachable!(), + } + + Ok(buf.len()) + } } - Ok(buf.len()) } fn seek(&mut self, _id: usize, _pos: isize, _whence: usize) -> syscall::Result { diff --git a/virtio-netd/Cargo.toml b/virtio-netd/Cargo.toml index f4a116f10c..3458d7b046 100644 --- a/virtio-netd/Cargo.toml +++ b/virtio-netd/Cargo.toml @@ -10,6 +10,7 @@ futures = { version = "0.3.28", features = ["executor"] } virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } +common = { path = "../common" } redox-daemon = "0.1" redox_syscall = "0.3" diff --git a/virtio-netd/src/scheme.rs b/virtio-netd/src/scheme.rs index 251a501ce0..829a3002e6 100644 --- a/virtio-netd/src/scheme.rs +++ b/virtio-netd/src/scheme.rs @@ -5,6 +5,8 @@ use std::sync::Arc; use syscall::Error as SysError; use syscall::*; +use common::dma::Dma; + use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::Queue; From a153c8bc1c15d76d05a70eec8f6499d041a910c0 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Thu, 20 Jul 2023 19:20:56 +1000 Subject: [PATCH 0674/1301] inputd: correctly pass on resize events Signed-off-by: Anhad Singh --- bgad/src/main.rs | 4 +- inputd/src/lib.rs | 107 +++++++++++++++++++++++++++++------ inputd/src/main.rs | 36 +++++++----- vboxd/src/main.rs | 2 +- vesad/src/scheme.rs | 26 ++++----- virtio-core/src/lib.rs | 2 +- virtio-core/src/probe.rs | 15 +++-- virtio-core/src/transport.rs | 22 ++++--- virtio-gpud/src/main.rs | 2 +- virtio-gpud/src/scheme.rs | 42 ++++++++------ 10 files changed, 178 insertions(+), 80 deletions(-) diff --git a/bgad/src/main.rs b/bgad/src/main.rs index 781e68ae8f..cc7570efab 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -37,8 +37,8 @@ fn main() { print!("{}", format!(" - BGA {}x{}\n", bga.width(), bga.height())); let mut scheme = BgaScheme { - bga: bga, - display: File::open("display/vesa:input").ok() + bga, + display: File::open("input:producer").ok() }; scheme.update_size(); diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index bd9cb6655d..3c2eb329d4 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -1,6 +1,7 @@ +#![feature(iter_next_chunk)] + use std::fs::File; use std::io::{Error, Read}; -use std::mem; pub struct Handle(File); @@ -19,33 +20,103 @@ impl Handle { #[derive(Debug, Copy, Clone, PartialEq)] #[repr(u8)] -pub enum CommandTy { +enum CmdTy { Unknown = 0, Activate, Deactivate, + Resize, } -#[repr(C)] -pub struct Command { - pub ty: CommandTy, - pub value: usize, +impl From for CmdTy { + fn from(value: u8) -> Self { + match value { + 1 => CmdTy::Activate, + 2 => CmdTy::Deactivate, + 3 => CmdTy::Resize, + _ => CmdTy::Unknown, + } + } } -impl Command { - pub fn new(ty: CommandTy, value: usize) -> Self { - Self { ty, value } - } +pub enum Cmd { + // TODO(andypython): #VT should really need to be a `u8`. + Activate(usize /* #VT */), + Deactivate(usize /* #VT */), + Resize { + // TODO(andypython): do we really need to pass the VT here? + vt: usize, - /// ## Panics - /// This function panics if the buffer is not `sizeof::()` bytes wide. - pub fn parse<'a>(buffer: &'a [u8]) -> &'a Command { - assert_eq!(buffer.len(), core::mem::size_of::()); - unsafe { &*(buffer.as_ptr() as *const Command) } - } + width: u32, + height: u32, + stride: u32, + }, +} - pub fn into_bytes(self) -> [u8; mem::size_of::()] { - unsafe { core::mem::transmute(self) } +impl Cmd { + fn ty(&self) -> CmdTy { + match self { + Cmd::Activate(_) => CmdTy::Activate, + Cmd::Deactivate(_) => CmdTy::Deactivate, + Cmd::Resize { .. } => CmdTy::Resize, + } + } +} + +pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), syscall::Error> { + use std::os::fd::AsRawFd; + + let mut result = vec![]; + result.push(command.ty() as u8); + + match command { + Cmd::Activate(vt) | Cmd::Deactivate(vt) => result.extend_from_slice(&vt.to_le_bytes()), + Cmd::Resize { + vt, + width, + height, + stride, + } => { + result.extend_from_slice(&vt.to_le_bytes()); + result.extend(width.to_le_bytes()); + result.extend(height.to_le_bytes()); + result.extend(stride.to_le_bytes()); + } + }; + + let written = syscall::write(file.as_raw_fd() as usize, &result)?; + + // XXX: Ensure all of the data is written. + assert_eq!(written, result.len()); + Ok(()) +} + +pub fn parse_command(buffer: &[u8]) -> Option { + const U32_SIZE: usize = core::mem::size_of::(); + const USIZE_SIZE: usize = core::mem::size_of::(); + + let mut parser = buffer.iter().cloned(); + + let command = CmdTy::from(parser.next()?); + let vt = usize::from_le_bytes(parser.next_chunk::().ok()?); + + match command { + CmdTy::Activate => Some(Cmd::Activate(vt)), + CmdTy::Deactivate => Some(Cmd::Deactivate(vt)), + CmdTy::Resize => { + let width = parser.next_chunk::().ok()?; + let height = parser.next_chunk::().ok()?; + let stride = parser.next_chunk::().ok()?; + + Some(Cmd::Resize { + vt, + width: u32::from_le_bytes(width), + height: u32::from_le_bytes(height), + stride: u32::from_le_bytes(stride), + }) + } + + CmdTy::Unknown => None, } } diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 0609cb1491..da9efd6619 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -13,11 +13,12 @@ use std::collections::BTreeMap; use std::fs::File; -use std::io::{self, Read, Write}; +use std::io::{Read, Write}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -use inputd::{Command, CommandTy}; +use inputd::Cmd; + use orbclient::{Event, EventOption}; use syscall::{Error as SysError, EventFlags, Packet, SchemeMut, EINVAL}; @@ -166,15 +167,25 @@ impl SchemeMut for InputScheme { _ => (), }, + EventOption::Resize(resize_event) => { + if let Some((_, file, current)) = self.active_vt.as_mut() { + inputd::send_comand( + file, + Cmd::Resize { + vt: current.clone(), + width: resize_event.width, + height: resize_event.height, + + // TODO(andypython): Figure out how to get the stride. + stride: resize_event.width, + }, + )?; + } + } + _ => continue, } - let deactivate = |file: &mut File, id: usize| -> io::Result<()> { - let command = Command::new(CommandTy::Deactivate, id).into_bytes(); - file.write(&command)?; - Ok(()) - }; - if let Some(new_active) = new_active_opt { if let Some(vt) = self.vts.get(&new_active).cloned() { if let Some((_, file, current)) = self.active_vt.as_mut() { @@ -183,20 +194,19 @@ impl SchemeMut for InputScheme { continue; } - deactivate(file, *current).unwrap(); + inputd::send_comand(file, Cmd::Deactivate(*current))?; } else { let id = self.next_vt_id.load(Ordering::SeqCst) - 1; let mut vt = File::open(self.vts.get_mut(&id).unwrap().as_ref()).unwrap(); - deactivate(&mut vt, id).unwrap(); + inputd::send_comand(&mut vt, Cmd::Deactivate(id))?; } log::info!("inputd: switching to VT #{new_active} (`{vt}`)"); let mut file = File::open(vt.as_ref()).unwrap(); - file.write(&Command::new(CommandTy::Activate, new_active).into_bytes()) - .unwrap(); + inputd::send_comand(&mut file, Cmd::Activate(new_active))?; self.active_vt = Some((vt.clone(), file, new_active)); } else { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); @@ -294,7 +304,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { last_allocated == *vt }; - // The activate VT is not the same as the VT that the consumer is listening to + // The activate VT is not the same as the VT that the consumer is listening to // for events. if !should_notify { continue; diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index cb3bba6035..845464d5e4 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -208,7 +208,7 @@ fn main() { let mut width = 0; let mut height = 0; - let mut display_opt = File::open("display/vesa:input").ok(); + let mut display_opt = File::open("inputd:producer").ok(); if let Some(ref display) = display_opt { let mut buf: [u8; 4096] = [0; 4096]; if let Ok(count) = syscall::fpath(display.as_raw_fd() as usize, &mut buf) { diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index d334c79a89..86f29b7c9e 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,8 +1,7 @@ use std::collections::BTreeMap; use std::{mem, ptr, slice, str}; -use orbclient::{Event, EventOption}; -use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE}; +use syscall::{Error, EventFlags, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE}; use crate::{ display::Display, @@ -37,7 +36,6 @@ pub struct DisplayScheme { pub vts: BTreeMap>>, next_id: usize, pub handles: BTreeMap, - super_key: bool, inputd_handle: inputd::Handle, } @@ -74,7 +72,6 @@ impl DisplayScheme { vts, next_id: 0, handles: BTreeMap::new(), - super_key: false, inputd_handle } } @@ -306,11 +303,13 @@ impl SchemeMut for DisplayScheme { match handle.kind { HandleKind::Input => { - let command = inputd::Command::parse(buf); + use inputd::Cmd as DisplayCommand; + + let command = inputd::parse_command(buf).unwrap(); - match command.ty { - inputd::CommandTy::Activate => { - let vt_i = VtIndex(command.value); + match command { + DisplayCommand::Activate(vt) => { + let vt_i = VtIndex(vt); if let Some(screens) = self.vts.get_mut(&vt_i) { for (screen_i, screen) in screens.iter_mut() { @@ -323,12 +322,13 @@ impl SchemeMut for DisplayScheme { self.active = vt_i; }, - - inputd::CommandTy::Deactivate => { - // Nothing :) - }, - _ => unreachable!() + DisplayCommand::Resize { width, height, stride, .. } => { + self.resize(width as usize, height as usize, stride as usize); + } + + // Nothing to do for deactivate :) + DisplayCommand::Deactivate(_) => {}, } Ok(buf.len()) diff --git a/virtio-core/src/lib.rs b/virtio-core/src/lib.rs index 54554679a1..87b737f124 100644 --- a/virtio-core/src/lib.rs +++ b/virtio-core/src/lib.rs @@ -6,4 +6,4 @@ pub mod utils; mod probe; -pub use probe::{probe_device, Device, MSIX_PRIMARY_VECTOR, reinit}; +pub use probe::{probe_device, reinit, Device, MSIX_PRIMARY_VECTOR}; diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index cdb029a60c..f97ae30f5a 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -11,7 +11,7 @@ use pcid_interface::*; use syscall::Io; use crate::spec::*; -use crate::transport::{Error, StandardTransport, Queue}; +use crate::transport::{Error, Queue, StandardTransport}; use crate::utils::{align_down, VolatileCell}; pub struct Device<'a> { @@ -190,7 +190,12 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result let size = offset + capability.length as usize; - let addr = common::physmap(aligned_addr, size, common::Prot::RW, common::MemoryType::Uncacheable)? as usize; + let addr = common::physmap( + aligned_addr, + size, + common::Prot::RW, + common::MemoryType::Uncacheable, + )? as usize; addr + offset }; @@ -262,12 +267,12 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result }; device.transport.reset(); - reinit(& device)?; + reinit(&device)?; Ok(device) } -pub fn reinit<'a>(device: & Device<'a>) -> Result<(), Error> { +pub fn reinit<'a>(device: &Device<'a>) -> Result<(), Error> { // XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits // in `device_status` is required to be done in two steps. let mut common = device.transport.common.lock().unwrap(); @@ -280,7 +285,5 @@ pub fn reinit<'a>(device: & Device<'a>) -> Result<(), Error> { let old = common.device_status.get(); common.device_status.set(old | DeviceStatusFlags::DRIVER); - - Ok(()) } diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 7118adbf9d..9d72b4fab0 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -161,7 +161,7 @@ impl<'a> Queue<'a> { descriptor_stack, used_head: AtomicU16::new(0), sref: sref.clone(), - vector + vector, }) } @@ -171,7 +171,7 @@ impl<'a> Queue<'a> { // Drain all of the available descriptors. while let Some(_) = self.descriptor_stack.pop() {} - + // Refill the descriptor stack. (0..self.descriptor.len() as u16).for_each(|i| self.descriptor_stack.push(i)); } @@ -244,9 +244,9 @@ impl<'a> Available<'a> { let size = size.next_multiple_of(syscall::PAGE_SIZE); // align to page size let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; - let virt = unsafe { - common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) - }.map_err(Error::SyscallError)?; + let virt = + unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) } + .map_err(Error::SyscallError)?; let ring = unsafe { &mut *(virt as *mut AvailableRing) }; @@ -312,7 +312,8 @@ impl<'a> Used<'a> { let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; let virt = - unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) }.map_err(Error::SyscallError)?; + unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) } + .map_err(Error::SyscallError)?; let ring = unsafe { &mut *(virt as *mut UsedRing) }; @@ -493,7 +494,14 @@ impl<'a> StandardTransport<'a> { log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})"); - let queue = Queue::new(descriptor, avail, used, notification_bell, queue_index, vector); + let queue = Queue::new( + descriptor, + avail, + used, + notification_bell, + queue_index, + vector, + ); let queue_copy = queue.clone(); let irq_fd = irq_handle.as_raw_fd(); diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index f22ed521da..3fdc3eb347 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -30,7 +30,7 @@ use std::sync::Arc; use pcid_interface::PcidServerHandle; use syscall::{Packet, SchemeMut}; -use virtio_core::transport::{Queue, self}; +use virtio_core::transport::{self, Queue}; use virtio_core::utils::VolatileCell; use virtio_core::MSIX_PRIMARY_VECTOR; diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index a07b54a8a5..a42a81c51e 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -6,7 +6,7 @@ use std::sync::Arc; use inputd::Damage; use common::dma::Dma; -use syscall::{Error as SysError, SchemeMut, EINVAL, EAGAIN}; +use syscall::{Error as SysError, SchemeMut, EAGAIN, EINVAL}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::{Error, Queue, StandardTransport}; @@ -117,8 +117,8 @@ impl<'a> Display<'a> { .next_multiple_of(syscall::PAGE_SIZE); let mapped = *self.mapped.get().unwrap(); - let address = unsafe {syscall::virttophys(mapped)}?; - + let address = unsafe { syscall::virttophys(mapped) }?; + self.map_screen_with(0, address, fb_size, mapped).await } @@ -130,7 +130,7 @@ impl<'a> Display<'a> { let bpp = 32; let fb_size = (self.width as usize * self.height as usize * bpp / 8) .next_multiple_of(syscall::PAGE_SIZE); - let address = unsafe { syscall::physalloc(fb_size) }? ; + let address = unsafe { syscall::physalloc(fb_size) }?; let mapped = unsafe { common::physmap( address as usize, @@ -147,7 +147,13 @@ impl<'a> Display<'a> { self.map_screen_with(offset, address, fb_size, mapped).await } - async fn map_screen_with(&self, offset: usize, address: usize, size: usize, mapped: usize) -> Result { + async fn map_screen_with( + &self, + offset: usize, + address: usize, + size: usize, + mapped: usize, + ) -> Result { // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. let mut request = Dma::new(ResourceCreate2d::default())?; @@ -158,10 +164,10 @@ impl<'a> Display<'a> { self.send_request(request).await?; - // Use the allocated framebuffer from tthe guest ram, and attach it as backing - // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. + // Use the allocated framebuffer from tthe guest ram, and attach it as backing + // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. // - // TODO(andypython): Scatter lists are supported, so the framebuffer doesn’t need to be + // TODO(andypython): Scatter lists are supported, so the framebuffer doesn’t need to be // contignous in guest physical memory. let entry = Dma::new(MemEntry { address: address as u64, @@ -421,7 +427,7 @@ impl<'a> SchemeMut for Scheme<'a> { Handle::Vt(id) => { let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?; - // The VT is not active and the device is reseted. Ask them to try + // The VT is not active and the device is reseted. Ask them to try // again later. if handle.is_reseted.load(Ordering::SeqCst) { return Err(SysError::new(EAGAIN)); @@ -442,24 +448,24 @@ impl<'a> SchemeMut for Scheme<'a> { } Handle::Input => { - let command = inputd::Command::parse(buf); + use inputd::Cmd as DisplayCommand; - match command.ty { - inputd::CommandTy::Activate => { - let vt = command.value; + let command = inputd::parse_command(buf).unwrap(); + match command { + DisplayCommand::Activate(vt) => { let display = self.vts.get(&vt).unwrap(); futures::executor::block_on(display.init()).unwrap(); - }, - - inputd::CommandTy::Deactivate => { - let vt = command.value; + } + DisplayCommand::Deactivate(vt) => { let display = self.vts.get(&vt).ok_or(SysError::new(EINVAL))?; futures::executor::block_on(display.detach()).unwrap(); } - _ => unreachable!(), + DisplayCommand::Resize { .. } => { + log::warn!("virtio-gpu: resize is not implemented yet") + } } Ok(buf.len()) From 443b7c9b8a5c0e5cc2d44926a7bad705181ccdfd Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Thu, 20 Jul 2023 20:08:30 +1000 Subject: [PATCH 0675/1301] virtio-netd: fix broken build Signed-off-by: Anhad Singh --- Cargo.lock | 1 + virtio-netd/Cargo.toml | 1 + virtio-netd/src/scheme.rs | 2 ++ 3 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 0e17d62f53..a0d8949010 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1908,6 +1908,7 @@ dependencies = [ name = "virtio-netd" version = "0.1.0" dependencies = [ + "common", "futures", "log", "netutils", diff --git a/virtio-netd/Cargo.toml b/virtio-netd/Cargo.toml index f4a116f10c..3458d7b046 100644 --- a/virtio-netd/Cargo.toml +++ b/virtio-netd/Cargo.toml @@ -10,6 +10,7 @@ futures = { version = "0.3.28", features = ["executor"] } virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } +common = { path = "../common" } redox-daemon = "0.1" redox_syscall = "0.3" diff --git a/virtio-netd/src/scheme.rs b/virtio-netd/src/scheme.rs index 251a501ce0..c535d7a886 100644 --- a/virtio-netd/src/scheme.rs +++ b/virtio-netd/src/scheme.rs @@ -8,6 +8,8 @@ use syscall::*; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::Queue; +use common::dma::Dma; + use crate::{VirtHeader, MAX_BUFFER_LEN}; pub struct NetworkScheme<'a> { From 440d6381f9423995b5c2cb37a48e11a53b87ab0d Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Thu, 20 Jul 2023 20:04:43 +1000 Subject: [PATCH 0676/1301] inputd: rework display events Signed-off-by: Anhad Singh --- Cargo.lock | 1 + inputd/Cargo.toml | 1 + inputd/src/lib.rs | 6 +- inputd/src/main.rs | 197 +++++++++++++++++++++++++++----------- vesad/src/main.rs | 2 + vesad/src/scheme.rs | 6 +- virtio-gpud/src/main.rs | 2 + virtio-gpud/src/scheme.rs | 18 ++-- 8 files changed, 166 insertions(+), 67 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0d8949010..67b819364a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -640,6 +640,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_syscall 0.3.5", + "spin", ] [[package]] diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index dfc537236e..78057535f6 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -11,3 +11,4 @@ redox-daemon = "0.1.0" redox-log = "0.1.1" redox_syscall = "0.3.5" orbclient = "0.3.27" +spin = "0.9.8" diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 3c2eb329d4..0f71bdd213 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -1,7 +1,7 @@ #![feature(iter_next_chunk)] use std::fs::File; -use std::io::{Error, Read}; +use std::io::{Error, Read, Write}; pub struct Handle(File); @@ -16,6 +16,10 @@ impl Handle { pub fn register(&mut self) -> Result { Ok(dbg!(self.0.read(&mut [])?)) } + + pub fn activate(&mut self, vt: usize) -> Result { + Ok(dbg!(self.0.write(&vt.to_le_bytes())?)) + } } #[derive(Debug, Copy, Clone, PartialEq)] diff --git a/inputd/src/main.rs b/inputd/src/main.rs index da9efd6619..91cd76c92a 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -19,6 +19,8 @@ use std::sync::Arc; use inputd::Cmd; +use spin::Mutex; + use orbclient::{Event, EventOption}; use syscall::{Error as SysError, EventFlags, Packet, SchemeMut, EINVAL}; @@ -30,7 +32,9 @@ enum Handle { notified: bool, vt: usize, }, - Device(Arc), + Device { + device: String, + }, } impl Handle { @@ -39,15 +43,52 @@ impl Handle { } } +/// VT Inner State +/// +/// This is *required* to be lazily initialized since opening the handle to the display +/// requires the system call to return first. Otherwise, it will block indefinitely. +struct VtInner { + handle_file: File, +} + +struct Vt { + display: String, + index: usize, + inner: spin::Once>, +} + +impl Vt { + pub fn new(display: D, index: usize) -> Arc + where + D: Into, + { + Arc::new(Self { + display: display.into(), + inner: spin::Once::new(), + index, + }) + } + + pub fn inner(&self) -> &Mutex { + self.inner.call_once(|| { + let handle_file = File::open(format!("{}:handle", self.display)).unwrap(); + + Mutex::new(VtInner { handle_file }) + }) + } +} + struct InputScheme { handles: BTreeMap, next_id: AtomicUsize, next_vt_id: AtomicUsize, - vts: BTreeMap>, + vts: BTreeMap>, super_key: bool, - active_vt: Option<(Arc, File, usize /* VT index */)>, + active_vt: Option>, + + todo: Vec, } impl InputScheme { @@ -60,6 +101,8 @@ impl InputScheme { vts: BTreeMap::new(), super_key: false, active_vt: None, + + todo: vec![], } } } @@ -74,25 +117,18 @@ impl SchemeMut for InputScheme { let handle_ty = match command { "producer" => Handle::Producer, "consumer" => { - let vt = if let Some((_, _, vt)) = self.active_vt { - vt - } else { - // No one is currently set as active, so we assume that the last allocated - // one will be willing to take this consumer. - self.next_vt_id.load(Ordering::SeqCst) - 1 - }; + let target = path_parts.next().unwrap().parse::().unwrap(); - dbg!(vt); Handle::Consumer { events: EventFlags::empty(), pending: Vec::new(), notified: false, - vt, + vt: target, } } "handle" => { - let value = path_parts.collect::>().join("/"); - Handle::Device(Arc::new(value)) + let display = path_parts.collect::>().join("/"); + Handle::Device { device: display } } _ => unreachable!("inputd: invalid path {path}"), @@ -104,6 +140,22 @@ impl SchemeMut for InputScheme { Ok(fd) } + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { + let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; + + if let Handle::Consumer { vt, .. } = handle { + let display = self.vts.get(vt).ok_or(SysError::new(EINVAL))?; + let vt = format!("{}:{vt}", display.display); + + let size = core::cmp::min(vt.len(), buf.len()); + buf[..size].copy_from_slice(&vt.as_bytes()[..size]); + + Ok(size) + } else { + Err(SysError::new(EINVAL)) + } + } + fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; @@ -118,9 +170,11 @@ impl SchemeMut for InputScheme { Ok(copy) } - Handle::Device(device) => { + Handle::Device { device } => { + assert!(buf.is_empty()); + let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); - self.vts.insert(vt, device.clone()); + self.vts.insert(vt, Vt::new(device.clone(), vt)); Ok(vt) } @@ -129,6 +183,25 @@ impl SchemeMut for InputScheme { } fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; + + match handle { + Handle::Device { .. } | Handle::Consumer { .. } => { + if buf.len() == core::mem::size_of::() { + // The device is requesting to activate a VT. + let vt = + usize::from_le_bytes(buf.try_into().map_err(|_| SysError::new(EINVAL))?); + + self.todo.push(vt); + return Ok(buf.len()); + } else { + unreachable!() + } + } + + _ => {} + } + if buf.len() == 1 && buf[0] > 0xf4 { return Ok(1); } @@ -168,62 +241,65 @@ impl SchemeMut for InputScheme { }, EventOption::Resize(resize_event) => { - if let Some((_, file, current)) = self.active_vt.as_mut() { - inputd::send_comand( - file, - Cmd::Resize { - vt: current.clone(), - width: resize_event.width, - height: resize_event.height, + let active_vt = self.active_vt.as_ref().unwrap(); + let mut vt_inner = active_vt.inner().lock(); - // TODO(andypython): Figure out how to get the stride. - stride: resize_event.width, - }, - )?; - } + inputd::send_comand( + &mut vt_inner.handle_file, + Cmd::Resize { + vt: active_vt.index, + width: resize_event.width, + height: resize_event.height, + + // TODO(andypython): Figure out how to get the stride. + stride: resize_event.width, + }, + )?; } _ => continue, } if let Some(new_active) = new_active_opt { - if let Some(vt) = self.vts.get(&new_active).cloned() { - if let Some((_, file, current)) = self.active_vt.as_mut() { - // If the VT is already active, don't do anything. - if new_active == *current { - continue; - } + if let Some(new_active) = self.vts.get(&new_active).cloned() { + { + let active_vt = self.active_vt.as_ref().unwrap(); + let mut vt_inner = active_vt.inner().lock(); - inputd::send_comand(file, Cmd::Deactivate(*current))?; - } else { - let id = self.next_vt_id.load(Ordering::SeqCst) - 1; - let mut vt = File::open(self.vts.get_mut(&id).unwrap().as_ref()).unwrap(); - - inputd::send_comand(&mut vt, Cmd::Deactivate(id))?; + inputd::send_comand( + &mut vt_inner.handle_file, + Cmd::Deactivate(active_vt.index), + )?; } - log::info!("inputd: switching to VT #{new_active} (`{vt}`)"); + let mut vt_inner = new_active.inner().lock(); - let mut file = File::open(vt.as_ref()).unwrap(); - - inputd::send_comand(&mut file, Cmd::Activate(new_active))?; - self.active_vt = Some((vt.clone(), file, new_active)); + inputd::send_comand( + &mut vt_inner.handle_file, + Cmd::Activate(new_active.index), + )?; + self.active_vt = Some(new_active.clone()); } else { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); } } } - let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; assert!(handle.is_producer()); + let active_vt = self.active_vt.as_ref().unwrap(); for handle in self.handles.values_mut() { match handle { Handle::Consumer { - ref mut pending, - ref mut notified, + pending, + notified, + vt, .. } => { + if *vt != active_vt.index { + continue; + } + pending.extend_from_slice(buf); *notified = false; } @@ -257,7 +333,7 @@ impl SchemeMut for InputScheme { } fn close(&mut self, _id: usize) -> syscall::Result { - todo!() + Ok(0) } } @@ -281,6 +357,20 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { scheme.handle(&mut packet); socket_file.write(&packet)?; + while let Some(vt) = scheme.todo.pop() { + let vt = scheme.vts.get_mut(&vt).unwrap(); + let mut vt_inner = vt.inner().lock(); + + // Failing to activate a VT is not a fatal error. + if let Err(err) = + inputd::send_comand(&mut vt_inner.handle_file, Cmd::Activate(vt.index)) + { + log::error!("inputd: failed to activate VT #{}: {err}", vt.index) + } + + scheme.active_vt = Some(vt.clone()); + } + if !should_handle { continue; } @@ -297,16 +387,11 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { continue; } - let should_notify = if let Some((_, _, active_vt)) = scheme.active_vt { - active_vt == *vt - } else { - let last_allocated = scheme.next_vt_id.load(Ordering::SeqCst) - 1; - last_allocated == *vt - }; + let active_vt = scheme.active_vt.as_ref().unwrap(); // The activate VT is not the same as the VT that the consumer is listening to // for events. - if !should_notify { + if active_vt.index != *vt { continue; } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 3d7cf98f4c..505eb0d95b 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -98,6 +98,8 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[b daemon.ready().expect("failed to notify parent"); + scheme.inputd_handle.activate(1).unwrap(); + let mut blocked = Vec::new(); loop { let mut packet = Packet::default(); diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 86f29b7c9e..ee781eb1e5 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -36,12 +36,12 @@ pub struct DisplayScheme { pub vts: BTreeMap>>, next_id: usize, pub handles: BTreeMap, - inputd_handle: inputd::Handle, + pub inputd_handle: inputd::Handle, } impl DisplayScheme { pub fn new(mut framebuffers: Vec, spec: &[bool]) -> DisplayScheme { - let mut inputd_handle = inputd::Handle::new("vesa:handle").unwrap(); + let mut inputd_handle = inputd::Handle::new("vesa").unwrap(); let mut onscreens = Vec::new(); for fb in framebuffers.iter_mut() { @@ -185,7 +185,7 @@ impl SchemeMut for DisplayScheme { } fn dup(&mut self, id: usize, buf: &[u8]) -> Result { - if ! buf.is_empty() { + if !buf.is_empty() { return Err(Error::new(EINVAL)); } diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index 3fdc3eb347..73434398e3 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -446,6 +446,8 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device.transport.clone(), ))?; + scheme.inputd_handle.activate(scheme.main_vt)?; + loop { let mut packet = Packet::default(); socket_file diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index a42a81c51e..5495218cbb 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -259,8 +259,10 @@ pub struct Scheme<'a> { handles: BTreeMap, /// Counter used for file descriptor allocation. next_id: AtomicUsize, - inputd_handle: inputd::Handle, displays: Vec>>, + + pub(crate) inputd_handle: inputd::Handle, + pub(crate) main_vt: usize, } impl<'a> Scheme<'a> { @@ -278,10 +280,11 @@ impl<'a> Scheme<'a> { ) .await?; - let mut inputd_handle = inputd::Handle::new("virtio-gpu:handle").unwrap(); + let mut inputd_handle = inputd::Handle::new("virtio-gpu").unwrap(); let mut vts = BTreeMap::new(); - vts.insert(inputd_handle.register().unwrap(), displays[0].clone()); + let main_vt = inputd_handle.register().unwrap(); + vts.insert(main_vt, displays[0].clone()); Ok(Self { vts, @@ -289,6 +292,7 @@ impl<'a> Scheme<'a> { next_id: AtomicUsize::new(0), inputd_handle, displays, + main_vt, }) } @@ -370,9 +374,9 @@ impl<'a> SchemeMut for Scheme<'a> { } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { - match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { + match self.handles.get(&id).unwrap() { Handle::Vt(id) => { - let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?; + let handle = self.vts.get_mut(&(id - 1)).ok_or(SysError::new(EINVAL))?; let bytes_copied = futures::executor::block_on(handle.get_fpath(buf)).unwrap(); Ok(bytes_copied) @@ -397,7 +401,7 @@ impl<'a> SchemeMut for Scheme<'a> { fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result { match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { Handle::Vt(id) => { - let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?; + let handle = self.vts.get_mut(&(id - 1)).ok_or(SysError::new(EINVAL))?; Ok(futures::executor::block_on(handle.map_screen(map.offset)).unwrap()) } _ => unreachable!(), @@ -425,7 +429,7 @@ impl<'a> SchemeMut for Scheme<'a> { fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { Handle::Vt(id) => { - let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?; + let handle = self.vts.get_mut(&(id - 1)).ok_or(SysError::new(EINVAL))?; // The VT is not active and the device is reseted. Ask them to try // again later. From 0f6d2b8c8109c03e16b27a278ed4fd1723b1f6ea Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Sun, 23 Jul 2023 22:48:13 -0700 Subject: [PATCH 0677/1301] acpid: fix physmap size bug --- acpid/src/acpi.rs | 2 +- acpid/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index bce1f2f6e0..33811e50c4 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -191,7 +191,7 @@ impl Sdt { while left > 0 { let to_copy = std::cmp::min(left, length_per_iteration); - let additional_pages = PhysmapGuard::map(offset, length_per_iteration)?; + let additional_pages = PhysmapGuard::map(offset, length_per_iteration.div_ceil(PAGE_SIZE))?; loaded.extend(&additional_pages[..to_copy]); diff --git a/acpid/src/main.rs b/acpid/src/main.rs index d94f762938..47a4cd5cbd 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -1,4 +1,4 @@ -#![feature(if_let_guard)] +#![feature(if_let_guard, int_roundings)] use std::convert::TryFrom; use std::io::{self, prelude::*}; From 8c0d255ccdd6d4763e6db31b54de904ba2be8359 Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Mon, 24 Jul 2023 01:15:28 -0700 Subject: [PATCH 0678/1301] acpid: improved bug fix --- acpid/src/acpi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 33811e50c4..9bd620ef6d 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -191,7 +191,7 @@ impl Sdt { while left > 0 { let to_copy = std::cmp::min(left, length_per_iteration); - let additional_pages = PhysmapGuard::map(offset, length_per_iteration.div_ceil(PAGE_SIZE))?; + let additional_pages = PhysmapGuard::map(offset, to_copy.div_ceil(PAGE_SIZE))?; loaded.extend(&additional_pages[..to_copy]); From 2a09f9627707101e486fb69ecee10d0ee5b36373 Mon Sep 17 00:00:00 2001 From: Ribbon Date: Mon, 24 Jul 2023 19:13:42 +0000 Subject: [PATCH 0679/1301] Quote the "A Note about Drivers" section --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b8f433684a..ada869c542 100644 --- a/README.md +++ b/README.md @@ -79,3 +79,5 @@ If you don't have datasheets, we recommend you to do reverse-engineering of avai We recommend BSDs drivers because BSD license is compatible with MIT (permissive), that way we can reuse the code in other drivers. You can see this [example](https://gitlab.redox-os.org/redox-os/exampled) driver, read the code of the existent ones or the most close driver type for your device. + +Before testing your changes be aware of [this](https://doc.redox-os.org/book/ch09-02-coding-and-building.html#a-note-about-drivers). From 820b8370ae76d2f9e7987a3e7ad074d8435ca36b Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 25 Jul 2023 16:34:25 +1000 Subject: [PATCH 0680/1301] virtio-gpu: remove the `+1` workaround Signed-off-by: Anhad Singh --- inputd/src/lib.rs | 53 ++++++++++++++++--- inputd/src/main.rs | 103 ++++++++++++++++++++++++++++-------- vesad/src/main.rs | 2 +- vesad/src/scheme.rs | 28 +++++++--- vesad/src/screen/graphic.rs | 2 +- virtio-core/src/probe.rs | 4 +- virtio-gpud/src/main.rs | 2 +- virtio-gpud/src/scheme.rs | 86 +++++++++++++++--------------- 8 files changed, 197 insertions(+), 83 deletions(-) diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 0f71bdd213..c8f9e7e532 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -3,6 +3,25 @@ use std::fs::File; use std::io::{Error, Read, Write}; +unsafe fn any_as_u8_slice(p: &T) -> &[u8] { + ::core::slice::from_raw_parts((p as *const T) as *const u8, ::core::mem::size_of::()) +} + +#[derive(Debug, Copy, Clone, PartialEq)] +#[repr(usize)] +pub enum VtMode { + Text = 0, + Graphic = 1, + Default = 2, +} + +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct VtActivate { + pub vt: usize, + pub mode: VtMode, +} + pub struct Handle(File); impl Handle { @@ -14,11 +33,12 @@ impl Handle { // The return value is the display identifier. It will be used to uniquely // identify the display on activation events. pub fn register(&mut self) -> Result { - Ok(dbg!(self.0.read(&mut [])?)) + Ok(self.0.read(&mut [])?) } - pub fn activate(&mut self, vt: usize) -> Result { - Ok(dbg!(self.0.write(&vt.to_le_bytes())?)) + pub fn activate(&mut self, vt: usize, mode: VtMode) -> Result { + let cmd = VtActivate { vt, mode }; + Ok(self.0.write(unsafe { any_as_u8_slice(&cmd) })?) } } @@ -43,9 +63,14 @@ impl From for CmdTy { } } +#[derive(Debug)] pub enum Cmd { // TODO(andypython): #VT should really need to be a `u8`. - Activate(usize /* #VT */), + Activate { + vt: usize, + mode: VtMode, + }, + Deactivate(usize /* #VT */), Resize { // TODO(andypython): do we really need to pass the VT here? @@ -60,7 +85,7 @@ pub enum Cmd { impl Cmd { fn ty(&self) -> CmdTy { match self { - Cmd::Activate(_) => CmdTy::Activate, + Cmd::Activate { .. } => CmdTy::Activate, Cmd::Deactivate(_) => CmdTy::Deactivate, Cmd::Resize { .. } => CmdTy::Resize, } @@ -74,7 +99,14 @@ pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), syscall::Error> result.push(command.ty() as u8); match command { - Cmd::Activate(vt) | Cmd::Deactivate(vt) => result.extend_from_slice(&vt.to_le_bytes()), + Cmd::Activate { vt, mode } => { + let cmd = VtActivate { vt, mode }; + let bytes = unsafe { any_as_u8_slice(&cmd) }; + + result.extend_from_slice(bytes); + } + + Cmd::Deactivate(vt) => result.extend_from_slice(&vt.to_le_bytes()), Cmd::Resize { vt, width, @@ -105,7 +137,14 @@ pub fn parse_command(buffer: &[u8]) -> Option { let vt = usize::from_le_bytes(parser.next_chunk::().ok()?); match command { - CmdTy::Activate => Some(Cmd::Activate(vt)), + CmdTy::Activate => { + let cmd = unsafe { &*buffer.as_ptr().offset(1).cast::() }; + Some(Cmd::Activate { + vt: cmd.vt, + mode: VtMode::from(cmd.mode), + }) + } + CmdTy::Deactivate => Some(Cmd::Deactivate(vt)), CmdTy::Resize => { let width = parser.next_chunk::().ok()?; diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 91cd76c92a..f2d6f1fd0f 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -17,7 +17,7 @@ use std::io::{Read, Write}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -use inputd::Cmd; +use inputd::{Cmd, VtActivate, VtMode}; use spin::Mutex; @@ -49,6 +49,7 @@ impl Handle { /// requires the system call to return first. Otherwise, it will block indefinitely. struct VtInner { handle_file: File, + mode: VtMode, } struct Vt { @@ -72,8 +73,10 @@ impl Vt { pub fn inner(&self) -> &Mutex { self.inner.call_once(|| { let handle_file = File::open(format!("{}:handle", self.display)).unwrap(); - - Mutex::new(VtInner { handle_file }) + Mutex::new(VtInner { + handle_file, + mode: VtMode::Default, + }) }) } } @@ -88,7 +91,7 @@ struct InputScheme { super_key: bool, active_vt: Option>, - todo: Vec, + todo: Vec, } impl InputScheme { @@ -186,19 +189,19 @@ impl SchemeMut for InputScheme { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; match handle { - Handle::Device { .. } | Handle::Consumer { .. } => { - if buf.len() == core::mem::size_of::() { - // The device is requesting to activate a VT. - let vt = - usize::from_le_bytes(buf.try_into().map_err(|_| SysError::new(EINVAL))?); + Handle::Device { device } => { + assert!(buf.len() == core::mem::size_of::()); - self.todo.push(vt); - return Ok(buf.len()); - } else { - unreachable!() - } + // SAFETY: We have verified the size of the buffer above. + let cmd = unsafe { &*buf.as_ptr().cast::() }; + + self.vts.insert(cmd.vt, Vt::new(device.clone(), cmd.vt)); + self.todo.push(cmd.clone()); + + return Ok(buf.len()); } + Handle::Consumer { .. } => unreachable!(), _ => {} } @@ -276,7 +279,10 @@ impl SchemeMut for InputScheme { inputd::send_comand( &mut vt_inner.handle_file, - Cmd::Activate(new_active.index), + Cmd::Activate { + vt: new_active.index, + mode: VtMode::Default, + }, )?; self.active_vt = Some(new_active.clone()); } else { @@ -287,7 +293,7 @@ impl SchemeMut for InputScheme { assert!(handle.is_producer()); - let active_vt = self.active_vt.as_ref().unwrap(); + let active_vt = self.active_vt.as_ref().unwrap(); for handle in self.handles.values_mut() { match handle { Handle::Consumer { @@ -357,17 +363,22 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { scheme.handle(&mut packet); socket_file.write(&packet)?; - while let Some(vt) = scheme.todo.pop() { - let vt = scheme.vts.get_mut(&vt).unwrap(); + while let Some(cmd) = scheme.todo.pop() { + let vt = scheme.vts.get_mut(&cmd.vt).unwrap(); let mut vt_inner = vt.inner().lock(); // Failing to activate a VT is not a fatal error. - if let Err(err) = - inputd::send_comand(&mut vt_inner.handle_file, Cmd::Activate(vt.index)) - { + if let Err(err) = inputd::send_comand( + &mut vt_inner.handle_file, + Cmd::Activate { + vt: vt.index, + mode: VtMode::from(cmd.mode), + }, + ) { log::error!("inputd: failed to activate VT #{}: {err}", vt.index) } + vt_inner.mode = cmd.mode; scheme.active_vt = Some(vt.clone()); } @@ -454,5 +465,53 @@ pub fn setup_logging(level: log::LevelFilter, name: &str) { pub fn main() { #[cfg(target_os = "redox")] setup_logging(log::LevelFilter::Trace, "inputd"); - redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); + + let mut args = std::env::args().skip(1); + + if let Some(val) = args.next() { + if val != "-G" { + panic!("inputd: invalid argument: {}", val); + } + + let vt = args.next().unwrap().parse::().unwrap(); + + // On startup, the VESA display driver is started which basically makes use of the framebuffer + // provided by the firmware. The GPU device are latter started by `pcid` (such as `virtio-gpu`). + let mut devices = vec![]; + let schemes = std::fs::read_dir(":").unwrap(); + + for entry in schemes { + let path = entry.unwrap().path(); + let path_str = path + .into_os_string() + .into_string() + .expect("inputd: failed to convert path to string"); + + if path_str.contains("display") { + println!("inputd: found display scheme {}", path_str); + devices.push(path_str); + } + } + + let device = devices + .iter() + .filter(|d| !d.contains("vesa")) + .collect::>(); + let device = if device.is_empty() { + "vesa" + } else { + // TODO: What should we do when there are multiple display devices? + device[0].split("/").nth(2).unwrap() + }; + + dbg!(&device); + let mut handle = + inputd::Handle::new(device).expect("inputd: failed to open display handle"); + + handle + .activate(vt, VtMode::Graphic) + .expect("inputd: failed to activate VT in graphic mode"); + } else { + redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); + } } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 505eb0d95b..08046147ca 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -98,7 +98,7 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[b daemon.ready().expect("failed to notify parent"); - scheme.inputd_handle.activate(1).unwrap(); + scheme.inputd_handle.activate(1, inputd::VtMode::Default).unwrap(); let mut blocked = Vec::new(); loop { diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index ee781eb1e5..fe9db07eba 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -37,6 +37,7 @@ pub struct DisplayScheme { next_id: usize, pub handles: BTreeMap, pub inputd_handle: inputd::Handle, + } impl DisplayScheme { @@ -72,7 +73,7 @@ impl DisplayScheme { vts, next_id: 0, handles: BTreeMap::new(), - inputd_handle + inputd_handle, } } @@ -303,20 +304,33 @@ impl SchemeMut for DisplayScheme { match handle.kind { HandleKind::Input => { - use inputd::Cmd as DisplayCommand; + use inputd::{Cmd as DisplayCommand, VtMode}; let command = inputd::parse_command(buf).unwrap(); + dbg!(&command); match command { - DisplayCommand::Activate(vt) => { + DisplayCommand::Activate { vt, mode } => { let vt_i = VtIndex(vt); if let Some(screens) = self.vts.get_mut(&vt_i) { for (screen_i, screen) in screens.iter_mut() { - screen.redraw( - self.onscreens[screen_i.0], - self.framebuffers[screen_i.0].stride - ); + match mode { + VtMode::Graphic => { + dbg!("yes"); + *screen = Box::new(GraphicScreen::new(Display::new(screen.width(), screen.height()))); + } + + VtMode::Default => { + dbg!("x", &mode); + screen.redraw( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); + } + + VtMode::Text => todo!() + } } } diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index e0bf22ca35..ca96be28a8 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -27,7 +27,7 @@ pub struct GraphicScreen { impl GraphicScreen { pub fn new(display: Display) -> GraphicScreen { GraphicScreen { - display: display, + display, input: VecDeque::new(), sync_rects: Vec::new(), } diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index f97ae30f5a..3e4ca9e1e8 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -11,7 +11,7 @@ use pcid_interface::*; use syscall::Io; use crate::spec::*; -use crate::transport::{Error, Queue, StandardTransport}; +use crate::transport::{Error, StandardTransport}; use crate::utils::{align_down, VolatileCell}; pub struct Device<'a> { @@ -21,6 +21,8 @@ pub struct Device<'a> { pub isr: &'a VolatileCell, } +// FIXME(andypython): `device_space` should not be `Send` nor `Sync`. Take +// it out of `Device`. unsafe impl Send for Device<'_> {} unsafe impl Sync for Device<'_> {} diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index 73434398e3..4f1f08eb80 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -446,7 +446,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device.transport.clone(), ))?; - scheme.inputd_handle.activate(scheme.main_vt)?; + // scheme.inputd_handle.activate(scheme.main_vt)?; loop { let mut packet = Packet::default(); diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 5495218cbb..7fe379a24c 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -249,20 +249,16 @@ impl<'a> Display<'a> { } } -enum Handle { - Vt(usize /* VT index */), +enum Handle<'a> { + Vt { display: Arc>, vt: usize }, Input, } pub struct Scheme<'a> { - vts: BTreeMap>>, - handles: BTreeMap, + handles: BTreeMap>, /// Counter used for file descriptor allocation. next_id: AtomicUsize, displays: Vec>>, - - pub(crate) inputd_handle: inputd::Handle, - pub(crate) main_vt: usize, } impl<'a> Scheme<'a> { @@ -280,19 +276,10 @@ impl<'a> Scheme<'a> { ) .await?; - let mut inputd_handle = inputd::Handle::new("virtio-gpu").unwrap(); - - let mut vts = BTreeMap::new(); - let main_vt = inputd_handle.register().unwrap(); - vts.insert(main_vt, displays[0].clone()); - Ok(Self { - vts, handles: BTreeMap::new(), next_id: AtomicUsize::new(0), - inputd_handle, displays, - main_vt, }) } @@ -363,22 +350,17 @@ impl<'a> SchemeMut for Scheme<'a> { dbg!(vt, id); - if self.displays.get(id).is_none() { - return Err(SysError::new(EINVAL)); - } + let display = self.displays.get(id).ok_or(SysError::new(EINVAL))?; let fd = self.next_id.fetch_add(1, Ordering::SeqCst); - // FIXME: The +1 is a hack. vesad smh - self.handles.insert(fd, Handle::Vt(vt + 1)); + self.handles.insert(fd, Handle::Vt {display: display.clone(), vt }); Ok(fd) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { match self.handles.get(&id).unwrap() { - Handle::Vt(id) => { - let handle = self.vts.get_mut(&(id - 1)).ok_or(SysError::new(EINVAL))?; - let bytes_copied = futures::executor::block_on(handle.get_fpath(buf)).unwrap(); - + Handle::Vt { display, .. } => { + let bytes_copied = futures::executor::block_on(display.get_fpath(buf)).unwrap(); Ok(bytes_copied) } @@ -400,9 +382,8 @@ impl<'a> SchemeMut for Scheme<'a> { fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result { match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { - Handle::Vt(id) => { - let handle = self.vts.get_mut(&(id - 1)).ok_or(SysError::new(EINVAL))?; - Ok(futures::executor::block_on(handle.map_screen(map.offset)).unwrap()) + Handle::Vt { display, .. } => { + Ok(futures::executor::block_on(display.map_screen(map.offset)).unwrap()) } _ => unreachable!(), } @@ -410,9 +391,8 @@ impl<'a> SchemeMut for Scheme<'a> { fn fsync(&mut self, id: usize) -> syscall::Result { match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { - Handle::Vt(id) => { - let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?; - futures::executor::block_on(handle.flush(None)).unwrap(); + Handle::Vt { display, .. } => { + futures::executor::block_on(display.flush(None)).unwrap(); Ok(0) } @@ -428,12 +408,10 @@ impl<'a> SchemeMut for Scheme<'a> { fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { - Handle::Vt(id) => { - let handle = self.vts.get_mut(&(id - 1)).ok_or(SysError::new(EINVAL))?; - + Handle::Vt { display, .. } => { // The VT is not active and the device is reseted. Ask them to try // again later. - if handle.is_reseted.load(Ordering::SeqCst) { + if display.is_reseted.load(Ordering::SeqCst) { return Err(SysError::new(EAGAIN)); } @@ -445,26 +423,48 @@ impl<'a> SchemeMut for Scheme<'a> { }; for damage in damages { - futures::executor::block_on(handle.flush(Some(damage))).unwrap(); + futures::executor::block_on(display.flush(Some(damage))).unwrap(); } Ok(buf.len()) } Handle::Input => { - use inputd::Cmd as DisplayCommand; + use inputd::{Cmd as DisplayCommand, VtMode}; let command = inputd::parse_command(buf).unwrap(); match command { - DisplayCommand::Activate(vt) => { - let display = self.vts.get(&vt).unwrap(); - futures::executor::block_on(display.init()).unwrap(); + DisplayCommand::Activate { mode, vt } => { + assert!(mode == VtMode::Graphic || mode == VtMode::Default); + let target_vt = vt; + + for handle in self.handles.values() { + if let Handle::Vt { display , vt } = handle { + if *vt != target_vt { + continue; + } + + futures::executor::block_on(display.init()).unwrap(); + } + } } - DisplayCommand::Deactivate(vt) => { - let display = self.vts.get(&vt).ok_or(SysError::new(EINVAL))?; - futures::executor::block_on(display.detach()).unwrap(); + DisplayCommand::Deactivate(target_vt) => { + for handle in self.handles.values() { + if let Handle::Vt { display , vt } = handle { + if *vt != target_vt { + continue; + } + + futures::executor::block_on(display.detach()).unwrap(); + break; + } + } + + // for display in self.displays.iter() { + // futures::executor::block_on(display.detach()).unwrap(); + // } } DisplayCommand::Resize { .. } => { From ed995306bd051fc8a28331deff7dee18c7f31c42 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 25 Jul 2023 16:36:46 +1000 Subject: [PATCH 0681/1301] inputd: minor clippy fixes Signed-off-by: Anhad Singh --- inputd/src/lib.rs | 8 ++++---- inputd/src/main.rs | 10 +++++++--- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index c8f9e7e532..a3d1020678 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -15,7 +15,7 @@ pub enum VtMode { Default = 2, } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] #[repr(C)] pub struct VtActivate { pub vt: usize, @@ -33,12 +33,12 @@ impl Handle { // The return value is the display identifier. It will be used to uniquely // identify the display on activation events. pub fn register(&mut self) -> Result { - Ok(self.0.read(&mut [])?) + self.0.read(&mut []) } pub fn activate(&mut self, vt: usize, mode: VtMode) -> Result { let cmd = VtActivate { vt, mode }; - Ok(self.0.write(unsafe { any_as_u8_slice(&cmd) })?) + self.0.write(unsafe { any_as_u8_slice(&cmd) }) } } @@ -141,7 +141,7 @@ pub fn parse_command(buffer: &[u8]) -> Option { let cmd = unsafe { &*buffer.as_ptr().offset(1).cast::() }; Some(Cmd::Activate { vt: cmd.vt, - mode: VtMode::from(cmd.mode), + mode: cmd.mode, }) } diff --git a/inputd/src/main.rs b/inputd/src/main.rs index f2d6f1fd0f..2ca582eba6 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -216,7 +216,7 @@ impl SchemeMut for InputScheme { ) }; - for event in events.iter() { + 'out: for event in events.iter() { let mut new_active_opt = None; match event.to_option() { EventOption::Key(key_event) => match key_event.scancode { @@ -264,6 +264,10 @@ impl SchemeMut for InputScheme { } if let Some(new_active) = new_active_opt { + if new_active == self.active_vt.as_ref().unwrap().index { + continue 'out; + } + if let Some(new_active) = self.vts.get(&new_active).cloned() { { let active_vt = self.active_vt.as_ref().unwrap(); @@ -372,7 +376,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { &mut vt_inner.handle_file, Cmd::Activate { vt: vt.index, - mode: VtMode::from(cmd.mode), + mode: cmd.mode, }, ) { log::error!("inputd: failed to activate VT #{}: {err}", vt.index) @@ -501,7 +505,7 @@ pub fn main() { "vesa" } else { // TODO: What should we do when there are multiple display devices? - device[0].split("/").nth(2).unwrap() + device[0].split('/').nth(2).unwrap() }; dbg!(&device); From 71a6eb1bb284feb109b29b529b8e247c8fe07223 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Tue, 25 Jul 2023 19:20:04 +1000 Subject: [PATCH 0682/1301] inputd: add `-A` command to activate a VT Signed-off-by: Anhad Singh --- inputd/src/main.rs | 101 +++++++++++++++++++++++++++----------------- vesad/src/scheme.rs | 3 -- 2 files changed, 62 insertions(+), 42 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 2ca582eba6..fa37f58b2c 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -14,6 +14,7 @@ use std::collections::BTreeMap; use std::fs::File; use std::io::{Read, Write}; +use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; @@ -473,48 +474,70 @@ pub fn main() { let mut args = std::env::args().skip(1); if let Some(val) = args.next() { - if val != "-G" { - panic!("inputd: invalid argument: {}", val); - } + match val.as_ref() { + // Sets the VT mode of the specified VT to [`VtMode::Graphic`]. + "-G" => { + let vt = args.next().unwrap().parse::().unwrap(); - let vt = args.next().unwrap().parse::().unwrap(); - - // On startup, the VESA display driver is started which basically makes use of the framebuffer - // provided by the firmware. The GPU device are latter started by `pcid` (such as `virtio-gpu`). - let mut devices = vec![]; - let schemes = std::fs::read_dir(":").unwrap(); - - for entry in schemes { - let path = entry.unwrap().path(); - let path_str = path - .into_os_string() - .into_string() - .expect("inputd: failed to convert path to string"); - - if path_str.contains("display") { - println!("inputd: found display scheme {}", path_str); - devices.push(path_str); + // On startup, the VESA display driver is started which basically makes use of the framebuffer + // provided by the firmware. The GPU devices are latter started by `pcid` (such as `virtio-gpu`). + let mut devices = vec![]; + let schemes = std::fs::read_dir(":").unwrap(); + + for entry in schemes { + let path = entry.unwrap().path(); + let path_str = path + .into_os_string() + .into_string() + .expect("inputd: failed to convert path to string"); + + if path_str.contains("display") { + println!("inputd: found display scheme {}", path_str); + devices.push(path_str); + } + } + + let device = devices + .iter() + .filter(|d| !d.contains("vesa")) + .collect::>(); + let device = if device.is_empty() { + "vesa" + } else { + // TODO: What should we do when there are multiple display devices? + device[0].split('/').nth(2).unwrap() + }; + + let mut handle = + inputd::Handle::new(device).expect("inputd: failed to open display handle"); + + handle + .activate(vt, VtMode::Graphic) + .expect("inputd: failed to activate VT in graphic mode"); } + + // Activates a VT. + "-A" => { + let vt = args.next().unwrap().parse::().unwrap(); + + let handle = File::open(format!("input:consumer/{vt}")).expect("inputd: failed to open consumer handle"); + let mut display_path = [0; 4096]; + + let written = syscall::fpath(handle.as_raw_fd() as usize, &mut display_path).expect("inputd: fpath() failed"); + + assert!(written <= display_path.len()); + drop(handle); + + let display_path = std::str::from_utf8(&display_path[..written]).expect("inputd: display path UTF-8 validation failed"); + let display_name = display_path.split('/').skip(1).next().expect("inputd: invalid display path"); + let display_scheme = display_name.split(':').next().expect("inputd: invalid display path"); + + let mut handle = inputd::Handle::new(display_scheme).expect("inputd: failed to open display handle"); + handle.activate(vt, VtMode::Default).expect("inputd: failed to activate VT"); + } + + _ => panic!("inputd: invalid argument: {}", val), } - - let device = devices - .iter() - .filter(|d| !d.contains("vesa")) - .collect::>(); - let device = if device.is_empty() { - "vesa" - } else { - // TODO: What should we do when there are multiple display devices? - device[0].split('/').nth(2).unwrap() - }; - - dbg!(&device); - let mut handle = - inputd::Handle::new(device).expect("inputd: failed to open display handle"); - - handle - .activate(vt, VtMode::Graphic) - .expect("inputd: failed to activate VT in graphic mode"); } else { redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index fe9db07eba..20d1b45719 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -307,7 +307,6 @@ impl SchemeMut for DisplayScheme { use inputd::{Cmd as DisplayCommand, VtMode}; let command = inputd::parse_command(buf).unwrap(); - dbg!(&command); match command { DisplayCommand::Activate { vt, mode } => { @@ -317,12 +316,10 @@ impl SchemeMut for DisplayScheme { for (screen_i, screen) in screens.iter_mut() { match mode { VtMode::Graphic => { - dbg!("yes"); *screen = Box::new(GraphicScreen::new(Display::new(screen.width(), screen.height()))); } VtMode::Default => { - dbg!("x", &mode); screen.redraw( self.onscreens[screen_i.0], self.framebuffers[screen_i.0].stride From 156be64a9d82c656ef0a688b9fbfef1ea18c868a Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Thu, 27 Jul 2023 01:22:56 -0700 Subject: [PATCH 0683/1301] pcid: replace add that should allow wrapping with explicit wrapping_add --- pcid/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 04de72a085..bbc92db7b9 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -375,7 +375,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, new & 0xFFFFFFF0 }; - let size = !masked + 1; + let size = (!masked).wrapping_add(1); bar_sizes[i] = if size <= 1 { 0 } else { From d23b3046a47094a58225b79e69a816f07abc3ac1 Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Fri, 28 Jul 2023 00:57:36 -0700 Subject: [PATCH 0684/1301] block-io-wrapper: simplify block calculations --- block-io-wrapper/Cargo.toml | 2 +- block-io-wrapper/src/lib.rs | 76 +++++++++++++++++++------------------ virtio-blkd/src/scheme.rs | 2 +- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/block-io-wrapper/Cargo.toml b/block-io-wrapper/Cargo.toml index e40054ccf1..b5de7fa458 100644 --- a/block-io-wrapper/Cargo.toml +++ b/block-io-wrapper/Cargo.toml @@ -2,7 +2,7 @@ name = "block-io-wrapper" version = "0.1.0" authors = ["4lDO2 <4lDO2@protonmail.com>"] -edition = "2018" +edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/block-io-wrapper/src/lib.rs b/block-io-wrapper/src/lib.rs index 6556067d42..278c88cc54 100644 --- a/block-io-wrapper/src/lib.rs +++ b/block-io-wrapper/src/lib.rs @@ -1,47 +1,49 @@ -pub fn read(offset: u64, blksize: u32, mut buf: &mut [u8], block_bytes: &mut [u8], mut read: impl FnMut(u64, &mut [u8]) -> Result<(), E>) -> Result { +use std::cmp::min; +use std::io::{Error, ErrorKind}; + +/// Split the read operation into a series of block reads. +/// `read_fn` will be called with a block number to be read, and a buffer to be filled. +/// The buffer must be large enough to hold `blksize` of data. +/// `read_fn` must return a full block of data. +/// Result will be the number of bytes read. +pub fn read( + offset: u64, + blksize: u32, + mut buf: &mut [u8], + block_bytes: &mut [u8], + mut read_fn: impl FnMut(u64, &mut [u8]) -> Result<(), Error>, +) -> Result { // TODO: Yield sometimes, perhaps after a few blocks or something. - use std::ops::{Add, Div, Rem}; - fn div_round_up(a: T, b: T) -> T - where - T: Add + Div + Rem + PartialEq + From + Copy - { - if a % b != T::from(0u8) { - a / b + T::from(1u8) - } else { - a / b - } + if buf.len() == 0 { + return Ok(0); } + let _ = offset.checked_add(buf.len() as u64).ok_or(Error::new( + ErrorKind::InvalidInput, + "Offset + Length greater than 2^64", + ))?; + let mut curr_buf = buf; + let mut curr_offset = offset; + let blk_size = usize::try_from(blksize).expect("blksize larger than usize"); + let mut total_read = 0; - let orig_buf_len = buf.len(); - - let start_block = offset / u64::from(blksize); - let end_block = div_round_up(offset + buf.len() as u64, u64::from(blksize)); // The first block not in the range - - let offset_from_start_block: u64 = offset % u64::from(blksize); - let offset_to_end_block: u64 = u64::from(blksize) - (offset + buf.len() as u64) % u64::from(blksize); - - let first_whole_block = start_block + if offset_from_start_block > 0 { 1 } else { 0 }; - let last_whole_block = end_block - if offset_to_end_block > 0 { 1 } else { 0 } - 1; - - let whole_blocks_to_read = last_whole_block - first_whole_block + 1; - - for block in start_block..=end_block { + while curr_buf.len() > 0 { // TODO: Async/await? I mean, shouldn't AHCI be async? - read(block, block_bytes)?; + let blk_offset = + usize::try_from(curr_offset % u64::from(blksize)).expect("usize smaller than blksize"); + let to_copy = min(curr_buf.len(), blk_size - blk_offset); + assert!(blk_offset + to_copy <= blk_size); - let (bytes_to_read, src_buf): (u64, &[u8]) = if block == start_block { - (u64::from(blksize) - offset_from_start_block, &block_bytes[offset_from_start_block as usize..]) - } else if block == end_block { - (u64::from(blksize) - offset_to_end_block, &block_bytes[..offset_to_end_block as usize]) - } else { - (blksize.into(), &block_bytes[..]) - }; - let bytes_to_read = std::cmp::min(bytes_to_read as usize, buf.len()); - buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]); - buf = &mut buf[bytes_to_read..]; + read_fn(curr_offset / u64::from(blksize), block_bytes)?; + + let src_buf = &block_bytes[blk_offset..]; + + curr_buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); + curr_buf = &mut curr_buf[to_copy..]; + curr_offset += u64::try_from(to_copy).expect("bytes to copy larger than u64"); + total_read += to_copy; } - Ok(std::cmp::min(orig_buf_len, whole_blocks_to_read as usize * blksize as usize + offset_from_start_block as usize + offset_to_end_block as usize)) + Ok(total_read) } diff --git a/virtio-blkd/src/scheme.rs b/virtio-blkd/src/scheme.rs index d94f9a76b4..7116b1adf5 100644 --- a/virtio-blkd/src/scheme.rs +++ b/virtio-blkd/src/scheme.rs @@ -122,7 +122,7 @@ impl<'a> DiskScheme<'a> { impl<'a, 'b> Read for VirtioShim<'a, 'b> { fn read(&mut self, buf: &mut [u8]) -> IoResult { - let read_block = |block: u64, block_bytes: &mut [u8]| -> Result<(), ()> { + let read_block = |block: u64, block_bytes: &mut [u8]| -> Result<(), std::io::Error> { let req = Dma::new(BlockVirtRequest { ty: BlockRequestTy::In, reserved: 0, From 4846d21ff9d0a77190c4468413cace07f2b40714 Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Fri, 28 Jul 2023 01:50:39 -0700 Subject: [PATCH 0685/1301] block-io-wrapper: allow up to MAX offset + len --- block-io-wrapper/src/lib.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/block-io-wrapper/src/lib.rs b/block-io-wrapper/src/lib.rs index 278c88cc54..ced957f2a6 100644 --- a/block-io-wrapper/src/lib.rs +++ b/block-io-wrapper/src/lib.rs @@ -18,11 +18,13 @@ pub fn read( if buf.len() == 0 { return Ok(0); } - let _ = offset.checked_add(buf.len() as u64).ok_or(Error::new( - ErrorKind::InvalidInput, - "Offset + Length greater than 2^64", - ))?; - let mut curr_buf = buf; + let (_, would_overflow) = offset.overflowing_add(buf.len() as u64); + let to_copy = if would_overflow { + usize::try_from(u64::MAX - offset).map_err(|_| Error::new(ErrorKind::Unsupported, "offset + len exceeds usize::MAX"))? + } else { + buf.len() + }; + let mut curr_buf = &mut buf[..to_copy]; let mut curr_offset = offset; let blk_size = usize::try_from(blksize).expect("blksize larger than usize"); let mut total_read = 0; From d9b719904d7e36833ebf486c0214212f1cd5de11 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 2 Aug 2023 09:32:12 -0600 Subject: [PATCH 0686/1301] Update Cargo.lock --- Cargo.lock | 272 ++++++++++++++++++----------------------------------- 1 file changed, 92 insertions(+), 180 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67b819364a..bf4e2d7ec4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6,7 +6,7 @@ version = 3 name = "ac97d" version = "0.1.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "common", "log", "redox-daemon", @@ -40,7 +40,7 @@ dependencies = [ name = "ahcid" version = "0.1.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "block-io-wrapper", "byteorder 1.4.3", "common", @@ -55,7 +55,7 @@ dependencies = [ name = "alxd" version = "0.1.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "common", "netutils", "redox-daemon", @@ -146,15 +146,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "autocfg" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" -dependencies = [ - "autocfg 1.1.0", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -193,9 +184,9 @@ checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" @@ -219,12 +210,6 @@ dependencies = [ name = "block-io-wrapper" version = "0.1.0" -[[package]] -name = "build_const" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" - [[package]] name = "bumpalo" version = "3.13.0" @@ -245,9 +230,12 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.79" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0" +dependencies = [ + "libc", +] [[package]] name = "cfg-if" @@ -294,22 +282,13 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags 1.2.1", + "bitflags 1.3.2", "strsim", "textwrap", "unicode-width", "vec_map", ] -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -dependencies = [ - "bitflags 1.2.1", -] - [[package]] name = "common" version = "0.1.0" @@ -325,13 +304,19 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "crc" -version = "1.8.1" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" dependencies = [ - "build_const", + "crc-catalog", ] +[[package]] +name = "crc-catalog" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" + [[package]] name = "crossbeam-channel" version = "0.4.4" @@ -368,7 +353,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.1.0", + "autocfg", "cfg-if 0.1.10", "lazy_static", ] @@ -386,7 +371,7 @@ dependencies = [ name = "e1000d" version = "0.1.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "common", "netutils", "redox-daemon", @@ -417,7 +402,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "fuchsia-zircon-sys", ] @@ -489,7 +474,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -523,11 +508,23 @@ dependencies = [ ] [[package]] -name = "gpt" -version = "0.6.3" -source = "git+https://gitlab.redox-os.org/redox-os/gpt#4d800981c5dfae60ae183dbddaa3e026f80a5e5c" +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ - "bitflags 1.2.1", + "cfg-if 1.0.0", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "gpt" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8283e7331b8c93b9756e0cfdbcfb90312852f953c6faf9bf741e684cc3b6ad69" +dependencies = [ + "bitflags 2.3.3", "crc", "log", "uuid", @@ -609,7 +606,7 @@ dependencies = [ name = "ihdad" version = "0.1.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "common", "log", "pcid", @@ -671,7 +668,7 @@ checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" name = "ixgbed" version = "1.0.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "common", "netutils", "redox-daemon", @@ -728,7 +725,7 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ - "autocfg 1.1.0", + "autocfg", "scopeguard", ] @@ -844,11 +841,11 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" dependencies = [ - "autocfg 1.1.0", + "autocfg", ] [[package]] @@ -862,7 +859,7 @@ name = "nvmed" version = "0.1.0" dependencies = [ "arrayvec 0.5.2", - "bitflags 1.2.1", + "bitflags 1.3.2", "block-io-wrapper", "common", "crossbeam-channel 0.4.4", @@ -884,8 +881,8 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "orbclient" -version = "0.3.45" -source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#def603f25763db3b8222b9cc84983cef5966a561" +version = "0.3.46" +source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#b24be0556b79bf7c78e2fbd76d5d97c9b1262251" dependencies = [ "libc", "redox_syscall 0.3.5", @@ -930,7 +927,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" dependencies = [ "libc", - "rand 0.4.6", + "rand", "smallvec 0.6.14", "winapi 0.3.9", ] @@ -952,7 +949,7 @@ dependencies = [ [[package]] name = "partitionlib" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/partitionlib.git#1c12e0d93f7a16f7a209abdcf318388e850a73c7" +source = "git+https://gitlab.redox-os.org/redox-os/partitionlib.git#9e48718a0553a4d0d4070994053e1c402bb33b91" dependencies = [ "gpt", "scroll", @@ -1008,7 +1005,7 @@ name = "pcid" version = "0.1.0" dependencies = [ "bincode", - "bitflags 1.2.1", + "bitflags 1.3.2", "byteorder 1.4.3", "common", "libc", @@ -1094,7 +1091,7 @@ dependencies = [ name = "ps2d" version = "0.1.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "orbclient", "redox-daemon", "redox_syscall 0.3.5", @@ -1102,9 +1099,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.31" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fe8a65d69dd0808184ebb5f836ab526bb259db23c657efa38711b1072ee47f0" +checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" dependencies = [ "proc-macro2", ] @@ -1128,35 +1125,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.8", - "libc", - "rand_chacha", - "rand_core 0.4.2", - "rand_hc", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift", - "winapi 0.3.9", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.3.1", -] - [[package]] name = "rand_core" version = "0.3.1" @@ -1172,68 +1140,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi 0.3.9", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi 0.3.9", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.8", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "ransid" version = "0.4.9" @@ -1289,7 +1195,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", ] [[package]] @@ -1298,7 +1204,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", ] [[package]] @@ -1314,7 +1220,7 @@ dependencies = [ name = "rtl8139d" version = "0.1.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "common", "log", "netutils", @@ -1329,7 +1235,7 @@ dependencies = [ name = "rtl8168d" version = "0.1.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "common", "log", "netutils", @@ -1367,7 +1273,7 @@ checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" name = "sb16d" version = "0.1.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "common", "log", "redox-daemon", @@ -1409,7 +1315,7 @@ version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7959277b623f1fb9e04aea73686c3ca52f01b2145f8ea16f4ff30d8b7623b1a" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "lazy_static", "libc", "sdl2-sys", @@ -1428,29 +1334,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.171" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" +checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.171" +version = "1.0.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" +checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] name = "serde_json" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d03b412469450d4404fe8499a268edd7f8b79fecb074b0d812ad64ca21f4031b" +checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" dependencies = [ "itoa", "ryu", @@ -1472,7 +1378,7 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ - "autocfg 1.1.0", + "autocfg", ] [[package]] @@ -1585,9 +1491,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.26" +version = "2.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c3457aacde3c65315de5031ec191ce46604304d2446e803d71ade03308d970" +checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" dependencies = [ "proc-macro2", "quote", @@ -1623,22 +1529,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a35fc5b8971143ca348fa6df4f024d4d55264f3468c71ad1c2f365b0a4d58c42" +checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.43" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "463fe12d7993d3b327787537ce8dd4dfa058de32fc2b195ef3cde03dc4771e8f" +checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", ] [[package]] @@ -1648,7 +1554,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", - "wasi", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi 0.3.9", ] @@ -1766,7 +1672,7 @@ dependencies = [ name = "usbhidd" version = "0.1.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "log", "orbclient", "redox-log", @@ -1795,11 +1701,11 @@ checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" [[package]] name = "uuid" -version = "0.7.4" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90dbc611eb48397705a6b0f6e917da23ae517e4d127123d2cf7674206627d32a" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" dependencies = [ - "rand 0.6.5", + "getrandom", ] [[package]] @@ -1935,6 +1841,12 @@ version = "0.10.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + [[package]] name = "wasm-bindgen" version = "0.2.87" @@ -1956,7 +1868,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", "wasm-bindgen-shared", ] @@ -1978,7 +1890,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.26", + "syn 2.0.28", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2091,9 +2003,9 @@ checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" [[package]] name = "winnow" -version = "0.5.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fac9742fd1ad1bd9643b991319f72dd031016d44b77039a26977eb667141e7" +checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807" dependencies = [ "memchr", ] @@ -2121,7 +2033,7 @@ dependencies = [ name = "xhcid" version = "0.1.0" dependencies = [ - "bitflags 1.2.1", + "bitflags 1.3.2", "chashmap", "common", "crossbeam-channel 0.4.4", From 8db2c6372e751bd4d3ba355a5be9172ec12336f6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 2 Aug 2023 09:32:25 -0600 Subject: [PATCH 0687/1301] Fix duplicate import --- virtio-netd/src/scheme.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/virtio-netd/src/scheme.rs b/virtio-netd/src/scheme.rs index deff07a923..829a3002e6 100644 --- a/virtio-netd/src/scheme.rs +++ b/virtio-netd/src/scheme.rs @@ -10,8 +10,6 @@ use common::dma::Dma; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::Queue; -use common::dma::Dma; - use crate::{VirtHeader, MAX_BUFFER_LEN}; pub struct NetworkScheme<'a> { From bd2a66d817e083ab25eeae88aad42c39f1cb74ca Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Wed, 2 Aug 2023 18:41:26 -0700 Subject: [PATCH 0688/1301] Use default branch of `netutils` instead of removed branch --- Cargo.lock | 125 +++++------------------------------------ alxd/Cargo.toml | 2 +- e1000d/Cargo.toml | 2 +- ixgbed/Cargo.toml | 2 +- rtl8139d/Cargo.toml | 2 +- rtl8168d/Cargo.toml | 2 +- virtio-netd/Cargo.toml | 2 +- 7 files changed, 21 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bf4e2d7ec4..570a1ff16a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,7 +106,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -143,7 +143,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -271,7 +271,7 @@ dependencies = [ "num-traits", "time", "wasm-bindgen", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -385,33 +385,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "extra" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/libextra.git#cf213969493db8667052a591e32a1e26d43c4234" - [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags 1.3.2", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "funty" version = "2.0.0" @@ -649,15 +628,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "iovec" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] - [[package]] name = "itoa" version = "1.0.9" @@ -685,28 +655,12 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" - [[package]] name = "libc" version = "0.2.147" @@ -753,36 +707,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" -[[package]] -name = "mio" -version = "0.6.14" -source = "git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix#c9a70849ced97387e2607c9c466d23b130ec8901" -dependencies = [ - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", - "lazycell", - "libc", - "log", - "miow", - "net2", - "slab", - "winapi 0.2.8", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - [[package]] name = "net2" version = "0.2.37" @@ -790,18 +714,16 @@ source = "git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=master#db0 dependencies = [ "cfg-if 0.1.10", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git?branch=redox-unix#105ed1ea43413a91152b289fbe76e7efc996e933" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#9bcbf8c4a881e743169fecb6d520d27fb0977f66" dependencies = [ "arg_parser", - "extra", "libc", - "mio", "net2", "ntpclient", "pbr", @@ -929,7 +851,7 @@ dependencies = [ "libc", "rand", "smallvec 0.6.14", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -943,7 +865,7 @@ dependencies = [ "libc", "redox_syscall 0.2.16", "smallvec 1.11.0", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -997,7 +919,7 @@ checksum = "ed5827dfa0d69b6c92493d6c38e633bbaa5937c153d0d7c28bf12313f8c6d514" dependencies = [ "crossbeam-channel 0.5.8", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1122,7 +1044,7 @@ dependencies = [ "libc", "rand_core 0.3.1", "rdrand", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1555,7 +1477,7 @@ checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" dependencies = [ "libc", "wasi 0.10.0+wasi-snapshot-preview1", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1901,12 +1823,6 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - [[package]] name = "winapi" version = "0.3.9" @@ -1917,12 +1833,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -2010,16 +1920,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ws2_32-sys" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - [[package]] name = "wyz" version = "0.5.1" @@ -2052,3 +1952,8 @@ dependencies = [ "thiserror", "toml 0.5.11", ] + +[[patch.unused]] +name = "mio" +version = "0.6.14" +source = "git+https://gitlab.redox-os.org/redox-os/mio.git?branch=redox-unix#c9a70849ced97387e2607c9c466d23b130ec8901" diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml index a9865f295a..18ff6d994a 100644 --- a/alxd/Cargo.toml +++ b/alxd/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" [dependencies] bitflags = "1" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" redox-daemon = "0.1" diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 2f2470cfbd..d88390e33f 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" [dependencies] bitflags = "1" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml index 2df2b871b2..e2730ccd04 100644 --- a/ixgbed/Cargo.toml +++ b/ixgbed/Cargo.toml @@ -4,7 +4,7 @@ version = "1.0.0" [dependencies] bitflags = "1.0" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" redox-daemon = "0.1" diff --git a/rtl8139d/Cargo.toml b/rtl8139d/Cargo.toml index 9dc4b9d24d..251cde405b 100644 --- a/rtl8139d/Cargo.toml +++ b/rtl8139d/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] bitflags = "1" log = "0.4" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" redox-daemon = "0.1" diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index 9cd8099fe2..e3f25601c4 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] bitflags = "1" log = "0.4" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.3" redox-daemon = "0.1" diff --git a/virtio-netd/Cargo.toml b/virtio-netd/Cargo.toml index 3458d7b046..bb54b293fd 100644 --- a/virtio-netd/Cargo.toml +++ b/virtio-netd/Cargo.toml @@ -14,4 +14,4 @@ common = { path = "../common" } redox-daemon = "0.1" redox_syscall = "0.3" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git", branch = "redox-unix" } +netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } From d90edb0808094ec1357d04bf517b903882fde597 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 1 Jul 2023 15:43:34 +0200 Subject: [PATCH 0689/1301] Implement improved mmap in vesad. --- Cargo.lock | 2 -- Cargo.toml | 1 + vesad/src/main.rs | 4 +-- vesad/src/scheme.rs | 61 ++++++++++++++++++++++++++++++++++++++------- 4 files changed, 55 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 570a1ff16a..6fbac8b5ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1123,8 +1123,6 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ "bitflags 1.3.2", ] diff --git a/Cargo.toml b/Cargo.toml index 2c9b8d6e06..363159b803 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,3 +39,4 @@ lto = "fat" mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } +redox_syscall = { path = "../../kernel/source/syscall" } diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 08046147ca..1b75efc0f4 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -112,7 +112,7 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[b if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.can_read(packet.b).is_none() { blocked.push(packet); } else { - scheme.handle(&mut packet); + scheme.do_handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); } @@ -122,7 +122,7 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[b while i < blocked.len() { if scheme.can_read(blocked[i].b).is_some() { let mut packet = blocked.remove(i); - scheme.handle(&mut packet); + scheme.do_handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); } else { i += 1; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 20d1b45719..e63eea8852 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,7 +1,8 @@ use std::collections::BTreeMap; use std::{mem, ptr, slice, str}; -use syscall::{Error, EventFlags, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE}; +use orbclient::{Event, EventOption}; +use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE, Packet, KSMSG_MMAP_PREP, KSMSG_MMAP, MapFlags, ESKMSG, SKMSG_PROVIDE_MMAP}; use crate::{ display::Display, @@ -213,6 +214,7 @@ impl SchemeMut for DisplayScheme { } } + /* fn fmap(&mut self, id: usize, map: &Map) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; @@ -226,14 +228,7 @@ impl SchemeMut for DisplayScheme { Err(Error::new(EBADF)) } - fn fmap_old(&mut self, id: usize, map: &syscall::OldMap) -> syscall::Result { - self.fmap(id, &Map { - offset: map.offset, - size: map.size, - flags: map.flags, - address: 0, - }) - } + */ fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; @@ -383,3 +378,51 @@ impl SchemeMut for DisplayScheme { Ok(0) } } +impl DisplayScheme { + pub fn do_handle(&mut self, packet: &mut Packet) { + match packet.a { + KSMSG_MMAP | KSMSG_MMAP_PREP => { + let off_lo = packet.uid; + let off_hi = packet.gid; + let req_off = u64::from(off_lo) | (u64::from(off_hi) << 32); + let req_flags = MapFlags::from_bits_truncate(packet.c); + let req_file_id = packet.b; + let req_page_count = packet.d; + + let is_lazy_mmap = packet.a == KSMSG_MMAP || req_flags.contains(MapFlags::MAP_LAZY); + + match self.mmap(req_file_id, req_flags, req_page_count * PAGE_SIZE, req_off) { + Ok(res) => if is_lazy_mmap { + packet.a = Error::mux(Err(Error::new(ESKMSG))); + packet.b = SKMSG_PROVIDE_MMAP; + packet.c = res; + packet.d = req_page_count; + + packet.uid = off_lo; + packet.gid = off_hi; + } else { + packet.a = Error::mux(Ok(res)); + }, + Err(err) => { + packet.a = Error::mux(Err(err)); + } + }; + + } + _ => self.handle(packet), + } + } + pub fn mmap(&mut self, id: usize, _flags: MapFlags, size: usize, off: u64) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + if let Some(screens) = self.vts.get(&vt_i) { + if let Some(screen) = screens.get(&screen_i) { + return screen.map(off as usize, size); + } + } + } + + Err(Error::new(EBADF)) + } +} From ca6ea9b81a5dc599618983ec7cd3a61c6425a78e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 13 Jul 2023 18:46:18 +0200 Subject: [PATCH 0690/1301] Use scheme trait for mmap_prep. --- vesad/src/main.rs | 4 ++-- vesad/src/scheme.rs | 37 +------------------------------------ virtio-gpud/src/main.rs | 2 +- virtio-gpud/src/scheme.rs | 34 +++++++++++----------------------- 4 files changed, 15 insertions(+), 62 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 1b75efc0f4..08046147ca 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -112,7 +112,7 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[b if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.can_read(packet.b).is_none() { blocked.push(packet); } else { - scheme.do_handle(&mut packet); + scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); } @@ -122,7 +122,7 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[b while i < blocked.len() { if scheme.can_read(blocked[i].b).is_some() { let mut packet = blocked.remove(i); - scheme.do_handle(&mut packet); + scheme.handle(&mut packet); socket.write(&packet).expect("vesad: failed to write display scheme"); } else { i += 1; diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index e63eea8852..ddd3f22607 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -377,42 +377,7 @@ impl SchemeMut for DisplayScheme { self.handles.remove(&id).ok_or(Error::new(EBADF))?; Ok(0) } -} -impl DisplayScheme { - pub fn do_handle(&mut self, packet: &mut Packet) { - match packet.a { - KSMSG_MMAP | KSMSG_MMAP_PREP => { - let off_lo = packet.uid; - let off_hi = packet.gid; - let req_off = u64::from(off_lo) | (u64::from(off_hi) << 32); - let req_flags = MapFlags::from_bits_truncate(packet.c); - let req_file_id = packet.b; - let req_page_count = packet.d; - - let is_lazy_mmap = packet.a == KSMSG_MMAP || req_flags.contains(MapFlags::MAP_LAZY); - - match self.mmap(req_file_id, req_flags, req_page_count * PAGE_SIZE, req_off) { - Ok(res) => if is_lazy_mmap { - packet.a = Error::mux(Err(Error::new(ESKMSG))); - packet.b = SKMSG_PROVIDE_MMAP; - packet.c = res; - packet.d = req_page_count; - - packet.uid = off_lo; - packet.gid = off_hi; - } else { - packet.a = Error::mux(Ok(res)); - }, - Err(err) => { - packet.a = Error::mux(Err(err)); - } - }; - - } - _ => self.handle(packet), - } - } - pub fn mmap(&mut self, id: usize, _flags: MapFlags, size: usize, off: u64) -> Result { + fn mmap_prep(&mut self, id: usize, _flags: MapFlags, size: usize, off: u64) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(vt_i, screen_i) = handle.kind { diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index 4f1f08eb80..f181b38ff2 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -453,7 +453,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { socket_file .read(&mut packet) .expect("virtio-gpud: failed to read disk scheme"); - scheme.handle(&mut packet); + unsafe { scheme.handle(&mut packet); } socket_file .write(&packet) .expect("virtio-gpud: failed to read disk scheme"); diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 7fe379a24c..4669ae2e3f 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -4,9 +4,9 @@ use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; use std::sync::Arc; use inputd::Damage; - use common::dma::Dma; -use syscall::{Error as SysError, SchemeMut, EAGAIN, EINVAL}; + +use syscall::{Error as SysError, SchemeMut, EAGAIN, EINVAL, MapFlags, PAGE_SIZE, KSMSG_MMAP, KSMSG_MMAP_PREP, KSMSG_MSYNC, KSMSG_MUNMAP}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::{Error, Queue, StandardTransport}; @@ -368,27 +368,6 @@ impl<'a> SchemeMut for Scheme<'a> { } } - fn fmap_old(&mut self, id: usize, map: &syscall::OldMap) -> syscall::Result { - self.fmap( - id, - &syscall::Map { - offset: map.offset, - size: map.size, - flags: map.flags, - address: 0, - }, - ) - } - - fn fmap(&mut self, id: usize, map: &syscall::Map) -> syscall::Result { - match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { - Handle::Vt { display, .. } => { - Ok(futures::executor::block_on(display.map_screen(map.offset)).unwrap()) - } - _ => unreachable!(), - } - } - fn fsync(&mut self, id: usize) -> syscall::Result { match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { Handle::Vt { display, .. } => { @@ -484,4 +463,13 @@ impl<'a> SchemeMut for Scheme<'a> { fn close(&mut self, _id: usize) -> syscall::Result { Ok(0) } + fn mmap_prep(&mut self, id: usize, flags: MapFlags, size: usize, offset: u64) -> syscall::Result { + log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); + match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { + Handle::Vt { display, .. } => { + Ok(futures::executor::block_on(display.map_screen(offset as usize)).unwrap()) + } + _ => unreachable!(), + } + } } From fc1dc21b1395f16a8ab33f47ff33c3cbf4b85669 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 22 Jul 2023 10:36:38 +0200 Subject: [PATCH 0691/1301] Use updated mmap_prep decl. --- vesad/src/scheme.rs | 2 +- virtio-gpud/src/scheme.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index ddd3f22607..cc5a70fcd1 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -377,7 +377,7 @@ impl SchemeMut for DisplayScheme { self.handles.remove(&id).ok_or(Error::new(EBADF))?; Ok(0) } - fn mmap_prep(&mut self, id: usize, _flags: MapFlags, size: usize, off: u64) -> Result { + fn mmap_prep(&mut self, id: usize, off: u64, size: usize, _flags: MapFlags) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(vt_i, screen_i) = handle.kind { diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 4669ae2e3f..6a75c72749 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -463,7 +463,7 @@ impl<'a> SchemeMut for Scheme<'a> { fn close(&mut self, _id: usize) -> syscall::Result { Ok(0) } - fn mmap_prep(&mut self, id: usize, flags: MapFlags, size: usize, offset: u64) -> syscall::Result { + fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, flags: MapFlags) -> syscall::Result { log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { Handle::Vt { display, .. } => { From 625ae7f9e4361b6b55e6938e14dded890062a616 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 3 Aug 2023 12:46:14 +0200 Subject: [PATCH 0692/1301] Use syscall git dependency. --- Cargo.lock | 1 + Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 6fbac8b5ce..8102337996 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1123,6 +1123,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.3.5" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#a525620c818a801bb7038e111b71033eff56a3ee" dependencies = [ "bitflags 1.3.2", ] diff --git a/Cargo.toml b/Cargo.toml index 363159b803..b68ec3665c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,4 +39,4 @@ lto = "fat" mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } -redox_syscall = { path = "../../kernel/source/syscall" } +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } From d56767216f5924e8b38aa5283b8f32b223b5905a Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Thu, 3 Aug 2023 19:05:33 -0700 Subject: [PATCH 0693/1301] inputd: Don't panic on open with invalid path --- inputd/src/main.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index fa37f58b2c..684368440e 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -121,7 +121,10 @@ impl SchemeMut for InputScheme { let handle_ty = match command { "producer" => Handle::Producer, "consumer" => { - let target = path_parts.next().unwrap().parse::().unwrap(); + let target = path_parts + .next() + .and_then(|x| x.parse::().ok()) + .ok_or(SysError::new(EINVAL))?; Handle::Consumer { events: EventFlags::empty(), @@ -135,7 +138,10 @@ impl SchemeMut for InputScheme { Handle::Device { device: display } } - _ => unreachable!("inputd: invalid path {path}"), + _ => { + log::error!("inputd: invalid path {path}"); + return Err(SysError::new(EINVAL)); + } }; log::info!("inputd: {path} channel has been opened"); From 901c238e0dacf460fc3b2205b762802e23337d05 Mon Sep 17 00:00:00 2001 From: Ron Williams Date: Fri, 4 Aug 2023 03:50:45 -0700 Subject: [PATCH 0694/1301] block-io-wrapper: simplify by using saturating_add --- block-io-wrapper/src/lib.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/block-io-wrapper/src/lib.rs b/block-io-wrapper/src/lib.rs index ced957f2a6..bf56b788a0 100644 --- a/block-io-wrapper/src/lib.rs +++ b/block-io-wrapper/src/lib.rs @@ -1,5 +1,5 @@ use std::cmp::min; -use std::io::{Error, ErrorKind}; +use std::io::Error; /// Split the read operation into a series of block reads. /// `read_fn` will be called with a block number to be read, and a buffer to be filled. @@ -9,7 +9,7 @@ use std::io::{Error, ErrorKind}; pub fn read( offset: u64, blksize: u32, - mut buf: &mut [u8], + buf: &mut [u8], block_bytes: &mut [u8], mut read_fn: impl FnMut(u64, &mut [u8]) -> Result<(), Error>, ) -> Result { @@ -18,12 +18,11 @@ pub fn read( if buf.len() == 0 { return Ok(0); } - let (_, would_overflow) = offset.overflowing_add(buf.len() as u64); - let to_copy = if would_overflow { - usize::try_from(u64::MAX - offset).map_err(|_| Error::new(ErrorKind::Unsupported, "offset + len exceeds usize::MAX"))? - } else { - buf.len() - }; + let to_copy = usize::try_from( + offset.saturating_add(u64::try_from(buf.len()).expect("buf.len() larger than u64")) + - offset, + ) + .expect("bytes to copy larger than usize"); let mut curr_buf = &mut buf[..to_copy]; let mut curr_offset = offset; let blk_size = usize::try_from(blksize).expect("blksize larger than usize"); @@ -46,6 +45,5 @@ pub fn read( curr_offset += u64::try_from(to_copy).expect("bytes to copy larger than u64"); total_read += to_copy; } - Ok(total_read) } From 2ba83c040176c483c5aabe53b0d0235d2cb9d657 Mon Sep 17 00:00:00 2001 From: Ribbon Date: Sat, 12 Aug 2023 09:10:23 +0000 Subject: [PATCH 0695/1301] Add code blocks on the TODOs of the README --- README.md | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index ada869c542..73548f6e20 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,19 @@ These are the currently implemented devices/hardware interfaces. - ac97d - Realtek audio chipsets. - acpid - ACPI (incomplete). -Lack of drivers for devices controlled using AML. - -The AML parser does not work on real hardware. - -It doesn't use any ACPI functionality other than S5 shutdown. - -Needs to implement something like "determine the battery status" on real hardware (hard). +``` +- Lack of drivers for devices controlled using AML +- The AML parser does not work on real hardware +- It doesn't use any ACPI functionality other than S5 shutdown +- Needs to implement something like "determine the battery status" on real hardware (hard) +``` - ahcid - SATA. - alxd - Atheros ethernet (incomplete). -Lack of datasheet to finish. +``` +- Lack of datasheet to finish +``` - amlserde - a library to provide serialization/deserialization of the AML symbol table from ACPI (incomplete). - bgad - Bochs emulator/debugger. @@ -34,19 +35,27 @@ Lack of datasheet to finish. - rtl8168d - Realtek ethernet. - sb16d - Sound Blaster audio (incomplete). -Still need to determine a way to allocate memory under 16MiB for use in ISA DMA. +``` +- Need to determine a way to allocate memory under 16MiB for use in ISA DMA +``` - usbctl - USB control (incomplete). -Missing class drivers for various classes. +``` +- Missing class drivers for various classes +``` - usbhidd - USB HID (incomplete). -Has tons of descriptors that are possible, not all are supported. +``` +- Has tons of descriptors that are possible, not all are supported +``` - usbscsid - USB SCSI (incomplete). -Missing class drivers for various classes. +``` +- Missing class drivers for various classes +``` - vboxd - VirtualBox guest. - vesad - VESA. From ac9e4abcd0badb410f733c2f1e6c3d3f645a5c45 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 21 Aug 2023 09:21:35 -0600 Subject: [PATCH 0696/1301] virtio-core: Fix compilation on non-x86_64 --- virtio-core/src/probe.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 3e4ca9e1e8..a9cf7f6362 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -3,9 +3,7 @@ use std::ptr::NonNull; use std::sync::Arc; use pcid_interface::irq_helpers::{allocate_single_interrupt_vector, read_bsp_apic_id}; -use pcid_interface::msi::x86_64 as x86_64_msix; -use pcid_interface::msi::x86_64::DeliveryMode; -use pcid_interface::msi::{MsixCapability, MsixTableEntry}; +use pcid_interface::msi::{self, MsixCapability, MsixTableEntry}; use pcid_interface::*; use syscall::Io; @@ -46,6 +44,7 @@ static_assertions::const_assert_eq!(std::mem::size_of::(), 16); pub const MSIX_PRIMARY_VECTOR: u16 = 0; +#[cfg(target_arch = "x86_64")] fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { let pci_config = pcid_handle.fetch_config()?; @@ -104,13 +103,13 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { let rh = false; let dm = false; - let addr = x86_64_msix::message_address(lapic_id, rh, dm); + let addr = msi::x86_64::message_address(lapic_id, rh, dm); let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id) .unwrap() .expect("virtio_core: interrupt vector exhaustion"); - let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + let msg_data = msi::x86_64::message_data_edge_triggered(msi::x86_64::DeliveryMode::Fixed, vector); table_entry_pointer.addr_lo.write(addr); table_entry_pointer.addr_hi.write(0); @@ -128,6 +127,11 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { Ok(interrupt_handle) } +#[cfg(not(target_arch = "x86_64"))] +fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { + panic!("Msi-X only supported on x86_64"); +} + /// VirtIO Device Probe /// /// ## Device State From 6a5e9d2613fbb92abaafa1969ae58a2039cd1358 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Thu, 10 Aug 2023 17:22:38 +1000 Subject: [PATCH 0697/1301] virtio-core: add support for legacy transport Signed-off-by: Anhad Singh --- Cargo.lock | 1 + inputd/src/main.rs | 37 ++- virtio-blkd/Cargo.toml | 1 + virtio-blkd/src/main.rs | 57 +++-- virtio-blkd/src/scheme.rs | 6 +- virtio-core/src/probe.rs | 118 +++++---- virtio-core/src/transport.rs | 449 +++++++++++++++++++++++++++++------ virtio-core/src/utils.rs | 2 +- virtio-gpud/src/scheme.rs | 35 ++- virtio-netd/src/main.rs | 2 +- 10 files changed, 544 insertions(+), 164 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 67b819364a..82abf7976e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1864,6 +1864,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_syscall 0.3.5", + "spin", "static_assertions", "thiserror", "virtio-core", diff --git a/inputd/src/main.rs b/inputd/src/main.rs index fa37f58b2c..f1d06198fb 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -483,20 +483,20 @@ pub fn main() { // provided by the firmware. The GPU devices are latter started by `pcid` (such as `virtio-gpu`). let mut devices = vec![]; let schemes = std::fs::read_dir(":").unwrap(); - + for entry in schemes { let path = entry.unwrap().path(); let path_str = path .into_os_string() .into_string() .expect("inputd: failed to convert path to string"); - + if path_str.contains("display") { println!("inputd: found display scheme {}", path_str); devices.push(path_str); } } - + let device = devices .iter() .filter(|d| !d.contains("vesa")) @@ -507,10 +507,10 @@ pub fn main() { // TODO: What should we do when there are multiple display devices? device[0].split('/').nth(2).unwrap() }; - + let mut handle = inputd::Handle::new(device).expect("inputd: failed to open display handle"); - + handle .activate(vt, VtMode::Graphic) .expect("inputd: failed to activate VT in graphic mode"); @@ -520,20 +520,33 @@ pub fn main() { "-A" => { let vt = args.next().unwrap().parse::().unwrap(); - let handle = File::open(format!("input:consumer/{vt}")).expect("inputd: failed to open consumer handle"); + let handle = File::open(format!("input:consumer/{vt}")) + .expect("inputd: failed to open consumer handle"); let mut display_path = [0; 4096]; - let written = syscall::fpath(handle.as_raw_fd() as usize, &mut display_path).expect("inputd: fpath() failed"); + let written = syscall::fpath(handle.as_raw_fd() as usize, &mut display_path) + .expect("inputd: fpath() failed"); assert!(written <= display_path.len()); drop(handle); - let display_path = std::str::from_utf8(&display_path[..written]).expect("inputd: display path UTF-8 validation failed"); - let display_name = display_path.split('/').skip(1).next().expect("inputd: invalid display path"); - let display_scheme = display_name.split(':').next().expect("inputd: invalid display path"); + let display_path = std::str::from_utf8(&display_path[..written]) + .expect("inputd: display path UTF-8 validation failed"); + let display_name = display_path + .split('/') + .skip(1) + .next() + .expect("inputd: invalid display path"); + let display_scheme = display_name + .split(':') + .next() + .expect("inputd: invalid display path"); - let mut handle = inputd::Handle::new(display_scheme).expect("inputd: failed to open display handle"); - handle.activate(vt, VtMode::Default).expect("inputd: failed to activate VT"); + let mut handle = inputd::Handle::new(display_scheme) + .expect("inputd: failed to open display handle"); + handle + .activate(vt, VtMode::Default) + .expect("inputd: failed to activate VT"); } _ => panic!("inputd: invalid argument: {}", val), diff --git a/virtio-blkd/Cargo.toml b/virtio-blkd/Cargo.toml index 2068f8923a..3f0f969ea6 100644 --- a/virtio-blkd/Cargo.toml +++ b/virtio-blkd/Cargo.toml @@ -10,6 +10,7 @@ log = "0.4" thiserror = "1.0.40" static_assertions = "1.1.0" futures = { version = "0.3.28", features = ["executor"] } +spin = "*" redox-daemon = "0.1" redox-log = "0.1" diff --git a/virtio-blkd/src/main.rs b/virtio-blkd/src/main.rs index 963156a37b..959361406e 100644 --- a/virtio-blkd/src/main.rs +++ b/virtio-blkd/src/main.rs @@ -1,9 +1,12 @@ #![deny(trivial_numeric_casts, unused_allocation)] #![feature(int_roundings, async_fn_in_trait)] +// TODO(andypython): driver panic with an empty disk. + use std::fs::File; use std::io::{Read, Write}; use std::os::fd::{FromRawFd, RawFd}; +use std::sync::{Arc, Weak}; use static_assertions::const_assert_eq; @@ -12,6 +15,7 @@ use virtio_core::spec::*; use syscall::{Packet, SchemeBlockMut}; +use virtio_core::transport::Transport; use virtio_core::utils::VolatileCell; mod scheme; @@ -43,23 +47,48 @@ pub struct BlockGeometry { pub sectors: VolatileCell, } -#[repr(C)] -pub struct BlockDeviceConfig { - capacity: VolatileCell, - pub size_max: VolatileCell, - pub seq_max: VolatileCell, - pub geometry: BlockGeometry, - blk_size: VolatileCell, +#[repr(u8)] +pub enum DeviceConfigTy { + Capacity = 0, + SizeMax = 0x8, + SeqMax = 0xc, + Geometry = 0x10, + BlkSize = 0x14, } +#[repr(C)] +pub struct BlockDeviceConfig(Weak); + impl BlockDeviceConfig { - /// Returns the capacity of the block device in bytes. - pub fn capacity(&self) -> u64 { - self.capacity.get() + #[inline] + fn new(tranport: &Arc) -> Self { + Self(Arc::downgrade(&tranport)) } + pub fn load_config(&self, ty: DeviceConfigTy) -> T + where + T: Sized + TryFrom, + >::Error: std::fmt::Debug, + { + let transport = self.0.upgrade().unwrap(); + + let size = core::mem::size_of::() + .try_into() + .expect("load_config: invalid size"); + + let value = transport.load_config(ty as u8, size); + T::try_from(value).unwrap() + } + + /// Returns the capacity of the block device in bytes. + #[inline] + pub fn capacity(&self) -> u64 { + self.load_config(DeviceConfigTy::Capacity) + } + + #[inline] pub fn block_size(&self) -> u32 { - self.blk_size.get() + self.load_config(DeviceConfigTy::BlkSize) } } @@ -98,15 +127,15 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { .transport .setup_queue(virtio_core::MSIX_PRIMARY_VECTOR, &device.irq_handle)?; - let device_space = unsafe { &mut *(device.device_space as *mut BlockDeviceConfig) }; + let device_space = BlockDeviceConfig::new(&device.transport); // At this point the device is alive! device.transport.run_device(); log::info!( "virtio-blk: disk size: {} sectors and block size of {} bytes", - device_space.capacity.get(), - device_space.blk_size.get() + device_space.capacity(), + device_space.block_size() ); let mut name = pci_config.func.name(); diff --git a/virtio-blkd/src/scheme.rs b/virtio-blkd/src/scheme.rs index d94f9a76b4..e4ec4c7b1d 100644 --- a/virtio-blkd/src/scheme.rs +++ b/virtio-blkd/src/scheme.rs @@ -99,13 +99,13 @@ pub enum Handle { pub struct DiskScheme<'a> { queue: Arc>, next_id: usize, - cfg: &'a mut BlockDeviceConfig, + cfg: BlockDeviceConfig, handles: BTreeMap, part_table: Option, } impl<'a> DiskScheme<'a> { - pub fn new(queue: Arc>, cfg: &'a mut BlockDeviceConfig) -> Self { + pub fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { let mut this = Self { queue, next_id: 0, @@ -157,7 +157,7 @@ impl<'a> DiskScheme<'a> { impl<'a, 'b> Seek for VirtioShim<'a, 'b> { fn seek(&mut self, from: std::io::SeekFrom) -> IoResult { - let size_u = self.scheme.cfg.capacity.get() * self.scheme.cfg.blk_size.get() as u64; + let size_u = self.scheme.cfg.capacity() * self.scheme.cfg.block_size() as u64; let size = i64::try_from(size_u).or(Err(std::io::Error::new( std::io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes", diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 3e4ca9e1e8..9dc1347cfa 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -11,11 +11,11 @@ use pcid_interface::*; use syscall::Io; use crate::spec::*; -use crate::transport::{Error, StandardTransport}; +use crate::transport::{Error, LegacyTransport, StandardTransport, Transport}; use crate::utils::{align_down, VolatileCell}; pub struct Device<'a> { - pub transport: Arc>, + pub transport: Arc, pub device_space: *const u8, pub irq_handle: File, pub isr: &'a VolatileCell, @@ -233,59 +233,95 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result log::trace!("virtio-core::device-probe: {capability:?}"); } - let common_addr = common_addr.ok_or(Error::InCapable(CfgType::Common))?; - let (notify_addr, notify_multiplier) = notify_addr.ok_or(Error::InCapable(CfgType::Notify))?; - let isr_addr = isr_addr.ok_or(Error::InCapable(CfgType::Isr))?; - let device_addr = device_addr.ok_or(Error::InCapable(CfgType::Device))?; + if let ( + Some(common_addr), + Some(isr_addr), + Some(device_addr), + Some((notify_addr, notify_multiplier)), + ) = (common_addr, isr_addr, device_addr, notify_addr) + { + assert!( + notify_multiplier != 0, + "virtio-core::device_probe: device uses the same Queue Notify addresses for all queues" + ); - assert!( - notify_multiplier != 0, - "virtio-core::device_probe: device uses the same Queue Notify addresses for all queues" - ); + let common = unsafe { &mut *(common_addr as *mut CommonCfg) }; + let device_space = unsafe { &mut *(device_addr as *mut u8) }; + let isr = unsafe { &*(isr_addr as *mut VolatileCell) }; - let common = unsafe { &mut *(common_addr as *mut CommonCfg) }; - let device_space = unsafe { &mut *(device_addr as *mut u8) }; - let isr = unsafe { &*(isr_addr as *mut VolatileCell) }; + let transport = StandardTransport::new( + common, + notify_addr as *const u8, + notify_multiplier, + device_space, + ); - let transport = StandardTransport::new(common, notify_addr as *const u8, notify_multiplier); + // Setup interrupts. + let all_pci_features = pcid_handle.fetch_all_features()?; + let has_msix = all_pci_features + .iter() + .any(|(feature, _)| feature.is_msix()); - // Setup interrupts. - let all_pci_features = pcid_handle.fetch_all_features()?; - let has_msix = all_pci_features - .iter() - .any(|(feature, _)| feature.is_msix()); + // According to the virtio specification, the device REQUIRED to support MSI-X. + assert!(has_msix, "virtio: device does not support MSI-X"); + let irq_handle = enable_msix(pcid_handle)?; - // According to the virtio specification, the device REQUIRED to support MSI-X. - assert!(has_msix, "virtio: device does not support MSI-X"); - let irq_handle = enable_msix(pcid_handle)?; + log::info!("virtio: using standard PCI transport"); - log::info!("virtio: using standard PCI transport"); + let device = Device { + transport, + device_space, + irq_handle, + isr, + }; - let device = Device { - transport, - device_space, - irq_handle, - isr, - }; + device.transport.reset(); + reinit(&device)?; - device.transport.reset(); - reinit(&device)?; + Ok(device) + } else { + if let PciBar::Port(port) = pci_header.get_bar(0) { + unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; + log::warn!("virtio: using legacy transport"); - Ok(device) + static SHIM: VolatileCell = VolatileCell::new(0); + + let transport = LegacyTransport::new(port); + + // Setup interrupts. + let all_pci_features = pcid_handle.fetch_all_features()?; + let has_msix = all_pci_features + .iter() + .any(|(feature, _)| feature.is_msix()); + + // According to the virtio specification, the device REQUIRED to support MSI-X. + assert!(has_msix, "virtio: device does not support MSI-X"); + let irq_handle = enable_msix(pcid_handle)?; + + let device = Device { + transport, + irq_handle, + isr: &SHIM, + device_space: core::ptr::null_mut(), + }; + + device.transport.reset(); + reinit(&device)?; + + Ok(device) + } else { + unreachable!("virtio: legacy transport with non-port IO?") + } + } } pub fn reinit<'a>(device: &Device<'a>) -> Result<(), Error> { // XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits // in `device_status` is required to be done in two steps. - let mut common = device.transport.common.lock().unwrap(); - let old = common.device_status.get(); - - common - .device_status - .set(old | DeviceStatusFlags::ACKNOWLEDGE); - - let old = common.device_status.get(); - common.device_status.set(old | DeviceStatusFlags::DRIVER); + device + .transport + .insert_status(DeviceStatusFlags::ACKNOWLEDGE); + device.transport.insert_status(DeviceStatusFlags::DRIVER); Ok(()) } diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 9d72b4fab0..53934b6f56 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -1,8 +1,9 @@ use crate::spec::*; use crate::utils::align; -use common::dma::Dma; +use common::dma::{Dma, PhysBox}; use event::EventQueue; +use syscall::{Io, Pio}; use core::mem::size_of; use core::sync::atomic::{AtomicU16, Ordering}; @@ -62,12 +63,43 @@ const fn queue_part_sizes(queue_size: usize) -> (usize, usize, usize) { let used = used_header + size_of::() * queue_size; ( - align(desc, DESCRIPTOR_ALIGN), - align(avail, AVAILABLE_ALIGN), - align(used, USED_ALIGN), + align(desc, DESCRIPTOR_ALIGN).next_multiple_of(syscall::PAGE_SIZE), + align(avail, AVAILABLE_ALIGN).next_multiple_of(syscall::PAGE_SIZE), + align(used, USED_ALIGN).next_multiple_of(syscall::PAGE_SIZE), ) } +fn spawn_irq_thread(irq_handle: &File, queue: &Arc>) -> Result<(), Error> { + let irq_fd = irq_handle.as_raw_fd(); + let queue_copy = queue.clone(); + + std::thread::spawn(move || { + let mut event_queue = EventQueue::::new().unwrap(); + + event_queue + .add(irq_fd, move |_| -> Result, std::io::Error> { + // Wake up the tasks waiting on the queue. + for (_, task) in queue_copy.waker.lock().unwrap().iter() { + task.wake_by_ref(); + } + + // Wake up the tasks waiting on the queue. + Ok(None) + }) + .unwrap(); + + loop { + event_queue.run().unwrap(); + } + }); + + Ok(()) +} + +pub trait NotifyBell { + fn ring(&self, queue_index: u16); +} + pub struct PendingRequest<'a> { queue: Arc>, first_descriptor: u32, @@ -133,26 +165,29 @@ pub struct Queue<'a> { pub used_head: AtomicU16, vector: u16, - notification_bell: &'a mut AtomicU16, + notification_bell: Box, descriptor_stack: crossbeam_queue::SegQueue, sref: Weak, } impl<'a> Queue<'a> { - pub fn new( + pub fn new( descriptor: Dma<[Descriptor]>, available: Available<'a>, used: Used<'a>, - notification_bell: &'a mut AtomicU16, + notification_bell: N, queue_index: u16, vector: u16, - ) -> Arc { + ) -> Arc + where + N: NotifyBell + 'static, + { let descriptor_stack = crossbeam_queue::SegQueue::new(); (0..descriptor.len() as u16).for_each(|i| descriptor_stack.push(i)); Arc::new_cyclic(|sref| Self { - notification_bell, + notification_bell: Box::new(notification_bell), available, descriptor, used, @@ -211,8 +246,7 @@ impl<'a> Queue<'a> { .set_table_index(first_descriptor as u16); self.available.set_head_idx(index as u16 + 1); - self.notification_bell - .store(self.queue_index, Ordering::SeqCst); + self.notification_bell.ring(self.queue_index); PendingRequest { queue: self.sref.upgrade().unwrap(), @@ -240,22 +274,33 @@ pub struct Available<'a> { impl<'a> Available<'a> { pub fn new(queue_size: usize) -> Result { - let (_, size, _) = queue_part_sizes(queue_size); - let size = size.next_multiple_of(syscall::PAGE_SIZE); // align to page size - + let (_, _, size) = queue_part_sizes(queue_size); let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; - let virt = - unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) } - .map_err(Error::SyscallError)?; + + unsafe { Self::from_raw(addr, size, queue_size) } + } + + /// `addr` is the physical address of the ring. + pub unsafe fn from_raw(addr: usize, size: usize, queue_size: usize) -> Result { + let virt = unsafe { + common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) + }?; let ring = unsafe { &mut *(virt as *mut AvailableRing) }; - - Ok(Self { + let ring = Self { addr, size, ring, queue_size, - }) + }; + + for i in 0..queue_size { + // Setting them to `u16::MAX` helps with debugging since qemu reports them + // as illegal values. + ring.get_element_at(i).table_index.store(u16::MAX, Ordering::SeqCst); + } + + Ok(ring) } /// ## Panics @@ -308,21 +353,32 @@ pub struct Used<'a> { impl<'a> Used<'a> { pub fn new(queue_size: usize) -> Result { let (_, _, size) = queue_part_sizes(queue_size); - let size = size.next_multiple_of(syscall::PAGE_SIZE); // align to page size - let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; - let virt = - unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) } - .map_err(Error::SyscallError)?; + + unsafe { Self::from_raw(addr, size, queue_size) } + } + + /// `addr` is the physical address of the ring. + pub unsafe fn from_raw(addr: usize, size: usize, queue_size: usize) -> Result { + let virt = unsafe { + common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) + }?; let ring = unsafe { &mut *(virt as *mut UsedRing) }; - - Ok(Self { + let mut ring = Self { addr, size, ring, queue_size, - }) + }; + + for i in 0..queue_size { + // Setting them to `u32::MAX` helps with debugging since qemu reports them + // as illegal values. + ring.get_mut_element_at(i).table_index.set(u32::MAX); + } + + Ok(ring) } /// ## Panics @@ -377,43 +433,307 @@ impl Drop for Used<'_> { } } +pub trait Transport: Sync + Send { + /// `size` specifies the size of the read in bytes. + /// + /// ## Panics + /// This function panics if the provided `size` is more then `size_of::()`. + fn load_config(&self, offset: u8, size: u8) -> u64; + + /// Resets the device. + fn reset(&self); + + /// Returns whether the device supports the specified feature. + fn check_device_feature(&self, feature: u32) -> bool; + + /// Acknowledges the specified feature. + /// + /// **Note**: [`Transport::check_device_feature`] must be used to check whether + /// the device supports the feature before acknowledging it. + fn ack_driver_feature(&self, feature: u32); + + /// Finalizes the acknowledged features by setting the `FEATURES_OK` bit in the + /// device status flags. No-op on a legacy device. + fn finalize_features(&self); + + /// Runs the device. + /// + /// At this point, all of the queues must be created and the features must be + /// finalized. + /// + /// ## Panics + /// This function panics if the device is already running. + fn run_device(&self) { + self.insert_status(DeviceStatusFlags::DRIVER_OK); + } + + /// Creates a new queue. + /// + /// ## Panics + /// This function panics if the device is running. + fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result, Error>; + + // TODO(andypython): Should this function be unsafe? + fn reinit_queue(&self, queue: Arc); + fn insert_status(&self, status: DeviceStatusFlags); +} + +pub enum LegacyRegister { + DeviceFeatures = 0, // u32 + + QueueAddress = 8, // u32 + QueueSize = 12, // u16 + QueueSelect = 14, // u16 + QueueNotify = 16, // u16 + + DeviceStatus = 18, // u8 + + ConfigMsixVector = 20, // u16 + QueueMsixVector = 22, // u16 +} + +struct LegacyBell(Weak); + +impl NotifyBell for LegacyBell { + #[inline] + fn ring(&self, queue_index: u16) { + let transport = self.0.upgrade().expect("bell: transport dropped"); + transport.write::(LegacyRegister::QueueNotify, queue_index) + } +} + +pub struct LegacyTransport(u16, AtomicU16, Weak); + +impl LegacyTransport { + pub(super) fn new(port: u16) -> Arc { + Arc::new_cyclic(|sref| Self(port, AtomicU16::new(0), sref.clone())) + } + + unsafe fn read_raw(&self, offset: usize) -> V + where + V: Sized + TryFrom, + >::Error: std::fmt::Debug, + { + let port = self.0 + offset as u16; + + if size_of::() == size_of::() { + V::try_from(Pio::::new(port).read() as u64).unwrap() + } else if size_of::() == size_of::() { + V::try_from(Pio::::new(port).read() as u64).unwrap() + } else if size_of::() == size_of::() { + V::try_from(Pio::::new(port).read() as u64).unwrap() + } else if size_of::() == size_of::() { + let lower = Pio::::new(port).read() as u64; + let upper = Pio::::new(port + size_of::() as u16).read() as u64; + + V::try_from(lower | (upper << 32)).unwrap() + } else { + unreachable!() + } + } + + fn read(&self, register: LegacyRegister) -> V + where + V: Sized + TryFrom, + >::Error: std::fmt::Debug, + { + unsafe { self.read_raw(register as usize) } + } + + fn write(&self, register: LegacyRegister, value: V) + where + V: Sized + TryInto, + >::Error: std::fmt::Debug, + { + if size_of::() == size_of::() { + Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u8); + } else if size_of::() == size_of::() { + Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u16); + } else if size_of::() == size_of::() { + Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u32); + } else { + unreachable!() + } + } +} + +impl Transport for LegacyTransport { + fn reset(&self) { + self.write(LegacyRegister::DeviceStatus, 0u8); + + let status = self.read::(LegacyRegister::DeviceStatus); + assert_eq!(status, 0); + } + + fn check_device_feature(&self, feature: u32) -> bool { + assert!( + feature < 32, + "virtio: cannot query feature {feature} on a legacy device" + ); + self.read::(LegacyRegister::DeviceFeatures) & (1 << feature) == (1 << feature) + } + + fn ack_driver_feature(&self, feature: u32) { + assert!( + feature < 32, + "virtio: cannot ack feature {feature} on a legacy device" + ); + + let current = self.read::(LegacyRegister::DeviceFeatures); + self.write::(LegacyRegister::DeviceFeatures, current | (1 << feature)); + } + + fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result, Error> { + let queue_index = self.1.fetch_add(1, Ordering::SeqCst); + self.write(LegacyRegister::QueueSelect, queue_index); + + let queue_size = self.read::(LegacyRegister::QueueSize) as usize; + let (desc_size, avail_size, used_size) = queue_part_sizes(queue_size); + + let size_bytes = desc_size + avail_size + used_size; + let addr = unsafe { syscall::physalloc(size_bytes).map_err(Error::SyscallError)? }; + + let descriptor = unsafe { + let physbox = PhysBox::from_raw_parts(addr, desc_size); + let table = Dma::<[Descriptor]>::from_physbox_uninit_unsized(physbox, queue_size)?; + + table.assume_init() + }; + + let avail_addr = addr + desc_size; + let avail = unsafe { Available::from_raw(avail_addr, avail_size, queue_size)? }; + + let used_addr = avail_addr + avail_size; + let used = unsafe { Used::from_raw(used_addr, used_size, queue_size)? }; + + self.write::(LegacyRegister::QueueMsixVector, vector); + self.write::(LegacyRegister::QueueAddress, (addr as u32) >> 12); + + log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})"); + + let queue = Queue::new( + descriptor, + avail, + used, + LegacyBell(self.2.clone()), + queue_index, + vector, + ); + + spawn_irq_thread(irq_handle, &queue)?; + Ok(queue) + } + + fn load_config(&self, offset: u8, size: u8) -> u64 { + // We always enable MSI-X. So, the device configuration space offset will + // always be 0x18. + // + // Checkout 4.1.4.8 Legacy Interfaces: A Note on PCI Device Layout + const DEVICE_SPACE_OFFSET: usize = 0x18; + + let size = size as usize; + let offset = DEVICE_SPACE_OFFSET + offset as usize; + + unsafe { + if size == size_of::() { + self.read_raw::(offset) as u64 + } else if size == size_of::() { + self.read_raw::(offset) as u64 + } else if size == size_of::() { + self.read_raw::(offset) as u64 + } else if size == size_of::() { + self.read_raw::(offset) as u64 + } else { + unreachable!() + } + } + } + + fn insert_status(&self, status: DeviceStatusFlags) { + let old = self.read::(LegacyRegister::DeviceStatus); + self.write(LegacyRegister::DeviceStatus, old | status.bits()); + } + + fn reinit_queue(&self, _queue: Arc) { + todo!() + } + + // Legacy devices do not have the `FEATURES_OK` bit. + fn finalize_features(&self) {} +} + +struct StandardBell<'a>(&'a mut AtomicU16); + +impl NotifyBell for StandardBell<'_> { + #[inline] + fn ring(&self, queue_index: u16) { + self.0.store(queue_index, Ordering::SeqCst); + } +} + pub struct StandardTransport<'a> { pub(crate) common: Mutex<&'a mut CommonCfg>, notify: *const u8, notify_mul: u32, + device_space: *const u8, queue_index: AtomicU16, } impl<'a> StandardTransport<'a> { - pub fn new(common: &'a mut CommonCfg, notify: *const u8, notify_mul: u32) -> Arc { + pub fn new( + common: &'a mut CommonCfg, + notify: *const u8, + notify_mul: u32, + device_space: *const u8, + ) -> Arc { Arc::new(Self { common: Mutex::new(common), notify, notify_mul, queue_index: AtomicU16::new(0), + device_space, }) } +} - pub fn reset(&self) { +impl Transport for StandardTransport<'_> { + fn load_config(&self, offset: u8, size: u8) -> u64 { + unsafe { + let ptr = self.device_space.add(offset as usize); + let size = size as usize; + + if size == size_of::() { + ptr.cast::().read() as u64 + } else if size == size_of::() { + ptr.cast::().read() as u64 + } else if size == size_of::() { + ptr.cast::().read() as u64 + } else if size == size_of::() { + ptr.cast::().read() as u64 + } else { + unreachable!() + } + } + } + + fn reset(&self) { let mut common = self.common.lock().unwrap(); common.device_status.set(DeviceStatusFlags::empty()); // Upon reset, the device must initialize device status to 0. assert_eq!(common.device_status.get(), DeviceStatusFlags::empty()); - - log::debug!("virtio: successfully reseted device"); } - pub fn check_device_feature(&self, feature: u32) -> bool { + fn check_device_feature(&self, feature: u32) -> bool { let mut common = self.common.lock().unwrap(); common.device_feature_select.set(feature >> 5); (common.device_feature.get() & (1 << (feature & 31))) != 0 } - pub fn ack_driver_feature(&self, feature: u32) { + fn ack_driver_feature(&self, feature: u32) { let mut common = self.common.lock().unwrap(); common.driver_feature_select.set(feature >> 5); @@ -422,7 +742,7 @@ impl<'a> StandardTransport<'a> { common.driver_feature.set(current | (1 << (feature & 31))); } - pub fn finalize_features(&self) { + fn finalize_features(&self) { // Check VirtIO version 1 compliance. assert!(self.check_device_feature(VIRTIO_F_VERSION_1)); self.ack_driver_feature(VIRTIO_F_VERSION_1); @@ -440,16 +760,7 @@ impl<'a> StandardTransport<'a> { assert!((confirm & DeviceStatusFlags::FEATURES_OK) == DeviceStatusFlags::FEATURES_OK); } - pub fn run_device(&self) { - let mut common = self.common.lock().unwrap(); - - let status = common.device_status.get(); - common - .device_status - .set(status | DeviceStatusFlags::DRIVER_OK); - } - - pub fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result>, Error> { + fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result, Error> { let mut common = self.common.lock().unwrap(); let queue_index = self.queue_index.fetch_add(1, Ordering::SeqCst); @@ -464,17 +775,7 @@ impl<'a> StandardTransport<'a> { }; let avail = Available::new(queue_size)?; - let mut used = Used::new(queue_size)?; - - for i in 0..queue_size { - // XXX: Fill the `table_index` of the elements with `T::MAX` to help with - // debugging since qemu reports them as illegal values. - avail - .get_element_at(i) - .table_index - .store(u16::MAX, Ordering::Relaxed); - used.get_mut_element_at(i).table_index.set(u32::MAX); - } + let used = Used::new(queue_size)?; common.queue_desc.set(descriptor.physical() as u64); common.queue_driver.set(avail.phys_addr() as u64); @@ -498,37 +799,24 @@ impl<'a> StandardTransport<'a> { descriptor, avail, used, - notification_bell, + StandardBell(notification_bell), queue_index, vector, ); - let queue_copy = queue.clone(); - let irq_fd = irq_handle.as_raw_fd(); - - std::thread::spawn(move || { - let mut event_queue = EventQueue::::new().unwrap(); - - event_queue - .add(irq_fd, move |_| -> Result, std::io::Error> { - // Wake up the tasks waiting on the queue. - for (_, task) in queue_copy.waker.lock().unwrap().iter() { - task.wake_by_ref(); - } - Ok(None) - }) - .unwrap(); - - loop { - event_queue.run().unwrap(); - } - }); - + spawn_irq_thread(irq_handle, &queue)?; Ok(queue) } + fn insert_status(&self, status: DeviceStatusFlags) { + let mut common = self.common.lock().unwrap(); + let old = common.device_status.get(); + + common.device_status.set(old | status); + } + /// Re-initializes a queue; usually done after a device reset. - pub fn reinit_queue(&self, queue: Arc) { + fn reinit_queue(&self, queue: Arc) { let mut common = self.common.lock().unwrap(); queue.reinit(); @@ -546,3 +834,6 @@ impl<'a> StandardTransport<'a> { common.queue_enable.set(1); } } + +unsafe impl Send for StandardTransport<'_> {} +unsafe impl Sync for StandardTransport<'_> {} diff --git a/virtio-core/src/utils.rs b/virtio-core/src/utils.rs index 6f71dac4ea..07214248e5 100644 --- a/virtio-core/src/utils.rs +++ b/virtio-core/src/utils.rs @@ -9,7 +9,7 @@ pub struct VolatileCell { impl VolatileCell { #[inline] - pub fn new(value: T) -> Self { + pub const fn new(value: T) -> Self { Self { value: UnsafeCell::new(value), } diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 7fe379a24c..7342eeea6c 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -9,7 +9,7 @@ use common::dma::Dma; use syscall::{Error as SysError, SchemeMut, EAGAIN, EINVAL}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; -use virtio_core::transport::{Error, Queue, StandardTransport}; +use virtio_core::transport::{Error, Queue, Transport}; use virtio_core::utils::VolatileCell; use crate::*; @@ -30,7 +30,7 @@ impl Into for &Damage { pub struct Display<'a> { control_queue: Arc>, cursor_queue: Arc>, - transport: Arc>, + transport: Arc, // TODO(andypython): Remove the need for the spin crate after the `once_cell` // API is stabilized. @@ -49,7 +49,7 @@ impl<'a> Display<'a> { pub fn new( control_queue: Arc>, cursor_queue: Arc>, - transport: Arc>, + transport: Arc, id: usize, ) -> Self { Self { @@ -250,7 +250,10 @@ impl<'a> Display<'a> { } enum Handle<'a> { - Vt { display: Arc>, vt: usize }, + Vt { + display: Arc>, + vt: usize, + }, Input, } @@ -266,7 +269,7 @@ impl<'a> Scheme<'a> { config: &'a mut GpuConfig, control_queue: Arc>, cursor_queue: Arc>, - transport: Arc>, + transport: Arc, ) -> Result, Error> { let displays = Self::probe( control_queue.clone(), @@ -286,7 +289,7 @@ impl<'a> Scheme<'a> { async fn probe( control_queue: Arc>, cursor_queue: Arc>, - transport: Arc>, + transport: Arc, config: &GpuConfig, ) -> Result>>, Error> { let mut display_info = Self::get_display_info(control_queue.clone()).await?; @@ -353,7 +356,13 @@ impl<'a> SchemeMut for Scheme<'a> { let display = self.displays.get(id).ok_or(SysError::new(EINVAL))?; let fd = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.insert(fd, Handle::Vt {display: display.clone(), vt }); + self.handles.insert( + fd, + Handle::Vt { + display: display.clone(), + vt, + }, + ); Ok(fd) } @@ -440,9 +449,9 @@ impl<'a> SchemeMut for Scheme<'a> { let target_vt = vt; for handle in self.handles.values() { - if let Handle::Vt { display , vt } = handle { - if *vt != target_vt { - continue; + if let Handle::Vt { display, vt } = handle { + if *vt != target_vt { + continue; } futures::executor::block_on(display.init()).unwrap(); @@ -452,9 +461,9 @@ impl<'a> SchemeMut for Scheme<'a> { DisplayCommand::Deactivate(target_vt) => { for handle in self.handles.values() { - if let Handle::Vt { display , vt } = handle { - if *vt != target_vt { - continue; + if let Handle::Vt { display, vt } = handle { + if *vt != target_vt { + continue; } futures::executor::block_on(display.detach()).unwrap(); diff --git a/virtio-netd/src/main.rs b/virtio-netd/src/main.rs index e6fb3ee842..4e38b1ec02 100644 --- a/virtio-netd/src/main.rs +++ b/virtio-netd/src/main.rs @@ -9,7 +9,7 @@ use pcid_interface::PcidServerHandle; use syscall::{Packet, SchemeBlockMut}; use virtio_core::spec::VIRTIO_NET_F_MAC; -use virtio_core::transport::Error; +use virtio_core::transport::{Error, Transport}; use scheme::NetworkScheme; From 9980fe6bb9d0efb799c9005eb15f6c4ea4bfc4c1 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Wed, 23 Aug 2023 15:09:51 +1000 Subject: [PATCH 0698/1301] virtio-blkd: remove repr(C) from the device config struct Signed-off-by: Anhad Singh --- virtio-blkd/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/virtio-blkd/src/main.rs b/virtio-blkd/src/main.rs index 959361406e..2083530c70 100644 --- a/virtio-blkd/src/main.rs +++ b/virtio-blkd/src/main.rs @@ -56,7 +56,6 @@ pub enum DeviceConfigTy { BlkSize = 0x14, } -#[repr(C)] pub struct BlockDeviceConfig(Weak); impl BlockDeviceConfig { From 74241e02738aa8fc81274132c06041a7bd25a89a Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Thu, 31 Aug 2023 16:14:14 +1000 Subject: [PATCH 0699/1301] inputd: fix panic when no devices are available Signed-off-by: Anhad Singh --- inputd/src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index f1d06198fb..de6027987a 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -497,6 +497,11 @@ pub fn main() { } } + if devices.is_empty() { + // No display devices found. + return; + } + let device = devices .iter() .filter(|d| !d.contains("vesa")) From ba661f9719f9f75307cb40a2d0e14f96b438cba4 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 31 Aug 2023 18:07:47 +0200 Subject: [PATCH 0700/1301] Replace SYS_PIPE2 with libc::pipe in pcid. --- pcid/src/main.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index bbc92db7b9..2a41da0a3a 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -466,11 +466,19 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, info!("PCID SPAWN {:?}", command); let (pcid_to_client_write, pcid_from_client_read, envs) = if driver.use_channel.unwrap_or(false) { - let mut fds1 = [0usize; 2]; - let mut fds2 = [0usize; 2]; + // TODO: libc wrapper? + let [fds1, fds2] = unsafe { + let mut fds1 = [0 as libc::c_int; 2]; + let mut fds2 = [0 as libc::c_int; 2]; - syscall::pipe2(&mut fds1, 0).expect("pcid: failed to create pcid->client pipe"); - syscall::pipe2(&mut fds2, 0).expect("pcid: failed to create client->pcid pipe"); + assert_eq!(libc::pipe(fds1.as_mut_ptr()), 0, "pcid: failed to create pcid->client pipe"); + assert_eq!(libc::pipe(fds2.as_mut_ptr()), 0, "pcid: failed to create client->pcid pipe"); + + [ + fds1.map(|c| c as usize), + fds2.map(|c| c as usize), + ] + }; let [pcid_to_client_read, pcid_to_client_write] = fds1; let [pcid_from_client_read, pcid_from_client_write] = fds2; From 9fe01a2cf1449d5ffebac55e78f11dc3d18a34f7 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 31 Aug 2023 21:14:28 +0200 Subject: [PATCH 0701/1301] Update dependencies. --- Cargo.lock | 122 ++++++++++++++++++++++++++--------------------------- 1 file changed, 61 insertions(+), 61 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1cad285fe6..6569119547 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -111,9 +111,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.72" +version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854" +checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arg_parser" @@ -190,9 +190,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.3.3" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" [[package]] name = "bitvec" @@ -230,9 +230,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cc" -version = "1.0.81" +version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6b2562119bf28c3439f7f02db99faf0aa1a8cdfe5772a2ee155d32227239f0" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] @@ -261,9 +261,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.26" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" +checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" dependencies = [ "android-tzdata", "iana-time-zone", @@ -271,7 +271,7 @@ dependencies = [ "num-traits", "time", "wasm-bindgen", - "winapi", + "windows-targets", ] [[package]] @@ -453,7 +453,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -503,7 +503,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8283e7331b8c93b9756e0cfdbcfb90312852f953c6faf9bf741e684cc3b6ad69" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "crc", "log", "uuid", @@ -685,9 +685,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "matches" @@ -703,9 +703,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.5.0" +version = "2.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" [[package]] name = "net2" @@ -720,7 +720,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#9bcbf8c4a881e743169fecb6d520d27fb0977f66" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#fc11b9bb3c1f5eefccb93ae670e4ec8b3d6fad4f" dependencies = [ "arg_parser", "libc", @@ -729,7 +729,7 @@ dependencies = [ "pbr", "redox-daemon", "redox_event", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "redox_termios", "termion", "url", @@ -960,9 +960,9 @@ checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" [[package]] name = "pin-project-lite" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" @@ -1021,9 +1021,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.32" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] @@ -1083,12 +1083,12 @@ dependencies = [ [[package]] name = "redox-daemon" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21e31c834277709c7ff3eb74959fe62be4b45b1189ba9d41fd3744cd3a9c554f" +checksum = "811fd0d382a70c9e9192166ee794567b65ef34cc7309c86a49b071779ca9b5f3" dependencies = [ "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", ] [[package]] @@ -1255,29 +1255,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.180" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea67f183f058fe88a4e3ec6e2788e003840893b91bac4559cabedd00863b3ed" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.180" +version = "1.0.188" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e744d7782b686ab3b73267ef05697159cc0e5abbed3f47f9933165e5219036" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] name = "serde_json" -version = "1.0.104" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" +checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" dependencies = [ "itoa", "ryu", @@ -1295,9 +1295,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] @@ -1412,9 +1412,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.28" +version = "2.0.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" dependencies = [ "proc-macro2", "quote", @@ -1450,22 +1450,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", ] [[package]] @@ -1701,7 +1701,7 @@ dependencies = [ name = "virtio-core" version = "0.1.0" dependencies = [ - "bitflags 2.3.3", + "bitflags 2.4.0", "common", "crossbeam-queue", "futures", @@ -1790,7 +1790,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-shared", ] @@ -1812,7 +1812,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.28", + "syn 2.0.29", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1856,9 +1856,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.48.1" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1871,51 +1871,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_msvc" -version = "0.48.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "winnow" -version = "0.5.3" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807" +checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" dependencies = [ "memchr", ] From 0d589a3189c418f1913ec13ad855f963386b12fe Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 13 Aug 2023 11:48:46 +0200 Subject: [PATCH 0702/1301] Add a livedisk daemon. --- Cargo.lock | 10 +++ Cargo.toml | 1 + lived/Cargo.toml | 14 +++ lived/src/main.rs | 220 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+) create mode 100644 lived/Cargo.toml create mode 100644 lived/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 6569119547..8021ac384d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -673,6 +673,16 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "lived" +version = "0.1.0" +dependencies = [ + "anyhow", + "redox-daemon", + "redox_syscall 0.3.5", + "slab", +] + [[package]] name = "lock_api" version = "0.4.10" diff --git a/Cargo.toml b/Cargo.toml index b68ec3665c..229e7724ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ members = [ "ihdad", "ixgbed", "nvmed", + "lived", # TODO: not really a driver... "pcid", "pcspkrd", "ps2d", diff --git a/lived/Cargo.toml b/lived/Cargo.toml new file mode 100644 index 0000000000..0621101e24 --- /dev/null +++ b/lived/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "lived" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +version = "0.1.0" +edition = "2021" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1" +redox-daemon = "0.1" +redox_syscall = "0.3" +slab = "0.4" diff --git a/lived/src/main.rs b/lived/src/main.rs new file mode 100644 index 0000000000..a133404c0e --- /dev/null +++ b/lived/src/main.rs @@ -0,0 +1,220 @@ +//! Disk scheme replacement when making live disk + +#![feature(int_roundings)] + +use std::fs::File; + +use std::io::{Read, Write}; +use std::os::fd::AsRawFd; +use std::str; + +use slab::Slab; +use syscall::data::Stat; +use syscall::{error::*, MapFlags, SchemeMut, Packet}; +use syscall::flag::{MODE_DIR, MODE_FILE}; +use syscall::scheme::calc_seek_offset_usize; +use syscall::PAGE_SIZE; + +use anyhow::{anyhow, Context, bail}; + +const LIST: [u8; 2] = *b"0\n"; + +struct Handle { + ty: HandleType, + seek: usize, +} +enum HandleType { + TopLevel, + TheData, +} + +pub struct DiskScheme { + the_data: &'static mut [u8], + handles: Slab, +} + +impl DiskScheme { + pub fn new() -> anyhow::Result { + let mut phys = 0; + let mut size = 0; + + // TODO: handle error + for line in std::fs::read_to_string("sys:env").context("failed to read env")?.lines() { + let mut parts = line.splitn(2, '='); + let name = parts.next().unwrap_or(""); + let value = parts.next().unwrap_or(""); + + if name == "DISK_LIVE_ADDR" { + phys = usize::from_str_radix(value, 16).unwrap_or(0); + } + + if name == "DISK_LIVE_SIZE" { + size = usize::from_str_radix(value, 16).unwrap_or(0); + } + } + + if phys == 0 || size == 0 { + bail!("either livedisk phys ({}) or size ({}) was zero", phys, size); + } + + let start = phys.div_floor(PAGE_SIZE) * PAGE_SIZE; + let end = phys.checked_add(size).context("phys + size overflow")?.next_multiple_of(PAGE_SIZE); + let size = end - start; + + let the_data = unsafe { + let file = File::open("memory:physical")?; + let base = syscall::fmap(file.as_raw_fd() as usize, &syscall::Map { + address: 0, + offset: start, + size, + flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_SHARED, + }).map_err(|err| anyhow!("failed to mmap livedisk: {}", err))?; + + std::slice::from_raw_parts_mut(base as *mut u8, size) + }; + + Ok(DiskScheme { + the_data, + handles: Slab::with_capacity(32), + }) + } +} + +impl SchemeMut for DiskScheme { + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { + let handle = self.handles.get_mut(id).ok_or(Error::new(EBADF))?; + let len = match handle.ty { + HandleType::TopLevel => LIST.len(), + HandleType::TheData => self.the_data.len(), + }; + let new_offset = calc_seek_offset_usize(handle.seek, pos, whence, len)?; + handle.seek = new_offset as usize; + Ok(new_offset) + } + + fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize) -> Result { + let _handle = self.handles.get(id).ok_or(Error::new(EBADF))?; + + Ok(0) + } + + fn fsync(&mut self, id: usize) -> Result { + let _handle = self.handles.get(id).ok_or(Error::new(EBADF))?; + + Ok(0) + } + + fn close(&mut self, id: usize) -> Result { + let _ = self.handles.remove(id); + + Ok(0) + } + fn open(&mut self, path: &str, _flags: usize, uid: u32, _gid: u32) -> Result { + if uid != 0 { + return Err(Error::new(EACCES)); + } + + let path_trimmed = path.trim_matches('/'); + + let handle = match path_trimmed { + "" => { + Handle { + //mode: MODE_DIR | 0o755, + seek: 0, + ty: HandleType::TopLevel, + } + }, + "0" => { + Handle { + //mode: MODE_FILE | 0o644, + seek: 0, + ty: HandleType::TheData, + } + } + _ => return Err(Error::new(ENOENT)), + }; + + Ok(self.handles.insert(handle)) + } + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + let handle = self.handles.get_mut(id).ok_or(Error::new(EBADF))?; + + let data = match handle.ty { + HandleType::TheData => &*self.the_data, + HandleType::TopLevel => &LIST, + }; + + let src = data.get(handle.seek..).unwrap_or(&[]); + let byte_count = std::cmp::min(src.len(), buf.len()); + buf[..byte_count].copy_from_slice(&src[..byte_count]); + handle.seek += byte_count; + + Ok(byte_count) + } + + fn write(&mut self, id: usize, buffer: &[u8]) -> Result { + let handle = self.handles.get_mut(id).ok_or(Error::new(EBADF))?; + + match handle.ty { + HandleType::TheData => { + let dst = self.the_data.get_mut(handle.seek..).unwrap_or(&mut []); + let byte_count = std::cmp::min(dst.len(), buffer.len()); + dst[..byte_count].copy_from_slice(&buffer[..byte_count]); + handle.seek += byte_count; + + Ok(byte_count) + }, + HandleType::TopLevel => Err(Error::new(EBADF)), + } + } + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + let path = match self.handles.get(id).ok_or(Error::new(EBADF))?.ty { + HandleType::TopLevel => "", + HandleType::TheData => "0", + }; + + let src = format!("disk/live:{}", path).into_bytes(); + + let byte_count = std::cmp::min(buf.len(), src.len()); + buf[..byte_count].copy_from_slice(&src[..byte_count]); + + Ok(byte_count) + } + fn fstat(&mut self, id: usize, stat_buf: &mut Stat) -> Result { + let handle = self.handles.get(id).ok_or(Error::new(EBADF))?; + + let (len, mode) = match handle.ty { + HandleType::TheData => (self.the_data.len(), MODE_FILE | 0o644), + HandleType::TopLevel => (LIST.len(), MODE_DIR | 0o755), + }; + + *stat_buf = Stat { + st_mode: mode, + st_uid: 0, + st_gid: 0, + st_size: len.try_into().map_err(|_| Error::new(EOVERFLOW))?, + ..Stat::default() + }; + + Ok(0) + } +} +fn main() -> anyhow::Result<()> { + redox_daemon::Daemon::new(move |daemon| { + let mut socket = File::create(":disk/live").expect("failed to open scheme"); + let mut scheme = DiskScheme::new().unwrap_or_else(|err| { + eprintln!("failed to initialize livedisk scheme: {}", err); + std::process::exit(1) + }); + daemon.ready().expect("failed to signal readiness"); + + let mut packet = Packet::default(); + + loop { + socket.read_exact(&mut packet).expect("failed to read packet"); + scheme.handle(&mut packet); + socket.write_all(&packet).expect("failed to write packet"); + } + + }).map_err(|err| anyhow!("failed to start daemon: {}", err))?; +} From 61e9512468efd898ab57c71ab7040222f103cf16 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 7 Sep 2023 20:49:37 -0600 Subject: [PATCH 0703/1301] Update redox_syscall to 0.4 --- Cargo.lock | 110 ++++++++++++++++++++++------------------- ac97d/Cargo.toml | 2 +- acpid/Cargo.toml | 2 +- ahcid/Cargo.toml | 2 +- alxd/Cargo.toml | 2 +- bgad/Cargo.toml | 2 +- common/Cargo.toml | 2 +- e1000d/Cargo.toml | 2 +- ided/Cargo.toml | 2 +- ihdad/Cargo.toml | 2 +- inputd/Cargo.toml | 2 +- ixgbed/Cargo.toml | 2 +- lived/Cargo.toml | 2 +- nvmed/Cargo.toml | 2 +- pcid/Cargo.toml | 2 +- pcspkrd/Cargo.toml | 2 +- ps2d/Cargo.toml | 2 +- rtl8139d/Cargo.toml | 2 +- rtl8168d/Cargo.toml | 2 +- sb16d/Cargo.toml | 2 +- usbhidd/Cargo.toml | 2 +- usbscsid/Cargo.toml | 2 +- vboxd/Cargo.toml | 2 +- vesad/Cargo.toml | 2 +- virtio-blkd/Cargo.toml | 2 +- virtio-core/Cargo.toml | 2 +- virtio-gpud/Cargo.toml | 2 +- virtio-netd/Cargo.toml | 2 +- xhcid/Cargo.toml | 2 +- 29 files changed, 87 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8021ac384d..6ab3b5df1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,7 +12,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "spin", ] @@ -30,7 +30,7 @@ dependencies = [ "plain", "redox-daemon", "redox-log", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "rustc-hash", "serde_json", "thiserror", @@ -48,7 +48,7 @@ dependencies = [ "partitionlib", "redox-daemon", "redox-log", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -60,7 +60,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -82,7 +82,7 @@ dependencies = [ "aml", "rustc-hash", "serde", - "toml 0.7.6", + "toml 0.7.7", ] [[package]] @@ -164,7 +164,7 @@ version = "0.1.0" dependencies = [ "orbclient", "redox-daemon", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -261,15 +261,14 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.28" +version = "0.4.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ed24df0632f708f5f6d8082675bef2596f7084dee3dd55f632290bf35bfe0f" +checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", - "time", "wasm-bindgen", "windows-targets", ] @@ -293,7 +292,7 @@ dependencies = [ name = "common" version = "0.1.0" dependencies = [ - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -376,7 +375,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -453,7 +452,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -567,7 +566,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -592,7 +591,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "spin", ] @@ -615,7 +614,7 @@ dependencies = [ "orbclient", "redox-daemon", "redox-log", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "spin", ] @@ -643,7 +642,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -679,7 +678,7 @@ version = "0.1.0" dependencies = [ "anyhow", "redox-daemon", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "slab", ] @@ -713,9 +712,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.6.2" +version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e" +checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" [[package]] name = "net2" @@ -730,7 +729,7 @@ dependencies = [ [[package]] name = "netutils" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#fc11b9bb3c1f5eefccb93ae670e4ec8b3d6fad4f" +source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#d1998d5aa2809b7f0c433f2df3125eecfbfa5c86" dependencies = [ "arg_parser", "libc", @@ -801,7 +800,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "smallvec 1.11.0", ] @@ -945,7 +944,7 @@ dependencies = [ "paw", "plain", "redox-log", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "serde", "serde_json", "smallvec 1.11.0", @@ -959,7 +958,7 @@ name = "pcspkrd" version = "0.1.0" dependencies = [ "redox-daemon", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -1026,7 +1025,7 @@ dependencies = [ "bitflags 1.3.2", "orbclient", "redox-daemon", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -1133,7 +1132,16 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.3.5" -source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#a525620c818a801bb7038e111b71033eff56a3ee" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.0" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#1bef275ffcc50c825214f5a349aa94932efb342c" dependencies = [ "bitflags 1.3.2", ] @@ -1159,7 +1167,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -1174,7 +1182,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -1210,7 +1218,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "spin", ] @@ -1280,7 +1288,7 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1422,9 +1430,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.29" +version = "2.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a" +checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" dependencies = [ "proc-macro2", "quote", @@ -1460,22 +1468,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f" +checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.47" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b" +checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", ] [[package]] @@ -1515,9 +1523,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +checksum = "de0a3ab2091e52d7299a39d098e200114a972df0a7724add02a273aa9aada592" dependencies = [ "serde", "serde_spanned", @@ -1536,9 +1544,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.14" +version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ "indexmap", "serde", @@ -1607,7 +1615,7 @@ dependencies = [ "log", "orbclient", "redox-log", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "ux", "xhcid", ] @@ -1619,7 +1627,7 @@ dependencies = [ "base64", "plain", "redox-daemon", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "thiserror", "xhcid", ] @@ -1653,7 +1661,7 @@ dependencies = [ "orbclient", "redox-daemon", "redox_event", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] @@ -1683,7 +1691,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "rusttype", ] @@ -1700,7 +1708,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "spin", "static_assertions", "thiserror", @@ -1719,7 +1727,7 @@ dependencies = [ "pcid", "redox-log", "redox_event", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "static_assertions", "thiserror", ] @@ -1737,7 +1745,7 @@ dependencies = [ "paste", "pcid", "redox-daemon", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "spin", "static_assertions", "virtio-core", @@ -1753,7 +1761,7 @@ dependencies = [ "netutils", "pcid", "redox-daemon", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "static_assertions", "virtio-core", ] @@ -1800,7 +1808,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", "wasm-bindgen-shared", ] @@ -1822,7 +1830,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.29", + "syn 2.0.31", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1955,7 +1963,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", "serde", "serde_json", "smallvec 1.11.0", diff --git a/ac97d/Cargo.toml b/ac97d/Cargo.toml index 1657a30cfb..784990155a 100644 --- a/ac97d/Cargo.toml +++ b/ac97d/Cargo.toml @@ -10,5 +10,5 @@ log = "0.4" redox-daemon = "0.1" redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.3" +redox_syscall = "0.4" spin = "0.9" diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 6914a81e68..92a6e8027d 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -15,7 +15,7 @@ parking_lot = "0.11.1" plain = "0.2.3" redox-daemon = "0.1" redox-log = "0.1.1" -redox_syscall = "0.3" +redox_syscall = "0.4" rustc-hash = "1.1.0" thiserror = "1" serde_json = "1.0.94" diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index 85704b42a1..2741d9d05f 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -10,7 +10,7 @@ log = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" block-io-wrapper = { path = "../block-io-wrapper" } common = { path = "../common" } diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml index 18ff6d994a..8830c189f8 100644 --- a/alxd/Cargo.toml +++ b/alxd/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.3" +redox_syscall = "0.4" redox-daemon = "0.1" common = { path = "../common" } diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml index b5ff6b4d6b..6ae79cdb86 100644 --- a/bgad/Cargo.toml +++ b/bgad/Cargo.toml @@ -6,4 +6,4 @@ edition = "2018" [dependencies] orbclient = "0.3.27" redox-daemon = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" diff --git a/common/Cargo.toml b/common/Cargo.toml index 7313a2eb95..02b611d345 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -8,4 +8,4 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -redox_syscall = "0.3" +redox_syscall = "0.4" diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index d88390e33f..bc1bc8b47e 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -8,6 +8,6 @@ bitflags = "1" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.3" +redox_syscall = "0.4" common = { path = "../common" } diff --git a/ided/Cargo.toml b/ided/Cargo.toml index e1dc341aae..6e4a036981 100644 --- a/ided/Cargo.toml +++ b/ided/Cargo.toml @@ -11,4 +11,4 @@ partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } pcid = { path = "../pcid" } redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" diff --git a/ihdad/Cargo.toml b/ihdad/Cargo.toml index 084efca393..799e0aadb8 100755 --- a/ihdad/Cargo.toml +++ b/ihdad/Cargo.toml @@ -9,7 +9,7 @@ log = "0.4" redox-daemon = "0.1" redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.3" +redox_syscall = "0.4" spin = "0.9" common = { path = "../common" } diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index 78057535f6..e88ab86f9e 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -9,6 +9,6 @@ anyhow = "1.0.71" log = "0.4.19" redox-daemon = "0.1.0" redox-log = "0.1.1" -redox_syscall = "0.3.5" +redox_syscall = "0.4" orbclient = "0.3.27" spin = "0.9.8" diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml index e2730ccd04..94d0af3ed1 100644 --- a/ixgbed/Cargo.toml +++ b/ixgbed/Cargo.toml @@ -6,7 +6,7 @@ version = "1.0.0" bitflags = "1.0" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.3" +redox_syscall = "0.4" redox-daemon = "0.1" common = { path = "../common" } diff --git a/lived/Cargo.toml b/lived/Cargo.toml index 0621101e24..cea304209c 100644 --- a/lived/Cargo.toml +++ b/lived/Cargo.toml @@ -10,5 +10,5 @@ license = "MIT" [dependencies] anyhow = "1" redox-daemon = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" slab = "0.4" diff --git a/nvmed/Cargo.toml b/nvmed/Cargo.toml index 039cdeac61..b18436d927 100644 --- a/nvmed/Cargo.toml +++ b/nvmed/Cargo.toml @@ -11,7 +11,7 @@ futures = "0.3" log = "0.4" redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } smallvec = "1" diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 1226f32d9d..f77bb23486 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -20,7 +20,7 @@ log = "0.4" paw = "1.0" plain = "0.2" redox-log = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = "1" diff --git a/pcspkrd/Cargo.toml b/pcspkrd/Cargo.toml index 7d2adf41d6..8f355d4e53 100644 --- a/pcspkrd/Cargo.toml +++ b/pcspkrd/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Tibor Nagy "] edition = "2018" [dependencies] -redox_syscall = "0.3" +redox_syscall = "0.4" redox-daemon = "0.1" diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index ce05723671..cfab793a52 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -6,5 +6,5 @@ edition = "2018" [dependencies] bitflags = "1" orbclient = "0.3.27" -redox_syscall = "0.3" +redox_syscall = "0.4" redox-daemon = "0.1" diff --git a/rtl8139d/Cargo.toml b/rtl8139d/Cargo.toml index 251cde405b..ff88b0e2dd 100644 --- a/rtl8139d/Cargo.toml +++ b/rtl8139d/Cargo.toml @@ -8,7 +8,7 @@ bitflags = "1" log = "0.4" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.3" +redox_syscall = "0.4" redox-daemon = "0.1" redox-log = "0.1" diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index e3f25601c4..d3cd6495f9 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -8,7 +8,7 @@ bitflags = "1" log = "0.4" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.3" +redox_syscall = "0.4" redox-daemon = "0.1" redox-log = "0.1" diff --git a/sb16d/Cargo.toml b/sb16d/Cargo.toml index daa3b7659a..fc49b61b26 100644 --- a/sb16d/Cargo.toml +++ b/sb16d/Cargo.toml @@ -10,5 +10,5 @@ log = "0.4" redox-daemon = "0.1" redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.3" +redox_syscall = "0.4" spin = "0.9" diff --git a/usbhidd/Cargo.toml b/usbhidd/Cargo.toml index 77b9adfdb5..8c51c019cd 100644 --- a/usbhidd/Cargo.toml +++ b/usbhidd/Cargo.toml @@ -12,6 +12,6 @@ bitflags = "1.2" log = "0.4" orbclient = "0.3.27" redox-log = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" ux = "0.1" xhcid = { path = "../xhcid" } diff --git a/usbscsid/Cargo.toml b/usbscsid/Cargo.toml index a1ed05126f..f014a19fd2 100644 --- a/usbscsid/Cargo.toml +++ b/usbscsid/Cargo.toml @@ -11,6 +11,6 @@ license = "MIT" base64 = "0.11" # Only for debugging plain = "0.2" redox-daemon = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" thiserror = "1" xhcid = { path = "../xhcid" } diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index bae4b35c82..b27804da77 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] orbclient = "0.3.27" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.3" +redox_syscall = "0.4" redox-daemon = "0.1" common = { path = "../common" } diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index 617aeb6787..e3880f63db 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" orbclient = "0.3.27" ransid = "0.4" rusttype = { version = "0.2", optional = true } -redox_syscall = "0.3" +redox_syscall = "0.4" redox-daemon = "0.1" common = { path = "../common" } diff --git a/virtio-blkd/Cargo.toml b/virtio-blkd/Cargo.toml index 3f0f969ea6..5f6ab31295 100644 --- a/virtio-blkd/Cargo.toml +++ b/virtio-blkd/Cargo.toml @@ -14,7 +14,7 @@ spin = "*" redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } block-io-wrapper = { path = "../block-io-wrapper" } diff --git a/virtio-core/Cargo.toml b/virtio-core/Cargo.toml index c060fabe78..8824169676 100644 --- a/virtio-core/Cargo.toml +++ b/virtio-core/Cargo.toml @@ -7,7 +7,7 @@ authors = ["Anhad Singh "] [dependencies] static_assertions = "1.1.0" bitflags = "2.3.2" -redox_syscall = "0.3" +redox_syscall = "0.4" log = "0.4" thiserror = "1.0.40" futures = { version = "0.3.28", features = ["executor"] } diff --git a/virtio-gpud/Cargo.toml b/virtio-gpud/Cargo.toml index 8979a09873..41fd2a69b5 100644 --- a/virtio-gpud/Cargo.toml +++ b/virtio-gpud/Cargo.toml @@ -17,6 +17,6 @@ pcid = { path = "../pcid" } inputd = { path = "../inputd" } redox-daemon = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" orbclient = "0.3.27" spin = "0.9.8" diff --git a/virtio-netd/Cargo.toml b/virtio-netd/Cargo.toml index bb54b293fd..cf5d40fe74 100644 --- a/virtio-netd/Cargo.toml +++ b/virtio-netd/Cargo.toml @@ -13,5 +13,5 @@ pcid = { path = "../pcid" } common = { path = "../common" } redox-daemon = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index db53e8ed36..7fa83821b5 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -22,7 +22,7 @@ log = "0.4" redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox-log = "0.1" -redox_syscall = "0.3" +redox_syscall = "0.4" serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1", features = ["serde"] } From 9193d4361a5ec0042cc36956908054e402f6d669 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 7 Sep 2023 20:54:53 -0600 Subject: [PATCH 0704/1301] Update redox_event --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ab3b5df1d..92ae3f2d14 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1115,9 +1115,9 @@ dependencies = [ [[package]] name = "redox_event" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/event.git#f7db3d25ca5e282c12ded12bf6c720087b570132" +source = "git+https://gitlab.redox-os.org/redox-os/event.git#3f9ca18968d2c2d0f9ea819983d666f8b24eacf1" dependencies = [ - "redox_syscall 0.3.5", + "redox_syscall 0.4.0", ] [[package]] From 051532e516970a8c69962997e1b36821ff9762df Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 8 Sep 2023 09:20:41 -0600 Subject: [PATCH 0705/1301] Do not use git redox_syscall --- Cargo.lock | 3 ++- Cargo.toml | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 92ae3f2d14..d2a1dc5dee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1141,7 +1141,8 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.4.0" -source = "git+https://gitlab.redox-os.org/redox-os/syscall.git#1bef275ffcc50c825214f5a349aa94932efb342c" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded0bce2d41cc3c57aefa284708ced249a64acb01745dbbe72bd78610bfd644c" dependencies = [ "bitflags 1.3.2", ] diff --git a/Cargo.toml b/Cargo.toml index 229e7724ab..a1eba0a22b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,4 +40,3 @@ lto = "fat" mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } -redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git" } From a271e455a64a9eb70290425fedcc70713529ab40 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 8 Sep 2023 11:16:15 -0600 Subject: [PATCH 0706/1301] Update redox_syscall --- Cargo.lock | 62 +++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d2a1dc5dee..ce0e684304 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,7 +12,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "spin", ] @@ -30,7 +30,7 @@ dependencies = [ "plain", "redox-daemon", "redox-log", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "rustc-hash", "serde_json", "thiserror", @@ -48,7 +48,7 @@ dependencies = [ "partitionlib", "redox-daemon", "redox-log", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -60,7 +60,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -164,7 +164,7 @@ version = "0.1.0" dependencies = [ "orbclient", "redox-daemon", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -292,7 +292,7 @@ dependencies = [ name = "common" version = "0.1.0" dependencies = [ - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -375,7 +375,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -566,7 +566,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -591,7 +591,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "spin", ] @@ -614,7 +614,7 @@ dependencies = [ "orbclient", "redox-daemon", "redox-log", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "spin", ] @@ -642,7 +642,7 @@ dependencies = [ "netutils", "redox-daemon", "redox_event", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -678,7 +678,7 @@ version = "0.1.0" dependencies = [ "anyhow", "redox-daemon", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "slab", ] @@ -800,7 +800,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "smallvec 1.11.0", ] @@ -944,7 +944,7 @@ dependencies = [ "paw", "plain", "redox-log", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "serde", "serde_json", "smallvec 1.11.0", @@ -958,7 +958,7 @@ name = "pcspkrd" version = "0.1.0" dependencies = [ "redox-daemon", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -1025,7 +1025,7 @@ dependencies = [ "bitflags 1.3.2", "orbclient", "redox-daemon", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -1117,7 +1117,7 @@ name = "redox_event" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/event.git#3f9ca18968d2c2d0f9ea819983d666f8b24eacf1" dependencies = [ - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -1140,9 +1140,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded0bce2d41cc3c57aefa284708ced249a64acb01745dbbe72bd78610bfd644c" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] @@ -1168,7 +1168,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -1183,7 +1183,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -1219,7 +1219,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "spin", ] @@ -1616,7 +1616,7 @@ dependencies = [ "log", "orbclient", "redox-log", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "ux", "xhcid", ] @@ -1628,7 +1628,7 @@ dependencies = [ "base64", "plain", "redox-daemon", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "thiserror", "xhcid", ] @@ -1662,7 +1662,7 @@ dependencies = [ "orbclient", "redox-daemon", "redox_event", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", ] [[package]] @@ -1692,7 +1692,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "rusttype", ] @@ -1709,7 +1709,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "spin", "static_assertions", "thiserror", @@ -1728,7 +1728,7 @@ dependencies = [ "pcid", "redox-log", "redox_event", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "static_assertions", "thiserror", ] @@ -1746,7 +1746,7 @@ dependencies = [ "paste", "pcid", "redox-daemon", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "spin", "static_assertions", "virtio-core", @@ -1762,7 +1762,7 @@ dependencies = [ "netutils", "pcid", "redox-daemon", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "static_assertions", "virtio-core", ] @@ -1964,7 +1964,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.4.0", + "redox_syscall 0.4.1", "serde", "serde_json", "smallvec 1.11.0", From 15e523c8ebb44d414d29e82564eee2ce98cd2a95 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 9 Sep 2023 11:19:17 -0600 Subject: [PATCH 0707/1301] alxd,ihdad,rtl8168d: support MMIO on 32-bit systems --- alxd/src/device/mod.rs | 9 ++++++--- alxd/src/main.rs | 2 +- ihdad/src/hda/cmdbuff.rs | 4 ++++ ihdad/src/hda/device.rs | 4 ++-- ihdad/src/hda/stream.rs | 13 ++++++++----- rtl8168d/src/device.rs | 15 ++++++++++----- 6 files changed, 31 insertions(+), 16 deletions(-) diff --git a/alxd/src/device/mod.rs b/alxd/src/device/mod.rs index 26395be10a..04da35d59e 100644 --- a/alxd/src/device/mod.rs +++ b/alxd/src/device/mod.rs @@ -213,13 +213,15 @@ struct Tpd { blen: Mmio, vlan: Mmio, flags: Mmio, - addr: Mmio, + addr_low: Mmio, + addr_high: Mmio, } /// Receive free descriptor #[repr(packed)] struct Rfd { - addr: Mmio, + addr_low: Mmio, + addr_high: Mmio, } /// Receive return descriptor @@ -1529,7 +1531,8 @@ impl Alx { // RFD ring for i in 0..self.rfd_ring.len() { - self.rfd_ring[i].addr.write(self.rfd_buffer[i].physical() as u64); + self.rfd_ring[i].addr_low.write(self.rfd_buffer[i].physical() as u32); + self.rfd_ring[i].addr_high.write(((self.rfd_buffer[i].physical() as u64) >> 32) as u32); } self.write(RFD_ADDR_LO, self.rfd_ring.physical() as u32); self.write(RFD_RING_SZ, self.rfd_ring.len() as u32); diff --git a/alxd/src/main.rs b/alxd/src/main.rs index 4de3005c6e..d52371f94a 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -112,7 +112,7 @@ fn main() { for event_count in event_queue.trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: EventFlags::empty(), }).expect("alxd: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, diff --git a/ihdad/src/hda/cmdbuff.rs b/ihdad/src/hda/cmdbuff.rs index 36ee9f2237..a401a1053a 100644 --- a/ihdad/src/hda/cmdbuff.rs +++ b/ihdad/src/hda/cmdbuff.rs @@ -73,6 +73,7 @@ struct Corb { impl Corb { pub fn new(regs_addr: usize, corb_buff_phys: usize, corb_buff_virt: usize) -> Corb { + println!("regs addr {:x}", regs_addr); unsafe { Corb { regs: &mut *(regs_addr as *mut CorbRegs), @@ -84,7 +85,9 @@ impl Corb { } //Intel 4.4.1.3 pub fn init(&mut self) { + println!("{}:{}", file!(), line!()); self.stop(); + println!("{}:{}", file!(), line!()); //Determine CORB and RIRB size and allocate buffer //3.3.24 @@ -122,6 +125,7 @@ impl Corb { self.regs.corbctl.writef(CORBRUN, true); } + #[inline(never)] pub fn stop(&mut self) { while self.regs.corbctl.readf(CORBRUN) { self.regs.corbctl.write(0); diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 9778ba1b09..718ab6ed73 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -459,7 +459,7 @@ impl IntelHDA { let o = self.output_streams.get_mut(0).unwrap(); for i in 0..NUM_SUB_BUFFS { - self.buff_desc[i].set_address(o.phys() + o.block_size() * i); + self.buff_desc[i].set_address((o.phys() + o.block_size() * i) as u64); self.buff_desc[i].set_length(o.block_size() as u32); self.buff_desc[i].set_interrupt_on_complete(true); } @@ -741,7 +741,7 @@ impl IntelHDA { } } - fn set_dma_position_buff_addr(&mut self, addr: usize) { + fn set_dma_position_buff_addr(&mut self, addr: u64) { let addr_val = addr & !0x7F; self.regs.dplbase.write((addr_val & 0xFFFFFFFF) as u32); self.regs.dpubase.write((addr_val >> 32) as u32); diff --git a/ihdad/src/hda/stream.rs b/ihdad/src/hda/stream.rs index 3f1e383419..62acd2c6d5 100644 --- a/ihdad/src/hda/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -246,18 +246,21 @@ impl OutputStream { #[repr(packed)] pub struct BufferDescriptorListEntry { - addr: Mmio, + addr_low: Mmio, + addr_high: Mmio, len: Mmio, ioc_resv: Mmio, } impl BufferDescriptorListEntry { - pub fn address(&self) -> usize { - self.addr.read() as usize + pub fn address(&self) -> u64 { + (self.addr_low.read() as u64) | + ((self.addr_high.read() as u64) << 32) } - pub fn set_address(&mut self, addr:usize) { - self.addr.write(addr as u64); + pub fn set_address(&mut self, addr: u64) { + self.addr_low.write(addr as u32); + self.addr_high.write((addr >> 32) as u32); } pub fn length(&self) -> u32 { diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index a32a5199ee..c3663b8b76 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -61,14 +61,16 @@ const LS: u32 = 1 << 28; struct Rd { ctrl: Mmio, _vlan: Mmio, - buffer: Mmio + buffer_low: Mmio, + buffer_high: Mmio, } #[repr(packed)] struct Td { ctrl: Mmio, _vlan: Mmio, - buffer: Mmio + buffer_low: Mmio, + buffer_high: Mmio, } pub struct Rtl8168 { @@ -299,7 +301,8 @@ impl Rtl8168 { for i in 0..self.receive_ring.len() { let rd = &mut self.receive_ring[i]; let data = &mut self.receive_buffer[i]; - rd.buffer.write(data.physical() as u64); + rd.buffer_low.write(data.physical() as u32); + rd.buffer_high.write((data.physical() as u64 >> 32) as u32); rd.ctrl.write(OWN | data.len() as u32); } if let Some(rd) = self.receive_ring.last_mut() { @@ -309,7 +312,8 @@ impl Rtl8168 { // Set up normal priority tx buffers println!(" - Transmit buffers (normal priority)"); for i in 0..self.transmit_ring.len() { - self.transmit_ring[i].buffer.write(self.transmit_buffer[i].physical() as u64); + self.transmit_ring[i].buffer_low.write(self.transmit_buffer[i].physical() as u32); + self.transmit_ring[i].buffer_high.write((self.transmit_buffer[i].physical() as u64 >> 32) as u32); } if let Some(td) = self.transmit_ring.last_mut() { td.ctrl.writef(EOR, true); @@ -318,7 +322,8 @@ impl Rtl8168 { // Set up high priority tx buffers println!(" - Transmit buffers (high priority)"); for i in 0..self.transmit_ring_h.len() { - self.transmit_ring_h[i].buffer.write(self.transmit_buffer_h[i].physical() as u64); + self.transmit_ring_h[i].buffer_low.write(self.transmit_buffer_h[i].physical() as u32); + self.transmit_ring_h[i].buffer_high.write((self.transmit_buffer_h[i].physical() as u64 >> 32) as u32); } if let Some(td) = self.transmit_ring_h.last_mut() { td.ctrl.writef(EOR, true); From 676b1cda6771898a4eda4cee3ec9cdf3225f7dd5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 9 Sep 2023 12:05:42 -0600 Subject: [PATCH 0708/1301] xhcid: support MMIO on 32-bit systems --- xhcid/src/xhci/context.rs | 6 ++++-- xhcid/src/xhci/event.rs | 6 ++++-- xhcid/src/xhci/irq_reactor.rs | 3 ++- xhcid/src/xhci/mod.rs | 16 ++++++++++------ xhcid/src/xhci/operational.rs | 6 ++++-- xhcid/src/xhci/runtime.rs | 6 ++++-- xhcid/src/xhci/scheme.rs | 6 +++--- xhcid/src/xhci/trb.rs | 24 ++++++++++++++++-------- 8 files changed, 47 insertions(+), 26 deletions(-) diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index d0fa24174a..4656a826fb 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -166,11 +166,13 @@ impl StreamContextArray { #[repr(packed)] pub struct ScratchpadBufferEntry { - pub value: Mmio, + pub value_low: Mmio, + pub value_high: Mmio, } impl ScratchpadBufferEntry { pub fn set_addr(&mut self, addr: u64) { - self.value.write(addr); + self.value_low.write(addr as u32); + self.value_high.write((addr >> 32) as u32); } } diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index 329afc0ed3..b42a126ae7 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -9,7 +9,8 @@ use super::trb::Trb; #[repr(packed)] pub struct EventRingSte { - pub address: Mmio, + pub address_low: Mmio, + pub address_high: Mmio, pub size: Mmio, _rsvd: Mmio, _rsvd2: Mmio, @@ -28,7 +29,8 @@ impl EventRing { ring: Ring::new(ac64, 256, false)?, }; - ring.ste[0].address.write(ring.ring.trbs.physical() as u64); + ring.ste[0].address_low.write(ring.ring.trbs.physical() as u32); + ring.ste[0].address_high.write((ring.ring.trbs.physical() as u64 >> 32) as u32); ring.ste[0].size.write(ring.ring.trbs.len() as u16); Ok(ring) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 602cce288f..215832ff9f 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -209,7 +209,8 @@ impl IrqReactor { trace!("Updated ERDP to {:#0x}", dequeue_pointer); - self.hci.run.lock().unwrap().ints[0].erdp.write(dequeue_pointer); + self.hci.run.lock().unwrap().ints[0].erdp_low.write(dequeue_pointer as u32); + self.hci.run.lock().unwrap().ints[0].erdp_high.write((dequeue_pointer >> 32) as u32); } fn handle_requests(&mut self) { self.states.extend(self.receiver.try_iter().inspect(|req| trace!("Received request: {:X?}", req))); diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index aa371007d7..99efcbd2e5 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -367,13 +367,15 @@ impl Xhci { // Set device context address array pointer let dcbaap = self.dev_ctx.dcbaap(); debug!("Writing DCBAAP: {:X}", dcbaap); - self.op.get_mut().unwrap().dcbaap.write(dcbaap as u64); + self.op.get_mut().unwrap().dcbaap_low.write(dcbaap as u32); + self.op.get_mut().unwrap().dcbaap_high.write((dcbaap as u64 >> 32) as u32); // Set command ring control register let crcr = self.cmd.get_mut().unwrap().register(); assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR"); debug!("Writing CRCR: {:X}", crcr); - self.op.get_mut().unwrap().crcr.write(crcr as u64); + self.op.get_mut().unwrap().crcr_low.write(crcr as u32); + self.op.get_mut().unwrap().crcr_high.write((crcr as u64 >> 32) as u32); // Set event ring segment table registers debug!("Interrupter 0: {:p}", self.run.get_mut().unwrap().ints.as_ptr()); @@ -386,11 +388,13 @@ impl Xhci { let erdp = self.primary_event_ring.get_mut().unwrap().erdp(); debug!("Writing ERDP: {:X}", erdp); - int.erdp.write(erdp as u64 | (1 << 3)); + int.erdp_low.write(erdp as u32 | (1 << 3)); + int.erdp_high.write((erdp as u64 >> 32) as u32); let erstba = self.primary_event_ring.get_mut().unwrap().erstba(); debug!("Writing ERSTBA: {:X}", erstba); - int.erstba.write(erstba as u64); + int.erstba_low.write(erstba as u32); + int.erstba_high.write((erstba as u64 >> 32) as u32); debug!("Writing IMODC and IMODI: {} and {}", 0, 0); int.imod.write(0); @@ -749,10 +753,10 @@ impl Xhci { if self.uses_msi() || self.uses_msix() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. - trace!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); + trace!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp_low.readf(3)); true } else if runtime_regs.ints[0].iman.readf(1) { - trace!("Successfully received INTx# interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp.readf(3)); + trace!("Successfully received INTx# interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp_low.readf(3)); // If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is // a special register to specify whether the IRQ actually came from the xHC. runtime_regs.ints[0].iman.writef(1, true); diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index 0d4af23901..855de69808 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -11,9 +11,11 @@ pub struct OperationalRegs { pub page_size: Mmio, _rsvd: [Mmio; 2], pub dn_ctrl: Mmio, - pub crcr: Mmio, + pub crcr_low: Mmio, + pub crcr_high: Mmio, _rsvd2: [Mmio; 4], - pub dcbaap: Mmio, + pub dcbaap_low: Mmio, + pub dcbaap_high: Mmio, pub config: Mmio, } diff --git a/xhcid/src/xhci/runtime.rs b/xhcid/src/xhci/runtime.rs index 4dc4663ea4..b18fb482e9 100644 --- a/xhcid/src/xhci/runtime.rs +++ b/xhcid/src/xhci/runtime.rs @@ -6,8 +6,10 @@ pub struct Interrupter { pub imod: Mmio, pub erstsz: Mmio, _rsvd: Mmio, - pub erstba: Mmio, - pub erdp: Mmio, + pub erstba_low: Mmio, + pub erstba_high: Mmio, + pub erdp_low: Mmio, + pub erdp_high: Mmio, } #[repr(packed)] diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 71e1610cf7..9af57334ef 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -259,8 +259,8 @@ impl Xhci { //TODO: find out why this bit is set earlier! let mut run = self.run.lock().unwrap(); let mut int = &mut run.ints[0]; - if int.erdp.readf(1 << 3) { - int.erdp.writef(1 << 3, true); + if int.erdp_low.readf(1 << 3) { + int.erdp_low.writef(1 << 3, true); } } @@ -2110,7 +2110,7 @@ impl Xhci { pub fn event_handler_finished(&self) { trace!("Event handler finished"); // write 1 to EHB to clear it - self.run.lock().unwrap().ints[0].erdp.writef(1 << 3, true); + self.run.lock().unwrap().ints[0].erdp_low.writef(1 << 3, true); } } pub fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()> { diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 66d30437be..8d71f8b81e 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -110,14 +110,16 @@ pub enum TransferKind { #[repr(packed)] pub struct Trb { - pub data: Mmio, + pub data_low: Mmio, + pub data_high: Mmio, pub status: Mmio, pub control: Mmio, } impl Clone for Trb { fn clone(&self) -> Self { Self { - data: Mmio::from(self.data.read()), + data_low: Mmio::from(self.data_low.read()), + data_high: Mmio::from(self.data_high.read()), status: Mmio::from(self.status.read()), control: Mmio::from(self.control.read()), } @@ -144,7 +146,8 @@ pub const TRB_CONTROL_ENDPOINT_ID_SHIFT: u8 = 16; impl Trb { pub fn set(&mut self, data: u64, status: u32, control: u32) { - self.data.write(data); + self.data_low.write(data as u32); + self.data_high.write((data >> 32) as u32); self.status.write(status); self.control.write(control); } @@ -153,6 +156,11 @@ impl Trb { self.set(0, 0, ((TrbType::Reserved as u32) << 10) | (cycle as u32)); } + pub fn read_data(&self) -> u64 { + (self.data_low.read() as u64) | + ((self.data_high.read() as u64) << 32) + } + pub fn completion_code(&self) -> u8 { (self.status.read() >> TRB_STATUS_COMPLETION_CODE_SHIFT) as u8 } @@ -172,7 +180,7 @@ impl Trb { debug_assert_eq!(self.trb_type(), TrbType::CommandCompletion as u8); if self.has_completion_trb_pointer() { - Some(self.data.read()) + Some(self.read_data()) } else { None } @@ -181,7 +189,7 @@ impl Trb { debug_assert_eq!(self.trb_type(), TrbType::Transfer as u8); if self.has_completion_trb_pointer() { - Some(self.data.read()) + Some(self.read_data()) } else { None } @@ -199,7 +207,7 @@ impl Trb { } pub fn event_data(&self) -> Option { if self.event_data_bit() { - Some(self.data.read()) + Some(self.read_data()) } else { None } @@ -459,7 +467,7 @@ impl fmt::Debug for Trb { write!( f, "Trb {{ data: {:>016X}, status: {:>08X}, control: {:>08X} }}", - self.data.read(), + self.read_data(), self.status.read(), self.control.read() ) @@ -471,7 +479,7 @@ impl fmt::Display for Trb { write!( f, "({:>016X}, {:>08X}, {:>08X})", - self.data.read(), + self.read_data(), self.status.read(), self.control.read() ) From f228483f1f07e0583a00c62675fddeed05972aa8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 9 Sep 2023 12:15:07 -0600 Subject: [PATCH 0709/1301] ahcid, nvmed: support MMIO on 32-bit systems --- ahcid/src/ahci/fis.rs | 4 +++- ahcid/src/ahci/hba.rs | 18 ++++++++++++------ nvmed/src/nvme/mod.rs | 20 +++++++++++++------- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/ahcid/src/ahci/fis.rs b/ahcid/src/ahci/fis.rs index e91e4229e2..1d4013ae88 100644 --- a/ahcid/src/ahci/fis.rs +++ b/ahcid/src/ahci/fis.rs @@ -139,7 +139,9 @@ pub struct FisDmaSetup { pub rsv1: [Mmio; 2], // Reserved // DWORD 1&2 - pub dma_buffer_id: Mmio, /* DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work. */ + /* DMA Buffer Identifier. Used to Identify DMA buffer in host memory. SATA Spec says host specific and not in Spec. Trying AHCI spec might work. */ + pub dma_buffer_id_low: Mmio, + pub dma_buffer_id_high: Mmio, // DWORD 3 pub rsv3: Mmio, // More reserved diff --git a/ahcid/src/ahci/hba.rs b/ahcid/src/ahci/hba.rs index 6f9217aa05..a11f2a1425 100644 --- a/ahcid/src/ahci/hba.rs +++ b/ahcid/src/ahci/hba.rs @@ -109,7 +109,8 @@ impl HbaPort { for i in 0..32 { let cmdheader = &mut clb[i]; - cmdheader.ctba.write(ctbas[i].physical() as u64); + cmdheader.ctba_low.write(ctbas[i].physical() as u32); + cmdheader.ctba_high.write((ctbas[i].physical() as u64 >> 32) as u32); cmdheader.prdtl.write(0); } @@ -149,7 +150,8 @@ impl HbaPort { cmdheader.prdtl.write(1); let prdt_entry = &mut prdt_entries[0]; - prdt_entry.dba.write(dest.physical() as u64); + prdt_entry.dba_low.write(dest.physical() as u32); + prdt_entry.dba_high.write((dest.physical() as u64 >> 32) as u32); prdt_entry.dbc.write(512 | 1); cmdfis.pm.write(1 << 7); @@ -234,7 +236,8 @@ impl HbaPort { cmdheader.prdtl.write(1); let prdt_entry = &mut prdt_entries[0]; - prdt_entry.dba.write(buf.physical() as u64); + prdt_entry.dba_low.write(buf.physical() as u32); + prdt_entry.dba_high.write((buf.physical() as u64 >> 32) as u32); prdt_entry.dbc.write(((sectors * 512) as u32) | 1); cmdfis.pm.write(1 << 7); @@ -268,7 +271,8 @@ impl HbaPort { cmdheader.prdtl.write(1); let prdt_entry = &mut prdt_entries[0]; - prdt_entry.dba.write(buf.physical() as u64); + prdt_entry.dba_low.write(buf.physical() as u32); + prdt_entry.dba_high.write((buf.physical() as u64 >> 32) as u32); prdt_entry.dbc.write(size - 1); cmdfis.pm.write(1 << 7); @@ -392,7 +396,8 @@ impl HbaMem { #[repr(packed)] pub struct HbaPrdtEntry { - dba: Mmio, // Data base address + dba_low: Mmio, // Data base address (low + dba_high: Mmio, // Data base address (high) _rsv0: Mmio, // Reserved dbc: Mmio, // Byte count, 4M max, interrupt = 1 } @@ -424,7 +429,8 @@ pub struct HbaCmdHeader { _prdbc: Mmio, // Physical region descriptor byte count transferred // DW2, 3 - ctba: Mmio, // Command table descriptor base address + ctba_low: Mmio, // Command table descriptor base address (low) + ctba_high: Mmio, // Command table descriptor base address (high) // DW4 - 7 _rsv1: [Mmio; 4], // Reserved diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 7e34801af2..1b368c521d 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -128,7 +128,8 @@ pub struct MsixCfg { #[repr(packed)] pub struct NvmeRegs { /// Controller Capabilities - cap: Mmio, + cap_low: Mmio, + cap_high: Mmio, /// Version vs: Mmio, /// Interrupt mask set @@ -146,9 +147,11 @@ pub struct NvmeRegs { /// Admin queue attributes aqa: Mmio, /// Admin submission queue base address - asq: Mmio, + asq_low: Mmio, + asq_high: Mmio, /// Admin completion queue base address - acq: Mmio, + acq_low: Mmio, + acq_high: Mmio, /// Controller memory buffer location cmbloc: Mmio, /// Controller memory buffer size @@ -242,7 +245,7 @@ impl Nvme { let mut regs_guard = self.regs.write().unwrap(); let mut regs: &mut NvmeRegs = regs_guard.deref_mut(); - let dstrd = ((regs.cap.read() >> 32) & 0b1111) as usize; + let dstrd = (regs.cap_high.read() & 0b1111) as usize; let addr = (regs as *mut NvmeRegs as usize) + 0x1000 + index * (4 << dstrd); (&mut *(addr as *mut Mmio)).write(value); } @@ -265,7 +268,8 @@ impl Nvme { { let regs = self.regs.read().unwrap(); - log::debug!("CAPS: {:X}", regs.cap.read()); + log::debug!("CAP_LOW: {:X}", regs.cap_low.read()); + log::debug!("CAP_HIGH: {:X}", regs.cap_high.read()); log::debug!("VS: {:X}", regs.vs.read()); log::debug!("CC: {:X}", regs.cc.read()); log::debug!("CSTS: {:X}", regs.csts.read()); @@ -315,8 +319,10 @@ impl Nvme { let (acq, _) = completion_queues.get_mut(&0).unwrap().get_mut().unwrap(); regs.aqa .write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1)); - regs.asq.write(asq.data.physical() as u64); - regs.acq.write(acq.data.physical() as u64); + regs.asq_low.write(asq.data.physical() as u32); + regs.asq_high.write((asq.data.physical() as u64 >> 32) as u32); + regs.acq_low.write(acq.data.physical() as u32); + regs.acq_high.write((acq.data.physical() as u64 >> 32) as u32); // Set IOCQES, IOSQES, AMS, MPS, and CSS let mut cc = regs.cc.read(); From ad9295715f61765288ee1ccbe469eebbc97defbb Mon Sep 17 00:00:00 2001 From: Enver Balalic Date: Thu, 19 Oct 2023 15:01:01 +0000 Subject: [PATCH 0710/1301] virtio-core: move things around so aarch64 builds --- virtio-core/src/arch/aarch64.rs | 16 +++ virtio-core/src/arch/x86.rs | 10 ++ virtio-core/src/arch/x86_64.rs | 137 +++++++++++++++++++ virtio-core/src/legacy_transport.rs | 191 +++++++++++++++++++++++++++ virtio-core/src/lib.rs | 16 +++ virtio-core/src/probe.rs | 131 +------------------ virtio-core/src/transport.rs | 195 +--------------------------- 7 files changed, 383 insertions(+), 313 deletions(-) create mode 100644 virtio-core/src/arch/aarch64.rs create mode 100644 virtio-core/src/arch/x86.rs create mode 100644 virtio-core/src/arch/x86_64.rs create mode 100644 virtio-core/src/legacy_transport.rs diff --git a/virtio-core/src/arch/aarch64.rs b/virtio-core/src/arch/aarch64.rs new file mode 100644 index 0000000000..e8f340580a --- /dev/null +++ b/virtio-core/src/arch/aarch64.rs @@ -0,0 +1,16 @@ +use std::fs::File; + +use pcid_interface::*; + +use crate::{transport::Error, Device}; + +pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { + unimplemented!("virtio_core: aarch64 enable_msix") +} + +pub fn probe_legacy_port_transport<'a>( + pci_header: &PciHeader, + pcid_handle: &mut PcidServerHandle, +) -> Result, Error> { + panic!("virtio-core: aarch64 doesn't support legacy port I/O") +} \ No newline at end of file diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs new file mode 100644 index 0000000000..9806acea4f --- /dev/null +++ b/virtio-core/src/arch/x86.rs @@ -0,0 +1,10 @@ +pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { + panic!("virtio-core: x86 doesn't support enable_msix") +} + +pub fn probe_legacy_port_transport<'a>( + pci_header: &PciHeader, + pcid_handle: &mut PcidServerHandle, +) -> Result, Error> { + crate::x86_64::probe_legacy_port_transport(pci_header, pcid_handle) +} \ No newline at end of file diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs new file mode 100644 index 0000000000..1909c20aec --- /dev/null +++ b/virtio-core/src/arch/x86_64.rs @@ -0,0 +1,137 @@ +use crate::{ + reinit, + transport::{Error}, + utils::VolatileCell, + Device, legacy_transport::LegacyTransport, +}; + +use pcid_interface::msi::{self, MsixTableEntry}; +use pcid_interface::irq_helpers::{allocate_single_interrupt_vector, read_bsp_apic_id}; +use std::{ptr::NonNull, fs::File}; + +use syscall::Io; + +use crate::{probe::MsixInfo, MSIX_PRIMARY_VECTOR}; + +use pcid_interface::*; + +pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { + + let pci_config = pcid_handle.fetch_config()?; + + // Extended message signaled interrupts. + let capability = match pcid_handle.feature_info(PciFeature::MsiX)? { + PciFeatureInfo::MsiX(capability) => capability, + _ => unreachable!(), + }; + + let table_size = capability.table_size(); + let table_base = capability.table_base_pointer(pci_config.func.bars); + let table_min_length = table_size * 16; + let pba_min_length = table_size.div_ceil(8); + + let pba_base = capability.pba_base_pointer(pci_config.func.bars); + + let bir = capability.table_bir() as usize; + let bar = pci_config.func.bars[bir]; + let bar_size = pci_config.func.bar_sizes[bir] as u64; + + let bar_ptr = match bar { + PciBar::Memory32(ptr) => ptr.into(), + PciBar::Memory64(ptr) => ptr, + _ => unreachable!(), + }; + + let address = unsafe { + common::physmap( + bar_ptr as usize, + bar_size as usize, + common::Prot::RW, + common::MemoryType::Uncacheable, + )? as usize + }; + + // Ensure that the table and PBA are be within the BAR. + { + let bar_range = bar_ptr..bar_ptr + bar_size; + assert!(bar_range.contains(&(table_base as u64 + table_min_length as u64))); + assert!(bar_range.contains(&(pba_base as u64 + pba_min_length as u64))); + } + + let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; + + let mut info = MsixInfo { + virt_table_base: NonNull::new(virt_table_base).unwrap(), + capability, + }; + + // Allocate the primary MSI vector. + let interrupt_handle = { + let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize); + + let destination_id = read_bsp_apic_id().expect("virtio_core: `read_bsp_apic_id()` failed"); + let lapic_id = u8::try_from(destination_id).unwrap(); + + let rh = false; + let dm = false; + let addr = msi::x86_64::message_address(lapic_id, rh, dm); + + let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id) + .unwrap() + .expect("virtio_core: interrupt vector exhaustion"); + + let msg_data = msi::x86_64::message_data_edge_triggered(msi::x86_64::DeliveryMode::Fixed, vector); + + table_entry_pointer.addr_lo.write(addr); + table_entry_pointer.addr_hi.write(0); + table_entry_pointer.msg_data.write(msg_data); + table_entry_pointer + .vec_ctl + .writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + + interrupt_handle + }; + + pcid_handle.enable_feature(PciFeature::MsiX)?; + + log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})"); + Ok(interrupt_handle) +} + +pub fn probe_legacy_port_transport<'a>( + pci_header: &PciHeader, + pcid_handle: &mut PcidServerHandle, +) -> Result, Error> { + if let PciBar::Port(port) = pci_header.get_bar(0) { + unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; + log::warn!("virtio: using legacy transport"); + + static SHIM: VolatileCell = VolatileCell::new(0); + + let transport = LegacyTransport::new(port); + + // Setup interrupts. + let all_pci_features = pcid_handle.fetch_all_features()?; + let has_msix = all_pci_features + .iter() + .any(|(feature, _)| feature.is_msix()); + + // According to the virtio specification, the device REQUIRED to support MSI-X. + assert!(has_msix, "virtio: device does not support MSI-X"); + let irq_handle = enable_msix(pcid_handle)?; + + let device = Device { + transport, + irq_handle, + isr: &SHIM, + device_space: core::ptr::null_mut(), + }; + + device.transport.reset(); + reinit(&device)?; + + Ok(device) + } else { + unreachable!("virtio: legacy transport with non-port IO?") + } +} diff --git a/virtio-core/src/legacy_transport.rs b/virtio-core/src/legacy_transport.rs new file mode 100644 index 0000000000..7769d597ac --- /dev/null +++ b/virtio-core/src/legacy_transport.rs @@ -0,0 +1,191 @@ +use std::{sync::{Weak, atomic::{AtomicU16, Ordering}, Arc}, mem::size_of, fs::File}; + +use common::dma::{PhysBox, Dma}; +use syscall::{Pio, Io}; + +use crate::{transport::{NotifyBell, Transport, Queue, Error, Available, Used, queue_part_sizes, spawn_irq_thread}, spec::{Descriptor, DeviceStatusFlags}}; + + +pub enum LegacyRegister { + DeviceFeatures = 0, // u32 + + QueueAddress = 8, // u32 + QueueSize = 12, // u16 + QueueSelect = 14, // u16 + QueueNotify = 16, // u16 + + DeviceStatus = 18, // u8 + + ConfigMsixVector = 20, // u16 + QueueMsixVector = 22, // u16 +} + +struct LegacyBell(Weak); + +impl NotifyBell for LegacyBell { + #[inline] + fn ring(&self, queue_index: u16) { + let transport = self.0.upgrade().expect("bell: transport dropped"); + transport.write::(LegacyRegister::QueueNotify, queue_index) + } +} + +pub struct LegacyTransport(u16, AtomicU16, Weak); + +impl LegacyTransport { + pub(super) fn new(port: u16) -> Arc { + Arc::new_cyclic(|sref| Self(port, AtomicU16::new(0), sref.clone())) + } + + unsafe fn read_raw(&self, offset: usize) -> V + where + V: Sized + TryFrom, + >::Error: std::fmt::Debug, + { + let port = self.0 + offset as u16; + + if size_of::() == size_of::() { + V::try_from(Pio::::new(port).read() as u64).unwrap() + } else if size_of::() == size_of::() { + V::try_from(Pio::::new(port).read() as u64).unwrap() + } else if size_of::() == size_of::() { + V::try_from(Pio::::new(port).read() as u64).unwrap() + } else if size_of::() == size_of::() { + let lower = Pio::::new(port).read() as u64; + let upper = Pio::::new(port + size_of::() as u16).read() as u64; + + V::try_from(lower | (upper << 32)).unwrap() + } else { + unreachable!() + } + } + + fn read(&self, register: LegacyRegister) -> V + where + V: Sized + TryFrom, + >::Error: std::fmt::Debug, + { + unsafe { self.read_raw(register as usize) } + } + + fn write(&self, register: LegacyRegister, value: V) + where + V: Sized + TryInto, + >::Error: std::fmt::Debug, + { + if size_of::() == size_of::() { + Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u8); + } else if size_of::() == size_of::() { + Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u16); + } else if size_of::() == size_of::() { + Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u32); + } else { + unreachable!() + } + } +} + +impl Transport for LegacyTransport { + fn reset(&self) { + self.write(LegacyRegister::DeviceStatus, 0u8); + + let status = self.read::(LegacyRegister::DeviceStatus); + assert_eq!(status, 0); + } + + fn check_device_feature(&self, feature: u32) -> bool { + assert!( + feature < 32, + "virtio: cannot query feature {feature} on a legacy device" + ); + self.read::(LegacyRegister::DeviceFeatures) & (1 << feature) == (1 << feature) + } + + fn ack_driver_feature(&self, feature: u32) { + assert!( + feature < 32, + "virtio: cannot ack feature {feature} on a legacy device" + ); + + let current = self.read::(LegacyRegister::DeviceFeatures); + self.write::(LegacyRegister::DeviceFeatures, current | (1 << feature)); + } + + fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result, Error> { + let queue_index = self.1.fetch_add(1, Ordering::SeqCst); + self.write(LegacyRegister::QueueSelect, queue_index); + + let queue_size = self.read::(LegacyRegister::QueueSize) as usize; + let (desc_size, avail_size, used_size) = queue_part_sizes(queue_size); + + let size_bytes = desc_size + avail_size + used_size; + let addr = unsafe { syscall::physalloc(size_bytes).map_err(Error::SyscallError)? }; + + let descriptor = unsafe { + let physbox = PhysBox::from_raw_parts(addr, desc_size); + let table = Dma::<[Descriptor]>::from_physbox_uninit_unsized(physbox, queue_size)?; + + table.assume_init() + }; + + let avail_addr = addr + desc_size; + let avail = unsafe { Available::from_raw(avail_addr, avail_size, queue_size)? }; + + let used_addr = avail_addr + avail_size; + let used = unsafe { Used::from_raw(used_addr, used_size, queue_size)? }; + + self.write::(LegacyRegister::QueueMsixVector, vector); + self.write::(LegacyRegister::QueueAddress, (addr as u32) >> 12); + + log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})"); + + let queue = Queue::new( + descriptor, + avail, + used, + LegacyBell(self.2.clone()), + queue_index, + vector, + ); + + spawn_irq_thread(irq_handle, &queue)?; + Ok(queue) + } + + fn load_config(&self, offset: u8, size: u8) -> u64 { + // We always enable MSI-X. So, the device configuration space offset will + // always be 0x18. + // + // Checkout 4.1.4.8 Legacy Interfaces: A Note on PCI Device Layout + const DEVICE_SPACE_OFFSET: usize = 0x18; + + let size = size as usize; + let offset = DEVICE_SPACE_OFFSET + offset as usize; + + unsafe { + if size == size_of::() { + self.read_raw::(offset) as u64 + } else if size == size_of::() { + self.read_raw::(offset) as u64 + } else if size == size_of::() { + self.read_raw::(offset) as u64 + } else if size == size_of::() { + self.read_raw::(offset) as u64 + } else { + unreachable!() + } + } + } + + fn insert_status(&self, status: DeviceStatusFlags) { + let old = self.read::(LegacyRegister::DeviceStatus); + self.write(LegacyRegister::DeviceStatus, old | status.bits()); + } + + fn reinit_queue(&self, _queue: Arc) { + todo!() + } + + // Legacy devices do not have the `FEATURES_OK` bit. + fn finalize_features(&self) {} +} diff --git a/virtio-core/src/lib.rs b/virtio-core/src/lib.rs index 87b737f124..c38a88ac3d 100644 --- a/virtio-core/src/lib.rs +++ b/virtio-core/src/lib.rs @@ -6,4 +6,20 @@ pub mod utils; mod probe; +#[cfg(target_arch = "aarch64")] +#[path="arch/aarch64.rs"] +mod arch; + +#[cfg(target_arch = "x86")] +#[path="arch/x86.rs"] +mod arch; + +#[cfg(target_arch = "x86_64")] +#[path="arch/x86_64.rs"] +mod arch; + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod legacy_transport; + + pub use probe::{probe_device, reinit, Device, MSIX_PRIMARY_VECTOR}; diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index a94d6f1925..1509187450 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -1,15 +1,12 @@ -use std::fs::File; + use std::ptr::NonNull; +use std::fs::File; use std::sync::Arc; - -use pcid_interface::irq_helpers::{allocate_single_interrupt_vector, read_bsp_apic_id}; -use pcid_interface::msi::{self, MsixCapability, MsixTableEntry}; use pcid_interface::*; - -use syscall::Io; +use pcid_interface::msi::{self, MsixTableEntry, MsixCapability}; use crate::spec::*; -use crate::transport::{Error, LegacyTransport, StandardTransport, Transport}; +use crate::transport::{Error, StandardTransport, Transport}; use crate::utils::{align_down, VolatileCell}; pub struct Device<'a> { @@ -24,7 +21,7 @@ pub struct Device<'a> { unsafe impl Send for Device<'_> {} unsafe impl Sync for Device<'_> {} -struct MsixInfo { +pub struct MsixInfo { pub virt_table_base: NonNull, pub capability: MsixCapability, } @@ -44,89 +41,6 @@ static_assertions::const_assert_eq!(std::mem::size_of::(), 16); pub const MSIX_PRIMARY_VECTOR: u16 = 0; -#[cfg(target_arch = "x86_64")] -fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { - let pci_config = pcid_handle.fetch_config()?; - - // Extended message signaled interrupts. - let capability = match pcid_handle.feature_info(PciFeature::MsiX)? { - PciFeatureInfo::MsiX(capability) => capability, - _ => unreachable!(), - }; - - let table_size = capability.table_size(); - let table_base = capability.table_base_pointer(pci_config.func.bars); - let table_min_length = table_size * 16; - let pba_min_length = table_size.div_ceil(8); - - let pba_base = capability.pba_base_pointer(pci_config.func.bars); - - let bir = capability.table_bir() as usize; - let bar = pci_config.func.bars[bir]; - let bar_size = pci_config.func.bar_sizes[bir] as u64; - - let bar_ptr = match bar { - PciBar::Memory32(ptr) => ptr.into(), - PciBar::Memory64(ptr) => ptr, - _ => unreachable!(), - }; - - let address = unsafe { - common::physmap( - bar_ptr as usize, - bar_size as usize, - common::Prot::RW, - common::MemoryType::Uncacheable, - )? as usize - }; - - // Ensure that the table and PBA are be within the BAR. - { - let bar_range = bar_ptr..bar_ptr + bar_size; - assert!(bar_range.contains(&(table_base as u64 + table_min_length as u64))); - assert!(bar_range.contains(&(pba_base as u64 + pba_min_length as u64))); - } - - let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; - - let mut info = MsixInfo { - virt_table_base: NonNull::new(virt_table_base).unwrap(), - capability, - }; - - // Allocate the primary MSI vector. - let interrupt_handle = { - let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize); - - let destination_id = read_bsp_apic_id().expect("virtio_core: `read_bsp_apic_id()` failed"); - let lapic_id = u8::try_from(destination_id).unwrap(); - - let rh = false; - let dm = false; - let addr = msi::x86_64::message_address(lapic_id, rh, dm); - - let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id) - .unwrap() - .expect("virtio_core: interrupt vector exhaustion"); - - let msg_data = msi::x86_64::message_data_edge_triggered(msi::x86_64::DeliveryMode::Fixed, vector); - - table_entry_pointer.addr_lo.write(addr); - table_entry_pointer.addr_hi.write(0); - table_entry_pointer.msg_data.write(msg_data); - table_entry_pointer - .vec_ctl - .writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); - - interrupt_handle - }; - - pcid_handle.enable_feature(PciFeature::MsiX)?; - - log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})"); - Ok(interrupt_handle) -} - #[cfg(not(target_arch = "x86_64"))] fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { panic!("Msi-X only supported on x86_64"); @@ -268,7 +182,7 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result // According to the virtio specification, the device REQUIRED to support MSI-X. assert!(has_msix, "virtio: device does not support MSI-X"); - let irq_handle = enable_msix(pcid_handle)?; + let irq_handle = crate::arch::enable_msix(pcid_handle)?; log::info!("virtio: using standard PCI transport"); @@ -284,38 +198,7 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result Ok(device) } else { - if let PciBar::Port(port) = pci_header.get_bar(0) { - unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; - log::warn!("virtio: using legacy transport"); - - static SHIM: VolatileCell = VolatileCell::new(0); - - let transport = LegacyTransport::new(port); - - // Setup interrupts. - let all_pci_features = pcid_handle.fetch_all_features()?; - let has_msix = all_pci_features - .iter() - .any(|(feature, _)| feature.is_msix()); - - // According to the virtio specification, the device REQUIRED to support MSI-X. - assert!(has_msix, "virtio: device does not support MSI-X"); - let irq_handle = enable_msix(pcid_handle)?; - - let device = Device { - transport, - irq_handle, - isr: &SHIM, - device_space: core::ptr::null_mut(), - }; - - device.transport.reset(); - reinit(&device)?; - - Ok(device) - } else { - unreachable!("virtio: legacy transport with non-port IO?") - } + crate::arch::probe_legacy_port_transport(&pci_header, pcid_handle) } } diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 53934b6f56..95a9001fb8 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -1,9 +1,8 @@ use crate::spec::*; use crate::utils::align; -use common::dma::{Dma, PhysBox}; +use common::dma::Dma; use event::EventQueue; -use syscall::{Io, Pio}; use core::mem::size_of; use core::sync::atomic::{AtomicU16, Ordering}; @@ -44,7 +43,7 @@ impl From for Error { /// /// ## Panics /// If `queue_size` is not a power of two or is zero. -const fn queue_part_sizes(queue_size: usize) -> (usize, usize, usize) { +pub const fn queue_part_sizes(queue_size: usize) -> (usize, usize, usize) { assert!(queue_size.is_power_of_two() && queue_size != 0); const DESCRIPTOR_ALIGN: usize = 16; @@ -69,7 +68,7 @@ const fn queue_part_sizes(queue_size: usize) -> (usize, usize, usize) { ) } -fn spawn_irq_thread(irq_handle: &File, queue: &Arc>) -> Result<(), Error> { +pub fn spawn_irq_thread(irq_handle: &File, queue: &Arc>) -> Result<(), Error> { let irq_fd = irq_handle.as_raw_fd(); let queue_copy = queue.clone(); @@ -297,7 +296,9 @@ impl<'a> Available<'a> { for i in 0..queue_size { // Setting them to `u16::MAX` helps with debugging since qemu reports them // as illegal values. - ring.get_element_at(i).table_index.store(u16::MAX, Ordering::SeqCst); + ring.get_element_at(i) + .table_index + .store(u16::MAX, Ordering::SeqCst); } Ok(ring) @@ -478,190 +479,6 @@ pub trait Transport: Sync + Send { fn insert_status(&self, status: DeviceStatusFlags); } -pub enum LegacyRegister { - DeviceFeatures = 0, // u32 - - QueueAddress = 8, // u32 - QueueSize = 12, // u16 - QueueSelect = 14, // u16 - QueueNotify = 16, // u16 - - DeviceStatus = 18, // u8 - - ConfigMsixVector = 20, // u16 - QueueMsixVector = 22, // u16 -} - -struct LegacyBell(Weak); - -impl NotifyBell for LegacyBell { - #[inline] - fn ring(&self, queue_index: u16) { - let transport = self.0.upgrade().expect("bell: transport dropped"); - transport.write::(LegacyRegister::QueueNotify, queue_index) - } -} - -pub struct LegacyTransport(u16, AtomicU16, Weak); - -impl LegacyTransport { - pub(super) fn new(port: u16) -> Arc { - Arc::new_cyclic(|sref| Self(port, AtomicU16::new(0), sref.clone())) - } - - unsafe fn read_raw(&self, offset: usize) -> V - where - V: Sized + TryFrom, - >::Error: std::fmt::Debug, - { - let port = self.0 + offset as u16; - - if size_of::() == size_of::() { - V::try_from(Pio::::new(port).read() as u64).unwrap() - } else if size_of::() == size_of::() { - V::try_from(Pio::::new(port).read() as u64).unwrap() - } else if size_of::() == size_of::() { - V::try_from(Pio::::new(port).read() as u64).unwrap() - } else if size_of::() == size_of::() { - let lower = Pio::::new(port).read() as u64; - let upper = Pio::::new(port + size_of::() as u16).read() as u64; - - V::try_from(lower | (upper << 32)).unwrap() - } else { - unreachable!() - } - } - - fn read(&self, register: LegacyRegister) -> V - where - V: Sized + TryFrom, - >::Error: std::fmt::Debug, - { - unsafe { self.read_raw(register as usize) } - } - - fn write(&self, register: LegacyRegister, value: V) - where - V: Sized + TryInto, - >::Error: std::fmt::Debug, - { - if size_of::() == size_of::() { - Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u8); - } else if size_of::() == size_of::() { - Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u16); - } else if size_of::() == size_of::() { - Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u32); - } else { - unreachable!() - } - } -} - -impl Transport for LegacyTransport { - fn reset(&self) { - self.write(LegacyRegister::DeviceStatus, 0u8); - - let status = self.read::(LegacyRegister::DeviceStatus); - assert_eq!(status, 0); - } - - fn check_device_feature(&self, feature: u32) -> bool { - assert!( - feature < 32, - "virtio: cannot query feature {feature} on a legacy device" - ); - self.read::(LegacyRegister::DeviceFeatures) & (1 << feature) == (1 << feature) - } - - fn ack_driver_feature(&self, feature: u32) { - assert!( - feature < 32, - "virtio: cannot ack feature {feature} on a legacy device" - ); - - let current = self.read::(LegacyRegister::DeviceFeatures); - self.write::(LegacyRegister::DeviceFeatures, current | (1 << feature)); - } - - fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result, Error> { - let queue_index = self.1.fetch_add(1, Ordering::SeqCst); - self.write(LegacyRegister::QueueSelect, queue_index); - - let queue_size = self.read::(LegacyRegister::QueueSize) as usize; - let (desc_size, avail_size, used_size) = queue_part_sizes(queue_size); - - let size_bytes = desc_size + avail_size + used_size; - let addr = unsafe { syscall::physalloc(size_bytes).map_err(Error::SyscallError)? }; - - let descriptor = unsafe { - let physbox = PhysBox::from_raw_parts(addr, desc_size); - let table = Dma::<[Descriptor]>::from_physbox_uninit_unsized(physbox, queue_size)?; - - table.assume_init() - }; - - let avail_addr = addr + desc_size; - let avail = unsafe { Available::from_raw(avail_addr, avail_size, queue_size)? }; - - let used_addr = avail_addr + avail_size; - let used = unsafe { Used::from_raw(used_addr, used_size, queue_size)? }; - - self.write::(LegacyRegister::QueueMsixVector, vector); - self.write::(LegacyRegister::QueueAddress, (addr as u32) >> 12); - - log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})"); - - let queue = Queue::new( - descriptor, - avail, - used, - LegacyBell(self.2.clone()), - queue_index, - vector, - ); - - spawn_irq_thread(irq_handle, &queue)?; - Ok(queue) - } - - fn load_config(&self, offset: u8, size: u8) -> u64 { - // We always enable MSI-X. So, the device configuration space offset will - // always be 0x18. - // - // Checkout 4.1.4.8 Legacy Interfaces: A Note on PCI Device Layout - const DEVICE_SPACE_OFFSET: usize = 0x18; - - let size = size as usize; - let offset = DEVICE_SPACE_OFFSET + offset as usize; - - unsafe { - if size == size_of::() { - self.read_raw::(offset) as u64 - } else if size == size_of::() { - self.read_raw::(offset) as u64 - } else if size == size_of::() { - self.read_raw::(offset) as u64 - } else if size == size_of::() { - self.read_raw::(offset) as u64 - } else { - unreachable!() - } - } - } - - fn insert_status(&self, status: DeviceStatusFlags) { - let old = self.read::(LegacyRegister::DeviceStatus); - self.write(LegacyRegister::DeviceStatus, old | status.bits()); - } - - fn reinit_queue(&self, _queue: Arc) { - todo!() - } - - // Legacy devices do not have the `FEATURES_OK` bit. - fn finalize_features(&self) {} -} - struct StandardBell<'a>(&'a mut AtomicU16); impl NotifyBell for StandardBell<'_> { From 02dcf9c1803a45c567bab522cf0cbebcf7f3ab80 Mon Sep 17 00:00:00 2001 From: Ribbon Date: Tue, 7 Nov 2023 15:12:50 +0000 Subject: [PATCH 0711/1301] Improve the README --- README.md | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 73548f6e20..5221d94d63 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Drivers -These are the currently implemented devices/hardware interfaces. +This document covers the driver details/status. + +Implemented devices/hardware interfaces: - ac97d - Realtek audio chipsets. - acpid - ACPI (incomplete). @@ -65,13 +67,18 @@ These are the currently implemented devices/hardware interfaces. - virtio-netd - VirtIO net device (incomplete). - xhcid - xHCI (incomplete). -## Kernel Interfaces +## Interfaces -These are the most used kernel interfaces by Redox drivers. +This section cover the interfaces used by Redox drivers. + +### System Calls - `iopl` - syscall that sets the I/O privilege level. x86 has four privilege rings (0/1/2/3), of which the kernel runs in ring 0 and userspace in ring 3. IOPL can only be changed by the kernel, for obvious security reasons, and therefore the Redox kernel needs root to set it. It is unique for each process. Processes with IOPL=3 can access I/O ports, and the kernel can access them as well. - `physalloc` - allocates physical memory frames. - `physfree` - frees memory frames. + +### Schemes + - `memory:physical` - allows mapping physical memory frames to driver-accessible virtual memory pages, with various available memory types: - `memory:physical`: default memory type (currently writeback) - `memory:physical@wb` writeback cached memory @@ -87,6 +94,6 @@ If you don't have datasheets, we recommend you to do reverse-engineering of avai We recommend BSDs drivers because BSD license is compatible with MIT (permissive), that way we can reuse the code in other drivers. -You can see this [example](https://gitlab.redox-os.org/redox-os/exampled) driver, read the code of the existent ones or the most close driver type for your device. +You can use the [example](https://gitlab.redox-os.org/redox-os/exampled) driver or read the code of other drivers with the same type of your device. -Before testing your changes be aware of [this](https://doc.redox-os.org/book/ch09-02-coding-and-building.html#a-note-about-drivers). +Before testing your changes, be aware of [this](https://doc.redox-os.org/book/ch09-02-coding-and-building.html#a-note-about-drivers). From 82fe14960fdac65268d1c5e9c5b01a9ff029da76 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 8 Nov 2023 09:54:27 -0700 Subject: [PATCH 0712/1301] Fix build on x86 --- virtio-core/src/arch/x86.rs | 46 +++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index 9806acea4f..08483e9346 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -1,3 +1,14 @@ +use crate::{ + legacy_transport::LegacyTransport, + reinit, + transport::Error, + utils::VolatileCell, + Device, +}; +use std::fs::File; + +use pcid_interface::*; + pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { panic!("virtio-core: x86 doesn't support enable_msix") } @@ -6,5 +17,36 @@ pub fn probe_legacy_port_transport<'a>( pci_header: &PciHeader, pcid_handle: &mut PcidServerHandle, ) -> Result, Error> { - crate::x86_64::probe_legacy_port_transport(pci_header, pcid_handle) -} \ No newline at end of file + if let PciBar::Port(port) = pci_header.get_bar(0) { + unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; + log::warn!("virtio: using legacy transport"); + + static SHIM: VolatileCell = VolatileCell::new(0); + + let transport = LegacyTransport::new(port); + + // Setup interrupts. + let all_pci_features = pcid_handle.fetch_all_features()?; + let has_msix = all_pci_features + .iter() + .any(|(feature, _)| feature.is_msix()); + + // According to the virtio specification, the device REQUIRED to support MSI-X. + assert!(has_msix, "virtio: device does not support MSI-X"); + let irq_handle = enable_msix(pcid_handle)?; + + let device = Device { + transport, + irq_handle, + isr: &SHIM, + device_space: core::ptr::null_mut(), + }; + + device.transport.reset(); + reinit(&device)?; + + Ok(device) + } else { + unreachable!("virtio: legacy transport with non-port IO?") + } +} From a6fee75f15ba75b78ce9e94bc5d8754b704c6796 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 29 Oct 2023 23:12:50 +0100 Subject: [PATCH 0713/1301] Phase out / in scheme names. --- acpid/src/main.rs | 8 ++++---- ahcid/src/main.rs | 2 +- ided/src/main.rs | 2 +- inputd/src/main.rs | 2 +- lived/src/main.rs | 4 ++-- nvmed/src/main.rs | 6 ++---- usbhidd/src/main.rs | 2 +- usbscsid/src/main.rs | 2 +- vesad/src/main.rs | 2 +- virtio-blkd/src/main.rs | 2 +- virtio-gpud/src/main.rs | 2 +- virtio-gpud/src/scheme.rs | 2 +- xhcid/src/main.rs | 2 +- 13 files changed, 18 insertions(+), 20 deletions(-) diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 47a4cd5cbd..e4c8711045 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -81,8 +81,8 @@ fn setup_logging() -> Option<&'static RedoxLogger> { fn daemon(daemon: redox_daemon::Daemon) -> ! { setup_logging(); - let rxsdt_raw_data: Arc<[u8]> = std::fs::read("kernel/acpi:rxsdt") - .expect("acpid: failed to read `kernel/acpi:rxsdt`") + let rxsdt_raw_data: Arc<[u8]> = std::fs::read("kernel.acpi:rxsdt") + .expect("acpid: failed to read `kernel.acpi:rxsdt`") .into(); let sdt = self::acpi::Sdt::new(rxsdt_raw_data) @@ -116,8 +116,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // TODO: I/O permission bitmap unsafe { syscall::iopl(3) }.expect("acpid: failed to set I/O privilege level to Ring 3"); - let shutdown_pipe = File::open("kernel/acpi:kstop") - .expect("acpid: failed to open `kernel/acpi:kstop`"); + let shutdown_pipe = File::open("kernel.acpi:kstop") + .expect("acpid: failed to open `kernel.acpi:kstop`"); let mut event_queue = OpenOptions::new() .write(true) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 584f6e1ec2..1e5d44b4bf 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -98,7 +98,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { ).expect("ahcid: failed to map address") }; { - let scheme_name = format!("disk/{}", name); + let scheme_name = format!("disk.{}", name); let socket_fd = syscall::open( &format!(":{}", scheme_name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK diff --git a/ided/src/main.rs b/ided/src/main.rs index 4556084d02..f8e42c5deb 100644 --- a/ided/src/main.rs +++ b/ided/src/main.rs @@ -233,7 +233,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - let scheme_name = format!("disk/{}", name); + let scheme_name = format!("disk.{}", name); let socket_fd = syscall::open( &format!(":{}", scheme_name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 02e2cd2b36..2a359f9b75 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -134,7 +134,7 @@ impl SchemeMut for InputScheme { } } "handle" => { - let display = path_parts.collect::>().join("/"); + let display = path_parts.collect::>().join("."); Handle::Device { device: display } } diff --git a/lived/src/main.rs b/lived/src/main.rs index a133404c0e..411d44db3f 100644 --- a/lived/src/main.rs +++ b/lived/src/main.rs @@ -173,7 +173,7 @@ impl SchemeMut for DiskScheme { HandleType::TheData => "0", }; - let src = format!("disk/live:{}", path).into_bytes(); + let src = format!("disk.live:{}", path).into_bytes(); let byte_count = std::cmp::min(buf.len(), src.len()); buf[..byte_count].copy_from_slice(&src[..byte_count]); @@ -201,7 +201,7 @@ impl SchemeMut for DiskScheme { } fn main() -> anyhow::Result<()> { redox_daemon::Daemon::new(move |daemon| { - let mut socket = File::create(":disk/live").expect("failed to open scheme"); + let mut socket = File::create(":disk.live").expect("failed to open scheme"); let mut scheme = DiskScheme::new().unwrap_or_else(|err| { eprintln!("failed to initialize livedisk scheme: {}", err); std::process::exit(1) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 65da7182c1..9074dcc4d7 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -299,10 +299,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .fetch_config() .expect("nvmed: failed to fetch config"); - let mut name = pci_config.func.name(); - name.push_str("_nvme"); + let mut scheme_name = format!("disk.pci-{:x}+{:x}+{:x}-nvme", pci_config.func.bus_num, pci_config.func.dev_num, pci_config.func.func_num); - let _logger_ref = setup_logging(&name); + let _logger_ref = setup_logging(&scheme_name); let bar = match pci_config.func.bars[0] { PciBar::Memory32(mem) => match mem { @@ -337,7 +336,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"), }); - let scheme_name = format!("disk/{}", name); let socket_fd = syscall::open( &format!(":{}", scheme_name), syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index bfefd2f798..8e11c70aed 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -382,7 +382,7 @@ fn main() { let report_ty = ReportTy::Input; let report_id = 0; - let mut display = File::open("display/vesa:input").expect("Failed to open orbital input socket"); + let mut display = File::open("display.vesa:input").expect("Failed to open orbital input socket"); //TODO: get dynamically let mut display_width = 0; diff --git a/usbscsid/src/main.rs b/usbscsid/src/main.rs index 05d37942f0..6f698e8c19 100644 --- a/usbscsid/src/main.rs +++ b/usbscsid/src/main.rs @@ -39,7 +39,7 @@ fn main() { redox_daemon::Daemon::new(move |d| daemon(d, scheme, port, protocol)).expect("usbscsid: failed to daemonize"); } fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u8) -> ! { - let disk_scheme_name = format!(":disk/{}-{}_scsi", scheme, port); + let disk_scheme_name = format!(":disk.usb-{scheme}+{port}-scsi"); // TODO: Use eventfds. let handle = XhciClientHandle::new(scheme.to_owned(), port); diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 08046147ca..47bd535022 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -90,7 +90,7 @@ fn main() { redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers, &spec)).expect("failed to create daemon"); } fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[bool]) -> ! { - let mut socket = File::create(":display/vesa").expect("vesad: failed to create display scheme"); + let mut socket = File::create(":display.vesa").expect("vesad: failed to create display scheme"); let mut scheme = DisplayScheme::new(framebuffers, &spec); diff --git a/virtio-blkd/src/main.rs b/virtio-blkd/src/main.rs index 2083530c70..e280f62b6a 100644 --- a/virtio-blkd/src/main.rs +++ b/virtio-blkd/src/main.rs @@ -140,7 +140,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut name = pci_config.func.name(); name.push_str("_virtio_blk"); - let scheme_name = format!("disk/{}", name); + let scheme_name = format!("disk.{}", name); let socket_fd = syscall::open( &format!(":{}", scheme_name), diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index f181b38ff2..4d16d87a97 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -438,7 +438,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device.transport.run_device(); deamon.ready().unwrap(); - let mut socket_file = File::create(":display/virtio-gpu")?; + let mut socket_file = File::create(":display.virtio-gpu")?; let mut scheme = futures::executor::block_on(scheme::Scheme::new( config, control_queue.clone(), diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index e4f294dad4..30dded638f 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -86,7 +86,7 @@ impl<'a> Display<'a> { } async fn get_fpath(&self, buffer: &mut [u8]) -> Result { - let path = format!("display/virtio-gpu:3.0/{}/{}", self.width, self.height); + let path = format!("display.virtio-gpu:3.0/{}/{}", self.width, self.height); // Copy the path into the target buffer. buffer[..path.len()].copy_from_slice(path.as_bytes()); diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index decacdd666..8f33ddce1a 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -275,7 +275,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq) ); - let scheme_name = format!("usb/{}", name); + let scheme_name = format!("usb.{}", name); let socket_fd = syscall::open( format!(":{}", scheme_name), syscall::O_RDWR | syscall::O_CREAT, From ce5409f9bf4ebf1fd3509fb24d0e0299c25c2912 Mon Sep 17 00:00:00 2001 From: Ribbon Date: Wed, 15 Nov 2023 17:20:37 +0000 Subject: [PATCH 0714/1301] Improve the README --- README.md | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 5221d94d63..eac9d4eab7 100644 --- a/README.md +++ b/README.md @@ -86,14 +86,30 @@ This section cover the interfaces used by Redox drivers. - `memory:physical@wc`: write-combining memory - `irq:` - allows getting events from interrupts. It is used primarily by listening for its file descriptors using the `event:` scheme. -## Contributing to Drivers +## Contributing -If you want to write drivers for Redox, datasheets are preferable, when they are freely available. Be aware that datasheets are often provided under a [Non-Disclosure Agreement](https://en.wikipedia.org/wiki/Non-disclosure_agreement) from hardware vendors, which can affect the ability to create an MIT-licensed driver. +### Driver Design -If you don't have datasheets, we recommend you to do reverse-engineering of available C code of BSD drivers. +A device driver on Redox is an user-space daemon that use system calls and schemes to work. -We recommend BSDs drivers because BSD license is compatible with MIT (permissive), that way we can reuse the code in other drivers. +For operating systems with monolithic kernels, drivers use internal kernel APIs instead of common program APIs. + +If you want to port a driver from a monolithic OS to Redox you will need to rewrite the driver with reverse enginnering of the code logic, because the logic is adapted to internal kernel APIs (it's a hard task if the device is complex, datasheets are more easy). + +### Write a Driver + +Datasheets are preferable, when they are freely available. Be aware that datasheets are often provided under a [Non-Disclosure Agreement](https://en.wikipedia.org/wiki/Non-disclosure_agreement) from hardware vendors, which can affect the ability to create an MIT-licensed driver. + +If you don't have datasheets, we recommend you to do reverse-engineering of available C code on BSD drivers. You can use the [example](https://gitlab.redox-os.org/redox-os/exampled) driver or read the code of other drivers with the same type of your device. Before testing your changes, be aware of [this](https://doc.redox-os.org/book/ch09-02-coding-and-building.html#a-note-about-drivers). + +### Driver References + +If you want to reverse enginner the existing drivers, you can access the BSD code using these links: + +- [FreeBSD drivers](https://github.com/freebsd/freebsd-src/tree/main/sys/dev) +- [NetBSD drivers](https://github.com/NetBSD/src/tree/trunk/sys/dev) +- [OpenBSD drivers](https://github.com/openbsd/src/tree/master/sys/dev) From 3871c99e6efc4572516fb2b8f793842bcf1a430e Mon Sep 17 00:00:00 2001 From: Ivan Tan Date: Sat, 9 Dec 2023 12:16:06 +0800 Subject: [PATCH 0715/1301] add bcm2835-sdhci driver --- Cargo.lock | 18 + Cargo.toml | 2 + bcm2835-sdhcid/Cargo.toml | 15 + bcm2835-sdhcid/src/main.rs | 115 ++++++ bcm2835-sdhcid/src/scheme.rs | 441 ++++++++++++++++++++ bcm2835-sdhcid/src/sd/mod.rs | 776 +++++++++++++++++++++++++++++++++++ common/src/lib.rs | 2 + 7 files changed, 1369 insertions(+) create mode 100644 bcm2835-sdhcid/Cargo.toml create mode 100644 bcm2835-sdhcid/src/main.rs create mode 100644 bcm2835-sdhcid/src/scheme.rs create mode 100644 bcm2835-sdhcid/src/sd/mod.rs diff --git a/Cargo.lock b/Cargo.lock index ce0e684304..434df3e8e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,6 +158,18 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" +[[package]] +name = "bcm2835-sdhcid" +version = "0.1.0" +dependencies = [ + "block-io-wrapper", + "common", + "fdt", + "partitionlib", + "redox-daemon", + "redox_syscall 0.4.1", +] + [[package]] name = "bgad" version = "0.1.0" @@ -384,6 +396,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "fdt" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67" + [[package]] name = "fuchsia-cprng" version = "0.1.1" diff --git a/Cargo.toml b/Cargo.toml index a1eba0a22b..2298868ad1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,8 @@ members = [ "virtio-netd", "virtio-gpud", "virtio-core", + + "bcm2835-sdhcid", ] [profile.release] diff --git a/bcm2835-sdhcid/Cargo.toml b/bcm2835-sdhcid/Cargo.toml new file mode 100644 index 0000000000..faa5ddfb77 --- /dev/null +++ b/bcm2835-sdhcid/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "bcm2835-sdhcid" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +fdt = "0.1.5" +redox_syscall = "0.4" +partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +block-io-wrapper = { path = "../block-io-wrapper" } +common = { path = "../common" } + +redox-daemon = "0.1" diff --git a/bcm2835-sdhcid/src/main.rs b/bcm2835-sdhcid/src/main.rs new file mode 100644 index 0000000000..f70e8cca4a --- /dev/null +++ b/bcm2835-sdhcid/src/main.rs @@ -0,0 +1,115 @@ +use std::{fs::File, io::{Read, Write}, process}; + +use fdt::{Fdt, node::FdtNode}; +use syscall::{Packet, SchemeBlockMut}; + +use crate::sd::Disk; +use crate::scheme::DiskScheme; + +mod sd; +mod scheme; + +#[cfg(target_os = "redox")] +fn get_dtb() -> Vec { + std::fs::read("kernel.dtb:").unwrap() +} + +#[cfg(target_os = "linux")] +fn get_dtb() -> Vec { + use std::env; + if let Some(arg1) = env::args().nth(1) { + std::fs::read(arg1).unwrap() + } else { + Vec::new() + } +} + +fn main() { + redox_daemon::Daemon::new(daemon).expect("mmc:failed to daemonize"); +} + +fn daemon(daemon: redox_daemon::Daemon) -> ! { + let dtb_data = get_dtb(); + println!("read from OS, len = {}", dtb_data.len()); + if dtb_data.len() == 0 { + process::exit(0); + } + + let fdt = Fdt::new(&dtb_data).unwrap(); + println!("DTB model = {}", fdt.root().model()); + let with = ["brcm,bcm2835-sdhcid"]; + let compat_node = fdt.find_compatible(&with).unwrap(); + let reg = compat_node.reg().unwrap().next().unwrap(); + let reg_size = reg.size.unwrap(); + println!("DeviceMemory start = 0x{:08x}, size = 0x{:08x}", reg.starting_address as usize, reg_size); + let addr = unsafe { + common::physmap(reg.starting_address as usize, reg_size, common::Prot::RW, common::MemoryType::DeviceMemory) + .expect("bcm2835-sdhcid: failed to map address") as usize + }; + println!("ioremap 0x{:08x} to 0x{:08x} 2222", reg.starting_address as usize, addr); + let mut sdhci = sd::SdHostCtrl::new(addr); + unsafe { + sdhci.init(); + /* + let mut buf1 = [0u32; 512]; + sdhci.sd_readblock(1, &mut buf1, 1); + println!("readblock {:?}", buf1); + buf1[0] = 0xdead_0000; + buf1[1] = 0xdead_0000; + buf1[2] = 0x0000_dead; + buf1[3] = 0x0000_dead; + sdhci.sd_writeblock(1, &buf1, 1); + sdhci.sd_readblock(1, &mut buf1, 1); + println!("readblock {:?}", buf1); + */ + /* + let mut buf1 = [0u8; 512]; + sdhci.read(1, &mut buf1); + println!("readblock {:?}", buf1); + buf1[0] = 0xde; + buf1[1] = 0xad; + buf1[2] = 0xde; + buf1[3] = 0xad; + sdhci.write(1, &buf1); + sdhci.read(1, &mut buf1); + println!("readblock {:?}", buf1); + */ + } + + + let scheme_name = ":disk.mmc"; + let mut socket = File::create(scheme_name).expect("mmc: failed to create disk scheme"); + syscall::setrens(0, 0).expect("mmc: failed to enter null namespace"); + + daemon.ready().expect("mmc: failed to notify parent"); + + let mut todo = Vec::new(); + let mut disks = Vec::new(); + + disks.push(Box::new(sdhci) as Box); + let mut scheme = DiskScheme::new(scheme_name.to_string(), disks); + loop { + let mut packet = Packet::default(); + if socket.read(&mut packet).expect("mmc: failed to read event") == 0 { + println!("zero, break"); + break; + } + if let Some(a) = scheme.handle(&packet) { + packet.a = a; + socket.write(&packet).expect("mmcd: failed to write disk scheme"); + } else { + todo.push(packet); + } + let mut i = 0; + while i < todo.len() { + if let Some(a) = scheme.handle(&todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&packet).expect("mmcd: failed to write disk scheme"); + } else { + i += 1; + } + } + } + process::exit(0); +} diff --git a/bcm2835-sdhcid/src/scheme.rs b/bcm2835-sdhcid/src/scheme.rs new file mode 100644 index 0000000000..fce64bb363 --- /dev/null +++ b/bcm2835-sdhcid/src/scheme.rs @@ -0,0 +1,441 @@ +use std::collections::BTreeMap; +use std::{cmp, str}; +use std::convert::{TryFrom}; +use std::fmt::Write; +use std::io::prelude::*; +use std::io::SeekFrom; +use std::io; +use std::sync::{Arc, Mutex}; + +use syscall::{ + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, + Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, + O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; + +use crate::sd::Disk; + +use partitionlib::{LogicalBlockSize, PartitionTable}; + +#[derive(Clone)] +enum Handle { + List(Vec, usize), // Dir contents buffer, position + Disk(usize, usize), // Disk index, position + Partition(usize, u32, usize), // Disk index, partition index, position +} + +pub struct DiskWrapper { + disk: Box, + pt: Option, +} + +impl DiskWrapper { + fn pt(disk: &mut dyn Disk) -> Option { + let bs = match disk.block_length() { + Ok(512) => LogicalBlockSize::Lb512, + _ => return None, + }; + struct Device<'a, 'b> { disk: &'a mut dyn Disk, offset: u64, block_bytes: &'b mut [u8] } + + impl<'a, 'b> Seek for Device<'a, 'b> { + fn seek(&mut self, from: SeekFrom) -> io::Result { + let size = i64::try_from(self.disk.size()).or(Err(io::Error::new(io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes")))?; + + self.offset = match from { + SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos), + SeekFrom::Current(new_pos) => cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64, + SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64, + }; + + Ok(self.offset) + } + } + // TODO: Perhaps this impl should be used in the rest of the scheme. + impl<'a, 'b> Read for Device<'a, 'b> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?; + let size_in_blocks = self.disk.size() / u64::from(blksize); + + let disk = &mut self.disk; + + let read_block = |block: u64, block_bytes: &mut [u8]| { + if block >= size_in_blocks { + return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); + } + loop { + match disk.read(block, block_bytes) { + Ok(Some(bytes)) => { + assert_eq!(bytes, block_bytes.len()); + assert_eq!(bytes, blksize as usize); + return Ok(()); + } + Ok(None) => { std::thread::yield_now(); continue } + Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), + } + } + }; + let bytes_read = block_io_wrapper::read(self.offset, blksize, buf, self.block_bytes, read_block)?; + + self.offset += bytes_read as u64; + Ok(bytes_read) + } + } + + let mut block_bytes = [0u8; 4096]; + + partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() + } + fn new(mut disk: Box) -> Self { + Self { + pt: Self::pt(&mut *disk), + disk, + } + } +} + +impl std::ops::Deref for DiskWrapper { + type Target = dyn Disk; + + fn deref(&self) -> &Self::Target { + &*self.disk + } +} +impl std::ops::DerefMut for DiskWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.disk + } +} + +pub struct DiskScheme { + scheme_name: String, + disks: Box<[DiskWrapper]>, + handles: BTreeMap, + next_id: usize +} + +impl DiskScheme { + pub fn new(scheme_name: String, disks: Vec>) -> DiskScheme { + DiskScheme { + scheme_name: scheme_name, + disks: disks.into_iter().map(DiskWrapper::new).collect::>().into_boxed_slice(), + handles: BTreeMap::new(), + next_id: 0 + } + } + + // Checks if any conflicting handles already exist + fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { + for (_, handle) in self.handles.iter() { + match handle { + Handle::Disk(i, _) => if disk_i == *i { + return Err(Error::new(ENOLCK)); + }, + Handle::Partition(i, p, _) => if disk_i == *i { + match part_i_opt { + Some(part_i) => if part_i == *p { + return Err(Error::new(ENOLCK)); + }, + None => { + return Err(Error::new(ENOLCK)); + } + } + }, + _ => (), + } + } + Ok(()) + } +} + +impl SchemeBlockMut for DiskScheme { + fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { + if uid == 0 { + let path_str = path.trim_matches('/'); + if path_str.is_empty() { + if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { + let mut list = String::new(); + + for (disk_index, disk) in self.disks.iter().enumerate() { + write!(list, "{}\n", disk_index).unwrap(); + + if disk.pt.is_none() { + continue + } + for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { + write!(list, "{}p{}\n", disk_index, part_index).unwrap(); + } + } + + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle::List(list.into_bytes(), 0)); + Ok(Some(id)) + } else { + Err(Error::new(EISDIR)) + } + } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { + let disk_id_str = &path_str[..p_pos]; + if p_pos + 1 >= path_str.len() { + return Err(Error::new(ENOENT)); + } + let part_id_str = &path_str[p_pos + 1..]; + let i = disk_id_str.parse::().or(Err(Error::new(ENOENT)))?; + let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; + + if let Some(disk) = self.disks.get(i) { + if disk.pt.is_none() || disk.pt.as_ref().unwrap().partitions.get(p as usize).is_none() { + return Err(Error::new(ENOENT)); + } + + self.check_locks(i, Some(p))?; + + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle::Partition(i, p, 0)); + Ok(Some(id)) + } else { + Err(Error::new(ENOENT)) + } + } else { + let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; + + if self.disks.get(i).is_some() { + self.check_locks(i, None)?; + + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, Handle::Disk(i, 0)); + Ok(Some(id)) + } else { + Err(Error::new(ENOENT)) + } + } + } else { + Err(Error::new(EACCES)) + } + } + + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { + if ! buf.is_empty() { + return Err(Error::new(EINVAL)); + } + + let new_handle = { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + handle.clone() + }; + + let new_id = self.next_id; + self.next_id += 1; + self.handles.insert(new_id, new_handle); + Ok(Some(new_id)) + } + + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + match *self.handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref data, _) => { + stat.st_mode = MODE_DIR; + stat.st_size = data.len() as u64; + Ok(Some(0)) + }, + Handle::Disk(number, _) => { + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + stat.st_mode = MODE_FILE; + stat.st_size = disk.size(); + stat.st_blksize = disk.block_length()?; + Ok(Some(0)) + } + Handle::Partition(disk_id, part_num, _) => { + let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; + let size = { + let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; + let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + partition.size + }; + + stat.st_mode = MODE_FILE; // TODO: Block device? + stat.st_size = size * u64::from(disk.block_length()?); + stat.st_blksize = disk.block_length()?; + stat.st_blocks = size; + Ok(Some(0)) + } + } + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let mut i = 0; + + let scheme_name = self.scheme_name.as_bytes(); + let mut j = 0; + while i < buf.len() && j < scheme_name.len() { + buf[i] = scheme_name[j]; + i += 1; + j += 1; + } + + if i < buf.len() { + buf[i] = b':'; + i += 1; + } + + match *handle { + Handle::List(_, _) => (), + Handle::Disk(number, _) => { + let number_str = format!("{}", number); + let number_bytes = number_str.as_bytes(); + j = 0; + while i < buf.len() && j < number_bytes.len() { + buf[i] = number_bytes[j]; + i += 1; + j += 1; + } + } + Handle::Partition(disk_num, part_num, _) => { + let path = format!("{}p{}", disk_num, part_num); + let path_bytes = path.as_bytes(); + j = 0; + while i < buf.len() && j < path_bytes.len() { + buf[i] = path_bytes[j]; + i += 1; + j += 1; + } + } + } + + Ok(Some(i)) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref handle, ref mut size) => { + let count = (&handle[*size..]).read(buf).unwrap(); + *size += count; + Ok(Some(count)) + }, + Handle::Disk(number, ref mut size) => { + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + let blk_len = disk.block_length()?; + if let Some(count) = disk.read((*size as u64)/(blk_len as u64), buf)? { + *size += count; + Ok(Some(count)) + } else { + Ok(None) + } + } + Handle::Partition(disk_num, part_num, ref mut position) => { + let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; + let blksize = disk.block_length()?; + + // validate that we're actually reading within the bounds of the partition + let rel_block = *position as u64 / blksize as u64; + + let abs_block = { + let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; + let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + + let abs_block = partition.start_lba + rel_block; + if rel_block >= partition.size { + return Err(Error::new(EOVERFLOW)); + } + abs_block + }; + + if let Some(count) = disk.read(abs_block, buf)? { + Ok(Some(count)) + } else { + Ok(None) + } + } + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(_, _) => { + Err(Error::new(EBADF)) + }, + Handle::Disk(number, ref mut size) => { + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + let blk_len = disk.block_length()?; + if let Some(count) = disk.write((*size as u64)/(blk_len as u64), buf)? { + *size += count; + Ok(Some(count)) + } else { + Ok(None) + } + } + Handle::Partition(disk_num, part_num, ref mut position) => { + let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; + let blksize = disk.block_length()?; + + // validate that we're actually reading within the bounds of the partition + let rel_block = *position as u64 / blksize as u64; + + let abs_block = { + let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; + let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + + let abs_block = partition.start_lba + rel_block; + if rel_block >= partition.size { + return Err(Error::new(EOVERFLOW)); + } + abs_block + }; + + if let Some(count) = disk.write(abs_block, buf)? { + Ok(Some(count)) + } else { + Ok(None) + } + } + } + } + + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { + let pos = pos as usize; + + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref mut handle, ref mut size) => { + let len = handle.len() as usize; + *size = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(Some(*size as isize)) + }, + Handle::Disk(number, ref mut size) => { + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + let len = disk.size() as usize; + *size = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)) + }; + + Ok(Some(*size as isize)) + } + Handle::Partition(disk_num, part_num, ref mut position) => { + let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; + let block_count = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?.size; + let len = u64::from(disk.block_length()?) * block_count; + + *position = match whence { + SEEK_SET => cmp::min(len as usize, pos) as usize, // Why isn't pos u64? + SEEK_CUR => cmp::max(0, cmp::min(len as isize, *position as isize + pos as isize)) as usize, + SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, + _ => return Err(Error::new(EINVAL)), + }; + Ok(Some(*position as isize)) + } + } + } + + fn close(&mut self, id: usize) -> Result> { + self.handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + } +} diff --git a/bcm2835-sdhcid/src/sd/mod.rs b/bcm2835-sdhcid/src/sd/mod.rs new file mode 100644 index 0000000000..be5c37df7b --- /dev/null +++ b/bcm2835-sdhcid/src/sd/mod.rs @@ -0,0 +1,776 @@ +use std::{sync::{Mutex, RwLock}, time::{self, Duration}, thread}; +use syscall::{io::Mmio, Io, Error, Result, EINVAL}; +use core::ptr::{read_volatile, write_volatile}; + +#[cfg(target_arch = "aarch64")] +#[inline(always)] +pub(crate) unsafe fn wait_cycles(mut n: usize) { + use core::arch::asm; + + while n > 0 { + asm!("nop"); + n -= 1; + } +} + +#[cfg(target_arch = "aarch64")] +#[inline(always)] +pub(crate) unsafe fn wait_msec(mut n: usize) { + use core::arch::asm; + + let mut f: usize; + let mut t: usize; + let mut r: usize; + + asm!("mrs {0}, cntfrq_el0", out(reg) f); + asm!("mrs {0}, cntpct_el0", out(reg) t); + + + t += ((f / 1000) * n) / 1000; + + loop { + asm!("mrs {0}, cntpct_el0", out(reg) r); + if r >= t { + break; + } + }; +} + +#[cfg(target_arch = "x86_64")] +#[inline(always)] +pub(crate) unsafe fn wait_msec(mut n: usize) { + thread::sleep(Duration::from_millis(n as u64)); +} + +//cmd Flags +const CMD_NEED_APP: u32 = 0x8000_0000; +const CMD_RSPNS_48: u32 = 0x0002_0000; +const CMD_ERRORS_MASK: u32 = 0xfff9_c004; +const CMD_RCA_MASK: u32 = 0xffff_0000; + +//CMD +const CMD_GO_IDLE: u32 = 0x0000_0000; +const CMD_ALL_SEND_CID: u32 = 0x0201_0000; +const CMD_SEND_CSD: u32 = 0x0901_0000; +const CMD_SEND_REL_ADDR: u32 = 0x0302_0000; +const CMD_CARD_SELECT: u32 = 0x0703_0000; +const CMD_SEND_IF_COND: u32 = 0x0802_0000; +const CMD_STOP_TRANS: u32 = 0x0c03_0000; +const CMD_READ_SINGLE: u32 = 0x1122_0010; +const CMD_READ_MULTI: u32 = 0x1222_0032; +const CMD_SET_BLOCKCNT: u32 = 0x1702_0000; +const CMD_WRITE_SINGLE:u32 = 0x1822_0000; +const CMD_WRITE_MULTI:u32 = 0x1922_0022; + +const CMD_APP_CMD: u32 = 0x3700_0000; +const CMD_SET_BUS_WIDTH: u32 = 0x0602_0000|CMD_NEED_APP; +const CMD_SEND_OP_COND: u32 = 0x2902_0000|CMD_NEED_APP; +const CMD_SEND_SCR: u32 = 0x3322_0010|CMD_NEED_APP; + + + +//STATUS register settings +const SR_READ_AVAILABLE: u32 = 0x0000_0800; +const SR_WRITE_AVAILABLE: u32 = 0x0000_0400; +const SR_DAT_INHIBIT: u32 = 0x0000_0002; +const SR_CMD_INHIBIT: u32 = 0x0000_0001; +const SR_APP_CMD: u32 = 0x0000_0020; + +//CONTROL register settings + +const C0_SPI_MODE_EN: u32 = 0x0010_0000; +const C0_HCTL_HS_EN: u32 = 0x0000_0004; +const C0_HCTL_DWITDH: u32 = 0x0000_0002; + +const C1_SRST_DATA: u32 = 0x0400_0000; +const C1_SRST_CMD: u32 = 0x0200_0000; +const C1_SRST_HC: u32 = 0x0100_0000; +const C1_TOUNIT_DIS: u32 = 0x000f_0000; +const C1_TOUNIT_MAX: u32 = 0x000e_0000; +const C1_CLK_GENSEL: u32 = 0x0000_0020; +const C1_CLK_EN: u32 = 0x0000_0004; +const C1_CLK_STABLE: u32 = 0x0000_0002; +const C1_CLK_INTLEN: u32 = 0x0000_0001; + + +//INTERRUPT register settings +const INT_DATA_TIMEOUT: u32 = 0x0010_0000; +const INT_CMD_TIMEOUT: u32 = 0x0001_0000; +const INT_READ_RDY: u32 = 0x0000_0020; +const INT_WRITE_RDY: u32 = 0x0000_0010; +const INT_DATA_DONE: u32 = 0x0000_0002; +const INT_CMD_DONE: u32 = 0x0000_0001; +const INT_ERROR_MASK: u32 = 0x017e_8000; + +const HOST_SPEC_VERSION_OFFSET: u32 = 16; +const HOST_SPEC_VERSION_MASK: u32 = 0x00ff_0000; +const HOST_SPEC_V3: u32 = 2; +const HOST_SPEC_V2: u32 = 1; +const HOST_SPEC_V1: u32 = 0; + +const ACMD41_VOLTAGE: u32 = 0x00ff_8000; +const ACMD41_CMD_COMPLETE: u32 = 0x8000_0000; +const ACMD41_CMD_CCS: u32 = 0x4000_0000; +const ACMD41_ARG_HC: u32 = 0x51ff_8000; + +const SCR_SD_BUS_WIDTH_4: u32 = 0x0000_0400; +const SCR_SUPP_SET_BLKCNT: u32 = 0x0200_0000; +//added by bztsrc driver +const SCR_SUPP_CCS: u32 = 0x0000_0001; + +#[repr(packed)] +pub struct SdHostCtrlRegs { + //LSB + + //ACMD23 Argument + _arg2: Mmio, + + //Block Size and Count + blksizecnt: Mmio, + + //Argument + arg1: Mmio, + + //Command and Transfer Mode + cmdtm: Mmio, + + //Response bit 0-127 + resp0: Mmio, + resp1: Mmio, + resp2: Mmio, + resp3: Mmio, + + //Data + data: Mmio, + + //Status + status: Mmio, + + //Host Configuration bits + control0: Mmio, + + //Host Configuration bits + control1: Mmio, + + //Interrupt Flags + interrupt: Mmio, + + //Interrupt Flag Enable + irpt_mask: Mmio, + + //Interrupt Generation Enable + irpt_en: Mmio, + + //Host Configuration bits + _control2: Mmio, + + _rsvd: [Mmio; 47], + + //Slot Interrupt Status and Version + slotisr_ver: Mmio +} + +//TODO: refactor, sd/sdhci/bcmh2835-sdhci three different modules. +pub struct SdHostCtrl { + regs: RwLock<&'static mut SdHostCtrlRegs>, + host_spec_ver: u32, + cid: [u32; 4], + csd: [u32; 4], + rca: u32, //relative card address + scr: [u32; 2], + ocr: u32, + size: u64 +} + +impl SdHostCtrl { + pub fn new(address: usize) -> Self { + SdHostCtrl { + regs: RwLock::new(unsafe { &mut *(address as *mut SdHostCtrlRegs)}), + host_spec_ver: 0, + cid: [0; 4], + csd: [0; 4], + rca: 0, + scr: [0; 2], + ocr: 0, + size: 0, + } + } + + pub unsafe fn init(&mut self) { + let regs = self.regs.get_mut().unwrap(); + + let mut reg_val = regs.slotisr_ver.read(); + self.host_spec_ver = (reg_val & HOST_SPEC_VERSION_MASK) >> HOST_SPEC_VERSION_OFFSET; + + regs.control0.write(0x0); + reg_val = regs.control1.read(); + regs.control1.write(reg_val | C1_SRST_HC); + let mut cnt = 1000; + while (cnt >= 0) && + ((regs.control1.read() & C1_SRST_HC) == C1_SRST_HC) { + cnt -= 1; + wait_msec(10); + } + + if cnt < 0 { + println!("ERROR: failed to reset EMMC"); + return ; + } + println!("EMMC: reset OK"); + reg_val = regs.control1.read(); + regs.control1.write(reg_val | C1_CLK_INTLEN | C1_TOUNIT_MAX); + + wait_msec(10); + + { + if let Err(_) = self.set_clock(40_0000) { + println!("ERROR: failed to set clock {}", 40_0000); + return ; + } + } + + let regs = self.regs.get_mut().unwrap(); + regs.irpt_en.write(0xffff_ffff); + regs.irpt_mask.write(0xffff_ffff); + + if let Err(_) = self.sd_cmd(CMD_GO_IDLE, 0) { + println!("failed to go idle"); + return ; + } + + if let Err(_) = self.sd_cmd(CMD_SEND_IF_COND, 0x0000_01aa) { + println!("failed to send if cond"); + return ; + } + + cnt = 6; + reg_val = 0; + + while ((reg_val & ACMD41_CMD_COMPLETE) == 0) && cnt > 0 { + wait_msec(10); + cnt -= 1; + + if let Ok(val) = self.sd_cmd(CMD_SEND_OP_COND, ACMD41_ARG_HC) { + reg_val = val; + self.ocr = reg_val; + print!("EMMC: CMD_SEND_OP_COND returned 0x{:08x} = ", reg_val); + + if (reg_val & ACMD41_CMD_COMPLETE) != 0 { + print!("COMPLETE "); + } + if (reg_val & ACMD41_VOLTAGE) != 0 { + print!("VOLTAGE "); + } + if (reg_val & ACMD41_CMD_CCS) != 0 { + print!("CCS "); + } + print!("\n"); + } else { + println!("ERROR: EMMC ACMD41 returned error"); + return ; + } + } + + if (reg_val & ACMD41_CMD_COMPLETE) == 0 || cnt <= 0 { + println!("ACMD41 TIMEOUT"); + return ; + } + + if (reg_val & ACMD41_VOLTAGE) == 0 { + println!("ACMD41 VOLTAGE NOT FOUND!"); + return ; + } + + let ccs = if (reg_val & ACMD41_CMD_CCS) != 0 { SCR_SUPP_CCS } else { 0 }; + + if let Err(_) = self.sd_cmd(CMD_ALL_SEND_CID, 0) { + println!("CMD_ALL_SEND_CID ERROR, IGNORE!"); + } + + let sd_rca = self.sd_cmd(CMD_SEND_REL_ADDR, 0x0).unwrap(); + println!("CMD_SEND_REL_ADDR = 0x{:08x}", sd_rca); + self.rca = sd_rca; + + if let Err(_) = self.sd_cmd(CMD_SEND_CSD, sd_rca) { + println!("failed to get csd"); + return ; + } + + let (csize, cmult) = if (self.ocr & ACMD41_CMD_CCS) != 0 { + let csize = (self.csd[1] & 0x3f) << 16 | (self.csd[2] & 0xffff_0000) >> 16; + let cmult = 8; + (csize as u64, cmult as u64) + } else { + let csize = (self.csd[1] & 0x3ff) << 2 | (self.csd[2] & 0xc000_0000) >> 30; + let cmult = (self.csd[2] & 0x0003_8000) >> 15; + (csize as u64, cmult as u64) + }; + self.size = ((csize + 1) << (cmult + 2)) * 512; + println!("mmc size = 0x{:08x}", self.size); + + + if let Err(_) = self.set_clock(2500_0000) { + println!("failed to set clock 2500_0000 Hz"); + return ; + } + + if let Err(_) = self.sd_cmd(CMD_CARD_SELECT, sd_rca) { + println!("failed to CMD_CARD_SELECT 0x{:08x}", sd_rca); + return ; + } + + if let Err(_) = self.sd_status(SR_DAT_INHIBIT) { + println!("SR_DAT_INHIBIT return"); + return ; + } + + let regs = self.regs.get_mut().unwrap(); + regs.blksizecnt.write(1 << 16 | 8); + + if let Err(_) = self.sd_cmd(CMD_SEND_SCR, 0) { + println!("failed to CMD_SEND_SCR"); + return ; + } + + if let Err(_) = self.sd_int(INT_READ_RDY) { + println!("failed to INT_READ_RDY"); + return ; + } + + cnt = 10000; + let mut i = 0; + let regs = self.regs.get_mut().unwrap(); + while i < 2 && cnt > 0 { + reg_val = regs.status.read(); + cnt -= 1; + if (reg_val & SR_READ_AVAILABLE) != 0 { + self.scr[i] = regs.data.read(); + i += 1; + } else { + wait_msec(10); + cnt -= 1; + } + } + if i != 2 { + println!("SD TIMEOUT FOR SCR[; 2]"); + return ; + } + + if (self.scr[0] & SCR_SD_BUS_WIDTH_4) != 0 { + if let Err(_) = self.sd_cmd(CMD_SET_BUS_WIDTH, sd_rca | 2) { + println!("failed to set bus width, {}", sd_rca | 2); + return ; + } + let regs = self.regs.get_mut().unwrap(); + regs.control0.write(C0_HCTL_DWITDH); + } + + print!("EMMC: supports "); + + if (self.scr[0] & SCR_SUPP_SET_BLKCNT) != 0 { + print!("SET_BLKCNT "); + } + + if ccs != 0 { + print!("CCS "); + } + + print!("\n"); + + self.scr[0] &= !SCR_SUPP_CCS; + self.scr[0] |= ccs; + } + + pub unsafe fn set_clock(&mut self, freq: u32) -> Result<()> { + let mut cnt: i32 = 0; + let regs = self.regs.get_mut().unwrap(); + + let mut reg_val = regs.status.read() & (SR_CMD_INHIBIT | SR_DAT_INHIBIT); + cnt = 10_0000; + while (cnt > 0) && reg_val != 0 { + wait_msec(1); + cnt -= 1; + reg_val = regs.status.read() & (SR_CMD_INHIBIT | SR_DAT_INHIBIT); + } + + if cnt <= 0 { + println!("ERROR: TIMEOUT WAITING FOR INHIBIT FLAG"); + return Err(Error::new(EINVAL)); + } + + reg_val = regs.control1.read(); + reg_val &= !C1_CLK_EN; + regs.control1.write(reg_val); + wait_msec(10); + + let c = 4166_6666 / freq; + let mut x: u32 = c - 1; + let mut s: u32 = 32; + + if x == 0 { + s = 0; + } else { + if (x & 0xffff_0000) == 0 { x <<= 16; s -= 16; } + if (x & 0xff00_0000) == 0 { x <<= 8; s -= 8; } + if (x & 0xf000_0000) == 0 { x <<= 4; s -= 4; } + if (x & 0xc000_0000) == 0 { x <<= 2; s -= 2; } + if (x & 0x8000_0000) == 0 { x <<= 1; s -= 1; } + if s > 0 { s -= 1; } + if s > 7 { s = 7; } + } + let mut d = 0; + if self.host_spec_ver > HOST_SPEC_V2 { + d = c; + } else { + d = 1 << s; + } + + if d <= 2 { + d = 2; + s = 0; + } + println!("sd clk divisor: 0x{:08x}, shift: 0x{:08x}", d, s); + + let mut h = 0; + if self.host_spec_ver > HOST_SPEC_V2 { + h = (d & 0x300) >> 2; + } + + d = ( ((d & 0xff) << 8)| h); + reg_val = regs.control1.read() & 0xffff_003f; + regs.control1.write(reg_val | d); + wait_msec(10); + reg_val = regs.control1.read(); + regs.control1.write(reg_val | C1_CLK_EN); + wait_msec(10); + + reg_val = regs.control1.read() & C1_CLK_STABLE; + cnt = 10000; + while cnt > 0 && reg_val == 0 { + wait_msec(10); + cnt -= 1; + reg_val = regs.control1.read() & C1_CLK_STABLE; + } + + if cnt <= 0 { + println!("ERROR: failed to get stable clock"); + return Err(Error::new(EINVAL)); + } + + Ok(()) + } + + pub unsafe fn sd_cmd(&mut self, mut code: u32, arg: u32) -> Result { + if (code & CMD_NEED_APP) != 0 { + let pre_cmd = CMD_APP_CMD | if self.rca != 0 { CMD_RSPNS_48 } else { 0 }; + match self.sd_cmd(pre_cmd, self.rca) { + Err(_) => { + println!("ERROR: failed to send SD APP command"); + return Err(Error::new(EINVAL)); + } + Ok(_) => { + code &= !CMD_NEED_APP; + } + } + } + + if let Err(_) = self.sd_status(SR_CMD_INHIBIT) { + println!("ERROR: Emmc busy"); + return Err(Error::new(EINVAL)); + } + + //println!("EMMC: Sending command 0x{:08x}, arg 0x{:08x}", code, arg); + + let regs = self.regs.get_mut().unwrap(); + let mut reg_val = regs.interrupt.read(); + regs.interrupt.write(reg_val); + regs.arg1.write(arg); + regs.cmdtm.write(code); + + if code == CMD_SEND_OP_COND { + wait_msec(1000); + } else if code == CMD_SEND_IF_COND || code == CMD_APP_CMD { + wait_msec(200); + } + + if let Err(_) = self.sd_int(INT_CMD_DONE) { + println!("ERROR: failed to send EMMC command"); + return Err(Error::new(EINVAL)); + } + + let regs = self.regs.get_mut().unwrap(); + reg_val = regs.resp0.read(); + + if code == CMD_GO_IDLE || code == CMD_APP_CMD { + return Ok(0); + } else if code == (CMD_APP_CMD | CMD_RSPNS_48) { + return Ok(reg_val & SR_APP_CMD); + } else if code == CMD_SEND_OP_COND { + return Ok(reg_val); + } else if code == CMD_SEND_IF_COND { + if reg_val == arg { + return Ok(0); + } else { + return Err(Error::new(EINVAL)); + } + } else if code == CMD_ALL_SEND_CID { + self.cid[0] = reg_val; + self.cid[1] = regs.resp1.read(); + self.cid[2] = regs.resp2.read(); + self.cid[3] = regs.resp3.read(); + + //FIXME: wrong implement, see CMD_SEND_CSD for detail + return Ok(reg_val); + } else if code == CMD_SEND_CSD { + let tmp0 = reg_val; + let tmp1 = regs.resp1.read(); + let tmp2 = regs.resp2.read(); + let tmp3 = regs.resp3.read(); + + self.csd[0] = tmp3 << 8 | tmp2 >> 24; + self.csd[1] = tmp2 << 8 | tmp1 >> 24; + self.csd[2] = tmp1 << 8 | tmp0 >> 24; + self.csd[3] = tmp0 << 8; + + //FIXME: support variable length of result. + return Ok(reg_val); + } else if code == CMD_SEND_REL_ADDR { + let mut err = reg_val & 0x1fff; + err |= ((reg_val & 0x2000) << 6); + err |= ((reg_val & 0x4000) << 8); + err |= ((reg_val & 0x8000) << 8); + err &= CMD_ERRORS_MASK; + + if err != 0 { + return Err(Error::new(EINVAL)); + } else { + return Ok(reg_val & CMD_RCA_MASK); + } + } else { + return Ok(reg_val & CMD_ERRORS_MASK); + } + + } + + pub unsafe fn sd_status(&mut self, mask: u32) -> Result<()> { + let regs = self.regs.get_mut().unwrap(); + let mut cnt = 500000; + + let mut reg_val = regs.status.read() & mask; + let mut reg_val1 = regs.interrupt.read() & INT_ERROR_MASK; + + while cnt > 0 && reg_val != 0 && reg_val1 == 0 { + wait_msec(1); + cnt -= 1; + reg_val = regs.status.read() & mask; + reg_val1 = regs.interrupt.read() & INT_ERROR_MASK; + } + reg_val1 = regs.interrupt.read() & INT_ERROR_MASK; + + if cnt <= 0 || reg_val1 != 0 { + return Err(Error::new(EINVAL)); + } else { + return Ok(()); + } + } + pub unsafe fn sd_int(&mut self, mask: u32) -> Result<()> { + let regs = self.regs.get_mut().unwrap(); + let mut cnt = 100_0000; + let m = mask | INT_ERROR_MASK; + + let mut reg_val = regs.interrupt.read() & m; + + while cnt > 0 && reg_val == 0 { + wait_msec(1); + cnt -= 1; + reg_val = regs.interrupt.read() & m; + } + reg_val = regs.interrupt.read(); + let err = reg_val & (INT_CMD_TIMEOUT | INT_DATA_TIMEOUT | INT_ERROR_MASK); + + if cnt <= 0 || err != 0 { + regs.interrupt.write(reg_val); + return Err(Error::new(EINVAL)); + } else { + regs.interrupt.write(mask); + return Ok(()); + } + } + + pub unsafe fn sd_readblock(&mut self, lba: u32, buf: &mut [u32], num: u32) -> Result { + let num = if num < 1 { 1 } else { num }; + let mut reg_val: usize = 0; + + //println!("sd_readblock lba 0x{:x}, num 0x{:x}", lba, num); + + if let Err(_) = self.sd_status(SR_DAT_INHIBIT) { + println!("SR_DAT_INHIBIT TIMEOUT"); + return Err(Error::new(EINVAL)); + } + + if (self.scr[0] & SCR_SUPP_CCS) != 0 { + if num > 1 && ((self.scr[0] & SCR_SUPP_SET_BLKCNT) != 0) { + if let Err(_) = self.sd_cmd(CMD_SET_BLOCKCNT, num) { + println!("CMD_SET_BLOCKCNT ERROR"); + return Err(Error::new(EINVAL)); + } + } + let regs = self.regs.get_mut().unwrap(); + regs.blksizecnt.write((num) << 16 | 512); + if num == 1 { + self.sd_cmd(CMD_READ_SINGLE, lba).unwrap(); + } else { + self.sd_cmd(CMD_READ_MULTI, lba).unwrap(); + } + } else { + let regs = self.regs.get_mut().unwrap(); + regs.blksizecnt.write(1 << 16 | 512); + } + + let mut cnt = 0; + while cnt < num { + if (self.scr[0] & SCR_SUPP_CCS) == 0 { + self.sd_cmd(CMD_READ_SINGLE, (lba + cnt) * 512).unwrap(); + } + + if let Err(_) = self.sd_int(INT_READ_RDY) { + println!("ERROR: Timeout waiting for ready to read"); + return Err(Error::new(EINVAL)); + } + + let regs = self.regs.get_mut().unwrap(); + regs.blksizecnt.write(1 << 16 | 512); + for d in 0..128 { + buf[(128 * cnt + d) as usize] = regs.data.read(); + } + cnt += 1; + } + + if num > 1 && (self.scr[0] & SCR_SUPP_SET_BLKCNT) == 0 && (self.scr[0] & SCR_SUPP_CCS) != 0 { + self.sd_cmd(CMD_STOP_TRANS, 0).unwrap(); + } + Ok((num * 512) as usize) + } + + pub unsafe fn sd_writeblock(&mut self, lba: u32, buf: &[u32], num: u32) -> Result { + let num = if num < 1 { 1 } else { num }; + let mut reg_val: usize = 0; + + //println!("sd_writelock lba 0x{:x}, num 0x{:x}", lba, num); + + if let Err(_) = self.sd_status(SR_DAT_INHIBIT | SR_WRITE_AVAILABLE) { + println!("SR_DAT_INHIBIT TIMEOUT"); + return Err(Error::new(EINVAL)); + } + + if (self.scr[0] & SCR_SUPP_CCS) != 0 { + if num > 1 && ((self.scr[0] & SCR_SUPP_SET_BLKCNT) != 0) { + if let Err(_) = self.sd_cmd(CMD_SET_BLOCKCNT, num) { + println!("CMD_SET_BLOCKCNT ERROR"); + return Err(Error::new(EINVAL)); + } + } + let regs = self.regs.get_mut().unwrap(); + regs.blksizecnt.write((num) << 16 | 512); + if num == 1 { + self.sd_cmd(CMD_WRITE_SINGLE, lba).unwrap(); + } else { + self.sd_cmd(CMD_WRITE_MULTI, lba).unwrap(); + } + } else { + let regs = self.regs.get_mut().unwrap(); + regs.blksizecnt.write(1 << 16 | 512); + } + + let mut cnt = 0; + while cnt < num { + if (self.scr[0] & SCR_SUPP_CCS) == 0 { + self.sd_cmd(CMD_WRITE_SINGLE, (lba + cnt) * 512).unwrap(); + } + + if let Err(_) = self.sd_int(INT_WRITE_RDY) { + println!("ERROR: Timeout waiting for ready to write"); + return Err(Error::new(EINVAL)); + } + + let regs = self.regs.get_mut().unwrap(); + regs.blksizecnt.write(1 << 16 | 512); + for d in 0..128 { + regs.data.write(buf[(128 * cnt + d) as usize]); + } + cnt += 1; + } + + if let Err(_) = self.sd_int(INT_DATA_DONE) { + println!("ERROR: Timeout waiting for data done"); + return Err(Error::new(EINVAL)); + } + + if num > 1 && (self.scr[0] & SCR_SUPP_SET_BLKCNT) == 0 && (self.scr[0] & SCR_SUPP_CCS) != 0 { + self.sd_cmd(CMD_STOP_TRANS, 0).unwrap(); + } + Ok((num * 512) as usize) + } +} + +pub trait Disk { + fn id(&self) -> usize; + fn size(&mut self) -> u64; + fn read(&mut self, block:u64, buffer: &mut [u8]) -> syscall::error::Result>; + fn write(&mut self, block:u64, buffer: &[u8]) -> syscall::error::Result>; + fn block_length(&mut self) -> syscall::error::Result; +} + +impl Disk for SdHostCtrl { + fn id(&self) -> usize { + 0xdead_dead + } + + fn size(&mut self) -> u64 { + //assert 512MiB + self.size + } + + fn read(&mut self, block:u64, buffer: &mut [u8]) -> Result> { + if (buffer.len() % 512) != 0 { + println!("buffer.len {} should be aligned to {}", + buffer.len(), 512); + return Err(Error::new(EINVAL)); + } + let u32_len = buffer.len() / core::mem::size_of::(); + let num = buffer.len() / 512; + let u8_ptr = buffer.as_mut_ptr(); + let ret = unsafe { + let u32_buffer = core::slice::from_raw_parts_mut(u8_ptr as *mut u32, u32_len); + self.sd_readblock(block as u32, u32_buffer, num as u32) + }; + match ret { + Ok(cnt) => Ok(Some(cnt)), + Err(err) => Err(err) + } + } + + fn write(&mut self, block:u64, buffer: &[u8]) -> Result> { + if (buffer.len() % 512) != 0 { + println!("buffer.len {} should be aligned to {}", + buffer.len(), 512); + return Err(Error::new(EINVAL)); + } + let u32_len = buffer.len() / core::mem::size_of::(); + let num = buffer.len() / 512; + let u8_ptr = buffer.as_ptr(); + let ret = unsafe { + let u32_buffer = core::slice::from_raw_parts(u8_ptr as *const u32, u32_len); + self.sd_writeblock(block as u32, u32_buffer, num as u32) + }; + match ret { + Ok(cnt) => Ok(Some(cnt)), + Err(err) => Err(err) + } + } + + fn block_length(&mut self) -> Result { + Ok(512) + } + +} diff --git a/common/src/lib.rs b/common/src/lib.rs index 35827a2197..b35bdefe68 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -11,6 +11,7 @@ pub enum MemoryType { Writeback, Uncacheable, WriteCombining, + DeviceMemory, } impl Default for MemoryType { fn default() -> Self { @@ -35,6 +36,7 @@ pub unsafe fn physmap(base_phys: usize, len: usize, Prot { read, write }: Prot, MemoryType::Writeback => "wb", MemoryType::Uncacheable => "uc", MemoryType::WriteCombining => "wc", + MemoryType::DeviceMemory => "dev", }); let mode = match (read, write) { (true, true) => O_RDWR, From 0d99333c3f33f00391ba17b9fbe7a54330156fde Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 17 Nov 2023 18:56:26 +0100 Subject: [PATCH 0716/1301] Remove PhysBox. --- README.md | 2 - ac97d/src/device.rs | 16 +-- common/src/dma.rs | 189 +++++++--------------------- common/src/lib.rs | 10 ++ ided/src/ide.rs | 14 +-- nvmed/src/nvme/queues.rs | 4 +- sb16d/src/device.rs | 1 - virtio-blkd/src/scheme.rs | 4 +- virtio-core/src/legacy_transport.rs | 14 +-- virtio-core/src/transport.rs | 2 +- virtio-netd/src/scheme.rs | 4 +- xhcid/src/xhci/mod.rs | 24 ++-- 12 files changed, 84 insertions(+), 200 deletions(-) diff --git a/README.md b/README.md index eac9d4eab7..6ea4ee85e5 100644 --- a/README.md +++ b/README.md @@ -74,8 +74,6 @@ This section cover the interfaces used by Redox drivers. ### System Calls - `iopl` - syscall that sets the I/O privilege level. x86 has four privilege rings (0/1/2/3), of which the kernel runs in ring 0 and userspace in ring 3. IOPL can only be changed by the kernel, for obvious security reasons, and therefore the Redox kernel needs root to set it. It is unique for each process. Processes with IOPL=3 can access I/O ports, and the kernel can access them as well. -- `physalloc` - allocates physical memory frames. -- `physfree` - frees memory frames. ### Schemes diff --git a/ac97d/src/device.rs b/ac97d/src/device.rs index e40b7e44a0..e5b747e8f9 100644 --- a/ac97d/src/device.rs +++ b/ac97d/src/device.rs @@ -8,7 +8,7 @@ use syscall::error::{Error, EACCES, EBADF, Result, EINVAL, ENOENT}; use syscall::io::{Mmio, Pio, Io}; use syscall::scheme::SchemeBlockMut; -use common::dma::{Dma, PhysBox}; +use common::dma::Dma; use spin::Mutex; const NUM_SUB_BUFFS: usize = 32; @@ -145,24 +145,14 @@ pub struct Ac97 { impl Ac97 { pub unsafe fn new(bar0: u16, bar1: u16) -> Result { - let round_page = |size: usize| -> usize { - let page_size = 4096; - let pages = (size + (page_size - 1)) / page_size; - pages * page_size - }; - let bdl_size = round_page(NUM_SUB_BUFFS * mem::size_of::()); - let buf_size = round_page(NUM_SUB_BUFFS * SUB_BUFF_SIZE); - let mut module = Ac97 { mixer: MixerRegs::new(bar0), bus: BusRegs::new(bar1), - bdl: Dma::from_physbox_zeroed( + bdl: Dma::zeroed( //TODO: PhysBox::new_in_32bit_space(bdl_size)? - PhysBox::new(bdl_size)? )?.assume_init(), - buf: Dma::from_physbox_zeroed( + buf: Dma::zeroed( //TODO: PhysBox::new_in_32bit_space(buf_size)? - PhysBox::new(buf_size)? )?.assume_init(), handles: Mutex::new(BTreeMap::new()), next_id: AtomicUsize::new(0), diff --git a/common/src/dma.rs b/common/src/dma.rs index 204e9a3a4d..c2ecbc37fc 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -1,196 +1,100 @@ -use std::mem::{self, MaybeUninit}; +use std::mem::{self, MaybeUninit, size_of}; use std::ops::{Deref, DerefMut}; -use std::{ptr, slice}; +use std::ptr; use syscall::PAGE_SIZE; use syscall::Result; -use syscall::{PartialAllocStrategy, PhysallocFlags}; use crate::MemoryType; -/// An RAII guard of a physical memory allocation. Currently all physically allocated memory are -/// page-aligned and take up at least 4k of space (on x86_64). -#[derive(Debug)] -pub struct PhysBox { - address: usize, - size: usize -} - -fn assert_aligned(x: usize) { - assert_eq!(x % PAGE_SIZE, 0); -} - const DMA_MEMTY: MemoryType = { if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { - // aarch64 currently must map DMA memory without caching to ensure coherence + // x86 ensures cache coherence with DMA memory MemoryType::Writeback } else if cfg!(target_arch = "aarch64") { - // x86 ensures cache coherence with DMA memory + // aarch64 currently must map DMA memory without caching to ensure coherence MemoryType::Uncacheable } else { panic!("invalid arch") } }; -impl PhysBox { - /// Construct a PhysBox from an address and a size. The address must be page-aligned, and the - /// size must similarly be a multiple of the page size. - /// - /// # Safety - /// This function is unsafe because when dropping, Self has to a valid allocation. - pub unsafe fn from_raw_parts(address: usize, size: usize) -> Self { - assert_aligned(address); - assert_aligned(size); - - Self { - address, - size, - } - } - - /// Retrieve the byte address in physical memory, of this allocation. - pub fn address(&self) -> usize { - self.address - } - - /// Retrieve the size in bytes of the alloc. - pub fn size(&self) -> usize { - self.size - } - - /// Allocate physical memory that must reside in 32-bit space. - pub fn new_in_32bit_space(size: usize) -> Result { - Self::new_with_flags(size, PhysallocFlags::SPACE_32) - } - - pub fn new_with_flags(size: usize, flags: PhysallocFlags) -> Result { - assert!(!flags.contains(PhysallocFlags::PARTIAL_ALLOC)); - assert_aligned(size); - - let address = unsafe { syscall::physalloc2(size, flags.bits())? }; - Ok(unsafe { Self::from_raw_parts(address, size) }) - } - - /// "Partially" allocate physical memory, in the sense that the allocation may be smaller than - /// expected, but still with a minimum limit. This is particularly useful when the physical - /// memory space is fragmented, and a device supports scatter-gather I/O. In that case, the - /// driver can optimistically request e.g. 1 alloc of 1 MiB, with the minimum of 512 KiB. If - /// that first allocation only returns half the size, the driver can do another allocation - /// and then let the device use both buffers. - pub fn new_partial_allocation(size: usize, flags: PhysallocFlags, strategy: Option, mut min: usize) -> Result { - assert_aligned(size); - debug_assert!(!(flags.contains(PhysallocFlags::PARTIAL_ALLOC) && strategy.is_none())); - - let address = unsafe { syscall::physalloc3(size, flags.bits() | strategy.map_or(0, |s| s as usize), &mut min)? }; - Ok(unsafe { Self::from_raw_parts(address, size) }) - } - - pub fn new(size: usize) -> Result { - assert_aligned(size); - - let address = unsafe { syscall::physalloc(size)? }; - Ok(unsafe { Self::from_raw_parts(address, size) }) - } -} - -impl Drop for PhysBox { - fn drop(&mut self) { - let _ = unsafe { syscall::physfree(self.address, self.size) }; +fn alloc_and_map(len: usize) -> Result<(usize, *mut ())> { + assert_eq!(len % PAGE_SIZE, 0); + unsafe { + let fd = syscall::open(format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), syscall::O_CLOEXEC)?; + let virt = syscall::fmap(fd, &syscall::Map { + offset: 0, // ignored + address: 0, // ignored + size: len, + flags: syscall::MapFlags::MAP_PRIVATE | syscall::MapFlags::PROT_READ | syscall::MapFlags::PROT_WRITE, + }); + let _ = syscall::close(fd); + let virt = virt?; + let phys = syscall::virttophys(virt)?; + /*for i in 1..len.div_ceil(PAGE_SIZE) { + assert_eq!(syscall::virttophys(virt + i * PAGE_SIZE), Ok(phys + i * PAGE_SIZE), "NOT CONTIGUOUS"); + }*/ + Ok((phys, virt as *mut ())) } } pub struct Dma { - phys: PhysBox, + phys: usize, + aligned_len: usize, virt: *mut T, } impl Dma { - pub fn from_physbox_uninit(phys: PhysBox) -> Result>> { - Ok(Dma { - virt: unsafe { crate::physmap(phys.address, phys.size, crate::Prot::RW, DMA_MEMTY)? } as *mut MaybeUninit, - phys, - }) - } - pub fn from_physbox_zeroed(phys: PhysBox) -> Result>> { - let this = Self::from_physbox_uninit(phys)?; - unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit, 0, this.phys.size) } - Ok(this) - } - - pub fn from_physbox(phys: PhysBox, value: T) -> Result { - let this = Self::from_physbox_uninit(phys)?; - - Ok(unsafe { - ptr::write(this.virt, MaybeUninit::new(value)); - this.assume_init() - }) - } - pub fn new(value: T) -> Result { - let phys = PhysBox::new(mem::size_of::().next_multiple_of(PAGE_SIZE))?; - Self::from_physbox(phys, value) + unsafe { + let mut zeroed = Self::zeroed()?; + zeroed.as_mut_ptr().write(value); + Ok(zeroed.assume_init()) + } } pub fn zeroed() -> Result>> { - let phys = PhysBox::new(mem::size_of::().next_multiple_of(PAGE_SIZE))?; - Self::from_physbox_zeroed(phys) + let aligned_len = size_of::().next_multiple_of(PAGE_SIZE); + let (phys, virt) = alloc_and_map(aligned_len)?; + Ok(Dma { phys, virt: virt.cast(), aligned_len }) } } impl Dma> { pub unsafe fn assume_init(self) -> Dma { - let &Dma { phys: PhysBox { address, size }, virt } = &self; + let Dma { phys, aligned_len, virt } = self; mem::forget(self); Dma { - phys: PhysBox { address, size }, - virt: virt as *mut T, + phys, + aligned_len, + virt: virt.cast(), } } } impl Dma { pub fn physical(&self) -> usize { - self.phys.address() - } - pub fn size(&self) -> usize { - self.phys.size() - } - pub fn phys(&self) -> &PhysBox { - &self.phys + self.phys } } impl Dma<[T]> { - pub fn from_physbox_uninit_unsized(phys: PhysBox, len: usize) -> Result]>> { - let max_len = phys.size() / mem::size_of::(); - assert!(len <= max_len); + pub fn zeroed_slice(count: usize) -> Result]>> { + let aligned_len = count.checked_mul(size_of::()).unwrap().next_multiple_of(PAGE_SIZE); + let (phys, virt) = alloc_and_map(aligned_len)?; - Ok(Dma { - virt: unsafe { slice::from_raw_parts_mut(crate::physmap(phys.address, phys.size, crate::Prot::RW, DMA_MEMTY)? as *mut MaybeUninit, len) } as *mut [MaybeUninit], - phys, - }) - } - pub fn from_physbox_zeroed_unsized(phys: PhysBox, len: usize) -> Result]>> { - let this = Self::from_physbox_uninit_unsized(phys, len)?; - unsafe { ptr::write_bytes(this.virt as *mut MaybeUninit, 0, this.phys.size()) } - Ok(this) - } - /// Creates a new DMA buffer with a size only known at runtime. - /// ## Safety - /// * `T` must be properly aligned. - /// * `T` must be valid as zeroed (i.e. no NonNull pointers). - pub unsafe fn zeroed_unsized(count: usize) -> Result { - let phys = PhysBox::new((mem::size_of::() * count).next_multiple_of(PAGE_SIZE))?; - Ok(Self::from_physbox_zeroed_unsized(phys, count)?.assume_init()) + Ok(Dma { phys, aligned_len, virt: ptr::slice_from_raw_parts_mut(virt.cast(), count) }) } } impl Dma<[MaybeUninit]> { pub unsafe fn assume_init(self) -> Dma<[T]> { - let &Dma { phys: PhysBox { address, size }, virt } = &self; + let &Dma { phys, aligned_len, virt } = &self; mem::forget(self); Dma { - phys: PhysBox { address, size }, + phys, + aligned_len, virt: virt as *mut [T], } } @@ -198,6 +102,7 @@ impl Dma<[MaybeUninit]> { impl Deref for Dma { type Target = T; + fn deref(&self) -> &T { unsafe { &*self.virt } } @@ -211,7 +116,9 @@ impl DerefMut for Dma { impl Drop for Dma { fn drop(&mut self) { - unsafe { ptr::drop_in_place(self.virt) } - let _ = unsafe { syscall::funmap(self.virt as *mut u8 as usize, self.phys.size) }; + unsafe { + ptr::drop_in_place(self.virt); + let _ = syscall::funmap(self.virt as *mut u8 as usize, self.aligned_len); + } } } diff --git a/common/src/lib.rs b/common/src/lib.rs index b35bdefe68..972d234cf0 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -59,3 +59,13 @@ pub unsafe fn physmap(base_phys: usize, len: usize, Prot { read, write }: Prot, Ok(base? as *mut ()) } + +impl std::fmt::Display for MemoryType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + Self::Writeback => "wb", + Self::Uncacheable => "uc", + Self::WriteCombining => "wc", + }) + } +} diff --git a/ided/src/ide.rs b/ided/src/ide.rs index dff603f90e..259997ab7d 100644 --- a/ided/src/ide.rs +++ b/ided/src/ide.rs @@ -10,7 +10,7 @@ use syscall::{ io::{Io, Pio, ReadOnly, WriteOnly}, }; -use common::dma::{Dma, PhysBox}; +use common::dma::Dma; static TIMEOUT: Duration = Duration::new(1, 0); @@ -61,7 +61,7 @@ pub struct Channel { impl Channel { pub fn new(base: u16, control_base: u16, busmaster_base: u16) -> Result { - let mut chan = Self { + Ok(Self { data8: Pio::new(base + 0), data32: Pio::new(base + 0), error: ReadOnly::new(Pio::new(base + 1)), @@ -79,20 +79,16 @@ impl Channel { busmaster_status: Pio::new(busmaster_base + 2), busmaster_prdt: Pio::new(busmaster_base + 4), prdt: unsafe { - Dma::from_physbox_zeroed( + Dma::zeroed( //TODO: PhysBox::new_in_32bit_space(4096)? - PhysBox::new(4096 /* 128 * 8 page aligned */)? )?.assume_init() }, buf: unsafe { - Dma::from_physbox_zeroed( + Dma::zeroed( //TODO: PhysBox::new_in_32bit_space(16 * 4096)? - PhysBox::new(128 * 512)? )?.assume_init() }, - }; - - Ok(chan) + }) } pub fn primary_compat(busmaster_base: u16) -> Result { diff --git a/nvmed/src/nvme/queues.rs b/nvmed/src/nvme/queues.rs index 892e220448..3fd1b23adf 100644 --- a/nvmed/src/nvme/queues.rs +++ b/nvmed/src/nvme/queues.rs @@ -57,7 +57,7 @@ pub struct NvmeCompQueue { impl NvmeCompQueue { pub fn new() -> Result { Ok(Self { - data: unsafe { Dma::zeroed_unsized(256)? }, + data: unsafe { Dma::zeroed_slice(256)?.assume_init() }, head: 0, phase: true, }) @@ -110,7 +110,7 @@ pub struct NvmeCmdQueue { impl NvmeCmdQueue { pub fn new() -> Result { Ok(Self { - data: unsafe { Dma::zeroed_unsized(64)? }, + data: unsafe { Dma::zeroed_slice(64)?.assume_init() }, tail: 0, head: 0, }) diff --git a/sb16d/src/device.rs b/sb16d/src/device.rs index 1e03f877a2..101d6e329b 100644 --- a/sb16d/src/device.rs +++ b/sb16d/src/device.rs @@ -8,7 +8,6 @@ use syscall::error::{Error, EACCES, EBADF, Result, EINVAL, ENODEV, ENOENT}; use syscall::io::{Mmio, Pio, Io, ReadOnly, WriteOnly}; use syscall::scheme::SchemeBlockMut; -use common::dma::{Dma, PhysBox}; use spin::Mutex; const NUM_SUB_BUFFS: usize = 32; diff --git a/virtio-blkd/src/scheme.rs b/virtio-blkd/src/scheme.rs index 9913c6711b..a92f084444 100644 --- a/virtio-blkd/src/scheme.rs +++ b/virtio-blkd/src/scheme.rs @@ -35,7 +35,7 @@ impl BlkExtension for Queue<'_> { }) .unwrap(); - let result = unsafe { Dma::<[u8]>::zeroed_unsized(target.len()) }.unwrap(); + let result = unsafe { Dma::<[u8]>::zeroed_slice(target.len()).unwrap().assume_init() }; let status = Dma::new(u8::MAX).unwrap(); let chain = ChainBuilder::new() @@ -60,7 +60,7 @@ impl BlkExtension for Queue<'_> { }) .unwrap(); - let mut result = unsafe { Dma::<[u8]>::zeroed_unsized(target.len()) }.unwrap(); + let mut result = unsafe { Dma::<[u8]>::zeroed_slice(target.len()).unwrap().assume_init() }; result.copy_from_slice(target.as_ref()); let status = Dma::new(u8::MAX).unwrap(); diff --git a/virtio-core/src/legacy_transport.rs b/virtio-core/src/legacy_transport.rs index 7769d597ac..f2d7535ad0 100644 --- a/virtio-core/src/legacy_transport.rs +++ b/virtio-core/src/legacy_transport.rs @@ -1,6 +1,6 @@ use std::{sync::{Weak, atomic::{AtomicU16, Ordering}, Arc}, mem::size_of, fs::File}; -use common::dma::{PhysBox, Dma}; +use common::dma::Dma; use syscall::{Pio, Io}; use crate::{transport::{NotifyBell, Transport, Queue, Error, Available, Used, queue_part_sizes, spawn_irq_thread}, spec::{Descriptor, DeviceStatusFlags}}; @@ -118,24 +118,18 @@ impl Transport for LegacyTransport { let queue_size = self.read::(LegacyRegister::QueueSize) as usize; let (desc_size, avail_size, used_size) = queue_part_sizes(queue_size); - let size_bytes = desc_size + avail_size + used_size; - let addr = unsafe { syscall::physalloc(size_bytes).map_err(Error::SyscallError)? }; - let descriptor = unsafe { - let physbox = PhysBox::from_raw_parts(addr, desc_size); - let table = Dma::<[Descriptor]>::from_physbox_uninit_unsized(physbox, queue_size)?; - - table.assume_init() + Dma::<[Descriptor]>::zeroed_slice(queue_size)?.assume_init() }; - let avail_addr = addr + desc_size; + let avail_addr = descriptor.physical() + desc_size; let avail = unsafe { Available::from_raw(avail_addr, avail_size, queue_size)? }; let used_addr = avail_addr + avail_size; let used = unsafe { Used::from_raw(used_addr, used_size, queue_size)? }; self.write::(LegacyRegister::QueueMsixVector, vector); - self.write::(LegacyRegister::QueueAddress, (addr as u32) >> 12); + self.write::(LegacyRegister::QueueAddress, (descriptor.physical() as u32) >> 12); log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})"); diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 95a9001fb8..7a2c662d10 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -588,7 +588,7 @@ impl Transport for StandardTransport<'_> { // Allocate memory for the queue structues. let descriptor = unsafe { - Dma::<[Descriptor]>::zeroed_unsized(queue_size).map_err(Error::SyscallError)? + Dma::<[Descriptor]>::zeroed_slice(queue_size).map_err(Error::SyscallError)?.assume_init() }; let avail = Available::new(queue_size)?; diff --git a/virtio-netd/src/scheme.rs b/virtio-netd/src/scheme.rs index 829a3002e6..5a48cba19f 100644 --- a/virtio-netd/src/scheme.rs +++ b/virtio-netd/src/scheme.rs @@ -31,7 +31,7 @@ impl<'a> NetworkScheme<'a> { // Populate all of the `rx_queue` with buffers to maximize performence. let mut rx_buffers = vec![]; for i in 0..(rx.descriptor_len() as usize) { - rx_buffers.push(unsafe { Dma::<[u8]>::zeroed_unsized(MAX_BUFFER_LEN) }.unwrap()); + rx_buffers.push(unsafe { Dma::<[u8]>::zeroed_slice(MAX_BUFFER_LEN).unwrap().assume_init() }); let chain = ChainBuilder::new() .chain(Buffer::new_unsized(&rx_buffers[i]).flags(DescriptorFlags::WRITE_ONLY)) @@ -123,7 +123,7 @@ impl<'a> SchemeBlockMut for NetworkScheme<'a> { let header = unsafe { Dma::::zeroed()?.assume_init() }; - let mut payload = unsafe { Dma::<[u8]>::zeroed_unsized(buffer.len())? }; + let mut payload = unsafe { Dma::<[u8]>::zeroed_slice(buffer.len())?.assume_init() }; payload.copy_from_slice(buffer); let chain = ChainBuilder::new() diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 99efcbd2e5..afe56101b8 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -14,7 +14,7 @@ use syscall::flag::{O_RDONLY, PhysallocFlags}; use syscall::io::Io; use chashmap::CHashMap; -use common::dma::{Dma, PhysBox}; +use common::dma::Dma; use crossbeam_channel::{Receiver, Sender}; use log::{debug, error, info, trace, warn}; use serde::Deserialize; @@ -490,26 +490,16 @@ impl Xhci { pub fn slot_state(&self, slot: usize) -> u8 { self.dev_ctx.contexts[slot].slot.state() } - pub unsafe fn alloc_phys(ac64: bool, byte_count: usize) -> Result { - let flags = if ac64 { - PhysallocFlags::SPACE_64 - } else { - PhysallocFlags::SPACE_32 - }; - PhysBox::new_with_flags(byte_count, flags) - } - fn page_align(size: usize) -> usize { - // TODO: PAGE_SIZE - (size+4095)/4096*4096 - } - pub unsafe fn alloc_dma_zeroed_raw(ac64: bool) -> Result> { - Ok(Dma::from_physbox_zeroed(Self::alloc_phys(ac64, Self::page_align(mem::size_of::()))?)?.assume_init()) + pub unsafe fn alloc_dma_zeroed_raw(_ac64: bool) -> Result> { + // TODO: ac64 + Ok(Dma::zeroed()?.assume_init()) } pub unsafe fn alloc_dma_zeroed(&self) -> Result> { Self::alloc_dma_zeroed_raw(self.cap.ac64()) } - pub unsafe fn alloc_dma_zeroed_unsized_raw(ac64: bool, count: usize) -> Result> { - Ok(Dma::from_physbox_zeroed_unsized(Self::alloc_phys(ac64, Self::page_align(mem::size_of::() * count))?, count)?.assume_init()) + pub unsafe fn alloc_dma_zeroed_unsized_raw(_ac64: bool, count: usize) -> Result> { + // TODO: ac64 + Ok(Dma::zeroed_slice(count)?.assume_init()) } pub unsafe fn alloc_dma_zeroed_unsized(&self, count: usize) -> Result> { Self::alloc_dma_zeroed_unsized_raw(self.cap.ac64(), count) From ea73da92bf3d581e19c50f836a51c86e691cedf6 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 17 Nov 2023 19:36:28 +0100 Subject: [PATCH 0717/1301] Replace all physalloc usages with Dma. --- common/src/dma.rs | 10 +++ ihdad/src/hda/cmdbuff.rs | 21 +++-- ihdad/src/hda/device.rs | 41 ++++----- ihdad/src/hda/stream.rs | 47 ++-------- virtio-core/src/legacy_transport.rs | 8 +- virtio-core/src/transport.rs | 134 ++++++++++++++++------------ virtio-gpud/src/scheme.rs | 19 ++-- xhcid/src/xhci/context.rs | 17 ++-- xhcid/src/xhci/mod.rs | 13 +-- 9 files changed, 153 insertions(+), 157 deletions(-) diff --git a/common/src/dma.rs b/common/src/dma.rs index c2ecbc37fc..3a092f1024 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -86,6 +86,16 @@ impl Dma<[T]> { Ok(Dma { phys, aligned_len, virt: ptr::slice_from_raw_parts_mut(virt.cast(), count) }) } + pub unsafe fn cast_slice(self) -> Dma<[U]> { + let Dma { phys, virt, aligned_len } = self; + core::mem::forget(self); + + Dma { + phys, + virt: virt as *mut [U], + aligned_len, + } + } } impl Dma<[MaybeUninit]> { pub unsafe fn assume_init(self) -> Dma<[T]> { diff --git a/ihdad/src/hda/cmdbuff.rs b/ihdad/src/hda/cmdbuff.rs index a401a1053a..a4af7820d7 100644 --- a/ihdad/src/hda/cmdbuff.rs +++ b/ihdad/src/hda/cmdbuff.rs @@ -1,3 +1,4 @@ +use common::dma::Dma; use syscall::io::{Io, Mmio}; use super::common::*; @@ -345,31 +346,33 @@ pub struct CommandBuffer { corb_rirb_base_phys: usize, use_immediate_cmd: bool, + mem: Dma<[u8; 0x1000]>, } impl CommandBuffer { pub fn new( regs_addr: usize, - cmd_buff_frame_phys: usize, - cmd_buff_frame: usize, + cmd_buff: Dma<[u8; 0x1000]>, ) -> CommandBuffer { - let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff_frame_phys, cmd_buff_frame); + let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff.physical(), cmd_buff.as_ptr() as usize); let rirb = Rirb::new( regs_addr + RIRB_OFFSET, - cmd_buff_frame_phys + CORB_BUFF_MAX_SIZE, - cmd_buff_frame + CORB_BUFF_MAX_SIZE, + cmd_buff.as_ptr() as usize + CORB_BUFF_MAX_SIZE, + cmd_buff.physical() + CORB_BUFF_MAX_SIZE, ); let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET); let cmdbuff = CommandBuffer { - corb: corb, - rirb: rirb, - icmd: icmd, + corb, + rirb, + icmd, - corb_rirb_base_phys: cmd_buff_frame_phys, + corb_rirb_base_phys: cmd_buff.physical(), use_immediate_cmd: false, + + mem: cmd_buff, }; cmdbuff diff --git a/ihdad/src/hda/device.rs b/ihdad/src/hda/device.rs index 718ab6ed73..09d2c56bfb 100755 --- a/ihdad/src/hda/device.rs +++ b/ihdad/src/hda/device.rs @@ -7,6 +7,7 @@ use std::str; use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; +use common::dma::Dma; use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; use syscall::io::{Mmio, Io}; @@ -137,8 +138,7 @@ pub struct IntelHDA { beep_addr: WidgetAddr, - buff_desc: &'static mut [BufferDescriptorListEntry; 256], - buff_desc_phys: usize, + buff_desc: Dma<[BufferDescriptorListEntry; 256]>, output_streams: Vec, @@ -153,31 +153,23 @@ impl IntelHDA { pub unsafe fn new(base: usize, vend_prod:u32) -> Result { let regs = &mut *(base as *mut Regs); - let buff_desc_phys = - syscall::physalloc(0x1000) - .expect("Could not allocate physical memory for buffer descriptor list."); + let buff_desc = Dma::<[BufferDescriptorListEntry; 256]>::zeroed() + .expect("Could not allocate physical memory for buffer descriptor list.") + .assume_init(); - let buff_desc_virt = - common::physmap(buff_desc_phys, 0x1000, common::Prot::RW, common::MemoryType::Uncacheable) - .expect("ihdad: failed to map address for buffer descriptor list.") as usize; + log::debug!("Virt: {:016X}, Phys: {:016X}", buff_desc.as_ptr() as usize, buff_desc.physical()); - log::debug!("Virt: {:016X}, Phys: {:016X}", buff_desc_virt, buff_desc_phys); + let cmd_buff = Dma::<[u8; 0x1000]>::zeroed() + .expect("Could not allocate physical memory for CORB and RIRB.") + .assume_init(); - let buff_desc = &mut *(buff_desc_virt as *mut [BufferDescriptorListEntry;256]); - - let cmd_buff_address = - syscall::physalloc(0x1000) - .expect("Could not allocate physical memory for CORB and RIRB."); - - let cmd_buff_virt = common::physmap(cmd_buff_address, 0x1000, common::Prot::RW, common::MemoryType::Uncacheable).expect("ihdad: failed to map address for CORB/RIRB buff") as usize; - - log::debug!("Virt: {:016X}, Phys: {:016X}", cmd_buff_virt, cmd_buff_address); + log::debug!("Virt: {:016X}, Phys: {:016X}", cmd_buff.as_ptr() as usize, cmd_buff.physical()); let mut module = IntelHDA { - vend_prod: vend_prod, - base: base, - regs: regs, + vend_prod, + base, + regs, - cmd: CommandBuffer::new(base + COMMAND_BUFFER_OFFSET, cmd_buff_address, cmd_buff_virt), + cmd: CommandBuffer::new(base + COMMAND_BUFFER_OFFSET, cmd_buff), beep_addr: (0,0), @@ -191,8 +183,7 @@ impl IntelHDA { output_pins: Vec::::new(), input_pins: Vec::::new(), - buff_desc: buff_desc, - buff_desc_phys: buff_desc_phys, + buff_desc, output_streams: Vec::::new(), @@ -498,7 +489,7 @@ impl IntelHDA { // Create output stream let output = self.get_output_stream_descriptor(0).unwrap(); - output.set_address(self.buff_desc_phys); + output.set_address(self.buff_desc.physical()); output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); output.set_cyclic_buffer_length((NUM_SUB_BUFFS * SUB_BUFF_SIZE) as u32); // number of bytes output.set_stream_number(1); diff --git a/ihdad/src/hda/stream.rs b/ihdad/src/hda/stream.rs index 62acd2c6d5..afad58a609 100644 --- a/ihdad/src/hda/stream.rs +++ b/ihdad/src/hda/stream.rs @@ -1,3 +1,4 @@ +use common::dma::Dma; use syscall::PAGE_SIZE; use syscall::error::{Error, EIO, Result}; use syscall::io::{Mmio, Io}; @@ -281,8 +282,7 @@ impl BufferDescriptorListEntry { } pub struct StreamBuffer { - phys: usize, - addr: usize, + mem: Dma<[u8]>, block_cnt: usize, block_len: usize, @@ -293,36 +293,10 @@ pub struct StreamBuffer { impl StreamBuffer { pub fn new(block_length: usize, block_count: usize) -> result::Result { let page_aligned_size = (block_length * block_count).next_multiple_of(PAGE_SIZE); - - let phys = match unsafe { - syscall::physalloc(page_aligned_size) - } { - Ok(phys) => phys, - Err(_err) => { - return Err("Could not allocate physical memory for buffer."); - } - }; - - let addr = match unsafe { - common::physmap(phys, page_aligned_size, common::Prot::RW, common::MemoryType::Uncacheable) - } { - Ok(ptr) => ptr as usize, - Err(_err) => { - unsafe { - syscall::physfree(phys, page_aligned_size); - } - return Err("Could not map physical memory for buffer."); - } - }; - - // TODO: Already zeroed by kernel? - unsafe { - ptr::write_bytes(addr as *mut u8, 0, block_length * block_count); - } + let mem = unsafe { Dma::zeroed_slice(page_aligned_size).map_err(|_| "Could not allocate physical memory for buffer.")?.assume_init() }; Ok(StreamBuffer { - phys: phys, - addr: addr, + mem, block_len: block_length, block_cnt: block_count, cur_pos: 0, @@ -334,11 +308,11 @@ impl StreamBuffer { } pub fn addr(&self) -> usize { - self.addr + self.mem.as_ptr() as usize } pub fn phys(&self) -> usize { - self.phys + self.mem.physical() } pub fn block_size(&self) -> usize { @@ -374,13 +348,6 @@ impl StreamBuffer { } impl Drop for StreamBuffer { fn drop(&mut self) { - unsafe { - log::debug!("IHDA: Deallocating buffer."); - let page_aligned_size = (self.block_len * self.block_cnt).next_multiple_of(PAGE_SIZE); - - if syscall::funmap(self.addr, page_aligned_size).is_ok() { - let _ = syscall::physfree(self.phys, page_aligned_size); - } - } + log::debug!("IHDA: Deallocating buffer."); } } diff --git a/virtio-core/src/legacy_transport.rs b/virtio-core/src/legacy_transport.rs index f2d7535ad0..e0a98e784f 100644 --- a/virtio-core/src/legacy_transport.rs +++ b/virtio-core/src/legacy_transport.rs @@ -3,7 +3,7 @@ use std::{sync::{Weak, atomic::{AtomicU16, Ordering}, Arc}, mem::size_of, fs::Fi use common::dma::Dma; use syscall::{Pio, Io}; -use crate::{transport::{NotifyBell, Transport, Queue, Error, Available, Used, queue_part_sizes, spawn_irq_thread}, spec::{Descriptor, DeviceStatusFlags}}; +use crate::{transport::{NotifyBell, Transport, Queue, Error, Available, Used, queue_part_sizes, spawn_irq_thread, Mem, Borrowed}, spec::{Descriptor, DeviceStatusFlags}}; pub enum LegacyRegister { @@ -123,10 +123,12 @@ impl Transport for LegacyTransport { }; let avail_addr = descriptor.physical() + desc_size; - let avail = unsafe { Available::from_raw(avail_addr, avail_size, queue_size)? }; + let avail_virt = (descriptor.as_ptr() as usize) + desc_size; + let avail = unsafe { Available::from_raw(Mem::Borrowed(Borrowed::new(avail_addr, avail_virt, avail_size)), queue_size)? }; let used_addr = avail_addr + avail_size; - let used = unsafe { Used::from_raw(used_addr, used_size, queue_size)? }; + let used_virt = avail_virt + desc_size; + let used = unsafe { Used::from_raw(Mem::Borrowed(Borrowed::new(used_addr, used_virt, used_size)), queue_size)? }; self.write::(LegacyRegister::QueueMsixVector, vector); self.write::(LegacyRegister::QueueAddress, (descriptor.physical() as u32) >> 12); diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 7a2c662d10..a324a288cc 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -263,33 +263,68 @@ unsafe impl Sync for Queue<'_> {} unsafe impl Send for Queue<'_> {} pub struct Available<'a> { - addr: usize, - size: usize, - + mem: Mem<'a>, queue_size: usize, - - ring: &'a mut AvailableRing, +} +pub struct Borrowed<'a> { + phys: usize, + virt: usize, + size: usize, + _unused: &'a (), +} +pub enum Mem<'a> { + Owned(Dma<[u8]>), + Borrowed(Borrowed<'a>), +} +impl Borrowed<'_> { + pub unsafe fn new(phys: usize, virt: usize, size: usize) -> Self { + Self { + phys, + virt, + size, + _unused: &(), + } + } +} +impl<'a> Mem<'a> { + pub fn as_ptr(&self) -> *const T { + match *self { + Self::Owned(ref dma) => dma.as_ptr().cast(), + Self::Borrowed(Borrowed { phys, virt, size, _unused }) => virt as *const T, + } + } + pub fn as_mut_ptr(&mut self) -> *mut T { + match *self { + Self::Owned(ref mut dma) => dma.as_mut_ptr().cast(), + Self::Borrowed(Borrowed { phys, virt, size, _unused }) => virt as *mut T, + } + } + pub fn physical(&self) -> usize { + match self { + Self::Owned(dma) => dma.physical(), + Self::Borrowed(borrowed) => borrowed.phys, + } + } } impl<'a> Available<'a> { + pub fn ring(&self) -> &AvailableRing { + unsafe { &*self.mem.as_ptr() } + } + pub fn ring_mut(&mut self) -> &mut AvailableRing { + unsafe { &mut *self.mem.as_mut_ptr() } + } pub fn new(queue_size: usize) -> Result { let (_, _, size) = queue_part_sizes(queue_size); - let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; + let mem = unsafe { Dma::zeroed_slice(size).map_err(Error::SyscallError)?.assume_init() }; - unsafe { Self::from_raw(addr, size, queue_size) } + unsafe { Self::from_raw(Mem::Owned(mem), queue_size) } } /// `addr` is the physical address of the ring. - pub unsafe fn from_raw(addr: usize, size: usize, queue_size: usize) -> Result { - let virt = unsafe { - common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) - }?; - - let ring = unsafe { &mut *(virt as *mut AvailableRing) }; + pub unsafe fn from_raw(mem: Mem<'a>, queue_size: usize) -> Result { let ring = Self { - addr, - size, - ring, + mem, queue_size, }; @@ -310,7 +345,7 @@ impl<'a> Available<'a> { // SAFETY: We have exclusive access to the elements and the number of elements // is correct; same as the queue size. unsafe { - self.ring + self.ring() .elements .as_slice(self.queue_size) .get(index % self.queue_size) @@ -319,58 +354,51 @@ impl<'a> Available<'a> { } pub fn head_index(&self) -> u16 { - self.ring.head_index.load(Ordering::SeqCst) + self.ring().head_index.load(Ordering::SeqCst) } pub fn set_head_idx(&self, index: u16) { - self.ring.head_index.store(index, Ordering::SeqCst); + self.ring().head_index.store(index, Ordering::SeqCst); } pub fn phys_addr(&self) -> usize { - self.addr + self.mem.physical() } } -impl Drop for Available<'_> { +impl<'a> Drop for Available<'a> { fn drop(&mut self) { - log::warn!("virtio-core: dropping 'available' ring at {:#x}", self.addr); - - unsafe { - syscall::funmap(self.addr, self.size).unwrap(); - syscall::physfree(self.addr, self.size).unwrap(); - } + log::warn!("virtio-core: dropping 'available' ring at {:#x}", self.phys_addr()); } } pub struct Used<'a> { - addr: usize, - size: usize, - + mem: Mem<'a>, queue_size: usize, - - ring: &'a mut UsedRing, + _unused: &'a (), } impl<'a> Used<'a> { + fn ring(&self) -> &UsedRing { + unsafe { &*self.mem.as_ptr() } + } + fn ring_mut(&mut self) -> &mut UsedRing { + unsafe { &mut *self.mem.as_mut_ptr() } + } + pub fn new(queue_size: usize) -> Result { let (_, _, size) = queue_part_sizes(queue_size); - let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?; + let mem = unsafe { Dma::zeroed_slice(size).map_err(Error::SyscallError)?.assume_init() }; - unsafe { Self::from_raw(addr, size, queue_size) } + unsafe { Self::from_raw(Mem::Owned(mem), queue_size) } } /// `addr` is the physical address of the ring. - pub unsafe fn from_raw(addr: usize, size: usize, queue_size: usize) -> Result { - let virt = unsafe { - common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) - }?; - - let ring = unsafe { &mut *(virt as *mut UsedRing) }; + pub unsafe fn from_raw(mem: Mem<'a>, queue_size: usize) -> Result { let mut ring = Self { - addr, - size, - ring, + mem, queue_size, + _unused: &(), }; for i in 0..queue_size { @@ -388,7 +416,7 @@ impl<'a> Used<'a> { // SAFETY: We have exclusive access to the elements and the number of elements // is correct; same as the queue size. unsafe { - self.ring + self.ring() .elements .as_slice(self.queue_size) .get(index % self.queue_size) @@ -401,36 +429,32 @@ impl<'a> Used<'a> { pub fn get_mut_element_at(&mut self, index: usize) -> &mut UsedRingElement { // SAFETY: We have exclusive access to the elements and the number of elements // is correct; same as the queue size. + let queue_size = self.queue_size; unsafe { - self.ring + self.ring_mut() .elements - .as_mut_slice(self.queue_size) + .as_mut_slice(queue_size) .get_mut(index % 256) .expect("virtio-core::used: index out of bounds") } } pub fn flags(&self) -> u16 { - self.ring.flags.get() + self.ring().flags.get() } pub fn head_index(&self) -> u16 { - self.ring.head_index.get() + self.ring().head_index.get() } pub fn phys_addr(&self) -> usize { - self.addr + self.mem.physical() } } impl Drop for Used<'_> { fn drop(&mut self) { - log::warn!("virtio-core: dropping 'used' ring at {:#x}", self.addr); - - unsafe { - syscall::funmap(self.addr, self.size).unwrap(); - syscall::physfree(self.addr, self.size).unwrap(); - } + log::warn!("virtio-core: dropping 'used' ring at {:#x}", self.phys_addr()); } } diff --git a/virtio-gpud/src/scheme.rs b/virtio-gpud/src/scheme.rs index 30dded638f..51cd14a76a 100644 --- a/virtio-gpud/src/scheme.rs +++ b/virtio-gpud/src/scheme.rs @@ -130,21 +130,18 @@ impl<'a> Display<'a> { let bpp = 32; let fb_size = (self.width as usize * self.height as usize * bpp / 8) .next_multiple_of(syscall::PAGE_SIZE); - let address = unsafe { syscall::physalloc(fb_size) }?; - let mapped = unsafe { - common::physmap( - address as usize, - fb_size, - common::Prot::RW, - common::MemoryType::default(), - ) - }? as usize; + let mut mapped = unsafe { Dma::zeroed_slice(fb_size)?.assume_init() }; unsafe { - core::ptr::write_bytes(mapped as *mut u8, 255, fb_size); + core::ptr::write_bytes(mapped.as_mut_ptr() as *mut u8, 255, fb_size); } - self.map_screen_with(offset, address, fb_size, mapped).await + let virt = mapped.as_mut_ptr() as usize; + let phys = mapped.physical(); + core::mem::forget(mapped); + // TODO: Keep Dma + + self.map_screen_with(offset, phys, fb_size, virt).await } async fn map_screen_with( diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 4656a826fb..3779218c28 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use log::debug; +use syscall::PAGE_SIZE; use syscall::error::Result; use syscall::io::{Io, Mmio}; @@ -178,18 +179,18 @@ impl ScratchpadBufferEntry { pub struct ScratchpadBufferArray { pub entries: Dma<[ScratchpadBufferEntry]>, - pub pages: Vec, + pub pages: Vec>, } impl ScratchpadBufferArray { - pub fn new(ac64: bool, page_size: usize, entries: u16) -> Result { + pub fn new(ac64: bool, entries: u16) -> Result { let mut entries = unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? }; - let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result { - let pointer = unsafe { syscall::physalloc(page_size)? }; - assert_eq!((pointer as u64) & 0xFFFF_FFFF_FFFF_F000, pointer as u64, "physically allocated pointer (physalloc) wasn't 4k page-aligned"); - entry.set_addr(pointer as u64); - Ok(pointer) - }).collect::, _>>()?; + let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| { + let dma = unsafe { Dma::<[u8; PAGE_SIZE]>::zeroed()?.assume_init() }; + assert_eq!(dma.physical() % PAGE_SIZE, 0); + entry.set_addr(dma.physical() as u64); + Ok(dma) + }).collect::, _>>()?; Ok(Self { entries, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index afe56101b8..aaf8b453c1 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -9,6 +9,7 @@ use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::{mem, process, slice, sync::atomic, task, thread}; +use syscall::PAGE_SIZE; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; use syscall::flag::{O_RDONLY, PhysallocFlags}; use syscall::io::Io; @@ -176,7 +177,7 @@ impl Xhci { pub struct Xhci { // immutable cap: &'static CapabilityRegs, - page_size: usize, + //page_size: usize, // XXX: It would be really useful to be able to mutably access individual elements of a slice, // without having to wrap every element in a lock (which wouldn't work since they're packed). @@ -248,12 +249,12 @@ impl Xhci { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; debug!("CAP REGS BASE {:X}", address); - let page_size = { + /*let page_size = { let memory_fd = syscall::open("memory:", O_RDONLY)?; let mut stat = syscall::data::StatVfs::default(); syscall::fstatvfs(memory_fd, &mut stat)?; stat.f_bsize as usize - }; + };*/ let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; @@ -306,7 +307,7 @@ impl Xhci { // Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the // DMA allocation (which is at least a 4k page). - let entries_per_page = page_size / mem::size_of::(); + let entries_per_page = PAGE_SIZE / mem::size_of::(); let cmd = Ring::new(cap.ac64(), entries_per_page, true)?; let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded(); @@ -315,7 +316,7 @@ impl Xhci { base: address as *const u8, cap, - page_size, + //page_size, op: Mutex::new(op), ports: Mutex::new(ports), @@ -459,7 +460,7 @@ impl Xhci { if buf_count == 0 { return Ok(()); } - let scratchpad_buf_arr = ScratchpadBufferArray::new(self.cap.ac64(), self.page_size,buf_count)?; + let scratchpad_buf_arr = ScratchpadBufferArray::new(self.cap.ac64(), buf_count)?; self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; debug!("Setting up {} scratchpads, at {:#0x}", buf_count, scratchpad_buf_arr.register()); self.scratchpad_buf_arr = Some(scratchpad_buf_arr); From 2e1e0078367e050a6d3d0441c2c5077dbbee6d7d Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 25 Nov 2023 11:06:39 +0100 Subject: [PATCH 0718/1301] Fix inputd path parsing. --- inputd/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 2a359f9b75..23f6b7b4e3 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -516,7 +516,7 @@ pub fn main() { "vesa" } else { // TODO: What should we do when there are multiple display devices? - device[0].split('/').nth(2).unwrap() + device[0][2..].split('.').nth(1).unwrap() }; let mut handle = From 8d11fb34defb48612c0ad5ab9a17cd72e5f9af88 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 16 Dec 2023 12:25:02 +0100 Subject: [PATCH 0719/1301] Fix impl Display for MemoryType. --- common/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/common/src/lib.rs b/common/src/lib.rs index 972d234cf0..05d76bf1dd 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -66,6 +66,7 @@ impl std::fmt::Display for MemoryType { Self::Writeback => "wb", Self::Uncacheable => "uc", Self::WriteCombining => "wc", + Self::DeviceMemory => "dev", }) } } From 04f60cf7beb5997815a9387cb970034b23cc53b3 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 16 Dec 2023 13:12:17 +0100 Subject: [PATCH 0720/1301] Fix ihdad. --- ihdad/src/hda/cmdbuff.rs | 18 +++++++----------- ihdad/src/main.rs | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/ihdad/src/hda/cmdbuff.rs b/ihdad/src/hda/cmdbuff.rs index a4af7820d7..c06c448d65 100644 --- a/ihdad/src/hda/cmdbuff.rs +++ b/ihdad/src/hda/cmdbuff.rs @@ -73,12 +73,12 @@ struct Corb { } impl Corb { - pub fn new(regs_addr: usize, corb_buff_phys: usize, corb_buff_virt: usize) -> Corb { + pub fn new(regs_addr: usize, corb_buff_phys: usize, corb_buff_virt: *mut u32) -> Corb { println!("regs addr {:x}", regs_addr); unsafe { Corb { regs: &mut *(regs_addr as *mut CorbRegs), - corb_base: (corb_buff_virt) as *mut u32, + corb_base: corb_buff_virt, corb_base_phys: corb_buff_phys, corb_count: 0, } @@ -209,11 +209,11 @@ struct Rirb { } impl Rirb { - pub fn new(regs_addr: usize, rirb_buff_phys: usize, rirb_buff_virt: usize) -> Rirb { + pub fn new(regs_addr: usize, rirb_buff_phys: usize, rirb_buff_virt: *mut u64) -> Rirb { unsafe { Rirb { regs: &mut *(regs_addr as *mut RirbRegs), - rirb_base: (rirb_buff_virt) as *mut u64, + rirb_base: rirb_buff_virt, rirb_rp: 0, rirb_base_phys: rirb_buff_phys, rirb_count: 0, @@ -343,8 +343,6 @@ pub struct CommandBuffer { rirb: Rirb, icmd: ImmediateCommand, - corb_rirb_base_phys: usize, - use_immediate_cmd: bool, mem: Dma<[u8; 0x1000]>, } @@ -352,13 +350,13 @@ pub struct CommandBuffer { impl CommandBuffer { pub fn new( regs_addr: usize, - cmd_buff: Dma<[u8; 0x1000]>, + mut cmd_buff: Dma<[u8; 0x1000]>, ) -> CommandBuffer { - let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff.physical(), cmd_buff.as_ptr() as usize); + let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff.physical(), cmd_buff.as_mut_ptr().cast()); let rirb = Rirb::new( regs_addr + RIRB_OFFSET, - cmd_buff.as_ptr() as usize + CORB_BUFF_MAX_SIZE, cmd_buff.physical() + CORB_BUFF_MAX_SIZE, + cmd_buff.as_mut_ptr().cast::().wrapping_add(CORB_BUFF_MAX_SIZE).cast(), ); let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET); @@ -368,8 +366,6 @@ impl CommandBuffer { rirb, icmd, - corb_rirb_base_phys: cmd_buff.physical(), - use_immediate_cmd: false, mem: cmd_buff, diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 6362fcb4e7..789b0be20e 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -33,7 +33,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_filter(log::LevelFilter::Debug) // limit global output to important info .with_ansi_escape_codes() .flush_on_newline(true) .build() From 6dd86d366ac3679b6d3d890436561485a7d8c305 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 7 Jan 2024 15:36:49 +0100 Subject: [PATCH 0721/1301] Add support for fetching the mac address from the e1000d driver --- e1000d/src/device.rs | 91 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 70 insertions(+), 21 deletions(-) diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index 45186b7695..e90f172a58 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -5,8 +5,9 @@ use std::{cmp, mem, ptr, slice}; use netutils::setcfg; use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; -use syscall::flag::{EventFlags, O_NONBLOCK}; +use syscall::flag::{EventFlags, MODE_FILE, O_NONBLOCK}; use syscall::scheme::SchemeBlockMut; +use syscall::Stat; use common::dma::Dma; @@ -99,6 +100,7 @@ const TD_DD: u8 = 1; pub struct Intel8254x { base: usize, + mac_address: [u8; 6], receive_buffer: [Dma<[u8; 16384]>; 16], receive_ring: Dma<[Rd; 16]>, receive_index: usize, @@ -108,7 +110,13 @@ pub struct Intel8254x { transmit_index: usize, transmit_clean_index: usize, next_id: usize, - pub handles: BTreeMap, + pub handles: BTreeMap, +} + +#[derive(Copy, Clone)] +pub enum Handle { + Data { flags: usize }, + Mac { offset: usize }, } fn wrap_ring(index: usize, ring_size: usize) -> usize { @@ -116,14 +124,20 @@ fn wrap_ring(index: usize, ring_size: usize) -> usize { } impl SchemeBlockMut for Intel8254x { - fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) - } else { - Err(Error::new(EACCES)) + fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { + if uid != 0 { + return Err(Error::new(EACCES)); } + + let handle = match path { + "" => Handle::Data { flags }, + "mac" => Handle::Mac { offset: 0 }, + _ => return Err(Error::new(EINVAL)), + }; + + self.next_id += 1; + self.handles.insert(self.next_id, handle); + Ok(Some(self.next_id)) } fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { @@ -131,17 +145,25 @@ impl SchemeBlockMut for Intel8254x { return Err(Error::new(EINVAL)); } - let flags = { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - *flags - }; + let handle = *self.handles.get(&id).ok_or(Error::new(EBADF))?; self.next_id += 1; - self.handles.insert(self.next_id, flags); + self.handles.insert(self.next_id, handle); Ok(Some(self.next_id)) } fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let flags = match *handle { + Handle::Data { flags } => flags, + Handle::Mac { ref mut offset } => { + let data = &self.mac_address[*offset..]; + let i = cmp::min(buf.len(), data.len()); + buf[..i].copy_from_slice(&data[..i]); + *offset += i; + return Ok(Some(i)); + } + }; let desc = unsafe { &mut *(self.receive_ring.as_ptr().add(self.receive_index) as *mut Rd) }; @@ -167,7 +189,12 @@ impl SchemeBlockMut for Intel8254x { } fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + match handle { + Handle::Data { .. } => {} + Handle::Mac { .. } => return Err(Error::new(EINVAL)), + } if self.transmit_ring_free == 0 { loop { @@ -222,15 +249,19 @@ impl SchemeBlockMut for Intel8254x { } fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; Ok(Some(EventFlags::empty())) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let scheme_path = match handle { + Handle::Data { .. } => &b"network:"[..], + Handle::Mac { .. } => &b"network:mac"[..], + }; let mut i = 0; - let scheme_path = b"network:"; while i < buf.len() && i < scheme_path.len() { buf[i] = scheme_path[i]; i += 1; @@ -238,8 +269,24 @@ impl SchemeBlockMut for Intel8254x { Ok(Some(i)) } + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + match handle { + Handle::Data { .. } => { + stat.st_mode = MODE_FILE | 0o700; + } + Handle::Mac { .. } => { + stat.st_mode = MODE_FILE | 0o400; + stat.st_size = 6; + } + } + + Ok(Some(0)) + } + fn fsync(&mut self, id: usize) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; Ok(Some(0)) } @@ -260,7 +307,8 @@ impl Intel8254x { pub unsafe fn new(base: usize) -> Result { #[rustfmt::skip] let mut module = Intel8254x { - base: base, + base, + mac_address: [0; 6], receive_buffer: dma_array()?, receive_ring: Dma::zeroed()?.assume_init(), transmit_buffer: dma_array()?, @@ -348,6 +396,7 @@ impl Intel8254x { mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ) ); + self.mac_address = mac; let _ = setcfg( "mac", &format!( From 8088cb8b2003b7768e4443f5921dc0d8a8041aeb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 10 Jan 2024 20:21:39 +0100 Subject: [PATCH 0722/1301] Fix missing ret in global_asm block This caused ps2d to get stuck in a crash loop when it's vmmouse support is enabled. --- ps2d/src/vm.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index c04185b480..90c8cba603 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -50,6 +50,8 @@ cmd_inner: mov DWORD PTR [rdi + 0x0C], edx mov DWORD PTR [rdi + 0x10], esi mov DWORD PTR [rdi + 0x14], r8d + + ret ", MAGIC = const MAGIC, PORT = const PORT, From f970a9c5712cfad7c34a7b06e2c0e9c3b078107b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 10 Jan 2024 20:22:14 +0100 Subject: [PATCH 0723/1301] Check for vmware backdoor support before trying to enable vmmouse --- ps2d/src/vm.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index 90c8cba603..9f341a2598 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -9,6 +9,7 @@ use core::arch::global_asm; const MAGIC: u32 = 0x564D5868; const PORT: u16 = 0x5658; +pub const GETVERSION: u32 = 10; pub const ABSPOINTER_DATA: u32 = 39; pub const ABSPOINTER_STATUS: u32 = 40; pub const ABSPOINTER_COMMAND: u32 = 41; @@ -82,6 +83,12 @@ pub fn enable(relative: bool) -> bool { eprintln!("ps2d: Enable vmmouse"); unsafe { + let (eax, ebx, _, _, _, _) = cmd(GETVERSION, 0); + if ebx != MAGIC || eax == 0xFFFFFFFF { + eprintln!("ps2d: No vmmouse support"); + return false; + } + let _ = cmd(ABSPOINTER_COMMAND, CMD_ENABLE); let (status, _, _, _, _, _) = cmd(ABSPOINTER_STATUS, 0); From 7d4dd990e09bd4d1ddb06376b367cddf522e7630 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 10 Jan 2024 20:23:04 +0100 Subject: [PATCH 0724/1301] Try to enable vmmouse by default This doesn't enable absolute mouse events yet as orbitral doesn't handle them correctly. --- ps2d/src/state.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index c23462a7fe..b556897645 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -49,7 +49,7 @@ impl char> Ps2d { let extra_packet = ps2.init().expect("ps2d: failed to initialize"); let vmmouse_relative = true; - let vmmouse = false; //vm::enable(vmmouse_relative); + let vmmouse = vm::enable(vmmouse_relative); let mut ps2d = Ps2d { ps2, From 94223667820e658613fce4b2f0081651baa61bf1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 11 Jan 2024 09:29:12 -0700 Subject: [PATCH 0725/1301] ps2d: fix build on non-x86_64 --- ps2d/src/vm.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index 9f341a2598..3445015091 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -78,6 +78,11 @@ pub unsafe fn cmd(_cmd: u32, _arg: u32) -> (u32, u32, u32, u32, u32, u32) { (0, 0, 0, 0, 0, 0) } +#[cfg(not(target_arch = "x86_64"))] +pub fn enable(relative: bool) -> bool { + false +} + #[cfg(target_arch = "x86_64")] pub fn enable(relative: bool) -> bool { eprintln!("ps2d: Enable vmmouse"); From bc7469f7cd177d91b5414f395b40109da3338203 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 12 Jan 2024 18:28:17 +0100 Subject: [PATCH 0726/1301] Switch vmmouse global_asm block back to inline asm There seems to be a bug somewhere in the global_asm block which causes a SIGSEGV when making unrelated code changes to ps2d. Using an inline asm block is easier to follow and less error prone around following the calling convention. --- ps2d/src/vm.rs | 59 +++++++++++++++++--------------------------------- 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index 3445015091..3f3ae50b50 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -4,7 +4,7 @@ // As well as the Linux implementation here: // http://elixir.free-electrons.com/linux/v4.1/source/drivers/input/mouse/vmmouse.c -use core::arch::global_asm; +use core::arch::asm; const MAGIC: u32 = 0x564D5868; const PORT: u16 = 0x5658; @@ -27,49 +27,30 @@ pub const LEFT_BUTTON: u32 = 0x20; pub const RIGHT_BUTTON: u32 = 0x10; pub const MIDDLE_BUTTON: u32 = 0x08; -#[cfg(target_arch = "x86_64")] -global_asm!(" - .globl cmd_inner -cmd_inner: - mov r8, rdi - - // 2nd argument `cmd` as per sysv64. - mov ecx, esi - // 3rd argument `arg` as per sysv64. - mov ebx, edx - - mov eax, {MAGIC} - mov dx, {PORT} - - in eax, dx - - xchg rdi, r8 - - mov DWORD PTR [rdi + 0x00], eax - mov DWORD PTR [rdi + 0x04], ebx - mov DWORD PTR [rdi + 0x08], ecx - mov DWORD PTR [rdi + 0x0C], edx - mov DWORD PTR [rdi + 0x10], esi - mov DWORD PTR [rdi + 0x14], r8d - - ret -", - MAGIC = const MAGIC, - PORT = const PORT, -); - #[cfg(target_arch = "x86_64")] pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32, u32, u32) { - extern "sysv64" { - fn cmd_inner(array_ptr: *mut u32, cmd: u32, arg: u32); - } + let a: u32; + let b: u32; + let c: u32; + let d: u32; + let si: u32; + let di: u32; - let mut array = [0_u32; 6]; + // ebx can't be used as input or output constraint in rust as LLVM reserves it. + // Use xchg to pass it through r9 instead while restoring the original value in + // rbx when leaving the inline asm block. + asm!( + "xchg r9, rbx; in eax, dx; xchg r9, rbx", + inout("eax") MAGIC => a, + inout("r9") arg => b, + inout("ecx") cmd => c, + inout("edx") PORT as u32 => d, + out("esi") si, + out("edi") di, + ); - cmd_inner(array.as_mut_ptr(), cmd, arg); + (a, b, c, d, si, di) - let [a, b, c, d, e, f] = array; - (a, b, c, d, e, f) } //TODO: is it possible to enable this on non-x86_64? From c2fd9125a7be67b881967046ef2eb007728913ac Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 12 Jan 2024 18:31:08 +0100 Subject: [PATCH 0727/1301] Fix absolute mouse events with vmmouse It is no longer possible to query the display size from inputd, so defer conversion to display pixel coordinates to orbital instead. This also avoids a lot of work every mouse event to query the display size as orbital saves this information already. --- ps2d/src/state.rs | 58 +++++++++++++++-------------------------------- 1 file changed, 18 insertions(+), 40 deletions(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index b556897645..2496ec2e64 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -26,8 +26,6 @@ pub struct Ps2d char> { vmmouse: bool, vmmouse_relative: bool, input: File, - width: u32, - height: u32, extended: bool, lshift: bool, rshift: bool, @@ -51,13 +49,11 @@ impl char> Ps2d { let vmmouse_relative = true; let vmmouse = vm::enable(vmmouse_relative); - let mut ps2d = Ps2d { + Ps2d { ps2, vmmouse, vmmouse_relative, input, - width: 0, - height: 0, extended: false, lshift: false, rshift: false, @@ -70,20 +66,6 @@ impl char> Ps2d { packet_i: 0, extra_packet, get_char: keymap - }; - - ps2d.resize(); - - ps2d - } - - pub fn resize(&mut self) { - let mut buf: [u8; 4096] = [0; 4096]; - if let Ok(count) = syscall::fpath(self.input.as_raw_fd() as usize, &mut buf) { - let path = unsafe { str::from_utf8_unchecked(&buf[..count]) }; - let res = path.split(":").nth(1).unwrap_or(""); - self.width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); - self.height = res.split("/").nth(2).unwrap_or("").parse::().unwrap_or(0); } } @@ -253,20 +235,20 @@ impl char> Ps2d { } } else if self.vmmouse { for _i in 0..256 { - let (status, _, _, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) }; - //TODO if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) + let (status, _, _, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) }; + //TODO if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) - let queue_length = status & 0xffff; - if queue_length == 0 { - break; + let queue_length = status & 0xffff; + if queue_length == 0 { + break; } - if queue_length % 4 != 0 { - eprintln!("ps2d: queue length not a multiple of 4: {}", queue_length); - break; - } + if queue_length % 4 != 0 { + eprintln!("ps2d: queue length not a multiple of 4: {}", queue_length); + break; + } - let (status, dx, dy, dz, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; + let (status, dx, dy, dz, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; if self.vmmouse_relative { if dx != 0 || dy != 0 { @@ -275,21 +257,17 @@ impl char> Ps2d { dy: dy as i32, }.to_event()).expect("ps2d: failed to write mouse event"); } - } else { - // TODO: Improve efficiency - self.resize(); - - let x = dx as i32 * self.width as i32 / 0xFFFF; - let y = dy as i32 * self.height as i32 / 0xFFFF; + } else { + let x = dx as i32; + let y = dy as i32; if x != self.mouse_x || y != self.mouse_y { self.mouse_x = x; self.mouse_y = y; - self.input.write(&MouseEvent { - x: x, - y: y, - }.to_event()).expect("ps2d: failed to write mouse event"); + self.input + .write(&MouseEvent { x, y }.to_event()) + .expect("ps2d: failed to write mouse event"); } - }; + }; if dz != 0 { self.input.write(&ScrollEvent { From 7a21573ebde3d90128b178ca648b5ce460e51781 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 12 Jan 2024 18:33:29 +0100 Subject: [PATCH 0728/1301] Switch to absolute mouse events by default when running in a VM This will transparently release the mouse grab of the VM when leaving the screen edge, making it much easier to quickly switch between the VM and other apps running on the host. --- ps2d/src/state.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 2496ec2e64..9891cc8e7e 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -46,7 +46,8 @@ impl char> Ps2d { let mut ps2 = Ps2::new(); let extra_packet = ps2.init().expect("ps2d: failed to initialize"); - let vmmouse_relative = true; + // FIXME add an option for orbital to disable this when an app captures the mouse. + let vmmouse_relative = false; let vmmouse = vm::enable(vmmouse_relative); Ps2d { From 6561685af88f5256e18ead84eb4c9d1860d6a8ba Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 12 Jan 2024 19:34:13 +0100 Subject: [PATCH 0729/1301] Fix MouseEvent for usbhidd --- usbhidd/src/main.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 8e11c70aed..259c3f323a 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -454,8 +454,11 @@ fn main() { binary_view.read_u8(16).expect("Failed to read array item") as u16 | (binary_view.read_u8(24).expect("Failed to read array item") as u16) << 8; - let x = ((raw_x as u32) * display_width) / 32767; - let y = ((raw_y as u32) * display_height) / 32767; + // ps2d uses 0..=65535 as range, while usb uses 0..=32767. orbital + // expects the former range, so multiply by two here to translate + // the usb coordinates to what orbital expects. + let x = raw_x * 2; + let y = raw_y * 2; log::trace!("Touchscreen {}, {} => {}, {}", raw_x, raw_y, x, y); if x != 0 || y != 0 { From 1ac2fdc5727926dbbcdcdf36c93b747a6e6eaf05 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 12 Jan 2024 19:33:41 +0100 Subject: [PATCH 0730/1301] Write events in usbhidd to input:producer Writing to display.vesa:input seems to get ignored by orbital. --- usbhidd/src/main.rs | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 259c3f323a..2165b6e604 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -382,20 +382,7 @@ fn main() { let report_ty = ReportTy::Input; let report_id = 0; - let mut display = File::open("display.vesa:input").expect("Failed to open orbital input socket"); - - //TODO: get dynamically - let mut display_width = 0; - let mut display_height = 0; - { - let mut buf = [0; 4096]; - if let Ok(count) = syscall::fpath(display.as_raw_fd() as usize, &mut buf) { - let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; - let res = path.split(":").nth(1).unwrap_or(""); - display_width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); - display_height = res.split("/").nth(2).unwrap_or("").parse::().unwrap_or(0); - } - } + let mut display = File::open("input:producer").expect("Failed to open orbital input socket"); let mut pressed_keys = Vec::<(u32, u8)>::new(); let mut last_pressed_keys = pressed_keys.clone(); From ee2a36b8891c6df6353c71b39146a5dc4687bfdc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 13 Jan 2024 16:09:55 +0100 Subject: [PATCH 0731/1301] Remove rusttype support from vesad It is never enabled and would add a fair amount of complexity to a system service which has effective root access despite sandboxing due to being able to read and write display contents and input device events. --- Cargo.lock | 53 +------------ vesad/Cargo.toml | 1 - vesad/res/DejaVu-Fonts-License.txt | 97 ----------------------- vesad/res/DejaVuSansMono-Bold.ttf | Bin 318392 -> 0 bytes vesad/res/DejaVuSansMono-BoldOblique.ttf | Bin 239876 -> 0 bytes vesad/res/DejaVuSansMono-Oblique.ttf | Bin 245948 -> 0 bytes vesad/res/DejaVuSansMono.ttf | Bin 335068 -> 0 bytes vesad/src/display.rs | 94 ---------------------- 8 files changed, 1 insertion(+), 244 deletions(-) delete mode 100644 vesad/res/DejaVu-Fonts-License.txt delete mode 100644 vesad/res/DejaVuSansMono-Bold.ttf delete mode 100644 vesad/res/DejaVuSansMono-BoldOblique.ttf delete mode 100644 vesad/res/DejaVuSansMono-Oblique.ttf delete mode 100644 vesad/res/DejaVuSansMono.ttf diff --git a/Cargo.lock b/Cargo.lock index 434df3e8e5..1d75ca68a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -120,15 +120,6 @@ name = "arg_parser" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/arg-parser.git#1c434b55f3e1a0375ebcca85b3e88db7378e82fa" -[[package]] -name = "arrayvec" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" -dependencies = [ - "nodrop", -] - [[package]] name = "arrayvec" version = "0.5.2" @@ -684,12 +675,6 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "lived" version = "0.1.0" @@ -762,12 +747,6 @@ dependencies = [ "url", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - [[package]] name = "ntpclient" version = "0.0.1" @@ -807,7 +786,7 @@ checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" name = "nvmed" version = "0.1.0" dependencies = [ - "arrayvec 0.5.2", + "arrayvec", "bitflags 1.3.2", "block-io-wrapper", "common", @@ -1210,17 +1189,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" -[[package]] -name = "rusttype" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8d729e72445ad579171b01a9231657736b3793a2cf423078e687e20ecb8695a" -dependencies = [ - "arrayvec 0.4.12", - "linked-hash-map", - "stb_truetype 0.2.8", -] - [[package]] name = "ryu" version = "1.0.15" @@ -1387,24 +1355,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "stb_truetype" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1bec4382294c5a680fcebd29f8451e8d8c04479a026f6909004e2ab1cb425d" -dependencies = [ - "stb_truetype 0.3.1", -] - -[[package]] -name = "stb_truetype" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f77b6b07e862c66a9f3e62a07588fee67cd90a9135a2b942409f195507b4fb51" -dependencies = [ - "byteorder 1.4.3", -] - [[package]] name = "strsim" version = "0.8.0" @@ -1711,7 +1661,6 @@ dependencies = [ "ransid", "redox-daemon", "redox_syscall 0.4.1", - "rusttype", ] [[package]] diff --git a/vesad/Cargo.toml b/vesad/Cargo.toml index e3880f63db..85d12fc9fb 100644 --- a/vesad/Cargo.toml +++ b/vesad/Cargo.toml @@ -6,7 +6,6 @@ edition = "2018" [dependencies] orbclient = "0.3.27" ransid = "0.4" -rusttype = { version = "0.2", optional = true } redox_syscall = "0.4" redox-daemon = "0.1" diff --git a/vesad/res/DejaVu-Fonts-License.txt b/vesad/res/DejaVu-Fonts-License.txt deleted file mode 100644 index 69399804ca..0000000000 --- a/vesad/res/DejaVu-Fonts-License.txt +++ /dev/null @@ -1,97 +0,0 @@ -Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. -Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) - -Bitstream Vera Fonts Copyright ------------------------------- - -Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is -a trademark of Bitstream, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of the fonts accompanying this license ("Fonts") and associated -documentation files (the "Font Software"), to reproduce and distribute the -Font Software, including without limitation the rights to use, copy, merge, -publish, distribute, and/or sell copies of the Font Software, and to permit -persons to whom the Font Software is furnished to do so, subject to the -following conditions: - -The above copyright and trademark notices and this permission notice shall -be included in all copies of one or more of the Font Software typefaces. - -The Font Software may be modified, altered, or added to, and in particular -the designs of glyphs or characters in the Fonts may be modified and -additional glyphs or characters may be added to the Fonts, only if the fonts -are renamed to names not containing either the words "Bitstream" or the word -"Vera". - -This License becomes null and void to the extent applicable to Fonts or Font -Software that has been modified and is distributed under the "Bitstream -Vera" names. - -The Font Software may be sold as part of a larger software package but no -copy of one or more of the Font Software typefaces may be sold by itself. - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, -TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME -FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING -ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF -THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE -FONT SOFTWARE. - -Except as contained in this notice, the names of Gnome, the Gnome -Foundation, and Bitstream Inc., shall not be used in advertising or -otherwise to promote the sale, use or other dealings in this Font Software -without prior written authorization from the Gnome Foundation or Bitstream -Inc., respectively. For further information, contact: fonts at gnome dot -org. - -Arev Fonts Copyright ------------------------------- - -Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the fonts accompanying this license ("Fonts") and -associated documentation files (the "Font Software"), to reproduce -and distribute the modifications to the Bitstream Vera Font Software, -including without limitation the rights to use, copy, merge, publish, -distribute, and/or sell copies of the Font Software, and to permit -persons to whom the Font Software is furnished to do so, subject to -the following conditions: - -The above copyright and trademark notices and this permission notice -shall be included in all copies of one or more of the Font Software -typefaces. - -The Font Software may be modified, altered, or added to, and in -particular the designs of glyphs or characters in the Fonts may be -modified and additional glyphs or characters may be added to the -Fonts, only if the fonts are renamed to names not containing either -the words "Tavmjong Bah" or the word "Arev". - -This License becomes null and void to the extent applicable to Fonts -or Font Software that has been modified and is distributed under the -"Tavmjong Bah Arev" names. - -The Font Software may be sold as part of a larger software package but -no copy of one or more of the Font Software typefaces may be sold by -itself. - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL -TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. - -Except as contained in this notice, the name of Tavmjong Bah shall not -be used in advertising or otherwise to promote the sale, use or other -dealings in this Font Software without prior written authorization -from Tavmjong Bah. For further information, contact: tavmjong @ free -. fr. \ No newline at end of file diff --git a/vesad/res/DejaVuSansMono-Bold.ttf b/vesad/res/DejaVuSansMono-Bold.ttf deleted file mode 100644 index 9c716794f70b10900beded00f5422deb832f01b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 318392 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 diff --git a/vesad/res/DejaVuSansMono-BoldOblique.ttf b/vesad/res/DejaVuSansMono-BoldOblique.ttf deleted file mode 100644 index d6536a5cc256583c156c6e284348ef066c740f13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 239876 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 z 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 z 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‹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 z%0A1R*n{$iq2}O<05MdXEnx&ki3Q=jSm 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

-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

b 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 diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 7f5626eaff..6c4aee2e0c 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -1,25 +1,9 @@ -#[cfg(feature="rusttype")] -extern crate rusttype; - use std::alloc::{self, Layout}; use std::{cmp, ptr}; use std::ptr::NonNull; -#[cfg(feature="rusttype")] -use self::rusttype::{Font, FontCollection, Scale, point}; - -#[cfg(not(feature="rusttype"))] use orbclient::FONT; -#[cfg(feature="rusttype")] -static FONT: &'static [u8] = include_bytes!("../res/DejaVuSansMono.ttf"); -#[cfg(feature="rusttype")] -static FONT_BOLD: &'static [u8] = include_bytes!("../res/DejaVuSansMono-Bold.ttf"); -#[cfg(feature="rusttype")] -static FONT_BOLD_ITALIC: &'static [u8] = include_bytes!("../res/DejaVuSansMono-BoldOblique.ttf"); -#[cfg(feature="rusttype")] -static FONT_ITALIC: &'static [u8] = include_bytes!("../res/DejaVuSansMono-Oblique.ttf"); - pub struct OffscreenBuffer { ptr: NonNull<[u32]>, } @@ -63,18 +47,9 @@ pub struct Display { pub width: usize, pub height: usize, pub offscreen: OffscreenBuffer, - #[cfg(feature="rusttype")] - pub font: Font<'static>, - #[cfg(feature="rusttype")] - pub font_bold: Font<'static>, - #[cfg(feature="rusttype")] - pub font_bold_italic: Font<'static>, - #[cfg(feature="rusttype")] - pub font_italic: Font<'static> } impl Display { - #[cfg(not(feature="rusttype"))] pub fn new(width: usize, height: usize) -> Display { let size = width * height; let offscreen = OffscreenBuffer::new(size); @@ -85,21 +60,6 @@ impl Display { } } - #[cfg(feature="rusttype")] - pub fn new(width: usize, height: usize) -> Display { - let size = width * height; - let offscreen = OffscreenBuffer::new(size); - Display { - width, - height, - offscreen, - font: FontCollection::from_bytes(FONT).into_font().unwrap(), - font_bold: FontCollection::from_bytes(FONT_BOLD).into_font().unwrap(), - font_bold_italic: FontCollection::from_bytes(FONT_BOLD_ITALIC).into_font().unwrap(), - font_italic: FontCollection::from_bytes(FONT_ITALIC).into_font().unwrap() - } - } - pub fn resize(&mut self, width: usize, height: usize) { if width != self.width || height != self.height { println!("Resize display to {}, {}", width, height); @@ -209,7 +169,6 @@ impl Display { } /// Draw a character - #[cfg(not(feature="rusttype"))] pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) { if x + 8 <= self.width && y + 16 <= self.height { let mut dst = self.offscreen.as_mut_ptr() as usize + (y * self.width + x) * 4; @@ -229,59 +188,6 @@ impl Display { } } - /// Draw a character - #[cfg(feature="rusttype")] - pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, bold: bool, italic: bool) { - let width = self.width; - let height = self.height; - let offscreen = self.offscreen.as_mut_ptr() as usize; - - let font = if bold && italic { - &self.font_bold_italic - } else if bold { - &self.font_bold - } else if italic { - &self.font_italic - } else { - &self.font - }; - - if let Some(glyph) = font.glyph(character){ - let scale = Scale::uniform(16.0); - let v_metrics = font.v_metrics(scale); - let point = point(0.0, v_metrics.ascent); - let glyph = glyph.scaled(scale).positioned(point); - if let Some(bb) = glyph.pixel_bounding_box() { - glyph.draw(|off_x, off_y, v| { - let off_x = x + (off_x as i32 + bb.min.x) as usize; - let off_y = y + (off_y as i32 + bb.min.y) as usize; - // There's still a possibility that the glyph clips the boundaries of the bitmap - if off_x < width && off_y < height { - if v > 0.0 { - let f_a = (v * 255.0) as u32; - let f_r = (((color >> 16) & 0xFF) * f_a)/255; - let f_g = (((color >> 8) & 0xFF) * f_a)/255; - let f_b = ((color & 0xFF) * f_a)/255; - - let offscreen_ptr = (offscreen + (off_y * width + off_x) * 4) as *mut u32; - - let bg = unsafe { *offscreen_ptr }; - - let b_a = 255 - f_a; - let b_r = (((bg >> 16) & 0xFF) * b_a)/255; - let b_g = (((bg >> 8) & 0xFF) * b_a)/255; - let b_b = ((bg & 0xFF) * b_a)/255; - - let c = ((f_r + b_r) << 16) | ((f_g + b_g) << 8) | (f_b + b_b); - - unsafe { *offscreen_ptr = c; } - } - } - }); - } - } - } - /// Copy from offscreen to onscreen pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize, onscreen: &mut [u32], stride: usize) { let start_y = cmp::min(self.height, y); From 1a698dec981a0d4215545066819fb5656ab2bd83 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 13 Jan 2024 16:24:34 +0100 Subject: [PATCH 0732/1301] Move text rendering to vesad::screen::text --- vesad/src/display.rs | 81 ----------------------------------- vesad/src/screen/text.rs | 91 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 85 insertions(+), 87 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 6c4aee2e0c..6a6e29ee64 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -2,8 +2,6 @@ use std::alloc::{self, Layout}; use std::{cmp, ptr}; use std::ptr::NonNull; -use orbclient::FONT; - pub struct OffscreenBuffer { ptr: NonNull<[u32]>, } @@ -109,85 +107,6 @@ impl Display { } } - /// Draw a rectangle - pub fn rect(&mut self, x: usize, y: usize, w: usize, h: usize, color: u32) { - let start_y = cmp::min(self.height, y); - let end_y = cmp::min(self.height, y + h); - - let start_x = cmp::min(self.width, x); - let len = cmp::min(self.width, x + w) - start_x; - - let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; - - let stride = self.width * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - - let mut rows = end_y - start_y; - while rows > 0 { - for i in 0..len { - unsafe { - *(offscreen_ptr as *mut u32).add(i) = color; - } - } - offscreen_ptr += stride; - rows -= 1; - } - } - - /// Invert a rectangle - pub fn invert(&mut self, x: usize, y: usize, w: usize, h: usize) { - let start_y = cmp::min(self.height, y); - let end_y = cmp::min(self.height, y + h); - - let start_x = cmp::min(self.width, x); - let len = cmp::min(self.width, x + w) - start_x; - - let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; - - let stride = self.width * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - - let mut rows = end_y - start_y; - while rows > 0 { - let mut row_ptr = offscreen_ptr; - let mut cols = len; - while cols > 0 { - unsafe { - let color = *(row_ptr as *mut u32); - *(row_ptr as *mut u32) = !color; - } - row_ptr += 4; - cols -= 1; - } - offscreen_ptr += stride; - rows -= 1; - } - } - - /// Draw a character - pub fn char(&mut self, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) { - if x + 8 <= self.width && y + 16 <= self.height { - let mut dst = self.offscreen.as_mut_ptr() as usize + (y * self.width + x) * 4; - - let font_i = 16 * (character as usize); - if font_i + 16 <= FONT.len() { - for row in 0..16 { - let row_data = FONT[font_i + row]; - for col in 0..8 { - if (row_data >> (7 - col)) & 1 == 1 { - unsafe { *((dst + col * 4) as *mut u32) = color; } - } - } - dst += self.width * 4; - } - } - } - } - /// Copy from offscreen to onscreen pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize, onscreen: &mut [u32], stride: usize) { let start_y = cmp::min(self.height, y); diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 834aca6cf2..45eb76bf5f 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -1,9 +1,9 @@ extern crate ransid; use std::collections::{BTreeSet, VecDeque}; -use std::ptr; +use std::{ptr, cmp}; -use orbclient::{Event, EventOption}; +use orbclient::{Event, EventOption, FONT}; use syscall::error::*; use crate::display::Display; @@ -27,6 +27,85 @@ impl TextScreen { input: VecDeque::new(), } } + + /// Draw a rectangle + fn rect(display: &mut Display, x: usize, y: usize, w: usize, h: usize, color: u32) { + let start_y = cmp::min(display.height, y); + let end_y = cmp::min(display.height, y + h); + + let start_x = cmp::min(display.width, x); + let len = cmp::min(display.width, x + w) - start_x; + + let mut offscreen_ptr = display.offscreen.as_mut_ptr() as usize; + + let stride = display.width * 4; + + let offset = y * stride + start_x * 4; + offscreen_ptr += offset; + + let mut rows = end_y - start_y; + while rows > 0 { + for i in 0..len { + unsafe { + *(offscreen_ptr as *mut u32).add(i) = color; + } + } + offscreen_ptr += stride; + rows -= 1; + } + } + + /// Invert a rectangle + fn invert(display: &mut Display, x: usize, y: usize, w: usize, h: usize) { + let start_y = cmp::min(display.height, y); + let end_y = cmp::min(display.height, y + h); + + let start_x = cmp::min(display.width, x); + let len = cmp::min(display.width, x + w) - start_x; + + let mut offscreen_ptr = display.offscreen.as_mut_ptr() as usize; + + let stride = display.width * 4; + + let offset = y * stride + start_x * 4; + offscreen_ptr += offset; + + let mut rows = end_y - start_y; + while rows > 0 { + let mut row_ptr = offscreen_ptr; + let mut cols = len; + while cols > 0 { + unsafe { + let color = *(row_ptr as *mut u32); + *(row_ptr as *mut u32) = !color; + } + row_ptr += 4; + cols -= 1; + } + offscreen_ptr += stride; + rows -= 1; + } + } + + /// Draw a character + fn char(display: &mut Display, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) { + if x + 8 <= display.width && y + 16 <= display.height { + let mut dst = display.offscreen.as_mut_ptr() as usize + (y * display.width + x) * 4; + + let font_i = 16 * (character as usize); + if font_i + 16 <= FONT.len() { + for row in 0..16 { + let row_data = FONT[font_i + row]; + for col in 0..8 { + if (row_data >> (7 - col)) & 1 == 1 { + unsafe { *((dst + col * 4) as *mut u32) = color; } + } + } + dst += display.width * 4; + } + } + } + } } impl Screen for TextScreen { @@ -136,7 +215,7 @@ impl Screen for TextScreen { if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { let x = self.console.state.x; let y = self.console.state.y; - self.display.invert(x * 8, y * 16, 8, 16); + Self::invert(&mut self.display, x * 8, y * 16, 8, 16); self.changed.insert(y); } @@ -147,14 +226,14 @@ impl Screen for TextScreen { self.console.write(buf, |event| { match event { ransid::Event::Char { x, y, c, color, bold, .. } => { - display.char(x * 8, y * 16, c, color.as_rgb(), bold, false); + Self::char(display, x * 8, y * 16, c, color.as_rgb(), bold, false); changed.insert(y); }, ransid::Event::Input { data } => { input.extend(data); }, ransid::Event::Rect { x, y, w, h, color } => { - display.rect(x * 8, y * 16, w * 8, h * 16, color.as_rgb()); + Self::rect(display, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); for y2 in y..y + h { changed.insert(y2); } @@ -198,7 +277,7 @@ impl Screen for TextScreen { if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { let x = self.console.state.x; let y = self.console.state.y; - self.display.invert(x * 8, y * 16, 8, 16); + Self::invert(&mut self.display, x * 8, y * 16, 8, 16); self.changed.insert(y); } From 6be07a30151d3948b5e660832c1b9288064c831e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 13 Jan 2024 17:30:52 +0100 Subject: [PATCH 0733/1301] Use GraphicScreen inside TextScreen In preparation for moving TextScreen to a separate daemon. --- vesad/src/screen/graphic.rs | 12 +++++------ vesad/src/screen/text.rs | 42 ++++++++++++++++++++++--------------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index ca96be28a8..506d4e4a0e 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -11,17 +11,17 @@ use crate::screen::Screen; // Keep synced with orbital #[derive(Clone, Copy)] #[repr(packed)] -struct SyncRect { - x: i32, - y: i32, - w: i32, - h: i32, +pub struct SyncRect { + pub x: i32, + pub y: i32, + pub w: i32, + pub h: i32, } pub struct GraphicScreen { pub display: Display, pub input: VecDeque, - sync_rects: Vec, + pub sync_rects: Vec, } impl GraphicScreen { diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 45eb76bf5f..c7bf57cd70 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -1,17 +1,21 @@ extern crate ransid; use std::collections::{BTreeSet, VecDeque}; +use std::convert::{TryFrom, TryInto}; use std::{ptr, cmp}; use orbclient::{Event, EventOption, FONT}; use syscall::error::*; use crate::display::Display; -use crate::screen::Screen; +use crate::screen::{Screen, GraphicScreen}; + +use super::graphic::SyncRect; pub struct TextScreen { pub console: ransid::Console, - pub display: Display, + // FIXME avoid directly accessing the fields of screen + pub screen: GraphicScreen, pub changed: BTreeSet, pub ctrl: bool, pub input: VecDeque, @@ -21,7 +25,7 @@ impl TextScreen { pub fn new(display: Display) -> TextScreen { TextScreen { console: ransid::Console::new(display.width/8, display.height/16), - display: display, + screen: GraphicScreen::new(display), changed: BTreeSet::new(), ctrl: false, input: VecDeque::new(), @@ -118,7 +122,7 @@ impl Screen for TextScreen { } fn resize(&mut self, width: usize, height: usize) { - self.display.resize(width, height); + self.screen.display.resize(width, height); self.console.state.w = width / 8; self.console.state.h = height / 16; } @@ -215,33 +219,33 @@ impl Screen for TextScreen { if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { let x = self.console.state.x; let y = self.console.state.y; - Self::invert(&mut self.display, x * 8, y * 16, 8, 16); + Self::invert(&mut self.screen.display, x * 8, y * 16, 8, 16); self.changed.insert(y); } { - let display = &mut self.display; + let screen = &mut self.screen; let changed = &mut self.changed; let input = &mut self.input; self.console.write(buf, |event| { match event { ransid::Event::Char { x, y, c, color, bold, .. } => { - Self::char(display, x * 8, y * 16, c, color.as_rgb(), bold, false); + Self::char(&mut screen.display, x * 8, y * 16, c, color.as_rgb(), bold, false); changed.insert(y); }, ransid::Event::Input { data } => { input.extend(data); }, ransid::Event::Rect { x, y, w, h, color } => { - Self::rect(display, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); + Self::rect(&mut screen.display, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); for y2 in y..y + h { changed.insert(y2); } }, ransid::Event::ScreenBuffer { .. } => (), ransid::Event::Move {from_x, from_y, to_x, to_y, w, h } => { - let width = display.width; - let pixels = &mut display.offscreen; + let width = screen.width(); + let pixels = &mut screen.display.offscreen; for raw_y in 0..h { let y = if from_y > to_y { @@ -277,7 +281,7 @@ impl Screen for TextScreen { if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { let x = self.console.state.x; let y = self.console.state.y; - Self::invert(&mut self.display, x * 8, y * 16, 8, 16); + Self::invert(&mut self.screen.display, x * 8, y * 16, 8, 16); self.changed.insert(y); } @@ -289,17 +293,21 @@ impl Screen for TextScreen { } fn sync(&mut self, onscreen: &mut [u32], stride: usize) { - let width = self.display.width; - for change in self.changed.iter() { - self.display.sync(0, change * 16, width, 16, onscreen, stride); + let width = self.screen.width().try_into().unwrap(); + for &change in self.changed.iter() { + self.screen.sync_rects.push(SyncRect { + x: 0, + y: i32::try_from(change).unwrap() * 16, + w: width, + h: 16, + }); } self.changed.clear(); + self.screen.sync(onscreen, stride); } fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { - let width = self.display.width; - let height = self.display.height; - self.display.sync(0, 0, width, height, onscreen, stride); + self.screen.redraw(onscreen, stride); self.changed.clear(); } } From 5375d9e97dd7f481aaddbefd11785fcda4bec28f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 13 Jan 2024 19:09:26 +0100 Subject: [PATCH 0734/1301] Remove some GraphicScreen direct fields accesses from TextScreen --- vesad/src/scheme.rs | 5 ++-- vesad/src/screen/text.rs | 61 ++++++++++++++++++++-------------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index cc5a70fcd1..199bd097cf 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -58,10 +58,11 @@ impl DisplayScheme { let mut screens = BTreeMap::>::new(); for fb_i in 0..framebuffers.len() { let fb = &framebuffers[fb_i]; + let graphic_screen = GraphicScreen::new(Display::new(fb.width, fb.height)); screens.insert(ScreenIndex(fb_i), if vt_type { - Box::new(GraphicScreen::new(Display::new(fb.width, fb.height))) + Box::new(graphic_screen) } else { - Box::new(TextScreen::new(Display::new(fb.width, fb.height))) + Box::new(TextScreen::new(graphic_screen)) }); } vts.insert(VtIndex(inputd_handle.register().unwrap()), screens); diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index c7bf57cd70..02695192e2 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -7,25 +7,24 @@ use std::{ptr, cmp}; use orbclient::{Event, EventOption, FONT}; use syscall::error::*; -use crate::display::Display; use crate::screen::{Screen, GraphicScreen}; use super::graphic::SyncRect; pub struct TextScreen { - pub console: ransid::Console, + console: ransid::Console, // FIXME avoid directly accessing the fields of screen - pub screen: GraphicScreen, - pub changed: BTreeSet, - pub ctrl: bool, - pub input: VecDeque, + screen: GraphicScreen, + changed: BTreeSet, + ctrl: bool, + input: VecDeque, } impl TextScreen { - pub fn new(display: Display) -> TextScreen { + pub fn new(screen: GraphicScreen) -> TextScreen { TextScreen { - console: ransid::Console::new(display.width/8, display.height/16), - screen: GraphicScreen::new(display), + console: ransid::Console::new(screen.width()/8, screen.height()/16), + screen, changed: BTreeSet::new(), ctrl: false, input: VecDeque::new(), @@ -33,16 +32,16 @@ impl TextScreen { } /// Draw a rectangle - fn rect(display: &mut Display, x: usize, y: usize, w: usize, h: usize, color: u32) { - let start_y = cmp::min(display.height, y); - let end_y = cmp::min(display.height, y + h); + fn rect(screen: &mut GraphicScreen, x: usize, y: usize, w: usize, h: usize, color: u32) { + let start_y = cmp::min(screen.height(), y); + let end_y = cmp::min(screen.height(), y + h); - let start_x = cmp::min(display.width, x); - let len = cmp::min(display.width, x + w) - start_x; + let start_x = cmp::min(screen.width(), x); + let len = cmp::min(screen.width(), x + w) - start_x; - let mut offscreen_ptr = display.offscreen.as_mut_ptr() as usize; + let mut offscreen_ptr = screen.display.offscreen.as_mut_ptr() as usize; - let stride = display.width * 4; + let stride = screen.width() * 4; let offset = y * stride + start_x * 4; offscreen_ptr += offset; @@ -60,16 +59,16 @@ impl TextScreen { } /// Invert a rectangle - fn invert(display: &mut Display, x: usize, y: usize, w: usize, h: usize) { - let start_y = cmp::min(display.height, y); - let end_y = cmp::min(display.height, y + h); + fn invert(screen: &mut GraphicScreen, x: usize, y: usize, w: usize, h: usize) { + let start_y = cmp::min(screen.height(), y); + let end_y = cmp::min(screen.height(), y + h); - let start_x = cmp::min(display.width, x); - let len = cmp::min(display.width, x + w) - start_x; + let start_x = cmp::min(screen.width(), x); + let len = cmp::min(screen.width(), x + w) - start_x; - let mut offscreen_ptr = display.offscreen.as_mut_ptr() as usize; + let mut offscreen_ptr = screen.display.offscreen.as_mut_ptr() as usize; - let stride = display.width * 4; + let stride = screen.width() * 4; let offset = y * stride + start_x * 4; offscreen_ptr += offset; @@ -92,9 +91,9 @@ impl TextScreen { } /// Draw a character - fn char(display: &mut Display, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) { - if x + 8 <= display.width && y + 16 <= display.height { - let mut dst = display.offscreen.as_mut_ptr() as usize + (y * display.width + x) * 4; + fn char(screen: &mut GraphicScreen, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) { + if x + 8 <= screen.width() && y + 16 <= screen.height() { + let mut dst = screen.display.offscreen.as_mut_ptr() as usize + (y * screen.width() + x) * 4; let font_i = 16 * (character as usize); if font_i + 16 <= FONT.len() { @@ -105,7 +104,7 @@ impl TextScreen { unsafe { *((dst + col * 4) as *mut u32) = color; } } } - dst += display.width * 4; + dst += screen.width() * 4; } } } @@ -219,7 +218,7 @@ impl Screen for TextScreen { if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { let x = self.console.state.x; let y = self.console.state.y; - Self::invert(&mut self.screen.display, x * 8, y * 16, 8, 16); + Self::invert(&mut self.screen, x * 8, y * 16, 8, 16); self.changed.insert(y); } @@ -230,14 +229,14 @@ impl Screen for TextScreen { self.console.write(buf, |event| { match event { ransid::Event::Char { x, y, c, color, bold, .. } => { - Self::char(&mut screen.display, x * 8, y * 16, c, color.as_rgb(), bold, false); + Self::char(screen, x * 8, y * 16, c, color.as_rgb(), bold, false); changed.insert(y); }, ransid::Event::Input { data } => { input.extend(data); }, ransid::Event::Rect { x, y, w, h, color } => { - Self::rect(&mut screen.display, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); + Self::rect(screen, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); for y2 in y..y + h { changed.insert(y2); } @@ -281,7 +280,7 @@ impl Screen for TextScreen { if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { let x = self.console.state.x; let y = self.console.state.y; - Self::invert(&mut self.screen.display, x * 8, y * 16, 8, 16); + Self::invert(&mut self.screen, x * 8, y * 16, 8, 16); self.changed.insert(y); } From 5f6edc7adcd589158dfcd6e854e0d88f54095094 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 13 Jan 2024 19:20:37 +0100 Subject: [PATCH 0735/1301] Fix warnings --- vesad/src/scheme.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 199bd097cf..37ce23d111 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -1,8 +1,7 @@ use std::collections::BTreeMap; use std::{mem, ptr, slice, str}; -use orbclient::{Event, EventOption}; -use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE, Packet, KSMSG_MMAP_PREP, KSMSG_MMAP, MapFlags, ESKMSG, SKMSG_PROVIDE_MMAP}; +use syscall::{Error, EventFlags, EBADF, EINVAL, ENOENT, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE, MapFlags}; use crate::{ display::Display, @@ -167,7 +166,7 @@ impl SchemeMut for DisplayScheme { vt_screen.next().unwrap_or("").parse::().unwrap_or(0) ); if let Some(screens) = self.vts.get_mut(&vt_i) { - if let Some(screen) = screens.get_mut(&screen_i) { + if screens.get_mut(&screen_i).is_some() { let id = self.next_id; self.next_id += 1; @@ -301,7 +300,7 @@ impl SchemeMut for DisplayScheme { match handle.kind { HandleKind::Input => { use inputd::{Cmd as DisplayCommand, VtMode}; - + let command = inputd::parse_command(buf).unwrap(); match command { From 24d1f95de3556e1da9f7a40e6313640ac4cc1861 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 13 Jan 2024 19:25:49 +0100 Subject: [PATCH 0736/1301] Minor change --- vesad/src/screen/text.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index 02695192e2..fd7647e77d 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -121,7 +121,8 @@ impl Screen for TextScreen { } fn resize(&mut self, width: usize, height: usize) { - self.screen.display.resize(width, height); + self.screen.resize(width, height); + self.screen.input.clear(); self.console.state.w = width / 8; self.console.state.h = height / 16; } From 5c591cf475bd5c6a100c20ee566831a3eeb73e3d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 13 Jan 2024 19:32:24 +0100 Subject: [PATCH 0737/1301] Merge Display into GraphicScreen --- vesad/src/display.rs | 101 +------------------------------- vesad/src/scheme.rs | 5 +- vesad/src/screen/graphic.rs | 114 +++++++++++++++++++++++++++++------- vesad/src/screen/text.rs | 8 +-- 4 files changed, 101 insertions(+), 127 deletions(-) diff --git a/vesad/src/display.rs b/vesad/src/display.rs index 6a6e29ee64..f746c5ac14 100644 --- a/vesad/src/display.rs +++ b/vesad/src/display.rs @@ -1,5 +1,5 @@ use std::alloc::{self, Layout}; -use std::{cmp, ptr}; +use std::ptr; use std::ptr::NonNull; pub struct OffscreenBuffer { @@ -14,7 +14,7 @@ impl OffscreenBuffer { } #[inline] - fn new(len: usize) -> Self { + pub fn new(len: usize) -> Self { let layout = Self::layout(len); let ptr = unsafe { alloc::alloc_zeroed(layout) }; let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len); @@ -39,100 +39,3 @@ impl std::ops::DerefMut for OffscreenBuffer { unsafe { self.ptr.as_mut() } } } - -/// A display -pub struct Display { - pub width: usize, - pub height: usize, - pub offscreen: OffscreenBuffer, -} - -impl Display { - pub fn new(width: usize, height: usize) -> Display { - let size = width * height; - let offscreen = OffscreenBuffer::new(size); - Display { - width, - height, - offscreen, - } - } - - pub fn resize(&mut self, width: usize, height: usize) { - if width != self.width || height != self.height { - println!("Resize display to {}, {}", width, height); - - let size = width * height; - let mut offscreen = OffscreenBuffer::new(size); - - { - let mut old_ptr = self.offscreen.as_ptr(); - let mut new_ptr = offscreen.as_mut_ptr(); - - for _y in 0..cmp::min(height, self.height) { - unsafe { - ptr::copy( - old_ptr as *const u8, - new_ptr as *mut u8, - cmp::min(width, self.width) * 4 - ); - if width > self.width { - ptr::write_bytes( - new_ptr.offset(self.width as isize), - 0, - width - self.width - ); - } - old_ptr = old_ptr.offset(self.width as isize); - new_ptr = new_ptr.offset(width as isize); - } - } - - if height > self.height { - for _y in self.height..height { - unsafe { - ptr::write_bytes(new_ptr, 0, width); - new_ptr = new_ptr.offset(width as isize); - } - } - } - } - - self.width = width; - self.height = height; - - self.offscreen = offscreen; - } else { - println!("Display is already {}, {}", width, height); - } - } - - /// Copy from offscreen to onscreen - pub fn sync(&mut self, x: usize, y: usize, w: usize, h: usize, onscreen: &mut [u32], stride: usize) { - let start_y = cmp::min(self.height, y); - let end_y = cmp::min(self.height, y + h); - - let start_x = cmp::min(self.width, x); - let len = (cmp::min(self.width, x + w) - start_x) * 4; - - let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; - let mut onscreen_ptr = onscreen.as_mut_ptr() as usize; - - offscreen_ptr += (y * self.width + start_x) * 4; - onscreen_ptr += (y * stride + start_x) * 4; - - let mut rows = end_y - start_y; - while rows > 0 { - unsafe { - ptr::copy( - offscreen_ptr as *const u8, - onscreen_ptr as *mut u8, - len - ); - } - offscreen_ptr += self.width * 4; - onscreen_ptr += stride * 4; - rows -= 1; - } - } -} diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 37ce23d111..9cce63e627 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -4,7 +4,6 @@ use std::{mem, ptr, slice, str}; use syscall::{Error, EventFlags, EBADF, EINVAL, ENOENT, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE, MapFlags}; use crate::{ - display::Display, framebuffer::FrameBuffer, screen::{Screen, GraphicScreen, TextScreen}, }; @@ -57,7 +56,7 @@ impl DisplayScheme { let mut screens = BTreeMap::>::new(); for fb_i in 0..framebuffers.len() { let fb = &framebuffers[fb_i]; - let graphic_screen = GraphicScreen::new(Display::new(fb.width, fb.height)); + let graphic_screen = GraphicScreen::new(fb.width, fb.height); screens.insert(ScreenIndex(fb_i), if vt_type { Box::new(graphic_screen) } else { @@ -311,7 +310,7 @@ impl SchemeMut for DisplayScheme { for (screen_i, screen) in screens.iter_mut() { match mode { VtMode::Graphic => { - *screen = Box::new(GraphicScreen::new(Display::new(screen.width(), screen.height()))); + *screen = Box::new(GraphicScreen::new(screen.width(), screen.height())); } VtMode::Default => { diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen/graphic.rs index 506d4e4a0e..7dbacae73e 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen/graphic.rs @@ -1,11 +1,11 @@ use std::collections::VecDeque; use std::convert::TryInto; -use std::{mem, slice}; +use std::{mem, slice, cmp, ptr}; use orbclient::{Event, ResizeEvent}; use syscall::error::*; -use crate::display::Display; +use crate::display::OffscreenBuffer; use crate::screen::Screen; // Keep synced with orbital @@ -19,15 +19,19 @@ pub struct SyncRect { } pub struct GraphicScreen { - pub display: Display, + pub width: usize, + pub height: usize, + pub offscreen: OffscreenBuffer, pub input: VecDeque, pub sync_rects: Vec, } impl GraphicScreen { - pub fn new(display: Display) -> GraphicScreen { + pub fn new(width: usize, height: usize) -> GraphicScreen { GraphicScreen { - display, + width, + height, + offscreen: OffscreenBuffer::new(width * height), input: VecDeque::new(), sync_rects: Vec::new(), } @@ -36,16 +40,61 @@ impl GraphicScreen { impl Screen for GraphicScreen { fn width(&self) -> usize { - self.display.width + self.width } fn height(&self) -> usize { - self.display.height + self.height } fn resize(&mut self, width: usize, height: usize) { //TODO: Fix issue with mapped screens - self.display.resize(width, height); + + if width != self.width || height != self.height { + println!("Resize display to {}, {}", width, height); + + let size = width * height; + let mut offscreen = OffscreenBuffer::new(size); + + let mut old_ptr = self.offscreen.as_ptr(); + let mut new_ptr = offscreen.as_mut_ptr(); + + for _y in 0..cmp::min(height, self.height) { + unsafe { + ptr::copy( + old_ptr as *const u8, + new_ptr as *mut u8, + cmp::min(width, self.width) * 4 + ); + if width > self.width { + ptr::write_bytes( + new_ptr.offset(self.width as isize), + 0, + width - self.width + ); + } + old_ptr = old_ptr.offset(self.width as isize); + new_ptr = new_ptr.offset(width as isize); + } + } + + if height > self.height { + for _y in self.height..height { + unsafe { + ptr::write_bytes(new_ptr, 0, width); + new_ptr = new_ptr.offset(width as isize); + } + } + } + + self.width = width; + self.height = height; + + self.offscreen = offscreen; + } else { + println!("Display is already {}, {}", width, height); + }; + self.input.push_back(ResizeEvent { width: width as u32, height: height as u32, @@ -53,8 +102,8 @@ impl Screen for GraphicScreen { } fn map(&self, offset: usize, size: usize) -> Result { - if offset + size <= self.display.offscreen.len() * 4 { - Ok(self.display.offscreen.as_ptr() as usize + offset) + if offset + size <= self.offscreen.len() * 4 { + Ok(self.offscreen.as_ptr() as usize + offset) } else { Err(Error::new(EINVAL)) } @@ -104,20 +153,43 @@ impl Screen for GraphicScreen { fn sync(&mut self, onscreen: &mut [u32], stride: usize) { for sync_rect in self.sync_rects.drain(..) { - self.display.sync( - sync_rect.x.try_into().unwrap_or(0), - sync_rect.y.try_into().unwrap_or(0), - sync_rect.w.try_into().unwrap_or(0), - sync_rect.h.try_into().unwrap_or(0), - onscreen, - stride, - ); + let x = sync_rect.x.try_into().unwrap_or(0); + let y = sync_rect.y.try_into().unwrap_or(0); + let w = sync_rect.w.try_into().unwrap_or(0); + let h = sync_rect.h.try_into().unwrap_or(0); + + let start_y = cmp::min(self.height, y); + let end_y = cmp::min(self.height, y + h); + + let start_x = cmp::min(self.width, x); + let len = (cmp::min(self.width, x + w) - start_x) * 4; + + let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; + let mut onscreen_ptr = onscreen.as_mut_ptr() as usize; + + offscreen_ptr += (y * self.width + start_x) * 4; + onscreen_ptr += (y * stride + start_x) * 4; + + let mut rows = end_y - start_y; + while rows > 0 { + unsafe { + ptr::copy( + offscreen_ptr as *const u8, + onscreen_ptr as *mut u8, + len + ); + } + offscreen_ptr += self.width * 4; + onscreen_ptr += stride * 4; + rows -= 1; + }; } } fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { - let width = self.display.width; - let height = self.display.height; - self.display.sync(0, 0, width, height, onscreen, stride); + let width = self.width.try_into().unwrap(); + let height = self.height.try_into().unwrap(); + self.sync_rects.push(SyncRect { x: 0, y: 0, w: width, h: height }); + self.sync(onscreen, stride); } } diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs index fd7647e77d..d4952d09b4 100644 --- a/vesad/src/screen/text.rs +++ b/vesad/src/screen/text.rs @@ -39,7 +39,7 @@ impl TextScreen { let start_x = cmp::min(screen.width(), x); let len = cmp::min(screen.width(), x + w) - start_x; - let mut offscreen_ptr = screen.display.offscreen.as_mut_ptr() as usize; + let mut offscreen_ptr = screen.offscreen.as_mut_ptr() as usize; let stride = screen.width() * 4; @@ -66,7 +66,7 @@ impl TextScreen { let start_x = cmp::min(screen.width(), x); let len = cmp::min(screen.width(), x + w) - start_x; - let mut offscreen_ptr = screen.display.offscreen.as_mut_ptr() as usize; + let mut offscreen_ptr = screen.offscreen.as_mut_ptr() as usize; let stride = screen.width() * 4; @@ -93,7 +93,7 @@ impl TextScreen { /// Draw a character fn char(screen: &mut GraphicScreen, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) { if x + 8 <= screen.width() && y + 16 <= screen.height() { - let mut dst = screen.display.offscreen.as_mut_ptr() as usize + (y * screen.width() + x) * 4; + let mut dst = screen.offscreen.as_mut_ptr() as usize + (y * screen.width() + x) * 4; let font_i = 16 * (character as usize); if font_i + 16 <= FONT.len() { @@ -245,7 +245,7 @@ impl Screen for TextScreen { ransid::Event::ScreenBuffer { .. } => (), ransid::Event::Move {from_x, from_y, to_x, to_y, w, h } => { let width = screen.width(); - let pixels = &mut screen.display.offscreen; + let pixels = &mut screen.offscreen; for raw_y in 0..h { let y = if from_y > to_y { From b3b1fb17264a1d22353edbcbae3b0ef1fc5b31ca Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 13 Jan 2024 19:36:08 +0100 Subject: [PATCH 0738/1301] Remove VtMode::Text It isn't used anywhere. --- inputd/src/lib.rs | 1 - vesad/src/scheme.rs | 2 -- 2 files changed, 3 deletions(-) diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index a3d1020678..4a52c09403 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -10,7 +10,6 @@ unsafe fn any_as_u8_slice(p: &T) -> &[u8] { #[derive(Debug, Copy, Clone, PartialEq)] #[repr(usize)] pub enum VtMode { - Text = 0, Graphic = 1, Default = 2, } diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 9cce63e627..933423ff69 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -319,8 +319,6 @@ impl SchemeMut for DisplayScheme { self.framebuffers[screen_i.0].stride ); } - - VtMode::Text => todo!() } } } From bc1a068a4ffa45cd1dbd3f1d4bade5c89201692e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 14 Jan 2024 18:14:40 +0100 Subject: [PATCH 0739/1301] Introduce fbcond to replace text console handling inside vesad This will in the future allow switching between graphical mode and text mode virtual terminals while keeping alternative graphics drivers like virtio-gpud enabled at all times rather than having to reset back to VGA mode every time. --- Cargo.lock | 58 ++++++-- Cargo.toml | 1 + fbcond/Cargo.toml | 16 +++ fbcond/src/display.rs | 154 ++++++++++++++++++++ fbcond/src/main.rs | 165 +++++++++++++++++++++ fbcond/src/scheme.rs | 186 ++++++++++++++++++++++++ fbcond/src/text.rs | 327 ++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 895 insertions(+), 12 deletions(-) create mode 100644 fbcond/Cargo.toml create mode 100644 fbcond/src/display.rs create mode 100644 fbcond/src/main.rs create mode 100644 fbcond/src/scheme.rs create mode 100644 fbcond/src/text.rs diff --git a/Cargo.lock b/Cargo.lock index 1d75ca68a9..5bd694432b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,7 +11,7 @@ dependencies = [ "log", "redox-daemon", "redox-log", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.4.1", "spin", ] @@ -59,7 +59,7 @@ dependencies = [ "common", "netutils", "redox-daemon", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.4.1", ] @@ -377,7 +377,7 @@ dependencies = [ "common", "netutils", "redox-daemon", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.4.1", ] @@ -387,6 +387,18 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "fbcond" +version = "0.1.0" +dependencies = [ + "inputd", + "orbclient", + "ransid", + "redox-daemon", + "redox_event 0.2.1", + "redox_syscall 0.4.1", +] + [[package]] name = "fdt" version = "0.1.5" @@ -599,7 +611,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.4.1", "spin", ] @@ -650,7 +662,7 @@ dependencies = [ "common", "netutils", "redox-daemon", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.4.1", ] @@ -675,6 +687,17 @@ version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +[[package]] +name = "libredox" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +dependencies = [ + "bitflags 2.4.0", + "libc", + "redox_syscall 0.4.1", +] + [[package]] name = "lived" version = "0.1.0" @@ -740,7 +763,7 @@ dependencies = [ "ntpclient", "pbr", "redox-daemon", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.3.5", "redox_termios", "termion", @@ -1117,6 +1140,17 @@ dependencies = [ "redox_syscall 0.4.1", ] +[[package]] +name = "redox_event" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "475e252d7add4825405d2248d530d33e22364ac5477eab816b56efbeec1e2712" +dependencies = [ + "bitflags 2.4.0", + "libredox", + "redox_syscall 0.4.1", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -1164,7 +1198,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.4.1", ] @@ -1179,7 +1213,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.4.1", ] @@ -1204,7 +1238,7 @@ dependencies = [ "log", "redox-daemon", "redox-log", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.4.1", "spin", ] @@ -1629,7 +1663,7 @@ dependencies = [ "common", "orbclient", "redox-daemon", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.4.1", ] @@ -1694,7 +1728,7 @@ dependencies = [ "log", "pcid", "redox-log", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.4.1", "static_assertions", "thiserror", @@ -1930,7 +1964,7 @@ dependencies = [ "plain", "redox-daemon", "redox-log", - "redox_event", + "redox_event 0.1.0", "redox_syscall 0.4.1", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 2298868ad1..444a5947c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = [ "block-io-wrapper", "common", "e1000d", + "fbcond", "ided", "ihdad", "ixgbed", diff --git a/fbcond/Cargo.toml b/fbcond/Cargo.toml new file mode 100644 index 0000000000..465876c071 --- /dev/null +++ b/fbcond/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "fbcond" +version = "0.1.0" +edition = "2021" + +[dependencies] +orbclient = "0.3.27" +ransid = "0.4" +redox_event = "0.2" +redox_syscall = "0.4" +redox-daemon = "0.1" + +inputd = { path = "../inputd" } + +[features] +default = [] diff --git a/fbcond/src/display.rs b/fbcond/src/display.rs new file mode 100644 index 0000000000..31f930756d --- /dev/null +++ b/fbcond/src/display.rs @@ -0,0 +1,154 @@ +use std::mem; +use std::{ + fs::File, + io, + os::fd::RawFd, + os::unix::io::{AsRawFd, FromRawFd}, + slice, +}; +use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; + +// Keep synced with vesad +#[derive(Clone, Copy)] +#[repr(packed)] +pub struct SyncRect { + pub x: i32, + pub y: i32, + pub w: i32, + pub h: i32, +} + +fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Result<*mut [u32]> { + unsafe { + let display_ptr = syscall::fmap( + display_fd, + &syscall::Map { + offset: 0, + size: (width * height * 4), + flags: syscall::PROT_READ | syscall::PROT_WRITE | syscall::MAP_SHARED, + address: 0, + }, + )?; + let display_slice = slice::from_raw_parts_mut(display_ptr as *mut u32, width * height); + Ok(display_slice) + } +} + +unsafe fn display_fd_unmap(image: *mut [u32], size: usize) { + // FIXME use image.len() instead of size once it is stable. + let _ = syscall::funmap(image as *mut u32 as usize, size * 4); +} + +pub struct Display { + pub input_handle: File, + pub display_file: File, + pub offscreen: *mut [u32], + pub width: usize, + pub height: usize, +} + +impl Display { + pub fn open_vt(vt: usize) -> io::Result { + let mut buffer = [0; 1024]; + + let input_handle = File::open(format!("input:consumer/{vt}"))?; + let fd = input_handle.as_raw_fd(); + + let written = syscall::fpath(fd as usize, &mut buffer) + .expect("init: failed to get the path to the display device"); + + assert!(written <= buffer.len()); + + let display_path = + std::str::from_utf8(&buffer[..written]).expect("init: display path UTF-8 check failed"); + + let display_file = syscall::open(display_path, O_CLOEXEC | O_NONBLOCK | O_RDWR) + .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) + .unwrap_or_else(|err| { + panic!("failed to open display {}: {}", display_path, err); + }); + + let mut buf: [u8; 4096] = [0; 4096]; + let count = + syscall::fpath(display_file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| { + panic!("Could not read display path with fpath(): {e}"); + }); + + let url = + String::from_utf8(Vec::from(&buf[..count])).expect("Could not create Utf8 Url String"); + let path = Self::url_parts(&url)?; + let (width, height) = Self::parse_display_path(path); + + let offscreen_buffer = display_fd_map(width, height, display_file.as_raw_fd() as usize) + .unwrap_or_else(|e| panic!("failed to map display '{display_path}: {e}")); + Ok(Self { + input_handle, + display_file, + offscreen: offscreen_buffer, + width, + height, + }) + } + + fn url_parts(url: &str) -> io::Result<&str> { + let mut url_parts = url.split(':'); + url_parts + .next() + .expect("Could not get scheme name from url"); + let path = url_parts.next().expect("Could not get path from url"); + Ok(path) + } + + fn parse_display_path(path: &str) -> (usize, usize) { + let mut path_parts = path.split('/').skip(1); + let width = path_parts + .next() + .unwrap_or("") + .parse::() + .unwrap_or(0); + let height = path_parts + .next() + .unwrap_or("") + .parse::() + .unwrap_or(0); + + (width, height) + } + + pub fn resize(&mut self, width: usize, height: usize) { + match display_fd_map(width, height, self.display_file.as_raw_fd() as usize) { + Ok(ok) => { + unsafe { + display_fd_unmap(self.offscreen, (self.width * self.height) as usize); + } + self.offscreen = ok; + self.width = width; + self.height = height; + } + Err(err) => { + eprintln!("failed to resize display to {}x{}: {}", width, height, err); + } + } + } + + pub fn sync_rect(&mut self, sync_rect: SyncRect) -> syscall::Result<()> { + unsafe { + syscall::write( + self.display_file.as_raw_fd().as_raw_fd() as usize, + slice::from_raw_parts( + &sync_rect as *const SyncRect as *const u8, + mem::size_of::(), + ), + )?; + Ok(()) + } + } +} + +impl Drop for Display { + fn drop(&mut self) { + unsafe { + display_fd_unmap(self.offscreen, self.width * self.height); + } + } +} diff --git a/fbcond/src/main.rs b/fbcond/src/main.rs new file mode 100644 index 0000000000..5349f038e2 --- /dev/null +++ b/fbcond/src/main.rs @@ -0,0 +1,165 @@ +use event::EventQueue; +use orbclient::Event; +use std::fs::File; +use std::io::{ErrorKind, Read, Write}; +use std::os::fd::AsRawFd; +use std::{env, io, mem, slice}; +use syscall::{Packet, SchemeMut, EVENT_READ}; + +use crate::scheme::{FbconScheme, VtIndex}; + +mod display; +mod scheme; +mod text; + +fn read_to_slice(mut r: R, buf: &mut [T]) -> io::Result { + unsafe { + r.read(slice::from_raw_parts_mut( + buf.as_mut_ptr() as *mut u8, + buf.len() * mem::size_of::(), + )) + .map(|count| count / mem::size_of::()) + } +} + +fn main() { + let vt_ids = env::args() + .skip(1) + .map(|arg| arg.parse().expect("invalid vt number")) + .collect::>(); + + redox_daemon::Daemon::new(|daemon| inner(daemon, &vt_ids)).expect("failed to create daemon"); +} +fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { + let mut event_queue = EventQueue::new().expect("fbcond: failed to create event queue"); + + // FIXME listen for resize events from inputd and handle them + + let mut socket = File::create(":fbcon").expect("fbcond: failed to create fbcon scheme"); + event_queue + .subscribe( + socket.as_raw_fd().as_raw_fd() as usize, + VtIndex::SCHEMA_SENTINEL, + event::EventFlags::READ, + ) + .expect("fbcond: failed to subscribe to scheme events"); + + let mut scheme = FbconScheme::new(vt_ids, &mut event_queue); + + syscall::setrens(0, 0).expect("fbcond: failed to enter null namespace"); + + daemon.ready().expect("failed to notify parent"); + + scheme + .inputd_handle + .activate(1, inputd::VtMode::Default) + .unwrap(); + + let mut blocked = Vec::new(); + for event in event_queue { + let event = event.expect("fbcond: failed to read event from event queue"); + + match event.user_data { + VtIndex::SCHEMA_SENTINEL => { + let mut packet = Packet::default(); + if socket + .read(&mut packet) + .expect("fbcond: failed to read display scheme") + == 0 + { + //TODO: Handle blocked + break; + } + + // If it is a read packet, and there is no data, block it. Otherwise, handle packet + if packet.a == syscall::number::SYS_READ + && packet.d > 0 + && scheme.can_read(packet.b).is_none() + { + blocked.push(packet); + } else { + scheme.handle(&mut packet); + socket + .write(&packet) + .expect("fbcond: failed to write display scheme"); + } + } + vt_i => { + let vt = scheme.vts.get_mut(&vt_i).unwrap(); + + let mut events = [Event::new(); 16]; + loop { + match read_to_slice(&mut vt.display.input_handle, &mut events) { + Ok(0) => break, + Err(err) if err.kind() == ErrorKind::WouldBlock => { + break; + } + + Ok(count) => { + let events = &mut events[..count]; + for event in events.iter_mut() { + vt.input(event) + } + } + Err(err) => { + panic!("fbcond: Error while reading events: {err}"); + } + } + } + } + } + + // If there are blocked readers, and data is available, handle them + { + let mut i = 0; + while i < blocked.len() { + if scheme.can_read(blocked[i].b).is_some() { + let mut packet = blocked.remove(i); + scheme.handle(&mut packet); + socket + .write(&packet) + .expect("fbcond: failed to write display scheme"); + } else { + i += 1; + } + } + } + + for (handle_id, handle) in scheme.handles.iter_mut() { + if !handle.events.contains(EVENT_READ) { + continue; + } + + // Can't use scheme.can_read() because we borrow handles as mutable. + // (and because it'd treat O_NONBLOCK sockets differently) + let count = scheme + .vts + .get(&handle.vt_i) + .and_then(|console| console.can_read()) + .unwrap_or(0); + + if count > 0 { + if !handle.notified_read { + handle.notified_read = true; + let event_packet = Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: EVENT_READ.bits(), + d: count, + }; + + socket + .write(&event_packet) + .expect("fbcond: failed to write display event"); + } + } else { + handle.notified_read = false; + } + } + } + std::process::exit(0); +} diff --git a/fbcond/src/scheme.rs b/fbcond/src/scheme.rs new file mode 100644 index 0000000000..a64a62cade --- /dev/null +++ b/fbcond/src/scheme.rs @@ -0,0 +1,186 @@ +use std::collections::BTreeMap; +use std::os::fd::AsRawFd; + +use event::{EventQueue, UserData}; +use syscall::{Error, EventFlags, Result, SchemeMut, EBADF, EINVAL, ENOENT, O_NONBLOCK}; + +use crate::display::Display; +use crate::text::TextScreen; + +#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)] +pub struct VtIndex(usize); + +impl VtIndex { + pub const SCHEMA_SENTINEL: VtIndex = VtIndex(usize::MAX); +} + +impl UserData for VtIndex { + fn into_user_data(self) -> usize { + self.0 + } + + fn from_user_data(user_data: usize) -> Self { + VtIndex(user_data) + } +} + +#[derive(Clone)] +pub struct Handle { + pub vt_i: VtIndex, + pub flags: usize, + pub events: EventFlags, + pub notified_read: bool, +} + +pub struct FbconScheme { + pub vts: BTreeMap, + next_id: usize, + pub handles: BTreeMap, + pub inputd_handle: inputd::Handle, +} + +impl FbconScheme { + pub fn new(vt_ids: &[usize], event_queue: &mut EventQueue) -> FbconScheme { + let inputd_handle = inputd::Handle::new("vesa").unwrap(); + + let mut vts = BTreeMap::new(); + + for &vt_i in vt_ids { + let display = Display::open_vt(vt_i).expect("Failed to open display for vt"); + event_queue.subscribe( + display.input_handle.as_raw_fd().as_raw_fd() as usize, + VtIndex(vt_i), + event::EventFlags::READ, + ).expect("Failed to subscribe to input events for vt"); + vts.insert(VtIndex(vt_i), TextScreen::new(display)); + } + + FbconScheme { + vts, + next_id: 0, + handles: BTreeMap::new(), + inputd_handle, + } + } + + pub fn can_read(&self, id: usize) -> Option { + if let Some(handle) = self.handles.get(&id) { + if let Some(console) = self.vts.get(&handle.vt_i) { + console + .can_read() + .or(if handle.flags & O_NONBLOCK == O_NONBLOCK { + Some(0) + } else { + None + }); + } + } + + Some(0) + } + + fn resize(&mut self, width: usize, height: usize, stride: usize) { + for console in self.vts.values_mut() { + console.resize(width, height); + } + } +} + +impl SchemeMut for FbconScheme { + fn open(&mut self, path_str: &str, flags: usize, _uid: u32, _gid: u32) -> Result { + let vt_i = VtIndex(path_str.parse::().map_err(|_| Error::new(ENOENT))?); + if let Some(_console) = self.vts.get_mut(&vt_i) { + let id = self.next_id; + self.next_id += 1; + + self.handles.insert( + id, + Handle { + vt_i, + flags, + events: EventFlags::empty(), + notified_read: false, + }, + ); + + Ok(id) + } else { + Err(Error::new(ENOENT)) + } + } + + fn dup(&mut self, id: usize, buf: &[u8]) -> Result { + if !buf.is_empty() { + return Err(Error::new(EINVAL)); + } + + let handle = self + .handles + .get(&id) + .map(|handle| handle.clone()) + .ok_or(Error::new(EBADF))?; + + let new_id = self.next_id; + self.next_id += 1; + + self.handles.insert(new_id, handle); + + Ok(new_id) + } + + fn fevent(&mut self, id: usize, flags: syscall::EventFlags) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + handle.notified_read = false; + + handle.events = flags; + Ok(syscall::EventFlags::empty()) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let path_str = format!("fbcon:{}", handle.vt_i.0); + + let path = path_str.as_bytes(); + + let mut i = 0; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; + i += 1; + } + + Ok(i) + } + + fn fsync(&mut self, id: usize) -> Result { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + return Ok(0); + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + if let Some(screen) = self.vts.get_mut(&handle.vt_i) { + return screen.read(buf); + } + + Err(Error::new(EBADF)) + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + if let Some(console) = self.vts.get_mut(&handle.vt_i) { + console.write(buf) + } else { + Err(Error::new(EBADF)) + } + } + + fn close(&mut self, id: usize) -> Result { + self.handles.remove(&id).ok_or(Error::new(EBADF))?; + Ok(0) + } +} diff --git a/fbcond/src/text.rs b/fbcond/src/text.rs new file mode 100644 index 0000000000..bdc24d66f5 --- /dev/null +++ b/fbcond/src/text.rs @@ -0,0 +1,327 @@ +extern crate ransid; + +use std::collections::{BTreeSet, VecDeque}; +use std::convert::{TryFrom, TryInto}; +use std::os::fd::AsRawFd; +use std::{cmp, ptr}; + +use orbclient::{Event, EventOption, FONT}; +use syscall::error::*; + +use crate::display::{Display, SyncRect}; + +pub struct TextScreen { + console: ransid::Console, + pub display: Display, + changed: BTreeSet, + ctrl: bool, + input: VecDeque, +} + +impl TextScreen { + pub fn new(display: Display) -> TextScreen { + TextScreen { + console: ransid::Console::new(display.width / 8, display.height / 16), + display, + changed: BTreeSet::new(), + ctrl: false, + input: VecDeque::new(), + } + } + + /// Draw a rectangle + fn rect(display: &mut Display, x: usize, y: usize, w: usize, h: usize, color: u32) { + let start_y = cmp::min(display.height, y); + let end_y = cmp::min(display.height, y + h); + + let start_x = cmp::min(display.width, x); + let len = cmp::min(display.width, x + w) - start_x; + + let mut offscreen_ptr = display.offscreen as *mut u8 as usize; + + let stride = display.width * 4; + + let offset = y * stride + start_x * 4; + offscreen_ptr += offset; + + let mut rows = end_y - start_y; + while rows > 0 { + for i in 0..len { + unsafe { + *(offscreen_ptr as *mut u32).add(i) = color; + } + } + offscreen_ptr += stride; + rows -= 1; + } + } + + /// Invert a rectangle + fn invert(display: &mut Display, x: usize, y: usize, w: usize, h: usize) { + let start_y = cmp::min(display.height, y); + let end_y = cmp::min(display.height, y + h); + + let start_x = cmp::min(display.width, x); + let len = cmp::min(display.width, x + w) - start_x; + + let mut offscreen_ptr = display.offscreen as *mut u8 as usize; + + let stride = display.width * 4; + + let offset = y * stride + start_x * 4; + offscreen_ptr += offset; + + let mut rows = end_y - start_y; + while rows > 0 { + let mut row_ptr = offscreen_ptr; + let mut cols = len; + while cols > 0 { + unsafe { + let color = *(row_ptr as *mut u32); + *(row_ptr as *mut u32) = !color; + } + row_ptr += 4; + cols -= 1; + } + offscreen_ptr += stride; + rows -= 1; + } + } + + /// Draw a character + fn char( + display: &mut Display, + x: usize, + y: usize, + character: char, + color: u32, + _bold: bool, + _italic: bool, + ) { + if x + 8 <= display.width && y + 16 <= display.height { + let mut dst = display.offscreen as *mut u8 as usize + (y * display.width + x) * 4; + + let font_i = 16 * (character as usize); + if font_i + 16 <= FONT.len() { + for row in 0..16 { + let row_data = FONT[font_i + row]; + for col in 0..8 { + if (row_data >> (7 - col)) & 1 == 1 { + unsafe { + *((dst + col * 4) as *mut u32) = color; + } + } + } + dst += display.width * 4; + } + } + } + } + + pub fn resize(&mut self, width: usize, height: usize) { + self.display + .resize(width.try_into().unwrap(), height.try_into().unwrap()); + self.console.state.w = width / 8; + self.console.state.h = height / 16; + } + + pub fn input(&mut self, event: &Event) { + let mut buf = vec![]; + + match event.to_option() { + EventOption::Key(key_event) => { + if key_event.scancode == 0x1D { + self.ctrl = key_event.pressed; + } else if key_event.pressed { + match key_event.scancode { + 0x0E => { + // Backspace + buf.extend_from_slice(b"\x7F"); + } + 0x47 => { + // Home + buf.extend_from_slice(b"\x1B[H"); + } + 0x48 => { + // Up + buf.extend_from_slice(b"\x1B[A"); + } + 0x49 => { + // Page up + buf.extend_from_slice(b"\x1B[5~"); + } + 0x4B => { + // Left + buf.extend_from_slice(b"\x1B[D"); + } + 0x4D => { + // Right + buf.extend_from_slice(b"\x1B[C"); + } + 0x4F => { + // End + buf.extend_from_slice(b"\x1B[F"); + } + 0x50 => { + // Down + buf.extend_from_slice(b"\x1B[B"); + } + 0x51 => { + // Page down + buf.extend_from_slice(b"\x1B[6~"); + } + 0x52 => { + // Insert + buf.extend_from_slice(b"\x1B[2~"); + } + 0x53 => { + // Delete + buf.extend_from_slice(b"\x1B[3~"); + } + _ => { + let c = match key_event.character { + c @ 'A'..='Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char, + c @ 'a'..='z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char, + c => c, + }; + + if c != '\0' { + let mut b = [0; 4]; + buf.extend_from_slice(c.encode_utf8(&mut b).as_bytes()); + } + } + } + } + } + _ => (), //TODO: Mouse in terminal + } + + for &b in buf.iter() { + self.input.push_back(b); + } + } + + pub fn can_read(&self) -> Option { + if self.input.is_empty() { + None + } else { + Some(self.input.len()) + } + } +} + +impl TextScreen { + pub fn read(&mut self, buf: &mut [u8]) -> Result { + let mut i = 0; + + while i < buf.len() && !self.input.is_empty() { + buf[i] = self.input.pop_front().unwrap(); + i += 1; + } + + Ok(i) + } + + pub fn write(&mut self, buf: &[u8]) -> Result { + if self.console.state.cursor + && self.console.state.x < self.console.state.w + && self.console.state.y < self.console.state.h + { + let x = self.console.state.x; + let y = self.console.state.y; + Self::invert(&mut self.display, x * 8, y * 16, 8, 16); + self.changed.insert(y); + } + + { + let display = &mut self.display; + let changed = &mut self.changed; + let input = &mut self.input; + self.console.write(buf, |event| match event { + ransid::Event::Char { + x, + y, + c, + color, + bold, + .. + } => { + Self::char(display, x * 8, y * 16, c, color.as_rgb(), bold, false); + changed.insert(y); + } + ransid::Event::Input { data } => { + input.extend(data); + } + ransid::Event::Rect { x, y, w, h, color } => { + Self::rect(display, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); + for y2 in y..y + h { + changed.insert(y2); + } + } + ransid::Event::ScreenBuffer { .. } => (), + ransid::Event::Move { + from_x, + from_y, + to_x, + to_y, + w, + h, + } => { + let width = display.width; + let pixels = unsafe { &mut *display.offscreen }; + + for raw_y in 0..h { + let y = if from_y > to_y { raw_y } else { h - raw_y - 1 }; + + for pixel_y in 0..16 { + { + let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8; + let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8; + let len = w * 8; + + if off_from + len <= pixels.len() && off_to + len <= pixels.len() { + unsafe { + let data_ptr = pixels.as_mut_ptr() as *mut u32; + ptr::copy( + data_ptr.offset(off_from as isize), + data_ptr.offset(off_to as isize), + len, + ); + } + } + } + } + + changed.insert(to_y + y); + } + } + ransid::Event::Resize { .. } => (), + ransid::Event::Title { .. } => (), + }); + } + + if self.console.state.cursor + && self.console.state.x < self.console.state.w + && self.console.state.y < self.console.state.h + { + let x = self.console.state.x; + let y = self.console.state.y; + Self::invert(&mut self.display, x * 8, y * 16, 8, 16); + self.changed.insert(y); + } + + let width = self.display.width.try_into().unwrap(); + for &change in self.changed.iter() { + self.display.sync_rect(SyncRect { + x: 0, + y: i32::try_from(change).unwrap() * 16, + w: width, + h: 16, + })?; + } + self.changed.clear(); + syscall::fsync(self.display.display_file.as_raw_fd().as_raw_fd() as usize)?; + + Ok(buf.len()) + } +} From f64a6e4c6f994f2944a6b3895eb64a56428ecc62 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 14 Jan 2024 18:22:52 +0100 Subject: [PATCH 0740/1301] Remove text mode support from vesad This is now handled by fbcond --- vesad/src/main.rs | 12 +- vesad/src/scheme.rs | 48 ++-- vesad/src/{screen/graphic.rs => screen.rs} | 29 +- vesad/src/screen/mod.rs | 32 --- vesad/src/screen/text.rs | 313 --------------------- 5 files changed, 29 insertions(+), 405 deletions(-) rename vesad/src/{screen/graphic.rs => screen.rs} (87%) delete mode 100644 vesad/src/screen/mod.rs delete mode 100644 vesad/src/screen/text.rs diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 47bd535022..5c28880d76 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -20,14 +20,8 @@ pub mod screen; fn main() { let mut spec = Vec::new(); - for arg in env::args().skip(1) { - if arg == "T" { - spec.push(false); - } else if arg == "G" { - spec.push(true); - } else { - eprintln!("vesad: unknown screen type: {}", arg); - } + for _ in env::args().skip(1) { + spec.push(()); } let width = usize::from_str_radix( @@ -89,7 +83,7 @@ fn main() { redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers, &spec)).expect("failed to create daemon"); } -fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[bool]) -> ! { +fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[()]) -> ! { let mut socket = File::create(":display.vesa").expect("vesad: failed to create display scheme"); let mut scheme = DisplayScheme::new(framebuffers, &spec); diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index 933423ff69..b2be35ab88 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -3,10 +3,7 @@ use std::{mem, ptr, slice, str}; use syscall::{Error, EventFlags, EBADF, EINVAL, ENOENT, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE, MapFlags}; -use crate::{ - framebuffer::FrameBuffer, - screen::{Screen, GraphicScreen, TextScreen}, -}; +use crate::{framebuffer::FrameBuffer, screen::GraphicScreen}; #[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)] pub struct VtIndex(usize); @@ -32,7 +29,7 @@ pub struct DisplayScheme { framebuffers: Vec, onscreens: Vec<&'static mut [u32]>, active: VtIndex, - pub vts: BTreeMap>>, + pub vts: BTreeMap>, next_id: usize, pub handles: BTreeMap, pub inputd_handle: inputd::Handle, @@ -40,7 +37,7 @@ pub struct DisplayScheme { } impl DisplayScheme { - pub fn new(mut framebuffers: Vec, spec: &[bool]) -> DisplayScheme { + pub fn new(mut framebuffers: Vec, spec: &[()]) -> DisplayScheme { let mut inputd_handle = inputd::Handle::new("vesa").unwrap(); let mut onscreens = Vec::new(); @@ -50,18 +47,13 @@ impl DisplayScheme { }); } - let mut vts = BTreeMap::>>::new(); + let mut vts = BTreeMap::>::new(); - for &vt_type in spec.iter() { - let mut screens = BTreeMap::>::new(); + for &() in spec.iter() { + let mut screens = BTreeMap::::new(); for fb_i in 0..framebuffers.len() { let fb = &framebuffers[fb_i]; - let graphic_screen = GraphicScreen::new(fb.width, fb.height); - screens.insert(ScreenIndex(fb_i), if vt_type { - Box::new(graphic_screen) - } else { - Box::new(TextScreen::new(graphic_screen)) - }); + screens.insert(ScreenIndex(fb_i), GraphicScreen::new(fb.width, fb.height)); } vts.insert(VtIndex(inputd_handle.register().unwrap()), screens); } @@ -298,28 +290,20 @@ impl SchemeMut for DisplayScheme { match handle.kind { HandleKind::Input => { - use inputd::{Cmd as DisplayCommand, VtMode}; + use inputd::Cmd as DisplayCommand; let command = inputd::parse_command(buf).unwrap(); match command { - DisplayCommand::Activate { vt, mode } => { + DisplayCommand::Activate { vt, mode: _ } => { let vt_i = VtIndex(vt); if let Some(screens) = self.vts.get_mut(&vt_i) { for (screen_i, screen) in screens.iter_mut() { - match mode { - VtMode::Graphic => { - *screen = Box::new(GraphicScreen::new(screen.width(), screen.height())); - } - - VtMode::Default => { - screen.redraw( - self.onscreens[screen_i.0], - self.framebuffers[screen_i.0].stride - ); - } - } + screen.redraw( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride + ); } } @@ -356,13 +340,13 @@ impl SchemeMut for DisplayScheme { } } - fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { + fn seek(&mut self, id: usize, _pos: isize, _whence: usize) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(vt_i, screen_i) = handle.kind { if let Some(screens) = self.vts.get_mut(&vt_i) { - if let Some(screen) = screens.get_mut(&screen_i) { - return screen.seek(pos, whence).map(|pos| pos as isize); + if screens.contains_key(&screen_i) { + return Ok(0); } } } diff --git a/vesad/src/screen/graphic.rs b/vesad/src/screen.rs similarity index 87% rename from vesad/src/screen/graphic.rs rename to vesad/src/screen.rs index 7dbacae73e..abb4fd424e 100644 --- a/vesad/src/screen/graphic.rs +++ b/vesad/src/screen.rs @@ -6,7 +6,6 @@ use orbclient::{Event, ResizeEvent}; use syscall::error::*; use crate::display::OffscreenBuffer; -use crate::screen::Screen; // Keep synced with orbital #[derive(Clone, Copy)] @@ -38,16 +37,16 @@ impl GraphicScreen { } } -impl Screen for GraphicScreen { - fn width(&self) -> usize { +impl GraphicScreen { + pub fn width(&self) -> usize { self.width } - fn height(&self) -> usize { + pub fn height(&self) -> usize { self.height } - fn resize(&mut self, width: usize, height: usize) { + pub fn resize(&mut self, width: usize, height: usize) { //TODO: Fix issue with mapped screens if width != self.width || height != self.height { @@ -101,7 +100,7 @@ impl Screen for GraphicScreen { }.to_event()); } - fn map(&self, offset: usize, size: usize) -> Result { + pub fn map(&self, offset: usize, size: usize) -> Result { if offset + size <= self.offscreen.len() * 4 { Ok(self.offscreen.as_ptr() as usize + offset) } else { @@ -109,11 +108,7 @@ impl Screen for GraphicScreen { } } - fn input(&mut self, event: &Event) { - self.input.push_back(*event); - } - - fn read(&mut self, buf: &mut [u8]) -> Result { + pub fn read(&mut self, buf: &mut [u8]) -> Result { let mut i = 0; let event_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Event, buf.len()/mem::size_of::()) }; @@ -126,7 +121,7 @@ impl Screen for GraphicScreen { Ok(i * mem::size_of::()) } - fn can_read(&self) -> Option { + pub fn can_read(&self) -> Option { if self.input.is_empty() { None } else { @@ -134,7 +129,7 @@ impl Screen for GraphicScreen { } } - fn write(&mut self, buf: &[u8]) -> Result { + pub fn write(&mut self, buf: &[u8]) -> Result { let sync_rects = unsafe { slice::from_raw_parts( buf.as_ptr() as *const SyncRect, @@ -147,11 +142,7 @@ impl Screen for GraphicScreen { Ok(sync_rects.len() * mem::size_of::()) } - fn seek(&mut self, _pos: isize, _whence: usize) -> Result { - Ok(0) - } - - fn sync(&mut self, onscreen: &mut [u32], stride: usize) { + pub fn sync(&mut self, onscreen: &mut [u32], stride: usize) { for sync_rect in self.sync_rects.drain(..) { let x = sync_rect.x.try_into().unwrap_or(0); let y = sync_rect.y.try_into().unwrap_or(0); @@ -186,7 +177,7 @@ impl Screen for GraphicScreen { } } - fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { + pub fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { let width = self.width.try_into().unwrap(); let height = self.height.try_into().unwrap(); self.sync_rects.push(SyncRect { x: 0, y: 0, w: width, h: height }); diff --git a/vesad/src/screen/mod.rs b/vesad/src/screen/mod.rs deleted file mode 100644 index e254e1c4fe..0000000000 --- a/vesad/src/screen/mod.rs +++ /dev/null @@ -1,32 +0,0 @@ -pub use self::graphic::GraphicScreen; -pub use self::text::TextScreen; - -use orbclient::Event; -use syscall::Result; - -mod graphic; -mod text; - -pub trait Screen { - fn width(&self) -> usize; - - fn height(&self) -> usize; - - fn resize(&mut self, width: usize, height: usize); - - fn map(&self, offset: usize, size: usize) -> Result; - - fn input(&mut self, event: &Event); - - fn read(&mut self, buf: &mut [u8]) -> Result; - - fn can_read(&self) -> Option; - - fn write(&mut self, buf: &[u8]) -> Result; - - fn seek(&mut self, pos: isize, whence: usize) -> Result; - - fn sync(&mut self, onscreen: &mut [u32], stride: usize); - - fn redraw(&mut self, onscreen: &mut [u32], stride: usize); -} diff --git a/vesad/src/screen/text.rs b/vesad/src/screen/text.rs deleted file mode 100644 index d4952d09b4..0000000000 --- a/vesad/src/screen/text.rs +++ /dev/null @@ -1,313 +0,0 @@ -extern crate ransid; - -use std::collections::{BTreeSet, VecDeque}; -use std::convert::{TryFrom, TryInto}; -use std::{ptr, cmp}; - -use orbclient::{Event, EventOption, FONT}; -use syscall::error::*; - -use crate::screen::{Screen, GraphicScreen}; - -use super::graphic::SyncRect; - -pub struct TextScreen { - console: ransid::Console, - // FIXME avoid directly accessing the fields of screen - screen: GraphicScreen, - changed: BTreeSet, - ctrl: bool, - input: VecDeque, -} - -impl TextScreen { - pub fn new(screen: GraphicScreen) -> TextScreen { - TextScreen { - console: ransid::Console::new(screen.width()/8, screen.height()/16), - screen, - changed: BTreeSet::new(), - ctrl: false, - input: VecDeque::new(), - } - } - - /// Draw a rectangle - fn rect(screen: &mut GraphicScreen, x: usize, y: usize, w: usize, h: usize, color: u32) { - let start_y = cmp::min(screen.height(), y); - let end_y = cmp::min(screen.height(), y + h); - - let start_x = cmp::min(screen.width(), x); - let len = cmp::min(screen.width(), x + w) - start_x; - - let mut offscreen_ptr = screen.offscreen.as_mut_ptr() as usize; - - let stride = screen.width() * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - - let mut rows = end_y - start_y; - while rows > 0 { - for i in 0..len { - unsafe { - *(offscreen_ptr as *mut u32).add(i) = color; - } - } - offscreen_ptr += stride; - rows -= 1; - } - } - - /// Invert a rectangle - fn invert(screen: &mut GraphicScreen, x: usize, y: usize, w: usize, h: usize) { - let start_y = cmp::min(screen.height(), y); - let end_y = cmp::min(screen.height(), y + h); - - let start_x = cmp::min(screen.width(), x); - let len = cmp::min(screen.width(), x + w) - start_x; - - let mut offscreen_ptr = screen.offscreen.as_mut_ptr() as usize; - - let stride = screen.width() * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - - let mut rows = end_y - start_y; - while rows > 0 { - let mut row_ptr = offscreen_ptr; - let mut cols = len; - while cols > 0 { - unsafe { - let color = *(row_ptr as *mut u32); - *(row_ptr as *mut u32) = !color; - } - row_ptr += 4; - cols -= 1; - } - offscreen_ptr += stride; - rows -= 1; - } - } - - /// Draw a character - fn char(screen: &mut GraphicScreen, x: usize, y: usize, character: char, color: u32, _bold: bool, _italic: bool) { - if x + 8 <= screen.width() && y + 16 <= screen.height() { - let mut dst = screen.offscreen.as_mut_ptr() as usize + (y * screen.width() + x) * 4; - - let font_i = 16 * (character as usize); - if font_i + 16 <= FONT.len() { - for row in 0..16 { - let row_data = FONT[font_i + row]; - for col in 0..8 { - if (row_data >> (7 - col)) & 1 == 1 { - unsafe { *((dst + col * 4) as *mut u32) = color; } - } - } - dst += screen.width() * 4; - } - } - } - } -} - -impl Screen for TextScreen { - fn width(&self) -> usize { - self.console.state.w - } - - fn height(&self) -> usize { - self.console.state.h - } - - fn resize(&mut self, width: usize, height: usize) { - self.screen.resize(width, height); - self.screen.input.clear(); - self.console.state.w = width / 8; - self.console.state.h = height / 16; - } - - fn map(&self, _offset: usize, _size: usize) -> Result { - Err(Error::new(EBADF)) - } - - fn input(&mut self, event: &Event) { - let mut buf = vec![]; - - match event.to_option() { - EventOption::Key(key_event) => { - if key_event.scancode == 0x1D { - self.ctrl = key_event.pressed; - } else if key_event.pressed { - match key_event.scancode { - 0x0E => { // Backspace - buf.extend_from_slice(b"\x7F"); - }, - 0x47 => { // Home - buf.extend_from_slice(b"\x1B[H"); - }, - 0x48 => { // Up - buf.extend_from_slice(b"\x1B[A"); - }, - 0x49 => { // Page up - buf.extend_from_slice(b"\x1B[5~"); - }, - 0x4B => { // Left - buf.extend_from_slice(b"\x1B[D"); - }, - 0x4D => { // Right - buf.extend_from_slice(b"\x1B[C"); - }, - 0x4F => { // End - buf.extend_from_slice(b"\x1B[F"); - }, - 0x50 => { // Down - buf.extend_from_slice(b"\x1B[B"); - }, - 0x51 => { // Page down - buf.extend_from_slice(b"\x1B[6~"); - }, - 0x52 => { // Insert - buf.extend_from_slice(b"\x1B[2~"); - }, - 0x53 => { // Delete - buf.extend_from_slice(b"\x1B[3~"); - }, - _ => { - let c = match key_event.character { - c @ 'A' ..= 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char, - c @ 'a' ..= 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char, - c => c - }; - - if c != '\0' { - let mut b = [0; 4]; - buf.extend_from_slice(c.encode_utf8(&mut b).as_bytes()); - } - } - } - } - }, - _ => () //TODO: Mouse in terminal - } - - for &b in buf.iter() { - self.input.push_back(b); - } - } - - fn read(&mut self, buf: &mut [u8]) -> Result { - let mut i = 0; - - while i < buf.len() && ! self.input.is_empty() { - buf[i] = self.input.pop_front().unwrap(); - i += 1; - } - - Ok(i) - } - - fn can_read(&self) -> Option { - if self.input.is_empty() { - None - } else { - Some(self.input.len()) - } - } - - fn write(&mut self, buf: &[u8]) -> Result { - if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { - let x = self.console.state.x; - let y = self.console.state.y; - Self::invert(&mut self.screen, x * 8, y * 16, 8, 16); - self.changed.insert(y); - } - - { - let screen = &mut self.screen; - let changed = &mut self.changed; - let input = &mut self.input; - self.console.write(buf, |event| { - match event { - ransid::Event::Char { x, y, c, color, bold, .. } => { - Self::char(screen, x * 8, y * 16, c, color.as_rgb(), bold, false); - changed.insert(y); - }, - ransid::Event::Input { data } => { - input.extend(data); - }, - ransid::Event::Rect { x, y, w, h, color } => { - Self::rect(screen, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); - for y2 in y..y + h { - changed.insert(y2); - } - }, - ransid::Event::ScreenBuffer { .. } => (), - ransid::Event::Move {from_x, from_y, to_x, to_y, w, h } => { - let width = screen.width(); - let pixels = &mut screen.offscreen; - - for raw_y in 0..h { - let y = if from_y > to_y { - raw_y - } else { - h - raw_y - 1 - }; - - for pixel_y in 0..16 { - { - let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8; - let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8; - let len = w * 8; - - if off_from + len <= pixels.len() && off_to + len <= pixels.len() { - unsafe { - let data_ptr = pixels.as_mut_ptr() as *mut u32; - ptr::copy(data_ptr.offset(off_from as isize), data_ptr.offset(off_to as isize), len); - } - } - } - } - - changed.insert(to_y + y); - } - }, - ransid::Event::Resize { .. } => (), - ransid::Event::Title { .. } => () - } - }); - } - - if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h { - let x = self.console.state.x; - let y = self.console.state.y; - Self::invert(&mut self.screen, x * 8, y * 16, 8, 16); - self.changed.insert(y); - } - - Ok(buf.len()) - } - - fn seek(&mut self, _pos: isize, _whence: usize) -> Result { - Ok(0) - } - - fn sync(&mut self, onscreen: &mut [u32], stride: usize) { - let width = self.screen.width().try_into().unwrap(); - for &change in self.changed.iter() { - self.screen.sync_rects.push(SyncRect { - x: 0, - y: i32::try_from(change).unwrap() * 16, - w: width, - h: 16, - }); - } - self.changed.clear(); - self.screen.sync(onscreen, stride); - } - - fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { - self.screen.redraw(onscreen, stride); - self.changed.clear(); - } -} From fe4f0880afb41e383c972b54b6323850230fd7d0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 14 Jan 2024 19:10:47 +0100 Subject: [PATCH 0741/1301] Couple of minor cleanups Among other things this removes the seek implementation as it doesn't seem to be used and didn't do anything anyway. --- vesad/src/main.rs | 8 ++++---- vesad/src/scheme.rs | 38 ++++++-------------------------------- vesad/src/screen.rs | 16 ---------------- 3 files changed, 10 insertions(+), 52 deletions(-) diff --git a/vesad/src/main.rs b/vesad/src/main.rs index 5c28880d76..9f1d8f2901 100644 --- a/vesad/src/main.rs +++ b/vesad/src/main.rs @@ -12,10 +12,10 @@ use crate::{ scheme::{DisplayScheme, HandleKind} }; -pub mod display; -pub mod framebuffer; -pub mod scheme; -pub mod screen; +mod display; +mod framebuffer; +mod scheme; +mod screen; fn main() { let mut spec = Vec::new(); diff --git a/vesad/src/scheme.rs b/vesad/src/scheme.rs index b2be35ab88..7f12cf0f9c 100644 --- a/vesad/src/scheme.rs +++ b/vesad/src/scheme.rs @@ -205,22 +205,6 @@ impl SchemeMut for DisplayScheme { } } - /* - fn fmap(&mut self, id: usize, map: &Map) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - if let Some(screens) = self.vts.get(&vt_i) { - if let Some(screen) = screens.get(&screen_i) { - return screen.map(map.offset, map.size); - } - } - } - - Err(Error::new(EBADF)) - } - */ - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; @@ -231,7 +215,7 @@ impl SchemeMut for DisplayScheme { }, HandleKind::Screen(vt_i, screen_i) => if let Some(screens) = self.vts.get(&vt_i) { if let Some(screen) = screens.get(&screen_i) { - format!("display:{}.{}/{}/{}", vt_i.0, screen_i.0, screen.width(), screen.height()) + format!("display:{}.{}/{}/{}", vt_i.0, screen_i.0, screen.width, screen.height) } else { return Err(Error::new(EBADF)); } @@ -340,20 +324,6 @@ impl SchemeMut for DisplayScheme { } } - fn seek(&mut self, id: usize, _pos: isize, _whence: usize) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - if let Some(screens) = self.vts.get_mut(&vt_i) { - if screens.contains_key(&screen_i) { - return Ok(0); - } - } - } - - Err(Error::new(EBADF)) - } - fn close(&mut self, id: usize) -> Result { self.handles.remove(&id).ok_or(Error::new(EBADF))?; Ok(0) @@ -364,7 +334,11 @@ impl SchemeMut for DisplayScheme { if let HandleKind::Screen(vt_i, screen_i) = handle.kind { if let Some(screens) = self.vts.get(&vt_i) { if let Some(screen) = screens.get(&screen_i) { - return screen.map(off as usize, size); + if off as usize + size <= screen.offscreen.len() * 4 { + return Ok(screen.offscreen.as_ptr() as usize + off as usize); + } else { + return Err(Error::new(EINVAL)); + } } } } diff --git a/vesad/src/screen.rs b/vesad/src/screen.rs index abb4fd424e..680c2bce9c 100644 --- a/vesad/src/screen.rs +++ b/vesad/src/screen.rs @@ -38,14 +38,6 @@ impl GraphicScreen { } impl GraphicScreen { - pub fn width(&self) -> usize { - self.width - } - - pub fn height(&self) -> usize { - self.height - } - pub fn resize(&mut self, width: usize, height: usize) { //TODO: Fix issue with mapped screens @@ -100,14 +92,6 @@ impl GraphicScreen { }.to_event()); } - pub fn map(&self, offset: usize, size: usize) -> Result { - if offset + size <= self.offscreen.len() * 4 { - Ok(self.offscreen.as_ptr() as usize + offset) - } else { - Err(Error::new(EINVAL)) - } - } - pub fn read(&mut self, buf: &mut [u8]) -> Result { let mut i = 0; From 4f6f4d72673135dc98aff9ab7733c7addbfe7067 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 14 Jan 2024 19:29:02 +0100 Subject: [PATCH 0742/1301] Prevent a potential deadlock when writing to multiple text consoles --- fbcond/src/display.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fbcond/src/display.rs b/fbcond/src/display.rs index 31f930756d..da16fe5804 100644 --- a/fbcond/src/display.rs +++ b/fbcond/src/display.rs @@ -1,4 +1,6 @@ +use std::fs::OpenOptions; use std::mem; +use std::os::unix::fs::OpenOptionsExt; use std::{ fs::File, io, @@ -51,7 +53,10 @@ impl Display { pub fn open_vt(vt: usize) -> io::Result { let mut buffer = [0; 1024]; - let input_handle = File::open(format!("input:consumer/{vt}"))?; + let input_handle = OpenOptions::new() + .read(true) + .custom_flags(O_NONBLOCK as i32) + .open(format!("input:consumer/{vt}"))?; let fd = input_handle.as_raw_fd(); let written = syscall::fpath(fd as usize, &mut buffer) From ed69a8ef6d177062fb4faf9cd555089a85620925 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 14 Jan 2024 21:20:42 +0100 Subject: [PATCH 0743/1301] Open scheme in non-blocking mode and ensure events aren't lost --- fbcond/src/main.rs | 188 ++++++++++++++++++++++++++------------------- 1 file changed, 110 insertions(+), 78 deletions(-) diff --git a/fbcond/src/main.rs b/fbcond/src/main.rs index 5349f038e2..cd0a859810 100644 --- a/fbcond/src/main.rs +++ b/fbcond/src/main.rs @@ -1,10 +1,11 @@ use event::EventQueue; use orbclient::Event; -use std::fs::File; +use std::fs::{File, OpenOptions}; use std::io::{ErrorKind, Read, Write}; use std::os::fd::AsRawFd; +use std::os::unix::fs::OpenOptionsExt; use std::{env, io, mem, slice}; -use syscall::{Packet, SchemeMut, EVENT_READ}; +use syscall::{Packet, SchemeMut, EVENT_READ, O_NONBLOCK}; use crate::scheme::{FbconScheme, VtIndex}; @@ -35,7 +36,13 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { // FIXME listen for resize events from inputd and handle them - let mut socket = File::create(":fbcon").expect("fbcond: failed to create fbcon scheme"); + let mut socket = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .custom_flags(O_NONBLOCK as i32) + .open(":fbcon") + .expect("fbcond: failed to create fbcon scheme"); event_queue .subscribe( socket.as_raw_fd().as_raw_fd() as usize, @@ -56,19 +63,45 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { .unwrap(); let mut blocked = Vec::new(); + + // Handle all events that could have happened before registering with the event queue. + handle_event( + &mut socket, + &mut scheme, + &mut blocked, + VtIndex::SCHEMA_SENTINEL, + ); + for vt_i in scheme.vts.keys().copied().collect::>() { + handle_event(&mut socket, &mut scheme, &mut blocked, vt_i); + } + for event in event_queue { let event = event.expect("fbcond: failed to read event from event queue"); + handle_event(&mut socket, &mut scheme, &mut blocked, event.user_data); + } - match event.user_data { - VtIndex::SCHEMA_SENTINEL => { + std::process::exit(0); +} + +fn handle_event( + socket: &mut File, + scheme: &mut FbconScheme, + blocked: &mut Vec, + event: VtIndex, +) { + match event { + VtIndex::SCHEMA_SENTINEL => { + loop { let mut packet = Packet::default(); - if socket - .read(&mut packet) - .expect("fbcond: failed to read display scheme") - == 0 - { - //TODO: Handle blocked - break; + match socket.read(&mut packet) { + Ok(0) => break, + Err(err) if err.kind() == ErrorKind::WouldBlock => { + break; + } + Ok(_) => {} + Err(err) => { + panic!("fbcond: failed to read display scheme: {err}"); + } } // If it is a read packet, and there is no data, block it. Otherwise, handle packet @@ -84,82 +117,81 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { .expect("fbcond: failed to write display scheme"); } } - vt_i => { - let vt = scheme.vts.get_mut(&vt_i).unwrap(); + } + vt_i => { + let vt = scheme.vts.get_mut(&vt_i).unwrap(); - let mut events = [Event::new(); 16]; - loop { - match read_to_slice(&mut vt.display.input_handle, &mut events) { - Ok(0) => break, - Err(err) if err.kind() == ErrorKind::WouldBlock => { - break; - } + let mut events = [Event::new(); 16]; + loop { + match read_to_slice(&mut vt.display.input_handle, &mut events) { + Ok(0) => break, + Err(err) if err.kind() == ErrorKind::WouldBlock => { + break; + } - Ok(count) => { - let events = &mut events[..count]; - for event in events.iter_mut() { - vt.input(event) - } - } - Err(err) => { - panic!("fbcond: Error while reading events: {err}"); + Ok(count) => { + let events = &mut events[..count]; + for event in events.iter_mut() { + vt.input(event) } } + Err(err) => { + panic!("fbcond: Error while reading events: {err}"); + } } } } + } - // If there are blocked readers, and data is available, handle them - { - let mut i = 0; - while i < blocked.len() { - if scheme.can_read(blocked[i].b).is_some() { - let mut packet = blocked.remove(i); - scheme.handle(&mut packet); - socket - .write(&packet) - .expect("fbcond: failed to write display scheme"); - } else { - i += 1; - } - } - } - - for (handle_id, handle) in scheme.handles.iter_mut() { - if !handle.events.contains(EVENT_READ) { - continue; - } - - // Can't use scheme.can_read() because we borrow handles as mutable. - // (and because it'd treat O_NONBLOCK sockets differently) - let count = scheme - .vts - .get(&handle.vt_i) - .and_then(|console| console.can_read()) - .unwrap_or(0); - - if count > 0 { - if !handle.notified_read { - handle.notified_read = true; - let event_packet = Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: EVENT_READ.bits(), - d: count, - }; - - socket - .write(&event_packet) - .expect("fbcond: failed to write display event"); - } + // If there are blocked readers, and data is available, handle them + { + let mut i = 0; + while i < blocked.len() { + if scheme.can_read(blocked[i].b).is_some() { + let mut packet = blocked.remove(i); + scheme.handle(&mut packet); + socket + .write(&packet) + .expect("fbcond: failed to write display scheme"); } else { - handle.notified_read = false; + i += 1; } } } - std::process::exit(0); + + for (handle_id, handle) in scheme.handles.iter_mut() { + if !handle.events.contains(EVENT_READ) { + continue; + } + + // Can't use scheme.can_read() because we borrow handles as mutable. + // (and because it'd treat O_NONBLOCK sockets differently) + let count = scheme + .vts + .get(&handle.vt_i) + .and_then(|console| console.can_read()) + .unwrap_or(0); + + if count > 0 { + if !handle.notified_read { + handle.notified_read = true; + let event_packet = Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: *handle_id, + c: EVENT_READ.bits(), + d: count, + }; + + socket + .write(&event_packet) + .expect("fbcond: failed to write display event"); + } + } else { + handle.notified_read = false; + } + } } From bd8b21817453b0b422b5b6d1134a6ae5342349ca Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Jan 2024 15:29:06 +0100 Subject: [PATCH 0744/1301] Don't return Result from spawn_irq_thread It never returns an error. --- virtio-core/src/legacy_transport.rs | 2 +- virtio-core/src/transport.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/virtio-core/src/legacy_transport.rs b/virtio-core/src/legacy_transport.rs index e0a98e784f..45341b103f 100644 --- a/virtio-core/src/legacy_transport.rs +++ b/virtio-core/src/legacy_transport.rs @@ -144,7 +144,7 @@ impl Transport for LegacyTransport { vector, ); - spawn_irq_thread(irq_handle, &queue)?; + spawn_irq_thread(irq_handle, &queue); Ok(queue) } diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index a324a288cc..1ff80a205f 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -68,7 +68,7 @@ pub const fn queue_part_sizes(queue_size: usize) -> (usize, usize, usize) { ) } -pub fn spawn_irq_thread(irq_handle: &File, queue: &Arc>) -> Result<(), Error> { +pub fn spawn_irq_thread(irq_handle: &File, queue: &Arc>) { let irq_fd = irq_handle.as_raw_fd(); let queue_copy = queue.clone(); @@ -91,8 +91,6 @@ pub fn spawn_irq_thread(irq_handle: &File, queue: &Arc>) -> Resul event_queue.run().unwrap(); } }); - - Ok(()) } pub trait NotifyBell { @@ -645,7 +643,7 @@ impl Transport for StandardTransport<'_> { vector, ); - spawn_irq_thread(irq_handle, &queue)?; + spawn_irq_thread(irq_handle, &queue); Ok(queue) } From 380a416258088777e41dda65341655e07cc33cfe Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Jan 2024 17:17:39 +0100 Subject: [PATCH 0745/1301] Reorganize virtio headers and add a couple of new fields Also add a decent amount of comments from the virtio spec. --- virtio-core/src/spec.rs | 303 ---------------------- virtio-core/src/spec/mod.rs | 54 ++++ virtio-core/src/spec/reserved_features.rs | 100 +++++++ virtio-core/src/spec/split_virtqueue.rs | 205 +++++++++++++++ virtio-core/src/spec/transport_pci.rs | 168 ++++++++++++ 5 files changed, 527 insertions(+), 303 deletions(-) delete mode 100644 virtio-core/src/spec.rs create mode 100644 virtio-core/src/spec/mod.rs create mode 100644 virtio-core/src/spec/reserved_features.rs create mode 100644 virtio-core/src/spec/split_virtqueue.rs create mode 100644 virtio-core/src/spec/transport_pci.rs diff --git a/virtio-core/src/spec.rs b/virtio-core/src/spec.rs deleted file mode 100644 index f4a3d79f8c..0000000000 --- a/virtio-core/src/spec.rs +++ /dev/null @@ -1,303 +0,0 @@ -//! https://docs.oasis-open.org/virtio/virtio/v1.1/virtio-v1.1.html - -use std::sync::atomic::{AtomicU16, AtomicU32, AtomicU64, Ordering}; - -use crate::utils::{IncompleteArrayField, VolatileCell}; -use static_assertions::const_assert_eq; - -#[derive(Debug, Copy, Clone)] -#[repr(u8)] -pub enum CfgType { - /// Common Configuration. - Common = 1, - /// Notifications. - Notify = 2, - /// ISR Status. - Isr = 3, - /// Device specific configuration. - Device = 4, - /// PCI configuration access. - PciConfig = 5, - /// Shared memory region. - SharedMemory = 8, - /// Vendor-specific data. - Vendor = 9, -} - -const_assert_eq!(core::mem::size_of::(), 1); - -#[derive(Debug, Copy, Clone)] -#[repr(C, packed)] -pub struct PciCapability { - /// Identifies the structure. - pub cfg_type: CfgType, - /// Where to find it. - pub bar: u8, - /// Pad to a full dword. - pub padding: [u8; 3], - /// Offset within the bar. - pub offset: u32, - /// Length of the structure, in bytes. - pub length: u32, - notify_multiplier: u32, -} - -// The size of `PciCapability` is 13 bytes since the generic -// PCI fields are *not* included. -const_assert_eq!(core::mem::size_of::(), 17); - -impl PciCapability { - /// ## Safety - /// Undefined if accessed from a capability type other than [`CfgType::Notify`]. - pub unsafe fn notify_multiplier(&self) -> u32 { - self.notify_multiplier - } -} - -bitflags::bitflags! { - #[derive(Debug, Copy, Clone, PartialEq)] - #[repr(transparent)] - pub struct DeviceStatusFlags: u8 { - /// Indicates that the guest OS has found the device and recognized it as a - /// valid device. - const ACKNOWLEDGE = 1; - /// Indicates that the guest OS knows how to drive the device. - const DRIVER = 2; - /// Indicates that something went wrong in the guest and it has given up on - /// the device. - const FAILED = 128; - /// Indicates that the driver has acknowledged all the features it understands - /// and feature negotiation is complete. - const FEATURES_OK = 8; - /// Indicates that the driver is set up and ready to drive the device. - const DRIVER_OK = 4; - /// Indicates that the device has experienced an error from which it can’t recover. - const DEVICE_NEEDS_RESET = 64; - } -} - -#[derive(Debug)] -#[repr(C)] -pub struct CommonCfg { - // About the whole device. - pub device_feature_select: VolatileCell, // read-write - pub device_feature: VolatileCell, // read-only for driver - pub driver_feature_select: VolatileCell, // read-write - pub driver_feature: VolatileCell, // read-write - pub msix_config: VolatileCell, // read-write - pub num_queues: VolatileCell, // read-only for driver - pub device_status: VolatileCell, // read-write - pub config_generation: VolatileCell, // read-only for driver - - // About a specific virtqueue. - pub queue_select: VolatileCell, // read-write - pub queue_size: VolatileCell, // read-write - pub queue_msix_vector: VolatileCell, // read-write - pub queue_enable: VolatileCell, // read-write - pub queue_notify_off: VolatileCell, // read-only for driver - pub queue_desc: VolatileCell, // read-write - pub queue_driver: VolatileCell, // read-write - pub queue_device: VolatileCell, // read-write -} - -const_assert_eq!(core::mem::size_of::(), 56); - -bitflags::bitflags! { - #[derive(Debug, Copy, Clone)] - #[repr(transparent)] - pub struct DescriptorFlags: u16 { - /// The next field contains linked buffer index. - const NEXT = 1 << 0; - /// The buffer is write-only (otherwise read-only). - const WRITE_ONLY = 1 << 1; - /// The buffer contains a list of buffer descriptors. - const INDIRECT = 1 << 2; - } -} - -#[repr(C)] -pub struct Descriptor { - /// Address (guest-physical). - pub address: AtomicU64, - /// Size of the descriptor. - pub size: AtomicU32, - flags: AtomicU16, - /// Index of next desciptor in chain. - pub next: AtomicU16, -} - -const_assert_eq!(core::mem::size_of::(), 16); - -impl Descriptor { - pub fn set_addr(&self, addr: u64) { - self.address.store(addr, Ordering::SeqCst) - } - - pub fn set_size(&self, size: u32) { - self.size.store(size, Ordering::SeqCst) - } - - pub fn set_next(&self, next: Option) { - self.next.store(next.unwrap_or_default(), Ordering::SeqCst) - } - - pub fn set_flags(&self, flags: DescriptorFlags) { - self.flags.store(flags.bits(), Ordering::SeqCst) - } - - pub fn next(&self) -> u16 { - self.next.load(Ordering::SeqCst) - } - - pub fn flags(&self) -> DescriptorFlags { - DescriptorFlags::from_bits_truncate(self.flags.load(Ordering::SeqCst)) - } -} - -/// This indicates compliance with the version 1 VirtIO specification. -/// -/// See `6.1 Driver Requirements: Reserved Feature Bits` section of the VirtIO -/// specification for more information. -pub const VIRTIO_F_VERSION_1: u32 = 32; -pub const VIRTIO_NET_F_MAC: u32 = 5; - -// ======== Available Ring ======== -// -// XXX: The driver uses the available ring to offer buffers to the -// device. Each ring entry refers to the head of a descriptor -// chain. -#[repr(C)] -pub struct AvailableRingElement { - pub table_index: AtomicU16, -} - -impl AvailableRingElement { - pub fn set_table_index(&self, index: u16) { - self.table_index.store(index, Ordering::SeqCst) - } -} - -const_assert_eq!(core::mem::size_of::(), 2); - -#[repr(C)] -pub struct AvailableRing { - pub flags: VolatileCell, - pub head_index: AtomicU16, - pub elements: IncompleteArrayField, -} - -const_assert_eq!(core::mem::size_of::(), 4); - -impl Default for AvailableRing { - fn default() -> Self { - Self { - flags: VolatileCell::new(0), - head_index: AtomicU16::new(0), - elements: IncompleteArrayField::new(), - } - } -} - -#[repr(C)] -pub struct AvailableRingExtra { - pub avail_event: VolatileCell, // Only if `VIRTIO_F_EVENT_IDX` -} - -const_assert_eq!(core::mem::size_of::(), 2); - -// ======== Used Ring ======== -#[repr(C)] -pub struct UsedRingElement { - pub table_index: VolatileCell, - pub written: VolatileCell, -} - -const_assert_eq!(core::mem::size_of::(), 8); - -#[repr(C)] -pub struct UsedRing { - pub flags: VolatileCell, - pub head_index: VolatileCell, - pub elements: IncompleteArrayField, -} - -const_assert_eq!(core::mem::size_of::(), 4); - -impl Default for UsedRing { - fn default() -> Self { - Self { - flags: VolatileCell::new(0), - head_index: VolatileCell::new(0), - elements: IncompleteArrayField::new(), - } - } -} - -#[repr(C)] -pub struct UsedRingExtra { - pub event_index: VolatileCell, -} - -// ======== Utils ======== -pub struct Buffer { - pub(crate) buffer: usize, - pub(crate) size: usize, - pub(crate) flags: DescriptorFlags, -} - -impl Buffer { - pub fn new(val: &common::dma::Dma) -> Self { - Self { - buffer: val.physical(), - size: core::mem::size_of::(), - flags: DescriptorFlags::empty(), - } - } - - pub fn new_unsized(val: &common::dma::Dma<[T]>) -> Self { - Self { - buffer: val.physical(), - size: core::mem::size_of::() * val.len(), - flags: DescriptorFlags::empty(), - } - } - - pub fn new_sized(val: &common::dma::Dma<[T]>, size: usize) -> Self { - Self { - buffer: val.physical(), - size, - flags: DescriptorFlags::empty(), - } - } - - pub fn flags(mut self, flags: DescriptorFlags) -> Self { - self.flags = flags; - self - } -} - -/// XXX: The [`DescriptorFlags::NEXT`] flag is set automatically. -pub struct ChainBuilder { - buffers: Vec, -} - -impl ChainBuilder { - pub fn new() -> Self { - Self { - buffers: Vec::new(), - } - } - - pub fn chain(mut self, mut buffer: Buffer) -> Self { - buffer.flags |= DescriptorFlags::NEXT; - self.buffers.push(buffer); - self - } - - pub fn build(mut self) -> Vec { - let last_buffer = self.buffers.last_mut().expect("virtio-core: empty chain"); - last_buffer.flags.remove(DescriptorFlags::NEXT); - - self.buffers - } -} diff --git a/virtio-core/src/spec/mod.rs b/virtio-core/src/spec/mod.rs new file mode 100644 index 0000000000..73efd22155 --- /dev/null +++ b/virtio-core/src/spec/mod.rs @@ -0,0 +1,54 @@ +//! https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html +//! +//! This file contains comments copied from the VirtIO specification which are +//! licensed under the following conditions: +//! +//! Copyright © OASIS Open 2022. All Rights Reserved. +//! +//! All capitalized terms in the following text have the meanings assigned to them +//! in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The +//! full Policy may be found at the OASIS website. +//! +//! This document and translations of it may be copied and furnished to others, +//! and derivative works that comment on or otherwise explain it or assist in its +//! implementation may be prepared, copied, published, and distributed, in whole +//! or in part, without restriction of any kind, provided that the above copyright +//! notice and this section are included on all such copies and derivative works. +//! However, this document itself may not be modified in any way, including by +//! removing the copyright notice or references to OASIS, except as needed for the +//! purpose of developing any document or deliverable produced by an OASIS Technical +//! Committee (in which case the rules applicable to copyrights, as set forth in the +//! OASIS IPR Policy, must be followed) or as required to translate it into languages +//! other than English. + +bitflags::bitflags! { + /// [2.1 Device Status Field](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-110001) + #[derive(Debug, Copy, Clone, PartialEq)] + #[repr(transparent)] + pub struct DeviceStatusFlags: u8 { + /// Indicates that the guest OS has found the device and recognized it as a + /// valid device. + const ACKNOWLEDGE = 1; + /// Indicates that the guest OS knows how to drive the device. + const DRIVER = 2; + /// Indicates that something went wrong in the guest and it has given up on + /// the device. + const FAILED = 128; + /// Indicates that the driver has acknowledged all the features it understands + /// and feature negotiation is complete. + const FEATURES_OK = 8; + /// Indicates that the driver is set up and ready to drive the device. + const DRIVER_OK = 4; + /// Indicates that the device has experienced an error from which it can’t recover. + const DEVICE_NEEDS_RESET = 64; + } +} + +mod split_virtqueue; +pub use split_virtqueue::*; + +mod transport_pci; +pub use transport_pci::*; + +mod reserved_features; +pub use reserved_features::*; diff --git a/virtio-core/src/spec/reserved_features.rs b/virtio-core/src/spec/reserved_features.rs new file mode 100644 index 0000000000..9f88676767 --- /dev/null +++ b/virtio-core/src/spec/reserved_features.rs @@ -0,0 +1,100 @@ +//! [6 Reserved Feature Bits](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-6600006) +//! +//! This file contains comments copied from the VirtIO specification which are +//! licensed under the following conditions: +//! +//! Copyright © OASIS Open 2022. All Rights Reserved. +//! +//! All capitalized terms in the following text have the meanings assigned to them +//! in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The +//! full Policy may be found at the OASIS website. +//! +//! This document and translations of it may be copied and furnished to others, +//! and derivative works that comment on or otherwise explain it or assist in its +//! implementation may be prepared, copied, published, and distributed, in whole +//! or in part, without restriction of any kind, provided that the above copyright +//! notice and this section are included on all such copies and derivative works. +//! However, this document itself may not be modified in any way, including by +//! removing the copyright notice or references to OASIS, except as needed for the +//! purpose of developing any document or deliverable produced by an OASIS Technical +//! Committee (in which case the rules applicable to copyrights, as set forth in the +//! OASIS IPR Policy, must be followed) or as required to translate it into languages +//! other than English. + +/// Negotiating this feature indicates that the driver can use descriptors +/// with the VIRTQ_DESC_F_INDIRECT flag set as described in 2.7.5.3 Indirect +/// Descriptors and 2.8.7 Indirect Flag: Scatter-Gather Support. +pub const VIRTIO_F_INDIRECT_DESC: u32 = 28; + +/// This feature enables the used_event and the avail_event fields as +/// described in 2.7.7, 2.7.8 and 2.8.10. +pub const VIRTIO_F_EVENT_IDX: u32 = 29; + +/// This indicates compliance with this specification, giving a simple way +/// to detect legacy devices or drivers. +pub const VIRTIO_F_VERSION_1: u32 = 32; + +/// This feature indicates that the device can be used on a platform where device +/// access to data in memory is limited and/or translated. E.g. this is the case +/// if the device can be located behind an IOMMU that translates bus addresses +/// from the device into physical addresses in memory, if the device can be limited +/// to only access certain memory addresses or if special commands such as a cache +/// flush can be needed to synchronise data in memory with the device. Whether +/// accesses are actually limited or translated is described by platform-specific +/// means. If this feature bit is set to 0, then the device has same access to +/// memory addresses supplied to it as the driver has. In particular, the device +/// will always use physical addresses matching addresses used by the driver +/// (typically meaning physical addresses used by the CPU) and not translated +/// further, and can access any address supplied to it by the driver. When clear, +/// this overrides any platform-specific description of whether device access is +/// limited or translated in any way, e.g. whether an IOMMU may be present. +pub const VIRTIO_F_ACCESS_PLATFORM: u32 = 33; + +/// This feature indicates support for the packed virtqueue layout as described +/// in 2.8 Packed Virtqueues. +pub const VIRTIO_F_RING_PACKED: u32 = 34; + +/// This feature indicates that all buffers are used by the device in the same order +/// in which they have been made available. +pub const VIRTIO_F_IN_ORDER: u32 = 35; + +/// This feature indicates that memory accesses by the driver and the device are +/// ordered in a way described by the platform. +/// If this feature bit is negotiated, the ordering in effect for any memory +/// accesses by the driver that need to be ordered in a specific way with respect +/// to accesses by the device is the one suitable for devices described by the +/// platform. This implies that the driver needs to use memory barriers suitable +/// for devices described by the platform; e.g. for the PCI transport in the case +/// of hardware PCI devices. +/// +/// If this feature bit is not negotiated, then the device and driver are assumed +/// to be implemented in software, that is they can be assumed to run on identical +/// CPUs in an SMP configuration. Thus a weaker form of memory barriers is sufficient +/// to yield better performance. +pub const VIRTIO_F_ORDER_PLATFORM: u32 = 36; + +/// This feature indicates that the device supports Single Root I/O Virtualization. +/// Currently only PCI devices support this feature. +pub const VIRTIO_F_SR_IOV: u32 = 37; + +/// This feature indicates that the driver passes extra data (besides identifying +/// the virtqueue) in its device notifications. See 2.9 Driver Notifications. +pub const VIRTIO_F_NOTIFICATION_DATA: u32 = 38; + +/// This feature indicates that the driver uses the data provided by the device as +/// a virtqueue identifier in available buffer notifications. As mentioned in section +/// 2.9, when the driver is required to send an available buffer notification to the +/// device, it sends the virtqueue number to be notified. The method of delivering +/// notifications is transport specific. With the PCI transport, the device can +/// optionally provide a per-virtqueue value for the driver to use in driver +/// notifications, instead of the virtqueue number. Some devices may benefit from this +/// flexibility by providing, for example, an internal virtqueue identifier, or an +/// internal offset related to the virtqueue number. +/// +/// This feature indicates the availability of such value. The definition of the data +/// to be provided in driver notification and the delivery method is transport +/// specific. For more details about driver notifications over PCI see 4.1.5.2. +pub const VIRTIO_F_NOTIF_CONFIG_DATA: u32 = 39; + +/// This feature indicates that the driver can reset a queue individually. See 2.6.1. +pub const VIRTIO_F_RING_RESET: u32 = 40; diff --git a/virtio-core/src/spec/split_virtqueue.rs b/virtio-core/src/spec/split_virtqueue.rs new file mode 100644 index 0000000000..b96367111f --- /dev/null +++ b/virtio-core/src/spec/split_virtqueue.rs @@ -0,0 +1,205 @@ +//! [2.7 Split Virtqueues](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-350007) +//! +//! This file contains comments copied from the VirtIO specification which are +//! licensed under the following conditions: +//! +//! Copyright © OASIS Open 2022. All Rights Reserved. +//! +//! All capitalized terms in the following text have the meanings assigned to them +//! in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The +//! full Policy may be found at the OASIS website. +//! +//! This document and translations of it may be copied and furnished to others, +//! and derivative works that comment on or otherwise explain it or assist in its +//! implementation may be prepared, copied, published, and distributed, in whole +//! or in part, without restriction of any kind, provided that the above copyright +//! notice and this section are included on all such copies and derivative works. +//! However, this document itself may not be modified in any way, including by +//! removing the copyright notice or references to OASIS, except as needed for the +//! purpose of developing any document or deliverable produced by an OASIS Technical +//! Committee (in which case the rules applicable to copyrights, as set forth in the +//! OASIS IPR Policy, must be followed) or as required to translate it into languages +//! other than English. + +use std::sync::atomic::{AtomicU16, AtomicU32, AtomicU64, Ordering}; + +use crate::utils::{IncompleteArrayField, VolatileCell}; +use static_assertions::const_assert_eq; + +/// [2.7.5 The Virtqueue Descriptor table](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-430005) +#[repr(C, align(16))] +pub struct Descriptor { + /// Address (guest-physical). + address: AtomicU64, + /// Size of the descriptor. + size: AtomicU32, + flags: AtomicU16, + /// Next field if flags & NEXT + next: AtomicU16, +} + +const_assert_eq!(core::mem::size_of::(), 16); + +bitflags::bitflags! { + #[derive(Debug, Copy, Clone)] + #[repr(transparent)] + pub struct DescriptorFlags: u16 { + /// This marks a buffer as continuing via the next field. + const NEXT = 1 << 0; + /// This marks a buffer as device write-only (otherwise device read-only). + const WRITE_ONLY = 1 << 1; + /// This means the buffer contains a list of buffer descriptors. + const INDIRECT = 1 << 2; + } +} + +impl Descriptor { + pub fn set_addr(&self, addr: u64) { + self.address.store(addr, Ordering::SeqCst) + } + + pub fn set_size(&self, size: u32) { + self.size.store(size, Ordering::SeqCst) + } + + pub fn set_next(&self, next: Option) { + self.next.store(next.unwrap_or_default(), Ordering::SeqCst) + } + + pub fn set_flags(&self, flags: DescriptorFlags) { + self.flags.store(flags.bits(), Ordering::SeqCst) + } + + pub fn next(&self) -> u16 { + self.next.load(Ordering::SeqCst) + } + + pub fn flags(&self) -> DescriptorFlags { + DescriptorFlags::from_bits_truncate(self.flags.load(Ordering::SeqCst)) + } +} + +// ======== Available Ring ======== +// +// XXX: The driver uses the available ring to offer buffers to the +// device. Each ring entry refers to the head of a descriptor +// chain. + +/// [2.7.6 The Virtqueue Available Ring](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-490006) +#[repr(C, align(2))] +pub struct AvailableRing { + pub flags: VolatileCell, + pub head_index: AtomicU16, + pub elements: IncompleteArrayField, +} + +const_assert_eq!(core::mem::size_of::(), 4); + +#[repr(C)] +pub struct AvailableRingElement { + pub table_index: AtomicU16, +} + +impl AvailableRingElement { + pub fn set_table_index(&self, index: u16) { + self.table_index.store(index, Ordering::SeqCst) + } +} + +const_assert_eq!(core::mem::size_of::(), 2); + +#[repr(C)] +pub struct AvailableRingExtra { + pub avail_event: VolatileCell, // Only if `VIRTIO_F_EVENT_IDX` +} + +const_assert_eq!(core::mem::size_of::(), 2); + +// ======== Used Ring ======== + +/// [2.7.8 The Virtqueue Used Ring](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-540008) +#[repr(C, align(4))] +pub struct UsedRing { + pub flags: VolatileCell, + pub head_index: VolatileCell, + pub elements: IncompleteArrayField, +} + +const_assert_eq!(core::mem::size_of::(), 4); + +#[repr(C)] +pub struct UsedRingElement { + pub table_index: VolatileCell, + pub written: VolatileCell, +} + +const_assert_eq!(core::mem::size_of::(), 8); + +#[repr(C)] +pub struct UsedRingExtra { + pub event_index: VolatileCell, +} + +// ======== Utils ======== +pub struct Buffer { + pub(crate) buffer: usize, + pub(crate) size: usize, + pub(crate) flags: DescriptorFlags, +} + +impl Buffer { + pub fn new(val: &common::dma::Dma) -> Self { + Self { + buffer: val.physical(), + size: core::mem::size_of::(), + flags: DescriptorFlags::empty(), + } + } + + pub fn new_unsized(val: &common::dma::Dma<[T]>) -> Self { + Self { + buffer: val.physical(), + size: core::mem::size_of::() * val.len(), + flags: DescriptorFlags::empty(), + } + } + + pub fn new_sized(val: &common::dma::Dma<[T]>, size: usize) -> Self { + Self { + buffer: val.physical(), + size, + flags: DescriptorFlags::empty(), + } + } + + pub fn flags(mut self, flags: DescriptorFlags) -> Self { + self.flags = flags; + self + } +} + +/// XXX: The [`DescriptorFlags::NEXT`] flag is set automatically. +pub struct ChainBuilder { + buffers: Vec, +} + +impl ChainBuilder { + pub fn new() -> Self { + Self { + buffers: Vec::new(), + } + } + + pub fn chain(mut self, mut buffer: Buffer) -> Self { + buffer.flags |= DescriptorFlags::NEXT; + self.buffers.push(buffer); + self + } + + pub fn build(mut self) -> Vec { + let last_buffer = self.buffers.last_mut().expect("virtio-core: empty chain"); + last_buffer.flags.remove(DescriptorFlags::NEXT); + + self.buffers + } +} diff --git a/virtio-core/src/spec/transport_pci.rs b/virtio-core/src/spec/transport_pci.rs new file mode 100644 index 0000000000..a27fcd6df6 --- /dev/null +++ b/virtio-core/src/spec/transport_pci.rs @@ -0,0 +1,168 @@ +//! [4.1 Virtio Over PCI Bus](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-1150001) +//! +//! This file contains comments copied from the VirtIO specification which are +//! licensed under the following conditions: +//! +//! Copyright © OASIS Open 2022. All Rights Reserved. +//! +//! All capitalized terms in the following text have the meanings assigned to them +//! in the OASIS Intellectual Property Rights Policy (the "OASIS IPR Policy"). The +//! full Policy may be found at the OASIS website. +//! +//! This document and translations of it may be copied and furnished to others, +//! and derivative works that comment on or otherwise explain it or assist in its +//! implementation may be prepared, copied, published, and distributed, in whole +//! or in part, without restriction of any kind, provided that the above copyright +//! notice and this section are included on all such copies and derivative works. +//! However, this document itself may not be modified in any way, including by +//! removing the copyright notice or references to OASIS, except as needed for the +//! purpose of developing any document or deliverable produced by an OASIS Technical +//! Committee (in which case the rules applicable to copyrights, as set forth in the +//! OASIS IPR Policy, must be followed) or as required to translate it into languages +//! other than English. + +use super::DeviceStatusFlags; +use crate::utils::VolatileCell; +use static_assertions::const_assert_eq; + +/// [4.1.4 Virtio Structure PCI Capabilities](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-1240004) +#[derive(Debug, Copy, Clone)] +#[repr(C, packed)] +pub struct PciCapability { + /// Identifies the structure. + pub cfg_type: CfgType, + /// Where to find it. + pub bar: u8, + /// Multiple capabilities of the same typel + pub id: u8, + /// Pad to a full dword. + pub padding: [u8; 2], + /// Offset within the bar. + pub offset: u32, + /// Length of the structure, in bytes. + pub length: u32, + // FIXME move out of PciCapability type + notify_multiplier: u32, +} + +// The size of `PciCapability` is 13 bytes since the generic +// PCI fields are *not* included. +const_assert_eq!(core::mem::size_of::(), 17); + +#[derive(Debug, Copy, Clone)] +#[repr(u8)] +pub enum CfgType { + /// Common Configuration. + Common = 1, + /// Notifications. + Notify = 2, + /// ISR Status. + Isr = 3, + /// Device specific configuration. + Device = 4, + /// PCI configuration access. + PciConfig = 5, + /// Shared memory region. + SharedMemory = 8, + /// Vendor-specific data. + Vendor = 9, +} + +const_assert_eq!(core::mem::size_of::(), 1); + +impl PciCapability { + /// ## Safety + /// Undefined if accessed from a capability type other than [`CfgType::Notify`]. + pub unsafe fn notify_multiplier(&self) -> u32 { + self.notify_multiplier + } +} + +#[derive(Debug)] +#[repr(C)] +pub struct CommonCfg { + // About the whole device. + /// The driver uses this to select which feature bits device_feature shows. + /// Value 0x0 selects Feature Bits 0 to 31, 0x1 selects Feature Bits 32 to 63, etc. + /// read-write + pub device_feature_select: VolatileCell, + /// The device uses this to report which feature bits it is offering to the driver: + /// the driver writes to device_feature_select to select which feature bits are presented. + /// read-only for driver + pub device_feature: VolatileCell, + /// The driver uses this to select which feature bits driver_feature shows. + /// Value 0x0 selects Feature Bits 0 to 31, 0x1 selects Feature Bits 32 to 63, etc. + /// read-write + pub driver_feature_select: VolatileCell, + /// The driver writes this to accept feature bits offered by the device. + /// Driver Feature Bits selected by driver_feature_select. + /// read-write + pub driver_feature: VolatileCell, + /// The driver sets the Configuration Vector for MSI-X. + /// read-write + pub config_msix_vector: VolatileCell, + /// The device specifies the maximum number of virtqueues supported here. + /// read-only for driver + pub num_queues: VolatileCell, + /// The driver writes the device status here (see 2.1). + /// Writing 0 into this field resets the device. + /// read-write + pub device_status: VolatileCell, + /// Configuration atomicity value. The device changes this every time the + /// configuration noticeably changes. + /// read-only for driver + pub config_generation: VolatileCell, + + // About a specific virtqueue. + /// Queue Select. The driver selects which virtqueue the following fields refer to. + /// read-write + pub queue_select: VolatileCell, + /// Queue Size. On reset, specifies the maximum queue size supported by the device. + /// This can be modified by the driver to reduce memory requirements. + /// A 0 means the queue is unavailable. + /// read-write + pub queue_size: VolatileCell, + /// The driver uses this to specify the queue vector for MSI-X. + /// read-write + pub queue_msix_vector: VolatileCell, + /// The driver uses this to selectively prevent the device from executing + /// requests from this virtqueue. 1 - enabled; 0 - disabled. + /// read-write + pub queue_enable: VolatileCell, + /// The driver reads this to calculate the offset from start of Notification + /// structure at which this virtqueue is located. Note: this is not an offset + /// in bytes. See 4.1.4.4 below. + /// read-only for driver + pub queue_notify_off: VolatileCell, + /// The driver writes the physical address of Descriptor Area here. + /// See section 2.6. + /// read-write + pub queue_desc: VolatileCell, + /// The driver writes the physical address of Driver Area here. + /// See section 2.6. + /// read-write + pub queue_driver: VolatileCell, + /// The driver writes the physical address of Device Area here. + /// See section 2.6. + /// read-write + pub queue_device: VolatileCell, + /// This field exists only if VIRTIO_F_NOTIF_CONFIG_DATA has been negotiated. + /// The driver will use this value to put it in the ’virtqueue number’ field + /// in the available buffer notification structure. See section 4.1.5.2. Note: + /// This field provides the device with flexibility to determine how virtqueues + /// will be referred to in available buffer notifications. In a trivial case the + /// device can set queue_notify_data=vqn. Some devices may benefit from providing + /// another value, for example an internal virtqueue identifier, or an internal + /// offset related to the virtqueue number. + /// read-only for driver + pub queue_notify_data: VolatileCell, + /// The driver uses this to selectively reset the queue. This field exists + /// only if VIRTIO_F_RING_RESET has been negotiated. (see 2.6.1). + /// read-write + pub queue_reset: VolatileCell, +} + +const_assert_eq!(core::mem::size_of::(), 64); + +/// Vector value used to disable MSI for queue +pub const VIRTIO_MSI_NO_VECTOR: u16 = 0xffff; From fcc55507ea69fc50e9eda73fe3da9e7b2a2a40d6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Jan 2024 18:07:05 +0100 Subject: [PATCH 0746/1301] Move the notify_multiplier field into a separate PciCapabilityNotify type It only exists for VIRTIO_PCI_CAP_NOTIFY_CFG and could conflict with fields of other capability types. --- virtio-core/src/probe.rs | 11 +++++++---- virtio-core/src/spec/transport_pci.rs | 28 ++++++++++++++++----------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 1509187450..2a258bda28 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -1,9 +1,9 @@ - -use std::ptr::NonNull; use std::fs::File; +use std::ptr::NonNull; use std::sync::Arc; + +use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use pcid_interface::*; -use pcid_interface::msi::{self, MsixTableEntry, MsixCapability}; use crate::spec::*; use crate::transport::{Error, StandardTransport, Transport}; @@ -131,7 +131,10 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result // SAFETY: The capability type is `Notify`, so its safe to access // the `notify_multiplier` field. - let multiplier = unsafe { capability.notify_multiplier() }; + let multiplier = unsafe { + (&*(capability as *const PciCapability as *const PciCapabilityNotify)) + .notify_off_multiplier() + }; notify_addr = Some((address, multiplier)); } diff --git a/virtio-core/src/spec/transport_pci.rs b/virtio-core/src/spec/transport_pci.rs index a27fcd6df6..cadfaad2de 100644 --- a/virtio-core/src/spec/transport_pci.rs +++ b/virtio-core/src/spec/transport_pci.rs @@ -41,13 +41,11 @@ pub struct PciCapability { pub offset: u32, /// Length of the structure, in bytes. pub length: u32, - // FIXME move out of PciCapability type - notify_multiplier: u32, } // The size of `PciCapability` is 13 bytes since the generic // PCI fields are *not* included. -const_assert_eq!(core::mem::size_of::(), 17); +const_assert_eq!(core::mem::size_of::(), 13); #[derive(Debug, Copy, Clone)] #[repr(u8)] @@ -70,14 +68,6 @@ pub enum CfgType { const_assert_eq!(core::mem::size_of::(), 1); -impl PciCapability { - /// ## Safety - /// Undefined if accessed from a capability type other than [`CfgType::Notify`]. - pub unsafe fn notify_multiplier(&self) -> u32 { - self.notify_multiplier - } -} - #[derive(Debug)] #[repr(C)] pub struct CommonCfg { @@ -164,5 +154,21 @@ pub struct CommonCfg { const_assert_eq!(core::mem::size_of::(), 64); +#[derive(Debug, Copy, Clone)] +#[repr(C, packed)] +pub struct PciCapabilityNotify { + pub cap: PciCapability, + /// Multiplier for queue_notify_off. + notify_off_multiplier: u32, +} + +impl PciCapabilityNotify { + pub fn notify_off_multiplier(&self) -> u32 { + self.notify_off_multiplier + } +} + +const_assert_eq!(core::mem::size_of::(), 17); + /// Vector value used to disable MSI for queue pub const VIRTIO_MSI_NO_VECTOR: u16 = 0xffff; From b06f0534aaff2e3bd8ce8b8c1c4cd8a50f77742f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Jan 2024 18:45:32 +0100 Subject: [PATCH 0747/1301] Remove interrupt status register probing It isn't used when MSI-X is used and we always use MSI-X interrupts. --- virtio-core/src/arch/x86.rs | 15 +++------------ virtio-core/src/arch/x86_64.rs | 22 +++++++--------------- virtio-core/src/probe.rs | 31 +++++++++---------------------- 3 files changed, 19 insertions(+), 49 deletions(-) diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index 08483e9346..56b33d8fd8 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -1,10 +1,4 @@ -use crate::{ - legacy_transport::LegacyTransport, - reinit, - transport::Error, - utils::VolatileCell, - Device, -}; +use crate::{legacy_transport::LegacyTransport, reinit, transport::Error, Device}; use std::fs::File; use pcid_interface::*; @@ -13,16 +7,14 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { panic!("virtio-core: x86 doesn't support enable_msix") } -pub fn probe_legacy_port_transport<'a>( +pub fn probe_legacy_port_transport( pci_header: &PciHeader, pcid_handle: &mut PcidServerHandle, -) -> Result, Error> { +) -> Result { if let PciBar::Port(port) = pci_header.get_bar(0) { unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; log::warn!("virtio: using legacy transport"); - static SHIM: VolatileCell = VolatileCell::new(0); - let transport = LegacyTransport::new(port); // Setup interrupts. @@ -38,7 +30,6 @@ pub fn probe_legacy_port_transport<'a>( let device = Device { transport, irq_handle, - isr: &SHIM, device_space: core::ptr::null_mut(), }; diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index 1909c20aec..f13850f4c1 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -1,13 +1,8 @@ -use crate::{ - reinit, - transport::{Error}, - utils::VolatileCell, - Device, legacy_transport::LegacyTransport, -}; +use crate::{legacy_transport::LegacyTransport, reinit, transport::Error, Device}; -use pcid_interface::msi::{self, MsixTableEntry}; use pcid_interface::irq_helpers::{allocate_single_interrupt_vector, read_bsp_apic_id}; -use std::{ptr::NonNull, fs::File}; +use pcid_interface::msi::{self, MsixTableEntry}; +use std::{fs::File, ptr::NonNull}; use syscall::Io; @@ -16,7 +11,6 @@ use crate::{probe::MsixInfo, MSIX_PRIMARY_VECTOR}; use pcid_interface::*; pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { - let pci_config = pcid_handle.fetch_config()?; // Extended message signaled interrupts. @@ -80,7 +74,8 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { .unwrap() .expect("virtio_core: interrupt vector exhaustion"); - let msg_data = msi::x86_64::message_data_edge_triggered(msi::x86_64::DeliveryMode::Fixed, vector); + let msg_data = + msi::x86_64::message_data_edge_triggered(msi::x86_64::DeliveryMode::Fixed, vector); table_entry_pointer.addr_lo.write(addr); table_entry_pointer.addr_hi.write(0); @@ -98,16 +93,14 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { Ok(interrupt_handle) } -pub fn probe_legacy_port_transport<'a>( +pub fn probe_legacy_port_transport( pci_header: &PciHeader, pcid_handle: &mut PcidServerHandle, -) -> Result, Error> { +) -> Result { if let PciBar::Port(port) = pci_header.get_bar(0) { unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; log::warn!("virtio: using legacy transport"); - static SHIM: VolatileCell = VolatileCell::new(0); - let transport = LegacyTransport::new(port); // Setup interrupts. @@ -123,7 +116,6 @@ pub fn probe_legacy_port_transport<'a>( let device = Device { transport, irq_handle, - isr: &SHIM, device_space: core::ptr::null_mut(), }; diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 2a258bda28..3e31284799 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -7,19 +7,18 @@ use pcid_interface::*; use crate::spec::*; use crate::transport::{Error, StandardTransport, Transport}; -use crate::utils::{align_down, VolatileCell}; +use crate::utils::align_down; -pub struct Device<'a> { +pub struct Device { pub transport: Arc, pub device_space: *const u8, pub irq_handle: File, - pub isr: &'a VolatileCell, } // FIXME(andypython): `device_space` should not be `Send` nor `Sync`. Take // it out of `Device`. -unsafe impl Send for Device<'_> {} -unsafe impl Sync for Device<'_> {} +unsafe impl Send for Device {} +unsafe impl Sync for Device {} pub struct MsixInfo { pub virt_table_base: NonNull, @@ -60,7 +59,7 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { /// /// ## Panics /// This function panics if the device is not a virtio device. -pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result, Error> { +pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result { let pci_config = pcid_handle.fetch_config()?; let pci_header = pcid_handle.fetch_header()?; @@ -71,7 +70,6 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result let mut common_addr = None; let mut notify_addr = None; - let mut isr_addr = None; let mut device_addr = None; for capability in pcid_handle @@ -89,7 +87,7 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result let capability = unsafe { &*(capability.data.as_ptr() as *const PciCapability) }; match capability.cfg_type { - CfgType::Common | CfgType::Notify | CfgType::Isr | CfgType::Device => {} + CfgType::Common | CfgType::Notify | CfgType::Device => {} _ => continue, } @@ -138,11 +136,6 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result notify_addr = Some((address, multiplier)); } - CfgType::Isr => { - debug_assert!(isr_addr.is_none()); - isr_addr = Some(address); - } - CfgType::Device => { debug_assert!(device_addr.is_none()); device_addr = Some(address); @@ -154,12 +147,8 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result log::trace!("virtio-core::device-probe: {capability:?}"); } - if let ( - Some(common_addr), - Some(isr_addr), - Some(device_addr), - Some((notify_addr, notify_multiplier)), - ) = (common_addr, isr_addr, device_addr, notify_addr) + if let (Some(common_addr), Some(device_addr), Some((notify_addr, notify_multiplier))) = + (common_addr, device_addr, notify_addr) { assert!( notify_multiplier != 0, @@ -168,7 +157,6 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result let common = unsafe { &mut *(common_addr as *mut CommonCfg) }; let device_space = unsafe { &mut *(device_addr as *mut u8) }; - let isr = unsafe { &*(isr_addr as *mut VolatileCell) }; let transport = StandardTransport::new( common, @@ -193,7 +181,6 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result transport, device_space, irq_handle, - isr, }; device.transport.reset(); @@ -205,7 +192,7 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result } } -pub fn reinit<'a>(device: &Device<'a>) -> Result<(), Error> { +pub fn reinit(device: &Device) -> Result<(), Error> { // XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits // in `device_status` is required to be done in two steps. device From 3f2f32de599b83731b15796c3a37f17dc6ce0ef7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Jan 2024 18:48:25 +0100 Subject: [PATCH 0748/1301] Add back VIRTIO_NET_F_MAC to virtio-netd --- virtio-netd/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/virtio-netd/src/main.rs b/virtio-netd/src/main.rs index 4e38b1ec02..c99b2c4577 100644 --- a/virtio-netd/src/main.rs +++ b/virtio-netd/src/main.rs @@ -8,11 +8,12 @@ use pcid_interface::PcidServerHandle; use syscall::{Packet, SchemeBlockMut}; -use virtio_core::spec::VIRTIO_NET_F_MAC; use virtio_core::transport::{Error, Transport}; use scheme::NetworkScheme; +pub const VIRTIO_NET_F_MAC: u32 = 5; + #[derive(Debug)] #[repr(C)] pub struct VirtHeader { From fbcf01b413012c7407e5b71696ce65530790fd25 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Jan 2024 19:03:10 +0100 Subject: [PATCH 0749/1301] Add a couple of FIXME --- virtio-core/src/arch/x86_64.rs | 2 ++ virtio-core/src/probe.rs | 1 + virtio-core/src/spec/mod.rs | 2 ++ 3 files changed, 5 insertions(+) diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index f13850f4c1..e8200da934 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -60,6 +60,8 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { }; // Allocate the primary MSI vector. + // FIXME allow the driver to register multiple MSI-X vectors + // FIXME move this MSI-X registering code into pcid_interface or pcid itself let interrupt_handle = { let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize); diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 3e31284799..157ffa0f1f 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -150,6 +150,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result if let (Some(common_addr), Some(device_addr), Some((notify_addr, notify_multiplier))) = (common_addr, device_addr, notify_addr) { + // FIXME this is explicitly allowed by the virtio specification to happen assert!( notify_multiplier != 0, "virtio-core::device_probe: device uses the same Queue Notify addresses for all queues" diff --git a/virtio-core/src/spec/mod.rs b/virtio-core/src/spec/mod.rs index 73efd22155..b78931d2cb 100644 --- a/virtio-core/src/spec/mod.rs +++ b/virtio-core/src/spec/mod.rs @@ -47,6 +47,8 @@ bitflags::bitflags! { mod split_virtqueue; pub use split_virtqueue::*; +// FIXME add [2.8 Packed Virtqueues](https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-720008) + mod transport_pci; pub use transport_pci::*; From 07d5d730d237fb6b2cd9031fa88c33b12a99eeb6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Jan 2024 19:32:14 +0100 Subject: [PATCH 0750/1301] Remove nolock CfgAccess methods They are only called by the corresponding locked methods. --- pcid/src/pci/mod.rs | 27 ++++++--------------------- pcid/src/pcie/mod.rs | 15 ++++++--------- 2 files changed, 12 insertions(+), 30 deletions(-) diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index e1a18b472f..f5cb4a6d00 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -23,10 +23,7 @@ pub mod header; pub mod msi; pub trait CfgAccess { - unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32; unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32; - - unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32); unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32); } @@ -68,7 +65,9 @@ impl Pci { } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] impl CfgAccess for Pci { - unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + let _guard = self.lock.lock().unwrap(); + self.iopl_once.call_once(Self::set_iopl); let offset = u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); @@ -78,12 +77,9 @@ impl CfgAccess for Pci { Pio::::new(0xCFC).read() } - unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { let _guard = self.lock.lock().unwrap(); - self.read_nolock(bus, dev, func, offset) - } - unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { self.iopl_once.call_once(Self::set_iopl); let offset = u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); @@ -92,28 +88,17 @@ impl CfgAccess for Pci { Pio::::new(0xCF8).write(address); Pio::::new(0xCFC).write(value); } - unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { - let _guard = self.lock.lock().unwrap(); - self.write_nolock(bus, dev, func, offset, value) - } } #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] impl CfgAccess for Pci { - unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { - todo!("Pci::CfgAccess::read_nolock on this architecture") - } - unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); - self.read_nolock(bus, dev, func, offset) + todo!("Pci::CfgAccess::read on this architecture") } - unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { - todo!("Pci::CfgAccess::write_nolock on this architecture") - } unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { let _guard = self.lock.lock().unwrap(); - self.write_nolock(bus, dev, func, offset, value) + todo!("Pci::CfgAccess::write on this architecture") } } diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 995f4b7482..2fa4994ca3 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -189,26 +189,23 @@ impl Pcie { } impl CfgAccess for Pcie { - unsafe fn read_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + let _guard = self.lock.lock().unwrap(); + self.with_pointer(bus, dev, func, offset, |pointer| match pointer { Some(address) => ptr::read_volatile::(address), None => self.fallback.read(bus, dev, func, offset), }) } - unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + + unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { let _guard = self.lock.lock().unwrap(); - self.read_nolock(bus, dev, func, offset) - } - unsafe fn write_nolock(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { + self.with_pointer(bus, dev, func, offset, |pointer| match pointer { Some(address) => ptr::write_volatile::(address, value), None => { self.fallback.read(bus, dev, func, offset); } }); } - unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { - let _guard = self.lock.lock().unwrap(); - self.write_nolock(bus, dev, func, offset, value); - } } impl Drop for Pcie { From a7c5391c6c2e8ad4dc80bdd9b50437640755fcd4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 12:14:00 +0100 Subject: [PATCH 0751/1301] Introduce PciAddress type copied from the pci_types crate --- Cargo.lock | 1 + pcid/Cargo.toml | 1 + pcid/src/main.rs | 32 ++++++++---- pcid/src/pci/bus.rs | 21 ++++---- pcid/src/pci/mod.rs | 115 ++++++++++++++++++++++++++++++++++--------- pcid/src/pcie/mod.rs | 69 +++++++++++++++++--------- 6 files changed, 174 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5bd694432b..1ec51a7bb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -956,6 +956,7 @@ name = "pcid" version = "0.1.0" dependencies = [ "bincode", + "bit_field", "bitflags 1.3.2", "byteorder 1.4.3", "common", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index f77bb23486..1927fa84f0 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -14,6 +14,7 @@ path = "src/lib.rs" [dependencies] bincode = "1.2" bitflags = "1" +bit_field = "0.10" byteorder = "1.2" libc = "0.2" log = "0.4" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 2a41da0a3a..51b5669026 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -10,7 +10,7 @@ use log::{debug, error, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; use crate::config::Config; -use crate::pci::{CfgAccess, Pci, PciIter, PciBar, PciBus, PciClass, PciDev, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::{CfgAccess, Pci, PciAddress, PciBar, PciBus, PciClass, PciDev, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; use crate::pcie::Pcie; @@ -327,9 +327,9 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, if let Some(ref args) = driver.command { // Enable bus mastering, memory space, and I/O space unsafe { - let mut data = pci.read(bus_num, dev_num, func_num, 0x04); + let mut data = pci.read(PciAddress::new(0, bus_num, dev_num, func_num), 0x04); data |= 7; - pci.write(bus_num, dev_num, func_num, 0x04, data); + pci.write(PciAddress::new(0, bus_num, dev_num, func_num), 0x04, data); } // Set IRQ line to 9 if not set @@ -337,14 +337,14 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, let mut interrupt_pin; unsafe { - let mut data = pci.read(bus_num, dev_num, func_num, 0x3C); + let mut data = pci.read(PciAddress::new(0, bus_num, dev_num, func_num), 0x3C); irq = (data & 0xFF) as u8; interrupt_pin = ((data & 0x0000_FF00) >> 8) as u8; if irq == 0xFF { irq = 9; } data = (data & 0xFFFFFF00) | irq as u32; - pci.write(bus_num, dev_num, func_num, 0x3C, data); + pci.write(PciAddress::new(0, bus_num, dev_num, func_num), 0x3C, data); }; // Find BAR sizes @@ -363,11 +363,25 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, let offset = 0x10 + (i as u8) * 4; - let original = pci.read(bus_num, dev_num, func_num, offset.into()); - pci.write(bus_num, dev_num, func_num, offset.into(), 0xFFFFFFFF); + let original = pci.read( + PciAddress::new(0, bus_num, dev_num, func_num), + offset.into(), + ); + pci.write( + PciAddress::new(0, bus_num, dev_num, func_num), + offset.into(), + 0xFFFFFFFF, + ); - let new = pci.read(bus_num, dev_num, func_num, offset.into()); - pci.write(bus_num, dev_num, func_num, offset.into(), original); + let new = pci.read( + PciAddress::new(0, bus_num, dev_num, func_num), + offset.into(), + ); + pci.write( + PciAddress::new(0, bus_num, dev_num, func_num), + offset.into(), + original, + ); let masked = if new & 1 == 1 { new & 0xFFFFFFFC diff --git a/pcid/src/pci/bus.rs b/pcid/src/pci/bus.rs index 0211c6d4ac..d00db29b04 100644 --- a/pcid/src/pci/bus.rs +++ b/pcid/src/pci/bus.rs @@ -1,8 +1,8 @@ -use super::{PciDev, CfgAccess}; +use super::{CfgAccess, PciAddress, PciDev}; pub struct PciBus<'pci> { pub pci: &'pci dyn CfgAccess, - pub num: u8 + pub num: u8, } impl<'pci> PciBus<'pci> { @@ -11,24 +11,23 @@ impl<'pci> PciBus<'pci> { } pub unsafe fn read(&self, dev: u8, func: u8, offset: u16) -> u32 { - self.pci.read(self.num, dev, func, offset) + self.pci + .read(PciAddress::new(0, self.num, dev, func), offset) } pub unsafe fn write(&self, dev: u8, func: u8, offset: u16, value: u32) { - self.pci.write(self.num, dev, func, offset, value) + self.pci + .write(PciAddress::new(0, self.num, dev, func), offset, value) } } pub struct PciBusIter<'pci> { bus: &'pci PciBus<'pci>, - num: u8 + num: u8, } impl<'pci> PciBusIter<'pci> { pub fn new(bus: &'pci PciBus<'pci>) -> Self { - PciBusIter { - bus, - num: 0 - } + PciBusIter { bus, num: 0 } } } @@ -39,11 +38,11 @@ impl<'pci> Iterator for PciBusIter<'pci> { dev_num if dev_num < 32 => { let dev = PciDev { bus: self.bus, - num: self.num + num: self.num, }; self.num += 1; Some(dev) - }, + } _ => None, } } diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index f5cb4a6d00..d7bc48d5f0 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,6 +1,8 @@ use std::convert::TryFrom; +use std::fmt; use std::sync::{Mutex, Once}; +use bit_field::BitField; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use syscall::io::{Io as _, Pio}; @@ -23,8 +25,69 @@ pub mod header; pub mod msi; pub trait CfgAccess { - unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32; - unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32); + unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32; + unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32); +} + +// Copied from the pci_types crate, version 0.6.1. +// FIXME If we start using it in the future use the upstream version instead. +/// The address of a PCIe function. +/// +/// PCIe supports 65536 segments, each with 256 buses, each with 32 slots, each with 8 possible functions. We pack this into a `u32`: +/// +/// ```ignore +/// 32 16 8 3 0 +/// +-------------------------------+---------------+---------+------+ +/// | segment | bus | device | func | +/// +-------------------------------+---------------+---------+------+ +/// ``` +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] +pub struct PciAddress(u32); + +impl PciAddress { + pub fn new(segment: u16, bus: u8, device: u8, function: u8) -> PciAddress { + let mut result = 0; + result.set_bits(0..3, function as u32); + result.set_bits(3..8, device as u32); + result.set_bits(8..16, bus as u32); + result.set_bits(16..32, segment as u32); + PciAddress(result) + } + + pub fn segment(&self) -> u16 { + self.0.get_bits(16..32) as u16 + } + + pub fn bus(&self) -> u8 { + self.0.get_bits(8..16) as u8 + } + + pub fn device(&self) -> u8 { + self.0.get_bits(3..8) as u8 + } + + pub fn function(&self) -> u8 { + self.0.get_bits(0..3) as u8 + } +} + +impl fmt::Display for PciAddress { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{:02x}-{:02x}:{:02x}.{}", + self.segment(), + self.bus(), + self.device(), + self.function() + ) + } +} + +impl fmt::Debug for PciAddress { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self) + } } pub struct Pci { @@ -48,42 +111,53 @@ impl Pci { // make sure that pcid is not granted io port permission unless pcie memory-mapped // configuration space is not available. info!("PCI: couldn't find or access PCIe extended configuration, and thus falling back to PCI 3.0 io ports"); - unsafe { syscall::iopl(3).expect("pcid: failed to set iopl to 3"); } + unsafe { + syscall::iopl(3).expect("pcid: failed to set iopl to 3"); + } } - fn address(bus: u8, dev: u8, func: u8, offset: u8) -> u32 { + fn address(address: PciAddress, offset: u8) -> u32 { // TODO: Find the part of pcid that uses an unaligned offset! // // assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); // let offset = offset & 0xFC; - assert_eq!(dev & 0x1F, dev, "pci device larger than 5 bits"); - assert_eq!(func & 0x7, func, "pci func larger than 3 bits"); + assert_eq!( + address.segment(), + 0, + "usage of multiple segments requires PCIe extended configuration" + ); - 0x80000000 | (u32::from(bus) << 16) | (u32::from(dev) << 11) | (u32::from(func) << 8) | u32::from(offset) + 0x80000000 + | (u32::from(address.bus()) << 16) + | (u32::from(address.device()) << 11) + | (u32::from(address.function()) << 8) + | u32::from(offset) } } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] impl CfgAccess for Pci { - unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); self.iopl_once.call_once(Self::set_iopl); - let offset = u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); - let address = Self::address(bus, dev, func, offset); + let offset = + u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); + let address = Self::address(address, offset); Pio::::new(0xCF8).write(address); Pio::::new(0xCFC).read() } - unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { + unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) { let _guard = self.lock.lock().unwrap(); self.iopl_once.call_once(Self::set_iopl); - let offset = u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); - let address = Self::address(bus, dev, func, offset); + let offset = + u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); + let address = Self::address(address, offset); Pio::::new(0xCF8).write(address); Pio::::new(0xCFC).write(value); @@ -91,12 +165,12 @@ impl CfgAccess for Pci { } #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] impl CfgAccess for Pci { - unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); todo!("Pci::CfgAccess::read on this architecture") } - unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { + unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32) { let _guard = self.lock.lock().unwrap(); todo!("Pci::CfgAccess::write on this architecture") } @@ -104,15 +178,12 @@ impl CfgAccess for Pci { pub struct PciIter<'pci> { pci: &'pci dyn CfgAccess, - num: Option + num: Option, } impl<'pci> PciIter<'pci> { pub fn new(pci: &'pci dyn CfgAccess) -> Self { - PciIter { - pci, - num: Some(0) - } + PciIter { pci, num: Some(0) } } } @@ -123,11 +194,11 @@ impl<'pci> Iterator for PciIter<'pci> { Some(bus_num) => { let bus = PciBus { pci: self.pci, - num: bus_num + num: bus_num, }; self.num = bus_num.checked_add(1); Some(bus) - }, + } None => None, } } diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 2fa4994ca3..ed5db202f9 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -1,12 +1,12 @@ -use std::{fmt, fs, io, mem, ptr, slice}; use std::collections::BTreeMap; use std::sync::{Arc, Mutex}; +use std::{fmt, fs, io, mem, ptr, slice}; use syscall::PAGE_SIZE; use smallvec::SmallVec; -use crate::pci::{CfgAccess, Pci, PciIter}; +use crate::pci::{CfgAccess, Pci, PciAddress, PciIter}; pub const MCFG_NAME: [u8; 4] = *b"MCFG"; @@ -137,7 +137,7 @@ impl fmt::Debug for Mcfgs { pub struct Pcie { lock: Mutex<()>, mcfgs: Mcfgs, - maps: Mutex>, + maps: Mutex>, fallback: Arc, } unsafe impl Send for Pcie {} @@ -154,34 +154,55 @@ impl Pcie { fallback, }) } - fn addr_offset_in_bytes(starting_bus: u8, bus: u8, dev: u8, func: u8, offset: u16) -> usize { + fn addr_offset_in_bytes(starting_bus: u8, address: PciAddress, offset: u16) -> usize { assert_eq!(offset & 0xFFFC, offset, "pcie offset not dword-aligned"); assert_eq!(offset & 0x0FFF, offset, "pcie offset larger than 4095"); - assert_eq!(dev & 0x1F, dev, "pcie dev number larger than 5 bits"); - assert_eq!(func & 0x7, func, "pcie func number larger than 3 bits"); - (((bus - starting_bus) as usize) << 20) | ((dev as usize) << 15) | ((func as usize) << 12) | (offset as usize) + assert_eq!( + address.segment(), + 0, + "multiple segments not yet implemented" + ); + + (((address.bus() - starting_bus) as usize) << 20) + | ((address.device() as usize) << 15) + | ((address.function() as usize) << 12) + | (offset as usize) } - fn addr_offset_in_dwords(starting_bus: u8, bus: u8, dev: u8, func: u8, offset: u16) -> usize { - Self::addr_offset_in_bytes(starting_bus, bus, dev, func, offset) / mem::size_of::() + fn addr_offset_in_dwords(starting_bus: u8, address: PciAddress, offset: u16) -> usize { + Self::addr_offset_in_bytes(starting_bus, address, offset) / mem::size_of::() } - unsafe fn with_pointer) -> T>(&self, bus: u8, dev: u8, func: u8, offset: u16, f: F) -> T { - let (base_address_phys, starting_bus) = match self.mcfgs.at_bus(bus) { + unsafe fn with_pointer) -> T>( + &self, + address: PciAddress, + offset: u16, + f: F, + ) -> T { + let (base_address_phys, starting_bus) = match self.mcfgs.at_bus(address.bus()) { Some(t) => (t.base_addr, t.start_bus), None => return f(None), }; let mut maps_lock = self.maps.lock().unwrap(); - let virt_pointer = maps_lock.entry((bus, dev, func)).or_insert_with(|| { + let virt_pointer = maps_lock.entry(address).or_insert_with(|| { common::physmap( - base_address_phys as usize + Self::addr_offset_in_bytes(starting_bus, bus, dev, func, 0), + base_address_phys as usize + Self::addr_offset_in_bytes(starting_bus, address, 0), PAGE_SIZE, - common::Prot { read: true, write: true }, + common::Prot { + read: true, + write: true, + }, common::MemoryType::Uncacheable, - ).unwrap_or_else(|error| { - panic!("failed to physmap pcie configuration space for {:2x}:{:2x}.{:2x}: {:?}", bus, dev, func, error) + ) + .unwrap_or_else(|error| { + panic!( + "failed to physmap pcie configuration space for {}: {:?}", + address, error + ) }) as *mut u32 }); - f(Some(&mut *virt_pointer.offset((offset as usize / mem::size_of::()) as isize))) + f(Some(&mut *virt_pointer.offset( + (offset as usize / mem::size_of::()) as isize, + ))) } pub fn buses<'pcie>(&'pcie self) -> PciIter<'pcie> { PciIter::new(self) @@ -189,21 +210,23 @@ impl Pcie { } impl CfgAccess for Pcie { - unsafe fn read(&self, bus: u8, dev: u8, func: u8, offset: u16) -> u32 { + unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); - self.with_pointer(bus, dev, func, offset, |pointer| match pointer { + self.with_pointer(address, offset, |pointer| match pointer { Some(address) => ptr::read_volatile::(address), - None => self.fallback.read(bus, dev, func, offset), + None => self.fallback.read(address, offset), }) } - unsafe fn write(&self, bus: u8, dev: u8, func: u8, offset: u16, value: u32) { + unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) { let _guard = self.lock.lock().unwrap(); - self.with_pointer(bus, dev, func, offset, |pointer| match pointer { + self.with_pointer(address, offset, |pointer| match pointer { Some(address) => ptr::write_volatile::(address, value), - None => { self.fallback.read(bus, dev, func, offset); } + None => { + self.fallback.write(address, offset, value); + } }); } } From 336903b90a3c0503c1c56cd99944d9b071f7c8b4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Jan 2024 20:14:34 +0100 Subject: [PATCH 0752/1301] Introduce SharedPciHeader to deduplicate fields between the General and PciToPci variants --- pcid/src/pci/header.rs | 191 ++++++++++++++++++++++++++++++----------- 1 file changed, 139 insertions(+), 52 deletions(-) diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index 6139c45bb9..534b376c19 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -1,15 +1,15 @@ use bitflags::bitflags; -use byteorder::{LittleEndian, ByteOrder}; -use serde::{Serialize, Deserialize}; +use byteorder::{ByteOrder, LittleEndian}; +use serde::{Deserialize, Serialize}; -use super::func::ConfigReader; -use super::class::PciClass; use super::bar::PciBar; +use super::class::PciClass; +use super::func::ConfigReader; #[derive(Debug, PartialEq)] pub enum PciHeaderError { NoDevice, - UnknownHeaderType(u8) + UnknownHeaderType(u8), } bitflags! { @@ -30,8 +30,7 @@ bitflags! { } #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] -pub enum PciHeader { - General { +pub struct SharedPciHeader { vendor_id: u16, device_id: u16, command: u16, @@ -44,6 +43,12 @@ pub enum PciHeader { latency_timer: u8, header_type: PciHeaderType, bist: u8, +} + +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +pub enum PciHeader { + General { + shared: SharedPciHeader, bars: [PciBar; 6], cardbus_cis_ptr: u32, subsystem_vendor_id: u16, @@ -53,21 +58,10 @@ pub enum PciHeader { interrupt_line: u8, interrupt_pin: u8, min_grant: u8, - max_latency: u8 + max_latency: u8, }, PciToPci { - vendor_id: u16, - device_id: u16, - command: u16, - status: u16, - revision: u8, - interface: u8, - subclass: u8, - class: PciClass, - cache_line_size: u8, - latency_timer: u8, - header_type: PciHeaderType, - bist: u8, + shared: SharedPciHeader, bars: [PciBar; 2], primary_bus_num: u8, secondary_bus_num: u8, @@ -87,9 +81,9 @@ pub enum PciHeader { cap_pointer: u8, expansion_rom: u32, interrupt_line: u8, - interrupt_pin : u8, - bridge_control: u16 - } + interrupt_pin: u8, + bridge_control: u16, + }, } impl PciHeader { @@ -111,7 +105,7 @@ impl PciHeader { addr |= (LittleEndian::read_u32(high_bytes) as u64) << 32; bars[i] = PciBar::Memory64(addr); i += 2; - }, + } bar => { bars[i] = bar; i += 1; @@ -138,6 +132,21 @@ impl PciHeader { let latency_timer = bytes[13]; let header_type = PciHeaderType::from_bits_truncate(bytes[14]); let bist = bytes[15]; + let shared = SharedPciHeader { + vendor_id, + device_id, + command, + status, + revision, + interface, + subclass, + class, + cache_line_size, + latency_timer, + header_type, + bist, + }; + match header_type & PciHeaderType::HEADER_TYPE { PciHeaderType::GENERAL => { let bytes = unsafe { reader.read_range(16, 48) }; @@ -153,13 +162,19 @@ impl PciHeader { let min_grant = bytes[46]; let max_latency = bytes[47]; Ok(PciHeader::General { - vendor_id, device_id, command, status, revision, interface, - subclass, class, cache_line_size, latency_timer, header_type, - bist, bars, cardbus_cis_ptr, subsystem_vendor_id, subsystem_id, - expansion_rom_bar, cap_pointer, interrupt_line, interrupt_pin, - min_grant, max_latency + shared, + bars, + cardbus_cis_ptr, + subsystem_vendor_id, + subsystem_id, + expansion_rom_bar, + cap_pointer, + interrupt_line, + interrupt_pin, + min_grant, + max_latency, }) - }, + } PciHeaderType::PCITOPCI => { let bytes = unsafe { reader.read_range(16, 48) }; let mut bars = [PciBar::None; 2]; @@ -185,17 +200,31 @@ impl PciHeader { let interrupt_pin = bytes[45]; let bridge_control = LittleEndian::read_u16(&bytes[46..48]); Ok(PciHeader::PciToPci { - vendor_id, device_id, command, status, revision, interface, - subclass, class, cache_line_size, latency_timer, header_type, - bist, bars, primary_bus_num, secondary_bus_num, subordinate_bus_num, - secondary_latency_timer, io_base, io_limit, secondary_status, - mem_base, mem_limit, prefetch_base, prefetch_limit, prefetch_base_upper, - prefetch_limit_upper, io_base_upper, io_limit_upper, cap_pointer, - expansion_rom, interrupt_line, interrupt_pin, bridge_control + shared, + bars, + primary_bus_num, + secondary_bus_num, + subordinate_bus_num, + secondary_latency_timer, + io_base, + io_limit, + secondary_status, + mem_base, + mem_limit, + prefetch_base, + prefetch_limit, + prefetch_base_upper, + prefetch_limit_upper, + io_base_upper, + io_limit_upper, + cap_pointer, + expansion_rom, + interrupt_line, + interrupt_pin, + bridge_control, }) - - }, - id => Err(PciHeaderError::UnknownHeaderType(id.bits())) + } + id => Err(PciHeaderError::UnknownHeaderType(id.bits())), } } else { Err(PciHeaderError::NoDevice) @@ -205,49 +234,98 @@ impl PciHeader { /// Return the Header Type. pub fn header_type(&self) -> PciHeaderType { match self { - &PciHeader::General { header_type, .. } | &PciHeader::PciToPci { header_type, .. } => header_type, + &PciHeader::General { + shared: SharedPciHeader { header_type, .. }, + .. + } + | &PciHeader::PciToPci { + shared: SharedPciHeader { header_type, .. }, + .. + } => header_type, } } /// Return the Vendor ID field. pub fn vendor_id(&self) -> u16 { match self { - &PciHeader::General { vendor_id, .. } | &PciHeader::PciToPci { vendor_id, .. } => vendor_id, + &PciHeader::General { + shared: SharedPciHeader { vendor_id, .. }, + .. + } + | &PciHeader::PciToPci { + shared: SharedPciHeader { vendor_id, .. }, + .. + } => vendor_id, } } /// Return the Device ID field. pub fn device_id(&self) -> u16 { match self { - &PciHeader::General { device_id, .. } | &PciHeader::PciToPci { device_id, .. } => device_id, + &PciHeader::General { + shared: SharedPciHeader { device_id, .. }, + .. + } + | &PciHeader::PciToPci { + shared: SharedPciHeader { device_id, .. }, + .. + } => device_id, } } /// Return the Revision field. pub fn revision(&self) -> u8 { match self { - &PciHeader::General { revision, .. } | &PciHeader::PciToPci { revision, .. } => revision, + &PciHeader::General { + shared: SharedPciHeader { revision, .. }, + .. + } + | &PciHeader::PciToPci { + shared: SharedPciHeader { revision, .. }, + .. + } => revision, } } /// Return the Interface field. pub fn interface(&self) -> u8 { match self { - &PciHeader::General { interface, .. } | &PciHeader::PciToPci { interface, .. } => interface, + &PciHeader::General { + shared: SharedPciHeader { interface, .. }, + .. + } + | &PciHeader::PciToPci { + shared: SharedPciHeader { interface, .. }, + .. + } => interface, } } /// Return the Subclass field. pub fn subclass(&self) -> u8 { match self { - &PciHeader::General { subclass, .. } | &PciHeader::PciToPci { subclass, .. } => subclass, + &PciHeader::General { + shared: SharedPciHeader { subclass, .. }, + .. + } + | &PciHeader::PciToPci { + shared: SharedPciHeader { subclass, .. }, + .. + } => subclass, } } /// Return the Class field. pub fn class(&self) -> PciClass { match self { - &PciHeader::General { class, .. } | &PciHeader::PciToPci { class, .. } => class, + &PciHeader::General { + shared: SharedPciHeader { class, .. }, + .. + } + | &PciHeader::PciToPci { + shared: SharedPciHeader { class, .. }, + .. + } => class, } } @@ -269,7 +347,7 @@ impl PciHeader { &PciHeader::General { bars, .. } => { assert!(idx < 6, "the general PCI device only has 6 BARs"); bars[idx] - }, + } &PciHeader::PciToPci { bars, .. } => { assert!(idx < 2, "the general PCI device only has 2 BARs"); bars[idx] @@ -280,20 +358,29 @@ impl PciHeader { /// Return the Interrupt Line field. pub fn interrupt_line(&self) -> u8 { match self { - &PciHeader::General { interrupt_line, .. } | &PciHeader::PciToPci { interrupt_line, .. } => - interrupt_line, + &PciHeader::General { interrupt_line, .. } + | &PciHeader::PciToPci { interrupt_line, .. } => interrupt_line, } } pub fn status(&self) -> u16 { match self { - &PciHeader::General { status, .. } | &PciHeader::PciToPci { status, .. } => status, + &PciHeader::General { + shared: SharedPciHeader { status, .. }, + .. + } + | &PciHeader::PciToPci { + shared: SharedPciHeader { status, .. }, + .. + } => status, } } pub fn cap_pointer(&self) -> u8 { match self { - &PciHeader::General { cap_pointer, .. } | &PciHeader::PciToPci { cap_pointer, .. } => cap_pointer, + &PciHeader::General { cap_pointer, .. } | &PciHeader::PciToPci { cap_pointer, .. } => { + cap_pointer + } } } } From e5491a9e9a81d0b12144acda1ca00330c71f057a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Jan 2024 21:07:38 +0100 Subject: [PATCH 0753/1301] Inline several layers of read and write methods --- pcid/src/pci/bus.rs | 11 +---------- pcid/src/pci/dev.rs | 20 +++++--------------- pcid/src/pci/func.rs | 27 ++++++++++++++++++--------- 3 files changed, 24 insertions(+), 34 deletions(-) diff --git a/pcid/src/pci/bus.rs b/pcid/src/pci/bus.rs index d00db29b04..849d6e5fdd 100644 --- a/pcid/src/pci/bus.rs +++ b/pcid/src/pci/bus.rs @@ -1,4 +1,4 @@ -use super::{CfgAccess, PciAddress, PciDev}; +use super::{CfgAccess, PciDev}; pub struct PciBus<'pci> { pub pci: &'pci dyn CfgAccess, @@ -9,15 +9,6 @@ impl<'pci> PciBus<'pci> { pub fn devs(&'pci self) -> PciBusIter<'pci> { PciBusIter::new(self) } - - pub unsafe fn read(&self, dev: u8, func: u8, offset: u16) -> u32 { - self.pci - .read(PciAddress::new(0, self.num, dev, func), offset) - } - pub unsafe fn write(&self, dev: u8, func: u8, offset: u16, value: u32) { - self.pci - .write(PciAddress::new(0, self.num, dev, func), offset, value) - } } pub struct PciBusIter<'pci> { diff --git a/pcid/src/pci/dev.rs b/pcid/src/pci/dev.rs index ca2e505bb4..4dd143a65f 100644 --- a/pcid/src/pci/dev.rs +++ b/pcid/src/pci/dev.rs @@ -2,33 +2,23 @@ use super::{PciBus, PciFunc}; pub struct PciDev<'pci> { pub bus: &'pci PciBus<'pci>, - pub num: u8 + pub num: u8, } impl<'pci> PciDev<'pci> { pub fn funcs(&'pci self) -> PciDevIter<'pci> { PciDevIter::new(self) } - - pub unsafe fn read(&self, func: u8, offset: u16) -> u32 { - self.bus.read(self.num, func, offset) - } - pub unsafe fn write(&self, func: u8, offset: u16, value: u32) { - self.bus.write(self.num, func, offset, value); - } } pub struct PciDevIter<'pci> { dev: &'pci PciDev<'pci>, - num: u8 + num: u8, } impl<'pci> PciDevIter<'pci> { pub fn new(dev: &'pci PciDev<'pci>) -> Self { - PciDevIter { - dev: dev, - num: 0 - } + PciDevIter { dev, num: 0 } } } @@ -39,11 +29,11 @@ impl<'pci> Iterator for PciDevIter<'pci> { func_num if func_num < 8 => { let func = PciFunc { dev: self.dev, - num: self.num + num: self.num, }; self.num += 1; Some(func) - }, + } _ => None, } } diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index fbdda1cfc6..80e91da576 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -1,16 +1,18 @@ -use byteorder::{LittleEndian, ByteOrder}; +use byteorder::{ByteOrder, LittleEndian}; -use super::PciDev; +use super::{PciAddress, PciDev}; pub trait ConfigReader { unsafe fn read_range(&self, offset: u16, len: u16) -> Vec { assert!(len > 3 && len % 4 == 0, "invalid range length: {}", len); let mut ret = Vec::with_capacity(len as usize); - let results = (offset..offset + len).step_by(4).fold(Vec::new(), |mut acc, offset| { - let val = self.read_u32(offset); - acc.push(val); - acc - }); + let results = (offset..offset + len) + .step_by(4) + .fold(Vec::new(), |mut acc, offset| { + let val = self.read_u32(offset); + acc.push(val); + acc + }); ret.set_len(len as usize); LittleEndian::write_u32_into(&*results, &mut ret); ret @@ -37,11 +39,18 @@ pub struct PciFunc<'pci> { impl<'pci> ConfigReader for PciFunc<'pci> { unsafe fn read_u32(&self, offset: u16) -> u32 { - self.dev.read(self.num, offset) + self.dev.bus.pci.read( + PciAddress::new(0, self.dev.bus.num, self.dev.num, self.num), + offset, + ) } } impl<'pci> ConfigWriter for PciFunc<'pci> { unsafe fn write_u32(&self, offset: u16, value: u32) { - self.dev.write(self.num, offset, value); + self.dev.bus.pci.write( + PciAddress::new(0, self.dev.bus.num, self.dev.num, self.num), + offset, + value, + ); } } From 42b2f52d419999a9084f1aba7f5218b2525854c1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Jan 2024 22:12:29 +0100 Subject: [PATCH 0754/1301] Directly store a PciAddress inside PciFunc instead of a PciDev + num --- pcid/src/main.rs | 30 +++++++----------------------- pcid/src/pci/bus.rs | 22 +++++++++++----------- pcid/src/pci/dev.rs | 24 +++++++++++++----------- pcid/src/pci/func.rs | 17 +++++------------ pcid/src/pci/mod.rs | 7 ++----- 5 files changed, 38 insertions(+), 62 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 51b5669026..ccdcc52aa3 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -43,17 +43,9 @@ pub struct DriverHandler { state: Arc, } fn with_pci_func_raw T>(pci: &dyn CfgAccess, bus_num: u8, dev_num: u8, func_num: u8, function: F) -> T { - let bus = PciBus { - pci, - num: bus_num, - }; - let dev = PciDev { - bus: &bus, - num: dev_num, - }; let func = PciFunc { - dev: &dev, - num: func_num, + pci, + addr: PciAddress::new(0, bus_num, dev_num, func_num), }; function(&func) } @@ -399,17 +391,9 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, } let capabilities = if header.status() & (1 << 4) != 0 { - let bus = PciBus { - pci: state.preferred_cfg_access(), - num: bus_num, - }; - let dev = PciDev { - bus: &bus, - num: dev_num - }; let func = PciFunc { - dev: &dev, - num: func_num, + pci: state.preferred_cfg_access(), + addr: PciAddress::new(0, bus_num, dev_num, func_num), }; crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() } else { @@ -631,10 +615,10 @@ fn main(args: Args) { let bus_num = bus_nums[bus_i]; bus_i += 1; - let bus = PciBus { pci, num: bus_num }; + let bus = PciBus { num: bus_num }; 'dev: for dev in bus.devs() { - for func in dev.funcs() { - let func_num = func.num; + for func in dev.funcs(pci) { + let func_num = func.addr.function(); match PciHeader::from_reader(func) { Ok(header) => { handle_parsed_header(Arc::clone(&state), &config, bus.num, dev.num, func_num, header); diff --git a/pcid/src/pci/bus.rs b/pcid/src/pci/bus.rs index 849d6e5fdd..9900d118d9 100644 --- a/pcid/src/pci/bus.rs +++ b/pcid/src/pci/bus.rs @@ -1,29 +1,29 @@ -use super::{CfgAccess, PciDev}; +use super::PciDev; -pub struct PciBus<'pci> { - pub pci: &'pci dyn CfgAccess, +#[derive(Copy, Clone)] +pub struct PciBus { pub num: u8, } -impl<'pci> PciBus<'pci> { - pub fn devs(&'pci self) -> PciBusIter<'pci> { +impl<'pci> PciBus { + pub fn devs(self) -> PciBusIter { PciBusIter::new(self) } } -pub struct PciBusIter<'pci> { - bus: &'pci PciBus<'pci>, +pub struct PciBusIter { + bus: PciBus, num: u8, } -impl<'pci> PciBusIter<'pci> { - pub fn new(bus: &'pci PciBus<'pci>) -> Self { +impl PciBusIter { + pub fn new(bus: PciBus) -> Self { PciBusIter { bus, num: 0 } } } -impl<'pci> Iterator for PciBusIter<'pci> { - type Item = PciDev<'pci>; +impl Iterator for PciBusIter { + type Item = PciDev; fn next(&mut self) -> Option { match self.num { dev_num if dev_num < 32 => { diff --git a/pcid/src/pci/dev.rs b/pcid/src/pci/dev.rs index 4dd143a65f..b64eeb1034 100644 --- a/pcid/src/pci/dev.rs +++ b/pcid/src/pci/dev.rs @@ -1,24 +1,26 @@ -use super::{PciBus, PciFunc}; +use super::{CfgAccess, PciAddress, PciBus, PciFunc}; -pub struct PciDev<'pci> { - pub bus: &'pci PciBus<'pci>, +#[derive(Copy, Clone)] +pub struct PciDev { + pub bus: PciBus, pub num: u8, } -impl<'pci> PciDev<'pci> { - pub fn funcs(&'pci self) -> PciDevIter<'pci> { - PciDevIter::new(self) +impl<'pci> PciDev { + pub fn funcs(self, pci: &'pci dyn CfgAccess) -> PciDevIter<'pci> { + PciDevIter::new(self, pci) } } pub struct PciDevIter<'pci> { - dev: &'pci PciDev<'pci>, + pci: &'pci dyn CfgAccess, + dev: PciDev, num: u8, } impl<'pci> PciDevIter<'pci> { - pub fn new(dev: &'pci PciDev<'pci>) -> Self { - PciDevIter { dev, num: 0 } + pub fn new(dev: PciDev, pci: &'pci dyn CfgAccess) -> Self { + PciDevIter { pci, dev, num: 0 } } } @@ -28,8 +30,8 @@ impl<'pci> Iterator for PciDevIter<'pci> { match self.num { func_num if func_num < 8 => { let func = PciFunc { - dev: self.dev, - num: self.num, + pci: self.pci, + addr: PciAddress::new(0, self.dev.bus.num, self.dev.num, func_num), }; self.num += 1; Some(func) diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index 80e91da576..6625542db9 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -1,6 +1,6 @@ use byteorder::{ByteOrder, LittleEndian}; -use super::{PciAddress, PciDev}; +use super::{CfgAccess, PciAddress, PciDev}; pub trait ConfigReader { unsafe fn read_range(&self, offset: u16, len: u16) -> Vec { @@ -33,24 +33,17 @@ pub trait ConfigWriter { } pub struct PciFunc<'pci> { - pub dev: &'pci PciDev<'pci>, - pub num: u8, + pub pci: &'pci dyn CfgAccess, + pub addr: PciAddress, } impl<'pci> ConfigReader for PciFunc<'pci> { unsafe fn read_u32(&self, offset: u16) -> u32 { - self.dev.bus.pci.read( - PciAddress::new(0, self.dev.bus.num, self.dev.num, self.num), - offset, - ) + self.pci.read(self.addr, offset) } } impl<'pci> ConfigWriter for PciFunc<'pci> { unsafe fn write_u32(&self, offset: u16, value: u32) { - self.dev.bus.pci.write( - PciAddress::new(0, self.dev.bus.num, self.dev.num, self.num), - offset, - value, - ); + self.pci.write(self.addr, offset, value); } } diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index d7bc48d5f0..708da62150 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -188,14 +188,11 @@ impl<'pci> PciIter<'pci> { } impl<'pci> Iterator for PciIter<'pci> { - type Item = PciBus<'pci>; + type Item = PciBus; fn next(&mut self) -> Option { match self.num { Some(bus_num) => { - let bus = PciBus { - pci: self.pci, - num: bus_num, - }; + let bus = PciBus { num: bus_num }; self.num = bus_num.checked_add(1); Some(bus) } From 2b5ed69a06cb57e9b05ff26d490f7d1c491dd962 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 11:34:54 +0100 Subject: [PATCH 0755/1301] Use PciAddress in a couple more places --- nvmed/src/main.rs | 4 +- pcid/src/driver_interface/mod.rs | 17 +++---- pcid/src/main.rs | 81 ++++++++++++-------------------- pcid/src/pci/mod.rs | 5 +- 4 files changed, 41 insertions(+), 66 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 9074dcc4d7..2fed31c18c 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -11,7 +11,7 @@ use std::{slice, usize}; use pcid_interface::{PciBar, PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; use syscall::{ - Event, Mmio, Packet, Result, SchemeBlockMut, + Event, Mmio, Packet, Result, SchemeBlockMut, PAGE_SIZE, }; use redox_log::{OutputBuilder, RedoxLogger}; @@ -299,7 +299,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .fetch_config() .expect("nvmed: failed to fetch config"); - let mut scheme_name = format!("disk.pci-{:x}+{:x}+{:x}-nvme", pci_config.func.bus_num, pci_config.func.dev_num, pci_config.func.func_num); + let scheme_name = format!("disk.pci-{}-nvme", pci_config.func.addr); let _logger_ref = setup_logging(&scheme_name); diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index e563c6d06a..1132423793 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -4,12 +4,12 @@ use std::{env, io}; use std::os::unix::io::{FromRawFd, RawFd}; -use serde::{Serialize, Deserialize, de::DeserializeOwned}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; use thiserror::Error; pub use crate::pci::cap::Capability; pub use crate::pci::msi; -pub use crate::pci::{PciBar, PciHeader}; +pub use crate::pci::{PciAddress, PciBar, PciHeader}; pub mod irq_helpers; @@ -28,14 +28,8 @@ pub enum LegacyInterruptPin { #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct PciFunction { - /// Number of PCI bus - pub bus_num: u8, - - /// Number of PCI device - pub dev_num: u8, - - /// Number of PCI function - pub func_num: u8, + /// Address of the PCI function. + pub addr: PciAddress, /// PCI Base Address Registers pub bars: [PciBar; 6], @@ -58,7 +52,8 @@ pub struct PciFunction { } impl PciFunction { pub fn name(&self) -> String { - format!("pci-{:>02X}.{:>02X}.{:>02X}", self.bus_num, self.dev_num, self.func_num) + // FIXME stop replacing : with - once it is a valid character in scheme names + format!("pci-{}", self.addr).replace(':', "-") } } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index ccdcc52aa3..0806a7701a 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -34,24 +34,22 @@ struct Args { pub struct DriverHandler { config: config::DriverConfig, - bus_num: u8, - dev_num: u8, - func_num: u8, + addr: PciAddress, header: PciHeader, capabilities: Vec<(u8, PciCapability)>, state: Arc, } -fn with_pci_func_raw T>(pci: &dyn CfgAccess, bus_num: u8, dev_num: u8, func_num: u8, function: F) -> T { +fn with_pci_func_raw T>(pci: &dyn CfgAccess, addr: PciAddress, function: F) -> T { let func = PciFunc { pci, - addr: PciAddress::new(0, bus_num, dev_num, func_num), + addr, }; function(&func) } impl DriverHandler { fn with_pci_func_raw T>(&self, function: F) -> T { - with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, function) + with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, function) } fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse { use driver_interface::*; @@ -81,7 +79,7 @@ impl DriverHandler { None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), }; unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { + with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { capability.set_enabled(true); capability.write_message_control(func, offset); }); @@ -94,7 +92,7 @@ impl DriverHandler { None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), }; unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { + with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { capability.set_msix_enabled(true); capability.write_a(func, offset); }); @@ -154,7 +152,7 @@ impl DriverHandler { info.set_mask_bits(mask_bits); } unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { + with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { info.write_all(func, offset); }); } @@ -166,7 +164,7 @@ impl DriverHandler { if let Some(mask) = function_mask { info.set_function_mask(mask); unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { + with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { info.write_a(func, offset); }); } @@ -178,7 +176,7 @@ impl DriverHandler { } PcidClientRequest::ReadConfig(offset) => { let value = unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { + with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { func.read_u32(offset) }) }; @@ -186,7 +184,7 @@ impl DriverHandler { }, PcidClientRequest::WriteConfig(offset, value) => { unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.bus_num, self.dev_num, self.func_num, |func| { + with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { func.write_u32(offset, value); }); } @@ -222,13 +220,12 @@ impl State { } } -fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, - dev_num: u8, func_num: u8, header: PciHeader) { +fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, header: PciHeader) { let pci = state.preferred_cfg_access(); let raw_class: u8 = header.class().into(); - let mut string = format!("PCI {:>02X}/{:>02X}/{:>02X} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", - bus_num, dev_num, func_num, header.vendor_id(), header.device_id(), raw_class, + let mut string = format!("PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", + addr, header.vendor_id(), header.device_id(), raw_class, header.subclass(), header.interface(), header.revision(), header.class()); match header.class() { PciClass::Legacy if header.subclass() == 1 => string.push_str(" VGA CTL"), @@ -319,9 +316,9 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, if let Some(ref args) = driver.command { // Enable bus mastering, memory space, and I/O space unsafe { - let mut data = pci.read(PciAddress::new(0, bus_num, dev_num, func_num), 0x04); + let mut data = pci.read(addr, 0x04); data |= 7; - pci.write(PciAddress::new(0, bus_num, dev_num, func_num), 0x04, data); + pci.write(addr, 0x04, data); } // Set IRQ line to 9 if not set @@ -329,14 +326,14 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, let mut interrupt_pin; unsafe { - let mut data = pci.read(PciAddress::new(0, bus_num, dev_num, func_num), 0x3C); + let mut data = pci.read(addr, 0x3C); irq = (data & 0xFF) as u8; interrupt_pin = ((data & 0x0000_FF00) >> 8) as u8; if irq == 0xFF { irq = 9; } data = (data & 0xFFFFFF00) | irq as u32; - pci.write(PciAddress::new(0, bus_num, dev_num, func_num), 0x3C, data); + pci.write(addr, 0x3C, data); }; // Find BAR sizes @@ -355,25 +352,11 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, let offset = 0x10 + (i as u8) * 4; - let original = pci.read( - PciAddress::new(0, bus_num, dev_num, func_num), - offset.into(), - ); - pci.write( - PciAddress::new(0, bus_num, dev_num, func_num), - offset.into(), - 0xFFFFFFFF, - ); + let original = pci.read(addr, offset.into()); + pci.write(addr, offset.into(), 0xFFFFFFFF); - let new = pci.read( - PciAddress::new(0, bus_num, dev_num, func_num), - offset.into(), - ); - pci.write( - PciAddress::new(0, bus_num, dev_num, func_num), - offset.into(), - original, - ); + let new = pci.read(addr, offset.into()); + pci.write(addr, offset.into(), original); let masked = if new & 1 == 1 { new & 0xFFFFFFFC @@ -393,7 +376,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, let capabilities = if header.status() & (1 << 4) != 0 { let func = PciFunc { pci: state.preferred_cfg_access(), - addr: PciAddress::new(0, bus_num, dev_num, func_num), + addr }; crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() } else { @@ -419,9 +402,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, let func = driver_interface::PciFunction { bars, bar_sizes, - bus_num, - dev_num, - func_num, + addr, devid: header.device_id(), legacy_interrupt_line: irq, legacy_interrupt_pin, @@ -437,9 +418,9 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, let mut command = Command::new(program); for arg in args { let arg = match arg.as_str() { - "$BUS" => format!("{:>02X}", bus_num), - "$DEV" => format!("{:>02X}", dev_num), - "$FUNC" => format!("{:>02X}", func_num), + "$BUS" => format!("{:>02X}", addr.bus()), + "$DEV" => format!("{:>02X}", addr.device()), + "$FUNC" => format!("{:>02X}", addr.function()), "$NAME" => func.name(), "$BAR0" => format!("{}", bars[0]), "$BAR1" => format!("{}", bars[1]), @@ -489,9 +470,7 @@ fn handle_parsed_header(state: Arc, config: &Config, bus_num: u8, match command.envs(envs).spawn() { Ok(mut child) => { let driver_handler = DriverHandler { - bus_num, - dev_num, - func_num, + addr, config: driver.clone(), header, state: Arc::clone(&state), @@ -618,16 +597,16 @@ fn main(args: Args) { let bus = PciBus { num: bus_num }; 'dev: for dev in bus.devs() { for func in dev.funcs(pci) { - let func_num = func.addr.function(); + let func_addr = func.addr; match PciHeader::from_reader(func) { Ok(header) => { - handle_parsed_header(Arc::clone(&state), &config, bus.num, dev.num, func_num, header); + handle_parsed_header(Arc::clone(&state), &config, func_addr, header); if let PciHeader::PciToPci { secondary_bus_num, .. } = header { bus_nums.push(secondary_bus_num); } } Err(PciHeaderError::NoDevice) => { - if func_num == 0 { + if func_addr.function() == 0 { if dev.num == 0 { trace!("PCI {:>02X}: no bus", bus.num); continue 'bus; diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 708da62150..84baf13f53 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -3,6 +3,7 @@ use std::fmt; use std::sync::{Mutex, Once}; use bit_field::BitField; +use serde::{Deserialize, Serialize}; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use syscall::io::{Io as _, Pio}; @@ -29,7 +30,7 @@ pub trait CfgAccess { unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32); } -// Copied from the pci_types crate, version 0.6.1. +// Copied from the pci_types crate, version 0.6.1. It has been modified to add serde support. // FIXME If we start using it in the future use the upstream version instead. /// The address of a PCIe function. /// @@ -41,7 +42,7 @@ pub trait CfgAccess { /// | segment | bus | device | func | /// +-------------------------------+---------------+---------+------+ /// ``` -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)] pub struct PciAddress(u32); impl PciAddress { From d010d03eefff990214f90a6a21cef2b7b71e1337 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 11:41:59 +0100 Subject: [PATCH 0756/1301] Fix pcid tests --- pcid/src/pci/header.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index 534b376c19..2c7b0556ff 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -467,7 +467,7 @@ mod test { macro_rules! read_range_should_panic { ($name:ident, $len:expr) => { #[test] - #[should_panic(expected = "assertion failed: len > 3 && len % 4 == 0")] + #[should_panic(expected = "invalid range length")] fn $name() { let _ = unsafe { (&IGB_DEV_BYTES[..]).read_range(0, $len) }; } From 15249127a550097dee0e62c917b0d1fd21dce5b2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 12:47:42 +0100 Subject: [PATCH 0757/1301] Fix a couple of warnings --- pcid/src/main.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 0806a7701a..c89fd1d1ed 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -10,7 +10,7 @@ use log::{debug, error, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; use crate::config::Config; -use crate::pci::{CfgAccess, Pci, PciAddress, PciBar, PciBus, PciClass, PciDev, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::{CfgAccess, Pci, PciAddress, PciBar, PciBus, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; use crate::pcie::Pcie; @@ -48,9 +48,6 @@ fn with_pci_func_raw T>(pci: &dyn CfgAccess, addr: Pci function(&func) } impl DriverHandler { - fn with_pci_func_raw T>(&self, function: F) -> T { - with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, function) - } fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse { use driver_interface::*; use crate::pci::cap::{MsiCapability, MsixCapability}; @@ -323,7 +320,7 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he // Set IRQ line to 9 if not set let mut irq; - let mut interrupt_pin; + let interrupt_pin; unsafe { let mut data = pci.read(addr, 0x3C); @@ -476,7 +473,7 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he state: Arc::clone(&state), capabilities, }; - let thread = thread::spawn(move || { + thread::spawn(move || { // RFLAGS are no longer kept in the relibc clone() implementation. unsafe { syscall::iopl(3).expect("pcid: failed to set IOPL"); } From b317484d6756d825a8c38907dc84f8850cac9d46 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 13:00:23 +0100 Subject: [PATCH 0758/1301] Simplify Mcfgs::fetch --- pcid/src/pcie/mod.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index ed5db202f9..b7a5e63f17 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -4,7 +4,7 @@ use std::{fmt, fs, io, mem, ptr, slice}; use syscall::PAGE_SIZE; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use crate::pci::{CfgAccess, Pci, PciAddress, PciIter}; @@ -89,25 +89,25 @@ impl Mcfgs { pub fn fetch() -> io::Result { let table_dir = fs::read_dir("acpi:tables")?; - let tables = table_dir.map(|table_direntry| -> io::Result> { + let mut tables = smallvec![]; + for table_direntry in table_dir { let table_direntry = table_direntry?; let table_path = table_direntry.path(); let table_filename = match table_path.file_name() { - Some(n) => n.to_str().ok_or(io::Error::new(io::ErrorKind::InvalidData, "Non-UTF-8 ACPI table filename"))?, - None => return Ok(None), + Some(n) => n.to_str().ok_or(io::Error::new( + io::ErrorKind::InvalidData, + "Non-UTF-8 ACPI table filename", + ))?, + None => continue, }; if table_filename.starts_with("MCFG") { - Ok(Some(fs::read(table_path)?)) - } else { - Ok(None) + tables.push(fs::read(table_path)?); } - }).filter_map(|result_option| result_option.transpose()).collect::, _>>()?; + } - Ok(Self { - tables, - }) + Ok(Self { tables }) } pub fn table_and_alloc_at_bus(&self, bus: u8) -> Option<(&Mcfg, &PcieAlloc)> { self.tables().find_map(|table| { From c611988768e165e52296c7d9b949eda20c71cc05 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 13:19:53 +0100 Subject: [PATCH 0759/1301] Fix MCFG parsing for PCIe --- pcid/src/main.rs | 4 +--- pcid/src/pcie/mod.rs | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index c89fd1d1ed..4ff108f710 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -211,9 +211,7 @@ pub struct State { } impl State { fn preferred_cfg_access(&self) -> &dyn CfgAccess { - // TODO - //self.pcie.as_ref().map(|pcie| pcie as &dyn CfgAccess).unwrap_or(&*self.pci as &dyn CfgAccess) - &*self.pci as &dyn CfgAccess + self.pcie.as_ref().map(|pcie| pcie as &dyn CfgAccess).unwrap_or(&*self.pci as &dyn CfgAccess) } } diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index b7a5e63f17..2ad4ead358 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -45,10 +45,15 @@ unsafe impl plain::Plain for PcieAlloc {} impl Mcfg { pub fn base_addr_structs(&self) -> &[PcieAlloc] { - let total_length = mem::size_of::(); - let len = total_length - 44; + let total_length = self.length as usize; + let len = total_length - mem::size_of::(); // safe because the length cannot be changed arbitrarily - unsafe { slice::from_raw_parts(&self.base_addrs as *const PcieAlloc, len / mem::size_of::()) } + unsafe { + slice::from_raw_parts( + &self.base_addrs as *const PcieAlloc, + len / mem::size_of::(), + ) + } } } impl fmt::Debug for Mcfg { @@ -111,9 +116,12 @@ impl Mcfgs { } pub fn table_and_alloc_at_bus(&self, bus: u8) -> Option<(&Mcfg, &PcieAlloc)> { self.tables().find_map(|table| { - Some((table, table.base_addr_structs().iter().find(|addr_struct| { - (addr_struct.start_bus..addr_struct.end_bus).contains(&bus) - })?)) + Some(( + table, + table.base_addr_structs().iter().find(|addr_struct| { + (addr_struct.start_bus..=addr_struct.end_bus).contains(&bus) + })?, + )) }) } pub fn at_bus(&self, bus: u8) -> Option<&PcieAlloc> { From 240e59e2bf20f7a830adb4285eead09cc49ff3d4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 14:45:48 +0100 Subject: [PATCH 0760/1301] Handle pci buses without a device at the first slot --- pcid/src/main.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 4ff108f710..df1799ffb0 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -585,7 +585,7 @@ fn main(args: Args) { let mut bus_nums = vec![0]; let mut bus_i = 0; - 'bus: while bus_i < bus_nums.len() { + while bus_i < bus_nums.len() { let bus_num = bus_nums[bus_i]; bus_i += 1; @@ -602,13 +602,8 @@ fn main(args: Args) { } Err(PciHeaderError::NoDevice) => { if func_addr.function() == 0 { - if dev.num == 0 { - trace!("PCI {:>02X}: no bus", bus.num); - continue 'bus; - } else { trace!("PCI {:>02X}/{:>02X}: no dev", bus.num, dev.num); continue 'dev; - } } }, Err(PciHeaderError::UnknownHeaderType(id)) => { From 101f062b56b207647db24946ff6ba45aff4ed98d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 14:58:09 +0100 Subject: [PATCH 0761/1301] Remove a couple of error conditions in Mcfgs::fetch() * Every directory entry has to have a filename, so use unwrap * Handle non-UTF-8 ACPI table filenames by using as_encoded_bytes --- pcid/src/pcie/mod.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 2ad4ead358..623471a230 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -31,7 +31,6 @@ unsafe impl plain::Plain for Mcfg {} /// The "Memory Mapped Enhanced Configuration Space Base Address Allocation Structure" (yes, it's /// called that). - #[repr(packed)] #[derive(Clone, Copy, Debug)] pub struct PcieAlloc { @@ -59,7 +58,7 @@ impl Mcfg { impl fmt::Debug for Mcfg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Mcfg") - .field("name", &"MCFG") + .field("name", &self.name) .field("length", &{ self.length }) .field("revision", &self.revision) .field("checksum", &self.checksum) @@ -88,7 +87,9 @@ impl Mcfgs { }) } pub fn allocs<'a>(&'a self) -> impl Iterator + 'a { - self.tables().map(|table| table.base_addr_structs().iter()).flatten() + self.tables() + .map(|table| table.base_addr_structs().iter()) + .flatten() } pub fn fetch() -> io::Result { @@ -96,18 +97,16 @@ impl Mcfgs { let mut tables = smallvec![]; for table_direntry in table_dir { - let table_direntry = table_direntry?; - let table_path = table_direntry.path(); + let table_path = table_direntry?.path(); - let table_filename = match table_path.file_name() { - Some(n) => n.to_str().ok_or(io::Error::new( - io::ErrorKind::InvalidData, - "Non-UTF-8 ACPI table filename", - ))?, - None => continue, - }; - - if table_filename.starts_with("MCFG") { + // Every directory entry has to have a filename unless + // the filesystem (or in this case acpid) misbehaves. + // If it misbehaves we have worse problems than pcid + // crashing. `as_encoded_bytes()` returns some superset + // of ASCII, so directly comparing it with an ASCII name + // is fine. + let table_filename = table_path.file_name().unwrap().as_encoded_bytes(); + if table_filename.get(0..4) == Some(&MCFG_NAME) { tables.push(fs::read(table_path)?); } } From 07c029ec21c352b79fa3b542a4544253568af971 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:10:57 +0100 Subject: [PATCH 0762/1301] Add a fixme for using ACPI --- pcid/src/main.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index df1799ffb0..83d7ef2ce7 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -581,8 +581,11 @@ fn main(args: Args) { let pci = state.preferred_cfg_access(); - info!("PCI BS/DV/FN VEND:DEVI CL.SC.IN.RV"); + info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV"); + // FIXME Use full ACPI for enumerating the host bridges. MCFG only describes the first + // host bridge, while multi-processor systems likely have a host bridge for each CPU. + // See also https://www.kernel.org/doc/html/latest/PCI/acpi-info.html let mut bus_nums = vec![0]; let mut bus_i = 0; while bus_i < bus_nums.len() { From ae7e2dac9f7eed4ec86535ed8afc7396131b9c2f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 18:41:28 +0100 Subject: [PATCH 0763/1301] Only parse a single MCFG ACPI table There should only be one and Linux only parses the first one too. --- Cargo.lock | 1 - pcid/Cargo.toml | 1 - pcid/src/pcie/mod.rs | 46 ++++++++++++++++++++------------------------ 3 files changed, 21 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ec51a7bb2..a75774a6d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -968,7 +968,6 @@ dependencies = [ "redox_syscall 0.4.1", "serde", "serde_json", - "smallvec 1.11.0", "structopt", "thiserror", "toml 0.5.11", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 1927fa84f0..6c276cc52b 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -24,7 +24,6 @@ redox-log = "0.1" redox_syscall = "0.4" serde = { version = "1", features = ["derive"] } serde_json = "1" -smallvec = "1" structopt = { version = "0.3", default-features = false, features = [ "paw" ] } thiserror = "1" toml = "0.5" diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 623471a230..46072ef883 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -4,8 +4,6 @@ use std::{fmt, fs, io, mem, ptr, slice}; use syscall::PAGE_SIZE; -use smallvec::{smallvec, SmallVec}; - use crate::pci::{CfgAccess, Pci, PciAddress, PciIter}; pub const MCFG_NAME: [u8; 4] = *b"MCFG"; @@ -73,29 +71,21 @@ impl fmt::Debug for Mcfg { } pub struct Mcfgs { - tables: SmallVec<[Vec; 2]>, + bytes: Vec, } impl Mcfgs { - pub fn tables<'a>(&'a self) -> impl Iterator + 'a { - self.tables.iter().filter_map(|bytes| { - let mcfg = plain::from_bytes::(bytes).ok()?; - if mcfg.length as usize > bytes.len() { + pub fn table<'a>(&'a self) -> Option<&'a Mcfg> { + let mcfg = plain::from_bytes::(&self.bytes).ok()?; + if mcfg.length as usize > self.bytes.len() { return None; } Some(mcfg) - }) - } - pub fn allocs<'a>(&'a self) -> impl Iterator + 'a { - self.tables() - .map(|table| table.base_addr_structs().iter()) - .flatten() } pub fn fetch() -> io::Result { let table_dir = fs::read_dir("acpi:tables")?; - let mut tables = smallvec![]; for table_direntry in table_dir { let table_path = table_direntry?.path(); @@ -107,24 +97,30 @@ impl Mcfgs { // is fine. let table_filename = table_path.file_name().unwrap().as_encoded_bytes(); if table_filename.get(0..4) == Some(&MCFG_NAME) { - tables.push(fs::read(table_path)?); + // There should only be a single MCFG table and Linux ignores + // all MCFG tables beyond the first too. + return Ok(Self { + bytes: fs::read(table_path)?, + }); } } - Ok(Self { tables }) + Err(io::Error::new( + io::ErrorKind::NotFound, + "couldn't find mcfg table", + )) } - pub fn table_and_alloc_at_bus(&self, bus: u8) -> Option<(&Mcfg, &PcieAlloc)> { - self.tables().find_map(|table| { - Some(( - table, + + pub fn at_bus(&self, bus: u8) -> Option<&PcieAlloc> { + if let Some(table) = (&self).table() { + Some( table.base_addr_structs().iter().find(|addr_struct| { (addr_struct.start_bus..=addr_struct.end_bus).contains(&bus) })?, - )) - }) + ) + } else { + None } - pub fn at_bus(&self, bus: u8) -> Option<&PcieAlloc> { - self.table_and_alloc_at_bus(bus).map(|(_, alloc)| alloc) } } @@ -133,7 +129,7 @@ impl fmt::Debug for Mcfgs { struct Tables<'a>(&'a Mcfgs); impl<'a> fmt::Debug for Tables<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.0.tables()).finish() + f.debug_list().entries(self.0.table()).finish() } } From 8d87b701ba9360caaaa3d2e3909b4024ea264027 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:10:35 +0100 Subject: [PATCH 0764/1301] Remove Mcfgs type This wrapper was only useful back when we accepted multiple MCFG tables. --- pcid/src/pcie/mod.rs | 136 ++++++++++++++++++++----------------------- 1 file changed, 64 insertions(+), 72 deletions(-) diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 46072ef883..272f904534 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -41,7 +41,65 @@ pub struct PcieAlloc { unsafe impl plain::Plain for PcieAlloc {} impl Mcfg { - pub fn base_addr_structs(&self) -> &[PcieAlloc] { + fn fetch() -> io::Result<&'static Mcfg> { + let table_dir = fs::read_dir("acpi:tables")?; + + for table_direntry in table_dir { + let table_path = table_direntry?.path(); + + // Every directory entry has to have a filename unless + // the filesystem (or in this case acpid) misbehaves. + // If it misbehaves we have worse problems than pcid + // crashing. `as_encoded_bytes()` returns some superset + // of ASCII, so directly comparing it with an ASCII name + // is fine. + let table_filename = table_path.file_name().unwrap().as_encoded_bytes(); + if table_filename.get(0..4) == Some(&MCFG_NAME) { + let bytes = fs::read(table_path)?.into_boxed_slice(); + if Mcfg::parse(&*bytes).is_none() { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "couldn't find mcfg table", + )); + } + + // Leaking memory is fine as this function is only called once + // and we need this for the entire lifetime of pcid anyway. + let bytes = Box::leak(bytes); + + // This unwrap is fine as we checked that it will return Some above. + let mcfg = Mcfg::parse(bytes).unwrap(); + + // There should only be a single MCFG table and Linux ignores + // all MCFG tables beyond the first too, so doing an early + // return here is fine. + return Ok(mcfg); + } + } + + Err(io::Error::new( + io::ErrorKind::NotFound, + "couldn't find mcfg table", + )) + } + + fn parse<'a>(bytes: &'a [u8]) -> Option<&'a Mcfg> { + let mcfg = plain::from_bytes::(bytes).ok()?; + if mcfg.length as usize > bytes.len() { + return None; + } + Some(mcfg) + } + + fn at_bus(&self, bus: u8) -> Option<&PcieAlloc> { + Some( + self.base_addr_structs() + .iter() + .find(|addr_struct| (addr_struct.start_bus..=addr_struct.end_bus).contains(&bus))?, + ) + } + + fn base_addr_structs(&self) -> &[PcieAlloc] { let total_length = self.length as usize; let len = total_length - mem::size_of::(); // safe because the length cannot be changed arbitrarily @@ -53,6 +111,7 @@ impl Mcfg { } } } + impl fmt::Debug for Mcfg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Mcfg") @@ -70,76 +129,9 @@ impl fmt::Debug for Mcfg { } } -pub struct Mcfgs { - bytes: Vec, -} - -impl Mcfgs { - pub fn table<'a>(&'a self) -> Option<&'a Mcfg> { - let mcfg = plain::from_bytes::(&self.bytes).ok()?; - if mcfg.length as usize > self.bytes.len() { - return None; - } - Some(mcfg) - } - - pub fn fetch() -> io::Result { - let table_dir = fs::read_dir("acpi:tables")?; - - for table_direntry in table_dir { - let table_path = table_direntry?.path(); - - // Every directory entry has to have a filename unless - // the filesystem (or in this case acpid) misbehaves. - // If it misbehaves we have worse problems than pcid - // crashing. `as_encoded_bytes()` returns some superset - // of ASCII, so directly comparing it with an ASCII name - // is fine. - let table_filename = table_path.file_name().unwrap().as_encoded_bytes(); - if table_filename.get(0..4) == Some(&MCFG_NAME) { - // There should only be a single MCFG table and Linux ignores - // all MCFG tables beyond the first too. - return Ok(Self { - bytes: fs::read(table_path)?, - }); - } - } - - Err(io::Error::new( - io::ErrorKind::NotFound, - "couldn't find mcfg table", - )) - } - - pub fn at_bus(&self, bus: u8) -> Option<&PcieAlloc> { - if let Some(table) = (&self).table() { - Some( - table.base_addr_structs().iter().find(|addr_struct| { - (addr_struct.start_bus..=addr_struct.end_bus).contains(&bus) - })?, - ) - } else { - None - } - } -} - -impl fmt::Debug for Mcfgs { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - struct Tables<'a>(&'a Mcfgs); - impl<'a> fmt::Debug for Tables<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.0.table()).finish() - } - } - - f.debug_tuple("Mcfgs").field(&Tables(self)).finish() - } -} - pub struct Pcie { lock: Mutex<()>, - mcfgs: Mcfgs, + mcfg: &'static Mcfg, maps: Mutex>, fallback: Arc, } @@ -148,11 +140,11 @@ unsafe impl Sync for Pcie {} impl Pcie { pub fn new(fallback: Arc) -> io::Result { - let mcfgs = Mcfgs::fetch()?; + let mcfg = Mcfg::fetch()?; Ok(Self { lock: Mutex::new(()), - mcfgs, + mcfg, maps: Mutex::new(BTreeMap::new()), fallback, }) @@ -181,7 +173,7 @@ impl Pcie { offset: u16, f: F, ) -> T { - let (base_address_phys, starting_bus) = match self.mcfgs.at_bus(address.bus()) { + let (base_address_phys, starting_bus) = match self.mcfg.at_bus(address.bus()) { Some(t) => (t.base_addr, t.start_bus), None => return f(None), }; From cb9edcb7d6f5437183a7f653d098c7b1843462db Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:11:05 +0100 Subject: [PATCH 0765/1301] Reduce log verbosity of Capability::parse_vendor by combining some logs --- pcid/src/pci/cap.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 02b3301450..99fc3e09b2 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -182,10 +182,9 @@ impl Capability { }) } unsafe fn parse_vendor(reader: &R, offset: u8) -> Self { - log::info!("Vendor specific offset: {}", offset); - log::info!("Vendor specific next: {}", reader.read_u8((offset+1).into())); + let next = reader.read_u8(u16::from(offset+1)); let length = reader.read_u8(u16::from(offset+2)); - log::info!("Vendor specific cap len: {}", length); + log::info!("Vendor specific offset: {offset:#02x} next: {next:#02x} cap len: {length:#02x}"); let data = if length > 0 { let mut raw_data = reader.read_range(offset.into(), length.into()); raw_data.drain(3..).collect() From 23d963361a2b9da9fe282ee1122d0e7476d0ac88 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:14:22 +0100 Subject: [PATCH 0766/1301] Fix a couple of warnings --- pcid/src/pcie/mod.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 272f904534..7a21b0e9a9 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -4,7 +4,7 @@ use std::{fmt, fs, io, mem, ptr, slice}; use syscall::PAGE_SIZE; -use crate::pci::{CfgAccess, Pci, PciAddress, PciIter}; +use crate::pci::{CfgAccess, Pci, PciAddress}; pub const MCFG_NAME: [u8; 4] = *b"MCFG"; @@ -164,9 +164,6 @@ impl Pcie { | ((address.function() as usize) << 12) | (offset as usize) } - fn addr_offset_in_dwords(starting_bus: u8, address: PciAddress, offset: u16) -> usize { - Self::addr_offset_in_bytes(starting_bus, address, offset) / mem::size_of::() - } unsafe fn with_pointer) -> T>( &self, address: PciAddress, @@ -199,9 +196,6 @@ impl Pcie { (offset as usize / mem::size_of::()) as isize, ))) } - pub fn buses<'pcie>(&'pcie self) -> PciIter<'pcie> { - PciIter::new(self) - } } impl CfgAccess for Pcie { From 529b4935ee8abdf1c729dfe1f9b1ad848fc42ac5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:50:11 +0100 Subject: [PATCH 0767/1301] Physmap all buses upfront This avoids a costly Mutex lock and BTreeMap lookup for each config space access. --- pcid/src/pcie/mod.rs | 93 ++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 7a21b0e9a9..b8f4da6c0a 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -1,9 +1,6 @@ -use std::collections::BTreeMap; use std::sync::{Arc, Mutex}; use std::{fmt, fs, io, mem, ptr, slice}; -use syscall::PAGE_SIZE; - use crate::pci::{CfgAccess, Pci, PciAddress}; pub const MCFG_NAME: [u8; 4] = *b"MCFG"; @@ -131,8 +128,7 @@ impl fmt::Debug for Mcfg { pub struct Pcie { lock: Mutex<()>, - mcfg: &'static Mcfg, - maps: Mutex>, + bus_maps: Vec>, fallback: Arc, } unsafe impl Send for Pcie {} @@ -142,25 +138,52 @@ impl Pcie { pub fn new(fallback: Arc) -> io::Result { let mcfg = Mcfg::fetch()?; + let alloc_maps = (0..=255) + .map(|bus| { + if let Some(alloc) = mcfg.at_bus(bus) { + Some(unsafe { Self::physmap_pcie_bus(alloc, bus) }) + } else { + None + } + }) + .collect(); + Ok(Self { lock: Mutex::new(()), - mcfg, - maps: Mutex::new(BTreeMap::new()), + bus_maps: alloc_maps, fallback, }) } - fn addr_offset_in_bytes(starting_bus: u8, address: PciAddress, offset: u16) -> usize { + + unsafe fn physmap_pcie_bus(alloc: &PcieAlloc, bus: u8) -> (*mut u32, usize) { + let base_phys = alloc.base_addr as usize + (((bus - alloc.start_bus) as usize) << 20); + let map_size = 1 << 20; + let ptr = common::physmap( + base_phys, + map_size, + common::Prot { + read: true, + write: true, + }, + common::MemoryType::Uncacheable, + ) + .unwrap_or_else(|error| { + panic!( + "failed to physmap pcie configuration space for segment {} bus {} @ {:p}: {:?}", + { alloc.seg_group_num }, + bus, + base_phys as *const u32, + error, + ) + }) as *mut u32; + (ptr, map_size) + } + + fn bus_addr_offset_in_bytes(address: PciAddress, offset: u16) -> usize { assert_eq!(offset & 0xFFFC, offset, "pcie offset not dword-aligned"); assert_eq!(offset & 0x0FFF, offset, "pcie offset larger than 4095"); - assert_eq!( - address.segment(), - 0, - "multiple segments not yet implemented" - ); - - (((address.bus() - starting_bus) as usize) << 20) - | ((address.device() as usize) << 15) + ((address.device() as usize) << 15) | ((address.function() as usize) << 12) | (offset as usize) } @@ -170,28 +193,20 @@ impl Pcie { offset: u16, f: F, ) -> T { - let (base_address_phys, starting_bus) = match self.mcfg.at_bus(address.bus()) { - Some(t) => (t.base_addr, t.start_bus), + assert_eq!( + address.segment(), + 0, + "multiple segments not yet implemented" + ); + + let bus_addr = match self.bus_maps[address.bus() as usize] { + Some(bus_addr) => bus_addr, None => return f(None), }; - let mut maps_lock = self.maps.lock().unwrap(); - let virt_pointer = maps_lock.entry(address).or_insert_with(|| { - common::physmap( - base_address_phys as usize + Self::addr_offset_in_bytes(starting_bus, address, 0), - PAGE_SIZE, - common::Prot { - read: true, - write: true, - }, - common::MemoryType::Uncacheable, - ) - .unwrap_or_else(|error| { - panic!( - "failed to physmap pcie configuration space for {}: {:?}", - address, error - ) - }) as *mut u32 - }); + let virt_pointer = unsafe { + // FIXME use byte_add once stable + (bus_addr.0 as *mut u8).add(Self::bus_addr_offset_in_bytes(address, 0)) as *mut u32 + }; f(Some(&mut *virt_pointer.offset( (offset as usize / mem::size_of::()) as isize, ))) @@ -222,8 +237,10 @@ impl CfgAccess for Pcie { impl Drop for Pcie { fn drop(&mut self) { - for address in self.maps.lock().unwrap().values().copied() { - let _ = unsafe { syscall::funmap(address as usize, PAGE_SIZE) }; + for &map in &self.bus_maps { + if let Some((ptr, size)) = map { + let _ = unsafe { syscall::funmap(ptr as usize, size) }; + } } } } From cf7fbacdaf6b89059f8e9421ef019e07cc5746d4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jan 2024 19:53:39 +0100 Subject: [PATCH 0768/1301] Stop leaking Mcfg again We don't need it after Pcie::new anymore --- pcid/src/pcie/mod.rs | 55 ++++++++++++++++++-------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index b8f4da6c0a..a5f41014ad 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -38,7 +38,7 @@ pub struct PcieAlloc { unsafe impl plain::Plain for PcieAlloc {} impl Mcfg { - fn fetch() -> io::Result<&'static Mcfg> { + fn with(f: impl FnOnce(&Mcfg) -> io::Result) -> io::Result { let table_dir = fs::read_dir("acpi:tables")?; for table_direntry in table_dir { @@ -53,24 +53,15 @@ impl Mcfg { let table_filename = table_path.file_name().unwrap().as_encoded_bytes(); if table_filename.get(0..4) == Some(&MCFG_NAME) { let bytes = fs::read(table_path)?.into_boxed_slice(); - if Mcfg::parse(&*bytes).is_none() { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "couldn't find mcfg table", - )); + match Mcfg::parse(&*bytes) { + Some(mcfg) => return f(mcfg), + None => { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "couldn't find mcfg table", + )); + } } - - // Leaking memory is fine as this function is only called once - // and we need this for the entire lifetime of pcid anyway. - let bytes = Box::leak(bytes); - - // This unwrap is fine as we checked that it will return Some above. - let mcfg = Mcfg::parse(bytes).unwrap(); - - // There should only be a single MCFG table and Linux ignores - // all MCFG tables beyond the first too, so doing an early - // return here is fine. - return Ok(mcfg); } } @@ -136,22 +127,22 @@ unsafe impl Sync for Pcie {} impl Pcie { pub fn new(fallback: Arc) -> io::Result { - let mcfg = Mcfg::fetch()?; + Mcfg::with(|mcfg| { + let alloc_maps = (0..=255) + .map(|bus| { + if let Some(alloc) = mcfg.at_bus(bus) { + Some(unsafe { Self::physmap_pcie_bus(alloc, bus) }) + } else { + None + } + }) + .collect(); - let alloc_maps = (0..=255) - .map(|bus| { - if let Some(alloc) = mcfg.at_bus(bus) { - Some(unsafe { Self::physmap_pcie_bus(alloc, bus) }) - } else { - None - } + Ok(Self { + lock: Mutex::new(()), + bus_maps: alloc_maps, + fallback, }) - .collect(); - - Ok(Self { - lock: Mutex::new(()), - bus_maps: alloc_maps, - fallback, }) } From 4f20b90fc3d3d79ab643b0812eac769d72e88dbd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 13:38:45 +0100 Subject: [PATCH 0769/1301] Remove PciBus and PciDev types They weren't used in a load bearing way. If we want to keep persistent state about buses and devices in the future they would probably get a different shape. --- pcid/src/main.rs | 12 ++++++------ pcid/src/pci/bus.rs | 40 ---------------------------------------- pcid/src/pci/dev.rs | 42 ------------------------------------------ pcid/src/pci/func.rs | 2 +- pcid/src/pci/mod.rs | 33 --------------------------------- 5 files changed, 7 insertions(+), 122 deletions(-) delete mode 100644 pcid/src/pci/bus.rs delete mode 100644 pcid/src/pci/dev.rs diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 83d7ef2ce7..65c3e1b4ad 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -10,7 +10,7 @@ use log::{debug, error, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; use crate::config::Config; -use crate::pci::{CfgAccess, Pci, PciAddress, PciBar, PciBus, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::{CfgAccess, Pci, PciAddress, PciBar, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; use crate::pcie::Pcie; @@ -592,10 +592,10 @@ fn main(args: Args) { let bus_num = bus_nums[bus_i]; bus_i += 1; - let bus = PciBus { num: bus_num }; - 'dev: for dev in bus.devs() { - for func in dev.funcs(pci) { - let func_addr = func.addr; + 'dev: for dev_num in 0..32 { + for func_num in 0..8 { + let func_addr = PciAddress::new(0, bus_num, dev_num, func_num); + let func = PciFunc { pci, addr: func_addr }; match PciHeader::from_reader(func) { Ok(header) => { handle_parsed_header(Arc::clone(&state), &config, func_addr, header); @@ -605,7 +605,7 @@ fn main(args: Args) { } Err(PciHeaderError::NoDevice) => { if func_addr.function() == 0 { - trace!("PCI {:>02X}/{:>02X}: no dev", bus.num, dev.num); + trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); continue 'dev; } }, diff --git a/pcid/src/pci/bus.rs b/pcid/src/pci/bus.rs deleted file mode 100644 index 9900d118d9..0000000000 --- a/pcid/src/pci/bus.rs +++ /dev/null @@ -1,40 +0,0 @@ -use super::PciDev; - -#[derive(Copy, Clone)] -pub struct PciBus { - pub num: u8, -} - -impl<'pci> PciBus { - pub fn devs(self) -> PciBusIter { - PciBusIter::new(self) - } -} - -pub struct PciBusIter { - bus: PciBus, - num: u8, -} - -impl PciBusIter { - pub fn new(bus: PciBus) -> Self { - PciBusIter { bus, num: 0 } - } -} - -impl Iterator for PciBusIter { - type Item = PciDev; - fn next(&mut self) -> Option { - match self.num { - dev_num if dev_num < 32 => { - let dev = PciDev { - bus: self.bus, - num: self.num, - }; - self.num += 1; - Some(dev) - } - _ => None, - } - } -} diff --git a/pcid/src/pci/dev.rs b/pcid/src/pci/dev.rs deleted file mode 100644 index b64eeb1034..0000000000 --- a/pcid/src/pci/dev.rs +++ /dev/null @@ -1,42 +0,0 @@ -use super::{CfgAccess, PciAddress, PciBus, PciFunc}; - -#[derive(Copy, Clone)] -pub struct PciDev { - pub bus: PciBus, - pub num: u8, -} - -impl<'pci> PciDev { - pub fn funcs(self, pci: &'pci dyn CfgAccess) -> PciDevIter<'pci> { - PciDevIter::new(self, pci) - } -} - -pub struct PciDevIter<'pci> { - pci: &'pci dyn CfgAccess, - dev: PciDev, - num: u8, -} - -impl<'pci> PciDevIter<'pci> { - pub fn new(dev: PciDev, pci: &'pci dyn CfgAccess) -> Self { - PciDevIter { pci, dev, num: 0 } - } -} - -impl<'pci> Iterator for PciDevIter<'pci> { - type Item = PciFunc<'pci>; - fn next(&mut self) -> Option { - match self.num { - func_num if func_num < 8 => { - let func = PciFunc { - pci: self.pci, - addr: PciAddress::new(0, self.dev.bus.num, self.dev.num, func_num), - }; - self.num += 1; - Some(func) - } - _ => None, - } - } -} diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index 6625542db9..d6c7e93b70 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -1,6 +1,6 @@ use byteorder::{ByteOrder, LittleEndian}; -use super::{CfgAccess, PciAddress, PciDev}; +use super::{CfgAccess, PciAddress}; pub trait ConfigReader { unsafe fn read_range(&self, offset: u16, len: u16) -> Vec { diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 84baf13f53..6fe191ea09 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -8,19 +8,15 @@ use serde::{Deserialize, Serialize}; use syscall::io::{Io as _, Pio}; pub use self::bar::PciBar; -pub use self::bus::{PciBus, PciBusIter}; pub use self::class::PciClass; -pub use self::dev::{PciDev, PciDevIter}; pub use self::func::PciFunc; pub use self::header::{PciHeader, PciHeaderError, PciHeaderType}; use log::info; mod bar; -mod bus; pub mod cap; mod class; -mod dev; pub mod func; pub mod header; pub mod msi; @@ -104,10 +100,6 @@ impl Pci { } } - pub fn buses<'pci>(&'pci self) -> PciIter<'pci> { - PciIter::new(self) - } - fn set_iopl() { // make sure that pcid is not granted io port permission unless pcie memory-mapped // configuration space is not available. @@ -176,28 +168,3 @@ impl CfgAccess for Pci { todo!("Pci::CfgAccess::write on this architecture") } } - -pub struct PciIter<'pci> { - pci: &'pci dyn CfgAccess, - num: Option, -} - -impl<'pci> PciIter<'pci> { - pub fn new(pci: &'pci dyn CfgAccess) -> Self { - PciIter { pci, num: Some(0) } - } -} - -impl<'pci> Iterator for PciIter<'pci> { - type Item = PciBus; - fn next(&mut self) -> Option { - match self.num { - Some(bus_num) => { - let bus = PciBus { num: bus_num }; - self.num = bus_num.checked_add(1); - Some(bus) - } - None => None, - } - } -} From 3cbfbf6442ce12feb8df7df3f55f12da8ae32a90 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 14:00:51 +0100 Subject: [PATCH 0770/1301] Move the IO port based fallback for PCI out of the pci module The pci module is included in the pcid_interface library, which never needs it. --- pcid/src/main.rs | 18 ++------ pcid/src/pci/mod.rs | 88 ------------------------------------- pcid/src/pcie/fallback.rs | 91 +++++++++++++++++++++++++++++++++++++++ pcid/src/pcie/mod.rs | 35 ++++++++++----- 4 files changed, 120 insertions(+), 112 deletions(-) create mode 100644 pcid/src/pcie/fallback.rs diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 65c3e1b4ad..0477d361a8 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -10,7 +10,7 @@ use log::{debug, error, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; use crate::config::Config; -use crate::pci::{CfgAccess, Pci, PciAddress, PciBar, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::{CfgAccess, PciAddress, PciBar, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; use crate::pcie::Pcie; @@ -206,12 +206,11 @@ impl DriverHandler { pub struct State { threads: Mutex>>, - pci: Arc, - pcie: Option, + pcie: Pcie, } impl State { fn preferred_cfg_access(&self) -> &dyn CfgAccess { - self.pcie.as_ref().map(|pcie| pcie as &dyn CfgAccess).unwrap_or(&*self.pci as &dyn CfgAccess) + &self.pcie } } @@ -565,17 +564,8 @@ fn main(args: Args) { let _logger_ref = setup_logging(args.verbose); - let pci = Arc::new(Pci::new()); - let state = Arc::new(State { - pci: Arc::clone(&pci), - pcie: match Pcie::new(Arc::clone(&pci)) { - Ok(pcie) => Some(pcie), - Err(error) => { - info!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error); - None - } - }, + pcie: Pcie::new(), threads: Mutex::new(Vec::new()), }); diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 6fe191ea09..6d39cbdb8f 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,19 +1,13 @@ -use std::convert::TryFrom; use std::fmt; -use std::sync::{Mutex, Once}; use bit_field::BitField; use serde::{Deserialize, Serialize}; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use syscall::io::{Io as _, Pio}; pub use self::bar::PciBar; pub use self::class::PciClass; pub use self::func::PciFunc; pub use self::header::{PciHeader, PciHeaderError, PciHeaderType}; -use log::info; - mod bar; pub mod cap; mod class; @@ -86,85 +80,3 @@ impl fmt::Debug for PciAddress { write!(f, "{}", self) } } - -pub struct Pci { - lock: Mutex<()>, - iopl_once: Once, -} - -impl Pci { - pub fn new() -> Self { - Self { - lock: Mutex::new(()), - iopl_once: Once::new(), - } - } - - fn set_iopl() { - // make sure that pcid is not granted io port permission unless pcie memory-mapped - // configuration space is not available. - info!("PCI: couldn't find or access PCIe extended configuration, and thus falling back to PCI 3.0 io ports"); - unsafe { - syscall::iopl(3).expect("pcid: failed to set iopl to 3"); - } - } - fn address(address: PciAddress, offset: u8) -> u32 { - // TODO: Find the part of pcid that uses an unaligned offset! - // - // assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); - // - let offset = offset & 0xFC; - - assert_eq!( - address.segment(), - 0, - "usage of multiple segments requires PCIe extended configuration" - ); - - 0x80000000 - | (u32::from(address.bus()) << 16) - | (u32::from(address.device()) << 11) - | (u32::from(address.function()) << 8) - | u32::from(offset) - } -} -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -impl CfgAccess for Pci { - unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { - let _guard = self.lock.lock().unwrap(); - - self.iopl_once.call_once(Self::set_iopl); - - let offset = - u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); - let address = Self::address(address, offset); - - Pio::::new(0xCF8).write(address); - Pio::::new(0xCFC).read() - } - - unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) { - let _guard = self.lock.lock().unwrap(); - - self.iopl_once.call_once(Self::set_iopl); - - let offset = - u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); - let address = Self::address(address, offset); - - Pio::::new(0xCF8).write(address); - Pio::::new(0xCFC).write(value); - } -} -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -impl CfgAccess for Pci { - unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { - let _guard = self.lock.lock().unwrap(); - todo!("Pci::CfgAccess::read on this architecture") - } - - unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32) { - let _guard = self.lock.lock().unwrap(); - todo!("Pci::CfgAccess::write on this architecture") - } -} diff --git a/pcid/src/pcie/fallback.rs b/pcid/src/pcie/fallback.rs new file mode 100644 index 0000000000..f9c874ee0a --- /dev/null +++ b/pcid/src/pcie/fallback.rs @@ -0,0 +1,91 @@ +use std::convert::TryFrom; +use std::sync::{Mutex, Once}; + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use syscall::io::{Io as _, Pio}; + +use log::info; + +use crate::pci::{CfgAccess, PciAddress}; + +pub(crate) struct Pci { + lock: Mutex<()>, + iopl_once: Once, +} + +impl Pci { + pub(crate) fn new() -> Self { + Self { + lock: Mutex::new(()), + iopl_once: Once::new(), + } + } + + fn set_iopl() { + // make sure that pcid is not granted io port permission unless pcie memory-mapped + // configuration space is not available. + info!("PCI: couldn't find or access PCIe extended configuration, and thus falling back to PCI 3.0 io ports"); + unsafe { + syscall::iopl(3).expect("pcid: failed to set iopl to 3"); + } + } + fn address(address: PciAddress, offset: u8) -> u32 { + // TODO: Find the part of pcid that uses an unaligned offset! + // + // assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); + // + let offset = offset & 0xFC; + + assert_eq!( + address.segment(), + 0, + "usage of multiple segments requires PCIe extended configuration" + ); + + 0x80000000 + | (u32::from(address.bus()) << 16) + | (u32::from(address.device()) << 11) + | (u32::from(address.function()) << 8) + | u32::from(offset) + } +} +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +impl CfgAccess for Pci { + unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { + let _guard = self.lock.lock().unwrap(); + + self.iopl_once.call_once(Self::set_iopl); + + let offset = + u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); + let address = Self::address(address, offset); + + Pio::::new(0xCF8).write(address); + Pio::::new(0xCFC).read() + } + + unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) { + let _guard = self.lock.lock().unwrap(); + + self.iopl_once.call_once(Self::set_iopl); + + let offset = + u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); + let address = Self::address(address, offset); + + Pio::::new(0xCF8).write(address); + Pio::::new(0xCFC).write(value); + } +} +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +impl CfgAccess for Pci { + unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { + let _guard = self.lock.lock().unwrap(); + todo!("Pci::CfgAccess::read on this architecture") + } + + unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32) { + let _guard = self.lock.lock().unwrap(); + todo!("Pci::CfgAccess::write on this architecture") + } +} diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index a5f41014ad..3efb019d93 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -1,7 +1,12 @@ -use std::sync::{Arc, Mutex}; +use std::sync::Mutex; use std::{fmt, fs, io, mem, ptr, slice}; -use crate::pci::{CfgAccess, Pci, PciAddress}; +use log::info; + +use crate::pci::{CfgAccess, PciAddress}; +use fallback::Pci; + +mod fallback; pub const MCFG_NAME: [u8; 4] = *b"MCFG"; @@ -120,14 +125,14 @@ impl fmt::Debug for Mcfg { pub struct Pcie { lock: Mutex<()>, bus_maps: Vec>, - fallback: Arc, + fallback: Pci, } unsafe impl Send for Pcie {} unsafe impl Sync for Pcie {} impl Pcie { - pub fn new(fallback: Arc) -> io::Result { - Mcfg::with(|mcfg| { + pub fn new() -> Self { + match Mcfg::with(|mcfg| { let alloc_maps = (0..=255) .map(|bus| { if let Some(alloc) = mcfg.at_bus(bus) { @@ -141,9 +146,19 @@ impl Pcie { Ok(Self { lock: Mutex::new(()), bus_maps: alloc_maps, - fallback, + fallback: Pci::new(), }) - }) + }) { + Ok(pcie) => pcie, + Err(error) => { + info!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error); + Self { + lock: Mutex::new(()), + bus_maps: vec![], + fallback: Pci::new(), + } + } + } } unsafe fn physmap_pcie_bus(alloc: &PcieAlloc, bus: u8) -> (*mut u32, usize) { @@ -190,9 +205,9 @@ impl Pcie { "multiple segments not yet implemented" ); - let bus_addr = match self.bus_maps[address.bus() as usize] { - Some(bus_addr) => bus_addr, - None => return f(None), + let bus_addr = match self.bus_maps.get(address.bus() as usize) { + Some(Some(bus_addr)) => bus_addr, + Some(None) | None => return f(None), }; let virt_pointer = unsafe { // FIXME use byte_add once stable From cb7dc2abd28ef48963cf9a99d38f2355a0ce9cca Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 14:17:51 +0100 Subject: [PATCH 0771/1301] Only set iopl for helper threads when actually necessary --- pcid/src/main.rs | 7 +++---- pcid/src/pcie/fallback.rs | 32 ++++++++++++++++++++++---------- pcid/src/pcie/mod.rs | 2 +- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 0477d361a8..9f552220f4 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -470,12 +470,11 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he state: Arc::clone(&state), capabilities, }; - thread::spawn(move || { - // RFLAGS are no longer kept in the relibc clone() implementation. - unsafe { syscall::iopl(3).expect("pcid: failed to set IOPL"); } - + let _handle = thread::spawn(move || { driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); }); + // FIXME this currently deadlocks as pcid doesn't daemonize + //state.threads.lock().unwrap().push(handle); match child.wait() { Ok(_status) => (), Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err), diff --git a/pcid/src/pcie/fallback.rs b/pcid/src/pcie/fallback.rs index f9c874ee0a..63f70eeb7a 100644 --- a/pcid/src/pcie/fallback.rs +++ b/pcid/src/pcie/fallback.rs @@ -1,5 +1,6 @@ +use std::cell::Cell; use std::convert::TryFrom; -use std::sync::{Mutex, Once}; +use std::sync::Mutex; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use syscall::io::{Io as _, Pio}; @@ -10,25 +11,36 @@ use crate::pci::{CfgAccess, PciAddress}; pub(crate) struct Pci { lock: Mutex<()>, - iopl_once: Once, } impl Pci { pub(crate) fn new() -> Self { Self { lock: Mutex::new(()), - iopl_once: Once::new(), } } fn set_iopl() { - // make sure that pcid is not granted io port permission unless pcie memory-mapped - // configuration space is not available. - info!("PCI: couldn't find or access PCIe extended configuration, and thus falling back to PCI 3.0 io ports"); - unsafe { - syscall::iopl(3).expect("pcid: failed to set iopl to 3"); + // The IO privilege level is per-thread, so we need to do the initialization on every thread. + thread_local! { + static IOPL_ONCE: Cell = Cell::new(false); } + + IOPL_ONCE.with(|iopl_once| { + if !iopl_once.replace(true) { + // make sure that pcid is not granted io port permission unless pcie memory-mapped + // configuration space is not available. + info!( + "PCI: couldn't find or access PCIe extended configuration, \ + and thus falling back to PCI 3.0 io ports" + ); + unsafe { + syscall::iopl(3).expect("pcid: failed to set iopl to 3"); + } + } + }); } + fn address(address: PciAddress, offset: u8) -> u32 { // TODO: Find the part of pcid that uses an unaligned offset! // @@ -54,7 +66,7 @@ impl CfgAccess for Pci { unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); - self.iopl_once.call_once(Self::set_iopl); + Self::set_iopl(); let offset = u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); @@ -67,7 +79,7 @@ impl CfgAccess for Pci { unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) { let _guard = self.lock.lock().unwrap(); - self.iopl_once.call_once(Self::set_iopl); + Self::set_iopl(); let offset = u8::try_from(offset).expect("offset too large for PCI 3.0 configuration space"); diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 3efb019d93..24dbee0d12 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -141,7 +141,7 @@ impl Pcie { None } }) - .collect(); + .collect::>(); Ok(Self { lock: Mutex::new(()), From 20eb92ae023ac9a4967cbecc392e603fb89176d1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 14:36:37 +0100 Subject: [PATCH 0772/1301] Assert PCI config space accesses are aligned --- pcid/src/pcie/fallback.rs | 8 ++------ pcid/src/pcie/mod.rs | 2 ++ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/pcid/src/pcie/fallback.rs b/pcid/src/pcie/fallback.rs index 63f70eeb7a..90023961f7 100644 --- a/pcid/src/pcie/fallback.rs +++ b/pcid/src/pcie/fallback.rs @@ -42,18 +42,14 @@ impl Pci { } fn address(address: PciAddress, offset: u8) -> u32 { - // TODO: Find the part of pcid that uses an unaligned offset! - // - // assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); - // - let offset = offset & 0xFC; - assert_eq!( address.segment(), 0, "usage of multiple segments requires PCIe extended configuration" ); + assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); + 0x80000000 | (u32::from(address.bus()) << 16) | (u32::from(address.device()) << 11) diff --git a/pcid/src/pcie/mod.rs b/pcid/src/pcie/mod.rs index 24dbee0d12..0925b21d03 100644 --- a/pcid/src/pcie/mod.rs +++ b/pcid/src/pcie/mod.rs @@ -205,6 +205,8 @@ impl Pcie { "multiple segments not yet implemented" ); + assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); + let bus_addr = match self.bus_maps.get(address.bus() as usize) { Some(Some(bus_addr)) => bus_addr, Some(None) | None => return f(None), From d832717bf9ab1a760b384063bbecf31b8eab81d2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 14:42:29 +0100 Subject: [PATCH 0773/1301] Remove a bit of dead code --- pcid/src/pci/cap.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 99fc3e09b2..5e852a528f 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -153,18 +153,6 @@ impl Capability { _ => None, } } - pub fn into_msi(self) -> Option { - match self { - Self::Msi(msi) => Some(msi), - _ => None, - } - } - pub fn into_msix(self) -> Option { - match self { - Self::MsiX(msix) => Some(msix), - _ => None, - } - } unsafe fn parse_msi(reader: &R, offset: u8) -> Self { Self::Msi(MsiCapability::parse(reader, offset)) } From 382047b14ed295159917705842a5578075e21ad8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 16:04:18 +0100 Subject: [PATCH 0774/1301] Rename the pcie module to cfg_access --- pcid/src/{pcie => cfg_access}/fallback.rs | 0 pcid/src/{pcie => cfg_access}/mod.rs | 0 pcid/src/main.rs | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) rename pcid/src/{pcie => cfg_access}/fallback.rs (100%) rename pcid/src/{pcie => cfg_access}/mod.rs (100%) diff --git a/pcid/src/pcie/fallback.rs b/pcid/src/cfg_access/fallback.rs similarity index 100% rename from pcid/src/pcie/fallback.rs rename to pcid/src/cfg_access/fallback.rs diff --git a/pcid/src/pcie/mod.rs b/pcid/src/cfg_access/mod.rs similarity index 100% rename from pcid/src/pcie/mod.rs rename to pcid/src/cfg_access/mod.rs diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 9f552220f4..5de73c48cc 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -9,16 +9,16 @@ use structopt::StructOpt; use log::{debug, error, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; +use crate::cfg_access::Pcie; use crate::config::Config; use crate::pci::{CfgAccess, PciAddress, PciBar, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; -use crate::pcie::Pcie; +mod cfg_access; mod config; mod driver_interface; mod pci; -mod pcie; #[derive(StructOpt)] #[structopt(about)] From de7677604e12c2fe0084479197339b53d5c4f496 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 17:59:38 +0100 Subject: [PATCH 0775/1301] Use hex instead of decimal in all config.toml This matches the way basically everyone prints PCI ids --- ac97d/config.toml | 4 ++-- bgad/config.toml | 12 ++++++------ e1000d/config.toml | 2 +- ihdad/config.toml | 4 ++-- ixgbed/config.toml | 2 +- rtl8139d/config.toml | 2 +- rtl8168d/config.toml | 2 +- vboxd/config.toml | 6 +++--- virtio-netd/config.toml | 6 +++--- xhcid/config.toml | 6 +++--- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/ac97d/config.toml b/ac97d/config.toml index 7bafbb4975..f7c662483f 100644 --- a/ac97d/config.toml +++ b/ac97d/config.toml @@ -1,5 +1,5 @@ [[drivers]] name = "AC97 Audio" -class = 4 -subclass = 1 +class = 0x04 +subclass = 0x01 command = ["ac97d", "$NAME", "$BAR0", "$BAR1", "$IRQ"] diff --git a/bgad/config.toml b/bgad/config.toml index 184aacc0d4..08bfa4ae81 100644 --- a/bgad/config.toml +++ b/bgad/config.toml @@ -1,13 +1,13 @@ [[drivers]] name = "QEMU Graphics Array" -class = 3 -vendor = 4660 -device = 4369 +class = 0x03 +vendor = 0x1234 +device = 0x1111 command = ["bgad", "$NAME", "$BAR0"] [[drivers]] name = "VirtualBox Graphics Array" -class = 3 -vendor = 33006 -device = 48879 +class = 0x03 +vendor = 0x80EE +device = 0xBEEF command = ["bgad", "$NAME", "$BAR0"] diff --git a/e1000d/config.toml b/e1000d/config.toml index 19d0b57f84..932e33bae8 100644 --- a/e1000d/config.toml +++ b/e1000d/config.toml @@ -1,5 +1,5 @@ [[drivers]] name = "E1000 NIC" -class = 2 +class = 0x02 ids = { 0x8086 = [0x1004, 0x100e, 0x100f, 0x1503] } command = ["e1000d", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ"] diff --git a/ihdad/config.toml b/ihdad/config.toml index b4d8a132d7..f19df27a2c 100644 --- a/ihdad/config.toml +++ b/ihdad/config.toml @@ -1,6 +1,6 @@ [[drivers]] name = "Intel HD Audio" -class = 4 -subclass = 3 +class = 0x04 +subclass = 0x03 command = ["ihdad"] use_channel = true diff --git a/ixgbed/config.toml b/ixgbed/config.toml index db2d47838a..f0921b6008 100644 --- a/ixgbed/config.toml +++ b/ixgbed/config.toml @@ -1,6 +1,6 @@ [[drivers]] name = "Intel 10G NIC" -class = 2 +class = 0x02 ids = { 0x8086 = [0x10F7, 0x1514, 0x1517, 0x151C, 0x10F9, 0x10FB, 0x152a, 0x1529, 0x1507, 0x154D, 0x1557, 0x10FC, 0x10F8, 0x154F, 0x1528, 0x154A, 0x1558, 0x1560, 0x1563, 0x15D1, 0x15AA, 0x15AB, 0x15AC, 0x15AD, 0x15AE, 0x15B0, 0x15C2, 0x15C3, 0x15C4, 0x15C6, 0x15C7, 0x15C8, 0x15CE, 0x15E4, 0x15E5, 0x10ED, 0x1515, 0x1565, 0x15A8, 0x15C5] } command = ["ixgbed", "$NAME", "$BAR0", "$IRQ"] diff --git a/rtl8139d/config.toml b/rtl8139d/config.toml index 92e19426e9..1688b9ce95 100644 --- a/rtl8139d/config.toml +++ b/rtl8139d/config.toml @@ -1,6 +1,6 @@ [[drivers]] name = "RTL8139 NIC" -class = 2 +class = 0x02 ids = { 0x10ec = [0x8139] } command = ["rtl8139d"] use_channel = true diff --git a/rtl8168d/config.toml b/rtl8168d/config.toml index 6fdb0e7b30..d1ddbefe5c 100644 --- a/rtl8168d/config.toml +++ b/rtl8168d/config.toml @@ -1,6 +1,6 @@ [[drivers]] name = "RTL8168 NIC" -class = 2 +class = 0x02 ids = { 0x10ec = [0x8168, 0x8169] } command = ["rtl8168d"] use_channel = true diff --git a/vboxd/config.toml b/vboxd/config.toml index c97272fb3d..d05651231a 100644 --- a/vboxd/config.toml +++ b/vboxd/config.toml @@ -1,6 +1,6 @@ [[drivers]] name = "VirtualBox Guest Device" -class = 8 -vendor = 33006 -device = 51966 +class = 0x08 +vendor = 0x80EE +device = 0xCAFE command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] diff --git a/virtio-netd/config.toml b/virtio-netd/config.toml index 93949ce905..9e70971f42 100644 --- a/virtio-netd/config.toml +++ b/virtio-netd/config.toml @@ -1,7 +1,7 @@ [[drivers]] name = "virtio-net" -class = 2 -vendor = 6900 -device = 4096 +class = 0x02 +vendor = 0x1AF4 +device = 0x1000 command = ["virtio-netd"] use_channel = true diff --git a/xhcid/config.toml b/xhcid/config.toml index b80bae57a4..80e781c52a 100644 --- a/xhcid/config.toml +++ b/xhcid/config.toml @@ -1,7 +1,7 @@ [[drivers]] name = "XHCI" -class = 12 -subclass = 3 -interface = 48 +class = 0x0C +subclass = 0x03 +interface = 0x30 command = ["xhcid"] use_channel = true From 558f11b3eb2f9dd88091e0c92a2402747f6426d9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 18:34:40 +0100 Subject: [PATCH 0776/1301] Migrate bgad to pcid_interface --- Cargo.lock | 1 + bgad/Cargo.toml | 2 ++ bgad/config.toml | 6 ++++-- bgad/src/main.rs | 34 ++++++++++++++++++++-------------- 4 files changed, 27 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a75774a6d9..afafaffb65 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -166,6 +166,7 @@ name = "bgad" version = "0.1.0" dependencies = [ "orbclient", + "pcid", "redox-daemon", "redox_syscall 0.4.1", ] diff --git a/bgad/Cargo.toml b/bgad/Cargo.toml index 6ae79cdb86..596bf0f54d 100644 --- a/bgad/Cargo.toml +++ b/bgad/Cargo.toml @@ -7,3 +7,5 @@ edition = "2018" orbclient = "0.3.27" redox-daemon = "0.1" redox_syscall = "0.4" + +pcid = { path = "../pcid" } diff --git a/bgad/config.toml b/bgad/config.toml index 08bfa4ae81..7660b1215a 100644 --- a/bgad/config.toml +++ b/bgad/config.toml @@ -3,11 +3,13 @@ name = "QEMU Graphics Array" class = 0x03 vendor = 0x1234 device = 0x1111 -command = ["bgad", "$NAME", "$BAR0"] +command = ["bgad"] +use_channel = true [[drivers]] name = "VirtualBox Graphics Array" class = 0x03 vendor = 0x80EE device = 0xBEEF -command = ["bgad", "$NAME", "$BAR0"] +command = ["bgad"] +use_channel = true diff --git a/bgad/src/main.rs b/bgad/src/main.rs index cc7570efab..e9b7bb7600 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -1,12 +1,10 @@ -#![deny(warnings)] - extern crate orbclient; extern crate syscall; -use std::env; use std::fs::File; use std::io::{Read, Write}; +use pcid_interface::PcidServerHandle; use syscall::call::iopl; use syscall::data::Packet; use syscall::scheme::SchemeMut; @@ -18,15 +16,16 @@ mod bga; mod scheme; fn main() { - let mut args = env::args().skip(1); + let mut pcid_handle = + PcidServerHandle::connect_default().expect("bgad: failed to setup channel to pcid"); + let pci_config = pcid_handle + .fetch_config() + .expect("bgad: failed to fetch config"); - let mut name = args.next().expect("bgad: no name provided"); + let mut name = pci_config.func.name(); name.push_str("_bga"); - let bar_str = args.next().expect("bgad: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("bgad: failed to parse address"); - - print!("{}", format!(" + BGA {} on: {:X}\n", name, bar)); + println!(" + BGA {}", name); redox_daemon::Daemon::new(move |daemon| { unsafe { iopl(3).unwrap() }; @@ -34,11 +33,11 @@ fn main() { let mut socket = File::create(":bga").expect("bgad: failed to create bga scheme"); let mut bga = Bga::new(); - print!("{}", format!(" - BGA {}x{}\n", bga.width(), bga.height())); + println!(" - BGA {}x{}", bga.width(), bga.height()); let mut scheme = BgaScheme { bga, - display: File::open("input:producer").ok() + display: File::open("input:producer").ok(), }; scheme.update_size(); @@ -49,12 +48,19 @@ fn main() { loop { let mut packet = Packet::default(); - if socket.read(&mut packet).expect("bgad: failed to read events from bga scheme") == 0 { + if socket + .read(&mut packet) + .expect("bgad: failed to read events from bga scheme") + == 0 + { break; } scheme.handle(&mut packet); - socket.write(&packet).expect("bgad: failed to write responses to bga scheme"); + socket + .write(&packet) + .expect("bgad: failed to write responses to bga scheme"); } std::process::exit(0); - }).expect("bgad: failed to daemonize"); + }) + .expect("bgad: failed to daemonize"); } From f9f3407f362b7936f1080a63977c79c00d4732a6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 18:51:29 +0100 Subject: [PATCH 0777/1301] Migrate ahacid to pcid_interface --- ahcid/Cargo.toml | 1 + ahcid/src/main.rs | 29 +++++++++++++++++------------ initfs.toml | 3 ++- 3 files changed, 20 insertions(+), 13 deletions(-) diff --git a/ahcid/Cargo.toml b/ahcid/Cargo.toml index 2741d9d05f..cb5637dd69 100644 --- a/ahcid/Cargo.toml +++ b/ahcid/Cargo.toml @@ -14,3 +14,4 @@ redox_syscall = "0.4" block-io-wrapper = { path = "../block-io-wrapper" } common = { path = "../common" } +pcid = { path = "../pcid" } diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 1e5d44b4bf..4636495228 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -9,6 +9,7 @@ use std::fs::File; use std::io::{ErrorKind, Read, Write}; use std::os::unix::io::{FromRawFd, RawFd}; +use pcid_interface::{PciBar, PcidServerHandle}; use syscall::error::{Error, ENODEV}; use syscall::data::{Event, Packet}; use syscall::flag::EVENT_READ; @@ -71,28 +72,32 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let mut args = env::args().skip(1); + let mut pcid_handle = + PcidServerHandle::connect_default().expect("ahcid: failed to setup channel to pcid"); + let pci_config = pcid_handle + .fetch_config() + .expect("ahcid: failed to fetch config"); - let mut name = args.next().expect("ahcid: no name provided"); + let mut name = pci_config.func.name(); name.push_str("_ahci"); - let bar_str = args.next().expect("ahcid: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("ahcid: failed to parse address"); + let bar = pci_config.func.bars[5]; + let bar_size = pci_config.func.bar_sizes[5]; - let bar_size_str = args.next().expect("ahcid: no address size provided"); - let bar_size = usize::from_str_radix(&bar_size_str, 16).expect("ahcid: failed to parse address size"); - - let irq_str = args.next().expect("ahcid: no irq provided"); - let irq = irq_str.parse::().expect("ahcid: failed to parse irq"); + let irq = pci_config.func.legacy_interrupt_line; let _logger_ref = setup_logging(&name); - info!(" + AHCI {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); + info!(" + AHCI {} on: {} size: {} IRQ: {}", name, bar, bar_size, irq); let address = unsafe { common::physmap( - bar, - bar_size, + match bar { + PciBar::Memory32(addr) => addr as usize, + PciBar::Memory64(addr) => addr as usize, + PciBar::None | PciBar::Port(_) => unreachable!(), + }, + bar_size as usize, common::Prot { read: true, write: true }, common::MemoryType::Uncacheable, ).expect("ahcid: failed to map address") diff --git a/initfs.toml b/initfs.toml index d648d466ad..0fc44e16e4 100644 --- a/initfs.toml +++ b/initfs.toml @@ -5,7 +5,8 @@ name = "AHCI storage" class = 1 subclass = 6 -command = ["ahcid", "$NAME", "$BAR5", "$BARSIZE5", "$IRQ"] +command = ["ahcid"] +use_channel = true # ided [[drivers]] From d950e331848dbed227d3e2679f3954468eedef8e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 18:58:09 +0100 Subject: [PATCH 0778/1301] Migrate ac97d to pcid_interface --- Cargo.lock | 2 ++ ac97d/Cargo.toml | 2 ++ ac97d/config.toml | 3 ++- ac97d/src/main.rs | 30 +++++++++++++++++++----------- 4 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index afafaffb65..28bca81fc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,6 +9,7 @@ dependencies = [ "bitflags 1.3.2", "common", "log", + "pcid", "redox-daemon", "redox-log", "redox_event 0.1.0", @@ -46,6 +47,7 @@ dependencies = [ "common", "log", "partitionlib", + "pcid", "redox-daemon", "redox-log", "redox_syscall 0.4.1", diff --git a/ac97d/Cargo.toml b/ac97d/Cargo.toml index 784990155a..6a8c4a477f 100644 --- a/ac97d/Cargo.toml +++ b/ac97d/Cargo.toml @@ -12,3 +12,5 @@ redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" spin = "0.9" + +pcid = { path = "../pcid" } diff --git a/ac97d/config.toml b/ac97d/config.toml index f7c662483f..efc85ac560 100644 --- a/ac97d/config.toml +++ b/ac97d/config.toml @@ -2,4 +2,5 @@ name = "AC97 Audio" class = 0x04 subclass = 0x01 -command = ["ac97d", "$NAME", "$BAR0", "$BAR1", "$IRQ"] +command = ["ac97d"] +use_channel = true diff --git a/ac97d/src/main.rs b/ac97d/src/main.rs index 6c65e75ad5..a1e6760070 100644 --- a/ac97d/src/main.rs +++ b/ac97d/src/main.rs @@ -5,16 +5,17 @@ extern crate spin; extern crate syscall; extern crate event; -use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; +use std::usize; use event::EventQueue; +use pcid_interface::{PciBar, PcidServerHandle}; use redox_log::{OutputBuilder, RedoxLogger}; +use syscall::{EventFlags, Packet, SchemeBlockMut}; pub mod device; @@ -63,26 +64,33 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } fn main() { - let mut args = env::args().skip(1); + let mut pcid_handle = + PcidServerHandle::connect_default().expect("ac97d: failed to setup channel to pcid"); + let pci_config = pcid_handle + .fetch_config() + .expect("ac97d: failed to fetch config"); - let mut name = args.next().expect("ac97: no name provided"); + let mut name = pci_config.func.name(); name.push_str("_ac97"); - let bar0_str = args.next().expect("ac97: no address provided"); - let bar0 = u16::from_str_radix(&bar0_str, 16).expect("ac97: failed to parse address"); + let bar0 = match pci_config.func.bars[0] { + PciBar::Port(port) => port, + _ => unreachable!(), + }; - let bar1_str = args.next().expect("ac97: no address provided"); - let bar1 = u16::from_str_radix(&bar1_str, 16).expect("ac97: failed to parse address"); + let bar1 = match pci_config.func.bars[1] { + PciBar::Port(port) => port, + _ => unreachable!(), + }; - let irq_str = args.next().expect("ac97: no irq provided"); - let irq = irq_str.parse::().expect("ac97: failed to parse irq"); + let irq = pci_config.func.legacy_interrupt_line; print!("{}", format!(" + ac97 {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1, irq)); // Daemonize redox_daemon::Daemon::new(move |daemon| { let _logger_ref = setup_logging(); - + unsafe { syscall::iopl(3) }.expect("ac97d: failed to set I/O privilege level to Ring 3"); let mut irq_file = File::open(format!("irq:{}", irq)).expect("ac97d: failed to open IRQ file"); From 075e28339f44060e041e7e4d11f9806ca075de9a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 19:04:15 +0100 Subject: [PATCH 0779/1301] Migrate e1000d to pcid_interface --- Cargo.lock | 1 + e1000d/Cargo.toml | 1 + e1000d/config.toml | 3 ++- e1000d/src/main.rs | 25 +++++++++++++++---------- 4 files changed, 19 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28bca81fc7..b539e5d1d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -379,6 +379,7 @@ dependencies = [ "bitflags 1.3.2", "common", "netutils", + "pcid", "redox-daemon", "redox_event 0.1.0", "redox_syscall 0.4.1", diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index bc1bc8b47e..90b9367de0 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -11,3 +11,4 @@ redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" common = { path = "../common" } +pcid = { path = "../pcid" } diff --git a/e1000d/config.toml b/e1000d/config.toml index 932e33bae8..5ab5ad0bd5 100644 --- a/e1000d/config.toml +++ b/e1000d/config.toml @@ -2,4 +2,5 @@ name = "E1000 NIC" class = 0x02 ids = { 0x8086 = [0x1004, 0x100e, 0x100f, 0x1503] } -command = ["e1000d", "$NAME", "$BAR0", "$BARSIZE0", "$IRQ"] +command = ["e1000d"] +use_channel = true diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 2e2a617c8f..328c7d0d3c 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -3,13 +3,14 @@ extern crate netutils; extern crate syscall; use std::cell::RefCell; -use std::{env, process}; use std::fs::File; use std::io::{ErrorKind, Read, Result, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::process; use std::sync::Arc; use event::EventQueue; +use pcid_interface::{PciBar, PcidServerHandle}; use syscall::{EventFlags, Packet, SchemeBlockMut}; pub mod device; @@ -58,19 +59,23 @@ fn handle_update( } fn main() { - let mut args = env::args().skip(1); + let mut pcid_handle = + PcidServerHandle::connect_default().expect("e1000d: failed to setup channel to pcid"); + let pci_config = pcid_handle + .fetch_config() + .expect("e1000d: failed to fetch config"); - let mut name = args.next().expect("e1000d: no name provided"); + let mut name = pci_config.func.name(); name.push_str("_e1000"); - let bar_str = args.next().expect("e1000d: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("e1000d: failed to parse address"); + let bar = match pci_config.func.bars[0] { + PciBar::Memory32(addr) => addr as usize, + PciBar::Memory64(addr) => addr as usize, + PciBar::None | PciBar::Port(_) => unreachable!(), + }; + let bar_size = pci_config.func.bar_sizes[0] as usize; - let bar_size_str = args.next().expect("e1000d: no address size provided"); - let bar_size = usize::from_str_radix(&bar_size_str, 16).expect("e1000d: failed to parse address size"); - - let irq_str = args.next().expect("e1000d: no irq provided"); - let irq = irq_str.parse::().expect("e1000d: failed to parse irq"); + let irq = pci_config.func.legacy_interrupt_line; eprintln!(" + E1000 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); From 878a02f29fbefad662b0837e5a2fbeb2cd9b9e19 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 19:13:27 +0100 Subject: [PATCH 0780/1301] Migrate ixgbed to pcid_interface (untested) --- Cargo.lock | 1 + ixgbed/Cargo.toml | 2 ++ ixgbed/config.toml | 4 ++-- ixgbed/src/device.rs | 2 +- ixgbed/src/main.rs | 21 ++++++++++++++------- 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b539e5d1d3..d497dd3898 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -665,6 +665,7 @@ dependencies = [ "bitflags 1.3.2", "common", "netutils", + "pcid", "redox-daemon", "redox_event 0.1.0", "redox_syscall 0.4.1", diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml index 94d0af3ed1..1760a676bc 100644 --- a/ixgbed/Cargo.toml +++ b/ixgbed/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "ixgbed" version = "1.0.0" +edition = "2021" [dependencies] bitflags = "1.0" @@ -10,3 +11,4 @@ redox_syscall = "0.4" redox-daemon = "0.1" common = { path = "../common" } +pcid = { path = "../pcid" } diff --git a/ixgbed/config.toml b/ixgbed/config.toml index f0921b6008..67577f22d9 100644 --- a/ixgbed/config.toml +++ b/ixgbed/config.toml @@ -2,5 +2,5 @@ name = "Intel 10G NIC" class = 0x02 ids = { 0x8086 = [0x10F7, 0x1514, 0x1517, 0x151C, 0x10F9, 0x10FB, 0x152a, 0x1529, 0x1507, 0x154D, 0x1557, 0x10FC, 0x10F8, 0x154F, 0x1528, 0x154A, 0x1558, 0x1560, 0x1563, 0x15D1, 0x15AA, 0x15AB, 0x15AC, 0x15AD, 0x15AE, 0x15B0, 0x15C2, 0x15C3, 0x15C4, 0x15C6, 0x15C7, 0x15C8, 0x15CE, 0x15E4, 0x15E5, 0x10ED, 0x1515, 0x1565, 0x15A8, 0x15C5] } -command = ["ixgbed", "$NAME", "$BAR0", "$IRQ"] - +command = ["ixgbed"] +use_channel = true diff --git a/ixgbed/src/device.rs b/ixgbed/src/device.rs index 2803ccca5f..9d0f59abd4 100644 --- a/ixgbed/src/device.rs +++ b/ixgbed/src/device.rs @@ -10,7 +10,7 @@ use syscall::scheme::SchemeBlockMut; use common::dma::Dma; use netutils::setcfg; -use ixgbe::*; +use crate::ixgbe::*; pub struct Intel8259x { base: usize, diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index b192450af0..b60cfb9982 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -10,9 +10,10 @@ use std::fs::File; use std::io::{ErrorKind, Read, Result, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; -use std::{env, thread}; +use std::thread; use event::EventQueue; +use pcid_interface::{PciBar, PcidServerHandle}; use std::time::Duration; use syscall::{EventFlags, Packet, SchemeBlockMut}; @@ -66,16 +67,22 @@ fn handle_update( } fn main() { - let mut args = env::args().skip(1); + let mut pcid_handle = + PcidServerHandle::connect_default().expect("ixgbed: failed to setup channel to pcid"); + let pci_config = pcid_handle + .fetch_config() + .expect("ixgbed: failed to fetch config"); - let mut name = args.next().expect("ixgbed: no name provided"); + let mut name = pci_config.func.name(); name.push_str("_ixgbe"); - let bar_str = args.next().expect("ixgbed: no address provided"); - let bar = usize::from_str_radix(&bar_str, 16).expect("ixgbed: failed to parse address"); + let bar = match pci_config.func.bars[0] { + PciBar::Memory32(addr) => addr as usize, + PciBar::Memory64(addr) => addr as usize, + PciBar::None | PciBar::Port(_) => unreachable!(), + }; - let irq_str = args.next().expect("ixgbed: no irq provided"); - let irq = irq_str.parse::().expect("ixgbed: failed to parse irq"); + let irq = pci_config.func.legacy_interrupt_line; println!(" + IXGBE {} on: {:X} IRQ: {}", name, bar, irq); From 3b4d0e858fdae18668d550473a492f9400d9f648 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 19:26:46 +0100 Subject: [PATCH 0781/1301] Migrate vboxd to pcid_interface (untested) --- Cargo.lock | 1 + vboxd/Cargo.toml | 1 + vboxd/config.toml | 3 ++- vboxd/src/main.rs | 27 ++++++++++++++++++--------- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d497dd3898..5364d127f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1667,6 +1667,7 @@ version = "0.1.0" dependencies = [ "common", "orbclient", + "pcid", "redox-daemon", "redox_event 0.1.0", "redox_syscall 0.4.1", diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index b27804da77..23a4273c2a 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -10,3 +10,4 @@ redox_syscall = "0.4" redox-daemon = "0.1" common = { path = "../common" } +pcid = { path = "../pcid" } diff --git a/vboxd/config.toml b/vboxd/config.toml index d05651231a..d41fca4576 100644 --- a/vboxd/config.toml +++ b/vboxd/config.toml @@ -3,4 +3,5 @@ name = "VirtualBox Guest Device" class = 0x08 vendor = 0x80EE device = 0xCAFE -command = ["vboxd", "$NAME", "$BAR0", "$BAR1", "$IRQ"] +command = ["vboxd"] +use_channel = true diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 845464d5e4..555b5eb675 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -5,11 +5,12 @@ extern crate orbclient; extern crate syscall; use event::EventQueue; -use std::{env, mem}; +use std::mem; use std::os::unix::io::AsRawFd; use std::fs::File; use std::io::{Result, Read, Write}; +use pcid_interface::{PciBar, PcidServerHandle}; use syscall::call::iopl; use syscall::flag::EventFlags; use syscall::io::{Io, Mmio, Pio}; @@ -184,19 +185,27 @@ impl VboxGuestInfo { } fn main() { - let mut args = env::args().skip(1); + let mut pcid_handle = + PcidServerHandle::connect_default().expect("vboxd: failed to setup channel to pcid"); + let pci_config = pcid_handle + .fetch_config() + .expect("vboxd: failed to fetch config"); - let mut name = args.next().expect("vboxd: no name provided"); + let mut name = pci_config.func.name(); name.push_str("_vbox"); - let bar0_str = args.next().expect("vboxd: no address provided"); - let bar0 = usize::from_str_radix(&bar0_str, 16).expect("vboxd: failed to parse address"); + let bar0 = match pci_config.func.bars[0] { + PciBar::Port(port) => port, + _ => unreachable!(), + }; - let bar1_str = args.next().expect("vboxd: no address provided"); - let bar1 = usize::from_str_radix(&bar1_str, 16).expect("vboxd: failed to parse address"); + let bar1 = match pci_config.func.bars[1] { + PciBar::Memory32(addr) => addr as usize, + PciBar::Memory64(addr) => addr as usize, + PciBar::None | PciBar::Port(_) => unreachable!(), + }; - let irq_str = args.next().expect("vboxd: no irq provided"); - let irq = irq_str.parse::().expect("vboxd: failed to parse irq"); + let irq = pci_config.func.legacy_interrupt_line; print!("{}", format!(" + VirtualBox {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1, irq)); From dc13752d74090d1de405f21bbf41dc5caa55d5a6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jan 2024 19:42:06 +0100 Subject: [PATCH 0782/1301] Force usage of pcid_interface --- ac97d/config.toml | 1 - ahcid/src/main.rs | 14 +++++------ bgad/config.toml | 2 -- e1000d/config.toml | 1 - ihdad/config.toml | 1 - ihdad/src/main.rs | 2 +- initfs.toml | 5 ---- ixgbed/config.toml | 1 - pcid/src/config.rs | 1 - pcid/src/main.rs | 51 +++++++++++++---------------------------- pcid/src/pci/bar.rs | 13 ----------- rtl8139d/config.toml | 1 - rtl8139d/src/main.rs | 4 ++-- rtl8168d/config.toml | 1 - rtl8168d/src/main.rs | 4 ++-- vboxd/config.toml | 1 - virtio-netd/config.toml | 1 - xhcid/src/main.rs | 6 ++--- 18 files changed, 31 insertions(+), 79 deletions(-) diff --git a/ac97d/config.toml b/ac97d/config.toml index efc85ac560..106ce703a3 100644 --- a/ac97d/config.toml +++ b/ac97d/config.toml @@ -3,4 +3,3 @@ name = "AC97 Audio" class = 0x04 subclass = 0x01 command = ["ac97d"] -use_channel = true diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 4636495228..f41f397e73 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -4,10 +4,10 @@ extern crate syscall; extern crate byteorder; -use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write}; use std::os::unix::io::{FromRawFd, RawFd}; +use std::usize; use pcid_interface::{PciBar, PcidServerHandle}; use syscall::error::{Error, ENODEV}; @@ -81,7 +81,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_ahci"); - let bar = pci_config.func.bars[5]; + let bar = match pci_config.func.bars[5] { + PciBar::Memory32(addr) => addr as usize, + PciBar::Memory64(addr) => addr as usize, + PciBar::None | PciBar::Port(_) => unreachable!(), + }; let bar_size = pci_config.func.bar_sizes[5]; let irq = pci_config.func.legacy_interrupt_line; @@ -92,11 +96,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { common::physmap( - match bar { - PciBar::Memory32(addr) => addr as usize, - PciBar::Memory64(addr) => addr as usize, - PciBar::None | PciBar::Port(_) => unreachable!(), - }, + bar, bar_size as usize, common::Prot { read: true, write: true }, common::MemoryType::Uncacheable, diff --git a/bgad/config.toml b/bgad/config.toml index 7660b1215a..a07ff05bbc 100644 --- a/bgad/config.toml +++ b/bgad/config.toml @@ -4,7 +4,6 @@ class = 0x03 vendor = 0x1234 device = 0x1111 command = ["bgad"] -use_channel = true [[drivers]] name = "VirtualBox Graphics Array" @@ -12,4 +11,3 @@ class = 0x03 vendor = 0x80EE device = 0xBEEF command = ["bgad"] -use_channel = true diff --git a/e1000d/config.toml b/e1000d/config.toml index 5ab5ad0bd5..44ce84dd09 100644 --- a/e1000d/config.toml +++ b/e1000d/config.toml @@ -3,4 +3,3 @@ name = "E1000 NIC" class = 0x02 ids = { 0x8086 = [0x1004, 0x100e, 0x100f, 0x1503] } command = ["e1000d"] -use_channel = true diff --git a/ihdad/config.toml b/ihdad/config.toml index f19df27a2c..8be0418577 100644 --- a/ihdad/config.toml +++ b/ihdad/config.toml @@ -3,4 +3,3 @@ name = "Intel HD Audio" class = 0x04 subclass = 0x03 command = ["ihdad"] -use_channel = true diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 789b0be20e..d91013cc47 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -171,7 +171,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { 0 => panic!("BAR 0 is mapped to address 0"), _ => ptr, }, - other => panic!("Expected memory bar, found {}", other), + other => panic!("Expected memory bar, found {:?}", other), }; log::info!(" + IHDA {} on: {:#X} size: {}", name, bar_ptr, bar_size); diff --git a/initfs.toml b/initfs.toml index 0fc44e16e4..62479eaee7 100644 --- a/initfs.toml +++ b/initfs.toml @@ -6,7 +6,6 @@ name = "AHCI storage" class = 1 subclass = 6 command = ["ahcid"] -use_channel = true # ided [[drivers]] @@ -14,7 +13,6 @@ name = "IDE storage" class = 1 subclass = 1 command = ["ided"] -use_channel = true # nvmed [[drivers]] @@ -22,7 +20,6 @@ name = "NVME storage" class = 1 subclass = 8 command = ["nvmed"] -use_channel = true [[drivers]] name = "virtio-blk" @@ -31,7 +28,6 @@ subclass = 0 vendor = 6900 device = 4097 command = ["virtio-blkd"] -use_channel = true [[drivers]] name = "virtio-gpu" @@ -39,4 +35,3 @@ class = 3 vendor = 6900 device = 4176 command = ["virtio-gpud"] -use_channel = true diff --git a/ixgbed/config.toml b/ixgbed/config.toml index 67577f22d9..a10fba5a8f 100644 --- a/ixgbed/config.toml +++ b/ixgbed/config.toml @@ -3,4 +3,3 @@ name = "Intel 10G NIC" class = 0x02 ids = { 0x8086 = [0x10F7, 0x1514, 0x1517, 0x151C, 0x10F9, 0x10FB, 0x152a, 0x1529, 0x1507, 0x154D, 0x1557, 0x10FC, 0x10F8, 0x154F, 0x1528, 0x154A, 0x1558, 0x1560, 0x1563, 0x15D1, 0x15AA, 0x15AB, 0x15AC, 0x15AD, 0x15AE, 0x15B0, 0x15C2, 0x15C3, 0x15C4, 0x15C6, 0x15C7, 0x15C8, 0x15CE, 0x15E4, 0x15E5, 0x10ED, 0x1515, 0x1565, 0x15A8, 0x15C5] } command = ["ixgbed"] -use_channel = true diff --git a/pcid/src/config.rs b/pcid/src/config.rs index c74f05842a..83faddd586 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -19,5 +19,4 @@ pub struct DriverConfig { pub device: Option, pub device_id_range: Option>, pub command: Option>, - pub use_channel: Option, } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 5de73c48cc..e579a6d4ab 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -189,17 +189,15 @@ impl DriverHandler { } } } - fn handle_spawn(mut self, pcid_to_client_write: Option, pcid_from_client_read: Option, args: driver_interface::SubdriverArguments) { + fn handle_spawn(mut self, pcid_to_client_write: usize, pcid_from_client_read: usize, args: driver_interface::SubdriverArguments) { use driver_interface::*; - if let (Some(pcid_to_client_fd), Some(pcid_from_client_fd)) = (pcid_to_client_write, pcid_from_client_read) { - let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd as RawFd) }; - let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd as RawFd) }; + let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_write as RawFd) }; + let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_read as RawFd) }; while let Ok(msg) = recv(&mut pcid_from_client) { let response = self.respond(msg, &args); send(&mut pcid_to_client, &response).unwrap(); - } } } } @@ -256,8 +254,11 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he } for (i, bar) in header.bars().iter().enumerate() { - if !bar.is_none() { - string.push_str(&format!(" {}={}", i, bar)); + match bar { + PciBar::None => {}, + PciBar::Memory32(addr) => string.push_str(&format!(" {i}={addr:08X}")), + PciBar::Memory64(addr) => string.push_str(&format!(" {i}={addr:016X}")), + PciBar::Port(port) => string.push_str(&format!(" {i}=P{port:04X}")), } } @@ -411,34 +412,14 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he if let Some(program) = args.next() { let mut command = Command::new(program); for arg in args { - let arg = match arg.as_str() { - "$BUS" => format!("{:>02X}", addr.bus()), - "$DEV" => format!("{:>02X}", addr.device()), - "$FUNC" => format!("{:>02X}", addr.function()), - "$NAME" => func.name(), - "$BAR0" => format!("{}", bars[0]), - "$BAR1" => format!("{}", bars[1]), - "$BAR2" => format!("{}", bars[2]), - "$BAR3" => format!("{}", bars[3]), - "$BAR4" => format!("{}", bars[4]), - "$BAR5" => format!("{}", bars[5]), - "$BARSIZE0" => format!("{:>08X}", bar_sizes[0]), - "$BARSIZE1" => format!("{:>08X}", bar_sizes[1]), - "$BARSIZE2" => format!("{:>08X}", bar_sizes[2]), - "$BARSIZE3" => format!("{:>08X}", bar_sizes[3]), - "$BARSIZE4" => format!("{:>08X}", bar_sizes[4]), - "$BARSIZE5" => format!("{:>08X}", bar_sizes[5]), - "$IRQ" => format!("{}", irq), - "$VENID" => format!("{:>04X}", header.vendor_id()), - "$DEVID" => format!("{:>04X}", header.device_id()), - _ => arg.clone() - }; - command.arg(&arg); + if arg.starts_with("$") { + panic!("support for $VARIABLE has been removed. use pcid_interface instead"); + } + command.arg(arg); } info!("PCID SPAWN {:?}", command); - let (pcid_to_client_write, pcid_from_client_read, envs) = if driver.use_channel.unwrap_or(false) { // TODO: libc wrapper? let [fds1, fds2] = unsafe { let mut fds1 = [0 as libc::c_int; 2]; @@ -456,10 +437,10 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he let [pcid_to_client_read, pcid_to_client_write] = fds1; let [pcid_from_client_read, pcid_from_client_write] = fds2; - (Some(pcid_to_client_write), Some(pcid_from_client_read), vec! [("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write))]) - } else { - (None, None, vec! []) - }; + let envs = vec![ + ("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), + ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write)), + ]; match command.envs(envs).spawn() { Ok(mut child) => { diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index 2698818f58..e51c0b31d2 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -1,5 +1,3 @@ -use std::fmt; - use serde::{Serialize, Deserialize}; #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] @@ -41,14 +39,3 @@ impl From for PciBar { } } } - -impl fmt::Display for PciBar { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - &PciBar::Memory32(address) => write!(f, "{:>08X}", address), - &PciBar::Memory64(address) => write!(f, "{:>016X}", address), - &PciBar::Port(address) => write!(f, "{:>04X}", address), - &PciBar::None => write!(f, "None") - } - } -} diff --git a/rtl8139d/config.toml b/rtl8139d/config.toml index 1688b9ce95..05c5322479 100644 --- a/rtl8139d/config.toml +++ b/rtl8139d/config.toml @@ -3,4 +3,3 @@ name = "RTL8139 NIC" class = 0x02 ids = { 0x10ec = [0x8139] } command = ["rtl8139d"] -use_channel = true diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index eac441a25f..fd26b06812 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -183,7 +183,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { 0 => panic!("BAR {} is mapped to address 0", bir), _ => ptr, }, - other => panic!("Expected memory bar, found {}", other), + other => panic!("Expected memory bar, found {:?}", other), }; let address = unsafe { @@ -325,7 +325,7 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { pci_config.func.bar_sizes[barnum].try_into().unwrap() )), }, - other => log::warn!("BAR {} is {} instead of memory BAR", barnum, other), + other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), } } None diff --git a/rtl8168d/config.toml b/rtl8168d/config.toml index d1ddbefe5c..ee98e345f3 100644 --- a/rtl8168d/config.toml +++ b/rtl8168d/config.toml @@ -3,4 +3,3 @@ name = "RTL8168 NIC" class = 0x02 ids = { 0x10ec = [0x8168, 0x8169] } command = ["rtl8168d"] -use_channel = true diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 2eea0c80f1..53415a2d0f 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -181,7 +181,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { 0 => panic!("BAR {} is mapped to address 0", bir), _ => ptr, }, - other => panic!("Expected memory bar, found {}", other), + other => panic!("Expected memory bar, found {:?}", other), }; let address = unsafe { @@ -323,7 +323,7 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { pci_config.func.bar_sizes[barnum].try_into().unwrap() )), }, - other => log::warn!("BAR {} is {} instead of memory BAR", barnum, other), + other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), } } None diff --git a/vboxd/config.toml b/vboxd/config.toml index d41fca4576..1216625579 100644 --- a/vboxd/config.toml +++ b/vboxd/config.toml @@ -4,4 +4,3 @@ class = 0x08 vendor = 0x80EE device = 0xCAFE command = ["vboxd"] -use_channel = true diff --git a/virtio-netd/config.toml b/virtio-netd/config.toml index 9e70971f42..ebedb9e40c 100644 --- a/virtio-netd/config.toml +++ b/virtio-netd/config.toml @@ -4,4 +4,3 @@ class = 0x02 vendor = 0x1AF4 device = 0x1000 command = ["virtio-netd"] -use_channel = true diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 8f33ddce1a..6e15e8b0da 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -98,7 +98,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option 0 => panic!("BAR 0 is mapped to address 0"), _ => ptr, }, - other => panic!("Expected memory bar, found {}", other), + other => panic!("Expected memory bar, found {:?}", other), }; let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); @@ -260,7 +260,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { 0 => panic!("BAR 0 is mapped to address 0"), _ => ptr, }, - other => panic!("Expected memory bar, found {}", other), + other => panic!("Expected memory bar, found {:?}", other), }; let address = unsafe { @@ -272,7 +272,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { print!( "{}", - format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq) + format!(" + XHCI {} on: {:016X} IRQ: {}\n", name, bar_ptr, irq) ); let scheme_name = format!("usb.{}", name); From 92428c535bb7f50e4361cda04cc4fc79644ed170 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Jan 2024 11:35:06 +0100 Subject: [PATCH 0783/1301] Only enable redox scheme logger when compiling for redox This allows running pcid tests on the host. --- pcid/src/main.rs | 66 +++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index e579a6d4ab..048b9cf03d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -195,9 +195,9 @@ impl DriverHandler { let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_write as RawFd) }; let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_read as RawFd) }; - while let Ok(msg) = recv(&mut pcid_from_client) { - let response = self.respond(msg, &args); - send(&mut pcid_to_client, &response).unwrap(); + while let Ok(msg) = recv(&mut pcid_from_client) { + let response = self.respond(msg, &args); + send(&mut pcid_to_client, &response).unwrap(); } } } @@ -420,22 +420,22 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he info!("PCID SPAWN {:?}", command); - // TODO: libc wrapper? - let [fds1, fds2] = unsafe { - let mut fds1 = [0 as libc::c_int; 2]; - let mut fds2 = [0 as libc::c_int; 2]; + // TODO: libc wrapper? + let [fds1, fds2] = unsafe { + let mut fds1 = [0 as libc::c_int; 2]; + let mut fds2 = [0 as libc::c_int; 2]; - assert_eq!(libc::pipe(fds1.as_mut_ptr()), 0, "pcid: failed to create pcid->client pipe"); - assert_eq!(libc::pipe(fds2.as_mut_ptr()), 0, "pcid: failed to create client->pcid pipe"); + assert_eq!(libc::pipe(fds1.as_mut_ptr()), 0, "pcid: failed to create pcid->client pipe"); + assert_eq!(libc::pipe(fds2.as_mut_ptr()), 0, "pcid: failed to create client->pcid pipe"); - [ - fds1.map(|c| c as usize), - fds2.map(|c| c as usize), - ] - }; + [ + fds1.map(|c| c as usize), + fds2.map(|c| c as usize), + ] + }; - let [pcid_to_client_read, pcid_to_client_write] = fds1; - let [pcid_from_client_read, pcid_from_client_write] = fds2; + let [pcid_to_client_read, pcid_to_client_write] = fds1; + let [pcid_from_client_read, pcid_from_client_write] = fds2; let envs = vec![ ("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), @@ -483,22 +483,24 @@ fn setup_logging(verbosity: u8) -> Option<&'static RedoxLogger> { .build() ); - match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Trace) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("pcid: failed to open pcid.log"), - } - match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.ansi.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Trace) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("pcid: failed to open pcid.ansi.log"), + #[cfg(target_os = "redox")] { + match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Trace) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("pcid: failed to open pcid.log"), + } + match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Trace) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("pcid: failed to open pcid.ansi.log"), + } } match logger.enable() { From b9c4c61dccabb22041afba6579925164aec4555a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Jan 2024 13:02:47 +0100 Subject: [PATCH 0784/1301] Move driver matching to config.rs --- pcid/src/config.rs | 68 ++++++++++++++++++++++++++++++++++++++++++++++ pcid/src/main.rs | 45 ++---------------------------- 2 files changed, 71 insertions(+), 42 deletions(-) diff --git a/pcid/src/config.rs b/pcid/src/config.rs index 83faddd586..6c79e7eb63 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -3,6 +3,8 @@ use std::ops::Range; use serde::Deserialize; +use crate::pci::PciHeader; + #[derive(Clone, Debug, Default, Deserialize)] pub struct Config { pub drivers: Vec, @@ -20,3 +22,69 @@ pub struct DriverConfig { pub device_id_range: Option>, pub command: Option>, } + +impl DriverConfig { + pub fn match_function(&self, header: &PciHeader) -> bool { + if let Some(class) = self.class { + if class != header.class().into() { + return false; + } + } + + if let Some(subclass) = self.subclass { + if subclass != header.subclass() { + return false; + } + } + + if let Some(interface) = self.interface { + if interface != header.interface() { + return false; + } + } + + if let Some(ref ids) = self.ids { + let mut device_found = false; + for (vendor, devices) in ids { + let vendor_without_prefix = vendor.trim_start_matches("0x"); + let vendor = i64::from_str_radix(vendor_without_prefix, 16).unwrap() as u16; + + if vendor != header.vendor_id() { + continue; + } + + for device in devices { + if *device == header.device_id() { + device_found = true; + break; + } + } + } + if !device_found { + return false; + } + } else { + if let Some(vendor) = self.vendor { + if vendor != header.vendor_id() { + return false; + } + } + + if let Some(device) = self.device { + if device != header.device_id() { + return false; + } + } + } + + if let Some(ref device_id_range) = self.device_id_range { + if header.device_id() < device_id_range.start + || device_id_range.end <= header.device_id() + { + return false; + } + } + + true + } +} diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 048b9cf03d..8e762dca09 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -2,8 +2,8 @@ use std::fs::{File, metadata, read_dir}; use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; use std::process::Command; +use std::thread; use std::sync::{Arc, Mutex}; -use std::{i64, thread}; use structopt::StructOpt; use log::{debug, error, info, warn, trace}; @@ -265,47 +265,8 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he info!("{}", string); for driver in config.drivers.iter() { - if let Some(class) = driver.class { - if class != raw_class { continue; } - } - - if let Some(subclass) = driver.subclass { - if subclass != header.subclass() { continue; } - } - - if let Some(interface) = driver.interface { - if interface != header.interface() { continue; } - } - - if let Some(ref ids) = driver.ids { - let mut device_found = false; - for (vendor, devices) in ids { - let vendor_without_prefix = vendor.trim_start_matches("0x"); - let vendor = i64::from_str_radix(vendor_without_prefix, 16).unwrap() as u16; - - if vendor != header.vendor_id() { continue; } - - for device in devices { - if *device == header.device_id() { - device_found = true; - break; - } - } - } - if !device_found { continue; } - } else { - if let Some(vendor) = driver.vendor { - if vendor != header.vendor_id() { continue; } - } - - if let Some(device) = driver.device { - if device != header.device_id() { continue; } - } - } - - if let Some(ref device_id_range) = driver.device_id_range { - if header.device_id() < device_id_range.start || - device_id_range.end <= header.device_id() { continue; } + if !driver.match_function(&header) { + continue; } if let Some(ref args) = driver.command { From 92914e808c43091d24bfa7b9fe60888562168cf6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Jan 2024 14:03:33 +0100 Subject: [PATCH 0785/1301] Reduce code indentation one level --- pcid/src/main.rs | 292 ++++++++++++++++++++++++----------------------- 1 file changed, 147 insertions(+), 145 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 8e762dca09..8db92b7cbf 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -269,161 +269,163 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he continue; } - if let Some(ref args) = driver.command { - // Enable bus mastering, memory space, and I/O space - unsafe { - let mut data = pci.read(addr, 0x04); - data |= 7; - pci.write(addr, 0x04, data); + let Some(ref args) = driver.command else { + continue; + }; + + // Enable bus mastering, memory space, and I/O space + unsafe { + let mut data = pci.read(addr, 0x04); + data |= 7; + pci.write(addr, 0x04, data); + } + + // Set IRQ line to 9 if not set + let mut irq; + let interrupt_pin; + + unsafe { + let mut data = pci.read(addr, 0x3C); + irq = (data & 0xFF) as u8; + interrupt_pin = ((data & 0x0000_FF00) >> 8) as u8; + if irq == 0xFF { + irq = 9; + } + data = (data & 0xFFFFFF00) | irq as u32; + pci.write(addr, 0x3C, data); + }; + + // Find BAR sizes + //TODO: support 64-bit BAR sizes? + let mut bars = [PciBar::None; 6]; + let mut bar_sizes = [0; 6]; + unsafe { + let count = match header.header_type() { + PciHeaderType::GENERAL => 6, + PciHeaderType::PCITOPCI => 2, + _ => 0, + }; + + for i in 0..count { + bars[i] = header.get_bar(i); + + let offset = 0x10 + (i as u8) * 4; + + let original = pci.read(addr, offset.into()); + pci.write(addr, offset.into(), 0xFFFFFFFF); + + let new = pci.read(addr, offset.into()); + pci.write(addr, offset.into(), original); + + let masked = if new & 1 == 1 { + new & 0xFFFFFFFC + } else { + new & 0xFFFFFFF0 + }; + + let size = (!masked).wrapping_add(1); + bar_sizes[i] = if size <= 1 { + 0 + } else { + size + }; + } + } + + let capabilities = if header.status() & (1 << 4) != 0 { + let func = PciFunc { + pci: state.preferred_cfg_access(), + addr + }; + crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() + } else { + Vec::new() + }; + debug!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); + + use driver_interface::LegacyInterruptPin; + + let legacy_interrupt_pin = match interrupt_pin { + 0 => None, + 1 => Some(LegacyInterruptPin::IntA), + 2 => Some(LegacyInterruptPin::IntB), + 3 => Some(LegacyInterruptPin::IntC), + 4 => Some(LegacyInterruptPin::IntD), + + other => { + warn!("pcid: invalid interrupt pin: {}", other); + None + } + }; + + let func = driver_interface::PciFunction { + bars, + bar_sizes, + addr, + devid: header.device_id(), + legacy_interrupt_line: irq, + legacy_interrupt_pin, + venid: header.vendor_id(), + }; + + let subdriver_args = driver_interface::SubdriverArguments { + func, + }; + + let mut args = args.iter(); + if let Some(program) = args.next() { + let mut command = Command::new(program); + for arg in args { + if arg.starts_with("$") { + panic!("support for $VARIABLE has been removed. use pcid_interface instead"); + } + command.arg(arg); } - // Set IRQ line to 9 if not set - let mut irq; - let interrupt_pin; + info!("PCID SPAWN {:?}", command); - unsafe { - let mut data = pci.read(addr, 0x3C); - irq = (data & 0xFF) as u8; - interrupt_pin = ((data & 0x0000_FF00) >> 8) as u8; - if irq == 0xFF { - irq = 9; - } - data = (data & 0xFFFFFF00) | irq as u32; - pci.write(addr, 0x3C, data); + // TODO: libc wrapper? + let [fds1, fds2] = unsafe { + let mut fds1 = [0 as libc::c_int; 2]; + let mut fds2 = [0 as libc::c_int; 2]; + + assert_eq!(libc::pipe(fds1.as_mut_ptr()), 0, "pcid: failed to create pcid->client pipe"); + assert_eq!(libc::pipe(fds2.as_mut_ptr()), 0, "pcid: failed to create client->pcid pipe"); + + [ + fds1.map(|c| c as usize), + fds2.map(|c| c as usize), + ] }; - // Find BAR sizes - //TODO: support 64-bit BAR sizes? - let mut bars = [PciBar::None; 6]; - let mut bar_sizes = [0; 6]; - unsafe { - let count = match header.header_type() { - PciHeaderType::GENERAL => 6, - PciHeaderType::PCITOPCI => 2, - _ => 0, - }; + let [pcid_to_client_read, pcid_to_client_write] = fds1; + let [pcid_from_client_read, pcid_from_client_write] = fds2; - for i in 0..count { - bars[i] = header.get_bar(i); + let envs = vec![ + ("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), + ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write)), + ]; - let offset = 0x10 + (i as u8) * 4; - - let original = pci.read(addr, offset.into()); - pci.write(addr, offset.into(), 0xFFFFFFFF); - - let new = pci.read(addr, offset.into()); - pci.write(addr, offset.into(), original); - - let masked = if new & 1 == 1 { - new & 0xFFFFFFFC - } else { - new & 0xFFFFFFF0 + match command.envs(envs).spawn() { + Ok(mut child) => { + let driver_handler = DriverHandler { + addr, + config: driver.clone(), + header, + state: Arc::clone(&state), + capabilities, }; - - let size = (!masked).wrapping_add(1); - bar_sizes[i] = if size <= 1 { - 0 - } else { - size - }; - } - } - - let capabilities = if header.status() & (1 << 4) != 0 { - let func = PciFunc { - pci: state.preferred_cfg_access(), - addr - }; - crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() - } else { - Vec::new() - }; - debug!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); - - use driver_interface::LegacyInterruptPin; - - let legacy_interrupt_pin = match interrupt_pin { - 0 => None, - 1 => Some(LegacyInterruptPin::IntA), - 2 => Some(LegacyInterruptPin::IntB), - 3 => Some(LegacyInterruptPin::IntC), - 4 => Some(LegacyInterruptPin::IntD), - - other => { - warn!("pcid: invalid interrupt pin: {}", other); - None - } - }; - - let func = driver_interface::PciFunction { - bars, - bar_sizes, - addr, - devid: header.device_id(), - legacy_interrupt_line: irq, - legacy_interrupt_pin, - venid: header.vendor_id(), - }; - - let subdriver_args = driver_interface::SubdriverArguments { - func, - }; - - let mut args = args.iter(); - if let Some(program) = args.next() { - let mut command = Command::new(program); - for arg in args { - if arg.starts_with("$") { - panic!("support for $VARIABLE has been removed. use pcid_interface instead"); + let _handle = thread::spawn(move || { + driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); + }); + // FIXME this currently deadlocks as pcid doesn't daemonize + //state.threads.lock().unwrap().push(handle); + match child.wait() { + Ok(_status) => (), + Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err), } - command.arg(arg); - } - - info!("PCID SPAWN {:?}", command); - - // TODO: libc wrapper? - let [fds1, fds2] = unsafe { - let mut fds1 = [0 as libc::c_int; 2]; - let mut fds2 = [0 as libc::c_int; 2]; - - assert_eq!(libc::pipe(fds1.as_mut_ptr()), 0, "pcid: failed to create pcid->client pipe"); - assert_eq!(libc::pipe(fds2.as_mut_ptr()), 0, "pcid: failed to create client->pcid pipe"); - - [ - fds1.map(|c| c as usize), - fds2.map(|c| c as usize), - ] - }; - - let [pcid_to_client_read, pcid_to_client_write] = fds1; - let [pcid_from_client_read, pcid_from_client_write] = fds2; - - let envs = vec![ - ("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), - ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write)), - ]; - - match command.envs(envs).spawn() { - Ok(mut child) => { - let driver_handler = DriverHandler { - addr, - config: driver.clone(), - header, - state: Arc::clone(&state), - capabilities, - }; - let _handle = thread::spawn(move || { - driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); - }); - // FIXME this currently deadlocks as pcid doesn't daemonize - //state.threads.lock().unwrap().push(handle); - match child.wait() { - Ok(_status) => (), - Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err), - } - } - Err(err) => error!("pcid: failed to execute {:?}: {}", command, err) } + Err(err) => error!("pcid: failed to execute {:?}: {}", command, err) } } } From 1890293e86616c813e08155609cc3802b2c76c52 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Jan 2024 15:18:56 +0100 Subject: [PATCH 0786/1301] Introduce a FullDeviceId type and pass it in pcid_interface --- ihdad/src/main.rs | 3 +- pcid/src/config.rs | 22 +++---- pcid/src/driver_interface/mod.rs | 8 +-- pcid/src/main.rs | 5 +- pcid/src/pci/header.rs | 108 +++++++++++-------------------- pcid/src/pci/id.rs | 12 ++++ pcid/src/pci/mod.rs | 2 + virtio-blkd/src/main.rs | 2 +- virtio-core/src/probe.rs | 2 +- virtio-gpud/src/main.rs | 2 +- virtio-netd/src/main.rs | 2 +- 11 files changed, 72 insertions(+), 96 deletions(-) create mode 100644 pcid/src/pci/id.rs diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index d91013cc47..16ab7ea4a9 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -185,7 +185,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut irq_file = get_int_method(&mut pcid_handle).expect("ihdad: no interrupt file"); { - let vend_prod:u32 = ((pci_config.func.venid as u32) << 16) | (pci_config.func.devid as u32); + let vend_prod: u32 = ((pci_config.func.full_device_id.vendor_id as u32) << 16) + | (pci_config.func.full_device_id.device_id as u32); let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ihdad: failed to create hda scheme"); diff --git a/pcid/src/config.rs b/pcid/src/config.rs index 6c79e7eb63..df82e437d4 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -3,7 +3,7 @@ use std::ops::Range; use serde::Deserialize; -use crate::pci::PciHeader; +use crate::pci::FullDeviceId; #[derive(Clone, Debug, Default, Deserialize)] pub struct Config { @@ -24,21 +24,21 @@ pub struct DriverConfig { } impl DriverConfig { - pub fn match_function(&self, header: &PciHeader) -> bool { + pub fn match_function(&self, id: &FullDeviceId) -> bool { if let Some(class) = self.class { - if class != header.class().into() { + if class != id.class { return false; } } if let Some(subclass) = self.subclass { - if subclass != header.subclass() { + if subclass != id.subclass { return false; } } if let Some(interface) = self.interface { - if interface != header.interface() { + if interface != id.interface { return false; } } @@ -49,12 +49,12 @@ impl DriverConfig { let vendor_without_prefix = vendor.trim_start_matches("0x"); let vendor = i64::from_str_radix(vendor_without_prefix, 16).unwrap() as u16; - if vendor != header.vendor_id() { + if vendor != id.vendor_id { continue; } for device in devices { - if *device == header.device_id() { + if *device == id.device_id { device_found = true; break; } @@ -65,22 +65,20 @@ impl DriverConfig { } } else { if let Some(vendor) = self.vendor { - if vendor != header.vendor_id() { + if vendor != id.vendor_id { return false; } } if let Some(device) = self.device { - if device != header.device_id() { + if device != id.device_id { return false; } } } if let Some(ref device_id_range) = self.device_id_range { - if header.device_id() < device_id_range.start - || device_id_range.end <= header.device_id() - { + if id.device_id < device_id_range.start || device_id_range.end <= id.device_id { return false; } } diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 1132423793..b7cb34a7f0 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -9,7 +9,7 @@ use thiserror::Error; pub use crate::pci::cap::Capability; pub use crate::pci::msi; -pub use crate::pci::{PciAddress, PciBar, PciHeader}; +pub use crate::pci::{FullDeviceId, PciAddress, PciBar, PciHeader}; pub mod irq_helpers; @@ -45,10 +45,8 @@ pub struct PciFunction { /// Legacy interrupt pin (INTx#), none if INTx# interrupts aren't supported at all. pub legacy_interrupt_pin: Option, - /// Vendor ID - pub venid: u16, - /// Device ID - pub devid: u16, + /// All identifying information of the PCI function. + pub full_device_id: FullDeviceId, } impl PciFunction { pub fn name(&self) -> String { diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 8db92b7cbf..f8725429e2 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -265,7 +265,7 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he info!("{}", string); for driver in config.drivers.iter() { - if !driver.match_function(&header) { + if !driver.match_function(header.full_device_id()) { continue; } @@ -362,10 +362,9 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he bars, bar_sizes, addr, - devid: header.device_id(), legacy_interrupt_line: irq, legacy_interrupt_pin, - venid: header.vendor_id(), + full_device_id: header.full_device_id().clone(), }; let subdriver_args = driver_interface::SubdriverArguments { diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index 2c7b0556ff..7f5a6adafa 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize}; use super::bar::PciBar; use super::class::PciClass; use super::func::ConfigReader; +use super::id::FullDeviceId; #[derive(Debug, PartialEq)] pub enum PciHeaderError { @@ -31,14 +32,9 @@ bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub struct SharedPciHeader { - vendor_id: u16, - device_id: u16, + full_device_id: FullDeviceId, command: u16, status: u16, - revision: u8, - interface: u8, - subclass: u8, - class: PciClass, cache_line_size: u8, latency_timer: u8, header_type: PciHeaderType, @@ -127,20 +123,22 @@ impl PciHeader { let revision = bytes[8]; let interface = bytes[9]; let subclass = bytes[10]; - let class = PciClass::from(bytes[11]); + let class = bytes[11]; let cache_line_size = bytes[12]; let latency_timer = bytes[13]; let header_type = PciHeaderType::from_bits_truncate(bytes[14]); let bist = bytes[15]; let shared = SharedPciHeader { + full_device_id: FullDeviceId { vendor_id, device_id, + class, + subclass, + interface, + revision, + }, command, status, - revision, - interface, - subclass, - class, cache_line_size, latency_timer, header_type, @@ -245,88 +243,56 @@ impl PciHeader { } } - /// Return the Vendor ID field. - pub fn vendor_id(&self) -> u16 { + /// Return all identifying information of the PCI function. + pub fn full_device_id(&self) -> &FullDeviceId { match self { - &PciHeader::General { - shared: SharedPciHeader { vendor_id, .. }, + PciHeader::General { + shared: + SharedPciHeader { + full_device_id: device_id, + .. + }, .. } - | &PciHeader::PciToPci { - shared: SharedPciHeader { vendor_id, .. }, - .. - } => vendor_id, - } - } - - /// Return the Device ID field. - pub fn device_id(&self) -> u16 { - match self { - &PciHeader::General { - shared: SharedPciHeader { device_id, .. }, - .. - } - | &PciHeader::PciToPci { - shared: SharedPciHeader { device_id, .. }, + | PciHeader::PciToPci { + shared: + SharedPciHeader { + full_device_id: device_id, + .. + }, .. } => device_id, } } + /// Return the Vendor ID field. + pub fn vendor_id(&self) -> u16 { + self.full_device_id().vendor_id + } + + /// Return the Device ID field. + pub fn device_id(&self) -> u16 { + self.full_device_id().device_id + } + /// Return the Revision field. pub fn revision(&self) -> u8 { - match self { - &PciHeader::General { - shared: SharedPciHeader { revision, .. }, - .. - } - | &PciHeader::PciToPci { - shared: SharedPciHeader { revision, .. }, - .. - } => revision, - } + self.full_device_id().revision } /// Return the Interface field. pub fn interface(&self) -> u8 { - match self { - &PciHeader::General { - shared: SharedPciHeader { interface, .. }, - .. - } - | &PciHeader::PciToPci { - shared: SharedPciHeader { interface, .. }, - .. - } => interface, - } + self.full_device_id().interface } /// Return the Subclass field. pub fn subclass(&self) -> u8 { - match self { - &PciHeader::General { - shared: SharedPciHeader { subclass, .. }, - .. - } - | &PciHeader::PciToPci { - shared: SharedPciHeader { subclass, .. }, - .. - } => subclass, - } + self.full_device_id().subclass } /// Return the Class field. pub fn class(&self) -> PciClass { - match self { - &PciHeader::General { - shared: SharedPciHeader { class, .. }, - .. - } - | &PciHeader::PciToPci { - shared: SharedPciHeader { class, .. }, - .. - } => class, - } + PciClass::from(self.full_device_id().class) } /// Return the Headers BARs. diff --git a/pcid/src/pci/id.rs b/pcid/src/pci/id.rs new file mode 100644 index 0000000000..9a59d660f6 --- /dev/null +++ b/pcid/src/pci/id.rs @@ -0,0 +1,12 @@ +use serde::{Deserialize, Serialize}; + +/// All identifying information of a PCI function. +#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +pub struct FullDeviceId { + pub vendor_id: u16, + pub device_id: u16, + pub class: u8, + pub subclass: u8, + pub interface: u8, + pub revision: u8, +} diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 6d39cbdb8f..264a3f35dd 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -7,12 +7,14 @@ pub use self::bar::PciBar; pub use self::class::PciClass; pub use self::func::PciFunc; pub use self::header::{PciHeader, PciHeaderError, PciHeaderType}; +pub use self::id::FullDeviceId; mod bar; pub mod cap; mod class; pub mod func; pub mod header; +mod id; pub mod msi; pub trait CfgAccess { diff --git a/virtio-blkd/src/main.rs b/virtio-blkd/src/main.rs index e280f62b6a..c6b3727a16 100644 --- a/virtio-blkd/src/main.rs +++ b/virtio-blkd/src/main.rs @@ -116,7 +116,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { // 0x1001 - virtio-blk let pci_config = pcid_handle.fetch_config()?; - assert_eq!(pci_config.func.devid, 0x1001); + assert_eq!(pci_config.func.full_device_id.device_id, 0x1001); log::info!("virtio-blk: initiating startup sequence :^)"); let device = virtio_core::probe_device(&mut pcid_handle)?; diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 157ffa0f1f..c0c5ec3e1f 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -64,7 +64,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result let pci_header = pcid_handle.fetch_header()?; assert_eq!( - pci_config.func.venid, 6900, + pci_config.func.full_device_id.vendor_id, 6900, "virtio_core::probe_device: not a virtio device" ); diff --git a/virtio-gpud/src/main.rs b/virtio-gpud/src/main.rs index 4d16d87a97..8a80510fbc 100644 --- a/virtio-gpud/src/main.rs +++ b/virtio-gpud/src/main.rs @@ -416,7 +416,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { // 0x1050 - virtio-gpu let pci_config = pcid_handle.fetch_config()?; - assert_eq!(pci_config.func.devid, 0x1050); + assert_eq!(pci_config.func.full_device_id.device_id, 0x1050); log::info!("virtio-gpu: initiating startup sequence :^)"); let device = DEVICE.try_call_once(|| virtio_core::probe_device(&mut pcid_handle))?; diff --git a/virtio-netd/src/main.rs b/virtio-netd/src/main.rs index c99b2c4577..c3113ed753 100644 --- a/virtio-netd/src/main.rs +++ b/virtio-netd/src/main.rs @@ -38,7 +38,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { // 0x1000 - virtio-net let pci_config = pcid_handle.fetch_config()?; - assert_eq!(pci_config.func.devid, 0x1000); + assert_eq!(pci_config.func.full_device_id.device_id, 0x1000); log::info!("virtio-net: initiating startup sequence :^)"); let device = virtio_core::probe_device(&mut pcid_handle)?; From e5772c132bc514f7c2a7b5f09c6419b8b5737d28 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Jan 2024 16:20:40 +0100 Subject: [PATCH 0787/1301] Remove a lot of fields from PciHeader which are unlikely to be used Some of these are removed with PCIe while many others only need to be used by the firmware to initialize the PCI bridges. If we ever need them anyway, we can always add them back, but for now it improves readability. --- pcid/src/pci/header.rs | 76 +++--------------------------------------- 1 file changed, 5 insertions(+), 71 deletions(-) diff --git a/pcid/src/pci/header.rs b/pcid/src/pci/header.rs index 7f5a6adafa..00de49ed30 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci/header.rs @@ -33,12 +33,9 @@ bitflags! { #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub struct SharedPciHeader { full_device_id: FullDeviceId, - command: u16, - status: u16, - cache_line_size: u8, - latency_timer: u8, - header_type: PciHeaderType, - bist: u8, + command: u16, + status: u16, + header_type: PciHeaderType, } #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] @@ -46,36 +43,17 @@ pub enum PciHeader { General { shared: SharedPciHeader, bars: [PciBar; 6], - cardbus_cis_ptr: u32, subsystem_vendor_id: u16, subsystem_id: u16, - expansion_rom_bar: u32, cap_pointer: u8, interrupt_line: u8, interrupt_pin: u8, - min_grant: u8, - max_latency: u8, }, PciToPci { shared: SharedPciHeader, bars: [PciBar; 2], - primary_bus_num: u8, secondary_bus_num: u8, - subordinate_bus_num: u8, - secondary_latency_timer: u8, - io_base: u8, - io_limit: u8, - secondary_status: u16, - mem_base: u16, - mem_limit: u16, - prefetch_base: u16, - prefetch_limit: u16, - prefetch_base_upper: u32, - prefetch_limit_upper: u32, - io_base_upper: u16, - io_limit_upper: u16, cap_pointer: u8, - expansion_rom: u32, interrupt_line: u8, interrupt_pin: u8, bridge_control: u16, @@ -124,14 +102,11 @@ impl PciHeader { let interface = bytes[9]; let subclass = bytes[10]; let class = bytes[11]; - let cache_line_size = bytes[12]; - let latency_timer = bytes[13]; let header_type = PciHeaderType::from_bits_truncate(bytes[14]); - let bist = bytes[15]; let shared = SharedPciHeader { full_device_id: FullDeviceId { - vendor_id, - device_id, + vendor_id, + device_id, class, subclass, interface, @@ -139,10 +114,7 @@ impl PciHeader { }, command, status, - cache_line_size, - latency_timer, header_type, - bist, }; match header_type & PciHeaderType::HEADER_TYPE { @@ -150,73 +122,35 @@ impl PciHeader { let bytes = unsafe { reader.read_range(16, 48) }; let mut bars = [PciBar::None; 6]; Self::get_bars(&bytes, &mut bars); - let cardbus_cis_ptr = LittleEndian::read_u32(&bytes[24..28]); let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]); let subsystem_id = LittleEndian::read_u16(&bytes[30..32]); - let expansion_rom_bar = LittleEndian::read_u32(&bytes[32..36]); let cap_pointer = bytes[36]; let interrupt_line = bytes[44]; let interrupt_pin = bytes[45]; - let min_grant = bytes[46]; - let max_latency = bytes[47]; Ok(PciHeader::General { shared, bars, - cardbus_cis_ptr, subsystem_vendor_id, subsystem_id, - expansion_rom_bar, cap_pointer, interrupt_line, interrupt_pin, - min_grant, - max_latency, }) } PciHeaderType::PCITOPCI => { let bytes = unsafe { reader.read_range(16, 48) }; let mut bars = [PciBar::None; 2]; Self::get_bars(&bytes, &mut bars); - let primary_bus_num = bytes[8]; let secondary_bus_num = bytes[9]; - let subordinate_bus_num = bytes[10]; - let secondary_latency_timer = bytes[11]; - let io_base = bytes[12]; - let io_limit = bytes[13]; - let secondary_status = LittleEndian::read_u16(&bytes[14..16]); - let mem_base = LittleEndian::read_u16(&bytes[16..18]); - let mem_limit = LittleEndian::read_u16(&bytes[18..20]); - let prefetch_base = LittleEndian::read_u16(&bytes[20..22]); - let prefetch_limit = LittleEndian::read_u16(&bytes[22..24]); - let prefetch_base_upper = LittleEndian::read_u32(&bytes[24..28]); - let prefetch_limit_upper = LittleEndian::read_u32(&bytes[28..32]); - let io_base_upper = LittleEndian::read_u16(&bytes[32..34]); - let io_limit_upper = LittleEndian::read_u16(&bytes[34..36]); let cap_pointer = bytes[36]; - let expansion_rom = LittleEndian::read_u32(&bytes[40..44]); let interrupt_line = bytes[44]; let interrupt_pin = bytes[45]; let bridge_control = LittleEndian::read_u16(&bytes[46..48]); Ok(PciHeader::PciToPci { shared, bars, - primary_bus_num, secondary_bus_num, - subordinate_bus_num, - secondary_latency_timer, - io_base, - io_limit, - secondary_status, - mem_base, - mem_limit, - prefetch_base, - prefetch_limit, - prefetch_base_upper, - prefetch_limit_upper, - io_base_upper, - io_limit_upper, cap_pointer, - expansion_rom, interrupt_line, interrupt_pin, bridge_control, From d0e90f5ded685862fd16a1ab6a82cf2450e8d617 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Jan 2024 19:35:39 +0100 Subject: [PATCH 0788/1301] Remove fetch_header from pcid_interface Most things are already stored in SubdriverArguments and the couple of things that aren't may change over time and thus should be read again each time they are accessed, while fetch_header would receive a fixed copy from pcid. --- ided/src/main.rs | 7 +++---- pcid/src/driver_interface/mod.rs | 11 +---------- pcid/src/main.rs | 7 ------- virtio-core/src/arch/x86_64.rs | 4 ++-- virtio-core/src/probe.rs | 5 ++--- 5 files changed, 8 insertions(+), 26 deletions(-) diff --git a/ided/src/main.rs b/ided/src/main.rs index f8e42c5deb..603a20baab 100644 --- a/ided/src/main.rs +++ b/ided/src/main.rs @@ -86,17 +86,16 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { info!("IDE PCI CONFIG: {:?}", pci_config); - let pci_header = pcid_handle.fetch_header().expect("ided: failed to fetch PCI header"); - let busmaster_base = match pci_header.get_bar(4) { + let busmaster_base = match pci_config.func.bars[4] { PciBar::Port(port) => port, other => panic!("TODO: IDE busmaster BAR {:#x?}", other), }; - let (primary, primary_irq) = if pci_header.interface() & 1 != 0 { + let (primary, primary_irq) = if pci_config.func.full_device_id.interface & 1 != 0 { panic!("TODO: IDE primary channel is PCI native"); } else { (Channel::primary_compat(busmaster_base).unwrap(), 14) }; - let (secondary, secondary_irq) = if pci_header.interface() & 1 != 0 { + let (secondary, secondary_irq) = if pci_config.func.full_device_id.interface & 1 != 0 { panic!("TODO: IDE secondary channel is PCI native"); } else { (Channel::secondary_compat(busmaster_base + 8).unwrap(), 15) diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index b7cb34a7f0..6357ec5a92 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -9,7 +9,7 @@ use thiserror::Error; pub use crate::pci::cap::Capability; pub use crate::pci::msi; -pub use crate::pci::{FullDeviceId, PciAddress, PciBar, PciHeader}; +pub use crate::pci::{FullDeviceId, PciAddress, PciBar}; pub mod irq_helpers; @@ -163,7 +163,6 @@ pub enum SetFeatureInfo { #[non_exhaustive] pub enum PcidClientRequest { RequestConfig, - RequestHeader, RequestFeatures, RequestCapabilities, EnableFeature(PciFeature), @@ -186,7 +185,6 @@ pub enum PcidServerResponseError { pub enum PcidClientResponse { Capabilities(Vec), Config(SubdriverArguments), - Header(PciHeader), AllFeatures(Vec<(PciFeature, FeatureStatus)>), FeatureEnabled(PciFeature), FeatureStatus(PciFeature, FeatureStatus), @@ -264,13 +262,6 @@ impl PcidServerHandle { } } - pub fn fetch_header(&mut self) -> Result { - self.send(&PcidClientRequest::RequestHeader)?; - match self.recv()? { - PcidClientResponse::Header(a) => Ok(a), - other => Err(PcidClientHandleError::InvalidResponse(other)), - } - } pub fn fetch_all_features(&mut self) -> Result> { self.send(&PcidClientRequest::RequestFeatures)?; match self.recv()? { diff --git a/pcid/src/main.rs b/pcid/src/main.rs index f8725429e2..74c3f80688 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -33,9 +33,7 @@ struct Args { } pub struct DriverHandler { - config: config::DriverConfig, addr: PciAddress, - header: PciHeader, capabilities: Vec<(u8, PciCapability)>, state: Arc, @@ -59,9 +57,6 @@ impl DriverHandler { PcidClientRequest::RequestConfig => { PcidClientResponse::Config(args.clone()) } - PcidClientRequest::RequestHeader => { - PcidClientResponse::Header(self.header.clone()) - } PcidClientRequest::RequestFeatures => { PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability { PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))), @@ -409,8 +404,6 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he Ok(mut child) => { let driver_handler = DriverHandler { addr, - config: driver.clone(), - header, state: Arc::clone(&state), capabilities, }; diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index e8200da934..502bfcdafa 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -96,10 +96,10 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { } pub fn probe_legacy_port_transport( - pci_header: &PciHeader, + pci_config: &SubdriverArguments, pcid_handle: &mut PcidServerHandle, ) -> Result { - if let PciBar::Port(port) = pci_header.get_bar(0) { + if let PciBar::Port(port) = pci_config.func.bars[0] { unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; log::warn!("virtio: using legacy transport"); diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index c0c5ec3e1f..292bf429a6 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -61,7 +61,6 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { /// This function panics if the device is not a virtio device. pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result { let pci_config = pcid_handle.fetch_config()?; - let pci_header = pcid_handle.fetch_header()?; assert_eq!( pci_config.func.full_device_id.vendor_id, 6900, @@ -91,7 +90,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result _ => continue, } - let bar = pci_header.get_bar(capability.bar as usize); + let bar = pci_config.func.bars[capability.bar as usize]; let addr = match bar { PciBar::Memory32(addr) => addr as usize, PciBar::Memory64(addr) => addr as usize, @@ -189,7 +188,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result Ok(device) } else { - crate::arch::probe_legacy_port_transport(&pci_header, pcid_handle) + crate::arch::probe_legacy_port_transport(&pci_config, pcid_handle) } } From be0e6b9dd7e8ce6f05755a9976e3592c951ff31e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Jan 2024 20:46:00 +0100 Subject: [PATCH 0789/1301] Pass self instead of &self to PciFeature methods PciFeature is Copy, so passing it behind a reference is not necessary. --- pcid/src/driver_interface/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 6357ec5a92..4f7fd64703 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -85,11 +85,11 @@ pub enum PciFeature { MsiX, } impl PciFeature { - pub fn is_msi(&self) -> bool { - if let &Self::Msi = self { true } else { false } + pub fn is_msi(self) -> bool { + if let Self::Msi = self { true } else { false } } - pub fn is_msix(&self) -> bool { - if let &Self::MsiX = self { true } else { false } + pub fn is_msix(self) -> bool { + if let Self::MsiX = self { true } else { false } } } #[derive(Debug, Serialize, Deserialize)] From 5192816de7760c6c359559943cbba9dc5d4df686 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Jan 2024 21:12:24 +0100 Subject: [PATCH 0790/1301] Introduce expect_port and expect_mem helpers --- ac97d/src/main.rs | 11 ++----- ahcid/src/main.rs | 6 +--- e1000d/src/main.rs | 6 +--- ided/src/main.rs | 5 +--- ihdad/src/main.rs | 15 ++-------- ixgbed/src/main.rs | 6 +--- nvmed/src/main.rs | 24 ++-------------- pcid/src/pci/bar.rs | 37 ++++++++++++++++++------ pcid/src/pci/msi.rs | 36 ++--------------------- rtl8139d/src/main.rs | 14 +-------- rtl8168d/src/main.rs | 12 +------- vboxd/src/main.rs | 11 ++----- virtio-core/src/arch/x86.rs | 44 ++++++++++++++-------------- virtio-core/src/arch/x86_64.rs | 52 ++++++++++++++-------------------- virtio-core/src/probe.rs | 8 +----- xhcid/src/main.rs | 28 ++---------------- 16 files changed, 91 insertions(+), 224 deletions(-) diff --git a/ac97d/src/main.rs b/ac97d/src/main.rs index a1e6760070..04a5f3f7be 100644 --- a/ac97d/src/main.rs +++ b/ac97d/src/main.rs @@ -73,15 +73,8 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_ac97"); - let bar0 = match pci_config.func.bars[0] { - PciBar::Port(port) => port, - _ => unreachable!(), - }; - - let bar1 = match pci_config.func.bars[1] { - PciBar::Port(port) => port, - _ => unreachable!(), - }; + let bar0 = pci_config.func.bars[0].expect_port(); + let bar1 = pci_config.func.bars[1].expect_port(); let irq = pci_config.func.legacy_interrupt_line; diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index f41f397e73..bd8e6af790 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -81,11 +81,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_ahci"); - let bar = match pci_config.func.bars[5] { - PciBar::Memory32(addr) => addr as usize, - PciBar::Memory64(addr) => addr as usize, - PciBar::None | PciBar::Port(_) => unreachable!(), - }; + let bar = pci_config.func.bars[5].expect_mem(); let bar_size = pci_config.func.bar_sizes[5]; let irq = pci_config.func.legacy_interrupt_line; diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 328c7d0d3c..58a8a9f4ed 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -68,11 +68,7 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_e1000"); - let bar = match pci_config.func.bars[0] { - PciBar::Memory32(addr) => addr as usize, - PciBar::Memory64(addr) => addr as usize, - PciBar::None | PciBar::Port(_) => unreachable!(), - }; + let bar = pci_config.func.bars[0].expect_mem(); let bar_size = pci_config.func.bar_sizes[0] as usize; let irq = pci_config.func.legacy_interrupt_line; diff --git a/ided/src/main.rs b/ided/src/main.rs index 603a20baab..bf176e4986 100644 --- a/ided/src/main.rs +++ b/ided/src/main.rs @@ -86,10 +86,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { info!("IDE PCI CONFIG: {:?}", pci_config); - let busmaster_base = match pci_config.func.bars[4] { - PciBar::Port(port) => port, - other => panic!("TODO: IDE busmaster BAR {:#x?}", other), - }; + let busmaster_base = pci_config.func.bars[4].expect_port(); let (primary, primary_irq) = if pci_config.func.full_device_id.interface & 1 != 0 { panic!("TODO: IDE primary channel is PCI native"); } else { diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 16ab7ea4a9..a4ff9a98f0 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -160,24 +160,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_ihda"); - let bar = pci_config.func.bars[0]; + let bar_ptr = pci_config.func.bars[0].expect_mem(); let bar_size = pci_config.func.bar_sizes[0]; - let bar_ptr = match bar { - pcid_interface::PciBar::Memory32(ptr) => match ptr { - 0 => panic!("BAR 0 is mapped to address 0"), - _ => ptr as u64, - }, - pcid_interface::PciBar::Memory64(ptr) => match ptr { - 0 => panic!("BAR 0 is mapped to address 0"), - _ => ptr, - }, - other => panic!("Expected memory bar, found {:?}", other), - }; log::info!(" + IHDA {} on: {:#X} size: {}", name, bar_ptr, bar_size); let address = unsafe { - common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) + common::physmap(bar_ptr, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) .expect("ihdad: failed to map address") as usize }; diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index b60cfb9982..a0b3d46c39 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -76,11 +76,7 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_ixgbe"); - let bar = match pci_config.func.bars[0] { - PciBar::Memory32(addr) => addr as usize, - PciBar::Memory64(addr) => addr as usize, - PciBar::None | PciBar::Port(_) => unreachable!(), - }; + let bar = pci_config.func.bars[0].expect_mem(); let irq = pci_config.func.legacy_interrupt_line; diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 2fed31c18c..07933e1659 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -93,17 +93,7 @@ fn get_int_method( match &mut *bar_guard { &mut Some(ref bar) => Ok(bar.ptr), bar_to_set @ &mut None => { - let bar = match function.bars[bir] { - PciBar::Memory32(addr) => match addr { - 0 => panic!("BAR {} is mapped to address 0", bir), - _ => addr as u64, - }, - PciBar::Memory64(addr) => match addr { - 0 => panic!("BAR {} is mapped to address 0", bir), - _ => addr, - }, - other => panic!("Expected memory BAR, found {:?}", other), - }; + let bar = function.bars[bir].expect_mem(); let bar_size = function.bar_sizes[bir]; let bar = Bar::allocate(bar as usize, bar_size as usize)?; @@ -303,17 +293,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(&scheme_name); - let bar = match pci_config.func.bars[0] { - PciBar::Memory32(mem) => match mem { - 0 => panic!("BAR 0 is mapped to address 0"), - _ => mem as u64, - }, - PciBar::Memory64(mem) => match mem { - 0 => panic!("BAR 0 is mapped to address 0"), - _ => mem, - }, - other => panic!("received a non-memory BAR ({:?})", other), - }; + let bar = pci_config.func.bars[0].expect_mem(); let bar_size = pci_config.func.bar_sizes[0]; let irq = pci_config.func.legacy_interrupt_line; diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index e51c0b31d2..f0d3a14911 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -1,11 +1,13 @@ -use serde::{Serialize, Deserialize}; +use std::convert::TryInto; + +use serde::{Deserialize, Serialize}; #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum PciBar { None, Memory32(u32), Memory64(u64), - Port(u16) + Port(u16), } impl PciBar { @@ -15,6 +17,27 @@ impl PciBar { _ => false, } } + + pub fn expect_port(&self) -> u16 { + match *self { + PciBar::Port(port) => port, + PciBar::Memory32(_) | PciBar::Memory64(_) => { + panic!("expected port BAR, found memory BAR"); + } + PciBar::None => panic!("expected BAR to exist"), + } + } + + pub fn expect_mem(&self) -> usize { + match *self { + PciBar::Memory32(ptr) => ptr as usize, + PciBar::Memory64(ptr) => ptr + .try_into() + .expect("conversion from 64bit BAR to usize failed"), + PciBar::Port(_) => panic!("expected memory BAR, found port BAR"), + PciBar::None => panic!("expected BAR to exist"), + } + } } impl From for PciBar { @@ -23,16 +46,12 @@ impl From for PciBar { PciBar::None } else if bar & 1 == 0 { match (bar >> 1) & 3 { - 0 => { - PciBar::Memory32(bar & 0xFFFFFFF0) - }, - 2 => { - PciBar::Memory64((bar & 0xFFFFFFF0) as u64) - }, + 0 => PciBar::Memory32(bar & 0xFFFFFFF0), + 2 => PciBar::Memory64((bar & 0xFFFFFFF0) as u64), other => { log::warn!("unsupported PCI memory type {}", other); PciBar::None - }, + } } } else { PciBar::Port((bar & 0xFFFC) as u16) diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index fc8a25f4a3..b4d3c67ca1 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -219,13 +219,9 @@ impl MsixCapability { self.a &= 0x0000_FFFF; self.a |= u32::from(message_control) << 16; } - /// Returns the MSI-X table size, subtracted by one. - pub const fn table_size_raw(&self) -> u16 { - self.message_control() & Self::MC_TABLE_SIZE_MASK - } /// Returns the MSI-X table size. pub const fn table_size(&self) -> u16 { - self.table_size_raw() + 1 + (self.message_control() & Self::MC_TABLE_SIZE_MASK) + 1 } /// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the /// MSI capability structure. @@ -289,20 +285,7 @@ impl MsixCapability { if self.table_bir() > 5 { panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir()); } - let base = bars[usize::from(self.table_bir())]; - - //TODO: ensure type conversions are safe - match base { - PciBar::Memory32(ptr) => { - ptr as usize + self.table_offset() as usize - }, - PciBar::Memory64(ptr) => { - ptr as usize + self.table_offset() as usize - }, - _ => { - panic!("MSI-X Table BIR referenced a non-memory BAR: {:?}", base); - } - } + bars[usize::from(self.table_bir())].expect_mem() + self.table_offset() as usize } pub fn table_pointer(&self, bars: [PciBar; 6], k: u16) -> usize { self.table_base_pointer(bars) + k as usize * 16 @@ -312,20 +295,7 @@ impl MsixCapability { if self.pba_bir() > 5 { panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir()); } - let base = bars[usize::from(self.pba_bir())]; - - //TODO: ensure type conversions are safe - match base { - PciBar::Memory32(ptr) => { - ptr as usize + self.pba_offset() as usize - }, - PciBar::Memory64(ptr) => { - ptr as usize + self.pba_offset() as usize - }, - _ => { - panic!("MSI-X PBA BIR referenced a non-memory BAR: {:?}", base); - } - } + bars[usize::from(self.pba_bir())].expect_mem() + self.pba_offset() as usize } pub fn pba_pointer_dword(&self, bars: [PciBar; 6], k: u16) -> usize { self.pba_base_pointer(bars) + (k as usize / 32) * 4 diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index fd26b06812..62925a1ec2 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -171,21 +171,9 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { let pba_base = capability.pba_base_pointer(pci_config.func.bars); let bir = capability.table_bir() as usize; - let bar = pci_config.func.bars[bir]; + let bar_ptr = pci_config.func.bars[bir].expect_mem() as u64; let bar_size = pci_config.func.bar_sizes[bir] as u64; - let bar_ptr = match bar { - pcid_interface::PciBar::Memory32(ptr) => match ptr { - 0 => panic!("BAR {} is mapped to address 0", bir), - _ => ptr as u64, - }, - pcid_interface::PciBar::Memory64(ptr) => match ptr { - 0 => panic!("BAR {} is mapped to address 0", bir), - _ => ptr, - }, - other => panic!("Expected memory bar, found {:?}", other), - }; - let address = unsafe { common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) .expect("rtl8139d: failed to map address") as usize diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 53415a2d0f..284b84c3e4 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -172,17 +172,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { let bar = pci_config.func.bars[bir]; let bar_size = pci_config.func.bar_sizes[bir] as u64; - let bar_ptr = match bar { - pcid_interface::PciBar::Memory32(ptr) => match ptr { - 0 => panic!("BAR {} is mapped to address 0", bir), - _ => ptr as u64, - }, - pcid_interface::PciBar::Memory64(ptr) => match ptr { - 0 => panic!("BAR {} is mapped to address 0", bir), - _ => ptr, - }, - other => panic!("Expected memory bar, found {:?}", other), - }; + let bar_ptr = bar.expect_mem() as u64; let address = unsafe { common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 555b5eb675..0602649c5c 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -194,16 +194,9 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_vbox"); - let bar0 = match pci_config.func.bars[0] { - PciBar::Port(port) => port, - _ => unreachable!(), - }; + let bar0 = pci_config.func.bars[0].expect_port(); - let bar1 = match pci_config.func.bars[1] { - PciBar::Memory32(addr) => addr as usize, - PciBar::Memory64(addr) => addr as usize, - PciBar::None | PciBar::Port(_) => unreachable!(), - }; + let bar1 = pci_config.func.bars[1].expect_mem(); let irq = pci_config.func.legacy_interrupt_line; diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index 56b33d8fd8..45d67b9a1c 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -11,33 +11,31 @@ pub fn probe_legacy_port_transport( pci_header: &PciHeader, pcid_handle: &mut PcidServerHandle, ) -> Result { - if let PciBar::Port(port) = pci_header.get_bar(0) { - unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; - log::warn!("virtio: using legacy transport"); + let port = pci_header.get_bar(0).expect_port(); - let transport = LegacyTransport::new(port); + unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; + log::warn!("virtio: using legacy transport"); - // Setup interrupts. - let all_pci_features = pcid_handle.fetch_all_features()?; - let has_msix = all_pci_features - .iter() - .any(|(feature, _)| feature.is_msix()); + let transport = LegacyTransport::new(port); - // According to the virtio specification, the device REQUIRED to support MSI-X. - assert!(has_msix, "virtio: device does not support MSI-X"); - let irq_handle = enable_msix(pcid_handle)?; + // Setup interrupts. + let all_pci_features = pcid_handle.fetch_all_features()?; + let has_msix = all_pci_features + .iter() + .any(|(feature, _)| feature.is_msix()); - let device = Device { - transport, - irq_handle, - device_space: core::ptr::null_mut(), - }; + // According to the virtio specification, the device REQUIRED to support MSI-X. + assert!(has_msix, "virtio: device does not support MSI-X"); + let irq_handle = enable_msix(pcid_handle)?; - device.transport.reset(); - reinit(&device)?; + let device = Device { + transport, + irq_handle, + device_space: core::ptr::null_mut(), + }; - Ok(device) - } else { - unreachable!("virtio: legacy transport with non-port IO?") - } + device.transport.reset(); + reinit(&device)?; + + Ok(device) } diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index 502bfcdafa..2dd3cd27d3 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -27,15 +27,9 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { let pba_base = capability.pba_base_pointer(pci_config.func.bars); let bir = capability.table_bir() as usize; - let bar = pci_config.func.bars[bir]; + let bar_ptr = pci_config.func.bars[bir].expect_mem() as u64; let bar_size = pci_config.func.bar_sizes[bir] as u64; - let bar_ptr = match bar { - PciBar::Memory32(ptr) => ptr.into(), - PciBar::Memory64(ptr) => ptr, - _ => unreachable!(), - }; - let address = unsafe { common::physmap( bar_ptr as usize, @@ -99,33 +93,31 @@ pub fn probe_legacy_port_transport( pci_config: &SubdriverArguments, pcid_handle: &mut PcidServerHandle, ) -> Result { - if let PciBar::Port(port) = pci_config.func.bars[0] { - unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; - log::warn!("virtio: using legacy transport"); + let port = pci_config.func.bars[0].expect_port(); - let transport = LegacyTransport::new(port); + unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; + log::warn!("virtio: using legacy transport"); - // Setup interrupts. - let all_pci_features = pcid_handle.fetch_all_features()?; - let has_msix = all_pci_features - .iter() - .any(|(feature, _)| feature.is_msix()); + let transport = LegacyTransport::new(port); - // According to the virtio specification, the device REQUIRED to support MSI-X. - assert!(has_msix, "virtio: device does not support MSI-X"); - let irq_handle = enable_msix(pcid_handle)?; + // Setup interrupts. + let all_pci_features = pcid_handle.fetch_all_features()?; + let has_msix = all_pci_features + .iter() + .any(|(feature, _)| feature.is_msix()); - let device = Device { - transport, - irq_handle, - device_space: core::ptr::null_mut(), - }; + // According to the virtio specification, the device REQUIRED to support MSI-X. + assert!(has_msix, "virtio: device does not support MSI-X"); + let irq_handle = enable_msix(pcid_handle)?; - device.transport.reset(); - reinit(&device)?; + let device = Device { + transport, + irq_handle, + device_space: core::ptr::null_mut(), + }; - Ok(device) - } else { - unreachable!("virtio: legacy transport with non-port IO?") - } + device.transport.reset(); + reinit(&device)?; + + Ok(device) } diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 292bf429a6..0ad300a673 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -90,13 +90,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result _ => continue, } - let bar = pci_config.func.bars[capability.bar as usize]; - let addr = match bar { - PciBar::Memory32(addr) => addr as usize, - PciBar::Memory64(addr) => addr as usize, - - _ => unreachable!("virtio: unsupported bar type: {bar:?}"), - }; + let addr = pci_config.func.bars[capability.bar as usize].expect_mem(); let address = unsafe { let addr = addr + capability.offset as usize; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 6e15e8b0da..497fb01a16 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -85,22 +85,10 @@ fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option, InterruptMethod) { let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); - let bar = pci_config.func.bars[0]; + let bar_ptr = pci_config.func.bars[0].expect_mem() as u64; let bar_size = pci_config.func.bar_sizes[0] as u64; let irq = pci_config.func.legacy_interrupt_line; - let bar_ptr = match bar { - pcid_interface::PciBar::Memory32(ptr) => match ptr { - 0 => panic!("BAR 0 is mapped to address 0"), - _ => ptr as u64, - }, - pcid_interface::PciBar::Memory64(ptr) => match ptr { - 0 => panic!("BAR 0 is mapped to address 0"), - _ => ptr, - }, - other => panic!("Expected memory bar, found {:?}", other), - }; - let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); log::debug!("XHCI PCI FEATURES: {:?}", all_pci_features); @@ -247,22 +235,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(&name); log::debug!("XHCI PCI CONFIG: {:?}", pci_config); - let bar = pci_config.func.bars[0]; + let bar_ptr = pci_config.func.bars[0].expect_mem(); let bar_size = pci_config.func.bar_sizes[0]; let irq = pci_config.func.legacy_interrupt_line; - let bar_ptr = match bar { - pcid_interface::PciBar::Memory32(ptr) => match ptr { - 0 => panic!("BAR 0 is mapped to address 0"), - _ => ptr as u64, - }, - pcid_interface::PciBar::Memory64(ptr) => match ptr { - 0 => panic!("BAR 0 is mapped to address 0"), - _ => ptr, - }, - other => panic!("Expected memory bar, found {:?}", other), - }; - let address = unsafe { common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) .expect("xhcid: failed to map address") as usize From cc015eab13b5c3d9f8ee73910911c4d9d6edc9c9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Jan 2024 21:25:50 +0100 Subject: [PATCH 0791/1301] Move PciHeader out of the pcid_interface crate --- pcid/src/main.rs | 4 +++- pcid/src/pci/mod.rs | 2 -- pcid/src/{pci/header.rs => pci_header.rs} | 12 +++++------- 3 files changed, 8 insertions(+), 10 deletions(-) rename pcid/src/{pci/header.rs => pci_header.rs} (98%) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 74c3f80688..13d16a2835 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -11,14 +11,16 @@ use redox_log::{OutputBuilder, RedoxLogger}; use crate::cfg_access::Pcie; use crate::config::Config; -use crate::pci::{CfgAccess, PciAddress, PciBar, PciClass, PciFunc, PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci::{CfgAccess, PciAddress, PciBar, PciClass, PciFunc}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; +use crate::pci_header::{PciHeader, PciHeaderError, PciHeaderType}; mod cfg_access; mod config; mod driver_interface; mod pci; +mod pci_header; #[derive(StructOpt)] #[structopt(about)] diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 264a3f35dd..8f5e661ab7 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -6,14 +6,12 @@ use serde::{Deserialize, Serialize}; pub use self::bar::PciBar; pub use self::class::PciClass; pub use self::func::PciFunc; -pub use self::header::{PciHeader, PciHeaderError, PciHeaderType}; pub use self::id::FullDeviceId; mod bar; pub mod cap; mod class; pub mod func; -pub mod header; mod id; pub mod msi; diff --git a/pcid/src/pci/header.rs b/pcid/src/pci_header.rs similarity index 98% rename from pcid/src/pci/header.rs rename to pcid/src/pci_header.rs index 00de49ed30..cb3c59405f 100644 --- a/pcid/src/pci/header.rs +++ b/pcid/src/pci_header.rs @@ -2,10 +2,8 @@ use bitflags::bitflags; use byteorder::{ByteOrder, LittleEndian}; use serde::{Deserialize, Serialize}; -use super::bar::PciBar; -use super::class::PciClass; -use super::func::ConfigReader; -use super::id::FullDeviceId; +use crate::pci::{FullDeviceId, PciBar, PciClass}; +use crate::pci::func::ConfigReader; #[derive(Debug, PartialEq)] pub enum PciHeaderError { @@ -38,6 +36,7 @@ pub struct SharedPciHeader { header_type: PciHeaderType, } +// FIXME move out of pcid_interface #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum PciHeader { General { @@ -297,9 +296,8 @@ impl<'a> ConfigReader for &'a [u8] { #[cfg(test)] mod test { use super::{PciHeaderError, PciHeader, PciHeaderType}; - use super::super::func::ConfigReader; - use super::super::class::PciClass; - use super::super::bar::PciBar; + use crate::pci::func::ConfigReader; + use crate::pci::{PciBar, PciClass}; const IGB_DEV_BYTES: [u8; 256] = [ 0x86, 0x80, 0x33, 0x15, 0x07, 0x04, 0x10, 0x00, 0x03, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, From d56881de88847c3e326a34fefe9c10229dd36516 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:00:17 +0100 Subject: [PATCH 0792/1301] Use CfgAccess instead of ConfigReader in PciHeader::from_reader This will enable getting BAR sizes directly inside this function in the future. --- pcid/src/main.rs | 3 +- pcid/src/pci_header.rs | 121 +++++++++++++++++++++++------------------ 2 files changed, 69 insertions(+), 55 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 13d16a2835..793505276b 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -524,8 +524,7 @@ fn main(args: Args) { 'dev: for dev_num in 0..32 { for func_num in 0..8 { let func_addr = PciAddress::new(0, bus_num, dev_num, func_num); - let func = PciFunc { pci, addr: func_addr }; - match PciHeader::from_reader(func) { + match PciHeader::from_reader(pci, func_addr) { Ok(header) => { handle_parsed_header(Arc::clone(&state), &config, func_addr, header); if let PciHeader::PciToPci { secondary_bus_num, .. } = header { diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index cb3c59405f..f904e1e930 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -2,8 +2,7 @@ use bitflags::bitflags; use byteorder::{ByteOrder, LittleEndian}; use serde::{Deserialize, Serialize}; -use crate::pci::{FullDeviceId, PciBar, PciClass}; -use crate::pci::func::ConfigReader; +use crate::pci::{CfgAccess, FullDeviceId, PciAddress, PciBar, PciClass}; #[derive(Debug, PartialEq)] pub enum PciHeaderError { @@ -89,10 +88,19 @@ impl PciHeader { /// Parse the bytes found in the Configuration Space of the PCI device into /// a more usable PciHeader. - pub fn from_reader(reader: T) -> Result { - if unsafe { reader.read_u32(0) } != 0xffffffff { + pub fn from_reader( + cfg_access: &dyn CfgAccess, + addr: PciAddress, + ) -> Result { + if unsafe { cfg_access.read(addr, 0) } != 0xffffffff { // Read the initial 16 bytes and set variables used by all header types. - let bytes = unsafe { reader.read_range(0, 16) }; + let bytes = unsafe { + let mut ret = Vec::with_capacity(16); + for offset in (0..16).step_by(4) { + ret.extend(cfg_access.read(addr, offset).to_le_bytes()); + } + ret + }; let vendor_id = LittleEndian::read_u16(&bytes[0..2]); let device_id = LittleEndian::read_u16(&bytes[2..4]); let command = LittleEndian::read_u16(&bytes[4..6]); @@ -118,7 +126,13 @@ impl PciHeader { match header_type & PciHeaderType::HEADER_TYPE { PciHeaderType::GENERAL => { - let bytes = unsafe { reader.read_range(16, 48) }; + let bytes = unsafe { + let mut ret = Vec::with_capacity(48); + for offset in (16..64).step_by(4) { + ret.extend(cfg_access.read(addr, offset).to_le_bytes()); + } + ret + }; let mut bars = [PciBar::None; 6]; Self::get_bars(&bytes, &mut bars); let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]); @@ -137,7 +151,13 @@ impl PciHeader { }) } PciHeaderType::PCITOPCI => { - let bytes = unsafe { reader.read_range(16, 48) }; + let bytes = unsafe { + let mut ret = Vec::with_capacity(48); + for offset in (16..64).step_by(4) { + ret.extend(cfg_access.read(addr, offset).to_le_bytes()); + } + ret + }; let mut bars = [PciBar::None; 2]; Self::get_bars(&bytes, &mut bars); let secondary_bus_num = bytes[9]; @@ -284,20 +304,30 @@ impl PciHeader { } } -#[cfg(test)] -impl<'a> ConfigReader for &'a [u8] { - unsafe fn read_u32(&self, offset: u16) -> u32 { - let offset = offset as usize; - assert!(offset < self.len()); - LittleEndian::read_u32(&self[offset..offset + 4]) - } -} - #[cfg(test)] mod test { - use super::{PciHeaderError, PciHeader, PciHeaderType}; - use crate::pci::func::ConfigReader; - use crate::pci::{PciBar, PciClass}; + use std::convert::TryInto; + + use super::{PciHeader, PciHeaderError, PciHeaderType}; + use crate::pci::{CfgAccess, PciAddress, PciBar, PciClass}; + + struct TestCfgAccess<'a> { + addr: PciAddress, + bytes: &'a [u8], + } + + impl CfgAccess for TestCfgAccess<'_> { + unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { + assert_eq!(addr, self.addr); + let offset = offset as usize; + assert!(offset < self.bytes.len()); + u32::from_le_bytes(self.bytes[offset..offset + 4].try_into().unwrap()) + } + + unsafe fn write(&self, _addr: PciAddress, _offset: u16, _value: u32) { + unreachable!("should not write during tests"); + } + } const IGB_DEV_BYTES: [u8; 256] = [ 0x86, 0x80, 0x33, 0x15, 0x07, 0x04, 0x10, 0x00, 0x03, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, @@ -320,7 +350,14 @@ mod test { #[test] fn tset_parse_igb_dev() { - let header = PciHeader::from_reader(&IGB_DEV_BYTES[..]).unwrap(); + let header = PciHeader::from_reader( + &TestCfgAccess { + addr: PciAddress::new(0, 2, 4, 0), + bytes: &IGB_DEV_BYTES, + }, + PciAddress::new(0, 2, 4, 0), + ) + .unwrap(); assert_eq!(header.header_type(), PciHeaderType::GENERAL); assert_eq!(header.device_id(), 0x1533); assert_eq!(header.vendor_id(), 0x8086); @@ -340,38 +377,16 @@ mod test { #[test] fn test_parse_nonexistent() { - let bytes = [ - 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff - ]; - assert_eq!(PciHeader::from_reader(&bytes[..]), Err(PciHeaderError::NoDevice)); + let bytes = &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; + assert_eq!( + PciHeader::from_reader( + &TestCfgAccess { + addr: PciAddress::new(0, 2, 4, 0), + bytes, + }, + PciAddress::new(0, 2, 4, 0), + ), + Err(PciHeaderError::NoDevice) + ); } - - #[test] - fn test_read_range() { - let res = unsafe { (&IGB_DEV_BYTES[..]).read_range(0, 4) }; - assert_eq!(res, &[0x86, 0x80, 0x33, 0x15][..]); - - let res = unsafe { (&IGB_DEV_BYTES[..]).read_range(16, 32) }; - let expected = [ - 0x00, 0x00, 0x50, 0xf7, 0x00, 0x00, 0x00, 0x00, - 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf7, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0xd9, 0x15, 0x33, 0x15 - ]; - assert_eq!(res, expected); - } - - macro_rules! read_range_should_panic { - ($name:ident, $len:expr) => { - #[test] - #[should_panic(expected = "invalid range length")] - fn $name() { - let _ = unsafe { (&IGB_DEV_BYTES[..]).read_range(0, $len) }; - } - } - } - - read_range_should_panic!(test_short_len, 2); - read_range_should_panic!(test_not_mod_4_len, 7); } From 0b611dca044b0d41bbaf691f4cdd532e77fe1ddd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 11:25:43 +0100 Subject: [PATCH 0793/1301] Start using the pci_types crate --- Cargo.lock | 23 +++++++--- pcid/Cargo.toml | 1 + pcid/src/cfg_access/fallback.rs | 15 +++++-- pcid/src/cfg_access/mod.rs | 8 +++- pcid/src/driver_interface/mod.rs | 20 +++++++++ pcid/src/main.rs | 7 ++-- pcid/src/pci/func.rs | 5 +-- pcid/src/pci/mod.rs | 72 +------------------------------- pcid/src/pci_header.rs | 16 +++++-- 9 files changed, 74 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5364d127f1..47e84816d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -196,9 +196,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" [[package]] name = "bitvec" @@ -527,7 +527,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8283e7331b8c93b9756e0cfdbcfb90312852f953c6faf9bf741e684cc3b6ad69" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.2", "crc", "log", "uuid", @@ -698,7 +698,7 @@ version = "0.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.2", "libc", "redox_syscall 0.4.1", ] @@ -956,6 +956,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "pci_types" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831e5bebf010674bc2e8070b892948120d4c453c71f37387e1ffea5636620dbe" +dependencies = [ + "bit_field", + "bitflags 2.4.2", +] + [[package]] name = "pcid" version = "0.1.0" @@ -968,6 +978,7 @@ dependencies = [ "libc", "log", "paw", + "pci_types", "plain", "redox-log", "redox_syscall 0.4.1", @@ -1151,7 +1162,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "475e252d7add4825405d2248d530d33e22364ac5477eab816b56efbeec1e2712" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.2", "libredox", "redox_syscall 0.4.1", ] @@ -1727,7 +1738,7 @@ dependencies = [ name = "virtio-core" version = "0.1.0" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.4.2", "common", "crossbeam-queue", "futures", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 6c276cc52b..794002fb18 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -19,6 +19,7 @@ byteorder = "1.2" libc = "0.2" log = "0.4" paw = "1.0" +pci_types = "0.6.1" plain = "0.2" redox-log = "0.1" redox_syscall = "0.4" diff --git a/pcid/src/cfg_access/fallback.rs b/pcid/src/cfg_access/fallback.rs index 90023961f7..65682e171f 100644 --- a/pcid/src/cfg_access/fallback.rs +++ b/pcid/src/cfg_access/fallback.rs @@ -6,8 +6,7 @@ use std::sync::Mutex; use syscall::io::{Io as _, Pio}; use log::info; - -use crate::pci::{CfgAccess, PciAddress}; +use pci_types::{ConfigRegionAccess, PciAddress}; pub(crate) struct Pci { lock: Mutex<()>, @@ -58,7 +57,11 @@ impl Pci { } } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -impl CfgAccess for Pci { +impl ConfigRegionAccess for Pci { + fn function_exists(&self, _address: PciAddress) -> bool { + todo!(); + } + unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); @@ -86,7 +89,11 @@ impl CfgAccess for Pci { } } #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -impl CfgAccess for Pci { +impl ConfigRegionAccess for Pci { + fn function_exists(&self, _address: PciAddress) -> bool { + todo!(); + } + unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); todo!("Pci::CfgAccess::read on this architecture") diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index 0925b21d03..fd7f6e706a 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -2,8 +2,8 @@ use std::sync::Mutex; use std::{fmt, fs, io, mem, ptr, slice}; use log::info; +use pci_types::{ConfigRegionAccess, PciAddress}; -use crate::pci::{CfgAccess, PciAddress}; use fallback::Pci; mod fallback; @@ -221,7 +221,11 @@ impl Pcie { } } -impl CfgAccess for Pcie { +impl ConfigRegionAccess for Pcie { + fn function_exists(&self, _address: PciAddress) -> bool { + todo!(); + } + unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 4f7fd64703..4c01b88282 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -26,9 +26,29 @@ pub enum LegacyInterruptPin { IntD = 4, } +#[derive(Serialize, Deserialize)] +#[serde(remote = "PciAddress")] +struct PciAddressDef { + #[serde(getter = "PciAddress::segment")] + segment: u16, + #[serde(getter = "PciAddress::bus")] + bus: u8, + #[serde(getter = "PciAddress::device")] + device: u8, + #[serde(getter = "PciAddress::function")] + function: u8, +} + +impl From for PciAddress { + fn from(value: PciAddressDef) -> Self { + PciAddress::new(value.segment, value.bus, value.device, value.function) + } +} + #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct PciFunction { /// Address of the PCI function. + #[serde(with = "PciAddressDef")] pub addr: PciAddress, /// PCI Base Address Registers diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 793505276b..bd61bdf4c9 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -5,13 +5,14 @@ use std::process::Command; use std::thread; use std::sync::{Arc, Mutex}; +use pci_types::{ConfigRegionAccess, PciAddress}; use structopt::StructOpt; use log::{debug, error, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; use crate::cfg_access::Pcie; use crate::config::Config; -use crate::pci::{CfgAccess, PciAddress, PciBar, PciClass, PciFunc}; +use crate::pci::{PciBar, PciClass, PciFunc}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; use crate::pci_header::{PciHeader, PciHeaderError, PciHeaderType}; @@ -40,7 +41,7 @@ pub struct DriverHandler { state: Arc, } -fn with_pci_func_raw T>(pci: &dyn CfgAccess, addr: PciAddress, function: F) -> T { +fn with_pci_func_raw T>(pci: &dyn ConfigRegionAccess, addr: PciAddress, function: F) -> T { let func = PciFunc { pci, addr, @@ -204,7 +205,7 @@ pub struct State { pcie: Pcie, } impl State { - fn preferred_cfg_access(&self) -> &dyn CfgAccess { + fn preferred_cfg_access(&self) -> &dyn ConfigRegionAccess { &self.pcie } } diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index d6c7e93b70..7bdabff43d 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -1,6 +1,5 @@ use byteorder::{ByteOrder, LittleEndian}; - -use super::{CfgAccess, PciAddress}; +use pci_types::{ConfigRegionAccess, PciAddress}; pub trait ConfigReader { unsafe fn read_range(&self, offset: u16, len: u16) -> Vec { @@ -33,7 +32,7 @@ pub trait ConfigWriter { } pub struct PciFunc<'pci> { - pub pci: &'pci dyn CfgAccess, + pub pci: &'pci dyn ConfigRegionAccess, pub addr: PciAddress, } diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 8f5e661ab7..f0eb8b558a 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,12 +1,8 @@ -use std::fmt; - -use bit_field::BitField; -use serde::{Deserialize, Serialize}; - pub use self::bar::PciBar; pub use self::class::PciClass; pub use self::func::PciFunc; pub use self::id::FullDeviceId; +pub use pci_types::PciAddress; mod bar; pub mod cap; @@ -14,69 +10,3 @@ mod class; pub mod func; mod id; pub mod msi; - -pub trait CfgAccess { - unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32; - unsafe fn write(&self, addr: PciAddress, offset: u16, value: u32); -} - -// Copied from the pci_types crate, version 0.6.1. It has been modified to add serde support. -// FIXME If we start using it in the future use the upstream version instead. -/// The address of a PCIe function. -/// -/// PCIe supports 65536 segments, each with 256 buses, each with 32 slots, each with 8 possible functions. We pack this into a `u32`: -/// -/// ```ignore -/// 32 16 8 3 0 -/// +-------------------------------+---------------+---------+------+ -/// | segment | bus | device | func | -/// +-------------------------------+---------------+---------+------+ -/// ``` -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize)] -pub struct PciAddress(u32); - -impl PciAddress { - pub fn new(segment: u16, bus: u8, device: u8, function: u8) -> PciAddress { - let mut result = 0; - result.set_bits(0..3, function as u32); - result.set_bits(3..8, device as u32); - result.set_bits(8..16, bus as u32); - result.set_bits(16..32, segment as u32); - PciAddress(result) - } - - pub fn segment(&self) -> u16 { - self.0.get_bits(16..32) as u16 - } - - pub fn bus(&self) -> u8 { - self.0.get_bits(8..16) as u8 - } - - pub fn device(&self) -> u8 { - self.0.get_bits(3..8) as u8 - } - - pub fn function(&self) -> u8 { - self.0.get_bits(0..3) as u8 - } -} - -impl fmt::Display for PciAddress { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{:02x}-{:02x}:{:02x}.{}", - self.segment(), - self.bus(), - self.device(), - self.function() - ) - } -} - -impl fmt::Debug for PciAddress { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self) - } -} diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index f904e1e930..183b5254a4 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -1,8 +1,9 @@ use bitflags::bitflags; use byteorder::{ByteOrder, LittleEndian}; +use pci_types::{ConfigRegionAccess, PciAddress}; use serde::{Deserialize, Serialize}; -use crate::pci::{CfgAccess, FullDeviceId, PciAddress, PciBar, PciClass}; +use crate::pci::{FullDeviceId, PciBar, PciClass}; #[derive(Debug, PartialEq)] pub enum PciHeaderError { @@ -89,7 +90,7 @@ impl PciHeader { /// Parse the bytes found in the Configuration Space of the PCI device into /// a more usable PciHeader. pub fn from_reader( - cfg_access: &dyn CfgAccess, + cfg_access: &dyn ConfigRegionAccess, addr: PciAddress, ) -> Result { if unsafe { cfg_access.read(addr, 0) } != 0xffffffff { @@ -308,15 +309,21 @@ impl PciHeader { mod test { use std::convert::TryInto; + use pci_types::{ConfigRegionAccess, PciAddress}; + use super::{PciHeader, PciHeaderError, PciHeaderType}; - use crate::pci::{CfgAccess, PciAddress, PciBar, PciClass}; + use crate::pci::{PciBar, PciClass}; struct TestCfgAccess<'a> { addr: PciAddress, bytes: &'a [u8], } - impl CfgAccess for TestCfgAccess<'_> { + impl ConfigRegionAccess for TestCfgAccess<'_> { + fn function_exists(&self, _address: PciAddress) -> bool { + unreachable!(); + } + unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { assert_eq!(addr, self.addr); let offset = offset as usize; @@ -329,6 +336,7 @@ mod test { } } + #[rustfmt::skip] const IGB_DEV_BYTES: [u8; 256] = [ 0x86, 0x80, 0x33, 0x15, 0x07, 0x04, 0x10, 0x00, 0x03, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf7, From d1b6009e3d86af3ad63269c1abb7c602b24d9831 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:25:08 +0100 Subject: [PATCH 0794/1301] Start converting PciHeader::from_reader to pci_types --- pcid/src/main.rs | 41 ++++------ pcid/src/pci_header.rs | 166 ++++++++++++++++++++--------------------- 2 files changed, 95 insertions(+), 112 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index bd61bdf4c9..6250e8ec8c 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -74,7 +74,7 @@ impl DriverHandler { None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), }; unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { + with_pci_func_raw(&self.state.pcie, self.addr, |func| { capability.set_enabled(true); capability.write_message_control(func, offset); }); @@ -87,7 +87,7 @@ impl DriverHandler { None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), }; unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { + with_pci_func_raw(&self.state.pcie, self.addr, |func| { capability.set_msix_enabled(true); capability.write_a(func, offset); }); @@ -147,7 +147,7 @@ impl DriverHandler { info.set_mask_bits(mask_bits); } unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { + with_pci_func_raw(&self.state.pcie, self.addr, |func| { info.write_all(func, offset); }); } @@ -159,7 +159,7 @@ impl DriverHandler { if let Some(mask) = function_mask { info.set_function_mask(mask); unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { + with_pci_func_raw(&self.state.pcie, self.addr, |func| { info.write_a(func, offset); }); } @@ -171,7 +171,7 @@ impl DriverHandler { } PcidClientRequest::ReadConfig(offset) => { let value = unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { + with_pci_func_raw(&self.state.pcie, self.addr, |func| { func.read_u32(offset) }) }; @@ -179,7 +179,7 @@ impl DriverHandler { }, PcidClientRequest::WriteConfig(offset, value) => { unsafe { - with_pci_func_raw(self.state.preferred_cfg_access(), self.addr, |func| { + with_pci_func_raw(&self.state.pcie, self.addr, |func| { func.write_u32(offset, value); }); } @@ -204,15 +204,8 @@ pub struct State { threads: Mutex>>, pcie: Pcie, } -impl State { - fn preferred_cfg_access(&self) -> &dyn ConfigRegionAccess { - &self.pcie - } -} fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, header: PciHeader) { - let pci = state.preferred_cfg_access(); - let raw_class: u8 = header.class().into(); let mut string = format!("PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", addr, header.vendor_id(), header.device_id(), raw_class, @@ -273,9 +266,9 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he // Enable bus mastering, memory space, and I/O space unsafe { - let mut data = pci.read(addr, 0x04); + let mut data = state.pcie.read(addr, 0x04); data |= 7; - pci.write(addr, 0x04, data); + state.pcie.write(addr, 0x04, data); } // Set IRQ line to 9 if not set @@ -283,14 +276,14 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he let interrupt_pin; unsafe { - let mut data = pci.read(addr, 0x3C); + let mut data = state.pcie.read(addr, 0x3C); irq = (data & 0xFF) as u8; interrupt_pin = ((data & 0x0000_FF00) >> 8) as u8; if irq == 0xFF { irq = 9; } data = (data & 0xFFFFFF00) | irq as u32; - pci.write(addr, 0x3C, data); + state.pcie.write(addr, 0x3C, data); }; // Find BAR sizes @@ -309,11 +302,11 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he let offset = 0x10 + (i as u8) * 4; - let original = pci.read(addr, offset.into()); - pci.write(addr, offset.into(), 0xFFFFFFFF); + let original = state.pcie.read(addr, offset.into()); + state.pcie.write(addr, offset.into(), 0xFFFFFFFF); - let new = pci.read(addr, offset.into()); - pci.write(addr, offset.into(), original); + let new = state.pcie.read(addr, offset.into()); + state.pcie.write(addr, offset.into(), original); let masked = if new & 1 == 1 { new & 0xFFFFFFFC @@ -332,7 +325,7 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he let capabilities = if header.status() & (1 << 4) != 0 { let func = PciFunc { - pci: state.preferred_cfg_access(), + pci: &state.pcie, addr }; crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() @@ -509,8 +502,6 @@ fn main(args: Args) { threads: Mutex::new(Vec::new()), }); - let pci = state.preferred_cfg_access(); - info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV"); // FIXME Use full ACPI for enumerating the host bridges. MCFG only describes the first @@ -525,7 +516,7 @@ fn main(args: Args) { 'dev: for dev_num in 0..32 { for func_num in 0..8 { let func_addr = PciAddress::new(0, bus_num, dev_num, func_num); - match PciHeader::from_reader(pci, func_addr) { + match PciHeader::from_reader(&state.pcie, func_addr) { Ok(header) => { handle_parsed_header(Arc::clone(&state), &config, func_addr, header); if let PciHeader::PciToPci { secondary_bus_num, .. } = header { diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 183b5254a4..94fac26dc6 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -1,6 +1,6 @@ use bitflags::bitflags; use byteorder::{ByteOrder, LittleEndian}; -use pci_types::{ConfigRegionAccess, PciAddress}; +use pci_types::{ConfigRegionAccess, PciAddress, PciHeader as TyPciHeader}; use serde::{Deserialize, Serialize}; use crate::pci::{FullDeviceId, PciBar, PciClass}; @@ -90,96 +90,88 @@ impl PciHeader { /// Parse the bytes found in the Configuration Space of the PCI device into /// a more usable PciHeader. pub fn from_reader( - cfg_access: &dyn ConfigRegionAccess, + access: &impl ConfigRegionAccess, addr: PciAddress, ) -> Result { - if unsafe { cfg_access.read(addr, 0) } != 0xffffffff { - // Read the initial 16 bytes and set variables used by all header types. - let bytes = unsafe { - let mut ret = Vec::with_capacity(16); - for offset in (0..16).step_by(4) { - ret.extend(cfg_access.read(addr, offset).to_le_bytes()); - } - ret - }; - let vendor_id = LittleEndian::read_u16(&bytes[0..2]); - let device_id = LittleEndian::read_u16(&bytes[2..4]); - let command = LittleEndian::read_u16(&bytes[4..6]); - let status = LittleEndian::read_u16(&bytes[6..8]); - let revision = bytes[8]; - let interface = bytes[9]; - let subclass = bytes[10]; - let class = bytes[11]; - let header_type = PciHeaderType::from_bits_truncate(bytes[14]); - let shared = SharedPciHeader { - full_device_id: FullDeviceId { - vendor_id, - device_id, - class, - subclass, - interface, - revision, - }, - command, - status, - header_type, - }; + if unsafe { access.read(addr, 0) } == 0xffffffff { + return Err(PciHeaderError::NoDevice); + } - match header_type & PciHeaderType::HEADER_TYPE { - PciHeaderType::GENERAL => { - let bytes = unsafe { - let mut ret = Vec::with_capacity(48); - for offset in (16..64).step_by(4) { - ret.extend(cfg_access.read(addr, offset).to_le_bytes()); - } - ret - }; - let mut bars = [PciBar::None; 6]; - Self::get_bars(&bytes, &mut bars); - let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]); - let subsystem_id = LittleEndian::read_u16(&bytes[30..32]); - let cap_pointer = bytes[36]; - let interrupt_line = bytes[44]; - let interrupt_pin = bytes[45]; - Ok(PciHeader::General { - shared, - bars, - subsystem_vendor_id, - subsystem_id, - cap_pointer, - interrupt_line, - interrupt_pin, - }) - } - PciHeaderType::PCITOPCI => { - let bytes = unsafe { - let mut ret = Vec::with_capacity(48); - for offset in (16..64).step_by(4) { - ret.extend(cfg_access.read(addr, offset).to_le_bytes()); - } - ret - }; - let mut bars = [PciBar::None; 2]; - Self::get_bars(&bytes, &mut bars); - let secondary_bus_num = bytes[9]; - let cap_pointer = bytes[36]; - let interrupt_line = bytes[44]; - let interrupt_pin = bytes[45]; - let bridge_control = LittleEndian::read_u16(&bytes[46..48]); - Ok(PciHeader::PciToPci { - shared, - bars, - secondary_bus_num, - cap_pointer, - interrupt_line, - interrupt_pin, - bridge_control, - }) - } - id => Err(PciHeaderError::UnknownHeaderType(id.bits())), + let header = TyPciHeader::new(addr); + let (vendor_id, device_id) = header.id(access); + let command_and_status = unsafe { access.read(addr, 4) }; + let command = (command_and_status & 0xffff) as u16; + let status = (command_and_status >> 16) as u16; + let (revision, class, subclass, interface) = header.revision_and_class(access); + let header_type = PciHeaderType::from_bits_truncate( + ((unsafe { access.read(addr, 12) } >> 24) & 0xff) as u8, + ); + let shared = SharedPciHeader { + full_device_id: FullDeviceId { + vendor_id, + device_id, + class, + subclass, + interface, + revision, + }, + command, + status, + header_type, + }; + + match header_type & PciHeaderType::HEADER_TYPE { + PciHeaderType::GENERAL => { + let bytes = unsafe { + let mut ret = Vec::with_capacity(48); + for offset in (16..64).step_by(4) { + ret.extend(access.read(addr, offset).to_le_bytes()); + } + ret + }; + let mut bars = [PciBar::None; 6]; + Self::get_bars(&bytes, &mut bars); + let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]); + let subsystem_id = LittleEndian::read_u16(&bytes[30..32]); + let cap_pointer = bytes[36]; + let interrupt_line = bytes[44]; + let interrupt_pin = bytes[45]; + Ok(PciHeader::General { + shared, + bars, + subsystem_vendor_id, + subsystem_id, + cap_pointer, + interrupt_line, + interrupt_pin, + }) } - } else { - Err(PciHeaderError::NoDevice) + PciHeaderType::PCITOPCI => { + let bytes = unsafe { + let mut ret = Vec::with_capacity(48); + for offset in (16..64).step_by(4) { + ret.extend(access.read(addr, offset).to_le_bytes()); + } + ret + }; + let mut bars = [PciBar::None; 2]; + Self::get_bars(&bytes, &mut bars); + let secondary_bus_num = bytes[9]; + let cap_pointer = bytes[36]; + let interrupt_line = bytes[44]; + let interrupt_pin = bytes[45]; + let bridge_control = LittleEndian::read_u16(&bytes[46..48]); + Ok(PciHeader::PciToPci { + shared, + bars, + secondary_bus_num, + cap_pointer, + interrupt_line, + interrupt_pin, + bridge_control, + }) + } + id => Err(PciHeaderError::UnknownHeaderType(id.bits())), } } From a5d0c7c3544df7f5c206d13f8756e9f5a9d06e35 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 15:54:18 +0100 Subject: [PATCH 0795/1301] Use pci_types for reading BARs This simplifies a lot of code and adds support for 64bit BARs. --- ahcid/src/main.rs | 7 +- e1000d/src/main.rs | 5 +- ihdad/src/main.rs | 5 +- ixgbed/src/main.rs | 4 +- nvmed/src/main.rs | 18 ++--- pcid/src/driver_interface/mod.rs | 4 +- pcid/src/main.rs | 45 +---------- pcid/src/pci/bar.rs | 38 +++------- pcid/src/pci/msi.rs | 4 +- pcid/src/pci_header.rs | 124 ++++++++++++++----------------- rtl8139d/src/main.rs | 35 ++++----- rtl8168d/src/main.rs | 37 ++++----- vboxd/src/main.rs | 2 +- virtio-core/src/arch/x86_64.rs | 9 +-- virtio-core/src/probe.rs | 2 +- xhcid/src/main.rs | 12 ++- 16 files changed, 129 insertions(+), 222 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index bd8e6af790..3d661c321f 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -9,7 +9,7 @@ use std::io::{ErrorKind, Read, Write}; use std::os::unix::io::{FromRawFd, RawFd}; use std::usize; -use pcid_interface::{PciBar, PcidServerHandle}; +use pcid_interface::PcidServerHandle; use syscall::error::{Error, ENODEV}; use syscall::data::{Event, Packet}; use syscall::flag::EVENT_READ; @@ -81,8 +81,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_ahci"); - let bar = pci_config.func.bars[5].expect_mem(); - let bar_size = pci_config.func.bar_sizes[5]; + let (bar, bar_size) = pci_config.func.bars[5].expect_mem(); let irq = pci_config.func.legacy_interrupt_line; @@ -93,7 +92,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { common::physmap( bar, - bar_size as usize, + bar_size, common::Prot { read: true, write: true }, common::MemoryType::Uncacheable, ).expect("ahcid: failed to map address") diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 58a8a9f4ed..dffeb43f4d 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -10,7 +10,7 @@ use std::process; use std::sync::Arc; use event::EventQueue; -use pcid_interface::{PciBar, PcidServerHandle}; +use pcid_interface::PcidServerHandle; use syscall::{EventFlags, Packet, SchemeBlockMut}; pub mod device; @@ -68,8 +68,7 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_e1000"); - let bar = pci_config.func.bars[0].expect_mem(); - let bar_size = pci_config.func.bar_sizes[0] as usize; + let (bar, bar_size) = pci_config.func.bars[0].expect_mem(); let irq = pci_config.func.legacy_interrupt_line; diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index a4ff9a98f0..860446ad5c 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -160,13 +160,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_ihda"); - let bar_ptr = pci_config.func.bars[0].expect_mem(); - let bar_size = pci_config.func.bar_sizes[0]; + let (bar_ptr, bar_size) = pci_config.func.bars[0].expect_mem(); log::info!(" + IHDA {} on: {:#X} size: {}", name, bar_ptr, bar_size); let address = unsafe { - common::physmap(bar_ptr, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) + common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) .expect("ihdad: failed to map address") as usize }; diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index a0b3d46c39..4666b98142 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -13,7 +13,7 @@ use std::sync::Arc; use std::thread; use event::EventQueue; -use pcid_interface::{PciBar, PcidServerHandle}; +use pcid_interface::PcidServerHandle; use std::time::Duration; use syscall::{EventFlags, Packet, SchemeBlockMut}; @@ -76,7 +76,7 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_ixgbe"); - let bar = pci_config.func.bars[0].expect_mem(); + let (bar, _) = pci_config.func.bars[0].expect_mem(); let irq = pci_config.func.legacy_interrupt_line; diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 07933e1659..09ced15aff 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -9,7 +9,7 @@ use std::ptr::NonNull; use std::sync::{Arc, Mutex}; use std::{slice, usize}; -use pcid_interface::{PciBar, PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; +use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; use syscall::{ Event, Mmio, Packet, Result, SchemeBlockMut, PAGE_SIZE, @@ -93,10 +93,9 @@ fn get_int_method( match &mut *bar_guard { &mut Some(ref bar) => Ok(bar.ptr), bar_to_set @ &mut None => { - let bar = function.bars[bir].expect_mem(); - let bar_size = function.bar_sizes[bir]; + let (bar, bar_size) = function.bars[bir].expect_mem(); - let bar = Bar::allocate(bar as usize, bar_size as usize)?; + let bar = Bar::allocate(bar, bar_size)?; *bar_to_set = Some(bar); Ok(bar_to_set.as_ref().unwrap().ptr) } @@ -293,8 +292,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(&scheme_name); - let bar = pci_config.func.bars[0].expect_mem(); - let bar_size = pci_config.func.bar_sizes[0]; + let (bar, bar_size) = pci_config.func.bars[0].expect_mem(); let irq = pci_config.func.legacy_interrupt_line; log::debug!("NVME PCI CONFIG: {:?}", pci_config); @@ -303,16 +301,16 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { common::physmap( - bar as usize, - bar_size as usize, + bar, + bar_size, common::Prot { read: true, write: true }, common::MemoryType::Uncacheable, ) .expect("nvmed: failed to map address") } as usize; *allocated_bars.0[0].lock().unwrap() = Some(Bar { - physical: bar as usize, - bar_size: bar_size as usize, + physical: bar, + bar_size, ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"), }); diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 4c01b88282..36c002a15f 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -54,9 +54,6 @@ pub struct PciFunction { /// PCI Base Address Registers pub bars: [PciBar; 6], - /// BAR sizes - pub bar_sizes: [u32; 6], - /// Legacy IRQ line: It's the responsibility of pcid to make sure that it be mapped in either /// the I/O APIC or the 8259 PIC, so that the subdriver can map the interrupt vector directly. /// The vector to map is always this field, plus 32. @@ -282,6 +279,7 @@ impl PcidServerHandle { } } + // FIXME turn into struct with bool fields pub fn fetch_all_features(&mut self) -> Result> { self.send(&PcidClientRequest::RequestFeatures)?; match self.recv()? { diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 6250e8ec8c..de3203345d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -244,11 +244,12 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he _ => () } - for (i, bar) in header.bars().iter().enumerate() { + let bars = header.bars(&state.pcie); + for (i, bar) in bars.iter().enumerate() { match bar { PciBar::None => {}, - PciBar::Memory32(addr) => string.push_str(&format!(" {i}={addr:08X}")), - PciBar::Memory64(addr) => string.push_str(&format!(" {i}={addr:016X}")), + PciBar::Memory32{addr,..} => string.push_str(&format!(" {i}={addr:08X}")), + PciBar::Memory64{addr,..} => string.push_str(&format!(" {i}={addr:016X}")), PciBar::Port(port) => string.push_str(&format!(" {i}=P{port:04X}")), } } @@ -286,43 +287,6 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he state.pcie.write(addr, 0x3C, data); }; - // Find BAR sizes - //TODO: support 64-bit BAR sizes? - let mut bars = [PciBar::None; 6]; - let mut bar_sizes = [0; 6]; - unsafe { - let count = match header.header_type() { - PciHeaderType::GENERAL => 6, - PciHeaderType::PCITOPCI => 2, - _ => 0, - }; - - for i in 0..count { - bars[i] = header.get_bar(i); - - let offset = 0x10 + (i as u8) * 4; - - let original = state.pcie.read(addr, offset.into()); - state.pcie.write(addr, offset.into(), 0xFFFFFFFF); - - let new = state.pcie.read(addr, offset.into()); - state.pcie.write(addr, offset.into(), original); - - let masked = if new & 1 == 1 { - new & 0xFFFFFFFC - } else { - new & 0xFFFFFFF0 - }; - - let size = (!masked).wrapping_add(1); - bar_sizes[i] = if size <= 1 { - 0 - } else { - size - }; - } - } - let capabilities = if header.status() & (1 << 4) != 0 { let func = PciFunc { pci: &state.pcie, @@ -351,7 +315,6 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he let func = driver_interface::PciFunction { bars, - bar_sizes, addr, legacy_interrupt_line: irq, legacy_interrupt_pin, diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index f0d3a14911..4ee887d91f 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -5,8 +5,8 @@ use serde::{Deserialize, Serialize}; #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum PciBar { None, - Memory32(u32), - Memory64(u64), + Memory32 { addr: u32, size: u32 }, + Memory64 { addr: u64, size: u64 }, Port(u16), } @@ -21,40 +21,24 @@ impl PciBar { pub fn expect_port(&self) -> u16 { match *self { PciBar::Port(port) => port, - PciBar::Memory32(_) | PciBar::Memory64(_) => { + PciBar::Memory32 { .. } | PciBar::Memory64 { .. } => { panic!("expected port BAR, found memory BAR"); } PciBar::None => panic!("expected BAR to exist"), } } - pub fn expect_mem(&self) -> usize { + pub fn expect_mem(&self) -> (usize, usize) { match *self { - PciBar::Memory32(ptr) => ptr as usize, - PciBar::Memory64(ptr) => ptr - .try_into() - .expect("conversion from 64bit BAR to usize failed"), + PciBar::Memory32 { addr, size } => (addr as usize, size as usize), + PciBar::Memory64 { addr, size } => ( + addr.try_into() + .expect("conversion from 64bit BAR to usize failed"), + size.try_into() + .expect("conversion from 64bit BAR size to usize failed"), + ), PciBar::Port(_) => panic!("expected memory BAR, found port BAR"), PciBar::None => panic!("expected BAR to exist"), } } } - -impl From for PciBar { - fn from(bar: u32) -> Self { - if bar & 0xFFFFFFFC == 0 { - PciBar::None - } else if bar & 1 == 0 { - match (bar >> 1) & 3 { - 0 => PciBar::Memory32(bar & 0xFFFFFFF0), - 2 => PciBar::Memory64((bar & 0xFFFFFFF0) as u64), - other => { - log::warn!("unsupported PCI memory type {}", other); - PciBar::None - } - } - } else { - PciBar::Port((bar & 0xFFFC) as u16) - } - } -} diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index b4d3c67ca1..ba37e30127 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -285,7 +285,7 @@ impl MsixCapability { if self.table_bir() > 5 { panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir()); } - bars[usize::from(self.table_bir())].expect_mem() + self.table_offset() as usize + bars[usize::from(self.table_bir())].expect_mem().0 + self.table_offset() as usize } pub fn table_pointer(&self, bars: [PciBar; 6], k: u16) -> usize { self.table_base_pointer(bars) + k as usize * 16 @@ -295,7 +295,7 @@ impl MsixCapability { if self.pba_bir() > 5 { panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir()); } - bars[usize::from(self.pba_bir())].expect_mem() + self.pba_offset() as usize + bars[usize::from(self.pba_bir())].expect_mem().0 + self.pba_offset() as usize } pub fn pba_pointer_dword(&self, bars: [PciBar; 6], k: u16) -> usize { self.pba_base_pointer(bars) + (k as usize / 32) * 4 diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 94fac26dc6..b9918fdba7 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -1,6 +1,10 @@ +use std::convert::TryInto; + use bitflags::bitflags; use byteorder::{ByteOrder, LittleEndian}; -use pci_types::{ConfigRegionAccess, PciAddress, PciHeader as TyPciHeader}; +use pci_types::{ + Bar as TyBar, ConfigRegionAccess, EndpointHeader, PciAddress, PciHeader as TyPciHeader, +}; use serde::{Deserialize, Serialize}; use crate::pci::{FullDeviceId, PciBar, PciClass}; @@ -28,20 +32,20 @@ bitflags! { } } -#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct SharedPciHeader { full_device_id: FullDeviceId, command: u16, status: u16, header_type: PciHeaderType, + addr: PciAddress, } // FIXME move out of pcid_interface -#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, PartialEq)] pub enum PciHeader { General { shared: SharedPciHeader, - bars: [PciBar; 6], subsystem_vendor_id: u16, subsystem_id: u16, cap_pointer: u8, @@ -50,7 +54,6 @@ pub enum PciHeader { }, PciToPci { shared: SharedPciHeader, - bars: [PciBar; 2], secondary_bus_num: u8, cap_pointer: u8, interrupt_line: u8, @@ -60,33 +63,6 @@ pub enum PciHeader { } impl PciHeader { - fn get_bars(bytes: &[u8], bars: &mut [PciBar]) { - let mut i = 0; - while i < bars.len() { - let offset = i * 4; - let bar_bytes = match bytes.get(offset..offset + 4) { - Some(some) => some, - None => continue, - }; - - match PciBar::from(LittleEndian::read_u32(bar_bytes)) { - PciBar::Memory64(mut addr) => { - let high_bytes = match bytes.get(offset + 4..offset + 8) { - Some(some) => some, - None => continue, - }; - addr |= (LittleEndian::read_u32(high_bytes) as u64) << 32; - bars[i] = PciBar::Memory64(addr); - i += 2; - } - bar => { - bars[i] = bar; - i += 1; - } - } - } - } - /// Parse the bytes found in the Configuration Space of the PCI device into /// a more usable PciHeader. pub fn from_reader( @@ -118,10 +94,12 @@ impl PciHeader { command, status, header_type, + addr, }; match header_type & PciHeaderType::HEADER_TYPE { PciHeaderType::GENERAL => { + let endpoint_header = EndpointHeader::from_header(header, access).unwrap(); let bytes = unsafe { let mut ret = Vec::with_capacity(48); for offset in (16..64).step_by(4) { @@ -129,16 +107,11 @@ impl PciHeader { } ret }; - let mut bars = [PciBar::None; 6]; - Self::get_bars(&bytes, &mut bars); - let subsystem_vendor_id = LittleEndian::read_u16(&bytes[28..30]); - let subsystem_id = LittleEndian::read_u16(&bytes[30..32]); + let (subsystem_id, subsystem_vendor_id) = endpoint_header.subsystem(access); let cap_pointer = bytes[36]; - let interrupt_line = bytes[44]; - let interrupt_pin = bytes[45]; + let (interrupt_pin, interrupt_line) = endpoint_header.interrupt(access); Ok(PciHeader::General { shared, - bars, subsystem_vendor_id, subsystem_id, cap_pointer, @@ -154,8 +127,6 @@ impl PciHeader { } ret }; - let mut bars = [PciBar::None; 2]; - Self::get_bars(&bytes, &mut bars); let secondary_bus_num = bytes[9]; let cap_pointer = bytes[36]; let interrupt_line = bytes[44]; @@ -163,7 +134,6 @@ impl PciHeader { let bridge_control = LittleEndian::read_u16(&bytes[46..48]); Ok(PciHeader::PciToPci { shared, - bars, secondary_bus_num, cap_pointer, interrupt_line, @@ -242,29 +212,52 @@ impl PciHeader { } /// Return the Headers BARs. - pub fn bars(&self) -> &[PciBar] { - match self { - &PciHeader::General { ref bars, .. } => bars, - &PciHeader::PciToPci { ref bars, .. } => bars, - } - } + // FIXME use pci_types::Bar instead + pub fn bars(&self, access: &impl ConfigRegionAccess) -> [PciBar; 6] { + let endpoint_header = match *self { + PciHeader::General { + shared: SharedPciHeader { addr, .. }, + .. + } => EndpointHeader::from_header(TyPciHeader::new(addr), access).unwrap(), + PciHeader::PciToPci { .. } => unreachable!(), + }; - /// Return the BAR at the given index. - /// - /// # Panics - /// This function panics if the requested BAR index is beyond the length of the header - /// types BAR array. - pub fn get_bar(&self, idx: usize) -> PciBar { - match self { - &PciHeader::General { bars, .. } => { - assert!(idx < 6, "the general PCI device only has 6 BARs"); - bars[idx] + let mut bars = [PciBar::None; 6]; + let mut skip = false; + for i in 0..6 { + if skip { + skip = false; + continue; } - &PciHeader::PciToPci { bars, .. } => { - assert!(idx < 2, "the general PCI device only has 2 BARs"); - bars[idx] + match endpoint_header.bar(i, access) { + Some(TyBar::Io { port }) => { + bars[i as usize] = PciBar::Port(port.try_into().unwrap()) + } + Some(TyBar::Memory32 { + address, + size, + prefetchable: _, + }) => { + bars[i as usize] = PciBar::Memory32 { + addr: address, + size, + } + } + Some(TyBar::Memory64 { + address, + size, + prefetchable: _, + }) => { + bars[i as usize] = PciBar::Memory64 { + addr: address, + size, + }; + skip = true; // Each 64bit memory BAR occupies two slots + } + None => bars[i as usize] = PciBar::None, } } + bars } /// Return the Interrupt Line field. @@ -304,7 +297,7 @@ mod test { use pci_types::{ConfigRegionAccess, PciAddress}; use super::{PciHeader, PciHeaderError, PciHeaderType}; - use crate::pci::{PciBar, PciClass}; + use crate::pci::PciClass; struct TestCfgAccess<'a> { addr: PciAddress, @@ -365,13 +358,6 @@ mod test { assert_eq!(header.interface(), 0); assert_eq!(header.class(), PciClass::Network); assert_eq!(header.subclass(), 0); - assert_eq!(header.bars().len(), 6); - assert_eq!(header.get_bar(0), PciBar::Memory32(0xf7500000)); - assert_eq!(header.get_bar(1), PciBar::None); - assert_eq!(header.get_bar(2), PciBar::Port(0xb000)); - assert_eq!(header.get_bar(3), PciBar::Memory32(0xf7580000)); - assert_eq!(header.get_bar(4), PciBar::None); - assert_eq!(header.get_bar(5), PciBar::None); assert_eq!(header.interrupt_line(), 10); } diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index 62925a1ec2..dc3616a08a 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -171,24 +171,23 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { let pba_base = capability.pba_base_pointer(pci_config.func.bars); let bir = capability.table_bir() as usize; - let bar_ptr = pci_config.func.bars[bir].expect_mem() as u64; - let bar_size = pci_config.func.bar_sizes[bir] as u64; + let (bar_ptr, bar_size) = pci_config.func.bars[bir].expect_mem(); let address = unsafe { - common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) + common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) .expect("rtl8139d: failed to map address") as usize }; - if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u64 + table_min_length as u64)) { + if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(table_base as u64 + table_min_length as u64)) { panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); } - if !(bar_ptr..bar_ptr + bar_size).contains(&(pba_base as u64 + pba_min_length as u64)) { + if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(pba_base as u64 + pba_min_length as u64)) { panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size); } - let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; - let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; + let virt_table_base = ((table_base - bar_ptr) + address) as *mut MsixTableEntry; + let virt_pba_base = ((pba_base - bar_ptr) + address) as *mut u64; let mut info = MsixInfo { virt_table_base: NonNull::new(virt_table_base).unwrap(), @@ -299,20 +298,14 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { // RTL8139 uses BAR2, RTL8169 uses BAR1, search in that order for &barnum in &[2, 1] { match pci_config.func.bars[barnum] { - pcid_interface::PciBar::Memory32(ptr) => match ptr { - 0 => log::warn!("BAR {} is mapped to address 0", barnum), - _ => return Some(( - ptr.try_into().unwrap(), - pci_config.func.bar_sizes[barnum].try_into().unwrap() - )), - }, - pcid_interface::PciBar::Memory64(ptr) => match ptr { - 0 => log::warn!("BAR {} is mapped to address 0", barnum), - _ => return Some(( - ptr.try_into().unwrap(), - pci_config.func.bar_sizes[barnum].try_into().unwrap() - )), - }, + pcid_interface::PciBar::Memory32 { addr, size } => return Some(( + addr.try_into().unwrap(), + size.try_into().unwrap() + )), + pcid_interface::PciBar::Memory64 { addr, size } => return Some(( + addr.try_into().unwrap(), + size.try_into().unwrap() + )), other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), } } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 284b84c3e4..2592100b2c 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -169,26 +169,23 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { let pba_base = capability.pba_base_pointer(pci_config.func.bars); let bir = capability.table_bir() as usize; - let bar = pci_config.func.bars[bir]; - let bar_size = pci_config.func.bar_sizes[bir] as u64; - - let bar_ptr = bar.expect_mem() as u64; + let (bar_ptr, bar_size) = pci_config.func.bars[bir].expect_mem(); let address = unsafe { - common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) + common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) .expect("rtl8168d: failed to map address") as usize }; - if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u64 + table_min_length as u64)) { + if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(table_base as u64 + table_min_length as u64)) { panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); } - if !(bar_ptr..bar_ptr + bar_size).contains(&(pba_base as u64 + pba_min_length as u64)) { + if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(pba_base as u64 + pba_min_length as u64)) { panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size); } - let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; - let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; + let virt_table_base = ((table_base - bar_ptr) + address) as *mut MsixTableEntry; + let virt_pba_base = ((pba_base - bar_ptr) + address) as *mut u64; let mut info = MsixInfo { virt_table_base: NonNull::new(virt_table_base).unwrap(), @@ -299,20 +296,14 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { // RTL8168 uses BAR2, RTL8169 uses BAR1, search in that order for &barnum in &[2, 1] { match pci_config.func.bars[barnum] { - pcid_interface::PciBar::Memory32(ptr) => match ptr { - 0 => log::warn!("BAR {} is mapped to address 0", barnum), - _ => return Some(( - ptr.try_into().unwrap(), - pci_config.func.bar_sizes[barnum].try_into().unwrap() - )), - }, - pcid_interface::PciBar::Memory64(ptr) => match ptr { - 0 => log::warn!("BAR {} is mapped to address 0", barnum), - _ => return Some(( - ptr.try_into().unwrap(), - pci_config.func.bar_sizes[barnum].try_into().unwrap() - )), - }, + pcid_interface::PciBar::Memory32 { addr, size } => return Some(( + addr.try_into().unwrap(), + size.try_into().unwrap() + )), + pcid_interface::PciBar::Memory64 { addr, size } => return Some(( + addr.try_into().unwrap(), + size.try_into().unwrap() + )), other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), } } diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 0602649c5c..77f43eb10d 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -196,7 +196,7 @@ fn main() { let bar0 = pci_config.func.bars[0].expect_port(); - let bar1 = pci_config.func.bars[1].expect_mem(); + let (bar1, _) = pci_config.func.bars[1].expect_mem(); let irq = pci_config.func.legacy_interrupt_line; diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index 2dd3cd27d3..5bccd00c2a 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -27,13 +27,12 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { let pba_base = capability.pba_base_pointer(pci_config.func.bars); let bir = capability.table_bir() as usize; - let bar_ptr = pci_config.func.bars[bir].expect_mem() as u64; - let bar_size = pci_config.func.bar_sizes[bir] as u64; + let (bar_ptr, bar_size) = pci_config.func.bars[bir].expect_mem(); let address = unsafe { common::physmap( - bar_ptr as usize, - bar_size as usize, + bar_ptr, + bar_size, common::Prot::RW, common::MemoryType::Uncacheable, )? as usize @@ -41,7 +40,7 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { // Ensure that the table and PBA are be within the BAR. { - let bar_range = bar_ptr..bar_ptr + bar_size; + let bar_range = bar_ptr as u64..bar_ptr as u64 + bar_size as u64; assert!(bar_range.contains(&(table_base as u64 + table_min_length as u64))); assert!(bar_range.contains(&(pba_base as u64 + pba_min_length as u64))); } diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 0ad300a673..4f7d48719d 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -90,7 +90,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result _ => continue, } - let addr = pci_config.func.bars[capability.bar as usize].expect_mem(); + let (addr, _) = pci_config.func.bars[capability.bar as usize].expect_mem(); let address = unsafe { let addr = addr + capability.offset as usize; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 497fb01a16..9c8dbf542e 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -85,8 +85,7 @@ fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option, InterruptMethod) { let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); - let bar_ptr = pci_config.func.bars[0].expect_mem() as u64; - let bar_size = pci_config.func.bar_sizes[0] as u64; + let (bar_ptr, bar_size) = pci_config.func.bars[0].expect_mem(); let irq = pci_config.func.legacy_interrupt_line; let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); @@ -146,11 +145,11 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option let pba_base = capability.pba_base_pointer(pci_config.func.bars); - if !(bar_ptr..bar_ptr + bar_size).contains(&(table_base as u64 + table_min_length as u64)) { + if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(table_base as u64 + table_min_length as u64)) { panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); } - if !(bar_ptr..bar_ptr + bar_size).contains(&(pba_base as u64 + pba_min_length as u64)) { + if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(pba_base as u64 + pba_min_length as u64)) { panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size); } @@ -235,12 +234,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(&name); log::debug!("XHCI PCI CONFIG: {:?}", pci_config); - let bar_ptr = pci_config.func.bars[0].expect_mem(); - let bar_size = pci_config.func.bar_sizes[0]; + let (bar_ptr, bar_size) = pci_config.func.bars[0].expect_mem(); let irq = pci_config.func.legacy_interrupt_line; let address = unsafe { - common::physmap(bar_ptr as usize, bar_size as usize, common::Prot::RW, common::MemoryType::Uncacheable) + common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) .expect("xhcid: failed to map address") as usize }; From d2431d41404c2afddcd069a11536454ba22192bb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:32:18 +0100 Subject: [PATCH 0796/1301] Make all parsing in PciHeader::from_reader use pci_types --- pcid/src/pci_header.rs | 68 +++++++----------------------------------- 1 file changed, 10 insertions(+), 58 deletions(-) diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index b9918fdba7..de5d02c004 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -1,9 +1,9 @@ use std::convert::TryInto; use bitflags::bitflags; -use byteorder::{ByteOrder, LittleEndian}; use pci_types::{ Bar as TyBar, ConfigRegionAccess, EndpointHeader, PciAddress, PciHeader as TyPciHeader, + PciPciBridgeHeader, }; use serde::{Deserialize, Serialize}; @@ -41,7 +41,6 @@ pub struct SharedPciHeader { addr: PciAddress, } -// FIXME move out of pcid_interface #[derive(Clone, Copy, Debug, PartialEq)] pub enum PciHeader { General { @@ -49,16 +48,11 @@ pub enum PciHeader { subsystem_vendor_id: u16, subsystem_id: u16, cap_pointer: u8, - interrupt_line: u8, - interrupt_pin: u8, }, PciToPci { shared: SharedPciHeader, secondary_bus_num: u8, cap_pointer: u8, - interrupt_line: u8, - interrupt_pin: u8, - bridge_control: u16, }, } @@ -100,65 +94,29 @@ impl PciHeader { match header_type & PciHeaderType::HEADER_TYPE { PciHeaderType::GENERAL => { let endpoint_header = EndpointHeader::from_header(header, access).unwrap(); - let bytes = unsafe { - let mut ret = Vec::with_capacity(48); - for offset in (16..64).step_by(4) { - ret.extend(access.read(addr, offset).to_le_bytes()); - } - ret - }; let (subsystem_id, subsystem_vendor_id) = endpoint_header.subsystem(access); - let cap_pointer = bytes[36]; - let (interrupt_pin, interrupt_line) = endpoint_header.interrupt(access); + let cap_pointer = (unsafe { access.read(addr, 0x34) } & 0xff) as u8; Ok(PciHeader::General { shared, subsystem_vendor_id, subsystem_id, cap_pointer, - interrupt_line, - interrupt_pin, }) } PciHeaderType::PCITOPCI => { - let bytes = unsafe { - let mut ret = Vec::with_capacity(48); - for offset in (16..64).step_by(4) { - ret.extend(access.read(addr, offset).to_le_bytes()); - } - ret - }; - let secondary_bus_num = bytes[9]; - let cap_pointer = bytes[36]; - let interrupt_line = bytes[44]; - let interrupt_pin = bytes[45]; - let bridge_control = LittleEndian::read_u16(&bytes[46..48]); + let bridge_header = PciPciBridgeHeader::from_header(header, access).unwrap(); + let secondary_bus_num = bridge_header.secondary_bus_number(access); + let cap_pointer = (unsafe { access.read(addr, 0x34) } & 0xff) as u8; Ok(PciHeader::PciToPci { shared, secondary_bus_num, cap_pointer, - interrupt_line, - interrupt_pin, - bridge_control, }) } id => Err(PciHeaderError::UnknownHeaderType(id.bits())), } } - /// Return the Header Type. - pub fn header_type(&self) -> PciHeaderType { - match self { - &PciHeader::General { - shared: SharedPciHeader { header_type, .. }, - .. - } - | &PciHeader::PciToPci { - shared: SharedPciHeader { header_type, .. }, - .. - } => header_type, - } - } - /// Return all identifying information of the PCI function. pub fn full_device_id(&self) -> &FullDeviceId { match self { @@ -260,14 +218,6 @@ impl PciHeader { bars } - /// Return the Interrupt Line field. - pub fn interrupt_line(&self) -> u8 { - match self { - &PciHeader::General { interrupt_line, .. } - | &PciHeader::PciToPci { interrupt_line, .. } => interrupt_line, - } - } - pub fn status(&self) -> u16 { match self { &PciHeader::General { @@ -296,7 +246,7 @@ mod test { use pci_types::{ConfigRegionAccess, PciAddress}; - use super::{PciHeader, PciHeaderError, PciHeaderType}; + use super::{PciHeader, PciHeaderError}; use crate::pci::PciClass; struct TestCfgAccess<'a> { @@ -351,14 +301,16 @@ mod test { PciAddress::new(0, 2, 4, 0), ) .unwrap(); - assert_eq!(header.header_type(), PciHeaderType::GENERAL); + match header { + PciHeader::General { .. } => {} + _ => panic!("wrong header type"), + } assert_eq!(header.device_id(), 0x1533); assert_eq!(header.vendor_id(), 0x8086); assert_eq!(header.revision(), 3); assert_eq!(header.interface(), 0); assert_eq!(header.class(), PciClass::Network); assert_eq!(header.subclass(), 0); - assert_eq!(header.interrupt_line(), 10); } #[test] From fb0dcb384bb789081ca823170a636370510096f1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:48:52 +0100 Subject: [PATCH 0797/1301] Use pci_types in a couple more places in PciHeader::from_reader --- pcid/src/main.rs | 4 ++-- pcid/src/pci_header.rs | 39 ++++++++------------------------------- 2 files changed, 10 insertions(+), 33 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index de3203345d..1c2c1d14e7 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -15,7 +15,7 @@ use crate::config::Config; use crate::pci::{PciBar, PciClass, PciFunc}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; -use crate::pci_header::{PciHeader, PciHeaderError, PciHeaderType}; +use crate::pci_header::{PciHeader, PciHeaderError}; mod cfg_access; mod config; @@ -493,7 +493,7 @@ fn main(args: Args) { } }, Err(PciHeaderError::UnknownHeaderType(id)) => { - warn!("pcid: unknown header type: {}", id); + warn!("pcid: unknown header type: {id:?}"); } } } diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index de5d02c004..605743d5a9 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -1,35 +1,16 @@ use std::convert::TryInto; -use bitflags::bitflags; use pci_types::{ - Bar as TyBar, ConfigRegionAccess, EndpointHeader, PciAddress, PciHeader as TyPciHeader, - PciPciBridgeHeader, + Bar as TyBar, ConfigRegionAccess, EndpointHeader, HeaderType, PciAddress, + PciHeader as TyPciHeader, PciPciBridgeHeader, }; -use serde::{Deserialize, Serialize}; use crate::pci::{FullDeviceId, PciBar, PciClass}; #[derive(Debug, PartialEq)] pub enum PciHeaderError { NoDevice, - UnknownHeaderType(u8), -} - -bitflags! { - /// Flags found in the status register of a PCI device - #[derive(Serialize, Deserialize)] - pub struct PciHeaderType: u8 { - /// A general PCI device (Type 0x01). - const GENERAL = 0b00000000; - /// A PCI-to-PCI bridge device (Type 0x01). - const PCITOPCI = 0b00000001; - /// A PCI-to-PCI bridge device (Type 0x02). - const CARDBUSBRIDGE = 0b00000010; - /// A multifunction device. - const MULTIFUNCTION = 0b01000000; - /// Mask used for fetching the header type. - const HEADER_TYPE = 0b00000011; - } + UnknownHeaderType(HeaderType), } #[derive(Clone, Copy, Debug, PartialEq)] @@ -37,7 +18,6 @@ pub struct SharedPciHeader { full_device_id: FullDeviceId, command: u16, status: u16, - header_type: PciHeaderType, addr: PciAddress, } @@ -73,9 +53,7 @@ impl PciHeader { let command = (command_and_status & 0xffff) as u16; let status = (command_and_status >> 16) as u16; let (revision, class, subclass, interface) = header.revision_and_class(access); - let header_type = PciHeaderType::from_bits_truncate( - ((unsafe { access.read(addr, 12) } >> 24) & 0xff) as u8, - ); + let header_type = header.header_type(access); let shared = SharedPciHeader { full_device_id: FullDeviceId { vendor_id, @@ -87,12 +65,11 @@ impl PciHeader { }, command, status, - header_type, addr, }; - match header_type & PciHeaderType::HEADER_TYPE { - PciHeaderType::GENERAL => { + match header_type { + HeaderType::Endpoint => { let endpoint_header = EndpointHeader::from_header(header, access).unwrap(); let (subsystem_id, subsystem_vendor_id) = endpoint_header.subsystem(access); let cap_pointer = (unsafe { access.read(addr, 0x34) } & 0xff) as u8; @@ -103,7 +80,7 @@ impl PciHeader { cap_pointer, }) } - PciHeaderType::PCITOPCI => { + HeaderType::PciPciBridge => { let bridge_header = PciPciBridgeHeader::from_header(header, access).unwrap(); let secondary_bus_num = bridge_header.secondary_bus_number(access); let cap_pointer = (unsafe { access.read(addr, 0x34) } & 0xff) as u8; @@ -113,7 +90,7 @@ impl PciHeader { cap_pointer, }) } - id => Err(PciHeaderError::UnknownHeaderType(id.bits())), + ty => Err(PciHeaderError::UnknownHeaderType(ty)), } } From 18529f6cee6ed02f4d4378b1e0395ab940d722a5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 16:57:53 +0100 Subject: [PATCH 0798/1301] Remove PciClass in favor of pci_types::DeviceType --- pcid/src/main.rs | 48 +++++++++---------------- pcid/src/pci/class.rs | 79 ------------------------------------------ pcid/src/pci/mod.rs | 2 -- pcid/src/pci_header.rs | 13 ++++--- 4 files changed, 25 insertions(+), 117 deletions(-) delete mode 100644 pcid/src/pci/class.rs diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 1c2c1d14e7..5789d21263 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -5,6 +5,7 @@ use std::process::Command; use std::thread; use std::sync::{Arc, Mutex}; +use pci_types::device_type::DeviceType; use pci_types::{ConfigRegionAccess, PciAddress}; use structopt::StructOpt; use log::{debug, error, info, warn, trace}; @@ -12,7 +13,7 @@ use redox_log::{OutputBuilder, RedoxLogger}; use crate::cfg_access::Pcie; use crate::config::Config; -use crate::pci::{PciBar, PciClass, PciFunc}; +use crate::pci::{PciBar, PciFunc}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; use crate::pci_header::{PciHeader, PciHeaderError}; @@ -210,38 +211,23 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he let mut string = format!("PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", addr, header.vendor_id(), header.device_id(), raw_class, header.subclass(), header.interface(), header.revision(), header.class()); - match header.class() { - PciClass::Legacy if header.subclass() == 1 => string.push_str(" VGA CTL"), - PciClass::Storage => match header.subclass() { - 0x01 => { - string.push_str(" IDE"); - }, - 0x06 => if header.interface() == 0 { - string.push_str(" SATA VND"); - } else if header.interface() == 1 { - string.push_str(" SATA AHCI"); - }, - _ => () + let device_type = DeviceType::from((header.class(), header.subclass())); + match device_type { + DeviceType::LegacyVgaCompatible => string.push_str(" VGA CTL"), + DeviceType::IdeController => string.push_str(" IDE"), + DeviceType::SataController => match header.interface() { + 0 => string.push_str(" SATA VND"), + 1 => string.push_str(" SATA AHCI"), + _ => (), }, - PciClass::SerialBus => match header.subclass() { - 0x03 => match header.interface() { - 0x00 => { - string.push_str(" UHCI"); - }, - 0x10 => { - string.push_str(" OHCI"); - }, - 0x20 => { - string.push_str(" EHCI"); - }, - 0x30 => { - string.push_str(" XHCI"); - }, - _ => () - }, - _ => () + DeviceType::UsbController => match header.interface() { + 0x00 => string.push_str(" UHCI"), + 0x10 => string.push_str(" OHCI"), + 0x20 => string.push_str(" EHCI"), + 0x30 => string.push_str(" XHCI"), + _ => (), }, - _ => () + _ => (), } let bars = header.bars(&state.pcie); diff --git a/pcid/src/pci/class.rs b/pcid/src/pci/class.rs deleted file mode 100644 index 042c354df0..0000000000 --- a/pcid/src/pci/class.rs +++ /dev/null @@ -1,79 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] -pub enum PciClass { - Legacy, - Storage, - Network, - Display, - Multimedia, - Memory, - Bridge, - SimpleComms, - Peripheral, - Input, - Docking, - Processor, - SerialBus, - Wireless, - IntelligentIo, - SatelliteComms, - Cryptography, - SignalProc, - Reserved(u8), - Unknown -} - -impl From for PciClass { - fn from(class: u8) -> PciClass { - match class { - 0x00 => PciClass::Legacy, - 0x01 => PciClass::Storage, - 0x02 => PciClass::Network, - 0x03 => PciClass::Display, - 0x04 => PciClass::Multimedia, - 0x05 => PciClass::Memory, - 0x06 => PciClass::Bridge, - 0x07 => PciClass::SimpleComms, - 0x08 => PciClass::Peripheral, - 0x09 => PciClass::Input, - 0x0A => PciClass::Docking, - 0x0B => PciClass::Processor, - 0x0C => PciClass::SerialBus, - 0x0D => PciClass::Wireless, - 0x0E => PciClass::IntelligentIo, - 0x0F => PciClass::SatelliteComms, - 0x10 => PciClass::Cryptography, - 0x11 => PciClass::SignalProc, - 0xFF => PciClass::Unknown, - reserved => PciClass::Reserved(reserved) - } - } -} - -impl Into for PciClass { - fn into(self) -> u8 { - match self { - PciClass::Legacy => 0x00, - PciClass::Storage => 0x01, - PciClass::Network => 0x02, - PciClass::Display => 0x03, - PciClass::Multimedia => 0x04, - PciClass::Memory => 0x05, - PciClass::Bridge => 0x06, - PciClass::SimpleComms => 0x07, - PciClass::Peripheral => 0x08, - PciClass::Input => 0x09, - PciClass::Docking => 0x0A, - PciClass::Processor => 0x0B, - PciClass::SerialBus => 0x0C, - PciClass::Wireless => 0x0D, - PciClass::IntelligentIo => 0x0E, - PciClass::SatelliteComms => 0x0F, - PciClass::Cryptography => 0x10, - PciClass::SignalProc => 0x11, - PciClass::Unknown => 0xFF, - PciClass::Reserved(reserved) => reserved - } - } -} diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index f0eb8b558a..b8080263f5 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,12 +1,10 @@ pub use self::bar::PciBar; -pub use self::class::PciClass; pub use self::func::PciFunc; pub use self::id::FullDeviceId; pub use pci_types::PciAddress; mod bar; pub mod cap; -mod class; pub mod func; mod id; pub mod msi; diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 605743d5a9..9905af380e 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -5,7 +5,7 @@ use pci_types::{ PciHeader as TyPciHeader, PciPciBridgeHeader, }; -use crate::pci::{FullDeviceId, PciBar, PciClass}; +use crate::pci::{FullDeviceId, PciBar}; #[derive(Debug, PartialEq)] pub enum PciHeaderError { @@ -142,8 +142,8 @@ impl PciHeader { } /// Return the Class field. - pub fn class(&self) -> PciClass { - PciClass::from(self.full_device_id().class) + pub fn class(&self) -> u8 { + self.full_device_id().class } /// Return the Headers BARs. @@ -221,10 +221,10 @@ impl PciHeader { mod test { use std::convert::TryInto; + use pci_types::device_type::DeviceType; use pci_types::{ConfigRegionAccess, PciAddress}; use super::{PciHeader, PciHeaderError}; - use crate::pci::PciClass; struct TestCfgAccess<'a> { addr: PciAddress, @@ -286,7 +286,10 @@ mod test { assert_eq!(header.vendor_id(), 0x8086); assert_eq!(header.revision(), 3); assert_eq!(header.interface(), 0); - assert_eq!(header.class(), PciClass::Network); + assert_eq!( + DeviceType::from((header.class(), header.subclass())), + DeviceType::EthernetController + ); assert_eq!(header.subclass(), 0); } From 545596f296f86680239f02441c09bb7faa80c00e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 17:54:38 +0100 Subject: [PATCH 0799/1301] Don't try to fetch BARs unless there is a matching driver Fetching BARs will temporarily invalidate them, which could cause crashes if a driver happens to access it at the same time. As we don't yet use a single pcid instance, we don't know which devices have a driver attached or not. As such approximate this as the set of devices for which the current pcid instance would load a driver. --- pcid/src/main.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 5789d21263..de7bbe0508 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -207,9 +207,8 @@ pub struct State { } fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, header: PciHeader) { - let raw_class: u8 = header.class().into(); let mut string = format!("PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", - addr, header.vendor_id(), header.device_id(), raw_class, + addr, header.vendor_id(), header.device_id(), header.class(), header.subclass(), header.interface(), header.revision(), header.class()); let device_type = DeviceType::from((header.class(), header.subclass())); match device_type { @@ -229,17 +228,6 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he }, _ => (), } - - let bars = header.bars(&state.pcie); - for (i, bar) in bars.iter().enumerate() { - match bar { - PciBar::None => {}, - PciBar::Memory32{addr,..} => string.push_str(&format!(" {i}={addr:08X}")), - PciBar::Memory64{addr,..} => string.push_str(&format!(" {i}={addr:016X}")), - PciBar::Port(port) => string.push_str(&format!(" {i}=P{port:04X}")), - } - } - info!("{}", string); for driver in config.drivers.iter() { @@ -251,6 +239,21 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he continue; }; + let mut string = String::new(); + let bars = header.bars(&state.pcie); + for (i, bar) in bars.iter().enumerate() { + match bar { + PciBar::None => {}, + PciBar::Memory32 { addr, .. } => string.push_str(&format!(" {i}={addr:08X}")), + PciBar::Memory64 { addr, .. } => string.push_str(&format!(" {i}={addr:016X}")), + PciBar::Port(port) => string.push_str(&format!(" {i}=P{port:04X}")), + } + } + + if !string.is_empty() { + info!(" BAR{}", string); + } + // Enable bus mastering, memory space, and I/O space unsafe { let mut data = state.pcie.read(addr, 0x04); From 623d12f2765b7d7f9fceb43c1f16d6d5509a5f0c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 18:03:46 +0100 Subject: [PATCH 0800/1301] Only try to load drivers for endpoint functions For bridge functions we don't have any existing drivers and we currently panic if we would try to load a driver for them. --- pcid/src/main.rs | 24 ++++++++++++++---- pcid/src/pci_header.rs | 55 ++++++++++++++++++------------------------ 2 files changed, 42 insertions(+), 37 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index de7bbe0508..b4778dbbaf 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -16,7 +16,7 @@ use crate::config::Config; use crate::pci::{PciBar, PciFunc}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; -use crate::pci_header::{PciHeader, PciHeaderError}; +use crate::pci_header::{PciEndpointHeader, PciHeader, PciHeaderError}; mod cfg_access; mod config; @@ -206,7 +206,7 @@ pub struct State { pcie: Pcie, } -fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, header: PciHeader) { +fn print_pci_function(addr: PciAddress, header: &PciHeader) { let mut string = format!("PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", addr, header.vendor_id(), header.device_id(), header.class(), header.subclass(), header.interface(), header.revision(), header.class()); @@ -229,7 +229,9 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he _ => (), } info!("{}", string); +} +fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, header: PciEndpointHeader) { for driver in config.drivers.iter() { if !driver.match_function(header.full_device_id()) { continue; @@ -470,9 +472,21 @@ fn main(args: Args) { let func_addr = PciAddress::new(0, bus_num, dev_num, func_num); match PciHeader::from_reader(&state.pcie, func_addr) { Ok(header) => { - handle_parsed_header(Arc::clone(&state), &config, func_addr, header); - if let PciHeader::PciToPci { secondary_bus_num, .. } = header { - bus_nums.push(secondary_bus_num); + print_pci_function(func_addr, &header); + match header { + PciHeader::General(endpoint_header) => { + handle_parsed_header( + Arc::clone(&state), + &config, + func_addr, + endpoint_header, + ); + } + PciHeader::PciToPci { + secondary_bus_num, .. + } => { + bus_nums.push(secondary_bus_num); + } } } Err(PciHeaderError::NoDevice) => { diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 9905af380e..136042b387 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -21,14 +21,17 @@ pub struct SharedPciHeader { addr: PciAddress, } +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct PciEndpointHeader { + shared: SharedPciHeader, + subsystem_vendor_id: u16, + subsystem_id: u16, + cap_pointer: u8, +} + #[derive(Clone, Copy, Debug, PartialEq)] pub enum PciHeader { - General { - shared: SharedPciHeader, - subsystem_vendor_id: u16, - subsystem_id: u16, - cap_pointer: u8, - }, + General(PciEndpointHeader), PciToPci { shared: SharedPciHeader, secondary_bus_num: u8, @@ -73,12 +76,12 @@ impl PciHeader { let endpoint_header = EndpointHeader::from_header(header, access).unwrap(); let (subsystem_id, subsystem_vendor_id) = endpoint_header.subsystem(access); let cap_pointer = (unsafe { access.read(addr, 0x34) } & 0xff) as u8; - Ok(PciHeader::General { + Ok(PciHeader::General(PciEndpointHeader { shared, subsystem_vendor_id, subsystem_id, cap_pointer, - }) + })) } HeaderType::PciPciBridge => { let bridge_header = PciPciBridgeHeader::from_header(header, access).unwrap(); @@ -97,14 +100,14 @@ impl PciHeader { /// Return all identifying information of the PCI function. pub fn full_device_id(&self) -> &FullDeviceId { match self { - PciHeader::General { + PciHeader::General(PciEndpointHeader { shared: SharedPciHeader { full_device_id: device_id, .. }, .. - } + }) | PciHeader::PciToPci { shared: SharedPciHeader { @@ -145,17 +148,18 @@ impl PciHeader { pub fn class(&self) -> u8 { self.full_device_id().class } +} + +impl PciEndpointHeader { + pub fn full_device_id(&self) -> &FullDeviceId { + &self.shared.full_device_id + } /// Return the Headers BARs. // FIXME use pci_types::Bar instead pub fn bars(&self, access: &impl ConfigRegionAccess) -> [PciBar; 6] { - let endpoint_header = match *self { - PciHeader::General { - shared: SharedPciHeader { addr, .. }, - .. - } => EndpointHeader::from_header(TyPciHeader::new(addr), access).unwrap(), - PciHeader::PciToPci { .. } => unreachable!(), - }; + let endpoint_header = + EndpointHeader::from_header(TyPciHeader::new(self.shared.addr), access).unwrap(); let mut bars = [PciBar::None; 6]; let mut skip = false; @@ -196,24 +200,11 @@ impl PciHeader { } pub fn status(&self) -> u16 { - match self { - &PciHeader::General { - shared: SharedPciHeader { status, .. }, - .. - } - | &PciHeader::PciToPci { - shared: SharedPciHeader { status, .. }, - .. - } => status, - } + self.shared.status } pub fn cap_pointer(&self) -> u8 { - match self { - &PciHeader::General { cap_pointer, .. } | &PciHeader::PciToPci { cap_pointer, .. } => { - cap_pointer - } - } + self.cap_pointer } } From e97204756787efa9dfc6a113827712a84c59c41d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 18:12:37 +0100 Subject: [PATCH 0801/1301] Use EndpointHeader methods for the command and status registers --- pcid/src/main.rs | 16 +++++++++------- pcid/src/pci_header.rs | 18 +++++------------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index b4778dbbaf..2858433a43 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -6,7 +6,7 @@ use std::thread; use std::sync::{Arc, Mutex}; use pci_types::device_type::DeviceType; -use pci_types::{ConfigRegionAccess, PciAddress}; +use pci_types::{CommandRegister, ConfigRegionAccess, PciAddress}; use structopt::StructOpt; use log::{debug, error, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; @@ -256,12 +256,14 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he info!(" BAR{}", string); } + let endpoint_header = header.endpoint_header(&state.pcie); + // Enable bus mastering, memory space, and I/O space - unsafe { - let mut data = state.pcie.read(addr, 0x04); - data |= 7; - state.pcie.write(addr, 0x04, data); - } + endpoint_header.update_command(&state.pcie, |cmd| { + cmd | CommandRegister::BUS_MASTER_ENABLE + | CommandRegister::MEMORY_ENABLE + | CommandRegister::IO_ENABLE + }); // Set IRQ line to 9 if not set let mut irq; @@ -278,7 +280,7 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he state.pcie.write(addr, 0x3C, data); }; - let capabilities = if header.status() & (1 << 4) != 0 { + let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { let func = PciFunc { pci: &state.pcie, addr diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 136042b387..2b3a64e4c5 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -16,8 +16,6 @@ pub enum PciHeaderError { #[derive(Clone, Copy, Debug, PartialEq)] pub struct SharedPciHeader { full_device_id: FullDeviceId, - command: u16, - status: u16, addr: PciAddress, } @@ -52,9 +50,6 @@ impl PciHeader { let header = TyPciHeader::new(addr); let (vendor_id, device_id) = header.id(access); - let command_and_status = unsafe { access.read(addr, 4) }; - let command = (command_and_status & 0xffff) as u16; - let status = (command_and_status >> 16) as u16; let (revision, class, subclass, interface) = header.revision_and_class(access); let header_type = header.header_type(access); let shared = SharedPciHeader { @@ -66,8 +61,6 @@ impl PciHeader { interface, revision, }, - command, - status, addr, }; @@ -151,6 +144,10 @@ impl PciHeader { } impl PciEndpointHeader { + pub fn endpoint_header(&self, access: &impl ConfigRegionAccess) -> EndpointHeader { + EndpointHeader::from_header(TyPciHeader::new(self.shared.addr), access).unwrap() + } + pub fn full_device_id(&self) -> &FullDeviceId { &self.shared.full_device_id } @@ -158,8 +155,7 @@ impl PciEndpointHeader { /// Return the Headers BARs. // FIXME use pci_types::Bar instead pub fn bars(&self, access: &impl ConfigRegionAccess) -> [PciBar; 6] { - let endpoint_header = - EndpointHeader::from_header(TyPciHeader::new(self.shared.addr), access).unwrap(); + let endpoint_header = self.endpoint_header(access); let mut bars = [PciBar::None; 6]; let mut skip = false; @@ -199,10 +195,6 @@ impl PciEndpointHeader { bars } - pub fn status(&self) -> u16 { - self.shared.status - } - pub fn cap_pointer(&self) -> u8 { self.cap_pointer } From bd6716efe490164f88e944fccfa7adf2da216e67 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 19:07:57 +0100 Subject: [PATCH 0802/1301] Make legacy_interrupt_line an Option Drivers don't need to know the exact legacy_interrupt_pin in use. Just if legacy interrupts are enabled and if so which legacy_interrupt_line is used. --- ac97d/src/main.rs | 2 +- ahcid/src/main.rs | 2 +- e1000d/src/main.rs | 2 +- ihdad/src/main.rs | 25 ++++++++++--------------- ixgbed/src/main.rs | 2 +- nvmed/src/main.rs | 14 ++++++-------- pcid/src/driver_interface/mod.rs | 6 ++---- pcid/src/main.rs | 28 +++++++++++----------------- rtl8139d/src/main.rs | 27 +++++++++++---------------- rtl8168d/src/main.rs | 27 +++++++++++---------------- vboxd/src/main.rs | 2 +- xhcid/src/main.rs | 9 +++------ 12 files changed, 59 insertions(+), 87 deletions(-) diff --git a/ac97d/src/main.rs b/ac97d/src/main.rs index 04a5f3f7be..f061fcda7d 100644 --- a/ac97d/src/main.rs +++ b/ac97d/src/main.rs @@ -76,7 +76,7 @@ fn main() { let bar0 = pci_config.func.bars[0].expect_port(); let bar1 = pci_config.func.bars[1].expect_port(); - let irq = pci_config.func.legacy_interrupt_line; + let irq = pci_config.func.legacy_interrupt_line.expect("ac97d: no legacy interrupts supported"); print!("{}", format!(" + ac97 {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1, irq)); diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 3d661c321f..03ebaefd69 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -83,7 +83,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let (bar, bar_size) = pci_config.func.bars[5].expect_mem(); - let irq = pci_config.func.legacy_interrupt_line; + let irq = pci_config.func.legacy_interrupt_line.expect("ahcid: no legacy interrupts supported"); let _logger_ref = setup_logging(&name); diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index dffeb43f4d..3520e5be71 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -70,7 +70,7 @@ fn main() { let (bar, bar_size) = pci_config.func.bars[0].expect_mem(); - let irq = pci_config.func.legacy_interrupt_line; + let irq = pci_config.func.legacy_interrupt_line.expect("e1000d: no legacy interrupts supported"); eprintln!(" + E1000 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 860446ad5c..f447df8566 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -74,11 +74,9 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } #[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); - let irq = pci_config.func.legacy_interrupt_line; - let all_pci_features = pcid_handle.fetch_all_features().expect("ihdad: failed to fetch pci features"); log::debug!("PCI FEATURES: {:?}", all_pci_features); @@ -123,30 +121,27 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { pcid_handle.enable_feature(PciFeature::Msi).expect("ihdad: failed to enable MSI"); log::debug!("Enabled MSI"); - Some(interrupt_handle) - } else if pci_config.func.legacy_interrupt_pin.is_some() { + interrupt_handle + } else if let Some(irq) = pci_config.func.legacy_interrupt_line { log::debug!("Legacy IRQ {}", irq); // legacy INTx# interrupt pins. - Some(File::open(format!("irq:{}", irq)).expect("ihdad: failed to open legacy IRQ file")) + File::open(format!("irq:{}", irq)).expect("ihdad: failed to open legacy IRQ file") } else { - // no interrupts at all - None + panic!("ihdad: no interrupts supported at all") } } //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); - let irq = pci_config.func.legacy_interrupt_line; - if pci_config.func.legacy_interrupt_pin.is_some() { + if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. - Some(File::open(format!("irq:{}", irq)).expect("ihdad: failed to open legacy IRQ file")) + File::open(format!("irq:{}", irq)).expect("ihdad: failed to open legacy IRQ file") } else { - // no interrupts at all - None + panic!("ihdad: no interrupts supported at all") } } @@ -170,7 +165,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { }; //TODO: MSI-X - let mut irq_file = get_int_method(&mut pcid_handle).expect("ihdad: no interrupt file"); + let mut irq_file = get_int_method(&mut pcid_handle); { let vend_prod: u32 = ((pci_config.func.full_device_id.vendor_id as u32) << 16) diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index 4666b98142..f53c0259b8 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -78,7 +78,7 @@ fn main() { let (bar, _) = pci_config.func.bars[0].expect_mem(); - let irq = pci_config.func.legacy_interrupt_line; + let irq = pci_config.func.legacy_interrupt_line.expect("ixgbed: no legacy interrupts supported"); println!(" + IXGBE {} on: {:X} IRQ: {}", name, bar, irq); diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 09ced15aff..eda7d701c9 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -205,14 +205,13 @@ fn get_int_method( pcid_handle.enable_feature(PciFeature::Msi).unwrap(); Ok((interrupt_method, interrupt_sources)) - } else if function.legacy_interrupt_pin.is_some() { + } else if let Some(irq) = function.legacy_interrupt_line { // INTx# pin based interrupts. - let irq_handle = File::open(format!("irq:{}", function.legacy_interrupt_line)) + let irq_handle = File::open(format!("irq:{}", irq)) .expect("nvmed: failed to open INTx# interrupt line"); Ok((InterruptMethod::Intx, InterruptSources::Intx(irq_handle))) } else { - // No interrupts at all - todo!("handling of no interrupts") + panic!("nvmed: no interrupts supported at all") } } @@ -223,14 +222,13 @@ fn get_int_method( function: &PciFunction, allocated_bars: &AllocatedBars, ) -> Result<(InterruptMethod, InterruptSources)> { - if function.legacy_interrupt_pin.is_some() { + if let Some(irq) = function.legacy_interrupt_line { // INTx# pin based interrupts. - let irq_handle = File::open(format!("irq:{}", function.legacy_interrupt_line)) + let irq_handle = File::open(format!("irq:{}", irq)) .expect("nvmed: failed to open INTx# interrupt line"); Ok((InterruptMethod::Intx, InterruptSources::Intx(irq_handle))) } else { - // No interrupts at all - todo!("handling of no interrupts") + panic!("nvmed: no interrupts supported at all") } } diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 36c002a15f..faae3229f8 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -57,10 +57,8 @@ pub struct PciFunction { /// Legacy IRQ line: It's the responsibility of pcid to make sure that it be mapped in either /// the I/O APIC or the 8259 PIC, so that the subdriver can map the interrupt vector directly. /// The vector to map is always this field, plus 32. - pub legacy_interrupt_line: u8, - - /// Legacy interrupt pin (INTx#), none if INTx# interrupts aren't supported at all. - pub legacy_interrupt_pin: Option, + /// If INTx# interrupts aren't supported at all this is `None`. + pub legacy_interrupt_line: Option, /// All identifying information of the PCI function. pub full_device_id: FullDeviceId, diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 2858433a43..09ef81d23b 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -280,6 +280,16 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he state.pcie.write(addr, 0x3C, data); }; + let legacy_interrupt_enabled = match interrupt_pin { + 0 => false, + 1 | 2 | 3 | 4 => true, + + other => { + warn!("pcid: invalid interrupt pin: {}", other); + false + } + }; + let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { let func = PciFunc { pci: &state.pcie, @@ -291,26 +301,10 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he }; debug!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); - use driver_interface::LegacyInterruptPin; - - let legacy_interrupt_pin = match interrupt_pin { - 0 => None, - 1 => Some(LegacyInterruptPin::IntA), - 2 => Some(LegacyInterruptPin::IntB), - 3 => Some(LegacyInterruptPin::IntC), - 4 => Some(LegacyInterruptPin::IntD), - - other => { - warn!("pcid: invalid interrupt pin: {}", other); - None - } - }; - let func = driver_interface::PciFunction { bars, addr, - legacy_interrupt_line: irq, - legacy_interrupt_pin, + legacy_interrupt_line: if legacy_interrupt_enabled { Some(irq) } else { None }, full_device_id: header.full_device_id().clone(), }; diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index dc3616a08a..95051c4eb4 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -108,11 +108,9 @@ impl MsixInfo { } #[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("rtl8139d: failed to fetch config"); - let irq = pci_config.func.legacy_interrupt_line; - let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8139d: failed to fetch pci features"); log::info!("PCI FEATURES: {:?}", all_pci_features); @@ -157,7 +155,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { pcid_handle.enable_feature(PciFeature::Msi).expect("rtl8139d: failed to enable MSI"); log::info!("Enabled MSI"); - Some(interrupt_handle) + interrupt_handle } else if msix_enabled { let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8139d: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), @@ -220,34 +218,31 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { table_entry_pointer.msg_data.write(msg_data); table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); - Some(interrupt_handle) + interrupt_handle }; pcid_handle.enable_feature(PciFeature::MsiX).expect("rtl8139d: failed to enable MSI-X"); log::info!("Enabled MSI-X"); method - } else if pci_config.func.legacy_interrupt_pin.is_some() { + } else if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. - Some(File::open(format!("irq:{}", irq)).expect("rtl8139d: failed to open legacy IRQ file")) + File::open(format!("irq:{}", irq)).expect("rtl8139d: failed to open legacy IRQ file") } else { - // no interrupts at all - None + panic!("rtl8139d: no interrupts supported at all") } } //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("rtl8139d: failed to fetch config"); - let irq = pci_config.func.legacy_interrupt_line; - if pci_config.func.legacy_interrupt_pin.is_some() { + if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. - Some(File::open(format!("irq:{}", irq)).expect("rtl8139d: failed to open legacy IRQ file")) + File::open(format!("irq:{}", irq)).expect("rtl8139d: failed to open legacy IRQ file") } else { - // no interrupts at all - None + panic!("rtl8139d: no interrupts supported at all") } } @@ -340,7 +335,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { })); //TODO: MSI-X - let mut irq_file = get_int_method(&mut pcid_handle).expect("rtl8139d: no interrupt file"); + let mut irq_file = get_int_method(&mut pcid_handle); { let device = Arc::new(RefCell::new(unsafe { diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 2592100b2c..c657a716dc 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -106,11 +106,9 @@ impl MsixInfo { } #[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); - let irq = pci_config.func.legacy_interrupt_line; - let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8168d: failed to fetch pci features"); log::info!("PCI FEATURES: {:?}", all_pci_features); @@ -155,7 +153,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { pcid_handle.enable_feature(PciFeature::Msi).expect("rtl8168d: failed to enable MSI"); log::info!("Enabled MSI"); - Some(interrupt_handle) + interrupt_handle } else if msix_enabled { let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8168d: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), @@ -218,34 +216,31 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { table_entry_pointer.msg_data.write(msg_data); table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); - Some(interrupt_handle) + interrupt_handle }; pcid_handle.enable_feature(PciFeature::MsiX).expect("rtl8168d: failed to enable MSI-X"); log::info!("Enabled MSI-X"); method - } else if pci_config.func.legacy_interrupt_pin.is_some() { + } else if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. - Some(File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open legacy IRQ file")) + File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open legacy IRQ file") } else { - // no interrupts at all - None + panic!("rtl8168d: no interrupts supported at all") } } //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> Option { +fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); - let irq = pci_config.func.legacy_interrupt_line; - if pci_config.func.legacy_interrupt_pin.is_some() { + if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. - Some(File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open legacy IRQ file")) + File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open legacy IRQ file") } else { - // no interrupts at all - None + panic!("rtl8168d: no interrupts supported at all") } } @@ -338,7 +333,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { })); //TODO: MSI-X - let mut irq_file = get_int_method(&mut pcid_handle).expect("rtl8168d: no interrupt file"); + let mut irq_file = get_int_method(&mut pcid_handle); { let device = Arc::new(RefCell::new(unsafe { diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 77f43eb10d..be17b4f934 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -198,7 +198,7 @@ fn main() { let (bar1, _) = pci_config.func.bars[1].expect_mem(); - let irq = pci_config.func.legacy_interrupt_line; + let irq = pci_config.func.legacy_interrupt_line.expect("vboxd: no legacy interrupts supported"); print!("{}", format!(" + VirtualBox {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1, irq)); diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 9c8dbf542e..7fad420600 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -86,7 +86,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); let (bar_ptr, bar_size) = pci_config.func.bars[0].expect_mem(); - let irq = pci_config.func.legacy_interrupt_line; let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); log::debug!("XHCI PCI FEATURES: {:?}", all_pci_features); @@ -194,7 +193,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option log::debug!("Enabled MSI-X"); method - } else if pci_config.func.legacy_interrupt_pin.is_some() { + } else if let Some(irq) = pci_config.func.legacy_interrupt_line { log::debug!("Legacy IRQ {}", irq); // legacy INTx# interrupt pins. @@ -209,9 +208,8 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option #[cfg(not(target_arch = "x86_64"))] fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option, InterruptMethod) { let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); - let irq = pci_config.func.legacy_interrupt_line; - if pci_config.func.legacy_interrupt_pin.is_some() { + if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. (Some(File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file")), InterruptMethod::Intx) } else { @@ -235,7 +233,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::debug!("XHCI PCI CONFIG: {:?}", pci_config); let (bar_ptr, bar_size) = pci_config.func.bars[0].expect_mem(); - let irq = pci_config.func.legacy_interrupt_line; let address = unsafe { common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) @@ -246,7 +243,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { print!( "{}", - format!(" + XHCI {} on: {:016X} IRQ: {}\n", name, bar_ptr, irq) + format!(" + XHCI {} on: {:016X}\n", name, bar_ptr) ); let scheme_name = format!("usb.{}", name); From ad23ad5d93f1c8980e867d884397ac0a9910300b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 19:34:26 +0100 Subject: [PATCH 0803/1301] Introduce irq_handle helper for legacy interrupts --- ac97d/src/main.rs | 2 +- ahcid/src/main.rs | 8 +++----- e1000d/src/main.rs | 6 +----- ixgbed/src/main.rs | 3 +-- nvmed/src/main.rs | 6 ++---- pcid/Cargo.toml | 2 +- pcid/src/driver_interface/mod.rs | 27 ++++++++++++++++----------- pcid/src/main.rs | 7 ++++++- rtl8139d/src/main.rs | 4 ++-- rtl8168d/src/main.rs | 4 ++-- vboxd/src/main.rs | 2 +- xhcid/src/main.rs | 4 ++-- 12 files changed, 38 insertions(+), 37 deletions(-) diff --git a/ac97d/src/main.rs b/ac97d/src/main.rs index f061fcda7d..93f6b3297f 100644 --- a/ac97d/src/main.rs +++ b/ac97d/src/main.rs @@ -86,7 +86,7 @@ fn main() { unsafe { syscall::iopl(3) }.expect("ac97d: failed to set I/O privilege level to Ring 3"); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("ac97d: failed to open IRQ file"); + let mut irq_file = irq.irq_handle("ac97d"); let device = Arc::new(RefCell::new(unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") })); let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ac97d: failed to create hda scheme"); diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 03ebaefd69..fcd3c0920d 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -6,6 +6,7 @@ extern crate byteorder; use std::fs::File; use std::io::{ErrorKind, Read, Write}; +use std::os::fd::AsRawFd; use std::os::unix::io::{FromRawFd, RawFd}; use std::usize; @@ -105,11 +106,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { ).expect("ahcid: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - let irq_fd = syscall::open( - &format!("irq:{}", irq), - syscall::O_RDWR | syscall::O_NONBLOCK - ).expect("ahcid: failed to open irq file"); - let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; + let mut irq_file = irq.irq_handle("ahcid"); + let irq_fd = irq_file.as_raw_fd() as usize; let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 3520e5be71..094ec47b03 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -84,11 +84,7 @@ fn main() { File::from_raw_fd(socket_fd as RawFd) })); - let irq_fd = syscall::open( - format!("irq:{}", irq), - syscall::O_RDWR | syscall::O_NONBLOCK - ).expect("e1000d: failed to open IRQ file"); - let mut irq_file = unsafe { File::from_raw_fd(irq_fd as RawFd) }; + let mut irq_file = irq.irq_handle("e1000d"); let address = unsafe { common::physmap(bar, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index f53c0259b8..a9a65cd248 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -94,8 +94,7 @@ fn main() { daemon.ready().expect("ixgbed: failed to signal readiness"); - let mut irq_file = - File::open(format!("irq:{}", irq)).expect("ixgbed: failed to open IRQ file"); + let mut irq_file = irq.irq_handle("ixgbed"); let address = unsafe { common::physmap(bar, IXGBE_MMIO_SIZE, common::Prot::RW, common::MemoryType::Uncacheable) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index eda7d701c9..e52b922ebd 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -207,8 +207,7 @@ fn get_int_method( Ok((interrupt_method, interrupt_sources)) } else if let Some(irq) = function.legacy_interrupt_line { // INTx# pin based interrupts. - let irq_handle = File::open(format!("irq:{}", irq)) - .expect("nvmed: failed to open INTx# interrupt line"); + let irq_handle = irq.irq_handle("nvmed"); Ok((InterruptMethod::Intx, InterruptSources::Intx(irq_handle))) } else { panic!("nvmed: no interrupts supported at all") @@ -224,8 +223,7 @@ fn get_int_method( ) -> Result<(InterruptMethod, InterruptSources)> { if let Some(irq) = function.legacy_interrupt_line { // INTx# pin based interrupts. - let irq_handle = File::open(format!("irq:{}", irq)) - .expect("nvmed: failed to open INTx# interrupt line"); + let irq_handle = irq.irq_handle("nvmed"); Ok((InterruptMethod::Intx, InterruptSources::Intx(irq_handle))) } else { panic!("nvmed: no interrupts supported at all") diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 794002fb18..b883b4e8ce 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "pcid" version = "0.1.0" -edition = "2018" +edition = "2021" [[bin]] name = "pcid" diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index faae3229f8..1678ef7594 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -1,3 +1,4 @@ +use std::fmt; use std::fs::File; use std::io::prelude::*; use std::{env, io}; @@ -14,16 +15,20 @@ pub use crate::pci::{FullDeviceId, PciAddress, PciBar}; pub mod irq_helpers; #[derive(Clone, Copy, Debug, Serialize, Deserialize)] -#[repr(u8)] -pub enum LegacyInterruptPin { - /// INTa# - IntA = 1, - /// INTb# - IntB = 2, - /// INTc# - IntC = 3, - /// INTd# - IntD = 4, +pub struct LegacyInterruptLine(pub(crate) u8); + +impl LegacyInterruptLine { + /// Get an IRQ handle for this interrupt line. + pub fn irq_handle(self, driver: &str) -> File { + File::open(format!("irq:{}", self.0)) + .unwrap_or_else(|err| panic!("{driver}: failed to open IRQ file: {err}")) + } +} + +impl fmt::Display for LegacyInterruptLine { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) + } } #[derive(Serialize, Deserialize)] @@ -58,7 +63,7 @@ pub struct PciFunction { /// the I/O APIC or the 8259 PIC, so that the subdriver can map the interrupt vector directly. /// The vector to map is always this field, plus 32. /// If INTx# interrupts aren't supported at all this is `None`. - pub legacy_interrupt_line: Option, + pub legacy_interrupt_line: Option, /// All identifying information of the PCI function. pub full_device_id: FullDeviceId, diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 09ef81d23b..6591e385e6 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -13,6 +13,7 @@ use redox_log::{OutputBuilder, RedoxLogger}; use crate::cfg_access::Pcie; use crate::config::Config; +use crate::driver_interface::LegacyInterruptLine; use crate::pci::{PciBar, PciFunc}; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; @@ -304,7 +305,11 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he let func = driver_interface::PciFunction { bars, addr, - legacy_interrupt_line: if legacy_interrupt_enabled { Some(irq) } else { None }, + legacy_interrupt_line: if legacy_interrupt_enabled { + Some(LegacyInterruptLine(irq)) + } else { + None + }, full_device_id: header.full_device_id().clone(), }; diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index 95051c4eb4..703fc55f1b 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -227,7 +227,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { method } else if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. - File::open(format!("irq:{}", irq)).expect("rtl8139d: failed to open legacy IRQ file") + irq.irq_handle("rtl8139d") } else { panic!("rtl8139d: no interrupts supported at all") } @@ -240,7 +240,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. - File::open(format!("irq:{}", irq)).expect("rtl8139d: failed to open legacy IRQ file") + irq.irq_handle("rtl8139d") } else { panic!("rtl8139d: no interrupts supported at all") } diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index c657a716dc..19140b6f9a 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -225,7 +225,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { method } else if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. - File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open legacy IRQ file") + irq.irq_handle("rtl8168d") } else { panic!("rtl8168d: no interrupts supported at all") } @@ -238,7 +238,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. - File::open(format!("irq:{}", irq)).expect("rtl8168d: failed to open legacy IRQ file") + irq.irq_handle("rtl8168d") } else { panic!("rtl8168d: no interrupts supported at all") } diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index be17b4f934..7905f00e7f 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -221,7 +221,7 @@ fn main() { } } - let mut irq_file = File::open(format!("irq:{}", irq)).expect("vboxd: failed to open IRQ file"); + let mut irq_file = irq.irq_handle("vboxd"); let mut port = Pio::::new(bar0 as u16); let address = unsafe { common::physmap(bar1, 4096, common::Prot::RW, common::MemoryType::Uncacheable).expect("vboxd: failed to map address") }; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 7fad420600..21ea4f9d4e 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -197,7 +197,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option log::debug!("Legacy IRQ {}", irq); // legacy INTx# interrupt pins. - (Some(File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file")), InterruptMethod::Intx) + (Some(irq.irq_handle("xhcid")), InterruptMethod::Intx) } else { // no interrupts at all (None, InterruptMethod::Polling) @@ -211,7 +211,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. - (Some(File::open(format!("irq:{}", irq)).expect("xhcid: failed to open legacy IRQ file")), InterruptMethod::Intx) + (Some(irq.irq_handle("xhcid")), InterruptMethod::Intx) } else { // no interrupts at all (None, InterruptMethod::Polling) From c13161c4a52e94acf78fdf0c78399e578bc60dcd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 19:57:24 +0100 Subject: [PATCH 0804/1301] Fix nvmed --- nvmed/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index e52b922ebd..6aeceeb7f8 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -284,7 +284,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .fetch_config() .expect("nvmed: failed to fetch config"); - let scheme_name = format!("disk.pci-{}-nvme", pci_config.func.addr); + let scheme_name = format!("disk.{}-nvme", pci_config.func.name()); let _logger_ref = setup_logging(&scheme_name); From 4302a35a7e7c01f8af87eeafaaefaf7fce5a093d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 22 Jan 2024 20:44:17 +0100 Subject: [PATCH 0805/1301] Remove a couple of unused functions from MsixCapability The set and write methods were useless as no rpc call is exposed by pcid to actually write the new values. As for the rest, there were no uses and they can be emulated using the other methods. --- pcid/src/pci/msi.rs | 60 +++++++-------------------------------------- 1 file changed, 9 insertions(+), 51 deletions(-) diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index ba37e30127..fe09768a91 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -203,11 +203,11 @@ impl MsiCapability { } impl MsixCapability { - pub const MC_MSIX_ENABLED_BIT: u16 = 1 << 15; - pub const MC_MSIX_ENABLED_SHIFT: u8 = 15; - pub const MC_FUNCTION_MASK_BIT: u16 = 1 << 14; - pub const MC_FUNCTION_MASK_SHIFT: u8 = 14; - pub const MC_TABLE_SIZE_MASK: u16 = 0x03FF; + const MC_MSIX_ENABLED_BIT: u16 = 1 << 15; + const MC_MSIX_ENABLED_SHIFT: u8 = 15; + const MC_FUNCTION_MASK_BIT: u16 = 1 << 14; + const MC_FUNCTION_MASK_SHIFT: u8 = 14; + const MC_TABLE_SIZE_MASK: u16 = 0x03FF; /// The Message Control field, containing the enabled and function mask bits, as well as the /// table size. @@ -246,8 +246,8 @@ impl MsixCapability { new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT; self.set_message_control(new_message_control); } - pub const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8; - pub const TABLE_BIR_MASK: u32 = 0x0000_0007; + const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8; + const TABLE_BIR_MASK: u32 = 0x0000_0007; /// The table offset is guaranteed to be QWORD aligned (8 bytes). pub const fn table_offset(&self) -> u32 { @@ -258,13 +258,8 @@ impl MsixCapability { (self.b & Self::TABLE_BIR_MASK) as u8 } - pub fn set_table_offset(&mut self, offset: u32) { - assert_eq!(offset & Self::TABLE_OFFSET_MASK, offset, "MSI-X table offset has to be QWORD aligned"); - self.b &= !Self::TABLE_OFFSET_MASK; - self.b |= offset; - } - pub const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8; - pub const PBA_BIR_MASK: u32 = 0x0000_0007; + const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8; + const PBA_BIR_MASK: u32 = 0x0000_0007; /// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes). pub const fn pba_offset(&self) -> u32 { @@ -275,11 +270,6 @@ impl MsixCapability { (self.c & Self::PBA_BIR_MASK) as u8 } - pub fn set_pba_offset(&mut self, offset: u32) { - assert_eq!(offset & Self::PBA_OFFSET_MASK, offset, "MSI-X Pending Bit Array offset has to be QWORD aligned"); - self.c &= !Self::PBA_OFFSET_MASK; - self.c |= offset; - } pub fn table_base_pointer(&self, bars: [PciBar; 6]) -> usize { if self.table_bir() > 5 { @@ -287,9 +277,6 @@ impl MsixCapability { } bars[usize::from(self.table_bir())].expect_mem().0 + self.table_offset() as usize } - pub fn table_pointer(&self, bars: [PciBar; 6], k: u16) -> usize { - self.table_base_pointer(bars) + k as usize * 16 - } pub fn pba_base_pointer(&self, bars: [PciBar; 6]) -> usize { if self.pba_bir() > 5 { @@ -297,41 +284,12 @@ impl MsixCapability { } bars[usize::from(self.pba_bir())].expect_mem().0 + self.pba_offset() as usize } - pub fn pba_pointer_dword(&self, bars: [PciBar; 6], k: u16) -> usize { - self.pba_base_pointer(bars) + (k as usize / 32) * 4 - } - pub const fn pba_bit_dword(&self, k: u16) -> u8 { - (k % 32) as u8 - } - - pub fn pba_pointer_qword(&self, bars: [PciBar; 6], k: u16) -> usize { - self.pba_base_pointer(bars) + (k as usize / 64) * 8 - } - pub const fn pba_bit_qword(&self, k: u16) -> u8 { - (k % 64) as u8 - } /// Write the first DWORD into configuration space (containing the partially modifiable Message /// Control field). pub unsafe fn write_a(&self, writer: &W, offset: u8) { writer.write_u32(u16::from(offset), self.a) } - /// Write the second DWORD into configuration space (containing the modifiable table - /// offset and the readonly table BIR). - pub unsafe fn write_b(&self, writer: &W, offset: u8) { - writer.write_u32(u16::from(offset + 4), self.a) - } - /// Write the third DWORD into configuration space (containing the modifiable pending bit array - /// offset, and the readonly PBA BIR). - pub unsafe fn write_c(&self, writer: &W, offset: u8) { - writer.write_u32(u16::from(offset + 8), self.a) - } - /// Write this capability structure back to configuration space. - pub unsafe fn write_all(&self, writer: &W, offset: u8) { - self.write_a(writer, offset); - self.write_b(writer, offset); - self.write_c(writer, offset); - } } #[repr(packed)] From 77b97bb2edfd81733e56cec343a43e0a8c7f3206 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 23 Jan 2024 12:02:40 +0100 Subject: [PATCH 0806/1301] Introduce PciBar::physmap_mem helper --- ahcid/src/main.rs | 14 ++++---------- e1000d/src/main.rs | 10 ++++------ ihdad/src/main.rs | 8 +++----- nvmed/src/main.rs | 23 ++++++++++------------- pcid/src/pci/bar.rs | 14 ++++++++++++++ rtl8139d/src/main.rs | 8 +++----- rtl8168d/src/main.rs | 8 +++----- vboxd/src/main.rs | 7 ++++--- virtio-core/src/arch/x86_64.rs | 12 +++--------- xhcid/src/main.rs | 8 +++----- 10 files changed, 51 insertions(+), 61 deletions(-) diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index fcd3c0920d..166214934c 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -82,22 +82,16 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_ahci"); - let (bar, bar_size) = pci_config.func.bars[5].expect_mem(); + let bar = &pci_config.func.bars[5]; + let (bar_ptr, bar_size) = bar.expect_mem(); let irq = pci_config.func.legacy_interrupt_line.expect("ahcid: no legacy interrupts supported"); let _logger_ref = setup_logging(&name); - info!(" + AHCI {} on: {} size: {} IRQ: {}", name, bar, bar_size, irq); + info!(" + AHCI {} on: {} size: {} IRQ: {}", name, bar_ptr, bar_size, irq); - let address = unsafe { - common::physmap( - bar, - bar_size, - common::Prot { read: true, write: true }, - common::MemoryType::Uncacheable, - ).expect("ahcid: failed to map address") - }; + let address = unsafe { bar.physmap_mem("ahcid") }; { let scheme_name = format!("disk.{}", name); let socket_fd = syscall::open( diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 094ec47b03..d77c3f82f0 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -68,11 +68,12 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_e1000"); - let (bar, bar_size) = pci_config.func.bars[0].expect_mem(); + let bar = &pci_config.func.bars[0]; + let (bar_ptr, bar_size) = bar.expect_mem(); let irq = pci_config.func.legacy_interrupt_line.expect("e1000d: no legacy interrupts supported"); - eprintln!(" + E1000 {} on: {:X} size: {} IRQ: {}", name, bar, bar_size, irq); + eprintln!(" + E1000 {} on: {:X} size: {} IRQ: {}", name, bar_ptr, bar_size, irq); redox_daemon::Daemon::new(move |daemon| { let socket_fd = syscall::open( @@ -86,10 +87,7 @@ fn main() { let mut irq_file = irq.irq_handle("e1000d"); - let address = unsafe { - common::physmap(bar, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) - .expect("e1000d: failed to map address") - } as usize; + let address = unsafe { bar.physmap_mem("e1000d") } as usize; { let device = Arc::new(RefCell::new(unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index f447df8566..f603197608 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -155,14 +155,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_ihda"); - let (bar_ptr, bar_size) = pci_config.func.bars[0].expect_mem(); + let bar = &pci_config.func.bars[0]; + let (bar_ptr, bar_size) = bar.expect_mem(); log::info!(" + IHDA {} on: {:#X} size: {}", name, bar_ptr, bar_size); - let address = unsafe { - common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) - .expect("ihdad: failed to map address") as usize - }; + let address = unsafe { bar.physmap_mem("ihdad") } as usize; //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 6aeceeb7f8..8e57eb4db0 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -48,7 +48,12 @@ impl Bar { impl Drop for Bar { fn drop(&mut self) { - let _ = unsafe { syscall::funmap(self.physical, self.bar_size.next_multiple_of(PAGE_SIZE)) }; + let _ = unsafe { + syscall::funmap( + self.ptr.as_ptr() as usize, + self.bar_size.next_multiple_of(PAGE_SIZE), + ) + }; } } @@ -288,24 +293,16 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(&scheme_name); - let (bar, bar_size) = pci_config.func.bars[0].expect_mem(); - let irq = pci_config.func.legacy_interrupt_line; + let bar = &pci_config.func.bars[0]; + let (bar_ptr, bar_size) = bar.expect_mem(); log::debug!("NVME PCI CONFIG: {:?}", pci_config); let allocated_bars = AllocatedBars::default(); - let address = unsafe { - common::physmap( - bar, - bar_size, - common::Prot { read: true, write: true }, - common::MemoryType::Uncacheable, - ) - .expect("nvmed: failed to map address") - } as usize; + let address = unsafe { bar.physmap_mem("nvmed") } as usize; *allocated_bars.0[0].lock().unwrap() = Some(Bar { - physical: bar, + physical: bar_ptr, bar_size, ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"), }); diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index 4ee887d91f..fa497d755b 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -41,4 +41,18 @@ impl PciBar { PciBar::None => panic!("expected BAR to exist"), } } + + pub unsafe fn physmap_mem(&self, driver: &str) -> *mut () { + let (bar, bar_size) = self.expect_mem(); + unsafe { + common::physmap( + bar, + bar_size, + common::Prot::RW, + // FIXME once the kernel supports this use write-through for prefetchable BAR + common::MemoryType::Uncacheable, + ) + } + .unwrap_or_else(|err| panic!("{driver}: failed to map BAR at {bar:016X}: {err}")) + } } diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index 703fc55f1b..771683010a 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -169,12 +169,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let pba_base = capability.pba_base_pointer(pci_config.func.bars); let bir = capability.table_bir() as usize; - let (bar_ptr, bar_size) = pci_config.func.bars[bir].expect_mem(); + let bar = &pci_config.func.bars[bir]; + let (bar_ptr, bar_size) = bar.expect_mem(); - let address = unsafe { - common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) - .expect("rtl8139d: failed to map address") as usize - }; + let address = unsafe { bar.physmap_mem("rtl8139d") } as usize; if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(table_base as u64 + table_min_length as u64)) { panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 19140b6f9a..c38b506d21 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -167,12 +167,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let pba_base = capability.pba_base_pointer(pci_config.func.bars); let bir = capability.table_bir() as usize; - let (bar_ptr, bar_size) = pci_config.func.bars[bir].expect_mem(); + let bar = &pci_config.func.bars[bir]; + let (bar_ptr, bar_size) = bar.expect_mem(); - let address = unsafe { - common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) - .expect("rtl8168d: failed to map address") as usize - }; + let address = unsafe { bar.physmap_mem("rtl8168d") } as usize; if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(table_base as u64 + table_min_length as u64)) { panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 7905f00e7f..17a8c23a2d 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -196,11 +196,12 @@ fn main() { let bar0 = pci_config.func.bars[0].expect_port(); - let (bar1, _) = pci_config.func.bars[1].expect_mem(); + let bar1 = &pci_config.func.bars[1]; + let (bar1_ptr, _) = bar1.expect_mem(); let irq = pci_config.func.legacy_interrupt_line.expect("vboxd: no legacy interrupts supported"); - print!("{}", format!(" + VirtualBox {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1, irq)); + print!("{}", format!(" + VirtualBox {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1_ptr, irq)); // Daemonize redox_daemon::Daemon::new(move |daemon| { @@ -224,7 +225,7 @@ fn main() { let mut irq_file = irq.irq_handle("vboxd"); let mut port = Pio::::new(bar0 as u16); - let address = unsafe { common::physmap(bar1, 4096, common::Prot::RW, common::MemoryType::Uncacheable).expect("vboxd: failed to map address") }; + let address = unsafe { bar1.physmap_mem("vboxd") }; { let vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index 5bccd00c2a..a160f508cd 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -27,16 +27,10 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { let pba_base = capability.pba_base_pointer(pci_config.func.bars); let bir = capability.table_bir() as usize; - let (bar_ptr, bar_size) = pci_config.func.bars[bir].expect_mem(); + let bar = &pci_config.func.bars[bir]; + let (bar_ptr, bar_size) = bar.expect_mem(); - let address = unsafe { - common::physmap( - bar_ptr, - bar_size, - common::Prot::RW, - common::MemoryType::Uncacheable, - )? as usize - }; + let address = unsafe { bar.physmap_mem("virtio-core") } as usize; // Ensure that the table and PBA are be within the BAR. { diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 21ea4f9d4e..9f95131be7 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -232,12 +232,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(&name); log::debug!("XHCI PCI CONFIG: {:?}", pci_config); - let (bar_ptr, bar_size) = pci_config.func.bars[0].expect_mem(); + let bar = &pci_config.func.bars[0]; + let (bar_ptr, _) = bar.expect_mem(); - let address = unsafe { - common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) - .expect("xhcid: failed to map address") as usize - }; + let address = unsafe { bar.physmap_mem("xhcid") } as usize; let (mut irq_file, interrupt_method) = get_int_method(&mut pcid_handle, address); From 354c351b1938a7b4a30e843b083ff28149b155b9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 23 Jan 2024 13:01:40 +0100 Subject: [PATCH 0807/1301] Unify device info printing between drivers --- ac97d/src/main.rs | 2 +- ahcid/src/main.rs | 3 +-- alxd/src/device/mod.rs | 2 +- alxd/src/main.rs | 2 +- bgad/src/main.rs | 2 +- e1000d/src/main.rs | 3 +-- ihdad/src/main.rs | 3 +-- ixgbed/src/main.rs | 2 +- pcid/src/driver_interface/mod.rs | 18 ++++++++++++++++++ pcid/src/main.rs | 7 ++----- pcid/src/pci/bar.rs | 9 +++++++++ rtl8139d/src/main.rs | 2 +- rtl8168d/src/main.rs | 2 +- sb16d/src/main.rs | 2 +- vboxd/src/main.rs | 3 +-- xhcid/src/main.rs | 8 ++------ 16 files changed, 43 insertions(+), 27 deletions(-) diff --git a/ac97d/src/main.rs b/ac97d/src/main.rs index 93f6b3297f..2a26dc193b 100644 --- a/ac97d/src/main.rs +++ b/ac97d/src/main.rs @@ -78,7 +78,7 @@ fn main() { let irq = pci_config.func.legacy_interrupt_line.expect("ac97d: no legacy interrupts supported"); - print!("{}", format!(" + ac97 {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1, irq)); + println!(" + ac97 {}", pci_config.func.display()); // Daemonize redox_daemon::Daemon::new(move |daemon| { diff --git a/ahcid/src/main.rs b/ahcid/src/main.rs index 166214934c..60dd30ab12 100644 --- a/ahcid/src/main.rs +++ b/ahcid/src/main.rs @@ -83,13 +83,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { name.push_str("_ahci"); let bar = &pci_config.func.bars[5]; - let (bar_ptr, bar_size) = bar.expect_mem(); let irq = pci_config.func.legacy_interrupt_line.expect("ahcid: no legacy interrupts supported"); let _logger_ref = setup_logging(&name); - info!(" + AHCI {} on: {} size: {} IRQ: {}", name, bar_ptr, bar_size, irq); + info!(" + AHCI {}", pci_config.func.display()); let address = unsafe { bar.physmap_mem("ahcid") }; { diff --git a/alxd/src/device/mod.rs b/alxd/src/device/mod.rs index 04da35d59e..e3d8ff4996 100644 --- a/alxd/src/device/mod.rs +++ b/alxd/src/device/mod.rs @@ -1705,7 +1705,7 @@ impl Alx { } let mac = self.get_perm_macaddr(); - print!("{}", format!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); if ! self.get_phy_info() { diff --git a/alxd/src/main.rs b/alxd/src/main.rs index d52371f94a..9bd0d6edb3 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -32,7 +32,7 @@ fn main() { let irq_str = args.next().expect("alxd: no irq provided"); let irq = irq_str.parse::().expect("alxd: failed to parse irq"); - print!("{}", format!(" + ALX {} on: {:X}, IRQ: {}\n", name, bar, irq)); + println!(" + ALX {} on: {:X}, IRQ: {}\n", name, bar, irq); // Daemonize redox_daemon::Daemon::new(move |daemon| { diff --git a/bgad/src/main.rs b/bgad/src/main.rs index e9b7bb7600..18ac70df34 100644 --- a/bgad/src/main.rs +++ b/bgad/src/main.rs @@ -25,7 +25,7 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_bga"); - println!(" + BGA {}", name); + println!(" + BGA {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { unsafe { iopl(3).unwrap() }; diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index d77c3f82f0..1746883701 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -69,11 +69,10 @@ fn main() { name.push_str("_e1000"); let bar = &pci_config.func.bars[0]; - let (bar_ptr, bar_size) = bar.expect_mem(); let irq = pci_config.func.legacy_interrupt_line.expect("e1000d: no legacy interrupts supported"); - eprintln!(" + E1000 {} on: {:X} size: {} IRQ: {}", name, bar_ptr, bar_size, irq); + eprintln!(" + E1000 {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { let socket_fd = syscall::open( diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index f603197608..7f87807b40 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -156,9 +156,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { name.push_str("_ihda"); let bar = &pci_config.func.bars[0]; - let (bar_ptr, bar_size) = bar.expect_mem(); - log::info!(" + IHDA {} on: {:#X} size: {}", name, bar_ptr, bar_size); + log::info!(" + IHDA {}", pci_config.func.display()); let address = unsafe { bar.physmap_mem("ihdad") } as usize; diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index a9a65cd248..a5ec7bfa7f 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -80,7 +80,7 @@ fn main() { let irq = pci_config.func.legacy_interrupt_line.expect("ixgbed: no legacy interrupts supported"); - println!(" + IXGBE {} on: {:X} IRQ: {}", name, bar, irq); + println!(" + IXGBE {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { let socket_fd = syscall::open( diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 1678ef7594..88b7068915 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -73,6 +73,24 @@ impl PciFunction { // FIXME stop replacing : with - once it is a valid character in scheme names format!("pci-{}", self.addr).replace(':', "-") } + + pub fn display(&self) -> String { + let mut string = self.name(); + let mut first = true; + for (i, bar) in self.bars.iter().enumerate() { + if !bar.is_none() { + if first { + first = false; + string.push_str(" on:"); + } + string.push_str(&format!(" {i}={}", bar.display())); + } + } + if let Some(irq) = self.legacy_interrupt_line { + string.push_str(&format!(" IRQ: {irq}")); + } + string + } } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 6591e385e6..bbc46d0794 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -245,11 +245,8 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he let mut string = String::new(); let bars = header.bars(&state.pcie); for (i, bar) in bars.iter().enumerate() { - match bar { - PciBar::None => {}, - PciBar::Memory32 { addr, .. } => string.push_str(&format!(" {i}={addr:08X}")), - PciBar::Memory64 { addr, .. } => string.push_str(&format!(" {i}={addr:016X}")), - PciBar::Port(port) => string.push_str(&format!(" {i}=P{port:04X}")), + if !bar.is_none() { + string.push_str(&format!(" {i}={}", bar.display())); } } diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index fa497d755b..b9e8008f51 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -11,6 +11,15 @@ pub enum PciBar { } impl PciBar { + pub fn display(&self) -> String { + match self { + PciBar::None => format!(""), + PciBar::Memory32 { addr, .. } => format!("{addr:08X}"), + PciBar::Memory64 { addr, .. } => format!("{addr:016X}"), + PciBar::Port(port) => format!("P{port:04X}"), + } + } + pub fn is_none(&self) -> bool { match self { &PciBar::None => true, diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index 771683010a..e0bfbf2648 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -316,7 +316,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { name.push_str("_rtl8139"); let (bar_ptr, bar_size) = find_bar(&pci_config).expect("rtl8139d: failed to find BAR"); - log::info!(" + RTL8139 {} on: {:#X} size: {}", name, bar_ptr, bar_size); + log::info!(" + RTL8139 {}", pci_config.func.display()); let address = unsafe { common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index c38b506d21..d157ab8706 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -314,7 +314,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { name.push_str("_rtl8168"); let (bar_ptr, bar_size) = find_bar(&pci_config).expect("rtl8168d: failed to find BAR"); - log::info!(" + RTL8168 {} on: {:#X} size: {}", name, bar_ptr, bar_size); + log::info!(" + RTL8168 {}", pci_config.func.display()); let address = unsafe { common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) diff --git a/sb16d/src/main.rs b/sb16d/src/main.rs index 5415e2fcb6..6671ac9b39 100644 --- a/sb16d/src/main.rs +++ b/sb16d/src/main.rs @@ -68,7 +68,7 @@ fn main() { let addr_str = args.next().unwrap_or("220".to_string()); let addr = u16::from_str_radix(&addr_str, 16).expect("sb16: failed to parse address"); - print!("{}", format!(" + sb16 at 0x{:X}\n", addr)); + println!(" + sb16 at 0x{:X}\n", addr); // Daemonize redox_daemon::Daemon::new(move |daemon| { diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 17a8c23a2d..7555482450 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -197,11 +197,10 @@ fn main() { let bar0 = pci_config.func.bars[0].expect_port(); let bar1 = &pci_config.func.bars[1]; - let (bar1_ptr, _) = bar1.expect_mem(); let irq = pci_config.func.legacy_interrupt_line.expect("vboxd: no legacy interrupts supported"); - print!("{}", format!(" + VirtualBox {} on: {:X}, {:X}, IRQ {}\n", name, bar0, bar1_ptr, irq)); + println!(" + VirtualBox {}", pci_config.func.display()); // Daemonize redox_daemon::Daemon::new(move |daemon| { diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 9f95131be7..c6dd1565a5 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -233,16 +233,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::debug!("XHCI PCI CONFIG: {:?}", pci_config); let bar = &pci_config.func.bars[0]; - let (bar_ptr, _) = bar.expect_mem(); let address = unsafe { bar.physmap_mem("xhcid") } as usize; - let (mut irq_file, interrupt_method) = get_int_method(&mut pcid_handle, address); + let (irq_file, interrupt_method) = get_int_method(&mut pcid_handle, address); - print!( - "{}", - format!(" + XHCI {} on: {:016X}\n", name, bar_ptr) - ); + println!(" + XHCI {}", pci_config.func.display()); let scheme_name = format!("usb.{}", name); let socket_fd = syscall::open( From 7dbf22331b7000ee0015f22a2231e0a41d8d3143 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 23 Jan 2024 13:38:31 +0100 Subject: [PATCH 0808/1301] Share msix config validation code --- nvmed/src/main.rs | 1 + pcid/src/pci/msi.rs | 36 ++++++++++++++++++++++++++++++++++ rtl8139d/src/main.rs | 14 ++----------- rtl8168d/src/main.rs | 15 ++------------ virtio-core/src/arch/x86_64.rs | 14 ++----------- xhcid/src/main.rs | 14 ++----------- 6 files changed, 45 insertions(+), 49 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 8e57eb4db0..92f5c14729 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -88,6 +88,7 @@ fn get_int_method( PciFeatureInfo::MsiX(msix) => msix, _ => unreachable!(), }; + capability_struct.validate(function.bars); fn bar_base( allocated_bars: &AllocatedBars, function: &PciFunction, diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index fe09768a91..a3c06d538a 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -203,6 +203,42 @@ impl MsiCapability { } impl MsixCapability { + pub fn validate(&self, bars: [PciBar; 6]) { + let table_size = self.table_size(); + let table_base = self.table_base_pointer(bars); + let table_min_length = table_size * 16; + let pba_min_length = table_size.div_ceil(8); + + let pba_base = self.pba_base_pointer(bars); + + let bir = self.table_bir() as usize; + let bar = &bars[bir]; + let (bar_ptr, bar_size) = bar.expect_mem(); + + // Ensure that the table and PBA are within the BAR. + let bar_range = bar_ptr as u64..bar_ptr as u64 + bar_size as u64; + + if !bar_range.contains(&(table_base as u64 + table_min_length as u64)) { + panic!( + "Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", + table_base, + table_base + table_min_length as usize, + bar_ptr, + bar_ptr + bar_size + ); + } + + if !bar_range.contains(&(pba_base as u64 + pba_min_length as u64)) { + panic!( + "PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", + pba_base, + pba_base + pba_min_length as usize, + bar_ptr, + bar_ptr + bar_size + ); + } + } + const MC_MSIX_ENABLED_BIT: u16 = 1 << 15; const MC_MSIX_ENABLED_SHIFT: u8 = 15; const MC_FUNCTION_MASK_BIT: u16 = 1 << 14; diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index e0bfbf2648..24e5e916fe 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -161,27 +161,17 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; - let table_size = capability.table_size(); + capability.validate(pci_config.func.bars); let table_base = capability.table_base_pointer(pci_config.func.bars); - let table_min_length = table_size * 16; - let pba_min_length = div_round_up(table_size, 8); let pba_base = capability.pba_base_pointer(pci_config.func.bars); let bir = capability.table_bir() as usize; let bar = &pci_config.func.bars[bir]; - let (bar_ptr, bar_size) = bar.expect_mem(); + let (bar_ptr, _) = bar.expect_mem(); let address = unsafe { bar.physmap_mem("rtl8139d") } as usize; - if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(table_base as u64 + table_min_length as u64)) { - panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); - } - - if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(pba_base as u64 + pba_min_length as u64)) { - panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size); - } - let virt_table_base = ((table_base - bar_ptr) + address) as *mut MsixTableEntry; let virt_pba_base = ((pba_base - bar_ptr) + address) as *mut u64; diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index d157ab8706..e93cf984bf 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -159,27 +159,16 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; - let table_size = capability.table_size(); + capability.validate(pci_config.func.bars); let table_base = capability.table_base_pointer(pci_config.func.bars); - let table_min_length = table_size * 16; - let pba_min_length = div_round_up(table_size, 8); - let pba_base = capability.pba_base_pointer(pci_config.func.bars); let bir = capability.table_bir() as usize; let bar = &pci_config.func.bars[bir]; - let (bar_ptr, bar_size) = bar.expect_mem(); + let (bar_ptr, _) = bar.expect_mem(); let address = unsafe { bar.physmap_mem("rtl8168d") } as usize; - if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(table_base as u64 + table_min_length as u64)) { - panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); - } - - if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(pba_base as u64 + pba_min_length as u64)) { - panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size); - } - let virt_table_base = ((table_base - bar_ptr) + address) as *mut MsixTableEntry; let virt_pba_base = ((pba_base - bar_ptr) + address) as *mut u64; diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index a160f508cd..0273423eb4 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -18,26 +18,16 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { PciFeatureInfo::MsiX(capability) => capability, _ => unreachable!(), }; + capability.validate(pci_config.func.bars); - let table_size = capability.table_size(); let table_base = capability.table_base_pointer(pci_config.func.bars); - let table_min_length = table_size * 16; - let pba_min_length = table_size.div_ceil(8); - - let pba_base = capability.pba_base_pointer(pci_config.func.bars); let bir = capability.table_bir() as usize; let bar = &pci_config.func.bars[bir]; - let (bar_ptr, bar_size) = bar.expect_mem(); + let (bar_ptr, _) = bar.expect_mem(); let address = unsafe { bar.physmap_mem("virtio-core") } as usize; - // Ensure that the table and PBA are be within the BAR. - { - let bar_range = bar_ptr as u64..bar_ptr as u64 + bar_size as u64; - assert!(bar_range.contains(&(table_base as u64 + table_min_length as u64))); - assert!(bar_range.contains(&(pba_base as u64 + pba_min_length as u64))); - } let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index c6dd1565a5..96821f5f35 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -137,21 +137,11 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; - let table_size = capability.table_size(); + capability.validate(pci_config.func.bars); + let table_base = capability.table_base_pointer(pci_config.func.bars); - let table_min_length = table_size * 16; - let pba_min_length = crate::xhci::scheme::div_round_up(table_size, 8); - let pba_base = capability.pba_base_pointer(pci_config.func.bars); - if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(table_base as u64 + table_min_length as u64)) { - panic!("Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", table_base, table_base + table_min_length as usize, bar_ptr, bar_ptr + bar_size); - } - - if !(bar_ptr as u64..bar_ptr as u64 + bar_size as u64).contains(&(pba_base as u64 + pba_min_length as u64)) { - panic!("PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", pba_base, pba_base + pba_min_length as usize, bar_ptr, bar_ptr + bar_size); - } - let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; From f43aa8574cc632087b5146c5e21232fec4c6deb1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 23 Jan 2024 14:24:26 +0100 Subject: [PATCH 0809/1301] Simplify MSI-X table pointer computation --- pcid/src/pci/msi.rs | 55 ++++++++++++++-------------------- rtl8139d/src/main.rs | 15 ++++------ rtl8168d/src/main.rs | 14 ++++----- virtio-core/src/arch/x86_64.rs | 14 +++------ xhcid/src/main.rs | 13 ++++---- 5 files changed, 41 insertions(+), 70 deletions(-) diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index a3c06d538a..a92351151a 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -204,37 +204,40 @@ impl MsiCapability { impl MsixCapability { pub fn validate(&self, bars: [PciBar; 6]) { + if self.table_bir() > 5 { + panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir()); + } + if self.pba_bir() > 5 { + panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir()); + } + let table_size = self.table_size(); - let table_base = self.table_base_pointer(bars); + let table_offset = self.table_offset() as usize; let table_min_length = table_size * 16; + + let pba_offset = self.pba_offset() as usize; let pba_min_length = table_size.div_ceil(8); - let pba_base = self.pba_base_pointer(bars); - - let bir = self.table_bir() as usize; - let bar = &bars[bir]; - let (bar_ptr, bar_size) = bar.expect_mem(); + let (_, table_bar_size) = bars[self.table_bir() as usize].expect_mem(); + let (_, pba_bar_size) = bars[self.pba_bir() as usize].expect_mem(); // Ensure that the table and PBA are within the BAR. - let bar_range = bar_ptr as u64..bar_ptr as u64 + bar_size as u64; - if !bar_range.contains(&(table_base as u64 + table_min_length as u64)) { + if !(0..table_bar_size as u64).contains(&(table_offset as u64 + table_min_length as u64)) { panic!( - "Table {:#x}{:#x} outside of BAR {:#x}:{:#x}", - table_base, - table_base + table_min_length as usize, - bar_ptr, - bar_ptr + bar_size + "Table {:#x}:{:#x} outside of BAR with length {:#x}", + table_offset, + table_offset + table_min_length as usize, + table_bar_size ); } - if !bar_range.contains(&(pba_base as u64 + pba_min_length as u64)) { + if !(0..pba_bar_size as u64).contains(&(pba_offset as u64 + pba_min_length as u64)) { panic!( - "PBA {:#x}{:#x} outside of BAR {:#x}:{:#X}", - pba_base, - pba_base + pba_min_length as usize, - bar_ptr, - bar_ptr + bar_size + "PBA {:#x}:{:#x} outside of BAR with length {:#x}", + pba_offset, + pba_offset + pba_min_length as usize, + pba_bar_size ); } } @@ -307,20 +310,6 @@ impl MsixCapability { } - pub fn table_base_pointer(&self, bars: [PciBar; 6]) -> usize { - if self.table_bir() > 5 { - panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir()); - } - bars[usize::from(self.table_bir())].expect_mem().0 + self.table_offset() as usize - } - - pub fn pba_base_pointer(&self, bars: [PciBar; 6]) -> usize { - if self.pba_bir() > 5 { - panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir()); - } - bars[usize::from(self.pba_bir())].expect_mem().0 + self.pba_offset() as usize - } - /// Write the first DWORD into configuration space (containing the partially modifiable Message /// Control field). pub unsafe fn write_a(&self, writer: &W, offset: u8) { diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index 24e5e916fe..b019c2c2ce 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -162,18 +162,13 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { PciFeatureInfo::MsiX(s) => s, }; capability.validate(pci_config.func.bars); - let table_base = capability.table_base_pointer(pci_config.func.bars); - let pba_base = capability.pba_base_pointer(pci_config.func.bars); + assert_eq!(capability.table_bir(), capability.pba_bir()); + let bar = &pci_config.func.bars[capability.table_bir() as usize]; + let bar_address = unsafe { bar.physmap_mem("rtl8139d") } as usize; - let bir = capability.table_bir() as usize; - let bar = &pci_config.func.bars[bir]; - let (bar_ptr, _) = bar.expect_mem(); - - let address = unsafe { bar.physmap_mem("rtl8139d") } as usize; - - let virt_table_base = ((table_base - bar_ptr) + address) as *mut MsixTableEntry; - let virt_pba_base = ((pba_base - bar_ptr) + address) as *mut u64; + let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry; + let virt_pba_base = (bar_address + capability.pba_offset() as usize) as *mut u64; let mut info = MsixInfo { virt_table_base: NonNull::new(virt_table_base).unwrap(), diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index e93cf984bf..b099a389e1 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -160,17 +160,13 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { PciFeatureInfo::MsiX(s) => s, }; capability.validate(pci_config.func.bars); - let table_base = capability.table_base_pointer(pci_config.func.bars); - let pba_base = capability.pba_base_pointer(pci_config.func.bars); - let bir = capability.table_bir() as usize; - let bar = &pci_config.func.bars[bir]; - let (bar_ptr, _) = bar.expect_mem(); + assert_eq!(capability.table_bir(), capability.pba_bir()); + let bar = &pci_config.func.bars[capability.table_bir() as usize]; + let bar_address = unsafe { bar.physmap_mem("rtl8168d") } as usize; - let address = unsafe { bar.physmap_mem("rtl8168d") } as usize; - - let virt_table_base = ((table_base - bar_ptr) + address) as *mut MsixTableEntry; - let virt_pba_base = ((pba_base - bar_ptr) + address) as *mut u64; + let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry; + let virt_pba_base = (bar_address + capability.pba_offset() as usize) as *mut u64; let mut info = MsixInfo { virt_table_base: NonNull::new(virt_table_base).unwrap(), diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index 0273423eb4..3ef5d171a3 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -20,16 +20,10 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { }; capability.validate(pci_config.func.bars); - let table_base = capability.table_base_pointer(pci_config.func.bars); - - let bir = capability.table_bir() as usize; - let bar = &pci_config.func.bars[bir]; - let (bar_ptr, _) = bar.expect_mem(); - - let address = unsafe { bar.physmap_mem("virtio-core") } as usize; - - - let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; + assert_eq!(capability.table_bir(), capability.pba_bir()); + let bar = &pci_config.func.bars[capability.table_bir() as usize]; + let bar_address = unsafe { bar.physmap_mem("virtio-core") } as usize; + let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry; let mut info = MsixInfo { virt_table_base: NonNull::new(virt_table_base).unwrap(), diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 96821f5f35..59290f4256 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -82,11 +82,9 @@ fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { } #[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option, InterruptMethod) { +fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (Option, InterruptMethod) { let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); - let (bar_ptr, bar_size) = pci_config.func.bars[0].expect_mem(); - let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); log::debug!("XHCI PCI FEATURES: {:?}", all_pci_features); @@ -139,11 +137,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option }; capability.validate(pci_config.func.bars); - let table_base = capability.table_base_pointer(pci_config.func.bars); - let pba_base = capability.pba_base_pointer(pci_config.func.bars); - - let virt_table_base = ((table_base - bar_ptr as usize) + address) as *mut MsixTableEntry; - let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *mut u64; + assert_eq!(capability.table_bir(), 0); + assert_eq!(capability.pba_bir(), 0); + let virt_table_base = (bar0_address + capability.table_offset() as usize) as *mut MsixTableEntry; + let virt_pba_base = (bar0_address + capability.pba_offset() as usize) as *mut u64; let mut info = xhci::MsixInfo { virt_table_base: NonNull::new(virt_table_base).unwrap(), From ecdcefba69f8b073ecb9d2b26607a29894ae8932 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 23 Jan 2024 15:45:44 +0100 Subject: [PATCH 0810/1301] Clarify message_address argument names --- pcid/src/pci/msi.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index a92351151a..96ab83e915 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -352,11 +352,11 @@ pub mod x86_64 { } // TODO: should the reserved field be preserved? - pub const fn message_address(destination_id: u8, rh: bool, dm: bool) -> u32 { + pub const fn message_address(destination_id: u8, redirect_hint: bool, dest_mode_logical: bool) -> u32 { 0xFEE0_0000u32 | ((destination_id as u32) << 12) - | ((rh as u32) << 3) - | ((dm as u32) << 2) + | ((redirect_hint as u32) << 3) + | ((dest_mode_logical as u32) << 2) } pub const fn message_data(trigger_mode: TriggerMode, level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 { ((trigger_mode as u32) << 15) From 9b809312c20f74f4fb52d184de602cabed1ac718 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 23 Jan 2024 15:56:29 +0100 Subject: [PATCH 0811/1301] Ignore MSI-X PBA in all drivers It isn't used in any driver and even on Linux no driver seems to use it at all. The only times it seems to be useful are if you were to mask an interrupt and want to check if the interrupt fired without unmasking or if you want to make the device itself trigger an interrupt. --- nvmed/src/main.rs | 10 ---------- nvmed/src/nvme/mod.rs | 1 - rtl8139d/src/main.rs | 16 ---------------- rtl8168d/src/main.rs | 16 ---------------- virtio-core/src/arch/x86_64.rs | 1 - xhcid/src/main.rs | 3 --- xhcid/src/xhci/mod.rs | 13 ------------- 7 files changed, 60 deletions(-) diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index 92f5c14729..e38060bc1b 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -109,22 +109,13 @@ fn get_int_method( } let table_bar_base: *mut u8 = bar_base(allocated_bars, function, capability_struct.table_bir())?.as_ptr(); - let pba_bar_base: *mut u8 = - bar_base(allocated_bars, function, capability_struct.pba_bir())?.as_ptr(); let table_base = unsafe { table_bar_base.offset(capability_struct.table_offset() as isize) }; - let pba_base = unsafe { pba_bar_base.offset(capability_struct.pba_offset() as isize) }; let vector_count = capability_struct.table_size(); let table_entries: &'static mut [MsixTableEntry] = unsafe { slice::from_raw_parts_mut(table_base as *mut MsixTableEntry, vector_count as usize) }; - let pba_entries: &'static mut [Mmio] = unsafe { - slice::from_raw_parts_mut( - table_base as *mut Mmio, - (vector_count as usize + 63) / 64, - ) - }; // Mask all interrupts in case some earlier driver/os already unmasked them (according to // the PCI Local Bus spec 3.0, they are masked after system reset). @@ -162,7 +153,6 @@ fn get_int_method( let interrupt_method = InterruptMethod::MsiX(MsixCfg { cap: capability_struct, table: table_entries, - pba: pba_entries, }); let interrupt_sources = InterruptSources::MsiX(std::iter::once((msix_vector_number, irq_handle)).collect()); diff --git a/nvmed/src/nvme/mod.rs b/nvmed/src/nvme/mod.rs index 1b368c521d..6378fa2fce 100644 --- a/nvmed/src/nvme/mod.rs +++ b/nvmed/src/nvme/mod.rs @@ -122,7 +122,6 @@ impl InterruptMethod { pub struct MsixCfg { pub cap: MsixCapability, pub table: &'static mut [MsixTableEntry], - pub pba: &'static mut [Mmio], } #[repr(packed)] diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index b019c2c2ce..a8400063be 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -81,7 +81,6 @@ where pub struct MsixInfo { pub virt_table_base: NonNull, - pub virt_pba_base: NonNull, pub capability: MsixCapability, } @@ -93,18 +92,6 @@ impl MsixInfo { assert!(k < self.capability.table_size() as usize); unsafe { self.table_entry_pointer_unchecked(k) } } - pub unsafe fn pba_pointer_unchecked(&mut self, k: usize) -> &mut u64 { - &mut *self.virt_pba_base.as_ptr().offset(k as isize) - } - pub fn pba_pointer(&mut self, k: usize) -> &mut u64 { - assert!(k < self.capability.table_size() as usize); - unsafe { self.pba_pointer_unchecked(k) } - } - pub fn pba(&mut self, k: usize) -> bool { - let byte = k / 64; - let bit = k % 64; - *self.pba_pointer(byte) & (1 << bit) != 0 - } } #[cfg(target_arch = "x86_64")] @@ -163,16 +150,13 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { }; capability.validate(pci_config.func.bars); - assert_eq!(capability.table_bir(), capability.pba_bir()); let bar = &pci_config.func.bars[capability.table_bir() as usize]; let bar_address = unsafe { bar.physmap_mem("rtl8139d") } as usize; let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry; - let virt_pba_base = (bar_address + capability.pba_offset() as usize) as *mut u64; let mut info = MsixInfo { virt_table_base: NonNull::new(virt_table_base).unwrap(), - virt_pba_base: NonNull::new(virt_pba_base).unwrap(), capability, }; diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index b099a389e1..334554d12e 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -79,7 +79,6 @@ where pub struct MsixInfo { pub virt_table_base: NonNull, - pub virt_pba_base: NonNull, pub capability: MsixCapability, } @@ -91,18 +90,6 @@ impl MsixInfo { assert!(k < self.capability.table_size() as usize); unsafe { self.table_entry_pointer_unchecked(k) } } - pub unsafe fn pba_pointer_unchecked(&mut self, k: usize) -> &mut u64 { - &mut *self.virt_pba_base.as_ptr().offset(k as isize) - } - pub fn pba_pointer(&mut self, k: usize) -> &mut u64 { - assert!(k < self.capability.table_size() as usize); - unsafe { self.pba_pointer_unchecked(k) } - } - pub fn pba(&mut self, k: usize) -> bool { - let byte = k / 64; - let bit = k % 64; - *self.pba_pointer(byte) & (1 << bit) != 0 - } } #[cfg(target_arch = "x86_64")] @@ -161,16 +148,13 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { }; capability.validate(pci_config.func.bars); - assert_eq!(capability.table_bir(), capability.pba_bir()); let bar = &pci_config.func.bars[capability.table_bir() as usize]; let bar_address = unsafe { bar.physmap_mem("rtl8168d") } as usize; let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry; - let virt_pba_base = (bar_address + capability.pba_offset() as usize) as *mut u64; let mut info = MsixInfo { virt_table_base: NonNull::new(virt_table_base).unwrap(), - virt_pba_base: NonNull::new(virt_pba_base).unwrap(), capability, }; diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index 3ef5d171a3..3965e08c39 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -20,7 +20,6 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { }; capability.validate(pci_config.func.bars); - assert_eq!(capability.table_bir(), capability.pba_bir()); let bar = &pci_config.func.bars[capability.table_bir() as usize]; let bar_address = unsafe { bar.physmap_mem("virtio-core") } as usize; let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 59290f4256..2315c2a1dc 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -138,13 +138,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (O capability.validate(pci_config.func.bars); assert_eq!(capability.table_bir(), 0); - assert_eq!(capability.pba_bir(), 0); let virt_table_base = (bar0_address + capability.table_offset() as usize) as *mut MsixTableEntry; - let virt_pba_base = (bar0_address + capability.pba_offset() as usize) as *mut u64; let mut info = xhci::MsixInfo { virt_table_base: NonNull::new(virt_table_base).unwrap(), - virt_pba_base: NonNull::new(virt_pba_base).unwrap(), capability, }; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index aaf8b453c1..32d9d1eb82 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -70,7 +70,6 @@ pub enum InterruptMethod { pub struct MsixInfo { pub virt_table_base: NonNull, - pub virt_pba_base: NonNull, pub capability: MsixCapability, } impl MsixInfo { @@ -81,18 +80,6 @@ impl MsixInfo { assert!(k < self.capability.table_size() as usize); unsafe { self.table_entry_pointer_unchecked(k) } } - pub unsafe fn pba_pointer_unchecked(&mut self, k: usize) -> &mut u64 { - &mut *self.virt_pba_base.as_ptr().offset(k as isize) - } - pub fn pba_pointer(&mut self, k: usize) -> &mut u64 { - assert!(k < self.capability.table_size() as usize); - unsafe { self.pba_pointer_unchecked(k) } - } - pub fn pba(&mut self, k: usize) -> bool { - let byte = k / 64; - let bit = k % 64; - *self.pba_pointer(byte) & (1 << bit) != 0 - } } impl Xhci { From 67d3015e2efea14b1e1d16d0762003d5869c5f1f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 23 Jan 2024 19:22:32 +0100 Subject: [PATCH 0812/1301] Add helper for allocating a single MSI/MSI-X interrupt vector It doesn't actually configure the device to emit it though, but does make this easier to do. --- ihdad/src/main.rs | 15 ++-------- nvmed/src/main.rs | 37 +++++------------------- pcid/src/driver_interface/irq_helpers.rs | 21 ++++++++++++++ pcid/src/driver_interface/mod.rs | 18 +++--------- pcid/src/main.rs | 22 +++++++------- pcid/src/pci/msi.rs | 33 +++++++++++++++++---- rtl8139d/src/main.rs | 35 +++++----------------- rtl8168d/src/main.rs | 35 +++++----------------- virtio-core/src/arch/x86_64.rs | 29 ++++--------------- xhcid/src/main.rs | 33 +++++---------------- 10 files changed, 104 insertions(+), 174 deletions(-) diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index 7f87807b40..ba8ae837d8 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -6,7 +6,6 @@ extern crate spin; extern crate syscall; extern crate event; -use std::convert::TryFrom; use std::usize; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; @@ -17,7 +16,7 @@ use std::sync::Arc; use event::EventQueue; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; -use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector}; +use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector_for_msi}; use redox_log::{OutputBuilder, RedoxLogger}; pub mod hda; @@ -91,8 +90,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { } if msi_enabled && !msix_enabled { - use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; - let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("ihdad: failed to retrieve the MSI capability structure from pcid") { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), @@ -103,17 +100,11 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. let destination_id = read_bsp_apic_id().expect("ihdad: failed to read BSP apic id"); - let lapic_id = u8::try_from(destination_id).expect("CPU id didn't fit inside u8"); - let msg_addr = x86_64_msix::message_address(lapic_id, false, false); - - let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("ihdad: failed to allocate interrupt vector").expect("ihdad: no interrupt vectors left"); - let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + let (msg_addr_and_data, interrupt_handle) = allocate_single_interrupt_vector_for_msi(destination_id); let set_feature_info = MsiSetFeatureInfo { multi_message_enable: Some(0), - message_address: Some(msg_addr), - message_upper_address: Some(0), - message_data: Some(msg_data as u16), + message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("ihdad: failed to set feature info"); diff --git a/nvmed/src/main.rs b/nvmed/src/main.rs index e38060bc1b..7058e9f6ae 100644 --- a/nvmed/src/main.rs +++ b/nvmed/src/main.rs @@ -127,25 +127,14 @@ fn get_int_method( capability_struct.set_msix_enabled(true); // only affects our local mirror of the cap let (msix_vector_number, irq_handle) = { - use msi_x86_64::DeliveryMode; - use pcid_interface::msi::x86_64 as msi_x86_64; - let entry: &mut MsixTableEntry = &mut table_entries[0]; let bsp_cpu_id = irq_helpers::read_bsp_apic_id().expect("nvmed: failed to read APIC ID"); - let bsp_lapic_id = bsp_cpu_id - .try_into() - .expect("nvmed: BSP local apic ID couldn't fit inside u8"); - let (vector, irq_handle) = irq_helpers::allocate_single_interrupt_vector(bsp_cpu_id) - .expect("nvmed: failed to allocate single MSI-X interrupt vector") - .expect("nvmed: no interrupt vectors left on BSP"); - - let msg_addr = msi_x86_64::message_address(bsp_lapic_id, false, false); - let msg_data = msi_x86_64::message_data_edge_triggered(DeliveryMode::Fixed, vector); - - entry.set_addr_lo(msg_addr); - entry.set_msg_data(msg_data); + let (msg_addr_and_data, irq_handle) = + irq_helpers::allocate_single_interrupt_vector_for_msi(bsp_cpu_id); + entry.write_addr_and_data(msg_addr_and_data); + entry.unmask(); (0, irq_handle) }; @@ -166,27 +155,15 @@ fn get_int_method( }; let (msi_vector_number, irq_handle) = { - use msi_x86_64::DeliveryMode; - use pcid_interface::msi::x86_64 as msi_x86_64; use pcid_interface::{MsiSetFeatureInfo, SetFeatureInfo}; let bsp_cpu_id = irq_helpers::read_bsp_apic_id().expect("nvmed: failed to read BSP APIC ID"); - let bsp_lapic_id = bsp_cpu_id - .try_into() - .expect("nvmed: BSP local apic ID couldn't fit inside u8"); - let (vector, irq_handle) = irq_helpers::allocate_single_interrupt_vector(bsp_cpu_id) - .expect("nvmed: failed to allocate single MSI interrupt vector") - .expect("nvmed: no interrupt vectors left on BSP"); - - let msg_addr = msi_x86_64::message_address(bsp_lapic_id, false, false); - let msg_data = - msi_x86_64::message_data_edge_triggered(DeliveryMode::Fixed, vector) as u16; + let (msg_addr_and_data, irq_handle) = + irq_helpers::allocate_single_interrupt_vector_for_msi(bsp_cpu_id); pcid_handle.set_feature_info(SetFeatureInfo::Msi(MsiSetFeatureInfo { - message_address: Some(msg_addr), - message_upper_address: Some(0), - message_data: Some(msg_data), + message_address_and_data: Some(msg_addr_and_data), multi_message_enable: Some(0), // enable 2^0=1 vectors mask_bits: None, })).unwrap(); diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index e0d63164e5..d7c9b4b5ea 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -8,6 +8,8 @@ use std::fs::{self, File}; use std::io::{self, prelude::*}; use std::num::NonZeroU8; +use crate::pci::msi::MsiAddrAndData; + /// Read the local APIC ID of the bootstrap processor. pub fn read_bsp_apic_id() -> io::Result { let mut buffer = [0u8; 8]; @@ -153,3 +155,22 @@ pub fn allocate_single_interrupt_vector(cpu_id: usize) -> io::Result (MsiAddrAndData, File) { + use crate::pci::msi::x86_64 as x86_64_msix; + + // FIXME for cpu_id >255 we need to use the IOMMU to use IRQ remapping + let lapic_id = u8::try_from(cpu_id).expect("CPU id couldn't fit inside u8"); + let rh = false; + let dm = false; + let addr = x86_64_msix::message_address(lapic_id, rh, dm); + + let (vector, interrupt_handle) = allocate_single_interrupt_vector(cpu_id) + .expect("failed to allocate interrupt vector") + .expect("no interrupt vectors left"); + let msg_data = + x86_64_msix::message_data_edge_triggered(x86_64_msix::DeliveryMode::Fixed, vector); + + (MsiAddrAndData::new(addr, msg_data), interrupt_handle) +} diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 88b7068915..0595fee914 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -163,22 +163,12 @@ pub struct MsiSetFeatureInfo { /// is the log2 of the interrupt vectors, minus one. Can only be 0b000..=0b101. pub multi_message_enable: Option, - /// The system-specific message address, must be DWORD aligned. + /// The system-specific message address and data. /// /// The message address contains things like the CPU that will be targeted, at least on - /// x86_64. - pub message_address: Option, - - /// The upper 32 bits of the 64-bit message address. Not guaranteed to exist, and is - /// reserved on x86_64 (currently). - pub message_upper_address: Option, - - /// The message data, containing the actual interrupt vector (lower 8 bits), etc. - /// - /// The spec mentions that the lower N bits can be modified, where N is the multi message - /// enable, which means that the vector set here has to be aligned to that number, and that - /// all vectors in that range have to be allocated. - pub message_data: Option, + /// x86_64. The message data contains the actual interrupt vector (lower 8 bits) and + /// the kind of interrupt, at least on x86_64. + pub message_address_and_data: Option, /// A bitmap of the vectors that are masked. This field is not guaranteed (and not likely, /// at least according to the feature flags I got from QEMU), to exist. diff --git a/pcid/src/main.rs b/pcid/src/main.rs index bbc46d0794..56f78191bf 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -14,7 +14,7 @@ use redox_log::{OutputBuilder, RedoxLogger}; use crate::cfg_access::Pcie; use crate::config::Config; use crate::driver_interface::LegacyInterruptLine; -use crate::pci::{PciBar, PciFunc}; +use crate::pci::PciFunc; use crate::pci::cap::Capability as PciCapability; use crate::pci::func::{ConfigReader, ConfigWriter}; use crate::pci_header::{PciEndpointHeader, PciHeader, PciHeaderError}; @@ -130,20 +130,22 @@ impl DriverHandler { info.set_multi_message_enable(mme); } - if let Some(message_addr) = info_to_set.message_address { + if let Some(message_addr_and_data) = info_to_set.message_address_and_data { + let message_addr = message_addr_and_data.addr; if message_addr & 0b11 != 0 { return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern); } - info.set_message_address(message_addr); - } - if let Some(message_addr_upper) = info_to_set.message_upper_address { - info.set_message_upper_address(message_addr_upper); - } - if let Some(message_data) = info_to_set.message_data { - if message_data & ((1 << info.multi_message_enable()) - 1) != 0 { + info.set_message_address(message_addr as u32); + info.set_message_upper_address((message_addr >> 32) as u32); + if message_addr_and_data.data & ((1 << info.multi_message_enable()) - 1) != 0 { return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern); } - info.set_message_data(message_data); + info.set_message_data( + message_addr_and_data + .data + .try_into() + .expect("pcid: MSI message data too big"), + ); } if let Some(mask_bits) = info_to_set.mask_bits { info.set_mask_bits(mask_bits); diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 96ab83e915..ce176a1846 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -4,8 +4,25 @@ use super::bar::PciBar; pub use super::cap::{MsiCapability, MsixCapability}; use super::func::{ConfigReader, ConfigWriter}; +use serde::{Deserialize, Serialize}; use syscall::{Io, Mmio}; +/// The address and data to use for MSI and MSI-X. +/// +/// For MSI using this only works when you need a single interrupt vector. +/// For MSI-X you can have a single [MsiEntry] for each interrupt vector. +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct MsiAddrAndData { + pub(crate) addr: u64, + pub(crate) data: u32, +} + +impl MsiAddrAndData { + pub fn new(addr: u64, data: u32) -> Self { + MsiAddrAndData { addr, data } + } +} + impl MsiCapability { pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8; pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7; @@ -352,11 +369,11 @@ pub mod x86_64 { } // TODO: should the reserved field be preserved? - pub const fn message_address(destination_id: u8, redirect_hint: bool, dest_mode_logical: bool) -> u32 { - 0xFEE0_0000u32 - | ((destination_id as u32) << 12) - | ((redirect_hint as u32) << 3) - | ((dest_mode_logical as u32) << 2) + pub const fn message_address(destination_id: u8, redirect_hint: bool, dest_mode_logical: bool) -> u64 { + 0x0000_0000_FEE0_0000u64 + | ((destination_id as u64) << 12) + | ((redirect_hint as u64) << 3) + | ((dest_mode_logical as u64) << 2) } pub const fn message_data(trigger_mode: TriggerMode, level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 { ((trigger_mode as u32) << 15) @@ -408,6 +425,12 @@ impl MsixTableEntry { pub fn unmask(&mut self) { self.set_masked(false); } + + pub fn write_addr_and_data(&mut self, entry: MsiAddrAndData) { + self.set_addr_lo(entry.addr as u32); + self.set_addr_hi((entry.addr >> 32) as u32); + self.set_msg_data(entry.data); + } } impl fmt::Debug for MsixTableEntry { diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index a8400063be..c61e3049ab 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -5,7 +5,7 @@ extern crate netutils; extern crate syscall; use std::cell::RefCell; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryInto; use std::{env, process}; use std::fs::File; use std::io::{ErrorKind, Read, Result, Write}; @@ -15,11 +15,10 @@ use std::sync::Arc; use event::EventQueue; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; -use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector}; +use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector_for_msi}; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::{EventFlags, Packet, SchemeBlockMut}; -use syscall::io::Io; pub mod device; @@ -112,8 +111,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { } if msi_enabled && !msix_enabled { - use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; - let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("rtl8139d: failed to retrieve the MSI capability structure from pcid") { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), @@ -124,17 +121,11 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. let destination_id = read_bsp_apic_id().expect("rtl8139d: failed to read BSP apic id"); - let lapic_id = u8::try_from(destination_id).expect("CPU id didn't fit inside u8"); - let msg_addr = x86_64_msix::message_address(lapic_id, false, false); - - let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("rtl8139d: failed to allocate interrupt vector").expect("rtl8139d: no interrupt vectors left"); - let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + let (msg_addr_and_data, interrupt_handle) = allocate_single_interrupt_vector_for_msi(destination_id); let set_feature_info = MsiSetFeatureInfo { multi_message_enable: Some(0), - message_address: Some(msg_addr), - message_upper_address: Some(0), - message_data: Some(msg_data as u16), + message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("rtl8139d: failed to set feature info"); @@ -163,8 +154,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { // Allocate one msi vector. let method = { - use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; - // primary interrupter let k = 0; @@ -172,18 +161,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let table_entry_pointer = info.table_entry_pointer(k); let destination_id = read_bsp_apic_id().expect("rtl8139d: failed to read BSP apic id"); - let lapic_id = u8::try_from(destination_id).expect("rtl8139d: CPU id couldn't fit inside u8"); - let rh = false; - let dm = false; - let addr = x86_64_msix::message_address(lapic_id, rh, dm); - - let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("rtl8139d: failed to allocate interrupt vector").expect("rtl8139d: no interrupt vectors left"); - let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); - - table_entry_pointer.addr_lo.write(addr); - table_entry_pointer.addr_hi.write(0); - table_entry_pointer.msg_data.write(msg_data); - table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); + table_entry_pointer.write_addr_and_data(msg_addr_and_data); + table_entry_pointer.unmask(); interrupt_handle }; diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 334554d12e..f5452baff9 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -3,7 +3,7 @@ extern crate netutils; extern crate syscall; use std::cell::RefCell; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryInto; use std::{env, process}; use std::fs::File; use std::io::{ErrorKind, Read, Result, Write}; @@ -13,11 +13,10 @@ use std::sync::Arc; use event::EventQueue; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; -use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector}; +use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector_for_msi}; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::{EventFlags, Packet, SchemeBlockMut}; -use syscall::io::Io; pub mod device; @@ -110,8 +109,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { } if msi_enabled && !msix_enabled { - use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; - let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("rtl8168d: failed to retrieve the MSI capability structure from pcid") { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), @@ -122,17 +119,11 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. let destination_id = read_bsp_apic_id().expect("rtl8168d: failed to read BSP apic id"); - let lapic_id = u8::try_from(destination_id).expect("CPU id didn't fit inside u8"); - let msg_addr = x86_64_msix::message_address(lapic_id, false, false); - - let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("rtl8168d: failed to allocate interrupt vector").expect("rtl8168d: no interrupt vectors left"); - let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + let (msg_addr_and_data, interrupt_handle) = allocate_single_interrupt_vector_for_msi(destination_id); let set_feature_info = MsiSetFeatureInfo { multi_message_enable: Some(0), - message_address: Some(msg_addr), - message_upper_address: Some(0), - message_data: Some(msg_data as u16), + message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("rtl8168d: failed to set feature info"); @@ -161,8 +152,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { // Allocate one msi vector. let method = { - use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; - // primary interrupter let k = 0; @@ -170,18 +159,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let table_entry_pointer = info.table_entry_pointer(k); let destination_id = read_bsp_apic_id().expect("rtl8168d: failed to read BSP apic id"); - let lapic_id = u8::try_from(destination_id).expect("rtl8168d: CPU id couldn't fit inside u8"); - let rh = false; - let dm = false; - let addr = x86_64_msix::message_address(lapic_id, rh, dm); - - let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("rtl8168d: failed to allocate interrupt vector").expect("rtl8168d: no interrupt vectors left"); - let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); - - table_entry_pointer.addr_lo.write(addr); - table_entry_pointer.addr_hi.write(0); - table_entry_pointer.msg_data.write(msg_data); - table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); + table_entry_pointer.write_addr_and_data(msg_addr_and_data); + table_entry_pointer.unmask(); interrupt_handle }; diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index 3965e08c39..e67d8ab767 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -1,11 +1,9 @@ use crate::{legacy_transport::LegacyTransport, reinit, transport::Error, Device}; -use pcid_interface::irq_helpers::{allocate_single_interrupt_vector, read_bsp_apic_id}; -use pcid_interface::msi::{self, MsixTableEntry}; +use pcid_interface::irq_helpers::{allocate_single_interrupt_vector_for_msi, read_bsp_apic_id}; +use pcid_interface::msi::MsixTableEntry; use std::{fs::File, ptr::NonNull}; -use syscall::Io; - use crate::{probe::MsixInfo, MSIX_PRIMARY_VECTOR}; use pcid_interface::*; @@ -36,25 +34,10 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize); let destination_id = read_bsp_apic_id().expect("virtio_core: `read_bsp_apic_id()` failed"); - let lapic_id = u8::try_from(destination_id).unwrap(); - - let rh = false; - let dm = false; - let addr = msi::x86_64::message_address(lapic_id, rh, dm); - - let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id) - .unwrap() - .expect("virtio_core: interrupt vector exhaustion"); - - let msg_data = - msi::x86_64::message_data_edge_triggered(msi::x86_64::DeliveryMode::Fixed, vector); - - table_entry_pointer.addr_lo.write(addr); - table_entry_pointer.addr_hi.write(0); - table_entry_pointer.msg_data.write(msg_data); - table_entry_pointer - .vec_ctl - .writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); + table_entry_pointer.write_addr_and_data(msg_addr_and_data); + table_entry_pointer.unmask(); interrupt_handle }; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 2315c2a1dc..bbab755d9a 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -12,8 +12,8 @@ use std::sync::{Arc, Mutex}; use std::env; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; -use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector}; -use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; +use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector_for_msi}; +use pcid_interface::msi::MsixTableEntry; use event::{Event, EventQueue}; use redox_log::{RedoxLogger, OutputBuilder}; @@ -99,8 +99,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (O } if msi_enabled && !msix_enabled { - use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; - let mut capability = match pcid_handle.feature_info(PciFeature::Msi).expect("xhcid: failed to retrieve the MSI capability structure from pcid") { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), @@ -111,17 +109,11 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (O // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); - let lapic_id = u8::try_from(destination_id).expect("CPU id didn't fit inside u8"); - let msg_addr = x86_64_msix::message_address(lapic_id, false, false); - - let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); - let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); + let (msg_addr_and_data, interrupt_handle) = allocate_single_interrupt_vector_for_msi(destination_id); let set_feature_info = MsiSetFeatureInfo { multi_message_enable: Some(0), - message_address: Some(msg_addr), - message_upper_address: Some(0), - message_data: Some(msg_data as u16), + message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("xhcid: failed to set feature info"); @@ -148,8 +140,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (O // Allocate one msi vector. let method = { - use pcid_interface::msi::x86_64::{DeliveryMode, self as x86_64_msix}; - // primary interrupter let k = 0; @@ -157,18 +147,9 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (O let table_entry_pointer = info.table_entry_pointer(k); let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); - let lapic_id = u8::try_from(destination_id).expect("xhcid: CPU id couldn't fit inside u8"); - let rh = false; - let dm = false; - let addr = x86_64_msix::message_address(lapic_id, rh, dm); - - let (vector, interrupt_handle) = allocate_single_interrupt_vector(destination_id).expect("xhcid: failed to allocate interrupt vector").expect("xhcid: no interrupt vectors left"); - let msg_data = x86_64_msix::message_data_edge_triggered(DeliveryMode::Fixed, vector); - - table_entry_pointer.addr_lo.write(addr); - table_entry_pointer.addr_hi.write(0); - table_entry_pointer.msg_data.write(msg_data); - table_entry_pointer.vec_ctl.writef(MsixTableEntry::VEC_CTL_MASK_BIT, false); + let (msg_addr_and_data, interrupt_handle) = allocate_single_interrupt_vector_for_msi(destination_id); + table_entry_pointer.write_addr_and_data(msg_addr_and_data); + table_entry_pointer.unmask(); (Some(interrupt_handle), InterruptMethod::MsiX(Mutex::new(info))) }; From 743926299411c19f7373d4c6f7072463ed5da776 Mon Sep 17 00:00:00 2001 From: Enver Balalic Date: Sat, 10 Feb 2024 19:03:36 +0100 Subject: [PATCH 0813/1301] ihdad, rtl8139d, rtl8168d, virtio-core, xhcid: Fix aarch64 build --- ihdad/src/main.rs | 4 +++- rtl8139d/src/main.rs | 4 +++- rtl8168d/src/main.rs | 4 +++- virtio-core/src/arch/aarch64.rs | 6 +++--- virtio-core/src/arch/x86.rs | 4 ++-- xhcid/src/main.rs | 4 +++- 6 files changed, 17 insertions(+), 9 deletions(-) diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index ba8ae837d8..c640cca9e0 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -16,7 +16,9 @@ use std::sync::Arc; use event::EventQueue; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; -use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector_for_msi}; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; +use pcid_interface::irq_helpers::read_bsp_apic_id; use redox_log::{OutputBuilder, RedoxLogger}; pub mod hda; diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index c61e3049ab..5687cbf768 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -15,7 +15,9 @@ use std::sync::Arc; use event::EventQueue; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; -use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector_for_msi}; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; +use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::{EventFlags, Packet, SchemeBlockMut}; diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index f5452baff9..e2fc5503f4 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -13,7 +13,9 @@ use std::sync::Arc; use event::EventQueue; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; -use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector_for_msi}; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; +use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::{EventFlags, Packet, SchemeBlockMut}; diff --git a/virtio-core/src/arch/aarch64.rs b/virtio-core/src/arch/aarch64.rs index e8f340580a..29e3b5855a 100644 --- a/virtio-core/src/arch/aarch64.rs +++ b/virtio-core/src/arch/aarch64.rs @@ -8,9 +8,9 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { unimplemented!("virtio_core: aarch64 enable_msix") } -pub fn probe_legacy_port_transport<'a>( - pci_header: &PciHeader, +pub fn probe_legacy_port_transport( + pci_config: &SubdriverArguments, pcid_handle: &mut PcidServerHandle, -) -> Result, Error> { +) -> Result { panic!("virtio-core: aarch64 doesn't support legacy port I/O") } \ No newline at end of file diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index 45d67b9a1c..9073ce8059 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -8,10 +8,10 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { } pub fn probe_legacy_port_transport( - pci_header: &PciHeader, + pci_config: &SubdriverArguments, pcid_handle: &mut PcidServerHandle, ) -> Result { - let port = pci_header.get_bar(0).expect_port(); + let port = pci_config.func.bars[0].expect_port(); unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; log::warn!("virtio: using legacy transport"); diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index bbab755d9a..9e6a71d3b0 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -12,7 +12,9 @@ use std::sync::{Arc, Mutex}; use std::env; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; -use pcid_interface::irq_helpers::{read_bsp_apic_id, allocate_single_interrupt_vector_for_msi}; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; +use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::MsixTableEntry; use event::{Event, EventQueue}; From 40e2189e220b7047fed3ddb3f5860c5999178596 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 15 Feb 2024 16:00:52 -0700 Subject: [PATCH 0814/1301] ahcid: spin for all requests --- ahcid/src/ahci/disk_ata.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/ahcid/src/ahci/disk_ata.rs b/ahcid/src/ahci/disk_ata.rs index d9dcef1769..cf9437765f 100644 --- a/ahcid/src/ahci/disk_ata.rs +++ b/ahcid/src/ahci/disk_ata.rs @@ -142,11 +142,23 @@ impl Disk for DiskATA { } fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result> { - self.request(block, BufferKind::Read(buffer)) + //TODO: FIGURE OUT WHY INTERRUPTS CAUSE HANGS + loop { + match self.request(block, BufferKind::Read(buffer))? { + Some(count) => return Ok(Some(count)), + None => std::thread::yield_now() + } + } } fn write(&mut self, block: u64, buffer: &[u8]) -> Result> { - self.request(block, BufferKind::Write(buffer)) + //TODO: FIGURE OUT WHY INTERRUPTS CAUSE HANGS + loop { + match self.request(block, BufferKind::Write(buffer))? { + Some(count) => return Ok(Some(count)), + None => std::thread::yield_now() + } + } } fn block_length(&mut self) -> Result { From de2fae8183015f51b7a34d7401432795674d0aab Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 16 Feb 2024 20:52:37 -0700 Subject: [PATCH 0815/1301] Do not compile MSI-X function for x86 32-bit --- pcid/src/driver_interface/irq_helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index d7c9b4b5ea..7a36210cc6 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -156,7 +156,7 @@ pub fn allocate_single_interrupt_vector(cpu_id: usize) -> io::Result (MsiAddrAndData, File) { use crate::pci::msi::x86_64 as x86_64_msix; From 2a4e292e1d80ae9a85b5913991a7eb1aa20c8206 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 16 Feb 2024 20:52:55 -0700 Subject: [PATCH 0816/1301] virtio-core: mark CommonCfg as packed --- virtio-core/src/spec/transport_pci.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtio-core/src/spec/transport_pci.rs b/virtio-core/src/spec/transport_pci.rs index cadfaad2de..e90b9ebb72 100644 --- a/virtio-core/src/spec/transport_pci.rs +++ b/virtio-core/src/spec/transport_pci.rs @@ -69,7 +69,7 @@ pub enum CfgType { const_assert_eq!(core::mem::size_of::(), 1); #[derive(Debug)] -#[repr(C)] +#[repr(C, packed)] pub struct CommonCfg { // About the whole device. /// The driver uses this to select which feature bits device_feature shows. From 2c672a0568879d73e2c255ef931a4ababecb40b5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 16 Feb 2024 20:58:54 -0700 Subject: [PATCH 0817/1301] More fixes for 32-bit x86 --- virtio-core/src/spec/transport_pci.rs | 4 +++- xhcid/src/main.rs | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/virtio-core/src/spec/transport_pci.rs b/virtio-core/src/spec/transport_pci.rs index e90b9ebb72..7ef8efa8ef 100644 --- a/virtio-core/src/spec/transport_pci.rs +++ b/virtio-core/src/spec/transport_pci.rs @@ -69,7 +69,7 @@ pub enum CfgType { const_assert_eq!(core::mem::size_of::(), 1); #[derive(Debug)] -#[repr(C, packed)] +#[repr(C)] pub struct CommonCfg { // About the whole device. /// The driver uses this to select which feature bits device_feature shows. @@ -152,6 +152,8 @@ pub struct CommonCfg { pub queue_reset: VolatileCell, } +//TODO: why does this fail on x86? +#[cfg(not(target_arch = "x86"))] const_assert_eq!(core::mem::size_of::(), 64); #[derive(Debug, Copy, Clone)] diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 9e6a71d3b0..faf50300ec 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -12,7 +12,7 @@ use std::sync::{Arc, Mutex}; use std::env; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::MsixTableEntry; From c52e17dd46c11109b528576feb5d13d28b8cfea8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 16 Feb 2024 21:00:13 -0700 Subject: [PATCH 0818/1301] Even more fixes for 32-bit x86 --- ihdad/src/main.rs | 2 +- rtl8139d/src/main.rs | 2 +- rtl8168d/src/main.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ihdad/src/main.rs b/ihdad/src/main.rs index c640cca9e0..7eeba58e2a 100755 --- a/ihdad/src/main.rs +++ b/ihdad/src/main.rs @@ -16,7 +16,7 @@ use std::sync::Arc; use event::EventQueue; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use redox_log::{OutputBuilder, RedoxLogger}; diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index 5687cbf768..268e1ddf3f 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -15,7 +15,7 @@ use std::sync::Arc; use event::EventQueue; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index e2fc5503f4..78fe7185fc 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -13,7 +13,7 @@ use std::sync::Arc; use event::EventQueue; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; From a2e9e281951c9cdeefdc45c64b48b8e44063230c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 16 Feb 2024 21:17:02 -0700 Subject: [PATCH 0819/1301] Fix build for 32-bit x86 --- Cargo.lock | 23 ++++++++++++++++------- Cargo.toml | 1 + 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 47e84816d9..59273691f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -688,9 +688,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libredox" @@ -703,6 +703,16 @@ dependencies = [ "redox_syscall 0.4.1", ] +[[package]] +name = "libredox" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138adbe77ccf68e1925b6ed3cc45e83a6845f17a687d6061ddeb518e9b756440" +dependencies = [ + "bitflags 2.4.2", + "libc", +] + [[package]] name = "lived" version = "0.1.0" @@ -1128,12 +1138,11 @@ dependencies = [ [[package]] name = "redox-daemon" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "811fd0d382a70c9e9192166ee794567b65ef34cc7309c86a49b071779ca9b5f3" +version = "0.1.3" +source = "git+https://gitlab.redox-os.org/redox-os/redox-daemon.git#31ab115cf17d6fe333515bfe19ac477352a1dcc0" dependencies = [ "libc", - "redox_syscall 0.3.5", + "libredox 0.1.0", ] [[package]] @@ -1163,7 +1172,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "475e252d7add4825405d2248d530d33e22364ac5477eab816b56efbeec1e2712" dependencies = [ "bitflags 2.4.2", - "libredox", + "libredox 0.0.1", "redox_syscall 0.4.1", ] diff --git a/Cargo.toml b/Cargo.toml index 444a5947c6..bd8c75cf68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,3 +43,4 @@ lto = "fat" mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } +redox-daemon = { git = "https://gitlab.redox-os.org/redox-os/redox-daemon.git" } From e7a6bb6c8121da6e48e5b798daad1c7c0a547964 Mon Sep 17 00:00:00 2001 From: Jacob Lorentzon <4ldo2@protonmail.com> Date: Tue, 20 Feb 2024 22:27:14 +0000 Subject: [PATCH 0820/1301] Only do one memory:physical map per MCFG entry. --- common/src/dma.rs | 59 +++++++--- common/src/lib.rs | 99 ++++++++++++---- pcid/src/cfg_access/mod.rs | 225 ++++++++++++++++++------------------- pcid/src/main.rs | 3 + 4 files changed, 231 insertions(+), 155 deletions(-) diff --git a/common/src/dma.rs b/common/src/dma.rs index 3a092f1024..ec06623360 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -1,4 +1,4 @@ -use std::mem::{self, MaybeUninit, size_of}; +use std::mem::{self, size_of, MaybeUninit}; use std::ops::{Deref, DerefMut}; use std::ptr; @@ -23,13 +23,21 @@ const DMA_MEMTY: MemoryType = { fn alloc_and_map(len: usize) -> Result<(usize, *mut ())> { assert_eq!(len % PAGE_SIZE, 0); unsafe { - let fd = syscall::open(format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), syscall::O_CLOEXEC)?; - let virt = syscall::fmap(fd, &syscall::Map { - offset: 0, // ignored - address: 0, // ignored - size: len, - flags: syscall::MapFlags::MAP_PRIVATE | syscall::MapFlags::PROT_READ | syscall::MapFlags::PROT_WRITE, - }); + let fd = syscall::open( + format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), + syscall::O_CLOEXEC, + )?; + let virt = syscall::fmap( + fd, + &syscall::Map { + offset: 0, // ignored + address: 0, // ignored + size: len, + flags: syscall::MapFlags::MAP_PRIVATE + | syscall::MapFlags::PROT_READ + | syscall::MapFlags::PROT_WRITE, + }, + ); let _ = syscall::close(fd); let virt = virt?; let phys = syscall::virttophys(virt)?; @@ -57,13 +65,21 @@ impl Dma { pub fn zeroed() -> Result>> { let aligned_len = size_of::().next_multiple_of(PAGE_SIZE); let (phys, virt) = alloc_and_map(aligned_len)?; - Ok(Dma { phys, virt: virt.cast(), aligned_len }) + Ok(Dma { + phys, + virt: virt.cast(), + aligned_len, + }) } } impl Dma> { pub unsafe fn assume_init(self) -> Dma { - let Dma { phys, aligned_len, virt } = self; + let Dma { + phys, + aligned_len, + virt, + } = self; mem::forget(self); Dma { @@ -81,13 +97,24 @@ impl Dma { impl Dma<[T]> { pub fn zeroed_slice(count: usize) -> Result]>> { - let aligned_len = count.checked_mul(size_of::()).unwrap().next_multiple_of(PAGE_SIZE); + let aligned_len = count + .checked_mul(size_of::()) + .unwrap() + .next_multiple_of(PAGE_SIZE); let (phys, virt) = alloc_and_map(aligned_len)?; - Ok(Dma { phys, aligned_len, virt: ptr::slice_from_raw_parts_mut(virt.cast(), count) }) + Ok(Dma { + phys, + aligned_len, + virt: ptr::slice_from_raw_parts_mut(virt.cast(), count), + }) } pub unsafe fn cast_slice(self) -> Dma<[U]> { - let Dma { phys, virt, aligned_len } = self; + let Dma { + phys, + virt, + aligned_len, + } = self; core::mem::forget(self); Dma { @@ -99,7 +126,11 @@ impl Dma<[T]> { } impl Dma<[MaybeUninit]> { pub unsafe fn assume_init(self) -> Dma<[T]> { - let &Dma { phys, aligned_len, virt } = &self; + let &Dma { + phys, + aligned_len, + virt, + } = &self; mem::forget(self); Dma { diff --git a/common/src/lib.rs b/common/src/lib.rs index 05d76bf1dd..2a9240f193 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,8 +1,8 @@ #![feature(int_roundings)] -use syscall::PAGE_SIZE; use syscall::error::{Error, Result, EINVAL}; use syscall::flag::{MapFlags, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; +use syscall::PAGE_SIZE; pub mod dma; @@ -25,19 +25,38 @@ pub struct Prot { pub write: bool, } impl Prot { - pub const RO: Self = Self { read: true, write: false }; - pub const WO: Self = Self { read: false, write: true }; - pub const RW: Self = Self { read: true, write: true }; + pub const RO: Self = Self { + read: true, + write: false, + }; + pub const WO: Self = Self { + read: false, + write: true, + }; + pub const RW: Self = Self { + read: true, + write: true, + }; } -pub unsafe fn physmap(base_phys: usize, len: usize, Prot { read, write }: Prot, ty: MemoryType) -> Result<*mut ()> { +// TODO: Safe, as the kernel ensures it doesn't conflict with any other memory described in the +// memory map for regular RAM. +pub unsafe fn physmap( + base_phys: usize, + len: usize, + Prot { read, write }: Prot, + ty: MemoryType, +) -> Result<*mut ()> { // TODO: arraystring? - let path = format!("memory:physical@{}", match ty { - MemoryType::Writeback => "wb", - MemoryType::Uncacheable => "uc", - MemoryType::WriteCombining => "wc", - MemoryType::DeviceMemory => "dev", - }); + let path = format!( + "memory:physical@{}", + match ty { + MemoryType::Writeback => "wb", + MemoryType::Uncacheable => "uc", + MemoryType::WriteCombining => "wc", + MemoryType::DeviceMemory => "dev", + } + ); let mode = match (read, write) { (true, true) => O_RDWR, (true, false) => O_RDONLY, @@ -49,12 +68,15 @@ pub unsafe fn physmap(base_phys: usize, len: usize, Prot { read, write }: Prot, prot.set(MapFlags::PROT_WRITE, write); let file = syscall::open(path, O_CLOEXEC | mode)?; - let base = syscall::fmap(file, &syscall::Map { - offset: base_phys, - size: len.next_multiple_of(PAGE_SIZE), - flags: MapFlags::MAP_SHARED | prot, - address: 0, - }); + let base = syscall::fmap( + file, + &syscall::Map { + offset: base_phys, + size: len.next_multiple_of(PAGE_SIZE), + flags: MapFlags::MAP_SHARED | prot, + address: 0, + }, + ); let _ = syscall::close(file); Ok(base? as *mut ()) @@ -62,11 +84,42 @@ pub unsafe fn physmap(base_phys: usize, len: usize, Prot { read, write }: Prot, impl std::fmt::Display for MemoryType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", match self { - Self::Writeback => "wb", - Self::Uncacheable => "uc", - Self::WriteCombining => "wc", - Self::DeviceMemory => "dev", - }) + write!( + f, + "{}", + match self { + Self::Writeback => "wb", + Self::Uncacheable => "uc", + Self::WriteCombining => "wc", + Self::DeviceMemory => "dev", + } + ) + } +} + +pub struct PhysBorrowed { + mem: *mut (), + len: usize, +} +impl PhysBorrowed { + pub fn map(base_phys: usize, len: usize, prot: Prot, ty: MemoryType) -> Result { + let mem = unsafe { physmap(base_phys, len, prot, ty)? }; + Ok(Self { + mem, + len: len.next_multiple_of(PAGE_SIZE), + }) + } + pub fn as_ptr(&self) -> *mut () { + self.mem + } + pub fn mapped_len(&self) -> usize { + self.len + } +} +impl Drop for PhysBorrowed { + fn drop(&mut self) { + unsafe { + let _ = syscall::funmap(self.mem as usize, self.len); + } } } diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index fd7f6e706a..e3f0d4ed91 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -1,7 +1,7 @@ use std::sync::Mutex; -use std::{fmt, fs, io, mem, ptr, slice}; +use std::{fmt, fs, io, mem, ptr}; -use log::info; +use common::{MemoryType, PhysBorrowed, Prot}; use pci_types::{ConfigRegionAccess, PciAddress}; use fallback::Pci; @@ -11,7 +11,7 @@ mod fallback; pub const MCFG_NAME: [u8; 4] = *b"MCFG"; #[repr(packed)] -#[derive(Clone, Copy)] +#[derive(Clone, Copy, Debug)] pub struct Mcfg { // base sdt fields name: [u8; 4], @@ -24,8 +24,6 @@ pub struct Mcfg { creator_id: [u8; 4], creator_revision: u32, _rsvd: [u8; 8], - - base_addrs: [PcieAlloc; 0], } unsafe impl plain::Plain for Mcfg {} @@ -42,10 +40,15 @@ pub struct PcieAlloc { } unsafe impl plain::Plain for PcieAlloc {} +#[derive(Debug)] +struct PcieAllocs<'a>(&'a [PcieAlloc]); + impl Mcfg { - fn with(f: impl FnOnce(&Mcfg) -> io::Result) -> io::Result { + fn with(f: impl FnOnce(&Mcfg, PcieAllocs<'_>) -> io::Result) -> io::Result { let table_dir = fs::read_dir("acpi:tables")?; + // TODO: validate/print MCFG? + for table_direntry in table_dir { let table_path = table_direntry?.path(); @@ -59,7 +62,7 @@ impl Mcfg { if table_filename.get(0..4) == Some(&MCFG_NAME) { let bytes = fs::read(table_path)?.into_boxed_slice(); match Mcfg::parse(&*bytes) { - Some(mcfg) => return f(mcfg), + Some((mcfg, allocs)) => return f(mcfg, allocs), None => { return Err(io::Error::new( io::ErrorKind::InvalidData, @@ -76,129 +79,136 @@ impl Mcfg { )) } - fn parse<'a>(bytes: &'a [u8]) -> Option<&'a Mcfg> { - let mcfg = plain::from_bytes::(bytes).ok()?; - if mcfg.length as usize > bytes.len() { + fn parse<'a>(bytes: &'a [u8]) -> Option<(&'a Mcfg, PcieAllocs<'a>)> { + if bytes.len() < mem::size_of::() { return None; } - Some(mcfg) - } + let (header_bytes, allocs_bytes) = bytes.split_at(mem::size_of::()); - fn at_bus(&self, bus: u8) -> Option<&PcieAlloc> { - Some( - self.base_addr_structs() - .iter() - .find(|addr_struct| (addr_struct.start_bus..=addr_struct.end_bus).contains(&bus))?, - ) - } - - fn base_addr_structs(&self) -> &[PcieAlloc] { - let total_length = self.length as usize; - let len = total_length - mem::size_of::(); - // safe because the length cannot be changed arbitrarily - unsafe { - slice::from_raw_parts( - &self.base_addrs as *const PcieAlloc, - len / mem::size_of::(), - ) + let mcfg = + plain::from_bytes::(header_bytes).expect("packed -> align 1, checked size"); + if mcfg.length as usize != bytes.len() { + log::warn!("MCFG {mcfg:?} length mismatch, expected {}", bytes.len()); + return None; } - } -} + // TODO: Allow invalid bytes not divisible by PcieAlloc? -impl fmt::Debug for Mcfg { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_struct("Mcfg") - .field("name", &self.name) - .field("length", &{ self.length }) - .field("revision", &self.revision) - .field("checksum", &self.checksum) - .field("oem_id", &self.oem_id) - .field("oem_table_id", &{ self.oem_table_id }) - .field("oem_revision", &{ self.oem_revision }) - .field("creator_revision", &{ self.creator_revision }) - .field("creator_id", &self.creator_id) - .field("base_addrs", &self.base_addr_structs()) - .finish() + let allocs_len = + allocs_bytes.len() / mem::size_of::() * mem::size_of::(); + + let allocs = plain::slice_from_bytes::(&allocs_bytes[..allocs_len]) + .expect("packed -> align 1, checked size"); + Some((mcfg, PcieAllocs(allocs))) } } pub struct Pcie { lock: Mutex<()>, - bus_maps: Vec>, + allocs: Vec, fallback: Pci, } +struct Alloc { + seg: u16, + start_bus: u8, + end_bus: u8, + mem: PhysBorrowed, +} + unsafe impl Send for Pcie {} unsafe impl Sync for Pcie {} +const BYTES_PER_BUS: usize = 1 << 20; + impl Pcie { pub fn new() -> Self { - match Mcfg::with(|mcfg| { - let alloc_maps = (0..=255) - .map(|bus| { - if let Some(alloc) = mcfg.at_bus(bus) { - Some(unsafe { Self::physmap_pcie_bus(alloc, bus) }) - } else { - None - } + match Mcfg::with(|mcfg, allocs| { + log::info!("MCFG {mcfg:?} ALLOCS {allocs:?}"); + let mut allocs = allocs + .0 + .iter() + .filter_map(|desc| { + Some(Alloc { + seg: desc.seg_group_num, + start_bus: desc.start_bus, + end_bus: desc.end_bus, + mem: PhysBorrowed::map( + desc.base_addr.try_into().ok()?, + BYTES_PER_BUS + * (usize::from(desc.end_bus) - usize::from(desc.start_bus) + 1), + Prot::RW, + MemoryType::Uncacheable, + ) + .inspect_err(|err| { + log::error!( + "failed to map seg {} bus {}..={}: {}", + { desc.seg_group_num }, + { desc.start_bus }, + { desc.end_bus }, + err + ) + }) + .ok()?, + }) }) .collect::>(); + allocs.sort_by_key(|alloc| (alloc.seg, alloc.start_bus)); + Ok(Self { lock: Mutex::new(()), - bus_maps: alloc_maps, + allocs, fallback: Pci::new(), }) }) { Ok(pcie) => pcie, Err(error) => { - info!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error); + log::warn!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error); Self { lock: Mutex::new(()), - bus_maps: vec![], + allocs: Vec::new(), fallback: Pci::new(), } } } } - - unsafe fn physmap_pcie_bus(alloc: &PcieAlloc, bus: u8) -> (*mut u32, usize) { - let base_phys = alloc.base_addr as usize + (((bus - alloc.start_bus) as usize) << 20); - let map_size = 1 << 20; - let ptr = common::physmap( - base_phys, - map_size, - common::Prot { - read: true, - write: true, - }, - common::MemoryType::Uncacheable, - ) - .unwrap_or_else(|error| { - panic!( - "failed to physmap pcie configuration space for segment {} bus {} @ {:p}: {:?}", - { alloc.seg_group_num }, - bus, - base_phys as *const u32, - error, - ) - }) as *mut u32; - (ptr, map_size) + fn bus_addr(&self, seg: u16, bus: u8) -> Option<*mut u32> { + let alloc = match self + .allocs + .binary_search_by_key(&(seg, bus), |alloc| (alloc.seg, alloc.start_bus)) + { + Ok(present_idx) => &self.allocs[present_idx], + Err(0) => return None, + Err(above_idx) => { + let below_alloc = &self.allocs[above_idx - 1]; + if bus > below_alloc.end_bus { + return None; + } + below_alloc + } + }; + let bus_off = bus - alloc.start_bus; + Some(unsafe { + alloc + .mem + .as_ptr() + .cast::() + .add(usize::from(bus_off) * BYTES_PER_BUS) + .cast::() + }) } - fn bus_addr_offset_in_bytes(address: PciAddress, offset: u16) -> usize { + fn bus_addr_offset_in_dwords(address: PciAddress, offset: u16) -> usize { assert_eq!(offset & 0xFFFC, offset, "pcie offset not dword-aligned"); assert_eq!(offset & 0x0FFF, offset, "pcie offset larger than 4095"); - ((address.device() as usize) << 15) + (((address.device() as usize) << 15) | ((address.function() as usize) << 12) - | (offset as usize) + | (offset as usize)) + >> 2 } - unsafe fn with_pointer) -> T>( - &self, - address: PciAddress, - offset: u16, - f: F, - ) -> T { + // TODO: A safer interface, using e.g. a VolatileCell or Volatile<'a>. The PhysBorrowed wrapper + // can possibly deref to or provide a Volatile. + fn mmio_addr(&self, address: PciAddress, offset: u16) -> Option<*mut u32> { assert_eq!( address.segment(), 0, @@ -207,17 +217,8 @@ impl Pcie { assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); - let bus_addr = match self.bus_maps.get(address.bus() as usize) { - Some(Some(bus_addr)) => bus_addr, - Some(None) | None => return f(None), - }; - let virt_pointer = unsafe { - // FIXME use byte_add once stable - (bus_addr.0 as *mut u8).add(Self::bus_addr_offset_in_bytes(address, 0)) as *mut u32 - }; - f(Some(&mut *virt_pointer.offset( - (offset as usize / mem::size_of::()) as isize, - ))) + let bus_addr = self.bus_addr(address.segment(), address.bus())?; + Some(unsafe { bus_addr.add(Self::bus_addr_offset_in_dwords(address, offset)) }) } } @@ -229,30 +230,18 @@ impl ConfigRegionAccess for Pcie { unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); - self.with_pointer(address, offset, |pointer| match pointer { - Some(address) => ptr::read_volatile::(address), + match self.mmio_addr(address, offset) { + Some(addr) => addr.read_volatile(), None => self.fallback.read(address, offset), - }) + } } unsafe fn write(&self, address: PciAddress, offset: u16, value: u32) { let _guard = self.lock.lock().unwrap(); - self.with_pointer(address, offset, |pointer| match pointer { - Some(address) => ptr::write_volatile::(address, value), - None => { - self.fallback.write(address, offset, value); - } - }); - } -} - -impl Drop for Pcie { - fn drop(&mut self) { - for &map in &self.bus_maps { - if let Some((ptr, size)) = map { - let _ = unsafe { syscall::funmap(ptr as usize, size) }; - } + match self.mmio_addr(address, offset) { + Some(addr) => addr.write_volatile(value), + None => self.fallback.write(address, offset, value), } } } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 56f78191bf..e2915272cb 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,3 +1,6 @@ +// Already stabilized, TODO: remove when Redox's rustc is updated +#![feature(result_option_inspect)] + use std::fs::{File, metadata, read_dir}; use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; From 3751c915fe5b077d399e5220b6fc002c7127da52 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 26 Feb 2024 20:43:41 +0100 Subject: [PATCH 0821/1301] Unify the scheme handling of all network drivers This deduplicates a fair bit of non-trivial logic and makes it easier to keep all network drivers in sync when the interface changes. --- Cargo.lock | 12 ++ Cargo.toml | 1 + driver-network/Cargo.toml | 8 ++ driver-network/src/lib.rs | 255 ++++++++++++++++++++++++++++++++++++++ e1000d/Cargo.toml | 1 + e1000d/src/device.rs | 131 +++----------------- e1000d/src/main.rs | 203 ++++++++---------------------- ixgbed/Cargo.toml | 1 + ixgbed/src/device.rs | 77 ++---------- ixgbed/src/main.rs | 221 +++++++++------------------------ rtl8139d/Cargo.toml | 1 + rtl8139d/src/device.rs | 75 ++--------- rtl8139d/src/main.rs | 207 ++++++++----------------------- rtl8168d/Cargo.toml | 1 + rtl8168d/src/device.rs | 78 ++---------- rtl8168d/src/main.rs | 200 +++++++----------------------- 16 files changed, 539 insertions(+), 933 deletions(-) create mode 100644 driver-network/Cargo.toml create mode 100644 driver-network/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 59273691f6..a5accc366e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -372,12 +372,21 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "driver-network" +version = "0.1.0" +dependencies = [ + "redox_event 0.1.0", + "redox_syscall 0.4.1", +] + [[package]] name = "e1000d" version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "driver-network", "netutils", "pcid", "redox-daemon", @@ -664,6 +673,7 @@ version = "1.0.0" dependencies = [ "bitflags 1.3.2", "common", + "driver-network", "netutils", "pcid", "redox-daemon", @@ -1218,6 +1228,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "driver-network", "log", "netutils", "pcid", @@ -1233,6 +1244,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "driver-network", "log", "netutils", "pcid", diff --git a/Cargo.toml b/Cargo.toml index bd8c75cf68..275cb4b681 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "bgad", "block-io-wrapper", "common", + "driver-network", "e1000d", "fbcond", "ided", diff --git a/driver-network/Cargo.toml b/driver-network/Cargo.toml new file mode 100644 index 0000000000..47be9d3175 --- /dev/null +++ b/driver-network/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "driver-network" +version = "0.1.0" +edition = "2021" + +[dependencies] +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox_syscall = "0.4" diff --git a/driver-network/src/lib.rs b/driver-network/src/lib.rs new file mode 100644 index 0000000000..23fcc38135 --- /dev/null +++ b/driver-network/src/lib.rs @@ -0,0 +1,255 @@ +use std::collections::BTreeMap; +use std::fs::File; +use std::io::{ErrorKind, Read, Write}; +use std::os::fd::{AsRawFd, FromRawFd, RawFd}; +use std::{cmp, io}; + +use syscall::{ + Error, EventFlags, Packet, Result, SchemeBlockMut, Stat, EACCES, EBADF, EINVAL, EWOULDBLOCK, + MODE_FILE, O_NONBLOCK, +}; + +pub trait NetworkAdapter { + /// The [MAC address](https://en.wikipedia.org/wiki/MAC_address) of this + /// network adapter. + fn mac_address(&mut self) -> [u8; 6]; + + /// The amount of network packets that can be read without blocking. + fn available_for_read(&mut self) -> usize; + + /// Attempt to read a network packet without blocking. + /// + /// Returns `Ok(None)` when there is no pending network packet. + fn read_packet(&mut self, buf: &mut [u8]) -> Result>; + + /// Write a single network packet. + // FIXME support back pressure on writes by returning EWOULDBLOCK or not + // returning from the write syscall until there is room. + fn write_packet(&mut self, buf: &[u8]) -> Result; +} + +pub struct NetworkScheme { + adapter: T, + scheme: File, + next_id: usize, + handles: BTreeMap, + todo_packets: Vec, +} + +#[derive(Copy, Clone)] +enum Handle { + Data { flags: usize }, + Mac { offset: usize }, +} + +impl NetworkScheme { + pub fn new(adapter: T, scheme_name: &str) -> Self { + let scheme_fd = syscall::open( + format!(":{scheme_name}"), + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + ) + .expect("e1000d: failed to create network scheme"); + let scheme = unsafe { File::from_raw_fd(scheme_fd as RawFd) }; + + NetworkScheme { + adapter, + scheme, + next_id: 0, + handles: BTreeMap::new(), + todo_packets: vec![], + } + } + + pub fn event_handle(&self) -> RawFd { + self.scheme.as_raw_fd() + } + + pub fn adapter(&self) -> &T { + &self.adapter + } + + pub fn adapter_mut(&mut self) -> &mut T { + &mut self.adapter + } + + /// Process pending and new packets. + /// + /// This needs to be called each time there is a new event on the scheme + /// file and each time a new network packet has been received by the + /// driver. + // FIXME maybe split into one method for events on the scheme fd and one + // to call when an irq is received to indicate that blocked packets can + // be processed. + pub fn tick(&mut self) -> io::Result<()> { + // Handle any blocked packets + let mut i = 0; + while i < self.todo_packets.len() { + let mut packet = self.todo_packets[i].clone(); + if let Some(a) = self.handle(&packet) { + self.todo_packets.remove(i); + packet.a = a; + self.scheme.write(&packet)?; + } else { + i += 1; + } + } + + // Handle new scheme packets + loop { + let mut packet = Packet::default(); + match self.scheme.read(&mut packet) { + Ok(0) => { + return Err(io::Error::new( + ErrorKind::BrokenPipe, + "scheme has been closed by the kernel", + )); + } + Ok(_) => {} + Err(err) if err.kind() == ErrorKind::WouldBlock => break, + Err(err) => { + return Err(err); + } + } + + if let Some(a) = self.handle(&packet) { + packet.a = a; + self.scheme.write(&packet)?; + } else { + self.todo_packets.push(packet); + } + } + + // Notify readers about incoming events + let available_for_read = self.adapter.available_for_read(); + if available_for_read > 0 { + for &handle_id in self.handles.keys() { + self.scheme.write(&Packet { + id: 0, + pid: 0, + uid: 0, + gid: 0, + a: syscall::number::SYS_FEVENT, + b: handle_id, + c: syscall::flag::EVENT_READ.bits(), + d: available_for_read, + })?; + } + return Ok(()); + } + + Ok(()) + } +} + +impl SchemeBlockMut for NetworkScheme { + fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { + if uid != 0 { + return Err(Error::new(EACCES)); + } + + let handle = match path { + "" => Handle::Data { flags }, + "mac" => Handle::Mac { offset: 0 }, + _ => return Err(Error::new(EINVAL)), + }; + + self.next_id += 1; + self.handles.insert(self.next_id, handle); + Ok(Some(self.next_id)) + } + + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { + if !buf.is_empty() { + return Err(Error::new(EINVAL)); + } + + let handle = *self.handles.get(&id).ok_or(Error::new(EBADF))?; + self.next_id += 1; + self.handles.insert(self.next_id, handle); + Ok(Some(self.next_id)) + } + + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let flags = match *handle { + Handle::Data { flags } => flags, + Handle::Mac { ref mut offset } => { + let data = &self.adapter.mac_address()[*offset..]; + let i = cmp::min(buf.len(), data.len()); + buf[..i].copy_from_slice(&data[..i]); + *offset += i; + return Ok(Some(i)); + } + }; + + match self.adapter.read_packet(buf)? { + Some(count) => Ok(Some(count)), + None => { + if flags & O_NONBLOCK == O_NONBLOCK { + Err(Error::new(EWOULDBLOCK)) + } else { + Ok(None) + } + } + } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + match handle { + Handle::Data { .. } => {} + Handle::Mac { .. } => return Err(Error::new(EINVAL)), + } + + Ok(Some(self.adapter.write_packet(buf)?)) + } + + fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + Ok(Some(EventFlags::empty())) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let scheme_path = match handle { + Handle::Data { .. } => &b"network:"[..], + Handle::Mac { .. } => &b"network:mac"[..], + }; + + let mut i = 0; + while i < buf.len() && i < scheme_path.len() { + buf[i] = scheme_path[i]; + i += 1; + } + Ok(Some(i)) + } + + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + match handle { + Handle::Data { .. } => { + stat.st_mode = MODE_FILE | 0o700; + } + Handle::Mac { .. } => { + stat.st_mode = MODE_FILE | 0o400; + stat.st_size = 6; + } + } + + Ok(Some(0)) + } + + fn fsync(&mut self, id: usize) -> Result> { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + Ok(Some(0)) + } + + fn close(&mut self, id: usize) -> Result> { + self.handles.remove(&id).ok_or(Error::new(EBADF))?; + Ok(Some(0)) + } +} diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 90b9367de0..8a958db6ca 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -11,4 +11,5 @@ redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" common = { path = "../common" } +driver-network = { path = "../driver-network" } pcid = { path = "../pcid" } diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index e90f172a58..d6e89495f8 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -1,13 +1,10 @@ -use std::collections::BTreeMap; use std::convert::TryInto; use std::{cmp, mem, ptr, slice}; +use driver_network::NetworkAdapter; use netutils::setcfg; -use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; -use syscall::flag::{EventFlags, MODE_FILE, O_NONBLOCK}; -use syscall::scheme::SchemeBlockMut; -use syscall::Stat; +use syscall::error::Result; use common::dma::Dma; @@ -109,8 +106,6 @@ pub struct Intel8254x { transmit_ring_free: usize, transmit_index: usize, transmit_clean_index: usize, - next_id: usize, - pub handles: BTreeMap, } #[derive(Copy, Clone)] @@ -123,48 +118,22 @@ fn wrap_ring(index: usize, ring_size: usize) -> usize { (index + 1) & (ring_size - 1) } -impl SchemeBlockMut for Intel8254x { - fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid != 0 { - return Err(Error::new(EACCES)); - } - - let handle = match path { - "" => Handle::Data { flags }, - "mac" => Handle::Mac { offset: 0 }, - _ => return Err(Error::new(EINVAL)), - }; - - self.next_id += 1; - self.handles.insert(self.next_id, handle); - Ok(Some(self.next_id)) +impl NetworkAdapter for Intel8254x { + fn mac_address(&mut self) -> [u8; 6] { + self.mac_address } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); + fn available_for_read(&mut self) -> usize { + let desc = unsafe { &*(self.receive_ring.as_ptr().add(self.receive_index) as *const Rd) }; + + if desc.status & RD_DD == RD_DD { + return desc.length as usize; } - let handle = *self.handles.get(&id).ok_or(Error::new(EBADF))?; - self.next_id += 1; - self.handles.insert(self.next_id, handle); - Ok(Some(self.next_id)) + 0 } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - let flags = match *handle { - Handle::Data { flags } => flags, - Handle::Mac { ref mut offset } => { - let data = &self.mac_address[*offset..]; - let i = cmp::min(buf.len(), data.len()); - buf[..i].copy_from_slice(&data[..i]); - *offset += i; - return Ok(Some(i)); - } - }; - + fn read_packet(&mut self, buf: &mut [u8]) -> Result> { let desc = unsafe { &mut *(self.receive_ring.as_ptr().add(self.receive_index) as *mut Rd) }; if desc.status & RD_DD == RD_DD { @@ -181,21 +150,10 @@ impl SchemeBlockMut for Intel8254x { return Ok(Some(i)); } - if flags & O_NONBLOCK == O_NONBLOCK { - Err(Error::new(EWOULDBLOCK)) - } else { - Ok(None) - } + Ok(None) } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - match handle { - Handle::Data { .. } => {} - Handle::Mac { .. } => return Err(Error::new(EINVAL)), - } - + fn write_packet(&mut self, buf: &[u8]) -> Result { if self.transmit_ring_free == 0 { loop { let desc = unsafe { @@ -245,54 +203,7 @@ impl SchemeBlockMut for Intel8254x { unsafe { self.write_reg(TDT, self.transmit_index as u32) }; - Ok(Some(i)) - } - - fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(EventFlags::empty())) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let scheme_path = match handle { - Handle::Data { .. } => &b"network:"[..], - Handle::Mac { .. } => &b"network:mac"[..], - }; - - let mut i = 0; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } - Ok(Some(i)) - } - - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - match handle { - Handle::Data { .. } => { - stat.st_mode = MODE_FILE | 0o700; - } - Handle::Mac { .. } => { - stat.st_mode = MODE_FILE | 0o400; - stat.st_size = 6; - } - } - - Ok(Some(0)) - } - - fn fsync(&mut self, id: usize) -> Result> { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) + Ok(i) } } @@ -317,8 +228,6 @@ impl Intel8254x { transmit_ring_free: 16, transmit_index: 0, transmit_clean_index: 0, - next_id: 0, - handles: BTreeMap::new(), }; module.init(); @@ -331,16 +240,6 @@ impl Intel8254x { icr != 0 } - pub fn next_read(&self) -> usize { - let desc = unsafe { &*(self.receive_ring.as_ptr().add(self.receive_index) as *const Rd) }; - - if desc.status & RD_DD == RD_DD { - return desc.length as usize; - } - - 0 - } - pub unsafe fn read_reg(&self, register: u32) -> u32 { ptr::read_volatile((self.base + register as usize) as *mut u32) } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 1746883701..2f141219ff 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -1,63 +1,16 @@ -extern crate event; -extern crate netutils; -extern crate syscall; - use std::cell::RefCell; -use std::fs::File; -use std::io::{ErrorKind, Read, Result, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::process; -use std::sync::Arc; +use std::convert::Infallible; +use std::io::{Read, Result, Write}; +use std::os::unix::io::AsRawFd; +use std::rc::Rc; +use driver_network::NetworkScheme; use event::EventQueue; use pcid_interface::PcidServerHandle; -use syscall::{EventFlags, Packet, SchemeBlockMut}; +use syscall::EventFlags; pub mod device; -fn handle_update( - socket: &mut File, - device: &mut device::Intel8254x, - todo: &mut Vec, -) -> Result { - // Handle any blocked packets - let mut i = 0; - while i < todo.len() { - if let Some(a) = device.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet)?; - } else { - i += 1; - } - } - - // Check that the socket is empty - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => return Ok(true), - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } - } - - if let Some(a) = device.handle(&packet) { - packet.a = a; - socket.write(&packet)?; - } else { - todo.push(packet); - } - } - - Ok(false) -} - fn main() { let mut pcid_handle = PcidServerHandle::connect_default().expect("e1000d: failed to setup channel to pcid"); @@ -70,122 +23,68 @@ fn main() { let bar = &pci_config.func.bars[0]; - let irq = pci_config.func.legacy_interrupt_line.expect("e1000d: no legacy interrupts supported"); + let irq = pci_config + .func + .legacy_interrupt_line + .expect("e1000d: no legacy interrupts supported"); eprintln!(" + E1000 {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { - let socket_fd = syscall::open( - ":network", - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ) - .expect("e1000d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) - })); - let mut irq_file = irq.irq_handle("e1000d"); let address = unsafe { bar.physmap_mem("e1000d") } as usize; - { - let device = Arc::new(RefCell::new(unsafe { - device::Intel8254x::new(address).expect("e1000d: failed to allocate device") - })); - let mut event_queue = - EventQueue::::new().expect("e1000d: failed to create event queue"); + let device = + unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }; - syscall::setrens(0, 0).expect("e1000d: failed to enter null namespace"); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); - daemon.ready().expect("e1000d: failed to mark daemon as ready"); + let mut event_queue = + EventQueue::::new().expect("e1000d: failed to create event queue"); - let todo = Arc::new(RefCell::new(Vec::::new())); + syscall::setrens(0, 0).expect("e1000d: failed to enter null namespace"); - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - if unsafe { device_irq.borrow().irq() } { - irq_file.write(&mut irq)?; + daemon + .ready() + .expect("e1000d: failed to mark daemon as ready"); - if handle_update( - &mut socket_irq.borrow_mut(), - &mut device_irq.borrow_mut(), - &mut todo_irq.borrow_mut(), - )? { - return Ok(Some(0)); - } + let scheme_irq = scheme.clone(); + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + if unsafe { scheme_irq.borrow().adapter().irq() } { + irq_file.write(&mut irq)?; - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }, - ) - .expect("e1000d: failed to catch events on IRQ file"); - - let device_packet = device.clone(); - let socket_packet = socket.clone(); - event_queue - .add(socket_fd as RawFd, move |_event| -> Result> { - if handle_update( - &mut socket_packet.borrow_mut(), - &mut device_packet.borrow_mut(), - &mut todo.borrow_mut(), - )? { - return Ok(Some(0)); + return scheme_irq.borrow_mut().tick().map(|()| None); } - - let next_read = device_packet.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - Ok(None) - }) - .expect("e1000d: failed to catch events on scheme file"); + }, + ) + .expect("e1000d: failed to catch events on IRQ file"); - let send_events = |event_count| { - for (handle_id, _handle) in device.borrow().handles.iter() { - socket - .borrow_mut() - .write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: syscall::flag::EVENT_READ.bits(), - d: event_count, - }) - .expect("e1000d: failed to write event"); - } - }; + let scheme_packet = scheme.clone(); + event_queue + .add( + scheme.borrow().event_handle(), + move |_event| -> Result> { + scheme_packet.borrow_mut().tick().map(|()| None) + }, + ) + .expect("e1000d: failed to catch events on scheme file"); - for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) - .expect("e1000d: failed to trigger events") - { - send_events(event_count); - } + event_queue + .trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }) + .expect("e1000d: failed to trigger events"); - loop { - let event_count = event_queue.run().expect("e1000d: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } - send_events(event_count); - } - } - process::exit(0); - }).expect("e1000d: failed to create daemon"); + #[allow(unreachable_code)] + match event_queue.run().expect("e1000d: failed to handle events") {} + }) + .expect("e1000d: failed to create daemon"); } diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml index 1760a676bc..780fc29e08 100644 --- a/ixgbed/Cargo.toml +++ b/ixgbed/Cargo.toml @@ -11,4 +11,5 @@ redox_syscall = "0.4" redox-daemon = "0.1" common = { path = "../common" } +driver-network = { path = "../driver-network" } pcid = { path = "../pcid" } diff --git a/ixgbed/src/device.rs b/ixgbed/src/device.rs index 9d0f59abd4..3fd47e029b 100644 --- a/ixgbed/src/device.rs +++ b/ixgbed/src/device.rs @@ -1,11 +1,9 @@ -use std::collections::BTreeMap; use std::convert::TryInto; use std::time::{Duration, Instant}; use std::{cmp, mem, ptr, slice, thread}; -use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EWOULDBLOCK}; -use syscall::flag::{EventFlags, O_NONBLOCK}; -use syscall::scheme::SchemeBlockMut; +use driver_network::NetworkAdapter; +use syscall::error::Result; use common::dma::Dma; use netutils::setcfg; @@ -23,42 +21,23 @@ pub struct Intel8259x { transmit_ring_free: usize, transmit_index: usize, transmit_clean_index: usize, - next_id: usize, - pub handles: BTreeMap, } fn wrap_ring(index: usize, ring_size: usize) -> usize { (index + 1) & (ring_size - 1) } -impl SchemeBlockMut for Intel8259x { - fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) - } else { - Err(Error::new(EACCES)) - } +impl NetworkAdapter for Intel8259x { + fn mac_address(&mut self) -> [u8; 6] { + // FIXME read from the network adapter itself + [0xfe; 6] // FE-FE-FE-FE-FE-FE } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let flags = { - let flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - *flags - }; - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) + fn available_for_read(&mut self) -> usize { + self.next_read() } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - + fn read_packet(&mut self, buf: &mut [u8]) -> Result> { let desc = unsafe { &mut *(self.receive_ring.as_ptr().add(self.receive_index) as *mut ixgbe_adv_rx_desc) }; @@ -86,16 +65,10 @@ impl SchemeBlockMut for Intel8259x { return Ok(Some(i)); } - if flags & O_NONBLOCK == O_NONBLOCK { - Err(Error::new(EWOULDBLOCK)) - } else { - Ok(None) - } + Ok(None) } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - + fn write_packet(&mut self, buf: &[u8]) -> Result { if self.transmit_ring_free == 0 { loop { let desc = unsafe { @@ -145,31 +118,7 @@ impl SchemeBlockMut for Intel8259x { self.write_reg(IXGBE_TDT(0), self.transmit_index as u32); - Ok(Some(i)) - } - - fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { - let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - Ok(Some(EventFlags::empty())) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - - let scheme_path = b"network:"; - let i = cmp::min(buf.len(), scheme_path.len()); - buf[..i].copy_from_slice(&scheme_path[..i]); - Ok(Some(i)) - } - - fn fsync(&mut self, id: usize) -> Result> { - let _flags = self.handles.get(&id).ok_or_else(|| Error::new(EBADF))?; - Ok(Some(0)) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or_else(|| Error::new(EBADF))?; - Ok(Some(0)) + Ok(i) } } @@ -196,8 +145,6 @@ impl Intel8259x { transmit_ring_free: 32, transmit_index: 0, transmit_clean_index: 0, - next_id: 0, - handles: BTreeMap::new(), }; module.init(); diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index a5ec7bfa7f..1f09e76b2d 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -1,21 +1,13 @@ -extern crate event; -extern crate netutils; -extern crate syscall; - -// TODO: Migrate to Rust 2018/2021 -extern crate common; - use std::cell::RefCell; -use std::fs::File; -use std::io::{ErrorKind, Read, Result, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::sync::Arc; -use std::thread; +use std::convert::Infallible; +use std::io::{Read, Result, Write}; +use std::os::unix::io::AsRawFd; +use std::rc::Rc; +use driver_network::NetworkScheme; use event::EventQueue; use pcid_interface::PcidServerHandle; -use std::time::Duration; -use syscall::{EventFlags, Packet, SchemeBlockMut}; +use syscall::EventFlags; pub mod device; #[rustfmt::skip] @@ -23,49 +15,6 @@ mod ixgbe; const IXGBE_MMIO_SIZE: usize = 512 * 1024; -fn handle_update( - socket: &mut File, - device: &mut device::Intel8259x, - todo: &mut Vec, -) -> Result { - // Handle any blocked packets - let mut i = 0; - while i < todo.len() { - if let Some(a) = device.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet)?; - } else { - i += 1; - } - } - - // Check that the socket is empty - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => return Ok(true), - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } - } - - if let Some(a) = device.handle(&packet) { - packet.a = a; - socket.write(&packet)?; - } else { - todo.push(packet); - } - } - - Ok(false) -} - fn main() { let mut pcid_handle = PcidServerHandle::connect_default().expect("ixgbed: failed to setup channel to pcid"); @@ -78,130 +27,76 @@ fn main() { let (bar, _) = pci_config.func.bars[0].expect_mem(); - let irq = pci_config.func.legacy_interrupt_line.expect("ixgbed: no legacy interrupts supported"); + let irq = pci_config + .func + .legacy_interrupt_line + .expect("ixgbed: no legacy interrupts supported"); println!(" + IXGBE {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { - let socket_fd = syscall::open( - ":network", - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ) - .expect("ixgbed: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) - })); - - daemon.ready().expect("ixgbed: failed to signal readiness"); - let mut irq_file = irq.irq_handle("ixgbed"); let address = unsafe { - common::physmap(bar, IXGBE_MMIO_SIZE, common::Prot::RW, common::MemoryType::Uncacheable) - .expect("ixgbed: failed to map address") as usize + common::physmap( + bar, + IXGBE_MMIO_SIZE, + common::Prot::RW, + common::MemoryType::Uncacheable, + ) + .expect("ixgbed: failed to map address") as usize }; - { - let device = Arc::new(RefCell::new( - device::Intel8259x::new(address, IXGBE_MMIO_SIZE) - .expect("ixgbed: failed to allocate device") - )); - let mut event_queue = - EventQueue::::new().expect("ixgbed: failed to create event queue"); + let device = device::Intel8259x::new(address, IXGBE_MMIO_SIZE) + .expect("ixgbed: failed to allocate device"); - syscall::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); - let todo = Arc::new(RefCell::new(Vec::::new())); + let mut event_queue = + EventQueue::::new().expect("ixgbed: failed to create event queue"); - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - if device_irq.borrow().irq() { - irq_file.write(&irq)?; + syscall::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); - if handle_update( - &mut socket_irq.borrow_mut(), - &mut device_irq.borrow_mut(), - &mut todo_irq.borrow_mut(), - )? { - return Ok(Some(0)); - } + daemon + .ready() + .expect("ixgbed: failed to mark daemon as ready"); - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }, - ) - .expect("ixgbed: failed to catch events on IRQ file"); + let scheme_irq = scheme.clone(); + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + if scheme_irq.borrow().adapter().irq() { + irq_file.write(&mut irq)?; - let device_packet = device.clone(); - let socket_packet = socket.clone(); - - event_queue - .add(socket_fd as RawFd, move |_event| -> Result> { - if handle_update( - &mut socket_packet.borrow_mut(), - &mut device_packet.borrow_mut(), - &mut todo.borrow_mut(), - )? { - return Ok(Some(0)); + return scheme_irq.borrow_mut().tick().map(|()| None); } - - let next_read = device_packet.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - Ok(None) - }) - .expect("ixgbed: failed to catch events on scheme file"); + }, + ) + .expect("ixgbed: failed to catch events on IRQ file"); - let send_events = |event_count| { - for (handle_id, _handle) in device.borrow().handles.iter() { - socket - .borrow_mut() - .write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: syscall::flag::EVENT_READ.bits(), - d: event_count, - }) - .expect("ixgbed: failed to write event"); - } - }; + let scheme_packet = scheme.clone(); + event_queue + .add( + scheme.borrow().event_handle(), + move |_event| -> Result> { + scheme_packet.borrow_mut().tick().map(|()| None) + }, + ) + .expect("ixgbed: failed to catch events on scheme file"); - for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) - .expect("ixgbed: failed to trigger events") - { - send_events(event_count); - } + event_queue + .trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }) + .expect("ixgbed: failed to trigger events"); - loop { - let event_count = event_queue.run().expect("ixgbed: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } - - send_events(event_count); - } - } - std::process::exit(0); - }).expect("ixgbed: failed to daemonize"); - - thread::sleep(Duration::from_secs(20)); + #[allow(unreachable_code)] + match event_queue.run().expect("ixgbed: failed to handle events") {} + }) + .expect("ixgbed: failed to create daemon"); } diff --git a/rtl8139d/Cargo.toml b/rtl8139d/Cargo.toml index ff88b0e2dd..e296be4330 100644 --- a/rtl8139d/Cargo.toml +++ b/rtl8139d/Cargo.toml @@ -13,4 +13,5 @@ redox-daemon = "0.1" redox-log = "0.1" common = { path = "../common" } +driver-network = { path = "../driver-network" } pcid = { path = "../pcid" } diff --git a/rtl8139d/src/device.rs b/rtl8139d/src/device.rs index f9bbcac38f..fd64fd294f 100644 --- a/rtl8139d/src/device.rs +++ b/rtl8139d/src/device.rs @@ -1,11 +1,9 @@ use std::mem; use std::convert::TryInto; -use std::collections::BTreeMap; -use syscall::error::{Error, EACCES, EBADF, EINVAL, EIO, EMSGSIZE, EWOULDBLOCK, Result}; -use syscall::flag::{EventFlags, O_NONBLOCK}; +use driver_network::NetworkAdapter; +use syscall::error::{Error, EIO, EMSGSIZE, Result}; use syscall::io::{Mmio, Io, ReadOnly}; -use syscall::scheme::SchemeBlockMut; use common::dma::Dma; use netutils::setcfg; @@ -126,38 +124,20 @@ pub struct Rtl8139 { receive_i: usize, transmit_buffer: [Dma<[Mmio; 1792]>; 4], transmit_i: usize, - next_id: usize, - pub handles: BTreeMap } -impl SchemeBlockMut for Rtl8139 { - fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) - } else { - Err(Error::new(EACCES)) - } +impl NetworkAdapter for Rtl8139 { + fn mac_address(&mut self) -> [u8; 6] { + // FIXME read from the network adapter itself + [0xfe; 6] // FE-FE-FE-FE-FE-FE } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if ! buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let flags = { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - *flags - }; - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) + fn available_for_read(&mut self) -> usize { + self.next_read() } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + fn read_packet(&mut self, buf: &mut [u8]) -> Result> { if !self.regs.cr.readf(CR_BUFE) { let rxsts = (self.rx(0) as u16) | @@ -185,16 +165,12 @@ impl SchemeBlockMut for Rtl8139 { self.regs.capr.write(capr); res - } else if flags & O_NONBLOCK == O_NONBLOCK { - Err(Error::new(EWOULDBLOCK)) } else { Ok(None) } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - + fn write_packet(&mut self, buf: &[u8]) -> Result { loop { if self.transmit_i >= 4 { self.transmit_i = 0; @@ -221,39 +197,12 @@ impl SchemeBlockMut for Rtl8139 { self.transmit_i += 1; - return Ok(Some(i)); + return Ok(i); } std::hint::spin_loop(); } } - - fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(EventFlags::empty())) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - let scheme_path = b"network:"; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } - Ok(Some(i)) - } - - fn fsync(&mut self, id: usize) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) - } } impl Rtl8139 { @@ -272,8 +221,6 @@ impl Rtl8139 { .try_into() .unwrap_or_else(|_| unreachable!()), transmit_i: 0, - next_id: 0, - handles: BTreeMap::new(), }; module.init(); diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index 268e1ddf3f..a7b9ca4540 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -1,26 +1,25 @@ #![feature(int_roundings)] -extern crate event; -extern crate netutils; -extern crate syscall; - use std::cell::RefCell; -use std::convert::TryInto; -use std::{env, process}; +use std::convert::{Infallible, TryInto}; use std::fs::File; -use std::io::{ErrorKind, Read, Result, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::io::{Read, Result, Write}; +use std::os::unix::io::AsRawFd; use std::ptr::NonNull; -use std::sync::Arc; +use std::rc::Rc; +use driver_network::NetworkScheme; use event::EventQueue; -use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; -use redox_log::{RedoxLogger, OutputBuilder}; -use syscall::{EventFlags, Packet, SchemeBlockMut}; +use pcid_interface::{ + MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PcidServerHandle, SetFeatureInfo, + SubdriverArguments, +}; +use redox_log::{OutputBuilder, RedoxLogger}; +use syscall::EventFlags; pub mod device; @@ -196,49 +195,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { } } -fn handle_update( - socket: &mut File, - device: &mut device::Rtl8139, - todo: &mut Vec, -) -> Result { - // Handle any blocked packets - let mut i = 0; - while i < todo.len() { - if let Some(a) = device.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet)?; - } else { - i += 1; - } - } - - // Check that the socket is empty - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => return Ok(true), - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } - } - - if let Some(a) = device.handle(&packet) { - packet.a = a; - socket.write(&packet)?; - } else { - todo.push(packet); - } - } - - Ok(false) -} - fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { // RTL8139 uses BAR2, RTL8169 uses BAR1, search in that order for &barnum in &[2, 1] { @@ -275,119 +231,62 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("rtl8139d: failed to map address") as usize }; - let socket_fd = syscall::open( - ":network", - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ) - .expect("rtl8139d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) - })); - //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); - { - let device = Arc::new(RefCell::new(unsafe { - device::Rtl8139::new(address).expect("rtl8139d: failed to allocate device") - })); + let device = + unsafe { device::Rtl8139::new(address).expect("rtl8139d: failed to allocate device") }; - let mut event_queue = - EventQueue::::new().expect("rtl8139d: failed to create event queue"); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); - syscall::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); + let mut event_queue = + EventQueue::::new().expect("rtl8139d: failed to create event queue"); - daemon.ready().expect("rtl8139d: failed to mark daemon as ready"); + syscall::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + daemon + .ready() + .expect("rtl8139d: failed to mark daemon as ready"); - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - //TODO: This may be causing spurious interrupts - if unsafe { device_irq.borrow_mut().irq() } { - irq_file.write(&mut irq)?; + let scheme_irq = scheme.clone(); + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + //TODO: This may be causing spurious interrupts + if unsafe { scheme_irq.borrow_mut().adapter_mut().irq() } { + irq_file.write(&mut irq)?; - if handle_update( - &mut socket_irq.borrow_mut(), - &mut device_irq.borrow_mut(), - &mut todo_irq.borrow_mut(), - )? { - return Ok(Some(0)); - } - - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }, - ) - .expect("rtl8139d: failed to catch events on IRQ file"); - - let device_packet = device.clone(); - let socket_packet = socket.clone(); - event_queue - .add(socket_fd as RawFd, move |_event| -> Result> { - if handle_update( - &mut socket_packet.borrow_mut(), - &mut device_packet.borrow_mut(), - &mut todo.borrow_mut(), - )? { - return Ok(Some(0)); + return scheme_irq.borrow_mut().tick().map(|()| None); } - - let next_read = device_packet.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - Ok(None) - }) - .expect("rtl8139d: failed to catch events on scheme file"); + }, + ) + .expect("rtl8139d: failed to catch events on IRQ file"); - let send_events = |event_count| { - for (handle_id, _handle) in device.borrow().handles.iter() { - socket - .borrow_mut() - .write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: syscall::flag::EVENT_READ.bits(), - d: event_count, - }) - .expect("rtl8139d: failed to write event"); - } - }; + let scheme_packet = scheme.clone(); + event_queue + .add( + scheme.borrow().event_handle(), + move |_event| -> Result> { + scheme_packet.borrow_mut().tick().map(|()| None) + }, + ) + .expect("rtl8139d: failed to catch events on scheme file"); - for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) - .expect("rtl8139d: failed to trigger events") - { - send_events(event_count); - } + event_queue + .trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }) + .expect("rtl8139d: failed to trigger events"); - loop { - let event_count = event_queue.run().expect("rtl8139d: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } - send_events(event_count); - } - } - process::exit(0); + #[allow(unreachable_code)] + match event_queue + .run() + .expect("rtl8139d: failed to handle events") {} } fn main() { diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index d3cd6495f9..c04b5c8478 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -13,4 +13,5 @@ redox-daemon = "0.1" redox-log = "0.1" common = { path = "../common" } +driver-network = { path = "../driver-network" } pcid = { path = "../pcid" } diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index c3663b8b76..eaff7ea829 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -1,14 +1,9 @@ -// Supports Realtek RTL8168, RTL8169, and other compatible devices -// See https://people.freebsd.org/~wpaul/RealTek/rtl8169spec-121.pdf - use std::mem; use std::convert::TryInto; -use std::collections::BTreeMap; -use syscall::error::{Error, EACCES, EBADF, EINVAL, EMSGSIZE, EWOULDBLOCK, Result}; -use syscall::flag::{EventFlags, O_NONBLOCK}; +use driver_network::NetworkAdapter; +use syscall::error::{Error, Result, EMSGSIZE}; use syscall::io::{Mmio, Io, ReadOnly}; -use syscall::scheme::SchemeBlockMut; use common::dma::Dma; use netutils::setcfg; @@ -83,38 +78,20 @@ pub struct Rtl8168 { transmit_i: usize, transmit_buffer_h: [Dma<[Mmio; 7552]>; 1], transmit_ring_h: Dma<[Td; 1]>, - next_id: usize, - pub handles: BTreeMap } -impl SchemeBlockMut for Rtl8168 { - fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) - } else { - Err(Error::new(EACCES)) - } +impl NetworkAdapter for Rtl8168 { + fn mac_address(&mut self) -> [u8; 6] { + // FIXME read from the network adapter itself + [0xfe; 6] // FE-FE-FE-FE-FE-FE } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if ! buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let flags = { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - *flags - }; - self.next_id += 1; - self.handles.insert(self.next_id, flags); - Ok(Some(self.next_id)) + fn available_for_read(&mut self) -> usize { + self.next_read() } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; + fn read_packet(&mut self, buf: &mut [u8]) -> Result> { if self.receive_i >= self.receive_ring.len() { self.receive_i = 0; } @@ -137,16 +114,12 @@ impl SchemeBlockMut for Rtl8168 { self.receive_i += 1; Ok(Some(i)) - } else if flags & O_NONBLOCK == O_NONBLOCK { - Err(Error::new(EWOULDBLOCK)) } else { Ok(None) } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - + fn write_packet(&mut self, buf: &[u8]) -> Result { loop { if self.transmit_i >= self.transmit_ring.len() { self.transmit_i = 0; @@ -177,39 +150,12 @@ impl SchemeBlockMut for Rtl8168 { self.transmit_i += 1; - return Ok(Some(i)); + return Ok(i); } std::hint::spin_loop(); } } - - fn fevent(&mut self, id: usize, _flags: EventFlags) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(EventFlags::empty())) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - let scheme_path = b"network:"; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } - Ok(Some(i)) - } - - fn fsync(&mut self, id: usize) -> Result> { - let _flags = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) - } } impl Rtl8168 { @@ -246,8 +192,6 @@ impl Rtl8168 { transmit_i: 0, transmit_buffer_h: [Dma::zeroed()?.assume_init()], transmit_ring_h: Dma::zeroed()?.assume_init(), - next_id: 0, - handles: BTreeMap::new(), }; module.init(); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 78fe7185fc..1cfaab1c9e 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -1,16 +1,12 @@ -extern crate event; -extern crate netutils; -extern crate syscall; - use std::cell::RefCell; -use std::convert::TryInto; -use std::{env, process}; +use std::convert::{Infallible, TryInto}; use std::fs::File; -use std::io::{ErrorKind, Read, Result, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::io::{Read, Result, Write}; +use std::os::unix::io::AsRawFd; use std::ptr::NonNull; -use std::sync::Arc; +use std::rc::Rc; +use driver_network::NetworkScheme; use event::EventQueue; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; #[cfg(target_arch = "x86_64")] @@ -18,7 +14,7 @@ use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixCapability, MsixTableEntry}; use redox_log::{RedoxLogger, OutputBuilder}; -use syscall::{EventFlags, Packet, SchemeBlockMut}; +use syscall::EventFlags; pub mod device; @@ -194,49 +190,6 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { } } -fn handle_update( - socket: &mut File, - device: &mut device::Rtl8168, - todo: &mut Vec, -) -> Result { - // Handle any blocked packets - let mut i = 0; - while i < todo.len() { - if let Some(a) = device.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet)?; - } else { - i += 1; - } - } - - // Check that the socket is empty - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => return Ok(true), - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } - } - - if let Some(a) = device.handle(&packet) { - packet.a = a; - socket.write(&packet)?; - } else { - todo.push(packet); - } - } - - Ok(false) -} - fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { // RTL8168 uses BAR2, RTL8169 uses BAR1, search in that order for &barnum in &[2, 1] { @@ -273,119 +226,62 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("rtl8168d: failed to map address") as usize }; - let socket_fd = syscall::open( - ":network", - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, - ) - .expect("rtl8168d: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) - })); - //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); - { - let device = Arc::new(RefCell::new(unsafe { - device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") - })); + let device = + unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") }; - let mut event_queue = - EventQueue::::new().expect("rtl8168d: failed to create event queue"); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); - syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); + let mut event_queue = + EventQueue::::new().expect("rtl8168d: failed to create event queue"); - daemon.ready().expect("rtl8168d: failed to mark daemon as ready"); + syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + daemon + .ready() + .expect("rtl8168d: failed to mark daemon as ready"); - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - //TODO: This may be causing spurious interrupts - if unsafe { device_irq.borrow_mut().irq() } { - irq_file.write(&mut irq)?; + let scheme_irq = scheme.clone(); + event_queue + .add( + irq_file.as_raw_fd(), + move |_event| -> Result> { + let mut irq = [0; 8]; + irq_file.read(&mut irq)?; + //TODO: This may be causing spurious interrupts + if unsafe { scheme_irq.borrow_mut().adapter_mut().irq() } { + irq_file.write(&mut irq)?; - if handle_update( - &mut socket_irq.borrow_mut(), - &mut device_irq.borrow_mut(), - &mut todo_irq.borrow_mut(), - )? { - return Ok(Some(0)); - } - - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - } - Ok(None) - }, - ) - .expect("rtl8168d: failed to catch events on IRQ file"); - - let device_packet = device.clone(); - let socket_packet = socket.clone(); - event_queue - .add(socket_fd as RawFd, move |_event| -> Result> { - if handle_update( - &mut socket_packet.borrow_mut(), - &mut device_packet.borrow_mut(), - &mut todo.borrow_mut(), - )? { - return Ok(Some(0)); + return scheme_irq.borrow_mut().tick().map(|()| None); } - - let next_read = device_packet.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - Ok(None) - }) - .expect("rtl8168d: failed to catch events on scheme file"); + }, + ) + .expect("rtl8168d: failed to catch events on IRQ file"); - let send_events = |event_count| { - for (handle_id, _handle) in device.borrow().handles.iter() { - socket - .borrow_mut() - .write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: syscall::flag::EVENT_READ.bits(), - d: event_count, - }) - .expect("rtl8168d: failed to write event"); - } - }; + let scheme_packet = scheme.clone(); + event_queue + .add( + scheme.borrow().event_handle(), + move |_event| -> Result> { + scheme_packet.borrow_mut().tick().map(|()| None) + }, + ) + .expect("rtl8168d: failed to catch events on scheme file"); - for event_count in event_queue - .trigger_all(event::Event { fd: 0, flags: EventFlags::empty() }) - .expect("rtl8168d: failed to trigger events") - { - send_events(event_count); - } + event_queue + .trigger_all(event::Event { + fd: 0, + flags: EventFlags::empty(), + }) + .expect("rtl8168d: failed to trigger events"); - loop { - let event_count = event_queue.run().expect("rtl8168d: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } - send_events(event_count); - } - } - process::exit(0); + #[allow(unreachable_code)] + match event_queue + .run() + .expect("rtl8168d: failed to handle events") {} } fn main() { From de6beb89929ae2b032121c8d3d30f5e41bf0f5e7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 26 Feb 2024 20:48:02 +0100 Subject: [PATCH 0822/1301] Implement network:mac in all remaining network drivers --- ixgbed/src/device.rs | 10 +++++++--- rtl8139d/src/device.rs | 6 ++++-- rtl8168d/src/device.rs | 6 ++++-- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/ixgbed/src/device.rs b/ixgbed/src/device.rs index 3fd47e029b..690dfb1be0 100644 --- a/ixgbed/src/device.rs +++ b/ixgbed/src/device.rs @@ -21,6 +21,7 @@ pub struct Intel8259x { transmit_ring_free: usize, transmit_index: usize, transmit_clean_index: usize, + mac_address: [u8; 6], } fn wrap_ring(index: usize, ring_size: usize) -> usize { @@ -29,8 +30,7 @@ fn wrap_ring(index: usize, ring_size: usize) -> usize { impl NetworkAdapter for Intel8259x { fn mac_address(&mut self) -> [u8; 6] { - // FIXME read from the network adapter itself - [0xfe; 6] // FE-FE-FE-FE-FE-FE + self.mac_address } fn available_for_read(&mut self) -> usize { @@ -145,6 +145,7 @@ impl Intel8259x { transmit_ring_free: 32, transmit_index: 0, transmit_clean_index: 0, + mac_address: [0; 6], }; module.init(); @@ -192,7 +193,7 @@ impl Intel8259x { /// Sets the mac address of this device. #[allow(dead_code)] - pub fn set_mac_addr(&self, mac: [u8; 6]) { + pub fn set_mac_addr(&mut self, mac: [u8; 6]) { let low: u32 = u32::from(mac[0]) + (u32::from(mac[1]) << 8) + (u32::from(mac[2]) << 16) @@ -201,6 +202,8 @@ impl Intel8259x { self.write_reg(IXGBE_RAL(0), low); self.write_reg(IXGBE_RAH(0), high); + + self.mac_address = mac; } /// Returns the register at `self.base` + `register`. @@ -289,6 +292,7 @@ impl Intel8259x { mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ), ); + self.mac_address = mac; // section 4.6.3 - wait for EEPROM auto read completion self.wait_write_reg(IXGBE_EEC, IXGBE_EEC_ARD); diff --git a/rtl8139d/src/device.rs b/rtl8139d/src/device.rs index fd64fd294f..746ecd5646 100644 --- a/rtl8139d/src/device.rs +++ b/rtl8139d/src/device.rs @@ -124,12 +124,12 @@ pub struct Rtl8139 { receive_i: usize, transmit_buffer: [Dma<[Mmio; 1792]>; 4], transmit_i: usize, + mac_address: [u8; 6], } impl NetworkAdapter for Rtl8139 { fn mac_address(&mut self) -> [u8; 6] { - // FIXME read from the network adapter itself - [0xfe; 6] // FE-FE-FE-FE-FE-FE + self.mac_address } fn available_for_read(&mut self) -> usize { @@ -221,6 +221,7 @@ impl Rtl8139 { .try_into() .unwrap_or_else(|_| unreachable!()), transmit_i: 0, + mac_address: [0; 6], }; module.init(); @@ -272,6 +273,7 @@ impl Rtl8139 { (mac_high >> 8) as u8]; println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value println!(" - Reset"); diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index eaff7ea829..5dd76a8504 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -78,12 +78,12 @@ pub struct Rtl8168 { transmit_i: usize, transmit_buffer_h: [Dma<[Mmio; 7552]>; 1], transmit_ring_h: Dma<[Td; 1]>, + mac_address: [u8; 6], } impl NetworkAdapter for Rtl8168 { fn mac_address(&mut self) -> [u8; 6] { - // FIXME read from the network adapter itself - [0xfe; 6] // FE-FE-FE-FE-FE-FE + self.mac_address } fn available_for_read(&mut self) -> usize { @@ -192,6 +192,7 @@ impl Rtl8168 { transmit_i: 0, transmit_buffer_h: [Dma::zeroed()?.assume_init()], transmit_ring_h: Dma::zeroed()?.assume_init(), + mac_address: [0; 6], }; module.init(); @@ -232,6 +233,7 @@ impl Rtl8168 { (mac_high >> 8) as u8]; println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); + self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value println!(" - Reset"); From 9262d034bd2cd7a2f9be51b6fcc595bd92b7ccbf Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 27 Feb 2024 14:07:17 +0100 Subject: [PATCH 0823/1301] Port virtio-netd to driver-network --- Cargo.lock | 1 + driver-network/src/lib.rs | 5 +++ virtio-netd/Cargo.toml | 1 + virtio-netd/src/main.rs | 92 ++++++++++++++++++++----------------- virtio-netd/src/scheme.rs | 95 ++++++++++----------------------------- 5 files changed, 82 insertions(+), 112 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a5accc366e..4e2017a6db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1796,6 +1796,7 @@ name = "virtio-netd" version = "0.1.0" dependencies = [ "common", + "driver-network", "futures", "log", "netutils", diff --git a/driver-network/src/lib.rs b/driver-network/src/lib.rs index 23fcc38135..eec2fc1fcb 100644 --- a/driver-network/src/lib.rs +++ b/driver-network/src/lib.rs @@ -30,6 +30,7 @@ pub trait NetworkAdapter { pub struct NetworkScheme { adapter: T, + _scheme_name: String, scheme: File, next_id: usize, handles: BTreeMap, @@ -44,6 +45,8 @@ enum Handle { impl NetworkScheme { pub fn new(adapter: T, scheme_name: &str) -> Self { + assert_eq!(scheme_name, "network"); // FIXME update fpath before removing this assertion + let scheme_fd = syscall::open( format!(":{scheme_name}"), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, @@ -53,6 +56,7 @@ impl NetworkScheme { NetworkScheme { adapter, + _scheme_name: scheme_name.to_owned(), scheme, next_id: 0, handles: BTreeMap::new(), @@ -215,6 +219,7 @@ impl SchemeBlockMut for NetworkScheme { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; let scheme_path = match handle { + // FIXME use self.scheme_name instead of hardcoding "network" Handle::Data { .. } => &b"network:"[..], Handle::Mac { .. } => &b"network:mac"[..], }; diff --git a/virtio-netd/Cargo.toml b/virtio-netd/Cargo.toml index cf5d40fe74..ae6927fb33 100644 --- a/virtio-netd/Cargo.toml +++ b/virtio-netd/Cargo.toml @@ -11,6 +11,7 @@ futures = { version = "0.3.28", features = ["executor"] } virtio-core = { path = "../virtio-core" } pcid = { path = "../pcid" } common = { path = "../common" } +driver-network = { path = "../driver-network" } redox-daemon = "0.1" redox_syscall = "0.4" diff --git a/virtio-netd/src/main.rs b/virtio-netd/src/main.rs index c3113ed753..ecda97d2cd 100644 --- a/virtio-netd/src/main.rs +++ b/virtio-netd/src/main.rs @@ -2,15 +2,12 @@ mod scheme; use std::fs::File; use std::io::{Read, Write}; -use std::os::fd::{FromRawFd, RawFd}; +use std::mem; +use driver_network::NetworkScheme; use pcid_interface::PcidServerHandle; -use syscall::{Packet, SchemeBlockMut}; - -use virtio_core::transport::{Error, Transport}; - -use scheme::NetworkScheme; +use scheme::VirtioNet; pub const VIRTIO_NET_F_MAC: u32 = 5; @@ -30,7 +27,7 @@ static_assertions::const_assert_eq!(core::mem::size_of::(), 12); const MAX_BUFFER_LEN: usize = 65535; -fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { +fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box> { let mut pcid_handle = PcidServerHandle::connect_default()?; // Double check that we have the right device. @@ -45,20 +42,30 @@ fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { let device_space = device.device_space; // Negotiate device features: - let mac_addr = if device.transport.check_device_feature(VIRTIO_NET_F_MAC) { - let mac = (0..6) - .map(|i| unsafe { core::ptr::read_volatile(device_space.add(i)) }) - .collect::>(); + let mac_address = if device.transport.check_device_feature(VIRTIO_NET_F_MAC) { + let mac = unsafe { + [ + core::ptr::read_volatile(device_space.add(0)), + core::ptr::read_volatile(device_space.add(1)), + core::ptr::read_volatile(device_space.add(2)), + core::ptr::read_volatile(device_space.add(3)), + core::ptr::read_volatile(device_space.add(4)), + core::ptr::read_volatile(device_space.add(5)), + ] + }; - let mac_str = format!( - "{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + log::info!( + "virtio-net: device MAC is {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + mac[0], + mac[1], + mac[2], + mac[3], + mac[4], + mac[5] ); - log::info!("virtio-net: device MAC is {mac_str}"); - device.transport.ack_driver_feature(VIRTIO_NET_F_MAC); - mac_str + mac } else { unimplemented!() }; @@ -85,35 +92,38 @@ fn deamon(deamon: redox_daemon::Daemon) -> Result<(), Error> { let mut name = pci_config.func.name(); name.push_str("_virtio_net"); - // Create the network scheme. - // - // FIXME(andypython): It should be fine to have multiple network devices. - let socket_fd = syscall::open( - &format!(":network"), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, - ) - .map_err(Error::SyscallError)?; + let device = VirtioNet::new(mac_address, rx_queue, tx_queue); + let mut scheme = NetworkScheme::new(device, "network"); - let mut socket_fd = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - let mut scheme = NetworkScheme::new(rx_queue, tx_queue); + let _ = netutils::setcfg( + "mac", + &format!( + "{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + mac_address[0], + mac_address[1], + mac_address[2], + mac_address[3], + mac_address[4], + mac_address[5] + ), + ); - let _ = netutils::setcfg("mac", &mac_addr); + let mut event_queue = File::open("event:")?; + event_queue.write(&syscall::Event { + id: scheme.event_handle() as usize, + flags: syscall::EVENT_READ, + data: 0, + })?; - deamon.ready().expect("virtio-netd: failed to deamonize"); + syscall::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); + + daemon.ready().expect("virtio-netd: failed to daemonize"); + + scheme.tick()?; loop { - let mut packet = Packet::default(); - socket_fd - .read(&mut packet) - .expect("virtio-netd: failed to read packet"); - - let result = scheme.handle(&mut packet); - // `packet.a` contains the return value. - packet.a = result.expect("virtio-netd: failed to handle packet"); - - socket_fd - .write(&packet) - .expect("virtio-netd: failed to write packet"); + event_queue.read(&mut [0; mem::size_of::()])?; // Wait for event + scheme.tick()?; } } diff --git a/virtio-netd/src/scheme.rs b/virtio-netd/src/scheme.rs index 5a48cba19f..59b3b93e20 100644 --- a/virtio-netd/src/scheme.rs +++ b/virtio-netd/src/scheme.rs @@ -1,9 +1,6 @@ -use std::collections::BTreeMap; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -use syscall::Error as SysError; -use syscall::*; +use driver_network::NetworkAdapter; use common::dma::Dma; @@ -12,26 +9,29 @@ use virtio_core::transport::Queue; use crate::{VirtHeader, MAX_BUFFER_LEN}; -pub struct NetworkScheme<'a> { +pub struct VirtioNet<'a> { + mac_address: [u8; 6], + /// Reciever Queue. rx: Arc>, rx_buffers: Vec>, /// Transmiter Queue. tx: Arc>, - /// File descriptor handles. - handles: BTreeMap, - next_id: AtomicUsize, recv_head: u16, } -impl<'a> NetworkScheme<'a> { - pub fn new(rx: Arc>, tx: Arc>) -> Self { +impl<'a> VirtioNet<'a> { + pub fn new(mac_address: [u8; 6], rx: Arc>, tx: Arc>) -> Self { // Populate all of the `rx_queue` with buffers to maximize performence. let mut rx_buffers = vec![]; for i in 0..(rx.descriptor_len() as usize) { - rx_buffers.push(unsafe { Dma::<[u8]>::zeroed_slice(MAX_BUFFER_LEN).unwrap().assume_init() }); + rx_buffers.push(unsafe { + Dma::<[u8]>::zeroed_slice(MAX_BUFFER_LEN) + .unwrap() + .assume_init() + }); let chain = ChainBuilder::new() .chain(Buffer::new_unsized(&rx_buffers[i]).flags(DescriptorFlags::WRITE_ONLY)) @@ -41,13 +41,12 @@ impl<'a> NetworkScheme<'a> { } Self { + mac_address, + rx, rx_buffers, tx, - handles: BTreeMap::new(), - next_id: AtomicUsize::new(0), - recv_head: 0, } } @@ -82,45 +81,27 @@ impl<'a> NetworkScheme<'a> { } } -impl<'a> SchemeBlockMut for NetworkScheme<'a> { - fn open( - &mut self, - _path: &str, - flags: usize, - uid: u32, - _gid: u32, - ) -> syscall::Result> { - if uid != 0 { - return Err(SysError::new(EACCES)); - } - - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.insert(id, flags); - - Ok(Some(id)) +impl<'a> NetworkAdapter for VirtioNet<'a> { + fn mac_address(&mut self) -> [u8; 6] { + self.mac_address } - fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result> { - let flags = *self.handles.get(&id).ok_or(SysError::new(EBADF))?; + fn available_for_read(&mut self) -> usize { + (self.rx.used.head_index() - self.recv_head).into() + } + + fn read_packet(&mut self, buf: &mut [u8]) -> syscall::Result> { let bytes = self.try_recv(buf); if bytes != 0 { // We read some bytes. Ok(Some(bytes)) - } else if flags & O_NONBLOCK == O_NONBLOCK { - // We are in non-blocking mode. - Err(SysError::new(EWOULDBLOCK)) } else { - // Block - unimplemented!() + Ok(None) } } - fn write(&mut self, id: usize, buffer: &[u8]) -> syscall::Result> { - if self.handles.get(&id).is_none() { - return Err(SysError::new(EBADF)); - } - + fn write_packet(&mut self, buffer: &[u8]) -> syscall::Result { let header = unsafe { Dma::::zeroed()?.assume_init() }; let mut payload = unsafe { Dma::<[u8]>::zeroed_slice(buffer.len())?.assume_init() }; @@ -132,34 +113,6 @@ impl<'a> SchemeBlockMut for NetworkScheme<'a> { .build(); futures::executor::block_on(self.tx.send(chain)); - Ok(Some(buffer.len())) - } - - fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> syscall::Result> { - unimplemented!() - } - - fn fevent( - &mut self, - id: usize, - _flags: syscall::EventFlags, - ) -> syscall::Result> { - if self.handles.get(&id).is_none() { - return Err(SysError::new(EBADF)); - } - - Ok(Some(syscall::EventFlags::empty())) - } - - fn fpath(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result> { - unimplemented!() - } - - fn fsync(&mut self, _id: usize) -> syscall::Result> { - unimplemented!() - } - - fn close(&mut self, _id: usize) -> syscall::Result> { - unimplemented!() + Ok(buffer.len()) } } From d33d7a91e5eec660bc6bf8f9dc688237ab57126b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 28 Feb 2024 09:36:42 +0100 Subject: [PATCH 0824/1301] Don't set the mac address network config from drivers The mac handle of the network scheme is now supported by all network drivers. --- Cargo.lock | 168 ++-------------------------------------- Cargo.toml | 1 - alxd/Cargo.toml | 1 - alxd/src/device/mod.rs | 2 - alxd/src/main.rs | 1 - e1000d/Cargo.toml | 1 - e1000d/src/device.rs | 8 -- ixgbed/Cargo.toml | 1 - ixgbed/src/device.rs | 8 -- rtl8139d/Cargo.toml | 1 - rtl8139d/src/device.rs | 2 - rtl8168d/Cargo.toml | 1 - rtl8168d/src/device.rs | 2 - virtio-netd/Cargo.toml | 1 - virtio-netd/src/main.rs | 13 ---- 15 files changed, 6 insertions(+), 205 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4e2017a6db..da45912c2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,7 +43,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "block-io-wrapper", - "byteorder 1.4.3", + "byteorder", "common", "log", "partitionlib", @@ -59,7 +59,6 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", - "netutils", "redox-daemon", "redox_event 0.1.0", "redox_syscall 0.4.1", @@ -72,7 +71,7 @@ source = "git+https://github.com/rw-vanc/acpi.git?branch=cumulative#e4eb93891367 dependencies = [ "bit_field", "bitvec", - "byteorder 1.4.3", + "byteorder", "log", "spinning_top", ] @@ -117,11 +116,6 @@ version = "1.0.75" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" -[[package]] -name = "arg_parser" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/arg-parser.git#1c434b55f3e1a0375ebcca85b3e88db7378e82fa" - [[package]] name = "arrayvec" version = "0.5.2" @@ -222,12 +216,6 @@ version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" -[[package]] -name = "byteorder" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" - [[package]] name = "byteorder" version = "1.4.3" @@ -332,16 +320,6 @@ dependencies = [ "maybe-uninit", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils 0.8.16", -] - [[package]] name = "crossbeam-queue" version = "0.3.8" @@ -387,7 +365,6 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", - "netutils", "pcid", "redox-daemon", "redox_event 0.1.0", @@ -527,7 +504,7 @@ checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -603,17 +580,6 @@ dependencies = [ "redox_syscall 0.4.1", ] -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "ihdad" version = "0.1.0" @@ -674,7 +640,6 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", - "netutils", "pcid", "redox-daemon", "redox_event 0.1.0", @@ -749,12 +714,6 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "maybe-uninit" version = "2.0.0" @@ -767,43 +726,6 @@ version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" -[[package]] -name = "net2" -version = "0.2.37" -source = "git+https://gitlab.redox-os.org/redox-os/net2-rs.git?branch=master#db0604dcb0a355e6b2fa5bcaad8f175bd6aeb5aa" -dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi", -] - -[[package]] -name = "netutils" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/netutils.git#d1998d5aa2809b7f0c433f2df3125eecfbfa5c86" -dependencies = [ - "arg_parser", - "libc", - "net2", - "ntpclient", - "pbr", - "redox-daemon", - "redox_event 0.1.0", - "redox_syscall 0.3.5", - "redox_termios", - "termion", - "url", -] - -[[package]] -name = "ntpclient" -version = "0.0.1" -source = "git+https://github.com/willem66745/ntpclient-rust#7e3bdf60eb940825789a8da5181025320e3050b0" -dependencies = [ - "byteorder 0.5.3", - "time", -] - [[package]] name = "num-derive" version = "0.3.3" @@ -838,7 +760,7 @@ dependencies = [ "bitflags 1.3.2", "block-io-wrapper", "common", - "crossbeam-channel 0.4.4", + "crossbeam-channel", "futures", "log", "partitionlib", @@ -965,17 +887,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" -[[package]] -name = "pbr" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5827dfa0d69b6c92493d6c38e633bbaa5937c153d0d7c28bf12313f8c6d514" -dependencies = [ - "crossbeam-channel 0.5.8", - "libc", - "winapi", -] - [[package]] name = "pci_types" version = "0.6.1" @@ -993,7 +904,7 @@ dependencies = [ "bincode", "bit_field", "bitflags 1.3.2", - "byteorder 1.4.3", + "byteorder", "common", "libc", "log", @@ -1017,12 +928,6 @@ dependencies = [ "redox_syscall 0.4.1", ] -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "pin-project-lite" version = "0.2.13" @@ -1230,7 +1135,6 @@ dependencies = [ "common", "driver-network", "log", - "netutils", "pcid", "redox-daemon", "redox-log", @@ -1246,7 +1150,6 @@ dependencies = [ "common", "driver-network", "log", - "netutils", "pcid", "redox-daemon", "redox-log", @@ -1526,32 +1429,6 @@ dependencies = [ "syn 2.0.31", ] -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "toml" version = "0.5.11" @@ -1595,27 +1472,12 @@ dependencies = [ "winnow", ] -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - [[package]] name = "unicode-ident" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-segmentation" version = "1.10.1" @@ -1628,17 +1490,6 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna", - "matches", - "percent-encoding", -] - [[package]] name = "usbctl" version = "0.1.0" @@ -1799,7 +1650,6 @@ dependencies = [ "driver-network", "futures", "log", - "netutils", "pcid", "redox-daemon", "redox_syscall 0.4.1", @@ -1816,12 +1666,6 @@ dependencies = [ "utf8parse", ] -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -1995,7 +1839,7 @@ dependencies = [ "bitflags 1.3.2", "chashmap", "common", - "crossbeam-channel 0.4.4", + "crossbeam-channel", "futures", "lazy_static", "log", diff --git a/Cargo.toml b/Cargo.toml index 275cb4b681..2d7456de34 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,5 @@ lto = "fat" [patch.crates-io] mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } -net2 = { git = "https://gitlab.redox-os.org/redox-os/net2-rs.git", branch = "master" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } redox-daemon = { git = "https://gitlab.redox-os.org/redox-os/redox-daemon.git" } diff --git a/alxd/Cargo.toml b/alxd/Cargo.toml index 8830c189f8..3b509dbf64 100644 --- a/alxd/Cargo.toml +++ b/alxd/Cargo.toml @@ -5,7 +5,6 @@ edition = "2018" [dependencies] bitflags = "1" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" redox-daemon = "0.1" diff --git a/alxd/src/device/mod.rs b/alxd/src/device/mod.rs index e3d8ff4996..3a20c9fc81 100644 --- a/alxd/src/device/mod.rs +++ b/alxd/src/device/mod.rs @@ -7,7 +7,6 @@ use syscall::io::{Io, Mmio}; use syscall::scheme; use common::dma::Dma; -use netutils::setcfg; use self::regs::*; @@ -1706,7 +1705,6 @@ impl Alx { let mac = self.get_perm_macaddr(); println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); if ! self.get_phy_info() { println!(" - Identify PHY failed"); diff --git a/alxd/src/main.rs b/alxd/src/main.rs index 9bd0d6edb3..ef1f745681 100644 --- a/alxd/src/main.rs +++ b/alxd/src/main.rs @@ -4,7 +4,6 @@ #![feature(concat_idents)] extern crate event; -extern crate netutils; extern crate syscall; use std::cell::RefCell; diff --git a/e1000d/Cargo.toml b/e1000d/Cargo.toml index 8a958db6ca..023d95b5d4 100644 --- a/e1000d/Cargo.toml +++ b/e1000d/Cargo.toml @@ -5,7 +5,6 @@ edition = "2018" [dependencies] bitflags = "1" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" diff --git a/e1000d/src/device.rs b/e1000d/src/device.rs index d6e89495f8..7da6965d13 100644 --- a/e1000d/src/device.rs +++ b/e1000d/src/device.rs @@ -2,7 +2,6 @@ use std::convert::TryInto; use std::{cmp, mem, ptr, slice}; use driver_network::NetworkAdapter; -use netutils::setcfg; use syscall::error::Result; @@ -296,13 +295,6 @@ impl Intel8254x { ) ); self.mac_address = mac; - let _ = setcfg( - "mac", - &format!( - "{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] - ), - ); // // MTA => 0; diff --git a/ixgbed/Cargo.toml b/ixgbed/Cargo.toml index 780fc29e08..c9399ace7d 100644 --- a/ixgbed/Cargo.toml +++ b/ixgbed/Cargo.toml @@ -5,7 +5,6 @@ edition = "2021" [dependencies] bitflags = "1.0" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" redox-daemon = "0.1" diff --git a/ixgbed/src/device.rs b/ixgbed/src/device.rs index 690dfb1be0..b36309e14f 100644 --- a/ixgbed/src/device.rs +++ b/ixgbed/src/device.rs @@ -6,7 +6,6 @@ use driver_network::NetworkAdapter; use syscall::error::Result; use common::dma::Dma; -use netutils::setcfg; use crate::ixgbe::*; @@ -285,13 +284,6 @@ impl Intel8259x { mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); - let _ = setcfg( - "mac", - &format!( - "{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] - ), - ); self.mac_address = mac; // section 4.6.3 - wait for EEPROM auto read completion diff --git a/rtl8139d/Cargo.toml b/rtl8139d/Cargo.toml index e296be4330..b03dcea6ef 100644 --- a/rtl8139d/Cargo.toml +++ b/rtl8139d/Cargo.toml @@ -6,7 +6,6 @@ edition = "2018" [dependencies] bitflags = "1" log = "0.4" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" redox-daemon = "0.1" diff --git a/rtl8139d/src/device.rs b/rtl8139d/src/device.rs index 746ecd5646..4b6ce854f0 100644 --- a/rtl8139d/src/device.rs +++ b/rtl8139d/src/device.rs @@ -6,7 +6,6 @@ use syscall::error::{Error, EIO, EMSGSIZE, Result}; use syscall::io::{Mmio, Io, ReadOnly}; use common::dma::Dma; -use netutils::setcfg; const RX_BUFFER_SIZE: usize = 64 * 1024; @@ -272,7 +271,6 @@ impl Rtl8139 { mac_high as u8, (mac_high >> 8) as u8]; println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value diff --git a/rtl8168d/Cargo.toml b/rtl8168d/Cargo.toml index c04b5c8478..ca59181391 100644 --- a/rtl8168d/Cargo.toml +++ b/rtl8168d/Cargo.toml @@ -6,7 +6,6 @@ edition = "2018" [dependencies] bitflags = "1" log = "0.4" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" redox-daemon = "0.1" diff --git a/rtl8168d/src/device.rs b/rtl8168d/src/device.rs index 5dd76a8504..25b6aea64a 100644 --- a/rtl8168d/src/device.rs +++ b/rtl8168d/src/device.rs @@ -6,7 +6,6 @@ use syscall::error::{Error, Result, EMSGSIZE}; use syscall::io::{Mmio, Io, ReadOnly}; use common::dma::Dma; -use netutils::setcfg; #[repr(packed)] struct Regs { @@ -232,7 +231,6 @@ impl Rtl8168 { mac_high as u8, (mac_high >> 8) as u8]; println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - let _ = setcfg("mac", &format!("{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}-{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5])); self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value diff --git a/virtio-netd/Cargo.toml b/virtio-netd/Cargo.toml index ae6927fb33..dc622bae92 100644 --- a/virtio-netd/Cargo.toml +++ b/virtio-netd/Cargo.toml @@ -15,4 +15,3 @@ driver-network = { path = "../driver-network" } redox-daemon = "0.1" redox_syscall = "0.4" -netutils = { git = "https://gitlab.redox-os.org/redox-os/netutils.git" } diff --git a/virtio-netd/src/main.rs b/virtio-netd/src/main.rs index ecda97d2cd..8357e3bfed 100644 --- a/virtio-netd/src/main.rs +++ b/virtio-netd/src/main.rs @@ -95,19 +95,6 @@ fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box let device = VirtioNet::new(mac_address, rx_queue, tx_queue); let mut scheme = NetworkScheme::new(device, "network"); - let _ = netutils::setcfg( - "mac", - &format!( - "{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac_address[0], - mac_address[1], - mac_address[2], - mac_address[3], - mac_address[4], - mac_address[5] - ), - ); - let mut event_queue = File::open("event:")?; event_queue.write(&syscall::Event { id: scheme.event_handle() as usize, From c4bc69a4d0c15bf49ac4baf3046905cf90f32826 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 28 Feb 2024 11:49:48 +0100 Subject: [PATCH 0825/1301] Give each network adapter a unique scheme name This will be necessary in the future to support multiple network adapters in a single system. --- driver-network/src/lib.rs | 41 ++++++++++++++++++++++++++------------- e1000d/src/main.rs | 2 +- ixgbed/src/main.rs | 2 +- rtl8139d/src/main.rs | 2 +- rtl8168d/src/main.rs | 2 +- virtio-netd/src/main.rs | 2 +- 6 files changed, 33 insertions(+), 18 deletions(-) diff --git a/driver-network/src/lib.rs b/driver-network/src/lib.rs index eec2fc1fcb..6c10a352d0 100644 --- a/driver-network/src/lib.rs +++ b/driver-network/src/lib.rs @@ -30,7 +30,7 @@ pub trait NetworkAdapter { pub struct NetworkScheme { adapter: T, - _scheme_name: String, + scheme_name: String, scheme: File, next_id: usize, handles: BTreeMap, @@ -44,9 +44,8 @@ enum Handle { } impl NetworkScheme { - pub fn new(adapter: T, scheme_name: &str) -> Self { - assert_eq!(scheme_name, "network"); // FIXME update fpath before removing this assertion - + pub fn new(adapter: T, scheme_name: String) -> Self { + assert!(scheme_name.starts_with("network")); let scheme_fd = syscall::open( format!(":{scheme_name}"), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, @@ -56,7 +55,7 @@ impl NetworkScheme { NetworkScheme { adapter, - _scheme_name: scheme_name.to_owned(), + scheme_name, scheme, next_id: 0, handles: BTreeMap::new(), @@ -218,17 +217,33 @@ impl SchemeBlockMut for NetworkScheme { fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - let scheme_path = match handle { - // FIXME use self.scheme_name instead of hardcoding "network" - Handle::Data { .. } => &b"network:"[..], - Handle::Mac { .. } => &b"network:mac"[..], - }; - let mut i = 0; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; + + let scheme_name = self.scheme_name.as_bytes(); + let mut j = 0; + while i < buf.len() && j < scheme_name.len() { + buf[i] = scheme_name[j]; + i += 1; + j += 1; + } + + if i < buf.len() { + buf[i] = b':'; i += 1; } + + let path = match handle { + Handle::Data { .. } => &b""[..], + Handle::Mac { .. } => &b"mac"[..], + }; + + j = 0; + while i < buf.len() && j < path.len() { + buf[i] = path[j]; + i += 1; + j += 1; + } + Ok(Some(i)) } diff --git a/e1000d/src/main.rs b/e1000d/src/main.rs index 2f141219ff..b8052b93f3 100644 --- a/e1000d/src/main.rs +++ b/e1000d/src/main.rs @@ -38,7 +38,7 @@ fn main() { let device = unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }; - let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, format!("network.{name}")))); let mut event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); diff --git a/ixgbed/src/main.rs b/ixgbed/src/main.rs index 1f09e76b2d..33c67083bd 100644 --- a/ixgbed/src/main.rs +++ b/ixgbed/src/main.rs @@ -50,7 +50,7 @@ fn main() { let device = device::Intel8259x::new(address, IXGBE_MMIO_SIZE) .expect("ixgbed: failed to allocate device"); - let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, format!("network.{name}")))); let mut event_queue = EventQueue::::new().expect("ixgbed: failed to create event queue"); diff --git a/rtl8139d/src/main.rs b/rtl8139d/src/main.rs index a7b9ca4540..048daf6d95 100644 --- a/rtl8139d/src/main.rs +++ b/rtl8139d/src/main.rs @@ -237,7 +237,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let device = unsafe { device::Rtl8139::new(address).expect("rtl8139d: failed to allocate device") }; - let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, format!("network.{name}")))); let mut event_queue = EventQueue::::new().expect("rtl8139d: failed to create event queue"); diff --git a/rtl8168d/src/main.rs b/rtl8168d/src/main.rs index 1cfaab1c9e..3767f2ddad 100644 --- a/rtl8168d/src/main.rs +++ b/rtl8168d/src/main.rs @@ -232,7 +232,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let device = unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") }; - let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, "network"))); + let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, format!("network.{name}")))); let mut event_queue = EventQueue::::new().expect("rtl8168d: failed to create event queue"); diff --git a/virtio-netd/src/main.rs b/virtio-netd/src/main.rs index 8357e3bfed..f00437a763 100644 --- a/virtio-netd/src/main.rs +++ b/virtio-netd/src/main.rs @@ -93,7 +93,7 @@ fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box name.push_str("_virtio_net"); let device = VirtioNet::new(mac_address, rx_queue, tx_queue); - let mut scheme = NetworkScheme::new(device, "network"); + let mut scheme = NetworkScheme::new(device, format!("network.{name}")); let mut event_queue = File::open("event:")?; event_queue.write(&syscall::Event { From e36b0a8e944b08aae1d25b56407a4376137e74dd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 28 Feb 2024 20:53:16 +0100 Subject: [PATCH 0826/1301] Move all network drivers to net/ --- Cargo.toml | 15 ++++++++------- {alxd => net/alxd}/Cargo.toml | 2 +- {alxd => net/alxd}/src/device/mod.rs | 0 {alxd => net/alxd}/src/device/regs.rs | 0 {alxd => net/alxd}/src/main.rs | 0 {driver-network => net/driver-network}/Cargo.toml | 0 {driver-network => net/driver-network}/src/lib.rs | 0 {e1000d => net/e1000d}/Cargo.toml | 4 ++-- {e1000d => net/e1000d}/config.toml | 0 {e1000d => net/e1000d}/src/device.rs | 0 {e1000d => net/e1000d}/src/main.rs | 0 {ixgbed => net/ixgbed}/Cargo.toml | 4 ++-- {ixgbed => net/ixgbed}/LICENSE | 0 {ixgbed => net/ixgbed}/README.md | 0 {ixgbed => net/ixgbed}/config.toml | 0 {ixgbed => net/ixgbed}/src/device.rs | 0 {ixgbed => net/ixgbed}/src/ixgbe.rs | 0 {ixgbed => net/ixgbed}/src/main.rs | 0 {rtl8139d => net/rtl8139d}/Cargo.toml | 4 ++-- {rtl8139d => net/rtl8139d}/config.toml | 0 {rtl8139d => net/rtl8139d}/src/device.rs | 0 {rtl8139d => net/rtl8139d}/src/main.rs | 0 {rtl8168d => net/rtl8168d}/Cargo.toml | 4 ++-- {rtl8168d => net/rtl8168d}/config.toml | 0 {rtl8168d => net/rtl8168d}/src/device.rs | 0 {rtl8168d => net/rtl8168d}/src/main.rs | 0 {virtio-netd => net/virtio-netd}/Cargo.toml | 6 +++--- {virtio-netd => net/virtio-netd}/config.toml | 0 {virtio-netd => net/virtio-netd}/src/main.rs | 0 {virtio-netd => net/virtio-netd}/src/scheme.rs | 0 30 files changed, 20 insertions(+), 19 deletions(-) rename {alxd => net/alxd}/Cargo.toml (85%) rename {alxd => net/alxd}/src/device/mod.rs (100%) rename {alxd => net/alxd}/src/device/regs.rs (100%) rename {alxd => net/alxd}/src/main.rs (100%) rename {driver-network => net/driver-network}/Cargo.toml (100%) rename {driver-network => net/driver-network}/src/lib.rs (100%) rename {e1000d => net/e1000d}/Cargo.toml (79%) rename {e1000d => net/e1000d}/config.toml (100%) rename {e1000d => net/e1000d}/src/device.rs (100%) rename {e1000d => net/e1000d}/src/main.rs (100%) rename {ixgbed => net/ixgbed}/Cargo.toml (79%) rename {ixgbed => net/ixgbed}/LICENSE (100%) rename {ixgbed => net/ixgbed}/README.md (100%) rename {ixgbed => net/ixgbed}/config.toml (100%) rename {ixgbed => net/ixgbed}/src/device.rs (100%) rename {ixgbed => net/ixgbed}/src/ixgbe.rs (100%) rename {ixgbed => net/ixgbed}/src/main.rs (100%) rename {rtl8139d => net/rtl8139d}/Cargo.toml (81%) rename {rtl8139d => net/rtl8139d}/config.toml (100%) rename {rtl8139d => net/rtl8139d}/src/device.rs (100%) rename {rtl8139d => net/rtl8139d}/src/main.rs (100%) rename {rtl8168d => net/rtl8168d}/Cargo.toml (81%) rename {rtl8168d => net/rtl8168d}/config.toml (100%) rename {rtl8168d => net/rtl8168d}/src/device.rs (100%) rename {rtl8168d => net/rtl8168d}/src/main.rs (100%) rename {virtio-netd => net/virtio-netd}/Cargo.toml (71%) rename {virtio-netd => net/virtio-netd}/config.toml (100%) rename {virtio-netd => net/virtio-netd}/src/main.rs (100%) rename {virtio-netd => net/virtio-netd}/src/scheme.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 2d7456de34..8982e528b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,23 +3,17 @@ members = [ "ac97d", "acpid", "ahcid", - "alxd", "bgad", "block-io-wrapper", "common", - "driver-network", - "e1000d", "fbcond", "ided", "ihdad", - "ixgbed", "nvmed", "lived", # TODO: not really a driver... "pcid", "pcspkrd", "ps2d", - "rtl8139d", - "rtl8168d", "sb16d", "vboxd", "vesad", @@ -30,10 +24,17 @@ members = [ "inputd", "virtio-blkd", - "virtio-netd", "virtio-gpud", "virtio-core", + "net/alxd", + "net/driver-network", + "net/e1000d", + "net/ixgbed", + "net/rtl8139d", + "net/rtl8168d", + "net/virtio-netd", + "bcm2835-sdhcid", ] diff --git a/alxd/Cargo.toml b/net/alxd/Cargo.toml similarity index 85% rename from alxd/Cargo.toml rename to net/alxd/Cargo.toml index 3b509dbf64..4a3ed09f03 100644 --- a/alxd/Cargo.toml +++ b/net/alxd/Cargo.toml @@ -9,4 +9,4 @@ redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" redox-daemon = "0.1" -common = { path = "../common" } +common = { path = "../../common" } diff --git a/alxd/src/device/mod.rs b/net/alxd/src/device/mod.rs similarity index 100% rename from alxd/src/device/mod.rs rename to net/alxd/src/device/mod.rs diff --git a/alxd/src/device/regs.rs b/net/alxd/src/device/regs.rs similarity index 100% rename from alxd/src/device/regs.rs rename to net/alxd/src/device/regs.rs diff --git a/alxd/src/main.rs b/net/alxd/src/main.rs similarity index 100% rename from alxd/src/main.rs rename to net/alxd/src/main.rs diff --git a/driver-network/Cargo.toml b/net/driver-network/Cargo.toml similarity index 100% rename from driver-network/Cargo.toml rename to net/driver-network/Cargo.toml diff --git a/driver-network/src/lib.rs b/net/driver-network/src/lib.rs similarity index 100% rename from driver-network/src/lib.rs rename to net/driver-network/src/lib.rs diff --git a/e1000d/Cargo.toml b/net/e1000d/Cargo.toml similarity index 79% rename from e1000d/Cargo.toml rename to net/e1000d/Cargo.toml index 023d95b5d4..395a6341cc 100644 --- a/e1000d/Cargo.toml +++ b/net/e1000d/Cargo.toml @@ -9,6 +9,6 @@ redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" -common = { path = "../common" } +common = { path = "../../common" } driver-network = { path = "../driver-network" } -pcid = { path = "../pcid" } +pcid = { path = "../../pcid" } diff --git a/e1000d/config.toml b/net/e1000d/config.toml similarity index 100% rename from e1000d/config.toml rename to net/e1000d/config.toml diff --git a/e1000d/src/device.rs b/net/e1000d/src/device.rs similarity index 100% rename from e1000d/src/device.rs rename to net/e1000d/src/device.rs diff --git a/e1000d/src/main.rs b/net/e1000d/src/main.rs similarity index 100% rename from e1000d/src/main.rs rename to net/e1000d/src/main.rs diff --git a/ixgbed/Cargo.toml b/net/ixgbed/Cargo.toml similarity index 79% rename from ixgbed/Cargo.toml rename to net/ixgbed/Cargo.toml index c9399ace7d..fd3258fa00 100644 --- a/ixgbed/Cargo.toml +++ b/net/ixgbed/Cargo.toml @@ -9,6 +9,6 @@ redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" redox-daemon = "0.1" -common = { path = "../common" } +common = { path = "../../common" } driver-network = { path = "../driver-network" } -pcid = { path = "../pcid" } +pcid = { path = "../../pcid" } diff --git a/ixgbed/LICENSE b/net/ixgbed/LICENSE similarity index 100% rename from ixgbed/LICENSE rename to net/ixgbed/LICENSE diff --git a/ixgbed/README.md b/net/ixgbed/README.md similarity index 100% rename from ixgbed/README.md rename to net/ixgbed/README.md diff --git a/ixgbed/config.toml b/net/ixgbed/config.toml similarity index 100% rename from ixgbed/config.toml rename to net/ixgbed/config.toml diff --git a/ixgbed/src/device.rs b/net/ixgbed/src/device.rs similarity index 100% rename from ixgbed/src/device.rs rename to net/ixgbed/src/device.rs diff --git a/ixgbed/src/ixgbe.rs b/net/ixgbed/src/ixgbe.rs similarity index 100% rename from ixgbed/src/ixgbe.rs rename to net/ixgbed/src/ixgbe.rs diff --git a/ixgbed/src/main.rs b/net/ixgbed/src/main.rs similarity index 100% rename from ixgbed/src/main.rs rename to net/ixgbed/src/main.rs diff --git a/rtl8139d/Cargo.toml b/net/rtl8139d/Cargo.toml similarity index 81% rename from rtl8139d/Cargo.toml rename to net/rtl8139d/Cargo.toml index b03dcea6ef..2ff86321ab 100644 --- a/rtl8139d/Cargo.toml +++ b/net/rtl8139d/Cargo.toml @@ -11,6 +11,6 @@ redox_syscall = "0.4" redox-daemon = "0.1" redox-log = "0.1" -common = { path = "../common" } +common = { path = "../../common" } driver-network = { path = "../driver-network" } -pcid = { path = "../pcid" } +pcid = { path = "../../pcid" } diff --git a/rtl8139d/config.toml b/net/rtl8139d/config.toml similarity index 100% rename from rtl8139d/config.toml rename to net/rtl8139d/config.toml diff --git a/rtl8139d/src/device.rs b/net/rtl8139d/src/device.rs similarity index 100% rename from rtl8139d/src/device.rs rename to net/rtl8139d/src/device.rs diff --git a/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs similarity index 100% rename from rtl8139d/src/main.rs rename to net/rtl8139d/src/main.rs diff --git a/rtl8168d/Cargo.toml b/net/rtl8168d/Cargo.toml similarity index 81% rename from rtl8168d/Cargo.toml rename to net/rtl8168d/Cargo.toml index ca59181391..3ec1bdfbcf 100644 --- a/rtl8168d/Cargo.toml +++ b/net/rtl8168d/Cargo.toml @@ -11,6 +11,6 @@ redox_syscall = "0.4" redox-daemon = "0.1" redox-log = "0.1" -common = { path = "../common" } +common = { path = "../../common" } driver-network = { path = "../driver-network" } -pcid = { path = "../pcid" } +pcid = { path = "../../pcid" } diff --git a/rtl8168d/config.toml b/net/rtl8168d/config.toml similarity index 100% rename from rtl8168d/config.toml rename to net/rtl8168d/config.toml diff --git a/rtl8168d/src/device.rs b/net/rtl8168d/src/device.rs similarity index 100% rename from rtl8168d/src/device.rs rename to net/rtl8168d/src/device.rs diff --git a/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs similarity index 100% rename from rtl8168d/src/main.rs rename to net/rtl8168d/src/main.rs diff --git a/virtio-netd/Cargo.toml b/net/virtio-netd/Cargo.toml similarity index 71% rename from virtio-netd/Cargo.toml rename to net/virtio-netd/Cargo.toml index dc622bae92..e1063e7414 100644 --- a/virtio-netd/Cargo.toml +++ b/net/virtio-netd/Cargo.toml @@ -8,9 +8,9 @@ log = "0.4" static_assertions = "1.1.0" futures = { version = "0.3.28", features = ["executor"] } -virtio-core = { path = "../virtio-core" } -pcid = { path = "../pcid" } -common = { path = "../common" } +virtio-core = { path = "../../virtio-core" } +pcid = { path = "../../pcid" } +common = { path = "../../common" } driver-network = { path = "../driver-network" } redox-daemon = "0.1" diff --git a/virtio-netd/config.toml b/net/virtio-netd/config.toml similarity index 100% rename from virtio-netd/config.toml rename to net/virtio-netd/config.toml diff --git a/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs similarity index 100% rename from virtio-netd/src/main.rs rename to net/virtio-netd/src/main.rs diff --git a/virtio-netd/src/scheme.rs b/net/virtio-netd/src/scheme.rs similarity index 100% rename from virtio-netd/src/scheme.rs rename to net/virtio-netd/src/scheme.rs From c75b560def7ed2889d11744cc08c37f2d781bc7e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 28 Feb 2024 21:26:09 +0100 Subject: [PATCH 0827/1301] Move all storage drivers to storage/ --- Cargo.toml | 16 ++++++++-------- {ahcid => storage/ahcid}/.gitignore | 0 {ahcid => storage/ahcid}/Cargo.toml | 4 ++-- {ahcid => storage/ahcid}/src/ahci/disk_ata.rs | 0 {ahcid => storage/ahcid}/src/ahci/disk_atapi.rs | 0 {ahcid => storage/ahcid}/src/ahci/fis.rs | 0 {ahcid => storage/ahcid}/src/ahci/hba.rs | 0 {ahcid => storage/ahcid}/src/ahci/mod.rs | 0 {ahcid => storage/ahcid}/src/main.rs | 0 {ahcid => storage/ahcid}/src/scheme.rs | 0 .../bcm2835-sdhcid}/Cargo.toml | 2 +- .../bcm2835-sdhcid}/src/main.rs | 0 .../bcm2835-sdhcid}/src/scheme.rs | 0 .../bcm2835-sdhcid}/src/sd/mod.rs | 0 .../block-io-wrapper}/.gitignore | 0 .../block-io-wrapper}/Cargo.toml | 0 .../block-io-wrapper}/src/lib.rs | 0 {ided => storage/ided}/.gitignore | 0 {ided => storage/ided}/Cargo.toml | 4 ++-- {ided => storage/ided}/src/ide.rs | 0 {ided => storage/ided}/src/main.rs | 0 {ided => storage/ided}/src/scheme.rs | 0 {lived => storage/lived}/Cargo.toml | 0 {lived => storage/lived}/src/main.rs | 0 {nvmed => storage/nvmed}/.gitignore | 0 {nvmed => storage/nvmed}/Cargo.toml | 4 ++-- {nvmed => storage/nvmed}/src/main.rs | 0 {nvmed => storage/nvmed}/src/nvme/cmd.rs | 0 {nvmed => storage/nvmed}/src/nvme/cq_reactor.rs | 0 {nvmed => storage/nvmed}/src/nvme/identify.rs | 0 {nvmed => storage/nvmed}/src/nvme/mod.rs | 0 {nvmed => storage/nvmed}/src/nvme/queues.rs | 0 {nvmed => storage/nvmed}/src/scheme.rs | 0 {usbscsid => storage/usbscsid}/.gitignore | 0 {usbscsid => storage/usbscsid}/Cargo.toml | 2 +- {usbscsid => storage/usbscsid}/src/main.rs | 0 .../usbscsid}/src/protocol/bot.rs | 0 .../usbscsid}/src/protocol/mod.rs | 0 {usbscsid => storage/usbscsid}/src/scheme.rs | 0 {usbscsid => storage/usbscsid}/src/scsi/cmds.rs | 0 {usbscsid => storage/usbscsid}/src/scsi/mod.rs | 0 .../usbscsid}/src/scsi/opcodes.rs | 0 {virtio-blkd => storage/virtio-blkd}/Cargo.toml | 6 +++--- {virtio-blkd => storage/virtio-blkd}/src/main.rs | 0 .../virtio-blkd}/src/scheme.rs | 0 45 files changed, 19 insertions(+), 19 deletions(-) rename {ahcid => storage/ahcid}/.gitignore (100%) rename {ahcid => storage/ahcid}/Cargo.toml (82%) rename {ahcid => storage/ahcid}/src/ahci/disk_ata.rs (100%) rename {ahcid => storage/ahcid}/src/ahci/disk_atapi.rs (100%) rename {ahcid => storage/ahcid}/src/ahci/fis.rs (100%) rename {ahcid => storage/ahcid}/src/ahci/hba.rs (100%) rename {ahcid => storage/ahcid}/src/ahci/mod.rs (100%) rename {ahcid => storage/ahcid}/src/main.rs (100%) rename {ahcid => storage/ahcid}/src/scheme.rs (100%) rename {bcm2835-sdhcid => storage/bcm2835-sdhcid}/Cargo.toml (91%) rename {bcm2835-sdhcid => storage/bcm2835-sdhcid}/src/main.rs (100%) rename {bcm2835-sdhcid => storage/bcm2835-sdhcid}/src/scheme.rs (100%) rename {bcm2835-sdhcid => storage/bcm2835-sdhcid}/src/sd/mod.rs (100%) rename {block-io-wrapper => storage/block-io-wrapper}/.gitignore (100%) rename {block-io-wrapper => storage/block-io-wrapper}/Cargo.toml (100%) rename {block-io-wrapper => storage/block-io-wrapper}/src/lib.rs (100%) rename {ided => storage/ided}/.gitignore (100%) rename {ided => storage/ided}/Cargo.toml (80%) rename {ided => storage/ided}/src/ide.rs (100%) rename {ided => storage/ided}/src/main.rs (100%) rename {ided => storage/ided}/src/scheme.rs (100%) rename {lived => storage/lived}/Cargo.toml (100%) rename {lived => storage/lived}/src/main.rs (100%) rename {nvmed => storage/nvmed}/.gitignore (100%) rename {nvmed => storage/nvmed}/Cargo.toml (86%) rename {nvmed => storage/nvmed}/src/main.rs (100%) rename {nvmed => storage/nvmed}/src/nvme/cmd.rs (100%) rename {nvmed => storage/nvmed}/src/nvme/cq_reactor.rs (100%) rename {nvmed => storage/nvmed}/src/nvme/identify.rs (100%) rename {nvmed => storage/nvmed}/src/nvme/mod.rs (100%) rename {nvmed => storage/nvmed}/src/nvme/queues.rs (100%) rename {nvmed => storage/nvmed}/src/scheme.rs (100%) rename {usbscsid => storage/usbscsid}/.gitignore (100%) rename {usbscsid => storage/usbscsid}/Cargo.toml (91%) rename {usbscsid => storage/usbscsid}/src/main.rs (100%) rename {usbscsid => storage/usbscsid}/src/protocol/bot.rs (100%) rename {usbscsid => storage/usbscsid}/src/protocol/mod.rs (100%) rename {usbscsid => storage/usbscsid}/src/scheme.rs (100%) rename {usbscsid => storage/usbscsid}/src/scsi/cmds.rs (100%) rename {usbscsid => storage/usbscsid}/src/scsi/mod.rs (100%) rename {usbscsid => storage/usbscsid}/src/scsi/opcodes.rs (100%) rename {virtio-blkd => storage/virtio-blkd}/Cargo.toml (81%) rename {virtio-blkd => storage/virtio-blkd}/src/main.rs (100%) rename {virtio-blkd => storage/virtio-blkd}/src/scheme.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 8982e528b9..0d2e7110c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,15 +2,10 @@ members = [ "ac97d", "acpid", - "ahcid", "bgad", - "block-io-wrapper", "common", "fbcond", - "ided", "ihdad", - "nvmed", - "lived", # TODO: not really a driver... "pcid", "pcspkrd", "ps2d", @@ -20,10 +15,8 @@ members = [ "xhcid", "usbctl", "usbhidd", - "usbscsid", "inputd", - "virtio-blkd", "virtio-gpud", "virtio-core", @@ -35,7 +28,14 @@ members = [ "net/rtl8168d", "net/virtio-netd", - "bcm2835-sdhcid", + "storage/ahcid", + "storage/bcm2835-sdhcid", + "storage/block-io-wrapper", + "storage/ided", + "storage/lived", # TODO: not really a driver... + "storage/nvmed", + "storage/usbscsid", + "storage/virtio-blkd", ] [profile.release] diff --git a/ahcid/.gitignore b/storage/ahcid/.gitignore similarity index 100% rename from ahcid/.gitignore rename to storage/ahcid/.gitignore diff --git a/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml similarity index 82% rename from ahcid/Cargo.toml rename to storage/ahcid/Cargo.toml index cb5637dd69..03fd054a25 100644 --- a/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -13,5 +13,5 @@ redox-log = "0.1" redox_syscall = "0.4" block-io-wrapper = { path = "../block-io-wrapper" } -common = { path = "../common" } -pcid = { path = "../pcid" } +common = { path = "../../common" } +pcid = { path = "../../pcid" } diff --git a/ahcid/src/ahci/disk_ata.rs b/storage/ahcid/src/ahci/disk_ata.rs similarity index 100% rename from ahcid/src/ahci/disk_ata.rs rename to storage/ahcid/src/ahci/disk_ata.rs diff --git a/ahcid/src/ahci/disk_atapi.rs b/storage/ahcid/src/ahci/disk_atapi.rs similarity index 100% rename from ahcid/src/ahci/disk_atapi.rs rename to storage/ahcid/src/ahci/disk_atapi.rs diff --git a/ahcid/src/ahci/fis.rs b/storage/ahcid/src/ahci/fis.rs similarity index 100% rename from ahcid/src/ahci/fis.rs rename to storage/ahcid/src/ahci/fis.rs diff --git a/ahcid/src/ahci/hba.rs b/storage/ahcid/src/ahci/hba.rs similarity index 100% rename from ahcid/src/ahci/hba.rs rename to storage/ahcid/src/ahci/hba.rs diff --git a/ahcid/src/ahci/mod.rs b/storage/ahcid/src/ahci/mod.rs similarity index 100% rename from ahcid/src/ahci/mod.rs rename to storage/ahcid/src/ahci/mod.rs diff --git a/ahcid/src/main.rs b/storage/ahcid/src/main.rs similarity index 100% rename from ahcid/src/main.rs rename to storage/ahcid/src/main.rs diff --git a/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs similarity index 100% rename from ahcid/src/scheme.rs rename to storage/ahcid/src/scheme.rs diff --git a/bcm2835-sdhcid/Cargo.toml b/storage/bcm2835-sdhcid/Cargo.toml similarity index 91% rename from bcm2835-sdhcid/Cargo.toml rename to storage/bcm2835-sdhcid/Cargo.toml index faa5ddfb77..f9bce4ae2b 100644 --- a/bcm2835-sdhcid/Cargo.toml +++ b/storage/bcm2835-sdhcid/Cargo.toml @@ -10,6 +10,6 @@ fdt = "0.1.5" redox_syscall = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } block-io-wrapper = { path = "../block-io-wrapper" } -common = { path = "../common" } +common = { path = "../../common" } redox-daemon = "0.1" diff --git a/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs similarity index 100% rename from bcm2835-sdhcid/src/main.rs rename to storage/bcm2835-sdhcid/src/main.rs diff --git a/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs similarity index 100% rename from bcm2835-sdhcid/src/scheme.rs rename to storage/bcm2835-sdhcid/src/scheme.rs diff --git a/bcm2835-sdhcid/src/sd/mod.rs b/storage/bcm2835-sdhcid/src/sd/mod.rs similarity index 100% rename from bcm2835-sdhcid/src/sd/mod.rs rename to storage/bcm2835-sdhcid/src/sd/mod.rs diff --git a/block-io-wrapper/.gitignore b/storage/block-io-wrapper/.gitignore similarity index 100% rename from block-io-wrapper/.gitignore rename to storage/block-io-wrapper/.gitignore diff --git a/block-io-wrapper/Cargo.toml b/storage/block-io-wrapper/Cargo.toml similarity index 100% rename from block-io-wrapper/Cargo.toml rename to storage/block-io-wrapper/Cargo.toml diff --git a/block-io-wrapper/src/lib.rs b/storage/block-io-wrapper/src/lib.rs similarity index 100% rename from block-io-wrapper/src/lib.rs rename to storage/block-io-wrapper/src/lib.rs diff --git a/ided/.gitignore b/storage/ided/.gitignore similarity index 100% rename from ided/.gitignore rename to storage/ided/.gitignore diff --git a/ided/Cargo.toml b/storage/ided/Cargo.toml similarity index 80% rename from ided/Cargo.toml rename to storage/ided/Cargo.toml index 6e4a036981..c580881d9e 100644 --- a/ided/Cargo.toml +++ b/storage/ided/Cargo.toml @@ -5,10 +5,10 @@ edition = "2018" [dependencies] block-io-wrapper = { path = "../block-io-wrapper" } -common = { path = "../common" } +common = { path = "../../common" } log = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } -pcid = { path = "../pcid" } +pcid = { path = "../../pcid" } redox-daemon = "0.1" redox-log = "0.1" redox_syscall = "0.4" diff --git a/ided/src/ide.rs b/storage/ided/src/ide.rs similarity index 100% rename from ided/src/ide.rs rename to storage/ided/src/ide.rs diff --git a/ided/src/main.rs b/storage/ided/src/main.rs similarity index 100% rename from ided/src/main.rs rename to storage/ided/src/main.rs diff --git a/ided/src/scheme.rs b/storage/ided/src/scheme.rs similarity index 100% rename from ided/src/scheme.rs rename to storage/ided/src/scheme.rs diff --git a/lived/Cargo.toml b/storage/lived/Cargo.toml similarity index 100% rename from lived/Cargo.toml rename to storage/lived/Cargo.toml diff --git a/lived/src/main.rs b/storage/lived/src/main.rs similarity index 100% rename from lived/src/main.rs rename to storage/lived/src/main.rs diff --git a/nvmed/.gitignore b/storage/nvmed/.gitignore similarity index 100% rename from nvmed/.gitignore rename to storage/nvmed/.gitignore diff --git a/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml similarity index 86% rename from nvmed/Cargo.toml rename to storage/nvmed/Cargo.toml index b18436d927..ce52f43752 100644 --- a/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -16,8 +16,8 @@ partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } smallvec = "1" block-io-wrapper = { path = "../block-io-wrapper" } -common = { path = "../common" } -pcid = { path = "../pcid" } +common = { path = "../../common" } +pcid = { path = "../../pcid" } [features] default = ["async"] diff --git a/nvmed/src/main.rs b/storage/nvmed/src/main.rs similarity index 100% rename from nvmed/src/main.rs rename to storage/nvmed/src/main.rs diff --git a/nvmed/src/nvme/cmd.rs b/storage/nvmed/src/nvme/cmd.rs similarity index 100% rename from nvmed/src/nvme/cmd.rs rename to storage/nvmed/src/nvme/cmd.rs diff --git a/nvmed/src/nvme/cq_reactor.rs b/storage/nvmed/src/nvme/cq_reactor.rs similarity index 100% rename from nvmed/src/nvme/cq_reactor.rs rename to storage/nvmed/src/nvme/cq_reactor.rs diff --git a/nvmed/src/nvme/identify.rs b/storage/nvmed/src/nvme/identify.rs similarity index 100% rename from nvmed/src/nvme/identify.rs rename to storage/nvmed/src/nvme/identify.rs diff --git a/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs similarity index 100% rename from nvmed/src/nvme/mod.rs rename to storage/nvmed/src/nvme/mod.rs diff --git a/nvmed/src/nvme/queues.rs b/storage/nvmed/src/nvme/queues.rs similarity index 100% rename from nvmed/src/nvme/queues.rs rename to storage/nvmed/src/nvme/queues.rs diff --git a/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs similarity index 100% rename from nvmed/src/scheme.rs rename to storage/nvmed/src/scheme.rs diff --git a/usbscsid/.gitignore b/storage/usbscsid/.gitignore similarity index 100% rename from usbscsid/.gitignore rename to storage/usbscsid/.gitignore diff --git a/usbscsid/Cargo.toml b/storage/usbscsid/Cargo.toml similarity index 91% rename from usbscsid/Cargo.toml rename to storage/usbscsid/Cargo.toml index f014a19fd2..28083405a3 100644 --- a/usbscsid/Cargo.toml +++ b/storage/usbscsid/Cargo.toml @@ -13,4 +13,4 @@ plain = "0.2" redox-daemon = "0.1" redox_syscall = "0.4" thiserror = "1" -xhcid = { path = "../xhcid" } +xhcid = { path = "../../xhcid" } diff --git a/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs similarity index 100% rename from usbscsid/src/main.rs rename to storage/usbscsid/src/main.rs diff --git a/usbscsid/src/protocol/bot.rs b/storage/usbscsid/src/protocol/bot.rs similarity index 100% rename from usbscsid/src/protocol/bot.rs rename to storage/usbscsid/src/protocol/bot.rs diff --git a/usbscsid/src/protocol/mod.rs b/storage/usbscsid/src/protocol/mod.rs similarity index 100% rename from usbscsid/src/protocol/mod.rs rename to storage/usbscsid/src/protocol/mod.rs diff --git a/usbscsid/src/scheme.rs b/storage/usbscsid/src/scheme.rs similarity index 100% rename from usbscsid/src/scheme.rs rename to storage/usbscsid/src/scheme.rs diff --git a/usbscsid/src/scsi/cmds.rs b/storage/usbscsid/src/scsi/cmds.rs similarity index 100% rename from usbscsid/src/scsi/cmds.rs rename to storage/usbscsid/src/scsi/cmds.rs diff --git a/usbscsid/src/scsi/mod.rs b/storage/usbscsid/src/scsi/mod.rs similarity index 100% rename from usbscsid/src/scsi/mod.rs rename to storage/usbscsid/src/scsi/mod.rs diff --git a/usbscsid/src/scsi/opcodes.rs b/storage/usbscsid/src/scsi/opcodes.rs similarity index 100% rename from usbscsid/src/scsi/opcodes.rs rename to storage/usbscsid/src/scsi/opcodes.rs diff --git a/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml similarity index 81% rename from virtio-blkd/Cargo.toml rename to storage/virtio-blkd/Cargo.toml index 5f6ab31295..c9ec28ced1 100644 --- a/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -18,6 +18,6 @@ redox_syscall = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } block-io-wrapper = { path = "../block-io-wrapper" } -common = { path = "../common" } -pcid = { path = "../pcid" } -virtio-core = { path = "../virtio-core" } +common = { path = "../../common" } +pcid = { path = "../../pcid" } +virtio-core = { path = "../../virtio-core" } diff --git a/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs similarity index 100% rename from virtio-blkd/src/main.rs rename to storage/virtio-blkd/src/main.rs diff --git a/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs similarity index 100% rename from virtio-blkd/src/scheme.rs rename to storage/virtio-blkd/src/scheme.rs From 0e98dc4a053014ff907ebf020f0d8824253074b0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 28 Feb 2024 21:30:02 +0100 Subject: [PATCH 0828/1301] Move all audio drivers to audio/ --- Cargo.toml | 9 +++++---- {ac97d => audio/ac97d}/Cargo.toml | 4 ++-- {ac97d => audio/ac97d}/config.toml | 0 {ac97d => audio/ac97d}/src/device.rs | 0 {ac97d => audio/ac97d}/src/main.rs | 0 {ihdad => audio/ihdad}/Cargo.toml | 4 ++-- {ihdad => audio/ihdad}/config.toml | 0 {ihdad => audio/ihdad}/src/hda/cmdbuff.rs | 0 {ihdad => audio/ihdad}/src/hda/common.rs | 0 {ihdad => audio/ihdad}/src/hda/device.rs | 0 {ihdad => audio/ihdad}/src/hda/mod.rs | 0 {ihdad => audio/ihdad}/src/hda/node.rs | 0 {ihdad => audio/ihdad}/src/hda/stream.rs | 0 {ihdad => audio/ihdad}/src/main.rs | 0 {pcspkrd => audio/pcspkrd}/Cargo.toml | 0 {pcspkrd => audio/pcspkrd}/src/main.rs | 0 {pcspkrd => audio/pcspkrd}/src/pcspkr.rs | 0 {pcspkrd => audio/pcspkrd}/src/scheme.rs | 0 {sb16d => audio/sb16d}/Cargo.toml | 2 +- {sb16d => audio/sb16d}/src/device.rs | 0 {sb16d => audio/sb16d}/src/main.rs | 0 21 files changed, 10 insertions(+), 9 deletions(-) rename {ac97d => audio/ac97d}/Cargo.toml (79%) rename {ac97d => audio/ac97d}/config.toml (100%) rename {ac97d => audio/ac97d}/src/device.rs (100%) rename {ac97d => audio/ac97d}/src/main.rs (100%) rename {ihdad => audio/ihdad}/Cargo.toml (79%) rename {ihdad => audio/ihdad}/config.toml (100%) rename {ihdad => audio/ihdad}/src/hda/cmdbuff.rs (100%) rename {ihdad => audio/ihdad}/src/hda/common.rs (100%) rename {ihdad => audio/ihdad}/src/hda/device.rs (100%) rename {ihdad => audio/ihdad}/src/hda/mod.rs (100%) rename {ihdad => audio/ihdad}/src/hda/node.rs (100%) rename {ihdad => audio/ihdad}/src/hda/stream.rs (100%) rename {ihdad => audio/ihdad}/src/main.rs (100%) rename {pcspkrd => audio/pcspkrd}/Cargo.toml (100%) rename {pcspkrd => audio/pcspkrd}/src/main.rs (100%) rename {pcspkrd => audio/pcspkrd}/src/pcspkr.rs (100%) rename {pcspkrd => audio/pcspkrd}/src/scheme.rs (100%) rename {sb16d => audio/sb16d}/Cargo.toml (87%) rename {sb16d => audio/sb16d}/src/device.rs (100%) rename {sb16d => audio/sb16d}/src/main.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 0d2e7110c8..f671f18059 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,15 +1,11 @@ [workspace] members = [ - "ac97d", "acpid", "bgad", "common", "fbcond", - "ihdad", "pcid", - "pcspkrd", "ps2d", - "sb16d", "vboxd", "vesad", "xhcid", @@ -20,6 +16,11 @@ members = [ "virtio-gpud", "virtio-core", + "audio/ac97d", + "audio/ihdad", + "audio/pcspkrd", + "audio/sb16d", + "net/alxd", "net/driver-network", "net/e1000d", diff --git a/ac97d/Cargo.toml b/audio/ac97d/Cargo.toml similarity index 79% rename from ac97d/Cargo.toml rename to audio/ac97d/Cargo.toml index 6a8c4a477f..4d780d5d99 100644 --- a/ac97d/Cargo.toml +++ b/audio/ac97d/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" [dependencies] bitflags = "1" -common = { path = "../common" } +common = { path = "../../common" } log = "0.4" redox-daemon = "0.1" redox-log = "0.1" @@ -13,4 +13,4 @@ redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" spin = "0.9" -pcid = { path = "../pcid" } +pcid = { path = "../../pcid" } diff --git a/ac97d/config.toml b/audio/ac97d/config.toml similarity index 100% rename from ac97d/config.toml rename to audio/ac97d/config.toml diff --git a/ac97d/src/device.rs b/audio/ac97d/src/device.rs similarity index 100% rename from ac97d/src/device.rs rename to audio/ac97d/src/device.rs diff --git a/ac97d/src/main.rs b/audio/ac97d/src/main.rs similarity index 100% rename from ac97d/src/main.rs rename to audio/ac97d/src/main.rs diff --git a/ihdad/Cargo.toml b/audio/ihdad/Cargo.toml similarity index 79% rename from ihdad/Cargo.toml rename to audio/ihdad/Cargo.toml index 799e0aadb8..32f294d95a 100755 --- a/ihdad/Cargo.toml +++ b/audio/ihdad/Cargo.toml @@ -12,5 +12,5 @@ redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.4" spin = "0.9" -common = { path = "../common" } -pcid = { path = "../pcid" } +common = { path = "../../common" } +pcid = { path = "../../pcid" } diff --git a/ihdad/config.toml b/audio/ihdad/config.toml similarity index 100% rename from ihdad/config.toml rename to audio/ihdad/config.toml diff --git a/ihdad/src/hda/cmdbuff.rs b/audio/ihdad/src/hda/cmdbuff.rs similarity index 100% rename from ihdad/src/hda/cmdbuff.rs rename to audio/ihdad/src/hda/cmdbuff.rs diff --git a/ihdad/src/hda/common.rs b/audio/ihdad/src/hda/common.rs similarity index 100% rename from ihdad/src/hda/common.rs rename to audio/ihdad/src/hda/common.rs diff --git a/ihdad/src/hda/device.rs b/audio/ihdad/src/hda/device.rs similarity index 100% rename from ihdad/src/hda/device.rs rename to audio/ihdad/src/hda/device.rs diff --git a/ihdad/src/hda/mod.rs b/audio/ihdad/src/hda/mod.rs similarity index 100% rename from ihdad/src/hda/mod.rs rename to audio/ihdad/src/hda/mod.rs diff --git a/ihdad/src/hda/node.rs b/audio/ihdad/src/hda/node.rs similarity index 100% rename from ihdad/src/hda/node.rs rename to audio/ihdad/src/hda/node.rs diff --git a/ihdad/src/hda/stream.rs b/audio/ihdad/src/hda/stream.rs similarity index 100% rename from ihdad/src/hda/stream.rs rename to audio/ihdad/src/hda/stream.rs diff --git a/ihdad/src/main.rs b/audio/ihdad/src/main.rs similarity index 100% rename from ihdad/src/main.rs rename to audio/ihdad/src/main.rs diff --git a/pcspkrd/Cargo.toml b/audio/pcspkrd/Cargo.toml similarity index 100% rename from pcspkrd/Cargo.toml rename to audio/pcspkrd/Cargo.toml diff --git a/pcspkrd/src/main.rs b/audio/pcspkrd/src/main.rs similarity index 100% rename from pcspkrd/src/main.rs rename to audio/pcspkrd/src/main.rs diff --git a/pcspkrd/src/pcspkr.rs b/audio/pcspkrd/src/pcspkr.rs similarity index 100% rename from pcspkrd/src/pcspkr.rs rename to audio/pcspkrd/src/pcspkr.rs diff --git a/pcspkrd/src/scheme.rs b/audio/pcspkrd/src/scheme.rs similarity index 100% rename from pcspkrd/src/scheme.rs rename to audio/pcspkrd/src/scheme.rs diff --git a/sb16d/Cargo.toml b/audio/sb16d/Cargo.toml similarity index 87% rename from sb16d/Cargo.toml rename to audio/sb16d/Cargo.toml index fc49b61b26..ccabfa3514 100644 --- a/sb16d/Cargo.toml +++ b/audio/sb16d/Cargo.toml @@ -5,7 +5,7 @@ edition = "2018" [dependencies] bitflags = "1" -common = { path = "../common" } +common = { path = "../../common" } log = "0.4" redox-daemon = "0.1" redox-log = "0.1" diff --git a/sb16d/src/device.rs b/audio/sb16d/src/device.rs similarity index 100% rename from sb16d/src/device.rs rename to audio/sb16d/src/device.rs diff --git a/sb16d/src/main.rs b/audio/sb16d/src/main.rs similarity index 100% rename from sb16d/src/main.rs rename to audio/sb16d/src/main.rs From 887412daf5ccc18760f151a5a8677e7a5dfa71ad Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 28 Feb 2024 21:36:43 +0100 Subject: [PATCH 0829/1301] Move all graphics related drivers to graphics/ --- Cargo.toml | 10 +++++----- {bgad => graphics/bgad}/Cargo.toml | 2 +- {bgad => graphics/bgad}/config.toml | 0 {bgad => graphics/bgad}/src/bga.rs | 0 {bgad => graphics/bgad}/src/main.rs | 0 {bgad => graphics/bgad}/src/scheme.rs | 0 {fbcond => graphics/fbcond}/Cargo.toml | 2 +- {fbcond => graphics/fbcond}/src/display.rs | 0 {fbcond => graphics/fbcond}/src/main.rs | 0 {fbcond => graphics/fbcond}/src/scheme.rs | 0 {fbcond => graphics/fbcond}/src/text.rs | 0 {vesad => graphics/vesad}/Cargo.toml | 4 ++-- {vesad => graphics/vesad}/src/display.rs | 0 {vesad => graphics/vesad}/src/framebuffer.rs | 0 {vesad => graphics/vesad}/src/main.rs | 0 {vesad => graphics/vesad}/src/scheme.rs | 0 {vesad => graphics/vesad}/src/screen.rs | 0 {virtio-gpud => graphics/virtio-gpud}/Cargo.toml | 8 ++++---- {virtio-gpud => graphics/virtio-gpud}/src/main.rs | 0 {virtio-gpud => graphics/virtio-gpud}/src/scheme.rs | 0 20 files changed, 13 insertions(+), 13 deletions(-) rename {bgad => graphics/bgad}/Cargo.toml (81%) rename {bgad => graphics/bgad}/config.toml (100%) rename {bgad => graphics/bgad}/src/bga.rs (100%) rename {bgad => graphics/bgad}/src/main.rs (100%) rename {bgad => graphics/bgad}/src/scheme.rs (100%) rename {fbcond => graphics/fbcond}/Cargo.toml (85%) rename {fbcond => graphics/fbcond}/src/display.rs (100%) rename {fbcond => graphics/fbcond}/src/main.rs (100%) rename {fbcond => graphics/fbcond}/src/scheme.rs (100%) rename {fbcond => graphics/fbcond}/src/text.rs (100%) rename {vesad => graphics/vesad}/Cargo.toml (72%) rename {vesad => graphics/vesad}/src/display.rs (100%) rename {vesad => graphics/vesad}/src/framebuffer.rs (100%) rename {vesad => graphics/vesad}/src/main.rs (100%) rename {vesad => graphics/vesad}/src/scheme.rs (100%) rename {vesad => graphics/vesad}/src/screen.rs (100%) rename {virtio-gpud => graphics/virtio-gpud}/Cargo.toml (70%) rename {virtio-gpud => graphics/virtio-gpud}/src/main.rs (100%) rename {virtio-gpud => graphics/virtio-gpud}/src/scheme.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index f671f18059..b489a829a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,19 +1,14 @@ [workspace] members = [ "acpid", - "bgad", "common", - "fbcond", "pcid", "ps2d", "vboxd", - "vesad", "xhcid", "usbctl", "usbhidd", "inputd", - - "virtio-gpud", "virtio-core", "audio/ac97d", @@ -21,6 +16,11 @@ members = [ "audio/pcspkrd", "audio/sb16d", + "graphics/bgad", + "graphics/fbcond", + "graphics/vesad", + "graphics/virtio-gpud", + "net/alxd", "net/driver-network", "net/e1000d", diff --git a/bgad/Cargo.toml b/graphics/bgad/Cargo.toml similarity index 81% rename from bgad/Cargo.toml rename to graphics/bgad/Cargo.toml index 596bf0f54d..afa6619215 100644 --- a/bgad/Cargo.toml +++ b/graphics/bgad/Cargo.toml @@ -8,4 +8,4 @@ orbclient = "0.3.27" redox-daemon = "0.1" redox_syscall = "0.4" -pcid = { path = "../pcid" } +pcid = { path = "../../pcid" } diff --git a/bgad/config.toml b/graphics/bgad/config.toml similarity index 100% rename from bgad/config.toml rename to graphics/bgad/config.toml diff --git a/bgad/src/bga.rs b/graphics/bgad/src/bga.rs similarity index 100% rename from bgad/src/bga.rs rename to graphics/bgad/src/bga.rs diff --git a/bgad/src/main.rs b/graphics/bgad/src/main.rs similarity index 100% rename from bgad/src/main.rs rename to graphics/bgad/src/main.rs diff --git a/bgad/src/scheme.rs b/graphics/bgad/src/scheme.rs similarity index 100% rename from bgad/src/scheme.rs rename to graphics/bgad/src/scheme.rs diff --git a/fbcond/Cargo.toml b/graphics/fbcond/Cargo.toml similarity index 85% rename from fbcond/Cargo.toml rename to graphics/fbcond/Cargo.toml index 465876c071..d934921104 100644 --- a/fbcond/Cargo.toml +++ b/graphics/fbcond/Cargo.toml @@ -10,7 +10,7 @@ redox_event = "0.2" redox_syscall = "0.4" redox-daemon = "0.1" -inputd = { path = "../inputd" } +inputd = { path = "../../inputd" } [features] default = [] diff --git a/fbcond/src/display.rs b/graphics/fbcond/src/display.rs similarity index 100% rename from fbcond/src/display.rs rename to graphics/fbcond/src/display.rs diff --git a/fbcond/src/main.rs b/graphics/fbcond/src/main.rs similarity index 100% rename from fbcond/src/main.rs rename to graphics/fbcond/src/main.rs diff --git a/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs similarity index 100% rename from fbcond/src/scheme.rs rename to graphics/fbcond/src/scheme.rs diff --git a/fbcond/src/text.rs b/graphics/fbcond/src/text.rs similarity index 100% rename from fbcond/src/text.rs rename to graphics/fbcond/src/text.rs diff --git a/vesad/Cargo.toml b/graphics/vesad/Cargo.toml similarity index 72% rename from vesad/Cargo.toml rename to graphics/vesad/Cargo.toml index 85d12fc9fb..5d6542ccf5 100644 --- a/vesad/Cargo.toml +++ b/graphics/vesad/Cargo.toml @@ -9,8 +9,8 @@ ransid = "0.4" redox_syscall = "0.4" redox-daemon = "0.1" -common = { path = "../common" } -inputd = { path = "../inputd" } +common = { path = "../../common" } +inputd = { path = "../../inputd" } [features] default = [] diff --git a/vesad/src/display.rs b/graphics/vesad/src/display.rs similarity index 100% rename from vesad/src/display.rs rename to graphics/vesad/src/display.rs diff --git a/vesad/src/framebuffer.rs b/graphics/vesad/src/framebuffer.rs similarity index 100% rename from vesad/src/framebuffer.rs rename to graphics/vesad/src/framebuffer.rs diff --git a/vesad/src/main.rs b/graphics/vesad/src/main.rs similarity index 100% rename from vesad/src/main.rs rename to graphics/vesad/src/main.rs diff --git a/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs similarity index 100% rename from vesad/src/scheme.rs rename to graphics/vesad/src/scheme.rs diff --git a/vesad/src/screen.rs b/graphics/vesad/src/screen.rs similarity index 100% rename from vesad/src/screen.rs rename to graphics/vesad/src/screen.rs diff --git a/virtio-gpud/Cargo.toml b/graphics/virtio-gpud/Cargo.toml similarity index 70% rename from virtio-gpud/Cargo.toml rename to graphics/virtio-gpud/Cargo.toml index 41fd2a69b5..a51e8b5a7a 100644 --- a/virtio-gpud/Cargo.toml +++ b/graphics/virtio-gpud/Cargo.toml @@ -11,10 +11,10 @@ futures = { version = "0.3.28", features = ["executor"] } anyhow = "1.0.71" paste = "1.0.13" -common = { path = "../common" } -virtio-core = { path = "../virtio-core" } -pcid = { path = "../pcid" } -inputd = { path = "../inputd" } +common = { path = "../../common" } +virtio-core = { path = "../../virtio-core" } +pcid = { path = "../../pcid" } +inputd = { path = "../../inputd" } redox-daemon = "0.1" redox_syscall = "0.4" diff --git a/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs similarity index 100% rename from virtio-gpud/src/main.rs rename to graphics/virtio-gpud/src/main.rs diff --git a/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs similarity index 100% rename from virtio-gpud/src/scheme.rs rename to graphics/virtio-gpud/src/scheme.rs From 9bb1222933fc85eaa326bad00a0db9c128e8dade Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 6 Mar 2024 21:06:26 +0100 Subject: [PATCH 0830/1301] Fix UB lint in virtio-core error: casting references to a bigger memory layout than the backing allocation is undefined behavior, even if the reference is unused --> virtio-core/src/probe.rs:126:21 | 86 | let capability = unsafe { &*(capability.data.as_ptr() as *const PciCapability) }; | --------------------------------------------------- backing allocation comes from here ... 126 | (&*(capability as *const PciCapability as *const PciCapabilityNotify)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: casting from `transport_pci::PciCapability` (13 bytes) to `transport_pci::PciCapabilityNotify` (17 bytes) = note: `#[deny(invalid_reference_casting)]` on by default --- virtio-core/src/probe.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 4f7d48719d..aebd065d04 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -71,7 +71,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result let mut notify_addr = None; let mut device_addr = None; - for capability in pcid_handle + for raw_capability in pcid_handle .get_capabilities()? .iter() .filter_map(|capability| { @@ -83,7 +83,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result }) { // SAFETY: We have verified that the length of the data is correct. - let capability = unsafe { &*(capability.data.as_ptr() as *const PciCapability) }; + let capability = unsafe { &*(raw_capability.data.as_ptr() as *const PciCapability) }; match capability.cfg_type { CfgType::Common | CfgType::Notify | CfgType::Device => {} @@ -123,7 +123,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result // SAFETY: The capability type is `Notify`, so its safe to access // the `notify_multiplier` field. let multiplier = unsafe { - (&*(capability as *const PciCapability as *const PciCapabilityNotify)) + (&*(raw_capability.data.as_ptr() as *const PciCapability as *const PciCapabilityNotify)) .notify_off_multiplier() }; notify_addr = Some((address, multiplier)); From 3e426370662325178d6aa082c7ce9c32ce9f4427 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 6 Mar 2024 21:09:31 +0100 Subject: [PATCH 0831/1301] Fix a panic message --- net/driver-network/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index 6c10a352d0..3790b33ba5 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -50,7 +50,7 @@ impl NetworkScheme { format!(":{scheme_name}"), syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, ) - .expect("e1000d: failed to create network scheme"); + .expect("failed to create network scheme"); let scheme = unsafe { File::from_raw_fd(scheme_fd as RawFd) }; NetworkScheme { From 20bc47f228e94d1859b4bd5ad00e3eb123524085 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 6 Mar 2024 21:09:22 +0100 Subject: [PATCH 0832/1301] Move DiskWrapper into a new driver-block crate Also merge block-io-wrapper into this crate. --- Cargo.lock | 25 ++-- Cargo.toml | 2 +- storage/ahcid/Cargo.toml | 3 +- storage/ahcid/src/ahci/mod.rs | 10 +- storage/ahcid/src/scheme.rs | 89 +------------- storage/bcm2835-sdhcid/Cargo.toml | 3 +- storage/bcm2835-sdhcid/src/main.rs | 6 +- storage/bcm2835-sdhcid/src/scheme.rs | 89 +------------- storage/bcm2835-sdhcid/src/sd/mod.rs | 20 +-- storage/block-io-wrapper/.gitignore | 1 - storage/block-io-wrapper/Cargo.toml | 9 -- storage/block-io-wrapper/src/lib.rs | 49 -------- storage/driver-block/Cargo.toml | 9 ++ storage/driver-block/src/lib.rs | 175 +++++++++++++++++++++++++++ storage/ided/Cargo.toml | 3 +- storage/ided/src/ide.rs | 9 +- storage/ided/src/main.rs | 3 +- storage/ided/src/scheme.rs | 90 +------------- storage/nvmed/Cargo.toml | 2 +- storage/nvmed/src/scheme.rs | 2 +- storage/virtio-blkd/Cargo.toml | 2 +- storage/virtio-blkd/src/scheme.rs | 2 +- 22 files changed, 222 insertions(+), 381 deletions(-) delete mode 100644 storage/block-io-wrapper/.gitignore delete mode 100644 storage/block-io-wrapper/Cargo.toml delete mode 100644 storage/block-io-wrapper/src/lib.rs create mode 100644 storage/driver-block/Cargo.toml create mode 100644 storage/driver-block/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index da45912c2c..f95e8e00f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -42,11 +42,10 @@ name = "ahcid" version = "0.1.0" dependencies = [ "bitflags 1.3.2", - "block-io-wrapper", "byteorder", "common", + "driver-block", "log", - "partitionlib", "pcid", "redox-daemon", "redox-log", @@ -149,10 +148,9 @@ checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" name = "bcm2835-sdhcid" version = "0.1.0" dependencies = [ - "block-io-wrapper", "common", + "driver-block", "fdt", - "partitionlib", "redox-daemon", "redox_syscall 0.4.1", ] @@ -206,10 +204,6 @@ dependencies = [ "wyz", ] -[[package]] -name = "block-io-wrapper" -version = "0.1.0" - [[package]] name = "bumpalo" version = "3.13.0" @@ -350,6 +344,14 @@ dependencies = [ "cfg-if 1.0.0", ] +[[package]] +name = "driver-block" +version = "0.1.0" +dependencies = [ + "partitionlib", + "redox_syscall 0.4.1", +] + [[package]] name = "driver-network" version = "0.1.0" @@ -570,10 +572,9 @@ dependencies = [ name = "ided" version = "0.1.0" dependencies = [ - "block-io-wrapper", "common", + "driver-block", "log", - "partitionlib", "pcid", "redox-daemon", "redox-log", @@ -758,9 +759,9 @@ version = "0.1.0" dependencies = [ "arrayvec", "bitflags 1.3.2", - "block-io-wrapper", "common", "crossbeam-channel", + "driver-block", "futures", "log", "partitionlib", @@ -1591,8 +1592,8 @@ name = "virtio-blkd" version = "0.1.0" dependencies = [ "anyhow", - "block-io-wrapper", "common", + "driver-block", "futures", "log", "partitionlib", diff --git a/Cargo.toml b/Cargo.toml index b489a829a7..ec66f52ad5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,7 @@ members = [ "storage/ahcid", "storage/bcm2835-sdhcid", - "storage/block-io-wrapper", + "storage/driver-block", "storage/ided", "storage/lived", # TODO: not really a driver... "storage/nvmed", diff --git a/storage/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml index 03fd054a25..4c84077667 100644 --- a/storage/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -7,11 +7,10 @@ edition = "2018" bitflags = "1.2" byteorder = "1.2" log = "0.4" -partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } redox-daemon = "0.1" redox-log = "0.1" redox_syscall = "0.4" -block-io-wrapper = { path = "../block-io-wrapper" } common = { path = "../../common" } +driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } diff --git a/storage/ahcid/src/ahci/mod.rs b/storage/ahcid/src/ahci/mod.rs index 2036189d24..3f63ca235e 100644 --- a/storage/ahcid/src/ahci/mod.rs +++ b/storage/ahcid/src/ahci/mod.rs @@ -1,6 +1,6 @@ +use driver_block::Disk; use log::{error, info}; use syscall::io::Io; -use syscall::error::Result; use self::disk_ata::DiskATA; use self::disk_atapi::DiskATAPI; @@ -11,14 +11,6 @@ pub mod disk_atapi; pub mod fis; pub mod hba; -pub trait Disk { - fn id(&self) -> usize; - fn size(&mut self) -> u64; - fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result>; - fn write(&mut self, block: u64, buffer: &[u8]) -> Result>; - fn block_length(&mut self) -> Result; -} - pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec>) { let hba_mem = unsafe { &mut *(base as *mut HbaMem) }; hba_mem.init(); diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index 77b36972a3..ae7bb32573 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -3,19 +3,15 @@ use std::{cmp, str}; use std::convert::{TryFrom}; use std::fmt::Write; use std::io::prelude::*; -use std::io::SeekFrom; -use std::io; +use driver_block::{Disk, DiskWrapper}; use syscall::{ Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; -use crate::ahci::Disk; use crate::ahci::hba::HbaMem; -use partitionlib::{LogicalBlockSize, PartitionTable}; - #[derive(Clone)] enum Handle { List(Vec, usize), // Dir contents buffer, position @@ -23,89 +19,6 @@ enum Handle { Partition(usize, u32, usize), // Disk index, partition index, position } -pub struct DiskWrapper { - disk: Box, - pt: Option, -} - -impl DiskWrapper { - fn pt(disk: &mut dyn Disk) -> Option { - let bs = match disk.block_length() { - Ok(512) => LogicalBlockSize::Lb512, - Ok(4096) => LogicalBlockSize::Lb4096, - _ => return None, - }; - struct Device<'a, 'b> { disk: &'a mut dyn Disk, offset: u64, block_bytes: &'b mut [u8] } - - impl<'a, 'b> Seek for Device<'a, 'b> { - fn seek(&mut self, from: SeekFrom) -> io::Result { - let size = i64::try_from(self.disk.size()).or(Err(io::Error::new(io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes")))?; - - self.offset = match from { - SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos), - SeekFrom::Current(new_pos) => cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64, - SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64, - }; - - Ok(self.offset) - } - } - // TODO: Perhaps this impl should be used in the rest of the scheme. - impl<'a, 'b> Read for Device<'a, 'b> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?; - let size_in_blocks = self.disk.size() / u64::from(blksize); - - let disk = &mut self.disk; - - let read_block = |block: u64, block_bytes: &mut [u8]| { - if block >= size_in_blocks { - return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); - } - loop { - match disk.read(block, block_bytes) { - Ok(Some(bytes)) => { - assert_eq!(bytes, block_bytes.len()); - assert_eq!(bytes, blksize as usize); - return Ok(()); - } - Ok(None) => { std::thread::yield_now(); continue } - Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), - } - } - }; - let bytes_read = block_io_wrapper::read(self.offset, blksize, buf, self.block_bytes, read_block)?; - - self.offset += bytes_read as u64; - Ok(bytes_read) - } - } - - let mut block_bytes = [0u8; 4096]; - - partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() - } - fn new(mut disk: Box) -> Self { - Self { - pt: Self::pt(&mut *disk), - disk, - } - } -} - -impl std::ops::Deref for DiskWrapper { - type Target = dyn Disk; - - fn deref(&self) -> &Self::Target { - &*self.disk - } -} -impl std::ops::DerefMut for DiskWrapper { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut *self.disk - } -} - pub struct DiskScheme { scheme_name: String, hba_mem: &'static mut HbaMem, diff --git a/storage/bcm2835-sdhcid/Cargo.toml b/storage/bcm2835-sdhcid/Cargo.toml index f9bce4ae2b..d92d58d3fa 100644 --- a/storage/bcm2835-sdhcid/Cargo.toml +++ b/storage/bcm2835-sdhcid/Cargo.toml @@ -8,8 +8,7 @@ edition = "2021" [dependencies] fdt = "0.1.5" redox_syscall = "0.4" -partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } -block-io-wrapper = { path = "../block-io-wrapper" } common = { path = "../../common" } +driver-block = { path = "../driver-block" } redox-daemon = "0.1" diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index f70e8cca4a..7a815a64e2 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -1,15 +1,15 @@ use std::{fs::File, io::{Read, Write}, process}; +use driver_block::Disk; use fdt::{Fdt, node::FdtNode}; use syscall::{Packet, SchemeBlockMut}; -use crate::sd::Disk; use crate::scheme::DiskScheme; mod sd; mod scheme; -#[cfg(target_os = "redox")] +#[cfg(target_os = "redox")] fn get_dtb() -> Vec { std::fs::read("kernel.dtb:").unwrap() } @@ -48,7 +48,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { }; println!("ioremap 0x{:08x} to 0x{:08x} 2222", reg.starting_address as usize, addr); let mut sdhci = sd::SdHostCtrl::new(addr); - unsafe { + unsafe { sdhci.init(); /* let mut buf1 = [0u32; 512]; diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs index fce64bb363..7f0e9f6e22 100644 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ b/storage/bcm2835-sdhcid/src/scheme.rs @@ -3,19 +3,14 @@ use std::{cmp, str}; use std::convert::{TryFrom}; use std::fmt::Write; use std::io::prelude::*; -use std::io::SeekFrom; -use std::io; use std::sync::{Arc, Mutex}; +use driver_block::{Disk, DiskWrapper}; use syscall::{ Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; -use crate::sd::Disk; - -use partitionlib::{LogicalBlockSize, PartitionTable}; - #[derive(Clone)] enum Handle { List(Vec, usize), // Dir contents buffer, position @@ -23,88 +18,6 @@ enum Handle { Partition(usize, u32, usize), // Disk index, partition index, position } -pub struct DiskWrapper { - disk: Box, - pt: Option, -} - -impl DiskWrapper { - fn pt(disk: &mut dyn Disk) -> Option { - let bs = match disk.block_length() { - Ok(512) => LogicalBlockSize::Lb512, - _ => return None, - }; - struct Device<'a, 'b> { disk: &'a mut dyn Disk, offset: u64, block_bytes: &'b mut [u8] } - - impl<'a, 'b> Seek for Device<'a, 'b> { - fn seek(&mut self, from: SeekFrom) -> io::Result { - let size = i64::try_from(self.disk.size()).or(Err(io::Error::new(io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes")))?; - - self.offset = match from { - SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos), - SeekFrom::Current(new_pos) => cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64, - SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64, - }; - - Ok(self.offset) - } - } - // TODO: Perhaps this impl should be used in the rest of the scheme. - impl<'a, 'b> Read for Device<'a, 'b> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?; - let size_in_blocks = self.disk.size() / u64::from(blksize); - - let disk = &mut self.disk; - - let read_block = |block: u64, block_bytes: &mut [u8]| { - if block >= size_in_blocks { - return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); - } - loop { - match disk.read(block, block_bytes) { - Ok(Some(bytes)) => { - assert_eq!(bytes, block_bytes.len()); - assert_eq!(bytes, blksize as usize); - return Ok(()); - } - Ok(None) => { std::thread::yield_now(); continue } - Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), - } - } - }; - let bytes_read = block_io_wrapper::read(self.offset, blksize, buf, self.block_bytes, read_block)?; - - self.offset += bytes_read as u64; - Ok(bytes_read) - } - } - - let mut block_bytes = [0u8; 4096]; - - partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() - } - fn new(mut disk: Box) -> Self { - Self { - pt: Self::pt(&mut *disk), - disk, - } - } -} - -impl std::ops::Deref for DiskWrapper { - type Target = dyn Disk; - - fn deref(&self) -> &Self::Target { - &*self.disk - } -} -impl std::ops::DerefMut for DiskWrapper { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut *self.disk - } -} - pub struct DiskScheme { scheme_name: String, disks: Box<[DiskWrapper]>, diff --git a/storage/bcm2835-sdhcid/src/sd/mod.rs b/storage/bcm2835-sdhcid/src/sd/mod.rs index be5c37df7b..ece800a329 100644 --- a/storage/bcm2835-sdhcid/src/sd/mod.rs +++ b/storage/bcm2835-sdhcid/src/sd/mod.rs @@ -1,6 +1,6 @@ use std::{sync::{Mutex, RwLock}, time::{self, Duration}, thread}; use syscall::{io::Mmio, Io, Error, Result, EINVAL}; -use core::ptr::{read_volatile, write_volatile}; +use driver_block::Disk; #[cfg(target_arch = "aarch64")] #[inline(always)] @@ -17,7 +17,7 @@ pub(crate) unsafe fn wait_cycles(mut n: usize) { #[inline(always)] pub(crate) unsafe fn wait_msec(mut n: usize) { use core::arch::asm; - + let mut f: usize; let mut t: usize; let mut r: usize; @@ -185,7 +185,7 @@ pub struct SdHostCtrl { impl SdHostCtrl { pub fn new(address: usize) -> Self { SdHostCtrl { - regs: RwLock::new(unsafe { &mut *(address as *mut SdHostCtrlRegs)}), + regs: RwLock::new(unsafe { &mut *(address as *mut SdHostCtrlRegs)}), host_spec_ver: 0, cid: [0; 4], csd: [0; 4], @@ -228,7 +228,7 @@ impl SdHostCtrl { return ; } } - + let regs = self.regs.get_mut().unwrap(); regs.irpt_en.write(0xffff_ffff); regs.irpt_mask.write(0xffff_ffff); @@ -518,7 +518,7 @@ impl SdHostCtrl { self.cid[1] = regs.resp1.read(); self.cid[2] = regs.resp2.read(); self.cid[3] = regs.resp3.read(); - + //FIXME: wrong implement, see CMD_SEND_CSD for detail return Ok(reg_val); } else if code == CMD_SEND_CSD { @@ -526,7 +526,7 @@ impl SdHostCtrl { let tmp1 = regs.resp1.read(); let tmp2 = regs.resp2.read(); let tmp3 = regs.resp3.read(); - + self.csd[0] = tmp3 << 8 | tmp2 >> 24; self.csd[1] = tmp2 << 8 | tmp1 >> 24; self.csd[2] = tmp1 << 8 | tmp0 >> 24; @@ -713,14 +713,6 @@ impl SdHostCtrl { } } -pub trait Disk { - fn id(&self) -> usize; - fn size(&mut self) -> u64; - fn read(&mut self, block:u64, buffer: &mut [u8]) -> syscall::error::Result>; - fn write(&mut self, block:u64, buffer: &[u8]) -> syscall::error::Result>; - fn block_length(&mut self) -> syscall::error::Result; -} - impl Disk for SdHostCtrl { fn id(&self) -> usize { 0xdead_dead diff --git a/storage/block-io-wrapper/.gitignore b/storage/block-io-wrapper/.gitignore deleted file mode 100644 index ea8c4bf7f3..0000000000 --- a/storage/block-io-wrapper/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/storage/block-io-wrapper/Cargo.toml b/storage/block-io-wrapper/Cargo.toml deleted file mode 100644 index b5de7fa458..0000000000 --- a/storage/block-io-wrapper/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "block-io-wrapper" -version = "0.1.0" -authors = ["4lDO2 <4lDO2@protonmail.com>"] -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/storage/block-io-wrapper/src/lib.rs b/storage/block-io-wrapper/src/lib.rs deleted file mode 100644 index bf56b788a0..0000000000 --- a/storage/block-io-wrapper/src/lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::cmp::min; -use std::io::Error; - -/// Split the read operation into a series of block reads. -/// `read_fn` will be called with a block number to be read, and a buffer to be filled. -/// The buffer must be large enough to hold `blksize` of data. -/// `read_fn` must return a full block of data. -/// Result will be the number of bytes read. -pub fn read( - offset: u64, - blksize: u32, - buf: &mut [u8], - block_bytes: &mut [u8], - mut read_fn: impl FnMut(u64, &mut [u8]) -> Result<(), Error>, -) -> Result { - // TODO: Yield sometimes, perhaps after a few blocks or something. - - if buf.len() == 0 { - return Ok(0); - } - let to_copy = usize::try_from( - offset.saturating_add(u64::try_from(buf.len()).expect("buf.len() larger than u64")) - - offset, - ) - .expect("bytes to copy larger than usize"); - let mut curr_buf = &mut buf[..to_copy]; - let mut curr_offset = offset; - let blk_size = usize::try_from(blksize).expect("blksize larger than usize"); - let mut total_read = 0; - - while curr_buf.len() > 0 { - // TODO: Async/await? I mean, shouldn't AHCI be async? - - let blk_offset = - usize::try_from(curr_offset % u64::from(blksize)).expect("usize smaller than blksize"); - let to_copy = min(curr_buf.len(), blk_size - blk_offset); - assert!(blk_offset + to_copy <= blk_size); - - read_fn(curr_offset / u64::from(blksize), block_bytes)?; - - let src_buf = &block_bytes[blk_offset..]; - - curr_buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); - curr_buf = &mut curr_buf[to_copy..]; - curr_offset += u64::try_from(to_copy).expect("bytes to copy larger than u64"); - total_read += to_copy; - } - Ok(total_read) -} diff --git a/storage/driver-block/Cargo.toml b/storage/driver-block/Cargo.toml new file mode 100644 index 0000000000..710b5efd5d --- /dev/null +++ b/storage/driver-block/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "driver-block" +version = "0.1.0" +edition = "2021" + +[dependencies] +partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } + +redox_syscall = "0.4" diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs new file mode 100644 index 0000000000..e9ac6c5dc0 --- /dev/null +++ b/storage/driver-block/src/lib.rs @@ -0,0 +1,175 @@ +use std::cmp; +use std::io::Error; +use std::io::{self, Read, Seek, SeekFrom}; + +use partitionlib::{LogicalBlockSize, PartitionTable}; + +/// Split the read operation into a series of block reads. +/// `read_fn` will be called with a block number to be read, and a buffer to be filled. +/// The buffer must be large enough to hold `blksize` of data. +/// `read_fn` must return a full block of data. +/// Result will be the number of bytes read. +// FIXME make private once nvmed uses the DiskWrapper defined in this crate +pub fn block_read( + offset: u64, + blksize: u32, + buf: &mut [u8], + block_bytes: &mut [u8], + mut read_fn: impl FnMut(u64, &mut [u8]) -> Result<(), Error>, +) -> Result { + // TODO: Yield sometimes, perhaps after a few blocks or something. + + if buf.len() == 0 { + return Ok(0); + } + let to_copy = usize::try_from( + offset.saturating_add(u64::try_from(buf.len()).expect("buf.len() larger than u64")) + - offset, + ) + .expect("bytes to copy larger than usize"); + let mut curr_buf = &mut buf[..to_copy]; + let mut curr_offset = offset; + let blk_size = usize::try_from(blksize).expect("blksize larger than usize"); + let mut total_read = 0; + + while curr_buf.len() > 0 { + // TODO: Async/await? I mean, shouldn't AHCI be async? + + let blk_offset = + usize::try_from(curr_offset % u64::from(blksize)).expect("usize smaller than blksize"); + let to_copy = cmp::min(curr_buf.len(), blk_size - blk_offset); + assert!(blk_offset + to_copy <= blk_size); + + read_fn(curr_offset / u64::from(blksize), block_bytes)?; + + let src_buf = &block_bytes[blk_offset..]; + + curr_buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); + curr_buf = &mut curr_buf[to_copy..]; + curr_offset += u64::try_from(to_copy).expect("bytes to copy larger than u64"); + total_read += to_copy; + } + Ok(total_read) +} + +pub trait Disk { + fn id(&self) -> usize; + fn block_length(&mut self) -> syscall::error::Result; + fn size(&mut self) -> u64; + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result>; + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result>; +} + +pub struct DiskWrapper { + pub disk: Box, + pub pt: Option, +} + +impl DiskWrapper { + fn pt(disk: &mut dyn Disk) -> Option { + let bs = match disk.block_length() { + Ok(512) => LogicalBlockSize::Lb512, + _ => return None, + }; + struct Device<'a, 'b> { + disk: &'a mut dyn Disk, + offset: u64, + block_bytes: &'b mut [u8], + } + + impl<'a, 'b> Seek for Device<'a, 'b> { + fn seek(&mut self, from: SeekFrom) -> io::Result { + let size = i64::try_from(self.disk.size()).or(Err(io::Error::new( + io::ErrorKind::Other, + "Disk larger than 2^63 - 1 bytes", + )))?; + + self.offset = match from { + SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos), + SeekFrom::Current(new_pos) => { + cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64 + } + SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64, + }; + + Ok(self.offset) + } + } + // TODO: Perhaps this impl should be used in the rest of the scheme. + impl<'a, 'b> Read for Device<'a, 'b> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let blksize = self + .disk + .block_length() + .map_err(|err| io::Error::from_raw_os_error(err.errno))?; + let size_in_blocks = self.disk.size() / u64::from(blksize); + + let disk = &mut self.disk; + + let read_block = |block: u64, block_bytes: &mut [u8]| { + if block >= size_in_blocks { + return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); + } + loop { + match disk.read(block, block_bytes) { + Ok(Some(bytes)) => { + assert_eq!(bytes, block_bytes.len()); + assert_eq!(bytes, blksize as usize); + return Ok(()); + } + Ok(None) => { + std::thread::yield_now(); + continue; + } + Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), + } + } + }; + let bytes_read = block_read( + self.offset, + blksize, + buf, + self.block_bytes, + read_block, + )?; + + self.offset += bytes_read as u64; + Ok(bytes_read) + } + } + + let mut block_bytes = [0u8; 4096]; + + partitionlib::get_partitions( + &mut Device { + disk, + offset: 0, + block_bytes: &mut block_bytes[..bs.into()], + }, + bs, + ) + .ok() + .flatten() + } + + pub fn new(mut disk: Box) -> Self { + Self { + pt: Self::pt(&mut *disk), + disk, + } + } +} + +impl std::ops::Deref for DiskWrapper { + type Target = dyn Disk; + + fn deref(&self) -> &Self::Target { + &*self.disk + } +} +impl std::ops::DerefMut for DiskWrapper { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut *self.disk + } +} diff --git a/storage/ided/Cargo.toml b/storage/ided/Cargo.toml index c580881d9e..1df0416b7b 100644 --- a/storage/ided/Cargo.toml +++ b/storage/ided/Cargo.toml @@ -4,10 +4,9 @@ version = "0.1.0" edition = "2018" [dependencies] -block-io-wrapper = { path = "../block-io-wrapper" } common = { path = "../../common" } +driver-block = { path = "../driver-block" } log = "0.4" -partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } pcid = { path = "../../pcid" } redox-daemon = "0.1" redox-log = "0.1" diff --git a/storage/ided/src/ide.rs b/storage/ided/src/ide.rs index 259997ab7d..8428d92b60 100644 --- a/storage/ided/src/ide.rs +++ b/storage/ided/src/ide.rs @@ -5,6 +5,7 @@ use std::{ time::{Duration, Instant}, }; +use driver_block::Disk; use syscall::{ error::{Error, Result, EIO}, io::{Io, Pio, ReadOnly, WriteOnly}, @@ -153,14 +154,6 @@ impl Channel { } } -pub trait Disk { - fn id(&self) -> usize; - fn size(&mut self) -> u64; - fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result>; - fn write(&mut self, block: u64, buffer: &[u8]) -> Result>; - fn block_length(&mut self) -> Result; -} - pub struct AtaDisk { pub chan: Arc>, pub chan_i: usize, diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index bf176e4986..ca27ab7e60 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -1,3 +1,4 @@ +use driver_block::Disk; use log::{error, info}; use pcid_interface::{PciBar, PcidServerHandle}; use redox_log::{OutputBuilder, RedoxLogger}; @@ -18,7 +19,7 @@ use syscall::{ }; use crate::{ - ide::{AtaCommand, AtaDisk, Channel, Disk}, + ide::{AtaCommand, AtaDisk, Channel}, scheme::DiskScheme, }; diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs index a5fe20b309..31032d4a9a 100644 --- a/storage/ided/src/scheme.rs +++ b/storage/ided/src/scheme.rs @@ -3,18 +3,15 @@ use std::{cmp, str}; use std::convert::{TryFrom}; use std::fmt::Write; use std::io::prelude::*; -use std::io::SeekFrom; -use std::io; use std::sync::{Arc, Mutex}; +use driver_block::{Disk, DiskWrapper}; use syscall::{ Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; -use crate::ide::{Channel, Disk}; - -use partitionlib::{LogicalBlockSize, PartitionTable}; +use crate::ide::Channel; #[derive(Clone)] enum Handle { @@ -23,89 +20,6 @@ enum Handle { Partition(usize, u32, usize), // Disk index, partition index, position } -pub struct DiskWrapper { - disk: Box, - pt: Option, -} - -impl DiskWrapper { - fn pt(disk: &mut dyn Disk) -> Option { - let bs = match disk.block_length() { - Ok(512) => LogicalBlockSize::Lb512, - Ok(4096) => LogicalBlockSize::Lb4096, - _ => return None, - }; - struct Device<'a, 'b> { disk: &'a mut dyn Disk, offset: u64, block_bytes: &'b mut [u8] } - - impl<'a, 'b> Seek for Device<'a, 'b> { - fn seek(&mut self, from: SeekFrom) -> io::Result { - let size = i64::try_from(self.disk.size()).or(Err(io::Error::new(io::ErrorKind::Other, "Disk larger than 2^63 - 1 bytes")))?; - - self.offset = match from { - SeekFrom::Start(new_pos) => cmp::min(self.disk.size(), new_pos), - SeekFrom::Current(new_pos) => cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64, - SeekFrom::End(new_pos) => cmp::max(0, cmp::min(size + new_pos, size)) as u64, - }; - - Ok(self.offset) - } - } - // TODO: Perhaps this impl should be used in the rest of the scheme. - impl<'a, 'b> Read for Device<'a, 'b> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let blksize = self.disk.block_length().map_err(|err| io::Error::from_raw_os_error(err.errno))?; - let size_in_blocks = self.disk.size() / u64::from(blksize); - - let disk = &mut self.disk; - - let read_block = |block: u64, block_bytes: &mut [u8]| { - if block >= size_in_blocks { - return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); - } - loop { - match disk.read(block, block_bytes) { - Ok(Some(bytes)) => { - assert_eq!(bytes, block_bytes.len()); - assert_eq!(bytes, blksize as usize); - return Ok(()); - } - Ok(None) => { std::thread::yield_now(); continue } - Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), - } - } - }; - let bytes_read = block_io_wrapper::read(self.offset, blksize, buf, self.block_bytes, read_block)?; - - self.offset += bytes_read as u64; - Ok(bytes_read) - } - } - - let mut block_bytes = [0u8; 4096]; - - partitionlib::get_partitions(&mut Device { disk, offset: 0, block_bytes: &mut block_bytes[..bs.into()] }, bs).ok().flatten() - } - fn new(mut disk: Box) -> Self { - Self { - pt: Self::pt(&mut *disk), - disk, - } - } -} - -impl std::ops::Deref for DiskWrapper { - type Target = dyn Disk; - - fn deref(&self) -> &Self::Target { - &*self.disk - } -} -impl std::ops::DerefMut for DiskWrapper { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut *self.disk - } -} - pub struct DiskScheme { scheme_name: String, chans: Box<[Arc>]>, diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index ce52f43752..59c9c36935 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -15,8 +15,8 @@ redox_syscall = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } smallvec = "1" -block-io-wrapper = { path = "../block-io-wrapper" } common = { path = "../../common" } +driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } [features] diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 654044aba0..638b426ae4 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -96,7 +96,7 @@ impl DiskWrapper { } } }; - let bytes_read = block_io_wrapper::read( + let bytes_read = driver_block::block_read( self.offset, blksize .try_into() diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index c9ec28ced1..690454263d 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -17,7 +17,7 @@ redox-log = "0.1" redox_syscall = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } -block-io-wrapper = { path = "../block-io-wrapper" } common = { path = "../../common" } +driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } virtio-core = { path = "../../virtio-core" } diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index a92f084444..e981de0369 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -148,7 +148,7 @@ impl<'a> DiskScheme<'a> { }; let bytes_read = - block_io_wrapper::read(self.offset, 512, buf, self.block_bytes, read_block) + driver_block::block_read(self.offset, 512, buf, self.block_bytes, read_block) .unwrap(); self.offset += bytes_read as u64; Ok(bytes_read) From 15c8ab233170f1645c2c98cbed865ef0135ef648 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 17 Mar 2024 14:23:44 +0100 Subject: [PATCH 0833/1301] Search for PCI ECAM in the device tree on ARM --- Cargo.lock | 11 ++- pcid/Cargo.toml | 1 + pcid/src/cfg_access/mod.rs | 193 +++++++++++++++++++++++++++---------- 3 files changed, 155 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f95e8e00f6..29c7c216d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -150,7 +150,7 @@ version = "0.1.0" dependencies = [ "common", "driver-block", - "fdt", + "fdt 0.1.5", "redox-daemon", "redox_syscall 0.4.1", ] @@ -391,6 +391,14 @@ dependencies = [ "redox_syscall 0.4.1", ] +[[package]] +name = "fdt" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/rosehuds/fdt.git#7358607679114ccab5f97e14894ed3b59c5d42d6" +dependencies = [ + "byteorder", +] + [[package]] name = "fdt" version = "0.1.5" @@ -907,6 +915,7 @@ dependencies = [ "bitflags 1.3.2", "byteorder", "common", + "fdt 0.1.0", "libc", "log", "paw", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index b883b4e8ce..a4ae567e9d 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -16,6 +16,7 @@ bincode = "1.2" bitflags = "1" bit_field = "0.10" byteorder = "1.2" +fdt = { git = "https://gitlab.redox-os.org/rosehuds/fdt.git" } libc = "0.2" log = "0.4" paw = "1.0" diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index e3f0d4ed91..8e0803339b 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -1,13 +1,94 @@ use std::sync::Mutex; -use std::{fmt, fs, io, mem, ptr}; +use std::{fs, io, mem}; use common::{MemoryType, PhysBorrowed, Prot}; +use fdt::{DeviceTree, Node}; use pci_types::{ConfigRegionAccess, PciAddress}; use fallback::Pci; mod fallback; +pub fn root_cell_sz(dt: &fdt::DeviceTree) -> Option<(u32, u32)> { + let root_node = dt.nodes().nth(0).unwrap(); + let address_cells = root_node + .properties() + .find(|p| p.name.contains("#address-cells")) + .unwrap(); + let size_cells = root_node + .properties() + .find(|p| p.name.contains("#size-cells")) + .unwrap(); + + Some(( + u32::from_be_bytes(<[u8; 4]>::try_from(address_cells.data).unwrap()), + u32::from_be_bytes(<[u8; 4]>::try_from(size_cells.data).unwrap()), + )) +} + +pub fn find_compatible_fdt_node<'a>( + dt: &'a fdt::DeviceTree<'a>, + compat_string: &str, +) -> Option> { + for node in dt.nodes() { + if let Some(compatible) = node.properties().find(|p| p.name.contains("compatible")) { + let s = core::str::from_utf8(compatible.data).unwrap(); + if s.contains(compat_string) { + return Some(node); + } + } + } + None +} + +// https://elinux.org/Device_Tree_Usage has a lot of useful information +fn locate_ecam_dtb(f: impl FnOnce(PcieAllocs<'_>) -> io::Result) -> io::Result { + let dtb = fs::read("kernel.dtb:")?; + let dt = DeviceTree::new(&dtb).map_err(|err| { + io::Error::new( + io::ErrorKind::InvalidData, + format!("invalid device tree: {err:?}"), + ) + })?; + + let node = find_compatible_fdt_node(&dt, "pci-host-ecam-generic").ok_or_else(|| { + io::Error::new( + io::ErrorKind::NotFound, + "couldn't find pci-host-ecam-generic node in device tree", + ) + })?; + + let (address_cells, size_cells) = root_cell_sz(&dt).unwrap(); + let reg = node.properties().find(|p| p.name.contains("reg")).unwrap(); + assert_eq!(reg.data.len(), ((address_cells + size_cells) * 4) as usize); + + let address = if address_cells == 1 { + u32::from_be_bytes(<[u8; 4]>::try_from(®.data[0..4]).unwrap()).into() + } else if address_cells == 2 { + u64::from_be_bytes(<[u8; 8]>::try_from(®.data[0..8]).unwrap()) + } else { + panic!(); + }; + + let bus_range = node + .properties() + .find(|p| p.name.contains("bus-range")) + .unwrap(); + assert_eq!(bus_range.data.len(), 8); + let start_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.data[0..4]).unwrap()); + let end_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.data[4..8]).unwrap()); + + // FIXME respect the BAR remappings in the ranges property + + f(PcieAllocs(&[PcieAlloc { + base_addr: address, + seg_group_num: 0, + start_bus: start_bus.try_into().unwrap(), + end_bus: end_bus.try_into().unwrap(), + _rsvd: [0; 4], + }])) +} + pub const MCFG_NAME: [u8; 4] = *b"MCFG"; #[repr(packed)] @@ -44,7 +125,7 @@ unsafe impl plain::Plain for PcieAlloc {} struct PcieAllocs<'a>(&'a [PcieAlloc]); impl Mcfg { - fn with(f: impl FnOnce(&Mcfg, PcieAllocs<'_>) -> io::Result) -> io::Result { + fn with(f: impl FnOnce(PcieAllocs<'_>) -> io::Result) -> io::Result { let table_dir = fs::read_dir("acpi:tables")?; // TODO: validate/print MCFG? @@ -62,7 +143,10 @@ impl Mcfg { if table_filename.get(0..4) == Some(&MCFG_NAME) { let bytes = fs::read(table_path)?.into_boxed_slice(); match Mcfg::parse(&*bytes) { - Some((mcfg, allocs)) => return f(mcfg, allocs), + Some((mcfg, allocs)) => { + log::info!("MCFG {mcfg:?} ALLOCS {allocs:?}"); + return f(allocs); + } None => { return Err(io::Error::new( io::ErrorKind::InvalidData, @@ -121,56 +205,67 @@ const BYTES_PER_BUS: usize = 1 << 20; impl Pcie { pub fn new() -> Self { - match Mcfg::with(|mcfg, allocs| { - log::info!("MCFG {mcfg:?} ALLOCS {allocs:?}"); - let mut allocs = allocs - .0 - .iter() - .filter_map(|desc| { - Some(Alloc { - seg: desc.seg_group_num, - start_bus: desc.start_bus, - end_bus: desc.end_bus, - mem: PhysBorrowed::map( - desc.base_addr.try_into().ok()?, - BYTES_PER_BUS - * (usize::from(desc.end_bus) - usize::from(desc.start_bus) + 1), - Prot::RW, - MemoryType::Uncacheable, - ) - .inspect_err(|err| { - log::error!( - "failed to map seg {} bus {}..={}: {}", - { desc.seg_group_num }, - { desc.start_bus }, - { desc.end_bus }, - err - ) - }) - .ok()?, - }) - }) - .collect::>(); - - allocs.sort_by_key(|alloc| (alloc.seg, alloc.start_bus)); - - Ok(Self { - lock: Mutex::new(()), - allocs, - fallback: Pci::new(), - }) - }) { + match Mcfg::with(Self::from_allocs) { Ok(pcie) => pcie, - Err(error) => { - log::warn!("Couldn't retrieve PCIe info, perhaps the kernel is not compiled with acpi? Using the PCI 3.0 configuration space instead. Error: {:?}", error); - Self { - lock: Mutex::new(()), - allocs: Vec::new(), - fallback: Pci::new(), + Err(acpi_error) => match locate_ecam_dtb(Self::from_allocs) { + Ok(pcie) => pcie, + Err(fdt_error) => { + log::warn!( + "Couldn't retrieve PCIe info, perhaps the kernel is not compiled with \ + acpi or device tree support? Using the PCI 3.0 configuration space \ + instead. ACPI error: {:?} FDT error: {:?}", + acpi_error, + fdt_error + ); + Self { + lock: Mutex::new(()), + allocs: Vec::new(), + fallback: Pci::new(), + } } - } + }, } } + + fn from_allocs(allocs: PcieAllocs<'_>) -> Result { + let mut allocs = allocs + .0 + .iter() + .filter_map(|desc| { + Some(Alloc { + seg: desc.seg_group_num, + start_bus: desc.start_bus, + end_bus: desc.end_bus, + mem: PhysBorrowed::map( + desc.base_addr.try_into().ok()?, + BYTES_PER_BUS + * (usize::from(desc.end_bus) - usize::from(desc.start_bus) + 1), + Prot::RW, + MemoryType::Uncacheable, + ) + .inspect_err(|err| { + log::error!( + "failed to map seg {} bus {}..={}: {}", + { desc.seg_group_num }, + { desc.start_bus }, + { desc.end_bus }, + err + ) + }) + .ok()?, + }) + }) + .collect::>(); + + allocs.sort_by_key(|alloc| (alloc.seg, alloc.start_bus)); + + Ok(Self { + lock: Mutex::new(()), + allocs, + fallback: Pci::new(), + }) + } + fn bus_addr(&self, seg: u16, bus: u8) -> Option<*mut u32> { let alloc = match self .allocs From 5286f453115145346fb9fc476c216235f1113473 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 17 Mar 2024 21:03:17 +0100 Subject: [PATCH 0834/1301] Fix potential race in nvmed Previously it was possible to submit commands before the event queue is created by the irq handler thread. --- storage/nvmed/src/nvme/cq_reactor.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/storage/nvmed/src/nvme/cq_reactor.rs b/storage/nvmed/src/nvme/cq_reactor.rs index 5926684974..ccadb14941 100644 --- a/storage/nvmed/src/nvme/cq_reactor.rs +++ b/storage/nvmed/src/nvme/cq_reactor.rs @@ -271,11 +271,9 @@ pub fn start_cq_reactor_thread( // subsystem can have some room for improvement regarding lowering the latency, but MSI-X allows // multiple vectors to point to different CPUs, so that the load can be balanced across the // logical processors. - thread::spawn(move || { - CqReactor::new(nvme, interrupt_sources, receiver) - .expect("nvmed: failed to setup CQ reactor") - .run() - }) + let reactor = CqReactor::new(nvme, interrupt_sources, receiver) + .expect("nvmed: failed to setup CQ reactor"); + thread::spawn(move || reactor.run()) } #[derive(Debug)] From 2e7dbf1cc1141858cdf91561883570d1dcb949ef Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 18 Mar 2024 19:23:05 +0100 Subject: [PATCH 0835/1301] Switch to libredox where applicable. --- Cargo.lock | 82 ++++++++++++++++++++++------ acpid/Cargo.toml | 1 + acpid/src/acpi.rs | 2 +- acpid/src/acpi/dmar/drhd.rs | 2 +- acpid/src/aml_physmem.rs | 4 +- acpid/src/main.rs | 6 +- audio/ac97d/Cargo.toml | 3 +- audio/ac97d/src/main.rs | 9 +-- audio/ihdad/Cargo.toml | 1 + audio/ihdad/src/main.rs | 5 +- audio/pcspkrd/Cargo.toml | 1 + audio/pcspkrd/src/main.rs | 2 +- audio/sb16d/Cargo.toml | 1 + audio/sb16d/src/main.rs | 9 ++- common/Cargo.toml | 3 +- common/src/dma.rs | 46 +++++++--------- common/src/lib.rs | 46 +++++++++------- graphics/bgad/Cargo.toml | 1 + graphics/bgad/src/main.rs | 2 +- graphics/fbcond/Cargo.toml | 1 + graphics/fbcond/src/display.rs | 28 +++++----- graphics/fbcond/src/main.rs | 2 +- graphics/fbcond/src/text.rs | 2 +- graphics/vesad/Cargo.toml | 1 + graphics/vesad/src/main.rs | 2 +- graphics/vesad/src/scheme.rs | 2 +- graphics/virtio-gpud/Cargo.toml | 1 + inputd/Cargo.toml | 5 +- inputd/src/lib.rs | 4 +- inputd/src/main.rs | 2 +- net/alxd/Cargo.toml | 3 +- net/alxd/src/device/mod.rs | 4 +- net/alxd/src/main.rs | 7 ++- net/driver-network/Cargo.toml | 3 +- net/driver-network/src/lib.rs | 6 +- net/e1000d/Cargo.toml | 3 +- net/e1000d/src/device.rs | 2 +- net/e1000d/src/main.rs | 4 +- net/ixgbed/Cargo.toml | 3 +- net/ixgbed/src/device.rs | 4 +- net/ixgbed/src/main.rs | 4 +- net/rtl8139d/Cargo.toml | 3 +- net/rtl8139d/src/device.rs | 4 +- net/rtl8139d/src/main.rs | 4 +- net/rtl8168d/Cargo.toml | 3 +- net/rtl8168d/src/device.rs | 6 +- net/rtl8168d/src/main.rs | 4 +- net/virtio-netd/Cargo.toml | 3 +- net/virtio-netd/src/main.rs | 2 +- pcid/Cargo.toml | 1 + pcid/src/cfg_access/fallback.rs | 4 +- ps2d/Cargo.toml | 1 + ps2d/src/main.rs | 2 +- storage/ahcid/Cargo.toml | 1 + storage/ahcid/src/main.rs | 12 ++-- storage/bcm2835-sdhcid/Cargo.toml | 1 + storage/bcm2835-sdhcid/src/main.rs | 2 +- storage/ided/Cargo.toml | 1 + storage/ided/src/main.rs | 20 ++++--- storage/lived/Cargo.toml | 1 + storage/lived/src/main.rs | 14 +++-- storage/nvmed/Cargo.toml | 1 + storage/nvmed/src/main.rs | 12 ++-- storage/nvmed/src/nvme/cq_reactor.rs | 4 +- storage/usbscsid/Cargo.toml | 1 + storage/usbscsid/src/main.rs | 5 +- storage/virtio-blkd/Cargo.toml | 1 + storage/virtio-blkd/src/main.rs | 6 +- vboxd/Cargo.toml | 3 +- vboxd/src/main.rs | 9 ++- virtio-core/Cargo.toml | 1 + virtio-core/src/arch/x86.rs | 2 +- virtio-core/src/arch/x86_64.rs | 2 +- virtio-core/src/transport.rs | 8 +-- xhcid/Cargo.toml | 5 +- xhcid/src/main.rs | 65 ++++++++++------------ xhcid/src/xhci/context.rs | 2 +- xhcid/src/xhci/irq_reactor.rs | 18 +++--- xhcid/src/xhci/mod.rs | 8 +-- 79 files changed, 323 insertions(+), 238 deletions(-) mode change 100755 => 100644 audio/ihdad/Cargo.toml diff --git a/Cargo.lock b/Cargo.lock index 29c7c216d7..a049a93f31 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,12 +8,13 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "spin", ] @@ -24,6 +25,7 @@ dependencies = [ "aml", "amlserde", "common", + "libredox 0.1.3", "log", "num-derive", "num-traits", @@ -45,6 +47,7 @@ dependencies = [ "byteorder", "common", "driver-block", + "libredox 0.1.3", "log", "pcid", "redox-daemon", @@ -58,9 +61,10 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "libredox 0.1.3", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -151,6 +155,7 @@ dependencies = [ "common", "driver-block", "fdt 0.1.5", + "libredox 0.1.3", "redox-daemon", "redox_syscall 0.4.1", ] @@ -159,6 +164,7 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ + "libredox 0.1.3", "orbclient", "pcid", "redox-daemon", @@ -280,7 +286,8 @@ dependencies = [ name = "common" version = "0.1.0" dependencies = [ - "redox_syscall 0.4.1", + "libredox 0.1.3", + "redox_syscall 0.5.1", ] [[package]] @@ -356,8 +363,9 @@ dependencies = [ name = "driver-network" version = "0.1.0" dependencies = [ + "libredox 0.1.3", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -367,10 +375,11 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", + "libredox 0.1.3", "pcid", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -384,6 +393,7 @@ name = "fbcond" version = "0.1.0" dependencies = [ "inputd", + "libredox 0.1.3", "orbclient", "ransid", "redox-daemon", @@ -582,6 +592,7 @@ version = "0.1.0" dependencies = [ "common", "driver-block", + "libredox 0.1.3", "log", "pcid", "redox-daemon", @@ -595,6 +606,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "libredox 0.1.3", "log", "pcid", "redox-daemon", @@ -619,11 +631,12 @@ name = "inputd" version = "0.1.0" dependencies = [ "anyhow", + "libredox 0.1.3", "log", "orbclient", "redox-daemon", "redox-log", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "spin", ] @@ -649,10 +662,11 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", + "libredox 0.1.3", "pcid", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -689,12 +703,13 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.0" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138adbe77ccf68e1925b6ed3cc45e83a6845f17a687d6061ddeb518e9b756440" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.4.2", "libc", + "redox_syscall 0.5.1", ] [[package]] @@ -702,6 +717,7 @@ name = "lived" version = "0.1.0" dependencies = [ "anyhow", + "libredox 0.1.3", "redox-daemon", "redox_syscall 0.4.1", "slab", @@ -771,6 +787,7 @@ dependencies = [ "crossbeam-channel", "driver-block", "futures", + "libredox 0.1.3", "log", "partitionlib", "pcid", @@ -917,6 +934,7 @@ dependencies = [ "common", "fdt 0.1.0", "libc", + "libredox 0.1.3", "log", "paw", "pci_types", @@ -934,6 +952,7 @@ dependencies = [ name = "pcspkrd" version = "0.1.0" dependencies = [ + "libredox 0.1.3", "redox-daemon", "redox_syscall 0.4.1", ] @@ -994,6 +1013,7 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 1.3.2", + "libredox 0.1.3", "orbclient", "redox-daemon", "redox_syscall 0.4.1", @@ -1067,7 +1087,7 @@ version = "0.1.3" source = "git+https://gitlab.redox-os.org/redox-os/redox-daemon.git#31ab115cf17d6fe333515bfe19ac477352a1dcc0" dependencies = [ "libc", - "libredox 0.1.0", + "libredox 0.1.3", ] [[package]] @@ -1101,6 +1121,16 @@ dependencies = [ "redox_syscall 0.4.1", ] +[[package]] +name = "redox_event" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69609faa5d5992247a4ef379917bb3e39be281405d6a0ccd4f942429400b956f" +dependencies = [ + "bitflags 2.4.2", + "libredox 0.1.3", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -1128,6 +1158,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.4.2", +] + [[package]] name = "redox_termios" version = "0.1.2" @@ -1144,12 +1183,13 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", + "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -1159,12 +1199,13 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", + "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -1185,6 +1226,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "libredox 0.1.3", "log", "redox-daemon", "redox-log", @@ -1526,6 +1568,7 @@ name = "usbscsid" version = "0.1.0" dependencies = [ "base64", + "libredox 0.1.3", "plain", "redox-daemon", "redox_syscall 0.4.1", @@ -1559,11 +1602,12 @@ name = "vboxd" version = "0.1.0" dependencies = [ "common", + "libredox 0.1.3", "orbclient", "pcid", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -1590,6 +1634,7 @@ version = "0.1.0" dependencies = [ "common", "inputd", + "libredox 0.1.3", "orbclient", "ransid", "redox-daemon", @@ -1604,6 +1649,7 @@ dependencies = [ "common", "driver-block", "futures", + "libredox 0.1.3", "log", "partitionlib", "pcid", @@ -1624,6 +1670,7 @@ dependencies = [ "common", "crossbeam-queue", "futures", + "libredox 0.1.3", "log", "pcid", "redox-log", @@ -1641,6 +1688,7 @@ dependencies = [ "common", "futures", "inputd", + "libredox 0.1.3", "log", "orbclient", "paste", @@ -1659,10 +1707,11 @@ dependencies = [ "common", "driver-network", "futures", + "libredox 0.1.3", "log", "pcid", "redox-daemon", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "static_assertions", "virtio-core", ] @@ -1852,13 +1901,14 @@ dependencies = [ "crossbeam-channel", "futures", "lazy_static", + "libredox 0.1.3", "log", "pcid", "plain", "redox-daemon", "redox-log", - "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_event 0.4.1", + "redox_syscall 0.5.1", "serde", "serde_json", "smallvec 1.11.0", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 92a6e8027d..23db6931f5 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -22,3 +22,4 @@ serde_json = "1.0.94" amlserde = { path = "../amlserde" } common = { path = "../common" } +libredox = "0.1.3" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 9bd620ef6d..6f73bab115 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -124,7 +124,7 @@ impl Deref for PhysmapGuard { impl Drop for PhysmapGuard { fn drop(&mut self) { unsafe { - let _ = syscall::funmap(self.virt as usize, self.size); + let _ = libredox::call::munmap(self.virt as *mut (), self.size); } } } diff --git a/acpid/src/acpi/dmar/drhd.rs b/acpid/src/acpi/dmar/drhd.rs index 091f553e95..70c8f8b42b 100644 --- a/acpid/src/acpi/dmar/drhd.rs +++ b/acpid/src/acpi/dmar/drhd.rs @@ -35,7 +35,7 @@ impl DerefMut for DrhdPage { impl Drop for DrhdPage { fn drop(&mut self) { unsafe { - let _ = syscall::funmap(self.virt as usize, crate::acpi::PAGE_SIZE); + let _ = libredox::call::munmap(self.virt.cast(), crate::acpi::PAGE_SIZE); } } } diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 98d78f1910..6658de3ee7 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -29,7 +29,7 @@ impl MappedPage { impl Drop for MappedPage { fn drop(&mut self) { log::trace!("Drop page {:#x}", self.phys_page); - if let Err(e) = unsafe { syscall::funmap(self.virt_page, PAGE_SIZE) } { + if let Err(e) = unsafe { libredox::call::munmap(self.virt_page as *mut (), PAGE_SIZE) } { log::error!("funmap (phys): {:?}", e); } } @@ -212,7 +212,7 @@ impl aml::Handler for AmlPhysMemHandler { } } - // Pio must be enabled via syscall::iopl(3) + // Pio must be enabled via syscall::iopl fn read_io_u8(&self, port: u16) -> u8 { Pio::::new(port).read() } diff --git a/acpid/src/main.rs b/acpid/src/main.rs index e4c8711045..93c54f9558 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -113,8 +113,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let acpi_context = self::acpi::AcpiContext::init(physaddrs_iter); - // TODO: I/O permission bitmap - unsafe { syscall::iopl(3) }.expect("acpid: failed to set I/O privilege level to Ring 3"); + // TODO: I/O permission bitmap? + common::acquire_port_io_rights().expect("acpid: failed to set I/O privilege level to Ring 3"); let shutdown_pipe = File::open("kernel.acpi:kstop") .expect("acpid: failed to open `kernel.acpi:kstop`"); @@ -136,7 +136,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("acpid: failed to notify parent"); - syscall::setrens(0, 0).expect("acpid: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace"); let _ = event_queue.write(&Event { id: shutdown_pipe.as_raw_fd() as usize, diff --git a/audio/ac97d/Cargo.toml b/audio/ac97d/Cargo.toml index 4d780d5d99..50b781cfca 100644 --- a/audio/ac97d/Cargo.toml +++ b/audio/ac97d/Cargo.toml @@ -10,7 +10,8 @@ log = "0.4" redox-daemon = "0.1" redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" spin = "0.9" pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index 2a26dc193b..8649e671d6 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -13,6 +13,7 @@ use std::sync::Arc; use std::usize; use event::EventQueue; +use libredox::flag; use pcid_interface::{PciBar, PcidServerHandle}; use redox_log::{OutputBuilder, RedoxLogger}; use syscall::{EventFlags, Packet, SchemeBlockMut}; @@ -84,19 +85,19 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let _logger_ref = setup_logging(); - unsafe { syscall::iopl(3) }.expect("ac97d: failed to set I/O privilege level to Ring 3"); + common::acquire_port_io_rights().expect("ac97d: failed to set I/O privilege level to Ring 3"); let mut irq_file = irq.irq_handle("ac97d"); let device = Arc::new(RefCell::new(unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") })); - let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ac97d: failed to create hda scheme"); + let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ac97d: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); daemon.ready().expect("ac97d: failed to signal readiness"); let mut event_queue = EventQueue::::new().expect("ac97d: Could not create event queue."); - syscall::setrens(0, 0).expect("ac97d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("ac97d: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -167,7 +168,7 @@ fn main() { for event_count in event_queue.trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }).expect("ac97d: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, diff --git a/audio/ihdad/Cargo.toml b/audio/ihdad/Cargo.toml old mode 100755 new mode 100644 index 32f294d95a..736e98d31e --- a/audio/ihdad/Cargo.toml +++ b/audio/ihdad/Cargo.toml @@ -14,3 +14,4 @@ spin = "0.9" common = { path = "../../common" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 7eeba58e2a..bb29a49007 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -10,6 +10,7 @@ use std::usize; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use libredox::flag; use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; @@ -162,13 +163,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { | (pci_config.func.full_device_id.device_id as u32); let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); - let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ihdad: failed to create hda scheme"); + let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ihdad: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); daemon.ready().expect("ihdad: failed to signal readiness"); let mut event_queue = EventQueue::::new().expect("ihdad: Could not create event queue."); - syscall::setrens(0, 0).expect("ihdad: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("ihdad: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); diff --git a/audio/pcspkrd/Cargo.toml b/audio/pcspkrd/Cargo.toml index 8f355d4e53..72bae14204 100644 --- a/audio/pcspkrd/Cargo.toml +++ b/audio/pcspkrd/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" [dependencies] redox_syscall = "0.4" redox-daemon = "0.1" +libredox = "0.1.3" diff --git a/audio/pcspkrd/src/main.rs b/audio/pcspkrd/src/main.rs index 7f9bfc1e40..75957745c3 100644 --- a/audio/pcspkrd/src/main.rs +++ b/audio/pcspkrd/src/main.rs @@ -29,7 +29,7 @@ fn main() { next_id: 0, }; - syscall::setrens(0, 0).expect("pcspkrd: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("pcspkrd: failed to enter null namespace"); loop { let mut packet = Packet::default(); diff --git a/audio/sb16d/Cargo.toml b/audio/sb16d/Cargo.toml index ccabfa3514..eb5a92a6e8 100644 --- a/audio/sb16d/Cargo.toml +++ b/audio/sb16d/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] bitflags = "1" common = { path = "../../common" } +libredox = "0.1.3" log = "0.4" redox-daemon = "0.1" redox-log = "0.1" diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index 6671ac9b39..814ed2066d 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -9,6 +9,7 @@ use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use libredox::flag; use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; @@ -74,10 +75,10 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let _logger_ref = setup_logging(); - unsafe { syscall::iopl(3) }.expect("sb16d: failed to set I/O privilege level to Ring 3"); + common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights"); let device = Arc::new(RefCell::new(unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") })); - let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("sb16d: failed to create hda scheme"); + let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("sb16d: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); //TODO: error on multiple IRQs? @@ -90,7 +91,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); - syscall::setrens(0, 0).expect("sb16d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("sb16d: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -98,6 +99,8 @@ fn main() { let device_irq = device.clone(); let socket_irq = socket.clone(); + // TODO: Use new event queue API + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; diff --git a/common/Cargo.toml b/common/Cargo.toml index 02b611d345..c1a072fa5d 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -8,4 +8,5 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -redox_syscall = "0.4" +libredox = "0.1.3" +redox_syscall = "0.5" diff --git a/common/src/dma.rs b/common/src/dma.rs index ec06623360..1adbbc6392 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -2,10 +2,10 @@ use std::mem::{self, size_of, MaybeUninit}; use std::ops::{Deref, DerefMut}; use std::ptr; +use libredox::call::MmapArgs; +use libredox::{flag, error::Result, Fd}; use syscall::PAGE_SIZE; -use syscall::Result; - use crate::MemoryType; const DMA_MEMTY: MemoryType = { @@ -20,30 +20,26 @@ const DMA_MEMTY: MemoryType = { } }; -fn alloc_and_map(len: usize) -> Result<(usize, *mut ())> { - assert_eq!(len % PAGE_SIZE, 0); +fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> { + assert_eq!(length % PAGE_SIZE, 0); unsafe { - let fd = syscall::open( - format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), - syscall::O_CLOEXEC, + let fd = Fd::open( + &format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), + flag::O_CLOEXEC, + 0, )?; - let virt = syscall::fmap( - fd, - &syscall::Map { - offset: 0, // ignored - address: 0, // ignored - size: len, - flags: syscall::MapFlags::MAP_PRIVATE - | syscall::MapFlags::PROT_READ - | syscall::MapFlags::PROT_WRITE, - }, - ); - let _ = syscall::close(fd); - let virt = virt?; - let phys = syscall::virttophys(virt)?; - /*for i in 1..len.div_ceil(PAGE_SIZE) { - assert_eq!(syscall::virttophys(virt + i * PAGE_SIZE), Ok(phys + i * PAGE_SIZE), "NOT CONTIGUOUS"); - }*/ + let virt = libredox::call::mmap(MmapArgs { + fd: fd.raw(), + offset: 0, // ignored + addr: core::ptr::null_mut(), // ignored + length, + flags: flag::MAP_PRIVATE, + prot: flag::PROT_READ | flag::PROT_WRITE, + })?; + let phys = syscall::virttophys(virt as usize)?; + for i in 1..length.div_ceil(PAGE_SIZE) { + debug_assert_eq!(syscall::virttophys(virt as usize + i * PAGE_SIZE), Ok(phys + i * PAGE_SIZE), "NOT CONTIGUOUS"); + } Ok((phys, virt as *mut ())) } } @@ -159,7 +155,7 @@ impl Drop for Dma { fn drop(&mut self) { unsafe { ptr::drop_in_place(self.virt); - let _ = syscall::funmap(self.virt as *mut u8 as usize, self.aligned_len); + let _ = libredox::call::munmap(self.virt as *mut (), self.aligned_len); } } } diff --git a/common/src/lib.rs b/common/src/lib.rs index 2a9240f193..2107a08660 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,7 +1,8 @@ #![feature(int_roundings)] -use syscall::error::{Error, Result, EINVAL}; -use syscall::flag::{MapFlags, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; +use libredox::call::MmapArgs; +use libredox::{Fd, error::*, errno::EINVAL}; +use libredox::flag::{self, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; use syscall::PAGE_SIZE; pub mod dma; @@ -63,23 +64,23 @@ pub unsafe fn physmap( (false, true) => O_WRONLY, (false, false) => return Err(Error::new(EINVAL)), }; - let mut prot = MapFlags::empty(); - prot.set(MapFlags::PROT_READ, read); - prot.set(MapFlags::PROT_WRITE, write); + let mut prot = 0; + if read { + prot |= flag::PROT_READ; + } + if write { + prot |= flag::PROT_WRITE; + } - let file = syscall::open(path, O_CLOEXEC | mode)?; - let base = syscall::fmap( - file, - &syscall::Map { - offset: base_phys, - size: len.next_multiple_of(PAGE_SIZE), - flags: MapFlags::MAP_SHARED | prot, - address: 0, - }, - ); - let _ = syscall::close(file); - - Ok(base? as *mut ()) + let fd = Fd::open(&path, O_CLOEXEC | mode, 0)?; + Ok(libredox::call::mmap(MmapArgs { + fd: fd.raw(), + offset: base_phys as u64, + length: len.next_multiple_of(PAGE_SIZE), + flags: flag::MAP_SHARED, + prot, + addr: core::ptr::null_mut(), + })? as *mut ()) } impl std::fmt::Display for MemoryType { @@ -119,7 +120,14 @@ impl PhysBorrowed { impl Drop for PhysBorrowed { fn drop(&mut self) { unsafe { - let _ = syscall::funmap(self.mem as usize, self.len); + let _ = libredox::call::munmap(self.mem, self.len); } } } + +pub fn acquire_port_io_rights() -> Result<()> { + unsafe { + syscall::iopl(3)?; + } + Ok(()) +} diff --git a/graphics/bgad/Cargo.toml b/graphics/bgad/Cargo.toml index afa6619215..0c439fd17a 100644 --- a/graphics/bgad/Cargo.toml +++ b/graphics/bgad/Cargo.toml @@ -9,3 +9,4 @@ redox-daemon = "0.1" redox_syscall = "0.4" pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index 18ac70df34..a80423f392 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -42,7 +42,7 @@ fn main() { scheme.update_size(); - syscall::setrens(0, 0).expect("bgad: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("bgad: failed to enter null namespace"); daemon.ready().expect("bgad: failed to notify parent"); diff --git a/graphics/fbcond/Cargo.toml b/graphics/fbcond/Cargo.toml index d934921104..fb930d8ab8 100644 --- a/graphics/fbcond/Cargo.toml +++ b/graphics/fbcond/Cargo.toml @@ -11,6 +11,7 @@ redox_syscall = "0.4" redox-daemon = "0.1" inputd = { path = "../../inputd" } +libredox = "0.1.3" [features] default = [] diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index da16fe5804..e2d3798046 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -8,6 +8,7 @@ use std::{ os::unix::io::{AsRawFd, FromRawFd}, slice, }; +use libredox::flag; use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; // Keep synced with vesad @@ -22,15 +23,14 @@ pub struct SyncRect { fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Result<*mut [u32]> { unsafe { - let display_ptr = syscall::fmap( - display_fd, - &syscall::Map { - offset: 0, - size: (width * height * 4), - flags: syscall::PROT_READ | syscall::PROT_WRITE | syscall::MAP_SHARED, - address: 0, - }, - )?; + let display_ptr = libredox::call::mmap(libredox::call::MmapArgs { + fd: display_fd, + offset: 0, + length: (width * height * 4), + prot: flag::PROT_READ | flag::PROT_WRITE, + flags: flag::MAP_SHARED, + addr: core::ptr::null_mut(), + })?; let display_slice = slice::from_raw_parts_mut(display_ptr as *mut u32, width * height); Ok(display_slice) } @@ -38,7 +38,7 @@ fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Re unsafe fn display_fd_unmap(image: *mut [u32], size: usize) { // FIXME use image.len() instead of size once it is stable. - let _ = syscall::funmap(image as *mut u32 as usize, size * 4); + let _ = libredox::call::munmap(image as *mut (), size * 4); } pub struct Display { @@ -59,7 +59,7 @@ impl Display { .open(format!("input:consumer/{vt}"))?; let fd = input_handle.as_raw_fd(); - let written = syscall::fpath(fd as usize, &mut buffer) + let written = libredox::call::fpath(fd as usize, &mut buffer) .expect("init: failed to get the path to the display device"); assert!(written <= buffer.len()); @@ -67,7 +67,7 @@ impl Display { let display_path = std::str::from_utf8(&buffer[..written]).expect("init: display path UTF-8 check failed"); - let display_file = syscall::open(display_path, O_CLOEXEC | O_NONBLOCK | O_RDWR) + let display_file = libredox::call::open(display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) .unwrap_or_else(|err| { panic!("failed to open display {}: {}", display_path, err); @@ -75,7 +75,7 @@ impl Display { let mut buf: [u8; 4096] = [0; 4096]; let count = - syscall::fpath(display_file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| { + libredox::call::fpath(display_file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| { panic!("Could not read display path with fpath(): {e}"); }); @@ -138,7 +138,7 @@ impl Display { pub fn sync_rect(&mut self, sync_rect: SyncRect) -> syscall::Result<()> { unsafe { - syscall::write( + libredox::call::write( self.display_file.as_raw_fd().as_raw_fd() as usize, slice::from_raw_parts( &sync_rect as *const SyncRect as *const u8, diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index cd0a859810..4db9e1b5fc 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -53,7 +53,7 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { let mut scheme = FbconScheme::new(vt_ids, &mut event_queue); - syscall::setrens(0, 0).expect("fbcond: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index bdc24d66f5..7f75c6fbc5 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -320,7 +320,7 @@ impl TextScreen { })?; } self.changed.clear(); - syscall::fsync(self.display.display_file.as_raw_fd().as_raw_fd() as usize)?; + libredox::call::fsync(self.display.display_file.as_raw_fd().as_raw_fd() as usize)?; Ok(buf.len()) } diff --git a/graphics/vesad/Cargo.toml b/graphics/vesad/Cargo.toml index 5d6542ccf5..da97862697 100644 --- a/graphics/vesad/Cargo.toml +++ b/graphics/vesad/Cargo.toml @@ -11,6 +11,7 @@ redox-daemon = "0.1" common = { path = "../../common" } inputd = { path = "../../inputd" } +libredox = "0.1.3" [features] default = [] diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 9f1d8f2901..2b6fd953c4 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -88,7 +88,7 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( let mut scheme = DisplayScheme::new(framebuffers, &spec); - syscall::setrens(0, 0).expect("vesad: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 7f12cf0f9c..4b94801b16 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -95,7 +95,7 @@ impl DisplayScheme { // Unmap old onscreen unsafe { let slice = mem::take(&mut self.onscreens[fb_i]); - syscall::funmap(slice.as_mut_ptr() as usize, (slice.len() * 4).next_multiple_of(PAGE_SIZE)).expect("vesad: failed to unmap framebuffer"); + libredox::call::munmap(slice.as_mut_ptr().cast(), (slice.len() * 4).next_multiple_of(PAGE_SIZE)).expect("vesad: failed to unmap framebuffer"); } // Map new onscreen diff --git a/graphics/virtio-gpud/Cargo.toml b/graphics/virtio-gpud/Cargo.toml index a51e8b5a7a..7d9d17b2f5 100644 --- a/graphics/virtio-gpud/Cargo.toml +++ b/graphics/virtio-gpud/Cargo.toml @@ -20,3 +20,4 @@ redox-daemon = "0.1" redox_syscall = "0.4" orbclient = "0.3.27" spin = "0.9.8" +libredox = "0.1.3" diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index e88ab86f9e..9b900edc13 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -7,8 +7,9 @@ authors = ["Anhad Singh "] [dependencies] anyhow = "1.0.71" log = "0.4.19" -redox-daemon = "0.1.0" +redox-daemon = "0.1.2" redox-log = "0.1.1" -redox_syscall = "0.4" +redox_syscall = "0.5" orbclient = "0.3.27" spin = "0.9.8" +libredox = "0.1.3" diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 4a52c09403..3112964993 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -91,7 +91,7 @@ impl Cmd { } } -pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), syscall::Error> { +pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), libredox::error::Error> { use std::os::fd::AsRawFd; let mut result = vec![]; @@ -119,7 +119,7 @@ pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), syscall::Error> } }; - let written = syscall::write(file.as_raw_fd() as usize, &result)?; + let written = libredox::call::write(file.as_raw_fd() as usize, &result)?; // XXX: Ensure all of the data is written. assert_eq!(written, result.len()); diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 23f6b7b4e3..e8b34c9585 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -535,7 +535,7 @@ pub fn main() { .expect("inputd: failed to open consumer handle"); let mut display_path = [0; 4096]; - let written = syscall::fpath(handle.as_raw_fd() as usize, &mut display_path) + let written = libredox::call::fpath(handle.as_raw_fd() as usize, &mut display_path) .expect("inputd: fpath() failed"); assert!(written <= display_path.len()); diff --git a/net/alxd/Cargo.toml b/net/alxd/Cargo.toml index 4a3ed09f03..5d20a58d5b 100644 --- a/net/alxd/Cargo.toml +++ b/net/alxd/Cargo.toml @@ -6,7 +6,8 @@ edition = "2018" [dependencies] bitflags = "1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" common = { path = "../../common" } +libredox = "0.1.3" diff --git a/net/alxd/src/device/mod.rs b/net/alxd/src/device/mod.rs index 3a20c9fc81..0222cd1c27 100644 --- a/net/alxd/src/device/mod.rs +++ b/net/alxd/src/device/mod.rs @@ -281,7 +281,7 @@ pub struct Alx { fn dma_array() -> Result<[Dma; N]> { Ok((0..N) - .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .map(|_| Ok(Dma::zeroed().map(|dma| unsafe { dma.assume_init() })?)) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!())) @@ -290,7 +290,7 @@ fn dma_array() -> Result<[Dma; N]> { impl Alx { pub unsafe fn new(base: usize) -> Result { let mut module = Alx { - base: base, + base, vendor_id: 0, device_id: 0, diff --git a/net/alxd/src/main.rs b/net/alxd/src/main.rs index ef1f745681..8ff8e18c52 100644 --- a/net/alxd/src/main.rs +++ b/net/alxd/src/main.rs @@ -14,6 +14,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; +use libredox::flag; use syscall::{EventFlags, Packet, SchemeMut}; use syscall::error::EWOULDBLOCK; @@ -35,7 +36,7 @@ fn main() { // Daemonize redox_daemon::Daemon::new(move |daemon| { - let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("alxd: failed to create network scheme"); + let socket_fd = libredox::call::open(":network", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("alxd: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); daemon.ready().expect("alxd: failed to signal readiness"); @@ -48,7 +49,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("alxd: failed to create event queue"); - syscall::setrens(0, 0).expect("alxd: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("alxd: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -111,7 +112,7 @@ fn main() { for event_count in event_queue.trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }).expect("alxd: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, diff --git a/net/driver-network/Cargo.toml b/net/driver-network/Cargo.toml index 47be9d3175..965bbcf23c 100644 --- a/net/driver-network/Cargo.toml +++ b/net/driver-network/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] +libredox = "0.1.3" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index 3790b33ba5..ce108dcd70 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -4,6 +4,7 @@ use std::io::{ErrorKind, Read, Write}; use std::os::fd::{AsRawFd, FromRawFd, RawFd}; use std::{cmp, io}; +use libredox::flag; use syscall::{ Error, EventFlags, Packet, Result, SchemeBlockMut, Stat, EACCES, EBADF, EINVAL, EWOULDBLOCK, MODE_FILE, O_NONBLOCK, @@ -46,9 +47,10 @@ enum Handle { impl NetworkScheme { pub fn new(adapter: T, scheme_name: String) -> Self { assert!(scheme_name.starts_with("network")); - let scheme_fd = syscall::open( + let scheme_fd = libredox::call::open( format!(":{scheme_name}"), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, + 0, ) .expect("failed to create network scheme"); let scheme = unsafe { File::from_raw_fd(scheme_fd as RawFd) }; diff --git a/net/e1000d/Cargo.toml b/net/e1000d/Cargo.toml index 395a6341cc..bc6c347647 100644 --- a/net/e1000d/Cargo.toml +++ b/net/e1000d/Cargo.toml @@ -7,8 +7,9 @@ edition = "2018" bitflags = "1" redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/net/e1000d/src/device.rs b/net/e1000d/src/device.rs index 7da6965d13..721e7cf913 100644 --- a/net/e1000d/src/device.rs +++ b/net/e1000d/src/device.rs @@ -208,7 +208,7 @@ impl NetworkAdapter for Intel8254x { fn dma_array() -> Result<[Dma; N]> { Ok((0..N) - .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!())) diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index b8052b93f3..8c532f3c68 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -43,7 +43,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); - syscall::setrens(0, 0).expect("e1000d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("e1000d: failed to enter null namespace"); daemon .ready() @@ -79,7 +79,7 @@ fn main() { event_queue .trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }) .expect("e1000d: failed to trigger events"); diff --git a/net/ixgbed/Cargo.toml b/net/ixgbed/Cargo.toml index fd3258fa00..38ee7a7477 100644 --- a/net/ixgbed/Cargo.toml +++ b/net/ixgbed/Cargo.toml @@ -6,9 +6,10 @@ edition = "2021" [dependencies] bitflags = "1.0" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/net/ixgbed/src/device.rs b/net/ixgbed/src/device.rs index b36309e14f..4ab8d0e530 100644 --- a/net/ixgbed/src/device.rs +++ b/net/ixgbed/src/device.rs @@ -129,13 +129,13 @@ impl Intel8259x { base, size, receive_buffer: (0..32) - .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), receive_ring: unsafe { Dma::zeroed()?.assume_init() }, transmit_buffer: (0..32) - .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index 33c67083bd..7c6aefbb27 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -55,7 +55,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("ixgbed: failed to create event queue"); - syscall::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); daemon .ready() @@ -91,7 +91,7 @@ fn main() { event_queue .trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }) .expect("ixgbed: failed to trigger events"); diff --git a/net/rtl8139d/Cargo.toml b/net/rtl8139d/Cargo.toml index 2ff86321ab..ef23f408db 100644 --- a/net/rtl8139d/Cargo.toml +++ b/net/rtl8139d/Cargo.toml @@ -7,10 +7,11 @@ edition = "2018" bitflags = "1" log = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" redox-log = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/net/rtl8139d/src/device.rs b/net/rtl8139d/src/device.rs index 4b6ce854f0..e6ef45053b 100644 --- a/net/rtl8139d/src/device.rs +++ b/net/rtl8139d/src/device.rs @@ -209,13 +209,13 @@ impl Rtl8139 { let regs = Regs::from_base(base); let mut module = Rtl8139 { - regs: regs, + regs, //TODO: limit to 32-bit receive_buffer: Dma::zeroed().map(|dma| dma.assume_init())?, receive_i: 0, //TODO: limit to 32-bit transmit_buffer: (0..4) - .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) + .map(|_| Ok(Dma::zeroed()?.assume_init())) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 048daf6d95..66ca3b533e 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -242,7 +242,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut event_queue = EventQueue::::new().expect("rtl8139d: failed to create event queue"); - syscall::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); daemon .ready() @@ -279,7 +279,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { event_queue .trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }) .expect("rtl8139d: failed to trigger events"); diff --git a/net/rtl8168d/Cargo.toml b/net/rtl8168d/Cargo.toml index 3ec1bdfbcf..2010b02b47 100644 --- a/net/rtl8168d/Cargo.toml +++ b/net/rtl8168d/Cargo.toml @@ -7,10 +7,11 @@ edition = "2018" bitflags = "1" log = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" redox-log = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/net/rtl8168d/src/device.rs b/net/rtl8168d/src/device.rs index 25b6aea64a..717ac194e2 100644 --- a/net/rtl8168d/src/device.rs +++ b/net/rtl8168d/src/device.rs @@ -173,9 +173,9 @@ impl Rtl8168 { assert_eq!(®s.mtps as *const _ as usize - base, 0xEC); let mut module = Rtl8168 { - regs: regs, + regs, receive_buffer: (0..64) - .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) + .map(|_| Ok(Dma::zeroed()?.assume_init())) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), @@ -183,7 +183,7 @@ impl Rtl8168 { receive_ring: Dma::zeroed()?.assume_init(), receive_i: 0, transmit_buffer: (0..16) - .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) + .map(|_| Ok(Dma::zeroed()?.assume_init())) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 3767f2ddad..e38501b3ec 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -237,7 +237,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut event_queue = EventQueue::::new().expect("rtl8168d: failed to create event queue"); - syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); daemon .ready() @@ -274,7 +274,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { event_queue .trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }) .expect("rtl8168d: failed to trigger events"); diff --git a/net/virtio-netd/Cargo.toml b/net/virtio-netd/Cargo.toml index e1063e7414..3becfd7897 100644 --- a/net/virtio-netd/Cargo.toml +++ b/net/virtio-netd/Cargo.toml @@ -14,4 +14,5 @@ common = { path = "../../common" } driver-network = { path = "../driver-network" } redox-daemon = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" +libredox = "0.1.3" diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index f00437a763..d2a2411f55 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -102,7 +102,7 @@ fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box data: 0, })?; - syscall::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); daemon.ready().expect("virtio-netd: failed to daemonize"); diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index a4ae567e9d..487b79029d 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -31,3 +31,4 @@ thiserror = "1" toml = "0.5" common = { path = "../common" } +libredox = "0.1.3" diff --git a/pcid/src/cfg_access/fallback.rs b/pcid/src/cfg_access/fallback.rs index 65682e171f..c1d51bfb5c 100644 --- a/pcid/src/cfg_access/fallback.rs +++ b/pcid/src/cfg_access/fallback.rs @@ -33,9 +33,7 @@ impl Pci { "PCI: couldn't find or access PCIe extended configuration, \ and thus falling back to PCI 3.0 io ports" ); - unsafe { - syscall::iopl(3).expect("pcid: failed to set iopl to 3"); - } + common::acquire_port_io_rights().expect("pcid: failed to get IO port rights"); } }); } diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index cfab793a52..90f5875711 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -8,3 +8,4 @@ bitflags = "1" orbclient = "0.3.27" redox_syscall = "0.4" redox-daemon = "0.1" +libredox = "0.1.3" diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index f9cdba3b6b..aa4ec5df2c 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -80,7 +80,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { data: 1 }).expect("ps2d: failed to event irq:12"); - syscall::setrens(0, 0).expect("ps2d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("ps2d: failed to enter null namespace"); daemon.ready().expect("ps2d: failed to mark daemon as ready"); diff --git a/storage/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml index 4c84077667..eb8e450c77 100644 --- a/storage/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -14,3 +14,4 @@ redox_syscall = "0.4" common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 60dd30ab12..050fa97bf4 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -10,6 +10,7 @@ use std::os::fd::AsRawFd; use std::os::unix::io::{FromRawFd, RawFd}; use std::usize; +use libredox::flag; use pcid_interface::PcidServerHandle; use syscall::error::{Error, ENODEV}; use syscall::data::{Event, Packet}; @@ -93,9 +94,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { bar.physmap_mem("ahcid") }; { let scheme_name = format!("disk.{}", name); - let socket_fd = syscall::open( + let socket_fd = libredox::call::open( &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK + flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK + 0, ).expect("ahcid: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; @@ -104,9 +106,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); - syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace"); - - daemon.ready().expect("ahcid: failed to notify parent"); + libredox::call::setrens(0, 0).expect("ahcid: failed to enter null namespace"); event_file.write(&Event { id: socket_fd, @@ -120,6 +120,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { data: 0 }).expect("ahcid: failed to event irq scheme"); + daemon.ready().expect("ahcid: failed to notify parent"); + let (hba_mem, disks) = ahci::disks(address as usize, &name); let mut scheme = DiskScheme::new(scheme_name, hba_mem, disks); diff --git a/storage/bcm2835-sdhcid/Cargo.toml b/storage/bcm2835-sdhcid/Cargo.toml index d92d58d3fa..b5c21ffb80 100644 --- a/storage/bcm2835-sdhcid/Cargo.toml +++ b/storage/bcm2835-sdhcid/Cargo.toml @@ -12,3 +12,4 @@ common = { path = "../../common" } driver-block = { path = "../driver-block" } redox-daemon = "0.1" +libredox = "0.1.3" diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index 7a815a64e2..edcafbb4ea 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -79,7 +79,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let scheme_name = ":disk.mmc"; let mut socket = File::create(scheme_name).expect("mmc: failed to create disk scheme"); - syscall::setrens(0, 0).expect("mmc: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("mmc: failed to enter null namespace"); daemon.ready().expect("mmc: failed to notify parent"); diff --git a/storage/ided/Cargo.toml b/storage/ided/Cargo.toml index 1df0416b7b..aab5d97153 100644 --- a/storage/ided/Cargo.toml +++ b/storage/ided/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] common = { path = "../../common" } driver-block = { path = "../driver-block" } +libredox = "0.1.3" log = "0.4" pcid = { path = "../../pcid" } redox-daemon = "0.1" diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index ca27ab7e60..2778a68324 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -1,4 +1,5 @@ use driver_block::Disk; +use libredox::flag; use log::{error, info}; use pcid_interface::{PciBar, PcidServerHandle}; use redox_log::{OutputBuilder, RedoxLogger}; @@ -99,7 +100,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { (Channel::secondary_compat(busmaster_base + 8).unwrap(), 15) }; - unsafe { syscall::iopl(3).expect("ided: failed to get I/O privilege") }; + common::acquire_port_io_rights().expect("ided: failed to get I/O privilege"); //TODO: move this to ide.rs? let chans = vec![ @@ -231,27 +232,30 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } let scheme_name = format!("disk.{}", name); - let socket_fd = syscall::open( + let socket_fd = libredox::call::open( &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK + flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, + 0, ).expect("ided: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - let primary_irq_fd = syscall::open( + let primary_irq_fd = libredox::call::open( &format!("irq:{}", primary_irq), - syscall::O_RDWR | syscall::O_NONBLOCK + flag::O_RDWR | flag::O_NONBLOCK, + 0, ).expect("ided: failed to open irq file"); let mut primary_irq_file = unsafe { File::from_raw_fd(primary_irq_fd as RawFd) }; - let secondary_irq_fd = syscall::open( + let secondary_irq_fd = libredox::call::open( &format!("irq:{}", secondary_irq), - syscall::O_RDWR | syscall::O_NONBLOCK + flag::O_RDWR | flag::O_NONBLOCK, + 0, ).expect("ided: failed to open irq file"); let mut secondary_irq_file = unsafe { File::from_raw_fd(secondary_irq_fd as RawFd) }; let mut event_file = File::open("event:").expect("ided: failed to open event file"); - syscall::setrens(0, 0).expect("ided: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("ided: failed to enter null namespace"); daemon.ready().expect("ided: failed to notify parent"); diff --git a/storage/lived/Cargo.toml b/storage/lived/Cargo.toml index cea304209c..339708856e 100644 --- a/storage/lived/Cargo.toml +++ b/storage/lived/Cargo.toml @@ -9,6 +9,7 @@ license = "MIT" [dependencies] anyhow = "1" +libredox = "0.1.3" redox-daemon = "0.1" redox_syscall = "0.4" slab = "0.4" diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index 411d44db3f..8470400938 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -8,6 +8,8 @@ use std::io::{Read, Write}; use std::os::fd::AsRawFd; use std::str; +use libredox::call::MmapArgs; +use libredox::flag; use slab::Slab; use syscall::data::Stat; use syscall::{error::*, MapFlags, SchemeMut, Packet}; @@ -63,11 +65,13 @@ impl DiskScheme { let the_data = unsafe { let file = File::open("memory:physical")?; - let base = syscall::fmap(file.as_raw_fd() as usize, &syscall::Map { - address: 0, - offset: start, - size, - flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_SHARED, + let base = libredox::call::mmap(MmapArgs { + fd: file.as_raw_fd() as usize, + addr: core::ptr::null_mut(), + offset: start as u64, + length: size, + prot: flag::PROT_READ | flag::PROT_WRITE, + flags: flag::MAP_SHARED, }).map_err(|err| anyhow!("failed to mmap livedisk: {}", err))?; std::slice::from_raw_parts_mut(base as *mut u8, size) diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 59c9c36935..6271a63fa8 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -18,6 +18,7 @@ smallvec = "1" common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } +libredox = "0.1.3" [features] default = ["async"] diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 7058e9f6ae..5b05e82cd0 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -9,6 +9,7 @@ use std::ptr::NonNull; use std::sync::{Arc, Mutex}; use std::{slice, usize}; +use libredox::flag; use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; use syscall::{ Event, Mmio, Packet, Result, SchemeBlockMut, @@ -49,8 +50,8 @@ impl Bar { impl Drop for Bar { fn drop(&mut self) { let _ = unsafe { - syscall::funmap( - self.ptr.as_ptr() as usize, + libredox::call::munmap( + self.ptr.as_ptr().cast(), self.bar_size.next_multiple_of(PAGE_SIZE), ) }; @@ -275,9 +276,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"), }); - let socket_fd = syscall::open( + let socket_fd = libredox::call::open( &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, + flag::O_RDWR | flag::O_CREAT | flag::O_CLOEXEC, + 0, ) .expect("nvmed: failed to create disk scheme"); let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; @@ -297,7 +299,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let reactor_thread = nvme::cq_reactor::start_cq_reactor_thread(Arc::clone(&nvme), interrupt_sources, reactor_receiver); let namespaces = nvme.init_with_queues(); - syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); let mut todo = Vec::new(); diff --git a/storage/nvmed/src/nvme/cq_reactor.rs b/storage/nvmed/src/nvme/cq_reactor.rs index 5926684974..3e67dd5deb 100644 --- a/storage/nvmed/src/nvme/cq_reactor.rs +++ b/storage/nvmed/src/nvme/cq_reactor.rs @@ -65,8 +65,8 @@ struct CqReactor { } impl CqReactor { fn create_event_queue(int_sources: &mut InterruptSources) -> Result { - use syscall::flag::*; - let fd = syscall::open("event:", O_CLOEXEC | O_RDWR)?; + use libredox::flag::*; + let fd = libredox::call::open("event:", O_CLOEXEC | O_RDWR, 0)?; let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; for (num, irq_handle) in int_sources.iter_mut() { diff --git a/storage/usbscsid/Cargo.toml b/storage/usbscsid/Cargo.toml index 28083405a3..d3ca3455ee 100644 --- a/storage/usbscsid/Cargo.toml +++ b/storage/usbscsid/Cargo.toml @@ -9,6 +9,7 @@ license = "MIT" [dependencies] base64 = "0.11" # Only for debugging +libredox = "0.1.3" plain = "0.2" redox-daemon = "0.1" redox_syscall = "0.4" diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index 6f698e8c19..e745c0ad3f 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -3,6 +3,7 @@ use std::fs::File; use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; +use libredox::flag; use syscall::{Packet, SchemeMut}; use xhcid_interface::{ConfigureEndpointsReq, DeviceReqData, XhciClientHandle}; @@ -84,11 +85,11 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u // TODO: Let all of the USB drivers syscall clone(2), and xhcid won't have to keep track of all // the drivers. - let socket_fd = syscall::open(disk_scheme_name, syscall::O_RDWR | syscall::O_CREAT) + let socket_fd = libredox::call::open(disk_scheme_name, flag::O_RDWR | flag::O_CREAT, 0) .expect("usbscsid: failed to create disk scheme"); let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - //syscall::setrens(0, 0).expect("scsid: failed to enter null namespace"); + //libredox::call::setrens(0, 0).expect("scsid: failed to enter null namespace"); let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI"); println!("SCSI initialized"); let mut buffer = [0u8; 512]; diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index 690454263d..34883809cd 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -21,3 +21,4 @@ common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } virtio-core = { path = "../../virtio-core" } +libredox = "0.1.3" diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index c6b3727a16..634621e3f4 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -8,6 +8,7 @@ use std::io::{Read, Write}; use std::os::fd::{FromRawFd, RawFd}; use std::sync::{Arc, Weak}; +use libredox::flag; use static_assertions::const_assert_eq; use pcid_interface::*; @@ -142,9 +143,10 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let scheme_name = format!("disk.{}", name); - let socket_fd = syscall::open( + let socket_fd = libredox::call::open( &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, + flag::O_RDWR | flag::O_CREAT | flag::O_CLOEXEC, + 0, ) .map_err(Error::SyscallError)?; diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index 23a4273c2a..ff25884242 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -6,8 +6,9 @@ edition = "2018" [dependencies] orbclient = "0.3.27" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" common = { path = "../common" } pcid = { path = "../pcid" } +libredox = "0.1.3" diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 7555482450..39b0c3efaf 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -11,7 +11,6 @@ use std::fs::File; use std::io::{Result, Read, Write}; use pcid_interface::{PciBar, PcidServerHandle}; -use syscall::call::iopl; use syscall::flag::EventFlags; use syscall::io::{Io, Mmio, Pio}; @@ -206,14 +205,14 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { daemon.ready().expect("failed to signal readiness"); - unsafe { iopl(3).expect("vboxd: failed to get I/O permission"); }; + common::acquire_port_io_rights().expect("vboxd: failed to get I/O permission"); let mut width = 0; let mut height = 0; let mut display_opt = File::open("inputd:producer").ok(); if let Some(ref display) = display_opt { let mut buf: [u8; 4096] = [0; 4096]; - if let Ok(count) = syscall::fpath(display.as_raw_fd() as usize, &mut buf) { + if let Ok(count) = libredox::call::fpath(display.as_raw_fd() as usize, &mut buf) { let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; let res = path.split(":").nth(1).unwrap_or(""); width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); @@ -245,7 +244,7 @@ fn main() { let mut event_queue = EventQueue::<()>::new().expect("vboxd: failed to create event queue"); - syscall::setrens(0, 0).expect("vboxd: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("vboxd: failed to enter null namespace"); let mut bga = Bga::new(); let get_mouse = VboxGetMouse::new().expect("vboxd: failed to map GetMouse"); @@ -295,7 +294,7 @@ fn main() { event_queue.trigger_all(event::Event { fd: 0, - flags: EventFlags::empty() + flags: Default::default(), }).expect("vboxd: failed to trigger events"); event_queue.run().expect("vboxd: failed to run event loop"); diff --git a/virtio-core/Cargo.toml b/virtio-core/Cargo.toml index 8824169676..a9d8c6713a 100644 --- a/virtio-core/Cargo.toml +++ b/virtio-core/Cargo.toml @@ -18,3 +18,4 @@ redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } common = { path = "../common" } pcid = { path = "../pcid" } +libredox = "0.1.3" diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index 9073ce8059..862d4dfee6 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -13,7 +13,7 @@ pub fn probe_legacy_port_transport( ) -> Result { let port = pci_config.func.bars[0].expect_port(); - unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; + common::acquire_io_port_rights().expect("virtio: failed to set I/O privilege level"); log::warn!("virtio: using legacy transport"); let transport = LegacyTransport::new(port); diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index e67d8ab767..fa0de00c6c 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -54,7 +54,7 @@ pub fn probe_legacy_port_transport( ) -> Result { let port = pci_config.func.bars[0].expect_port(); - unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; + common::acquire_port_io_rights().expect("virtio: failed to set I/O privilege level"); log::warn!("virtio: using legacy transport"); let transport = LegacyTransport::new(port); diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 1ff80a205f..133c5e53c4 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -16,7 +16,7 @@ use std::task::{Poll, Waker}; #[derive(thiserror::Error, Debug)] pub enum Error { #[error("syscall failed")] - SyscallError(syscall::Error), + SyscallError(#[from] libredox::error::Error), #[error("pcid client handle error")] PcidClientHandle(pcid_interface::PcidClientHandleError), #[error("the device is incapable of {0:?}")] @@ -29,12 +29,6 @@ impl From for Error { } } -impl From for Error { - fn from(value: syscall::Error) -> Self { - Self::SyscallError(value) - } -} - /// Returns the queue part sizes in bytes. /// /// ## Reference diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 7fa83821b5..94e09eb0b3 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -20,9 +20,9 @@ plain = "0.2" lazy_static = "1.4" log = "0.4" redox-daemon = "0.1" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox_event = "0.4.1" redox-log = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1", features = ["serde"] } @@ -31,3 +31,4 @@ toml = "0.5" common = { path = "../common" } pcid = { path = "../pcid" } +libredox = "0.1.3" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index faf50300ec..6b9fe1bd79 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -11,13 +11,14 @@ use std::ptr::NonNull; use std::sync::{Arc, Mutex}; use std::env; +use libredox::flag; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::MsixTableEntry; -use event::{Event, EventQueue}; +use event::{Event, RawEventQueue}; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; @@ -208,9 +209,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { println!(" + XHCI {}", pci_config.func.display()); let scheme_name = format!("usb.{}", name); - let socket_fd = syscall::open( + let socket_fd = libredox::call::open( format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT, + flag::O_RDWR | flag::O_CREAT, + 0, ) .expect("xhcid: failed to create usb scheme"); let socket = Arc::new(Mutex::new(unsafe { @@ -223,47 +225,38 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { xhci::start_irq_reactor(&hci, irq_file); futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe"); - let mut event_queue = - EventQueue::<()>::new().expect("xhcid: failed to create event queue"); + //let event_queue = RawEventQueue::new().expect("xhcid: failed to create event queue"); - syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("xhcid: failed to enter null namespace"); let todo = Arc::new(Mutex::new(Vec::::new())); - let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); + //let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); + + //let socket_fd = socket.lock().unwrap().as_raw_fd(); + //event_queue.subscribe(socket_fd as usize, 0, event::EventFlags::READ).unwrap(); - let socket_fd = socket.lock().unwrap().as_raw_fd(); let socket_packet = socket.clone(); - event_queue - .add(socket_fd, move |_| -> io::Result> { - let mut socket = socket_packet.lock().unwrap(); - let mut todo = todo.lock().unwrap(); - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => break, - Ok(_) => (), - Err(err) => return Err(err), - } + loop { + let mut socket = socket_packet.lock().unwrap(); + let mut todo = todo.lock().unwrap(); - let a = packet.a; - hci.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.push(packet); - } else { - socket.write(&packet)?; - } - } - Ok(None) - }) - .expect("xhcid: failed to catch events on scheme file"); + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => break, + Ok(_) => (), + Err(err) => panic!("xhcid failed to read from socket: {err}"), + } - event_queue - .trigger_all(Event { fd: 0, flags: EventFlags::empty() }) - .expect("xhcid: failed to trigger events"); - - event_queue.run().expect("xhcid: failed to handle events"); + let a = packet.a; + hci.handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.push(packet); + } else { + socket.write(&packet).expect("xhcid failed to write to socket"); + } + } std::process::exit(0); } diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 3779218c28..5f364a5524 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -185,7 +185,7 @@ impl ScratchpadBufferArray { pub fn new(ac64: bool, entries: u16) -> Result { let mut entries = unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? }; - let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| { + let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result<_, syscall::Error> { let dma = unsafe { Dma::<[u8; PAGE_SIZE]>::zeroed()?.assume_init() }; assert_eq!(dma.physical() % PAGE_SIZE, 0); entry.set_addr(dma.physical() as u64); diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 215832ff9f..a697561ad5 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -14,7 +14,7 @@ use log::{debug, error, info, warn, trace}; use futures::Stream; use syscall::Io; -use event::{Event, EventQueue}; +use event::{Event, EventQueue, RawEventQueue}; use super::Xhci; use super::doorbell::Doorbell; @@ -146,12 +146,13 @@ impl IrqReactor { debug!("Running IRQ reactor with IRQ file and event queue"); let hci_clone = Arc::clone(&self.hci); - let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); + let mut event_queue = RawEventQueue::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); + event_queue.subscribe(irq_fd as usize, 0, event::EventFlags::READ).unwrap(); let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() }; - event_queue.add(irq_fd, move |_| -> io::Result> { + for _event in event_queue { trace!("IRQ event queue notified"); let mut buffer = [0u8; 8]; @@ -160,7 +161,7 @@ impl IrqReactor { if !self.hci.received_irq() { // continue only when an IRQ to this device was received trace!("no interrupt pending"); - return Ok(None); + break; } trace!("IRQ reactor received an IRQ"); @@ -173,13 +174,13 @@ impl IrqReactor { let mut count = 0; - 'trb_loop: loop { + loop { let event_trb = &mut event_ring.ring.trbs[event_trb_index]; if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { if count == 0 { warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } // no more events were found, continue the loop - return Ok(None); + return; } else { count += 1 } trace!("Found event TRB type {}: {:?}", event_trb.trb_type(), event_trb); @@ -187,7 +188,7 @@ impl IrqReactor { if self.check_event_ring_full(event_trb.clone()) { info!("Had to resize event TRB, retrying..."); hci_clone.event_handler_finished(); - return Ok(None); + return; } self.handle_requests(); @@ -199,8 +200,7 @@ impl IrqReactor { event_trb_index = event_ring.ring.next_index(); } - }).expect("xhcid: failed to catch irq events"); - event_queue.run().expect("xhcid: failed to run IRQ event queue"); + } } fn update_erdp(&self, event_ring: &EventRing) { let dequeue_pointer_and_dcs = event_ring.erdp(); diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 32d9d1eb82..52d544d845 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -11,7 +11,6 @@ use std::{mem, process, slice, sync::atomic, task, thread}; use syscall::PAGE_SIZE; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; -use syscall::flag::{O_RDONLY, PhysallocFlags}; use syscall::io::Io; use chashmap::CHashMap; @@ -236,12 +235,7 @@ impl Xhci { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; debug!("CAP REGS BASE {:X}", address); - /*let page_size = { - let memory_fd = syscall::open("memory:", O_RDONLY)?; - let mut stat = syscall::data::StatVfs::default(); - syscall::fstatvfs(memory_fd, &mut stat)?; - stat.f_bsize as usize - };*/ + //let page_size = ... let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; From 98078650f803636c56ef8c91d06189ae1fb7fee4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 18 Mar 2024 15:00:52 -0600 Subject: [PATCH 0836/1301] Revert "Switch to libredox where applicable." This reverts commit 2e7dbf1cc1141858cdf91561883570d1dcb949ef. --- Cargo.lock | 82 ++++++---------------------- acpid/Cargo.toml | 1 - acpid/src/acpi.rs | 2 +- acpid/src/acpi/dmar/drhd.rs | 2 +- acpid/src/aml_physmem.rs | 4 +- acpid/src/main.rs | 6 +- audio/ac97d/Cargo.toml | 3 +- audio/ac97d/src/main.rs | 9 ++- audio/ihdad/Cargo.toml | 1 - audio/ihdad/src/main.rs | 5 +- audio/pcspkrd/Cargo.toml | 1 - audio/pcspkrd/src/main.rs | 2 +- audio/sb16d/Cargo.toml | 1 - audio/sb16d/src/main.rs | 9 +-- common/Cargo.toml | 3 +- common/src/dma.rs | 46 +++++++++------- common/src/lib.rs | 46 +++++++--------- graphics/bgad/Cargo.toml | 1 - graphics/bgad/src/main.rs | 2 +- graphics/fbcond/Cargo.toml | 1 - graphics/fbcond/src/display.rs | 28 +++++----- graphics/fbcond/src/main.rs | 2 +- graphics/fbcond/src/text.rs | 2 +- graphics/vesad/Cargo.toml | 1 - graphics/vesad/src/main.rs | 2 +- graphics/vesad/src/scheme.rs | 2 +- graphics/virtio-gpud/Cargo.toml | 1 - inputd/Cargo.toml | 5 +- inputd/src/lib.rs | 4 +- inputd/src/main.rs | 2 +- net/alxd/Cargo.toml | 3 +- net/alxd/src/device/mod.rs | 4 +- net/alxd/src/main.rs | 7 +-- net/driver-network/Cargo.toml | 3 +- net/driver-network/src/lib.rs | 6 +- net/e1000d/Cargo.toml | 3 +- net/e1000d/src/device.rs | 2 +- net/e1000d/src/main.rs | 4 +- net/ixgbed/Cargo.toml | 3 +- net/ixgbed/src/device.rs | 4 +- net/ixgbed/src/main.rs | 4 +- net/rtl8139d/Cargo.toml | 3 +- net/rtl8139d/src/device.rs | 4 +- net/rtl8139d/src/main.rs | 4 +- net/rtl8168d/Cargo.toml | 3 +- net/rtl8168d/src/device.rs | 6 +- net/rtl8168d/src/main.rs | 4 +- net/virtio-netd/Cargo.toml | 3 +- net/virtio-netd/src/main.rs | 2 +- pcid/Cargo.toml | 1 - pcid/src/cfg_access/fallback.rs | 4 +- ps2d/Cargo.toml | 1 - ps2d/src/main.rs | 2 +- storage/ahcid/Cargo.toml | 1 - storage/ahcid/src/main.rs | 12 ++-- storage/bcm2835-sdhcid/Cargo.toml | 1 - storage/bcm2835-sdhcid/src/main.rs | 2 +- storage/ided/Cargo.toml | 1 - storage/ided/src/main.rs | 20 +++---- storage/lived/Cargo.toml | 1 - storage/lived/src/main.rs | 14 ++--- storage/nvmed/Cargo.toml | 1 - storage/nvmed/src/main.rs | 12 ++-- storage/nvmed/src/nvme/cq_reactor.rs | 4 +- storage/usbscsid/Cargo.toml | 1 - storage/usbscsid/src/main.rs | 5 +- storage/virtio-blkd/Cargo.toml | 1 - storage/virtio-blkd/src/main.rs | 6 +- vboxd/Cargo.toml | 3 +- vboxd/src/main.rs | 9 +-- virtio-core/Cargo.toml | 1 - virtio-core/src/arch/x86.rs | 2 +- virtio-core/src/arch/x86_64.rs | 2 +- virtio-core/src/transport.rs | 8 ++- xhcid/Cargo.toml | 5 +- xhcid/src/main.rs | 65 ++++++++++++---------- xhcid/src/xhci/context.rs | 2 +- xhcid/src/xhci/irq_reactor.rs | 18 +++--- xhcid/src/xhci/mod.rs | 8 ++- 79 files changed, 238 insertions(+), 323 deletions(-) mode change 100644 => 100755 audio/ihdad/Cargo.toml diff --git a/Cargo.lock b/Cargo.lock index a049a93f31..29c7c216d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,13 +8,12 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", - "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", "redox_event 0.1.0", - "redox_syscall 0.5.1", + "redox_syscall 0.4.1", "spin", ] @@ -25,7 +24,6 @@ dependencies = [ "aml", "amlserde", "common", - "libredox 0.1.3", "log", "num-derive", "num-traits", @@ -47,7 +45,6 @@ dependencies = [ "byteorder", "common", "driver-block", - "libredox 0.1.3", "log", "pcid", "redox-daemon", @@ -61,10 +58,9 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", - "libredox 0.1.3", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.5.1", + "redox_syscall 0.4.1", ] [[package]] @@ -155,7 +151,6 @@ dependencies = [ "common", "driver-block", "fdt 0.1.5", - "libredox 0.1.3", "redox-daemon", "redox_syscall 0.4.1", ] @@ -164,7 +159,6 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ - "libredox 0.1.3", "orbclient", "pcid", "redox-daemon", @@ -286,8 +280,7 @@ dependencies = [ name = "common" version = "0.1.0" dependencies = [ - "libredox 0.1.3", - "redox_syscall 0.5.1", + "redox_syscall 0.4.1", ] [[package]] @@ -363,9 +356,8 @@ dependencies = [ name = "driver-network" version = "0.1.0" dependencies = [ - "libredox 0.1.3", "redox_event 0.1.0", - "redox_syscall 0.5.1", + "redox_syscall 0.4.1", ] [[package]] @@ -375,11 +367,10 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", - "libredox 0.1.3", "pcid", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.5.1", + "redox_syscall 0.4.1", ] [[package]] @@ -393,7 +384,6 @@ name = "fbcond" version = "0.1.0" dependencies = [ "inputd", - "libredox 0.1.3", "orbclient", "ransid", "redox-daemon", @@ -592,7 +582,6 @@ version = "0.1.0" dependencies = [ "common", "driver-block", - "libredox 0.1.3", "log", "pcid", "redox-daemon", @@ -606,7 +595,6 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", - "libredox 0.1.3", "log", "pcid", "redox-daemon", @@ -631,12 +619,11 @@ name = "inputd" version = "0.1.0" dependencies = [ "anyhow", - "libredox 0.1.3", "log", "orbclient", "redox-daemon", "redox-log", - "redox_syscall 0.5.1", + "redox_syscall 0.4.1", "spin", ] @@ -662,11 +649,10 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", - "libredox 0.1.3", "pcid", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.5.1", + "redox_syscall 0.4.1", ] [[package]] @@ -703,13 +689,12 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "138adbe77ccf68e1925b6ed3cc45e83a6845f17a687d6061ddeb518e9b756440" dependencies = [ "bitflags 2.4.2", "libc", - "redox_syscall 0.5.1", ] [[package]] @@ -717,7 +702,6 @@ name = "lived" version = "0.1.0" dependencies = [ "anyhow", - "libredox 0.1.3", "redox-daemon", "redox_syscall 0.4.1", "slab", @@ -787,7 +771,6 @@ dependencies = [ "crossbeam-channel", "driver-block", "futures", - "libredox 0.1.3", "log", "partitionlib", "pcid", @@ -934,7 +917,6 @@ dependencies = [ "common", "fdt 0.1.0", "libc", - "libredox 0.1.3", "log", "paw", "pci_types", @@ -952,7 +934,6 @@ dependencies = [ name = "pcspkrd" version = "0.1.0" dependencies = [ - "libredox 0.1.3", "redox-daemon", "redox_syscall 0.4.1", ] @@ -1013,7 +994,6 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 1.3.2", - "libredox 0.1.3", "orbclient", "redox-daemon", "redox_syscall 0.4.1", @@ -1087,7 +1067,7 @@ version = "0.1.3" source = "git+https://gitlab.redox-os.org/redox-os/redox-daemon.git#31ab115cf17d6fe333515bfe19ac477352a1dcc0" dependencies = [ "libc", - "libredox 0.1.3", + "libredox 0.1.0", ] [[package]] @@ -1121,16 +1101,6 @@ dependencies = [ "redox_syscall 0.4.1", ] -[[package]] -name = "redox_event" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69609faa5d5992247a4ef379917bb3e39be281405d6a0ccd4f942429400b956f" -dependencies = [ - "bitflags 2.4.2", - "libredox 0.1.3", -] - [[package]] name = "redox_syscall" version = "0.2.16" @@ -1158,15 +1128,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "redox_syscall" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" -dependencies = [ - "bitflags 2.4.2", -] - [[package]] name = "redox_termios" version = "0.1.2" @@ -1183,13 +1144,12 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", - "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", "redox_event 0.1.0", - "redox_syscall 0.5.1", + "redox_syscall 0.4.1", ] [[package]] @@ -1199,13 +1159,12 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", - "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", "redox_event 0.1.0", - "redox_syscall 0.5.1", + "redox_syscall 0.4.1", ] [[package]] @@ -1226,7 +1185,6 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", - "libredox 0.1.3", "log", "redox-daemon", "redox-log", @@ -1568,7 +1526,6 @@ name = "usbscsid" version = "0.1.0" dependencies = [ "base64", - "libredox 0.1.3", "plain", "redox-daemon", "redox_syscall 0.4.1", @@ -1602,12 +1559,11 @@ name = "vboxd" version = "0.1.0" dependencies = [ "common", - "libredox 0.1.3", "orbclient", "pcid", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.5.1", + "redox_syscall 0.4.1", ] [[package]] @@ -1634,7 +1590,6 @@ version = "0.1.0" dependencies = [ "common", "inputd", - "libredox 0.1.3", "orbclient", "ransid", "redox-daemon", @@ -1649,7 +1604,6 @@ dependencies = [ "common", "driver-block", "futures", - "libredox 0.1.3", "log", "partitionlib", "pcid", @@ -1670,7 +1624,6 @@ dependencies = [ "common", "crossbeam-queue", "futures", - "libredox 0.1.3", "log", "pcid", "redox-log", @@ -1688,7 +1641,6 @@ dependencies = [ "common", "futures", "inputd", - "libredox 0.1.3", "log", "orbclient", "paste", @@ -1707,11 +1659,10 @@ dependencies = [ "common", "driver-network", "futures", - "libredox 0.1.3", "log", "pcid", "redox-daemon", - "redox_syscall 0.5.1", + "redox_syscall 0.4.1", "static_assertions", "virtio-core", ] @@ -1901,14 +1852,13 @@ dependencies = [ "crossbeam-channel", "futures", "lazy_static", - "libredox 0.1.3", "log", "pcid", "plain", "redox-daemon", "redox-log", - "redox_event 0.4.1", - "redox_syscall 0.5.1", + "redox_event 0.1.0", + "redox_syscall 0.4.1", "serde", "serde_json", "smallvec 1.11.0", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 23db6931f5..92a6e8027d 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -22,4 +22,3 @@ serde_json = "1.0.94" amlserde = { path = "../amlserde" } common = { path = "../common" } -libredox = "0.1.3" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 6f73bab115..9bd620ef6d 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -124,7 +124,7 @@ impl Deref for PhysmapGuard { impl Drop for PhysmapGuard { fn drop(&mut self) { unsafe { - let _ = libredox::call::munmap(self.virt as *mut (), self.size); + let _ = syscall::funmap(self.virt as usize, self.size); } } } diff --git a/acpid/src/acpi/dmar/drhd.rs b/acpid/src/acpi/dmar/drhd.rs index 70c8f8b42b..091f553e95 100644 --- a/acpid/src/acpi/dmar/drhd.rs +++ b/acpid/src/acpi/dmar/drhd.rs @@ -35,7 +35,7 @@ impl DerefMut for DrhdPage { impl Drop for DrhdPage { fn drop(&mut self) { unsafe { - let _ = libredox::call::munmap(self.virt.cast(), crate::acpi::PAGE_SIZE); + let _ = syscall::funmap(self.virt as usize, crate::acpi::PAGE_SIZE); } } } diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 6658de3ee7..98d78f1910 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -29,7 +29,7 @@ impl MappedPage { impl Drop for MappedPage { fn drop(&mut self) { log::trace!("Drop page {:#x}", self.phys_page); - if let Err(e) = unsafe { libredox::call::munmap(self.virt_page as *mut (), PAGE_SIZE) } { + if let Err(e) = unsafe { syscall::funmap(self.virt_page, PAGE_SIZE) } { log::error!("funmap (phys): {:?}", e); } } @@ -212,7 +212,7 @@ impl aml::Handler for AmlPhysMemHandler { } } - // Pio must be enabled via syscall::iopl + // Pio must be enabled via syscall::iopl(3) fn read_io_u8(&self, port: u16) -> u8 { Pio::::new(port).read() } diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 93c54f9558..e4c8711045 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -113,8 +113,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let acpi_context = self::acpi::AcpiContext::init(physaddrs_iter); - // TODO: I/O permission bitmap? - common::acquire_port_io_rights().expect("acpid: failed to set I/O privilege level to Ring 3"); + // TODO: I/O permission bitmap + unsafe { syscall::iopl(3) }.expect("acpid: failed to set I/O privilege level to Ring 3"); let shutdown_pipe = File::open("kernel.acpi:kstop") .expect("acpid: failed to open `kernel.acpi:kstop`"); @@ -136,7 +136,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("acpid: failed to notify parent"); - libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace"); + syscall::setrens(0, 0).expect("acpid: failed to enter null namespace"); let _ = event_queue.write(&Event { id: shutdown_pipe.as_raw_fd() as usize, diff --git a/audio/ac97d/Cargo.toml b/audio/ac97d/Cargo.toml index 50b781cfca..4d780d5d99 100644 --- a/audio/ac97d/Cargo.toml +++ b/audio/ac97d/Cargo.toml @@ -10,8 +10,7 @@ log = "0.4" redox-daemon = "0.1" redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.5" +redox_syscall = "0.4" spin = "0.9" pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index 8649e671d6..2a26dc193b 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -13,7 +13,6 @@ use std::sync::Arc; use std::usize; use event::EventQueue; -use libredox::flag; use pcid_interface::{PciBar, PcidServerHandle}; use redox_log::{OutputBuilder, RedoxLogger}; use syscall::{EventFlags, Packet, SchemeBlockMut}; @@ -85,19 +84,19 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let _logger_ref = setup_logging(); - common::acquire_port_io_rights().expect("ac97d: failed to set I/O privilege level to Ring 3"); + unsafe { syscall::iopl(3) }.expect("ac97d: failed to set I/O privilege level to Ring 3"); let mut irq_file = irq.irq_handle("ac97d"); let device = Arc::new(RefCell::new(unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") })); - let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ac97d: failed to create hda scheme"); + let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ac97d: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); daemon.ready().expect("ac97d: failed to signal readiness"); let mut event_queue = EventQueue::::new().expect("ac97d: Could not create event queue."); - libredox::call::setrens(0, 0).expect("ac97d: failed to enter null namespace"); + syscall::setrens(0, 0).expect("ac97d: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -168,7 +167,7 @@ fn main() { for event_count in event_queue.trigger_all(event::Event { fd: 0, - flags: Default::default(), + flags: EventFlags::empty(), }).expect("ac97d: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, diff --git a/audio/ihdad/Cargo.toml b/audio/ihdad/Cargo.toml old mode 100644 new mode 100755 index 736e98d31e..32f294d95a --- a/audio/ihdad/Cargo.toml +++ b/audio/ihdad/Cargo.toml @@ -14,4 +14,3 @@ spin = "0.9" common = { path = "../../common" } pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index bb29a49007..7eeba58e2a 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -10,7 +10,6 @@ use std::usize; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use libredox::flag; use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; @@ -163,13 +162,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { | (pci_config.func.full_device_id.device_id as u32); let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); - let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ihdad: failed to create hda scheme"); + let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ihdad: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); daemon.ready().expect("ihdad: failed to signal readiness"); let mut event_queue = EventQueue::::new().expect("ihdad: Could not create event queue."); - libredox::call::setrens(0, 0).expect("ihdad: failed to enter null namespace"); + syscall::setrens(0, 0).expect("ihdad: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); diff --git a/audio/pcspkrd/Cargo.toml b/audio/pcspkrd/Cargo.toml index 72bae14204..8f355d4e53 100644 --- a/audio/pcspkrd/Cargo.toml +++ b/audio/pcspkrd/Cargo.toml @@ -7,4 +7,3 @@ edition = "2018" [dependencies] redox_syscall = "0.4" redox-daemon = "0.1" -libredox = "0.1.3" diff --git a/audio/pcspkrd/src/main.rs b/audio/pcspkrd/src/main.rs index 75957745c3..7f9bfc1e40 100644 --- a/audio/pcspkrd/src/main.rs +++ b/audio/pcspkrd/src/main.rs @@ -29,7 +29,7 @@ fn main() { next_id: 0, }; - libredox::call::setrens(0, 0).expect("pcspkrd: failed to enter null namespace"); + syscall::setrens(0, 0).expect("pcspkrd: failed to enter null namespace"); loop { let mut packet = Packet::default(); diff --git a/audio/sb16d/Cargo.toml b/audio/sb16d/Cargo.toml index eb5a92a6e8..ccabfa3514 100644 --- a/audio/sb16d/Cargo.toml +++ b/audio/sb16d/Cargo.toml @@ -6,7 +6,6 @@ edition = "2018" [dependencies] bitflags = "1" common = { path = "../../common" } -libredox = "0.1.3" log = "0.4" redox-daemon = "0.1" redox-log = "0.1" diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index 814ed2066d..6671ac9b39 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -9,7 +9,6 @@ use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use libredox::flag; use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; @@ -75,10 +74,10 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let _logger_ref = setup_logging(); - common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights"); + unsafe { syscall::iopl(3) }.expect("sb16d: failed to set I/O privilege level to Ring 3"); let device = Arc::new(RefCell::new(unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") })); - let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("sb16d: failed to create hda scheme"); + let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("sb16d: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); //TODO: error on multiple IRQs? @@ -91,7 +90,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); - libredox::call::setrens(0, 0).expect("sb16d: failed to enter null namespace"); + syscall::setrens(0, 0).expect("sb16d: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -99,8 +98,6 @@ fn main() { let device_irq = device.clone(); let socket_irq = socket.clone(); - // TODO: Use new event queue API - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; diff --git a/common/Cargo.toml b/common/Cargo.toml index c1a072fa5d..02b611d345 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -8,5 +8,4 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libredox = "0.1.3" -redox_syscall = "0.5" +redox_syscall = "0.4" diff --git a/common/src/dma.rs b/common/src/dma.rs index 1adbbc6392..ec06623360 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -2,10 +2,10 @@ use std::mem::{self, size_of, MaybeUninit}; use std::ops::{Deref, DerefMut}; use std::ptr; -use libredox::call::MmapArgs; -use libredox::{flag, error::Result, Fd}; use syscall::PAGE_SIZE; +use syscall::Result; + use crate::MemoryType; const DMA_MEMTY: MemoryType = { @@ -20,26 +20,30 @@ const DMA_MEMTY: MemoryType = { } }; -fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> { - assert_eq!(length % PAGE_SIZE, 0); +fn alloc_and_map(len: usize) -> Result<(usize, *mut ())> { + assert_eq!(len % PAGE_SIZE, 0); unsafe { - let fd = Fd::open( - &format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), - flag::O_CLOEXEC, - 0, + let fd = syscall::open( + format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), + syscall::O_CLOEXEC, )?; - let virt = libredox::call::mmap(MmapArgs { - fd: fd.raw(), - offset: 0, // ignored - addr: core::ptr::null_mut(), // ignored - length, - flags: flag::MAP_PRIVATE, - prot: flag::PROT_READ | flag::PROT_WRITE, - })?; - let phys = syscall::virttophys(virt as usize)?; - for i in 1..length.div_ceil(PAGE_SIZE) { - debug_assert_eq!(syscall::virttophys(virt as usize + i * PAGE_SIZE), Ok(phys + i * PAGE_SIZE), "NOT CONTIGUOUS"); - } + let virt = syscall::fmap( + fd, + &syscall::Map { + offset: 0, // ignored + address: 0, // ignored + size: len, + flags: syscall::MapFlags::MAP_PRIVATE + | syscall::MapFlags::PROT_READ + | syscall::MapFlags::PROT_WRITE, + }, + ); + let _ = syscall::close(fd); + let virt = virt?; + let phys = syscall::virttophys(virt)?; + /*for i in 1..len.div_ceil(PAGE_SIZE) { + assert_eq!(syscall::virttophys(virt + i * PAGE_SIZE), Ok(phys + i * PAGE_SIZE), "NOT CONTIGUOUS"); + }*/ Ok((phys, virt as *mut ())) } } @@ -155,7 +159,7 @@ impl Drop for Dma { fn drop(&mut self) { unsafe { ptr::drop_in_place(self.virt); - let _ = libredox::call::munmap(self.virt as *mut (), self.aligned_len); + let _ = syscall::funmap(self.virt as *mut u8 as usize, self.aligned_len); } } } diff --git a/common/src/lib.rs b/common/src/lib.rs index 2107a08660..2a9240f193 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,8 +1,7 @@ #![feature(int_roundings)] -use libredox::call::MmapArgs; -use libredox::{Fd, error::*, errno::EINVAL}; -use libredox::flag::{self, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; +use syscall::error::{Error, Result, EINVAL}; +use syscall::flag::{MapFlags, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; use syscall::PAGE_SIZE; pub mod dma; @@ -64,23 +63,23 @@ pub unsafe fn physmap( (false, true) => O_WRONLY, (false, false) => return Err(Error::new(EINVAL)), }; - let mut prot = 0; - if read { - prot |= flag::PROT_READ; - } - if write { - prot |= flag::PROT_WRITE; - } + let mut prot = MapFlags::empty(); + prot.set(MapFlags::PROT_READ, read); + prot.set(MapFlags::PROT_WRITE, write); - let fd = Fd::open(&path, O_CLOEXEC | mode, 0)?; - Ok(libredox::call::mmap(MmapArgs { - fd: fd.raw(), - offset: base_phys as u64, - length: len.next_multiple_of(PAGE_SIZE), - flags: flag::MAP_SHARED, - prot, - addr: core::ptr::null_mut(), - })? as *mut ()) + let file = syscall::open(path, O_CLOEXEC | mode)?; + let base = syscall::fmap( + file, + &syscall::Map { + offset: base_phys, + size: len.next_multiple_of(PAGE_SIZE), + flags: MapFlags::MAP_SHARED | prot, + address: 0, + }, + ); + let _ = syscall::close(file); + + Ok(base? as *mut ()) } impl std::fmt::Display for MemoryType { @@ -120,14 +119,7 @@ impl PhysBorrowed { impl Drop for PhysBorrowed { fn drop(&mut self) { unsafe { - let _ = libredox::call::munmap(self.mem, self.len); + let _ = syscall::funmap(self.mem as usize, self.len); } } } - -pub fn acquire_port_io_rights() -> Result<()> { - unsafe { - syscall::iopl(3)?; - } - Ok(()) -} diff --git a/graphics/bgad/Cargo.toml b/graphics/bgad/Cargo.toml index 0c439fd17a..afa6619215 100644 --- a/graphics/bgad/Cargo.toml +++ b/graphics/bgad/Cargo.toml @@ -9,4 +9,3 @@ redox-daemon = "0.1" redox_syscall = "0.4" pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index a80423f392..18ac70df34 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -42,7 +42,7 @@ fn main() { scheme.update_size(); - libredox::call::setrens(0, 0).expect("bgad: failed to enter null namespace"); + syscall::setrens(0, 0).expect("bgad: failed to enter null namespace"); daemon.ready().expect("bgad: failed to notify parent"); diff --git a/graphics/fbcond/Cargo.toml b/graphics/fbcond/Cargo.toml index fb930d8ab8..d934921104 100644 --- a/graphics/fbcond/Cargo.toml +++ b/graphics/fbcond/Cargo.toml @@ -11,7 +11,6 @@ redox_syscall = "0.4" redox-daemon = "0.1" inputd = { path = "../../inputd" } -libredox = "0.1.3" [features] default = [] diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index e2d3798046..da16fe5804 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -8,7 +8,6 @@ use std::{ os::unix::io::{AsRawFd, FromRawFd}, slice, }; -use libredox::flag; use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; // Keep synced with vesad @@ -23,14 +22,15 @@ pub struct SyncRect { fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Result<*mut [u32]> { unsafe { - let display_ptr = libredox::call::mmap(libredox::call::MmapArgs { - fd: display_fd, - offset: 0, - length: (width * height * 4), - prot: flag::PROT_READ | flag::PROT_WRITE, - flags: flag::MAP_SHARED, - addr: core::ptr::null_mut(), - })?; + let display_ptr = syscall::fmap( + display_fd, + &syscall::Map { + offset: 0, + size: (width * height * 4), + flags: syscall::PROT_READ | syscall::PROT_WRITE | syscall::MAP_SHARED, + address: 0, + }, + )?; let display_slice = slice::from_raw_parts_mut(display_ptr as *mut u32, width * height); Ok(display_slice) } @@ -38,7 +38,7 @@ fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Re unsafe fn display_fd_unmap(image: *mut [u32], size: usize) { // FIXME use image.len() instead of size once it is stable. - let _ = libredox::call::munmap(image as *mut (), size * 4); + let _ = syscall::funmap(image as *mut u32 as usize, size * 4); } pub struct Display { @@ -59,7 +59,7 @@ impl Display { .open(format!("input:consumer/{vt}"))?; let fd = input_handle.as_raw_fd(); - let written = libredox::call::fpath(fd as usize, &mut buffer) + let written = syscall::fpath(fd as usize, &mut buffer) .expect("init: failed to get the path to the display device"); assert!(written <= buffer.len()); @@ -67,7 +67,7 @@ impl Display { let display_path = std::str::from_utf8(&buffer[..written]).expect("init: display path UTF-8 check failed"); - let display_file = libredox::call::open(display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) + let display_file = syscall::open(display_path, O_CLOEXEC | O_NONBLOCK | O_RDWR) .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) .unwrap_or_else(|err| { panic!("failed to open display {}: {}", display_path, err); @@ -75,7 +75,7 @@ impl Display { let mut buf: [u8; 4096] = [0; 4096]; let count = - libredox::call::fpath(display_file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| { + syscall::fpath(display_file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| { panic!("Could not read display path with fpath(): {e}"); }); @@ -138,7 +138,7 @@ impl Display { pub fn sync_rect(&mut self, sync_rect: SyncRect) -> syscall::Result<()> { unsafe { - libredox::call::write( + syscall::write( self.display_file.as_raw_fd().as_raw_fd() as usize, slice::from_raw_parts( &sync_rect as *const SyncRect as *const u8, diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 4db9e1b5fc..cd0a859810 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -53,7 +53,7 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { let mut scheme = FbconScheme::new(vt_ids, &mut event_queue); - libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace"); + syscall::setrens(0, 0).expect("fbcond: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index 7f75c6fbc5..bdc24d66f5 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -320,7 +320,7 @@ impl TextScreen { })?; } self.changed.clear(); - libredox::call::fsync(self.display.display_file.as_raw_fd().as_raw_fd() as usize)?; + syscall::fsync(self.display.display_file.as_raw_fd().as_raw_fd() as usize)?; Ok(buf.len()) } diff --git a/graphics/vesad/Cargo.toml b/graphics/vesad/Cargo.toml index da97862697..5d6542ccf5 100644 --- a/graphics/vesad/Cargo.toml +++ b/graphics/vesad/Cargo.toml @@ -11,7 +11,6 @@ redox-daemon = "0.1" common = { path = "../../common" } inputd = { path = "../../inputd" } -libredox = "0.1.3" [features] default = [] diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 2b6fd953c4..9f1d8f2901 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -88,7 +88,7 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( let mut scheme = DisplayScheme::new(framebuffers, &spec); - libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); + syscall::setrens(0, 0).expect("vesad: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 4b94801b16..7f12cf0f9c 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -95,7 +95,7 @@ impl DisplayScheme { // Unmap old onscreen unsafe { let slice = mem::take(&mut self.onscreens[fb_i]); - libredox::call::munmap(slice.as_mut_ptr().cast(), (slice.len() * 4).next_multiple_of(PAGE_SIZE)).expect("vesad: failed to unmap framebuffer"); + syscall::funmap(slice.as_mut_ptr() as usize, (slice.len() * 4).next_multiple_of(PAGE_SIZE)).expect("vesad: failed to unmap framebuffer"); } // Map new onscreen diff --git a/graphics/virtio-gpud/Cargo.toml b/graphics/virtio-gpud/Cargo.toml index 7d9d17b2f5..a51e8b5a7a 100644 --- a/graphics/virtio-gpud/Cargo.toml +++ b/graphics/virtio-gpud/Cargo.toml @@ -20,4 +20,3 @@ redox-daemon = "0.1" redox_syscall = "0.4" orbclient = "0.3.27" spin = "0.9.8" -libredox = "0.1.3" diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index 9b900edc13..e88ab86f9e 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -7,9 +7,8 @@ authors = ["Anhad Singh "] [dependencies] anyhow = "1.0.71" log = "0.4.19" -redox-daemon = "0.1.2" +redox-daemon = "0.1.0" redox-log = "0.1.1" -redox_syscall = "0.5" +redox_syscall = "0.4" orbclient = "0.3.27" spin = "0.9.8" -libredox = "0.1.3" diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 3112964993..4a52c09403 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -91,7 +91,7 @@ impl Cmd { } } -pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), libredox::error::Error> { +pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), syscall::Error> { use std::os::fd::AsRawFd; let mut result = vec![]; @@ -119,7 +119,7 @@ pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), libredox::error: } }; - let written = libredox::call::write(file.as_raw_fd() as usize, &result)?; + let written = syscall::write(file.as_raw_fd() as usize, &result)?; // XXX: Ensure all of the data is written. assert_eq!(written, result.len()); diff --git a/inputd/src/main.rs b/inputd/src/main.rs index e8b34c9585..23f6b7b4e3 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -535,7 +535,7 @@ pub fn main() { .expect("inputd: failed to open consumer handle"); let mut display_path = [0; 4096]; - let written = libredox::call::fpath(handle.as_raw_fd() as usize, &mut display_path) + let written = syscall::fpath(handle.as_raw_fd() as usize, &mut display_path) .expect("inputd: fpath() failed"); assert!(written <= display_path.len()); diff --git a/net/alxd/Cargo.toml b/net/alxd/Cargo.toml index 5d20a58d5b..4a3ed09f03 100644 --- a/net/alxd/Cargo.toml +++ b/net/alxd/Cargo.toml @@ -6,8 +6,7 @@ edition = "2018" [dependencies] bitflags = "1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.5" +redox_syscall = "0.4" redox-daemon = "0.1" common = { path = "../../common" } -libredox = "0.1.3" diff --git a/net/alxd/src/device/mod.rs b/net/alxd/src/device/mod.rs index 0222cd1c27..3a20c9fc81 100644 --- a/net/alxd/src/device/mod.rs +++ b/net/alxd/src/device/mod.rs @@ -281,7 +281,7 @@ pub struct Alx { fn dma_array() -> Result<[Dma; N]> { Ok((0..N) - .map(|_| Ok(Dma::zeroed().map(|dma| unsafe { dma.assume_init() })?)) + .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!())) @@ -290,7 +290,7 @@ fn dma_array() -> Result<[Dma; N]> { impl Alx { pub unsafe fn new(base: usize) -> Result { let mut module = Alx { - base, + base: base, vendor_id: 0, device_id: 0, diff --git a/net/alxd/src/main.rs b/net/alxd/src/main.rs index 8ff8e18c52..ef1f745681 100644 --- a/net/alxd/src/main.rs +++ b/net/alxd/src/main.rs @@ -14,7 +14,6 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; -use libredox::flag; use syscall::{EventFlags, Packet, SchemeMut}; use syscall::error::EWOULDBLOCK; @@ -36,7 +35,7 @@ fn main() { // Daemonize redox_daemon::Daemon::new(move |daemon| { - let socket_fd = libredox::call::open(":network", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("alxd: failed to create network scheme"); + let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("alxd: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); daemon.ready().expect("alxd: failed to signal readiness"); @@ -49,7 +48,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("alxd: failed to create event queue"); - libredox::call::setrens(0, 0).expect("alxd: failed to enter null namespace"); + syscall::setrens(0, 0).expect("alxd: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -112,7 +111,7 @@ fn main() { for event_count in event_queue.trigger_all(event::Event { fd: 0, - flags: Default::default(), + flags: EventFlags::empty(), }).expect("alxd: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, diff --git a/net/driver-network/Cargo.toml b/net/driver-network/Cargo.toml index 965bbcf23c..47be9d3175 100644 --- a/net/driver-network/Cargo.toml +++ b/net/driver-network/Cargo.toml @@ -4,6 +4,5 @@ version = "0.1.0" edition = "2021" [dependencies] -libredox = "0.1.3" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.5" +redox_syscall = "0.4" diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index ce108dcd70..3790b33ba5 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -4,7 +4,6 @@ use std::io::{ErrorKind, Read, Write}; use std::os::fd::{AsRawFd, FromRawFd, RawFd}; use std::{cmp, io}; -use libredox::flag; use syscall::{ Error, EventFlags, Packet, Result, SchemeBlockMut, Stat, EACCES, EBADF, EINVAL, EWOULDBLOCK, MODE_FILE, O_NONBLOCK, @@ -47,10 +46,9 @@ enum Handle { impl NetworkScheme { pub fn new(adapter: T, scheme_name: String) -> Self { assert!(scheme_name.starts_with("network")); - let scheme_fd = libredox::call::open( + let scheme_fd = syscall::open( format!(":{scheme_name}"), - flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, - 0, + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, ) .expect("failed to create network scheme"); let scheme = unsafe { File::from_raw_fd(scheme_fd as RawFd) }; diff --git a/net/e1000d/Cargo.toml b/net/e1000d/Cargo.toml index bc6c347647..395a6341cc 100644 --- a/net/e1000d/Cargo.toml +++ b/net/e1000d/Cargo.toml @@ -7,9 +7,8 @@ edition = "2018" bitflags = "1" redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.5" +redox_syscall = "0.4" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/net/e1000d/src/device.rs b/net/e1000d/src/device.rs index 721e7cf913..7da6965d13 100644 --- a/net/e1000d/src/device.rs +++ b/net/e1000d/src/device.rs @@ -208,7 +208,7 @@ impl NetworkAdapter for Intel8254x { fn dma_array() -> Result<[Dma; N]> { Ok((0..N) - .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) + .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!())) diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index 8c532f3c68..b8052b93f3 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -43,7 +43,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); - libredox::call::setrens(0, 0).expect("e1000d: failed to enter null namespace"); + syscall::setrens(0, 0).expect("e1000d: failed to enter null namespace"); daemon .ready() @@ -79,7 +79,7 @@ fn main() { event_queue .trigger_all(event::Event { fd: 0, - flags: Default::default(), + flags: EventFlags::empty(), }) .expect("e1000d: failed to trigger events"); diff --git a/net/ixgbed/Cargo.toml b/net/ixgbed/Cargo.toml index 38ee7a7477..fd3258fa00 100644 --- a/net/ixgbed/Cargo.toml +++ b/net/ixgbed/Cargo.toml @@ -6,10 +6,9 @@ edition = "2021" [dependencies] bitflags = "1.0" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.5" +redox_syscall = "0.4" redox-daemon = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/net/ixgbed/src/device.rs b/net/ixgbed/src/device.rs index 4ab8d0e530..b36309e14f 100644 --- a/net/ixgbed/src/device.rs +++ b/net/ixgbed/src/device.rs @@ -129,13 +129,13 @@ impl Intel8259x { base, size, receive_buffer: (0..32) - .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) + .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), receive_ring: unsafe { Dma::zeroed()?.assume_init() }, transmit_buffer: (0..32) - .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) + .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index 7c6aefbb27..33c67083bd 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -55,7 +55,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("ixgbed: failed to create event queue"); - libredox::call::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); + syscall::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); daemon .ready() @@ -91,7 +91,7 @@ fn main() { event_queue .trigger_all(event::Event { fd: 0, - flags: Default::default(), + flags: EventFlags::empty(), }) .expect("ixgbed: failed to trigger events"); diff --git a/net/rtl8139d/Cargo.toml b/net/rtl8139d/Cargo.toml index ef23f408db..2ff86321ab 100644 --- a/net/rtl8139d/Cargo.toml +++ b/net/rtl8139d/Cargo.toml @@ -7,11 +7,10 @@ edition = "2018" bitflags = "1" log = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.5" +redox_syscall = "0.4" redox-daemon = "0.1" redox-log = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/net/rtl8139d/src/device.rs b/net/rtl8139d/src/device.rs index e6ef45053b..4b6ce854f0 100644 --- a/net/rtl8139d/src/device.rs +++ b/net/rtl8139d/src/device.rs @@ -209,13 +209,13 @@ impl Rtl8139 { let regs = Regs::from_base(base); let mut module = Rtl8139 { - regs, + regs: regs, //TODO: limit to 32-bit receive_buffer: Dma::zeroed().map(|dma| dma.assume_init())?, receive_i: 0, //TODO: limit to 32-bit transmit_buffer: (0..4) - .map(|_| Ok(Dma::zeroed()?.assume_init())) + .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 66ca3b533e..048daf6d95 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -242,7 +242,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut event_queue = EventQueue::::new().expect("rtl8139d: failed to create event queue"); - libredox::call::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); + syscall::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); daemon .ready() @@ -279,7 +279,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { event_queue .trigger_all(event::Event { fd: 0, - flags: Default::default(), + flags: EventFlags::empty(), }) .expect("rtl8139d: failed to trigger events"); diff --git a/net/rtl8168d/Cargo.toml b/net/rtl8168d/Cargo.toml index 2010b02b47..3ec1bdfbcf 100644 --- a/net/rtl8168d/Cargo.toml +++ b/net/rtl8168d/Cargo.toml @@ -7,11 +7,10 @@ edition = "2018" bitflags = "1" log = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.5" +redox_syscall = "0.4" redox-daemon = "0.1" redox-log = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/net/rtl8168d/src/device.rs b/net/rtl8168d/src/device.rs index 717ac194e2..25b6aea64a 100644 --- a/net/rtl8168d/src/device.rs +++ b/net/rtl8168d/src/device.rs @@ -173,9 +173,9 @@ impl Rtl8168 { assert_eq!(®s.mtps as *const _ as usize - base, 0xEC); let mut module = Rtl8168 { - regs, + regs: regs, receive_buffer: (0..64) - .map(|_| Ok(Dma::zeroed()?.assume_init())) + .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), @@ -183,7 +183,7 @@ impl Rtl8168 { receive_ring: Dma::zeroed()?.assume_init(), receive_i: 0, transmit_buffer: (0..16) - .map(|_| Ok(Dma::zeroed()?.assume_init())) + .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index e38501b3ec..3767f2ddad 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -237,7 +237,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut event_queue = EventQueue::::new().expect("rtl8168d: failed to create event queue"); - libredox::call::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); + syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); daemon .ready() @@ -274,7 +274,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { event_queue .trigger_all(event::Event { fd: 0, - flags: Default::default(), + flags: EventFlags::empty(), }) .expect("rtl8168d: failed to trigger events"); diff --git a/net/virtio-netd/Cargo.toml b/net/virtio-netd/Cargo.toml index 3becfd7897..e1063e7414 100644 --- a/net/virtio-netd/Cargo.toml +++ b/net/virtio-netd/Cargo.toml @@ -14,5 +14,4 @@ common = { path = "../../common" } driver-network = { path = "../driver-network" } redox-daemon = "0.1" -redox_syscall = "0.5" -libredox = "0.1.3" +redox_syscall = "0.4" diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index d2a2411f55..f00437a763 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -102,7 +102,7 @@ fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box data: 0, })?; - libredox::call::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); + syscall::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); daemon.ready().expect("virtio-netd: failed to daemonize"); diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 487b79029d..a4ae567e9d 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -31,4 +31,3 @@ thiserror = "1" toml = "0.5" common = { path = "../common" } -libredox = "0.1.3" diff --git a/pcid/src/cfg_access/fallback.rs b/pcid/src/cfg_access/fallback.rs index c1d51bfb5c..65682e171f 100644 --- a/pcid/src/cfg_access/fallback.rs +++ b/pcid/src/cfg_access/fallback.rs @@ -33,7 +33,9 @@ impl Pci { "PCI: couldn't find or access PCIe extended configuration, \ and thus falling back to PCI 3.0 io ports" ); - common::acquire_port_io_rights().expect("pcid: failed to get IO port rights"); + unsafe { + syscall::iopl(3).expect("pcid: failed to set iopl to 3"); + } } }); } diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 90f5875711..cfab793a52 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -8,4 +8,3 @@ bitflags = "1" orbclient = "0.3.27" redox_syscall = "0.4" redox-daemon = "0.1" -libredox = "0.1.3" diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index aa4ec5df2c..f9cdba3b6b 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -80,7 +80,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { data: 1 }).expect("ps2d: failed to event irq:12"); - libredox::call::setrens(0, 0).expect("ps2d: failed to enter null namespace"); + syscall::setrens(0, 0).expect("ps2d: failed to enter null namespace"); daemon.ready().expect("ps2d: failed to mark daemon as ready"); diff --git a/storage/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml index eb8e450c77..4c84077667 100644 --- a/storage/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -14,4 +14,3 @@ redox_syscall = "0.4" common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 050fa97bf4..60dd30ab12 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -10,7 +10,6 @@ use std::os::fd::AsRawFd; use std::os::unix::io::{FromRawFd, RawFd}; use std::usize; -use libredox::flag; use pcid_interface::PcidServerHandle; use syscall::error::{Error, ENODEV}; use syscall::data::{Event, Packet}; @@ -94,10 +93,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { bar.physmap_mem("ahcid") }; { let scheme_name = format!("disk.{}", name); - let socket_fd = libredox::call::open( + let socket_fd = syscall::open( &format!(":{}", scheme_name), - flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK - 0, + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK ).expect("ahcid: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; @@ -106,7 +104,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); - libredox::call::setrens(0, 0).expect("ahcid: failed to enter null namespace"); + syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace"); + + daemon.ready().expect("ahcid: failed to notify parent"); event_file.write(&Event { id: socket_fd, @@ -120,8 +120,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { data: 0 }).expect("ahcid: failed to event irq scheme"); - daemon.ready().expect("ahcid: failed to notify parent"); - let (hba_mem, disks) = ahci::disks(address as usize, &name); let mut scheme = DiskScheme::new(scheme_name, hba_mem, disks); diff --git a/storage/bcm2835-sdhcid/Cargo.toml b/storage/bcm2835-sdhcid/Cargo.toml index b5c21ffb80..d92d58d3fa 100644 --- a/storage/bcm2835-sdhcid/Cargo.toml +++ b/storage/bcm2835-sdhcid/Cargo.toml @@ -12,4 +12,3 @@ common = { path = "../../common" } driver-block = { path = "../driver-block" } redox-daemon = "0.1" -libredox = "0.1.3" diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index edcafbb4ea..7a815a64e2 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -79,7 +79,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let scheme_name = ":disk.mmc"; let mut socket = File::create(scheme_name).expect("mmc: failed to create disk scheme"); - libredox::call::setrens(0, 0).expect("mmc: failed to enter null namespace"); + syscall::setrens(0, 0).expect("mmc: failed to enter null namespace"); daemon.ready().expect("mmc: failed to notify parent"); diff --git a/storage/ided/Cargo.toml b/storage/ided/Cargo.toml index aab5d97153..1df0416b7b 100644 --- a/storage/ided/Cargo.toml +++ b/storage/ided/Cargo.toml @@ -6,7 +6,6 @@ edition = "2018" [dependencies] common = { path = "../../common" } driver-block = { path = "../driver-block" } -libredox = "0.1.3" log = "0.4" pcid = { path = "../../pcid" } redox-daemon = "0.1" diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 2778a68324..ca27ab7e60 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -1,5 +1,4 @@ use driver_block::Disk; -use libredox::flag; use log::{error, info}; use pcid_interface::{PciBar, PcidServerHandle}; use redox_log::{OutputBuilder, RedoxLogger}; @@ -100,7 +99,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { (Channel::secondary_compat(busmaster_base + 8).unwrap(), 15) }; - common::acquire_port_io_rights().expect("ided: failed to get I/O privilege"); + unsafe { syscall::iopl(3).expect("ided: failed to get I/O privilege") }; //TODO: move this to ide.rs? let chans = vec![ @@ -232,30 +231,27 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } let scheme_name = format!("disk.{}", name); - let socket_fd = libredox::call::open( + let socket_fd = syscall::open( &format!(":{}", scheme_name), - flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, - 0, + syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK ).expect("ided: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - let primary_irq_fd = libredox::call::open( + let primary_irq_fd = syscall::open( &format!("irq:{}", primary_irq), - flag::O_RDWR | flag::O_NONBLOCK, - 0, + syscall::O_RDWR | syscall::O_NONBLOCK ).expect("ided: failed to open irq file"); let mut primary_irq_file = unsafe { File::from_raw_fd(primary_irq_fd as RawFd) }; - let secondary_irq_fd = libredox::call::open( + let secondary_irq_fd = syscall::open( &format!("irq:{}", secondary_irq), - flag::O_RDWR | flag::O_NONBLOCK, - 0, + syscall::O_RDWR | syscall::O_NONBLOCK ).expect("ided: failed to open irq file"); let mut secondary_irq_file = unsafe { File::from_raw_fd(secondary_irq_fd as RawFd) }; let mut event_file = File::open("event:").expect("ided: failed to open event file"); - libredox::call::setrens(0, 0).expect("ided: failed to enter null namespace"); + syscall::setrens(0, 0).expect("ided: failed to enter null namespace"); daemon.ready().expect("ided: failed to notify parent"); diff --git a/storage/lived/Cargo.toml b/storage/lived/Cargo.toml index 339708856e..cea304209c 100644 --- a/storage/lived/Cargo.toml +++ b/storage/lived/Cargo.toml @@ -9,7 +9,6 @@ license = "MIT" [dependencies] anyhow = "1" -libredox = "0.1.3" redox-daemon = "0.1" redox_syscall = "0.4" slab = "0.4" diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index 8470400938..411d44db3f 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -8,8 +8,6 @@ use std::io::{Read, Write}; use std::os::fd::AsRawFd; use std::str; -use libredox::call::MmapArgs; -use libredox::flag; use slab::Slab; use syscall::data::Stat; use syscall::{error::*, MapFlags, SchemeMut, Packet}; @@ -65,13 +63,11 @@ impl DiskScheme { let the_data = unsafe { let file = File::open("memory:physical")?; - let base = libredox::call::mmap(MmapArgs { - fd: file.as_raw_fd() as usize, - addr: core::ptr::null_mut(), - offset: start as u64, - length: size, - prot: flag::PROT_READ | flag::PROT_WRITE, - flags: flag::MAP_SHARED, + let base = syscall::fmap(file.as_raw_fd() as usize, &syscall::Map { + address: 0, + offset: start, + size, + flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_SHARED, }).map_err(|err| anyhow!("failed to mmap livedisk: {}", err))?; std::slice::from_raw_parts_mut(base as *mut u8, size) diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 6271a63fa8..59c9c36935 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -18,7 +18,6 @@ smallvec = "1" common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } -libredox = "0.1.3" [features] default = ["async"] diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 5b05e82cd0..7058e9f6ae 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -9,7 +9,6 @@ use std::ptr::NonNull; use std::sync::{Arc, Mutex}; use std::{slice, usize}; -use libredox::flag; use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; use syscall::{ Event, Mmio, Packet, Result, SchemeBlockMut, @@ -50,8 +49,8 @@ impl Bar { impl Drop for Bar { fn drop(&mut self) { let _ = unsafe { - libredox::call::munmap( - self.ptr.as_ptr().cast(), + syscall::funmap( + self.ptr.as_ptr() as usize, self.bar_size.next_multiple_of(PAGE_SIZE), ) }; @@ -276,10 +275,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"), }); - let socket_fd = libredox::call::open( + let socket_fd = syscall::open( &format!(":{}", scheme_name), - flag::O_RDWR | flag::O_CREAT | flag::O_CLOEXEC, - 0, + syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, ) .expect("nvmed: failed to create disk scheme"); let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; @@ -299,7 +297,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let reactor_thread = nvme::cq_reactor::start_cq_reactor_thread(Arc::clone(&nvme), interrupt_sources, reactor_receiver); let namespaces = nvme.init_with_queues(); - libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); let mut todo = Vec::new(); diff --git a/storage/nvmed/src/nvme/cq_reactor.rs b/storage/nvmed/src/nvme/cq_reactor.rs index a41f576f64..ccadb14941 100644 --- a/storage/nvmed/src/nvme/cq_reactor.rs +++ b/storage/nvmed/src/nvme/cq_reactor.rs @@ -65,8 +65,8 @@ struct CqReactor { } impl CqReactor { fn create_event_queue(int_sources: &mut InterruptSources) -> Result { - use libredox::flag::*; - let fd = libredox::call::open("event:", O_CLOEXEC | O_RDWR, 0)?; + use syscall::flag::*; + let fd = syscall::open("event:", O_CLOEXEC | O_RDWR)?; let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; for (num, irq_handle) in int_sources.iter_mut() { diff --git a/storage/usbscsid/Cargo.toml b/storage/usbscsid/Cargo.toml index d3ca3455ee..28083405a3 100644 --- a/storage/usbscsid/Cargo.toml +++ b/storage/usbscsid/Cargo.toml @@ -9,7 +9,6 @@ license = "MIT" [dependencies] base64 = "0.11" # Only for debugging -libredox = "0.1.3" plain = "0.2" redox-daemon = "0.1" redox_syscall = "0.4" diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index e745c0ad3f..6f698e8c19 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -3,7 +3,6 @@ use std::fs::File; use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; -use libredox::flag; use syscall::{Packet, SchemeMut}; use xhcid_interface::{ConfigureEndpointsReq, DeviceReqData, XhciClientHandle}; @@ -85,11 +84,11 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u // TODO: Let all of the USB drivers syscall clone(2), and xhcid won't have to keep track of all // the drivers. - let socket_fd = libredox::call::open(disk_scheme_name, flag::O_RDWR | flag::O_CREAT, 0) + let socket_fd = syscall::open(disk_scheme_name, syscall::O_RDWR | syscall::O_CREAT) .expect("usbscsid: failed to create disk scheme"); let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - //libredox::call::setrens(0, 0).expect("scsid: failed to enter null namespace"); + //syscall::setrens(0, 0).expect("scsid: failed to enter null namespace"); let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI"); println!("SCSI initialized"); let mut buffer = [0u8; 512]; diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index 34883809cd..690454263d 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -21,4 +21,3 @@ common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } virtio-core = { path = "../../virtio-core" } -libredox = "0.1.3" diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 634621e3f4..c6b3727a16 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -8,7 +8,6 @@ use std::io::{Read, Write}; use std::os::fd::{FromRawFd, RawFd}; use std::sync::{Arc, Weak}; -use libredox::flag; use static_assertions::const_assert_eq; use pcid_interface::*; @@ -143,10 +142,9 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let scheme_name = format!("disk.{}", name); - let socket_fd = libredox::call::open( + let socket_fd = syscall::open( &format!(":{}", scheme_name), - flag::O_RDWR | flag::O_CREAT | flag::O_CLOEXEC, - 0, + syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, ) .map_err(Error::SyscallError)?; diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index ff25884242..23a4273c2a 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -6,9 +6,8 @@ edition = "2018" [dependencies] orbclient = "0.3.27" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.5" +redox_syscall = "0.4" redox-daemon = "0.1" common = { path = "../common" } pcid = { path = "../pcid" } -libredox = "0.1.3" diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 39b0c3efaf..7555482450 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -11,6 +11,7 @@ use std::fs::File; use std::io::{Result, Read, Write}; use pcid_interface::{PciBar, PcidServerHandle}; +use syscall::call::iopl; use syscall::flag::EventFlags; use syscall::io::{Io, Mmio, Pio}; @@ -205,14 +206,14 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { daemon.ready().expect("failed to signal readiness"); - common::acquire_port_io_rights().expect("vboxd: failed to get I/O permission"); + unsafe { iopl(3).expect("vboxd: failed to get I/O permission"); }; let mut width = 0; let mut height = 0; let mut display_opt = File::open("inputd:producer").ok(); if let Some(ref display) = display_opt { let mut buf: [u8; 4096] = [0; 4096]; - if let Ok(count) = libredox::call::fpath(display.as_raw_fd() as usize, &mut buf) { + if let Ok(count) = syscall::fpath(display.as_raw_fd() as usize, &mut buf) { let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; let res = path.split(":").nth(1).unwrap_or(""); width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); @@ -244,7 +245,7 @@ fn main() { let mut event_queue = EventQueue::<()>::new().expect("vboxd: failed to create event queue"); - libredox::call::setrens(0, 0).expect("vboxd: failed to enter null namespace"); + syscall::setrens(0, 0).expect("vboxd: failed to enter null namespace"); let mut bga = Bga::new(); let get_mouse = VboxGetMouse::new().expect("vboxd: failed to map GetMouse"); @@ -294,7 +295,7 @@ fn main() { event_queue.trigger_all(event::Event { fd: 0, - flags: Default::default(), + flags: EventFlags::empty() }).expect("vboxd: failed to trigger events"); event_queue.run().expect("vboxd: failed to run event loop"); diff --git a/virtio-core/Cargo.toml b/virtio-core/Cargo.toml index a9d8c6713a..8824169676 100644 --- a/virtio-core/Cargo.toml +++ b/virtio-core/Cargo.toml @@ -18,4 +18,3 @@ redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } common = { path = "../common" } pcid = { path = "../pcid" } -libredox = "0.1.3" diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index 862d4dfee6..9073ce8059 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -13,7 +13,7 @@ pub fn probe_legacy_port_transport( ) -> Result { let port = pci_config.func.bars[0].expect_port(); - common::acquire_io_port_rights().expect("virtio: failed to set I/O privilege level"); + unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; log::warn!("virtio: using legacy transport"); let transport = LegacyTransport::new(port); diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index fa0de00c6c..e67d8ab767 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -54,7 +54,7 @@ pub fn probe_legacy_port_transport( ) -> Result { let port = pci_config.func.bars[0].expect_port(); - common::acquire_port_io_rights().expect("virtio: failed to set I/O privilege level"); + unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; log::warn!("virtio: using legacy transport"); let transport = LegacyTransport::new(port); diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 133c5e53c4..1ff80a205f 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -16,7 +16,7 @@ use std::task::{Poll, Waker}; #[derive(thiserror::Error, Debug)] pub enum Error { #[error("syscall failed")] - SyscallError(#[from] libredox::error::Error), + SyscallError(syscall::Error), #[error("pcid client handle error")] PcidClientHandle(pcid_interface::PcidClientHandleError), #[error("the device is incapable of {0:?}")] @@ -29,6 +29,12 @@ impl From for Error { } } +impl From for Error { + fn from(value: syscall::Error) -> Self { + Self::SyscallError(value) + } +} + /// Returns the queue part sizes in bytes. /// /// ## Reference diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 94e09eb0b3..7fa83821b5 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -20,9 +20,9 @@ plain = "0.2" lazy_static = "1.4" log = "0.4" redox-daemon = "0.1" -redox_event = "0.4.1" +redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox-log = "0.1" -redox_syscall = "0.5" +redox_syscall = "0.4" serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1", features = ["serde"] } @@ -31,4 +31,3 @@ toml = "0.5" common = { path = "../common" } pcid = { path = "../pcid" } -libredox = "0.1.3" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 6b9fe1bd79..faf50300ec 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -11,14 +11,13 @@ use std::ptr::NonNull; use std::sync::{Arc, Mutex}; use std::env; -use libredox::flag; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::MsixTableEntry; -use event::{Event, RawEventQueue}; +use event::{Event, EventQueue}; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; @@ -209,10 +208,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { println!(" + XHCI {}", pci_config.func.display()); let scheme_name = format!("usb.{}", name); - let socket_fd = libredox::call::open( + let socket_fd = syscall::open( format!(":{}", scheme_name), - flag::O_RDWR | flag::O_CREAT, - 0, + syscall::O_RDWR | syscall::O_CREAT, ) .expect("xhcid: failed to create usb scheme"); let socket = Arc::new(Mutex::new(unsafe { @@ -225,38 +223,47 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { xhci::start_irq_reactor(&hci, irq_file); futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe"); - //let event_queue = RawEventQueue::new().expect("xhcid: failed to create event queue"); + let mut event_queue = + EventQueue::<()>::new().expect("xhcid: failed to create event queue"); - libredox::call::setrens(0, 0).expect("xhcid: failed to enter null namespace"); + syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); let todo = Arc::new(Mutex::new(Vec::::new())); - //let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); - - //let socket_fd = socket.lock().unwrap().as_raw_fd(); - //event_queue.subscribe(socket_fd as usize, 0, event::EventFlags::READ).unwrap(); + let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); + let socket_fd = socket.lock().unwrap().as_raw_fd(); let socket_packet = socket.clone(); + event_queue + .add(socket_fd, move |_| -> io::Result> { + let mut socket = socket_packet.lock().unwrap(); + let mut todo = todo.lock().unwrap(); - loop { - let mut socket = socket_packet.lock().unwrap(); - let mut todo = todo.lock().unwrap(); + loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => break, + Ok(_) => (), + Err(err) => return Err(err), + } - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => break, - Ok(_) => (), - Err(err) => panic!("xhcid failed to read from socket: {err}"), - } + let a = packet.a; + hci.handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.push(packet); + } else { + socket.write(&packet)?; + } + } + Ok(None) + }) + .expect("xhcid: failed to catch events on scheme file"); - let a = packet.a; - hci.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.push(packet); - } else { - socket.write(&packet).expect("xhcid failed to write to socket"); - } - } + event_queue + .trigger_all(Event { fd: 0, flags: EventFlags::empty() }) + .expect("xhcid: failed to trigger events"); + + event_queue.run().expect("xhcid: failed to handle events"); std::process::exit(0); } diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 5f364a5524..3779218c28 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -185,7 +185,7 @@ impl ScratchpadBufferArray { pub fn new(ac64: bool, entries: u16) -> Result { let mut entries = unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? }; - let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result<_, syscall::Error> { + let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| { let dma = unsafe { Dma::<[u8; PAGE_SIZE]>::zeroed()?.assume_init() }; assert_eq!(dma.physical() % PAGE_SIZE, 0); entry.set_addr(dma.physical() as u64); diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index a697561ad5..215832ff9f 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -14,7 +14,7 @@ use log::{debug, error, info, warn, trace}; use futures::Stream; use syscall::Io; -use event::{Event, EventQueue, RawEventQueue}; +use event::{Event, EventQueue}; use super::Xhci; use super::doorbell::Doorbell; @@ -146,13 +146,12 @@ impl IrqReactor { debug!("Running IRQ reactor with IRQ file and event queue"); let hci_clone = Arc::clone(&self.hci); - let mut event_queue = RawEventQueue::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); + let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); - event_queue.subscribe(irq_fd as usize, 0, event::EventFlags::READ).unwrap(); let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() }; - for _event in event_queue { + event_queue.add(irq_fd, move |_| -> io::Result> { trace!("IRQ event queue notified"); let mut buffer = [0u8; 8]; @@ -161,7 +160,7 @@ impl IrqReactor { if !self.hci.received_irq() { // continue only when an IRQ to this device was received trace!("no interrupt pending"); - break; + return Ok(None); } trace!("IRQ reactor received an IRQ"); @@ -174,13 +173,13 @@ impl IrqReactor { let mut count = 0; - loop { + 'trb_loop: loop { let event_trb = &mut event_ring.ring.trbs[event_trb_index]; if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { if count == 0 { warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } // no more events were found, continue the loop - return; + return Ok(None); } else { count += 1 } trace!("Found event TRB type {}: {:?}", event_trb.trb_type(), event_trb); @@ -188,7 +187,7 @@ impl IrqReactor { if self.check_event_ring_full(event_trb.clone()) { info!("Had to resize event TRB, retrying..."); hci_clone.event_handler_finished(); - return; + return Ok(None); } self.handle_requests(); @@ -200,7 +199,8 @@ impl IrqReactor { event_trb_index = event_ring.ring.next_index(); } - } + }).expect("xhcid: failed to catch irq events"); + event_queue.run().expect("xhcid: failed to run IRQ event queue"); } fn update_erdp(&self, event_ring: &EventRing) { let dequeue_pointer_and_dcs = event_ring.erdp(); diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 52d544d845..32d9d1eb82 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -11,6 +11,7 @@ use std::{mem, process, slice, sync::atomic, task, thread}; use syscall::PAGE_SIZE; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; +use syscall::flag::{O_RDONLY, PhysallocFlags}; use syscall::io::Io; use chashmap::CHashMap; @@ -235,7 +236,12 @@ impl Xhci { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; debug!("CAP REGS BASE {:X}", address); - //let page_size = ... + /*let page_size = { + let memory_fd = syscall::open("memory:", O_RDONLY)?; + let mut stat = syscall::data::StatVfs::default(); + syscall::fstatvfs(memory_fd, &mut stat)?; + stat.f_bsize as usize + };*/ let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; From ff956fd3bba8a6d0306884e7d55350fddc417012 Mon Sep 17 00:00:00 2001 From: Jacob Lorentzon <4ldo2@protonmail.com> Date: Mon, 18 Mar 2024 22:09:25 +0000 Subject: [PATCH 0837/1301] Switch to libredox where applicable (fixed) --- Cargo.lock | 102 ++++++++++++++++++++------- acpid/Cargo.toml | 3 +- acpid/src/acpi.rs | 4 +- acpid/src/acpi/dmar/drhd.rs | 2 +- acpid/src/aml_physmem.rs | 6 +- acpid/src/main.rs | 6 +- audio/ac97d/Cargo.toml | 3 +- audio/ac97d/src/main.rs | 9 +-- audio/ihdad/Cargo.toml | 1 + audio/ihdad/src/main.rs | 5 +- audio/pcspkrd/Cargo.toml | 1 + audio/pcspkrd/src/main.rs | 2 +- audio/sb16d/Cargo.toml | 1 + audio/sb16d/src/main.rs | 9 ++- common/Cargo.toml | 3 +- common/src/dma.rs | 46 ++++++------ common/src/lib.rs | 46 +++++++----- graphics/bgad/Cargo.toml | 1 + graphics/bgad/src/main.rs | 2 +- graphics/fbcond/Cargo.toml | 3 +- graphics/fbcond/src/display.rs | 28 ++++---- graphics/fbcond/src/main.rs | 2 +- graphics/fbcond/src/text.rs | 2 +- graphics/vesad/Cargo.toml | 3 +- graphics/vesad/src/main.rs | 2 +- graphics/vesad/src/scheme.rs | 2 +- graphics/virtio-gpud/Cargo.toml | 3 +- graphics/virtio-gpud/src/scheme.rs | 2 +- inputd/Cargo.toml | 5 +- inputd/src/lib.rs | 4 +- inputd/src/main.rs | 2 +- net/alxd/Cargo.toml | 3 +- net/alxd/src/device/mod.rs | 4 +- net/alxd/src/main.rs | 7 +- net/driver-network/Cargo.toml | 3 +- net/driver-network/src/lib.rs | 6 +- net/e1000d/Cargo.toml | 3 +- net/e1000d/src/device.rs | 2 +- net/e1000d/src/main.rs | 4 +- net/ixgbed/Cargo.toml | 3 +- net/ixgbed/src/device.rs | 4 +- net/ixgbed/src/main.rs | 4 +- net/rtl8139d/Cargo.toml | 3 +- net/rtl8139d/src/device.rs | 4 +- net/rtl8139d/src/main.rs | 4 +- net/rtl8168d/Cargo.toml | 3 +- net/rtl8168d/src/device.rs | 6 +- net/rtl8168d/src/main.rs | 4 +- net/virtio-netd/Cargo.toml | 3 +- net/virtio-netd/src/main.rs | 2 +- pcid/Cargo.toml | 1 + pcid/src/cfg_access/fallback.rs | 4 +- ps2d/Cargo.toml | 1 + ps2d/src/main.rs | 2 +- storage/ahcid/Cargo.toml | 3 +- storage/ahcid/src/ahci/disk_ata.rs | 2 +- storage/ahcid/src/ahci/disk_atapi.rs | 2 +- storage/ahcid/src/main.rs | 12 ++-- storage/bcm2835-sdhcid/Cargo.toml | 1 + storage/bcm2835-sdhcid/src/main.rs | 2 +- storage/driver-block/Cargo.toml | 2 +- storage/ided/Cargo.toml | 3 +- storage/ided/src/main.rs | 20 +++--- storage/lived/Cargo.toml | 1 + storage/lived/src/main.rs | 14 ++-- storage/nvmed/Cargo.toml | 3 +- storage/nvmed/src/main.rs | 12 ++-- storage/nvmed/src/nvme/cq_reactor.rs | 4 +- storage/usbscsid/Cargo.toml | 1 + storage/usbscsid/src/main.rs | 5 +- storage/virtio-blkd/Cargo.toml | 3 +- storage/virtio-blkd/src/main.rs | 7 +- vboxd/Cargo.toml | 3 +- vboxd/src/main.rs | 9 ++- virtio-core/Cargo.toml | 3 +- virtio-core/src/arch/x86.rs | 2 +- virtio-core/src/arch/x86_64.rs | 2 +- virtio-core/src/transport.rs | 8 +-- xhcid/Cargo.toml | 5 +- xhcid/src/main.rs | 65 ++++++++--------- xhcid/src/xhci/context.rs | 2 +- xhcid/src/xhci/irq_reactor.rs | 18 ++--- xhcid/src/xhci/mod.rs | 8 +-- 83 files changed, 349 insertions(+), 263 deletions(-) mode change 100755 => 100644 audio/ihdad/Cargo.toml diff --git a/Cargo.lock b/Cargo.lock index 29c7c216d7..4c5879c1d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,12 +8,13 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "spin", ] @@ -24,6 +25,7 @@ dependencies = [ "aml", "amlserde", "common", + "libredox 0.1.3", "log", "num-derive", "num-traits", @@ -31,7 +33,7 @@ dependencies = [ "plain", "redox-daemon", "redox-log", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "rustc-hash", "serde_json", "thiserror", @@ -45,11 +47,12 @@ dependencies = [ "byteorder", "common", "driver-block", + "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -58,9 +61,10 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "libredox 0.1.3", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -151,6 +155,7 @@ dependencies = [ "common", "driver-block", "fdt 0.1.5", + "libredox 0.1.3", "redox-daemon", "redox_syscall 0.4.1", ] @@ -159,6 +164,7 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ + "libredox 0.1.3", "orbclient", "pcid", "redox-daemon", @@ -280,7 +286,8 @@ dependencies = [ name = "common" version = "0.1.0" dependencies = [ - "redox_syscall 0.4.1", + "libredox 0.1.3", + "redox_syscall 0.5.1", ] [[package]] @@ -349,15 +356,16 @@ name = "driver-block" version = "0.1.0" dependencies = [ "partitionlib", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] name = "driver-network" version = "0.1.0" dependencies = [ + "libredox 0.1.3", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -367,10 +375,11 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", + "libredox 0.1.3", "pcid", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -384,11 +393,12 @@ name = "fbcond" version = "0.1.0" dependencies = [ "inputd", + "libredox 0.1.3", "orbclient", "ransid", "redox-daemon", "redox_event 0.2.1", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -582,11 +592,12 @@ version = "0.1.0" dependencies = [ "common", "driver-block", + "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -595,6 +606,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "libredox 0.1.3", "log", "pcid", "redox-daemon", @@ -619,11 +631,12 @@ name = "inputd" version = "0.1.0" dependencies = [ "anyhow", + "libredox 0.1.3", "log", "orbclient", "redox-daemon", "redox-log", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "spin", ] @@ -649,10 +662,11 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", + "libredox 0.1.3", "pcid", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -689,12 +703,13 @@ dependencies = [ [[package]] name = "libredox" -version = "0.1.0" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138adbe77ccf68e1925b6ed3cc45e83a6845f17a687d6061ddeb518e9b756440" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.4.2", "libc", + "redox_syscall 0.5.1", ] [[package]] @@ -702,6 +717,7 @@ name = "lived" version = "0.1.0" dependencies = [ "anyhow", + "libredox 0.1.3", "redox-daemon", "redox_syscall 0.4.1", "slab", @@ -771,12 +787,13 @@ dependencies = [ "crossbeam-channel", "driver-block", "futures", + "libredox 0.1.3", "log", "partitionlib", "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "smallvec 1.11.0", ] @@ -917,6 +934,7 @@ dependencies = [ "common", "fdt 0.1.0", "libc", + "libredox 0.1.3", "log", "paw", "pci_types", @@ -934,6 +952,7 @@ dependencies = [ name = "pcspkrd" version = "0.1.0" dependencies = [ + "libredox 0.1.3", "redox-daemon", "redox_syscall 0.4.1", ] @@ -994,6 +1013,7 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 1.3.2", + "libredox 0.1.3", "orbclient", "redox-daemon", "redox_syscall 0.4.1", @@ -1067,7 +1087,7 @@ version = "0.1.3" source = "git+https://gitlab.redox-os.org/redox-os/redox-daemon.git#31ab115cf17d6fe333515bfe19ac477352a1dcc0" dependencies = [ "libc", - "libredox 0.1.0", + "libredox 0.1.3", ] [[package]] @@ -1101,6 +1121,16 @@ dependencies = [ "redox_syscall 0.4.1", ] +[[package]] +name = "redox_event" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69609faa5d5992247a4ef379917bb3e39be281405d6a0ccd4f942429400b956f" +dependencies = [ + "bitflags 2.4.2", + "libredox 0.1.3", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -1128,6 +1158,15 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_syscall" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +dependencies = [ + "bitflags 2.4.2", +] + [[package]] name = "redox_termios" version = "0.1.2" @@ -1144,12 +1183,13 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", + "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -1159,12 +1199,13 @@ dependencies = [ "bitflags 1.3.2", "common", "driver-network", + "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -1185,6 +1226,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "libredox 0.1.3", "log", "redox-daemon", "redox-log", @@ -1526,6 +1568,7 @@ name = "usbscsid" version = "0.1.0" dependencies = [ "base64", + "libredox 0.1.3", "plain", "redox-daemon", "redox_syscall 0.4.1", @@ -1559,11 +1602,12 @@ name = "vboxd" version = "0.1.0" dependencies = [ "common", + "libredox 0.1.3", "orbclient", "pcid", "redox-daemon", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -1590,10 +1634,11 @@ version = "0.1.0" dependencies = [ "common", "inputd", + "libredox 0.1.3", "orbclient", "ransid", "redox-daemon", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -1604,12 +1649,13 @@ dependencies = [ "common", "driver-block", "futures", + "libredox 0.1.3", "log", "partitionlib", "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "spin", "static_assertions", "thiserror", @@ -1624,11 +1670,12 @@ dependencies = [ "common", "crossbeam-queue", "futures", + "libredox 0.1.3", "log", "pcid", "redox-log", "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "static_assertions", "thiserror", ] @@ -1641,12 +1688,13 @@ dependencies = [ "common", "futures", "inputd", + "libredox 0.1.3", "log", "orbclient", "paste", "pcid", "redox-daemon", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "spin", "static_assertions", "virtio-core", @@ -1659,10 +1707,11 @@ dependencies = [ "common", "driver-network", "futures", + "libredox 0.1.3", "log", "pcid", "redox-daemon", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "static_assertions", "virtio-core", ] @@ -1852,13 +1901,14 @@ dependencies = [ "crossbeam-channel", "futures", "lazy_static", + "libredox 0.1.3", "log", "pcid", "plain", "redox-daemon", "redox-log", - "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_event 0.4.1", + "redox_syscall 0.5.1", "serde", "serde_json", "smallvec 1.11.0", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 92a6e8027d..4e03f757e7 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -15,10 +15,11 @@ parking_lot = "0.11.1" plain = "0.2.3" redox-daemon = "0.1" redox-log = "0.1.1" -redox_syscall = "0.4" +redox_syscall = "0.5" rustc-hash = "1.1.0" thiserror = "1" serde_json = "1.0.94" amlserde = { path = "../amlserde" } common = { path = "../common" } +libredox = "0.1.3" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 9bd620ef6d..34edc263b9 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -105,7 +105,7 @@ impl PhysmapGuard { let size = page_count * PAGE_SIZE; let virt = unsafe { common::physmap(page, size, common::Prot::RO, common::MemoryType::default()) - .map_err(|error| std::io::Error::from_raw_os_error(error.errno))? + .map_err(|error| std::io::Error::from_raw_os_error(error.errno()))? }; Ok(Self { @@ -124,7 +124,7 @@ impl Deref for PhysmapGuard { impl Drop for PhysmapGuard { fn drop(&mut self) { unsafe { - let _ = syscall::funmap(self.virt as usize, self.size); + let _ = libredox::call::munmap(self.virt as *mut (), self.size); } } } diff --git a/acpid/src/acpi/dmar/drhd.rs b/acpid/src/acpi/dmar/drhd.rs index 091f553e95..70c8f8b42b 100644 --- a/acpid/src/acpi/dmar/drhd.rs +++ b/acpid/src/acpi/dmar/drhd.rs @@ -35,7 +35,7 @@ impl DerefMut for DrhdPage { impl Drop for DrhdPage { fn drop(&mut self) { unsafe { - let _ = syscall::funmap(self.virt as usize, crate::acpi::PAGE_SIZE); + let _ = libredox::call::munmap(self.virt.cast(), crate::acpi::PAGE_SIZE); } } } diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 98d78f1910..03d0eb5fef 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -17,7 +17,7 @@ impl MappedPage { fn new(phys_page: usize) -> std::io::Result { let virt_page = unsafe { common::physmap(phys_page, PAGE_SIZE, common::Prot::RO, common::MemoryType::default()) - .map_err(|error| std::io::Error::from_raw_os_error(error.errno))? + .map_err(|error| std::io::Error::from_raw_os_error(error.errno()))? } as usize; Ok(Self { phys_page, @@ -29,7 +29,7 @@ impl MappedPage { impl Drop for MappedPage { fn drop(&mut self) { log::trace!("Drop page {:#x}", self.phys_page); - if let Err(e) = unsafe { syscall::funmap(self.virt_page, PAGE_SIZE) } { + if let Err(e) = unsafe { libredox::call::munmap(self.virt_page as *mut (), PAGE_SIZE) } { log::error!("funmap (phys): {:?}", e); } } @@ -212,7 +212,7 @@ impl aml::Handler for AmlPhysMemHandler { } } - // Pio must be enabled via syscall::iopl(3) + // Pio must be enabled via syscall::iopl fn read_io_u8(&self, port: u16) -> u8 { Pio::::new(port).read() } diff --git a/acpid/src/main.rs b/acpid/src/main.rs index e4c8711045..93c54f9558 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -113,8 +113,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let acpi_context = self::acpi::AcpiContext::init(physaddrs_iter); - // TODO: I/O permission bitmap - unsafe { syscall::iopl(3) }.expect("acpid: failed to set I/O privilege level to Ring 3"); + // TODO: I/O permission bitmap? + common::acquire_port_io_rights().expect("acpid: failed to set I/O privilege level to Ring 3"); let shutdown_pipe = File::open("kernel.acpi:kstop") .expect("acpid: failed to open `kernel.acpi:kstop`"); @@ -136,7 +136,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("acpid: failed to notify parent"); - syscall::setrens(0, 0).expect("acpid: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace"); let _ = event_queue.write(&Event { id: shutdown_pipe.as_raw_fd() as usize, diff --git a/audio/ac97d/Cargo.toml b/audio/ac97d/Cargo.toml index 4d780d5d99..50b781cfca 100644 --- a/audio/ac97d/Cargo.toml +++ b/audio/ac97d/Cargo.toml @@ -10,7 +10,8 @@ log = "0.4" redox-daemon = "0.1" redox-log = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" spin = "0.9" pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index 2a26dc193b..8649e671d6 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -13,6 +13,7 @@ use std::sync::Arc; use std::usize; use event::EventQueue; +use libredox::flag; use pcid_interface::{PciBar, PcidServerHandle}; use redox_log::{OutputBuilder, RedoxLogger}; use syscall::{EventFlags, Packet, SchemeBlockMut}; @@ -84,19 +85,19 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let _logger_ref = setup_logging(); - unsafe { syscall::iopl(3) }.expect("ac97d: failed to set I/O privilege level to Ring 3"); + common::acquire_port_io_rights().expect("ac97d: failed to set I/O privilege level to Ring 3"); let mut irq_file = irq.irq_handle("ac97d"); let device = Arc::new(RefCell::new(unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") })); - let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ac97d: failed to create hda scheme"); + let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ac97d: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); daemon.ready().expect("ac97d: failed to signal readiness"); let mut event_queue = EventQueue::::new().expect("ac97d: Could not create event queue."); - syscall::setrens(0, 0).expect("ac97d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("ac97d: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -167,7 +168,7 @@ fn main() { for event_count in event_queue.trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }).expect("ac97d: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, diff --git a/audio/ihdad/Cargo.toml b/audio/ihdad/Cargo.toml old mode 100755 new mode 100644 index 32f294d95a..736e98d31e --- a/audio/ihdad/Cargo.toml +++ b/audio/ihdad/Cargo.toml @@ -14,3 +14,4 @@ spin = "0.9" common = { path = "../../common" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 7eeba58e2a..bb29a49007 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -10,6 +10,7 @@ use std::usize; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use libredox::flag; use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; @@ -162,13 +163,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { | (pci_config.func.full_device_id.device_id as u32); let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); - let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("ihdad: failed to create hda scheme"); + let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ihdad: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); daemon.ready().expect("ihdad: failed to signal readiness"); let mut event_queue = EventQueue::::new().expect("ihdad: Could not create event queue."); - syscall::setrens(0, 0).expect("ihdad: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("ihdad: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); diff --git a/audio/pcspkrd/Cargo.toml b/audio/pcspkrd/Cargo.toml index 8f355d4e53..72bae14204 100644 --- a/audio/pcspkrd/Cargo.toml +++ b/audio/pcspkrd/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" [dependencies] redox_syscall = "0.4" redox-daemon = "0.1" +libredox = "0.1.3" diff --git a/audio/pcspkrd/src/main.rs b/audio/pcspkrd/src/main.rs index 7f9bfc1e40..75957745c3 100644 --- a/audio/pcspkrd/src/main.rs +++ b/audio/pcspkrd/src/main.rs @@ -29,7 +29,7 @@ fn main() { next_id: 0, }; - syscall::setrens(0, 0).expect("pcspkrd: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("pcspkrd: failed to enter null namespace"); loop { let mut packet = Packet::default(); diff --git a/audio/sb16d/Cargo.toml b/audio/sb16d/Cargo.toml index ccabfa3514..eb5a92a6e8 100644 --- a/audio/sb16d/Cargo.toml +++ b/audio/sb16d/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] bitflags = "1" common = { path = "../../common" } +libredox = "0.1.3" log = "0.4" redox-daemon = "0.1" redox-log = "0.1" diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index 6671ac9b39..814ed2066d 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -9,6 +9,7 @@ use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use libredox::flag; use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; @@ -74,10 +75,10 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let _logger_ref = setup_logging(); - unsafe { syscall::iopl(3) }.expect("sb16d: failed to set I/O privilege level to Ring 3"); + common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights"); let device = Arc::new(RefCell::new(unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") })); - let socket_fd = syscall::open(":audiohw", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("sb16d: failed to create hda scheme"); + let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("sb16d: failed to create hda scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); //TODO: error on multiple IRQs? @@ -90,7 +91,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); - syscall::setrens(0, 0).expect("sb16d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("sb16d: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -98,6 +99,8 @@ fn main() { let device_irq = device.clone(); let socket_irq = socket.clone(); + // TODO: Use new event queue API + event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { let mut irq = [0; 8]; irq_file.read(&mut irq)?; diff --git a/common/Cargo.toml b/common/Cargo.toml index 02b611d345..c1a072fa5d 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -8,4 +8,5 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -redox_syscall = "0.4" +libredox = "0.1.3" +redox_syscall = "0.5" diff --git a/common/src/dma.rs b/common/src/dma.rs index ec06623360..1adbbc6392 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -2,10 +2,10 @@ use std::mem::{self, size_of, MaybeUninit}; use std::ops::{Deref, DerefMut}; use std::ptr; +use libredox::call::MmapArgs; +use libredox::{flag, error::Result, Fd}; use syscall::PAGE_SIZE; -use syscall::Result; - use crate::MemoryType; const DMA_MEMTY: MemoryType = { @@ -20,30 +20,26 @@ const DMA_MEMTY: MemoryType = { } }; -fn alloc_and_map(len: usize) -> Result<(usize, *mut ())> { - assert_eq!(len % PAGE_SIZE, 0); +fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> { + assert_eq!(length % PAGE_SIZE, 0); unsafe { - let fd = syscall::open( - format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), - syscall::O_CLOEXEC, + let fd = Fd::open( + &format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), + flag::O_CLOEXEC, + 0, )?; - let virt = syscall::fmap( - fd, - &syscall::Map { - offset: 0, // ignored - address: 0, // ignored - size: len, - flags: syscall::MapFlags::MAP_PRIVATE - | syscall::MapFlags::PROT_READ - | syscall::MapFlags::PROT_WRITE, - }, - ); - let _ = syscall::close(fd); - let virt = virt?; - let phys = syscall::virttophys(virt)?; - /*for i in 1..len.div_ceil(PAGE_SIZE) { - assert_eq!(syscall::virttophys(virt + i * PAGE_SIZE), Ok(phys + i * PAGE_SIZE), "NOT CONTIGUOUS"); - }*/ + let virt = libredox::call::mmap(MmapArgs { + fd: fd.raw(), + offset: 0, // ignored + addr: core::ptr::null_mut(), // ignored + length, + flags: flag::MAP_PRIVATE, + prot: flag::PROT_READ | flag::PROT_WRITE, + })?; + let phys = syscall::virttophys(virt as usize)?; + for i in 1..length.div_ceil(PAGE_SIZE) { + debug_assert_eq!(syscall::virttophys(virt as usize + i * PAGE_SIZE), Ok(phys + i * PAGE_SIZE), "NOT CONTIGUOUS"); + } Ok((phys, virt as *mut ())) } } @@ -159,7 +155,7 @@ impl Drop for Dma { fn drop(&mut self) { unsafe { ptr::drop_in_place(self.virt); - let _ = syscall::funmap(self.virt as *mut u8 as usize, self.aligned_len); + let _ = libredox::call::munmap(self.virt as *mut (), self.aligned_len); } } } diff --git a/common/src/lib.rs b/common/src/lib.rs index 2a9240f193..2107a08660 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,7 +1,8 @@ #![feature(int_roundings)] -use syscall::error::{Error, Result, EINVAL}; -use syscall::flag::{MapFlags, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; +use libredox::call::MmapArgs; +use libredox::{Fd, error::*, errno::EINVAL}; +use libredox::flag::{self, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; use syscall::PAGE_SIZE; pub mod dma; @@ -63,23 +64,23 @@ pub unsafe fn physmap( (false, true) => O_WRONLY, (false, false) => return Err(Error::new(EINVAL)), }; - let mut prot = MapFlags::empty(); - prot.set(MapFlags::PROT_READ, read); - prot.set(MapFlags::PROT_WRITE, write); + let mut prot = 0; + if read { + prot |= flag::PROT_READ; + } + if write { + prot |= flag::PROT_WRITE; + } - let file = syscall::open(path, O_CLOEXEC | mode)?; - let base = syscall::fmap( - file, - &syscall::Map { - offset: base_phys, - size: len.next_multiple_of(PAGE_SIZE), - flags: MapFlags::MAP_SHARED | prot, - address: 0, - }, - ); - let _ = syscall::close(file); - - Ok(base? as *mut ()) + let fd = Fd::open(&path, O_CLOEXEC | mode, 0)?; + Ok(libredox::call::mmap(MmapArgs { + fd: fd.raw(), + offset: base_phys as u64, + length: len.next_multiple_of(PAGE_SIZE), + flags: flag::MAP_SHARED, + prot, + addr: core::ptr::null_mut(), + })? as *mut ()) } impl std::fmt::Display for MemoryType { @@ -119,7 +120,14 @@ impl PhysBorrowed { impl Drop for PhysBorrowed { fn drop(&mut self) { unsafe { - let _ = syscall::funmap(self.mem as usize, self.len); + let _ = libredox::call::munmap(self.mem, self.len); } } } + +pub fn acquire_port_io_rights() -> Result<()> { + unsafe { + syscall::iopl(3)?; + } + Ok(()) +} diff --git a/graphics/bgad/Cargo.toml b/graphics/bgad/Cargo.toml index afa6619215..0c439fd17a 100644 --- a/graphics/bgad/Cargo.toml +++ b/graphics/bgad/Cargo.toml @@ -9,3 +9,4 @@ redox-daemon = "0.1" redox_syscall = "0.4" pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index 18ac70df34..a80423f392 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -42,7 +42,7 @@ fn main() { scheme.update_size(); - syscall::setrens(0, 0).expect("bgad: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("bgad: failed to enter null namespace"); daemon.ready().expect("bgad: failed to notify parent"); diff --git a/graphics/fbcond/Cargo.toml b/graphics/fbcond/Cargo.toml index d934921104..0e466e15cb 100644 --- a/graphics/fbcond/Cargo.toml +++ b/graphics/fbcond/Cargo.toml @@ -7,10 +7,11 @@ edition = "2021" orbclient = "0.3.27" ransid = "0.4" redox_event = "0.2" -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" inputd = { path = "../../inputd" } +libredox = "0.1.3" [features] default = [] diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index da16fe5804..e2d3798046 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -8,6 +8,7 @@ use std::{ os::unix::io::{AsRawFd, FromRawFd}, slice, }; +use libredox::flag; use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; // Keep synced with vesad @@ -22,15 +23,14 @@ pub struct SyncRect { fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Result<*mut [u32]> { unsafe { - let display_ptr = syscall::fmap( - display_fd, - &syscall::Map { - offset: 0, - size: (width * height * 4), - flags: syscall::PROT_READ | syscall::PROT_WRITE | syscall::MAP_SHARED, - address: 0, - }, - )?; + let display_ptr = libredox::call::mmap(libredox::call::MmapArgs { + fd: display_fd, + offset: 0, + length: (width * height * 4), + prot: flag::PROT_READ | flag::PROT_WRITE, + flags: flag::MAP_SHARED, + addr: core::ptr::null_mut(), + })?; let display_slice = slice::from_raw_parts_mut(display_ptr as *mut u32, width * height); Ok(display_slice) } @@ -38,7 +38,7 @@ fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Re unsafe fn display_fd_unmap(image: *mut [u32], size: usize) { // FIXME use image.len() instead of size once it is stable. - let _ = syscall::funmap(image as *mut u32 as usize, size * 4); + let _ = libredox::call::munmap(image as *mut (), size * 4); } pub struct Display { @@ -59,7 +59,7 @@ impl Display { .open(format!("input:consumer/{vt}"))?; let fd = input_handle.as_raw_fd(); - let written = syscall::fpath(fd as usize, &mut buffer) + let written = libredox::call::fpath(fd as usize, &mut buffer) .expect("init: failed to get the path to the display device"); assert!(written <= buffer.len()); @@ -67,7 +67,7 @@ impl Display { let display_path = std::str::from_utf8(&buffer[..written]).expect("init: display path UTF-8 check failed"); - let display_file = syscall::open(display_path, O_CLOEXEC | O_NONBLOCK | O_RDWR) + let display_file = libredox::call::open(display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) .unwrap_or_else(|err| { panic!("failed to open display {}: {}", display_path, err); @@ -75,7 +75,7 @@ impl Display { let mut buf: [u8; 4096] = [0; 4096]; let count = - syscall::fpath(display_file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| { + libredox::call::fpath(display_file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| { panic!("Could not read display path with fpath(): {e}"); }); @@ -138,7 +138,7 @@ impl Display { pub fn sync_rect(&mut self, sync_rect: SyncRect) -> syscall::Result<()> { unsafe { - syscall::write( + libredox::call::write( self.display_file.as_raw_fd().as_raw_fd() as usize, slice::from_raw_parts( &sync_rect as *const SyncRect as *const u8, diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index cd0a859810..4db9e1b5fc 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -53,7 +53,7 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { let mut scheme = FbconScheme::new(vt_ids, &mut event_queue); - syscall::setrens(0, 0).expect("fbcond: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index bdc24d66f5..7f75c6fbc5 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -320,7 +320,7 @@ impl TextScreen { })?; } self.changed.clear(); - syscall::fsync(self.display.display_file.as_raw_fd().as_raw_fd() as usize)?; + libredox::call::fsync(self.display.display_file.as_raw_fd().as_raw_fd() as usize)?; Ok(buf.len()) } diff --git a/graphics/vesad/Cargo.toml b/graphics/vesad/Cargo.toml index 5d6542ccf5..87f9083af7 100644 --- a/graphics/vesad/Cargo.toml +++ b/graphics/vesad/Cargo.toml @@ -6,11 +6,12 @@ edition = "2018" [dependencies] orbclient = "0.3.27" ransid = "0.4" -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" common = { path = "../../common" } inputd = { path = "../../inputd" } +libredox = "0.1.3" [features] default = [] diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 9f1d8f2901..2b6fd953c4 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -88,7 +88,7 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( let mut scheme = DisplayScheme::new(framebuffers, &spec); - syscall::setrens(0, 0).expect("vesad: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 7f12cf0f9c..4b94801b16 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -95,7 +95,7 @@ impl DisplayScheme { // Unmap old onscreen unsafe { let slice = mem::take(&mut self.onscreens[fb_i]); - syscall::funmap(slice.as_mut_ptr() as usize, (slice.len() * 4).next_multiple_of(PAGE_SIZE)).expect("vesad: failed to unmap framebuffer"); + libredox::call::munmap(slice.as_mut_ptr().cast(), (slice.len() * 4).next_multiple_of(PAGE_SIZE)).expect("vesad: failed to unmap framebuffer"); } // Map new onscreen diff --git a/graphics/virtio-gpud/Cargo.toml b/graphics/virtio-gpud/Cargo.toml index a51e8b5a7a..75901d433e 100644 --- a/graphics/virtio-gpud/Cargo.toml +++ b/graphics/virtio-gpud/Cargo.toml @@ -17,6 +17,7 @@ pcid = { path = "../../pcid" } inputd = { path = "../../inputd" } redox-daemon = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" orbclient = "0.3.27" spin = "0.9.8" +libredox = "0.1.3" diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 51cd14a76a..907ebc873e 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -117,7 +117,7 @@ impl<'a> Display<'a> { .next_multiple_of(syscall::PAGE_SIZE); let mapped = *self.mapped.get().unwrap(); - let address = unsafe { syscall::virttophys(mapped) }?; + let address = (unsafe { syscall::virttophys(mapped) }).map_err(libredox::error::Error::from)?; self.map_screen_with(0, address, fb_size, mapped).await } diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index e88ab86f9e..9b900edc13 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -7,8 +7,9 @@ authors = ["Anhad Singh "] [dependencies] anyhow = "1.0.71" log = "0.4.19" -redox-daemon = "0.1.0" +redox-daemon = "0.1.2" redox-log = "0.1.1" -redox_syscall = "0.4" +redox_syscall = "0.5" orbclient = "0.3.27" spin = "0.9.8" +libredox = "0.1.3" diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 4a52c09403..3112964993 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -91,7 +91,7 @@ impl Cmd { } } -pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), syscall::Error> { +pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), libredox::error::Error> { use std::os::fd::AsRawFd; let mut result = vec![]; @@ -119,7 +119,7 @@ pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), syscall::Error> } }; - let written = syscall::write(file.as_raw_fd() as usize, &result)?; + let written = libredox::call::write(file.as_raw_fd() as usize, &result)?; // XXX: Ensure all of the data is written. assert_eq!(written, result.len()); diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 23f6b7b4e3..e8b34c9585 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -535,7 +535,7 @@ pub fn main() { .expect("inputd: failed to open consumer handle"); let mut display_path = [0; 4096]; - let written = syscall::fpath(handle.as_raw_fd() as usize, &mut display_path) + let written = libredox::call::fpath(handle.as_raw_fd() as usize, &mut display_path) .expect("inputd: fpath() failed"); assert!(written <= display_path.len()); diff --git a/net/alxd/Cargo.toml b/net/alxd/Cargo.toml index 4a3ed09f03..5d20a58d5b 100644 --- a/net/alxd/Cargo.toml +++ b/net/alxd/Cargo.toml @@ -6,7 +6,8 @@ edition = "2018" [dependencies] bitflags = "1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" common = { path = "../../common" } +libredox = "0.1.3" diff --git a/net/alxd/src/device/mod.rs b/net/alxd/src/device/mod.rs index 3a20c9fc81..0222cd1c27 100644 --- a/net/alxd/src/device/mod.rs +++ b/net/alxd/src/device/mod.rs @@ -281,7 +281,7 @@ pub struct Alx { fn dma_array() -> Result<[Dma; N]> { Ok((0..N) - .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .map(|_| Ok(Dma::zeroed().map(|dma| unsafe { dma.assume_init() })?)) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!())) @@ -290,7 +290,7 @@ fn dma_array() -> Result<[Dma; N]> { impl Alx { pub unsafe fn new(base: usize) -> Result { let mut module = Alx { - base: base, + base, vendor_id: 0, device_id: 0, diff --git a/net/alxd/src/main.rs b/net/alxd/src/main.rs index ef1f745681..8ff8e18c52 100644 --- a/net/alxd/src/main.rs +++ b/net/alxd/src/main.rs @@ -14,6 +14,7 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use event::EventQueue; +use libredox::flag; use syscall::{EventFlags, Packet, SchemeMut}; use syscall::error::EWOULDBLOCK; @@ -35,7 +36,7 @@ fn main() { // Daemonize redox_daemon::Daemon::new(move |daemon| { - let socket_fd = syscall::open(":network", syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK).expect("alxd: failed to create network scheme"); + let socket_fd = libredox::call::open(":network", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("alxd: failed to create network scheme"); let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); daemon.ready().expect("alxd: failed to signal readiness"); @@ -48,7 +49,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("alxd: failed to create event queue"); - syscall::setrens(0, 0).expect("alxd: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("alxd: failed to enter null namespace"); let todo = Arc::new(RefCell::new(Vec::::new())); @@ -111,7 +112,7 @@ fn main() { for event_count in event_queue.trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }).expect("alxd: failed to trigger events") { socket.borrow_mut().write(&Packet { id: 0, diff --git a/net/driver-network/Cargo.toml b/net/driver-network/Cargo.toml index 47be9d3175..965bbcf23c 100644 --- a/net/driver-network/Cargo.toml +++ b/net/driver-network/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] +libredox = "0.1.3" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index 3790b33ba5..ce108dcd70 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -4,6 +4,7 @@ use std::io::{ErrorKind, Read, Write}; use std::os::fd::{AsRawFd, FromRawFd, RawFd}; use std::{cmp, io}; +use libredox::flag; use syscall::{ Error, EventFlags, Packet, Result, SchemeBlockMut, Stat, EACCES, EBADF, EINVAL, EWOULDBLOCK, MODE_FILE, O_NONBLOCK, @@ -46,9 +47,10 @@ enum Handle { impl NetworkScheme { pub fn new(adapter: T, scheme_name: String) -> Self { assert!(scheme_name.starts_with("network")); - let scheme_fd = syscall::open( + let scheme_fd = libredox::call::open( format!(":{scheme_name}"), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK, + flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, + 0, ) .expect("failed to create network scheme"); let scheme = unsafe { File::from_raw_fd(scheme_fd as RawFd) }; diff --git a/net/e1000d/Cargo.toml b/net/e1000d/Cargo.toml index 395a6341cc..bc6c347647 100644 --- a/net/e1000d/Cargo.toml +++ b/net/e1000d/Cargo.toml @@ -7,8 +7,9 @@ edition = "2018" bitflags = "1" redox-daemon = "0.1" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/net/e1000d/src/device.rs b/net/e1000d/src/device.rs index 7da6965d13..721e7cf913 100644 --- a/net/e1000d/src/device.rs +++ b/net/e1000d/src/device.rs @@ -208,7 +208,7 @@ impl NetworkAdapter for Intel8254x { fn dma_array() -> Result<[Dma; N]> { Ok((0..N) - .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!())) diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index b8052b93f3..8c532f3c68 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -43,7 +43,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); - syscall::setrens(0, 0).expect("e1000d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("e1000d: failed to enter null namespace"); daemon .ready() @@ -79,7 +79,7 @@ fn main() { event_queue .trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }) .expect("e1000d: failed to trigger events"); diff --git a/net/ixgbed/Cargo.toml b/net/ixgbed/Cargo.toml index fd3258fa00..38ee7a7477 100644 --- a/net/ixgbed/Cargo.toml +++ b/net/ixgbed/Cargo.toml @@ -6,9 +6,10 @@ edition = "2021" [dependencies] bitflags = "1.0" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/net/ixgbed/src/device.rs b/net/ixgbed/src/device.rs index b36309e14f..4ab8d0e530 100644 --- a/net/ixgbed/src/device.rs +++ b/net/ixgbed/src/device.rs @@ -129,13 +129,13 @@ impl Intel8259x { base, size, receive_buffer: (0..32) - .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), receive_ring: unsafe { Dma::zeroed()?.assume_init() }, transmit_buffer: (0..32) - .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index 33c67083bd..7c6aefbb27 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -55,7 +55,7 @@ fn main() { let mut event_queue = EventQueue::::new().expect("ixgbed: failed to create event queue"); - syscall::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); daemon .ready() @@ -91,7 +91,7 @@ fn main() { event_queue .trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }) .expect("ixgbed: failed to trigger events"); diff --git a/net/rtl8139d/Cargo.toml b/net/rtl8139d/Cargo.toml index 2ff86321ab..ef23f408db 100644 --- a/net/rtl8139d/Cargo.toml +++ b/net/rtl8139d/Cargo.toml @@ -7,10 +7,11 @@ edition = "2018" bitflags = "1" log = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" redox-log = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/net/rtl8139d/src/device.rs b/net/rtl8139d/src/device.rs index 4b6ce854f0..e6ef45053b 100644 --- a/net/rtl8139d/src/device.rs +++ b/net/rtl8139d/src/device.rs @@ -209,13 +209,13 @@ impl Rtl8139 { let regs = Regs::from_base(base); let mut module = Rtl8139 { - regs: regs, + regs, //TODO: limit to 32-bit receive_buffer: Dma::zeroed().map(|dma| dma.assume_init())?, receive_i: 0, //TODO: limit to 32-bit transmit_buffer: (0..4) - .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) + .map(|_| Ok(Dma::zeroed()?.assume_init())) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 048daf6d95..66ca3b533e 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -242,7 +242,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut event_queue = EventQueue::::new().expect("rtl8139d: failed to create event queue"); - syscall::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); daemon .ready() @@ -279,7 +279,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { event_queue .trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }) .expect("rtl8139d: failed to trigger events"); diff --git a/net/rtl8168d/Cargo.toml b/net/rtl8168d/Cargo.toml index 3ec1bdfbcf..2010b02b47 100644 --- a/net/rtl8168d/Cargo.toml +++ b/net/rtl8168d/Cargo.toml @@ -7,10 +7,11 @@ edition = "2018" bitflags = "1" log = "0.4" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" redox-log = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/net/rtl8168d/src/device.rs b/net/rtl8168d/src/device.rs index 25b6aea64a..717ac194e2 100644 --- a/net/rtl8168d/src/device.rs +++ b/net/rtl8168d/src/device.rs @@ -173,9 +173,9 @@ impl Rtl8168 { assert_eq!(®s.mtps as *const _ as usize - base, 0xEC); let mut module = Rtl8168 { - regs: regs, + regs, receive_buffer: (0..64) - .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) + .map(|_| Ok(Dma::zeroed()?.assume_init())) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), @@ -183,7 +183,7 @@ impl Rtl8168 { receive_ring: Dma::zeroed()?.assume_init(), receive_i: 0, transmit_buffer: (0..16) - .map(|_| Dma::zeroed().map(|dma| dma.assume_init())) + .map(|_| Ok(Dma::zeroed()?.assume_init())) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()), diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 3767f2ddad..e38501b3ec 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -237,7 +237,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut event_queue = EventQueue::::new().expect("rtl8168d: failed to create event queue"); - syscall::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); daemon .ready() @@ -274,7 +274,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { event_queue .trigger_all(event::Event { fd: 0, - flags: EventFlags::empty(), + flags: Default::default(), }) .expect("rtl8168d: failed to trigger events"); diff --git a/net/virtio-netd/Cargo.toml b/net/virtio-netd/Cargo.toml index e1063e7414..3becfd7897 100644 --- a/net/virtio-netd/Cargo.toml +++ b/net/virtio-netd/Cargo.toml @@ -14,4 +14,5 @@ common = { path = "../../common" } driver-network = { path = "../driver-network" } redox-daemon = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" +libredox = "0.1.3" diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index f00437a763..d2a2411f55 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -102,7 +102,7 @@ fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box data: 0, })?; - syscall::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); daemon.ready().expect("virtio-netd: failed to daemonize"); diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index a4ae567e9d..487b79029d 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -31,3 +31,4 @@ thiserror = "1" toml = "0.5" common = { path = "../common" } +libredox = "0.1.3" diff --git a/pcid/src/cfg_access/fallback.rs b/pcid/src/cfg_access/fallback.rs index 65682e171f..c1d51bfb5c 100644 --- a/pcid/src/cfg_access/fallback.rs +++ b/pcid/src/cfg_access/fallback.rs @@ -33,9 +33,7 @@ impl Pci { "PCI: couldn't find or access PCIe extended configuration, \ and thus falling back to PCI 3.0 io ports" ); - unsafe { - syscall::iopl(3).expect("pcid: failed to set iopl to 3"); - } + common::acquire_port_io_rights().expect("pcid: failed to get IO port rights"); } }); } diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index cfab793a52..90f5875711 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -8,3 +8,4 @@ bitflags = "1" orbclient = "0.3.27" redox_syscall = "0.4" redox-daemon = "0.1" +libredox = "0.1.3" diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index f9cdba3b6b..aa4ec5df2c 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -80,7 +80,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { data: 1 }).expect("ps2d: failed to event irq:12"); - syscall::setrens(0, 0).expect("ps2d: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("ps2d: failed to enter null namespace"); daemon.ready().expect("ps2d: failed to mark daemon as ready"); diff --git a/storage/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml index 4c84077667..5cc6e7f0b9 100644 --- a/storage/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -9,8 +9,9 @@ byteorder = "1.2" log = "0.4" redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } +libredox = "0.1.3" diff --git a/storage/ahcid/src/ahci/disk_ata.rs b/storage/ahcid/src/ahci/disk_ata.rs index cf9437765f..394b61dd35 100644 --- a/storage/ahcid/src/ahci/disk_ata.rs +++ b/storage/ahcid/src/ahci/disk_ata.rs @@ -36,7 +36,7 @@ impl DiskATA { let mut clb = unsafe { Dma::zeroed()?.assume_init() }; let mut ctbas: [_; 32] = (0..32) - .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()); diff --git a/storage/ahcid/src/ahci/disk_atapi.rs b/storage/ahcid/src/ahci/disk_atapi.rs index a7abf2e1d6..a3c63f7abb 100644 --- a/storage/ahcid/src/ahci/disk_atapi.rs +++ b/storage/ahcid/src/ahci/disk_atapi.rs @@ -32,7 +32,7 @@ impl DiskATAPI { let mut clb = unsafe { Dma::zeroed()?.assume_init() }; let mut ctbas: [_; 32] = (0..32) - .map(|_| Dma::zeroed().map(|dma| unsafe { dma.assume_init() })) + .map(|_| Ok(unsafe { Dma::zeroed()?.assume_init() })) .collect::>>()? .try_into() .unwrap_or_else(|_| unreachable!()); diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 60dd30ab12..4f19891cf0 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -10,6 +10,7 @@ use std::os::fd::AsRawFd; use std::os::unix::io::{FromRawFd, RawFd}; use std::usize; +use libredox::flag; use pcid_interface::PcidServerHandle; use syscall::error::{Error, ENODEV}; use syscall::data::{Event, Packet}; @@ -93,9 +94,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { bar.physmap_mem("ahcid") }; { let scheme_name = format!("disk.{}", name); - let socket_fd = syscall::open( + let socket_fd = libredox::call::open( &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK + flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, + 0, ).expect("ahcid: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; @@ -104,9 +106,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); - syscall::setrens(0, 0).expect("ahcid: failed to enter null namespace"); - - daemon.ready().expect("ahcid: failed to notify parent"); + libredox::call::setrens(0, 0).expect("ahcid: failed to enter null namespace"); event_file.write(&Event { id: socket_fd, @@ -120,6 +120,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { data: 0 }).expect("ahcid: failed to event irq scheme"); + daemon.ready().expect("ahcid: failed to notify parent"); + let (hba_mem, disks) = ahci::disks(address as usize, &name); let mut scheme = DiskScheme::new(scheme_name, hba_mem, disks); diff --git a/storage/bcm2835-sdhcid/Cargo.toml b/storage/bcm2835-sdhcid/Cargo.toml index d92d58d3fa..b5c21ffb80 100644 --- a/storage/bcm2835-sdhcid/Cargo.toml +++ b/storage/bcm2835-sdhcid/Cargo.toml @@ -12,3 +12,4 @@ common = { path = "../../common" } driver-block = { path = "../driver-block" } redox-daemon = "0.1" +libredox = "0.1.3" diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index 7a815a64e2..edcafbb4ea 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -79,7 +79,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let scheme_name = ":disk.mmc"; let mut socket = File::create(scheme_name).expect("mmc: failed to create disk scheme"); - syscall::setrens(0, 0).expect("mmc: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("mmc: failed to enter null namespace"); daemon.ready().expect("mmc: failed to notify parent"); diff --git a/storage/driver-block/Cargo.toml b/storage/driver-block/Cargo.toml index 710b5efd5d..f876f19832 100644 --- a/storage/driver-block/Cargo.toml +++ b/storage/driver-block/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" [dependencies] partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" diff --git a/storage/ided/Cargo.toml b/storage/ided/Cargo.toml index 1df0416b7b..2303be020b 100644 --- a/storage/ided/Cargo.toml +++ b/storage/ided/Cargo.toml @@ -6,8 +6,9 @@ edition = "2018" [dependencies] common = { path = "../../common" } driver-block = { path = "../driver-block" } +libredox = "0.1.3" log = "0.4" pcid = { path = "../../pcid" } redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index ca27ab7e60..2778a68324 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -1,4 +1,5 @@ use driver_block::Disk; +use libredox::flag; use log::{error, info}; use pcid_interface::{PciBar, PcidServerHandle}; use redox_log::{OutputBuilder, RedoxLogger}; @@ -99,7 +100,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { (Channel::secondary_compat(busmaster_base + 8).unwrap(), 15) }; - unsafe { syscall::iopl(3).expect("ided: failed to get I/O privilege") }; + common::acquire_port_io_rights().expect("ided: failed to get I/O privilege"); //TODO: move this to ide.rs? let chans = vec![ @@ -231,27 +232,30 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } let scheme_name = format!("disk.{}", name); - let socket_fd = syscall::open( + let socket_fd = libredox::call::open( &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK + flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, + 0, ).expect("ided: failed to create disk scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - let primary_irq_fd = syscall::open( + let primary_irq_fd = libredox::call::open( &format!("irq:{}", primary_irq), - syscall::O_RDWR | syscall::O_NONBLOCK + flag::O_RDWR | flag::O_NONBLOCK, + 0, ).expect("ided: failed to open irq file"); let mut primary_irq_file = unsafe { File::from_raw_fd(primary_irq_fd as RawFd) }; - let secondary_irq_fd = syscall::open( + let secondary_irq_fd = libredox::call::open( &format!("irq:{}", secondary_irq), - syscall::O_RDWR | syscall::O_NONBLOCK + flag::O_RDWR | flag::O_NONBLOCK, + 0, ).expect("ided: failed to open irq file"); let mut secondary_irq_file = unsafe { File::from_raw_fd(secondary_irq_fd as RawFd) }; let mut event_file = File::open("event:").expect("ided: failed to open event file"); - syscall::setrens(0, 0).expect("ided: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("ided: failed to enter null namespace"); daemon.ready().expect("ided: failed to notify parent"); diff --git a/storage/lived/Cargo.toml b/storage/lived/Cargo.toml index cea304209c..339708856e 100644 --- a/storage/lived/Cargo.toml +++ b/storage/lived/Cargo.toml @@ -9,6 +9,7 @@ license = "MIT" [dependencies] anyhow = "1" +libredox = "0.1.3" redox-daemon = "0.1" redox_syscall = "0.4" slab = "0.4" diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index 411d44db3f..8470400938 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -8,6 +8,8 @@ use std::io::{Read, Write}; use std::os::fd::AsRawFd; use std::str; +use libredox::call::MmapArgs; +use libredox::flag; use slab::Slab; use syscall::data::Stat; use syscall::{error::*, MapFlags, SchemeMut, Packet}; @@ -63,11 +65,13 @@ impl DiskScheme { let the_data = unsafe { let file = File::open("memory:physical")?; - let base = syscall::fmap(file.as_raw_fd() as usize, &syscall::Map { - address: 0, - offset: start, - size, - flags: MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_SHARED, + let base = libredox::call::mmap(MmapArgs { + fd: file.as_raw_fd() as usize, + addr: core::ptr::null_mut(), + offset: start as u64, + length: size, + prot: flag::PROT_READ | flag::PROT_WRITE, + flags: flag::MAP_SHARED, }).map_err(|err| anyhow!("failed to mmap livedisk: {}", err))?; std::slice::from_raw_parts_mut(base as *mut u8, size) diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 59c9c36935..7306d843c3 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -11,13 +11,14 @@ futures = "0.3" log = "0.4" redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } smallvec = "1" common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } +libredox = "0.1.3" [features] default = ["async"] diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 7058e9f6ae..5b05e82cd0 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -9,6 +9,7 @@ use std::ptr::NonNull; use std::sync::{Arc, Mutex}; use std::{slice, usize}; +use libredox::flag; use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; use syscall::{ Event, Mmio, Packet, Result, SchemeBlockMut, @@ -49,8 +50,8 @@ impl Bar { impl Drop for Bar { fn drop(&mut self) { let _ = unsafe { - syscall::funmap( - self.ptr.as_ptr() as usize, + libredox::call::munmap( + self.ptr.as_ptr().cast(), self.bar_size.next_multiple_of(PAGE_SIZE), ) }; @@ -275,9 +276,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"), }); - let socket_fd = syscall::open( + let socket_fd = libredox::call::open( &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, + flag::O_RDWR | flag::O_CREAT | flag::O_CLOEXEC, + 0, ) .expect("nvmed: failed to create disk scheme"); let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; @@ -297,7 +299,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let reactor_thread = nvme::cq_reactor::start_cq_reactor_thread(Arc::clone(&nvme), interrupt_sources, reactor_receiver); let namespaces = nvme.init_with_queues(); - syscall::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); let mut todo = Vec::new(); diff --git a/storage/nvmed/src/nvme/cq_reactor.rs b/storage/nvmed/src/nvme/cq_reactor.rs index ccadb14941..a41f576f64 100644 --- a/storage/nvmed/src/nvme/cq_reactor.rs +++ b/storage/nvmed/src/nvme/cq_reactor.rs @@ -65,8 +65,8 @@ struct CqReactor { } impl CqReactor { fn create_event_queue(int_sources: &mut InterruptSources) -> Result { - use syscall::flag::*; - let fd = syscall::open("event:", O_CLOEXEC | O_RDWR)?; + use libredox::flag::*; + let fd = libredox::call::open("event:", O_CLOEXEC | O_RDWR, 0)?; let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; for (num, irq_handle) in int_sources.iter_mut() { diff --git a/storage/usbscsid/Cargo.toml b/storage/usbscsid/Cargo.toml index 28083405a3..d3ca3455ee 100644 --- a/storage/usbscsid/Cargo.toml +++ b/storage/usbscsid/Cargo.toml @@ -9,6 +9,7 @@ license = "MIT" [dependencies] base64 = "0.11" # Only for debugging +libredox = "0.1.3" plain = "0.2" redox-daemon = "0.1" redox_syscall = "0.4" diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index 6f698e8c19..e745c0ad3f 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -3,6 +3,7 @@ use std::fs::File; use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; +use libredox::flag; use syscall::{Packet, SchemeMut}; use xhcid_interface::{ConfigureEndpointsReq, DeviceReqData, XhciClientHandle}; @@ -84,11 +85,11 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u // TODO: Let all of the USB drivers syscall clone(2), and xhcid won't have to keep track of all // the drivers. - let socket_fd = syscall::open(disk_scheme_name, syscall::O_RDWR | syscall::O_CREAT) + let socket_fd = libredox::call::open(disk_scheme_name, flag::O_RDWR | flag::O_CREAT, 0) .expect("usbscsid: failed to create disk scheme"); let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - //syscall::setrens(0, 0).expect("scsid: failed to enter null namespace"); + //libredox::call::setrens(0, 0).expect("scsid: failed to enter null namespace"); let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI"); println!("SCSI initialized"); let mut buffer = [0u8; 512]; diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index 690454263d..60bfed2ba6 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -14,10 +14,11 @@ spin = "*" redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } virtio-core = { path = "../../virtio-core" } +libredox = "0.1.3" diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index c6b3727a16..8c5313c8b6 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -8,6 +8,7 @@ use std::io::{Read, Write}; use std::os::fd::{FromRawFd, RawFd}; use std::sync::{Arc, Weak}; +use libredox::flag; use static_assertions::const_assert_eq; use pcid_interface::*; @@ -142,10 +143,12 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let scheme_name = format!("disk.{}", name); - let socket_fd = syscall::open( + let socket_fd = libredox::call::open( &format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT | syscall::O_CLOEXEC, + flag::O_RDWR | flag::O_CREAT | flag::O_CLOEXEC, + 0, ) + .map_err(syscall::Error::from) .map_err(Error::SyscallError)?; let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index 23a4273c2a..ff25884242 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -6,8 +6,9 @@ edition = "2018" [dependencies] orbclient = "0.3.27" redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" common = { path = "../common" } pcid = { path = "../pcid" } +libredox = "0.1.3" diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 7555482450..39b0c3efaf 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -11,7 +11,6 @@ use std::fs::File; use std::io::{Result, Read, Write}; use pcid_interface::{PciBar, PcidServerHandle}; -use syscall::call::iopl; use syscall::flag::EventFlags; use syscall::io::{Io, Mmio, Pio}; @@ -206,14 +205,14 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { daemon.ready().expect("failed to signal readiness"); - unsafe { iopl(3).expect("vboxd: failed to get I/O permission"); }; + common::acquire_port_io_rights().expect("vboxd: failed to get I/O permission"); let mut width = 0; let mut height = 0; let mut display_opt = File::open("inputd:producer").ok(); if let Some(ref display) = display_opt { let mut buf: [u8; 4096] = [0; 4096]; - if let Ok(count) = syscall::fpath(display.as_raw_fd() as usize, &mut buf) { + if let Ok(count) = libredox::call::fpath(display.as_raw_fd() as usize, &mut buf) { let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; let res = path.split(":").nth(1).unwrap_or(""); width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); @@ -245,7 +244,7 @@ fn main() { let mut event_queue = EventQueue::<()>::new().expect("vboxd: failed to create event queue"); - syscall::setrens(0, 0).expect("vboxd: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("vboxd: failed to enter null namespace"); let mut bga = Bga::new(); let get_mouse = VboxGetMouse::new().expect("vboxd: failed to map GetMouse"); @@ -295,7 +294,7 @@ fn main() { event_queue.trigger_all(event::Event { fd: 0, - flags: EventFlags::empty() + flags: Default::default(), }).expect("vboxd: failed to trigger events"); event_queue.run().expect("vboxd: failed to run event loop"); diff --git a/virtio-core/Cargo.toml b/virtio-core/Cargo.toml index 8824169676..379821c233 100644 --- a/virtio-core/Cargo.toml +++ b/virtio-core/Cargo.toml @@ -7,7 +7,7 @@ authors = ["Anhad Singh "] [dependencies] static_assertions = "1.1.0" bitflags = "2.3.2" -redox_syscall = "0.4" +redox_syscall = "0.5" log = "0.4" thiserror = "1.0.40" futures = { version = "0.3.28", features = ["executor"] } @@ -18,3 +18,4 @@ redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } common = { path = "../common" } pcid = { path = "../pcid" } +libredox = "0.1.3" diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index 9073ce8059..862d4dfee6 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -13,7 +13,7 @@ pub fn probe_legacy_port_transport( ) -> Result { let port = pci_config.func.bars[0].expect_port(); - unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; + common::acquire_io_port_rights().expect("virtio: failed to set I/O privilege level"); log::warn!("virtio: using legacy transport"); let transport = LegacyTransport::new(port); diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index e67d8ab767..fa0de00c6c 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -54,7 +54,7 @@ pub fn probe_legacy_port_transport( ) -> Result { let port = pci_config.func.bars[0].expect_port(); - unsafe { syscall::iopl(3).expect("virtio: failed to set I/O privilege level") }; + common::acquire_port_io_rights().expect("virtio: failed to set I/O privilege level"); log::warn!("virtio: using legacy transport"); let transport = LegacyTransport::new(port); diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 1ff80a205f..133c5e53c4 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -16,7 +16,7 @@ use std::task::{Poll, Waker}; #[derive(thiserror::Error, Debug)] pub enum Error { #[error("syscall failed")] - SyscallError(syscall::Error), + SyscallError(#[from] libredox::error::Error), #[error("pcid client handle error")] PcidClientHandle(pcid_interface::PcidClientHandleError), #[error("the device is incapable of {0:?}")] @@ -29,12 +29,6 @@ impl From for Error { } } -impl From for Error { - fn from(value: syscall::Error) -> Self { - Self::SyscallError(value) - } -} - /// Returns the queue part sizes in bytes. /// /// ## Reference diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 7fa83821b5..94e09eb0b3 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -20,9 +20,9 @@ plain = "0.2" lazy_static = "1.4" log = "0.4" redox-daemon = "0.1" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox_event = "0.4.1" redox-log = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" smallvec = { version = "1", features = ["serde"] } @@ -31,3 +31,4 @@ toml = "0.5" common = { path = "../common" } pcid = { path = "../pcid" } +libredox = "0.1.3" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index faf50300ec..6b9fe1bd79 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -11,13 +11,14 @@ use std::ptr::NonNull; use std::sync::{Arc, Mutex}; use std::env; +use libredox::flag; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::MsixTableEntry; -use event::{Event, EventQueue}; +use event::{Event, RawEventQueue}; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; @@ -208,9 +209,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { println!(" + XHCI {}", pci_config.func.display()); let scheme_name = format!("usb.{}", name); - let socket_fd = syscall::open( + let socket_fd = libredox::call::open( format!(":{}", scheme_name), - syscall::O_RDWR | syscall::O_CREAT, + flag::O_RDWR | flag::O_CREAT, + 0, ) .expect("xhcid: failed to create usb scheme"); let socket = Arc::new(Mutex::new(unsafe { @@ -223,47 +225,38 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { xhci::start_irq_reactor(&hci, irq_file); futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe"); - let mut event_queue = - EventQueue::<()>::new().expect("xhcid: failed to create event queue"); + //let event_queue = RawEventQueue::new().expect("xhcid: failed to create event queue"); - syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace"); + libredox::call::setrens(0, 0).expect("xhcid: failed to enter null namespace"); let todo = Arc::new(Mutex::new(Vec::::new())); - let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); + //let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); + + //let socket_fd = socket.lock().unwrap().as_raw_fd(); + //event_queue.subscribe(socket_fd as usize, 0, event::EventFlags::READ).unwrap(); - let socket_fd = socket.lock().unwrap().as_raw_fd(); let socket_packet = socket.clone(); - event_queue - .add(socket_fd, move |_| -> io::Result> { - let mut socket = socket_packet.lock().unwrap(); - let mut todo = todo.lock().unwrap(); - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => break, - Ok(_) => (), - Err(err) => return Err(err), - } + loop { + let mut socket = socket_packet.lock().unwrap(); + let mut todo = todo.lock().unwrap(); - let a = packet.a; - hci.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.push(packet); - } else { - socket.write(&packet)?; - } - } - Ok(None) - }) - .expect("xhcid: failed to catch events on scheme file"); + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => break, + Ok(_) => (), + Err(err) => panic!("xhcid failed to read from socket: {err}"), + } - event_queue - .trigger_all(Event { fd: 0, flags: EventFlags::empty() }) - .expect("xhcid: failed to trigger events"); - - event_queue.run().expect("xhcid: failed to handle events"); + let a = packet.a; + hci.handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.push(packet); + } else { + socket.write(&packet).expect("xhcid failed to write to socket"); + } + } std::process::exit(0); } diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 3779218c28..5f364a5524 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -185,7 +185,7 @@ impl ScratchpadBufferArray { pub fn new(ac64: bool, entries: u16) -> Result { let mut entries = unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? }; - let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| { + let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result<_, syscall::Error> { let dma = unsafe { Dma::<[u8; PAGE_SIZE]>::zeroed()?.assume_init() }; assert_eq!(dma.physical() % PAGE_SIZE, 0); entry.set_addr(dma.physical() as u64); diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 215832ff9f..a697561ad5 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -14,7 +14,7 @@ use log::{debug, error, info, warn, trace}; use futures::Stream; use syscall::Io; -use event::{Event, EventQueue}; +use event::{Event, EventQueue, RawEventQueue}; use super::Xhci; use super::doorbell::Doorbell; @@ -146,12 +146,13 @@ impl IrqReactor { debug!("Running IRQ reactor with IRQ file and event queue"); let hci_clone = Arc::clone(&self.hci); - let mut event_queue = EventQueue::<()>::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); + let mut event_queue = RawEventQueue::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); + event_queue.subscribe(irq_fd as usize, 0, event::EventFlags::READ).unwrap(); let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() }; - event_queue.add(irq_fd, move |_| -> io::Result> { + for _event in event_queue { trace!("IRQ event queue notified"); let mut buffer = [0u8; 8]; @@ -160,7 +161,7 @@ impl IrqReactor { if !self.hci.received_irq() { // continue only when an IRQ to this device was received trace!("no interrupt pending"); - return Ok(None); + break; } trace!("IRQ reactor received an IRQ"); @@ -173,13 +174,13 @@ impl IrqReactor { let mut count = 0; - 'trb_loop: loop { + loop { let event_trb = &mut event_ring.ring.trbs[event_trb_index]; if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { if count == 0 { warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } // no more events were found, continue the loop - return Ok(None); + return; } else { count += 1 } trace!("Found event TRB type {}: {:?}", event_trb.trb_type(), event_trb); @@ -187,7 +188,7 @@ impl IrqReactor { if self.check_event_ring_full(event_trb.clone()) { info!("Had to resize event TRB, retrying..."); hci_clone.event_handler_finished(); - return Ok(None); + return; } self.handle_requests(); @@ -199,8 +200,7 @@ impl IrqReactor { event_trb_index = event_ring.ring.next_index(); } - }).expect("xhcid: failed to catch irq events"); - event_queue.run().expect("xhcid: failed to run IRQ event queue"); + } } fn update_erdp(&self, event_ring: &EventRing) { let dequeue_pointer_and_dcs = event_ring.erdp(); diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 32d9d1eb82..52d544d845 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -11,7 +11,6 @@ use std::{mem, process, slice, sync::atomic, task, thread}; use syscall::PAGE_SIZE; use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; -use syscall::flag::{O_RDONLY, PhysallocFlags}; use syscall::io::Io; use chashmap::CHashMap; @@ -236,12 +235,7 @@ impl Xhci { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; debug!("CAP REGS BASE {:X}", address); - /*let page_size = { - let memory_fd = syscall::open("memory:", O_RDONLY)?; - let mut stat = syscall::data::StatVfs::default(); - syscall::fstatvfs(memory_fd, &mut stat)?; - stat.f_bsize as usize - };*/ + //let page_size = ... let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; From ff7015a55a61fd0a115450d57b1ab4230a2d29e3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 19 Mar 2024 16:19:47 -0600 Subject: [PATCH 0838/1301] virtio-core: fix compilation on i686 --- virtio-core/src/arch/x86.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index 862d4dfee6..23fdbbf3a0 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -13,7 +13,7 @@ pub fn probe_legacy_port_transport( ) -> Result { let port = pci_config.func.bars[0].expect_port(); - common::acquire_io_port_rights().expect("virtio: failed to set I/O privilege level"); + common::acquire_port_io_rights().expect("virtio: failed to set I/O privilege level"); log::warn!("virtio: using legacy transport"); let transport = LegacyTransport::new(port); From ee725b7a087c3134ed2310ac20daeb8f130cf336 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 24 Mar 2024 14:09:12 +0100 Subject: [PATCH 0839/1301] Fix 257 page allocation in ahcid. --- storage/ahcid/src/ahci/hba.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/storage/ahcid/src/ahci/hba.rs b/storage/ahcid/src/ahci/hba.rs index a11f2a1425..5ca6af72f7 100644 --- a/storage/ahcid/src/ahci/hba.rs +++ b/storage/ahcid/src/ahci/hba.rs @@ -289,7 +289,7 @@ impl HbaPort { } pub fn ata_start(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], callback: F) -> Option - where F: FnOnce(&mut HbaCmdHeader, &mut FisRegH2D, &mut [HbaPrdtEntry; 65536], &mut [Mmio; 16]) { + where F: FnOnce(&mut HbaCmdHeader, &mut FisRegH2D, &mut [HbaPrdtEntry; PRDT_ENTRIES], &mut [Mmio; 16]) { //TODO: Should probably remove self.is.write(u32::MAX); @@ -414,8 +414,10 @@ pub struct HbaCmdTable { _rsv: [Mmio; 48], // Reserved // 0x80 - prdt_entry: [HbaPrdtEntry; 65536], // Physical region descriptor table entries, 0 ~ 65535 + prdt_entry: [HbaPrdtEntry; PRDT_ENTRIES], // Physical region descriptor table entries, 0 ~ 65535 } +const CMD_TBL_SIZE: usize = 256 * 4096; +const PRDT_ENTRIES: usize = (CMD_TBL_SIZE - 128) / size_of::(); #[repr(packed)] pub struct HbaCmdHeader { From 5612346e687ac12793a8f9737e1e2b104ec5f580 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 29 Mar 2024 10:10:13 -0600 Subject: [PATCH 0840/1301] ps2d: implement vmmouse for i686 --- ps2d/src/state.rs | 4 ++-- ps2d/src/vm.rs | 31 +++++++------------------------ 2 files changed, 9 insertions(+), 26 deletions(-) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 9891cc8e7e..381b642d3f 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -236,7 +236,7 @@ impl char> Ps2d { } } else if self.vmmouse { for _i in 0..256 { - let (status, _, _, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) }; + let (status, _, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_STATUS, 0) }; //TODO if ((status & VMMOUSE_ERROR) == VMMOUSE_ERROR) let queue_length = status & 0xffff; @@ -249,7 +249,7 @@ impl char> Ps2d { break; } - let (status, dx, dy, dz, _, _) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; + let (status, dx, dy, dz) = unsafe { vm::cmd(vm::ABSPOINTER_DATA, 4) }; if self.vmmouse_relative { if dx != 0 || dy != 0 { diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index 3f3ae50b50..5d691cee86 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -27,49 +27,32 @@ pub const LEFT_BUTTON: u32 = 0x20; pub const RIGHT_BUTTON: u32 = 0x10; pub const MIDDLE_BUTTON: u32 = 0x08; -#[cfg(target_arch = "x86_64")] -pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32, u32, u32) { +pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32) { let a: u32; let b: u32; let c: u32; let d: u32; - let si: u32; - let di: u32; // ebx can't be used as input or output constraint in rust as LLVM reserves it. // Use xchg to pass it through r9 instead while restoring the original value in // rbx when leaving the inline asm block. asm!( - "xchg r9, rbx; in eax, dx; xchg r9, rbx", + "xchg edi, ebx; in eax, dx; xchg edi, ebx", inout("eax") MAGIC => a, - inout("r9") arg => b, + inout("edi") arg => b, inout("ecx") cmd => c, inout("edx") PORT as u32 => d, - out("esi") si, - out("edi") di, ); - (a, b, c, d, si, di) + (a, b, c, d) } -//TODO: is it possible to enable this on non-x86_64? -#[cfg(not(target_arch = "x86_64"))] -pub unsafe fn cmd(_cmd: u32, _arg: u32) -> (u32, u32, u32, u32, u32, u32) { - (0, 0, 0, 0, 0, 0) -} - -#[cfg(not(target_arch = "x86_64"))] -pub fn enable(relative: bool) -> bool { - false -} - -#[cfg(target_arch = "x86_64")] pub fn enable(relative: bool) -> bool { eprintln!("ps2d: Enable vmmouse"); unsafe { - let (eax, ebx, _, _, _, _) = cmd(GETVERSION, 0); + let (eax, ebx, _, _) = cmd(GETVERSION, 0); if ebx != MAGIC || eax == 0xFFFFFFFF { eprintln!("ps2d: No vmmouse support"); return false; @@ -77,13 +60,13 @@ pub fn enable(relative: bool) -> bool { let _ = cmd(ABSPOINTER_COMMAND, CMD_ENABLE); - let (status, _, _, _, _, _) = cmd(ABSPOINTER_STATUS, 0); + let (status, _, _, _) = cmd(ABSPOINTER_STATUS, 0); if (status & 0x0000ffff) == 0 { eprintln!("ps2d: No vmmouse"); return false; } - let (version, _, _, _, _, _) = cmd(ABSPOINTER_DATA, 1); + let (version, _, _, _) = cmd(ABSPOINTER_DATA, 1); if version != VERSION { eprintln!("ps2d: Invalid vmmouse version: {} instead of {}", version, VERSION); let _ = cmd(ABSPOINTER_COMMAND, CMD_DISABLE); From acaa8e490c8d436a343071bb625179ca84afd577 Mon Sep 17 00:00:00 2001 From: Ivan Tan Date: Sat, 30 Mar 2024 22:29:25 +0800 Subject: [PATCH 0841/1301] bcm2835-sdhcid: update redox_syscall version --- storage/bcm2835-sdhcid/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/bcm2835-sdhcid/Cargo.toml b/storage/bcm2835-sdhcid/Cargo.toml index b5c21ffb80..78a350e29f 100644 --- a/storage/bcm2835-sdhcid/Cargo.toml +++ b/storage/bcm2835-sdhcid/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] fdt = "0.1.5" -redox_syscall = "0.4" +redox_syscall = "0.5" common = { path = "../../common" } driver-block = { path = "../driver-block" } From 4c35e88997762033971490e18864206bcde40e79 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 19 Mar 2024 17:05:59 +0100 Subject: [PATCH 0842/1301] Use latest event queue interface everywhere. --- Cargo.lock | 415 +++++++++++++++------------------- audio/ac97d/Cargo.toml | 6 +- audio/ac97d/src/main.rs | 213 ++++++++--------- audio/ihdad/Cargo.toml | 10 +- audio/ihdad/src/main.rs | 213 ++++++++--------- audio/pcspkrd/Cargo.toml | 2 +- audio/sb16d/Cargo.toml | 8 +- audio/sb16d/src/main.rs | 169 +++++--------- graphics/bgad/Cargo.toml | 4 +- graphics/fbcond/Cargo.toml | 2 +- net/alxd/Cargo.toml | 4 +- net/alxd/src/main.rs | 159 ++++++------- net/driver-network/Cargo.toml | 1 - net/e1000d/Cargo.toml | 8 +- net/e1000d/src/main.rs | 65 +++--- net/ixgbed/Cargo.toml | 6 +- net/ixgbed/src/main.rs | 65 +++--- net/rtl8139d/Cargo.toml | 6 +- net/rtl8139d/src/main.rs | 67 +++--- net/rtl8168d/Cargo.toml | 6 +- net/rtl8168d/src/main.rs | 67 +++--- pcid/Cargo.toml | 2 +- ps2d/Cargo.toml | 2 +- storage/lived/Cargo.toml | 2 +- storage/usbscsid/Cargo.toml | 2 +- usbhidd/Cargo.toml | 6 +- usbhidd/src/report_desc.rs | 1 + vboxd/Cargo.toml | 6 +- vboxd/src/main.rs | 40 ++-- virtio-core/Cargo.toml | 4 +- virtio-core/src/transport.rs | 23 +- 31 files changed, 678 insertions(+), 906 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4c5879c1d3..7286e2c967 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_event 0.1.0", + "redox_event", "redox_syscall 0.5.1", "spin", ] @@ -59,11 +59,11 @@ dependencies = [ name = "alxd" version = "0.1.0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "common", "libredox 0.1.3", "redox-daemon", - "redox_event 0.1.0", + "redox_event", "redox_syscall 0.5.1", ] @@ -86,7 +86,7 @@ dependencies = [ "aml", "rustc-hash", "serde", - "toml 0.7.7", + "toml 0.7.8", ] [[package]] @@ -115,9 +115,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" [[package]] name = "arrayvec" @@ -157,7 +157,7 @@ dependencies = [ "fdt 0.1.5", "libredox 0.1.3", "redox-daemon", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -168,7 +168,7 @@ dependencies = [ "orbclient", "pcid", "redox-daemon", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -194,9 +194,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "bitvec" @@ -212,24 +212,21 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.13.0" +version = "3.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" @@ -255,9 +252,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.30" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd4e7873dbddba6c7c91e199c7fcb946abc4a6a4ac3195400bcfb01b5de877" +checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" dependencies = [ "android-tzdata", "iana-time-zone", @@ -292,9 +289,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "crc" @@ -307,9 +304,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.2.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cace84e55f07e7301bae1c519df89cdad8cc3cd868413d3fdbdeca9ff3db484" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crossbeam-channel" @@ -323,12 +320,11 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils 0.8.16", + "crossbeam-utils 0.8.19", ] [[package]] @@ -344,12 +340,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "driver-block" @@ -364,7 +357,6 @@ name = "driver-network" version = "0.1.0" dependencies = [ "libredox 0.1.3", - "redox_event 0.1.0", "redox_syscall 0.5.1", ] @@ -372,13 +364,13 @@ dependencies = [ name = "e1000d" version = "0.1.0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "common", "driver-network", "libredox 0.1.3", "pcid", "redox-daemon", - "redox_event 0.1.0", + "redox_event", "redox_syscall 0.5.1", ] @@ -397,7 +389,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox_event 0.2.1", + "redox_event", "redox_syscall 0.5.1", ] @@ -429,9 +421,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -444,9 +436,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -454,15 +446,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -471,38 +463,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.53", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -518,9 +510,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.10" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" dependencies = [ "cfg-if 1.0.0", "libc", @@ -533,7 +525,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8283e7331b8c93b9756e0cfdbcfb90312852f953c6faf9bf741e684cc3b6ad69" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "crc", "log", "uuid", @@ -541,9 +533,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "heck" @@ -565,16 +557,16 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.57" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows", + "windows-core", ] [[package]] @@ -604,23 +596,23 @@ dependencies = [ name = "ihdad" version = "0.1.0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "common", "libredox 0.1.3", "log", "pcid", "redox-daemon", "redox-log", - "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_event", + "redox_syscall 0.5.1", "spin", ] [[package]] name = "indexmap" -version = "2.0.0" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown", @@ -651,29 +643,29 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "ixgbed" version = "1.0.0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "common", "driver-network", "libredox 0.1.3", "pcid", "redox-daemon", - "redox_event 0.1.0", + "redox_event", "redox_syscall 0.5.1", ] [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -692,11 +684,11 @@ checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libredox" -version = "0.0.1" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "redox_syscall 0.4.1", ] @@ -707,7 +699,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libc", "redox_syscall 0.5.1", ] @@ -719,15 +711,15 @@ dependencies = [ "anyhow", "libredox 0.1.3", "redox-daemon", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "slab", ] [[package]] name = "lock_api" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", @@ -735,9 +727,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.20" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "maybe-uninit" @@ -747,9 +739,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.6.3" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "num-derive" @@ -764,9 +756,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.16" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", ] @@ -794,22 +786,22 @@ dependencies = [ "redox-daemon", "redox-log", "redox_syscall 0.5.1", - "smallvec 1.11.0", + "smallvec 1.13.1", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "orbclient" -version = "0.3.46" -source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#b24be0556b79bf7c78e2fbd76d5d97c9b1262251" +version = "0.3.47" +source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#8de2b5ac9ff71811cde41e3085fe6722a823a7e2" dependencies = [ "libc", - "redox_syscall 0.3.5", + "libredox 0.0.2", "sdl2", "sdl2-sys", ] @@ -866,7 +858,7 @@ dependencies = [ "instant", "libc", "redox_syscall 0.2.16", - "smallvec 1.11.0", + "smallvec 1.13.1", "winapi", ] @@ -915,12 +907,12 @@ checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" [[package]] name = "pci_types" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831e5bebf010674bc2e8070b892948120d4c453c71f37387e1ffea5636620dbe" +checksum = "ebac2b2ee11791f721a51184b632a916b3044f2ee7b2374e7fdcfdf3eaf29c79" dependencies = [ "bit_field", - "bitflags 2.4.2", + "bitflags 2.5.0", ] [[package]] @@ -940,7 +932,7 @@ dependencies = [ "pci_types", "plain", "redox-log", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "serde", "serde_json", "structopt", @@ -954,7 +946,7 @@ version = "0.1.0" dependencies = [ "libredox 0.1.3", "redox-daemon", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] @@ -1001,9 +993,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -1016,14 +1008,14 @@ dependencies = [ "libredox 0.1.3", "orbclient", "redox-daemon", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1092,42 +1084,23 @@ dependencies = [ [[package]] name = "redox-log" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf6d33a003a5c0b94ec11f10c7c797303f236592964ddb1bfb93e1b438a1557" +checksum = "dbd7c67eb2d8e610a74a8f1e67eecd3042f87b1aebfa620de4b40257265a54f2" dependencies = [ "chrono", "log", - "smallvec 1.11.0", + "smallvec 1.13.1", "termion", ] -[[package]] -name = "redox_event" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/event.git#3f9ca18968d2c2d0f9ea819983d666f8b24eacf1" -dependencies = [ - "redox_syscall 0.4.1", -] - -[[package]] -name = "redox_event" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475e252d7add4825405d2248d530d33e22364ac5477eab816b56efbeec1e2712" -dependencies = [ - "bitflags 2.4.2", - "libredox 0.0.1", - "redox_syscall 0.4.1", -] - [[package]] name = "redox_event" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69609faa5d5992247a4ef379917bb3e39be281405d6a0ccd4f942429400b956f" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "libredox 0.1.3", ] @@ -1140,15 +1113,6 @@ dependencies = [ "bitflags 1.3.2", ] -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.4.1" @@ -1164,23 +1128,20 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", ] [[package]] name = "redox_termios" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" -dependencies = [ - "redox_syscall 0.2.16", -] +checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" [[package]] name = "rtl8139d" version = "0.1.0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "common", "driver-network", "libredox 0.1.3", @@ -1188,7 +1149,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_event 0.1.0", + "redox_event", "redox_syscall 0.5.1", ] @@ -1196,7 +1157,7 @@ dependencies = [ name = "rtl8168d" version = "0.1.0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "common", "driver-network", "libredox 0.1.3", @@ -1204,7 +1165,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_event 0.1.0", + "redox_event", "redox_syscall 0.5.1", ] @@ -1216,22 +1177,22 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "ryu" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" [[package]] name = "sb16d" version = "0.1.0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "common", "libredox 0.1.3", "log", "redox-daemon", "redox-log", - "redox_event 0.1.0", - "redox_syscall 0.4.1", + "redox_event", + "redox_syscall 0.5.1", "spin", ] @@ -1286,29 +1247,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.188" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.53", ] [[package]] name = "serde_json" -version = "1.0.105" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -1317,9 +1278,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" dependencies = [ "serde", ] @@ -1344,9 +1305,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" dependencies = [ "serde", ] @@ -1425,9 +1386,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.31" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718fa2415bcb8d8bd775917a1bf12a7931b6dfa890753378538118181e0cb398" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -1442,13 +1403,13 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "termion" -version = "1.5.6" +version = "2.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e" +checksum = "c4648c7def6f2043b2568617b9f9b75eae88ca185dbc1f1fda30e95a85d49d7d" dependencies = [ "libc", + "libredox 0.0.2", "numtoa", - "redox_syscall 0.2.16", "redox_termios", ] @@ -1463,22 +1424,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.48" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6d7a740b8a666a7e828dd00da9c0dc290dff53154ea77ac109281de90589b7" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.48" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49922ecae66cc8a249b77e68d1d0623c1b2c514f0060c27cdc68bd62a1219d35" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.53", ] [[package]] @@ -1492,9 +1453,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0a3ab2091e52d7299a39d098e200114a972df0a7724add02a273aa9aada592" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" dependencies = [ "serde", "serde_spanned", @@ -1504,9 +1465,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" dependencies = [ "serde", ] @@ -1526,21 +1487,21 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-segmentation" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" [[package]] name = "usbctl" @@ -1554,11 +1515,11 @@ dependencies = [ name = "usbhidd" version = "0.1.0" dependencies = [ - "bitflags 1.3.2", + "bitflags 2.5.0", "log", "orbclient", "redox-log", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "ux", "xhcid", ] @@ -1571,7 +1532,7 @@ dependencies = [ "libredox 0.1.3", "plain", "redox-daemon", - "redox_syscall 0.4.1", + "redox_syscall 0.5.1", "thiserror", "xhcid", ] @@ -1584,9 +1545,9 @@ checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" [[package]] name = "uuid" -version = "1.4.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ "getrandom", ] @@ -1606,7 +1567,7 @@ dependencies = [ "orbclient", "pcid", "redox-daemon", - "redox_event 0.1.0", + "redox_event", "redox_syscall 0.5.1", ] @@ -1666,7 +1627,7 @@ dependencies = [ name = "virtio-core" version = "0.1.0" dependencies = [ - "bitflags 2.4.2", + "bitflags 2.5.0", "common", "crossbeam-queue", "futures", @@ -1674,7 +1635,7 @@ dependencies = [ "log", "pcid", "redox-log", - "redox_event 0.1.0", + "redox_event", "redox_syscall 0.5.1", "static_assertions", "thiserror", @@ -1733,9 +1694,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if 1.0.0", "wasm-bindgen-macro", @@ -1743,24 +1704,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.53", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1768,22 +1729,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.31", + "syn 2.0.53", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "winapi" @@ -1808,19 +1769,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows" -version = "0.48.0" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1833,51 +1794,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "winnow" -version = "0.5.15" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" dependencies = [ "memchr", ] @@ -1907,11 +1868,11 @@ dependencies = [ "plain", "redox-daemon", "redox-log", - "redox_event 0.4.1", + "redox_event", "redox_syscall 0.5.1", "serde", "serde_json", - "smallvec 1.11.0", + "smallvec 1.13.1", "thiserror", "toml 0.5.11", ] diff --git a/audio/ac97d/Cargo.toml b/audio/ac97d/Cargo.toml index 50b781cfca..da7d2f14c5 100644 --- a/audio/ac97d/Cargo.toml +++ b/audio/ac97d/Cargo.toml @@ -6,12 +6,12 @@ edition = "2018" [dependencies] bitflags = "1" common = { path = "../../common" } +libredox = "0.1.3" log = "0.4" redox-daemon = "0.1" -redox-log = "0.1" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox-log = "0.1.2" +redox_event = "0.4.1" redox_syscall = "0.5" spin = "0.9" pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index 8649e671d6..322f86e56a 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -12,7 +12,7 @@ use std::cell::RefCell; use std::sync::Arc; use std::usize; -use event::EventQueue; +use event::{user_data, EventQueue}; use libredox::flag; use pcid_interface::{PciBar, PcidServerHandle}; use redox_log::{OutputBuilder, RedoxLogger}; @@ -24,10 +24,10 @@ fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() ); #[cfg(target_os = "redox")] @@ -35,8 +35,8 @@ fn setup_logging() -> Option<&'static RedoxLogger> { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() + .flush_on_newline(true) + .build() ), Err(error) => eprintln!("ac97d: failed to create ac97.log: {}", error), } @@ -45,9 +45,9 @@ fn setup_logging() -> Option<&'static RedoxLogger> { match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "ac97.ansi.log") { Ok(b) => logger = logger.with_output( b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() ), Err(error) => eprintln!("ac97d: failed to create ac97.ansi.log: {}", error), } @@ -65,145 +65,110 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } fn main() { - let mut pcid_handle = + let mut pcid_handle = PcidServerHandle::connect_default().expect("ac97d: failed to setup channel to pcid"); let pci_config = pcid_handle .fetch_config() .expect("ac97d: failed to fetch config"); - let mut name = pci_config.func.name(); - name.push_str("_ac97"); + let mut name = pci_config.func.name(); + name.push_str("_ac97"); - let bar0 = pci_config.func.bars[0].expect_port(); - let bar1 = pci_config.func.bars[1].expect_port(); + let bar0 = pci_config.func.bars[0].expect_port(); + let bar1 = pci_config.func.bars[1].expect_port(); - let irq = pci_config.func.legacy_interrupt_line.expect("ac97d: no legacy interrupts supported"); + let irq = pci_config.func.legacy_interrupt_line.expect("ac97d: no legacy interrupts supported"); - println!(" + ac97 {}", pci_config.func.display()); + println!(" + ac97 {}", pci_config.func.display()); - // Daemonize + // Daemonize redox_daemon::Daemon::new(move |daemon| { - let _logger_ref = setup_logging(); + let _logger_ref = setup_logging(); common::acquire_port_io_rights().expect("ac97d: failed to set I/O privilege level to Ring 3"); - let mut irq_file = irq.irq_handle("ac97d"); + let mut irq_file = irq.irq_handle("ac97d"); - let device = Arc::new(RefCell::new(unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") })); - let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ac97d: failed to create hda scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + let mut device = unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") }; + let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ac97d: failed to create hda scheme"); + let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + + user_data! { + enum Source { + Irq, + Scheme, + } + } + + let mut event_queue = EventQueue::::new().expect("ac97d: Could not create event queue."); + event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); + event_queue.subscribe(socket_fd, Source::Scheme, event::EventFlags::READ).unwrap(); daemon.ready().expect("ac97d: failed to signal readiness"); - let mut event_queue = EventQueue::::new().expect("ac97d: Could not create event queue."); - libredox::call::setrens(0, 0).expect("ac97d: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + let mut todo = Vec::::new(); - let todo_irq = todo.clone(); - let device_irq = device.clone(); - let socket_irq = socket.clone(); + 'events: for event in event_queue.map(|e| e.expect("ac97d: failed to get next event")) { + match event.user_data { + Source::Irq => { + let mut irq = [0; 8]; + irq_file.read(&mut irq).unwrap(); - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; + if device.irq() { + irq_file.write(&mut irq).unwrap(); - if device_irq.borrow_mut().irq() { - irq_file.write(&mut irq)?; + let mut i = 0; + while i < todo.len() { + if let Some(a) = device.handle(&mut todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&packet).unwrap(); + } else { + i += 1; + } + } - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - if let Some(a) = device_irq.borrow_mut().handle(&mut todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket_irq.borrow_mut().write(&packet)?; - } else { - i += 1; - } - } + /* + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + } + } + Source::Scheme => { + loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => break 'events, + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; + } else { + panic!("ac97d: failed to read socket: {err}"); + } + } - /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - } - Ok(None) - }).expect("ac97d: failed to catch events on IRQ file"); - let socket_fd = socket.borrow().as_raw_fd(); - let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_event| -> Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => return Ok(Some(0)), - Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } + if let Some(a) = device.handle(&mut packet) { + packet.a = a; + socket.write(&packet).unwrap(); + } else { + todo.push(packet); + } + } - if let Some(a) = device.borrow_mut().handle(&mut packet) { - packet.a = a; - socket_packet.borrow_mut().write(&packet)?; - } else { - todo.borrow_mut().push(packet); - } - } - - /* - let next_read = device.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - - Ok(None) - }).expect("ac97d: failed to catch events on IRQ file"); - - for event_count in event_queue.trigger_all(event::Event { - fd: 0, - flags: Default::default(), - }).expect("ac97d: failed to trigger events") { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("ac97d: failed to write event"); - } - - loop { - { - //device_loop.borrow_mut().handle_interrupts(); - } - let event_count = event_queue.run().expect("ac97d: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } - - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("ac97d: failed to write event"); - } + /* + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + } + } + } std::process::exit(0); - }).expect("ac97d: failed to daemonize"); + }).expect("ac97d: failed to daemonize"); } diff --git a/audio/ihdad/Cargo.toml b/audio/ihdad/Cargo.toml index 736e98d31e..c356f48056 100644 --- a/audio/ihdad/Cargo.toml +++ b/audio/ihdad/Cargo.toml @@ -4,14 +4,14 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "1" +bitflags = "2" +libredox = "0.1.3" log = "0.4" redox-daemon = "0.1" -redox-log = "0.1" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox-log = "0.1.2" +redox_event = "0.4.1" +redox_syscall = "0.5" spin = "0.9" common = { path = "../../common" } pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index bb29a49007..2e5c83a3fe 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -15,7 +15,7 @@ use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; -use event::EventQueue; +use event::{user_data, EventQueue}; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; @@ -25,20 +25,20 @@ use redox_log::{OutputBuilder, RedoxLogger}; pub mod hda; /* - VEND:PROD - Virtualbox 8086:2668 - QEMU ICH9 8086:293E - 82801H ICH8 8086:284B -*/ + VEND:PROD + Virtualbox 8086:2668 + QEMU ICH9 8086:293E + 82801H ICH8 8086:284B + */ fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( OutputBuilder::stderr() - .with_filter(log::LevelFilter::Debug) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() + .with_filter(log::LevelFilter::Debug) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() ); #[cfg(target_os = "redox")] @@ -46,8 +46,8 @@ fn setup_logging() -> Option<&'static RedoxLogger> { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() + .flush_on_newline(true) + .build() ), Err(error) => eprintln!("ihdad: failed to create ihda.log: {}", error), } @@ -56,9 +56,9 @@ fn setup_logging() -> Option<&'static RedoxLogger> { match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "ihda.ansi.log") { Ok(b) => logger = logger.with_output( b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() ), Err(error) => eprintln!("ihdad: failed to create ihda.ansi.log: {}", error), } @@ -153,133 +153,100 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::info!(" + IHDA {}", pci_config.func.display()); - let address = unsafe { bar.physmap_mem("ihdad") } as usize; + let address = unsafe { bar.physmap_mem("ihdad") } as usize; //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); - { - let vend_prod: u32 = ((pci_config.func.full_device_id.vendor_id as u32) << 16) + { + let vend_prod: u32 = ((pci_config.func.full_device_id.vendor_id as u32) << 16) | (pci_config.func.full_device_id.device_id as u32); - let device = Arc::new(RefCell::new(unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") })); - let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ihdad: failed to create hda scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); - daemon.ready().expect("ihdad: failed to signal readiness"); + user_data! { + enum Source { + Irq, + Scheme, + } + } - let mut event_queue = EventQueue::::new().expect("ihdad: Could not create event queue."); + let mut event_queue = EventQueue::::new().expect("ihdad: Could not create event queue."); + let mut device = unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") }; + let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ihdad: failed to create hda scheme"); + let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + + event_queue.subscribe(socket_fd, Source::Scheme, event::EventFlags::READ).unwrap(); + event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); + + daemon.ready().expect("ihdad: failed to signal readiness"); libredox::call::setrens(0, 0).expect("ihdad: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + let mut todo = Vec::::new(); - let todo_irq = todo.clone(); - let device_irq = device.clone(); - let socket_irq = socket.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; + 'events: for event in event_queue.map(|e| e.expect("failed to get next event")) { + match event.user_data { + Source::Irq => { + let mut irq = [0; 8]; + irq_file.read(&mut irq).unwrap(); - if device_irq.borrow_mut().irq() { - irq_file.write(&mut irq)?; + if device.irq() { + irq_file.write(&mut irq).unwrap(); - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - if let Some(a) = device_irq.borrow_mut().handle(&mut todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket_irq.borrow_mut().write(&packet)?; - } else { - i += 1; - } - } + let mut i = 0; + while i < todo.len() { + if let Some(a) = device.handle(&mut todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&packet).unwrap(); + } else { + i += 1; + } + } - /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - } - Ok(None) - }).expect("ihdad: failed to catch events on IRQ file"); - let socket_fd = socket.borrow().as_raw_fd(); - let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_event| -> Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => return Ok(Some(0)), - Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); - } - } + /* + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + } + } + Source::Scheme => { + loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => break 'events, + Ok(_) => (), + Err(err) => if err.kind() == ErrorKind::WouldBlock { + break; + } else { + panic!("ihdad: failed to read from socket: {err}"); + } + } - if let Some(a) = device.borrow_mut().handle(&mut packet) { - packet.a = a; - socket_packet.borrow_mut().write(&packet)?; - } else { - todo.borrow_mut().push(packet); - } - } + if let Some(a) = device.handle(&mut packet) { + packet.a = a; + socket.write(&packet).unwrap(); + } else { + todo.push(packet); + } + } - /* - let next_read = device.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ + /* + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + } + } + } - Ok(None) - }).expect("ihdad: failed to catch events on IRQ file"); - - for event_count in event_queue.trigger_all(event::Event { - fd: 0, - flags: EventFlags::empty(), - }).expect("ihdad: failed to trigger events") { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("ihdad: failed to write event"); - } - - loop { - { - //device_loop.borrow_mut().handle_interrupts(); - } - let event_count = event_queue.run().expect("ihdad: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } - - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("ihdad: failed to write event"); - } - } - - std::process::exit(0); + std::process::exit(0); + } } fn main() { - // Daemonize + // Daemonize redox_daemon::Daemon::new(daemon).expect("ihdad: failed to daemonize"); } diff --git a/audio/pcspkrd/Cargo.toml b/audio/pcspkrd/Cargo.toml index 72bae14204..2ff4476a9a 100644 --- a/audio/pcspkrd/Cargo.toml +++ b/audio/pcspkrd/Cargo.toml @@ -5,6 +5,6 @@ authors = ["Tibor Nagy "] edition = "2018" [dependencies] -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" libredox = "0.1.3" diff --git a/audio/sb16d/Cargo.toml b/audio/sb16d/Cargo.toml index eb5a92a6e8..89e816451d 100644 --- a/audio/sb16d/Cargo.toml +++ b/audio/sb16d/Cargo.toml @@ -4,12 +4,12 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "1" +bitflags = "2" common = { path = "../../common" } libredox = "0.1.3" log = "0.4" redox-daemon = "0.1" -redox-log = "0.1" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } -redox_syscall = "0.4" +redox-log = "0.1.2" +redox_event = "0.4.1" +redox_syscall = "0.5" spin = "0.9" diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index 814ed2066d..c6e1d1571a 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -1,20 +1,16 @@ //#![deny(warnings)] -extern crate bitflags; -extern crate spin; -extern crate syscall; -extern crate event; - use std::{env, usize}; use std::fs::File; use std::io::{ErrorKind, Read, Write, Result}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use libredox::flag; +use libredox::errno::{EAGAIN, EWOULDBLOCK}; +use libredox::{flag, Fd}; use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; use std::sync::Arc; -use event::EventQueue; +use event::{user_data, EventQueue}; use redox_log::{OutputBuilder, RedoxLogger}; pub mod device; @@ -77,127 +73,82 @@ fn main() { common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights"); - let device = Arc::new(RefCell::new(unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") })); - let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("sb16d: failed to create hda scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + let mut device = unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") }; + let socket = Fd::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("sb16d: failed to create hda scheme"); //TODO: error on multiple IRQs? - let mut irq_file = match device.borrow().irqs.first() { - Some(irq) => File::open(format!("irq:{}", irq)).expect("sb16d: failed to open IRQ file"), + let mut irq_file = match device.irqs.first() { + Some(irq) => Fd::open(&format!("irq:{}", irq), flag::O_RDWR, 0).expect("sb16d: failed to open IRQ file"), None => panic!("sb16d: no IRQs found"), }; + user_data! { + enum Source { + Irq, + Scheme, + } + } + + let mut event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); + event_queue.subscribe(irq_file.raw(), Source::Irq, event::EventFlags::READ).unwrap(); + event_queue.subscribe(socket.raw(), Source::Scheme, event::EventFlags::READ).unwrap(); daemon.ready().expect("sb16d: failed to signal readiness"); - let mut event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); - libredox::call::setrens(0, 0).expect("sb16d: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + let mut todo = Vec::::new(); - let todo_irq = todo.clone(); - let device_irq = device.clone(); - let socket_irq = socket.clone(); + 'events: for event_res in event_queue { + let event = event_res.expect("sb16d: failed to get next event"); + match event.user_data { + Source::Irq => { + let mut irq = [0; 8]; + irq_file.read(&mut irq).unwrap(); - // TODO: Use new event queue API + if device.irq() { + irq_file.write(&mut irq).unwrap(); - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; + let mut i = 0; + while i < todo.len() { + if let Some(a) = device.handle(&mut todo[i]) { + let mut packet = todo.remove(i); + packet.a = a; + socket.write(&packet).expect("sb16d: failed to write to socket"); + } else { + i += 1; + } + } - if device_irq.borrow_mut().irq() { - irq_file.write(&mut irq)?; - - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - if let Some(a) = device_irq.borrow_mut().handle(&mut todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket_irq.borrow_mut().write(&packet)?; - } else { - i += 1; + /* + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ } } + Source::Scheme => { + loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => break 'events, + Ok(_) => (), + Err(err) => if err.errno() == EWOULDBLOCK || err.errno() == EAGAIN { + break; + } else { + panic!("sb16d: failed to read from scheme socket"); + } + } - /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - } - Ok(None) - }).expect("sb16d: failed to catch events on IRQ file"); - let socket_fd = socket.borrow().as_raw_fd(); - let socket_packet = socket.clone(); - event_queue.add(socket_fd, move |_event| -> Result> { - loop { - let mut packet = Packet::default(); - match socket_packet.borrow_mut().read(&mut packet) { - Ok(0) => return Ok(Some(0)), - Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { - break; - } else { - return Err(err); + if let Some(a) = device.handle(&mut packet) { + packet.a = a; + socket.write(&packet).expect("sb16d: failed to write to scheme socket"); + } else { + todo.push(packet); + } } } - - if let Some(a) = device.borrow_mut().handle(&mut packet) { - packet.a = a; - socket_packet.borrow_mut().write(&packet)?; - } else { - todo.borrow_mut().push(packet); - } } - - /* - let next_read = device.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ - - Ok(None) - }).expect("sb16d: failed to catch events on IRQ file"); - - for event_count in event_queue.trigger_all(event::Event { - fd: 0, - flags: EventFlags::empty(), - }).expect("sb16d: failed to trigger events") { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("sb16d: failed to write event"); - } - - loop { - { - //device_loop.borrow_mut().handle_interrupts(); - } - let event_count = event_queue.run().expect("sb16d: failed to handle events"); - if event_count == 0 { - //TODO: Handle todo - break; - } - - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("sb16d: failed to write event"); } std::process::exit(0); diff --git a/graphics/bgad/Cargo.toml b/graphics/bgad/Cargo.toml index 0c439fd17a..76dc78b582 100644 --- a/graphics/bgad/Cargo.toml +++ b/graphics/bgad/Cargo.toml @@ -4,9 +4,9 @@ version = "0.1.0" edition = "2018" [dependencies] -orbclient = "0.3.27" +orbclient = "0.3.47" redox-daemon = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" pcid = { path = "../../pcid" } libredox = "0.1.3" diff --git a/graphics/fbcond/Cargo.toml b/graphics/fbcond/Cargo.toml index 0e466e15cb..42e155eaac 100644 --- a/graphics/fbcond/Cargo.toml +++ b/graphics/fbcond/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] orbclient = "0.3.27" ransid = "0.4" -redox_event = "0.2" +redox_event = "0.4" redox_syscall = "0.5" redox-daemon = "0.1" diff --git a/net/alxd/Cargo.toml b/net/alxd/Cargo.toml index 5d20a58d5b..af09892e0b 100644 --- a/net/alxd/Cargo.toml +++ b/net/alxd/Cargo.toml @@ -4,8 +4,8 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "1" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +bitflags = "2" +redox_event = "0.4.1" redox_syscall = "0.5" redox-daemon = "0.1" diff --git a/net/alxd/src/main.rs b/net/alxd/src/main.rs index 8ff8e18c52..2ffce2e201 100644 --- a/net/alxd/src/main.rs +++ b/net/alxd/src/main.rs @@ -6,16 +6,15 @@ extern crate event; extern crate syscall; -use std::cell::RefCell; -use std::env; +use std::{env, iter}; use std::fs::File; -use std::io::{Read, Write, Result}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::sync::Arc; +use std::io::{Read, Write}; +use std::os::fd::AsRawFd; +use std::os::unix::io::{FromRawFd, RawFd}; -use event::EventQueue; +use event::{user_data, EventQueue}; use libredox::flag; -use syscall::{EventFlags, Packet, SchemeMut}; +use syscall::{Packet, SchemeMut}; use syscall::error::EWOULDBLOCK; pub mod device; @@ -37,7 +36,7 @@ fn main() { // Daemonize redox_daemon::Daemon::new(move |daemon| { let socket_fd = libredox::call::open(":network", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("alxd: failed to create network scheme"); - let socket = Arc::new(RefCell::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; daemon.ready().expect("alxd: failed to signal readiness"); @@ -45,100 +44,78 @@ fn main() { let address = unsafe { common::physmap(bar, 128*1024, common::Prot::RW, common::MemoryType::Uncacheable).expect("alxd: failed to map address") as usize }; { - let device = Arc::new(RefCell::new(unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") })); + let mut device = unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") }; - let mut event_queue = EventQueue::::new().expect("alxd: failed to create event queue"); + user_data! { + enum Source { + Irq, + Scheme, + } + } + + let event_queue = EventQueue::::new().expect("alxd: failed to create event queue"); + event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); + event_queue.subscribe(socket_fd, Source::Scheme, event::EventFlags::READ).unwrap(); libredox::call::setrens(0, 0).expect("alxd: failed to enter null namespace"); - let todo = Arc::new(RefCell::new(Vec::::new())); + let mut todo = Vec::::new(); - let device_irq = device.clone(); - let socket_irq = socket.clone(); - let todo_irq = todo.clone(); - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { - let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - if unsafe { device_irq.borrow_mut().intr_legacy() } { - irq_file.write(&mut irq)?; + for event in iter::once(Source::Scheme).chain(event_queue.map(|e| e.expect("alxd: failed to get next event").user_data)) { + match event { + Source::Irq => { + let mut irq = [0; 8]; + irq_file.read(&mut irq).unwrap(); + if unsafe { device.intr_legacy() } { + irq_file.write(&mut irq).unwrap(); - let mut todo = todo_irq.borrow_mut(); - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - device_irq.borrow_mut().handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket_irq.borrow_mut().write(&mut todo[i])?; - todo.remove(i); + let mut i = 0; + while i < todo.len() { + let a = todo[i].a; + device.handle(&mut todo[i]); + if todo[i].a == (-EWOULDBLOCK) as usize { + todo[i].a = a; + i += 1; + } else { + socket.write(&mut todo[i]).expect("alxd: failed to write to socket"); + todo.remove(i); + } + } + + /* TODO: Currently a no-op + let next_read = device.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ } } + Source::Scheme => { + loop { + let mut packet = Packet::default(); + if socket.read(&mut packet).expect("alxd: failed read from socket") == 0 { + break; + } - let next_read = device_irq.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); + let a = packet.a; + device.handle(&mut packet); + if packet.a == (-EWOULDBLOCK) as usize { + packet.a = a; + todo.push(packet); + } else { + socket.write(&mut packet).expect("alxd: failed to write to socket"); + } + } + + // TODO + /* + let next_read = device.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ } } - Ok(None) - }).expect("alxd: failed to catch events on IRQ file"); - - let socket_packet = socket.clone(); - event_queue.add(socket_fd as RawFd, move |_event| -> Result> { - loop { - let mut packet = Packet::default(); - if socket_packet.borrow_mut().read(&mut packet)? == 0 { - break; - } - - let a = packet.a; - device.borrow_mut().handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.borrow_mut().push(packet); - } else { - socket_packet.borrow_mut().write(&mut packet)?; - } - } - - let next_read = device.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - - Ok(None) - }).expect("alxd: failed to catch events on IRQ file"); - - for event_count in event_queue.trigger_all(event::Event { - fd: 0, - flags: Default::default(), - }).expect("alxd: failed to trigger events") { - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("alxd: failed to write event"); - } - - loop { - let event_count = event_queue.run().expect("alxd: failed to handle events"); - - socket.borrow_mut().write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: 0, - c: syscall::flag::EVENT_READ.bits(), - d: event_count - }).expect("alxd: failed to write event"); } } std::process::exit(0); diff --git a/net/driver-network/Cargo.toml b/net/driver-network/Cargo.toml index 965bbcf23c..bfec9b86d1 100644 --- a/net/driver-network/Cargo.toml +++ b/net/driver-network/Cargo.toml @@ -5,5 +5,4 @@ edition = "2021" [dependencies] libredox = "0.1.3" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } redox_syscall = "0.5" diff --git a/net/e1000d/Cargo.toml b/net/e1000d/Cargo.toml index bc6c347647..3066ac6c16 100644 --- a/net/e1000d/Cargo.toml +++ b/net/e1000d/Cargo.toml @@ -4,12 +4,12 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "1" -redox-daemon = "0.1" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +bitflags = "2" +redox-daemon = "0.1.2" +libredox = "0.1.3" +redox_event = "0.4.1" redox_syscall = "0.5" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index 8c532f3c68..b5480587bc 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -5,7 +5,7 @@ use std::os::unix::io::AsRawFd; use std::rc::Rc; use driver_network::NetworkScheme; -use event::EventQueue; +use event::{user_data, EventQueue}; use pcid_interface::PcidServerHandle; use syscall::EventFlags; @@ -38,10 +38,22 @@ fn main() { let device = unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }; - let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, format!("network.{name}")))); + let mut scheme = NetworkScheme::new(device, format!("network.{name}")); + + user_data! { + enum Source { + Irq, + Scheme, + } + } let mut event_queue = - EventQueue::::new().expect("e1000d: failed to create event queue"); + EventQueue::::new().expect("e1000d: failed to create event queue"); + + event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ) + .expect("e1000d: failed to subscribe to IRQ fd"); + event_queue.subscribe(scheme.event_handle() as usize, Source::Scheme, event::EventFlags::READ) + .expect("e1000d: failed to subscribe to scheme fd"); libredox::call::setrens(0, 0).expect("e1000d: failed to enter null namespace"); @@ -49,42 +61,23 @@ fn main() { .ready() .expect("e1000d: failed to mark daemon as ready"); - let scheme_irq = scheme.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { + scheme.tick().unwrap(); + + for event in event_queue.map(|e| e.expect("e1000d: failed to get event")) { + match event.user_data { + Source::Irq => { let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - if unsafe { scheme_irq.borrow().adapter().irq() } { - irq_file.write(&mut irq)?; + irq_file.read(&mut irq).unwrap(); + if unsafe { scheme.adapter().irq() } { + irq_file.write(&mut irq).unwrap(); - return scheme_irq.borrow_mut().tick().map(|()| None); + scheme.tick().expect("e1000d: failed to handle IRQ") } - Ok(None) - }, - ) - .expect("e1000d: failed to catch events on IRQ file"); - - let scheme_packet = scheme.clone(); - event_queue - .add( - scheme.borrow().event_handle(), - move |_event| -> Result> { - scheme_packet.borrow_mut().tick().map(|()| None) - }, - ) - .expect("e1000d: failed to catch events on scheme file"); - - event_queue - .trigger_all(event::Event { - fd: 0, - flags: Default::default(), - }) - .expect("e1000d: failed to trigger events"); - - #[allow(unreachable_code)] - match event_queue.run().expect("e1000d: failed to handle events") {} + } + Source::Scheme => scheme.tick().expect("e1000d: failed to handle scheme op"), + } + } + unreachable!() }) .expect("e1000d: failed to create daemon"); } diff --git a/net/ixgbed/Cargo.toml b/net/ixgbed/Cargo.toml index 38ee7a7477..cce0badf9f 100644 --- a/net/ixgbed/Cargo.toml +++ b/net/ixgbed/Cargo.toml @@ -4,12 +4,12 @@ version = "1.0.0" edition = "2021" [dependencies] -bitflags = "1.0" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +bitflags = "2" +libredox = "0.1.3" +redox_event = "0.4.1" redox_syscall = "0.5" redox-daemon = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index 7c6aefbb27..716253324a 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -5,7 +5,7 @@ use std::os::unix::io::AsRawFd; use std::rc::Rc; use driver_network::NetworkScheme; -use event::EventQueue; +use event::{user_data, EventQueue}; use pcid_interface::PcidServerHandle; use syscall::EventFlags; @@ -50,10 +50,18 @@ fn main() { let device = device::Intel8259x::new(address, IXGBE_MMIO_SIZE) .expect("ixgbed: failed to allocate device"); - let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, format!("network.{name}")))); + let mut scheme = NetworkScheme::new(device, format!("network.{name}")); - let mut event_queue = - EventQueue::::new().expect("ixgbed: failed to create event queue"); + user_data! { + enum Source { + Irq, + Scheme, + } + } + + let mut event_queue = EventQueue::::new().expect("ixgbed: Could not create event queue."); + event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); + event_queue.subscribe(scheme.event_handle() as usize, Source::Scheme, event::EventFlags::READ).unwrap(); libredox::call::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); @@ -61,42 +69,25 @@ fn main() { .ready() .expect("ixgbed: failed to mark daemon as ready"); - let scheme_irq = scheme.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { + scheme.tick().unwrap(); + + for event in event_queue.map(|e| e.expect("ixgbed: failed to get next event")) { + match event.user_data { + Source::Irq => { let mut irq = [0; 8]; - irq_file.read(&mut irq)?; - if scheme_irq.borrow().adapter().irq() { - irq_file.write(&mut irq)?; + irq_file.read(&mut irq).unwrap(); + if scheme.adapter().irq() { + irq_file.write(&mut irq).unwrap(); - return scheme_irq.borrow_mut().tick().map(|()| None); + scheme.tick().unwrap(); } - Ok(None) - }, - ) - .expect("ixgbed: failed to catch events on IRQ file"); - - let scheme_packet = scheme.clone(); - event_queue - .add( - scheme.borrow().event_handle(), - move |_event| -> Result> { - scheme_packet.borrow_mut().tick().map(|()| None) - }, - ) - .expect("ixgbed: failed to catch events on scheme file"); - - event_queue - .trigger_all(event::Event { - fd: 0, - flags: Default::default(), - }) - .expect("ixgbed: failed to trigger events"); - - #[allow(unreachable_code)] - match event_queue.run().expect("ixgbed: failed to handle events") {} + } + Source::Scheme => { + scheme.tick().unwrap(); + } + } + } + unreachable!() }) .expect("ixgbed: failed to create daemon"); } diff --git a/net/rtl8139d/Cargo.toml b/net/rtl8139d/Cargo.toml index ef23f408db..432b562cb9 100644 --- a/net/rtl8139d/Cargo.toml +++ b/net/rtl8139d/Cargo.toml @@ -4,9 +4,10 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "1" +bitflags = "2" +libredox = "0.1.3" log = "0.4" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox_event = "0.4.1" redox_syscall = "0.5" redox-daemon = "0.1" redox-log = "0.1" @@ -14,4 +15,3 @@ redox-log = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 66ca3b533e..113b395e2c 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -9,7 +9,7 @@ use std::ptr::NonNull; use std::rc::Rc; use driver_network::NetworkScheme; -use event::EventQueue; +use event::{user_data, EventQueue}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; @@ -237,10 +237,18 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let device = unsafe { device::Rtl8139::new(address).expect("rtl8139d: failed to allocate device") }; - let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, format!("network.{name}")))); + let mut scheme = NetworkScheme::new(device, format!("network.{name}")); - let mut event_queue = - EventQueue::::new().expect("rtl8139d: failed to create event queue"); + user_data! { + enum Source { + Irq, + Scheme, + } + } + + let mut event_queue = EventQueue::::new().expect("rtl8139d: Could not create event queue."); + event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); + event_queue.subscribe(scheme.event_handle() as usize, Source::Scheme, event::EventFlags::READ).unwrap(); libredox::call::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); @@ -248,45 +256,26 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .ready() .expect("rtl8139d: failed to mark daemon as ready"); - let scheme_irq = scheme.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { + scheme.tick().unwrap(); + + for event in event_queue.map(|e| e.expect("rtl8139d: failed to get next event")) { + match event.user_data { + Source::Irq => { let mut irq = [0; 8]; - irq_file.read(&mut irq)?; + irq_file.read(&mut irq).unwrap(); //TODO: This may be causing spurious interrupts - if unsafe { scheme_irq.borrow_mut().adapter_mut().irq() } { - irq_file.write(&mut irq)?; + if unsafe { scheme.adapter_mut().irq() } { + irq_file.write(&mut irq).unwrap(); - return scheme_irq.borrow_mut().tick().map(|()| None); + scheme.tick().unwrap(); } - Ok(None) - }, - ) - .expect("rtl8139d: failed to catch events on IRQ file"); - - let scheme_packet = scheme.clone(); - event_queue - .add( - scheme.borrow().event_handle(), - move |_event| -> Result> { - scheme_packet.borrow_mut().tick().map(|()| None) - }, - ) - .expect("rtl8139d: failed to catch events on scheme file"); - - event_queue - .trigger_all(event::Event { - fd: 0, - flags: Default::default(), - }) - .expect("rtl8139d: failed to trigger events"); - - #[allow(unreachable_code)] - match event_queue - .run() - .expect("rtl8139d: failed to handle events") {} + } + Source::Scheme => { + scheme.tick().unwrap(); + } + } + } + unreachable!() } fn main() { diff --git a/net/rtl8168d/Cargo.toml b/net/rtl8168d/Cargo.toml index 2010b02b47..54a91855dd 100644 --- a/net/rtl8168d/Cargo.toml +++ b/net/rtl8168d/Cargo.toml @@ -4,9 +4,10 @@ version = "0.1.0" edition = "2018" [dependencies] -bitflags = "1" +bitflags = "2" +libredox = "0.1.3" log = "0.4" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox_event = "0.4.1" redox_syscall = "0.5" redox-daemon = "0.1" redox-log = "0.1" @@ -14,4 +15,3 @@ redox-log = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } pcid = { path = "../../pcid" } -libredox = "0.1.3" diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index e38501b3ec..7127effb52 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -7,7 +7,7 @@ use std::ptr::NonNull; use std::rc::Rc; use driver_network::NetworkScheme; -use event::EventQueue; +use event::{user_data, EventQueue}; use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; @@ -232,10 +232,18 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let device = unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") }; - let scheme = Rc::new(RefCell::new(NetworkScheme::new(device, format!("network.{name}")))); + let mut scheme = NetworkScheme::new(device, format!("network.{name}")); - let mut event_queue = - EventQueue::::new().expect("rtl8168d: failed to create event queue"); + user_data! { + enum Source { + Irq, + Scheme, + } + } + + let mut event_queue = EventQueue::::new().expect("rtl8168d: Could not create event queue."); + event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); + event_queue.subscribe(scheme.event_handle() as usize, Source::Scheme, event::EventFlags::READ).unwrap(); libredox::call::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); @@ -243,45 +251,26 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .ready() .expect("rtl8168d: failed to mark daemon as ready"); - let scheme_irq = scheme.clone(); - event_queue - .add( - irq_file.as_raw_fd(), - move |_event| -> Result> { + scheme.tick().unwrap(); + + for event in event_queue.map(|e| e.expect("rtl8168d: failed to get next event")) { + match event.user_data { + Source::Irq => { let mut irq = [0; 8]; - irq_file.read(&mut irq)?; + irq_file.read(&mut irq).unwrap(); //TODO: This may be causing spurious interrupts - if unsafe { scheme_irq.borrow_mut().adapter_mut().irq() } { - irq_file.write(&mut irq)?; + if unsafe { scheme.adapter_mut().irq() } { + irq_file.write(&mut irq).unwrap(); - return scheme_irq.borrow_mut().tick().map(|()| None); + scheme.tick().unwrap(); } - Ok(None) - }, - ) - .expect("rtl8168d: failed to catch events on IRQ file"); - - let scheme_packet = scheme.clone(); - event_queue - .add( - scheme.borrow().event_handle(), - move |_event| -> Result> { - scheme_packet.borrow_mut().tick().map(|()| None) - }, - ) - .expect("rtl8168d: failed to catch events on scheme file"); - - event_queue - .trigger_all(event::Event { - fd: 0, - flags: Default::default(), - }) - .expect("rtl8168d: failed to trigger events"); - - #[allow(unreachable_code)] - match event_queue - .run() - .expect("rtl8168d: failed to handle events") {} + } + Source::Scheme => { + scheme.tick().unwrap(); + } + } + } + unreachable!() } fn main() { diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 487b79029d..17d8061c36 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -23,7 +23,7 @@ paw = "1.0" pci_types = "0.6.1" plain = "0.2" redox-log = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" structopt = { version = "0.3", default-features = false, features = [ "paw" ] } diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 90f5875711..fb629ea72a 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -6,6 +6,6 @@ edition = "2018" [dependencies] bitflags = "1" orbclient = "0.3.27" -redox_syscall = "0.4" +redox_syscall = "0.5" redox-daemon = "0.1" libredox = "0.1.3" diff --git a/storage/lived/Cargo.toml b/storage/lived/Cargo.toml index 339708856e..d5fcdb91b6 100644 --- a/storage/lived/Cargo.toml +++ b/storage/lived/Cargo.toml @@ -11,5 +11,5 @@ license = "MIT" anyhow = "1" libredox = "0.1.3" redox-daemon = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" slab = "0.4" diff --git a/storage/usbscsid/Cargo.toml b/storage/usbscsid/Cargo.toml index d3ca3455ee..8b38f8617f 100644 --- a/storage/usbscsid/Cargo.toml +++ b/storage/usbscsid/Cargo.toml @@ -12,6 +12,6 @@ base64 = "0.11" # Only for debugging libredox = "0.1.3" plain = "0.2" redox-daemon = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" thiserror = "1" xhcid = { path = "../../xhcid" } diff --git a/usbhidd/Cargo.toml b/usbhidd/Cargo.toml index 8c51c019cd..b1cd4f0e9f 100644 --- a/usbhidd/Cargo.toml +++ b/usbhidd/Cargo.toml @@ -8,10 +8,10 @@ license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bitflags = "1.2" +bitflags = "2" log = "0.4" -orbclient = "0.3.27" +orbclient = "0.3.47" redox-log = "0.1" -redox_syscall = "0.4" +redox_syscall = "0.5" ux = "0.1" xhcid = { path = "../xhcid" } diff --git a/usbhidd/src/report_desc.rs b/usbhidd/src/report_desc.rs index b33927e13e..2835ba225c 100644 --- a/usbhidd/src/report_desc.rs +++ b/usbhidd/src/report_desc.rs @@ -9,6 +9,7 @@ enum Protocol { }*/ bitflags! { + #[derive(Clone, Copy, Debug)] pub struct MainItemFlags: u32 { const CONSTANT = 1 << 0; const VARIABLE = 1 << 1; diff --git a/vboxd/Cargo.toml b/vboxd/Cargo.toml index ff25884242..5c595e5ea1 100644 --- a/vboxd/Cargo.toml +++ b/vboxd/Cargo.toml @@ -4,11 +4,11 @@ version = "0.1.0" edition = "2018" [dependencies] -orbclient = "0.3.27" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +libredox = "0.1.3" +orbclient = "0.3.47" +redox_event = "0.4.1" redox_syscall = "0.5" redox-daemon = "0.1" common = { path = "../common" } pcid = { path = "../pcid" } -libredox = "0.1.3" diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 39b0c3efaf..f7269be46f 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -1,10 +1,6 @@ //#![deny(warnings)] -extern crate event; -extern crate orbclient; -extern crate syscall; - -use event::EventQueue; +use event::{user_data, EventQueue}; use std::mem; use std::os::unix::io::AsRawFd; use std::fs::File; @@ -203,8 +199,6 @@ fn main() { // Daemonize redox_daemon::Daemon::new(move |daemon| { - daemon.ready().expect("failed to signal readiness"); - common::acquire_port_io_rights().expect("vboxd: failed to get I/O permission"); let mut width = 0; @@ -242,7 +236,16 @@ fn main() { vmmdev.guest_events.write(VBOX_EVENT_DISPLAY | VBOX_EVENT_MOUSE); - let mut event_queue = EventQueue::<()>::new().expect("vboxd: failed to create event queue"); + user_data! { + enum Source { + Irq, + } + } + + let event_queue = EventQueue::::new().expect("vboxd: Could not create event queue."); + event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); + + daemon.ready().expect("failed to signal readiness"); libredox::call::setrens(0, 0).expect("vboxd: failed to enter null namespace"); @@ -250,13 +253,14 @@ fn main() { let get_mouse = VboxGetMouse::new().expect("vboxd: failed to map GetMouse"); let display_change = VboxDisplayChange::new().expect("vboxd: failed to map DisplayChange"); let ack_events = VboxAckEvents::new().expect("vboxd: failed to map AckEvents"); - event_queue.add(irq_file.as_raw_fd(), move |_event| -> Result> { + + for Source::Irq in event_queue.map(|e| e.expect("vboxd: failed to get next event").user_data) { let mut irq = [0; 8]; - if irq_file.read(&mut irq)? >= irq.len() { + if irq_file.read(&mut irq).unwrap() >= irq.len() { let host_events = vmmdev.host_events.read(); if host_events != 0 { port.write(ack_events.physical() as u32); - irq_file.write(&irq)?; + irq_file.write(&irq).unwrap(); if host_events & VBOX_EVENT_DISPLAY == VBOX_EVENT_DISPLAY { port.write(display_change.physical() as u32); @@ -269,8 +273,8 @@ fn main() { println!("Display {}, {}", width, height); bga.set_size(width as u16, height as u16); let _ = display.write(&orbclient::ResizeEvent { - width: width, - height: height, + width, + height, }.to_event()); } } @@ -289,15 +293,7 @@ fn main() { } } } - Ok(None) - }).expect("vboxd: failed to poll irq"); - - event_queue.trigger_all(event::Event { - fd: 0, - flags: Default::default(), - }).expect("vboxd: failed to trigger events"); - - event_queue.run().expect("vboxd: failed to run event loop"); + } } std::process::exit(0); diff --git a/virtio-core/Cargo.toml b/virtio-core/Cargo.toml index 379821c233..6568a5cc10 100644 --- a/virtio-core/Cargo.toml +++ b/virtio-core/Cargo.toml @@ -8,14 +8,14 @@ authors = ["Anhad Singh "] static_assertions = "1.1.0" bitflags = "2.3.2" redox_syscall = "0.5" +libredox = "0.1.3" log = "0.4" thiserror = "1.0.40" futures = { version = "0.3.28", features = ["executor"] } crossbeam-queue = "0.3.8" redox-log = "0.1" -redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git" } +redox_event = "0.4.1" common = { path = "../common" } pcid = { path = "../pcid" } -libredox = "0.1.3" diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 133c5e53c4..14150cb279 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -2,7 +2,7 @@ use crate::spec::*; use crate::utils::align; use common::dma::Dma; -use event::EventQueue; +use event::{EventQueue, RawEventQueue}; use core::mem::size_of; use core::sync::atomic::{AtomicU16, Ordering}; @@ -67,22 +67,15 @@ pub fn spawn_irq_thread(irq_handle: &File, queue: &Arc>) { let queue_copy = queue.clone(); std::thread::spawn(move || { - let mut event_queue = EventQueue::::new().unwrap(); + let mut event_queue = RawEventQueue::new().unwrap(); - event_queue - .add(irq_fd, move |_| -> Result, std::io::Error> { - // Wake up the tasks waiting on the queue. - for (_, task) in queue_copy.waker.lock().unwrap().iter() { - task.wake_by_ref(); - } + event_queue.subscribe(irq_fd as usize, 0, event::EventFlags::READ).unwrap(); - // Wake up the tasks waiting on the queue. - Ok(None) - }) - .unwrap(); - - loop { - event_queue.run().unwrap(); + for event in event_queue.map(Result::unwrap) { + // Wake up the tasks waiting on the queue. + for (_, task) in queue_copy.waker.lock().unwrap().iter() { + task.wake_by_ref(); + } } }); } From e97ba747898764aa55c32d9575930fe801b5f016 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 23 Mar 2024 12:06:45 +0100 Subject: [PATCH 0843/1301] Reimplement all event_queue.trigger behavior. --- audio/ac97d/Cargo.toml | 2 +- audio/ac97d/src/main.rs | 5 +++-- audio/ihdad/Cargo.toml | 2 +- audio/ihdad/src/main.rs | 6 ++++-- audio/sb16d/Cargo.toml | 2 +- audio/sb16d/src/device.rs | 8 ++++---- audio/sb16d/src/main.rs | 18 +++++++----------- vboxd/src/main.rs | 4 ++-- 8 files changed, 23 insertions(+), 24 deletions(-) diff --git a/audio/ac97d/Cargo.toml b/audio/ac97d/Cargo.toml index da7d2f14c5..143a127079 100644 --- a/audio/ac97d/Cargo.toml +++ b/audio/ac97d/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ac97d" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] bitflags = "1" diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index 322f86e56a..bbc6143b46 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -110,8 +110,9 @@ fn main() { let mut todo = Vec::::new(); - 'events: for event in event_queue.map(|e| e.expect("ac97d: failed to get next event")) { - match event.user_data { + let all = [Source::Irq, Source::Scheme]; + 'events: for event in all.into_iter().chain(event_queue.map(|e| e.expect("ac97d: failed to get next event").user_data)) { + match event { Source::Irq => { let mut irq = [0; 8]; irq_file.read(&mut irq).unwrap(); diff --git a/audio/ihdad/Cargo.toml b/audio/ihdad/Cargo.toml index c356f48056..c431a9cb2e 100644 --- a/audio/ihdad/Cargo.toml +++ b/audio/ihdad/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ihdad" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] bitflags = "2" diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 2e5c83a3fe..bab7c5b6df 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -183,8 +183,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut todo = Vec::::new(); - 'events: for event in event_queue.map(|e| e.expect("failed to get next event")) { - match event.user_data { + let all = [Source::Irq, Source::Scheme]; + + 'events: for event in all.into_iter().chain(event_queue.map(|e| e.expect("failed to get next event").user_data)) { + match event { Source::Irq => { let mut irq = [0; 8]; irq_file.read(&mut irq).unwrap(); diff --git a/audio/sb16d/Cargo.toml b/audio/sb16d/Cargo.toml index 89e816451d..84a7357bec 100644 --- a/audio/sb16d/Cargo.toml +++ b/audio/sb16d/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "sb16d" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] bitflags = "2" diff --git a/audio/sb16d/src/device.rs b/audio/sb16d/src/device.rs index 101d6e329b..ea0530d78f 100644 --- a/audio/sb16d/src/device.rs +++ b/audio/sb16d/src/device.rs @@ -1,11 +1,11 @@ #![allow(dead_code)] -use std::{mem, thread, time}; +use std::{thread, time}; use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; -use syscall::error::{Error, EACCES, EBADF, Result, EINVAL, ENODEV, ENOENT}; -use syscall::io::{Mmio, Pio, Io, ReadOnly, WriteOnly}; +use syscall::error::{Error, EACCES, EBADF, Result, ENODEV}; +use syscall::io::{Pio, Io, ReadOnly, WriteOnly}; use syscall::scheme::SchemeBlockMut; use spin::Mutex; @@ -191,7 +191,7 @@ impl SchemeBlockMut for Sb16 { } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + fn write(&mut self, _id: usize, _buf: &[u8]) -> Result> { //TODO Err(Error::new(EBADF)) } diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index c6e1d1571a..e01125ce4e 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -1,14 +1,9 @@ //#![deny(warnings)] use std::{env, usize}; -use std::fs::File; -use std::io::{ErrorKind, Read, Write, Result}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use libredox::errno::{EAGAIN, EWOULDBLOCK}; use libredox::{flag, Fd}; -use syscall::{Packet, SchemeBlockMut, EventFlags}; -use std::cell::RefCell; -use std::sync::Arc; +use syscall::{Packet, SchemeBlockMut}; use event::{user_data, EventQueue}; use redox_log::{OutputBuilder, RedoxLogger}; @@ -77,7 +72,7 @@ fn main() { let socket = Fd::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("sb16d: failed to create hda scheme"); //TODO: error on multiple IRQs? - let mut irq_file = match device.irqs.first() { + let irq_file = match device.irqs.first() { Some(irq) => Fd::open(&format!("irq:{}", irq), flag::O_RDWR, 0).expect("sb16d: failed to open IRQ file"), None => panic!("sb16d: no IRQs found"), }; @@ -88,7 +83,7 @@ fn main() { } } - let mut event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); + let event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); event_queue.subscribe(irq_file.raw(), Source::Irq, event::EventFlags::READ).unwrap(); event_queue.subscribe(socket.raw(), Source::Scheme, event::EventFlags::READ).unwrap(); @@ -98,9 +93,10 @@ fn main() { let mut todo = Vec::::new(); - 'events: for event_res in event_queue { - let event = event_res.expect("sb16d: failed to get next event"); - match event.user_data { + let all = [Source::Irq, Source::Scheme]; + + 'events: for event in all.into_iter().chain(event_queue.map(|e| e.expect("sb16d: failed to get next event").user_data)) { + match event { Source::Irq => { let mut irq = [0; 8]; irq_file.read(&mut irq).unwrap(); diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index f7269be46f..b24ddb0dcf 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -1,7 +1,7 @@ //#![deny(warnings)] use event::{user_data, EventQueue}; -use std::mem; +use std::{iter, mem}; use std::os::unix::io::AsRawFd; use std::fs::File; use std::io::{Result, Read, Write}; @@ -254,7 +254,7 @@ fn main() { let display_change = VboxDisplayChange::new().expect("vboxd: failed to map DisplayChange"); let ack_events = VboxAckEvents::new().expect("vboxd: failed to map AckEvents"); - for Source::Irq in event_queue.map(|e| e.expect("vboxd: failed to get next event").user_data) { + for Source::Irq in iter::once(Source::Irq).chain(event_queue.map(|e| e.expect("vboxd: failed to get next event").user_data)) { let mut irq = [0; 8]; if irq_file.read(&mut irq).unwrap() >= irq.len() { let host_events = vmmdev.host_events.read(); From 331b75f9bce34a2abc233d89d859728fe4d25cb3 Mon Sep 17 00:00:00 2001 From: Ribbon Date: Wed, 3 Apr 2024 21:45:26 +0000 Subject: [PATCH 0844/1301] Improve and cleanup the README --- README.md | 95 +++++++++++++++++++------------------------------------ 1 file changed, 32 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 6ea4ee85e5..6eba98ce74 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,42 @@ # Drivers -This document covers the driver details/status. +This document covers the driver details. -Implemented devices/hardware interfaces: +## Hardware Interfaces and Devices -- ac97d - Realtek audio chipsets. -- acpid - ACPI (incomplete). - -``` -- Lack of drivers for devices controlled using AML -- The AML parser does not work on real hardware -- It doesn't use any ACPI functionality other than S5 shutdown -- Needs to implement something like "determine the battery status" on real hardware (hard) -``` - -- ahcid - SATA. -- alxd - Atheros ethernet (incomplete). - -``` -- Lack of datasheet to finish -``` - -- amlserde - a library to provide serialization/deserialization of the AML symbol table from ACPI (incomplete). -- bgad - Bochs emulator/debugger. -- block-io-wrapper - Library used by other drivers. -- e1000d - Intel Gigabit ethernet. -- ided - IDE. -- ihdad - Intel HD Audio chipsets. -- inputd - Multiplexes input from multiple input drivers and provides that to Orbital. -- ixgbed - Intel 10 Gigabit ethernet. -- nvmed - NVMe. -- pcid - PCI. +- ac97d - Realtek audio chipsets +- acpid - ACPI interface +- ahcid - SATA interface +- alxd - Atheros ethernet +- amlserde - a library to provide serialization/deserialization of the AML symbol table from ACPI +- bgad - Bochs emulator and debugger +- block-io-wrapper - Library used by other drivers +- e1000d - Intel Gigabit ethernet +- ided - IDE interface +- ihdad - Intel HD Audio chipsets +- inputd - Multiplexes input from multiple input drivers and provides that to Orbital +- ixgbed - Intel 10 Gigabit ethernet +- nvmed - NVMe interface +- pcid - PCI interface with extensions for PCI Express - pcspkrd - PC speaker -- ps2d - PS/2 -- rtl8139d - Realtek ethernet. -- rtl8168d - Realtek ethernet. -- sb16d - Sound Blaster audio (incomplete). +- ps2d - PS/2 interface +- rtl8139d - Realtek ethernet +- rtl8168d - Realtek ethernet +- sb16d - Sound Blaster audio +- usbctl - USB control +- usbhidd - USB HID +- usbscsid - USB SCSI +- vboxd - VirtualBox guest +- vesad - VESA interface +- virtio-blkd - VirtIO block device +- virtio-core - VirtIO core +- virtio-gpud - VirtIO GPU device +- virtio-netd - VirtIO Network device +- xhcid - xHCI USB controller -``` -- Need to determine a way to allocate memory under 16MiB for use in ISA DMA -``` +Some drivers are work-in-progress and incomplete, read [this](https://gitlab.redox-os.org/redox-os/drivers/-/issues/41) tracking issue to verify. -- usbctl - USB control (incomplete). - -``` -- Missing class drivers for various classes -``` - -- usbhidd - USB HID (incomplete). - -``` -- Has tons of descriptors that are possible, not all are supported -``` - -- usbscsid - USB SCSI (incomplete). - -``` -- Missing class drivers for various classes -``` - -- vboxd - VirtualBox guest. -- vesad - VESA. -- virtio-blkd - VirtIO block device (incomplete). -- virtio-core - VirtIO core. -- virtio-gpud - VirtIO GPU device (incomplete). -- virtio-netd - VirtIO net device (incomplete). -- xhcid - xHCI (incomplete). - -## Interfaces +## System Interfaces This section cover the interfaces used by Redox drivers. From 32b7cc3b779705f71f7f76db551baa09ce7ef204 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 10 Apr 2024 10:38:05 -0600 Subject: [PATCH 0845/1301] ps2d: fix typo --- ps2d/src/controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index e5972b5de1..ce35259a1d 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -455,7 +455,7 @@ impl Ps2 { } // Clear remaining data - self.flush_read("set sample rate"); + self.flush_read("set scaling"); } { From 571bd9cf3e3b32e86f83dd0d45f7ca741a71336a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 11 Apr 2024 09:36:20 -0600 Subject: [PATCH 0846/1301] usbhidd: move code to rehid --- Cargo.lock | 11 +- usbhidd/Cargo.toml | 2 +- usbhidd/src/main.rs | 57 +----- usbhidd/src/report_desc.rs | 393 ------------------------------------ usbhidd/src/reqs.rs | 9 +- usbhidd/src/usage_tables.rs | 45 ----- 6 files changed, 18 insertions(+), 499 deletions(-) delete mode 100644 usbhidd/src/report_desc.rs delete mode 100644 usbhidd/src/usage_tables.rs diff --git a/Cargo.lock b/Cargo.lock index 7286e2c967..d683e99a04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1137,6 +1137,15 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" +[[package]] +name = "rehid" +version = "0.1.0" +source = "git+https://gitlab.redox-os.org/redox-os/rehid.git#9bf6c9ef7cc4f95932fcaabfa3141a24bfd39bbf" +dependencies = [ + "bitflags 2.5.0", + "ux", +] + [[package]] name = "rtl8139d" version = "0.1.0" @@ -1520,7 +1529,7 @@ dependencies = [ "orbclient", "redox-log", "redox_syscall 0.5.1", - "ux", + "rehid", "xhcid", ] diff --git a/usbhidd/Cargo.toml b/usbhidd/Cargo.toml index b1cd4f0e9f..54a80e1e2f 100644 --- a/usbhidd/Cargo.toml +++ b/usbhidd/Cargo.toml @@ -13,5 +13,5 @@ log = "0.4" orbclient = "0.3.47" redox-log = "0.1" redox_syscall = "0.5" -ux = "0.1" +rehid = { git = "https://gitlab.redox-os.org/redox-os/rehid.git" } xhcid = { path = "../xhcid" } diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 2165b6e604..4235c78457 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -7,64 +7,18 @@ use std::os::unix::io::AsRawFd; use bitflags::bitflags; use orbclient::KeyEvent as OrbKeyEvent; use redox_log::{OutputBuilder, RedoxLogger}; +use rehid::{binary_view::BinaryView, report_desc::{self, ReportTy}, usage_tables}; use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle}; mod keymap; -mod report_desc; mod reqs; -mod usage_tables; use report_desc::{LocalItemsState, MainCollectionFlags, MainItem, MainItemFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY}; -use reqs::ReportTy; fn div_round_up(num: u32, denom: u32) -> u32 { if num % denom == 0 { num / denom } else { num / denom + 1 } } -struct BinaryView<'a> { - data: &'a [u8], - offset: usize, - len: usize, -} -impl<'a> BinaryView<'a> { - pub fn new(data: &'a [u8], offset: usize, len: usize) -> Self { - Self { - data, - offset, - len, - } - } - pub fn get(&self, bit_index: usize) -> Option { - let bit_index = self.offset + bit_index; - - if bit_index >= self.offset + self.len { return None } - - let byte_index = bit_index / 8; - let bits_from_first = bit_index % 8; - let byte = self.data.get(byte_index)?; - Some(byte & (1 << bits_from_first) != 0) - } - pub fn read_u8(&self, bit_index: usize) -> Option { - let bit_index = self.offset + bit_index; - - if bit_index >= self.offset + self.len { return None } - - let first = bit_index / 8; - let bits_from_first = bit_index % 8; - let first_byte = self.data.get(first)?; - let lo = first_byte >> bits_from_first; - - let hi = if bits_from_first > 0 { - let hi = self.data.get(first + 1)? & ((1 << bits_from_first) - 1); - let bits_to_next = 8 - bits_from_first; - hi << bits_to_next - } else { 0 }; - - - Some(lo | hi) - } -} - fn setup_logging() -> Option<&'static RedoxLogger> { let mut logger = RedoxLogger::new() .with_output( @@ -403,11 +357,12 @@ fn main() { let report_count = global_state.report_count.unwrap(); log::trace!( - "size {} count {} at {} length {}", + "size {} count {} offset {} length {} usage page {:?}", report_size, report_count, bit_offset, - bit_length + bit_length, + global_state.usage_page ); // TODO: For now, the dynamic value usages cannot overlap with selector usages... @@ -516,7 +471,7 @@ fn main() { } } } else { - log::trace!("Unknown report variable item: size {} count {} at {}", report_size, report_count, bit_offset); + log::trace!("Unknown report variable item: size {} count {} offset {} usage page {:?}", report_size, report_count, bit_offset, global_state.usage_page); } } else { // The item is an array. @@ -532,7 +487,7 @@ fn main() { log::trace!("Report index array {}: {:#x}", report_index, usage); } } else { - log::trace!("Unknown report array item: size {} count {} at {}", report_size, report_count, bit_offset); + log::trace!("Unknown report array item: size {} count {} offset {} usage page {:?}", report_size, report_count, bit_offset, global_state.usage_page); } } } diff --git a/usbhidd/src/report_desc.rs b/usbhidd/src/report_desc.rs deleted file mode 100644 index 2835ba225c..0000000000 --- a/usbhidd/src/report_desc.rs +++ /dev/null @@ -1,393 +0,0 @@ -use bitflags::bitflags; -use ux::{u2, u4}; - -use crate::reqs::ReportTy; - -/*#[repr(u8)] -enum Protocol { - -}*/ - -bitflags! { - #[derive(Clone, Copy, Debug)] - pub struct MainItemFlags: u32 { - const CONSTANT = 1 << 0; - const VARIABLE = 1 << 1; - const RELATIVE = 1 << 2; - const WRAP = 1 << 3; - const NONLINEAR = 1 << 4; - const NO_PREFERRED_STATE = 1 << 5; - const NULL_STATE = 1 << 6; - const VOLATILE = 1 << 7; - const BUFFERED_BYTES = 1 << 8; - } -} -#[repr(u8)] -pub enum MainCollectionFlags { - Physical = 0, - Application, - Logical, - Report, - NamedArray, - UsageSwitch, - UsageModifier, -} - -pub const REPORT_DESC_TY: u8 = 34; - -#[derive(Debug)] -pub enum MainItem { - Input(u32), - Output(u32), - Feature(u32), - Collection(u8), - EndOfCollection, -} -impl MainItem { - pub fn report_ty(&self) -> Option { - match self { - Self::Input(_) => Some(ReportTy::Input), - Self::Output(_) => Some(ReportTy::Output), - Self::Feature(_) => Some(ReportTy::Feature), - _ => None, - } - } -} -#[derive(Debug)] -pub enum GlobalItem { - UsagePage(u32), - LogicalMinimum(u32), - LogicalMaximum(u32), - PhysicalMinimum(u32), - PhysicalMaximum(u32), - UnitExponent(u32), - Unit(u32), - ReportSize(u32), - ReportId(u32), - ReportCount(u32), - Push, - Pop, -} - -#[derive(Clone, Copy, Debug, Default)] -pub struct GlobalItemsState { - pub usage_page: Option, - pub logical_min: Option, - pub logical_max: Option, - pub physical_min: Option, - pub physical_max: Option, - pub unit_exponent: Option, - pub unit: Option, - pub report_size: Option, - pub report_id: Option, - pub report_count: Option, -} - -#[derive(Debug)] -pub struct Invalid; - -pub fn update_global_state(current_state: &mut GlobalItemsState, stack: &mut Vec, report_item: &ReportItem) -> Result<(), Invalid> { - match report_item { - ReportItem::Global(global) => match global { - &GlobalItem::UsagePage(u) => current_state.usage_page = Some(u), - &GlobalItem::LogicalMinimum(m) => current_state.logical_min = Some(m), - &GlobalItem::LogicalMaximum(m) => current_state.logical_max = Some(m), - &GlobalItem::PhysicalMinimum(m) => current_state.physical_min = Some(m), - &GlobalItem::PhysicalMaximum(m) => current_state.physical_max = Some(m), - &GlobalItem::UnitExponent(e) => current_state.unit_exponent = Some(e), - &GlobalItem::Unit(u) => current_state.unit = Some(u), - &GlobalItem::ReportSize(s) => current_state.report_size = Some(s), - &GlobalItem::ReportId(i) => current_state.report_id = Some(i), - &GlobalItem::ReportCount(c) => current_state.report_count = Some(c), - &GlobalItem::Push => stack.push(*current_state), - &GlobalItem::Pop => *current_state = stack.pop().ok_or(Invalid)?, - } - ReportItem::Local(local) => (), // TODO - ReportItem::Main(_) => (), - } - Ok(()) -} - -#[derive(Debug)] -pub enum LocalItem { - Usage(u32), - UsageMinimum(u32), - UsageMaximum(u32), - DesignatorIndex(u32), - DesignatorMinimum(u32), - DesignatorMaximum(u32), - StringIndex(u32), - StringMinimum(u32), - StringMaximum(u32), - Delimeter(u32), -} - -#[derive(Clone, Copy, Debug, Default)] -pub struct LocalItemsState { - pub usage: Option, - pub usage_min: Option, - pub usage_max: Option, - pub desig_idx: Option, - pub desig_min: Option, - pub desig_max: Option, - pub str_idx: Option, - pub str_min: Option, - pub str_max: Option, -} -pub fn update_local_state(current_state: &mut LocalItemsState, report_item: &ReportItem) { - match report_item { - ReportItem::Local(local) => match local { - &LocalItem::Usage(u) => current_state.usage = Some(u), - &LocalItem::UsageMinimum(m) => current_state.usage_min = Some(m), - &LocalItem::UsageMaximum(m) => current_state.usage_max = Some(m), - &LocalItem::DesignatorIndex(i) => current_state.desig_idx = Some(i), - &LocalItem::DesignatorMinimum(m) => current_state.desig_min = Some(m), - &LocalItem::DesignatorMaximum(m) => current_state.desig_max = Some(m), - &LocalItem::StringIndex(i) => current_state.str_idx = Some(i), - &LocalItem::StringMinimum(m) => current_state.str_min = Some(m), - &LocalItem::StringMaximum(m) => current_state.str_max = Some(m), - &LocalItem::Delimeter(_) => todo!(), - }, - _ => (), - } -} - -#[derive(Debug)] -pub enum ReportItem { - Main(MainItem), - Global(GlobalItem), - Local(LocalItem), -} -impl ReportItem { - pub fn as_main_item(&self) -> Option<&MainItem> { - match self { - Self::Main(m) => Some(m), - _ => None, - } - } -} -impl From for ReportItem { - fn from(main: MainItem) -> Self { - Self::Main(main) - } -} -impl From for ReportItem { - fn from(main: GlobalItem) -> Self { - Self::Global(main) - } -} -impl From for ReportItem { - fn from(main: LocalItem) -> Self { - Self::Local(main) - } -} - -impl ReportItem { - pub fn size(size: u2) -> u8 { - match u8::from(size) { - 0 => 0, - 1 => 1, - 2 => 2, - 3 => 4, - _ => unreachable!(), - } - } - pub fn parse_short(size: u2, ty: u2, tag: u4, bytes: &[u8]) -> Option<(Self, usize)> { - Some(match (u8::from(tag), u8::from(ty)) { - (tag, 0b00) => { - let real_size = Self::size(size) as usize; - let mut value_bytes = [0u8; 4]; - if real_size > 0 { - value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) - }; - let value = u32::from_le_bytes(value_bytes); - - match tag { - 0b1000 => (MainItem::Input(value).into(), 1 + real_size), - 0b1001 => (MainItem::Output(value).into(), 1 + real_size), - 0b1011 => (MainItem::Feature(value).into(), 1 + real_size), - 0b1010 => (MainItem::Collection(bytes[0]).into(), 2), - 0b1100 => (MainItem::EndOfCollection.into(), 1 + real_size), - _ => return None, - } - } - (tag, 0b01) => { - let real_size = Self::size(size) as usize; - let mut value_bytes = [0u8; 4]; - if real_size > 0 { - value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) - }; - let value = u32::from_le_bytes(value_bytes); - match tag { - 0b0000 => (GlobalItem::UsagePage(value).into(), 1 + real_size), - 0b0001 => (GlobalItem::LogicalMinimum(value).into(), 1 + real_size), - 0b0010 => (GlobalItem::LogicalMaximum(value).into(), 1 + real_size), - 0b0011 => (GlobalItem::PhysicalMinimum(value).into(), 1 + real_size), - 0b0100 => (GlobalItem::PhysicalMaximum(value).into(), 1 + real_size), - 0b0101 => (GlobalItem::UnitExponent(value).into(), 1 + real_size), - 0b0110 => (GlobalItem::Unit(value).into(), 1 + real_size), - 0b0111 => (GlobalItem::ReportSize(value).into(), 1 + real_size), - 0b1000 => (GlobalItem::ReportId(value).into(), 1 + real_size), - 0b1001 => (GlobalItem::ReportCount(value).into(), 1 + real_size), - 0b1010 => (GlobalItem::Push.into(), 1), - 0b1011 => (GlobalItem::Pop.into(), 1), - _ => return None, - } - } - (tag, 0b10) => { - let real_size = Self::size(size) as usize; - let mut value_bytes = [0u8; 4]; - if real_size > 0 { - value_bytes[..real_size].copy_from_slice(&bytes[..real_size]) - }; - let value = u32::from_le_bytes(value_bytes); - match tag { - 0b0000 => (LocalItem::Usage(value).into(), 1 + real_size), - 0b0001 => (LocalItem::UsageMinimum(value).into(), 1 + real_size), - 0b0010 => (LocalItem::UsageMaximum(value).into(), 1 + real_size), - 0b0011 => (LocalItem::DesignatorIndex(value).into(), 1 + real_size), - 0b0100 => (LocalItem::DesignatorMinimum(value).into(), 1 + real_size), - 0b0101 => (LocalItem::DesignatorMaximum(value).into(), 1 + real_size), - 0b0111 => (LocalItem::StringIndex(value).into(), 1 + real_size), - 0b1000 => (LocalItem::StringMinimum(value).into(), 1 + real_size), - 0b1001 => (LocalItem::StringMaximum(value).into(), 1 + real_size), - 0b1010 => (LocalItem::Delimeter(value).into(), 1 + real_size), - _ => return None, - } - } - (_, 0b11) => panic!("Calling parse_short but with long item"), - _ => unreachable!(), - }) - } - pub fn parse_long(size: u8, long_tag: u8, bytes: &[u8]) -> (Self, usize) { - todo!() - } -} - -pub struct ReportFlatIter<'a> { - desc: &'a [u8], - offset: usize, -} -impl<'a> ReportFlatIter<'a> { - pub fn new(desc: &'a [u8]) -> Self { - Self { desc, offset: 0 } - } -} -impl<'a> Iterator for ReportFlatIter<'a> { - type Item = ReportItem; - - fn next(&mut self) -> Option { - if self.offset >= self.desc.len() { - return None; - } - - let first = self.desc[self.offset]; - let size = first & 0b11; - let ty = (first & 0b1100) >> 2; - let tag = (first & 0b11110000) >> 4; - - if size == 0b10 && ty == 3 && tag == 0b1111 { - // Long Item - let size = self.desc[self.offset + 1]; - let long_tag = self.desc[self.offset + 2]; - let data = &self.desc[self.offset + 2..self.offset + 2 + size as usize]; - - let (item, len) = ReportItem::parse_long(size, long_tag, data); - self.offset += len; - Some(item) - } else { - // Short Item - - // Although there is a 2-bit size field, the size doesn't have to be the actual size of the data. - let data = &self.desc[self.offset + 1..]; - - let (item, len) = - ReportItem::parse_short(u2::new(size), u2::new(ty), u4::new(tag), data)?; - self.offset += len; - Some(item) - } - } -} - -pub struct ReportIter<'a> { - flat: ReportFlatIter<'a>, - error: bool, - // this is just for reusing the vec - // TODO: When GATs are available, this could be done simply using iterators. Every collection - // yields a child iterator, which returns the mutable reference to the flat iter to its parent - // when dropped. - open_collections: Vec<(u8, Vec)>, -} -#[derive(Debug)] -pub enum ReportIterItem { - // collection and end of collection tags will never be found here - Item(ReportItem), - Collection(u8, Vec), -} -impl ReportIterItem { - pub fn as_item(&self) -> Option<&ReportItem> { - match self { - Self::Item(i) => Some(i), - _ => None, - } - } - pub fn as_collection(&self) -> Option<(u8, &[ReportIterItem])> { - match self { - &Self::Collection(n, ref c) => Some((n, c)), - _ => None, - } - } -} -impl<'a> ReportIter<'a> { - pub fn new(flat: ReportFlatIter<'a>) -> Self { - Self { - flat, - error: false, - open_collections: Vec::new(), - } - } -} -impl<'a> Iterator for ReportIter<'a> { - type Item = ReportIterItem; - - fn next(&mut self) -> Option { - if self.error { - return None; - } - - self.open_collections.clear(); - - loop { - let item = self.flat.next()?; - - match item { - ReportItem::Main(MainItem::Collection(m)) => { - self.open_collections.push((m, Vec::new())); - } - ReportItem::Main(MainItem::EndOfCollection) => { - let (value, finished_collection) = match self.open_collections.pop() { - Some(finished) => finished, - None => { - self.error = true; - return None; - } - }; - if let Some((_, ref mut last)) = self.open_collections.last_mut() { - last.push(ReportIterItem::Collection(value, finished_collection)); - } else { - return Some(ReportIterItem::Collection(value, finished_collection)); - } - } - other if self.open_collections.is_empty() => { - return Some(ReportIterItem::Item(other)) - } - other => self - .open_collections - .last_mut() - .unwrap() - .1 - .push(ReportIterItem::Item(other)), - } - } - } -} diff --git a/usbhidd/src/reqs.rs b/usbhidd/src/reqs.rs index 680497279b..b7887b2490 100644 --- a/usbhidd/src/reqs.rs +++ b/usbhidd/src/reqs.rs @@ -1,5 +1,6 @@ use std::slice; +use rehid::report_desc::ReportTy; use xhcid_interface::{ DeviceReqData, PortReqRecipient, PortReqTy, XhciClientHandle, XhciClientHandleError, }; @@ -11,14 +12,6 @@ const SET_IDLE_REQ: u8 = 0xA; const GET_PROTOCOL_REQ: u8 = 0x3; const SET_PROTOCOL_REQ: u8 = 0xB; -#[repr(u8)] -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum ReportTy { - Input = 1, - Output, - Feature, -} - fn concat(hi: u8, lo: u8) -> u16 { (u16::from(hi) << 8) | u16::from(lo) } diff --git a/usbhidd/src/usage_tables.rs b/usbhidd/src/usage_tables.rs deleted file mode 100644 index cf7b8d3424..0000000000 --- a/usbhidd/src/usage_tables.rs +++ /dev/null @@ -1,45 +0,0 @@ -// See https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf - -#[repr(u8)] -pub enum UsagePage { - GenericDesktop = 1, - SimulationsControl, - VrControls, - SportControls, - GameControls, - GenericDeviceControls, - KeyboardOrKeypad, - Led, - Button, - Ordinal, - TelephonyDevice, - Consumer, - Digitizer, - Unicode = 0x10, - AlphanumericDisplay = 0x14, - MedicalInstrument = 0x40, -} - -#[repr(u8)] -pub enum GenericDesktopUsage { - Pointer = 0x01, - Mouse, - Joystick = 0x04, - GamePad, - Keyboard, - Keypad, - MultiAxisController, - - // 0x0A-0x2F are reserved - - CountedBuffer = 0x3A, - SysControl = 0x80, -} - -#[repr(u8)] -pub enum KeyboardOrKeypadUsage { - KbdErrorRollover = 0x1, - KbdPostFail, - KbdErrorUndefined, - // the rest are used as regular keycodes -} From c99cd3a843d2d98cdb84ccb3f7319cdd598c07f6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 12 Apr 2024 09:27:36 -0600 Subject: [PATCH 0847/1301] usbhidd: use rehid ReportHandler --- Cargo.lock | 3 +- usbhidd/src/keymap.rs | 10 +- usbhidd/src/main.rs | 461 +++++++++++++++--------------------------- usbhidd/src/reqs.rs | 5 +- 4 files changed, 176 insertions(+), 303 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d683e99a04..1c8f413c60 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1140,9 +1140,10 @@ checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" [[package]] name = "rehid" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/rehid.git#9bf6c9ef7cc4f95932fcaabfa3141a24bfd39bbf" +source = "git+https://gitlab.redox-os.org/redox-os/rehid.git#d3c74a8abbdb75d93260883e3378c46b3e875fa9" dependencies = [ "bitflags 2.5.0", + "log", "ux", ] diff --git a/usbhidd/src/keymap.rs b/usbhidd/src/keymap.rs index 236e7caa07..46264606a7 100644 --- a/usbhidd/src/keymap.rs +++ b/usbhidd/src/keymap.rs @@ -57,7 +57,7 @@ pub mod us { ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], - [' ', ' '] + [' ', ' '], ]; pub fn get_char(scancode: u8, shift: bool) -> char { @@ -236,7 +236,7 @@ pub mod dvorak { ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], - [' ', ' '] + [' ', ' '], ]; pub fn get_char(scancode: u8, shift: bool) -> char { @@ -311,7 +311,7 @@ pub mod azerty { ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], - [' ', ' '] + [' ', ' '], ]; pub fn get_char(scancode: u8, shift: bool) -> char { @@ -386,7 +386,7 @@ pub mod bepo { ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], - [' ', ' '] + [' ', ' '], ]; pub fn get_char(scancode: u8, shift: bool) -> char { @@ -461,7 +461,7 @@ pub mod it { ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], - [' ', ' '] + [' ', ' '], ]; pub fn get_char(scancode: u8, shift: bool) -> char { diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 4235c78457..da9c143aa7 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -2,52 +2,51 @@ use std::collections::VecDeque; use std::env; use std::fs::File; use std::io::Write; -use std::os::unix::io::AsRawFd; -use bitflags::bitflags; use orbclient::KeyEvent as OrbKeyEvent; use redox_log::{OutputBuilder, RedoxLogger}; -use rehid::{binary_view::BinaryView, report_desc::{self, ReportTy}, usage_tables}; +use rehid::{ + report_desc::{self, ReportTy, REPORT_DESC_TY}, + report_handler::ReportHandler, + usage_tables::{GenericDesktopUsage, UsagePage}, +}; use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle}; mod keymap; mod reqs; -use report_desc::{LocalItemsState, MainCollectionFlags, MainItem, MainItemFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY}; - -fn div_round_up(num: u32, denom: u32) -> u32 { - if num % denom == 0 { num / denom } else { num / denom + 1 } -} - fn setup_logging() -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); + let mut logger = RedoxLogger::new().with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ); #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("usb", "device", "hid.log") { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() - ), + Ok(b) => { + logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build(), + ) + } Err(error) => eprintln!("Failed to create hid.log: {}", error), } #[cfg(target_os = "redox")] match OutputBuilder::in_redox_logging_scheme("usb", "device", "hid.ansi.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), + Ok(b) => { + logger = logger.with_output( + b.with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ) + } Err(error) => eprintln!("Failed to create hid.ansi.log: {}", error), } @@ -63,7 +62,13 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } } -fn send_key_event(display: &mut File, usage_page: u32, usage: u8, pressed: bool, shift_opt: Option) { +fn send_key_event( + display: &mut File, + usage_page: u32, + usage: u32, + pressed: bool, + shift_opt: Option, +) { let scancode = match usage_page { 0x07 => match usage { 0x04 => orbclient::K_A, @@ -170,7 +175,7 @@ fn send_key_event(display: &mut File, usage_page: u32, usage: u8, pressed: bool, 0xE0 => orbclient::K_CTRL, // TODO: left control 0xE1 => orbclient::K_LEFT_SHIFT, 0xE2 => orbclient::K_ALT, - 0xE3 => 0x5B, // left super + 0xE3 => 0x5B, // left super 0xE4 => orbclient::K_CTRL, // TODO: right control 0xE5 => orbclient::K_RIGHT_SHIFT, 0xE6 => orbclient::K_ALT_GR, @@ -179,12 +184,12 @@ fn send_key_event(display: &mut File, usage_page: u32, usage: u8, pressed: bool, _ => { log::warn!("unknown usage_page {:#x} usage {:#x}", usage_page, usage); return; - }, + } }, _ => { log::warn!("unknown usage_page {:#x}", usage_page); return; - }, + } }; //TODO: other keymaps @@ -225,7 +230,9 @@ fn main() { log::info!( "USB HID driver spawned with scheme `{}`, port {}, protocol {}", - scheme, port, protocol + scheme, + port, + protocol ); let handle = XhciClientHandle::new(scheme, port); @@ -251,292 +258,160 @@ fn main() { ) .expect("Failed to retrieve report descriptor"); - let report_desc = ReportIter::new(ReportFlatIter::new(&report_desc_bytes)).collect::>(); + let mut handler = + ReportHandler::new(&report_desc_bytes).expect("failed to parse report descriptor"); - for item in &report_desc { - log::debug!("{:?}", item); - } - - handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0, interface_desc: None, alternate_setting: None }).expect("Failed to configure endpoints"); - - let (mut global_state, mut local_state, mut stack) = (GlobalItemsState::default(), LocalItemsState::default(), Vec::new()); - - let (_, application_collection, application_global_state, application_local_state) = report_desc.iter().filter_map(|item: &ReportIterItem| { - log::trace!("1: {:?}", item); - match item { - &ReportIterItem::Item(ref item) => { - report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); - report_desc::update_local_state(&mut local_state, item); - None - } - &ReportIterItem::Collection(n, ref collection) => { - let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default()); - Some((n, collection, global_state, lc_state)) - } - } - }).find(|&(n, _, _, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection"); + handle + .configure_endpoints(&ConfigureEndpointsReq { + config_desc: 0, + interface_desc: None, + alternate_setting: None, + }) + .expect("Failed to configure endpoints"); // Get all main items, and their global item options. { - let mut collections = VecDeque::new(); - collections.push_back(application_collection); - let mut items = Vec::new(); - while let Some(collection) = collections.pop_front() { - for item in collection { - log::trace!("2: {:?}", item); - match item { - ReportIterItem::Item(item) => match item { - ReportItem::Global(_) => { - report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); - } - ReportItem::Main(m) => { - let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default()); - items.push((global_state, lc_state, m)); - } - ReportItem::Local(_) => { - report_desc::update_local_state(&mut local_state, item); - }, - }, - //TODO: does local state need to be different for inner collections? - ReportIterItem::Collection(_, collection) => { - collections.push_back(collection); - }, - } - } - } - let mut bit_offset = 0; - let inputs = items.iter().filter_map(|(global_state, local_state, item)| { - log::trace!("3: {:?}", item); - - if let &MainItem::Input(flags) = item { - let report_size = match global_state.report_size { - Some(s) => s, - None => return None, - }; - let report_count = match global_state.report_count { - Some(c) => c, - None => return None, - }; - - let bit_length = report_size * report_count; - let offset = bit_offset; - bit_offset += bit_length; - - Some((bit_length, offset, global_state, local_state, MainItemFlags::from_bits_truncate(*flags))) - } else { - None - } - }).collect::>(); - let total_bit_length = inputs.iter().map(|(bit_length, _, _, _, _)| bit_length).sum(); - - let total_byte_length = div_round_up(total_bit_length, 8); - - let mut report_buffer = vec! [0u8; total_byte_length as usize]; - let mut last_buffer = report_buffer.clone(); + let mut report_buffer = vec![0u8; handler.total_byte_length]; let report_ty = ReportTy::Input; let report_id = 0; - let mut display = File::open("input:producer").expect("Failed to open orbital input socket"); - - let mut pressed_keys = Vec::<(u32, u8)>::new(); - let mut last_pressed_keys = pressed_keys.clone(); - let mut last_buttons = (false, false, false); - + let mut display = + File::open("input:producer").expect("Failed to open orbital input socket"); + let mut left_shift = false; + let mut right_shift = false; + let mut last_mouse_pos = (0, 0); + let mut last_buttons = [false, false, false]; loop { + //TODO: get frequency from device std::thread::sleep(std::time::Duration::from_millis(10)); - std::mem::swap(&mut report_buffer, &mut last_buffer); - reqs::get_report(&handle, report_ty, report_id, interface_num, &mut report_buffer).expect("Failed to get report"); + reqs::get_report( + &handle, + report_ty, + report_id, + interface_num, + &mut report_buffer, + ) + .expect("Failed to get report"); - if report_buffer == last_buffer { - continue - } - - for &(bit_length, bit_offset, global_state, local_state, input) in &inputs { - let report_size = global_state.report_size.unwrap(); - let report_count = global_state.report_count.unwrap(); - - log::trace!( - "size {} count {} offset {} length {} usage page {:?}", - report_size, - report_count, - bit_offset, - bit_length, - global_state.usage_page - ); - - // TODO: For now, the dynamic value usages cannot overlap with selector usages... - // for now. - - if local_state.usage_min == Some(224) && local_state.usage_max == Some(231) { - // The usages that this descriptor references are all dynamic values. - } else { - // The usages are selectors. - } - - if input.contains(MainItemFlags::VARIABLE) { - // The item is a variable. - - let binary_view = BinaryView::new(&report_buffer, bit_offset as usize, bit_length as usize); - - if report_count == 8 && report_size == 1 && global_state.usage_page == Some(7) && local_state.usage_min == Some(224) && local_state.usage_max == Some(231) && global_state.logical_min == Some(0) && global_state.logical_max == Some(1) { - let bits = binary_view.read_u8(0).expect("Failed to read array item"); - for bit in 0..8 { - if bits & (1 << bit) > 0 { - pressed_keys.push((0x07, 0xE0 + bit)); - } + let mut mouse_pos = last_mouse_pos; + let mut mouse_dx = 0i32; + let mut mouse_dy = 0i32; + let mut buttons = last_buttons; + for event in handler + .handle(&report_buffer) + .expect("failed to parse report") + { + log::debug!("{:X?}", event); + if event.usage_page == UsagePage::GenericDesktop as u32 { + if event.usage == GenericDesktopUsage::X as u32 { + if event.relative { + mouse_dx += event.value; + } else { + mouse_pos.0 = event.value; } - log::trace!("Report variable {:#x?}", bits); - } else if report_count == 2 && report_size == 16 && global_state.usage_page == Some(1) { - //TODO: Make this less hard-coded - let raw_x = - binary_view.read_u8(0).expect("Failed to read array item") as u16 | - (binary_view.read_u8(8).expect("Failed to read array item") as u16) << 8; - let raw_y = - binary_view.read_u8(16).expect("Failed to read array item") as u16 | - (binary_view.read_u8(24).expect("Failed to read array item") as u16) << 8; - - // ps2d uses 0..=65535 as range, while usb uses 0..=32767. orbital - // expects the former range, so multiply by two here to translate - // the usb coordinates to what orbital expects. - let x = raw_x * 2; - let y = raw_y * 2; - - log::trace!("Touchscreen {}, {} => {}, {}", raw_x, raw_y, x, y); - if x != 0 || y != 0 { - let mouse_event = orbclient::event::MouseEvent { - x: x as i32, - y: y as i32, - }; - - match display.write(&mouse_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send mouse event to orbital: {}", err); - } - } - } - } else if report_count == 3 && report_size == 8 && global_state.usage_page == Some(1) { - //TODO: Make this less hard-coded - let dx = binary_view.read_u8(0).expect("Failed to read array item") as i8; - let dy = binary_view.read_u8(8).expect("Failed to read array item") as i8; - let dz = binary_view.read_u8(16).expect("Failed to read array item") as i8; - log::trace!("Mouse {}, {}, {}", dx, dy, dz); - if dx != 0 || dy != 0 { - let mouse_event = orbclient::event::MouseRelativeEvent { - dx: dx as i32, - dy: dy as i32, - }; - - match display.write(&mouse_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send mouse event to orbital: {}", err); - } - } - } - if dz != 0 { - let scroll_event = orbclient::event::ScrollEvent { - x: dz as i32, - y: 0, - }; - - match display.write(&scroll_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send scroll event to orbital: {}", err); - } - } - } - } else if report_count == 3 && report_size == 1 && global_state.usage_page == Some(9) { - //TODO: Make this less hard-coded - let left = binary_view.get(0).expect("Failed to read array item"); - let right = binary_view.get(1).expect("Failed to read array item"); - let middle = binary_view.get(2).expect("Failed to read array item"); - log::trace!("Left {}, Right {}, Middle {}", left, right, middle); - if last_buttons != (left, right, middle) { - last_buttons = (left, right, middle); - - let button_event = orbclient::event::ButtonEvent { - left, - right, - middle, - }; - - match display.write(&button_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send button event to orbital: {}", err); - } - } + } else if event.usage == GenericDesktopUsage::Y as u32 { + if event.relative { + mouse_dy += event.value; + } else { + mouse_pos.1 = event.value; } } else { - log::trace!("Unknown report variable item: size {} count {} offset {} usage page {:?}", report_size, report_count, bit_offset, global_state.usage_page); + log::info!( + "unsupported generic desktop usage 0x{:X}:0x{:X} value {}", + event.usage_page, + event.usage, + event.value + ); + } + } else if event.usage_page == UsagePage::KeyboardOrKeypad as u32 { + let (pressed, shift_opt) = if event.value != 0 { + (true, Some(left_shift | right_shift)) + } else { + (false, None) + }; + if event.usage == 0xE1 { + left_shift = pressed; + } else if event.usage == 0xE5 { + right_shift = pressed; + } + send_key_event( + &mut display, + event.usage_page, + event.usage, + pressed, + shift_opt, + ); + } else if event.usage_page == UsagePage::Button as u32 { + if event.usage > 0 && event.usage as usize <= buttons.len() { + buttons[event.usage as usize - 1] = event.value != 0; + } else { + log::info!( + "unsupported buttons usage 0x{:X}:0x{:X} value {}", + event.usage_page, + event.usage, + event.value + ); } } else { - // The item is an array. + log::info!( + "unsupported usage 0x{:X}:0x{:X} value {}", + event.usage_page, + event.usage, + event.value + ); + } + } - log::trace!("INPUT FLAGS: {:?}", input); - if report_size == 8 { - for report_index in 0..report_count as usize { - let binary_view = BinaryView::new(&report_buffer, bit_offset as usize + report_index * report_size as usize, report_size as usize); - let usage = binary_view.read_u8(0).expect("Failed to read array item"); - if usage != 0 { - pressed_keys.push((global_state.usage_page.unwrap_or(0), usage)); - } - log::trace!("Report index array {}: {:#x}", report_index, usage); - } - } else { - log::trace!("Unknown report array item: size {} count {} offset {} usage page {:?}", report_size, report_count, bit_offset, global_state.usage_page); + if mouse_pos != last_mouse_pos { + last_mouse_pos = mouse_pos; + + // ps2d uses 0..=65535 as range, while usb uses 0..=32767. orbital + // expects the former range, so multiply by two here to translate + // the usb coordinates to what orbital expects. + let mouse_event = orbclient::event::MouseEvent { + x: mouse_pos.0 * 2, + y: mouse_pos.1 * 2, + }; + + match display.write(&mouse_event.to_event()) { + Ok(_) => (), + Err(err) => { + log::warn!("failed to send mouse event to orbital: {}", err); } } } + if mouse_dx != 0 || mouse_dy != 0 { + let mouse_event = orbclient::event::MouseRelativeEvent { + dx: mouse_dx, + dy: mouse_dy, + }; - for &(usage_page, usage) in last_pressed_keys.iter() { - if ! pressed_keys.contains(&(usage_page, usage)) { - log::debug!("Released {:#x},{:#x}", usage_page, usage); - send_key_event(&mut display, usage_page, usage, false, None); + match display.write(&mouse_event.to_event()) { + Ok(_) => (), + Err(err) => { + log::warn!("failed to send mouse event to orbital: {}", err); + } } } - for &(usage_page, usage) in pressed_keys.iter() { - if ! last_pressed_keys.contains(&(usage_page, usage)) { - log::debug!("Pressed {:#x},{:#x}", usage_page, usage); - send_key_event(&mut display, usage_page, usage, true, Some( - pressed_keys.contains(&(0x07, 0xE1)) || pressed_keys.contains(&(0x07, 0xE5)) - )); + if buttons != last_buttons { + last_buttons = buttons; + + let button_event = orbclient::event::ButtonEvent { + left: buttons[0], + right: buttons[1], + middle: buttons[2], + }; + + match display.write(&button_event.to_event()) { + Ok(_) => (), + Err(err) => { + log::warn!("failed to send button event to orbital: {}", err); + } } } - - std::mem::swap(&mut pressed_keys, &mut last_pressed_keys); - pressed_keys.clear(); } } } - -#[cfg(test)] -mod tests { - #[test] - fn binary_view() { - // 0000 1000 1100 0111 - // E S - let view = super::BinaryView::new(&[0xC7, 0x08], 3, 11); - assert_eq!(view.get(0), Some(false)); - assert_eq!(view.get(2), Some(false)); - assert_eq!(view.get(3), Some(true)); - assert_eq!(view.get(7), Some(false)); - assert_eq!(view.get(17), None); - - assert_eq!(view.read_u8(0), Some(0b0001_1000)); - assert_eq!(view.read_u8(1), Some(0b1000_1100)); - assert_eq!(view.read_u8(2), Some(0b0100_0110)); - assert_eq!(view.read_u8(3), Some(0b0010_0011)); - assert_eq!(view.read_u8(7), None); - - // 0000 1000 1100 0111 - // E S - let view = super::BinaryView::new(&[0xC7, 0x08], 8, 8); - assert_eq!(view.read_u8(0), Some(0b0000_1000)); - } -} diff --git a/usbhidd/src/reqs.rs b/usbhidd/src/reqs.rs index b7887b2490..c74281dd3d 100644 --- a/usbhidd/src/reqs.rs +++ b/usbhidd/src/reqs.rs @@ -80,10 +80,7 @@ pub fn set_idle( DeviceReqData::NoData, ) } -pub fn get_protocol( - handle: &XhciClientHandle, - if_num: u16, -) -> Result { +pub fn get_protocol(handle: &XhciClientHandle, if_num: u16) -> Result { let mut protocol = 0; let buffer = slice::from_mut(&mut protocol); handle.device_request( From e070abc7cb5fb4257f3b714644ad7686ad86872f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 12 Apr 2024 10:37:42 -0600 Subject: [PATCH 0848/1301] Fix network device logging paths --- net/rtl8139d/src/main.rs | 4 ++-- net/rtl8168d/src/main.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 113b395e2c..b04e5a7829 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -34,7 +34,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { ); #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "host", "rtl8139.log") { + match OutputBuilder::in_redox_logging_scheme("net", "pcie", "rtl8139.log") { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this b.with_filter(log::LevelFilter::Info) @@ -45,7 +45,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "host", "rtl8139.ansi.log") { + match OutputBuilder::in_redox_logging_scheme("net", "pcie", "rtl8139.ansi.log") { Ok(b) => logger = logger.with_output( b.with_filter(log::LevelFilter::Info) .with_ansi_escape_codes() diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 7127effb52..e2d594948e 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -29,7 +29,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { ); #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "host", "rtl8168.log") { + match OutputBuilder::in_redox_logging_scheme("net", "pcie", "rtl8168.log") { Ok(b) => logger = logger.with_output( // TODO: Add a configuration file for this b.with_filter(log::LevelFilter::Info) @@ -40,7 +40,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "host", "rtl8168.ansi.log") { + match OutputBuilder::in_redox_logging_scheme("net", "pcie", "rtl8168.ansi.log") { Ok(b) => logger = logger.with_output( b.with_filter(log::LevelFilter::Info) .with_ansi_escape_codes() From 12bc7273bfb25da69df9eed479a77ec90f9189f7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 12 Apr 2024 11:25:15 -0600 Subject: [PATCH 0849/1301] xhcid: add more debugging --- xhcid/src/xhci/mod.rs | 33 +++++++++++++++++++++++++++------ xhcid/src/xhci/scheme.rs | 2 ++ 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 52d544d845..06c57ab35f 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -513,12 +513,24 @@ impl Xhci { debug!("Slot type: {}", slot_ty); debug!("Enabling slot."); - let slot = self.enable_port_slot(slot_ty).await?; + let slot = match self.enable_port_slot(slot_ty).await { + Ok(ok) => ok, + Err(err) => { + error!("Failed to enable slot for port {}: {}", i, err); + continue; + } + }; info!("Enabled port {}, which the xHC mapped to {}", i, slot); let mut input = unsafe { self.alloc_dma_zeroed::()? }; - let mut ring = self.address_device(&mut input, i, slot_ty, slot, speed).await?; + let mut ring = match self.address_device(&mut input, i, slot_ty, slot, speed).await { + Ok(ok) => ok, + Err(err) => { + error!("Failed to address device for port {}: {}", i, err); + continue; + } + }; debug!("Addressed device"); // TODO: Should the descriptors be cached in PortState, or refetched? @@ -688,7 +700,7 @@ impl Xhci { }).await; if event_trb.completion_code() != TrbCompletionCode::Success as u8 { - error!("Failed to address device at slot {} (port {})", slot, i); + error!("Failed to address device at slot {} (port {}), completion code 0x{:X}", slot, i, event_trb.completion_code()); self.event_handler_finished(); return Err(Error::new(EIO)); } @@ -751,13 +763,22 @@ impl Xhci { let ifdesc = &ps .dev_desc - .as_ref().ok_or(Error::new(EBADF))? + .as_ref().ok_or_else(|| { + log::warn!("Missing device descriptor"); + Error::new(EBADF) + })? .config_descs .first() - .ok_or(Error::new(EBADF))? + .ok_or_else(|| { + log::warn!("Missing config descriptor"); + Error::new(EBADF) + })? .interface_descs .first() - .ok_or(Error::new(EBADF))?; + .ok_or_else(|| { + log::warn!("Missing interface descriptor"); + Error::new(EBADF) + })?; let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 9af57334ef..4a682ff8e6 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1036,6 +1036,7 @@ impl Xhci { } let raw_dd = self.fetch_dev_desc(port_id, slot).await?; + log::debug!("port {}, slot {}, desc {:?}", port_id, slot, raw_dd); let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { @@ -1066,6 +1067,7 @@ impl Xhci { for index in 0..raw_dd.configurations { let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?; + log::debug!("port {}, slot {}, config {}, desc {:?}", port_id, slot, index, desc); let extra_length = desc.total_length as usize - mem::size_of_val(&desc); let data = &data[..extra_length]; From 64fcd0a32347488c5e78df6f67a3e96c082b6566 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 15 Apr 2024 12:54:05 -0600 Subject: [PATCH 0850/1301] xhcid: ensure max packet size is set correctly before reading descriptors --- xhcid/src/usb/device.rs | 27 ++++++++++++++++++++++-- xhcid/src/usb/mod.rs | 2 +- xhcid/src/xhci/mod.rs | 45 ++++++++++++++++++++++++++++++++++++++-- xhcid/src/xhci/scheme.rs | 5 +++-- 4 files changed, 72 insertions(+), 7 deletions(-) diff --git a/xhcid/src/usb/device.rs b/xhcid/src/usb/device.rs index 7c99946bfb..c7d1835cf7 100644 --- a/xhcid/src/usb/device.rs +++ b/xhcid/src/usb/device.rs @@ -20,10 +20,33 @@ pub struct DeviceDescriptor { unsafe impl plain::Plain for DeviceDescriptor {} impl DeviceDescriptor { - fn minor_usb_vers(&self) -> u8 { + pub fn minor_usb_vers(&self) -> u8 { (self.usb & 0xFF) as u8 } - fn major_usb_vers(&self) -> u8 { + pub fn major_usb_vers(&self) -> u8 { + ((self.usb >> 8) & 0xFF) as u8 + } +} + +#[repr(packed)] +#[derive(Clone, Copy, Debug, Default)] +pub struct DeviceDescriptor8Byte { + pub length: u8, + pub kind: u8, + pub usb: u16, + pub class: u8, + pub sub_class: u8, + pub protocol: u8, + pub packet_size: u8, +} + +unsafe impl plain::Plain for DeviceDescriptor8Byte {} + +impl DeviceDescriptor8Byte { + pub fn minor_usb_vers(&self) -> u8 { + (self.usb & 0xFF) as u8 + } + pub fn major_usb_vers(&self) -> u8 { ((self.usb >> 8) & 0xFF) as u8 } } diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 4c1e57a8f0..14af518556 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -1,6 +1,6 @@ pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuperSpeedDesc}; pub use self::config::ConfigDescriptor; -pub use self::device::DeviceDescriptor; +pub use self::device::{DeviceDescriptor, DeviceDescriptor8Byte}; pub use self::endpoint::{ EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 06c57ab35f..4e4da6fbd7 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -129,6 +129,12 @@ impl Xhci { Ok(()) } + async fn fetch_dev_desc_8_byte(&self, port: usize, slot: u8) -> Result { + let mut desc = unsafe { self.alloc_dma_zeroed::()? }; + self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?; + Ok(*desc) + } + async fn fetch_dev_desc(&self, port: usize, slot: u8) -> Result { let mut desc = unsafe { self.alloc_dma_zeroed::()? }; self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?; @@ -552,6 +558,16 @@ impl Xhci { }; self.port_states.insert(i, port_state); + // Ensure correct packet size is used + let dev_desc_8_byte = self.fetch_dev_desc_8_byte(i, slot).await?; + { + let mut port_state = self.port_states.get_mut(&i).unwrap(); + + let mut input = port_state.input_context.lock().unwrap(); + + self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte).await?; + } + let dev_desc = self.get_desc(i, slot).await?; self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc); @@ -574,6 +590,33 @@ impl Xhci { Ok(()) } + pub async fn update_max_packet_size( + &self, + input_context: &mut Dma, + slot_id: u8, + dev_desc: usb::DeviceDescriptor8Byte + ) -> Result<()> { + let new_max_packet_size = if dev_desc.major_usb_vers() == 2 { + u32::from(dev_desc.packet_size) + } else { + 1u32 << dev_desc.packet_size + }; + let endp_ctx = &mut input_context.device.endpoints[0]; + let mut b = endp_ctx.b.read(); + b &= 0x0000_FFFF; + b |= (new_max_packet_size) << 16; + endp_ctx.b.write(b); + + let (event_trb, command_trb) = self.execute_command(|trb, cycle| { + trb.evaluate_context(slot_id, input_context.physical(), false, cycle) + }).await; + + self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; + self.event_handler_finished(); + + Ok(()) + } + pub async fn update_default_control_pipe( &self, input_context: &mut Dma, @@ -594,14 +637,12 @@ impl Xhci { b |= (new_max_packet_size) << 16; endp_ctx.b.write(b); - /*TODO: this causes issues on real hardware, maybe it should only be used on USB 2? let (event_trb, command_trb) = self.execute_command(|trb, cycle| { trb.evaluate_context(slot_id, input_context.physical(), false, cycle) }).await; self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; self.event_handler_finished(); - */ Ok(()) } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 4a682ff8e6..afb5a200ad 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1036,7 +1036,7 @@ impl Xhci { } let raw_dd = self.fetch_dev_desc(port_id, slot).await?; - log::debug!("port {}, slot {}, desc {:?}", port_id, slot, raw_dd); + log::debug!("port {} slot {} desc {:X?}", port_id, slot, raw_dd); let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { @@ -1055,6 +1055,7 @@ impl Xhci { None }, ); + log::debug!("manufacturer {:?} product {:?} serial {:?}", manufacturer_str, product_str, serial_str); //TODO let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot).await?; @@ -1067,7 +1068,7 @@ impl Xhci { for index in 0..raw_dd.configurations { let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?; - log::debug!("port {}, slot {}, config {}, desc {:?}", port_id, slot, index, desc); + log::debug!("port {} slot {} config {} desc {:X?}", port_id, slot, index, desc); let extra_length = desc.total_length as usize - mem::size_of_val(&desc); let data = &data[..extra_length]; From 806be9bdc67c0eb8d8b5bae9979635b841298345 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 15 Apr 2024 15:02:05 -0600 Subject: [PATCH 0851/1301] xhcid: associate stalls on setup stage with transfers --- xhcid/src/xhci/irq_reactor.rs | 76 ++++++++++++++++++++--------------- xhcid/src/xhci/mod.rs | 5 ++- xhcid/src/xhci/scheme.rs | 8 +++- 3 files changed, 54 insertions(+), 35 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index a697561ad5..45d22a0eb7 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -66,7 +66,7 @@ impl RingId { #[derive(Clone, Copy, Debug)] pub enum StateKind { CommandCompletion { phys_ptr: u64 }, - Transfer { phys_ptr: u64, ring_id: RingId }, + Transfer { first_phys_ptr: u64, last_phys_ptr: u64, ring_id: RingId }, Other(TrbType), } @@ -259,32 +259,42 @@ impl IrqReactor { } } - StateKind::Transfer { phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => { + StateKind::Transfer { first_phys_ptr, last_phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => { if let Some(src_trb) = trb.transfer_event_trb_pointer().map(|ptr| self.hci.get_transfer_trb(ptr, ring_id)).flatten() { - if trb.transfer_event_trb_pointer() == Some(phys_ptr) { - // Give the source transfer TRB together with the event TRB, to the future. - - let state = self.states.remove(index); - *state.message.lock().unwrap() = Some(NextEventTrb { - src_trb: Some(src_trb), - event_trb: trb.clone(), - }); - state.waker.wake(); - return; - } else if trb.transfer_event_trb_pointer().is_none() { - // Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full. - // - // These errors are caused when either an isoch transfer that shall write data, doesn't - // have any data since the ring is empty, or if an isoch receive is impossible due to a - // full ring. The Virtual Function Event Ring Full is only for Virtual Machine - // Managers, and since this isn't implemented yet, they are irrelevant. - // - // The best solution here is to differentiate between isoch transfers (and - // virtual function event rings when virtualization gets implemented), with - // regular commands and transfers, and send the error TRB to all of them, or - // possibly an error code wrapped in a Result. - self.acknowledge_failed_transfer_trbs(trb); - return; + match trb.transfer_event_trb_pointer() { + Some(phys_ptr) => { + let matches = if first_phys_ptr <= last_phys_ptr { + phys_ptr >= first_phys_ptr && phys_ptr <= last_phys_ptr + } else { + // Handle ring buffer wrap + phys_ptr >= first_phys_ptr || phys_ptr <= last_phys_ptr + }; + if matches { + // Give the source transfer TRB together with the event TRB, to the future. + let state = self.states.remove(index); + *state.message.lock().unwrap() = Some(NextEventTrb { + src_trb: Some(src_trb), + event_trb: trb.clone(), + }); + state.waker.wake(); + return; + } + }, + None => { + // Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full. + // + // These errors are caused when either an isoch transfer that shall write data, doesn't + // have any data since the ring is empty, or if an isoch receive is impossible due to a + // full ring. The Virtual Function Event Ring Full is only for Virtual Machine + // Managers, and since this isn't implemented yet, they are irrelevant. + // + // The best solution here is to differentiate between isoch transfers (and + // virtual function event rings when virtualization gets implemented), with + // regular commands and transfers, and send the error TRB to all of them, or + // possibly an error code wrapped in a Result. + self.acknowledge_failed_transfer_trbs(trb); + return; + } } } } @@ -445,19 +455,21 @@ impl Xhci { Some(function(ring_ref)) } - pub fn next_transfer_event_trb(&self, ring_id: RingId, ring: &Ring, trb: &Trb, doorbell: EventDoorbell) -> impl Future + Send + Sync + 'static { - if ! trb.is_transfer_trb() { - panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", trb.trb_type(), trb) + pub fn next_transfer_event_trb(&self, ring_id: RingId, ring: &Ring, first_trb: &Trb, last_trb: &Trb, doorbell: EventDoorbell) -> impl Future + Send + Sync + 'static { + if ! last_trb.is_transfer_trb() { + panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", last_trb.trb_type(), last_trb) } - let is_isoch_or_vf = trb.trb_type() == TrbType::Isoch as u8; - let phys_ptr = ring.trb_phys_ptr(self.cap.ac64(), trb); + let is_isoch_or_vf = last_trb.trb_type() == TrbType::Isoch as u8; + let first_phys_ptr = ring.trb_phys_ptr(self.cap.ac64(), first_trb); + let last_phys_ptr = ring.trb_phys_ptr(self.cap.ac64(), last_trb); EventTrbFuture::Pending { state: FutureState { is_isoch_or_vf, state_kind: StateKind::Transfer { ring_id, - phys_ptr, + first_phys_ptr, + last_phys_ptr, }, message: Arc::new(Mutex::new(None)), }, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 4e4da6fbd7..33762adf84 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -85,12 +85,14 @@ impl Xhci { /// Gets descriptors, before the port state is initiated. async fn get_desc_raw(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, desc: &mut Dma) -> Result<()> { let len = mem::size_of::(); + log::debug!("get_desc_raw port {} slot {} kind {:?} index {} len {}", port, slot, kind, index, len); let future = { let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; let ring = port_state.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().expect("no ring for the default control pipe"); - let (cmd, cycle) = ring.next(); + let first_index = ring.next_index(); + let (cmd, cycle) = (&mut ring.trbs[first_index], ring.cycle); cmd.setup( usb::Setup::get_descriptor(kind, index, 0, len as u16), TransferKind::In, @@ -114,6 +116,7 @@ impl Xhci { self.next_transfer_event_trb( RingId::default_control_pipe(port as u8), &ring, + &ring.trbs[first_index], &ring.trbs[last_index], EventDoorbell::new(self, usize::from(slot), Self::def_control_endp_doorbell()) ) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index afb5a200ad..2a12fb5a4c 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -313,7 +313,8 @@ impl Xhci { .ring() .ok_or(Error::new(EIO))?; - let (cmd, cycle) = ring.next(); + let first_index = ring.next_index(); + let (cmd, cycle) = (&mut ring.trbs[first_index], ring.cycle); cmd.setup(setup, tk, cycle); if tk != TransferKind::NoData { @@ -340,6 +341,7 @@ impl Xhci { self.next_transfer_event_trb( RingId::default_control_pipe(port_num as u8), ring, + &ring.trbs[first_index], &ring.trbs[last_index], EventDoorbell::new(self, usize::from(slot), Self::def_control_endp_doorbell()) ) @@ -430,6 +432,8 @@ impl Xhci { break self.next_transfer_event_trb( super::irq_reactor::RingId { port: port_num as u8, endpoint_num: endp_num, stream_id }, ring, + //TODO: find first TRB + &ring.trbs[last_index], &ring.trbs[last_index], EventDoorbell::new(self, usize::from(slot), if has_streams { doorbell_data_stream @@ -2128,7 +2132,7 @@ pub fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb if event_trb.completion_code() == TrbCompletionCode::Success as u8 || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 { Ok(()) } else { - error!("{} transfer (TRB {:?}) failed with event trb {:?}", name, transfer_trb, event_trb); + error!("{} transfer {:?} failed with event {:?}", name, transfer_trb, event_trb); Err(Error::new(EIO)) } } From 61e2ee224acfa6bab4b43a229a3507d67c51a504 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 08:10:32 -0600 Subject: [PATCH 0852/1301] xhcid: improve endpoint parsing --- xhcid/src/driver_interface.rs | 3 ++- xhcid/src/xhci/scheme.rs | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 8b560a5cd1..efea45b6e5 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -156,7 +156,8 @@ impl EndpDesc { self.ssc.is_some() } pub fn is_superspeedplus(&self) -> bool { - todo!() + log::warn!("TODO: is_superspeedplus not implemented, defaulting to false"); + false } fn interrupt_usage_bits(&self) -> u8 { assert!(self.is_interrupt()); diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 2a12fb5a4c..410b677c09 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1093,14 +1093,18 @@ impl Xhci { let mut endpoints = SmallVec::<[EndpDesc; 4]>::new(); let mut hid_descs = SmallVec::<[HidDesc; 1]>::new(); - for _ in 0..idesc.endpoints { + while endpoints.len() < idesc.endpoints as usize { let next = match iter.next() { Some(AnyDescriptor::Endpoint(n)) => n, Some(AnyDescriptor::Hid(h)) if idesc.class == 3 => { hid_descs.push(h.into()); - break; + continue; } - _ => break, + Some(unexpected) => { + log::warn!("expected endpoint, got {:X?}", unexpected); + break; + }, + None => break, }; let mut endp = EndpDesc::from(next); @@ -1124,6 +1128,7 @@ impl Xhci { interface_descs.push(self.new_if_desc(port_id, slot, idesc, endpoints, hid_descs).await?); } else { + log::warn!("expected interface, got {:?}", item); // TODO break; } From a3be1d88d46d35062a22ba6b3dd35bd6bacc15a3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 08:11:05 -0600 Subject: [PATCH 0853/1301] usbhidd: dynamically locate config, interface, and alternate setting --- usbhidd/src/main.rs | 67 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index da9c143aa7..fd6b6d0e6e 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -1,7 +1,7 @@ use std::collections::VecDeque; use std::env; use std::fs::File; -use std::io::Write; +use std::io::{Read, Write}; use orbclient::KeyEvent as OrbKeyEvent; use redox_log::{OutputBuilder, RedoxLogger}; @@ -236,14 +236,46 @@ fn main() { ); let handle = XhciClientHandle::new(scheme, port); - let dev_desc: DevDesc = handle + let desc: DevDesc = handle .get_standard_descs() .expect("Failed to get standard descriptors"); - let hid_desc = dev_desc.config_descs[0].interface_descs[0].hid_descs[0]; + log::info!("{:X?}", desc); - // TODO: Currently it's assumed that config 0 and interface 0 are used. + // TODO: Perhaps the drivers should just be given the config, interface, and alternate setting + // from xhcid. + let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting, hid_desc)) = desc + .config_descs + .iter() + .find_map(|conf_desc| { + let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { + if if_desc.class == 3 { + let hid_desc = if_desc.hid_descs.iter().find_map(|hid_desc| { + //TODO: should we do any filtering? + Some(hid_desc) + })?; + Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting, hid_desc)) + } else { + None + } + })?; + Some(( + conf_desc.clone(), + conf_desc.configuration_value, + if_desc, + )) + }) + .expect("Failed to find suitable configuration"); + + log::info!("using config {configuration_value}, interface {interface_num}, alternate setting {alternate_setting}"); + + handle + .configure_endpoints(&ConfigureEndpointsReq { + config_desc: configuration_value, + interface_desc: Some(interface_num), + alternate_setting: Some(alternate_setting), + }) + .expect("Failed to configure endpoints"); - let interface_num = 0; let report_desc_len = hid_desc.desc_len; assert_eq!(hid_desc.desc_ty, REPORT_DESC_TY); @@ -253,7 +285,8 @@ fn main() { PortReqRecipient::Interface, REPORT_DESC_TY, 0, - interface_num, + //TODO: should this be an index into interface_descs? + interface_num as u16, &mut report_desc_bytes, ) .expect("Failed to retrieve report descriptor"); @@ -261,22 +294,17 @@ fn main() { let mut handler = ReportHandler::new(&report_desc_bytes).expect("failed to parse report descriptor"); - handle - .configure_endpoints(&ConfigureEndpointsReq { - config_desc: 0, - interface_desc: None, - alternate_setting: None, - }) - .expect("Failed to configure endpoints"); - // Get all main items, and their global item options. { let mut report_buffer = vec![0u8; handler.total_byte_length]; let report_ty = ReportTy::Input; let report_id = 0; + //TODO: make this dynamic? + let mut interrupt_endpoint = 0x81; let mut display = File::open("input:producer").expect("Failed to open orbital input socket"); + //TODO: let mut interrupt_data = handle.open_endpoint_data(interrupt_endpoint).expect("failed to open interrupt endpoint"); let mut left_shift = false; let mut right_shift = false; let mut last_mouse_pos = (0, 0); @@ -285,14 +313,21 @@ fn main() { //TODO: get frequency from device std::thread::sleep(std::time::Duration::from_millis(10)); + /*TODO + // interrupt transfer + interrupt_data.read(&mut report_buffer).expect("failed to get report"); + */ + + // control transfer reqs::get_report( &handle, report_ty, report_id, - interface_num, + //TODO: should this be an index into interface_descs? + interface_num as u16, &mut report_buffer, ) - .expect("Failed to get report"); + .expect("failed to get report"); let mut mouse_pos = last_mouse_pos; let mut mouse_dx = 0i32; From bd092569918edc4a1b41fd7f2ecc8de0775b521a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 08:55:55 -0600 Subject: [PATCH 0854/1301] usbhidd: find endpoint number --- usbhidd/src/main.rs | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index fd6b6d0e6e..8b843bce1c 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -10,7 +10,7 @@ use rehid::{ report_handler::ReportHandler, usage_tables::{GenericDesktopUsage, UsagePage}, }; -use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle}; +use xhcid_interface::{ConfigureEndpointsReq, DevDesc, EndpDirection, PortReqRecipient, XhciClientHandle}; mod keymap; mod reqs; @@ -243,17 +243,24 @@ fn main() { // TODO: Perhaps the drivers should just be given the config, interface, and alternate setting // from xhcid. - let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting, hid_desc)) = desc + let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting, endpoint_num, hid_desc)) = desc .config_descs .iter() .find_map(|conf_desc| { let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { if if_desc.class == 3 { + let endpoint_num = if_desc.endpoints.iter().enumerate().find_map(|(endpoint_i, endpoint)| { + if endpoint.direction() == EndpDirection::In { + Some(endpoint_i + 1) + } else { + None + } + })?; let hid_desc = if_desc.hid_descs.iter().find_map(|hid_desc| { //TODO: should we do any filtering? Some(hid_desc) })?; - Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting, hid_desc)) + Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting, endpoint_num, hid_desc)) } else { None } @@ -299,12 +306,10 @@ fn main() { let mut report_buffer = vec![0u8; handler.total_byte_length]; let report_ty = ReportTy::Input; let report_id = 0; - //TODO: make this dynamic? - let mut interrupt_endpoint = 0x81; let mut display = File::open("input:producer").expect("Failed to open orbital input socket"); - //TODO: let mut interrupt_data = handle.open_endpoint_data(interrupt_endpoint).expect("failed to open interrupt endpoint"); + //TODO: let mut endpoint = handle.open_endpoint(endpoint_num as u8).expect("failed to open interrupt endpoint"); let mut left_shift = false; let mut right_shift = false; let mut last_mouse_pos = (0, 0); @@ -313,9 +318,8 @@ fn main() { //TODO: get frequency from device std::thread::sleep(std::time::Duration::from_millis(10)); - /*TODO - // interrupt transfer - interrupt_data.read(&mut report_buffer).expect("failed to get report"); + /*TODO: interrupt transfer + endpoint.transfer_read(&mut report_buffer).expect("failed to get report"); */ // control transfer From c85baf220ee1a456121763ba663375680c45ce36 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 08:56:16 -0600 Subject: [PATCH 0855/1301] xhcid: add number to trb completion codes --- xhcid/src/xhci/trb.rs | 74 +++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 8d71f8b81e..1072981503 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -57,43 +57,43 @@ pub enum TrbType { #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum TrbCompletionCode { - Invalid, - Success, - DataBuffer, - BabbleDetected, - UsbTransaction, - Trb, - Stall, - Resource, - Bandwidth, - NoSlotsAvailable, - InvalidStreamType, - SlotNotEnabled, - EndpointNotEnabled, - ShortPacket, - RingUnderrun, - RingOverrun, - VfEventRingFull, - Parameter, - BandwidthOverrun, - ContextState, - NoPingResponse, - EventRingFull, - IncompatibleDevice, - MissedService, - CommandRingStopped, - CommandAborted, - Stopped, - StoppedLengthInvalid, - StoppedShortPacket, - MaxExitLatencyTooLarge, - Rsv30, - IsochBuffer, - EventLost, - Undefined, - InvalidStreamId, - SecondaryBandwidth, - SplitTransaction, + Invalid = 0x00, + Success = 0x01, + DataBuffer = 0x02, + BabbleDetected = 0x03, + UsbTransaction = 0x04, + Trb = 0x05, + Stall = 0x06, + Resource = 0x07, + Bandwidth = 0x08, + NoSlotsAvailable = 0x09, + InvalidStreamType = 0x0A, + SlotNotEnabled = 0x0B, + EndpointNotEnabled = 0x0C, + ShortPacket = 0x0D, + RingUnderrun = 0x0E, + RingOverrun = 0x0F, + VfEventRingFull = 0x10, + Parameter = 0x11, + BandwidthOverrun = 0x12, + ContextState = 0x13, + NoPingResponse = 0x14, + EventRingFull = 0x15, + IncompatibleDevice = 0x16, + MissedService = 0x17, + CommandRingStopped = 0x18, + CommandAborted = 0x19, + Stopped = 0x1A, + StoppedLengthInvalid = 0x1B, + StoppedShortPacket = 0x1C, + MaxExitLatencyTooLarge = 0x1D, + Rsv30 = 0x1E, + IsochBuffer = 0x1F, + EventLost = 0x20, + Undefined = 0x21, + InvalidStreamId = 0x22, + SecondaryBandwidth = 0x23, + SplitTransaction = 0x24, /* Values from 37 to 191 are reserved */ /* 192 to 223 are vendor defined errors */ /* 224 to 255 are vendor defined information */ From 29b1c1aa0dcc63202bfb2662746a881bf124dba3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 09:13:44 -0600 Subject: [PATCH 0856/1301] xhcid: fix isoch and interrupt endpoint types being swapped --- xhcid/src/driver_interface.rs | 4 ++-- xhcid/src/usb/endpoint.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index efea45b6e5..3456987fb5 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -112,9 +112,9 @@ impl EndpDesc { pub fn ty(self) -> EndpointTy { match self.attributes & ENDP_ATTR_TY_MASK { 0 => EndpointTy::Ctrl, - 1 => EndpointTy::Interrupt, + 1 => EndpointTy::Isoch, 2 => EndpointTy::Bulk, - 3 => EndpointTy::Isoch, + 3 => EndpointTy::Interrupt, _ => unreachable!(), } } diff --git a/xhcid/src/usb/endpoint.rs b/xhcid/src/usb/endpoint.rs index 42ab8b1022..39e28eb6f4 100644 --- a/xhcid/src/usb/endpoint.rs +++ b/xhcid/src/usb/endpoint.rs @@ -17,18 +17,18 @@ pub const ENDP_ATTR_TY_MASK: u8 = 0x3; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum EndpointTy { Ctrl = 0, - Interrupt = 1, + Isoch = 1, Bulk = 2, - Isoch = 3, + Interrupt = 3, } impl EndpointDescriptor { fn ty(self) -> EndpointTy { match self.attributes & ENDP_ATTR_TY_MASK { 0 => EndpointTy::Ctrl, - 1 => EndpointTy::Interrupt, + 1 => EndpointTy::Isoch, 2 => EndpointTy::Bulk, - 3 => EndpointTy::Isoch, + 3 => EndpointTy::Interrupt, _ => unreachable!(), } } From ec4f2f594c1466b8c912b224b16f85326f9249fe Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 09:47:34 -0600 Subject: [PATCH 0857/1301] xhcid: document arguments to trb.normal --- xhcid/src/xhci/scheme.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 410b677c09..e555fa361d 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -999,18 +999,22 @@ impl Xhci { let ioc = bytes_left <= max_transfer_size as usize; let chain = !ioc; + let interrupter = 0; + let ent = false; + let isp = true; + let bei = false; trb.normal( buffer, len, cycle, estimated_td_size, - 0, - false, - true, + interrupter, + ent, + isp, chain, ioc, idt, - false, + bei, ); bytes_left -= len as usize; From a2c024c03e3ca7f15dd64a12f1e0cbde5fb8cb8b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 10:20:25 -0600 Subject: [PATCH 0858/1301] Add HID protocol and idle configuration to USB stack --- storage/usbscsid/src/main.rs | 1 + usbhidd/src/main.rs | 247 ++++++++++++++++++---------------- xhcid/src/driver_interface.rs | 7 +- xhcid/src/usb/setup.rs | 21 +++ xhcid/src/xhci/scheme.rs | 45 ++++++- 5 files changed, 198 insertions(+), 123 deletions(-) diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index e745c0ad3f..aef4cde0b6 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -77,6 +77,7 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u config_desc: configuration_value, interface_desc: Some(interface_num), alternate_setting: Some(alternate_setting), + ..Default::default() }) .expect("Failed to configure endpoints"); diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 8b843bce1c..81c27f83cf 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -10,7 +10,7 @@ use rehid::{ report_handler::ReportHandler, usage_tables::{GenericDesktopUsage, UsagePage}, }; -use xhcid_interface::{ConfigureEndpointsReq, DevDesc, EndpDirection, PortReqRecipient, XhciClientHandle}; +use xhcid_interface::{ConfigureEndpointsReq, DevDesc, EndpDirection, EndpointTy, PortReqRecipient, XhciClientHandle, PROTOCOL_REPORT}; mod keymap; mod reqs; @@ -243,24 +243,24 @@ fn main() { // TODO: Perhaps the drivers should just be given the config, interface, and alternate setting // from xhcid. - let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting, endpoint_num, hid_desc)) = desc + let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting, endpoint_num_opt, hid_desc)) = desc .config_descs .iter() .find_map(|conf_desc| { let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { if if_desc.class == 3 { - let endpoint_num = if_desc.endpoints.iter().enumerate().find_map(|(endpoint_i, endpoint)| { - if endpoint.direction() == EndpDirection::In { + let endpoint_num_opt = if_desc.endpoints.iter().enumerate().find_map(|(endpoint_i, endpoint)| { + if endpoint.ty() == EndpointTy::Interrupt && endpoint.direction() == EndpDirection::In { Some(endpoint_i + 1) } else { None } - })?; + }); let hid_desc = if_desc.hid_descs.iter().find_map(|hid_desc| { //TODO: should we do any filtering? Some(hid_desc) })?; - Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting, endpoint_num, hid_desc)) + Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting, endpoint_num_opt, hid_desc)) } else { None } @@ -280,6 +280,10 @@ fn main() { config_desc: configuration_value, interface_desc: Some(interface_num), alternate_setting: Some(alternate_setting), + protocol: Some(PROTOCOL_REPORT), + //TODO: dynamically create good values, fix xhcid so it does not block on each request + // This sets all reports to a duration of 4ms + report_idles: vec![(0, 1)] }) .expect("Failed to configure endpoints"); @@ -301,27 +305,34 @@ fn main() { let mut handler = ReportHandler::new(&report_desc_bytes).expect("failed to parse report descriptor"); - // Get all main items, and their global item options. - { - let mut report_buffer = vec![0u8; handler.total_byte_length]; - let report_ty = ReportTy::Input; - let report_id = 0; + let mut report_buffer = vec![0u8; handler.total_byte_length]; + let report_ty = ReportTy::Input; + let report_id = 0; - let mut display = - File::open("input:producer").expect("Failed to open orbital input socket"); - //TODO: let mut endpoint = handle.open_endpoint(endpoint_num as u8).expect("failed to open interrupt endpoint"); - let mut left_shift = false; - let mut right_shift = false; - let mut last_mouse_pos = (0, 0); - let mut last_buttons = [false, false, false]; - loop { - //TODO: get frequency from device - std::thread::sleep(std::time::Duration::from_millis(10)); + let mut display = + File::open("input:producer").expect("Failed to open orbital input socket"); + let mut endpoint_opt = match endpoint_num_opt { + Some(endpoint_num) => match handle.open_endpoint(endpoint_num as u8) { + Ok(ok) => Some(ok), + Err(err) => { + log::warn!("failed to open endpoint {endpoint_num}: {err}"); + None + } + }, + None => None, + }; + let mut left_shift = false; + let mut right_shift = false; + let mut last_mouse_pos = (0, 0); + let mut last_buttons = [false, false, false]; + loop { + //TODO: get frequency from device + std::thread::sleep(std::time::Duration::from_millis(10)); - /*TODO: interrupt transfer + if let Some(endpoint) = &mut endpoint_opt { + // interrupt transfer endpoint.transfer_read(&mut report_buffer).expect("failed to get report"); - */ - + } else { // control transfer reqs::get_report( &handle, @@ -332,123 +343,123 @@ fn main() { &mut report_buffer, ) .expect("failed to get report"); + } - let mut mouse_pos = last_mouse_pos; - let mut mouse_dx = 0i32; - let mut mouse_dy = 0i32; - let mut buttons = last_buttons; - for event in handler - .handle(&report_buffer) - .expect("failed to parse report") - { - log::debug!("{:X?}", event); - if event.usage_page == UsagePage::GenericDesktop as u32 { - if event.usage == GenericDesktopUsage::X as u32 { - if event.relative { - mouse_dx += event.value; - } else { - mouse_pos.0 = event.value; - } - } else if event.usage == GenericDesktopUsage::Y as u32 { - if event.relative { - mouse_dy += event.value; - } else { - mouse_pos.1 = event.value; - } + let mut mouse_pos = last_mouse_pos; + let mut mouse_dx = 0i32; + let mut mouse_dy = 0i32; + let mut buttons = last_buttons; + for event in handler + .handle(&report_buffer) + .expect("failed to parse report") + { + log::debug!("{:X?}", event); + if event.usage_page == UsagePage::GenericDesktop as u32 { + if event.usage == GenericDesktopUsage::X as u32 { + if event.relative { + mouse_dx += event.value; } else { - log::info!( - "unsupported generic desktop usage 0x{:X}:0x{:X} value {}", - event.usage_page, - event.usage, - event.value - ); + mouse_pos.0 = event.value; } - } else if event.usage_page == UsagePage::KeyboardOrKeypad as u32 { - let (pressed, shift_opt) = if event.value != 0 { - (true, Some(left_shift | right_shift)) + } else if event.usage == GenericDesktopUsage::Y as u32 { + if event.relative { + mouse_dy += event.value; } else { - (false, None) - }; - if event.usage == 0xE1 { - left_shift = pressed; - } else if event.usage == 0xE5 { - right_shift = pressed; - } - send_key_event( - &mut display, - event.usage_page, - event.usage, - pressed, - shift_opt, - ); - } else if event.usage_page == UsagePage::Button as u32 { - if event.usage > 0 && event.usage as usize <= buttons.len() { - buttons[event.usage as usize - 1] = event.value != 0; - } else { - log::info!( - "unsupported buttons usage 0x{:X}:0x{:X} value {}", - event.usage_page, - event.usage, - event.value - ); + mouse_pos.1 = event.value; } } else { log::info!( - "unsupported usage 0x{:X}:0x{:X} value {}", + "unsupported generic desktop usage 0x{:X}:0x{:X} value {}", event.usage_page, event.usage, event.value ); } - } - - if mouse_pos != last_mouse_pos { - last_mouse_pos = mouse_pos; - - // ps2d uses 0..=65535 as range, while usb uses 0..=32767. orbital - // expects the former range, so multiply by two here to translate - // the usb coordinates to what orbital expects. - let mouse_event = orbclient::event::MouseEvent { - x: mouse_pos.0 * 2, - y: mouse_pos.1 * 2, + } else if event.usage_page == UsagePage::KeyboardOrKeypad as u32 { + let (pressed, shift_opt) = if event.value != 0 { + (true, Some(left_shift | right_shift)) + } else { + (false, None) }; + if event.usage == 0xE1 { + left_shift = pressed; + } else if event.usage == 0xE5 { + right_shift = pressed; + } + send_key_event( + &mut display, + event.usage_page, + event.usage, + pressed, + shift_opt, + ); + } else if event.usage_page == UsagePage::Button as u32 { + if event.usage > 0 && event.usage as usize <= buttons.len() { + buttons[event.usage as usize - 1] = event.value != 0; + } else { + log::info!( + "unsupported buttons usage 0x{:X}:0x{:X} value {}", + event.usage_page, + event.usage, + event.value + ); + } + } else { + log::info!( + "unsupported usage 0x{:X}:0x{:X} value {}", + event.usage_page, + event.usage, + event.value + ); + } + } - match display.write(&mouse_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send mouse event to orbital: {}", err); - } + if mouse_pos != last_mouse_pos { + last_mouse_pos = mouse_pos; + + // ps2d uses 0..=65535 as range, while usb uses 0..=32767. orbital + // expects the former range, so multiply by two here to translate + // the usb coordinates to what orbital expects. + let mouse_event = orbclient::event::MouseEvent { + x: mouse_pos.0 * 2, + y: mouse_pos.1 * 2, + }; + + match display.write(&mouse_event.to_event()) { + Ok(_) => (), + Err(err) => { + log::warn!("failed to send mouse event to orbital: {}", err); } } + } - if mouse_dx != 0 || mouse_dy != 0 { - let mouse_event = orbclient::event::MouseRelativeEvent { - dx: mouse_dx, - dy: mouse_dy, - }; + if mouse_dx != 0 || mouse_dy != 0 { + let mouse_event = orbclient::event::MouseRelativeEvent { + dx: mouse_dx, + dy: mouse_dy, + }; - match display.write(&mouse_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send mouse event to orbital: {}", err); - } + match display.write(&mouse_event.to_event()) { + Ok(_) => (), + Err(err) => { + log::warn!("failed to send mouse event to orbital: {}", err); } } + } - if buttons != last_buttons { - last_buttons = buttons; + if buttons != last_buttons { + last_buttons = buttons; - let button_event = orbclient::event::ButtonEvent { - left: buttons[0], - right: buttons[1], - middle: buttons[2], - }; + let button_event = orbclient::event::ButtonEvent { + left: buttons[0], + right: buttons[1], + middle: buttons[2], + }; - match display.write(&button_event.to_event()) { - Ok(_) => (), - Err(err) => { - log::warn!("failed to send button event to orbital: {}", err); - } + match display.write(&button_event.to_event()) { + Ok(_) => (), + Err(err) => { + log::warn!("failed to send button event to orbital: {}", err); } } } diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 3456987fb5..bd5b0e662a 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -14,12 +14,17 @@ use thiserror::Error; pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK}; -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +pub const PROTOCOL_BOOT: u8 = 0; +pub const PROTOCOL_REPORT: u8 = 1; + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct ConfigureEndpointsReq { /// Index into the configuration descriptors of the device descriptor. pub config_desc: u8, pub interface_desc: Option, pub alternate_setting: Option, + pub protocol: Option, + pub report_idles: Vec<(u8, u8)>, } #[derive(Clone, Debug, Serialize, Deserialize)] diff --git a/xhcid/src/usb/setup.rs b/xhcid/src/usb/setup.rs index d62cb5b988..0112238961 100644 --- a/xhcid/src/usb/setup.rs +++ b/xhcid/src/usb/setup.rs @@ -181,6 +181,7 @@ impl Setup { length: 0, } } + pub const fn set_interface(interface: u8, alternate_setting: u8) -> Self { Self { kind: 0b0000_0001, @@ -190,4 +191,24 @@ impl Setup { length: 0, } } + + pub const fn set_protocol(interface: u8, protocol: u8) -> Self { + Self { + kind: 0b0010_0001, + request: 0x0B, + value: protocol as u16, + index: interface as u16, + length: 0, + } + } + + pub const fn set_idle(interface: u8, report_id: u8, duration: u8) -> Self { + Self { + kind: 0b0010_0001, + request: 0x0A, + value: (report_id as u16) | ((duration as u16) << 8), + index: interface as u16, + length: 0, + } + } } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index e555fa361d..95492f6447 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -481,10 +481,12 @@ impl Xhci { ).await?; Ok(()) } + async fn set_configuration(&self, port: usize, config: u8) -> Result<()> { debug!("Setting configuration value {} to port {}", config, port); self.device_req_no_data(port, usb::Setup::set_configuration(config)).await } + async fn set_interface( &self, port: usize, @@ -498,6 +500,33 @@ impl Xhci { ).await } + async fn set_protocol( + &self, + port: usize, + interface_num: u8, + protocol: u8, + ) -> Result<()> { + debug!("Setting idle value {} (protocol {}) to port {}", interface_num, protocol, port); + self.device_req_no_data( + port, + usb::Setup::set_protocol(interface_num, protocol), + ).await + } + + async fn set_idle( + &self, + port: usize, + interface_num: u8, + report_id: u8, + duration: u8, + ) -> Result<()> { + debug!("Setting idle value {} (report_id {}, duration {}) to port {}", interface_num, report_id, duration, port); + self.device_req_no_data( + port, + usb::Setup::set_idle(interface_num, report_id, duration), + ).await + } + async fn reset_endpoint(&self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; @@ -838,10 +867,18 @@ impl Xhci { // Tell the device about this configuration. self.set_configuration(port, configuration_value).await?; - if let (Some(interface_num), Some(alternate_setting)) = - (req.interface_desc, req.alternate_setting) - { - self.set_interface(port, interface_num, alternate_setting).await?; + if let Some(interface_num) = req.interface_desc { + if let Some(alternate_setting) = req.alternate_setting { + self.set_interface(port, interface_num, alternate_setting).await?; + } + + if let Some(protocol) = req.protocol { + self.set_protocol(port, interface_num, protocol).await?; + } + + for (report_id, duration) in req.report_idles { + self.set_idle(port, interface_num, report_id, duration).await?; + } } Ok(()) From 784575032f0eae53147226ed7d382b27d88ab08b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 11:09:11 -0600 Subject: [PATCH 0859/1301] usbhidd: fix configuration request --- usbhidd/src/main.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 81c27f83cf..55f91c2c89 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -243,10 +243,11 @@ fn main() { // TODO: Perhaps the drivers should just be given the config, interface, and alternate setting // from xhcid. - let (conf_desc, configuration_value, (if_desc, interface_num, alternate_setting, endpoint_num_opt, hid_desc)) = desc + let (conf_desc, conf_num, (if_desc, interface_num, alternate_setting, endpoint_num_opt, hid_desc)) = desc .config_descs .iter() - .find_map(|conf_desc| { + .enumerate() + .find_map(|(conf_num, conf_desc)| { let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { if if_desc.class == 3 { let endpoint_num_opt = if_desc.endpoints.iter().enumerate().find_map(|(endpoint_i, endpoint)| { @@ -267,23 +268,24 @@ fn main() { })?; Some(( conf_desc.clone(), - conf_desc.configuration_value, + conf_num, if_desc, )) }) .expect("Failed to find suitable configuration"); - log::info!("using config {configuration_value}, interface {interface_num}, alternate setting {alternate_setting}"); + log::info!("using config {conf_num}, interface {interface_num}, alternate setting {alternate_setting}"); handle .configure_endpoints(&ConfigureEndpointsReq { - config_desc: configuration_value, + config_desc: conf_num as u8, interface_desc: Some(interface_num), alternate_setting: Some(alternate_setting), - protocol: Some(PROTOCOL_REPORT), + //TODO: do we need to set this? It fails for mice. protocol: Some(PROTOCOL_REPORT), //TODO: dynamically create good values, fix xhcid so it does not block on each request // This sets all reports to a duration of 4ms - report_idles: vec![(0, 1)] + report_idles: vec![(0, 1)], + ..Default::default() }) .expect("Failed to configure endpoints"); From 667a8e42f916e8cbb5be264f069c2ee4b10c2f9f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 11:09:26 -0600 Subject: [PATCH 0860/1301] xhcid: fix set_interface request type --- xhcid/src/usb/setup.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xhcid/src/usb/setup.rs b/xhcid/src/usb/setup.rs index 0112238961..9a9a2ef970 100644 --- a/xhcid/src/usb/setup.rs +++ b/xhcid/src/usb/setup.rs @@ -185,7 +185,7 @@ impl Setup { pub const fn set_interface(interface: u8, alternate_setting: u8) -> Self { Self { kind: 0b0000_0001, - request: 0x09, + request: 0x0B, value: alternate_setting as u16, index: interface as u16, length: 0, From 18eab7c0dcdc85b8227379d20efc48904743543d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 11:09:38 -0600 Subject: [PATCH 0861/1301] xhcid: always set CIE to match CIC --- xhcid/src/xhci/mod.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 33762adf84..a2ee03c814 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -415,10 +415,7 @@ impl Xhci { info!("XHCI initialized."); - if self.cap.cic() { - self.op.get_mut().unwrap().set_cie(true); - } - + self.op.get_mut().unwrap().set_cie(self.cap.cic()); // Reset ports { From 9069c64b87fba6ebf281f0a22b84fc4cb927f2e7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 11:09:57 -0600 Subject: [PATCH 0862/1301] xhcid: fixes for setting config and interface when CIC is false --- xhcid/src/xhci/scheme.rs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 95492f6447..4c2fbf92b6 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -636,22 +636,15 @@ impl Xhci { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; - debug!("Running configure endpoints command, at port {}, request: {:?}", port, req); + info!("Running configure endpoints command, at port {}, request: {:?}", port, req); - if (!self.cap.cic() || !self.op.lock().unwrap().cie()) - && (req.config_desc != 0 || req.interface_desc != None || req.alternate_setting != None) - { - //return Err(Error::new(EOPNOTSUPP)); - req.config_desc = 0; - req.alternate_setting = None; - req.interface_desc = None; - } if req.interface_desc.is_some() != req.alternate_setting.is_some() { return Err(Error::new(EBADMSG)); } let (endp_desc_count, new_context_entries, configuration_value) = { let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; + port_state.cfg_idx = Some(req.config_desc); port_state.if_idx = Some(req.interface_desc.unwrap_or(0)); @@ -702,11 +695,14 @@ impl Xhci { | ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT) & CONTEXT_ENTRIES_MASK), ); - input_context.control.write( + let control = if self.op.lock().unwrap().cie() { (u32::from(req.alternate_setting.unwrap_or(0)) << 16) | (u32::from(req.interface_desc.unwrap_or(0)) << 8) - | u32::from(req.config_desc), - ); + | u32::from(configuration_value) + } else { + 0 + }; + input_context.control.write(control); } for endp_idx in 0..endp_desc_count as u8 { From 13ebe960ddaaa7c070638737ca1a99141691a11d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 11:13:50 -0600 Subject: [PATCH 0863/1301] xhcid: always use polling --- xhcid/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 6b9fe1bd79..6a10660160 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -204,7 +204,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { bar.physmap_mem("xhcid") } as usize; - let (irq_file, interrupt_method) = get_int_method(&mut pcid_handle, address); + let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //TODO: get_int_method(&mut pcid_handle, address); println!(" + XHCI {}", pci_config.func.display()); From 12c28e90fd32ff2a6873d051d70fdd53be341497 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 11:21:51 -0600 Subject: [PATCH 0864/1301] usbhidd: do not log vendor defined events --- usbhidd/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 55f91c2c89..412f27563e 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -406,6 +406,8 @@ fn main() { event.value ); } + } else if event.usage_page >= 0xFF00 { + // Ignore vendor defined event } else { log::info!( "unsupported usage 0x{:X}:0x{:X} value {}", From 42f612bfdad1924f613d5c40ba8adc3f0f126138 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 13:07:17 -0600 Subject: [PATCH 0865/1301] xhcid/usbhidd: WIP spawning drivers on all interfaces --- usbhidd/src/main.rs | 24 ++++++++-------- xhcid/drivers.toml | 2 +- xhcid/src/xhci/mod.rs | 67 +++++++++++++++++++++---------------------- 3 files changed, 45 insertions(+), 48 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 412f27563e..6f1b8a2e1c 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -218,7 +218,7 @@ fn main() { let mut args = env::args().skip(1); - const USAGE: &'static str = "usbhidd "; + const USAGE: &'static str = "usbhidd "; let scheme = args.next().expect(USAGE); let port = args @@ -226,13 +226,17 @@ fn main() { .expect(USAGE) .parse::() .expect("Expected integer as input of port"); - let protocol = args.next().expect(USAGE); + let interface_num = args + .next() + .expect(USAGE) + .parse::() + .expect("Expected integer as input of interface"); log::info!( - "USB HID driver spawned with scheme `{}`, port {}, protocol {}", + "USB HID driver spawned with scheme `{}`, port {}, interface {}", scheme, port, - protocol + interface_num ); let handle = XhciClientHandle::new(scheme, port); @@ -241,15 +245,13 @@ fn main() { .expect("Failed to get standard descriptors"); log::info!("{:X?}", desc); - // TODO: Perhaps the drivers should just be given the config, interface, and alternate setting - // from xhcid. - let (conf_desc, conf_num, (if_desc, interface_num, alternate_setting, endpoint_num_opt, hid_desc)) = desc + let (conf_desc, conf_num, (if_desc, endpoint_num_opt, hid_desc)) = desc .config_descs .iter() .enumerate() .find_map(|(conf_num, conf_desc)| { let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { - if if_desc.class == 3 { + if if_desc.number == interface_num { let endpoint_num_opt = if_desc.endpoints.iter().enumerate().find_map(|(endpoint_i, endpoint)| { if endpoint.ty() == EndpointTy::Interrupt && endpoint.direction() == EndpDirection::In { Some(endpoint_i + 1) @@ -261,7 +263,7 @@ fn main() { //TODO: should we do any filtering? Some(hid_desc) })?; - Some((if_desc.clone(), if_desc.number, if_desc.alternate_setting, endpoint_num_opt, hid_desc)) + Some((if_desc.clone(), endpoint_num_opt, hid_desc)) } else { None } @@ -274,13 +276,11 @@ fn main() { }) .expect("Failed to find suitable configuration"); - log::info!("using config {conf_num}, interface {interface_num}, alternate setting {alternate_setting}"); - handle .configure_endpoints(&ConfigureEndpointsReq { config_desc: conf_num as u8, interface_desc: Some(interface_num), - alternate_setting: Some(alternate_setting), + alternate_setting: Some(if_desc.alternate_setting), //TODO: do we need to set this? It fails for mice. protocol: Some(PROTOCOL_REPORT), //TODO: dynamically create good values, fix xhcid so it does not block on each request // This sets all reports to a duration of 4ms diff --git a/xhcid/drivers.toml b/xhcid/drivers.toml index 53cfc0eb39..8c154af55a 100644 --- a/xhcid/drivers.toml +++ b/xhcid/drivers.toml @@ -8,4 +8,4 @@ command = ["/bin/usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"] name = "USB HID" class = 3 # HID class subclass = -1 -command = ["/bin/usbhidd", "$SCHEME", "$PORT", "$IF_PROTO"] +command = ["/bin/usbhidd", "$SCHEME", "$PORT", "$IF_NUM"] diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index a2ee03c814..e32f8af2a6 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -802,7 +802,8 @@ impl Xhci { let ps = self.port_states.get(&port).unwrap(); - let ifdesc = &ps + //TODO: support choosing config? + let config_desc = &ps .dev_desc .as_ref().ok_or_else(|| { log::warn!("Missing device descriptor"); @@ -813,45 +814,41 @@ impl Xhci { .ok_or_else(|| { log::warn!("Missing config descriptor"); Error::new(EBADF) - })? - .interface_descs - .first() - .ok_or_else(|| { - log::warn!("Missing interface descriptor"); - Error::new(EBADF) })?; let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; - if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| { - driver.class == ifdesc.class - && driver - .subclass() - .map(|subclass| subclass == ifdesc.sub_class) - .unwrap_or(true) - }) { - info!("Loading subdriver \"{}\"", driver.name); - let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; + //TODO: allow spawning on all interfaces (will require fixing port state) + for ifdesc in config_desc.interface_descs.iter().take(1) { + if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| { + driver.class == ifdesc.class + && driver + .subclass() + .map(|subclass| subclass == ifdesc.sub_class) + .unwrap_or(true) + }) { + info!("Loading subdriver \"{}\"", driver.name); + let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; - let if_proto = ifdesc.protocol; - - let process = process::Command::new(command) - .args( - args.into_iter() - .map(|arg| { - arg.replace("$SCHEME", &self.scheme_name) - .replace("$PORT", &format!("{}", port)) - .replace("$IF_PROTO", &format!("{}", if_proto)) - }) - .collect::>(), - ) - .stdin(process::Stdio::null()) - .spawn() - .or(Err(Error::new(ENOENT)))?; - self.drivers.insert(port, process); - } else { - warn!("No driver for USB class {}.{}", ifdesc.class, ifdesc.sub_class); - return Err(Error::new(ENOENT)); + let process = process::Command::new(command) + .args( + args.into_iter() + .map(|arg| { + arg.replace("$SCHEME", &self.scheme_name) + .replace("$PORT", &format!("{}", port)) + .replace("$IF_NUM", &format!("{}", ifdesc.number)) + .replace("$IF_PROTO", &format!("{}", ifdesc.protocol)) + }) + .collect::>(), + ) + .stdin(process::Stdio::null()) + .spawn() + .or(Err(Error::new(ENOENT)))?; + self.drivers.insert(port, process); + } else { + warn!("No driver for USB class {}.{}", ifdesc.class, ifdesc.sub_class); + return Err(Error::new(ENOENT)); + } } Ok(()) From c0a4448c0b7f58af75375bb78ba0e4daf8022433 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 21:26:14 -0600 Subject: [PATCH 0866/1301] xhcid/usbhidd: remove extra set idle code, just use device request --- storage/usbscsid/src/main.rs | 1 - usbhidd/src/main.rs | 13 ++++----- xhcid/src/driver_interface.rs | 7 +---- xhcid/src/usb/setup.rs | 20 -------------- xhcid/src/xhci/scheme.rs | 50 +++++++---------------------------- 5 files changed, 18 insertions(+), 73 deletions(-) diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index aef4cde0b6..e745c0ad3f 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -77,7 +77,6 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u config_desc: configuration_value, interface_desc: Some(interface_num), alternate_setting: Some(alternate_setting), - ..Default::default() }) .expect("Failed to configure endpoints"); diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 6f1b8a2e1c..921de656ae 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -10,7 +10,7 @@ use rehid::{ report_handler::ReportHandler, usage_tables::{GenericDesktopUsage, UsagePage}, }; -use xhcid_interface::{ConfigureEndpointsReq, DevDesc, EndpDirection, EndpointTy, PortReqRecipient, XhciClientHandle, PROTOCOL_REPORT}; +use xhcid_interface::{ConfigureEndpointsReq, DevDesc, EndpDirection, EndpointTy, PortReqRecipient, XhciClientHandle}; mod keymap; mod reqs; @@ -281,14 +281,15 @@ fn main() { config_desc: conf_num as u8, interface_desc: Some(interface_num), alternate_setting: Some(if_desc.alternate_setting), - //TODO: do we need to set this? It fails for mice. protocol: Some(PROTOCOL_REPORT), - //TODO: dynamically create good values, fix xhcid so it does not block on each request - // This sets all reports to a duration of 4ms - report_idles: vec![(0, 1)], - ..Default::default() }) .expect("Failed to configure endpoints"); + //TODO: do we need to set protocol to report? It fails for mice. + + //TODO: dynamically create good values, fix xhcid so it does not block on each request + // This sets all reports to a duration of 4ms + reqs::set_idle(&handle, 1, 0, interface_num as u16).expect("Failed to set idle"); + let report_desc_len = hid_desc.desc_len; assert_eq!(hid_desc.desc_ty, REPORT_DESC_TY); diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index bd5b0e662a..c850f252d6 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -14,17 +14,12 @@ use thiserror::Error; pub use crate::usb::{EndpointTy, ENDP_ATTR_TY_MASK}; -pub const PROTOCOL_BOOT: u8 = 0; -pub const PROTOCOL_REPORT: u8 = 1; - #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct ConfigureEndpointsReq { /// Index into the configuration descriptors of the device descriptor. pub config_desc: u8, pub interface_desc: Option, pub alternate_setting: Option, - pub protocol: Option, - pub report_idles: Vec<(u8, u8)>, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -477,7 +472,7 @@ impl XhciClientHandle { value, index, length, - transfers_data: true, + transfers_data: !matches!(data, DeviceReqData::NoData), }; let json = serde_json::to_vec(&req)?; diff --git a/xhcid/src/usb/setup.rs b/xhcid/src/usb/setup.rs index 9a9a2ef970..879a424776 100644 --- a/xhcid/src/usb/setup.rs +++ b/xhcid/src/usb/setup.rs @@ -191,24 +191,4 @@ impl Setup { length: 0, } } - - pub const fn set_protocol(interface: u8, protocol: u8) -> Self { - Self { - kind: 0b0010_0001, - request: 0x0B, - value: protocol as u16, - index: interface as u16, - length: 0, - } - } - - pub const fn set_idle(interface: u8, report_id: u8, duration: u8) -> Self { - Self { - kind: 0b0010_0001, - request: 0x0A, - value: (report_id as u16) | ((duration as u16) << 8), - index: interface as u16, - length: 0, - } - } } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 4c2fbf92b6..3a6f3d78ac 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -465,7 +465,7 @@ impl Xhci { } // TODO: Handle event data - debug!("EVENT DATA: {:?}", event_trb.event_data()); + trace!("EVENT DATA: {:?}", event_trb.event_data()); Ok(event_trb) } @@ -500,33 +500,6 @@ impl Xhci { ).await } - async fn set_protocol( - &self, - port: usize, - interface_num: u8, - protocol: u8, - ) -> Result<()> { - debug!("Setting idle value {} (protocol {}) to port {}", interface_num, protocol, port); - self.device_req_no_data( - port, - usb::Setup::set_protocol(interface_num, protocol), - ).await - } - - async fn set_idle( - &self, - port: usize, - interface_num: u8, - report_id: u8, - duration: u8, - ) -> Result<()> { - debug!("Setting idle value {} (report_id {}, duration {}) to port {}", interface_num, report_id, duration, port); - self.device_req_no_data( - port, - usb::Setup::set_idle(interface_num, report_id, duration), - ).await - } - async fn reset_endpoint(&self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; @@ -867,14 +840,6 @@ impl Xhci { if let Some(alternate_setting) = req.alternate_setting { self.set_interface(port, interface_num, alternate_setting).await?; } - - if let Some(protocol) = req.protocol { - self.set_protocol(port, interface_num, protocol).await?; - } - - for (report_id, duration) in req.report_idles { - self.set_idle(port, interface_num, report_id, duration).await?; - } } Ok(()) @@ -1267,12 +1232,17 @@ impl Xhci { // TODO: Reuse buffers, or something. // TODO: Validate the size. // TODO: Sizes above 65536, *perhaps*. - let data_buffer = unsafe { self.alloc_dma_zeroed_unsized(req.length as usize)? }; - assert_eq!(data_buffer.len(), req.length as usize); + let data_buffer_opt = if req.transfers_data { + let data_buffer = unsafe { self.alloc_dma_zeroed_unsized(req.length as usize)? }; + assert_eq!(data_buffer.len(), req.length as usize); + Some(data_buffer) + } else { + None + }; Ok(match transfer_kind { - TransferKind::In => PortReqState::WaitingForDeviceBytes(data_buffer, setup), - TransferKind::Out => PortReqState::WaitingForHostBytes(data_buffer, setup), + TransferKind::In => PortReqState::WaitingForDeviceBytes(data_buffer_opt.ok_or(Error::new(EINVAL))?, setup), + TransferKind::Out => PortReqState::WaitingForHostBytes(data_buffer_opt.ok_or(Error::new(EINVAL))?, setup), TransferKind::NoData => PortReqState::TmpSetup(setup), _ => unreachable!(), }) From f3dc1e0c7e279990554f2d1cdb9e66b9c920100f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 21:26:47 -0600 Subject: [PATCH 0867/1301] xhcid: add hub descriptor and do not return error if driver not found --- xhcid/src/usb/hub.rs | 14 ++++++++++++++ xhcid/src/usb/mod.rs | 23 +++++++++++++---------- xhcid/src/xhci/mod.rs | 1 - 3 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 xhcid/src/usb/hub.rs diff --git a/xhcid/src/usb/hub.rs b/xhcid/src/usb/hub.rs new file mode 100644 index 0000000000..227c075d04 --- /dev/null +++ b/xhcid/src/usb/hub.rs @@ -0,0 +1,14 @@ + +#[repr(packed)] +#[derive(Clone, Copy, Debug)] +pub struct HubDescriptor { + pub length: u8, + pub kind: u8, + pub ports: u8, + pub characteristics: u16, + pub power_on_good: u8, + pub current: u8, + // device_removable: bitmap of ports, maximum of 256 bits (32 bytes) + // power_control_mask: bitmap of ports, maximum of 256 bits (32 bytes) + bitmaps: [u8; 64] +} diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 14af518556..989f26b09a 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -5,24 +5,26 @@ pub use self::endpoint::{ EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK, }; +pub use self::hub::HubDescriptor; pub use self::interface::InterfaceDescriptor; pub use self::setup::Setup; #[derive(Clone, Copy, Debug)] #[repr(u8)] pub enum DescriptorKind { - None, - Device, - Configuration, - String, - Interface, - Endpoint, - DeviceQualifier, - OtherSpeedConfiguration, - InterfacePower, - OnTheGo, + None = 0, + Device = 1, + Configuration = 2, + String = 3, + Interface = 4, + Endpoint = 5, + DeviceQualifier = 6, + OtherSpeedConfiguration = 7, + InterfacePower = 8, + OnTheGo = 9, BinaryObjectStorage = 15, Hid = 33, + Hub = 41, SuperSpeedCompanion = 48, } @@ -30,5 +32,6 @@ pub(crate) mod bos; pub(crate) mod config; pub(crate) mod device; pub(crate) mod endpoint; +pub(crate) mod hub; pub(crate) mod interface; pub(crate) mod setup; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index e32f8af2a6..f6c11b9198 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -847,7 +847,6 @@ impl Xhci { self.drivers.insert(port, process); } else { warn!("No driver for USB class {}.{}", ifdesc.class, ifdesc.sub_class); - return Err(Error::new(ENOENT)); } } From 68d838650a64839b2cf6e9f86c334e53e8efdbfb Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 16 Apr 2024 21:44:37 -0600 Subject: [PATCH 0868/1301] Init usbhubd --- Cargo.lock | 10 ++++ Cargo.toml | 1 + usbhubd/.gitignore | 1 + usbhubd/Cargo.toml | 13 +++++ usbhubd/src/main.rs | 132 +++++++++++++++++++++++++++++++++++++++++++ xhcid/drivers.toml | 6 ++ xhcid/src/lib.rs | 4 +- xhcid/src/usb/hub.rs | 17 +++++- 8 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 usbhubd/.gitignore create mode 100644 usbhubd/Cargo.toml create mode 100644 usbhubd/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 1c8f413c60..56c5b23ca3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1534,6 +1534,16 @@ dependencies = [ "xhcid", ] +[[package]] +name = "usbhubd" +version = "0.1.0" +dependencies = [ + "log", + "redox-log", + "redox_syscall 0.5.1", + "xhcid", +] + [[package]] name = "usbscsid" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index ec66f52ad5..65715466f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "vboxd", "xhcid", "usbctl", + "usbhubd", "usbhidd", "inputd", "virtio-core", diff --git a/usbhubd/.gitignore b/usbhubd/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/usbhubd/.gitignore @@ -0,0 +1 @@ +/target diff --git a/usbhubd/Cargo.toml b/usbhubd/Cargo.toml new file mode 100644 index 0000000000..abc8eb8abc --- /dev/null +++ b/usbhubd/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "usbhubd" +version = "0.1.0" +edition = "2018" +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "0.4" +redox-log = "0.1" +redox_syscall = "0.5" +xhcid = { path = "../xhcid" } diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs new file mode 100644 index 0000000000..7c95cb6b5d --- /dev/null +++ b/usbhubd/src/main.rs @@ -0,0 +1,132 @@ +use std::collections::VecDeque; +use std::env; +use std::fs::File; +use std::io::{Read, Write}; + +use redox_log::{OutputBuilder, RedoxLogger}; +use xhcid_interface::{plain, usb, ConfigureEndpointsReq, DevDesc, DeviceReqData, EndpDirection, EndpointTy, PortReqRecipient, PortReqTy, XhciClientHandle}; + +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new().with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("usb", "device", "hub.log") { + Ok(b) => { + logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build(), + ) + } + Err(error) => eprintln!("Failed to create hub.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("usb", "device", "hub.ansi.log") { + Ok(b) => { + logger = logger.with_output( + b.with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ) + } + Err(error) => eprintln!("Failed to create hub.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("usbhubd: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("usbhubd: failed to set default logger: {}", error); + None + } + } +} + +fn main() { + let _logger_ref = setup_logging(); + + let mut args = env::args().skip(1); + + const USAGE: &'static str = "usbhubd "; + + let scheme = args.next().expect(USAGE); + let port = args + .next() + .expect(USAGE) + .parse::() + .expect("Expected integer as input of port"); + let interface_num = args + .next() + .expect(USAGE) + .parse::() + .expect("Expected integer as input of interface"); + + log::info!( + "USB HUB driver spawned with scheme `{}`, port {}, interface {}", + scheme, + port, + interface_num + ); + + let handle = XhciClientHandle::new(scheme, port); + let desc: DevDesc = handle + .get_standard_descs() + .expect("Failed to get standard descriptors"); + log::info!("{:X?}", desc); + + let (conf_desc, conf_num, if_desc) = desc + .config_descs + .iter() + .enumerate() + .find_map(|(conf_num, conf_desc)| { + let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { + if if_desc.number == interface_num { + Some(if_desc.clone()) + } else { + None + } + })?; + Some(( + conf_desc.clone(), + conf_num, + if_desc, + )) + }) + .expect("Failed to find suitable configuration"); + + /*TODO + handle + .configure_endpoints(&ConfigureEndpointsReq { + config_desc: conf_num as u8, + interface_desc: Some(interface_num), + alternate_setting: Some(if_desc.alternate_setting), + }) + .expect("Failed to configure endpoints"); + */ + + let mut hub_desc = usb::HubDescriptor::default(); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Device, + 0x6, + 0, + //TODO: should this be an index into interface_descs? + interface_num as u16, + DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), + ) + .expect("Failed to retrieve hub descriptor"); + + log::info!("{:X?}", hub_desc); +} diff --git a/xhcid/drivers.toml b/xhcid/drivers.toml index 8c154af55a..8b28dbd8d4 100644 --- a/xhcid/drivers.toml +++ b/xhcid/drivers.toml @@ -4,6 +4,12 @@ class = 8 # Mass Storage class subclass = 6 # SCSI transparent command set command = ["/bin/usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"] +[[drivers]] +name = "USB HUB" +class = 9 # HUB class +subclass = -1 +command = ["/bin/usbhubd", "$SCHEME", "$PORT", "$IF_NUM"] + [[drivers]] name = "USB HID" class = 3 # HID class diff --git a/xhcid/src/lib.rs b/xhcid/src/lib.rs index e5e4b806ab..16b3d91b64 100644 --- a/xhcid/src/lib.rs +++ b/xhcid/src/lib.rs @@ -1,4 +1,6 @@ +pub extern crate plain; + mod driver_interface; -mod usb; +pub mod usb; pub use driver_interface::*; diff --git a/xhcid/src/usb/hub.rs b/xhcid/src/usb/hub.rs index 227c075d04..b81d86a74b 100644 --- a/xhcid/src/usb/hub.rs +++ b/xhcid/src/usb/hub.rs @@ -1,4 +1,3 @@ - #[repr(packed)] #[derive(Clone, Copy, Debug)] pub struct HubDescriptor { @@ -12,3 +11,19 @@ pub struct HubDescriptor { // power_control_mask: bitmap of ports, maximum of 256 bits (32 bytes) bitmaps: [u8; 64] } + +unsafe impl plain::Plain for HubDescriptor {} + +impl Default for HubDescriptor { + fn default() -> Self { + Self { + length: 0, + kind: 0, + ports: 0, + characteristics: 0, + power_on_good: 0, + current: 0, + bitmaps: [0; 64] + } + } +} From 9ec71c6ba49eaee5f3fc4c9fab1395eff3f22550 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 17 Apr 2024 08:51:02 -0600 Subject: [PATCH 0869/1301] xhcid/usbhidd: build out USB HUB driver --- usbhubd/src/main.rs | 51 ++++++++++++++++++++++++++++++++++++++++-- xhcid/src/usb/hub.rs | 48 +++++++++++++++++++++++++++++++++++++++ xhcid/src/usb/mod.rs | 4 ++-- xhcid/src/usb/setup.rs | 15 +++++++++++++ 4 files changed, 114 insertions(+), 4 deletions(-) diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index 7c95cb6b5d..21cccadd14 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -120,13 +120,60 @@ fn main() { .device_request( PortReqTy::Class, PortReqRecipient::Device, - 0x6, + usb::SetupReq::GetDescriptor as u8, 0, //TODO: should this be an index into interface_descs? interface_num as u16, DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), ) .expect("Failed to retrieve hub descriptor"); - log::info!("{:X?}", hub_desc); + + for port in 1..=hub_desc.ports { + log::info!("power on port {port}"); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Other, + usb::SetupReq::SetFeature as u8, + usb::HubFeature::PortPower as u16, + port as u16, + DeviceReqData::NoData, + ) + .expect("Failed to set port power"); + } + + for port in 1..=hub_desc.ports { + let mut port_sts = usb::HubPortStatus::default(); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Other, + usb::SetupReq::GetStatus as u8, + 0, + port as u16, + DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut port_sts) }), + ) + .expect("Failed to retrieve port status"); + log::info!("port {} status {:X?}", port, port_sts); + + if port_sts.contains(usb::HubPortStatus::CONNECTION) { + /*TODO + log::info!("reset port {port}"); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Other, + usb::SetupReq::SetFeature as u8, + usb::HubFeature::PortReset as u16, + port as u16, + DeviceReqData::NoData, + ) + .expect("Failed to set port enable"); + */ + //TODO: address device + } + } + + //TODO: read interrupt port for changes } diff --git a/xhcid/src/usb/hub.rs b/xhcid/src/usb/hub.rs index b81d86a74b..854ff30a74 100644 --- a/xhcid/src/usb/hub.rs +++ b/xhcid/src/usb/hub.rs @@ -27,3 +27,51 @@ impl Default for HubDescriptor { } } } + +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +pub enum HubFeature { + //TODO: CHubLocalPower = 0, + //TODO: CHubOverCurrent = 1, + PortConnection = 0, + PortEnable = 1, + PortSuspend = 2, + PortOverCurrent = 3, + PortReset = 4, + PortPower = 8, + PortLowSpeed = 9, + CPortConnection = 16, + CPortEnable = 17, + CPortSuspend = 18, + CPortOverCurrent = 19, + CPortReset = 20, + PortTest = 21, + PortIndicator = 22, +} + +bitflags::bitflags! { + #[derive(Default)] + #[repr(transparent)] + pub struct HubPortStatus: u32 { + const CONNECTION = 1 << 0; + const ENABLE = 1 << 1; + const SUSPEND = 1 << 2; + const OVER_CURRENT = 1 << 3; + const RESET = 1 << 4; + // bits 5-7 reserved + const POWER = 1 << 8; + const LOW_SPEED = 1 << 9; + const HIGH_SPEED = 1 << 10; + const TEST = 1 << 11; + const INDICATOR = 1 << 12; + // bits 13-15 reserved + const CONNECTION_CHANGED = 1 << 16; + const ENABLE_CHANGED = 1 << 17; + const SUSPEND_CHANGED = 1 << 18; + const OVER_CURRENT_CHANGED = 1 << 19; + const RESET_CHANGED = 1 << 20; + // bits 21 - 31 reserved + } +} + +unsafe impl plain::Plain for HubPortStatus {} diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 989f26b09a..246cc77f8b 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -5,9 +5,9 @@ pub use self::endpoint::{ EndpointDescriptor, EndpointTy, HidDescriptor, SuperSpeedCompanionDescriptor, SuperSpeedPlusIsochCmpDescriptor, ENDP_ATTR_TY_MASK, }; -pub use self::hub::HubDescriptor; +pub use self::hub::*; pub use self::interface::InterfaceDescriptor; -pub use self::setup::Setup; +pub use self::setup::{Setup, SetupReq}; #[derive(Clone, Copy, Debug)] #[repr(u8)] diff --git a/xhcid/src/usb/setup.rs b/xhcid/src/usb/setup.rs index 879a424776..aa430e2363 100644 --- a/xhcid/src/usb/setup.rs +++ b/xhcid/src/usb/setup.rs @@ -71,6 +71,21 @@ impl From for ReqRecipient { } } +#[repr(u8)] +pub enum SetupReq { + GetStatus = 0x00, + ClearFeature = 0x01, + SetFeature = 0x03, + SetAddress = 0x05, + GetDescriptor = 0x06, + SetDescriptor = 0x07, + GetConfiguration = 0x08, + SetConfiguration = 0x09, + GetInterface = 0x0A, + SetInterface = 0x0B, + SynchFrame = 0x0C, +} + pub const USB_SETUP_DIR_BIT: u8 = 1 << 7; pub const USB_SETUP_DIR_SHIFT: u8 = 7; pub const USB_SETUP_REQ_TY_MASK: u8 = 0x60; From fd973a1d7dd98ba16f53a7af6f9173fac935d820 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 17 Apr 2024 09:24:28 -0600 Subject: [PATCH 0870/1301] xhcid: allow configuring multiple interfaces --- xhcid/src/xhci/mod.rs | 21 ++++++++++-- xhcid/src/xhci/scheme.rs | 74 +++++++++++++--------------------------- 2 files changed, 43 insertions(+), 52 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index f6c11b9198..d88a87c7be 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -215,12 +215,30 @@ unsafe impl Sync for Xhci {} struct PortState { slot: u8, cfg_idx: Option, - if_idx: Option, input_context: Mutex>, dev_desc: Option, endpoint_states: BTreeMap, } +impl PortState { + //TODO: fetch using endpoint number instead + fn get_endp_desc(&self, endp_idx: u8) -> Option<&EndpDesc> { + let cfg_idx = self.cfg_idx?; + let config_desc = self.dev_desc.as_ref()? + .config_descs.get(cfg_idx as usize)?; + let mut endp_count = 0; + for if_desc in config_desc.interface_descs.iter() { + for endp_desc in if_desc.endpoints.iter() { + if endp_idx == endp_count { + return Some(endp_desc); + } + endp_count += 1; + } + } + None + } +} + pub(crate) enum RingOrStreams { Ring(Ring), Streams(StreamContextArray), @@ -546,7 +564,6 @@ impl Xhci { input_context: Mutex::new(input), dev_desc: None, cfg_idx: None, - if_idx: None, endpoint_states: std::iter::once(( 0, EndpointState { diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 3a6f3d78ac..d3dec98d5a 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -375,19 +375,10 @@ impl Xhci { let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?; let mut port_state = self.port_state_mut(port_num)?; - let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { - (Some(c), Some(i)) => (c, i), - _ => return Err(Error::new(EIO)), - }; - let slot = port_state.slot; let (doorbell_data_stream, doorbell_data_no_stream) = { - let endp_desc = port_state - .dev_desc.as_ref().unwrap() - .config_descs.get(usize::from(cfg_idx)).ok_or(Error::new(EIO))? - .interface_descs.get(usize::from(if_idx)).ok_or(Error::new(EIO))? - .endpoints.get(usize::from(endp_idx)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?; //TODO: clean this up ( @@ -501,14 +492,10 @@ impl Xhci { } async fn reset_endpoint(&self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { + let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?; let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; - let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { - (Some(c), Some(i)) => (c, i), - _ => return Err(Error::new(EIO)), - }; - - let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); let slot = self @@ -619,23 +606,31 @@ impl Xhci { let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; port_state.cfg_idx = Some(req.config_desc); - port_state.if_idx = Some(req.interface_desc.unwrap_or(0)); let config_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; - let endpoints = &config_desc.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; + //TODO: USE ENDPOINTS FROM ALL INTERFACES + let mut endp_desc_count = 0; + let mut new_context_entries = 1; + for if_desc in config_desc.interface_descs.iter() { + for endpoint in if_desc.endpoints.iter() { + endp_desc_count += 1; + let entry = Self::endp_num_to_dci(endp_desc_count, endpoint); + if entry > new_context_entries { + new_context_entries = entry; + } + } + } + new_context_entries += 1; - if endpoints.len() >= 31 { - warn!("endpoints length {} >= 31", endpoints.len()); + if endp_desc_count >= 31 { + warn!("endpoints length {} >= 31", endp_desc_count); return Err(Error::new(EIO)); } ( - endpoints.len(), - (match endpoints.last() { - Some(l) => Self::endp_num_to_dci(endpoints.len() as u8, l), - None => 1, - }) + 1, + endp_desc_count, + new_context_entries, config_desc.configuration_value, ) }; @@ -683,8 +678,7 @@ impl Xhci { let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; let dev_desc = port_state.dev_desc.as_ref().unwrap(); - let endpoints = &dev_desc.config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?.interface_descs.get(usize::from(req.interface_desc.unwrap_or(0))).ok_or(Error::new(EBADFD))?.endpoints; - let endp_desc = endpoints.get(endp_idx as usize).ok_or_else(|| { + let endp_desc = port_state.get_endp_desc(endp_idx).ok_or_else(|| { warn!("failed to find endpoint {}", endp_idx); Error::new(EIO) })?; @@ -922,23 +916,7 @@ impl Xhci { .get_mut(&port_num) .ok_or(Error::new(EBADFD))?; - let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { - (Some(c), Some(i)) => (c, i), - _ => return Err(Error::new(EIO)), - }; - - let endp_desc: &EndpDesc = port_state - .dev_desc - .as_ref().unwrap() - .config_descs - .get(usize::from(cfg_idx)) - .ok_or(Error::new(EIO))? - .interface_descs - .get(usize::from(if_idx)) - .ok_or(Error::new(EIO))? - .endpoints - .get(endp_idx as usize) - .ok_or(Error::new(EBADFD))?; + let endp_desc: &EndpDesc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?; let direction = endp_desc.direction(); @@ -1856,15 +1834,11 @@ impl Xhci { endp_num: u8, deque_ptr_and_cycle: u64, ) -> Result<()> { + let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?; let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; let slot = port_state.slot; - let (cfg_idx, if_idx) = match (port_state.cfg_idx, port_state.if_idx) { - (Some(c), Some(i)) => (c, i), - _ => return Err(Error::new(EIO)), - }; - - let endp_desc = port_state.dev_desc.as_ref().unwrap().config_descs[usize::from(cfg_idx)].interface_descs[usize::from(if_idx)].endpoints.get(usize::from(endp_num)).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); let (event_trb, command_trb) = self.execute_command(|trb, cycle| { From 8caf28793ef9fb3680c7a999ad1af752bfbd45a3 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 1 May 2024 13:29:21 -0600 Subject: [PATCH 0871/1301] Implement USB HID scroll --- usbhidd/src/main.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 921de656ae..5e338cfcbe 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -351,6 +351,7 @@ fn main() { let mut mouse_pos = last_mouse_pos; let mut mouse_dx = 0i32; let mut mouse_dy = 0i32; + let mut scroll_y = 0i32; let mut buttons = last_buttons; for event in handler .handle(&report_buffer) @@ -370,6 +371,13 @@ fn main() { } else { mouse_pos.1 = event.value; } + } else if event.usage == GenericDesktopUsage::Wheel as u32 { + //TODO: what is X scroll? + if event.relative { + scroll_y += event.value; + } else { + log::warn!("absolute mouse wheel not supported"); + } } else { log::info!( "unsupported generic desktop usage 0x{:X}:0x{:X} value {}", @@ -452,6 +460,20 @@ fn main() { } } + if scroll_y != 0 { + let scroll_event = orbclient::event::ScrollEvent { + x: 0, + y: scroll_y, + }; + + match display.write(&scroll_event.to_event()) { + Ok(_) => (), + Err(err) => { + log::warn!("failed to send scroll event to orbital: {}", err); + } + } + } + if buttons != last_buttons { last_buttons = buttons; From 67df958d11b0d7ece1c729c76da90cf0bdbd15d4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 11 May 2024 14:11:58 -0600 Subject: [PATCH 0872/1301] Update to new nightly --- rust-toolchain.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5d56faf9ae..46893dd3f4 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,3 @@ [toolchain] -channel = "nightly" +channel = "nightly-2024-05-11" +components = ["rust-src"] From ccfe5ece204a03f134328535bb771a2b12262585 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 11 May 2024 14:16:02 -0600 Subject: [PATCH 0873/1301] Update feature required for aarch64 yield --- storage/nvmed/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 5b05e82cd0..3ca9b0e22c 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -1,4 +1,4 @@ -#![cfg_attr(target_arch = "aarch64", feature(stdsimd))] // Required for yield instruction +#![cfg_attr(target_arch = "aarch64", feature(stdarch_arm_hints))] // Required for yield instruction #![feature(int_roundings)] use std::convert::TryInto; From 020a3ef63101fc85b01e6f35e2c4cb8045412e31 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:38:34 +0200 Subject: [PATCH 0874/1301] pcid: Update to pci_types 0.9.0 --- Cargo.lock | 4 ++-- pcid/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 56c5b23ca3..d84e864362 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -907,9 +907,9 @@ checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" [[package]] name = "pci_types" -version = "0.6.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebac2b2ee11791f721a51184b632a916b3044f2ee7b2374e7fdcfdf3eaf29c79" +checksum = "6f966dfb3dde50a726cc62ae44dc48efd10a211db15296c00cd88550ad8ef24c" dependencies = [ "bit_field", "bitflags 2.5.0", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 17d8061c36..705daf00fa 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -20,7 +20,7 @@ fdt = { git = "https://gitlab.redox-os.org/rosehuds/fdt.git" } libc = "0.2" log = "0.4" paw = "1.0" -pci_types = "0.6.1" +pci_types = "0.9.0" plain = "0.2" redox-log = "0.1" redox_syscall = "0.5" From 38a729bc76e2e7613ccd2b0d765218eeef83535f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:39:39 +0200 Subject: [PATCH 0875/1301] Handle some stabilized rustc features --- pcid/src/main.rs | 3 --- storage/virtio-blkd/src/main.rs | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index e2915272cb..56f78191bf 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,6 +1,3 @@ -// Already stabilized, TODO: remove when Redox's rustc is updated -#![feature(result_option_inspect)] - use std::fs::{File, metadata, read_dir}; use std::io::prelude::*; use std::os::unix::io::{FromRawFd, RawFd}; diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 8c5313c8b6..1c13166341 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -1,5 +1,5 @@ #![deny(trivial_numeric_casts, unused_allocation)] -#![feature(int_roundings, async_fn_in_trait)] +#![feature(int_roundings)] // TODO(andypython): driver panic with an empty disk. From 785f53c70c418eb9f11ca1e9bcd655b17dcd3d63 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:41:59 +0200 Subject: [PATCH 0876/1301] pcid: Stop explicitly passing PciAddress to several functions The PciHeader/PciEndpointHeader argument already contains the PciAddress. --- pcid/src/main.rs | 25 ++++++++++--------------- pcid/src/pci_header.rs | 12 ++++++++++++ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 56f78191bf..984c108ad1 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -209,9 +209,9 @@ pub struct State { pcie: Pcie, } -fn print_pci_function(addr: PciAddress, header: &PciHeader) { +fn print_pci_function(header: &PciHeader) { let mut string = format!("PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", - addr, header.vendor_id(), header.device_id(), header.class(), + header.address(), header.vendor_id(), header.device_id(), header.class(), header.subclass(), header.interface(), header.revision(), header.class()); let device_type = DeviceType::from((header.class(), header.subclass())); match device_type { @@ -234,7 +234,7 @@ fn print_pci_function(addr: PciAddress, header: &PciHeader) { info!("{}", string); } -fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, header: PciEndpointHeader) { +fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointHeader) { for driver in config.drivers.iter() { if !driver.match_function(header.full_device_id()) { continue; @@ -270,14 +270,14 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he let interrupt_pin; unsafe { - let mut data = state.pcie.read(addr, 0x3C); + let mut data = state.pcie.read(header.address(), 0x3C); irq = (data & 0xFF) as u8; interrupt_pin = ((data & 0x0000_FF00) >> 8) as u8; if irq == 0xFF { irq = 9; } data = (data & 0xFFFFFF00) | irq as u32; - state.pcie.write(addr, 0x3C, data); + state.pcie.write(header.address(), 0x3C, data); }; let legacy_interrupt_enabled = match interrupt_pin { @@ -293,7 +293,7 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { let func = PciFunc { pci: &state.pcie, - addr + addr: header.address(), }; crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() } else { @@ -303,7 +303,7 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he let func = driver_interface::PciFunction { bars, - addr, + addr: header.address(), legacy_interrupt_line: if legacy_interrupt_enabled { Some(LegacyInterruptLine(irq)) } else { @@ -353,7 +353,7 @@ fn handle_parsed_header(state: Arc, config: &Config, addr: PciAddress, he match command.envs(envs).spawn() { Ok(mut child) => { let driver_handler = DriverHandler { - addr, + addr: header.address(), state: Arc::clone(&state), capabilities, }; @@ -472,15 +472,10 @@ fn main(args: Args) { let func_addr = PciAddress::new(0, bus_num, dev_num, func_num); match PciHeader::from_reader(&state.pcie, func_addr) { Ok(header) => { - print_pci_function(func_addr, &header); + print_pci_function(&header); match header { PciHeader::General(endpoint_header) => { - handle_parsed_header( - Arc::clone(&state), - &config, - func_addr, - endpoint_header, - ); + handle_parsed_header(Arc::clone(&state), &config, endpoint_header); } PciHeader::PciToPci { secondary_bus_num, .. diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 2b3a64e4c5..1b884b7849 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -112,6 +112,14 @@ impl PciHeader { } } + /// Return the PCI address. + pub fn address(&self) -> PciAddress { + match self { + PciHeader::General(header) => header.address(), + PciHeader::PciToPci { shared, .. } => shared.addr, + } + } + /// Return the Vendor ID field. pub fn vendor_id(&self) -> u16 { self.full_device_id().vendor_id @@ -144,6 +152,10 @@ impl PciHeader { } impl PciEndpointHeader { + pub fn address(&self) -> PciAddress { + self.shared.addr + } + pub fn endpoint_header(&self, access: &impl ConfigRegionAccess) -> EndpointHeader { EndpointHeader::from_header(TyPciHeader::new(self.shared.addr), access).unwrap() } From 6825d9b2ba2bb7820edbe8db07091b21842edbc0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 13:57:35 +0200 Subject: [PATCH 0877/1301] pcid: Remove support for connecting to non-default server --- pcid/src/driver_interface/mod.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 0595fee914..4949a748c2 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -255,17 +255,14 @@ pub(crate) fn recv(r: &mut R) -> Result { } impl PcidServerHandle { - pub fn connect(pcid_to_client: RawFd, pcid_from_client: RawFd) -> Result { - Ok(Self { - pcid_to_client: unsafe { File::from_raw_fd(pcid_to_client) }, - pcid_from_client: unsafe { File::from_raw_fd(pcid_from_client) }, - }) - } pub fn connect_default() -> Result { let pcid_to_client_fd = env::var("PCID_TO_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; let pcid_from_client_fd = env::var("PCID_FROM_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; - Self::connect(pcid_to_client_fd, pcid_from_client_fd) + Ok(Self { + pcid_to_client: unsafe { File::from_raw_fd(pcid_to_client_fd) }, + pcid_from_client: unsafe { File::from_raw_fd(pcid_from_client_fd) }, + }) } pub(crate) fn send(&mut self, req: &PcidClientRequest) -> Result<()> { send(&mut self.pcid_from_client, req) From 3737a70cc15fc4af700605206da80362fddfaf55 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 14:00:30 +0200 Subject: [PATCH 0878/1301] pcid: Reduce visibility of server handle send/recv --- pcid/src/driver_interface/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 4949a748c2..aa03a9d587 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -264,10 +264,10 @@ impl PcidServerHandle { pcid_from_client: unsafe { File::from_raw_fd(pcid_from_client_fd) }, }) } - pub(crate) fn send(&mut self, req: &PcidClientRequest) -> Result<()> { + fn send(&mut self, req: &PcidClientRequest) -> Result<()> { send(&mut self.pcid_from_client, req) } - pub(crate) fn recv(&mut self) -> Result { + fn recv(&mut self) -> Result { recv(&mut self.pcid_to_client) } pub fn fetch_config(&mut self) -> Result { From 7ddae5fa03f7babf8aa301007390f90804660525 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 14:03:32 +0200 Subject: [PATCH 0879/1301] pcid: Add fixme --- pcid/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 984c108ad1..4d0cf1e94f 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -269,6 +269,7 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH let mut irq; let interrupt_pin; + // FIXME use pci_types' update_interrupt once it is released to crates.io unsafe { let mut data = state.pcie.read(header.address(), 0x3C); irq = (data & 0xFF) as u8; From 4b384066f2408c05345986739a648e8064b0c7aa Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 15:05:47 +0200 Subject: [PATCH 0880/1301] Use pci_types for setting the interrupt line --- Cargo.lock | 4 ++-- pcid/Cargo.toml | 2 +- pcid/src/main.rs | 23 ++++++++++------------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d84e864362..9ce5ed9fb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -907,9 +907,9 @@ checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" [[package]] name = "pci_types" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f966dfb3dde50a726cc62ae44dc48efd10a211db15296c00cd88550ad8ef24c" +checksum = "d6848549f754bd20aa382ffec0f4f04ba50e55a18ff75a0862bf9e227fe42b57" dependencies = [ "bit_field", "bitflags 2.5.0", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 705daf00fa..864e9a0598 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -20,7 +20,7 @@ fdt = { git = "https://gitlab.redox-os.org/rosehuds/fdt.git" } libc = "0.2" log = "0.4" paw = "1.0" -pci_types = "0.9.0" +pci_types = "0.9.1" plain = "0.2" redox-log = "0.1" redox_syscall = "0.5" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 4d0cf1e94f..9e674fd437 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -256,7 +256,7 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH info!(" BAR{}", string); } - let endpoint_header = header.endpoint_header(&state.pcie); + let mut endpoint_header = header.endpoint_header(&state.pcie); // Enable bus mastering, memory space, and I/O space endpoint_header.update_command(&state.pcie, |cmd| { @@ -266,20 +266,17 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH }); // Set IRQ line to 9 if not set - let mut irq; - let interrupt_pin; + let mut irq = 0xFF; + let mut interrupt_pin = 0xFF; - // FIXME use pci_types' update_interrupt once it is released to crates.io - unsafe { - let mut data = state.pcie.read(header.address(), 0x3C); - irq = (data & 0xFF) as u8; - interrupt_pin = ((data & 0x0000_FF00) >> 8) as u8; - if irq == 0xFF { - irq = 9; + endpoint_header.update_interrupt(&state.pcie, |(pin, mut line)| { + if line == 0xFF { + line = 9; } - data = (data & 0xFFFFFF00) | irq as u32; - state.pcie.write(header.address(), 0x3C, data); - }; + irq = line; + interrupt_pin = pin; + (pin, line) + }); let legacy_interrupt_enabled = match interrupt_pin { 0 => false, From ba6b91d561802ed7275ea825ba86718cb0f0a9d3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 16:46:59 +0200 Subject: [PATCH 0881/1301] pcid: Move print_pci_function to a PciHeader method --- pcid/src/main.rs | 28 +--------------------------- pcid/src/pci_header.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 27 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 9e674fd437..08f8eb09a6 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -5,7 +5,6 @@ use std::process::Command; use std::thread; use std::sync::{Arc, Mutex}; -use pci_types::device_type::DeviceType; use pci_types::{CommandRegister, ConfigRegionAccess, PciAddress}; use structopt::StructOpt; use log::{debug, error, info, warn, trace}; @@ -209,31 +208,6 @@ pub struct State { pcie: Pcie, } -fn print_pci_function(header: &PciHeader) { - let mut string = format!("PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", - header.address(), header.vendor_id(), header.device_id(), header.class(), - header.subclass(), header.interface(), header.revision(), header.class()); - let device_type = DeviceType::from((header.class(), header.subclass())); - match device_type { - DeviceType::LegacyVgaCompatible => string.push_str(" VGA CTL"), - DeviceType::IdeController => string.push_str(" IDE"), - DeviceType::SataController => match header.interface() { - 0 => string.push_str(" SATA VND"), - 1 => string.push_str(" SATA AHCI"), - _ => (), - }, - DeviceType::UsbController => match header.interface() { - 0x00 => string.push_str(" UHCI"), - 0x10 => string.push_str(" OHCI"), - 0x20 => string.push_str(" EHCI"), - 0x30 => string.push_str(" XHCI"), - _ => (), - }, - _ => (), - } - info!("{}", string); -} - fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointHeader) { for driver in config.drivers.iter() { if !driver.match_function(header.full_device_id()) { @@ -470,7 +444,7 @@ fn main(args: Args) { let func_addr = PciAddress::new(0, bus_num, dev_num, func_num); match PciHeader::from_reader(&state.pcie, func_addr) { Ok(header) => { - print_pci_function(&header); + info!("{}", header.display()); match header { PciHeader::General(endpoint_header) => { handle_parsed_header(Arc::clone(&state), &config, endpoint_header); diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 1b884b7849..343d66b466 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -1,5 +1,6 @@ use std::convert::TryInto; +use pci_types::device_type::DeviceType; use pci_types::{ Bar as TyBar, ConfigRegionAccess, EndpointHeader, HeaderType, PciAddress, PciHeader as TyPciHeader, PciPciBridgeHeader, @@ -149,6 +150,40 @@ impl PciHeader { pub fn class(&self) -> u8 { self.full_device_id().class } + + /// Format a human readable string indicating the address and type of PCI device. + pub fn display(&self) -> String { + let mut string = format!( + "PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", + self.address(), + self.vendor_id(), + self.device_id(), + self.class(), + self.subclass(), + self.interface(), + self.revision(), + self.class() + ); + let device_type = DeviceType::from((self.class(), self.subclass())); + match device_type { + DeviceType::LegacyVgaCompatible => string.push_str(" VGA CTL"), + DeviceType::IdeController => string.push_str(" IDE"), + DeviceType::SataController => match self.interface() { + 0 => string.push_str(" SATA VND"), + 1 => string.push_str(" SATA AHCI"), + _ => (), + }, + DeviceType::UsbController => match self.interface() { + 0x00 => string.push_str(" UHCI"), + 0x10 => string.push_str(" OHCI"), + 0x20 => string.push_str(" EHCI"), + 0x30 => string.push_str(" XHCI"), + _ => (), + }, + _ => (), + } + string + } } impl PciEndpointHeader { From 7f5a340c83e6453dae3673858ec05bc0ed4b5bf3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:06:33 +0200 Subject: [PATCH 0882/1301] pcid: Remove cap_pointer from PciHeader::PciToPci It is never used. --- pcid/src/pci_header.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 343d66b466..af5fcee75d 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -34,7 +34,6 @@ pub enum PciHeader { PciToPci { shared: SharedPciHeader, secondary_bus_num: u8, - cap_pointer: u8, }, } @@ -80,11 +79,9 @@ impl PciHeader { HeaderType::PciPciBridge => { let bridge_header = PciPciBridgeHeader::from_header(header, access).unwrap(); let secondary_bus_num = bridge_header.secondary_bus_number(access); - let cap_pointer = (unsafe { access.read(addr, 0x34) } & 0xff) as u8; Ok(PciHeader::PciToPci { shared, secondary_bus_num, - cap_pointer, }) } ty => Err(PciHeaderError::UnknownHeaderType(ty)), From 1593884938bf27b1a582104f3be66f393c0056a5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:12:59 +0200 Subject: [PATCH 0883/1301] pcid: Use capability_pointer method instead of a raw read --- pcid/src/pci_header.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index af5fcee75d..471f74b27c 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -1,5 +1,3 @@ -use std::convert::TryInto; - use pci_types::device_type::DeviceType; use pci_types::{ Bar as TyBar, ConfigRegionAccess, EndpointHeader, HeaderType, PciAddress, @@ -68,7 +66,10 @@ impl PciHeader { HeaderType::Endpoint => { let endpoint_header = EndpointHeader::from_header(header, access).unwrap(); let (subsystem_id, subsystem_vendor_id) = endpoint_header.subsystem(access); - let cap_pointer = (unsafe { access.read(addr, 0x34) } & 0xff) as u8; + let cap_pointer = endpoint_header + .capability_pointer(access) + .try_into() + .unwrap(); Ok(PciHeader::General(PciEndpointHeader { shared, subsystem_vendor_id, From 9d37d15827e7ef1fe3ffdc847cdcd8ca2351be89 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:14:18 +0200 Subject: [PATCH 0884/1301] pcid: Avoid duplicate read of vendor and device id --- pcid/src/pci_header.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 471f74b27c..95c960851a 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -42,12 +42,13 @@ impl PciHeader { access: &impl ConfigRegionAccess, addr: PciAddress, ) -> Result { - if unsafe { access.read(addr, 0) } == 0xffffffff { + let header = TyPciHeader::new(addr); + let (vendor_id, device_id) = header.id(access); + + if vendor_id == 0xffff && device_id == 0xffff { return Err(PciHeaderError::NoDevice); } - let header = TyPciHeader::new(addr); - let (vendor_id, device_id) = header.id(access); let (revision, class, subclass, interface) = header.revision_and_class(access); let header_type = header.header_type(access); let shared = SharedPciHeader { From 9aed7d560e8f760452f93141c217408dc0f4c682 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:21:50 +0200 Subject: [PATCH 0885/1301] pcid: Merge CapabilityOffsetsIter into CapabilitiesIter --- pcid/src/main.rs | 2 +- pcid/src/pci/cap.rs | 36 +++++++++++++----------------------- 2 files changed, 14 insertions(+), 24 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 08f8eb09a6..7e852bb982 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -267,7 +267,7 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH pci: &state.pcie, addr: header.address(), }; - crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::>() + crate::pci::cap::CapabilitiesIter::new(header.cap_pointer(), &func).collect::>() } else { Vec::new() }; diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 5e852a528f..41e480a71c 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -1,11 +1,11 @@ use super::func::ConfigReader; use serde::{Serialize, Deserialize}; -pub struct CapabilityOffsetsIter<'a, R> { +pub struct CapabilitiesIter<'a, R> { offset: u8, reader: &'a R, } -impl<'a, R> CapabilityOffsetsIter<'a, R> { +impl<'a, R> CapabilitiesIter<'a, R> { pub fn new(offset: u8, reader: &'a R) -> Self { Self { offset, @@ -13,14 +13,14 @@ impl<'a, R> CapabilityOffsetsIter<'a, R> { } } } -impl<'a, R> Iterator for CapabilityOffsetsIter<'a, R> +impl<'a, R> Iterator for CapabilitiesIter<'a, R> where R: ConfigReader { - type Item = u8; + type Item = (u8, Capability); fn next(&mut self) -> Option { - unsafe { + let offset = unsafe { // mask RsvdP bits self.offset = self.offset & 0xFC; @@ -32,8 +32,14 @@ where let offset = self.offset; self.offset = next; - Some(offset) - } + offset + }; + + let cap = unsafe { + Capability::parse(self.reader, offset) + }; + + Some((offset, cap)) } } @@ -229,19 +235,3 @@ impl Capability { } } } - -pub struct CapabilitiesIter<'a, R> { - pub inner: CapabilityOffsetsIter<'a, R>, -} - -impl<'a, R> Iterator for CapabilitiesIter<'a, R> -where - R: ConfigReader -{ - type Item = (u8, Capability); - - fn next(&mut self) -> Option { - let offset = self.inner.next()?; - Some((offset, unsafe { Capability::parse(self.inner.reader, offset) })) - } -} From d70cf080bb8e02fa867549083e73fd8e4a9fac6e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:40:03 +0200 Subject: [PATCH 0886/1301] pcid: Remove with_pci_func_raw --- pcid/src/main.rs | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 7e852bb982..18a64f2060 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -5,7 +5,7 @@ use std::process::Command; use std::thread; use std::sync::{Arc, Mutex}; -use pci_types::{CommandRegister, ConfigRegionAccess, PciAddress}; +use pci_types::{CommandRegister, PciAddress}; use structopt::StructOpt; use log::{debug, error, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; @@ -42,18 +42,17 @@ pub struct DriverHandler { state: Arc, } -fn with_pci_func_raw T>(pci: &dyn ConfigRegionAccess, addr: PciAddress, function: F) -> T { - let func = PciFunc { - pci, - addr, - }; - function(&func) -} + impl DriverHandler { fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse { use driver_interface::*; use crate::pci::cap::{MsiCapability, MsixCapability}; + let func = PciFunc { + pci: &self.state.pcie, + addr: self.addr, + }; + match request { PcidClientRequest::RequestCapabilities => { PcidClientResponse::Capabilities(self.capabilities.iter().map(|(_, capability)| capability.clone()).collect::>()) @@ -75,10 +74,8 @@ impl DriverHandler { None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), }; unsafe { - with_pci_func_raw(&self.state.pcie, self.addr, |func| { - capability.set_enabled(true); - capability.write_message_control(func, offset); - }); + capability.set_enabled(true); + capability.write_message_control(&func, offset); } PcidClientResponse::FeatureEnabled(feature) } @@ -88,10 +85,8 @@ impl DriverHandler { None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), }; unsafe { - with_pci_func_raw(&self.state.pcie, self.addr, |func| { - capability.set_msix_enabled(true); - capability.write_a(func, offset); - }); + capability.set_msix_enabled(true); + capability.write_a(&func, offset); } PcidClientResponse::FeatureEnabled(feature) } @@ -150,9 +145,7 @@ impl DriverHandler { info.set_mask_bits(mask_bits); } unsafe { - with_pci_func_raw(&self.state.pcie, self.addr, |func| { - info.write_all(func, offset); - }); + info.write_all(&func, offset); } PcidClientResponse::SetFeatureInfo(PciFeature::Msi) } else { @@ -162,9 +155,7 @@ impl DriverHandler { if let Some(mask) = function_mask { info.set_function_mask(mask); unsafe { - with_pci_func_raw(&self.state.pcie, self.addr, |func| { - info.write_a(func, offset); - }); + info.write_a(&func, offset); } } PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) @@ -173,18 +164,12 @@ impl DriverHandler { } } PcidClientRequest::ReadConfig(offset) => { - let value = unsafe { - with_pci_func_raw(&self.state.pcie, self.addr, |func| { - func.read_u32(offset) - }) - }; + let value = unsafe { func.read_u32(offset) }; return PcidClientResponse::ReadConfig(value); }, PcidClientRequest::WriteConfig(offset, value) => { unsafe { - with_pci_func_raw(&self.state.pcie, self.addr, |func| { - func.write_u32(offset, value); - }); + func.write_u32(offset, value); } return PcidClientResponse::WriteConfig; } From b04915673d957f9aaadf68b83ee60c88bb55231e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:51:55 +0200 Subject: [PATCH 0887/1301] pcid: Remove ConfigReader and ConfigWriter traits Only PciFunc implements this trait. --- pcid/src/main.rs | 1 - pcid/src/pci/cap.rs | 96 ++++++++++++++++++++++---------------------- pcid/src/pci/func.rs | 29 +++++-------- pcid/src/pci/msi.rs | 78 +++++++++++++++++------------------ 4 files changed, 97 insertions(+), 107 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 18a64f2060..f5d146632f 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -15,7 +15,6 @@ use crate::config::Config; use crate::driver_interface::LegacyInterruptLine; use crate::pci::PciFunc; use crate::pci::cap::Capability as PciCapability; -use crate::pci::func::{ConfigReader, ConfigWriter}; use crate::pci_header::{PciEndpointHeader, PciHeader, PciHeaderError}; mod cfg_access; diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 41e480a71c..729845ef84 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -1,22 +1,20 @@ -use super::func::ConfigReader; +use super::func::PciFunc; + use serde::{Serialize, Deserialize}; -pub struct CapabilitiesIter<'a, R> { +pub struct CapabilitiesIter<'a> { offset: u8, - reader: &'a R, + func: &'a PciFunc<'a>, } -impl<'a, R> CapabilitiesIter<'a, R> { - pub fn new(offset: u8, reader: &'a R) -> Self { +impl<'a> CapabilitiesIter<'a> { + pub fn new(offset: u8, func: &'a PciFunc) -> Self { Self { offset, - reader, + func, } } } -impl<'a, R> Iterator for CapabilitiesIter<'a, R> -where - R: ConfigReader -{ +impl<'a> Iterator for CapabilitiesIter<'a> { type Item = (u8, Capability); fn next(&mut self) -> Option { @@ -26,7 +24,7 @@ where if self.offset == 0 { return None }; - let first_dword = self.reader.read_u32(u16::from(self.offset)); + let first_dword = self.func.read_u32(u16::from(self.offset)); let next = ((first_dword >> 8) & 0xFF) as u8; let offset = self.offset; @@ -36,7 +34,7 @@ where }; let cap = unsafe { - Capability::parse(self.reader, offset) + Capability::parse(self.func, offset) }; Some((offset, cap)) @@ -159,28 +157,28 @@ impl Capability { _ => None, } } - unsafe fn parse_msi(reader: &R, offset: u8) -> Self { - Self::Msi(MsiCapability::parse(reader, offset)) + unsafe fn parse_msi(func: &PciFunc, offset: u8) -> Self { + Self::Msi(MsiCapability::parse(func, offset)) } - unsafe fn parse_msix(reader: &R, offset: u8) -> Self { + unsafe fn parse_msix(func: &PciFunc, offset: u8) -> Self { Self::MsiX(MsixCapability { - a: reader.read_u32(u16::from(offset)), - b: reader.read_u32(u16::from(offset + 4)), - c: reader.read_u32(u16::from(offset + 8)), + a: func.read_u32(u16::from(offset)), + b: func.read_u32(u16::from(offset + 4)), + c: func.read_u32(u16::from(offset + 8)), }) } - unsafe fn parse_pwr(reader: &R, offset: u8) -> Self { + unsafe fn parse_pwr(func: &PciFunc, offset: u8) -> Self { Self::PwrMgmt(PwrMgmtCapability { - a: reader.read_u32(u16::from(offset)), - b: reader.read_u32(u16::from(offset + 4)), + a: func.read_u32(u16::from(offset)), + b: func.read_u32(u16::from(offset + 4)), }) } - unsafe fn parse_vendor(reader: &R, offset: u8) -> Self { - let next = reader.read_u8(u16::from(offset+1)); - let length = reader.read_u8(u16::from(offset+2)); + unsafe fn parse_vendor(func: &PciFunc, offset: u8) -> Self { + let next = func.read_u8(u16::from(offset+1)); + let length = func.read_u8(u16::from(offset+2)); log::info!("Vendor specific offset: {offset:#02x} next: {next:#02x} cap len: {length:#02x}"); let data = if length > 0 { - let mut raw_data = reader.read_range(offset.into(), length.into()); + let mut raw_data = func.read_range(offset.into(), length.into()); raw_data.drain(3..).collect() } else { log::warn!("Vendor specific capability is invalid"); @@ -190,45 +188,45 @@ impl Capability { data }) } - unsafe fn parse_pcie(reader: &R, offset: u8) -> Self { + unsafe fn parse_pcie(func: &PciFunc, offset: u8) -> Self { let offset = u16::from(offset); Self::Pcie(PcieCapability { - pcie_caps: reader.read_u32(offset), - dev_caps: reader.read_u32(offset + 0x04), - dev_sts_ctl: reader.read_u32(offset + 0x08), - link_caps: reader.read_u32(offset + 0x0C), - link_sts_ctl: reader.read_u32(offset + 0x10), - slot_caps: reader.read_u32(offset + 0x14), - slot_sts_ctl: reader.read_u32(offset + 0x18), - root_cap_ctl: reader.read_u32(offset + 0x1C), - root_sts: reader.read_u32(offset + 0x20), - dev_caps2: reader.read_u32(offset + 0x24), - dev_sts_ctl2: reader.read_u32(offset + 0x28), - link_caps2: reader.read_u32(offset + 0x2C), - link_sts_ctl2: reader.read_u32(offset + 0x30), - slot_caps2: reader.read_u32(offset + 0x34), - slot_sts_ctl2: reader.read_u32(offset + 0x38), + pcie_caps: func.read_u32(offset), + dev_caps: func.read_u32(offset + 0x04), + dev_sts_ctl: func.read_u32(offset + 0x08), + link_caps: func.read_u32(offset + 0x0C), + link_sts_ctl: func.read_u32(offset + 0x10), + slot_caps: func.read_u32(offset + 0x14), + slot_sts_ctl: func.read_u32(offset + 0x18), + root_cap_ctl: func.read_u32(offset + 0x1C), + root_sts: func.read_u32(offset + 0x20), + dev_caps2: func.read_u32(offset + 0x24), + dev_sts_ctl2: func.read_u32(offset + 0x28), + link_caps2: func.read_u32(offset + 0x2C), + link_sts_ctl2: func.read_u32(offset + 0x30), + slot_caps2: func.read_u32(offset + 0x34), + slot_sts_ctl2: func.read_u32(offset + 0x38), }) } - unsafe fn parse(reader: &R, offset: u8) -> Self { + unsafe fn parse(func: &PciFunc, offset: u8) -> Self { assert_eq!(offset & 0xFC, offset, "capability must be dword aligned"); - let dword = reader.read_u32(u16::from(offset)); + let dword = func.read_u32(u16::from(offset)); let capability_id = (dword & 0xFF) as u8; if capability_id == CapabilityId::Msi as u8 { - Self::parse_msi(reader, offset) + Self::parse_msi(func, offset) } else if capability_id == CapabilityId::MsiX as u8 { - Self::parse_msix(reader, offset) + Self::parse_msix(func, offset) } else if capability_id == CapabilityId::Pcie as u8 { - Self::parse_pcie(reader, offset) + Self::parse_pcie(func, offset) } else if capability_id == CapabilityId::PwrMgmt as u8{ - Self::parse_pwr(reader, offset) + Self::parse_pwr(func, offset) } else if capability_id == CapabilityId::Vendor as u8 { - Self::parse_vendor(reader, offset) + Self::parse_vendor(func, offset) } else if capability_id == CapabilityId::Sata as u8 { - Self::FunctionSpecific(capability_id, reader.read_range(offset.into(), 8)) + Self::FunctionSpecific(capability_id, func.read_range(offset.into(), 8)) } else { log::warn!("unimplemented or malformed capability id: {}", capability_id); Self::Other(capability_id) diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index 7bdabff43d..e94e40818d 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -1,8 +1,13 @@ use byteorder::{ByteOrder, LittleEndian}; use pci_types::{ConfigRegionAccess, PciAddress}; -pub trait ConfigReader { - unsafe fn read_range(&self, offset: u16, len: u16) -> Vec { +pub struct PciFunc<'pci> { + pub pci: &'pci dyn ConfigRegionAccess, + pub addr: PciAddress, +} + +impl<'pci> PciFunc<'pci> { + pub unsafe fn read_range(&self, offset: u16, len: u16) -> Vec { assert!(len > 3 && len % 4 == 0, "invalid range length: {}", len); let mut ret = Vec::with_capacity(len as usize); let results = (offset..offset + len) @@ -17,32 +22,20 @@ pub trait ConfigReader { ret } - unsafe fn read_u32(&self, offset: u16) -> u32; - - unsafe fn read_u8(&self, offset: u16) -> u8 { + pub unsafe fn read_u8(&self, offset: u16) -> u8 { let dword_offset = (offset / 4) * 4; let dword = self.read_u32(dword_offset); let shift = (offset % 4) * 8; ((dword >> shift) & 0xFF) as u8 } -} -pub trait ConfigWriter { - unsafe fn write_u32(&self, offset: u16, value: u32); -} -pub struct PciFunc<'pci> { - pub pci: &'pci dyn ConfigRegionAccess, - pub addr: PciAddress, -} - -impl<'pci> ConfigReader for PciFunc<'pci> { - unsafe fn read_u32(&self, offset: u16) -> u32 { + pub unsafe fn read_u32(&self, offset: u16) -> u32 { self.pci.read(self.addr, offset) } } -impl<'pci> ConfigWriter for PciFunc<'pci> { - unsafe fn write_u32(&self, offset: u16, value: u32) { +impl<'pci> PciFunc<'pci> { + pub unsafe fn write_u32(&self, offset: u16, value: u32) { self.pci.write(self.addr, offset, value); } } diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index ce176a1846..8d6e8f4f83 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -2,7 +2,7 @@ use std::fmt; use super::bar::PciBar; pub use super::cap::{MsiCapability, MsixCapability}; -use super::func::{ConfigReader, ConfigWriter}; +use super::func::PciFunc; use serde::{Deserialize, Serialize}; use syscall::{Io, Mmio}; @@ -35,8 +35,8 @@ impl MsiCapability { pub const MC_MSI_ENABLED_BIT: u16 = 1; - pub unsafe fn parse(reader: &R, offset: u8) -> Self { - let dword = reader.read_u32(u16::from(offset)); + pub unsafe fn parse(func: &PciFunc, offset: u8) -> Self { + let dword = func.read_u32(u16::from(offset)); let message_control = (dword >> 16) as u16; @@ -44,34 +44,34 @@ impl MsiCapability { if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { Self::_64BitAddressWithPvm { message_control: dword, - message_address_lo: reader.read_u32(u16::from(offset + 4)), - message_address_hi: reader.read_u32(u16::from(offset + 8)), - message_data: reader.read_u32(u16::from(offset + 12)), - mask_bits: reader.read_u32(u16::from(offset + 16)), - pending_bits: reader.read_u32(u16::from(offset + 20)), + message_address_lo: func.read_u32(u16::from(offset + 4)), + message_address_hi: func.read_u32(u16::from(offset + 8)), + message_data: func.read_u32(u16::from(offset + 12)), + mask_bits: func.read_u32(u16::from(offset + 16)), + pending_bits: func.read_u32(u16::from(offset + 20)), } } else { Self::_32BitAddressWithPvm { message_control: dword, - message_address: reader.read_u32(u16::from(offset + 4)), - message_data: reader.read_u32(u16::from(offset + 8)), - mask_bits: reader.read_u32(u16::from(offset + 12)), - pending_bits: reader.read_u32(u16::from(offset + 16)), + message_address: func.read_u32(u16::from(offset + 4)), + message_data: func.read_u32(u16::from(offset + 8)), + mask_bits: func.read_u32(u16::from(offset + 12)), + pending_bits: func.read_u32(u16::from(offset + 16)), } } } else { if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { Self::_64BitAddress { message_control: dword, - message_address_lo: reader.read_u32(u16::from(offset + 4)), - message_address_hi: reader.read_u32(u16::from(offset + 8)), - message_data: reader.read_u32(u16::from(offset + 12)) as u16, + message_address_lo: func.read_u32(u16::from(offset + 4)), + message_address_hi: func.read_u32(u16::from(offset + 8)), + message_data: func.read_u32(u16::from(offset + 12)) as u16, } } else { Self::_32BitAddress { message_control: dword, - message_address: reader.read_u32(u16::from(offset + 4)), - message_data: reader.read_u32(u16::from(offset + 8)) as u16, + message_address: func.read_u32(u16::from(offset + 4)), + message_data: func.read_u32(u16::from(offset + 8)) as u16, } } } @@ -97,8 +97,8 @@ impl MsiCapability { | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, } } - pub unsafe fn write_message_control(&self, writer: &W, offset: u8) { - writer.write_u32(u16::from(offset), self.message_control_raw()); + pub unsafe fn write_message_control(&self, func: &PciFunc, offset: u8) { + func.write_u32(u16::from(offset), self.message_control_raw()); } pub fn is_pvt_capable(&self) -> bool { self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 @@ -186,36 +186,36 @@ impl MsiCapability { } Some(()) } - pub unsafe fn write_message_address(&self, writer: &W, offset: u8) { - writer.write_u32(u16::from(offset) + 4, self.message_address()) + pub unsafe fn write_message_address(&self, func: &PciFunc, offset: u8) { + func.write_u32(u16::from(offset) + 4, self.message_address()) } - pub unsafe fn write_message_upper_address(&self, writer: &W, offset: u8) -> Option<()> { + pub unsafe fn write_message_upper_address(&self, func: &PciFunc, offset: u8) -> Option<()> { let value = self.message_upper_address()?; - writer.write_u32(u16::from(offset + 8), value); + func.write_u32(u16::from(offset + 8), value); Some(()) } - pub unsafe fn write_message_data(&self, writer: &W, offset: u8) { + pub unsafe fn write_message_data(&self, func: &PciFunc, offset: u8) { match self { - &Self::_32BitAddress { message_data, .. } => writer.write_u32(u16::from(offset + 8), message_data.into()), - &Self::_32BitAddressWithPvm { message_data, .. } => writer.write_u32(u16::from(offset + 8), message_data), - &Self::_64BitAddress { message_data, .. } => writer.write_u32(u16::from(offset + 12), message_data.into()), - &Self::_64BitAddressWithPvm { message_data, .. } => writer.write_u32(u16::from(offset + 12), message_data), + &Self::_32BitAddress { message_data, .. } => func.write_u32(u16::from(offset + 8), message_data.into()), + &Self::_32BitAddressWithPvm { message_data, .. } => func.write_u32(u16::from(offset + 8), message_data), + &Self::_64BitAddress { message_data, .. } => func.write_u32(u16::from(offset + 12), message_data.into()), + &Self::_64BitAddressWithPvm { message_data, .. } => func.write_u32(u16::from(offset + 12), message_data), } } - pub unsafe fn write_mask_bits(&self, writer: &W, offset: u8) -> Option<()> { + pub unsafe fn write_mask_bits(&self, func: &PciFunc, offset: u8) -> Option<()> { match self { - &Self::_32BitAddressWithPvm { mask_bits, .. } => writer.write_u32(u16::from(offset + 12), mask_bits), - &Self::_64BitAddressWithPvm { mask_bits, .. } => writer.write_u32(u16::from(offset + 16), mask_bits), + &Self::_32BitAddressWithPvm { mask_bits, .. } => func.write_u32(u16::from(offset + 12), mask_bits), + &Self::_64BitAddressWithPvm { mask_bits, .. } => func.write_u32(u16::from(offset + 16), mask_bits), &Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => return None, } Some(()) } - pub unsafe fn write_all(&self, writer: &W, offset: u8) { - self.write_message_control(writer, offset); - self.write_message_address(writer, offset); - self.write_message_upper_address(writer, offset); - self.write_message_data(writer, offset); - self.write_mask_bits(writer, offset); + pub unsafe fn write_all(&self, func: &PciFunc, offset: u8) { + self.write_message_control(func, offset); + self.write_message_address(func, offset); + self.write_message_upper_address(func, offset); + self.write_message_data(func, offset); + self.write_mask_bits(func, offset); } } @@ -329,8 +329,8 @@ impl MsixCapability { /// Write the first DWORD into configuration space (containing the partially modifiable Message /// Control field). - pub unsafe fn write_a(&self, writer: &W, offset: u8) { - writer.write_u32(u16::from(offset), self.a) + pub unsafe fn write_a(&self, func: &PciFunc, offset: u8) { + func.write_u32(u16::from(offset), self.a) } } From eb2e670cd6f67df447ec009b1ec19870b38af495 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:53:19 +0200 Subject: [PATCH 0888/1301] pcid: Explain why PciBar is used instead of pcid_types::Bar --- pcid/src/pci/bar.rs | 2 ++ pcid/src/pci_header.rs | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index b9e8008f51..b279c44577 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -2,6 +2,8 @@ use std::convert::TryInto; use serde::{Deserialize, Serialize}; +// This type is used instead of [pci_types::Bar] in the driver interface as the +// latter can't be serialized and is missing the convenience functions of [PciBar]. #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] pub enum PciBar { None, diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 95c960851a..5e450ca26c 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -199,7 +199,6 @@ impl PciEndpointHeader { } /// Return the Headers BARs. - // FIXME use pci_types::Bar instead pub fn bars(&self, access: &impl ConfigRegionAccess) -> [PciBar; 6] { let endpoint_header = self.endpoint_header(access); From fd3cf798840dcbbcd5610c4aa3fe9c017b71fef5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:07:38 +0200 Subject: [PATCH 0889/1301] pcid: Move spawning and interacting with subdrivers out of main.rs --- pcid/src/driver_handler.rs | 331 +++++++++++++++++++++++++++++++++++++ pcid/src/main.rs | 217 +----------------------- 2 files changed, 334 insertions(+), 214 deletions(-) create mode 100644 pcid/src/driver_handler.rs diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs new file mode 100644 index 0000000000..60c893dd85 --- /dev/null +++ b/pcid/src/driver_handler.rs @@ -0,0 +1,331 @@ +use std::fs::File; +use std::os::unix::io::{FromRawFd, RawFd}; +use std::process::Command; +use std::sync::Arc; +use std::thread; + +use log::{error, info}; +use pci_types::PciAddress; + +use crate::driver_interface; +use crate::pci::cap::Capability as PciCapability; +use crate::pci::PciFunc; +use crate::State; + +pub struct DriverHandler { + addr: PciAddress, + capabilities: Vec<(u8, PciCapability)>, + + state: Arc, +} + +impl DriverHandler { + pub fn spawn( + state: Arc, + func: driver_interface::PciFunction, + capabilities: Vec<(u8, PciCapability)>, + args: &[String], + ) { + let subdriver_args = driver_interface::SubdriverArguments { func }; + + let mut args = args.iter(); + if let Some(program) = args.next() { + let mut command = Command::new(program); + for arg in args { + if arg.starts_with("$") { + panic!("support for $VARIABLE has been removed. use pcid_interface instead"); + } + command.arg(arg); + } + + info!("PCID SPAWN {:?}", command); + + // TODO: libc wrapper? + let [fds1, fds2] = unsafe { + let mut fds1 = [0 as libc::c_int; 2]; + let mut fds2 = [0 as libc::c_int; 2]; + + assert_eq!( + libc::pipe(fds1.as_mut_ptr()), + 0, + "pcid: failed to create pcid->client pipe" + ); + assert_eq!( + libc::pipe(fds2.as_mut_ptr()), + 0, + "pcid: failed to create client->pcid pipe" + ); + + [fds1.map(|c| c as usize), fds2.map(|c| c as usize)] + }; + + let [pcid_to_client_read, pcid_to_client_write] = fds1; + let [pcid_from_client_read, pcid_from_client_write] = fds2; + + let envs = vec![ + ("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), + ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write)), + ]; + + match command.envs(envs).spawn() { + Ok(mut child) => { + let driver_handler = DriverHandler { + addr: func.addr, + state, + capabilities, + }; + let _handle = thread::spawn(move || { + driver_handler.handle_spawn( + pcid_to_client_write, + pcid_from_client_read, + subdriver_args, + ); + }); + // FIXME this currently deadlocks as pcid doesn't daemonize + //state.threads.lock().unwrap().push(handle); + match child.wait() { + Ok(_status) => (), + Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err), + } + } + Err(err) => error!("pcid: failed to execute {:?}: {}", command, err), + } + } + } + + fn respond( + &mut self, + request: driver_interface::PcidClientRequest, + args: &driver_interface::SubdriverArguments, + ) -> driver_interface::PcidClientResponse { + use crate::pci::cap::{MsiCapability, MsixCapability}; + use driver_interface::*; + + let func = PciFunc { + pci: &self.state.pcie, + addr: self.addr, + }; + + match request { + PcidClientRequest::RequestCapabilities => PcidClientResponse::Capabilities( + self.capabilities + .iter() + .map(|(_, capability)| capability.clone()) + .collect::>(), + ), + PcidClientRequest::RequestConfig => PcidClientResponse::Config(args.clone()), + PcidClientRequest::RequestFeatures => PcidClientResponse::AllFeatures( + self.capabilities + .iter() + .filter_map(|(_, capability)| match capability { + PciCapability::Msi(msi) => { + Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))) + } + PciCapability::MsiX(msix) => Some(( + PciFeature::MsiX, + FeatureStatus::enabled(msix.msix_enabled()), + )), + _ => None, + }) + .collect(), + ), + PcidClientRequest::EnableFeature(feature) => match feature { + PciFeature::Msi => { + let (offset, capability): (u8, &mut MsiCapability) = match self + .capabilities + .iter_mut() + .find_map(|&mut (offset, ref mut capability)| { + capability.as_msi_mut().map(|cap| (offset, cap)) + }) { + Some(tuple) => tuple, + None => { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(feature), + ) + } + }; + unsafe { + capability.set_enabled(true); + capability.write_message_control(&func, offset); + } + PcidClientResponse::FeatureEnabled(feature) + } + PciFeature::MsiX => { + let (offset, capability): (u8, &mut MsixCapability) = match self + .capabilities + .iter_mut() + .find_map(|&mut (offset, ref mut capability)| { + capability.as_msix_mut().map(|cap| (offset, cap)) + }) { + Some(tuple) => tuple, + None => { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(feature), + ) + } + }; + unsafe { + capability.set_msix_enabled(true); + capability.write_a(&func, offset); + } + PcidClientResponse::FeatureEnabled(feature) + } + }, + PcidClientRequest::FeatureStatus(feature) => PcidClientResponse::FeatureStatus( + feature, + match feature { + PciFeature::Msi => self + .capabilities + .iter() + .find_map(|(_, capability)| { + if let PciCapability::Msi(msi) = capability { + Some(FeatureStatus::enabled(msi.enabled())) + } else { + None + } + }) + .unwrap_or(FeatureStatus::Disabled), + PciFeature::MsiX => self + .capabilities + .iter() + .find_map(|(_, capability)| { + if let PciCapability::MsiX(msix) = capability { + Some(FeatureStatus::enabled(msix.msix_enabled())) + } else { + None + } + }) + .unwrap_or(FeatureStatus::Disabled), + }, + ), + PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo( + feature, + match feature { + PciFeature::Msi => { + if let Some(info) = self + .capabilities + .iter() + .find_map(|(_, capability)| capability.as_msi()) + { + PciFeatureInfo::Msi(*info) + } else { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(feature), + ); + } + } + PciFeature::MsiX => { + if let Some(info) = self + .capabilities + .iter() + .find_map(|(_, capability)| capability.as_msix()) + { + PciFeatureInfo::MsiX(*info) + } else { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(feature), + ); + } + } + }, + ), + PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set { + SetFeatureInfo::Msi(info_to_set) => { + if let Some((offset, info)) = self + .capabilities + .iter_mut() + .find_map(|(offset, capability)| Some((*offset, capability.as_msi_mut()?))) + { + if let Some(mme) = info_to_set.multi_message_enable { + if info.multi_message_capable() < mme || mme > 0b101 { + return PcidClientResponse::Error( + PcidServerResponseError::InvalidBitPattern, + ); + } + info.set_multi_message_enable(mme); + } + if let Some(message_addr_and_data) = info_to_set.message_address_and_data { + let message_addr = message_addr_and_data.addr; + if message_addr & 0b11 != 0 { + return PcidClientResponse::Error( + PcidServerResponseError::InvalidBitPattern, + ); + } + info.set_message_address(message_addr as u32); + info.set_message_upper_address((message_addr >> 32) as u32); + if message_addr_and_data.data & ((1 << info.multi_message_enable()) - 1) + != 0 + { + return PcidClientResponse::Error( + PcidServerResponseError::InvalidBitPattern, + ); + } + info.set_message_data( + message_addr_and_data + .data + .try_into() + .expect("pcid: MSI message data too big"), + ); + } + if let Some(mask_bits) = info_to_set.mask_bits { + info.set_mask_bits(mask_bits); + } + unsafe { + info.write_all(&func, offset); + } + PcidClientResponse::SetFeatureInfo(PciFeature::Msi) + } else { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(PciFeature::Msi), + ); + } + } + SetFeatureInfo::MsiX { function_mask } => { + if let Some((offset, info)) = self + .capabilities + .iter_mut() + .find_map(|(offset, capability)| Some((*offset, capability.as_msix_mut()?))) + { + if let Some(mask) = function_mask { + info.set_function_mask(mask); + unsafe { + info.write_a(&func, offset); + } + } + PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) + } else { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(PciFeature::MsiX), + ); + } + } + }, + PcidClientRequest::ReadConfig(offset) => { + let value = unsafe { func.read_u32(offset) }; + return PcidClientResponse::ReadConfig(value); + } + PcidClientRequest::WriteConfig(offset, value) => { + unsafe { + func.write_u32(offset, value); + } + return PcidClientResponse::WriteConfig; + } + } + } + fn handle_spawn( + mut self, + pcid_to_client_write: usize, + pcid_from_client_read: usize, + args: driver_interface::SubdriverArguments, + ) { + use driver_interface::*; + + let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_write as RawFd) }; + let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_read as RawFd) }; + + while let Ok(msg) = recv(&mut pcid_from_client) { + let response = self.respond(msg, &args); + send(&mut pcid_to_client, &response).unwrap(); + } + } +} diff --git a/pcid/src/main.rs b/pcid/src/main.rs index f5d146632f..5ee29bc3e3 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,24 +1,22 @@ use std::fs::{File, metadata, read_dir}; use std::io::prelude::*; -use std::os::unix::io::{FromRawFd, RawFd}; -use std::process::Command; use std::thread; use std::sync::{Arc, Mutex}; use pci_types::{CommandRegister, PciAddress}; use structopt::StructOpt; -use log::{debug, error, info, warn, trace}; +use log::{debug, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; use crate::cfg_access::Pcie; use crate::config::Config; use crate::driver_interface::LegacyInterruptLine; use crate::pci::PciFunc; -use crate::pci::cap::Capability as PciCapability; use crate::pci_header::{PciEndpointHeader, PciHeader, PciHeaderError}; mod cfg_access; mod config; +mod driver_handler; mod driver_interface; mod pci; mod pci_header; @@ -35,158 +33,6 @@ struct Args { config_path: Option, } -pub struct DriverHandler { - addr: PciAddress, - capabilities: Vec<(u8, PciCapability)>, - - state: Arc, -} - -impl DriverHandler { - fn respond(&mut self, request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments) -> driver_interface::PcidClientResponse { - use driver_interface::*; - use crate::pci::cap::{MsiCapability, MsixCapability}; - - let func = PciFunc { - pci: &self.state.pcie, - addr: self.addr, - }; - - match request { - PcidClientRequest::RequestCapabilities => { - PcidClientResponse::Capabilities(self.capabilities.iter().map(|(_, capability)| capability.clone()).collect::>()) - } - PcidClientRequest::RequestConfig => { - PcidClientResponse::Config(args.clone()) - } - PcidClientRequest::RequestFeatures => { - PcidClientResponse::AllFeatures(self.capabilities.iter().filter_map(|(_, capability)| match capability { - PciCapability::Msi(msi) => Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))), - PciCapability::MsiX(msix) => Some((PciFeature::MsiX, FeatureStatus::enabled(msix.msix_enabled()))), - _ => None, - }).collect()) - } - PcidClientRequest::EnableFeature(feature) => match feature { - PciFeature::Msi => { - let (offset, capability): (u8, &mut MsiCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msi_mut().map(|cap| (offset, cap))) { - Some(tuple) => tuple, - None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), - }; - unsafe { - capability.set_enabled(true); - capability.write_message_control(&func, offset); - } - PcidClientResponse::FeatureEnabled(feature) - } - PciFeature::MsiX => { - let (offset, capability): (u8, &mut MsixCapability) = match self.capabilities.iter_mut().find_map(|&mut (offset, ref mut capability)| capability.as_msix_mut().map(|cap| (offset, cap))) { - Some(tuple) => tuple, - None => return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)), - }; - unsafe { - capability.set_msix_enabled(true); - capability.write_a(&func, offset); - } - PcidClientResponse::FeatureEnabled(feature) - } - } - PcidClientRequest::FeatureStatus(feature) => PcidClientResponse::FeatureStatus(feature, match feature { - PciFeature::Msi => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::Msi(msi) = capability { - Some(FeatureStatus::enabled(msi.enabled())) - } else { - None - }).unwrap_or(FeatureStatus::Disabled), - PciFeature::MsiX => self.capabilities.iter().find_map(|(_, capability)| if let PciCapability::MsiX(msix) = capability { - Some(FeatureStatus::enabled(msix.msix_enabled())) - } else { - None - }).unwrap_or(FeatureStatus::Disabled), - }), - PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo(feature, match feature { - PciFeature::Msi => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msi()) { - PciFeatureInfo::Msi(*info) - } else { - return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)); - } - PciFeature::MsiX => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msix()) { - PciFeatureInfo::MsiX(*info) - } else { - return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature)); - } - }), - PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set { - SetFeatureInfo::Msi(info_to_set) => if let Some((offset, info)) = self.capabilities.iter_mut().find_map(|(offset, capability)| Some((*offset, capability.as_msi_mut()?))) { - if let Some(mme) = info_to_set.multi_message_enable { - if info.multi_message_capable() < mme || mme > 0b101 { - return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern); - } - info.set_multi_message_enable(mme); - - } - if let Some(message_addr_and_data) = info_to_set.message_address_and_data { - let message_addr = message_addr_and_data.addr; - if message_addr & 0b11 != 0 { - return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern); - } - info.set_message_address(message_addr as u32); - info.set_message_upper_address((message_addr >> 32) as u32); - if message_addr_and_data.data & ((1 << info.multi_message_enable()) - 1) != 0 { - return PcidClientResponse::Error(PcidServerResponseError::InvalidBitPattern); - } - info.set_message_data( - message_addr_and_data - .data - .try_into() - .expect("pcid: MSI message data too big"), - ); - } - if let Some(mask_bits) = info_to_set.mask_bits { - info.set_mask_bits(mask_bits); - } - unsafe { - info.write_all(&func, offset); - } - PcidClientResponse::SetFeatureInfo(PciFeature::Msi) - } else { - return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(PciFeature::Msi)); - } - SetFeatureInfo::MsiX { function_mask } => if let Some((offset, info)) = self.capabilities.iter_mut().find_map(|(offset, capability)| Some((*offset, capability.as_msix_mut()?))) { - if let Some(mask) = function_mask { - info.set_function_mask(mask); - unsafe { - info.write_a(&func, offset); - } - } - PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) - } else { - return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(PciFeature::MsiX)); - } - } - PcidClientRequest::ReadConfig(offset) => { - let value = unsafe { func.read_u32(offset) }; - return PcidClientResponse::ReadConfig(value); - }, - PcidClientRequest::WriteConfig(offset, value) => { - unsafe { - func.write_u32(offset, value); - } - return PcidClientResponse::WriteConfig; - } - } - } - fn handle_spawn(mut self, pcid_to_client_write: usize, pcid_from_client_read: usize, args: driver_interface::SubdriverArguments) { - use driver_interface::*; - - let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_write as RawFd) }; - let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_read as RawFd) }; - - while let Ok(msg) = recv(&mut pcid_from_client) { - let response = self.respond(msg, &args); - send(&mut pcid_to_client, &response).unwrap(); - } - } -} - pub struct State { threads: Mutex>>, pcie: Pcie, @@ -268,64 +114,7 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH full_device_id: header.full_device_id().clone(), }; - let subdriver_args = driver_interface::SubdriverArguments { - func, - }; - - let mut args = args.iter(); - if let Some(program) = args.next() { - let mut command = Command::new(program); - for arg in args { - if arg.starts_with("$") { - panic!("support for $VARIABLE has been removed. use pcid_interface instead"); - } - command.arg(arg); - } - - info!("PCID SPAWN {:?}", command); - - // TODO: libc wrapper? - let [fds1, fds2] = unsafe { - let mut fds1 = [0 as libc::c_int; 2]; - let mut fds2 = [0 as libc::c_int; 2]; - - assert_eq!(libc::pipe(fds1.as_mut_ptr()), 0, "pcid: failed to create pcid->client pipe"); - assert_eq!(libc::pipe(fds2.as_mut_ptr()), 0, "pcid: failed to create client->pcid pipe"); - - [ - fds1.map(|c| c as usize), - fds2.map(|c| c as usize), - ] - }; - - let [pcid_to_client_read, pcid_to_client_write] = fds1; - let [pcid_from_client_read, pcid_from_client_write] = fds2; - - let envs = vec![ - ("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), - ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write)), - ]; - - match command.envs(envs).spawn() { - Ok(mut child) => { - let driver_handler = DriverHandler { - addr: header.address(), - state: Arc::clone(&state), - capabilities, - }; - let _handle = thread::spawn(move || { - driver_handler.handle_spawn(pcid_to_client_write, pcid_from_client_read, subdriver_args); - }); - // FIXME this currently deadlocks as pcid doesn't daemonize - //state.threads.lock().unwrap().push(handle); - match child.wait() { - Ok(_status) => (), - Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err), - } - } - Err(err) => error!("pcid: failed to execute {:?}: {}", command, err) - } - } + driver_handler::DriverHandler::spawn(Arc::clone(&state), func, capabilities, args); } } From 8f9bbecd0cdbeffc2fa8e8b29b3f5951a76c1302 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:08:12 +0200 Subject: [PATCH 0890/1301] pcid: Rustfmt main.rs --- pcid/src/main.rs | 78 +++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 31 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 5ee29bc3e3..648a291a4c 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,12 +1,12 @@ -use std::fs::{File, metadata, read_dir}; +use std::fs::{metadata, read_dir, File}; use std::io::prelude::*; -use std::thread; use std::sync::{Arc, Mutex}; +use std::thread; +use log::{debug, info, trace, warn}; use pci_types::{CommandRegister, PciAddress}; -use structopt::StructOpt; -use log::{debug, info, warn, trace}; use redox_log::{OutputBuilder, RedoxLogger}; +use structopt::StructOpt; use crate::cfg_access::Pcie; use crate::config::Config; @@ -24,12 +24,17 @@ mod pci_header; #[derive(StructOpt)] #[structopt(about)] struct Args { - #[structopt(short, long, - help="Increase logging level once for each arg.", parse(from_occurrences))] + #[structopt( + short, + long, + help = "Increase logging level once for each arg.", + parse(from_occurrences) + )] verbose: u8, #[structopt( - help="A path to a pcid config file or a directory that contains pcid config files.")] + help = "A path to a pcid config file or a directory that contains pcid config files." + )] config_path: Option, } @@ -101,7 +106,14 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH } else { Vec::new() }; - debug!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities); + debug!( + "PCI DEVICE CAPABILITIES for {}: {:?}", + args.iter() + .map(|string| string.as_ref()) + .nth(0) + .unwrap_or("[unknown]"), + capabilities + ); let func = driver_interface::PciFunction { bars, @@ -124,31 +136,35 @@ fn setup_logging(verbosity: u8) -> Option<&'static RedoxLogger> { 1 => log::LevelFilter::Debug, _ => log::LevelFilter::Trace, }; - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_ansi_escape_codes() - .with_filter(log_level) - .flush_on_newline(true) - .build() - ); + let mut logger = RedoxLogger::new().with_output( + OutputBuilder::stderr() + .with_ansi_escape_codes() + .with_filter(log_level) + .flush_on_newline(true) + .build(), + ); - #[cfg(target_os = "redox")] { + #[cfg(target_os = "redox")] + { match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Trace) - .flush_on_newline(true) - .build() - ), + Ok(b) => { + logger = logger.with_output( + b.with_filter(log::LevelFilter::Trace) + .flush_on_newline(true) + .build(), + ) + } Err(error) => eprintln!("pcid: failed to open pcid.log"), } match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.ansi.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Trace) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), + Ok(b) => { + logger = logger.with_output( + b.with_filter(log::LevelFilter::Trace) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ) + } Err(error) => eprintln!("pcid: failed to open pcid.ansi.log"), } } @@ -231,10 +247,10 @@ fn main(args: Args) { } Err(PciHeaderError::NoDevice) => { if func_addr.function() == 0 { - trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); - continue 'dev; + trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); + continue 'dev; } - }, + } Err(PciHeaderError::UnknownHeaderType(id)) => { warn!("pcid: unknown header type: {id:?}"); } From 027d952c39e600e7af168363087663a0124a952b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 19:35:04 +0200 Subject: [PATCH 0891/1301] pcid: Remove parsing of unused capabilities This will make it easier to switch to pci_types for capability parsing in the future. --- pcid/src/pci/cap.rs | 72 ++++++--------------------------------------- 1 file changed, 9 insertions(+), 63 deletions(-) diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 729845ef84..21ce506f00 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -83,32 +83,6 @@ pub enum MsiCapability { }, } - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub struct PcieCapability { - pub pcie_caps: u32, - pub dev_caps: u32, - pub dev_sts_ctl: u32, - pub link_caps: u32, - pub link_sts_ctl: u32, - pub slot_caps: u32, - pub slot_sts_ctl: u32, - pub root_cap_ctl: u32, - pub root_sts: u32, - pub dev_caps2: u32, - pub dev_sts_ctl2: u32, - pub link_caps2: u32, - pub link_sts_ctl2: u32, - pub slot_caps2: u32, - pub slot_sts_ctl2: u32, -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub struct PwrMgmtCapability { - pub a: u32, - pub b: u32, -} - #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct MsixCapability { pub a: u32, @@ -125,10 +99,7 @@ pub struct VendorSpecificCapability { pub enum Capability { Msi(MsiCapability), MsiX(MsixCapability), - Pcie(PcieCapability), - PwrMgmt(PwrMgmtCapability), Vendor(VendorSpecificCapability), - FunctionSpecific(u8, Vec), // TODO: Arrayvec Other(u8), } @@ -167,12 +138,6 @@ impl Capability { c: func.read_u32(u16::from(offset + 8)), }) } - unsafe fn parse_pwr(func: &PciFunc, offset: u8) -> Self { - Self::PwrMgmt(PwrMgmtCapability { - a: func.read_u32(u16::from(offset)), - b: func.read_u32(u16::from(offset + 4)), - }) - } unsafe fn parse_vendor(func: &PciFunc, offset: u8) -> Self { let next = func.read_u8(u16::from(offset+1)); let length = func.read_u8(u16::from(offset+2)); @@ -188,27 +153,6 @@ impl Capability { data }) } - unsafe fn parse_pcie(func: &PciFunc, offset: u8) -> Self { - let offset = u16::from(offset); - - Self::Pcie(PcieCapability { - pcie_caps: func.read_u32(offset), - dev_caps: func.read_u32(offset + 0x04), - dev_sts_ctl: func.read_u32(offset + 0x08), - link_caps: func.read_u32(offset + 0x0C), - link_sts_ctl: func.read_u32(offset + 0x10), - slot_caps: func.read_u32(offset + 0x14), - slot_sts_ctl: func.read_u32(offset + 0x18), - root_cap_ctl: func.read_u32(offset + 0x1C), - root_sts: func.read_u32(offset + 0x20), - dev_caps2: func.read_u32(offset + 0x24), - dev_sts_ctl2: func.read_u32(offset + 0x28), - link_caps2: func.read_u32(offset + 0x2C), - link_sts_ctl2: func.read_u32(offset + 0x30), - slot_caps2: func.read_u32(offset + 0x34), - slot_sts_ctl2: func.read_u32(offset + 0x38), - }) - } unsafe fn parse(func: &PciFunc, offset: u8) -> Self { assert_eq!(offset & 0xFC, offset, "capability must be dword aligned"); @@ -219,16 +163,18 @@ impl Capability { Self::parse_msi(func, offset) } else if capability_id == CapabilityId::MsiX as u8 { Self::parse_msix(func, offset) - } else if capability_id == CapabilityId::Pcie as u8 { - Self::parse_pcie(func, offset) - } else if capability_id == CapabilityId::PwrMgmt as u8{ - Self::parse_pwr(func, offset) } else if capability_id == CapabilityId::Vendor as u8 { Self::parse_vendor(func, offset) - } else if capability_id == CapabilityId::Sata as u8 { - Self::FunctionSpecific(capability_id, func.read_range(offset.into(), 8)) } else { - log::warn!("unimplemented or malformed capability id: {}", capability_id); + if capability_id != CapabilityId::Pcie as u8 + && capability_id != CapabilityId::PwrMgmt as u8 + && capability_id != CapabilityId::Sata as u8 + { + log::warn!( + "unimplemented or malformed capability id: {}", + capability_id + ); + } Self::Other(capability_id) } } From 123eef963572f07d55a19167c2d4ea41dfd15054 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 21:34:48 +0200 Subject: [PATCH 0892/1301] pcid: Move capability offset into the Capability enum This makes it easier to move to using pci_types for parsing PCI capabilities. --- pcid/src/driver_handler.rs | 50 ++++++++++++++++------------------ pcid/src/pci/cap.rs | 10 +++++-- pcid/src/pci/msi.rs | 56 +++++++++++++++++++++++--------------- 3 files changed, 66 insertions(+), 50 deletions(-) diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 60c893dd85..4ecb55a4c7 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -14,7 +14,7 @@ use crate::State; pub struct DriverHandler { addr: PciAddress, - capabilities: Vec<(u8, PciCapability)>, + capabilities: Vec, state: Arc, } @@ -23,7 +23,7 @@ impl DriverHandler { pub fn spawn( state: Arc, func: driver_interface::PciFunction, - capabilities: Vec<(u8, PciCapability)>, + capabilities: Vec, args: &[String], ) { let subdriver_args = driver_interface::SubdriverArguments { func }; @@ -110,14 +110,14 @@ impl DriverHandler { PcidClientRequest::RequestCapabilities => PcidClientResponse::Capabilities( self.capabilities .iter() - .map(|(_, capability)| capability.clone()) + .map(|capability| capability.clone()) .collect::>(), ), PcidClientRequest::RequestConfig => PcidClientResponse::Config(args.clone()), PcidClientRequest::RequestFeatures => PcidClientResponse::AllFeatures( self.capabilities .iter() - .filter_map(|(_, capability)| match capability { + .filter_map(|capability| match capability { PciCapability::Msi(msi) => { Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))) } @@ -131,13 +131,12 @@ impl DriverHandler { ), PcidClientRequest::EnableFeature(feature) => match feature { PciFeature::Msi => { - let (offset, capability): (u8, &mut MsiCapability) = match self + let capability: &mut MsiCapability = match self .capabilities .iter_mut() - .find_map(|&mut (offset, ref mut capability)| { - capability.as_msi_mut().map(|cap| (offset, cap)) - }) { - Some(tuple) => tuple, + .find_map(|capability| capability.as_msi_mut()) + { + Some(capability) => capability, None => { return PcidClientResponse::Error( PcidServerResponseError::NonexistentFeature(feature), @@ -146,18 +145,17 @@ impl DriverHandler { }; unsafe { capability.set_enabled(true); - capability.write_message_control(&func, offset); + capability.write_message_control(&func); } PcidClientResponse::FeatureEnabled(feature) } PciFeature::MsiX => { - let (offset, capability): (u8, &mut MsixCapability) = match self + let capability: &mut MsixCapability = match self .capabilities .iter_mut() - .find_map(|&mut (offset, ref mut capability)| { - capability.as_msix_mut().map(|cap| (offset, cap)) - }) { - Some(tuple) => tuple, + .find_map(|capability| capability.as_msix_mut()) + { + Some(capability) => capability, None => { return PcidClientResponse::Error( PcidServerResponseError::NonexistentFeature(feature), @@ -166,7 +164,7 @@ impl DriverHandler { }; unsafe { capability.set_msix_enabled(true); - capability.write_a(&func, offset); + capability.write_a(&func); } PcidClientResponse::FeatureEnabled(feature) } @@ -177,7 +175,7 @@ impl DriverHandler { PciFeature::Msi => self .capabilities .iter() - .find_map(|(_, capability)| { + .find_map(|capability| { if let PciCapability::Msi(msi) = capability { Some(FeatureStatus::enabled(msi.enabled())) } else { @@ -188,7 +186,7 @@ impl DriverHandler { PciFeature::MsiX => self .capabilities .iter() - .find_map(|(_, capability)| { + .find_map(|capability| { if let PciCapability::MsiX(msix) = capability { Some(FeatureStatus::enabled(msix.msix_enabled())) } else { @@ -205,7 +203,7 @@ impl DriverHandler { if let Some(info) = self .capabilities .iter() - .find_map(|(_, capability)| capability.as_msi()) + .find_map(|capability| capability.as_msi()) { PciFeatureInfo::Msi(*info) } else { @@ -218,7 +216,7 @@ impl DriverHandler { if let Some(info) = self .capabilities .iter() - .find_map(|(_, capability)| capability.as_msix()) + .find_map(|capability| capability.as_msix()) { PciFeatureInfo::MsiX(*info) } else { @@ -231,10 +229,10 @@ impl DriverHandler { ), PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set { SetFeatureInfo::Msi(info_to_set) => { - if let Some((offset, info)) = self + if let Some(info) = self .capabilities .iter_mut() - .find_map(|(offset, capability)| Some((*offset, capability.as_msi_mut()?))) + .find_map(|capability| capability.as_msi_mut()) { if let Some(mme) = info_to_set.multi_message_enable { if info.multi_message_capable() < mme || mme > 0b101 { @@ -271,7 +269,7 @@ impl DriverHandler { info.set_mask_bits(mask_bits); } unsafe { - info.write_all(&func, offset); + info.write_all(&func); } PcidClientResponse::SetFeatureInfo(PciFeature::Msi) } else { @@ -281,15 +279,15 @@ impl DriverHandler { } } SetFeatureInfo::MsiX { function_mask } => { - if let Some((offset, info)) = self + if let Some(info) = self .capabilities .iter_mut() - .find_map(|(offset, capability)| Some((*offset, capability.as_msix_mut()?))) + .find_map(|capability| capability.as_msix_mut()) { if let Some(mask) = function_mask { info.set_function_mask(mask); unsafe { - info.write_a(&func, offset); + info.write_a(&func); } } PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 21ce506f00..06e1436f5f 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -15,7 +15,7 @@ impl<'a> CapabilitiesIter<'a> { } } impl<'a> Iterator for CapabilitiesIter<'a> { - type Item = (u8, Capability); + type Item = Capability; fn next(&mut self) -> Option { let offset = unsafe { @@ -37,7 +37,7 @@ impl<'a> Iterator for CapabilitiesIter<'a> { Capability::parse(self.func, offset) }; - Some((offset, cap)) + Some(cap) } } @@ -56,17 +56,20 @@ pub enum CapabilityId { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum MsiCapability { _32BitAddress { + cap_offset: u8, message_control: u32, message_address: u32, message_data: u16, }, _64BitAddress { + cap_offset: u8, message_control: u32, message_address_lo: u32, message_address_hi: u32, message_data: u16, }, _32BitAddressWithPvm { + cap_offset: u8, message_control: u32, message_address: u32, message_data: u32, @@ -74,6 +77,7 @@ pub enum MsiCapability { pending_bits: u32, }, _64BitAddressWithPvm { + cap_offset: u8, message_control: u32, message_address_lo: u32, message_address_hi: u32, @@ -85,6 +89,7 @@ pub enum MsiCapability { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct MsixCapability { + pub cap_offset: u8, pub a: u32, pub b: u32, pub c: u32, @@ -133,6 +138,7 @@ impl Capability { } unsafe fn parse_msix(func: &PciFunc, offset: u8) -> Self { Self::MsiX(MsixCapability { + cap_offset: offset, a: func.read_u32(u16::from(offset)), b: func.read_u32(u16::from(offset + 4)), c: func.read_u32(u16::from(offset + 8)), diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 8d6e8f4f83..ce9b35cb9e 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -43,6 +43,7 @@ impl MsiCapability { if message_control & Self::MC_PVT_CAPABLE_BIT != 0 { if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { Self::_64BitAddressWithPvm { + cap_offset: offset, message_control: dword, message_address_lo: func.read_u32(u16::from(offset + 4)), message_address_hi: func.read_u32(u16::from(offset + 8)), @@ -52,6 +53,7 @@ impl MsiCapability { } } else { Self::_32BitAddressWithPvm { + cap_offset: offset, message_control: dword, message_address: func.read_u32(u16::from(offset + 4)), message_data: func.read_u32(u16::from(offset + 8)), @@ -62,6 +64,7 @@ impl MsiCapability { } else { if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { Self::_64BitAddress { + cap_offset: offset, message_control: dword, message_address_lo: func.read_u32(u16::from(offset + 4)), message_address_hi: func.read_u32(u16::from(offset + 8)), @@ -69,6 +72,7 @@ impl MsiCapability { } } else { Self::_32BitAddress { + cap_offset: offset, message_control: dword, message_address: func.read_u32(u16::from(offset + 4)), message_data: func.read_u32(u16::from(offset + 8)) as u16, @@ -76,6 +80,14 @@ impl MsiCapability { } } } + fn cap_offset(&self) -> u16 { + match *self { + MsiCapability::_32BitAddress { cap_offset, .. } + | MsiCapability::_64BitAddress { cap_offset, .. } + | MsiCapability::_32BitAddressWithPvm { cap_offset, .. } + | MsiCapability::_64BitAddressWithPvm { cap_offset, .. } => u16::from(cap_offset), + } + } fn message_control_raw(&self) -> u32 { match self { @@ -97,8 +109,8 @@ impl MsiCapability { | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, } } - pub unsafe fn write_message_control(&self, func: &PciFunc, offset: u8) { - func.write_u32(u16::from(offset), self.message_control_raw()); + pub unsafe fn write_message_control(&self, func: &PciFunc) { + func.write_u32(self.cap_offset(), self.message_control_raw()); } pub fn is_pvt_capable(&self) -> bool { self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 @@ -186,36 +198,36 @@ impl MsiCapability { } Some(()) } - pub unsafe fn write_message_address(&self, func: &PciFunc, offset: u8) { - func.write_u32(u16::from(offset) + 4, self.message_address()) + pub unsafe fn write_message_address(&self, func: &PciFunc) { + func.write_u32(self.cap_offset() + 4, self.message_address()) } - pub unsafe fn write_message_upper_address(&self, func: &PciFunc, offset: u8) -> Option<()> { + pub unsafe fn write_message_upper_address(&self, func: &PciFunc) -> Option<()> { let value = self.message_upper_address()?; - func.write_u32(u16::from(offset + 8), value); + func.write_u32(self.cap_offset() + 8, value); Some(()) } - pub unsafe fn write_message_data(&self, func: &PciFunc, offset: u8) { + pub unsafe fn write_message_data(&self, func: &PciFunc) { match self { - &Self::_32BitAddress { message_data, .. } => func.write_u32(u16::from(offset + 8), message_data.into()), - &Self::_32BitAddressWithPvm { message_data, .. } => func.write_u32(u16::from(offset + 8), message_data), - &Self::_64BitAddress { message_data, .. } => func.write_u32(u16::from(offset + 12), message_data.into()), - &Self::_64BitAddressWithPvm { message_data, .. } => func.write_u32(u16::from(offset + 12), message_data), + &Self::_32BitAddress { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 8), message_data.into()), + &Self::_32BitAddressWithPvm { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 8), message_data), + &Self::_64BitAddress { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 12), message_data.into()), + &Self::_64BitAddressWithPvm { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 12), message_data), } } - pub unsafe fn write_mask_bits(&self, func: &PciFunc, offset: u8) -> Option<()> { + pub unsafe fn write_mask_bits(&self, func: &PciFunc) -> Option<()> { match self { - &Self::_32BitAddressWithPvm { mask_bits, .. } => func.write_u32(u16::from(offset + 12), mask_bits), - &Self::_64BitAddressWithPvm { mask_bits, .. } => func.write_u32(u16::from(offset + 16), mask_bits), + &Self::_32BitAddressWithPvm { cap_offset, mask_bits, .. } => func.write_u32(u16::from(cap_offset + 12), mask_bits), + &Self::_64BitAddressWithPvm { cap_offset, mask_bits, .. } => func.write_u32(u16::from(cap_offset + 16), mask_bits), &Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => return None, } Some(()) } - pub unsafe fn write_all(&self, func: &PciFunc, offset: u8) { - self.write_message_control(func, offset); - self.write_message_address(func, offset); - self.write_message_upper_address(func, offset); - self.write_message_data(func, offset); - self.write_mask_bits(func, offset); + pub unsafe fn write_all(&self, func: &PciFunc) { + self.write_message_control(func); + self.write_message_address(func); + self.write_message_upper_address(func); + self.write_message_data(func); + self.write_mask_bits(func); } } @@ -329,8 +341,8 @@ impl MsixCapability { /// Write the first DWORD into configuration space (containing the partially modifiable Message /// Control field). - pub unsafe fn write_a(&self, func: &PciFunc, offset: u8) { - func.write_u32(u16::from(offset), self.a) + pub unsafe fn write_a(&self, func: &PciFunc) { + func.write_u32(u16::from(self.cap_offset), self.a) } } From e14e56349f436d5f4e18f614f7629c2afb21ada2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 21:40:43 +0200 Subject: [PATCH 0893/1301] pcid: Remove method to get the current feature status Devices should never change the feature status behind the back of the driver, so storing the current status after setting it is fine. Drivers should reset all state when they start to recover from a crashed driver, so they shouldn't need to get the current feature status at startup either. --- pcid/src/driver_handler.rs | 27 --------------------------- pcid/src/driver_interface/mod.rs | 8 -------- 2 files changed, 35 deletions(-) diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 4ecb55a4c7..741e374fe4 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -169,33 +169,6 @@ impl DriverHandler { PcidClientResponse::FeatureEnabled(feature) } }, - PcidClientRequest::FeatureStatus(feature) => PcidClientResponse::FeatureStatus( - feature, - match feature { - PciFeature::Msi => self - .capabilities - .iter() - .find_map(|capability| { - if let PciCapability::Msi(msi) = capability { - Some(FeatureStatus::enabled(msi.enabled())) - } else { - None - } - }) - .unwrap_or(FeatureStatus::Disabled), - PciFeature::MsiX => self - .capabilities - .iter() - .find_map(|capability| { - if let PciCapability::MsiX(msix) = capability { - Some(FeatureStatus::enabled(msix.msix_enabled())) - } else { - None - } - }) - .unwrap_or(FeatureStatus::Disabled), - }, - ), PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo( feature, match feature { diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index aa03a9d587..32e324ec4e 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -194,7 +194,6 @@ pub enum PcidClientRequest { RequestFeatures, RequestCapabilities, EnableFeature(PciFeature), - FeatureStatus(PciFeature), FeatureInfo(PciFeature), SetFeatureInfo(SetFeatureInfo), ReadConfig(u16), @@ -295,13 +294,6 @@ impl PcidServerHandle { other => Err(PcidClientHandleError::InvalidResponse(other)), } } - pub fn feature_status(&mut self, feature: PciFeature) -> Result { - self.send(&PcidClientRequest::FeatureStatus(feature))?; - match self.recv()? { - PcidClientResponse::FeatureStatus(feat, status) if feat == feature => Ok(status), - other => Err(PcidClientHandleError::InvalidResponse(other)), - } - } pub fn enable_feature(&mut self, feature: PciFeature) -> Result<()> { self.send(&PcidClientRequest::EnableFeature(feature))?; match self.recv()? { From 588bbfe6a3ec25ed3716dd7f0cc1e46774477854 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Jun 2024 21:54:36 +0200 Subject: [PATCH 0894/1301] pcid: Stop returning feature enable status from fetch_all_features For the same reason the feature_status method was removed. --- audio/ihdad/src/main.rs | 13 +++---------- net/rtl8139d/src/main.rs | 15 ++++----------- net/rtl8168d/src/main.rs | 15 ++++----------- pcid/src/driver_handler.rs | 9 ++------- pcid/src/driver_interface/mod.rs | 4 ++-- storage/nvmed/src/main.rs | 4 ++-- virtio-core/src/arch/x86.rs | 4 +--- virtio-core/src/arch/x86_64.rs | 4 +--- virtio-core/src/probe.rs | 7 +++---- xhcid/src/main.rs | 15 ++++----------- 10 files changed, 26 insertions(+), 64 deletions(-) diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index bab7c5b6df..e86cc832a4 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -82,17 +82,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let all_pci_features = pcid_handle.fetch_all_features().expect("ihdad: failed to fetch pci features"); log::debug!("PCI FEATURES: {:?}", all_pci_features); - let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); - let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); + let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - if has_msi && !msi_enabled && !has_msix { - msi_enabled = true; - } - if has_msix && !msix_enabled { - msix_enabled = true; - } - - if msi_enabled && !msix_enabled { + if has_msi && !has_msix { let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("ihdad: failed to retrieve the MSI capability structure from pcid") { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index b04e5a7829..fc51f4653b 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -101,17 +101,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8139d: failed to fetch pci features"); log::info!("PCI FEATURES: {:?}", all_pci_features); - let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); - let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); + let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - if has_msi && !msi_enabled && !has_msix { - msi_enabled = true; - } - if has_msix && !msix_enabled { - msix_enabled = true; - } - - if msi_enabled && !msix_enabled { + if has_msi && !has_msix { let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("rtl8139d: failed to retrieve the MSI capability structure from pcid") { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), @@ -135,7 +128,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { log::info!("Enabled MSI"); interrupt_handle - } else if msix_enabled { + } else if has_msix { let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8139d: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index e2d594948e..d13cc10d80 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -96,17 +96,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8168d: failed to fetch pci features"); log::info!("PCI FEATURES: {:?}", all_pci_features); - let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); - let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); + let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - if has_msi && !msi_enabled && !has_msix { - msi_enabled = true; - } - if has_msix && !msix_enabled { - msix_enabled = true; - } - - if msi_enabled && !msix_enabled { + if has_msi && !has_msix { let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("rtl8168d: failed to retrieve the MSI capability structure from pcid") { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), @@ -130,7 +123,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { log::info!("Enabled MSI"); interrupt_handle - } else if msix_enabled { + } else if has_msix { let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8168d: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 741e374fe4..210cf9eefe 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -118,13 +118,8 @@ impl DriverHandler { self.capabilities .iter() .filter_map(|capability| match capability { - PciCapability::Msi(msi) => { - Some((PciFeature::Msi, FeatureStatus::enabled(msi.enabled()))) - } - PciCapability::MsiX(msix) => Some(( - PciFeature::MsiX, - FeatureStatus::enabled(msix.msix_enabled()), - )), + PciCapability::Msi(_) => Some(PciFeature::Msi), + PciCapability::MsiX(_) => Some(PciFeature::MsiX), _ => None, }) .collect(), diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 32e324ec4e..d7c1cdf16a 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -212,7 +212,7 @@ pub enum PcidServerResponseError { pub enum PcidClientResponse { Capabilities(Vec), Config(SubdriverArguments), - AllFeatures(Vec<(PciFeature, FeatureStatus)>), + AllFeatures(Vec), FeatureEnabled(PciFeature), FeatureStatus(PciFeature, FeatureStatus), Error(PcidServerResponseError), @@ -287,7 +287,7 @@ impl PcidServerHandle { } // FIXME turn into struct with bool fields - pub fn fetch_all_features(&mut self) -> Result> { + pub fn fetch_all_features(&mut self) -> Result> { self.send(&PcidClientRequest::RequestFeatures)?; match self.recv()? { PcidClientResponse::AllFeatures(a) => Ok(a), diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 3ca9b0e22c..dd9c1682c8 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -76,8 +76,8 @@ fn get_int_method( let features = pcid_handle.fetch_all_features().unwrap(); - let has_msi = features.iter().any(|(feature, _)| feature.is_msi()); - let has_msix = features.iter().any(|(feature, _)| feature.is_msix()); + let has_msi = features.iter().any(|feature| feature.is_msi()); + let has_msix = features.iter().any(|feature| feature.is_msix()); // TODO: Allocate more than one vector when possible and useful. if has_msix { diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index 23fdbbf3a0..be993050c5 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -20,9 +20,7 @@ pub fn probe_legacy_port_transport( // Setup interrupts. let all_pci_features = pcid_handle.fetch_all_features()?; - let has_msix = all_pci_features - .iter() - .any(|(feature, _)| feature.is_msix()); + let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); // According to the virtio specification, the device REQUIRED to support MSI-X. assert!(has_msix, "virtio: device does not support MSI-X"); diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index fa0de00c6c..7b95c4fe84 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -61,9 +61,7 @@ pub fn probe_legacy_port_transport( // Setup interrupts. let all_pci_features = pcid_handle.fetch_all_features()?; - let has_msix = all_pci_features - .iter() - .any(|(feature, _)| feature.is_msix()); + let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); // According to the virtio specification, the device REQUIRED to support MSI-X. assert!(has_msix, "virtio: device does not support MSI-X"); diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index aebd065d04..e61898f848 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -123,7 +123,8 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result // SAFETY: The capability type is `Notify`, so its safe to access // the `notify_multiplier` field. let multiplier = unsafe { - (&*(raw_capability.data.as_ptr() as *const PciCapability as *const PciCapabilityNotify)) + (&*(raw_capability.data.as_ptr() as *const PciCapability + as *const PciCapabilityNotify)) .notify_off_multiplier() }; notify_addr = Some((address, multiplier)); @@ -161,9 +162,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result // Setup interrupts. let all_pci_features = pcid_handle.fetch_all_features()?; - let has_msix = all_pci_features - .iter() - .any(|(feature, _)| feature.is_msix()); + let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); // According to the virtio specification, the device REQUIRED to support MSI-X. assert!(has_msix, "virtio: device does not support MSI-X"); diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 6a10660160..047e16e148 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -91,17 +91,10 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (O let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); log::debug!("XHCI PCI FEATURES: {:?}", all_pci_features); - let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); - let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false)); + let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); + let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - if has_msi && !msi_enabled && !has_msix { - msi_enabled = true; - } - if has_msix && !msix_enabled { - msix_enabled = true; - } - - if msi_enabled && !msix_enabled { + if has_msi && !has_msix { let mut capability = match pcid_handle.feature_info(PciFeature::Msi).expect("xhcid: failed to retrieve the MSI capability structure from pcid") { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), @@ -125,7 +118,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (O log::debug!("Enabled MSI"); (Some(interrupt_handle), InterruptMethod::Msi) - } else if msix_enabled { + } else if has_msix { let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, From 15c9ad1ba6f485323c261ca71931b8eaa25d99d2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:33:40 +0200 Subject: [PATCH 0895/1301] pcid: Ensure MSI and MSI-X are not enabled at the same time --- pcid/src/driver_handler.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 210cf9eefe..c809184d9d 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -126,6 +126,19 @@ impl DriverHandler { ), PcidClientRequest::EnableFeature(feature) => match feature { PciFeature::Msi => { + if let Some(msix_capability) = self + .capabilities + .iter_mut() + .find_map(|capability| capability.as_msix_mut()) + { + // If MSI-X is supported disable it before enabling MSI as they can't be + // active at the same time. + unsafe { + msix_capability.set_msix_enabled(false); + msix_capability.write_a(&func); + } + } + let capability: &mut MsiCapability = match self .capabilities .iter_mut() @@ -145,6 +158,19 @@ impl DriverHandler { PcidClientResponse::FeatureEnabled(feature) } PciFeature::MsiX => { + if let Some(msi_capability) = self + .capabilities + .iter_mut() + .find_map(|capability| capability.as_msi_mut()) + { + // If MSI is supported disable it before enabling MSI-X as they can't be + // active at the same time. + unsafe { + msi_capability.set_enabled(false); + msi_capability.write_message_control(&func); + } + } + let capability: &mut MsixCapability = match self .capabilities .iter_mut() From 7c112c34dd7fba1134502dfa1784b242f8ef9f7f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 10 Jun 2024 13:46:14 +0200 Subject: [PATCH 0896/1301] pcid: Remove some unused methods on MsixCapability --- pcid/src/pci/msi.rs | 18 ++++-------------- storage/nvmed/src/main.rs | 1 - 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index ce9b35cb9e..ac042985c9 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -279,11 +279,11 @@ impl MsixCapability { /// The Message Control field, containing the enabled and function mask bits, as well as the /// table size. - pub const fn message_control(&self) -> u16 { + const fn message_control(&self) -> u16 { (self.a >> 16) as u16 } - pub fn set_message_control(&mut self, message_control: u16) { + pub(crate) fn set_message_control(&mut self, message_control: u16) { self.a &= 0x0000_FFFF; self.a |= u32::from(message_control) << 16; } @@ -291,24 +291,14 @@ impl MsixCapability { pub const fn table_size(&self) -> u16 { (self.message_control() & Self::MC_TABLE_SIZE_MASK) + 1 } - /// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the - /// MSI capability structure. - pub const fn msix_enabled(&self) -> bool { - self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0 - } - /// The MSI-X function mask, which overrides each of the vectors' mask bit, when set. - pub const fn function_mask(&self) -> bool { - self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0 - } - - pub fn set_msix_enabled(&mut self, enabled: bool) { + pub(crate) fn set_msix_enabled(&mut self, enabled: bool) { let mut new_message_control = self.message_control(); new_message_control &= !(Self::MC_MSIX_ENABLED_BIT); new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT; self.set_message_control(new_message_control); } - pub fn set_function_mask(&mut self, function_mask: bool) { + pub(crate) fn set_function_mask(&mut self, function_mask: bool) { let mut new_message_control = self.message_control(); new_message_control &= !(Self::MC_FUNCTION_MASK_BIT); new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT; diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index dd9c1682c8..30d0b2788a 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -125,7 +125,6 @@ fn get_int_method( } pcid_handle.enable_feature(PciFeature::MsiX).unwrap(); - capability_struct.set_msix_enabled(true); // only affects our local mirror of the cap let (msix_vector_number, irq_handle) = { let entry: &mut MsixTableEntry = &mut table_entries[0]; From df666331116c26f9d6d2c6007afc015293df9802 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 10 Jun 2024 21:00:07 +0200 Subject: [PATCH 0897/1301] pcid: Store decoded MsixInfo instead of full capability in PciFeatureInfo --- net/rtl8139d/src/main.rs | 22 +++++++++++----------- net/rtl8168d/src/main.rs | 22 +++++++++++----------- pcid/src/driver_handler.rs | 8 +++++++- pcid/src/driver_interface/mod.rs | 2 +- pcid/src/pci/msi.rs | 31 +++++++++++++++++++++---------- storage/nvmed/src/main.rs | 16 ++++++++-------- storage/nvmed/src/nvme/mod.rs | 8 ++++---- virtio-core/src/arch/x86_64.rs | 14 +++++++------- virtio-core/src/probe.rs | 10 +++++----- xhcid/src/main.rs | 12 ++++++------ xhcid/src/xhci/mod.rs | 16 ++++++++-------- 11 files changed, 89 insertions(+), 72 deletions(-) diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index fc51f4653b..a949d46e18 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -13,7 +13,7 @@ use event::{user_data, EventQueue}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; -use pcid_interface::msi::{MsixCapability, MsixTableEntry}; +use pcid_interface::msi::{MsixInfo, MsixTableEntry}; use pcid_interface::{ MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PcidServerHandle, SetFeatureInfo, SubdriverArguments, @@ -79,17 +79,17 @@ where } } -pub struct MsixInfo { +pub struct MappedMsixRegs { pub virt_table_base: NonNull, - pub capability: MsixCapability, + pub info: MsixInfo, } -impl MsixInfo { +impl MappedMsixRegs { pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { &mut *self.virt_table_base.as_ptr().offset(k as isize) } pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { - assert!(k < self.capability.table_size() as usize); + assert!(k < self.info.table_size as usize); unsafe { self.table_entry_pointer_unchecked(k) } } } @@ -129,20 +129,20 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { interrupt_handle } else if has_msix { - let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8139d: failed to retrieve the MSI-X capability structure from pcid") { + let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8139d: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; - capability.validate(pci_config.func.bars); + msix_info.validate(pci_config.func.bars); - let bar = &pci_config.func.bars[capability.table_bir() as usize]; + let bar = &pci_config.func.bars[msix_info.table_bar as usize]; let bar_address = unsafe { bar.physmap_mem("rtl8139d") } as usize; - let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry; + let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; - let mut info = MsixInfo { + let mut info = MappedMsixRegs { virt_table_base: NonNull::new(virt_table_base).unwrap(), - capability, + info: msix_info, }; // Allocate one msi vector. diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index d13cc10d80..c797c2e059 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -12,7 +12,7 @@ use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeature #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; -use pcid_interface::msi::{MsixCapability, MsixTableEntry}; +use pcid_interface::msi::{MsixInfo, MsixTableEntry}; use redox_log::{RedoxLogger, OutputBuilder}; use syscall::EventFlags; @@ -74,17 +74,17 @@ where } } -pub struct MsixInfo { +pub struct MappedMsixRegs { pub virt_table_base: NonNull, - pub capability: MsixCapability, + pub info: MsixInfo, } -impl MsixInfo { +impl MappedMsixRegs { pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { &mut *self.virt_table_base.as_ptr().offset(k as isize) } pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { - assert!(k < self.capability.table_size() as usize); + assert!(k < self.info.table_size as usize); unsafe { self.table_entry_pointer_unchecked(k) } } } @@ -124,20 +124,20 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { interrupt_handle } else if has_msix { - let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8168d: failed to retrieve the MSI-X capability structure from pcid") { + let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8168d: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; - capability.validate(pci_config.func.bars); + msix_info.validate(pci_config.func.bars); - let bar = &pci_config.func.bars[capability.table_bir() as usize]; + let bar = &pci_config.func.bars[msix_info.table_bar as usize]; let bar_address = unsafe { bar.physmap_mem("rtl8168d") } as usize; - let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry; + let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; - let mut info = MsixInfo { + let mut info = MappedMsixRegs { virt_table_base: NonNull::new(virt_table_base).unwrap(), - capability, + info: msix_info, }; // Allocate one msi vector. diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index c809184d9d..3358a501fc 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -212,7 +212,13 @@ impl DriverHandler { .iter() .find_map(|capability| capability.as_msix()) { - PciFeatureInfo::MsiX(*info) + PciFeatureInfo::MsiX(msi::MsixInfo { + table_bar: info.table_bir(), + table_offset: info.table_offset(), + table_size: info.table_size(), + pba_bar: info.pba_bir(), + pba_offset: info.pba_offset(), + }) } else { return PcidClientResponse::Error( PcidServerResponseError::NonexistentFeature(feature), diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index d7c1cdf16a..483da35602 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -133,7 +133,7 @@ impl PciFeature { #[derive(Debug, Serialize, Deserialize)] pub enum PciFeatureInfo { Msi(msi::MsiCapability), - MsiX(msi::MsixCapability), + MsiX(msi::MsixInfo), } #[derive(Debug, Error)] diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index ac042985c9..179ae638f2 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -231,24 +231,33 @@ impl MsiCapability { } } -impl MsixCapability { +#[derive(Debug, Serialize, Deserialize)] +pub struct MsixInfo { + pub table_bar: u8, + pub table_offset: u32, + pub table_size: u16, + pub pba_bar: u8, + pub pba_offset: u32, +} + +impl MsixInfo { pub fn validate(&self, bars: [PciBar; 6]) { - if self.table_bir() > 5 { - panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir()); + if self.table_bar > 5 { + panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bar); } - if self.pba_bir() > 5 { - panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir()); + if self.pba_bar > 5 { + panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bar); } - let table_size = self.table_size(); - let table_offset = self.table_offset() as usize; + let table_size = self.table_size; + let table_offset = self.table_offset as usize; let table_min_length = table_size * 16; - let pba_offset = self.pba_offset() as usize; + let pba_offset = self.pba_offset as usize; let pba_min_length = table_size.div_ceil(8); - let (_, table_bar_size) = bars[self.table_bir() as usize].expect_mem(); - let (_, pba_bar_size) = bars[self.pba_bir() as usize].expect_mem(); + let (_, table_bar_size) = bars[self.table_bar as usize].expect_mem(); + let (_, pba_bar_size) = bars[self.pba_bar as usize].expect_mem(); // Ensure that the table and PBA are within the BAR. @@ -270,7 +279,9 @@ impl MsixCapability { ); } } +} +impl MsixCapability { const MC_MSIX_ENABLED_BIT: u16 = 1 << 15; const MC_MSIX_ENABLED_SHIFT: u8 = 15; const MC_FUNCTION_MASK_BIT: u16 = 1 << 14; diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 30d0b2788a..501c1b74e8 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -82,14 +82,14 @@ fn get_int_method( // TODO: Allocate more than one vector when possible and useful. if has_msix { // Extended message signaled interrupts. - use self::nvme::MsixCfg; + use self::nvme::MappedMsixRegs; use pcid_interface::msi::MsixTableEntry; - let mut capability_struct = match pcid_handle.feature_info(PciFeature::MsiX).unwrap() { + let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).unwrap() { PciFeatureInfo::MsiX(msix) => msix, _ => unreachable!(), }; - capability_struct.validate(function.bars); + msix_info.validate(function.bars); fn bar_base( allocated_bars: &AllocatedBars, function: &PciFunction, @@ -109,11 +109,11 @@ fn get_int_method( } } let table_bar_base: *mut u8 = - bar_base(allocated_bars, function, capability_struct.table_bir())?.as_ptr(); + bar_base(allocated_bars, function, msix_info.table_bar)?.as_ptr(); let table_base = - unsafe { table_bar_base.offset(capability_struct.table_offset() as isize) }; + unsafe { table_bar_base.offset(msix_info.table_offset as isize) }; - let vector_count = capability_struct.table_size(); + let vector_count = msix_info.table_size; let table_entries: &'static mut [MsixTableEntry] = unsafe { slice::from_raw_parts_mut(table_base as *mut MsixTableEntry, vector_count as usize) }; @@ -139,8 +139,8 @@ fn get_int_method( (0, irq_handle) }; - let interrupt_method = InterruptMethod::MsiX(MsixCfg { - cap: capability_struct, + let interrupt_method = InterruptMethod::MsiX(MappedMsixRegs { + info: msix_info, table: table_entries, }); let interrupt_sources = diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 6378fa2fce..7781f477bc 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -22,7 +22,7 @@ pub mod queues; use self::cq_reactor::NotifReq; pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue}; -use pcid_interface::msi::{MsiCapability, MsixCapability, MsixTableEntry}; +use pcid_interface::msi::{MsiCapability, MsixInfo, MsixTableEntry}; use pcid_interface::PcidServerHandle; #[cfg(target_arch = "aarch64")] @@ -93,7 +93,7 @@ pub enum InterruptMethod { /// Message signaled interrupts Msi(MsiCapability), /// Extended message signaled interrupts - MsiX(MsixCfg), + MsiX(MappedMsixRegs), } impl InterruptMethod { fn is_intx(&self) -> bool { @@ -119,8 +119,8 @@ impl InterruptMethod { } } -pub struct MsixCfg { - pub cap: MsixCapability, +pub struct MappedMsixRegs { + pub info: MsixInfo, pub table: &'static mut [MsixTableEntry], } diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index 7b95c4fe84..e1b25fbbb5 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -4,7 +4,7 @@ use pcid_interface::irq_helpers::{allocate_single_interrupt_vector_for_msi, read use pcid_interface::msi::MsixTableEntry; use std::{fs::File, ptr::NonNull}; -use crate::{probe::MsixInfo, MSIX_PRIMARY_VECTOR}; +use crate::{probe::MappedMsixRegs, MSIX_PRIMARY_VECTOR}; use pcid_interface::*; @@ -12,19 +12,19 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { let pci_config = pcid_handle.fetch_config()?; // Extended message signaled interrupts. - let capability = match pcid_handle.feature_info(PciFeature::MsiX)? { + let msix_info = match pcid_handle.feature_info(PciFeature::MsiX)? { PciFeatureInfo::MsiX(capability) => capability, _ => unreachable!(), }; - capability.validate(pci_config.func.bars); + msix_info.validate(pci_config.func.bars); - let bar = &pci_config.func.bars[capability.table_bir() as usize]; + let bar = &pci_config.func.bars[msix_info.table_bar as usize]; let bar_address = unsafe { bar.physmap_mem("virtio-core") } as usize; - let virt_table_base = (bar_address + capability.table_offset() as usize) as *mut MsixTableEntry; + let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; - let mut info = MsixInfo { + let mut info = MappedMsixRegs { virt_table_base: NonNull::new(virt_table_base).unwrap(), - capability, + info: msix_info, }; // Allocate the primary MSI vector. diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index e61898f848..7650736993 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -2,7 +2,7 @@ use std::fs::File; use std::ptr::NonNull; use std::sync::Arc; -use pcid_interface::msi::{MsixCapability, MsixTableEntry}; +use pcid_interface::msi::{MsixInfo, MsixTableEntry}; use pcid_interface::*; use crate::spec::*; @@ -20,18 +20,18 @@ pub struct Device { unsafe impl Send for Device {} unsafe impl Sync for Device {} -pub struct MsixInfo { +pub struct MappedMsixRegs { pub virt_table_base: NonNull, - pub capability: MsixCapability, + pub info: MsixInfo, } -impl MsixInfo { +impl MappedMsixRegs { pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { &mut *self.virt_table_base.as_ptr().add(k) } pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { - assert!(k < self.capability.table_size() as usize); + assert!(k < self.info.table_size as usize); unsafe { self.table_entry_pointer_unchecked(k) } } } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 047e16e148..ef5b122beb 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -119,18 +119,18 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (O (Some(interrupt_handle), InterruptMethod::Msi) } else if has_msix { - let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") { + let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; - capability.validate(pci_config.func.bars); + msix_info.validate(pci_config.func.bars); - assert_eq!(capability.table_bir(), 0); - let virt_table_base = (bar0_address + capability.table_offset() as usize) as *mut MsixTableEntry; + assert_eq!(msix_info.table_bar, 0); + let virt_table_base = (bar0_address + msix_info.table_offset as usize) as *mut MsixTableEntry; - let mut info = xhci::MsixInfo { + let mut info = xhci::MappedMsixRegs { virt_table_base: NonNull::new(virt_table_base).unwrap(), - capability, + info: msix_info, }; // Allocate one msi vector. diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index d88a87c7be..32eb7f7dd4 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -21,7 +21,7 @@ use serde::Deserialize; use crate::usb; -use pcid_interface::msi::{MsixTableEntry, MsixCapability}; +use pcid_interface::msi::{MsixInfo, MsixTableEntry}; use pcid_interface::{PcidServerHandle, PciFeature}; mod capability; @@ -64,19 +64,19 @@ pub enum InterruptMethod { Msi, /// Extended message signaled interrupts. - MsiX(Mutex), + MsiX(Mutex), } -pub struct MsixInfo { +pub struct MappedMsixRegs { pub virt_table_base: NonNull, - pub capability: MsixCapability, + pub info: MsixInfo, } -impl MsixInfo { +impl MappedMsixRegs { pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { &mut *self.virt_table_base.as_ptr().offset(k as isize) } pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { - assert!(k < self.capability.table_size() as usize); + assert!(k < self.info.table_size as usize); unsafe { self.table_entry_pointer_unchecked(k) } } } @@ -774,13 +774,13 @@ impl Xhci { if let InterruptMethod::MsiX(_) = self.interrupt_method { true } else { false } } // TODO: Perhaps use an rwlock? - pub fn msix_info(&self) -> Option> { + pub fn msix_info(&self) -> Option> { match self.interrupt_method { InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), _ => None, } } - pub fn msix_info_mut(&self) -> Option> { + pub fn msix_info_mut(&self) -> Option> { match self.interrupt_method { InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), _ => None, From 4f583b1cfb113bf0acfde69ee4e94b7eda784c81 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 11 Jun 2024 16:47:08 +0200 Subject: [PATCH 0898/1301] Store decoded MSI info instead of full capability in PciFeatureInfo --- pcid/src/driver_handler.rs | 6 +++++- pcid/src/driver_interface/mod.rs | 2 +- pcid/src/pci/msi.rs | 7 +++++++ storage/nvmed/src/main.rs | 7 +++++-- storage/nvmed/src/nvme/mod.rs | 12 ++++++------ 5 files changed, 24 insertions(+), 10 deletions(-) diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 3358a501fc..77f1729829 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -199,7 +199,11 @@ impl DriverHandler { .iter() .find_map(|capability| capability.as_msi()) { - PciFeatureInfo::Msi(*info) + PciFeatureInfo::Msi(msi::MsiInfo { + log2_multiple_message_capable: info.multi_message_capable(), + is_64bit: info.has_64_bit_addr(), + has_per_vector_masking: info.is_pvt_capable(), + }) } else { return PcidClientResponse::Error( PcidServerResponseError::NonexistentFeature(feature), diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 483da35602..4ba2eb789e 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -132,7 +132,7 @@ impl PciFeature { } #[derive(Debug, Serialize, Deserialize)] pub enum PciFeatureInfo { - Msi(msi::MsiCapability), + Msi(msi::MsiInfo), MsiX(msi::MsixInfo), } diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 179ae638f2..dab62c190f 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -23,6 +23,13 @@ impl MsiAddrAndData { } } +#[derive(Debug, Serialize, Deserialize)] +pub struct MsiInfo { + pub log2_multiple_message_capable: u8, + pub is_64bit: bool, + pub has_per_vector_masking: bool, +} + impl MsiCapability { pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8; pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7; diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 501c1b74e8..4aee22d621 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -149,7 +149,7 @@ fn get_int_method( Ok((interrupt_method, interrupt_sources)) } else if has_msi { // Message signaled interrupts. - let capability_struct = match pcid_handle.feature_info(PciFeature::Msi).unwrap() { + let msi_info = match pcid_handle.feature_info(PciFeature::Msi).unwrap() { PciFeatureInfo::Msi(msi) => msi, _ => unreachable!(), }; @@ -171,7 +171,10 @@ fn get_int_method( (0, irq_handle) }; - let interrupt_method = InterruptMethod::Msi(capability_struct); + let interrupt_method = InterruptMethod::Msi { + msi_info, + log2_multiple_message_enabled: 0, + }; let interrupt_sources = InterruptSources::Msi(std::iter::once((msi_vector_number, irq_handle)).collect()); diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 7781f477bc..993736b890 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -22,7 +22,7 @@ pub mod queues; use self::cq_reactor::NotifReq; pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue}; -use pcid_interface::msi::{MsiCapability, MsixInfo, MsixTableEntry}; +use pcid_interface::msi::{MsiInfo, MsixInfo, MsixTableEntry}; use pcid_interface::PcidServerHandle; #[cfg(target_arch = "aarch64")] @@ -91,7 +91,7 @@ pub enum InterruptMethod { /// Traditional level-triggered, INTx# interrupt pins. Intx, /// Message signaled interrupts - Msi(MsiCapability), + Msi { msi_info: MsiInfo, log2_multiple_message_enabled: u8 }, /// Extended message signaled interrupts MsiX(MappedMsixRegs), } @@ -104,7 +104,7 @@ impl InterruptMethod { } } fn is_msi(&self) -> bool { - if let Self::Msi(_) = self { + if let Self::Msi { .. } = self { true } else { false @@ -289,7 +289,7 @@ impl Nvme { } match self.interrupt_method.get_mut().unwrap() { - &mut InterruptMethod::Intx | InterruptMethod::Msi(_) => { + &mut InterruptMethod::Intx | InterruptMethod::Msi { .. } => { self.regs.get_mut().unwrap().intms.write(0xFFFF_FFFF); self.regs.get_mut().unwrap().intmc.write(0x0000_0001); } @@ -371,13 +371,13 @@ impl Nvme { self.regs.write().unwrap().intmc.write(0x0000_0001); } } - &mut InterruptMethod::Msi(ref mut cap) => { + &mut InterruptMethod::Msi { msi_info: _, log2_multiple_message_enabled: log2_enabled_messages } => { let mut to_mask = 0x0000_0000; let mut to_clear = 0x0000_0000; for (vector, mask) in vectors { assert!( - vector < (1 << cap.multi_message_enable()), + vector < (1 << log2_enabled_messages), "nvmed: internal error: MSI vector out of range" ); let vector = vector as u8; From 8e02a87474fd128210b289a2499e37cab8d24bda Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 11 Jun 2024 16:57:58 +0200 Subject: [PATCH 0899/1301] pcid: Reduce visibility of MsiCapability and MsixCapability methods --- pcid/src/pci/msi.rs | 89 +++++++++++++++++---------------------------- 1 file changed, 34 insertions(+), 55 deletions(-) diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index dab62c190f..2af0c43d99 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -31,18 +31,18 @@ pub struct MsiInfo { } impl MsiCapability { - pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8; - pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7; + const MC_PVT_CAPABLE_BIT: u16 = 1 << 8; + const MC_64_BIT_ADDR_BIT: u16 = 1 << 7; - pub const MC_MULTI_MESSAGE_MASK: u16 = 0x000E; - pub const MC_MULTI_MESSAGE_SHIFT: u8 = 1; + const MC_MULTI_MESSAGE_MASK: u16 = 0x000E; + const MC_MULTI_MESSAGE_SHIFT: u8 = 1; - pub const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070; - pub const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4; + const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070; + const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4; - pub const MC_MSI_ENABLED_BIT: u16 = 1; + const MC_MSI_ENABLED_BIT: u16 = 1; - pub unsafe fn parse(func: &PciFunc, offset: u8) -> Self { + pub(crate) unsafe fn parse(func: &PciFunc, offset: u8) -> Self { let dword = func.read_u32(u16::from(offset)); let message_control = (dword >> 16) as u16; @@ -101,10 +101,10 @@ impl MsiCapability { Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control, } } - pub fn message_control(&self) -> u16 { + fn message_control(&self) -> u16 { (self.message_control_raw() >> 16) as u16 } - pub fn set_message_control(&mut self, value: u16) { + pub(crate) fn set_message_control(&mut self, value: u16) { let mut new_message_control = self.message_control_raw(); new_message_control &= 0x0000_FFFF; new_message_control |= u32::from(value) << 16; @@ -116,80 +116,59 @@ impl MsiCapability { | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, } } - pub unsafe fn write_message_control(&self, func: &PciFunc) { + pub(crate) unsafe fn write_message_control(&self, func: &PciFunc) { func.write_u32(self.cap_offset(), self.message_control_raw()); } - pub fn is_pvt_capable(&self) -> bool { + pub(crate) fn is_pvt_capable(&self) -> bool { self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 } - pub fn has_64_bit_addr(&self) -> bool { + pub(crate) fn has_64_bit_addr(&self) -> bool { self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0 } - pub fn enabled(&self) -> bool { - self.message_control() & Self::MC_MSI_ENABLED_BIT != 0 - } - pub fn set_enabled(&mut self, enabled: bool) { + pub(crate) fn set_enabled(&mut self, enabled: bool) { let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); new_message_control |= u16::from(enabled); self.set_message_control(new_message_control); } - pub fn multi_message_capable(&self) -> u8 { + pub(crate) fn multi_message_capable(&self) -> u8 { ((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8 } - pub fn multi_message_enable(&self) -> u8 { + pub(crate) fn multi_message_enable(&self) -> u8 { ((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8 } - pub fn set_multi_message_enable(&mut self, log_mme: u8) { + pub(crate) fn set_multi_message_enable(&mut self, log_mme: u8) { let mut new_message_control = self.message_control() & (!Self::MC_MULTI_MESSAGE_ENABLE_MASK); new_message_control |= u16::from(log_mme) << Self::MC_MULTI_MESSAGE_ENABLE_SHIFT; self.set_message_control(new_message_control); } - pub fn message_address(&self) -> u32 { + fn message_address(&self) -> u32 { match self { &Self::_32BitAddress { message_address, .. } | &Self::_32BitAddressWithPvm { message_address, .. } => message_address, &Self::_64BitAddress { message_address_lo, .. } | &Self::_64BitAddressWithPvm { message_address_lo, .. } => message_address_lo, } } - pub fn message_upper_address(&self) -> Option { + fn message_upper_address(&self) -> Option { match self { &Self::_64BitAddress { message_address_hi, .. } | &Self::_64BitAddressWithPvm { message_address_hi, .. } => Some(message_address_hi), &Self::_32BitAddress { .. } | &Self::_32BitAddressWithPvm { .. } => None, } } - pub fn message_data(&self) -> u16 { - match self { - &Self::_32BitAddress { message_data, .. } | &Self::_64BitAddress { message_data, .. } => message_data, - &Self::_32BitAddressWithPvm { message_data, .. } | &Self::_64BitAddressWithPvm { message_data, .. } => message_data as u16, - } - } - pub fn mask_bits(&self) -> Option { - match self { - &Self::_32BitAddressWithPvm { mask_bits, .. } | &Self::_64BitAddressWithPvm { mask_bits, .. } => Some(mask_bits), - &Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => None, - } - } - pub fn pending_bits(&self) -> Option { - match self { - &Self::_32BitAddressWithPvm { pending_bits, .. } | &Self::_64BitAddressWithPvm { pending_bits, .. } => Some(pending_bits), - &Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => None, - } - } - pub fn set_message_address(&mut self, message_address: u32) { + pub(crate) fn set_message_address(&mut self, message_address: u32) { assert_eq!(message_address & 0xFFFF_FFFC, message_address, "unaligned message address (this should already be validated)"); match self { &mut Self::_32BitAddress { message_address: ref mut addr, .. } | &mut Self::_32BitAddressWithPvm { message_address: ref mut addr, .. } => *addr = message_address, &mut Self::_64BitAddress { message_address_lo: ref mut addr, .. } | &mut Self::_64BitAddressWithPvm { message_address_lo: ref mut addr, .. } => *addr = message_address, } } - pub fn set_message_upper_address(&mut self, message_upper_address: u32) -> Option<()> { + pub(crate) fn set_message_upper_address(&mut self, message_upper_address: u32) -> Option<()> { match self { &mut Self::_64BitAddress { ref mut message_address_hi, .. } | &mut Self::_64BitAddressWithPvm { ref mut message_address_hi, .. } => *message_address_hi = message_upper_address, &mut Self::_32BitAddress { .. } | &mut Self::_32BitAddressWithPvm { .. } => return None, } Some(()) } - pub fn set_message_data(&mut self, value: u16) { + pub(crate) fn set_message_data(&mut self, value: u16) { match self { &mut Self::_32BitAddress { ref mut message_data, .. } | &mut Self::_64BitAddress { ref mut message_data, .. } => *message_data = value, &mut Self::_32BitAddressWithPvm { ref mut message_data, .. } | &mut Self::_64BitAddressWithPvm { ref mut message_data, .. } => { @@ -198,22 +177,22 @@ impl MsiCapability { } } } - pub fn set_mask_bits(&mut self, mask_bits: u32) -> Option<()> { + pub(crate) fn set_mask_bits(&mut self, mask_bits: u32) -> Option<()> { match self { &mut Self::_32BitAddressWithPvm { mask_bits: ref mut bits, .. } | &mut Self::_64BitAddressWithPvm { mask_bits: ref mut bits, .. } => *bits = mask_bits, &mut Self::_32BitAddress { .. } | &mut Self::_64BitAddress { .. } => return None, } Some(()) } - pub unsafe fn write_message_address(&self, func: &PciFunc) { + unsafe fn write_message_address(&self, func: &PciFunc) { func.write_u32(self.cap_offset() + 4, self.message_address()) } - pub unsafe fn write_message_upper_address(&self, func: &PciFunc) -> Option<()> { + unsafe fn write_message_upper_address(&self, func: &PciFunc) -> Option<()> { let value = self.message_upper_address()?; func.write_u32(self.cap_offset() + 8, value); Some(()) } - pub unsafe fn write_message_data(&self, func: &PciFunc) { + unsafe fn write_message_data(&self, func: &PciFunc) { match self { &Self::_32BitAddress { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 8), message_data.into()), &Self::_32BitAddressWithPvm { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 8), message_data), @@ -221,7 +200,7 @@ impl MsiCapability { &Self::_64BitAddressWithPvm { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 12), message_data), } } - pub unsafe fn write_mask_bits(&self, func: &PciFunc) -> Option<()> { + unsafe fn write_mask_bits(&self, func: &PciFunc) -> Option<()> { match self { &Self::_32BitAddressWithPvm { cap_offset, mask_bits, .. } => func.write_u32(u16::from(cap_offset + 12), mask_bits), &Self::_64BitAddressWithPvm { cap_offset, mask_bits, .. } => func.write_u32(u16::from(cap_offset + 16), mask_bits), @@ -229,7 +208,7 @@ impl MsiCapability { } Some(()) } - pub unsafe fn write_all(&self, func: &PciFunc) { + pub(crate) unsafe fn write_all(&self, func: &PciFunc) { self.write_message_control(func); self.write_message_address(func); self.write_message_upper_address(func); @@ -306,7 +285,7 @@ impl MsixCapability { self.a |= u32::from(message_control) << 16; } /// Returns the MSI-X table size. - pub const fn table_size(&self) -> u16 { + pub(crate) const fn table_size(&self) -> u16 { (self.message_control() & Self::MC_TABLE_SIZE_MASK) + 1 } pub(crate) fn set_msix_enabled(&mut self, enabled: bool) { @@ -326,11 +305,11 @@ impl MsixCapability { const TABLE_BIR_MASK: u32 = 0x0000_0007; /// The table offset is guaranteed to be QWORD aligned (8 bytes). - pub const fn table_offset(&self) -> u32 { + pub(crate) const fn table_offset(&self) -> u32 { self.b & Self::TABLE_OFFSET_MASK } /// The table BIR, which is used to map the offset to a memory location. - pub const fn table_bir(&self) -> u8 { + pub(crate) const fn table_bir(&self) -> u8 { (self.b & Self::TABLE_BIR_MASK) as u8 } @@ -338,18 +317,18 @@ impl MsixCapability { const PBA_BIR_MASK: u32 = 0x0000_0007; /// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes). - pub const fn pba_offset(&self) -> u32 { + pub(crate) const fn pba_offset(&self) -> u32 { self.c & Self::PBA_OFFSET_MASK } /// The Pending Bit Array BIR, which is used to map the offset to a memory location. - pub const fn pba_bir(&self) -> u8 { + pub(crate) const fn pba_bir(&self) -> u8 { (self.c & Self::PBA_BIR_MASK) as u8 } /// Write the first DWORD into configuration space (containing the partially modifiable Message /// Control field). - pub unsafe fn write_a(&self, func: &PciFunc) { + pub(crate) unsafe fn write_a(&self, func: &PciFunc) { func.write_u32(u16::from(self.cap_offset), self.a) } } From dc33cba4c08b2035e33337bc60ff340ebcc838a2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 11 Jun 2024 20:51:01 +0200 Subject: [PATCH 0900/1301] Fix typo --- virtio-core/src/spec/transport_pci.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtio-core/src/spec/transport_pci.rs b/virtio-core/src/spec/transport_pci.rs index 7ef8efa8ef..c6cb4a8af4 100644 --- a/virtio-core/src/spec/transport_pci.rs +++ b/virtio-core/src/spec/transport_pci.rs @@ -33,7 +33,7 @@ pub struct PciCapability { pub cfg_type: CfgType, /// Where to find it. pub bar: u8, - /// Multiple capabilities of the same typel + /// Multiple capabilities of the same type. pub id: u8, /// Pad to a full dword. pub padding: [u8; 2], From f6a709ee5aea5be311125cc85559dcf58afcf2a3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 11 Jun 2024 20:50:48 +0200 Subject: [PATCH 0901/1301] pcid: Simplify PciFunc::read_range This also avoids UB caused by creating a slice of uninitialized u8. --- Cargo.lock | 1 - pcid/Cargo.toml | 1 - pcid/src/pci/func.rs | 14 +++----------- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9ce5ed9fb6..ad80b39ff7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -922,7 +922,6 @@ dependencies = [ "bincode", "bit_field", "bitflags 1.3.2", - "byteorder", "common", "fdt 0.1.0", "libc", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 864e9a0598..6083222d46 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -15,7 +15,6 @@ path = "src/lib.rs" bincode = "1.2" bitflags = "1" bit_field = "0.10" -byteorder = "1.2" fdt = { git = "https://gitlab.redox-os.org/rosehuds/fdt.git" } libc = "0.2" log = "0.4" diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index e94e40818d..7caec137a8 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -1,4 +1,3 @@ -use byteorder::{ByteOrder, LittleEndian}; use pci_types::{ConfigRegionAccess, PciAddress}; pub struct PciFunc<'pci> { @@ -9,17 +8,10 @@ pub struct PciFunc<'pci> { impl<'pci> PciFunc<'pci> { pub unsafe fn read_range(&self, offset: u16, len: u16) -> Vec { assert!(len > 3 && len % 4 == 0, "invalid range length: {}", len); - let mut ret = Vec::with_capacity(len as usize); - let results = (offset..offset + len) + (offset..offset + len) .step_by(4) - .fold(Vec::new(), |mut acc, offset| { - let val = self.read_u32(offset); - acc.push(val); - acc - }); - ret.set_len(len as usize); - LittleEndian::write_u32_into(&*results, &mut ret); - ret + .flat_map(|offset| self.read_u32(offset).to_le_bytes()) + .collect::>() } pub unsafe fn read_u8(&self, offset: u16) -> u8 { From b13b7c8e7c5409cca70cefe89b3e80d09c38f2be Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 12 Jun 2024 07:57:54 -0600 Subject: [PATCH 0902/1301] ided: detect when controller is DMA capable --- storage/ided/src/main.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 2778a68324..decfacd9bc 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -88,6 +88,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { info!("IDE PCI CONFIG: {:?}", pci_config); + // Get controller DMA capable + let dma = pci_config.func.full_device_id.interface & 0x80 != 0; + let busmaster_base = pci_config.func.bars[4].expect_port(); let (primary, primary_irq) = if pci_config.func.full_device_id.interface & 1 != 0 { panic!("TODO: IDE primary channel is PCI native"); @@ -216,15 +219,16 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { println!(" Serial: {}", serial.trim()); println!(" Firmware: {}", firmware.trim()); println!(" Model: {}", model.trim()); - println!(" {}-bit LBA", lba_bits); println!(" Size: {} MB", sectors / 2048); + println!(" DMA: {}", dma); + println!(" {}-bit LBA", lba_bits); disks.push(Box::new(AtaDisk { chan: chan_lock.clone(), chan_i, dev, size: sectors * 512, - dma: true, //TODO: detect! + dma, lba_48: lba_bits == 48, })); } From d3dc2e0f80d5333b2fb328142e9bf34864b62d98 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 11 Jun 2024 20:56:45 +0200 Subject: [PATCH 0903/1301] pcid: Remove all PciFunc methods --- pcid/src/driver_handler.rs | 6 ++--- pcid/src/pci/cap.rs | 28 +++++++++++++++------ pcid/src/pci/func.rs | 27 -------------------- pcid/src/pci/msi.rs | 50 +++++++++++++++++++------------------- 4 files changed, 48 insertions(+), 63 deletions(-) diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 77f1729829..8bb18f4db3 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use std::thread; use log::{error, info}; -use pci_types::PciAddress; +use pci_types::{ConfigRegionAccess, PciAddress}; use crate::driver_interface; use crate::pci::cap::Capability as PciCapability; @@ -303,12 +303,12 @@ impl DriverHandler { } }, PcidClientRequest::ReadConfig(offset) => { - let value = unsafe { func.read_u32(offset) }; + let value = unsafe { self.state.pcie.read(self.addr, offset) }; return PcidClientResponse::ReadConfig(value); } PcidClientRequest::WriteConfig(offset, value) => { unsafe { - func.write_u32(offset, value); + self.state.pcie.write(self.addr, offset, value); } return PcidClientResponse::WriteConfig; } diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 06e1436f5f..39cc0ff329 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -24,7 +24,7 @@ impl<'a> Iterator for CapabilitiesIter<'a> { if self.offset == 0 { return None }; - let first_dword = self.func.read_u32(u16::from(self.offset)); + let first_dword = self.func.pci.read(self.func.addr, u16::from(self.offset)); let next = ((first_dword >> 8) & 0xFF) as u8; let offset = self.offset; @@ -139,17 +139,29 @@ impl Capability { unsafe fn parse_msix(func: &PciFunc, offset: u8) -> Self { Self::MsiX(MsixCapability { cap_offset: offset, - a: func.read_u32(u16::from(offset)), - b: func.read_u32(u16::from(offset + 4)), - c: func.read_u32(u16::from(offset + 8)), + a: func.pci.read(func.addr, u16::from(offset)), + b: func.pci.read(func.addr, u16::from(offset + 4)), + c: func.pci.read(func.addr, u16::from(offset + 8)), }) } unsafe fn parse_vendor(func: &PciFunc, offset: u8) -> Self { - let next = func.read_u8(u16::from(offset+1)); - let length = func.read_u8(u16::from(offset+2)); + let dword = func.pci.read(func.addr, u16::from(offset)); + let next = (dword >> 8) & 0xFF; + let length = ((dword >> 16) & 0xFF) as u16; log::info!("Vendor specific offset: {offset:#02x} next: {next:#02x} cap len: {length:#02x}"); let data = if length > 0 { - let mut raw_data = func.read_range(offset.into(), length.into()); + assert!( + length > 3 && length % 4 == 0, + "invalid range length: {}", + length + ); + let offset = u16::from(offset); + let mut raw_data = { + (offset..offset + length) + .step_by(4) + .flat_map(|offset| func.pci.read(func.addr, offset).to_le_bytes()) + .collect::>() + }; raw_data.drain(3..).collect() } else { log::warn!("Vendor specific capability is invalid"); @@ -162,7 +174,7 @@ impl Capability { unsafe fn parse(func: &PciFunc, offset: u8) -> Self { assert_eq!(offset & 0xFC, offset, "capability must be dword aligned"); - let dword = func.read_u32(u16::from(offset)); + let dword = func.pci.read(func.addr, u16::from(offset)); let capability_id = (dword & 0xFF) as u8; if capability_id == CapabilityId::Msi as u8 { diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs index 7caec137a8..259a74542b 100644 --- a/pcid/src/pci/func.rs +++ b/pcid/src/pci/func.rs @@ -4,30 +4,3 @@ pub struct PciFunc<'pci> { pub pci: &'pci dyn ConfigRegionAccess, pub addr: PciAddress, } - -impl<'pci> PciFunc<'pci> { - pub unsafe fn read_range(&self, offset: u16, len: u16) -> Vec { - assert!(len > 3 && len % 4 == 0, "invalid range length: {}", len); - (offset..offset + len) - .step_by(4) - .flat_map(|offset| self.read_u32(offset).to_le_bytes()) - .collect::>() - } - - pub unsafe fn read_u8(&self, offset: u16) -> u8 { - let dword_offset = (offset / 4) * 4; - let dword = self.read_u32(dword_offset); - - let shift = (offset % 4) * 8; - ((dword >> shift) & 0xFF) as u8 - } - - pub unsafe fn read_u32(&self, offset: u16) -> u32 { - self.pci.read(self.addr, offset) - } -} -impl<'pci> PciFunc<'pci> { - pub unsafe fn write_u32(&self, offset: u16, value: u32) { - self.pci.write(self.addr, offset, value); - } -} diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 2af0c43d99..4c43ff0920 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -43,7 +43,7 @@ impl MsiCapability { const MC_MSI_ENABLED_BIT: u16 = 1; pub(crate) unsafe fn parse(func: &PciFunc, offset: u8) -> Self { - let dword = func.read_u32(u16::from(offset)); + let dword = func.pci.read(func.addr, u16::from(offset)); let message_control = (dword >> 16) as u16; @@ -52,20 +52,20 @@ impl MsiCapability { Self::_64BitAddressWithPvm { cap_offset: offset, message_control: dword, - message_address_lo: func.read_u32(u16::from(offset + 4)), - message_address_hi: func.read_u32(u16::from(offset + 8)), - message_data: func.read_u32(u16::from(offset + 12)), - mask_bits: func.read_u32(u16::from(offset + 16)), - pending_bits: func.read_u32(u16::from(offset + 20)), + message_address_lo: func.pci.read(func.addr, u16::from(offset + 4)), + message_address_hi: func.pci.read(func.addr, u16::from(offset + 8)), + message_data: func.pci.read(func.addr, u16::from(offset + 12)), + mask_bits: func.pci.read(func.addr, u16::from(offset + 16)), + pending_bits: func.pci.read(func.addr, u16::from(offset + 20)), } } else { Self::_32BitAddressWithPvm { cap_offset: offset, message_control: dword, - message_address: func.read_u32(u16::from(offset + 4)), - message_data: func.read_u32(u16::from(offset + 8)), - mask_bits: func.read_u32(u16::from(offset + 12)), - pending_bits: func.read_u32(u16::from(offset + 16)), + message_address: func.pci.read(func.addr, u16::from(offset + 4)), + message_data: func.pci.read(func.addr, u16::from(offset + 8)), + mask_bits: func.pci.read(func.addr, u16::from(offset + 12)), + pending_bits: func.pci.read(func.addr, u16::from(offset + 16)), } } } else { @@ -73,16 +73,16 @@ impl MsiCapability { Self::_64BitAddress { cap_offset: offset, message_control: dword, - message_address_lo: func.read_u32(u16::from(offset + 4)), - message_address_hi: func.read_u32(u16::from(offset + 8)), - message_data: func.read_u32(u16::from(offset + 12)) as u16, + message_address_lo: func.pci.read(func.addr, u16::from(offset + 4)), + message_address_hi: func.pci.read(func.addr, u16::from(offset + 8)), + message_data: func.pci.read(func.addr, u16::from(offset + 12)) as u16, } } else { Self::_32BitAddress { cap_offset: offset, message_control: dword, - message_address: func.read_u32(u16::from(offset + 4)), - message_data: func.read_u32(u16::from(offset + 8)) as u16, + message_address: func.pci.read(func.addr, u16::from(offset + 4)), + message_data: func.pci.read(func.addr, u16::from(offset + 8)) as u16, } } } @@ -117,7 +117,7 @@ impl MsiCapability { } } pub(crate) unsafe fn write_message_control(&self, func: &PciFunc) { - func.write_u32(self.cap_offset(), self.message_control_raw()); + func.pci.write(func.addr, self.cap_offset(), self.message_control_raw()); } pub(crate) fn is_pvt_capable(&self) -> bool { self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 @@ -185,25 +185,25 @@ impl MsiCapability { Some(()) } unsafe fn write_message_address(&self, func: &PciFunc) { - func.write_u32(self.cap_offset() + 4, self.message_address()) + func.pci.write(func.addr, self.cap_offset() + 4, self.message_address()) } unsafe fn write_message_upper_address(&self, func: &PciFunc) -> Option<()> { let value = self.message_upper_address()?; - func.write_u32(self.cap_offset() + 8, value); + func.pci.write(func.addr, self.cap_offset() + 8, value); Some(()) } unsafe fn write_message_data(&self, func: &PciFunc) { match self { - &Self::_32BitAddress { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 8), message_data.into()), - &Self::_32BitAddressWithPvm { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 8), message_data), - &Self::_64BitAddress { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 12), message_data.into()), - &Self::_64BitAddressWithPvm { cap_offset, message_data, .. } => func.write_u32(u16::from(cap_offset + 12), message_data), + &Self::_32BitAddress { cap_offset, message_data, .. } => func.pci.write(func.addr, u16::from(cap_offset + 8), message_data.into()), + &Self::_32BitAddressWithPvm { cap_offset, message_data, .. } => func.pci.write(func.addr, u16::from(cap_offset + 8), message_data), + &Self::_64BitAddress { cap_offset, message_data, .. } => func.pci.write(func.addr, u16::from(cap_offset + 12), message_data.into()), + &Self::_64BitAddressWithPvm { cap_offset, message_data, .. } => func.pci.write(func.addr, u16::from(cap_offset + 12), message_data), } } unsafe fn write_mask_bits(&self, func: &PciFunc) -> Option<()> { match self { - &Self::_32BitAddressWithPvm { cap_offset, mask_bits, .. } => func.write_u32(u16::from(cap_offset + 12), mask_bits), - &Self::_64BitAddressWithPvm { cap_offset, mask_bits, .. } => func.write_u32(u16::from(cap_offset + 16), mask_bits), + &Self::_32BitAddressWithPvm { cap_offset, mask_bits, .. } => func.pci.write(func.addr, u16::from(cap_offset + 12), mask_bits), + &Self::_64BitAddressWithPvm { cap_offset, mask_bits, .. } => func.pci.write(func.addr, u16::from(cap_offset + 16), mask_bits), &Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => return None, } Some(()) @@ -329,7 +329,7 @@ impl MsixCapability { /// Write the first DWORD into configuration space (containing the partially modifiable Message /// Control field). pub(crate) unsafe fn write_a(&self, func: &PciFunc) { - func.write_u32(u16::from(self.cap_offset), self.a) + func.pci.write(func.addr, u16::from(self.cap_offset), self.a) } } From d2084e58cb6cbfdc8557b61567ce947e37ac191f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 11 Jun 2024 21:01:12 +0200 Subject: [PATCH 0904/1301] pcid: Remove PciFunc --- pcid/src/driver_handler.rs | 18 +++----- pcid/src/main.rs | 15 ++++--- pcid/src/pci/cap.rs | 89 ++++++++++++++++++++------------------ pcid/src/pci/func.rs | 6 --- pcid/src/pci/mod.rs | 2 - pcid/src/pci/msi.rs | 87 +++++++++++++++++++------------------ pcid/src/pci_header.rs | 4 +- 7 files changed, 108 insertions(+), 113 deletions(-) delete mode 100644 pcid/src/pci/func.rs diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 8bb18f4db3..8cf114276f 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -9,7 +9,6 @@ use pci_types::{ConfigRegionAccess, PciAddress}; use crate::driver_interface; use crate::pci::cap::Capability as PciCapability; -use crate::pci::PciFunc; use crate::State; pub struct DriverHandler { @@ -101,11 +100,6 @@ impl DriverHandler { use crate::pci::cap::{MsiCapability, MsixCapability}; use driver_interface::*; - let func = PciFunc { - pci: &self.state.pcie, - addr: self.addr, - }; - match request { PcidClientRequest::RequestCapabilities => PcidClientResponse::Capabilities( self.capabilities @@ -135,7 +129,7 @@ impl DriverHandler { // active at the same time. unsafe { msix_capability.set_msix_enabled(false); - msix_capability.write_a(&func); + msix_capability.write_a(self.addr, &self.state.pcie); } } @@ -153,7 +147,7 @@ impl DriverHandler { }; unsafe { capability.set_enabled(true); - capability.write_message_control(&func); + capability.write_message_control(self.addr, &self.state.pcie); } PcidClientResponse::FeatureEnabled(feature) } @@ -167,7 +161,7 @@ impl DriverHandler { // active at the same time. unsafe { msi_capability.set_enabled(false); - msi_capability.write_message_control(&func); + msi_capability.write_message_control(self.addr, &self.state.pcie); } } @@ -185,7 +179,7 @@ impl DriverHandler { }; unsafe { capability.set_msix_enabled(true); - capability.write_a(&func); + capability.write_a(self.addr, &self.state.pcie); } PcidClientResponse::FeatureEnabled(feature) } @@ -273,7 +267,7 @@ impl DriverHandler { info.set_mask_bits(mask_bits); } unsafe { - info.write_all(&func); + info.write_all(self.addr, &self.state.pcie); } PcidClientResponse::SetFeatureInfo(PciFeature::Msi) } else { @@ -291,7 +285,7 @@ impl DriverHandler { if let Some(mask) = function_mask { info.set_function_mask(mask); unsafe { - info.write_a(&func); + info.write_a(self.addr, &self.state.pcie); } } PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 648a291a4c..039e0fd2ea 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -4,6 +4,7 @@ use std::sync::{Arc, Mutex}; use std::thread; use log::{debug, info, trace, warn}; +use pci_types::capability::PciCapabilityAddress; use pci_types::{CommandRegister, PciAddress}; use redox_log::{OutputBuilder, RedoxLogger}; use structopt::StructOpt; @@ -11,7 +12,6 @@ use structopt::StructOpt; use crate::cfg_access::Pcie; use crate::config::Config; use crate::driver_interface::LegacyInterruptLine; -use crate::pci::PciFunc; use crate::pci_header::{PciEndpointHeader, PciHeader, PciHeaderError}; mod cfg_access; @@ -98,11 +98,14 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH }; let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { - let func = PciFunc { - pci: &state.pcie, - addr: header.address(), - }; - crate::pci::cap::CapabilitiesIter::new(header.cap_pointer(), &func).collect::>() + crate::pci::cap::CapabilitiesIter::new( + PciCapabilityAddress { + address: header.address(), + offset: header.cap_pointer(), + }, + &state.pcie, + ) + .collect::>() } else { Vec::new() }; diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 39cc0ff329..47dc68fc55 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -1,40 +1,39 @@ -use super::func::PciFunc; - +use pci_types::capability::PciCapabilityAddress; +use pci_types::ConfigRegionAccess; use serde::{Serialize, Deserialize}; pub struct CapabilitiesIter<'a> { - offset: u8, - func: &'a PciFunc<'a>, + addr: PciCapabilityAddress, + access: &'a dyn ConfigRegionAccess, } impl<'a> CapabilitiesIter<'a> { - pub fn new(offset: u8, func: &'a PciFunc) -> Self { - Self { - offset, - func, - } + pub fn new(addr: PciCapabilityAddress, access: &'a dyn ConfigRegionAccess) -> Self { + Self { addr, access } } } impl<'a> Iterator for CapabilitiesIter<'a> { type Item = Capability; fn next(&mut self) -> Option { - let offset = unsafe { + let addr = unsafe { // mask RsvdP bits - self.offset = self.offset & 0xFC; + self.addr.offset = self.addr.offset & 0xFC; - if self.offset == 0 { return None }; + if self.addr.offset == 0 { + return None; + }; - let first_dword = self.func.pci.read(self.func.addr, u16::from(self.offset)); - let next = ((first_dword >> 8) & 0xFF) as u8; + let first_dword = self.access.read(self.addr.address, self.addr.offset); + let next = ((first_dword >> 8) & 0xFF) as u16; - let offset = self.offset; - self.offset = next; + let addr = self.addr; + self.addr.offset = next; - offset + addr }; let cap = unsafe { - Capability::parse(self.func, offset) + Capability::parse(addr, self.access) }; Some(cap) @@ -56,20 +55,20 @@ pub enum CapabilityId { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub enum MsiCapability { _32BitAddress { - cap_offset: u8, + cap_offset: u16, message_control: u32, message_address: u32, message_data: u16, }, _64BitAddress { - cap_offset: u8, + cap_offset: u16, message_control: u32, message_address_lo: u32, message_address_hi: u32, message_data: u16, }, _32BitAddressWithPvm { - cap_offset: u8, + cap_offset: u16, message_control: u32, message_address: u32, message_data: u32, @@ -77,7 +76,7 @@ pub enum MsiCapability { pending_bits: u32, }, _64BitAddressWithPvm { - cap_offset: u8, + cap_offset: u16, message_control: u32, message_address_lo: u32, message_address_hi: u32, @@ -89,7 +88,7 @@ pub enum MsiCapability { #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct MsixCapability { - pub cap_offset: u8, + pub cap_offset: u16, pub a: u32, pub b: u32, pub c: u32, @@ -133,33 +132,35 @@ impl Capability { _ => None, } } - unsafe fn parse_msi(func: &PciFunc, offset: u8) -> Self { - Self::Msi(MsiCapability::parse(func, offset)) + unsafe fn parse_msi(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { + Self::Msi(MsiCapability::parse(addr, access)) } - unsafe fn parse_msix(func: &PciFunc, offset: u8) -> Self { + unsafe fn parse_msix(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { Self::MsiX(MsixCapability { - cap_offset: offset, - a: func.pci.read(func.addr, u16::from(offset)), - b: func.pci.read(func.addr, u16::from(offset + 4)), - c: func.pci.read(func.addr, u16::from(offset + 8)), + cap_offset: addr.offset, + a: access.read(addr.address, addr.offset), + b: access.read(addr.address, addr.offset + 4), + c: access.read(addr.address, addr.offset + 8), }) } - unsafe fn parse_vendor(func: &PciFunc, offset: u8) -> Self { - let dword = func.pci.read(func.addr, u16::from(offset)); + unsafe fn parse_vendor(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { + let dword = access.read(addr.address, addr.offset); let next = (dword >> 8) & 0xFF; let length = ((dword >> 16) & 0xFF) as u16; - log::info!("Vendor specific offset: {offset:#02x} next: {next:#02x} cap len: {length:#02x}"); + log::info!( + "Vendor specific offset: {:#02x} next: {next:#02x} cap len: {length:#02x}", + addr.offset + ); let data = if length > 0 { assert!( length > 3 && length % 4 == 0, "invalid range length: {}", length ); - let offset = u16::from(offset); let mut raw_data = { - (offset..offset + length) + (addr.offset..addr.offset + length) .step_by(4) - .flat_map(|offset| func.pci.read(func.addr, offset).to_le_bytes()) + .flat_map(|offset| access.read(addr.address, offset).to_le_bytes()) .collect::>() }; raw_data.drain(3..).collect() @@ -171,18 +172,22 @@ impl Capability { data }) } - unsafe fn parse(func: &PciFunc, offset: u8) -> Self { - assert_eq!(offset & 0xFC, offset, "capability must be dword aligned"); + unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { + assert_eq!( + addr.offset & 0xFC, + addr.offset, + "capability must be dword aligned" + ); - let dword = func.pci.read(func.addr, u16::from(offset)); + let dword = access.read(addr.address, addr.offset); let capability_id = (dword & 0xFF) as u8; if capability_id == CapabilityId::Msi as u8 { - Self::parse_msi(func, offset) + Self::parse_msi(addr, access) } else if capability_id == CapabilityId::MsiX as u8 { - Self::parse_msix(func, offset) + Self::parse_msix(addr, access) } else if capability_id == CapabilityId::Vendor as u8 { - Self::parse_vendor(func, offset) + Self::parse_vendor(addr, access) } else { if capability_id != CapabilityId::Pcie as u8 && capability_id != CapabilityId::PwrMgmt as u8 diff --git a/pcid/src/pci/func.rs b/pcid/src/pci/func.rs deleted file mode 100644 index 259a74542b..0000000000 --- a/pcid/src/pci/func.rs +++ /dev/null @@ -1,6 +0,0 @@ -use pci_types::{ConfigRegionAccess, PciAddress}; - -pub struct PciFunc<'pci> { - pub pci: &'pci dyn ConfigRegionAccess, - pub addr: PciAddress, -} diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index b8080263f5..2db9368d9b 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,10 +1,8 @@ pub use self::bar::PciBar; -pub use self::func::PciFunc; pub use self::id::FullDeviceId; pub use pci_types::PciAddress; mod bar; pub mod cap; -pub mod func; mod id; pub mod msi; diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 4c43ff0920..727d36695f 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -2,8 +2,9 @@ use std::fmt; use super::bar::PciBar; pub use super::cap::{MsiCapability, MsixCapability}; -use super::func::PciFunc; +use pci_types::capability::PciCapabilityAddress; +use pci_types::{ConfigRegionAccess, PciAddress}; use serde::{Deserialize, Serialize}; use syscall::{Io, Mmio}; @@ -42,47 +43,47 @@ impl MsiCapability { const MC_MSI_ENABLED_BIT: u16 = 1; - pub(crate) unsafe fn parse(func: &PciFunc, offset: u8) -> Self { - let dword = func.pci.read(func.addr, u16::from(offset)); + pub(crate) unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { + let dword = access.read(addr.address, addr.offset); let message_control = (dword >> 16) as u16; if message_control & Self::MC_PVT_CAPABLE_BIT != 0 { if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { Self::_64BitAddressWithPvm { - cap_offset: offset, + cap_offset: addr.offset, message_control: dword, - message_address_lo: func.pci.read(func.addr, u16::from(offset + 4)), - message_address_hi: func.pci.read(func.addr, u16::from(offset + 8)), - message_data: func.pci.read(func.addr, u16::from(offset + 12)), - mask_bits: func.pci.read(func.addr, u16::from(offset + 16)), - pending_bits: func.pci.read(func.addr, u16::from(offset + 20)), + message_address_lo: access.read(addr.address, addr.offset + 4), + message_address_hi: access.read(addr.address, addr.offset + 8), + message_data: access.read(addr.address, addr.offset + 12), + mask_bits: access.read(addr.address, addr.offset + 16), + pending_bits: access.read(addr.address, addr.offset + 20), } } else { Self::_32BitAddressWithPvm { - cap_offset: offset, + cap_offset: addr.offset, message_control: dword, - message_address: func.pci.read(func.addr, u16::from(offset + 4)), - message_data: func.pci.read(func.addr, u16::from(offset + 8)), - mask_bits: func.pci.read(func.addr, u16::from(offset + 12)), - pending_bits: func.pci.read(func.addr, u16::from(offset + 16)), + message_address: access.read(addr.address, addr.offset + 4), + message_data: access.read(addr.address, addr.offset + 8), + mask_bits: access.read(addr.address, addr.offset + 12), + pending_bits: access.read(addr.address, addr.offset + 16), } } } else { if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { Self::_64BitAddress { - cap_offset: offset, + cap_offset: addr.offset, message_control: dword, - message_address_lo: func.pci.read(func.addr, u16::from(offset + 4)), - message_address_hi: func.pci.read(func.addr, u16::from(offset + 8)), - message_data: func.pci.read(func.addr, u16::from(offset + 12)) as u16, + message_address_lo: access.read(addr.address, addr.offset + 4), + message_address_hi: access.read(addr.address, addr.offset + 8), + message_data: access.read(addr.address, addr.offset + 12) as u16, } } else { Self::_32BitAddress { - cap_offset: offset, + cap_offset: addr.offset, message_control: dword, - message_address: func.pci.read(func.addr, u16::from(offset + 4)), - message_data: func.pci.read(func.addr, u16::from(offset + 8)) as u16, + message_address: access.read(addr.address, addr.offset + 4), + message_data: access.read(addr.address, addr.offset + 8) as u16, } } } @@ -116,8 +117,8 @@ impl MsiCapability { | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, } } - pub(crate) unsafe fn write_message_control(&self, func: &PciFunc) { - func.pci.write(func.addr, self.cap_offset(), self.message_control_raw()); + pub(crate) unsafe fn write_message_control(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) { + access.write(addr, self.cap_offset(), self.message_control_raw()); } pub(crate) fn is_pvt_capable(&self) -> bool { self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 @@ -184,36 +185,36 @@ impl MsiCapability { } Some(()) } - unsafe fn write_message_address(&self, func: &PciFunc) { - func.pci.write(func.addr, self.cap_offset() + 4, self.message_address()) + unsafe fn write_message_address(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) { + access.write(addr, self.cap_offset() + 4, self.message_address()) } - unsafe fn write_message_upper_address(&self, func: &PciFunc) -> Option<()> { + unsafe fn write_message_upper_address(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) -> Option<()> { let value = self.message_upper_address()?; - func.pci.write(func.addr, self.cap_offset() + 8, value); + access.write(addr, self.cap_offset() + 8, value); Some(()) } - unsafe fn write_message_data(&self, func: &PciFunc) { + unsafe fn write_message_data(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) { match self { - &Self::_32BitAddress { cap_offset, message_data, .. } => func.pci.write(func.addr, u16::from(cap_offset + 8), message_data.into()), - &Self::_32BitAddressWithPvm { cap_offset, message_data, .. } => func.pci.write(func.addr, u16::from(cap_offset + 8), message_data), - &Self::_64BitAddress { cap_offset, message_data, .. } => func.pci.write(func.addr, u16::from(cap_offset + 12), message_data.into()), - &Self::_64BitAddressWithPvm { cap_offset, message_data, .. } => func.pci.write(func.addr, u16::from(cap_offset + 12), message_data), + &Self::_32BitAddress { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 8), message_data.into()), + &Self::_32BitAddressWithPvm { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 8), message_data), + &Self::_64BitAddress { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 12), message_data.into()), + &Self::_64BitAddressWithPvm { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 12), message_data), } } - unsafe fn write_mask_bits(&self, func: &PciFunc) -> Option<()> { + unsafe fn write_mask_bits(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) -> Option<()> { match self { - &Self::_32BitAddressWithPvm { cap_offset, mask_bits, .. } => func.pci.write(func.addr, u16::from(cap_offset + 12), mask_bits), - &Self::_64BitAddressWithPvm { cap_offset, mask_bits, .. } => func.pci.write(func.addr, u16::from(cap_offset + 16), mask_bits), + &Self::_32BitAddressWithPvm { cap_offset, mask_bits, .. } => access.write(addr, u16::from(cap_offset + 12), mask_bits), + &Self::_64BitAddressWithPvm { cap_offset, mask_bits, .. } => access.write(addr, u16::from(cap_offset + 16), mask_bits), &Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => return None, } Some(()) } - pub(crate) unsafe fn write_all(&self, func: &PciFunc) { - self.write_message_control(func); - self.write_message_address(func); - self.write_message_upper_address(func); - self.write_message_data(func); - self.write_mask_bits(func); + pub(crate) unsafe fn write_all(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) { + self.write_message_control(addr, access); + self.write_message_address(addr, access); + self.write_message_upper_address(addr, access); + self.write_message_data(addr, access); + self.write_mask_bits(addr, access); } } @@ -328,8 +329,8 @@ impl MsixCapability { /// Write the first DWORD into configuration space (containing the partially modifiable Message /// Control field). - pub(crate) unsafe fn write_a(&self, func: &PciFunc) { - func.pci.write(func.addr, u16::from(self.cap_offset), self.a) + pub(crate) unsafe fn write_a(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) { + access.write(addr, u16::from(self.cap_offset), self.a) } } diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 5e450ca26c..4779427aea 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -23,7 +23,7 @@ pub struct PciEndpointHeader { shared: SharedPciHeader, subsystem_vendor_id: u16, subsystem_id: u16, - cap_pointer: u8, + cap_pointer: u16, } #[derive(Clone, Copy, Debug, PartialEq)] @@ -240,7 +240,7 @@ impl PciEndpointHeader { bars } - pub fn cap_pointer(&self) -> u8 { + pub fn cap_pointer(&self) -> u16 { self.cap_pointer } } From 32bcf25f99a6ea1ba91d68fbb3d3dc80ae008da5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 13 Jun 2024 17:22:23 +0200 Subject: [PATCH 0905/1301] virtio-blkd: Do not crash when the disk is empty --- storage/virtio-blkd/src/main.rs | 2 -- storage/virtio-blkd/src/scheme.rs | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 1c13166341..9d71b3a8d1 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -1,8 +1,6 @@ #![deny(trivial_numeric_casts, unused_allocation)] #![feature(int_roundings)] -// TODO(andypython): driver panic with an empty disk. - use std::fs::File; use std::io::{Read, Write}; use std::os::fd::{FromRawFd, RawFd}; diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index e981de0369..3eec34d69b 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -184,10 +184,10 @@ impl<'a> DiskScheme<'a> { }; let part_table = partitionlib::get_partitions(&mut shim, LogicalBlockSize::Lb512) - .unwrap() - .expect("virtiod: no partitions found"); + .ok() + .flatten(); - this.part_table = Some(part_table); + this.part_table = part_table; this } } From 47ce36741e4fc5c3d81fc172e560573327dfb50c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 13 Jun 2024 21:47:22 +0200 Subject: [PATCH 0906/1301] virtio-blkd: Avoid crash on ls /scheme --- storage/virtio-blkd/src/scheme.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 3eec34d69b..3b37b547ff 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -210,10 +210,10 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { // to the namespace id). write!(list, "{}\n", 0).unwrap(); - let part_table = self.part_table.as_ref().unwrap(); - - for part_num in 0..part_table.partitions.len() { - write!(list, "{}p{}\n", 0, part_num).unwrap(); + if let Some(part_table) = &self.part_table { + for part_num in 0..part_table.partitions.len() { + write!(list, "{}p{}\n", 0, part_num).unwrap(); + } } let id = self.next_id; @@ -389,8 +389,11 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { todo!() } - fn fstat(&mut self, _id: usize, _stat: &mut syscall::Stat) -> syscall::Result> { - todo!() + fn fstat(&mut self, id: usize, _stat: &mut syscall::Stat) -> syscall::Result> { + match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List { .. } => Ok(Some(0)), + Handle::Disk { .. } | Handle::Partition { .. } => todo!(), + } } fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> Result> { From 7b2f4dda90c03b5f6ee0e75ad3e4b63cae013f6f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 14 Jun 2024 08:18:45 +0200 Subject: [PATCH 0907/1301] Use scatter-gather list for virtio framebuffer. The current frame allocator limits requests to powers of two, between 4 KiB and 4 MiB. As such, a 8-bit color 1920x1080 framebuffer needs at least two allocations. --- common/src/dma.rs | 14 +++-- common/src/lib.rs | 1 + common/src/sgl.rs | 89 ++++++++++++++++++++++++++++++ graphics/virtio-gpud/src/scheme.rs | 76 ++++++++++++------------- 4 files changed, 134 insertions(+), 46 deletions(-) create mode 100644 common/src/sgl.rs diff --git a/common/src/dma.rs b/common/src/dma.rs index 1adbbc6392..4c723a001b 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -20,14 +20,18 @@ const DMA_MEMTY: MemoryType = { } }; +pub(crate) fn phys_contiguous_fd() -> Result { + Fd::open( + &format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), + flag::O_CLOEXEC, + 0, + ) +} + fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> { assert_eq!(length % PAGE_SIZE, 0); unsafe { - let fd = Fd::open( - &format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), - flag::O_CLOEXEC, - 0, - )?; + let fd = phys_contiguous_fd()?; let virt = libredox::call::mmap(MmapArgs { fd: fd.raw(), offset: 0, // ignored diff --git a/common/src/lib.rs b/common/src/lib.rs index 2107a08660..b22d93bcda 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -6,6 +6,7 @@ use libredox::flag::{self, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; use syscall::PAGE_SIZE; pub mod dma; +pub mod sgl; #[derive(Clone, Copy, Debug)] pub enum MemoryType { diff --git a/common/src/sgl.rs b/common/src/sgl.rs new file mode 100644 index 0000000000..236ab85a05 --- /dev/null +++ b/common/src/sgl.rs @@ -0,0 +1,89 @@ +use std::num::NonZeroUsize; + +use libredox::call::MmapArgs; +use libredox::errno::EINVAL; +use libredox::error::{Error, Result}; +use libredox::flag::{MAP_PRIVATE, PROT_READ, PROT_WRITE}; +use syscall::{MAP_FIXED, PAGE_SIZE}; + +use crate::dma::phys_contiguous_fd; + +#[derive(Debug)] +pub struct Sgl { + virt: *mut u8, + unaligned_length: NonZeroUsize, + chunks: Vec, +} +#[derive(Debug)] +pub struct Chunk { + pub offset: usize, + pub phys: usize, + pub virt: *mut u8, + pub length: usize, +} + +impl Sgl { + pub fn new(unaligned_length: usize) -> Result { + let unaligned_length = NonZeroUsize::new(unaligned_length).ok_or(Error::new(EINVAL))?; + + unsafe { + let virt = libredox::call::mmap(MmapArgs { + flags: MAP_PRIVATE, + prot: PROT_READ | PROT_WRITE, + length: unaligned_length.get(), + + offset: 0, + fd: !0, + addr: core::ptr::null_mut(), + })?.cast::(); + + let mut this = Self { + virt, + unaligned_length, + chunks: Vec::new(), + }; + + let phys_contiguous_fd = phys_contiguous_fd()?; + + // TODO: Both PAGE_SIZE and MAX_ALLOC_SIZE should be dynamic. + let aligned_length = unaligned_length.get().next_multiple_of(PAGE_SIZE); + const MAX_ALLOC_SIZE: usize = 1 << 22; + + let mut offset = 0; + while offset < unaligned_length.get() { + let chunk_length = (aligned_length - offset).min(MAX_ALLOC_SIZE).next_power_of_two(); + libredox::call::mmap(MmapArgs { + addr: virt.add(offset).cast(), + flags: MAP_PRIVATE | (MAP_FIXED.bits() as u32), + prot: PROT_READ | PROT_WRITE, + length: chunk_length, + fd: phys_contiguous_fd.raw(), + + offset: 0, + })?; + let phys = syscall::virttophys(virt as usize + offset)?; + this.chunks.push(Chunk { offset, phys, length: (unaligned_length.get() - offset).min(chunk_length), virt: virt.add(offset) }); + offset += chunk_length; + } + + Ok(this) + } + } + pub fn chunks(&self) -> &[Chunk] { + &self.chunks + } + pub fn as_ptr(&self) -> *mut u8 { + self.virt + } + pub fn len(&self) -> usize { + self.unaligned_length.get() + } +} + +impl Drop for Sgl { + fn drop(&mut self) { + unsafe { + let _ = libredox::call::munmap(self.virt.cast(), self.unaligned_length.get()); + } + } +} diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 907ebc873e..4782dfca59 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -1,12 +1,13 @@ +use std::cell::OnceCell; use std::collections::BTreeMap; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; use std::sync::Arc; use inputd::Damage; -use common::dma::Dma; +use common::{dma::Dma, sgl}; -use syscall::{Error as SysError, SchemeMut, EAGAIN, EINVAL, MapFlags, PAGE_SIZE, KSMSG_MMAP, KSMSG_MMAP_PREP, KSMSG_MSYNC, KSMSG_MUNMAP}; +use syscall::{Error as SysError, MapFlags, SchemeMut, EAGAIN, EINVAL, PAGE_SIZE}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::{Error, Queue, Transport}; @@ -32,9 +33,7 @@ pub struct Display<'a> { cursor_queue: Arc>, transport: Arc, - // TODO(andypython): Remove the need for the spin crate after the `once_cell` - // API is stabilized. - mapped: spin::Once, + mapped: OnceCell, width: u32, height: u32, @@ -56,7 +55,7 @@ impl<'a> Display<'a> { control_queue, cursor_queue, - mapped: spin::Once::new(), + mapped: OnceCell::new(), width: 1920, height: 1080, @@ -111,46 +110,41 @@ impl<'a> Display<'a> { Ok(()) } - async fn remap_screen(&self) -> Result { + // TODO: Is this a no-op? + async fn remap_screen(&self) -> Result<*mut u8, Error> { let bpp = 32; - let fb_size = (self.width as usize * self.height as usize * bpp / 8) - .next_multiple_of(syscall::PAGE_SIZE); - let mapped = *self.mapped.get().unwrap(); - let address = (unsafe { syscall::virttophys(mapped) }).map_err(libredox::error::Error::from)?; + let fb_size = self.width as usize * self.height as usize * bpp / 8; - self.map_screen_with(0, address, fb_size, mapped).await + let mapped = self.mapped.get().unwrap(); + self.map_screen_with(0, fb_size, mapped.as_ptr(), mapped.chunks()).await } - async fn map_screen(&self, offset: usize) -> Result { + async fn map_screen(&self, offset: usize) -> Result<*mut u8, Error> { if let Some(mapped) = self.mapped.get() { - return Ok(mapped + offset); + return Ok(mapped.as_ptr().wrapping_add(offset)); } let bpp = 32; - let fb_size = (self.width as usize * self.height as usize * bpp / 8) - .next_multiple_of(syscall::PAGE_SIZE); - let mut mapped = unsafe { Dma::zeroed_slice(fb_size)?.assume_init() }; + let fb_size = self.width as usize * self.height as usize * bpp / 8; + let mapped = sgl::Sgl::new(fb_size)?; unsafe { - core::ptr::write_bytes(mapped.as_mut_ptr() as *mut u8, 255, fb_size); + core::ptr::write_bytes(mapped.as_ptr() as *mut u8, 255, fb_size); } + let _ = self.mapped.set(mapped); + let mapped = self.mapped.get().unwrap(); - let virt = mapped.as_mut_ptr() as usize; - let phys = mapped.physical(); - core::mem::forget(mapped); - // TODO: Keep Dma - - self.map_screen_with(offset, phys, fb_size, virt).await + self.map_screen_with(offset, fb_size, mapped.as_ptr(), mapped.chunks()).await } async fn map_screen_with( &self, offset: usize, - address: usize, - size: usize, - mapped: usize, - ) -> Result { + _size: usize, + virt: *mut u8, + chunks: &[sgl::Chunk], + ) -> Result<*mut u8, Error> { // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. let mut request = Dma::new(ResourceCreate2d::default())?; @@ -163,20 +157,21 @@ impl<'a> Display<'a> { // Use the allocated framebuffer from tthe guest ram, and attach it as backing // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. - // - // TODO(andypython): Scatter lists are supported, so the framebuffer doesn’t need to be - // contignous in guest physical memory. - let entry = Dma::new(MemEntry { - address: address as u64, - length: size as u32, - padding: 0, - })?; - let attach_request = Dma::new(AttachBacking::new(self.resource_id, 1))?; + let mut mem_entries = unsafe { Dma::zeroed_slice(chunks.len())?.assume_init() }; + for (entry, chunk) in mem_entries.iter_mut().zip(chunks.iter()) { + *entry = MemEntry { + address: chunk.phys as u64, + length: chunk.length.next_multiple_of(PAGE_SIZE) as u32, + padding: 0, + }; + } + + let attach_request = Dma::new(AttachBacking::new(self.resource_id, mem_entries.len() as u32))?; let header = Dma::new(ControlHeader::default())?; let command = ChainBuilder::new() .chain(Buffer::new(&attach_request)) - .chain(Buffer::new(&entry)) + .chain(Buffer::new_unsized(&mem_entries)) .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) .build(); @@ -192,9 +187,8 @@ impl<'a> Display<'a> { assert_eq!(header.ty.get(), CommandTy::RespOkNodata); self.flush(None).await?; - self.mapped.call_once(|| mapped); - Ok(mapped + offset) + Ok(virt.wrapping_add(offset)) } /// If `damage` is `None`, the entire screen is flushed. @@ -473,7 +467,7 @@ impl<'a> SchemeMut for Scheme<'a> { log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { Handle::Vt { display, .. } => { - Ok(futures::executor::block_on(display.map_screen(offset as usize)).unwrap()) + Ok(futures::executor::block_on(display.map_screen(offset as usize)).unwrap() as usize) } _ => unreachable!(), } From 019779daee62e3d73c1cf144e72e0f4d8a8861cc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 14 Jun 2024 11:06:49 +0200 Subject: [PATCH 0908/1301] Use hex pci id's in initfs.toml This is consistent with the pcid configs for non-initfs drivers. --- initfs.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/initfs.toml b/initfs.toml index 62479eaee7..c2a22fbaff 100644 --- a/initfs.toml +++ b/initfs.toml @@ -25,13 +25,13 @@ command = ["nvmed"] name = "virtio-blk" class = 1 subclass = 0 -vendor = 6900 -device = 4097 +vendor = 0x1AF4 +device = 0x1001 command = ["virtio-blkd"] [[drivers]] name = "virtio-gpu" class = 3 -vendor = 6900 -device = 4176 +vendor = 0x1AF4 +device = 0x1050 command = ["virtio-gpud"] From 386a63df422f3b2d5e6eb01bccbea3bae1f202c7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 11 Jun 2024 19:18:30 +0200 Subject: [PATCH 0909/1301] pcid: Replace get_capabilities with get_vendor_capabilities While this stops returning raw MSI/MSI-X capabilities from get_capabilities, the same info can be obtained using fetch_all_features and feature_info. --- pcid/src/driver_handler.rs | 7 +++++-- pcid/src/driver_interface/mod.rs | 14 +++++++------- virtio-core/src/probe.rs | 12 +----------- 3 files changed, 13 insertions(+), 20 deletions(-) diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 8cf114276f..c1b08d0937 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -101,10 +101,13 @@ impl DriverHandler { use driver_interface::*; match request { - PcidClientRequest::RequestCapabilities => PcidClientResponse::Capabilities( + PcidClientRequest::RequestVendorCapabilities => PcidClientResponse::VendorCapabilities( self.capabilities .iter() - .map(|capability| capability.clone()) + .filter_map(|capability| match capability { + PciCapability::Vendor(capability) => Some(capability.clone()), + _ => None, + }) .collect::>(), ), PcidClientRequest::RequestConfig => PcidClientResponse::Config(args.clone()), diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 4ba2eb789e..70bb982c33 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -8,7 +8,7 @@ use std::os::unix::io::{FromRawFd, RawFd}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use thiserror::Error; -pub use crate::pci::cap::Capability; +pub use crate::pci::cap::VendorSpecificCapability; pub use crate::pci::msi; pub use crate::pci::{FullDeviceId, PciAddress, PciBar}; @@ -192,7 +192,7 @@ pub enum SetFeatureInfo { pub enum PcidClientRequest { RequestConfig, RequestFeatures, - RequestCapabilities, + RequestVendorCapabilities, EnableFeature(PciFeature), FeatureInfo(PciFeature), SetFeatureInfo(SetFeatureInfo), @@ -210,9 +210,9 @@ pub enum PcidServerResponseError { #[derive(Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum PcidClientResponse { - Capabilities(Vec), Config(SubdriverArguments), AllFeatures(Vec), + VendorCapabilities(Vec), FeatureEnabled(PciFeature), FeatureStatus(PciFeature, FeatureStatus), Error(PcidServerResponseError), @@ -247,7 +247,7 @@ pub(crate) fn recv(r: &mut R) -> Result { if length > 0x100_000 { panic!("pcid_interface: buffer too large"); } - let mut data = vec! [0u8; length as usize]; + let mut data = vec![0u8; length as usize]; r.read_exact(&mut data)?; Ok(bincode::deserialize_from(&data[..])?) @@ -277,11 +277,11 @@ impl PcidServerHandle { } } - pub fn get_capabilities(&mut self) -> Result> { - self.send(&PcidClientRequest::RequestCapabilities)?; + pub fn get_vendor_capabilities(&mut self) -> Result> { + self.send(&PcidClientRequest::RequestVendorCapabilities)?; match self.recv()? { - PcidClientResponse::Capabilities(a) => Ok(a), + PcidClientResponse::VendorCapabilities(a) => Ok(a), other => Err(PcidClientHandleError::InvalidResponse(other)), } } diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 7650736993..3cd6d8d8fb 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -71,17 +71,7 @@ pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result let mut notify_addr = None; let mut device_addr = None; - for raw_capability in pcid_handle - .get_capabilities()? - .iter() - .filter_map(|capability| { - if let Capability::Vendor(vendor) = capability { - Some(vendor) - } else { - None - } - }) - { + for raw_capability in pcid_handle.get_vendor_capabilities()? { // SAFETY: We have verified that the length of the data is correct. let capability = unsafe { &*(raw_capability.data.as_ptr() as *const PciCapability) }; From 0ccf87f3572f0b4102c71bbf2567da2bea63499c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 11 Jun 2024 17:05:21 +0200 Subject: [PATCH 0910/1301] Use schemev2 for ahcid. --- Cargo.lock | 205 +++++++++++++++++++----------------- Cargo.toml | 1 + storage/ahcid/Cargo.toml | 4 +- storage/ahcid/src/main.rs | 87 ++++++--------- storage/ahcid/src/scheme.rs | 12 +-- 5 files changed, 156 insertions(+), 153 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ad80b39ff7..cee523d05a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,8 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", + "redox-scheme", + "redox_event", "redox_syscall 0.5.1", ] @@ -115,9 +117,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arrayvec" @@ -138,9 +140,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "base64" @@ -212,9 +214,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.15.4" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" @@ -224,9 +226,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.90" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cfg-if" @@ -252,9 +254,9 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", @@ -295,9 +297,9 @@ checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "crc" -version = "3.0.1" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86ec7a15cbe22e59248fc7eadb1907dab5ba09372595da4d73dd805ed4417dfe" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" dependencies = [ "crc-catalog", ] @@ -324,7 +326,7 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ - "crossbeam-utils 0.8.19", + "crossbeam-utils 0.8.20", ] [[package]] @@ -340,9 +342,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "driver-block" @@ -475,7 +477,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.66", ] [[package]] @@ -510,9 +512,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if 1.0.0", "libc", @@ -533,9 +535,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "heck" @@ -610,9 +612,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.5" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown", @@ -634,18 +636,18 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if 1.0.0", ] [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "ixgbed" @@ -678,9 +680,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libredox" @@ -717,9 +719,9 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -739,9 +741,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "num-derive" @@ -756,9 +758,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] @@ -786,7 +788,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_syscall 0.5.1", - "smallvec 1.13.1", + "smallvec 1.13.2", ] [[package]] @@ -798,7 +800,7 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "orbclient" version = "0.3.47" -source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#8de2b5ac9ff71811cde41e3085fe6722a823a7e2" +source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#563f1457890be4a81e9613bc803617482d38aa3b" dependencies = [ "libc", "libredox 0.0.2", @@ -858,7 +860,7 @@ dependencies = [ "instant", "libc", "redox_syscall 0.2.16", - "smallvec 1.13.1", + "smallvec 1.13.2", "winapi", ] @@ -874,9 +876,9 @@ dependencies = [ [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "paw" @@ -950,9 +952,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -992,9 +994,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] @@ -1012,9 +1014,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.35" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -1089,10 +1091,19 @@ checksum = "dbd7c67eb2d8e610a74a8f1e67eecd3042f87b1aebfa620de4b40257265a54f2" dependencies = [ "chrono", "log", - "smallvec 1.13.1", + "smallvec 1.13.2", "termion", ] +[[package]] +name = "redox-scheme" +version = "0.2.0" +source = "git+https://gitlab.redox-os.org/4lDO2/redox-scheme.git?branch=schemev2#aeff1a7ef5d456679437551a910e5b22a213d8a7" +dependencies = [ + "libredox 0.1.3", + "redox_syscall 0.5.1", +] + [[package]] name = "redox_event" version = "0.4.1" @@ -1124,8 +1135,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=schemev2#ef3273b17114fe02848eaccf102119fc7fdd6056" dependencies = [ "bitflags 2.5.0", ] @@ -1139,7 +1149,7 @@ checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" [[package]] name = "rehid" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/rehid.git#d3c74a8abbdb75d93260883e3378c46b3e875fa9" +source = "git+https://gitlab.redox-os.org/redox-os/rehid.git#ea48fff4901986903359cb616a9b0d0ff8d0d8b4" dependencies = [ "bitflags 2.5.0", "log", @@ -1186,9 +1196,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "ryu" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "sb16d" @@ -1256,29 +1266,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.66", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -1287,9 +1297,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -1314,9 +1324,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" dependencies = [ "serde", ] @@ -1395,9 +1405,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.53" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -1433,22 +1443,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.58" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.66", ] [[package]] @@ -1474,9 +1484,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] @@ -1508,9 +1518,9 @@ checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "usbctl" @@ -1573,9 +1583,9 @@ dependencies = [ [[package]] name = "ux" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cb3ff47e36907a6267572c1e398ff32ef78ac5131de8aa272e53846592c207e" +checksum = "3b59fc5417e036e53226bbebd90196825d358624fd5577432c4e486c95b1b096" [[package]] name = "vboxd" @@ -1732,7 +1742,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -1754,7 +1764,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.53", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1798,13 +1808,14 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -1813,45 +1824,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.52.4" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" @@ -1891,7 +1908,7 @@ dependencies = [ "redox_syscall 0.5.1", "serde", "serde_json", - "smallvec 1.13.1", + "smallvec 1.13.2", "thiserror", "toml 0.5.11", ] diff --git a/Cargo.toml b/Cargo.toml index 65715466f7..98a246a883 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,3 +47,4 @@ lto = "fat" mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } redox-daemon = { git = "https://gitlab.redox-os.org/redox-os/redox-daemon.git" } +redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "schemev2", features = ["std"] } diff --git a/storage/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml index 5cc6e7f0b9..746a660bc3 100644 --- a/storage/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ahcid" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] bitflags = "1.2" @@ -15,3 +15,5 @@ common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } libredox = "0.1.3" +redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2" } +redox_event = "0.4" diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 4f19891cf0..7aae947b78 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -4,21 +4,18 @@ extern crate syscall; extern crate byteorder; -use std::fs::File; -use std::io::{ErrorKind, Read, Write}; +use std::io::{Read, Write}; use std::os::fd::AsRawFd; -use std::os::unix::io::{FromRawFd, RawFd}; use std::usize; -use libredox::flag; +use event::{EventFlags, RawEventQueue}; use pcid_interface::PcidServerHandle; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; use syscall::error::{Error, ENODEV}; -use syscall::data::{Event, Packet}; -use syscall::flag::EVENT_READ; -use syscall::scheme::SchemeBlockMut; use log::{error, info}; use redox_log::{OutputBuilder, RedoxLogger}; +use syscall::{EAGAIN, EWOULDBLOCK}; use crate::scheme::DiskScheme; @@ -94,31 +91,17 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { bar.physmap_mem("ahcid") }; { let scheme_name = format!("disk.{}", name); - let socket_fd = libredox::call::open( - &format!(":{}", scheme_name), - flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, - 0, - ).expect("ahcid: failed to create disk scheme"); - let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + let socket = Socket::::nonblock(&scheme_name).expect("ahcid: failed to create disk scheme"); let mut irq_file = irq.irq_handle("ahcid"); let irq_fd = irq_file.as_raw_fd() as usize; - let mut event_file = File::open("event:").expect("ahcid: failed to open event file"); + let mut event_queue = RawEventQueue::new().expect("ahcid: failed to create event queue"); libredox::call::setrens(0, 0).expect("ahcid: failed to enter null namespace"); - event_file.write(&Event { - id: socket_fd, - flags: EVENT_READ, - data: 0 - }).expect("ahcid: failed to event disk scheme"); - - event_file.write(&Event { - id: irq_fd, - flags: EVENT_READ, - data: 0 - }).expect("ahcid: failed to event irq scheme"); + event_queue.subscribe(socket.inner().raw(), 1, EventFlags::READ).expect("ahcid: failed to event scheme socket"); + event_queue.subscribe(irq_fd, 1, EventFlags::READ).expect("ahcid: failed to event irq scheme"); daemon.ready().expect("ahcid: failed to notify parent"); @@ -128,34 +111,37 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut mounted = true; let mut todo = Vec::new(); while mounted { - let mut event = Event::default(); - if event_file.read(&mut event).expect("ahcid: failed to read event file") == 0 { + let Some(event) = event_queue.next().transpose().expect("ahcid: failed to read event file") else { break; - } - if event.id == socket_fd { + }; + if event.fd == socket.inner().raw() { loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => { + let sqe = match socket.next_request(SignalBehavior::Interrupt) { + Ok(None) => { mounted = false; break; }, - Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { + Ok(Some(s)) => if let RequestKind::Call(call) = s.kind() { + call + } else { + // TODO: Support e.g. cancellation + continue; + }, + Err(err) => if err.errno == EWOULDBLOCK || err.errno == EAGAIN { break; } else { panic!("ahcid: failed to read disk scheme: {}", err); } - } + }; - if let Some(a) = scheme.handle(&packet) { - packet.a = a; - socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + if let Some(response) = sqe.handle_scheme_block_mut(&mut scheme) { + // TODO: handle full CQE? + socket.write_response(response, SignalBehavior::Restart).expect("ahcid: failed to write disk scheme"); } else { - todo.push(packet); + todo.push(sqe); } } - } else if event.id == irq_fd { + } else if event.fd == irq_fd { let mut irq = [0; 8]; if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() { if scheme.irq() { @@ -164,10 +150,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // Handle todos in order to finish previous packets if possible let mut i = 0; while i < todo.len() { - if let Some(a) = scheme.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&mut packet).expect("ahcid: failed to write disk scheme"); + if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + let _sqe = todo.remove(i); + socket.write_response(resp, SignalBehavior::Restart).expect("ahcid: failed to write disk scheme"); } else { i += 1; } @@ -175,25 +160,23 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } } else { - error!("Unknown event {}", event.id); + error!("Unknown event {}", event.fd); } // Handle todos to start new packets if possible let mut i = 0; while i < todo.len() { - if let Some(a) = scheme.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet).expect("ahcid: failed to write disk scheme"); + if let Some(response) = todo[i].handle_scheme_block_mut(&mut scheme) { + let _sqe = todo.remove(i); + socket.write_response(response, SignalBehavior::Restart).expect("ahcid: failed to write disk scheme"); } else { i += 1; } } if ! mounted { - for mut packet in todo.drain(..) { - packet.a = Error::mux(Err(Error::new(ENODEV))); - socket.write(&packet).expect("ahcid: failed to write disk scheme"); + for sqe in todo.drain(..) { + socket.write_response(Response::new(&sqe, Err(Error::new(ENODEV))), SignalBehavior::Restart).expect("ahcid: failed to write disk scheme"); } } } diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index ae7bb32573..9f6635fa27 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -1,14 +1,14 @@ use std::collections::BTreeMap; use std::{cmp, str}; -use std::convert::{TryFrom}; use std::fmt::Write; use std::io::prelude::*; use driver_block::{Disk, DiskWrapper}; use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, - Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Io, Stat, MODE_DIR, + MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET, +}; +use redox_scheme::SchemeBlockMut; use crate::ahci::hba::HbaMem; @@ -30,8 +30,8 @@ pub struct DiskScheme { impl DiskScheme { pub fn new(scheme_name: String, hba_mem: &'static mut HbaMem, disks: Vec>) -> DiskScheme { DiskScheme { - scheme_name: scheme_name, - hba_mem: hba_mem, + scheme_name, + hba_mem, disks: disks.into_iter().map(DiskWrapper::new).collect::>().into_boxed_slice(), handles: BTreeMap::new(), next_id: 0 From 9dee2c12ae8571c972739dfb809c8c7ff9ba63b0 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 11 Jun 2024 21:05:14 +0200 Subject: [PATCH 0911/1301] Migrate nvmed to schemev2. --- Cargo.lock | 2 ++ storage/ahcid/Cargo.toml | 2 +- storage/nvmed/Cargo.toml | 4 +++- storage/nvmed/src/main.rs | 36 ++++++++++++++---------------------- storage/nvmed/src/scheme.rs | 5 +++-- 5 files changed, 23 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cee523d05a..2032af2703 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -787,6 +787,8 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", + "redox-scheme", + "redox_event", "redox_syscall 0.5.1", "smallvec 1.13.2", ] diff --git a/storage/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml index 746a660bc3..661f28e2c4 100644 --- a/storage/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -9,7 +9,7 @@ byteorder = "1.2" log = "0.4" redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.5" +redox_syscall = { version = "0.5", features = ["std"] } common = { path = "../../common" } driver-block = { path = "../driver-block" } diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 7306d843c3..9b8eed9cec 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -11,7 +11,9 @@ futures = "0.3" log = "0.4" redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.5" +redox_syscall = { version = "0.5", features = ["std"] } +redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2" } +redox_event = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } smallvec = "1" diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 4aee22d621..39167633d2 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -11,6 +11,7 @@ use std::{slice, usize}; use libredox::flag; use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; +use redox_scheme::{CallRequest, RequestKind, SignalBehavior, Socket, V2}; use syscall::{ Event, Mmio, Packet, Result, SchemeBlockMut, PAGE_SIZE, @@ -278,13 +279,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"), }); - let socket_fd = libredox::call::open( - &format!(":{}", scheme_name), - flag::O_RDWR | flag::O_CREAT | flag::O_CLOEXEC, - 0, - ) - .expect("nvmed: failed to create disk scheme"); - let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + let socket = Socket::::create(&scheme_name).expect("nvmed: failed to create disk scheme"); daemon.ready().expect("nvmed: failed to signal readiness"); @@ -306,27 +301,24 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); let mut todo = Vec::new(); loop { - let mut packet = Packet::default(); - match socket_file.read(&mut packet) { - Ok(0) => { + // TODO: Use a proper event queue once interrupt support is back. + match socket.next_request(SignalBehavior::Restart).expect("nvmed: failed to read disk scheme") { + None => { break; }, - Ok(_) => { - todo.push(packet); - }, - Err(err) => match err.kind() { - ErrorKind::WouldBlock => break, - _ => Err(err).expect("nvmed: failed to read disk scheme"), - }, + Some(req) => if let RequestKind::Call(c) = req.kind() { + todo.push(c); + } else { + // TODO: cancellation + continue; + } } let mut i = 0; while i < todo.len() { - if let Some(a) = scheme.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket_file - .write(&packet) + if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + let _req = todo.remove(i); + socket.write_response(resp, SignalBehavior::Restart) .expect("nvmed: failed to write disk scheme"); } else { i += 1; diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 638b426ae4..71944e9712 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -7,9 +7,10 @@ use std::sync::Arc; use std::{cmp, str}; use syscall::{ - Error, Io, Result, SchemeBlockMut, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, - EOVERFLOW, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET, + Error, Io, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, + MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET, }; +use redox_scheme::SchemeBlockMut; use crate::nvme::{Nvme, NvmeNamespace}; From a36684177782a6268423286936142bdba5b01356 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 12 Jun 2024 11:36:24 +0200 Subject: [PATCH 0912/1301] Switch remaining storage daemons to schemev2. --- Cargo.lock | 2 ++ storage/usbscsid/Cargo.toml | 3 ++- storage/usbscsid/src/main.rs | 39 ++++++++++++++----------------- storage/usbscsid/src/scheme.rs | 4 ++-- storage/virtio-blkd/Cargo.toml | 3 ++- storage/virtio-blkd/src/main.rs | 29 ++++++++++------------- storage/virtio-blkd/src/scheme.rs | 4 +++- 7 files changed, 41 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2032af2703..7f3e5cc940 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1563,6 +1563,7 @@ dependencies = [ "libredox 0.1.3", "plain", "redox-daemon", + "redox-scheme", "redox_syscall 0.5.1", "thiserror", "xhcid", @@ -1647,6 +1648,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", + "redox-scheme", "redox_syscall 0.5.1", "spin", "static_assertions", diff --git a/storage/usbscsid/Cargo.toml b/storage/usbscsid/Cargo.toml index 8b38f8617f..4bcf696cad 100644 --- a/storage/usbscsid/Cargo.toml +++ b/storage/usbscsid/Cargo.toml @@ -12,6 +12,7 @@ base64 = "0.11" # Only for debugging libredox = "0.1.3" plain = "0.2" redox-daemon = "0.1" -redox_syscall = "0.5" +redox_syscall = { version = "0.5", features = ["std"] } +redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2" } thiserror = "1" xhcid = { path = "../../xhcid" } diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index e745c0ad3f..39cc0e9771 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -1,11 +1,7 @@ use std::env; -use std::fs::File; -use std::io::prelude::*; -use std::os::unix::io::{FromRawFd, RawFd}; -use libredox::flag; -use syscall::{Packet, SchemeMut}; -use xhcid_interface::{ConfigureEndpointsReq, DeviceReqData, XhciClientHandle}; +use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; +use xhcid_interface::{ConfigureEndpointsReq, XhciClientHandle}; pub mod protocol; pub mod scsi; @@ -83,11 +79,10 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u let mut protocol = protocol::setup(&handle, protocol, &desc, &conf_desc, &if_desc) .expect("Failed to setup protocol"); - // TODO: Let all of the USB drivers syscall clone(2), and xhcid won't have to keep track of all - // the drivers. - let socket_fd = libredox::call::open(disk_scheme_name, flag::O_RDWR | flag::O_CREAT, 0) + // TODO: Let all of the USB drivers fork or be managed externally, and xhcid won't have to keep + // track of all the drivers. + let socket_fd = Socket::::create(&disk_scheme_name) .expect("usbscsid: failed to create disk scheme"); - let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; //libredox::call::setrens(0, 0).expect("scsid: failed to enter null namespace"); let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI"); @@ -99,17 +94,19 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u let mut scsi_scheme = ScsiScheme::new(&mut scsi, &mut *protocol); // TODO: Use nonblocking and put all pending calls in a todo VecDeque. Use an eventfd as well. - 'scheme_loop: loop { - let mut packet = Packet::default(); - match socket_file.read(&mut packet) { - Ok(0) => break 'scheme_loop, - Ok(_) => (), - Err(err) => panic!("scsid: failed to read disk scheme: {}", err), - } - scsi_scheme.handle(&mut packet); - socket_file - .write(&packet) - .expect("scsid: failed to write packet"); + loop { + let req = match socket_fd.next_request(SignalBehavior::Restart).expect("scsid: failed to read disk scheme") { + Some(r) => if let RequestKind::Call(c) = r.kind() { + c + } else { + continue; + } + None => break, + }; + let resp = req.handle_scheme_mut(&mut scsi_scheme); + socket_fd + .write_response(resp, SignalBehavior::Restart) + .expect("scsid: failed to write cqe"); } std::process::exit(0); diff --git a/storage/usbscsid/src/scheme.rs b/storage/usbscsid/src/scheme.rs index 1ec7b20638..c0defdca0d 100644 --- a/storage/usbscsid/src/scheme.rs +++ b/storage/usbscsid/src/scheme.rs @@ -4,12 +4,12 @@ use std::{cmp, str}; use crate::protocol::Protocol; use crate::scsi::Scsi; +use redox_scheme::SchemeMut; use syscall::error::{Error, Result}; use syscall::error::{EACCES, EBADF, EINVAL, EIO, ENOENT, ENOSYS}; use syscall::flag::{MODE_CHR, MODE_DIR}; use syscall::flag::{O_DIRECTORY, O_STAT}; use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET}; -use syscall::SchemeMut; // TODO: Only one disk, right? const LIST_CONTENTS: &'static [u8] = b"0\n"; @@ -38,7 +38,7 @@ impl<'a> ScsiScheme<'a> { } } -impl<'a> SchemeMut for ScsiScheme<'a> { +impl SchemeMut for ScsiScheme<'_> { fn open(&mut self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result { if uid != 0 { return Err(Error::new(EACCES)); diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index 60bfed2ba6..9e05406e61 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -14,7 +14,8 @@ spin = "*" redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.5" +redox_syscall = { version = "0.5", features = ["std"] } +redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2" } partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } common = { path = "../../common" } diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 9d71b3a8d1..abdbacaba7 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -7,6 +7,7 @@ use std::os::fd::{FromRawFd, RawFd}; use std::sync::{Arc, Weak}; use libredox::flag; +use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; use static_assertions::const_assert_eq; use pcid_interface::*; @@ -141,30 +142,24 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let scheme_name = format!("disk.{}", name); - let socket_fd = libredox::call::open( - &format!(":{}", scheme_name), - flag::O_RDWR | flag::O_CREAT | flag::O_CLOEXEC, - 0, - ) - .map_err(syscall::Error::from) - .map_err(Error::SyscallError)?; + let socket_fd = Socket::::create(&scheme_name).map_err(Error::SyscallError)?; - let mut socket_file = unsafe { File::from_raw_fd(socket_fd as RawFd) }; let mut scheme = scheme::DiskScheme::new(queue, device_space); deamon.ready().expect("virtio-blkd: failed to deamonize"); loop { - let mut packet = Packet::default(); - socket_file - .read(&mut packet) - .expect("virtio-blkd: failed to read disk scheme"); - let packey = scheme.handle(&mut packet); - packet.a = packey.unwrap(); - socket_file - .write(&mut packet) - .expect("virtio-blkd: failed to read disk scheme"); + let req = match socket_fd.next_request(SignalBehavior::Restart) + .expect("virtio-blkd: failed to read disk scheme") { + Some(r) => if let RequestKind::Call(c) = r.kind() { c } else { continue }, + None => break, + }; + let resp = req.handle_scheme_block_mut(&mut scheme).expect("TODO: block?"); + socket_fd + .write_response(resp, SignalBehavior::Restart) + .expect("virtio-blkd: failed to write to disk scheme"); } + Ok(()) } fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 3b37b547ff..84d9e23a39 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -10,8 +10,10 @@ use std::sync::Arc; use common::dma::Dma; use partitionlib::LogicalBlockSize; use partitionlib::PartitionTable; -use syscall::*; +use redox_scheme::SchemeBlockMut; +use syscall::flag::*; +use syscall::error::*; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::Queue; From 0058d7c94816002f3d58ceaf7c33948871e79bf5 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 12 Jun 2024 17:22:05 +0200 Subject: [PATCH 0913/1301] Positioned IO. --- Cargo.lock | 4 +- Cargo.toml | 2 +- storage/ahcid/Cargo.toml | 2 +- storage/ahcid/src/scheme.rs | 132 ++++++++++------------------ storage/nvmed/Cargo.toml | 2 +- storage/nvmed/src/scheme.rs | 137 +++++++++--------------------- storage/usbscsid/Cargo.toml | 4 +- storage/usbscsid/src/scheme.rs | 104 +++++++++-------------- storage/virtio-blkd/Cargo.toml | 2 +- storage/virtio-blkd/src/scheme.rs | 108 +++++++---------------- 10 files changed, 166 insertions(+), 331 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f3e5cc940..4fc06669d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1100,7 +1100,7 @@ dependencies = [ [[package]] name = "redox-scheme" version = "0.2.0" -source = "git+https://gitlab.redox-os.org/4lDO2/redox-scheme.git?branch=schemev2#aeff1a7ef5d456679437551a910e5b22a213d8a7" +source = "git+https://gitlab.redox-os.org/4lDO2/redox-scheme.git?branch=schemev2plus#ca239589c873374a17715b637be1f9385345721c" dependencies = [ "libredox 0.1.3", "redox_syscall 0.5.1", @@ -1137,7 +1137,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.5.1" -source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=schemev2#ef3273b17114fe02848eaccf102119fc7fdd6056" +source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=schemev2plus#b4f9a8952cec870ed7f457e3c15652d09aa0c9c7" dependencies = [ "bitflags 2.5.0", ] diff --git a/Cargo.toml b/Cargo.toml index 98a246a883..7637bcbedd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,4 +47,4 @@ lto = "fat" mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } redox-daemon = { git = "https://gitlab.redox-os.org/redox-os/redox-daemon.git" } -redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "schemev2", features = ["std"] } +redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "schemev2plus", features = ["std"] } diff --git a/storage/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml index 661f28e2c4..d845d95533 100644 --- a/storage/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -15,5 +15,5 @@ common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } libredox = "0.1.3" -redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2" } +redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2plus" } redox_event = "0.4" diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index 9f6635fa27..224fdb3d97 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -1,12 +1,11 @@ use std::collections::BTreeMap; -use std::{cmp, str}; +use std::str; use std::fmt::Write; -use std::io::prelude::*; use driver_block::{Disk, DiskWrapper}; use syscall::{ Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Io, Stat, MODE_DIR, - MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET, + MODE_FILE, O_DIRECTORY, O_STAT, }; use redox_scheme::SchemeBlockMut; @@ -14,9 +13,9 @@ use crate::ahci::hba::HbaMem; #[derive(Clone)] enum Handle { - List(Vec, usize), // Dir contents buffer, position - Disk(usize, usize), // Disk index, position - Partition(usize, u32, usize), // Disk index, partition index, position + List(Vec), // Dir contents buffer + Disk(usize), // Disk index + Partition(usize, u32), // Disk index, partition index } pub struct DiskScheme { @@ -61,10 +60,10 @@ impl DiskScheme { fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { for (_, handle) in self.handles.iter() { match handle { - Handle::Disk(i, _) => if disk_i == *i { + Handle::Disk(i) => if disk_i == *i { return Err(Error::new(ENOLCK)); }, - Handle::Partition(i, p, _) => if disk_i == *i { + Handle::Partition(i, p) => if disk_i == *i { match part_i_opt { Some(part_i) => if part_i == *p { return Err(Error::new(ENOLCK)); @@ -102,7 +101,7 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::List(list.into_bytes(), 0)); + self.handles.insert(id, Handle::List(list.into_bytes())); Ok(Some(id)) } else { Err(Error::new(EISDIR)) @@ -125,7 +124,7 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::Partition(i, p, 0)); + self.handles.insert(id, Handle::Partition(i, p)); Ok(Some(id)) } else { Err(Error::new(ENOENT)) @@ -138,7 +137,7 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::Disk(i, 0)); + self.handles.insert(id, Handle::Disk(i)); Ok(Some(id)) } else { Err(Error::new(ENOENT)) @@ -167,19 +166,19 @@ impl SchemeBlockMut for DiskScheme { fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data, _) => { + Handle::List(ref data) => { stat.st_mode = MODE_DIR; stat.st_size = data.len() as u64; Ok(Some(0)) }, - Handle::Disk(number, _) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = disk.size(); stat.st_blksize = disk.block_length()?; Ok(Some(0)) } - Handle::Partition(disk_id, part_num, _) => { + Handle::Partition(disk_id, part_num) => { let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; let size = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; @@ -215,8 +214,8 @@ impl SchemeBlockMut for DiskScheme { } match *handle { - Handle::List(_, _) => (), - Handle::Disk(number, _) => { + Handle::List(_) => (), + Handle::Disk(number) => { let number_str = format!("{}", number); let number_bytes = number_str.as_bytes(); j = 0; @@ -226,7 +225,7 @@ impl SchemeBlockMut for DiskScheme { j += 1; } } - Handle::Partition(disk_num, part_num, _) => { + Handle::Partition(disk_num, part_num) => { let path = format!("{}p{}", disk_num, part_num); let path_bytes = path.as_bytes(); j = 0; @@ -241,71 +240,60 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(i)) } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle, ref mut size) => { - let count = (&handle[*size..]).read(buf).unwrap(); - *size += count; - Ok(Some(count)) + Handle::List(ref handle) => { + let src = usize::try_from(offset).ok().and_then(|o| handle.get(o..)).unwrap_or(&[]); + + let byte_count = core::cmp::min(src.len(), buf.len()); + buf[..byte_count].copy_from_slice(&src[..byte_count]); + Ok(Some(byte_count)) }, - Handle::Disk(number, ref mut size) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; - if let Some(count) = disk.read((*size as u64)/(blk_len as u64), buf)? { - *size += count; - Ok(Some(count)) - } else { - Ok(None) - } + disk.read(offset / u64::from(blk_len), buf) } - Handle::Partition(disk_num, part_num, ref mut position) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; let blksize = disk.block_length()?; // validate that we're actually reading within the bounds of the partition - let rel_block = *position as u64 / blksize as u64; + let rel_block = offset / u64::from(blksize); let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; let abs_block = partition.start_lba + rel_block; + // TODO: This shouldn't return EOVERFLOW? if rel_block >= partition.size { return Err(Error::new(EOVERFLOW)); } abs_block }; - if let Some(count) = disk.read(abs_block, buf)? { - Ok(Some(count)) - } else { - Ok(None) - } + disk.read(abs_block, buf) } } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + fn write(&mut self, id: usize, buf: &[u8], offset: u64, _fcntl_flags: u32) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_, _) => { + Handle::List(_) => { Err(Error::new(EBADF)) }, - Handle::Disk(number, ref mut size) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; - if let Some(count) = disk.write((*size as u64)/(blk_len as u64), buf)? { - *size += count; - Ok(Some(count)) - } else { - Ok(None) - } + disk.write(offset / u64::from(blk_len), buf) } - Handle::Partition(disk_num, part_num, ref mut position) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; let blksize = disk.block_length()?; // validate that we're actually reading within the bounds of the partition - let rel_block = *position as u64 / blksize as u64; + let rel_block = offset / u64::from(blksize); let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; @@ -318,56 +306,24 @@ impl SchemeBlockMut for DiskScheme { abs_block }; - if let Some(count) = disk.write(abs_block, buf)? { - Ok(Some(count)) - } else { - Ok(None) - } + disk.write(abs_block, buf) } } } - fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { - let pos = pos as usize; - - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle, ref mut size) => { - let len = handle.len() as usize; - *size = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(Some(*size as isize)) - }, - Handle::Disk(number, ref mut size) => { + fn fsize(&mut self, id: usize) -> Result> { + Ok(Some(match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref mut handle) => handle.len() as u64, + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let len = disk.size() as usize; - *size = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(Some(*size as isize)) + disk.size() } - Handle::Partition(disk_num, part_num, ref mut position) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; let block_count = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?.size; - let len = u64::from(disk.block_length()?) * block_count; - - *position = match whence { - SEEK_SET => cmp::min(len as usize, pos) as usize, // Why isn't pos u64? - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *position as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)), - }; - Ok(Some(*position as isize)) + u64::from(disk.block_length()?) * block_count } - } + })) } fn close(&mut self, id: usize) -> Result> { diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 9b8eed9cec..46c6947593 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -12,7 +12,7 @@ log = "0.4" redox-daemon = "0.1" redox-log = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2" } +redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2plus" } redox_event = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } smallvec = "1" diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 71944e9712..6b852f887d 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -18,9 +18,9 @@ use partitionlib::{LogicalBlockSize, PartitionTable}; #[derive(Clone)] enum Handle { - List(Vec, usize), // entries, offset - Disk(u32, usize), // disk num, offset - Partition(u32, u32, usize), // disk num, part num, offset + List(Vec), // entries + Disk(u32), // disk num + Partition(u32, u32), // disk num, part num } pub struct DiskWrapper { @@ -163,10 +163,10 @@ impl DiskScheme { fn check_locks(&self, disk_i: u32, part_i_opt: Option) -> Result<()> { for (_, handle) in self.handles.iter() { match handle { - Handle::Disk(i, _) => if disk_i == *i { + Handle::Disk(i) => if disk_i == *i { return Err(Error::new(ENOLCK)); }, - Handle::Partition(i, p, _) => if disk_i == *i { + Handle::Partition(i, p) => if disk_i == *i { match part_i_opt { Some(part_i) => if part_i == *p { return Err(Error::new(ENOLCK)); @@ -205,7 +205,7 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::List(list.into_bytes(), 0)); + self.handles.insert(id, Handle::List(list.into_bytes())); Ok(Some(id)) } else { Err(Error::new(EISDIR)) @@ -235,7 +235,7 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; self.handles - .insert(id, Handle::Partition(nsid, part_num, 0)); + .insert(id, Handle::Partition(nsid, part_num)); Ok(Some(id)) } else { Err(Error::new(ENOENT)) @@ -251,7 +251,7 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::Disk(nsid, 0)); + self.handles.insert(id, Handle::Disk(nsid)); Ok(Some(id)) } else { Err(Error::new(ENOENT)) @@ -280,12 +280,12 @@ impl SchemeBlockMut for DiskScheme { fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data, _) => { + Handle::List(ref data) => { stat.st_mode = MODE_DIR; stat.st_size = data.len() as u64; Ok(Some(0)) } - Handle::Disk(number, _) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_blocks = disk.as_ref().blocks; @@ -297,7 +297,7 @@ impl SchemeBlockMut for DiskScheme { stat.st_size = disk.as_ref().blocks * disk.as_ref().block_size; Ok(Some(0)) } - Handle::Partition(disk_num, part_num, _) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; let part = disk .pt @@ -338,8 +338,8 @@ impl SchemeBlockMut for DiskScheme { } match *handle { - Handle::List(_, _) => (), - Handle::Disk(number, _) => { + Handle::List(_) => (), + Handle::Disk(number) => { let number_str = format!("{}", number); let number_bytes = number_str.as_bytes(); j = 0; @@ -349,7 +349,7 @@ impl SchemeBlockMut for DiskScheme { j += 1; } } - Handle::Partition(disk_num, part_num, _) => { + Handle::Partition(disk_num, part_num) => { let number_str = format!("{}p{}", disk_num, part_num); let number_bytes = number_str.as_bytes(); j = 0; @@ -364,24 +364,20 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(i)) } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle, ref mut size) => { - let count = (&handle[*size..]).read(buf).unwrap(); - *size += count; + Handle::List(ref handle) => { + let src = usize::try_from(offset).ok().and_then(|o| handle.get(o..)).unwrap_or(&[]); + let count = core::cmp::min(src.len(), buf.len()); + buf[..count].copy_from_slice(&src[..count]); Ok(Some(count)) } - Handle::Disk(number, ref mut size) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; - if let Some(count) = self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, (*size as u64) / block_size, buf)? { - *size += count; - Ok(Some(count)) - } else { - Ok(None) - } + self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, offset / block_size, buf) } - Handle::Partition(disk_num, part_num, ref mut offset) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; let part = disk .pt @@ -392,38 +388,27 @@ impl SchemeBlockMut for DiskScheme { .ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; - let rel_block = (*offset as u64) / block_size; + let rel_block = offset / block_size; if rel_block >= part.size { return Err(Error::new(EOVERFLOW)); } let abs_block = part.start_lba + rel_block; - if let Some(count) = self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, abs_block, buf)? { - *offset += count; - Ok(Some(count)) - } else { - Ok(None) - } + self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, abs_block, buf) } } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + fn write(&mut self, id: usize, buf: &[u8], offset: u64, _fcntl_flags: u32) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_, _) => Err(Error::new(EBADF)), - Handle::Disk(number, ref mut size) => { + Handle::List(_) => Err(Error::new(EBADF)), + Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; - if let Some(count) = self.nvme - .namespace_write(disk.as_ref(), disk.as_ref().id, (*size as u64) / block_size, buf)? { - *size += count; - Ok(Some(count)) - } else { - Ok(None) - } + self.nvme.namespace_write(disk.as_ref(), disk.as_ref().id, offset / block_size, buf) } - Handle::Partition(disk_num, part_num, ref mut offset) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; let part = disk .pt @@ -434,57 +419,26 @@ impl SchemeBlockMut for DiskScheme { .ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; - let rel_block = (*offset as u64) / block_size; + let rel_block = offset / block_size; if rel_block >= part.size { return Err(Error::new(EOVERFLOW)); } let abs_block = part.start_lba + rel_block; - if let Some(count) = self.nvme.namespace_write(disk.as_ref(), disk.as_ref().id, abs_block, buf)? { - *offset += count; - Ok(Some(count)) - } else { - Ok(None) - } + self.nvme.namespace_write(disk.as_ref(), disk.as_ref().id, abs_block, buf) } } } - fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle, ref mut size) => { - let len = handle.len() as isize; - *size = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => { - cmp::max(0, cmp::min(len, *size as isize + pos)) - } - SEEK_END => { - cmp::max(0, cmp::min(len, len + pos)) - } - _ => return Err(Error::new(EINVAL)), - } as usize; - - Ok(Some(*size as isize)) - } - Handle::Disk(number, ref mut size) => { + fn fsize(&mut self, id: usize) -> Result> { + Ok(Some(match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref handle) => handle.len() as u64, + Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let len = (disk.as_ref().blocks * disk.as_ref().block_size) as isize; - *size = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => { - cmp::max(0, cmp::min(len, *size as isize + pos)) - } - SEEK_END => { - cmp::max(0, cmp::min(len, len + pos)) - } - _ => return Err(Error::new(EINVAL)), - } as usize; - - Ok(Some(*size as isize)) + disk.as_ref().blocks * disk.as_ref().block_size } - Handle::Partition(disk_num, part_num, ref mut size) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; let part = disk .pt @@ -494,22 +448,9 @@ impl SchemeBlockMut for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))?; - let len = (part.size * disk.as_ref().block_size) as isize; - - *size = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => { - cmp::max(0, cmp::min(len, *size as isize + pos)) - } - SEEK_END => { - cmp::max(0, cmp::min(len, len + pos)) - } - _ => return Err(Error::new(EINVAL)), - } as usize; - - Ok(Some(*size as isize)) + part.size * disk.as_ref().block_size } - } + })) } fn close(&mut self, id: usize) -> Result> { diff --git a/storage/usbscsid/Cargo.toml b/storage/usbscsid/Cargo.toml index 4bcf696cad..80df55b2da 100644 --- a/storage/usbscsid/Cargo.toml +++ b/storage/usbscsid/Cargo.toml @@ -2,7 +2,7 @@ name = "usbscsid" version = "0.1.0" authors = ["4lDO2 <4lDO2@protonmail.com>"] -edition = "2018" +edition = "2021" license = "MIT" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -13,6 +13,6 @@ libredox = "0.1.3" plain = "0.2" redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2" } +redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2plus" } thiserror = "1" xhcid = { path = "../../xhcid" } diff --git a/storage/usbscsid/src/scheme.rs b/storage/usbscsid/src/scheme.rs index c0defdca0d..41fc0a5d82 100644 --- a/storage/usbscsid/src/scheme.rs +++ b/storage/usbscsid/src/scheme.rs @@ -15,9 +15,9 @@ use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET}; const LIST_CONTENTS: &'static [u8] = b"0\n"; enum Handle { - List(usize), - Disk(usize), - //Partition(usize, u32, usize), + List, + Disk, + //Partition(usize, u32), } pub struct ScsiScheme<'a> { @@ -50,12 +50,12 @@ impl SchemeMut for ScsiScheme<'_> { .trim_start_matches('/'); let handle = if path_str.is_empty() { // List - Handle::List(0) + Handle::List } else if let Some(_p_pos) = path_str.chars().position(|c| c == 'p') { // TODO: Partitions. return Err(Error::new(ENOSYS)); } else { - Handle::Disk(0) + Handle::Disk }; self.next_fd += 1; self.handles.insert(self.next_fd, handle); @@ -63,13 +63,13 @@ impl SchemeMut for ScsiScheme<'_> { } fn fstat(&mut self, fd: usize, stat: &mut syscall::Stat) -> Result { match self.handles.get(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk(_) => { + Handle::Disk => { stat.st_mode = MODE_CHR; stat.st_size = self.scsi.get_disk_size(); stat.st_blksize = self.scsi.block_size; stat.st_blocks = self.scsi.block_count; } - Handle::List(_) => { + Handle::List => { stat.st_mode = MODE_DIR; stat.st_size = LIST_CONTENTS.len() as u64; } @@ -78,84 +78,64 @@ impl SchemeMut for ScsiScheme<'_> { } fn fpath(&mut self, fd: usize, buf: &mut [u8]) -> Result { let path = match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk(_) => "0", - Handle::List(_) => "", + Handle::Disk => "0", + Handle::List => "", } .as_bytes(); let min = std::cmp::min(path.len(), buf.len()); buf[..min].copy_from_slice(&path[..min]); Ok(min) } - fn seek(&mut self, fd: usize, pos: isize, whence: usize) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk(ref mut offset) => { - let len = self.scsi.get_disk_size() as isize; - *offset = match whence { - SEEK_SET => cmp::max(0, cmp::min(pos, len)), - SEEK_CUR => cmp::max(0, cmp::min(*offset as isize + pos, len)), - SEEK_END => cmp::max(0, cmp::min(len + pos, len)), - _ => return Err(Error::new(EINVAL)), - } as usize; - Ok(*offset as isize) - } - Handle::List(ref mut offset) => { - let len = LIST_CONTENTS.len() as isize; - *offset = match whence { - SEEK_SET => cmp::max(0, cmp::min(pos, len)), - SEEK_CUR => cmp::max(0, cmp::min(*offset as isize + pos, len)), - SEEK_END => cmp::max(0, cmp::min(len + pos, len)), - _ => return Err(Error::new(EINVAL)), - } as usize; - Ok(*offset as isize) - } - } + fn fsize(&mut self, fd: usize) -> Result { + Ok(match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { + Handle::Disk => self.scsi.get_disk_size(), + Handle::List => LIST_CONTENTS.len() as u64, + }) } - fn read(&mut self, fd: usize, buf: &mut [u8]) -> Result { + fn read(&mut self, fd: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk(ref mut offset) => { - if *offset as u64 % u64::from(self.scsi.block_size) != 0 + Handle::Disk => { + if offset % u64::from(self.scsi.block_size) != 0 || buf.len() as u64 % u64::from(self.scsi.block_size) != 0 { return Err(Error::new(EINVAL)); } - let lba = *offset as u64 / u64::from(self.scsi.block_size); - let bytes_read = self - .scsi - .read(self.protocol, lba, buf) - .map_err(|err| dbg!(err)) - .or(Err(Error::new(EIO)))?; - *offset += bytes_read as usize; - Ok(bytes_read as usize) + let lba = offset / u64::from(self.scsi.block_size); + match self.scsi.read(self.protocol, lba, buf) { + Ok(bytes_read) => Ok(bytes_read as usize), + Err(err) => { + eprintln!("usbscsid: READ IO ERROR: {err}"); + Err(Error::new(EIO)) + } + } } - Handle::List(ref mut offset) => { - let max_bytes_to_read = cmp::min(LIST_CONTENTS.len(), buf.len()); - let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset; + Handle::List => { + let src = usize::try_from(offset).ok().and_then(|o| LIST_CONTENTS.get(o..)).unwrap_or(&[]); + let min = core::cmp::min(src.len(), buf.len()); + buf[..min].copy_from_slice(&src[..min]); - buf[..bytes_to_read].copy_from_slice(&LIST_CONTENTS[..bytes_to_read]); - *offset += bytes_to_read; - - Ok(bytes_to_read) + Ok(min) } } } - fn write(&mut self, fd: usize, buf: &[u8]) -> Result { + fn write(&mut self, fd: usize, buf: &[u8], offset: u64, _fcntl_flags: u32) -> Result { match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk(ref mut offset) => { - if *offset as u64 % u64::from(self.scsi.block_size) != 0 + Handle::Disk => { + if offset % u64::from(self.scsi.block_size) != 0 || buf.len() as u64 % u64::from(self.scsi.block_size) != 0 { return Err(Error::new(EINVAL)); } - let lba = *offset as u64 / u64::from(self.scsi.block_size); - let bytes_written = self - .scsi - .write(self.protocol, lba, buf) - .map_err(|err| dbg!(err)) - .or(Err(Error::new(EIO)))?; - *offset += bytes_written as usize; - Ok(bytes_written as usize) + let lba = offset / u64::from(self.scsi.block_size); + match self.scsi.write(self.protocol, lba, buf) { + Ok(bytes_written) => Ok(bytes_written as usize), + Err(err) => { + eprintln!("usbscsid: WRITE IO ERROR: {err}"); + Err(Error::new(EIO)) + } + } } - Handle::List(_) => Err(Error::new(EBADF)), + Handle::List => Err(Error::new(EBADF)), } } } diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index 9e05406e61..f67de06320 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -15,7 +15,7 @@ spin = "*" redox-daemon = "0.1" redox-log = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2" } +redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2plus" } partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } common = { path = "../../common" } diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 84d9e23a39..c0cd7a0575 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -84,18 +84,13 @@ pub enum Handle { Partition { /// Partition Number number: u32, - /// Offset in bytes - offset: usize, }, List { entries: Vec, - offset: usize, }, - Disk { - offset: usize, - }, + Disk, } pub struct DiskScheme<'a> { @@ -224,7 +219,6 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { id, Handle::List { entries: list.into_bytes(), - offset: 0, }, ); @@ -250,7 +244,6 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { id, Handle::Partition { number: part_num, - offset: 0, }, ); @@ -261,25 +254,24 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::Disk { offset: 0 }); + self.handles.insert(id, Handle::Disk); Ok(Some(id)) } } - fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> syscall::Result> { + Ok(Some(match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List { ref mut entries, - ref mut offset, } => { - let count = (&entries[*offset..]).read(buf).unwrap(); - *offset += count; - Ok(Some(count)) + let src = usize::try_from(offset).ok().and_then(|o| entries.get(o..)).unwrap_or(&[]); + let count = core::cmp::min(src.len(), buf.len()); + buf[..count].copy_from_slice(&src[..count]); + count } Handle::Partition { number, - ref mut offset, } => { let part_table = self.part_table.as_ref().unwrap(); let part = part_table @@ -288,68 +280,52 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { .ok_or(Error::new(EBADF))?; // Get the offset in sectors. - let rel_block = (*offset as u64) / BLK_SIZE; + let rel_block = offset / BLK_SIZE; // if rel_block >= part.size { // return Err(Error::new(EOVERFLOW)); // } let abs_block = part.start_lba + rel_block; - let count = futures::executor::block_on(self.queue.read(abs_block, buf)); - *offset += count; - Ok(Some(count)) + futures::executor::block_on(self.queue.read(abs_block, buf)) } - Handle::Disk { ref mut offset } => { + Handle::Disk => { let block_size = self.cfg.block_size(); - let count = futures::executor::block_on( - self.queue.read((*offset as u64) / block_size as u64, buf), - ); - *offset += count; - Ok(Some(count)) + futures::executor::block_on( + self.queue.read(offset / u64::from(block_size), buf), + ) } - } + })) } - fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::Disk { ref mut offset } => { + fn write(&mut self, id: usize, buf: &[u8], offset: u64, _fcntl_flags: u32) -> syscall::Result> { + Ok(Some(match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::Disk => { let block_size = self.cfg.block_size(); - let count = futures::executor::block_on( - self.queue.write((*offset as u64) / block_size as u64, buf), - ); - - *offset += count; - Ok(Some(count)) + futures::executor::block_on( + self.queue.write(offset / u64::from(block_size), buf), + ) } - _ => unimplemented!(), - } + _ => todo!(), + })) } - fn seek(&mut self, id: usize, pos: isize, whence: usize) -> syscall::Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + fn fsize(&mut self, id: usize) -> syscall::Result> { + Ok(Some(match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List { ref entries, - ref mut offset, } => { - let len = entries.len() as isize; - log::debug!("list: whence={whence:?} pos={pos:?} part_len={len:?}"); + let len = entries.len() as u64; + log::debug!("list: part_len={len:?}"); - *offset = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len, *offset as isize + pos)), - SEEK_END => cmp::max(0, cmp::min(len, len + pos)), - _ => return Err(Error::new(EINVAL)), - } as usize; - - Ok(Some(*offset as isize)) + len } Handle::Partition { number, - ref mut offset, } => { let part_table = self.part_table.as_ref().unwrap(); let part = part_table @@ -358,33 +334,15 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { .ok_or(Error::new(EBADF))?; // Partition size in bytes. - let len = (part.size * BLK_SIZE) as isize; + let len = part.size * BLK_SIZE; - log::debug!("part: whence={whence:?} pos={pos:?} part_len={len:?}"); + log::debug!("part: part_len={len:?}"); - *offset = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len, *offset as isize + pos)), - SEEK_END => cmp::max(0, cmp::min(len, len + pos)), - _ => return Err(Error::new(EINVAL)), - } as usize; - - Ok(Some(*offset as isize)) + len } - Handle::Disk { ref mut offset } => { - let len = (self.cfg.capacity() * self.cfg.block_size() as u64) as isize; - - *offset = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len, *offset as isize + pos)), - SEEK_END => cmp::max(0, cmp::min(len, len + pos)), - _ => return Err(Error::new(EINVAL)), - } as usize; - - Ok(Some(*offset as isize)) - } - } + Handle::Disk => self.cfg.capacity() * u64::from(self.cfg.block_size()), + })) } fn fpath(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result> { From 2b146f87789baebcbf5c880082ba9c3e3ea0507a Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Wed, 12 Jun 2024 17:45:24 +0200 Subject: [PATCH 0914/1301] Properly pass POSITIONED new fd flag. --- storage/ahcid/src/scheme.rs | 113 ++++++++++++-------------- storage/nvmed/src/scheme.rs | 128 ++++++++++++++---------------- storage/usbscsid/src/scheme.rs | 9 ++- storage/virtio-blkd/src/scheme.rs | 16 ++-- 4 files changed, 127 insertions(+), 139 deletions(-) diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index 224fdb3d97..8a6cc89480 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -3,11 +3,12 @@ use std::str; use std::fmt::Write; use driver_block::{Disk, DiskWrapper}; +use syscall::schemev2::NewFdFlags; use syscall::{ Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Io, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, }; -use redox_scheme::SchemeBlockMut; +use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; use crate::ahci::hba::HbaMem; @@ -81,74 +82,64 @@ impl DiskScheme { } impl SchemeBlockMut for DiskScheme { - fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { - let path_str = path.trim_matches('/'); - if path_str.is_empty() { - if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { - let mut list = String::new(); + fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { + if ctx.uid != 0 { + return Err(Error::new(EACCES)); + } + let path_str = path.trim_matches('/'); - for (disk_index, disk) in self.disks.iter().enumerate() { - write!(list, "{}\n", disk_index).unwrap(); + let handle = if path_str.is_empty() { + if flags & O_DIRECTORY != O_DIRECTORY && flags & O_STAT != O_STAT { + return Err(Error::new(EISDIR)); + } + let mut list = String::new(); - if disk.pt.is_none() { - continue - } - for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { - write!(list, "{}p{}\n", disk_index, part_index).unwrap(); - } - } + for (disk_index, disk) in self.disks.iter().enumerate() { + write!(list, "{}\n", disk_index).unwrap(); - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::List(list.into_bytes())); - Ok(Some(id)) - } else { - Err(Error::new(EISDIR)) + if disk.pt.is_none() { + continue } - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let disk_id_str = &path_str[..p_pos]; - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_id_str = &path_str[p_pos + 1..]; - let i = disk_id_str.parse::().or(Err(Error::new(ENOENT)))?; - let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; - - if let Some(disk) = self.disks.get(i) { - if disk.pt.is_none() || disk.pt.as_ref().unwrap().partitions.get(p as usize).is_none() { - return Err(Error::new(ENOENT)); - } - - self.check_locks(i, Some(p))?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Partition(i, p)); - Ok(Some(id)) - } else { - Err(Error::new(ENOENT)) - } - } else { - let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if self.disks.get(i).is_some() { - self.check_locks(i, None)?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Disk(i)); - Ok(Some(id)) - } else { - Err(Error::new(ENOENT)) + for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { + write!(list, "{}p{}\n", disk_index, part_index).unwrap(); } } + + Handle::List(list.into_bytes()) + } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { + let disk_id_str = &path_str[..p_pos]; + if p_pos + 1 >= path_str.len() { + return Err(Error::new(ENOENT)); + } + let part_id_str = &path_str[p_pos + 1..]; + let i = disk_id_str.parse::().or(Err(Error::new(ENOENT)))?; + let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; + + let disk = self.disks.get(i).ok_or(Error::new(ENOENT))?; + if disk.pt.is_none() || disk.pt.as_ref().unwrap().partitions.get(p as usize).is_none() { + return Err(Error::new(ENOENT)); + } + + self.check_locks(i, Some(p))?; + + Handle::Partition(i, p) } else { - Err(Error::new(EACCES)) - } + let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; + + if self.disks.get(i).is_none() { + return Err(Error::new(ENOENT)); + } + self.check_locks(i, None)?; + + Handle::Disk(i) + }; + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, handle); + Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { + fn xdup(&mut self, id: usize, buf: &[u8], _: &CallerCtx) -> Result> { if ! buf.is_empty() { return Err(Error::new(EINVAL)); } @@ -161,7 +152,7 @@ impl SchemeBlockMut for DiskScheme { let new_id = self.next_id; self.next_id += 1; self.handles.insert(new_id, new_handle); - Ok(Some(new_id)) + Ok(Some(OpenResult::ThisScheme { number: new_id, flags: NewFdFlags::POSITIONED })) } fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 6b852f887d..a301a7fa98 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -6,11 +6,12 @@ use std::io::prelude::*; use std::sync::Arc; use std::{cmp, str}; +use syscall::schemev2::NewFdFlags; use syscall::{ Error, Io, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET, }; -use redox_scheme::SchemeBlockMut; +use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; use crate::nvme::{Nvme, NvmeNamespace}; @@ -184,82 +185,75 @@ impl DiskScheme { } impl SchemeBlockMut for DiskScheme { - fn open(&mut self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { - let path_str = path_str - .trim_matches('/'); - if path_str.is_empty() { - if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { - let mut list = String::new(); + fn xopen(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result> { + if ctx.uid != 0 { + return Err(Error::new(EACCES)); + } + let path_str = path_str + .trim_matches('/'); - for (nsid, disk) in self.disks.iter() { - write!(list, "{}\n", nsid).unwrap(); + let handle = if path_str.is_empty() { + if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { + let mut list = String::new(); - if disk.pt.is_none() { - continue; - } - for part_num in 0..disk.pt.as_ref().unwrap().partitions.len() { - write!(list, "{}p{}\n", nsid, part_num).unwrap(); - } + for (nsid, disk) in self.disks.iter() { + write!(list, "{}\n", nsid).unwrap(); + + if disk.pt.is_none() { + continue; + } + for part_num in 0..disk.pt.as_ref().unwrap().partitions.len() { + write!(list, "{}p{}\n", nsid, part_num).unwrap(); } - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::List(list.into_bytes())); - Ok(Some(id)) - } else { - Err(Error::new(EISDIR)) } - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let nsid_str = &path_str[..p_pos]; - if p_pos + 1 >= path_str.len() { + Handle::List(list.into_bytes()) + } else { + return Err(Error::new(EISDIR)); + } + } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { + let nsid_str = &path_str[..p_pos]; + + if p_pos + 1 >= path_str.len() { + return Err(Error::new(ENOENT)); + } + let part_num_str = &path_str[p_pos + 1..]; + + let nsid = nsid_str.parse::().or(Err(Error::new(ENOENT)))?; + let part_num = part_num_str.parse::().or(Err(Error::new(ENOENT)))?; + + if let Some(disk) = self.disks.get(&nsid) { + if disk + .pt + .as_ref() + .ok_or(Error::new(ENOENT))? + .partitions + .get(part_num as usize) + .is_some() + { + self.check_locks(nsid, Some(part_num))?; + + Handle::Partition(nsid, part_num) + } else { return Err(Error::new(ENOENT)); } - let part_num_str = &path_str[p_pos + 1..]; - - let nsid = nsid_str.parse::().or(Err(Error::new(ENOENT)))?; - let part_num = part_num_str.parse::().or(Err(Error::new(ENOENT)))?; - - if let Some(disk) = self.disks.get(&nsid) { - if disk - .pt - .as_ref() - .ok_or(Error::new(ENOENT))? - .partitions - .get(part_num as usize) - .is_some() - { - self.check_locks(nsid, Some(part_num))?; - - let id = self.next_id; - self.next_id += 1; - self.handles - .insert(id, Handle::Partition(nsid, part_num)); - Ok(Some(id)) - } else { - Err(Error::new(ENOENT)) - } - } else { - Err(Error::new(ENOENT)) - } } else { - let nsid = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if self.disks.contains_key(&nsid) { - self.check_locks(nsid, None)?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Disk(nsid)); - Ok(Some(id)) - } else { - Err(Error::new(ENOENT)) - } + return Err(Error::new(ENOENT)); } } else { - Err(Error::new(EACCES)) - } + let nsid = path_str.parse::().or(Err(Error::new(ENOENT)))?; + + if self.disks.contains_key(&nsid) { + self.check_locks(nsid, None)?; + Handle::Disk(nsid) + } else { + return Err(Error::new(ENOENT)); + } + }; + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, handle); + Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) } fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { diff --git a/storage/usbscsid/src/scheme.rs b/storage/usbscsid/src/scheme.rs index 41fc0a5d82..a175780958 100644 --- a/storage/usbscsid/src/scheme.rs +++ b/storage/usbscsid/src/scheme.rs @@ -4,12 +4,13 @@ use std::{cmp, str}; use crate::protocol::Protocol; use crate::scsi::Scsi; -use redox_scheme::SchemeMut; +use redox_scheme::{CallerCtx, OpenResult, SchemeMut}; use syscall::error::{Error, Result}; use syscall::error::{EACCES, EBADF, EINVAL, EIO, ENOENT, ENOSYS}; use syscall::flag::{MODE_CHR, MODE_DIR}; use syscall::flag::{O_DIRECTORY, O_STAT}; use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET}; +use syscall::schemev2::NewFdFlags; // TODO: Only one disk, right? const LIST_CONTENTS: &'static [u8] = b"0\n"; @@ -39,8 +40,8 @@ impl<'a> ScsiScheme<'a> { } impl SchemeMut for ScsiScheme<'_> { - fn open(&mut self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result { - if uid != 0 { + fn xopen(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result { + if ctx.uid != 0 { return Err(Error::new(EACCES)); } if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { @@ -59,7 +60,7 @@ impl SchemeMut for ScsiScheme<'_> { }; self.next_fd += 1; self.handles.insert(self.next_fd, handle); - Ok(self.next_fd) + Ok(OpenResult::ThisScheme { number: self.next_fd, flags: NewFdFlags::POSITIONED }) } fn fstat(&mut self, fd: usize, stat: &mut syscall::Stat) -> Result { match self.handles.get(&fd).ok_or(Error::new(EBADF))? { diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index c0cd7a0575..fe24c5b813 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -11,9 +11,12 @@ use common::dma::Dma; use partitionlib::LogicalBlockSize; use partitionlib::PartitionTable; +use redox_scheme::CallerCtx; +use redox_scheme::OpenResult; use redox_scheme::SchemeBlockMut; use syscall::flag::*; use syscall::error::*; +use syscall::schemev2::NewFdFlags; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::Queue; @@ -190,13 +193,12 @@ impl<'a> DiskScheme<'a> { } impl<'a> SchemeBlockMut for DiskScheme<'a> { - fn open( + fn xopen( &mut self, path: &str, flags: usize, - _uid: u32, - _gid: u32, - ) -> syscall::Result> { + _ctx: &CallerCtx, + ) -> syscall::Result> { log::info!("virtiod: open: {}", path); let path_str = path.trim_matches('/'); @@ -222,7 +224,7 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { }, ); - Ok(Some(id)) + Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) } else { return Err(syscall::Error::new(EISDIR)); } @@ -247,7 +249,7 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { }, ); - Ok(Some(id)) + Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) } else { let nsid = path_str.parse::().unwrap(); assert_eq!(nsid, 0); @@ -255,7 +257,7 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle::Disk); - Ok(Some(id)) + Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) } } From 05ec7464eaacce63c5f300a04ca0197184da1f4e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 14 Jun 2024 14:22:01 +0200 Subject: [PATCH 0915/1301] Update syscall. --- Cargo.lock | 81 +++++++++++++++++----------------- Cargo.toml | 1 - storage/ahcid/Cargo.toml | 2 +- storage/nvmed/Cargo.toml | 2 +- storage/usbscsid/Cargo.toml | 2 +- storage/virtio-blkd/Cargo.toml | 2 +- 6 files changed, 45 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4fc06669d5..7c4b35cb71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "spin", ] @@ -33,7 +33,7 @@ dependencies = [ "plain", "redox-daemon", "redox-log", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "rustc-hash", "serde_json", "thiserror", @@ -54,7 +54,7 @@ dependencies = [ "redox-log", "redox-scheme", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -66,7 +66,7 @@ dependencies = [ "libredox 0.1.3", "redox-daemon", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -159,7 +159,7 @@ dependencies = [ "fdt 0.1.5", "libredox 0.1.3", "redox-daemon", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -170,7 +170,7 @@ dependencies = [ "orbclient", "pcid", "redox-daemon", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -286,7 +286,7 @@ name = "common" version = "0.1.0" dependencies = [ "libredox 0.1.3", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -351,7 +351,7 @@ name = "driver-block" version = "0.1.0" dependencies = [ "partitionlib", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -359,7 +359,7 @@ name = "driver-network" version = "0.1.0" dependencies = [ "libredox 0.1.3", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -373,7 +373,7 @@ dependencies = [ "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -392,7 +392,7 @@ dependencies = [ "ransid", "redox-daemon", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -591,7 +591,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -606,7 +606,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "spin", ] @@ -630,7 +630,7 @@ dependencies = [ "orbclient", "redox-daemon", "redox-log", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "spin", ] @@ -660,7 +660,7 @@ dependencies = [ "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -703,7 +703,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.5.0", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -713,7 +713,7 @@ dependencies = [ "anyhow", "libredox 0.1.3", "redox-daemon", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "slab", ] @@ -741,9 +741,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "num-derive" @@ -789,7 +789,7 @@ dependencies = [ "redox-log", "redox-scheme", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "smallvec 1.13.2", ] @@ -935,7 +935,7 @@ dependencies = [ "pci_types", "plain", "redox-log", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "serde", "serde_json", "structopt", @@ -949,7 +949,7 @@ version = "0.1.0" dependencies = [ "libredox 0.1.3", "redox-daemon", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -1011,7 +1011,7 @@ dependencies = [ "libredox 0.1.3", "orbclient", "redox-daemon", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -1100,10 +1100,10 @@ dependencies = [ [[package]] name = "redox-scheme" version = "0.2.0" -source = "git+https://gitlab.redox-os.org/4lDO2/redox-scheme.git?branch=schemev2plus#ca239589c873374a17715b637be1f9385345721c" +source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#62aed6c712cca31bb18078adacd27b400f5ccf93" dependencies = [ "libredox 0.1.3", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -1136,8 +1136,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" -source = "git+https://gitlab.redox-os.org/4lDO2/syscall.git?branch=schemev2plus#b4f9a8952cec870ed7f457e3c15652d09aa0c9c7" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ "bitflags 2.5.0", ] @@ -1171,7 +1172,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -1187,7 +1188,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -1213,7 +1214,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "spin", ] @@ -1540,7 +1541,7 @@ dependencies = [ "log", "orbclient", "redox-log", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "rehid", "xhcid", ] @@ -1551,7 +1552,7 @@ version = "0.1.0" dependencies = [ "log", "redox-log", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "xhcid", ] @@ -1564,7 +1565,7 @@ dependencies = [ "plain", "redox-daemon", "redox-scheme", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "thiserror", "xhcid", ] @@ -1600,7 +1601,7 @@ dependencies = [ "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -1631,7 +1632,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", ] [[package]] @@ -1649,7 +1650,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox-scheme", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "spin", "static_assertions", "thiserror", @@ -1669,7 +1670,7 @@ dependencies = [ "pcid", "redox-log", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "static_assertions", "thiserror", ] @@ -1688,7 +1689,7 @@ dependencies = [ "paste", "pcid", "redox-daemon", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "spin", "static_assertions", "virtio-core", @@ -1705,7 +1706,7 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "static_assertions", "virtio-core", ] @@ -1909,7 +1910,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "serde", "serde_json", "smallvec 1.13.2", diff --git a/Cargo.toml b/Cargo.toml index 7637bcbedd..65715466f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,4 +47,3 @@ lto = "fat" mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } redox-daemon = { git = "https://gitlab.redox-os.org/redox-os/redox-daemon.git" } -redox_syscall = { git = "https://gitlab.redox-os.org/4lDO2/syscall.git", branch = "schemev2plus", features = ["std"] } diff --git a/storage/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml index d845d95533..0f9793e19a 100644 --- a/storage/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -15,5 +15,5 @@ common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } libredox = "0.1.3" -redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2plus" } +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 46c6947593..b4fe28398b 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -12,7 +12,7 @@ log = "0.4" redox-daemon = "0.1" redox-log = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2plus" } +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } smallvec = "1" diff --git a/storage/usbscsid/Cargo.toml b/storage/usbscsid/Cargo.toml index 80df55b2da..7a7f1e3752 100644 --- a/storage/usbscsid/Cargo.toml +++ b/storage/usbscsid/Cargo.toml @@ -13,6 +13,6 @@ libredox = "0.1.3" plain = "0.2" redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2plus" } +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } thiserror = "1" xhcid = { path = "../../xhcid" } diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index f67de06320..6ac79495d2 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -15,7 +15,7 @@ spin = "*" redox-daemon = "0.1" redox-log = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/4lDO2/redox-scheme.git", branch = "schemev2plus" } +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } common = { path = "../../common" } From ccbc1d6d693d94e816fd4fbb65d211ce310695e1 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 15 Jun 2024 12:14:18 +0200 Subject: [PATCH 0916/1301] Switch ided to v2 scheme protocol. --- Cargo.lock | 2 + storage/ided/Cargo.toml | 6 +- storage/ided/src/main.rs | 114 ++++++++++++---------------- storage/ided/src/scheme.rs | 147 +++++++++++++------------------------ 4 files changed, 106 insertions(+), 163 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7c4b35cb71..44fde5ca6b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -591,6 +591,8 @@ dependencies = [ "pcid", "redox-daemon", "redox-log", + "redox-scheme", + "redox_event", "redox_syscall 0.5.2", ] diff --git a/storage/ided/Cargo.toml b/storage/ided/Cargo.toml index 2303be020b..e590d22e97 100644 --- a/storage/ided/Cargo.toml +++ b/storage/ided/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ided" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] common = { path = "../../common" } @@ -11,4 +11,6 @@ log = "0.4" pcid = { path = "../../pcid" } redox-daemon = "0.1" redox-log = "0.1" -redox_syscall = "0.5" +redox_syscall = { version = "0.5", features = ["std"] } +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox_event = "0.4" diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index decfacd9bc..0a10a625a0 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -1,8 +1,10 @@ use driver_block::Disk; +use event::{EventFlags, RawEventQueue}; use libredox::flag; use log::{error, info}; use pcid_interface::{PciBar, PcidServerHandle}; use redox_log::{OutputBuilder, RedoxLogger}; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; use std::{ fs::File, io::{ErrorKind, Read, Write}, @@ -12,11 +14,7 @@ use std::{ time::Duration, }; use syscall::{ - data::{Event, Packet}, - error::{Error, ENODEV}, - flag::{EVENT_READ}, - io::Io, - scheme::SchemeBlockMut, + data::{Event, Packet}, error::{Error, ENODEV}, flag::EVENT_READ, io::Io, scheme::SchemeBlockMut, EAGAIN, EINTR, EWOULDBLOCK }; use crate::{ @@ -236,12 +234,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } let scheme_name = format!("disk.{}", name); - let socket_fd = libredox::call::open( - &format!(":{}", scheme_name), - flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, - 0, - ).expect("ided: failed to create disk scheme"); - let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + let socket_fd = Socket::::nonblock(&scheme_name) + .expect("ided: failed to create disk scheme"); let primary_irq_fd = libredox::call::open( &format!("irq:{}", primary_irq), @@ -257,63 +251,59 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { ).expect("ided: failed to open irq file"); let mut secondary_irq_file = unsafe { File::from_raw_fd(secondary_irq_fd as RawFd) }; - let mut event_file = File::open("event:").expect("ided: failed to open event file"); + let mut event_queue = RawEventQueue::new().expect("ided: failed to open event file"); libredox::call::setrens(0, 0).expect("ided: failed to enter null namespace"); daemon.ready().expect("ided: failed to notify parent"); - event_file.write(&Event { - id: socket_fd, - flags: EVENT_READ, - data: 0 - }).expect("ided: failed to event disk scheme"); + event_queue.subscribe( + socket_fd.inner().raw(), + 0, + EventFlags::READ, + ).expect("ided: failed to event disk scheme"); - event_file.write(&Event { - id: primary_irq_fd, - flags: EVENT_READ, - data: 0 - }).expect("ided: failed to event irq scheme"); + event_queue.subscribe( + primary_irq_fd, + 0, + EventFlags::READ, + ).expect("ided: failed to event irq scheme"); - event_file.write(&Event { - id: secondary_irq_fd, - flags: EVENT_READ, - data: 0 - }).expect("ided: failed to event irq scheme"); + event_queue.subscribe( + secondary_irq_fd, + 0, + EventFlags::READ, + ).expect("ided: failed to event irq scheme"); let mut scheme = DiskScheme::new(scheme_name, chans, disks); - let mut mounted = true; let mut todo = Vec::new(); - while mounted { - let mut event = Event::default(); - if event_file.read(&mut event).expect("ided: failed to read event file") == 0 { + 'outer: loop { + let Some(event) = event_queue.next().transpose().expect("ided: failed to read event file") else { break; - } - if event.id == socket_fd { + }; + if event.fd == socket_fd.inner().raw() { loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => { - mounted = false; - break; + let req = match socket_fd.next_request(SignalBehavior::Interrupt) { + Ok(None) => break 'outer, + Ok(Some(r)) => if let RequestKind::Call(c) = r.kind() { + c + } else { + continue; }, - Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { + Err(err) => if matches!(err.errno, EAGAIN | EWOULDBLOCK | EINTR) { break; } else { panic!("ided: failed to read disk scheme: {}", err); } - } - - if let Some(a) = scheme.handle(&packet) { - packet.a = a; - socket.write(&mut packet).expect("ided: failed to write disk scheme"); + }; + if let Some(resp) = req.handle_scheme_block_mut(&mut scheme) { + socket_fd.write_response(resp, SignalBehavior::Restart).expect("ided: failed to write disk scheme"); } else { - todo.push(packet); + todo.push(req); } } - } else if event.id == primary_irq_fd { + } else if event.fd == primary_irq_fd { let mut irq = [0; 8]; if primary_irq_file.read(&mut irq).expect("ided: failed to read irq file") >= irq.len() { if scheme.irq(0) { @@ -322,17 +312,15 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // Handle todos in order to finish previous packets if possible let mut i = 0; while i < todo.len() { - if let Some(a) = scheme.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&mut packet).expect("ided: failed to write disk scheme"); + if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + socket_fd.write_response(resp, SignalBehavior::Restart).expect("ided: failed to write disk scheme"); } else { i += 1; } } } } - } else if event.id == secondary_irq_fd { + } else if event.fd == secondary_irq_fd { let mut irq = [0; 8]; if secondary_irq_file.read(&mut irq).expect("ided: failed to read irq file") >= irq.len() { if scheme.irq(1) { @@ -341,10 +329,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // Handle todos in order to finish previous packets if possible let mut i = 0; while i < todo.len() { - if let Some(a) = scheme.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&mut packet).expect("ided: failed to write disk scheme"); + if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + socket_fd.write_response(resp, SignalBehavior::Restart).expect("ided: failed to write disk scheme"); } else { i += 1; } @@ -352,26 +338,22 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } } else { - error!("Unknown event {}", event.id); + error!("Unknown event {}", event.fd); } // Handle todos to start new packets if possible let mut i = 0; while i < todo.len() { - if let Some(a) = scheme.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet).expect("ided: failed to write disk scheme"); + if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + socket_fd.write_response(resp, SignalBehavior::Restart).expect("ided: failed to write disk scheme"); } else { i += 1; } } - if ! mounted { - for mut packet in todo.drain(..) { - packet.a = Error::mux(Err(Error::new(ENODEV))); - socket.write(&packet).expect("ided: failed to write disk scheme"); - } + for req in todo.drain(..) { + socket_fd.write_response(Response::new(&req, Err(Error::new(ENODEV))), SignalBehavior::Restart) + .expect("ided: failed to write disk scheme"); } } diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs index 31032d4a9a..bb46d11082 100644 --- a/storage/ided/src/scheme.rs +++ b/storage/ided/src/scheme.rs @@ -1,23 +1,23 @@ use std::collections::BTreeMap; -use std::{cmp, str}; -use std::convert::{TryFrom}; +use std::str; use std::fmt::Write; -use std::io::prelude::*; use std::sync::{Arc, Mutex}; use driver_block::{Disk, DiskWrapper}; +use syscall::schemev2::NewFdFlags; use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, - Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Stat, MODE_DIR, + MODE_FILE, O_DIRECTORY, O_STAT, +}; +use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; use crate::ide::Channel; #[derive(Clone)] enum Handle { - List(Vec, usize), // Dir contents buffer, position - Disk(usize, usize), // Disk index, position - Partition(usize, u32, usize), // Disk index, partition index, position + List(Vec), // Dir contents buffer + Disk(usize), // Disk index + Partition(usize, u32), // Disk index, partition index } pub struct DiskScheme { @@ -31,7 +31,7 @@ pub struct DiskScheme { impl DiskScheme { pub fn new(scheme_name: String, chans: Vec>>, disks: Vec>) -> DiskScheme { DiskScheme { - scheme_name: scheme_name, + scheme_name, chans: chans.into_boxed_slice(), disks: disks.into_iter().map(DiskWrapper::new).collect::>().into_boxed_slice(), handles: BTreeMap::new(), @@ -40,7 +40,7 @@ impl DiskScheme { } pub fn irq(&mut self, chan_i: usize) -> bool { - let mut chan = self.chans[chan_i].lock().unwrap(); + let _chan = self.chans[chan_i].lock().unwrap(); //TODO: check chan for irq true } @@ -49,10 +49,10 @@ impl DiskScheme { fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { for (_, handle) in self.handles.iter() { match handle { - Handle::Disk(i, _) => if disk_i == *i { + Handle::Disk(i) => if disk_i == *i { return Err(Error::new(ENOLCK)); }, - Handle::Partition(i, p, _) => if disk_i == *i { + Handle::Partition(i, p) => if disk_i == *i { match part_i_opt { Some(part_i) => if part_i == *p { return Err(Error::new(ENOLCK)); @@ -70,8 +70,8 @@ impl DiskScheme { } impl SchemeBlockMut for DiskScheme { - fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { + fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { + if ctx.uid == 0 { let path_str = path.trim_matches('/'); if path_str.is_empty() { if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { @@ -90,8 +90,8 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::List(list.into_bytes(), 0)); - Ok(Some(id)) + self.handles.insert(id, Handle::List(list.into_bytes())); + Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) } else { Err(Error::new(EISDIR)) } @@ -113,8 +113,8 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::Partition(i, p, 0)); - Ok(Some(id)) + self.handles.insert(id, Handle::Partition(i, p)); + Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) } else { Err(Error::new(ENOENT)) } @@ -126,8 +126,8 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::Disk(i, 0)); - Ok(Some(id)) + self.handles.insert(id, Handle::Disk(i)); + Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) } else { Err(Error::new(ENOENT)) } @@ -155,19 +155,19 @@ impl SchemeBlockMut for DiskScheme { fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data, _) => { + Handle::List(ref data) => { stat.st_mode = MODE_DIR; stat.st_size = data.len() as u64; Ok(Some(0)) }, - Handle::Disk(number, _) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = disk.size(); stat.st_blksize = disk.block_length()?; Ok(Some(0)) } - Handle::Partition(disk_id, part_num, _) => { + Handle::Partition(disk_id, part_num) => { let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; let size = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; @@ -203,8 +203,8 @@ impl SchemeBlockMut for DiskScheme { } match *handle { - Handle::List(_, _) => (), - Handle::Disk(number, _) => { + Handle::List(_) => (), + Handle::Disk(number) => { let number_str = format!("{}", number); let number_bytes = number_str.as_bytes(); j = 0; @@ -214,7 +214,7 @@ impl SchemeBlockMut for DiskScheme { j += 1; } } - Handle::Partition(disk_num, part_num, _) => { + Handle::Partition(disk_num, part_num) => { let path = format!("{}p{}", disk_num, part_num); let path_bytes = path.as_bytes(); j = 0; @@ -229,29 +229,25 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(i)) } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _flags: u32) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle, ref mut size) => { - let count = (&handle[*size..]).read(buf).unwrap(); - *size += count; - Ok(Some(count)) + Handle::List(ref handle) => { + let src = usize::try_from(offset).ok().and_then(|o| handle.get(o..)).unwrap_or(&[]); + let bytes = src.len().min(buf.len()); + buf[..bytes].copy_from_slice(&src[..bytes]); + Ok(Some(bytes)) }, - Handle::Disk(number, ref mut size) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; - if let Some(count) = disk.read((*size as u64)/(blk_len as u64), buf)? { - *size += count; - Ok(Some(count)) - } else { - Ok(None) - } + disk.read(offset / u64::from(blk_len), buf) } - Handle::Partition(disk_num, part_num, ref mut position) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; let blksize = disk.block_length()?; // validate that we're actually reading within the bounds of the partition - let rel_block = *position as u64 / blksize as u64; + let rel_block = offset / u64::from(blksize); let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; @@ -264,36 +260,27 @@ impl SchemeBlockMut for DiskScheme { abs_block }; - if let Some(count) = disk.read(abs_block, buf)? { - Ok(Some(count)) - } else { - Ok(None) - } + disk.read(abs_block, buf) } } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_, _) => { + Handle::List(_) => { Err(Error::new(EBADF)) }, - Handle::Disk(number, ref mut size) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; - if let Some(count) = disk.write((*size as u64)/(blk_len as u64), buf)? { - *size += count; - Ok(Some(count)) - } else { - Ok(None) - } + disk.write(offset / u64::from(blk_len), buf) } - Handle::Partition(disk_num, part_num, ref mut position) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; let blksize = disk.block_length()?; // validate that we're actually reading within the bounds of the partition - let rel_block = *position as u64 / blksize as u64; + let rel_block = offset / u64::from(blksize as u64); let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; @@ -306,54 +293,24 @@ impl SchemeBlockMut for DiskScheme { abs_block }; - if let Some(count) = disk.write(abs_block, buf)? { - Ok(Some(count)) - } else { - Ok(None) - } + disk.write(abs_block, buf) } } } - fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { - let pos = pos as usize; - + fn fsize(&mut self, id: usize) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle, ref mut size) => { - let len = handle.len() as usize; - *size = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(Some(*size as isize)) + Handle::List(ref mut handle) => { + Ok(Some(handle.len() as u64)) }, - Handle::Disk(number, ref mut size) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let len = disk.size() as usize; - *size = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(Some(*size as isize)) + Ok(Some(disk.size())) } - Handle::Partition(disk_num, part_num, ref mut position) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; let block_count = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?.size; - let len = u64::from(disk.block_length()?) * block_count; - - *position = match whence { - SEEK_SET => cmp::min(len as usize, pos) as usize, // Why isn't pos u64? - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *position as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)), - }; - Ok(Some(*position as isize)) + Ok(Some(u64::from(disk.block_length()?) * block_count)) } } } From 2ab2fe7b5e190102129a34affad70d1ffe0f2259 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Jun 2024 13:41:51 +0200 Subject: [PATCH 0917/1301] Update to pci_types 0.10.0 --- Cargo.lock | 4 ++-- pcid/Cargo.toml | 2 +- pcid/src/cfg_access/fallback.rs | 4 ---- pcid/src/cfg_access/mod.rs | 4 ---- pcid/src/pci_header.rs | 4 ---- 5 files changed, 3 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44fde5ca6b..df85130837 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -913,9 +913,9 @@ checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" [[package]] name = "pci_types" -version = "0.9.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6848549f754bd20aa382ffec0f4f04ba50e55a18ff75a0862bf9e227fe42b57" +checksum = "c4325c6aa3cca3373503b1527e75756f9fbfe5fd76be4b4c8a143ee47430b8e0" dependencies = [ "bit_field", "bitflags 2.5.0", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 6083222d46..8e7db297ac 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -19,7 +19,7 @@ fdt = { git = "https://gitlab.redox-os.org/rosehuds/fdt.git" } libc = "0.2" log = "0.4" paw = "1.0" -pci_types = "0.9.1" +pci_types = "0.10" plain = "0.2" redox-log = "0.1" redox_syscall = "0.5" diff --git a/pcid/src/cfg_access/fallback.rs b/pcid/src/cfg_access/fallback.rs index c1d51bfb5c..bd073eaf27 100644 --- a/pcid/src/cfg_access/fallback.rs +++ b/pcid/src/cfg_access/fallback.rs @@ -56,10 +56,6 @@ impl Pci { } #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] impl ConfigRegionAccess for Pci { - fn function_exists(&self, _address: PciAddress) -> bool { - todo!(); - } - unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index 8e0803339b..894f4f448b 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -318,10 +318,6 @@ impl Pcie { } impl ConfigRegionAccess for Pcie { - fn function_exists(&self, _address: PciAddress) -> bool { - todo!(); - } - unsafe fn read(&self, address: PciAddress, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 4779427aea..52ea3a512e 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -260,10 +260,6 @@ mod test { } impl ConfigRegionAccess for TestCfgAccess<'_> { - fn function_exists(&self, _address: PciAddress) -> bool { - unreachable!(); - } - unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { assert_eq!(addr, self.addr); let offset = offset as usize; From 4bd978da7a18fbd0f3765f612c3f84e82debcea6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 10 Jun 2024 17:37:32 +0200 Subject: [PATCH 0918/1301] pcid: Use pci_types for parsing capabilties --- pcid/src/driver_handler.rs | 216 +++++++++++++++++-------------- pcid/src/main.rs | 12 +- pcid/src/pci/cap.rs | 170 +----------------------- pcid/src/pci/msi.rs | 256 ------------------------------------- pcid/src/pci_header.rs | 10 -- 5 files changed, 125 insertions(+), 539 deletions(-) diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index c1b08d0937..4374df9387 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -5,10 +5,10 @@ use std::sync::Arc; use std::thread; use log::{error, info}; +use pci_types::capability::{MultipleMessageSupport, PciCapability}; use pci_types::{ConfigRegionAccess, PciAddress}; use crate::driver_interface; -use crate::pci::cap::Capability as PciCapability; use crate::State; pub struct DriverHandler { @@ -97,7 +97,6 @@ impl DriverHandler { request: driver_interface::PcidClientRequest, args: &driver_interface::SubdriverArguments, ) -> driver_interface::PcidClientResponse { - use crate::pci::cap::{MsiCapability, MsixCapability}; use driver_interface::*; match request { @@ -105,7 +104,9 @@ impl DriverHandler { self.capabilities .iter() .filter_map(|capability| match capability { - PciCapability::Vendor(capability) => Some(capability.clone()), + PciCapability::Vendor(addr) => unsafe { + Some(VendorSpecificCapability::parse(*addr, &self.state.pcie)) + }, _ => None, }) .collect::>(), @@ -121,85 +122,87 @@ impl DriverHandler { }) .collect(), ), - PcidClientRequest::EnableFeature(feature) => match feature { - PciFeature::Msi => { - if let Some(msix_capability) = self - .capabilities - .iter_mut() - .find_map(|capability| capability.as_msix_mut()) - { - // If MSI-X is supported disable it before enabling MSI as they can't be - // active at the same time. - unsafe { - msix_capability.set_msix_enabled(false); - msix_capability.write_a(self.addr, &self.state.pcie); + PcidClientRequest::EnableFeature(feature) => { + match feature { + PciFeature::Msi => { + if let Some(msix_capability) = + self.capabilities + .iter_mut() + .find_map(|capability| match capability { + PciCapability::MsiX(cap) => Some(cap), + _ => None, + }) + { + // If MSI-X is supported disable it before enabling MSI as they can't be + // active at the same time. + msix_capability.set_enabled(false, &self.state.pcie); } - } - let capability: &mut MsiCapability = match self - .capabilities - .iter_mut() - .find_map(|capability| capability.as_msi_mut()) - { - Some(capability) => capability, - None => { - return PcidClientResponse::Error( - PcidServerResponseError::NonexistentFeature(feature), - ) - } - }; - unsafe { - capability.set_enabled(true); - capability.write_message_control(self.addr, &self.state.pcie); + let capability = match self.capabilities.iter_mut().find_map(|capability| { + match capability { + PciCapability::Msi(cap) => Some(cap), + _ => None, + } + }) { + Some(capability) => capability, + None => { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(feature), + ) + } + }; + capability.set_enabled(true, &self.state.pcie); + PcidClientResponse::FeatureEnabled(feature) } - PcidClientResponse::FeatureEnabled(feature) - } - PciFeature::MsiX => { - if let Some(msi_capability) = self - .capabilities - .iter_mut() - .find_map(|capability| capability.as_msi_mut()) - { - // If MSI is supported disable it before enabling MSI-X as they can't be - // active at the same time. - unsafe { - msi_capability.set_enabled(false); - msi_capability.write_message_control(self.addr, &self.state.pcie); + PciFeature::MsiX => { + if let Some(msi_capability) = + self.capabilities + .iter_mut() + .find_map(|capability| match capability { + PciCapability::Msi(cap) => Some(cap), + _ => None, + }) + { + // If MSI is supported disable it before enabling MSI-X as they can't be + // active at the same time. + msi_capability.set_enabled(false, &self.state.pcie); } - } - let capability: &mut MsixCapability = match self - .capabilities - .iter_mut() - .find_map(|capability| capability.as_msix_mut()) - { - Some(capability) => capability, - None => { - return PcidClientResponse::Error( - PcidServerResponseError::NonexistentFeature(feature), - ) - } - }; - unsafe { - capability.set_msix_enabled(true); - capability.write_a(self.addr, &self.state.pcie); + let capability = match self.capabilities.iter_mut().find_map(|capability| { + match capability { + PciCapability::MsiX(cap) => Some(cap), + _ => None, + } + }) { + Some(capability) => capability, + None => { + return PcidClientResponse::Error( + PcidServerResponseError::NonexistentFeature(feature), + ) + } + }; + capability.set_enabled(true, &self.state.pcie); + PcidClientResponse::FeatureEnabled(feature) } - PcidClientResponse::FeatureEnabled(feature) } - }, + } PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo( feature, match feature { PciFeature::Msi => { - if let Some(info) = self - .capabilities - .iter() - .find_map(|capability| capability.as_msi()) + if let Some(info) = + self.capabilities + .iter() + .find_map(|capability| match capability { + PciCapability::Msi(cap) => Some(cap), + _ => None, + }) { PciFeatureInfo::Msi(msi::MsiInfo { - log2_multiple_message_capable: info.multi_message_capable(), - is_64bit: info.has_64_bit_addr(), - has_per_vector_masking: info.is_pvt_capable(), + log2_multiple_message_capable: info.multiple_message_capable() + as u8, + is_64bit: info.is_64bit(), + has_per_vector_masking: info.has_per_vector_masking(), }) } else { return PcidClientResponse::Error( @@ -208,16 +211,19 @@ impl DriverHandler { } } PciFeature::MsiX => { - if let Some(info) = self - .capabilities - .iter() - .find_map(|capability| capability.as_msix()) + if let Some(info) = + self.capabilities + .iter() + .find_map(|capability| match capability { + PciCapability::MsiX(cap) => Some(cap), + _ => None, + }) { PciFeatureInfo::MsiX(msi::MsixInfo { - table_bar: info.table_bir(), + table_bar: info.table_bar(), table_offset: info.table_offset(), table_size: info.table_size(), - pba_bar: info.pba_bir(), + pba_bar: info.pba_bar(), pba_offset: info.pba_offset(), }) } else { @@ -230,18 +236,36 @@ impl DriverHandler { ), PcidClientRequest::SetFeatureInfo(info_to_set) => match info_to_set { SetFeatureInfo::Msi(info_to_set) => { - if let Some(info) = self - .capabilities - .iter_mut() - .find_map(|capability| capability.as_msi_mut()) + if let Some(info) = + self.capabilities + .iter_mut() + .find_map(|capability| match capability { + PciCapability::Msi(cap) => Some(cap), + _ => None, + }) { if let Some(mme) = info_to_set.multi_message_enable { - if info.multi_message_capable() < mme || mme > 0b101 { + if (info.multiple_message_capable() as u8) < mme { return PcidClientResponse::Error( PcidServerResponseError::InvalidBitPattern, ); } - info.set_multi_message_enable(mme); + info.set_multiple_message_enable( + match mme { + 0 => MultipleMessageSupport::Int1, + 1 => MultipleMessageSupport::Int2, + 2 => MultipleMessageSupport::Int4, + 3 => MultipleMessageSupport::Int8, + 4 => MultipleMessageSupport::Int16, + 5 => MultipleMessageSupport::Int32, + _ => { + return PcidClientResponse::Error( + PcidServerResponseError::InvalidBitPattern, + ) + } + }, + &self.state.pcie, + ); } if let Some(message_addr_and_data) = info_to_set.message_address_and_data { let message_addr = message_addr_and_data.addr; @@ -250,27 +274,25 @@ impl DriverHandler { PcidServerResponseError::InvalidBitPattern, ); } - info.set_message_address(message_addr as u32); - info.set_message_upper_address((message_addr >> 32) as u32); - if message_addr_and_data.data & ((1 << info.multi_message_enable()) - 1) + if message_addr_and_data.data + & ((1 << info.multiple_message_enable(&self.state.pcie) as u8) - 1) != 0 { return PcidClientResponse::Error( PcidServerResponseError::InvalidBitPattern, ); } - info.set_message_data( + info.set_message_info( + message_addr, message_addr_and_data .data .try_into() .expect("pcid: MSI message data too big"), + &self.state.pcie, ); } if let Some(mask_bits) = info_to_set.mask_bits { - info.set_mask_bits(mask_bits); - } - unsafe { - info.write_all(self.addr, &self.state.pcie); + info.set_message_mask(mask_bits, &self.state.pcie); } PcidClientResponse::SetFeatureInfo(PciFeature::Msi) } else { @@ -280,16 +302,16 @@ impl DriverHandler { } } SetFeatureInfo::MsiX { function_mask } => { - if let Some(info) = self - .capabilities - .iter_mut() - .find_map(|capability| capability.as_msix_mut()) + if let Some(info) = + self.capabilities + .iter_mut() + .find_map(|capability| match capability { + PciCapability::MsiX(cap) => Some(cap), + _ => None, + }) { if let Some(mask) = function_mask { - info.set_function_mask(mask); - unsafe { - info.write_a(self.addr, &self.state.pcie); - } + info.set_function_mask(mask, &self.state.pcie); } PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) } else { diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 039e0fd2ea..3f126f7e3d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -4,7 +4,6 @@ use std::sync::{Arc, Mutex}; use std::thread; use log::{debug, info, trace, warn}; -use pci_types::capability::PciCapabilityAddress; use pci_types::{CommandRegister, PciAddress}; use redox_log::{OutputBuilder, RedoxLogger}; use structopt::StructOpt; @@ -98,14 +97,9 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH }; let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { - crate::pci::cap::CapabilitiesIter::new( - PciCapabilityAddress { - address: header.address(), - offset: header.cap_pointer(), - }, - &state.pcie, - ) - .collect::>() + endpoint_header + .capabilities(&state.pcie) + .collect::>() } else { Vec::new() }; diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 47dc68fc55..7655be1c14 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -2,148 +2,13 @@ use pci_types::capability::PciCapabilityAddress; use pci_types::ConfigRegionAccess; use serde::{Serialize, Deserialize}; -pub struct CapabilitiesIter<'a> { - addr: PciCapabilityAddress, - access: &'a dyn ConfigRegionAccess, -} -impl<'a> CapabilitiesIter<'a> { - pub fn new(addr: PciCapabilityAddress, access: &'a dyn ConfigRegionAccess) -> Self { - Self { addr, access } - } -} -impl<'a> Iterator for CapabilitiesIter<'a> { - type Item = Capability; - - fn next(&mut self) -> Option { - let addr = unsafe { - // mask RsvdP bits - self.addr.offset = self.addr.offset & 0xFC; - - if self.addr.offset == 0 { - return None; - }; - - let first_dword = self.access.read(self.addr.address, self.addr.offset); - let next = ((first_dword >> 8) & 0xFF) as u16; - - let addr = self.addr; - self.addr.offset = next; - - addr - }; - - let cap = unsafe { - Capability::parse(addr, self.access) - }; - - Some(cap) - } -} - -#[repr(u8)] -pub enum CapabilityId { - PwrMgmt = 0x01, - Msi = 0x05, - MsiX = 0x11, - Pcie = 0x10, - Vendor = 0x09, - - // function specific - Sata = 0x12, // only on AHCI functions -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub enum MsiCapability { - _32BitAddress { - cap_offset: u16, - message_control: u32, - message_address: u32, - message_data: u16, - }, - _64BitAddress { - cap_offset: u16, - message_control: u32, - message_address_lo: u32, - message_address_hi: u32, - message_data: u16, - }, - _32BitAddressWithPvm { - cap_offset: u16, - message_control: u32, - message_address: u32, - message_data: u32, - mask_bits: u32, - pending_bits: u32, - }, - _64BitAddressWithPvm { - cap_offset: u16, - message_control: u32, - message_address_lo: u32, - message_address_hi: u32, - message_data: u32, - mask_bits: u32, - pending_bits: u32, - }, -} - -#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub struct MsixCapability { - pub cap_offset: u16, - pub a: u32, - pub b: u32, - pub c: u32, -} - #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct VendorSpecificCapability { pub data: Vec, } -#[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] -pub enum Capability { - Msi(MsiCapability), - MsiX(MsixCapability), - Vendor(VendorSpecificCapability), - Other(u8), -} - -impl Capability { - pub fn as_msi(&self) -> Option<&MsiCapability> { - match self { - &Self::Msi(ref msi) => Some(msi), - _ => None, - } - } - pub fn as_msix(&self) -> Option<&MsixCapability> { - match self { - &Self::MsiX(ref msix) => Some(msix), - _ => None, - } - } - pub fn as_msi_mut(&mut self) -> Option<&mut MsiCapability> { - match self { - &mut Self::Msi(ref mut msi) => Some(msi), - _ => None, - } - } - pub fn as_msix_mut(&mut self) -> Option<&mut MsixCapability> { - match self { - &mut Self::MsiX(ref mut msix) => Some(msix), - _ => None, - } - } - unsafe fn parse_msi(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { - Self::Msi(MsiCapability::parse(addr, access)) - } - unsafe fn parse_msix(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { - Self::MsiX(MsixCapability { - cap_offset: addr.offset, - a: access.read(addr.address, addr.offset), - b: access.read(addr.address, addr.offset + 4), - c: access.read(addr.address, addr.offset + 8), - }) - } - unsafe fn parse_vendor(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { +impl VendorSpecificCapability { + pub(crate) unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { let dword = access.read(addr.address, addr.offset); let next = (dword >> 8) & 0xFF; let length = ((dword >> 16) & 0xFF) as u16; @@ -168,37 +33,8 @@ impl Capability { log::warn!("Vendor specific capability is invalid"); Vec::new() }; - Self::Vendor(VendorSpecificCapability { + VendorSpecificCapability { data - }) - } - unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { - assert_eq!( - addr.offset & 0xFC, - addr.offset, - "capability must be dword aligned" - ); - - let dword = access.read(addr.address, addr.offset); - let capability_id = (dword & 0xFF) as u8; - - if capability_id == CapabilityId::Msi as u8 { - Self::parse_msi(addr, access) - } else if capability_id == CapabilityId::MsiX as u8 { - Self::parse_msix(addr, access) - } else if capability_id == CapabilityId::Vendor as u8 { - Self::parse_vendor(addr, access) - } else { - if capability_id != CapabilityId::Pcie as u8 - && capability_id != CapabilityId::PwrMgmt as u8 - && capability_id != CapabilityId::Sata as u8 - { - log::warn!( - "unimplemented or malformed capability id: {}", - capability_id - ); - } - Self::Other(capability_id) } } } diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 727d36695f..1332f19ce4 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -1,10 +1,7 @@ use std::fmt; use super::bar::PciBar; -pub use super::cap::{MsiCapability, MsixCapability}; -use pci_types::capability::PciCapabilityAddress; -use pci_types::{ConfigRegionAccess, PciAddress}; use serde::{Deserialize, Serialize}; use syscall::{Io, Mmio}; @@ -31,193 +28,6 @@ pub struct MsiInfo { pub has_per_vector_masking: bool, } -impl MsiCapability { - const MC_PVT_CAPABLE_BIT: u16 = 1 << 8; - const MC_64_BIT_ADDR_BIT: u16 = 1 << 7; - - const MC_MULTI_MESSAGE_MASK: u16 = 0x000E; - const MC_MULTI_MESSAGE_SHIFT: u8 = 1; - - const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070; - const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4; - - const MC_MSI_ENABLED_BIT: u16 = 1; - - pub(crate) unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { - let dword = access.read(addr.address, addr.offset); - - let message_control = (dword >> 16) as u16; - - if message_control & Self::MC_PVT_CAPABLE_BIT != 0 { - if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { - Self::_64BitAddressWithPvm { - cap_offset: addr.offset, - message_control: dword, - message_address_lo: access.read(addr.address, addr.offset + 4), - message_address_hi: access.read(addr.address, addr.offset + 8), - message_data: access.read(addr.address, addr.offset + 12), - mask_bits: access.read(addr.address, addr.offset + 16), - pending_bits: access.read(addr.address, addr.offset + 20), - } - } else { - Self::_32BitAddressWithPvm { - cap_offset: addr.offset, - message_control: dword, - message_address: access.read(addr.address, addr.offset + 4), - message_data: access.read(addr.address, addr.offset + 8), - mask_bits: access.read(addr.address, addr.offset + 12), - pending_bits: access.read(addr.address, addr.offset + 16), - } - } - } else { - if message_control & Self::MC_64_BIT_ADDR_BIT != 0 { - Self::_64BitAddress { - cap_offset: addr.offset, - message_control: dword, - message_address_lo: access.read(addr.address, addr.offset + 4), - message_address_hi: access.read(addr.address, addr.offset + 8), - message_data: access.read(addr.address, addr.offset + 12) as u16, - } - } else { - Self::_32BitAddress { - cap_offset: addr.offset, - message_control: dword, - message_address: access.read(addr.address, addr.offset + 4), - message_data: access.read(addr.address, addr.offset + 8) as u16, - } - } - } - } - fn cap_offset(&self) -> u16 { - match *self { - MsiCapability::_32BitAddress { cap_offset, .. } - | MsiCapability::_64BitAddress { cap_offset, .. } - | MsiCapability::_32BitAddressWithPvm { cap_offset, .. } - | MsiCapability::_64BitAddressWithPvm { cap_offset, .. } => u16::from(cap_offset), - } - } - - fn message_control_raw(&self) -> u32 { - match self { - Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control, - } - } - fn message_control(&self) -> u16 { - (self.message_control_raw() >> 16) as u16 - } - pub(crate) fn set_message_control(&mut self, value: u16) { - let mut new_message_control = self.message_control_raw(); - new_message_control &= 0x0000_FFFF; - new_message_control |= u32::from(value) << 16; - - match self { - Self::_32BitAddress { ref mut message_control, .. } - | Self::_64BitAddress { ref mut message_control, .. } - | Self::_32BitAddressWithPvm { ref mut message_control, .. } - | Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control, - } - } - pub(crate) unsafe fn write_message_control(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) { - access.write(addr, self.cap_offset(), self.message_control_raw()); - } - pub(crate) fn is_pvt_capable(&self) -> bool { - self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0 - } - pub(crate) fn has_64_bit_addr(&self) -> bool { - self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0 - } - pub(crate) fn set_enabled(&mut self, enabled: bool) { - let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT); - new_message_control |= u16::from(enabled); - self.set_message_control(new_message_control); - } - pub(crate) fn multi_message_capable(&self) -> u8 { - ((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8 - } - pub(crate) fn multi_message_enable(&self) -> u8 { - ((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8 - } - pub(crate) fn set_multi_message_enable(&mut self, log_mme: u8) { - let mut new_message_control = self.message_control() & (!Self::MC_MULTI_MESSAGE_ENABLE_MASK); - new_message_control |= u16::from(log_mme) << Self::MC_MULTI_MESSAGE_ENABLE_SHIFT; - self.set_message_control(new_message_control); - } - - fn message_address(&self) -> u32 { - match self { - &Self::_32BitAddress { message_address, .. } | &Self::_32BitAddressWithPvm { message_address, .. } => message_address, - &Self::_64BitAddress { message_address_lo, .. } | &Self::_64BitAddressWithPvm { message_address_lo, .. } => message_address_lo, - } - } - fn message_upper_address(&self) -> Option { - match self { - &Self::_64BitAddress { message_address_hi, .. } | &Self::_64BitAddressWithPvm { message_address_hi, .. } => Some(message_address_hi), - &Self::_32BitAddress { .. } | &Self::_32BitAddressWithPvm { .. } => None, - } - } - pub(crate) fn set_message_address(&mut self, message_address: u32) { - assert_eq!(message_address & 0xFFFF_FFFC, message_address, "unaligned message address (this should already be validated)"); - match self { - &mut Self::_32BitAddress { message_address: ref mut addr, .. } | &mut Self::_32BitAddressWithPvm { message_address: ref mut addr, .. } => *addr = message_address, - &mut Self::_64BitAddress { message_address_lo: ref mut addr, .. } | &mut Self::_64BitAddressWithPvm { message_address_lo: ref mut addr, .. } => *addr = message_address, - } - } - pub(crate) fn set_message_upper_address(&mut self, message_upper_address: u32) -> Option<()> { - match self { - &mut Self::_64BitAddress { ref mut message_address_hi, .. } | &mut Self::_64BitAddressWithPvm { ref mut message_address_hi, .. } => *message_address_hi = message_upper_address, - &mut Self::_32BitAddress { .. } | &mut Self::_32BitAddressWithPvm { .. } => return None, - } - Some(()) - } - pub(crate) fn set_message_data(&mut self, value: u16) { - match self { - &mut Self::_32BitAddress { ref mut message_data, .. } | &mut Self::_64BitAddress { ref mut message_data, .. } => *message_data = value, - &mut Self::_32BitAddressWithPvm { ref mut message_data, .. } | &mut Self::_64BitAddressWithPvm { ref mut message_data, .. } => { - *message_data &= 0xFFFF_0000; - *message_data |= u32::from(value); - } - } - } - pub(crate) fn set_mask_bits(&mut self, mask_bits: u32) -> Option<()> { - match self { - &mut Self::_32BitAddressWithPvm { mask_bits: ref mut bits, .. } | &mut Self::_64BitAddressWithPvm { mask_bits: ref mut bits, .. } => *bits = mask_bits, - &mut Self::_32BitAddress { .. } | &mut Self::_64BitAddress { .. } => return None, - } - Some(()) - } - unsafe fn write_message_address(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) { - access.write(addr, self.cap_offset() + 4, self.message_address()) - } - unsafe fn write_message_upper_address(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) -> Option<()> { - let value = self.message_upper_address()?; - access.write(addr, self.cap_offset() + 8, value); - Some(()) - } - unsafe fn write_message_data(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) { - match self { - &Self::_32BitAddress { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 8), message_data.into()), - &Self::_32BitAddressWithPvm { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 8), message_data), - &Self::_64BitAddress { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 12), message_data.into()), - &Self::_64BitAddressWithPvm { cap_offset, message_data, .. } => access.write(addr, u16::from(cap_offset + 12), message_data), - } - } - unsafe fn write_mask_bits(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) -> Option<()> { - match self { - &Self::_32BitAddressWithPvm { cap_offset, mask_bits, .. } => access.write(addr, u16::from(cap_offset + 12), mask_bits), - &Self::_64BitAddressWithPvm { cap_offset, mask_bits, .. } => access.write(addr, u16::from(cap_offset + 16), mask_bits), - &Self::_32BitAddress { .. } | &Self::_64BitAddress { .. } => return None, - } - Some(()) - } - pub(crate) unsafe fn write_all(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) { - self.write_message_control(addr, access); - self.write_message_address(addr, access); - self.write_message_upper_address(addr, access); - self.write_message_data(addr, access); - self.write_mask_bits(addr, access); - } -} - #[derive(Debug, Serialize, Deserialize)] pub struct MsixInfo { pub table_bar: u8, @@ -268,72 +78,6 @@ impl MsixInfo { } } -impl MsixCapability { - const MC_MSIX_ENABLED_BIT: u16 = 1 << 15; - const MC_MSIX_ENABLED_SHIFT: u8 = 15; - const MC_FUNCTION_MASK_BIT: u16 = 1 << 14; - const MC_FUNCTION_MASK_SHIFT: u8 = 14; - const MC_TABLE_SIZE_MASK: u16 = 0x03FF; - - /// The Message Control field, containing the enabled and function mask bits, as well as the - /// table size. - const fn message_control(&self) -> u16 { - (self.a >> 16) as u16 - } - - pub(crate) fn set_message_control(&mut self, message_control: u16) { - self.a &= 0x0000_FFFF; - self.a |= u32::from(message_control) << 16; - } - /// Returns the MSI-X table size. - pub(crate) const fn table_size(&self) -> u16 { - (self.message_control() & Self::MC_TABLE_SIZE_MASK) + 1 - } - pub(crate) fn set_msix_enabled(&mut self, enabled: bool) { - let mut new_message_control = self.message_control(); - new_message_control &= !(Self::MC_MSIX_ENABLED_BIT); - new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT; - self.set_message_control(new_message_control); - } - - pub(crate) fn set_function_mask(&mut self, function_mask: bool) { - let mut new_message_control = self.message_control(); - new_message_control &= !(Self::MC_FUNCTION_MASK_BIT); - new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT; - self.set_message_control(new_message_control); - } - const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8; - const TABLE_BIR_MASK: u32 = 0x0000_0007; - - /// The table offset is guaranteed to be QWORD aligned (8 bytes). - pub(crate) const fn table_offset(&self) -> u32 { - self.b & Self::TABLE_OFFSET_MASK - } - /// The table BIR, which is used to map the offset to a memory location. - pub(crate) const fn table_bir(&self) -> u8 { - (self.b & Self::TABLE_BIR_MASK) as u8 - } - - const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8; - const PBA_BIR_MASK: u32 = 0x0000_0007; - - /// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes). - pub(crate) const fn pba_offset(&self) -> u32 { - self.c & Self::PBA_OFFSET_MASK - } - /// The Pending Bit Array BIR, which is used to map the offset to a memory location. - pub(crate) const fn pba_bir(&self) -> u8 { - (self.c & Self::PBA_BIR_MASK) as u8 - } - - - /// Write the first DWORD into configuration space (containing the partially modifiable Message - /// Control field). - pub(crate) unsafe fn write_a(&self, addr: PciAddress, access: &dyn ConfigRegionAccess) { - access.write(addr, u16::from(self.cap_offset), self.a) - } -} - #[repr(packed)] pub struct MsixTableEntry { pub addr_lo: Mmio, diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 52ea3a512e..8bde8369c8 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -23,7 +23,6 @@ pub struct PciEndpointHeader { shared: SharedPciHeader, subsystem_vendor_id: u16, subsystem_id: u16, - cap_pointer: u16, } #[derive(Clone, Copy, Debug, PartialEq)] @@ -67,15 +66,10 @@ impl PciHeader { HeaderType::Endpoint => { let endpoint_header = EndpointHeader::from_header(header, access).unwrap(); let (subsystem_id, subsystem_vendor_id) = endpoint_header.subsystem(access); - let cap_pointer = endpoint_header - .capability_pointer(access) - .try_into() - .unwrap(); Ok(PciHeader::General(PciEndpointHeader { shared, subsystem_vendor_id, subsystem_id, - cap_pointer, })) } HeaderType::PciPciBridge => { @@ -239,10 +233,6 @@ impl PciEndpointHeader { } bars } - - pub fn cap_pointer(&self) -> u16 { - self.cap_pointer - } } #[cfg(test)] From 3299a070f23b5a4c2102b502382eafd2d1f1c5a9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 14 Jun 2024 19:21:37 +0200 Subject: [PATCH 0919/1301] pcid: Also return bar size from physmap_mem and use it in two more drivers --- audio/ihdad/src/main.rs | 2 +- net/e1000d/src/main.rs | 2 +- net/ixgbed/src/main.rs | 16 +++------------ net/rtl8139d/src/main.rs | 2 +- net/rtl8168d/src/main.rs | 2 +- pcid/src/pci/bar.rs | 7 ++++--- storage/ahcid/src/main.rs | 2 +- storage/nvmed/src/main.rs | 37 ++++++++++++++-------------------- vboxd/src/main.rs | 2 +- virtio-core/src/arch/x86_64.rs | 2 +- xhcid/src/main.rs | 2 +- 11 files changed, 30 insertions(+), 46 deletions(-) diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index e86cc832a4..a8e6aa4ef3 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -146,7 +146,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::info!(" + IHDA {}", pci_config.func.display()); - let address = unsafe { bar.physmap_mem("ihdad") } as usize; + let address = unsafe { bar.physmap_mem("ihdad") }.0 as usize; //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index b5480587bc..db893106e7 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -33,7 +33,7 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let mut irq_file = irq.irq_handle("e1000d"); - let address = unsafe { bar.physmap_mem("e1000d") } as usize; + let address = unsafe { bar.physmap_mem("e1000d") }.0 as usize; let device = unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }; diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index 716253324a..2c54c73ee2 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -13,8 +13,6 @@ pub mod device; #[rustfmt::skip] mod ixgbe; -const IXGBE_MMIO_SIZE: usize = 512 * 1024; - fn main() { let mut pcid_handle = PcidServerHandle::connect_default().expect("ixgbed: failed to setup channel to pcid"); @@ -25,8 +23,6 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_ixgbe"); - let (bar, _) = pci_config.func.bars[0].expect_mem(); - let irq = pci_config .func .legacy_interrupt_line @@ -37,17 +33,11 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let mut irq_file = irq.irq_handle("ixgbed"); - let address = unsafe { - common::physmap( - bar, - IXGBE_MMIO_SIZE, - common::Prot::RW, - common::MemoryType::Uncacheable, - ) - .expect("ixgbed: failed to map address") as usize + let (address, size) = unsafe { + pci_config.func.bars[0].physmap_mem("ixgbed") }; - let device = device::Intel8259x::new(address, IXGBE_MMIO_SIZE) + let device = device::Intel8259x::new(address as usize, size) .expect("ixgbed: failed to allocate device"); let mut scheme = NetworkScheme::new(device, format!("network.{name}")); diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index a949d46e18..04cba8fc48 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -136,7 +136,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { msix_info.validate(pci_config.func.bars); let bar = &pci_config.func.bars[msix_info.table_bar as usize]; - let bar_address = unsafe { bar.physmap_mem("rtl8139d") } as usize; + let bar_address = unsafe { bar.physmap_mem("rtl8139d") }.0 as usize; let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index c797c2e059..f8177b98d8 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -131,7 +131,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { msix_info.validate(pci_config.func.bars); let bar = &pci_config.func.bars[msix_info.table_bar as usize]; - let bar_address = unsafe { bar.physmap_mem("rtl8168d") } as usize; + let bar_address = unsafe { bar.physmap_mem("rtl8168d") }.0 as usize; let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index b279c44577..706479008b 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -53,9 +53,9 @@ impl PciBar { } } - pub unsafe fn physmap_mem(&self, driver: &str) -> *mut () { + pub unsafe fn physmap_mem(&self, driver: &str) -> (*mut (), usize) { let (bar, bar_size) = self.expect_mem(); - unsafe { + let addr = unsafe { common::physmap( bar, bar_size, @@ -64,6 +64,7 @@ impl PciBar { common::MemoryType::Uncacheable, ) } - .unwrap_or_else(|err| panic!("{driver}: failed to map BAR at {bar:016X}: {err}")) + .unwrap_or_else(|err| panic!("{driver}: failed to map BAR at {bar:016X}: {err}")); + (addr, bar_size) } } diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 7aae947b78..a5bb6f79db 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -88,7 +88,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { info!(" + AHCI {}", pci_config.func.display()); - let address = unsafe { bar.physmap_mem("ahcid") }; + let (address, _) = unsafe { bar.physmap_mem("ahcid") }; { let scheme_name = format!("disk.{}", name); let socket = Socket::::nonblock(&scheme_name).expect("ahcid: failed to create disk scheme"); diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 39167633d2..6910e0a65b 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -27,22 +27,12 @@ mod scheme; /// A wrapper for a BAR allocation. pub struct Bar { ptr: NonNull, - physical: usize, bar_size: usize, } impl Bar { - pub fn allocate(bar: usize, bar_size: usize) -> Result { + pub fn new(ptr: *mut (), bar_size: usize) -> Result { Ok(Self { - ptr: NonNull::new( - unsafe { common::physmap( - bar, - bar_size, - common::Prot { read: true, write: true }, - common::MemoryType::Uncacheable, - )? as *mut u8 }, - ) - .expect("Mapping a BAR resulted in a nullptr"), - physical: bar, + ptr: NonNull::new(ptr.cast::()).expect("Mapping a BAR resulted in a nullptr"), bar_size, }) } @@ -101,9 +91,9 @@ fn get_int_method( match &mut *bar_guard { &mut Some(ref bar) => Ok(bar.ptr), bar_to_set @ &mut None => { - let (bar, bar_size) = function.bars[bir].expect_mem(); + let (ptr, bar_size) = unsafe { function.bars[bir].physmap_mem("nvmed") }; - let bar = Bar::allocate(bar, bar_size)?; + let bar = Bar::new(ptr, bar_size)?; *bar_to_set = Some(bar); Ok(bar_to_set.as_ref().unwrap().ptr) } @@ -265,18 +255,16 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(&scheme_name); - let bar = &pci_config.func.bars[0]; - let (bar_ptr, bar_size) = bar.expect_mem(); - log::debug!("NVME PCI CONFIG: {:?}", pci_config); let allocated_bars = AllocatedBars::default(); - let address = unsafe { bar.physmap_mem("nvmed") } as usize; + let bar = &pci_config.func.bars[0]; + let (address, bar_size) = unsafe { bar.physmap_mem("nvmed") }; + *allocated_bars.0[0].lock().unwrap() = Some(Bar { - physical: bar_ptr, bar_size, - ptr: NonNull::new(address as *mut u8).expect("Physmapping BAR gave nullptr"), + ptr: NonNull::new(address.cast::()).expect("Physmapping BAR gave nullptr"), }); let socket = Socket::::create(&scheme_name).expect("nvmed: failed to create disk scheme"); @@ -287,8 +275,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let (interrupt_method, interrupt_sources) = get_int_method(&mut pcid_handle, &pci_config.func, &allocated_bars) .expect("nvmed: failed to find a suitable interrupt method"); - let mut nvme = Nvme::new(address, interrupt_method, pcid_handle, reactor_sender) - .expect("nvmed: failed to allocate driver data"); + let mut nvme = Nvme::new( + address as usize, + interrupt_method, + pcid_handle, + reactor_sender, + ) + .expect("nvmed: failed to allocate driver data"); unsafe { nvme.init() } log::debug!("Finished base initialization"); let nvme = Arc::new(nvme); diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index b24ddb0dcf..be65b6a11d 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -217,7 +217,7 @@ fn main() { let mut irq_file = irq.irq_handle("vboxd"); let mut port = Pio::::new(bar0 as u16); - let address = unsafe { bar1.physmap_mem("vboxd") }; + let (address, _) = unsafe { bar1.physmap_mem("vboxd") }; { let vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index e1b25fbbb5..95072fd0ac 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -19,7 +19,7 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { msix_info.validate(pci_config.func.bars); let bar = &pci_config.func.bars[msix_info.table_bar as usize]; - let bar_address = unsafe { bar.physmap_mem("virtio-core") } as usize; + let bar_address = unsafe { bar.physmap_mem("virtio-core") }.0 as usize; let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; let mut info = MappedMsixRegs { diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index ef5b122beb..3c3aa0dbce 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -195,7 +195,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::debug!("XHCI PCI CONFIG: {:?}", pci_config); let bar = &pci_config.func.bars[0]; - let address = unsafe { bar.physmap_mem("xhcid") } as usize; + let address = unsafe { bar.physmap_mem("xhcid") }.0 as usize; let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //TODO: get_int_method(&mut pcid_handle, address); From fdb9ea816b99077b320657afadbb6d3fc192c10f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Jun 2024 15:05:42 +0200 Subject: [PATCH 0920/1301] pcid: Rename PcidServerHandle to PciFunctionHandle --- audio/ac97d/src/main.rs | 4 ++-- audio/ihdad/src/main.rs | 8 ++++---- graphics/bgad/src/main.rs | 4 ++-- graphics/virtio-gpud/src/main.rs | 4 ++-- net/e1000d/src/main.rs | 4 ++-- net/ixgbed/src/main.rs | 4 ++-- net/rtl8139d/src/main.rs | 8 ++++---- net/rtl8168d/src/main.rs | 8 ++++---- net/virtio-netd/src/main.rs | 4 ++-- pcid/src/driver_interface/mod.rs | 4 ++-- storage/ahcid/src/main.rs | 4 ++-- storage/ided/src/main.rs | 4 ++-- storage/nvmed/src/main.rs | 8 ++++---- storage/nvmed/src/nvme/mod.rs | 6 +++--- storage/virtio-blkd/src/main.rs | 2 +- vboxd/src/main.rs | 4 ++-- virtio-core/src/arch/x86_64.rs | 4 ++-- virtio-core/src/probe.rs | 4 ++-- xhcid/src/main.rs | 8 ++++---- xhcid/src/xhci/mod.rs | 6 +++--- 20 files changed, 51 insertions(+), 51 deletions(-) diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index bbc6143b46..846a8af1a0 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -14,7 +14,7 @@ use std::usize; use event::{user_data, EventQueue}; use libredox::flag; -use pcid_interface::{PciBar, PcidServerHandle}; +use pcid_interface::{PciBar, PciFunctionHandle}; use redox_log::{OutputBuilder, RedoxLogger}; use syscall::{EventFlags, Packet, SchemeBlockMut}; @@ -66,7 +66,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { fn main() { let mut pcid_handle = - PcidServerHandle::connect_default().expect("ac97d: failed to setup channel to pcid"); + PciFunctionHandle::connect_default().expect("ac97d: failed to setup channel to pcid"); let pci_config = pcid_handle .fetch_config() .expect("ac97d: failed to fetch config"); diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index a8e6aa4ef3..a7ba09d801 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -16,7 +16,7 @@ use std::cell::RefCell; use std::sync::Arc; use event::{user_data, EventQueue}; -use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; +use pcid_interface::{MsiSetFeatureInfo, PciFunctionHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; @@ -76,7 +76,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } #[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { +fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); let all_pci_features = pcid_handle.fetch_all_features().expect("ihdad: failed to fetch pci features"); @@ -121,7 +121,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { +fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); if let Some(irq) = pci_config.func.legacy_interrupt_line { @@ -135,7 +135,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(); - let mut pcid_handle = PcidServerHandle::connect_default().expect("ihdad: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default().expect("ihdad: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index a80423f392..b03f81a2f0 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -4,7 +4,7 @@ extern crate syscall; use std::fs::File; use std::io::{Read, Write}; -use pcid_interface::PcidServerHandle; +use pcid_interface::PciFunctionHandle; use syscall::call::iopl; use syscall::data::Packet; use syscall::scheme::SchemeMut; @@ -17,7 +17,7 @@ mod scheme; fn main() { let mut pcid_handle = - PcidServerHandle::connect_default().expect("bgad: failed to setup channel to pcid"); + PciFunctionHandle::connect_default().expect("bgad: failed to setup channel to pcid"); let pci_config = pcid_handle .fetch_config() .expect("bgad: failed to fetch config"); diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 8a80510fbc..3fbeb0681d 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -27,7 +27,7 @@ use std::fs::File; use std::io::{Read, Write}; use std::sync::Arc; -use pcid_interface::PcidServerHandle; +use pcid_interface::PciFunctionHandle; use syscall::{Packet, SchemeMut}; use virtio_core::transport::{self, Queue}; @@ -409,7 +409,7 @@ fn reinit(control_queue: Arc, cursor_queue: Arc) -> Result<(), tra } fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { - let mut pcid_handle = PcidServerHandle::connect_default()?; + let mut pcid_handle = PciFunctionHandle::connect_default()?; // Double check that we have the right device. // diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index db893106e7..005770f09d 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -6,14 +6,14 @@ use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; -use pcid_interface::PcidServerHandle; +use pcid_interface::PciFunctionHandle; use syscall::EventFlags; pub mod device; fn main() { let mut pcid_handle = - PcidServerHandle::connect_default().expect("e1000d: failed to setup channel to pcid"); + PciFunctionHandle::connect_default().expect("e1000d: failed to setup channel to pcid"); let pci_config = pcid_handle .fetch_config() .expect("e1000d: failed to fetch config"); diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index 2c54c73ee2..a9fe183a79 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -6,7 +6,7 @@ use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; -use pcid_interface::PcidServerHandle; +use pcid_interface::PciFunctionHandle; use syscall::EventFlags; pub mod device; @@ -15,7 +15,7 @@ mod ixgbe; fn main() { let mut pcid_handle = - PcidServerHandle::connect_default().expect("ixgbed: failed to setup channel to pcid"); + PciFunctionHandle::connect_default().expect("ixgbed: failed to setup channel to pcid"); let pci_config = pcid_handle .fetch_config() .expect("ixgbed: failed to fetch config"); diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 04cba8fc48..2eb17379b8 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -15,7 +15,7 @@ use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixInfo, MsixTableEntry}; use pcid_interface::{ - MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PcidServerHandle, SetFeatureInfo, + MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, SubdriverArguments, }; use redox_log::{OutputBuilder, RedoxLogger}; @@ -95,7 +95,7 @@ impl MappedMsixRegs { } #[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { +fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("rtl8139d: failed to fetch config"); let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8139d: failed to fetch pci features"); @@ -177,7 +177,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { +fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("rtl8139d: failed to fetch config"); if let Some(irq) = pci_config.func.legacy_interrupt_line { @@ -209,7 +209,7 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(); - let mut pcid_handle = PcidServerHandle::connect_default().expect("rtl8139d: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default().expect("rtl8139d: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("rtl8139d: failed to fetch config"); diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index f8177b98d8..45a16d3ca5 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -8,7 +8,7 @@ use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; -use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; +use pcid_interface::{MsiSetFeatureInfo, PciFunctionHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; @@ -90,7 +90,7 @@ impl MappedMsixRegs { } #[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { +fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8168d: failed to fetch pci features"); @@ -172,7 +172,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PcidServerHandle) -> File { +fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); if let Some(irq) = pci_config.func.legacy_interrupt_line { @@ -204,7 +204,7 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(); - let mut pcid_handle = PcidServerHandle::connect_default().expect("rtl8168d: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default().expect("rtl8168d: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index d2a2411f55..d413e62da8 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -5,7 +5,7 @@ use std::io::{Read, Write}; use std::mem; use driver_network::NetworkScheme; -use pcid_interface::PcidServerHandle; +use pcid_interface::PciFunctionHandle; use scheme::VirtioNet; @@ -28,7 +28,7 @@ static_assertions::const_assert_eq!(core::mem::size_of::(), 12); const MAX_BUFFER_LEN: usize = 65535; fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box> { - let mut pcid_handle = PcidServerHandle::connect_default()?; + let mut pcid_handle = PciFunctionHandle::connect_default()?; // Double check that we have the right device. // diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 70bb982c33..6f92124b53 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -227,7 +227,7 @@ pub enum PcidClientResponse { // very similar to crossbeam-channel or libstd's mpsc (except the cycle, enqueue and dequeue fields // are stored in the same buffer as the actual data). /// A handle from a `pcid` client (e.g. `ahcid`) to `pcid`. -pub struct PcidServerHandle { +pub struct PciFunctionHandle { pcid_to_client: File, pcid_from_client: File, } @@ -253,7 +253,7 @@ pub(crate) fn recv(r: &mut R) -> Result { Ok(bincode::deserialize_from(&data[..])?) } -impl PcidServerHandle { +impl PciFunctionHandle { pub fn connect_default() -> Result { let pcid_to_client_fd = env::var("PCID_TO_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; let pcid_from_client_fd = env::var("PCID_FROM_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index a5bb6f79db..a912de71a5 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -9,7 +9,7 @@ use std::os::fd::AsRawFd; use std::usize; use event::{EventFlags, RawEventQueue}; -use pcid_interface::PcidServerHandle; +use pcid_interface::PciFunctionHandle; use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; use syscall::error::{Error, ENODEV}; @@ -72,7 +72,7 @@ fn main() { fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut pcid_handle = - PcidServerHandle::connect_default().expect("ahcid: failed to setup channel to pcid"); + PciFunctionHandle::connect_default().expect("ahcid: failed to setup channel to pcid"); let pci_config = pcid_handle .fetch_config() .expect("ahcid: failed to fetch config"); diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 0a10a625a0..b8dd79a70d 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -2,7 +2,7 @@ use driver_block::Disk; use event::{EventFlags, RawEventQueue}; use libredox::flag; use log::{error, info}; -use pcid_interface::{PciBar, PcidServerHandle}; +use pcid_interface::{PciBar, PciFunctionHandle}; use redox_log::{OutputBuilder, RedoxLogger}; use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; use std::{ @@ -75,7 +75,7 @@ fn main() { fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut pcid_handle = - PcidServerHandle::connect_default().expect("ided: failed to setup channel to pcid"); + PciFunctionHandle::connect_default().expect("ided: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("ided: failed to fetch config"); diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 6910e0a65b..f00ef3bbb9 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -10,7 +10,7 @@ use std::sync::{Arc, Mutex}; use std::{slice, usize}; use libredox::flag; -use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PcidServerHandle}; +use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PciFunctionHandle}; use redox_scheme::{CallRequest, RequestKind, SignalBehavior, Socket, V2}; use syscall::{ Event, Mmio, Packet, Result, SchemeBlockMut, @@ -58,7 +58,7 @@ pub struct AllocatedBars(pub [Mutex>; 6]); /// structures), and the handles to the interrupts. #[cfg(target_arch = "x86_64")] fn get_int_method( - pcid_handle: &mut PcidServerHandle, + pcid_handle: &mut PciFunctionHandle, function: &PciFunction, allocated_bars: &AllocatedBars, ) -> Result<(InterruptMethod, InterruptSources)> { @@ -184,7 +184,7 @@ fn get_int_method( //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] fn get_int_method( - pcid_handle: &mut PcidServerHandle, + pcid_handle: &mut PciFunctionHandle, function: &PciFunction, allocated_bars: &AllocatedBars, ) -> Result<(InterruptMethod, InterruptSources)> { @@ -246,7 +246,7 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut pcid_handle = - PcidServerHandle::connect_default().expect("nvmed: failed to setup channel to pcid"); + PciFunctionHandle::connect_default().expect("nvmed: failed to setup channel to pcid"); let pci_config = pcid_handle .fetch_config() .expect("nvmed: failed to fetch config"); diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 993736b890..14e502777a 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -23,7 +23,7 @@ use self::cq_reactor::NotifReq; pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue}; use pcid_interface::msi::{MsiInfo, MsixInfo, MsixTableEntry}; -use pcid_interface::PcidServerHandle; +use pcid_interface::PciFunctionHandle; #[cfg(target_arch = "aarch64")] #[inline(always)] @@ -173,7 +173,7 @@ pub type AtomicCmdId = AtomicU16; pub struct Nvme { interrupt_method: Mutex, - pcid_interface: Mutex, + pcid_interface: Mutex, regs: RwLock<&'static mut NvmeRegs>, pub(crate) submission_queues: RwLock, CqId)>>, @@ -209,7 +209,7 @@ impl Nvme { pub fn new( address: usize, interrupt_method: InterruptMethod, - pcid_interface: PcidServerHandle, + pcid_interface: PciFunctionHandle, reactor_sender: Sender, ) -> Result { Ok(Nvme { diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index abdbacaba7..289a4d91a1 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -109,7 +109,7 @@ pub struct BlockVirtRequest { const_assert_eq!(core::mem::size_of::(), 16); fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { - let mut pcid_handle = PcidServerHandle::connect_default()?; + let mut pcid_handle = PciFunctionHandle::connect_default()?; // Double check that we have the right device. // diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index be65b6a11d..16b1dae847 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -6,7 +6,7 @@ use std::os::unix::io::AsRawFd; use std::fs::File; use std::io::{Result, Read, Write}; -use pcid_interface::{PciBar, PcidServerHandle}; +use pcid_interface::{PciBar, PciFunctionHandle}; use syscall::flag::EventFlags; use syscall::io::{Io, Mmio, Pio}; @@ -181,7 +181,7 @@ impl VboxGuestInfo { fn main() { let mut pcid_handle = - PcidServerHandle::connect_default().expect("vboxd: failed to setup channel to pcid"); + PciFunctionHandle::connect_default().expect("vboxd: failed to setup channel to pcid"); let pci_config = pcid_handle .fetch_config() .expect("vboxd: failed to fetch config"); diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index 95072fd0ac..5413b2f169 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -8,7 +8,7 @@ use crate::{probe::MappedMsixRegs, MSIX_PRIMARY_VECTOR}; use pcid_interface::*; -pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { +pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { let pci_config = pcid_handle.fetch_config()?; // Extended message signaled interrupts. @@ -50,7 +50,7 @@ pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { pub fn probe_legacy_port_transport( pci_config: &SubdriverArguments, - pcid_handle: &mut PcidServerHandle, + pcid_handle: &mut PciFunctionHandle, ) -> Result { let port = pci_config.func.bars[0].expect_port(); diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 3cd6d8d8fb..7da40a958d 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -41,7 +41,7 @@ static_assertions::const_assert_eq!(std::mem::size_of::(), 16); pub const MSIX_PRIMARY_VECTOR: u16 = 0; #[cfg(not(target_arch = "x86_64"))] -fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { +fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { panic!("Msi-X only supported on x86_64"); } @@ -59,7 +59,7 @@ fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { /// /// ## Panics /// This function panics if the device is not a virtio device. -pub fn probe_device(pcid_handle: &mut PcidServerHandle) -> Result { +pub fn probe_device(pcid_handle: &mut PciFunctionHandle) -> Result { let pci_config = pcid_handle.fetch_config()?; assert_eq!( diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 3c3aa0dbce..9a1bb570f4 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -12,7 +12,7 @@ use std::sync::{Arc, Mutex}; use std::env; use libredox::flag; -use pcid_interface::{MsiSetFeatureInfo, PcidServerHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; +use pcid_interface::{MsiSetFeatureInfo, PciFunctionHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; @@ -85,7 +85,7 @@ fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { } #[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (Option, InterruptMethod) { +fn get_int_method(pcid_handle: &mut PciFunctionHandle, bar0_address: usize) -> (Option, InterruptMethod) { let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); @@ -167,7 +167,7 @@ fn get_int_method(pcid_handle: &mut PcidServerHandle, bar0_address: usize) -> (O //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PcidServerHandle, address: usize) -> (Option, InterruptMethod) { +fn get_int_method(pcid_handle: &mut PciFunctionHandle, address: usize) -> (Option, InterruptMethod) { let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); if let Some(irq) = pci_config.func.legacy_interrupt_line { @@ -184,7 +184,7 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); let mut name = pci_config.func.name(); diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 32eb7f7dd4..f42482f1ea 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -22,7 +22,7 @@ use serde::Deserialize; use crate::usb; use pcid_interface::msi::{MsixInfo, MsixTableEntry}; -use pcid_interface::{PcidServerHandle, PciFeature}; +use pcid_interface::{PciFunctionHandle, PciFeature}; mod capability; mod context; @@ -198,7 +198,7 @@ pub struct Xhci { scheme_name: String, interrupt_method: InterruptMethod, - pcid_handle: Mutex, + pcid_handle: Mutex, irq_reactor: Mutex>>, @@ -258,7 +258,7 @@ impl EndpointState { } impl Xhci { - pub fn new(scheme_name: String, address: usize, interrupt_method: InterruptMethod, pcid_handle: PcidServerHandle) -> Result { + pub fn new(scheme_name: String, address: usize, interrupt_method: InterruptMethod, pcid_handle: PciFunctionHandle) -> Result { let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; debug!("CAP REGS BASE {:X}", address); From a3b957c2e5b7c9138732e2c4c14eba9bf62d8b3e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Jun 2024 15:16:09 +0200 Subject: [PATCH 0921/1301] pcid: Fetch config in PciFunctionHandle::connect_default() --- audio/ac97d/src/main.rs | 6 ++---- audio/ihdad/src/main.rs | 6 +++--- graphics/bgad/src/main.rs | 6 ++---- graphics/virtio-gpud/src/main.rs | 2 +- net/e1000d/src/main.rs | 6 ++---- net/ixgbed/src/main.rs | 6 ++---- net/rtl8139d/src/main.rs | 6 +++--- net/rtl8168d/src/main.rs | 6 +++--- net/virtio-netd/src/main.rs | 2 +- pcid/src/driver_interface/mod.rs | 23 +++++++++++++++-------- storage/ahcid/src/main.rs | 6 ++---- storage/ided/src/main.rs | 4 ++-- storage/nvmed/src/main.rs | 4 +--- storage/virtio-blkd/src/main.rs | 2 +- vboxd/src/main.rs | 6 ++---- virtio-core/src/arch/x86_64.rs | 2 +- virtio-core/src/probe.rs | 2 +- xhcid/src/main.rs | 8 ++++---- 18 files changed, 48 insertions(+), 55 deletions(-) diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index 846a8af1a0..9066acc52a 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -65,11 +65,9 @@ fn setup_logging() -> Option<&'static RedoxLogger> { } fn main() { - let mut pcid_handle = + let pcid_handle = PciFunctionHandle::connect_default().expect("ac97d: failed to setup channel to pcid"); - let pci_config = pcid_handle - .fetch_config() - .expect("ac97d: failed to fetch config"); + let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_ac97"); diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index a7ba09d801..820b5d2cc1 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -77,7 +77,7 @@ fn setup_logging() -> Option<&'static RedoxLogger> { #[cfg(target_arch = "x86_64")] fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); + let pci_config = pcid_handle.config(); let all_pci_features = pcid_handle.fetch_all_features().expect("ihdad: failed to fetch pci features"); log::debug!("PCI FEATURES: {:?}", all_pci_features); @@ -122,7 +122,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); + let pci_config = pcid_handle.config(); if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. @@ -137,7 +137,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut pcid_handle = PciFunctionHandle::connect_default().expect("ihdad: failed to setup channel to pcid"); - let pci_config = pcid_handle.fetch_config().expect("ihdad: failed to fetch config"); + let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_ihda"); diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index b03f81a2f0..c4832e8560 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -16,11 +16,9 @@ mod bga; mod scheme; fn main() { - let mut pcid_handle = + let pcid_handle = PciFunctionHandle::connect_default().expect("bgad: failed to setup channel to pcid"); - let pci_config = pcid_handle - .fetch_config() - .expect("bgad: failed to fetch config"); + let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_bga"); diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 3fbeb0681d..938ec8c817 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -414,7 +414,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { // Double check that we have the right device. // // 0x1050 - virtio-gpu - let pci_config = pcid_handle.fetch_config()?; + let pci_config = pcid_handle.config(); assert_eq!(pci_config.func.full_device_id.device_id, 0x1050); log::info!("virtio-gpu: initiating startup sequence :^)"); diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index 005770f09d..7e7bb90ade 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -12,11 +12,9 @@ use syscall::EventFlags; pub mod device; fn main() { - let mut pcid_handle = + let pcid_handle = PciFunctionHandle::connect_default().expect("e1000d: failed to setup channel to pcid"); - let pci_config = pcid_handle - .fetch_config() - .expect("e1000d: failed to fetch config"); + let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_e1000"); diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index a9fe183a79..0b8640dafc 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -14,11 +14,9 @@ pub mod device; mod ixgbe; fn main() { - let mut pcid_handle = + let pcid_handle = PciFunctionHandle::connect_default().expect("ixgbed: failed to setup channel to pcid"); - let pci_config = pcid_handle - .fetch_config() - .expect("ixgbed: failed to fetch config"); + let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_ixgbe"); diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 2eb17379b8..d0893aec93 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -96,7 +96,7 @@ impl MappedMsixRegs { #[cfg(target_arch = "x86_64")] fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.fetch_config().expect("rtl8139d: failed to fetch config"); + let pci_config = pcid_handle.config(); let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8139d: failed to fetch pci features"); log::info!("PCI FEATURES: {:?}", all_pci_features); @@ -178,7 +178,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.fetch_config().expect("rtl8139d: failed to fetch config"); + let pci_config = pcid_handle.config(); if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. @@ -211,7 +211,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut pcid_handle = PciFunctionHandle::connect_default().expect("rtl8139d: failed to setup channel to pcid"); - let pci_config = pcid_handle.fetch_config().expect("rtl8139d: failed to fetch config"); + let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_rtl8139"); diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 45a16d3ca5..b2ec6f69b5 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -91,7 +91,7 @@ impl MappedMsixRegs { #[cfg(target_arch = "x86_64")] fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); + let pci_config = pcid_handle.config(); let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8168d: failed to fetch pci features"); log::info!("PCI FEATURES: {:?}", all_pci_features); @@ -173,7 +173,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); + let pci_config = pcid_handle.config(); if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. @@ -206,7 +206,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut pcid_handle = PciFunctionHandle::connect_default().expect("rtl8168d: failed to setup channel to pcid"); - let pci_config = pcid_handle.fetch_config().expect("rtl8168d: failed to fetch config"); + let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_rtl8168"); diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index d413e62da8..76e07b160f 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -33,7 +33,7 @@ fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box // Double check that we have the right device. // // 0x1000 - virtio-net - let pci_config = pcid_handle.fetch_config()?; + let pci_config = pcid_handle.config(); assert_eq!(pci_config.func.full_device_id.device_id, 0x1000); log::info!("virtio-net: initiating startup sequence :^)"); diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 6f92124b53..5f57c343ad 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -230,6 +230,7 @@ pub enum PcidClientResponse { pub struct PciFunctionHandle { pcid_to_client: File, pcid_from_client: File, + config: SubdriverArguments, } pub(crate) fn send(w: &mut W, message: &T) -> Result<()> { @@ -258,9 +259,19 @@ impl PciFunctionHandle { let pcid_to_client_fd = env::var("PCID_TO_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; let pcid_from_client_fd = env::var("PCID_FROM_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; + let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd) }; + let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd) }; + + send(&mut pcid_from_client, &PcidClientRequest::RequestConfig)?; + let config = match recv(&mut pcid_to_client)? { + PcidClientResponse::Config(a) => a, + other => return Err(PcidClientHandleError::InvalidResponse(other)), + }; + Ok(Self { - pcid_to_client: unsafe { File::from_raw_fd(pcid_to_client_fd) }, - pcid_from_client: unsafe { File::from_raw_fd(pcid_from_client_fd) }, + pcid_to_client, + pcid_from_client, + config, }) } fn send(&mut self, req: &PcidClientRequest) -> Result<()> { @@ -269,12 +280,8 @@ impl PciFunctionHandle { fn recv(&mut self) -> Result { recv(&mut self.pcid_to_client) } - pub fn fetch_config(&mut self) -> Result { - self.send(&PcidClientRequest::RequestConfig)?; - match self.recv()? { - PcidClientResponse::Config(a) => Ok(a), - other => Err(PcidClientHandleError::InvalidResponse(other)), - } + pub fn config(&self) -> SubdriverArguments { + self.config.clone() } pub fn get_vendor_capabilities(&mut self) -> Result> { diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index a912de71a5..1947c02094 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -71,11 +71,9 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let mut pcid_handle = + let pcid_handle = PciFunctionHandle::connect_default().expect("ahcid: failed to setup channel to pcid"); - let pci_config = pcid_handle - .fetch_config() - .expect("ahcid: failed to fetch config"); + let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_ahci"); diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index b8dd79a70d..c4723fad54 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -74,10 +74,10 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let mut pcid_handle = + let pcid_handle = PciFunctionHandle::connect_default().expect("ided: failed to setup channel to pcid"); - let pci_config = pcid_handle.fetch_config().expect("ided: failed to fetch config"); + let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_ide"); diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index f00ef3bbb9..b6abc0e856 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -247,9 +247,7 @@ fn main() { fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut pcid_handle = PciFunctionHandle::connect_default().expect("nvmed: failed to setup channel to pcid"); - let pci_config = pcid_handle - .fetch_config() - .expect("nvmed: failed to fetch config"); + let pci_config = pcid_handle.config(); let scheme_name = format!("disk.{}-nvme", pci_config.func.name()); diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 289a4d91a1..8d819db570 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -114,7 +114,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { // Double check that we have the right device. // // 0x1001 - virtio-blk - let pci_config = pcid_handle.fetch_config()?; + let pci_config = pcid_handle.config(); assert_eq!(pci_config.func.full_device_id.device_id, 0x1001); log::info!("virtio-blk: initiating startup sequence :^)"); diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 16b1dae847..9a1ab423db 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -180,11 +180,9 @@ impl VboxGuestInfo { } fn main() { - let mut pcid_handle = + let pcid_handle = PciFunctionHandle::connect_default().expect("vboxd: failed to setup channel to pcid"); - let pci_config = pcid_handle - .fetch_config() - .expect("vboxd: failed to fetch config"); + let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_vbox"); diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index 5413b2f169..c804ab9dfa 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -9,7 +9,7 @@ use crate::{probe::MappedMsixRegs, MSIX_PRIMARY_VECTOR}; use pcid_interface::*; pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { - let pci_config = pcid_handle.fetch_config()?; + let pci_config = pcid_handle.config(); // Extended message signaled interrupts. let msix_info = match pcid_handle.feature_info(PciFeature::MsiX)? { diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 7da40a958d..984acd88d2 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -60,7 +60,7 @@ fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { /// ## Panics /// This function panics if the device is not a virtio device. pub fn probe_device(pcid_handle: &mut PciFunctionHandle) -> Result { - let pci_config = pcid_handle.fetch_config()?; + let pci_config = pcid_handle.config(); assert_eq!( pci_config.func.full_device_id.vendor_id, 6900, diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 9a1bb570f4..fc441b03bc 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -86,7 +86,7 @@ fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { #[cfg(target_arch = "x86_64")] fn get_int_method(pcid_handle: &mut PciFunctionHandle, bar0_address: usize) -> (Option, InterruptMethod) { - let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); + let pci_config = pcid_handle.config(); let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); log::debug!("XHCI PCI FEATURES: {:?}", all_pci_features); @@ -168,7 +168,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle, bar0_address: usize) -> ( //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] fn get_int_method(pcid_handle: &mut PciFunctionHandle, address: usize) -> (Option, InterruptMethod) { - let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); + let pci_config = pcid_handle.config(); if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. @@ -184,8 +184,8 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let mut pcid_handle = PciFunctionHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); - let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config"); + let pcid_handle = PciFunctionHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); + let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_xhci"); From 23ac69649163c41d4573060a66d7bb4050ef4447 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Jun 2024 15:47:48 +0200 Subject: [PATCH 0922/1301] pcid: Add PciFunctionHandle::map_bar method This will enable the pcid driver interface to safely map the MSI-X table in the future without having to worry about a BAR being mapped twice. --- audio/ihdad/src/main.rs | 4 +- net/e1000d/src/main.rs | 9 +++-- net/ixgbed/src/main.rs | 8 ++-- net/rtl8139d/src/main.rs | 5 ++- net/rtl8168d/src/main.rs | 5 ++- pcid/src/driver_interface/mod.rs | 31 +++++++++++++++ pcid/src/pci/bar.rs | 15 -------- storage/ahcid/src/main.rs | 6 +-- storage/nvmed/src/main.rs | 66 +++----------------------------- vboxd/src/main.rs | 6 +-- virtio-core/src/arch/x86_64.rs | 5 ++- xhcid/src/main.rs | 9 +++-- 12 files changed, 66 insertions(+), 103 deletions(-) diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 820b5d2cc1..78f2ebbe32 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -142,11 +142,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_ihda"); - let bar = &pci_config.func.bars[0]; - log::info!(" + IHDA {}", pci_config.func.display()); - let address = unsafe { bar.physmap_mem("ihdad") }.0 as usize; + let address = unsafe { pcid_handle.map_bar(0).expect("ihdad") }.ptr.as_ptr() as usize; //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index 7e7bb90ade..1ed1608237 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -12,15 +12,13 @@ use syscall::EventFlags; pub mod device; fn main() { - let pcid_handle = + let mut pcid_handle = PciFunctionHandle::connect_default().expect("e1000d: failed to setup channel to pcid"); let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_e1000"); - let bar = &pci_config.func.bars[0]; - let irq = pci_config .func .legacy_interrupt_line @@ -31,7 +29,10 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let mut irq_file = irq.irq_handle("e1000d"); - let address = unsafe { bar.physmap_mem("e1000d") }.0 as usize; + let address = unsafe { pcid_handle.map_bar(0) } + .expect("e1000d") + .ptr + .as_ptr() as usize; let device = unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }; diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index 0b8640dafc..8382823230 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -14,7 +14,7 @@ pub mod device; mod ixgbe; fn main() { - let pcid_handle = + let mut pcid_handle = PciFunctionHandle::connect_default().expect("ixgbed: failed to setup channel to pcid"); let pci_config = pcid_handle.config(); @@ -31,9 +31,9 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let mut irq_file = irq.irq_handle("ixgbed"); - let (address, size) = unsafe { - pci_config.func.bars[0].physmap_mem("ixgbed") - }; + let mapped_bar = unsafe { pcid_handle.map_bar(0) }.expect("ixgbed"); + let address = mapped_bar.ptr.as_ptr(); + let size = mapped_bar.bar_size; let device = device::Intel8259x::new(address as usize, size) .expect("ixgbed: failed to allocate device"); diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index d0893aec93..4c3d8d0073 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -135,8 +135,9 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { }; msix_info.validate(pci_config.func.bars); - let bar = &pci_config.func.bars[msix_info.table_bar as usize]; - let bar_address = unsafe { bar.physmap_mem("rtl8139d") }.0 as usize; + let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar).expect("rtl8139d") } + .ptr + .as_ptr() as usize; let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index b2ec6f69b5..7ba886d4c5 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -130,8 +130,9 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { }; msix_info.validate(pci_config.func.bars); - let bar = &pci_config.func.bars[msix_info.table_bar as usize]; - let bar_address = unsafe { bar.physmap_mem("rtl8168d") }.0 as usize; + let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar).expect("rtl8168d") } + .ptr + .as_ptr() as usize; let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 5f57c343ad..f65d2885cc 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -1,6 +1,7 @@ use std::fmt; use std::fs::File; use std::io::prelude::*; +use std::ptr::NonNull; use std::{env, io}; use std::os::unix::io::{FromRawFd, RawFd}; @@ -222,6 +223,11 @@ pub enum PcidClientResponse { WriteConfig, } +pub struct MappedBar { + pub ptr: NonNull, + pub bar_size: usize, +} + // TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over // a channel, the communication could potentially be done via mmap, using a channel // very similar to crossbeam-channel or libstd's mpsc (except the cycle, enqueue and dequeue fields @@ -231,6 +237,7 @@ pub struct PciFunctionHandle { pcid_to_client: File, pcid_from_client: File, config: SubdriverArguments, + mapped_bars: [Option; 6], } pub(crate) fn send(w: &mut W, message: &T) -> Result<()> { @@ -272,6 +279,7 @@ impl PciFunctionHandle { pcid_to_client, pcid_from_client, config, + mapped_bars: [const { None }; 6], }) } fn send(&mut self, req: &PcidClientRequest) -> Result<()> { @@ -336,4 +344,27 @@ impl PciFunctionHandle { other => Err(PcidClientHandleError::InvalidResponse(other)), } } + pub unsafe fn map_bar(&mut self, bir: u8) -> Result<&MappedBar> { + let mapped_bar = &mut self.mapped_bars[bir as usize]; + if let Some(mapped_bar) = mapped_bar { + Ok(mapped_bar) + } else { + let (bar, bar_size) = self.config.func.bars[bir as usize].expect_mem(); + let ptr = unsafe { + common::physmap( + bar, + bar_size, + common::Prot::RW, + // FIXME once the kernel supports this use write-through for prefetchable BAR + common::MemoryType::Uncacheable, + ) + } + .map_err(|err| io::Error::other(format!("failed to map BAR at {bar:016X}: {err}")))?; + + Ok(mapped_bar.insert(MappedBar { + ptr: NonNull::new(ptr.cast::()).expect("Mapping a BAR resulted in a nullptr"), + bar_size, + })) + } + } } diff --git a/pcid/src/pci/bar.rs b/pcid/src/pci/bar.rs index 706479008b..b2c1d35bbd 100644 --- a/pcid/src/pci/bar.rs +++ b/pcid/src/pci/bar.rs @@ -52,19 +52,4 @@ impl PciBar { PciBar::None => panic!("expected BAR to exist"), } } - - pub unsafe fn physmap_mem(&self, driver: &str) -> (*mut (), usize) { - let (bar, bar_size) = self.expect_mem(); - let addr = unsafe { - common::physmap( - bar, - bar_size, - common::Prot::RW, - // FIXME once the kernel supports this use write-through for prefetchable BAR - common::MemoryType::Uncacheable, - ) - } - .unwrap_or_else(|err| panic!("{driver}: failed to map BAR at {bar:016X}: {err}")); - (addr, bar_size) - } } diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 1947c02094..a3a8107729 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -71,22 +71,20 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let pcid_handle = + let mut pcid_handle = PciFunctionHandle::connect_default().expect("ahcid: failed to setup channel to pcid"); let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); name.push_str("_ahci"); - let bar = &pci_config.func.bars[5]; - let irq = pci_config.func.legacy_interrupt_line.expect("ahcid: no legacy interrupts supported"); let _logger_ref = setup_logging(&name); info!(" + AHCI {}", pci_config.func.display()); - let (address, _) = unsafe { bar.physmap_mem("ahcid") }; + let address = unsafe { pcid_handle.map_bar(5).expect("ahcid") }.ptr.as_ptr() as usize; { let scheme_name = format!("disk.{}", name); let socket = Socket::::nonblock(&scheme_name).expect("ahcid: failed to create disk scheme"); diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index b6abc0e856..f3bc114106 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -24,35 +24,6 @@ use self::scheme::DiskScheme; mod nvme; mod scheme; -/// A wrapper for a BAR allocation. -pub struct Bar { - ptr: NonNull, - bar_size: usize, -} -impl Bar { - pub fn new(ptr: *mut (), bar_size: usize) -> Result { - Ok(Self { - ptr: NonNull::new(ptr.cast::()).expect("Mapping a BAR resulted in a nullptr"), - bar_size, - }) - } -} - -impl Drop for Bar { - fn drop(&mut self) { - let _ = unsafe { - libredox::call::munmap( - self.ptr.as_ptr().cast(), - self.bar_size.next_multiple_of(PAGE_SIZE), - ) - }; - } -} - -/// The PCI BARs that may be allocated. -#[derive(Default)] -pub struct AllocatedBars(pub [Mutex>; 6]); - /// Get the most optimal yet functional interrupt mechanism: either (in the order of preference): /// MSI-X, MSI, and INTx# pin. Returns both runtime interrupt structures (MSI/MSI-X capability /// structures), and the handles to the interrupts. @@ -60,7 +31,6 @@ pub struct AllocatedBars(pub [Mutex>; 6]); fn get_int_method( pcid_handle: &mut PciFunctionHandle, function: &PciFunction, - allocated_bars: &AllocatedBars, ) -> Result<(InterruptMethod, InterruptSources)> { log::trace!("Begin get_int_method"); use pcid_interface::irq_helpers; @@ -81,26 +51,11 @@ fn get_int_method( _ => unreachable!(), }; msix_info.validate(function.bars); - fn bar_base( - allocated_bars: &AllocatedBars, - function: &PciFunction, - bir: u8, - ) -> Result> { - let bir = usize::from(bir); - let mut bar_guard = allocated_bars.0[bir].lock().unwrap(); - match &mut *bar_guard { - &mut Some(ref bar) => Ok(bar.ptr), - bar_to_set @ &mut None => { - let (ptr, bar_size) = unsafe { function.bars[bir].physmap_mem("nvmed") }; - - let bar = Bar::new(ptr, bar_size)?; - *bar_to_set = Some(bar); - Ok(bar_to_set.as_ref().unwrap().ptr) - } - } + fn bar_base(pcid_handle: &mut PciFunctionHandle, bir: u8) -> Result> { + Ok(unsafe { pcid_handle.map_bar(bir) }.expect("nvmed").ptr) } let table_bar_base: *mut u8 = - bar_base(allocated_bars, function, msix_info.table_bar)?.as_ptr(); + bar_base(pcid_handle, msix_info.table_bar)?.as_ptr(); let table_base = unsafe { table_bar_base.offset(msix_info.table_offset as isize) }; @@ -186,7 +141,6 @@ fn get_int_method( fn get_int_method( pcid_handle: &mut PciFunctionHandle, function: &PciFunction, - allocated_bars: &AllocatedBars, ) -> Result<(InterruptMethod, InterruptSources)> { if let Some(irq) = function.legacy_interrupt_line { // INTx# pin based interrupts. @@ -255,15 +209,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::debug!("NVME PCI CONFIG: {:?}", pci_config); - let allocated_bars = AllocatedBars::default(); - - let bar = &pci_config.func.bars[0]; - let (address, bar_size) = unsafe { bar.physmap_mem("nvmed") }; - - *allocated_bars.0[0].lock().unwrap() = Some(Bar { - bar_size, - ptr: NonNull::new(address.cast::()).expect("Physmapping BAR gave nullptr"), - }); + let address = unsafe { pcid_handle.map_bar(0).expect("nvmed").ptr }; let socket = Socket::::create(&scheme_name).expect("nvmed: failed to create disk scheme"); @@ -271,10 +217,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); let (interrupt_method, interrupt_sources) = - get_int_method(&mut pcid_handle, &pci_config.func, &allocated_bars) + get_int_method(&mut pcid_handle, &pci_config.func) .expect("nvmed: failed to find a suitable interrupt method"); let mut nvme = Nvme::new( - address as usize, + address.as_ptr() as usize, interrupt_method, pcid_handle, reactor_sender, diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 9a1ab423db..fac9717351 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -180,7 +180,7 @@ impl VboxGuestInfo { } fn main() { - let pcid_handle = + let mut pcid_handle = PciFunctionHandle::connect_default().expect("vboxd: failed to setup channel to pcid"); let pci_config = pcid_handle.config(); @@ -189,8 +189,6 @@ fn main() { let bar0 = pci_config.func.bars[0].expect_port(); - let bar1 = &pci_config.func.bars[1]; - let irq = pci_config.func.legacy_interrupt_line.expect("vboxd: no legacy interrupts supported"); println!(" + VirtualBox {}", pci_config.func.display()); @@ -215,7 +213,7 @@ fn main() { let mut irq_file = irq.irq_handle("vboxd"); let mut port = Pio::::new(bar0 as u16); - let (address, _) = unsafe { bar1.physmap_mem("vboxd") }; + let address = unsafe { pcid_handle.map_bar(1) }.expect("vboxd").ptr.as_ptr(); { let vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs index c804ab9dfa..edb85ab942 100644 --- a/virtio-core/src/arch/x86_64.rs +++ b/virtio-core/src/arch/x86_64.rs @@ -18,8 +18,9 @@ pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { }; msix_info.validate(pci_config.func.bars); - let bar = &pci_config.func.bars[msix_info.table_bar as usize]; - let bar_address = unsafe { bar.physmap_mem("virtio-core") }.0 as usize; + let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar)? } + .ptr + .as_ptr() as usize; let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; let mut info = MappedMsixRegs { diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index fc441b03bc..6248e4264f 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -184,7 +184,8 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let pcid_handle = PciFunctionHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); + let mut pcid_handle = + PciFunctionHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); @@ -193,9 +194,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let _logger_ref = setup_logging(&name); log::debug!("XHCI PCI CONFIG: {:?}", pci_config); - let bar = &pci_config.func.bars[0]; - let address = unsafe { bar.physmap_mem("xhcid") }.0 as usize; + let address = unsafe { pcid_handle.map_bar(0) } + .expect("xhcid") + .ptr + .as_ptr() as usize; let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //TODO: get_int_method(&mut pcid_handle, address); From 2144eaa62c915b20ea1e362c47bee89f9d9b02b0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Jun 2024 15:58:16 +0200 Subject: [PATCH 0923/1301] Rustfmt pcid --- pcid/src/driver_interface/irq_helpers.rs | 54 +++++++++++++++++------- pcid/src/driver_interface/mod.rs | 26 +++++++++--- pcid/src/pci/cap.rs | 11 ++--- pcid/src/pci/msi.rs | 43 ++++++++++++++++--- 4 files changed, 101 insertions(+), 33 deletions(-) diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index 7a36210cc6..c5c8d0d7f4 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -20,29 +20,45 @@ pub fn read_bsp_apic_id() -> io::Result { (if bytes_read == 8 { usize::try_from(u64::from_le_bytes(buffer)) } else if bytes_read == 4 { - usize::try_from(u32::from_le_bytes([buffer[0], buffer[1], buffer[2], buffer[3]])) + usize::try_from(u32::from_le_bytes([ + buffer[0], buffer[1], buffer[2], buffer[3], + ])) } else { - panic!("`irq:` scheme responded with {} bytes, expected {}", bytes_read, std::mem::size_of::()); - }).or(Err(io::Error::new(io::ErrorKind::InvalidData, "bad BSP int size"))) + panic!( + "`irq:` scheme responded with {} bytes, expected {}", + bytes_read, + std::mem::size_of::() + ); + }) + .or(Err(io::Error::new( + io::ErrorKind::InvalidData, + "bad BSP int size", + ))) } // TODO: Perhaps read the MADT instead? /// Obtains an interator over all of the visible CPU ids, for use in IRQ allocation and MSI /// capability structs or MSI-X tables. pub fn cpu_ids() -> io::Result> + 'static> { - Ok(fs::read_dir("irq:")? - .filter_map(|entry| -> Option> { match entry { - Ok(e) => { - let path = e.path(); - let file_name = path.file_name()?.to_str()?; - // the file name should be in the format `cpu-` - if ! file_name.starts_with("cpu-") { - return None; + Ok( + fs::read_dir("irq:")?.filter_map(|entry| -> Option> { + match entry { + Ok(e) => { + let path = e.path(); + let file_name = path.file_name()?.to_str()?; + // the file name should be in the format `cpu-` + if !file_name.starts_with("cpu-") { + return None; + } + u8::from_str_radix(&file_name[4..], 16) + .map(usize::from) + .map(Ok) + .ok() } - u8::from_str_radix(&file_name[4..], 16).map(usize::from).map(Ok).ok() + Err(e) => Some(Err(e)), } - Err(e) => Some(Err(e)), - } })) + }), + ) } /// Allocate multiple interrupt vectors, from the IDT of the specified processor, returning the @@ -62,9 +78,15 @@ pub fn cpu_ids() -> io::Result> + 'static /// individually allocated vectors that might be spread out, even on multiple CPUs. Thus, multiple /// invocations with alignment 1 and count 1 are totally acceptable, although allocating in bulk /// minimizes the initialization overhead. -pub fn allocate_aligned_interrupt_vectors(cpu_id: usize, alignment: NonZeroU8, count: u8) -> io::Result)>> { +pub fn allocate_aligned_interrupt_vectors( + cpu_id: usize, + alignment: NonZeroU8, + count: u8, +) -> io::Result)>> { let cpu_id = u8::try_from(cpu_id).expect("usize cpu ids not implemented yet"); - if count == 0 { return Ok(None) } + if count == 0 { + return Ok(None); + } let available_irqs = fs::read_dir(format!("irq:cpu-{:02x}", cpu_id))?; let mut available_irq_numbers = available_irqs.filter_map(|entry| -> Option> { diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index f65d2885cc..b0e33cee4d 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -114,7 +114,11 @@ impl FeatureStatus { } } pub fn is_enabled(&self) -> bool { - if let &Self::Enabled = self { true } else { false } + if let &Self::Enabled = self { + true + } else { + false + } } } @@ -125,10 +129,18 @@ pub enum PciFeature { } impl PciFeature { pub fn is_msi(self) -> bool { - if let Self::Msi = self { true } else { false } + if let Self::Msi = self { + true + } else { + false + } } pub fn is_msix(self) -> bool { - if let Self::MsiX = self { true } else { false } + if let Self::MsiX = self { + true + } else { + false + } } } #[derive(Debug, Serialize, Deserialize)] @@ -263,8 +275,12 @@ pub(crate) fn recv(r: &mut R) -> Result { impl PciFunctionHandle { pub fn connect_default() -> Result { - let pcid_to_client_fd = env::var("PCID_TO_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; - let pcid_from_client_fd = env::var("PCID_FROM_CLIENT_FD")?.parse::().map_err(PcidClientHandleError::EnvValidityError)?; + let pcid_to_client_fd = env::var("PCID_TO_CLIENT_FD")? + .parse::() + .map_err(PcidClientHandleError::EnvValidityError)?; + let pcid_from_client_fd = env::var("PCID_FROM_CLIENT_FD")? + .parse::() + .map_err(PcidClientHandleError::EnvValidityError)?; let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd) }; let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd) }; diff --git a/pcid/src/pci/cap.rs b/pcid/src/pci/cap.rs index 7655be1c14..d03e6ff520 100644 --- a/pcid/src/pci/cap.rs +++ b/pcid/src/pci/cap.rs @@ -1,6 +1,6 @@ use pci_types::capability::PciCapabilityAddress; use pci_types::ConfigRegionAccess; -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] pub struct VendorSpecificCapability { @@ -8,7 +8,10 @@ pub struct VendorSpecificCapability { } impl VendorSpecificCapability { - pub(crate) unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { + pub(crate) unsafe fn parse( + addr: PciCapabilityAddress, + access: &dyn ConfigRegionAccess, + ) -> Self { let dword = access.read(addr.address, addr.offset); let next = (dword >> 8) & 0xFF; let length = ((dword >> 16) & 0xFF) as u16; @@ -33,8 +36,6 @@ impl VendorSpecificCapability { log::warn!("Vendor specific capability is invalid"); Vec::new() }; - VendorSpecificCapability { - data - } + VendorSpecificCapability { data } } } diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index 1332f19ce4..a29a12cd96 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -40,10 +40,16 @@ pub struct MsixInfo { impl MsixInfo { pub fn validate(&self, bars: [PciBar; 6]) { if self.table_bar > 5 { - panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bar); + panic!( + "MSI-X Table BIR contained a reserved enum value: {}", + self.table_bar + ); } if self.pba_bar > 5 { - panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bar); + panic!( + "MSI-X PBA BIR contained a reserved enum value: {}", + self.pba_bar + ); } let table_size = self.table_size; @@ -113,23 +119,46 @@ pub mod x86_64 { } // TODO: should the reserved field be preserved? - pub const fn message_address(destination_id: u8, redirect_hint: bool, dest_mode_logical: bool) -> u64 { + pub const fn message_address( + destination_id: u8, + redirect_hint: bool, + dest_mode_logical: bool, + ) -> u64 { 0x0000_0000_FEE0_0000u64 | ((destination_id as u64) << 12) | ((redirect_hint as u64) << 3) | ((dest_mode_logical as u64) << 2) } - pub const fn message_data(trigger_mode: TriggerMode, level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 { + pub const fn message_data( + trigger_mode: TriggerMode, + level_trigger_mode: LevelTriggerMode, + delivery_mode: DeliveryMode, + vector: u8, + ) -> u32 { ((trigger_mode as u32) << 15) | ((level_trigger_mode as u32) << 14) | ((delivery_mode as u32) << 8) | vector as u32 } - pub const fn message_data_level_triggered(level_trigger_mode: LevelTriggerMode, delivery_mode: DeliveryMode, vector: u8) -> u32 { - message_data(TriggerMode::Level, level_trigger_mode, delivery_mode, vector) + pub const fn message_data_level_triggered( + level_trigger_mode: LevelTriggerMode, + delivery_mode: DeliveryMode, + vector: u8, + ) -> u32 { + message_data( + TriggerMode::Level, + level_trigger_mode, + delivery_mode, + vector, + ) } pub const fn message_data_edge_triggered(delivery_mode: DeliveryMode, vector: u8) -> u32 { - message_data(TriggerMode::Edge, LevelTriggerMode::Deassert, delivery_mode, vector) + message_data( + TriggerMode::Edge, + LevelTriggerMode::Deassert, + delivery_mode, + vector, + ) } } From b6a75d0a165fc46ab37632622ad9037a20232e35 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Jun 2024 21:54:36 +0200 Subject: [PATCH 0924/1301] virtio: Support the modern transport on x86 --- pcid/src/driver_interface/irq_helpers.rs | 8 ++-- pcid/src/pci/msi.rs | 4 +- virtio-core/src/arch/x86.rs | 50 ++++++++++++++++++++++-- 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index c5c8d0d7f4..9d7615a285 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -178,21 +178,21 @@ pub fn allocate_single_interrupt_vector(cpu_id: usize) -> io::Result (MsiAddrAndData, File) { - use crate::pci::msi::x86_64 as x86_64_msix; + use crate::pci::msi::x86 as x86_msix; // FIXME for cpu_id >255 we need to use the IOMMU to use IRQ remapping let lapic_id = u8::try_from(cpu_id).expect("CPU id couldn't fit inside u8"); let rh = false; let dm = false; - let addr = x86_64_msix::message_address(lapic_id, rh, dm); + let addr = x86_msix::message_address(lapic_id, rh, dm); let (vector, interrupt_handle) = allocate_single_interrupt_vector(cpu_id) .expect("failed to allocate interrupt vector") .expect("no interrupt vectors left"); let msg_data = - x86_64_msix::message_data_edge_triggered(x86_64_msix::DeliveryMode::Fixed, vector); + x86_msix::message_data_edge_triggered(x86_msix::DeliveryMode::Fixed, vector); (MsiAddrAndData::new(addr, msg_data), interrupt_handle) } diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index a29a12cd96..f477737c3c 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -92,8 +92,8 @@ pub struct MsixTableEntry { pub vec_ctl: Mmio, } -#[cfg(target_arch = "x86_64")] -pub mod x86_64 { +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub mod x86 { #[repr(u8)] pub enum TriggerMode { Edge = 0, diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index be993050c5..edb85ab942 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -1,15 +1,57 @@ use crate::{legacy_transport::LegacyTransport, reinit, transport::Error, Device}; -use std::fs::File; + +use pcid_interface::irq_helpers::{allocate_single_interrupt_vector_for_msi, read_bsp_apic_id}; +use pcid_interface::msi::MsixTableEntry; +use std::{fs::File, ptr::NonNull}; + +use crate::{probe::MappedMsixRegs, MSIX_PRIMARY_VECTOR}; use pcid_interface::*; -pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { - panic!("virtio-core: x86 doesn't support enable_msix") +pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { + let pci_config = pcid_handle.config(); + + // Extended message signaled interrupts. + let msix_info = match pcid_handle.feature_info(PciFeature::MsiX)? { + PciFeatureInfo::MsiX(capability) => capability, + _ => unreachable!(), + }; + msix_info.validate(pci_config.func.bars); + + let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar)? } + .ptr + .as_ptr() as usize; + let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; + + let mut info = MappedMsixRegs { + virt_table_base: NonNull::new(virt_table_base).unwrap(), + info: msix_info, + }; + + // Allocate the primary MSI vector. + // FIXME allow the driver to register multiple MSI-X vectors + // FIXME move this MSI-X registering code into pcid_interface or pcid itself + let interrupt_handle = { + let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize); + + let destination_id = read_bsp_apic_id().expect("virtio_core: `read_bsp_apic_id()` failed"); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); + table_entry_pointer.write_addr_and_data(msg_addr_and_data); + table_entry_pointer.unmask(); + + interrupt_handle + }; + + pcid_handle.enable_feature(PciFeature::MsiX)?; + + log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})"); + Ok(interrupt_handle) } pub fn probe_legacy_port_transport( pci_config: &SubdriverArguments, - pcid_handle: &mut PcidServerHandle, + pcid_handle: &mut PciFunctionHandle, ) -> Result { let port = pci_config.func.bars[0].expect_port(); From 359f4482dd0353c5b8a4e2e3fa12966215e3eb5e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Jun 2024 21:56:25 +0200 Subject: [PATCH 0925/1301] virtio: Merge the x86 and x86_64 platform specific code --- virtio-core/src/arch/x86_64.rs | 81 ---------------------------------- virtio-core/src/lib.rs | 6 +-- 2 files changed, 1 insertion(+), 86 deletions(-) delete mode 100644 virtio-core/src/arch/x86_64.rs diff --git a/virtio-core/src/arch/x86_64.rs b/virtio-core/src/arch/x86_64.rs deleted file mode 100644 index edb85ab942..0000000000 --- a/virtio-core/src/arch/x86_64.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::{legacy_transport::LegacyTransport, reinit, transport::Error, Device}; - -use pcid_interface::irq_helpers::{allocate_single_interrupt_vector_for_msi, read_bsp_apic_id}; -use pcid_interface::msi::MsixTableEntry; -use std::{fs::File, ptr::NonNull}; - -use crate::{probe::MappedMsixRegs, MSIX_PRIMARY_VECTOR}; - -use pcid_interface::*; - -pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { - let pci_config = pcid_handle.config(); - - // Extended message signaled interrupts. - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX)? { - PciFeatureInfo::MsiX(capability) => capability, - _ => unreachable!(), - }; - msix_info.validate(pci_config.func.bars); - - let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar)? } - .ptr - .as_ptr() as usize; - let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; - - let mut info = MappedMsixRegs { - virt_table_base: NonNull::new(virt_table_base).unwrap(), - info: msix_info, - }; - - // Allocate the primary MSI vector. - // FIXME allow the driver to register multiple MSI-X vectors - // FIXME move this MSI-X registering code into pcid_interface or pcid itself - let interrupt_handle = { - let table_entry_pointer = info.table_entry_pointer(MSIX_PRIMARY_VECTOR as usize); - - let destination_id = read_bsp_apic_id().expect("virtio_core: `read_bsp_apic_id()` failed"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - table_entry_pointer.write_addr_and_data(msg_addr_and_data); - table_entry_pointer.unmask(); - - interrupt_handle - }; - - pcid_handle.enable_feature(PciFeature::MsiX)?; - - log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})"); - Ok(interrupt_handle) -} - -pub fn probe_legacy_port_transport( - pci_config: &SubdriverArguments, - pcid_handle: &mut PciFunctionHandle, -) -> Result { - let port = pci_config.func.bars[0].expect_port(); - - common::acquire_port_io_rights().expect("virtio: failed to set I/O privilege level"); - log::warn!("virtio: using legacy transport"); - - let transport = LegacyTransport::new(port); - - // Setup interrupts. - let all_pci_features = pcid_handle.fetch_all_features()?; - let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - - // According to the virtio specification, the device REQUIRED to support MSI-X. - assert!(has_msix, "virtio: device does not support MSI-X"); - let irq_handle = enable_msix(pcid_handle)?; - - let device = Device { - transport, - irq_handle, - device_space: core::ptr::null_mut(), - }; - - device.transport.reset(); - reinit(&device)?; - - Ok(device) -} diff --git a/virtio-core/src/lib.rs b/virtio-core/src/lib.rs index c38a88ac3d..8dfd9a676f 100644 --- a/virtio-core/src/lib.rs +++ b/virtio-core/src/lib.rs @@ -10,14 +10,10 @@ mod probe; #[path="arch/aarch64.rs"] mod arch; -#[cfg(target_arch = "x86")] +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] #[path="arch/x86.rs"] mod arch; -#[cfg(target_arch = "x86_64")] -#[path="arch/x86_64.rs"] -mod arch; - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] mod legacy_transport; From dd10d773508ed3df5f0f9679c69077b2adca6e1c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 16 Jun 2024 11:09:12 +0200 Subject: [PATCH 0926/1301] Make lived stateless. --- Cargo.lock | 3 +- storage/lived/Cargo.toml | 5 +- storage/lived/src/main.rs | 143 +++++++++++++++++--------------------- 3 files changed, 68 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df85130837..715a684924 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -715,8 +715,9 @@ dependencies = [ "anyhow", "libredox 0.1.3", "redox-daemon", + "redox-scheme", + "redox_event", "redox_syscall 0.5.2", - "slab", ] [[package]] diff --git a/storage/lived/Cargo.toml b/storage/lived/Cargo.toml index d5fcdb91b6..57ec2be9fe 100644 --- a/storage/lived/Cargo.toml +++ b/storage/lived/Cargo.toml @@ -11,5 +11,6 @@ license = "MIT" anyhow = "1" libredox = "0.1.3" redox-daemon = "0.1" -redox_syscall = "0.5" -slab = "0.4" +redox_syscall = { version = "0.5", features = ["std"] } +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox_event = "0.4" diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index 8470400938..ce6dbd95ab 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -4,35 +4,40 @@ use std::fs::File; -use std::io::{Read, Write}; use std::os::fd::AsRawFd; use std::str; use libredox::call::MmapArgs; use libredox::flag; -use slab::Slab; +use redox_scheme::{CallerCtx, OpenResult, RequestKind, SchemeMut, SignalBehavior, Socket, V2}; + use syscall::data::Stat; -use syscall::{error::*, MapFlags, SchemeMut, Packet}; +use syscall::schemev2::NewFdFlags; +use syscall::error::*; use syscall::flag::{MODE_DIR, MODE_FILE}; -use syscall::scheme::calc_seek_offset_usize; use syscall::PAGE_SIZE; use anyhow::{anyhow, Context, bail}; const LIST: [u8; 2] = *b"0\n"; -struct Handle { - ty: HandleType, - seek: usize, -} +#[repr(usize)] enum HandleType { - TopLevel, - TheData, + TopLevel = 0, + TheData = 1, +} +impl HandleType { + fn try_from_raw(raw: usize) -> Option { + Some(match raw { + 0 => Self::TopLevel, + 1 => Self::TheData, + _ => return None, + }) + } } pub struct DiskScheme { the_data: &'static mut [u8], - handles: Slab, } impl DiskScheme { @@ -79,100 +84,74 @@ impl DiskScheme { Ok(DiskScheme { the_data, - handles: Slab::with_capacity(32), }) } } impl SchemeMut for DiskScheme { - fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { - let handle = self.handles.get_mut(id).ok_or(Error::new(EBADF))?; - let len = match handle.ty { - HandleType::TopLevel => LIST.len(), - HandleType::TheData => self.the_data.len(), - }; - let new_offset = calc_seek_offset_usize(handle.seek, pos, whence, len)?; - handle.seek = new_offset as usize; - Ok(new_offset) + fn fsize(&mut self, id: usize) -> Result { + Ok(match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { + HandleType::TopLevel => LIST.len() as u64, + HandleType::TheData => self.the_data.len() as u64, + }) } - fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize) -> Result { - let _handle = self.handles.get(id).ok_or(Error::new(EBADF))?; - + fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize) -> Result { Ok(0) } - fn fsync(&mut self, id: usize) -> Result { - let _handle = self.handles.get(id).ok_or(Error::new(EBADF))?; - + fn fsync(&mut self, _id: usize) -> Result { Ok(0) } - fn close(&mut self, id: usize) -> Result { - let _ = self.handles.remove(id); - + fn close(&mut self, _id: usize) -> Result { Ok(0) } - fn open(&mut self, path: &str, _flags: usize, uid: u32, _gid: u32) -> Result { - if uid != 0 { + fn xopen(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> Result { + if ctx.uid != 0 { return Err(Error::new(EACCES)); } let path_trimmed = path.trim_matches('/'); - let handle = match path_trimmed { - "" => { - Handle { - //mode: MODE_DIR | 0o755, - seek: 0, - ty: HandleType::TopLevel, + Ok(OpenResult::ThisScheme { + number: match path_trimmed { + "" => { + HandleType::TopLevel as usize + }, + "0" => { + HandleType::TheData as usize } + _ => return Err(Error::new(ENOENT)), }, - "0" => { - Handle { - //mode: MODE_FILE | 0o644, - seek: 0, - ty: HandleType::TheData, - } - } - _ => return Err(Error::new(ENOENT)), - }; - - Ok(self.handles.insert(handle)) + flags: NewFdFlags::POSITIONED, + }) } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { - let handle = self.handles.get_mut(id).ok_or(Error::new(EBADF))?; - - let data = match handle.ty { + fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _flags: u32) -> Result { + let data = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { HandleType::TheData => &*self.the_data, HandleType::TopLevel => &LIST, }; - let src = data.get(handle.seek..).unwrap_or(&[]); + let src = usize::try_from(offset).ok().and_then(|o| data.get(o..)).unwrap_or(&[]); let byte_count = std::cmp::min(src.len(), buf.len()); buf[..byte_count].copy_from_slice(&src[..byte_count]); - handle.seek += byte_count; + Ok(byte_count) + } + fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result { + let data = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { + HandleType::TheData => &mut *self.the_data, + HandleType::TopLevel => return Err(Error::new(EBADF)), + }; + let dst = usize::try_from(offset).ok().and_then(|o| data.get_mut(o..)).unwrap_or(&mut []); + let byte_count = std::cmp::min(dst.len(), buf.len()); + dst[..byte_count].copy_from_slice(&buf[..byte_count]); Ok(byte_count) } - fn write(&mut self, id: usize, buffer: &[u8]) -> Result { - let handle = self.handles.get_mut(id).ok_or(Error::new(EBADF))?; - - match handle.ty { - HandleType::TheData => { - let dst = self.the_data.get_mut(handle.seek..).unwrap_or(&mut []); - let byte_count = std::cmp::min(dst.len(), buffer.len()); - dst[..byte_count].copy_from_slice(&buffer[..byte_count]); - handle.seek += byte_count; - - Ok(byte_count) - }, - HandleType::TopLevel => Err(Error::new(EBADF)), - } - } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let path = match self.handles.get(id).ok_or(Error::new(EBADF))?.ty { + let path = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { HandleType::TopLevel => "", HandleType::TheData => "0", }; @@ -185,9 +164,7 @@ impl SchemeMut for DiskScheme { Ok(byte_count) } fn fstat(&mut self, id: usize, stat_buf: &mut Stat) -> Result { - let handle = self.handles.get(id).ok_or(Error::new(EBADF))?; - - let (len, mode) = match handle.ty { + let (len, mode) = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { HandleType::TheData => (self.the_data.len(), MODE_FILE | 0o644), HandleType::TopLevel => (LIST.len(), MODE_DIR | 0o755), }; @@ -205,20 +182,26 @@ impl SchemeMut for DiskScheme { } fn main() -> anyhow::Result<()> { redox_daemon::Daemon::new(move |daemon| { - let mut socket = File::create(":disk.live").expect("failed to open scheme"); + let socket_fd = Socket::::create("disk.live").expect("failed to open scheme"); let mut scheme = DiskScheme::new().unwrap_or_else(|err| { eprintln!("failed to initialize livedisk scheme: {}", err); std::process::exit(1) }); daemon.ready().expect("failed to signal readiness"); - let mut packet = Packet::default(); - loop { - socket.read_exact(&mut packet).expect("failed to read packet"); - scheme.handle(&mut packet); - socket.write_all(&packet).expect("failed to write packet"); + let req = match socket_fd.next_request(SignalBehavior::Restart).expect("failed to get next request") { + Some(r) => if let RequestKind::Call(c) = r.kind() { + c + } else { + continue; + }, + None => break, + }; + let resp = req.handle_scheme_mut(&mut scheme); + socket_fd.write_response(resp, SignalBehavior::Restart).expect("failed to write packet"); } + std::process::exit(0); }).map_err(|err| anyhow!("failed to start daemon: {}", err))?; } From fc9331b16a618bf1621e460493835bdb185924a1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Jun 2024 21:49:33 +0200 Subject: [PATCH 0927/1301] virtio: Remove legacy transport support Transitional virtio devices (which have both legacy and virtio 1.0 support) have been the default since QEMU 2.7.0, which was released 8 years ago. Basically every non-commercial Linux distro with an older QEMU has been EOL already. The legacy transport is also one of the few places where port I/O is necessary, which is non-trivial to sandbox even once we have IOMMU support. As it isn't possible to distinguish legacy and modern virtio devices for pcid, this would mean that all virtio drivers have to be started as privileged even if it turns out the modern transport is supported by the VMM. --- virtio-core/src/arch/aarch64.rs | 7 -- virtio-core/src/arch/x86.rs | 33 +---- virtio-core/src/legacy_transport.rs | 187 ---------------------------- virtio-core/src/lib.rs | 3 - virtio-core/src/probe.rs | 66 +++++----- virtio-core/src/transport.rs | 2 +- 6 files changed, 34 insertions(+), 264 deletions(-) delete mode 100644 virtio-core/src/legacy_transport.rs diff --git a/virtio-core/src/arch/aarch64.rs b/virtio-core/src/arch/aarch64.rs index 29e3b5855a..5d855258ca 100644 --- a/virtio-core/src/arch/aarch64.rs +++ b/virtio-core/src/arch/aarch64.rs @@ -7,10 +7,3 @@ use crate::{transport::Error, Device}; pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { unimplemented!("virtio_core: aarch64 enable_msix") } - -pub fn probe_legacy_port_transport( - pci_config: &SubdriverArguments, - pcid_handle: &mut PcidServerHandle, -) -> Result { - panic!("virtio-core: aarch64 doesn't support legacy port I/O") -} \ No newline at end of file diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index edb85ab942..ebea0f9aa7 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -1,4 +1,4 @@ -use crate::{legacy_transport::LegacyTransport, reinit, transport::Error, Device}; +use crate::transport::Error; use pcid_interface::irq_helpers::{allocate_single_interrupt_vector_for_msi, read_bsp_apic_id}; use pcid_interface::msi::MsixTableEntry; @@ -48,34 +48,3 @@ pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})"); Ok(interrupt_handle) } - -pub fn probe_legacy_port_transport( - pci_config: &SubdriverArguments, - pcid_handle: &mut PciFunctionHandle, -) -> Result { - let port = pci_config.func.bars[0].expect_port(); - - common::acquire_port_io_rights().expect("virtio: failed to set I/O privilege level"); - log::warn!("virtio: using legacy transport"); - - let transport = LegacyTransport::new(port); - - // Setup interrupts. - let all_pci_features = pcid_handle.fetch_all_features()?; - let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - - // According to the virtio specification, the device REQUIRED to support MSI-X. - assert!(has_msix, "virtio: device does not support MSI-X"); - let irq_handle = enable_msix(pcid_handle)?; - - let device = Device { - transport, - irq_handle, - device_space: core::ptr::null_mut(), - }; - - device.transport.reset(); - reinit(&device)?; - - Ok(device) -} diff --git a/virtio-core/src/legacy_transport.rs b/virtio-core/src/legacy_transport.rs deleted file mode 100644 index 45341b103f..0000000000 --- a/virtio-core/src/legacy_transport.rs +++ /dev/null @@ -1,187 +0,0 @@ -use std::{sync::{Weak, atomic::{AtomicU16, Ordering}, Arc}, mem::size_of, fs::File}; - -use common::dma::Dma; -use syscall::{Pio, Io}; - -use crate::{transport::{NotifyBell, Transport, Queue, Error, Available, Used, queue_part_sizes, spawn_irq_thread, Mem, Borrowed}, spec::{Descriptor, DeviceStatusFlags}}; - - -pub enum LegacyRegister { - DeviceFeatures = 0, // u32 - - QueueAddress = 8, // u32 - QueueSize = 12, // u16 - QueueSelect = 14, // u16 - QueueNotify = 16, // u16 - - DeviceStatus = 18, // u8 - - ConfigMsixVector = 20, // u16 - QueueMsixVector = 22, // u16 -} - -struct LegacyBell(Weak); - -impl NotifyBell for LegacyBell { - #[inline] - fn ring(&self, queue_index: u16) { - let transport = self.0.upgrade().expect("bell: transport dropped"); - transport.write::(LegacyRegister::QueueNotify, queue_index) - } -} - -pub struct LegacyTransport(u16, AtomicU16, Weak); - -impl LegacyTransport { - pub(super) fn new(port: u16) -> Arc { - Arc::new_cyclic(|sref| Self(port, AtomicU16::new(0), sref.clone())) - } - - unsafe fn read_raw(&self, offset: usize) -> V - where - V: Sized + TryFrom, - >::Error: std::fmt::Debug, - { - let port = self.0 + offset as u16; - - if size_of::() == size_of::() { - V::try_from(Pio::::new(port).read() as u64).unwrap() - } else if size_of::() == size_of::() { - V::try_from(Pio::::new(port).read() as u64).unwrap() - } else if size_of::() == size_of::() { - V::try_from(Pio::::new(port).read() as u64).unwrap() - } else if size_of::() == size_of::() { - let lower = Pio::::new(port).read() as u64; - let upper = Pio::::new(port + size_of::() as u16).read() as u64; - - V::try_from(lower | (upper << 32)).unwrap() - } else { - unreachable!() - } - } - - fn read(&self, register: LegacyRegister) -> V - where - V: Sized + TryFrom, - >::Error: std::fmt::Debug, - { - unsafe { self.read_raw(register as usize) } - } - - fn write(&self, register: LegacyRegister, value: V) - where - V: Sized + TryInto, - >::Error: std::fmt::Debug, - { - if size_of::() == size_of::() { - Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u8); - } else if size_of::() == size_of::() { - Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u16); - } else if size_of::() == size_of::() { - Pio::::new(self.0 + register as u16).write(value.try_into().unwrap() as u32); - } else { - unreachable!() - } - } -} - -impl Transport for LegacyTransport { - fn reset(&self) { - self.write(LegacyRegister::DeviceStatus, 0u8); - - let status = self.read::(LegacyRegister::DeviceStatus); - assert_eq!(status, 0); - } - - fn check_device_feature(&self, feature: u32) -> bool { - assert!( - feature < 32, - "virtio: cannot query feature {feature} on a legacy device" - ); - self.read::(LegacyRegister::DeviceFeatures) & (1 << feature) == (1 << feature) - } - - fn ack_driver_feature(&self, feature: u32) { - assert!( - feature < 32, - "virtio: cannot ack feature {feature} on a legacy device" - ); - - let current = self.read::(LegacyRegister::DeviceFeatures); - self.write::(LegacyRegister::DeviceFeatures, current | (1 << feature)); - } - - fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result, Error> { - let queue_index = self.1.fetch_add(1, Ordering::SeqCst); - self.write(LegacyRegister::QueueSelect, queue_index); - - let queue_size = self.read::(LegacyRegister::QueueSize) as usize; - let (desc_size, avail_size, used_size) = queue_part_sizes(queue_size); - - let descriptor = unsafe { - Dma::<[Descriptor]>::zeroed_slice(queue_size)?.assume_init() - }; - - let avail_addr = descriptor.physical() + desc_size; - let avail_virt = (descriptor.as_ptr() as usize) + desc_size; - let avail = unsafe { Available::from_raw(Mem::Borrowed(Borrowed::new(avail_addr, avail_virt, avail_size)), queue_size)? }; - - let used_addr = avail_addr + avail_size; - let used_virt = avail_virt + desc_size; - let used = unsafe { Used::from_raw(Mem::Borrowed(Borrowed::new(used_addr, used_virt, used_size)), queue_size)? }; - - self.write::(LegacyRegister::QueueMsixVector, vector); - self.write::(LegacyRegister::QueueAddress, (descriptor.physical() as u32) >> 12); - - log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})"); - - let queue = Queue::new( - descriptor, - avail, - used, - LegacyBell(self.2.clone()), - queue_index, - vector, - ); - - spawn_irq_thread(irq_handle, &queue); - Ok(queue) - } - - fn load_config(&self, offset: u8, size: u8) -> u64 { - // We always enable MSI-X. So, the device configuration space offset will - // always be 0x18. - // - // Checkout 4.1.4.8 Legacy Interfaces: A Note on PCI Device Layout - const DEVICE_SPACE_OFFSET: usize = 0x18; - - let size = size as usize; - let offset = DEVICE_SPACE_OFFSET + offset as usize; - - unsafe { - if size == size_of::() { - self.read_raw::(offset) as u64 - } else if size == size_of::() { - self.read_raw::(offset) as u64 - } else if size == size_of::() { - self.read_raw::(offset) as u64 - } else if size == size_of::() { - self.read_raw::(offset) as u64 - } else { - unreachable!() - } - } - } - - fn insert_status(&self, status: DeviceStatusFlags) { - let old = self.read::(LegacyRegister::DeviceStatus); - self.write(LegacyRegister::DeviceStatus, old | status.bits()); - } - - fn reinit_queue(&self, _queue: Arc) { - todo!() - } - - // Legacy devices do not have the `FEATURES_OK` bit. - fn finalize_features(&self) {} -} diff --git a/virtio-core/src/lib.rs b/virtio-core/src/lib.rs index 8dfd9a676f..817caaf913 100644 --- a/virtio-core/src/lib.rs +++ b/virtio-core/src/lib.rs @@ -14,8 +14,5 @@ mod arch; #[path="arch/x86.rs"] mod arch; -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -mod legacy_transport; - pub use probe::{probe_device, reinit, Device, MSIX_PRIMARY_VECTOR}; diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 984acd88d2..9ecdd01ab4 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -131,48 +131,46 @@ pub fn probe_device(pcid_handle: &mut PciFunctionHandle) -> Result Result<(), Error> { diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 14150cb279..c679dd8699 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -463,7 +463,7 @@ pub trait Transport: Sync + Send { fn ack_driver_feature(&self, feature: u32); /// Finalizes the acknowledged features by setting the `FEATURES_OK` bit in the - /// device status flags. No-op on a legacy device. + /// device status flags. fn finalize_features(&self); /// Runs the device. From 0d926fb3f7271feac185dfecf846fe341cc26b4c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 12:04:05 +0200 Subject: [PATCH 0928/1301] xhcid: Sleep for 2ms on every poll loop This significantly reduces cpu usage. On my laptop before this change a single core would be fully loaded while running at 3-4GHz. With this change it would only be loaded for about 50% while running at 1-2GHz. This improves battery lifetime while also preventing the fan from spinning up to a distracting level. This shouldn't noticably affect latency given that most keyboards and mice don't support polling at 500Hz anyway. --- xhcid/src/xhci/irq_reactor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 45d22a0eb7..f496280ed7 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -105,7 +105,7 @@ impl IrqReactor { } // TODO: Configure the amount of time wait when no more work can be done (for IRQ-less polling). fn pause(&self) { - std::thread::yield_now(); + std::thread::sleep(std::time::Duration::from_millis(2)); } fn run_polling(mut self) { debug!("Running IRQ reactor in polling mode."); From 56000cbd9cc5a1a266015debf248c0375b760eac Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:03:58 +0200 Subject: [PATCH 0929/1301] pcid: Remove subsystem id from PciEndpointHeader --- pcid/src/pci_header.rs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 8bde8369c8..5c8097604c 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -21,8 +21,6 @@ pub struct SharedPciHeader { #[derive(Clone, Copy, Debug, PartialEq)] pub struct PciEndpointHeader { shared: SharedPciHeader, - subsystem_vendor_id: u16, - subsystem_id: u16, } #[derive(Clone, Copy, Debug, PartialEq)] @@ -63,15 +61,7 @@ impl PciHeader { }; match header_type { - HeaderType::Endpoint => { - let endpoint_header = EndpointHeader::from_header(header, access).unwrap(); - let (subsystem_id, subsystem_vendor_id) = endpoint_header.subsystem(access); - Ok(PciHeader::General(PciEndpointHeader { - shared, - subsystem_vendor_id, - subsystem_id, - })) - } + HeaderType::Endpoint => Ok(PciHeader::General(PciEndpointHeader { shared })), HeaderType::PciPciBridge => { let bridge_header = PciPciBridgeHeader::from_header(header, access).unwrap(); let secondary_bus_num = bridge_header.secondary_bus_number(access); From ae2240ef0fd9a2d856b047bc83ad9672fd601a66 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:12:29 +0200 Subject: [PATCH 0930/1301] pcid: Remove some PciHeader methods --- pcid/src/pci_header.rs | 79 +++++++++++++----------------------------- 1 file changed, 24 insertions(+), 55 deletions(-) diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 5c8097604c..76154fe5ad 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -96,67 +96,33 @@ impl PciHeader { } } - /// Return the PCI address. - pub fn address(&self) -> PciAddress { - match self { - PciHeader::General(header) => header.address(), - PciHeader::PciToPci { shared, .. } => shared.addr, - } - } - - /// Return the Vendor ID field. - pub fn vendor_id(&self) -> u16 { - self.full_device_id().vendor_id - } - - /// Return the Device ID field. - pub fn device_id(&self) -> u16 { - self.full_device_id().device_id - } - - /// Return the Revision field. - pub fn revision(&self) -> u8 { - self.full_device_id().revision - } - - /// Return the Interface field. - pub fn interface(&self) -> u8 { - self.full_device_id().interface - } - - /// Return the Subclass field. - pub fn subclass(&self) -> u8 { - self.full_device_id().subclass - } - - /// Return the Class field. - pub fn class(&self) -> u8 { - self.full_device_id().class - } - /// Format a human readable string indicating the address and type of PCI device. pub fn display(&self) -> String { let mut string = format!( "PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", - self.address(), - self.vendor_id(), - self.device_id(), - self.class(), - self.subclass(), - self.interface(), - self.revision(), - self.class() + match self { + PciHeader::General(header) => header.address(), + PciHeader::PciToPci { shared, .. } => shared.addr, + }, + self.full_device_id().vendor_id, + self.full_device_id().device_id, + self.full_device_id().class, + self.full_device_id().subclass, + self.full_device_id().interface, + self.full_device_id().revision, + self.full_device_id().class, ); - let device_type = DeviceType::from((self.class(), self.subclass())); + let device_type = + DeviceType::from((self.full_device_id().class, self.full_device_id().subclass)); match device_type { DeviceType::LegacyVgaCompatible => string.push_str(" VGA CTL"), DeviceType::IdeController => string.push_str(" IDE"), - DeviceType::SataController => match self.interface() { + DeviceType::SataController => match self.full_device_id().interface { 0 => string.push_str(" SATA VND"), 1 => string.push_str(" SATA AHCI"), _ => (), }, - DeviceType::UsbController => match self.interface() { + DeviceType::UsbController => match self.full_device_id().interface { 0x00 => string.push_str(" UHCI"), 0x10 => string.push_str(" OHCI"), 0x20 => string.push_str(" EHCI"), @@ -286,15 +252,18 @@ mod test { PciHeader::General { .. } => {} _ => panic!("wrong header type"), } - assert_eq!(header.device_id(), 0x1533); - assert_eq!(header.vendor_id(), 0x8086); - assert_eq!(header.revision(), 3); - assert_eq!(header.interface(), 0); + assert_eq!(header.full_device_id().device_id, 0x1533); + assert_eq!(header.full_device_id().vendor_id, 0x8086); + assert_eq!(header.full_device_id().revision, 3); + assert_eq!(header.full_device_id().interface, 0); assert_eq!( - DeviceType::from((header.class(), header.subclass())), + DeviceType::from(( + header.full_device_id().class, + header.full_device_id().subclass + )), DeviceType::EthernetController ); - assert_eq!(header.subclass(), 0); + assert_eq!(header.full_device_id().subclass, 0); } #[test] From 1179d01e765f46e06aa3039ea1a2a397511e6018 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:12:52 +0200 Subject: [PATCH 0931/1301] pcid: Add pretty string for the NVME device type --- pcid/src/pci_header.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 76154fe5ad..34e3dca46f 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -129,6 +129,7 @@ impl PciHeader { 0x30 => string.push_str(" XHCI"), _ => (), }, + DeviceType::NvmeController => string.push_str(" NVME"), _ => (), } string From 160acff5a82c02d1bb1bd46b7b3e71327e6a18ec Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:20:16 +0200 Subject: [PATCH 0932/1301] pcid: Move the code in PciHeader::display to other places --- pcid/src/main.rs | 2 +- pcid/src/pci/id.rs | 36 ++++++++++++++++++++++++++++++++++++ pcid/src/pci_header.rs | 40 ---------------------------------------- 3 files changed, 37 insertions(+), 41 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 3f126f7e3d..c5870f3b0a 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -230,7 +230,7 @@ fn main(args: Args) { let func_addr = PciAddress::new(0, bus_num, dev_num, func_num); match PciHeader::from_reader(&state.pcie, func_addr) { Ok(header) => { - info!("{}", header.display()); + info!("PCI {} {}", func_addr, header.full_device_id().display()); match header { PciHeader::General(endpoint_header) => { handle_parsed_header(Arc::clone(&state), &config, endpoint_header); diff --git a/pcid/src/pci/id.rs b/pcid/src/pci/id.rs index 9a59d660f6..307efc955a 100644 --- a/pcid/src/pci/id.rs +++ b/pcid/src/pci/id.rs @@ -1,3 +1,4 @@ +use pci_types::device_type::DeviceType; use serde::{Deserialize, Serialize}; /// All identifying information of a PCI function. @@ -10,3 +11,38 @@ pub struct FullDeviceId { pub interface: u8, pub revision: u8, } + +impl FullDeviceId { + pub(crate) fn display(&self) -> String { + let mut string = format!( + "{:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", + self.vendor_id, + self.device_id, + self.class, + self.subclass, + self.interface, + self.revision, + self.class, + ); + let device_type = DeviceType::from((self.class, self.subclass)); + match device_type { + DeviceType::LegacyVgaCompatible => string.push_str(" VGA CTL"), + DeviceType::IdeController => string.push_str(" IDE"), + DeviceType::SataController => match self.interface { + 0 => string.push_str(" SATA VND"), + 1 => string.push_str(" SATA AHCI"), + _ => (), + }, + DeviceType::UsbController => match self.interface { + 0x00 => string.push_str(" UHCI"), + 0x10 => string.push_str(" OHCI"), + 0x20 => string.push_str(" EHCI"), + 0x30 => string.push_str(" XHCI"), + _ => (), + }, + DeviceType::NvmeController => string.push_str(" NVME"), + _ => (), + } + string + } +} diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 34e3dca46f..376aa42bdd 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -1,4 +1,3 @@ -use pci_types::device_type::DeviceType; use pci_types::{ Bar as TyBar, ConfigRegionAccess, EndpointHeader, HeaderType, PciAddress, PciHeader as TyPciHeader, PciPciBridgeHeader, @@ -95,45 +94,6 @@ impl PciHeader { } => device_id, } } - - /// Format a human readable string indicating the address and type of PCI device. - pub fn display(&self) -> String { - let mut string = format!( - "PCI {} {:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", - match self { - PciHeader::General(header) => header.address(), - PciHeader::PciToPci { shared, .. } => shared.addr, - }, - self.full_device_id().vendor_id, - self.full_device_id().device_id, - self.full_device_id().class, - self.full_device_id().subclass, - self.full_device_id().interface, - self.full_device_id().revision, - self.full_device_id().class, - ); - let device_type = - DeviceType::from((self.full_device_id().class, self.full_device_id().subclass)); - match device_type { - DeviceType::LegacyVgaCompatible => string.push_str(" VGA CTL"), - DeviceType::IdeController => string.push_str(" IDE"), - DeviceType::SataController => match self.full_device_id().interface { - 0 => string.push_str(" SATA VND"), - 1 => string.push_str(" SATA AHCI"), - _ => (), - }, - DeviceType::UsbController => match self.full_device_id().interface { - 0x00 => string.push_str(" UHCI"), - 0x10 => string.push_str(" OHCI"), - 0x20 => string.push_str(" EHCI"), - 0x30 => string.push_str(" XHCI"), - _ => (), - }, - DeviceType::NvmeController => string.push_str(" NVME"), - _ => (), - } - string - } } impl PciEndpointHeader { From de4d79e69e5793079447cb83b2207a7cbfeeca50 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:23:27 +0200 Subject: [PATCH 0933/1301] pcid: Inline PciEndpointHeader::bars --- pcid/src/main.rs | 44 ++++++++++++++++++++++++++++++++++---- pcid/src/pci_header.rs | 48 +++--------------------------------------- 2 files changed, 43 insertions(+), 49 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index c5870f3b0a..e0d9c44ff5 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -4,13 +4,14 @@ use std::sync::{Arc, Mutex}; use std::thread; use log::{debug, info, trace, warn}; -use pci_types::{CommandRegister, PciAddress}; +use pci_types::{Bar as TyBar, CommandRegister, PciAddress}; use redox_log::{OutputBuilder, RedoxLogger}; use structopt::StructOpt; use crate::cfg_access::Pcie; use crate::config::Config; use crate::driver_interface::LegacyInterruptLine; +use crate::pci::PciBar; use crate::pci_header::{PciEndpointHeader, PciHeader, PciHeaderError}; mod cfg_access; @@ -43,6 +44,8 @@ pub struct State { } fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointHeader) { + let mut endpoint_header = header.endpoint_header(&state.pcie); + for driver in config.drivers.iter() { if !driver.match_function(header.full_device_id()) { continue; @@ -52,8 +55,43 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH continue; }; + let mut bars = [PciBar::None; 6]; + let mut skip = false; + for i in 0..6 { + if skip { + skip = false; + continue; + } + match endpoint_header.bar(i, &state.pcie) { + Some(TyBar::Io { port }) => { + bars[i as usize] = PciBar::Port(port.try_into().unwrap()) + } + Some(TyBar::Memory32 { + address, + size, + prefetchable: _, + }) => { + bars[i as usize] = PciBar::Memory32 { + addr: address, + size, + } + } + Some(TyBar::Memory64 { + address, + size, + prefetchable: _, + }) => { + bars[i as usize] = PciBar::Memory64 { + addr: address, + size, + }; + skip = true; // Each 64bit memory BAR occupies two slots + } + None => bars[i as usize] = PciBar::None, + } + } + let mut string = String::new(); - let bars = header.bars(&state.pcie); for (i, bar) in bars.iter().enumerate() { if !bar.is_none() { string.push_str(&format!(" {i}={}", bar.display())); @@ -64,8 +102,6 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH info!(" BAR{}", string); } - let mut endpoint_header = header.endpoint_header(&state.pcie); - // Enable bus mastering, memory space, and I/O space endpoint_header.update_command(&state.pcie, |cmd| { cmd | CommandRegister::BUS_MASTER_ENABLE diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 376aa42bdd..e777689696 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -1,9 +1,9 @@ use pci_types::{ - Bar as TyBar, ConfigRegionAccess, EndpointHeader, HeaderType, PciAddress, - PciHeader as TyPciHeader, PciPciBridgeHeader, + ConfigRegionAccess, EndpointHeader, HeaderType, PciAddress, PciHeader as TyPciHeader, + PciPciBridgeHeader, }; -use crate::pci::{FullDeviceId, PciBar}; +use crate::pci::FullDeviceId; #[derive(Debug, PartialEq)] pub enum PciHeaderError { @@ -108,48 +108,6 @@ impl PciEndpointHeader { pub fn full_device_id(&self) -> &FullDeviceId { &self.shared.full_device_id } - - /// Return the Headers BARs. - pub fn bars(&self, access: &impl ConfigRegionAccess) -> [PciBar; 6] { - let endpoint_header = self.endpoint_header(access); - - let mut bars = [PciBar::None; 6]; - let mut skip = false; - for i in 0..6 { - if skip { - skip = false; - continue; - } - match endpoint_header.bar(i, access) { - Some(TyBar::Io { port }) => { - bars[i as usize] = PciBar::Port(port.try_into().unwrap()) - } - Some(TyBar::Memory32 { - address, - size, - prefetchable: _, - }) => { - bars[i as usize] = PciBar::Memory32 { - addr: address, - size, - } - } - Some(TyBar::Memory64 { - address, - size, - prefetchable: _, - }) => { - bars[i as usize] = PciBar::Memory64 { - addr: address, - size, - }; - skip = true; // Each 64bit memory BAR occupies two slots - } - None => bars[i as usize] = PciBar::None, - } - } - bars - } } #[cfg(test)] From 6c2fdae08c2f208539cc38d5304e7b1821721461 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:32:11 +0200 Subject: [PATCH 0934/1301] pcid: Remove all tests of PciHeader --- pcid/src/pci_header.rs | 91 ------------------------------------------ 1 file changed, 91 deletions(-) diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index e777689696..9ae20ba2df 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -109,94 +109,3 @@ impl PciEndpointHeader { &self.shared.full_device_id } } - -#[cfg(test)] -mod test { - use std::convert::TryInto; - - use pci_types::device_type::DeviceType; - use pci_types::{ConfigRegionAccess, PciAddress}; - - use super::{PciHeader, PciHeaderError}; - - struct TestCfgAccess<'a> { - addr: PciAddress, - bytes: &'a [u8], - } - - impl ConfigRegionAccess for TestCfgAccess<'_> { - unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { - assert_eq!(addr, self.addr); - let offset = offset as usize; - assert!(offset < self.bytes.len()); - u32::from_le_bytes(self.bytes[offset..offset + 4].try_into().unwrap()) - } - - unsafe fn write(&self, _addr: PciAddress, _offset: u16, _value: u32) { - unreachable!("should not write during tests"); - } - } - - #[rustfmt::skip] - const IGB_DEV_BYTES: [u8; 256] = [ - 0x86, 0x80, 0x33, 0x15, 0x07, 0x04, 0x10, 0x00, 0x03, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x50, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x01, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x58, 0xf7, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x15, 0x33, 0x15, - 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, - 0x01, 0x50, 0x23, 0xc8, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x05, 0x70, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x11, 0xa0, 0x04, 0x80, 0x03, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x10, 0x00, 0x02, 0x00, 0xc2, 0x8c, 0x00, 0x10, 0x0f, 0x28, 0x19, 0x00, 0x11, 0x5c, 0x42, 0x00, - 0x42, 0x00, 0x11, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - ]; - - #[test] - fn tset_parse_igb_dev() { - let header = PciHeader::from_reader( - &TestCfgAccess { - addr: PciAddress::new(0, 2, 4, 0), - bytes: &IGB_DEV_BYTES, - }, - PciAddress::new(0, 2, 4, 0), - ) - .unwrap(); - match header { - PciHeader::General { .. } => {} - _ => panic!("wrong header type"), - } - assert_eq!(header.full_device_id().device_id, 0x1533); - assert_eq!(header.full_device_id().vendor_id, 0x8086); - assert_eq!(header.full_device_id().revision, 3); - assert_eq!(header.full_device_id().interface, 0); - assert_eq!( - DeviceType::from(( - header.full_device_id().class, - header.full_device_id().subclass - )), - DeviceType::EthernetController - ); - assert_eq!(header.full_device_id().subclass, 0); - } - - #[test] - fn test_parse_nonexistent() { - let bytes = &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]; - assert_eq!( - PciHeader::from_reader( - &TestCfgAccess { - addr: PciAddress::new(0, 2, 4, 0), - bytes, - }, - PciAddress::new(0, 2, 4, 0), - ), - Err(PciHeaderError::NoDevice) - ); - } -} From a34266b029a870831d6fa51894b3706a4bb93287 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:33:55 +0200 Subject: [PATCH 0935/1301] pcid: Remove all PciEndpointHeader methods --- pcid/src/main.rs | 61 +++++++++++++++++++++++++++--------------- pcid/src/pci_header.rs | 43 +++-------------------------- 2 files changed, 43 insertions(+), 61 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index e0d9c44ff5..ea243a3f8d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -4,15 +4,17 @@ use std::sync::{Arc, Mutex}; use std::thread; use log::{debug, info, trace, warn}; -use pci_types::{Bar as TyBar, CommandRegister, PciAddress}; +use pci_types::{ + Bar as TyBar, CommandRegister, EndpointHeader, PciAddress, PciHeader as TyPciHeader, +}; use redox_log::{OutputBuilder, RedoxLogger}; use structopt::StructOpt; use crate::cfg_access::Pcie; use crate::config::Config; use crate::driver_interface::LegacyInterruptLine; -use crate::pci::PciBar; -use crate::pci_header::{PciEndpointHeader, PciHeader, PciHeaderError}; +use crate::pci::{FullDeviceId, PciBar}; +use crate::pci_header::{PciHeader, PciHeaderError}; mod cfg_access; mod config; @@ -43,11 +45,14 @@ pub struct State { pcie: Pcie, } -fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointHeader) { - let mut endpoint_header = header.endpoint_header(&state.pcie); - +fn handle_parsed_header( + state: Arc, + config: &Config, + mut endpoint_header: EndpointHeader, + full_device_id: FullDeviceId, +) { for driver in config.drivers.iter() { - if !driver.match_function(header.full_device_id()) { + if !driver.match_function(&full_device_id) { continue; } @@ -150,13 +155,13 @@ fn handle_parsed_header(state: Arc, config: &Config, header: PciEndpointH let func = driver_interface::PciFunction { bars, - addr: header.address(), + addr: endpoint_header.header().address(), legacy_interrupt_line: if legacy_interrupt_enabled { Some(LegacyInterruptLine(irq)) } else { None }, - full_device_id: header.full_device_id().clone(), + full_device_id: full_device_id.clone(), }; driver_handler::DriverHandler::spawn(Arc::clone(&state), func, capabilities, args); @@ -265,19 +270,33 @@ fn main(args: Args) { for func_num in 0..8 { let func_addr = PciAddress::new(0, bus_num, dev_num, func_num); match PciHeader::from_reader(&state.pcie, func_addr) { - Ok(header) => { - info!("PCI {} {}", func_addr, header.full_device_id().display()); - match header { - PciHeader::General(endpoint_header) => { - handle_parsed_header(Arc::clone(&state), &config, endpoint_header); - } - PciHeader::PciToPci { - secondary_bus_num, .. - } => { - bus_nums.push(secondary_bus_num); - } + Ok(header) => match header { + PciHeader::General(endpoint_header) => { + info!( + "PCI {} {}", + func_addr, + endpoint_header.shared.full_device_id.display() + ); + handle_parsed_header( + Arc::clone(&state), + &config, + EndpointHeader::from_header( + TyPciHeader::new(func_addr), + &state.pcie, + ) + .unwrap(), + endpoint_header.shared.full_device_id, + ); } - } + PciHeader::PciToPci { + shared, + secondary_bus_num, + } => { + info!("PCI {} {}", func_addr, shared.full_device_id.display()); + + bus_nums.push(secondary_bus_num); + } + }, Err(PciHeaderError::NoDevice) => { if func_addr.function() == 0 { trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs index 9ae20ba2df..25d61a96e7 100644 --- a/pcid/src/pci_header.rs +++ b/pcid/src/pci_header.rs @@ -1,6 +1,5 @@ use pci_types::{ - ConfigRegionAccess, EndpointHeader, HeaderType, PciAddress, PciHeader as TyPciHeader, - PciPciBridgeHeader, + ConfigRegionAccess, HeaderType, PciAddress, PciHeader as TyPciHeader, PciPciBridgeHeader, }; use crate::pci::FullDeviceId; @@ -13,13 +12,13 @@ pub enum PciHeaderError { #[derive(Clone, Copy, Debug, PartialEq)] pub struct SharedPciHeader { - full_device_id: FullDeviceId, + pub full_device_id: FullDeviceId, addr: PciAddress, } #[derive(Clone, Copy, Debug, PartialEq)] pub struct PciEndpointHeader { - shared: SharedPciHeader, + pub shared: SharedPciHeader, } #[derive(Clone, Copy, Debug, PartialEq)] @@ -72,40 +71,4 @@ impl PciHeader { ty => Err(PciHeaderError::UnknownHeaderType(ty)), } } - - /// Return all identifying information of the PCI function. - pub fn full_device_id(&self) -> &FullDeviceId { - match self { - PciHeader::General(PciEndpointHeader { - shared: - SharedPciHeader { - full_device_id: device_id, - .. - }, - .. - }) - | PciHeader::PciToPci { - shared: - SharedPciHeader { - full_device_id: device_id, - .. - }, - .. - } => device_id, - } - } -} - -impl PciEndpointHeader { - pub fn address(&self) -> PciAddress { - self.shared.addr - } - - pub fn endpoint_header(&self, access: &impl ConfigRegionAccess) -> EndpointHeader { - EndpointHeader::from_header(TyPciHeader::new(self.shared.addr), access).unwrap() - } - - pub fn full_device_id(&self) -> &FullDeviceId { - &self.shared.full_device_id - } } From 16819bc693e30cb440fb30888e1c157c34786d7e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 13:42:45 +0200 Subject: [PATCH 0936/1301] pcid: Get rid of PciHeader It is a reminant of when pci_types wasn't used yet and doesn't simplify things a lot anymore. --- pcid/src/main.rs | 78 ++++++++++++++++++++++-------------------- pcid/src/pci_header.rs | 74 --------------------------------------- 2 files changed, 40 insertions(+), 112 deletions(-) delete mode 100644 pcid/src/pci_header.rs diff --git a/pcid/src/main.rs b/pcid/src/main.rs index ea243a3f8d..87280eda73 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -5,7 +5,8 @@ use std::thread; use log::{debug, info, trace, warn}; use pci_types::{ - Bar as TyBar, CommandRegister, EndpointHeader, PciAddress, PciHeader as TyPciHeader, + Bar as TyBar, CommandRegister, EndpointHeader, HeaderType, PciAddress, + PciHeader as TyPciHeader, PciPciBridgeHeader, }; use redox_log::{OutputBuilder, RedoxLogger}; use structopt::StructOpt; @@ -14,14 +15,12 @@ use crate::cfg_access::Pcie; use crate::config::Config; use crate::driver_interface::LegacyInterruptLine; use crate::pci::{FullDeviceId, PciBar}; -use crate::pci_header::{PciHeader, PciHeaderError}; mod cfg_access; mod config; mod driver_handler; mod driver_interface; mod pci; -mod pci_header; #[derive(StructOpt)] #[structopt(about)] @@ -268,43 +267,46 @@ fn main(args: Args) { 'dev: for dev_num in 0..32 { for func_num in 0..8 { - let func_addr = PciAddress::new(0, bus_num, dev_num, func_num); - match PciHeader::from_reader(&state.pcie, func_addr) { - Ok(header) => match header { - PciHeader::General(endpoint_header) => { - info!( - "PCI {} {}", - func_addr, - endpoint_header.shared.full_device_id.display() - ); - handle_parsed_header( - Arc::clone(&state), - &config, - EndpointHeader::from_header( - TyPciHeader::new(func_addr), - &state.pcie, - ) - .unwrap(), - endpoint_header.shared.full_device_id, - ); - } - PciHeader::PciToPci { - shared, - secondary_bus_num, - } => { - info!("PCI {} {}", func_addr, shared.full_device_id.display()); + let header = TyPciHeader::new(PciAddress::new(0, bus_num, dev_num, func_num)); - bus_nums.push(secondary_bus_num); - } - }, - Err(PciHeaderError::NoDevice) => { - if func_addr.function() == 0 { - trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); - continue 'dev; - } + let (vendor_id, device_id) = header.id(&state.pcie); + if vendor_id == 0xffff && device_id == 0xffff { + if func_num == 0 { + trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); + continue 'dev; } - Err(PciHeaderError::UnknownHeaderType(id)) => { - warn!("pcid: unknown header type: {id:?}"); + + continue; + } + + let (revision, class, subclass, interface) = header.revision_and_class(&state.pcie); + let full_device_id = FullDeviceId { + vendor_id, + device_id, + class, + subclass, + interface, + revision, + }; + + info!("PCI {} {}", header.address(), full_device_id.display()); + + match header.header_type(&state.pcie) { + HeaderType::Endpoint => { + handle_parsed_header( + Arc::clone(&state), + &config, + EndpointHeader::from_header(header, &state.pcie).unwrap(), + full_device_id, + ); + } + HeaderType::PciPciBridge => { + let bridge_header = + PciPciBridgeHeader::from_header(header, &state.pcie).unwrap(); + bus_nums.push(bridge_header.secondary_bus_number(&state.pcie)); + } + ty => { + warn!("pcid: unknown header type: {ty:?}"); } } } diff --git a/pcid/src/pci_header.rs b/pcid/src/pci_header.rs deleted file mode 100644 index 25d61a96e7..0000000000 --- a/pcid/src/pci_header.rs +++ /dev/null @@ -1,74 +0,0 @@ -use pci_types::{ - ConfigRegionAccess, HeaderType, PciAddress, PciHeader as TyPciHeader, PciPciBridgeHeader, -}; - -use crate::pci::FullDeviceId; - -#[derive(Debug, PartialEq)] -pub enum PciHeaderError { - NoDevice, - UnknownHeaderType(HeaderType), -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct SharedPciHeader { - pub full_device_id: FullDeviceId, - addr: PciAddress, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub struct PciEndpointHeader { - pub shared: SharedPciHeader, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum PciHeader { - General(PciEndpointHeader), - PciToPci { - shared: SharedPciHeader, - secondary_bus_num: u8, - }, -} - -impl PciHeader { - /// Parse the bytes found in the Configuration Space of the PCI device into - /// a more usable PciHeader. - pub fn from_reader( - access: &impl ConfigRegionAccess, - addr: PciAddress, - ) -> Result { - let header = TyPciHeader::new(addr); - let (vendor_id, device_id) = header.id(access); - - if vendor_id == 0xffff && device_id == 0xffff { - return Err(PciHeaderError::NoDevice); - } - - let (revision, class, subclass, interface) = header.revision_and_class(access); - let header_type = header.header_type(access); - let shared = SharedPciHeader { - full_device_id: FullDeviceId { - vendor_id, - device_id, - class, - subclass, - interface, - revision, - }, - addr, - }; - - match header_type { - HeaderType::Endpoint => Ok(PciHeader::General(PciEndpointHeader { shared })), - HeaderType::PciPciBridge => { - let bridge_header = PciPciBridgeHeader::from_header(header, access).unwrap(); - let secondary_bus_num = bridge_header.secondary_bus_number(access); - Ok(PciHeader::PciToPci { - shared, - secondary_bus_num, - }) - } - ty => Err(PciHeaderError::UnknownHeaderType(ty)), - } - } -} From 52d1c0fb4fee59da2978d4d06a56d553ac84eb32 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 15:19:14 +0200 Subject: [PATCH 0937/1301] pcid: Move FullDeviceId from pci to driver_interface --- pcid/src/config.rs | 2 +- pcid/src/{pci => driver_interface}/id.rs | 0 pcid/src/driver_interface/mod.rs | 4 +++- pcid/src/main.rs | 4 ++-- pcid/src/pci/mod.rs | 2 -- 5 files changed, 6 insertions(+), 6 deletions(-) rename pcid/src/{pci => driver_interface}/id.rs (100%) diff --git a/pcid/src/config.rs b/pcid/src/config.rs index df82e437d4..8278f33c3c 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -3,7 +3,7 @@ use std::ops::Range; use serde::Deserialize; -use crate::pci::FullDeviceId; +use crate::driver_interface::FullDeviceId; #[derive(Clone, Debug, Default, Deserialize)] pub struct Config { diff --git a/pcid/src/pci/id.rs b/pcid/src/driver_interface/id.rs similarity index 100% rename from pcid/src/pci/id.rs rename to pcid/src/driver_interface/id.rs diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index b0e33cee4d..815af7bc84 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -11,8 +11,10 @@ use thiserror::Error; pub use crate::pci::cap::VendorSpecificCapability; pub use crate::pci::msi; -pub use crate::pci::{FullDeviceId, PciAddress, PciBar}; +pub use crate::pci::{PciAddress, PciBar}; +pub use id::FullDeviceId; +mod id; pub mod irq_helpers; #[derive(Clone, Copy, Debug, Serialize, Deserialize)] diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 87280eda73..d54089a243 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -13,8 +13,8 @@ use structopt::StructOpt; use crate::cfg_access::Pcie; use crate::config::Config; -use crate::driver_interface::LegacyInterruptLine; -use crate::pci::{FullDeviceId, PciBar}; +use crate::driver_interface::{FullDeviceId, LegacyInterruptLine}; +use crate::pci::PciBar; mod cfg_access; mod config; diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 2db9368d9b..5507cea877 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,8 +1,6 @@ pub use self::bar::PciBar; -pub use self::id::FullDeviceId; pub use pci_types::PciAddress; mod bar; pub mod cap; -mod id; pub mod msi; From 5c9bbb5c96b3aa1ad7808357d3f22541f13bfb5a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 15:20:52 +0200 Subject: [PATCH 0938/1301] pcid: Move PciBar from pci to driver_interface --- pcid/src/{pci => driver_interface}/bar.rs | 0 pcid/src/driver_interface/mod.rs | 4 +++- pcid/src/main.rs | 3 +-- pcid/src/pci/mod.rs | 2 -- pcid/src/pci/msi.rs | 2 +- 5 files changed, 5 insertions(+), 6 deletions(-) rename pcid/src/{pci => driver_interface}/bar.rs (100%) diff --git a/pcid/src/pci/bar.rs b/pcid/src/driver_interface/bar.rs similarity index 100% rename from pcid/src/pci/bar.rs rename to pcid/src/driver_interface/bar.rs diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 815af7bc84..25f97fe738 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -11,9 +11,11 @@ use thiserror::Error; pub use crate::pci::cap::VendorSpecificCapability; pub use crate::pci::msi; -pub use crate::pci::{PciAddress, PciBar}; +pub use crate::pci::PciAddress; +pub use bar::PciBar; pub use id::FullDeviceId; +mod bar; mod id; pub mod irq_helpers; diff --git a/pcid/src/main.rs b/pcid/src/main.rs index d54089a243..c7e0e644e1 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -13,8 +13,7 @@ use structopt::StructOpt; use crate::cfg_access::Pcie; use crate::config::Config; -use crate::driver_interface::{FullDeviceId, LegacyInterruptLine}; -use crate::pci::PciBar; +use crate::driver_interface::{FullDeviceId, LegacyInterruptLine, PciBar}; mod cfg_access; mod config; diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index 5507cea877..f8b0ef4997 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,6 +1,4 @@ -pub use self::bar::PciBar; pub use pci_types::PciAddress; -mod bar; pub mod cap; pub mod msi; diff --git a/pcid/src/pci/msi.rs b/pcid/src/pci/msi.rs index f477737c3c..0a625d53e0 100644 --- a/pcid/src/pci/msi.rs +++ b/pcid/src/pci/msi.rs @@ -1,6 +1,6 @@ use std::fmt; -use super::bar::PciBar; +use crate::driver_interface::PciBar; use serde::{Deserialize, Serialize}; use syscall::{Io, Mmio}; From ba6224bc27115f0fcf10946d87565532eaff6508 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 15:21:51 +0200 Subject: [PATCH 0939/1301] pcid: Move VendorSpecificCapability form pci to driver_interface --- pcid/src/{pci => driver_interface}/cap.rs | 0 pcid/src/driver_interface/mod.rs | 3 ++- pcid/src/pci/mod.rs | 1 - 3 files changed, 2 insertions(+), 2 deletions(-) rename pcid/src/{pci => driver_interface}/cap.rs (100%) diff --git a/pcid/src/pci/cap.rs b/pcid/src/driver_interface/cap.rs similarity index 100% rename from pcid/src/pci/cap.rs rename to pcid/src/driver_interface/cap.rs diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 25f97fe738..58bdcdd054 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -9,13 +9,14 @@ use std::os::unix::io::{FromRawFd, RawFd}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use thiserror::Error; -pub use crate::pci::cap::VendorSpecificCapability; pub use crate::pci::msi; pub use crate::pci::PciAddress; pub use bar::PciBar; +pub use cap::VendorSpecificCapability; pub use id::FullDeviceId; mod bar; +pub mod cap; mod id; pub mod irq_helpers; diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs index f8b0ef4997..6b6b3739f9 100644 --- a/pcid/src/pci/mod.rs +++ b/pcid/src/pci/mod.rs @@ -1,4 +1,3 @@ pub use pci_types::PciAddress; -pub mod cap; pub mod msi; From 6d15fbba75b6f1422fbfe42cbbd2cda474f1fbb4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 15:23:32 +0200 Subject: [PATCH 0940/1301] pcid: Move msi from pci to driver_interface --- pcid/src/driver_interface/irq_helpers.rs | 4 ++-- pcid/src/driver_interface/mod.rs | 4 ++-- pcid/src/{pci => driver_interface}/msi.rs | 0 pcid/src/lib.rs | 1 - pcid/src/main.rs | 1 - pcid/src/pci/mod.rs | 3 --- 6 files changed, 4 insertions(+), 9 deletions(-) rename pcid/src/{pci => driver_interface}/msi.rs (100%) delete mode 100644 pcid/src/pci/mod.rs diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index 9d7615a285..2624be2951 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -8,7 +8,7 @@ use std::fs::{self, File}; use std::io::{self, prelude::*}; use std::num::NonZeroU8; -use crate::pci::msi::MsiAddrAndData; +use crate::driver_interface::msi::MsiAddrAndData; /// Read the local APIC ID of the bootstrap processor. pub fn read_bsp_apic_id() -> io::Result { @@ -180,7 +180,7 @@ pub fn allocate_single_interrupt_vector(cpu_id: usize) -> io::Result (MsiAddrAndData, File) { - use crate::pci::msi::x86 as x86_msix; + use crate::driver_interface::msi::x86 as x86_msix; // FIXME for cpu_id >255 we need to use the IOMMU to use IRQ remapping let lapic_id = u8::try_from(cpu_id).expect("CPU id couldn't fit inside u8"); diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 58bdcdd054..fd9792a270 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -9,16 +9,16 @@ use std::os::unix::io::{FromRawFd, RawFd}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use thiserror::Error; -pub use crate::pci::msi; -pub use crate::pci::PciAddress; pub use bar::PciBar; pub use cap::VendorSpecificCapability; pub use id::FullDeviceId; +pub use pci_types::PciAddress; mod bar; pub mod cap; mod id; pub mod irq_helpers; +pub mod msi; #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct LegacyInterruptLine(pub(crate) u8); diff --git a/pcid/src/pci/msi.rs b/pcid/src/driver_interface/msi.rs similarity index 100% rename from pcid/src/pci/msi.rs rename to pcid/src/driver_interface/msi.rs diff --git a/pcid/src/lib.rs b/pcid/src/lib.rs index bf750605da..312a886cf5 100644 --- a/pcid/src/lib.rs +++ b/pcid/src/lib.rs @@ -1,5 +1,4 @@ //! Interface to `pcid`. mod driver_interface; -mod pci; pub use driver_interface::*; diff --git a/pcid/src/main.rs b/pcid/src/main.rs index c7e0e644e1..7a6df7d091 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -19,7 +19,6 @@ mod cfg_access; mod config; mod driver_handler; mod driver_interface; -mod pci; #[derive(StructOpt)] #[structopt(about)] diff --git a/pcid/src/pci/mod.rs b/pcid/src/pci/mod.rs deleted file mode 100644 index 6b6b3739f9..0000000000 --- a/pcid/src/pci/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub use pci_types::PciAddress; - -pub mod msi; From 07aaf6ea948b3d1de03ddccb356044aea3422f84 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 15:29:09 +0200 Subject: [PATCH 0941/1301] pcid: Don't include source files in two different crates This confuses rust-analyzer. --- pcid/src/config.rs | 2 +- pcid/src/driver_handler.rs | 20 +++++++++++--------- pcid/src/driver_interface/cap.rs | 2 +- pcid/src/driver_interface/id.rs | 2 +- pcid/src/driver_interface/irq_helpers.rs | 2 +- pcid/src/driver_interface/mod.rs | 8 +++++--- pcid/src/driver_interface/msi.rs | 10 ++-------- pcid/src/main.rs | 7 ++++--- 8 files changed, 26 insertions(+), 27 deletions(-) diff --git a/pcid/src/config.rs b/pcid/src/config.rs index 8278f33c3c..c9610f667c 100644 --- a/pcid/src/config.rs +++ b/pcid/src/config.rs @@ -3,7 +3,7 @@ use std::ops::Range; use serde::Deserialize; -use crate::driver_interface::FullDeviceId; +use pcid_interface::FullDeviceId; #[derive(Clone, Debug, Default, Deserialize)] pub struct Config { diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 4374df9387..7b3098101a 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -8,7 +8,6 @@ use log::{error, info}; use pci_types::capability::{MultipleMessageSupport, PciCapability}; use pci_types::{ConfigRegionAccess, PciAddress}; -use crate::driver_interface; use crate::State; pub struct DriverHandler { @@ -21,11 +20,11 @@ pub struct DriverHandler { impl DriverHandler { pub fn spawn( state: Arc, - func: driver_interface::PciFunction, + func: pcid_interface::PciFunction, capabilities: Vec, args: &[String], ) { - let subdriver_args = driver_interface::SubdriverArguments { func }; + let subdriver_args = pcid_interface::SubdriverArguments { func }; let mut args = args.iter(); if let Some(program) = args.next() { @@ -94,11 +93,12 @@ impl DriverHandler { fn respond( &mut self, - request: driver_interface::PcidClientRequest, - args: &driver_interface::SubdriverArguments, - ) -> driver_interface::PcidClientResponse { - use driver_interface::*; + request: pcid_interface::PcidClientRequest, + args: &pcid_interface::SubdriverArguments, + ) -> pcid_interface::PcidClientResponse { + use pcid_interface::*; + #[forbid(non_exhaustive_omitted_patterns)] match request { PcidClientRequest::RequestVendorCapabilities => PcidClientResponse::VendorCapabilities( self.capabilities @@ -320,6 +320,7 @@ impl DriverHandler { ); } } + _ => unreachable!(), }, PcidClientRequest::ReadConfig(offset) => { let value = unsafe { self.state.pcie.read(self.addr, offset) }; @@ -331,15 +332,16 @@ impl DriverHandler { } return PcidClientResponse::WriteConfig; } + _ => unreachable!(), } } fn handle_spawn( mut self, pcid_to_client_write: usize, pcid_from_client_read: usize, - args: driver_interface::SubdriverArguments, + args: pcid_interface::SubdriverArguments, ) { - use driver_interface::*; + use pcid_interface::*; let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_write as RawFd) }; let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_read as RawFd) }; diff --git a/pcid/src/driver_interface/cap.rs b/pcid/src/driver_interface/cap.rs index d03e6ff520..aa3f5540de 100644 --- a/pcid/src/driver_interface/cap.rs +++ b/pcid/src/driver_interface/cap.rs @@ -8,7 +8,7 @@ pub struct VendorSpecificCapability { } impl VendorSpecificCapability { - pub(crate) unsafe fn parse( + pub unsafe fn parse( addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess, ) -> Self { diff --git a/pcid/src/driver_interface/id.rs b/pcid/src/driver_interface/id.rs index 307efc955a..7b4ec84444 100644 --- a/pcid/src/driver_interface/id.rs +++ b/pcid/src/driver_interface/id.rs @@ -13,7 +13,7 @@ pub struct FullDeviceId { } impl FullDeviceId { - pub(crate) fn display(&self) -> String { + pub fn display(&self) -> String { let mut string = format!( "{:>04X}:{:>04X} {:>02X}.{:>02X}.{:>02X}.{:>02X} {:?}", self.vendor_id, diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index 2624be2951..82f444eabe 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -194,5 +194,5 @@ pub fn allocate_single_interrupt_vector_for_msi(cpu_id: usize) -> (MsiAddrAndDat let msg_data = x86_msix::message_data_edge_triggered(x86_msix::DeliveryMode::Fixed, vector); - (MsiAddrAndData::new(addr, msg_data), interrupt_handle) + (MsiAddrAndData { addr, data: msg_data }, interrupt_handle) } diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index fd9792a270..ece101d3bb 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -21,7 +21,7 @@ pub mod irq_helpers; pub mod msi; #[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct LegacyInterruptLine(pub(crate) u8); +pub struct LegacyInterruptLine(#[doc(hidden)] pub u8); impl LegacyInterruptLine { /// Get an IRQ handle for this interrupt line. @@ -257,7 +257,8 @@ pub struct PciFunctionHandle { mapped_bars: [Option; 6], } -pub(crate) fn send(w: &mut W, message: &T) -> Result<()> { +#[doc(hidden)] +pub fn send(w: &mut W, message: &T) -> Result<()> { let mut data = Vec::new(); bincode::serialize_into(&mut data, message)?; let length_bytes = u64::to_le_bytes(data.len() as u64); @@ -265,7 +266,8 @@ pub(crate) fn send(w: &mut W, message: &T) -> Result<()> w.write_all(&data)?; Ok(()) } -pub(crate) fn recv(r: &mut R) -> Result { +#[doc(hidden)] +pub fn recv(r: &mut R) -> Result { let mut length_bytes = [0u8; 8]; r.read_exact(&mut length_bytes)?; let length = u64::from_le_bytes(length_bytes); diff --git a/pcid/src/driver_interface/msi.rs b/pcid/src/driver_interface/msi.rs index 0a625d53e0..cba4d21399 100644 --- a/pcid/src/driver_interface/msi.rs +++ b/pcid/src/driver_interface/msi.rs @@ -11,14 +11,8 @@ use syscall::{Io, Mmio}; /// For MSI-X you can have a single [MsiEntry] for each interrupt vector. #[derive(Debug, Default, Serialize, Deserialize)] pub struct MsiAddrAndData { - pub(crate) addr: u64, - pub(crate) data: u32, -} - -impl MsiAddrAndData { - pub fn new(addr: u64, data: u32) -> Self { - MsiAddrAndData { addr, data } - } + pub addr: u64, + pub data: u32, } #[derive(Debug, Serialize, Deserialize)] diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 7a6df7d091..e392ba37b0 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,3 +1,5 @@ +#![feature(non_exhaustive_omitted_patterns_lint)] + use std::fs::{metadata, read_dir, File}; use std::io::prelude::*; use std::sync::{Arc, Mutex}; @@ -13,12 +15,11 @@ use structopt::StructOpt; use crate::cfg_access::Pcie; use crate::config::Config; -use crate::driver_interface::{FullDeviceId, LegacyInterruptLine, PciBar}; +use pcid_interface::{FullDeviceId, LegacyInterruptLine, PciBar}; mod cfg_access; mod config; mod driver_handler; -mod driver_interface; #[derive(StructOpt)] #[structopt(about)] @@ -150,7 +151,7 @@ fn handle_parsed_header( capabilities ); - let func = driver_interface::PciFunction { + let func = pcid_interface::PciFunction { bars, addr: endpoint_header.header().address(), legacy_interrupt_line: if legacy_interrupt_enabled { From 4ffed8096da9a58092447d15db20957c398dbfcb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:02:14 +0200 Subject: [PATCH 0942/1301] Move all drivers to /usr/lib/drivers This makes them harder to accidentally run them from the shell, which would not work. In the future this may also allow embedding the driver config in the driver executable itself without having to look at all non-driver executables too. --- initfs.toml | 10 +++++----- pcid/src/driver_handler.rs | 5 +++++ xhcid/drivers.toml | 6 +++--- xhcid/src/xhci/mod.rs | 5 +++++ 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/initfs.toml b/initfs.toml index c2a22fbaff..12290f9b38 100644 --- a/initfs.toml +++ b/initfs.toml @@ -5,21 +5,21 @@ name = "AHCI storage" class = 1 subclass = 6 -command = ["ahcid"] +command = ["/scheme/initfs/lib/drivers/ahcid"] # ided [[drivers]] name = "IDE storage" class = 1 subclass = 1 -command = ["ided"] +command = ["/scheme/initfs/lib/drivers/ided"] # nvmed [[drivers]] name = "NVME storage" class = 1 subclass = 8 -command = ["nvmed"] +command = ["/scheme/initfs/lib/drivers/nvmed"] [[drivers]] name = "virtio-blk" @@ -27,11 +27,11 @@ class = 1 subclass = 0 vendor = 0x1AF4 device = 0x1001 -command = ["virtio-blkd"] +command = ["/scheme/initfs/lib/drivers/virtio-blkd"] [[drivers]] name = "virtio-gpu" class = 3 vendor = 0x1AF4 device = 0x1050 -command = ["virtio-gpud"] +command = ["/scheme/initfs/lib/drivers/virtio-gpud"] diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 7b3098101a..d34a067d3c 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -28,6 +28,11 @@ impl DriverHandler { let mut args = args.iter(); if let Some(program) = args.next() { + let program = if program.starts_with('/') { + program.to_owned() + } else { + "/usr/lib/drivers/".to_owned() + program + }; let mut command = Command::new(program); for arg in args { if arg.starts_with("$") { diff --git a/xhcid/drivers.toml b/xhcid/drivers.toml index 8b28dbd8d4..470ec06321 100644 --- a/xhcid/drivers.toml +++ b/xhcid/drivers.toml @@ -2,16 +2,16 @@ name = "SCSI over USB" class = 8 # Mass Storage class subclass = 6 # SCSI transparent command set -command = ["/bin/usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"] +command = ["usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"] [[drivers]] name = "USB HUB" class = 9 # HUB class subclass = -1 -command = ["/bin/usbhubd", "$SCHEME", "$PORT", "$IF_NUM"] +command = ["usbhubd", "$SCHEME", "$PORT", "$IF_NUM"] [[drivers]] name = "USB HID" class = 3 # HID class subclass = -1 -command = ["/bin/usbhidd", "$SCHEME", "$PORT", "$IF_NUM"] +command = ["usbhidd", "$SCHEME", "$PORT", "$IF_NUM"] diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index f42482f1ea..52b582adea 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -847,6 +847,11 @@ impl Xhci { info!("Loading subdriver \"{}\"", driver.name); let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; + let command = if command.starts_with('/') { + command.to_owned() + } else { + "/usr/lib/drivers/".to_owned() + command + }; let process = process::Command::new(command) .args( args.into_iter() From ab0b1561593499df6e210fe81599519bdb9c2c9e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 17 Jun 2024 12:42:23 -0600 Subject: [PATCH 0943/1301] ps2d: reduce timeouts --- ps2d/src/controller.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index ce35259a1d..1b0ae6fecb 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -126,7 +126,7 @@ impl Ps2 { } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 1_000_000; + let mut timeout = 100_000; while timeout > 0 { if self.status().contains(StatusFlags::OUTPUT_FULL) { return Ok(()); @@ -138,7 +138,7 @@ impl Ps2 { } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 1_000_000; + let mut timeout = 100_000; while timeout > 0 { if ! self.status().contains(StatusFlags::INPUT_FULL) { return Ok(()); From e7781dcced8a23aa48ec9454c6c4d447fdf27b81 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 24 Jun 2024 11:43:17 -0600 Subject: [PATCH 0944/1301] Fix compilation on aarch64 --- pcid/src/cfg_access/fallback.rs | 4 ---- virtio-core/src/arch/aarch64.rs | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/pcid/src/cfg_access/fallback.rs b/pcid/src/cfg_access/fallback.rs index bd073eaf27..1f1e49a8ae 100644 --- a/pcid/src/cfg_access/fallback.rs +++ b/pcid/src/cfg_access/fallback.rs @@ -84,10 +84,6 @@ impl ConfigRegionAccess for Pci { } #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] impl ConfigRegionAccess for Pci { - fn function_exists(&self, _address: PciAddress) -> bool { - todo!(); - } - unsafe fn read(&self, addr: PciAddress, offset: u16) -> u32 { let _guard = self.lock.lock().unwrap(); todo!("Pci::CfgAccess::read on this architecture") diff --git a/virtio-core/src/arch/aarch64.rs b/virtio-core/src/arch/aarch64.rs index 5d855258ca..4801a1f25d 100644 --- a/virtio-core/src/arch/aarch64.rs +++ b/virtio-core/src/arch/aarch64.rs @@ -4,6 +4,6 @@ use pcid_interface::*; use crate::{transport::Error, Device}; -pub fn enable_msix(pcid_handle: &mut PcidServerHandle) -> Result { +pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { unimplemented!("virtio_core: aarch64 enable_msix") } From 93d5ceb465c14492ac301a12da280ae811ee5c2f Mon Sep 17 00:00:00 2001 From: ramla-i Date: Tue, 9 Jul 2024 12:55:48 -0400 Subject: [PATCH 0945/1301] bug fixes --- net/ixgbed/src/device.rs | 11 ++++++----- net/ixgbed/src/ixgbe.rs | 1 + 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/net/ixgbed/src/device.rs b/net/ixgbed/src/device.rs index 4ab8d0e530..a61441bca3 100644 --- a/net/ixgbed/src/device.rs +++ b/net/ixgbed/src/device.rs @@ -290,7 +290,7 @@ impl Intel8259x { self.wait_write_reg(IXGBE_EEC, IXGBE_EEC_ARD); // section 4.6.3 - wait for dma initialization done - self.wait_write_reg(IXGBE_RDRXCTL, IXGBE_RDRXCTL_DMAIDONE); + self.wait_write_reg(IXGBE_RDRXCTL, IXGBE_RDRXCTL_DMAIDONE | IXGBE_RDRXCTL_RESERVED_BITS); // section 4.6.4 - initialize link (auto negotiation) self.init_link(); @@ -314,9 +314,6 @@ impl Intel8259x { // section 4.6.3.9 - enable interrupts self.enable_msix_interrupt(0); - // enable promisc mode by default to make testing easier - self.set_promisc(true); - // wait some time for the link to come up self.wait_for_link(); } @@ -380,6 +377,10 @@ impl Intel8259x { // probably a broken feature, this flag is initialized with 1 but has to be set to 0 self.clear_flag(IXGBE_DCA_RXCTRL(i), 1 << 12); + // enable promisc mode by default to make testing easier + // this has to be done when the rxctrl.rxen bit is not set + self.set_promisc(true); + // start rx self.write_flag(IXGBE_RXCTRL, IXGBE_RXCTRL_RXEN); } @@ -397,7 +398,7 @@ impl Intel8259x { } // required when not using DCB/VTd - self.write_reg(IXGBE_DTXMXSZRQ, 0xffff); + self.write_reg(IXGBE_DTXMXSZRQ, 0xfff); self.clear_flag(IXGBE_RTTDCS, IXGBE_RTTDCS_ARBDIS); // configure a single transmit queue/ring diff --git a/net/ixgbed/src/ixgbe.rs b/net/ixgbed/src/ixgbe.rs index c86d9d827b..abfd5ddda1 100644 --- a/net/ixgbed/src/ixgbe.rs +++ b/net/ixgbed/src/ixgbe.rs @@ -14,6 +14,7 @@ pub const IXGBE_EEC: u32 = 0x10010; pub const IXGBE_EEC_ARD: u32 = 0x00000200; /* EEPROM Auto Read Done */ pub const IXGBE_RDRXCTL: u32 = 0x02F00; +pub const IXGBE_RDRXCTL_RESERVED_BITS: u32 = 1 << 25 | 1 << 26; pub const IXGBE_RDRXCTL_DMAIDONE: u32 = 0x00000008; /* DMA init cycle done */ pub const IXGBE_AUTOC: u32 = 0x042A0; From fd8dabd1bc72e80ff342f7e3cb4bd4ddd585f07a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 11 Jul 2024 21:14:42 +0200 Subject: [PATCH 0946/1301] Use the new scheme format in most places The graphics subsystem still uses the old format as orbital manually parses the fpath result. --- README.md | 12 ++++++------ acpid/src/main.rs | 10 +++++----- audio/ihdad/src/main.rs | 4 ++-- audio/sb16d/src/main.rs | 2 +- common/src/dma.rs | 2 +- common/src/lib.rs | 2 +- graphics/bgad/src/main.rs | 2 +- graphics/fbcond/src/display.rs | 2 +- graphics/fbcond/src/main.rs | 2 +- inputd/src/lib.rs | 2 +- inputd/src/main.rs | 4 ++-- net/alxd/src/main.rs | 2 +- net/virtio-netd/src/main.rs | 2 +- pcid/src/cfg_access/mod.rs | 2 +- pcid/src/driver_interface/irq_helpers.rs | 16 ++++++++-------- pcid/src/driver_interface/mod.rs | 2 +- ps2d/src/main.rs | 20 ++++++++++---------- storage/ided/src/main.rs | 4 ++-- storage/lived/src/main.rs | 4 ++-- storage/nvmed/src/nvme/cq_reactor.rs | 2 +- usbhidd/src/main.rs | 2 +- xhcid/src/driver_interface.rs | 12 ++++++------ 22 files changed, 56 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 6eba98ce74..93a21c3cf1 100644 --- a/README.md +++ b/README.md @@ -46,12 +46,12 @@ This section cover the interfaces used by Redox drivers. ### Schemes -- `memory:physical` - allows mapping physical memory frames to driver-accessible virtual memory pages, with various available memory types: - - `memory:physical`: default memory type (currently writeback) - - `memory:physical@wb` writeback cached memory - - `memory:physical@uc`: uncacheable memory - - `memory:physical@wc`: write-combining memory -- `irq:` - allows getting events from interrupts. It is used primarily by listening for its file descriptors using the `event:` scheme. +- `/scheme/memory/physical` - allows mapping physical memory frames to driver-accessible virtual memory pages, with various available memory types: + - `/scheme/memory/physical`: default memory type (currently writeback) + - `/scheme/memory/physical@wb` writeback cached memory + - `/scheme/memory/physical@uc`: uncacheable memory + - `/scheme/memory/physical@wc`: write-combining memory +- `/scheme/irq` - allows getting events from interrupts. It is used primarily by listening for its file descriptors using the `/scheme/event` scheme. ## Contributing diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 93c54f9558..1aebe40a97 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -81,8 +81,8 @@ fn setup_logging() -> Option<&'static RedoxLogger> { fn daemon(daemon: redox_daemon::Daemon) -> ! { setup_logging(); - let rxsdt_raw_data: Arc<[u8]> = std::fs::read("kernel.acpi:rxsdt") - .expect("acpid: failed to read `kernel.acpi:rxsdt`") + let rxsdt_raw_data: Arc<[u8]> = std::fs::read("/scheme/kernel.acpi/rxsdt") + .expect("acpid: failed to read `/scheme/kernel.acpi/rxsdt`") .into(); let sdt = self::acpi::Sdt::new(rxsdt_raw_data) @@ -116,14 +116,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // TODO: I/O permission bitmap? common::acquire_port_io_rights().expect("acpid: failed to set I/O privilege level to Ring 3"); - let shutdown_pipe = File::open("kernel.acpi:kstop") - .expect("acpid: failed to open `kernel.acpi:kstop`"); + let shutdown_pipe = File::open("/scheme/kernel.acpi/kstop") + .expect("acpid: failed to open `/scheme/kernel.acpi/kstop`"); let mut event_queue = OpenOptions::new() .write(true) .read(true) .create(false) - .open("event:") + .open("/scheme/event") .expect("acpid: failed to open event queue"); let mut scheme_socket = OpenOptions::new() diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 78f2ebbe32..755a5bcc4e 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -113,7 +113,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { log::debug!("Legacy IRQ {}", irq); // legacy INTx# interrupt pins. - File::open(format!("irq:{}", irq)).expect("ihdad: failed to open legacy IRQ file") + irq.irq_handle("ihdad") } else { panic!("ihdad: no interrupts supported at all") } @@ -126,7 +126,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. - File::open(format!("irq:{}", irq)).expect("ihdad: failed to open legacy IRQ file") + irq.irq_handle("ihdad") } else { panic!("ihdad: no interrupts supported at all") } diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index e01125ce4e..002c707974 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -73,7 +73,7 @@ fn main() { //TODO: error on multiple IRQs? let irq_file = match device.irqs.first() { - Some(irq) => Fd::open(&format!("irq:{}", irq), flag::O_RDWR, 0).expect("sb16d: failed to open IRQ file"), + Some(irq) => Fd::open(&format!("/scheme/irq/{}", irq), flag::O_RDWR, 0).expect("sb16d: failed to open IRQ file"), None => panic!("sb16d: no IRQs found"), }; user_data! { diff --git a/common/src/dma.rs b/common/src/dma.rs index 4c723a001b..fef60d04e0 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -22,7 +22,7 @@ const DMA_MEMTY: MemoryType = { pub(crate) fn phys_contiguous_fd() -> Result { Fd::open( - &format!("memory:zeroed@{DMA_MEMTY}?phys_contiguous"), + &format!("/scheme/memory/zeroed@{DMA_MEMTY}?phys_contiguous"), flag::O_CLOEXEC, 0, ) diff --git a/common/src/lib.rs b/common/src/lib.rs index b22d93bcda..c96e3e8c4e 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -51,7 +51,7 @@ pub unsafe fn physmap( ) -> Result<*mut ()> { // TODO: arraystring? let path = format!( - "memory:physical@{}", + "/scheme/memory/physical@{}", match ty { MemoryType::Writeback => "wb", MemoryType::Uncacheable => "uc", diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index c4832e8560..ad3a4fe393 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -35,7 +35,7 @@ fn main() { let mut scheme = BgaScheme { bga, - display: File::open("input:producer").ok(), + display: File::open("/scheme/input/producer").ok(), }; scheme.update_size(); diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index e2d3798046..4a7e005ce2 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -56,7 +56,7 @@ impl Display { let input_handle = OpenOptions::new() .read(true) .custom_flags(O_NONBLOCK as i32) - .open(format!("input:consumer/{vt}"))?; + .open(format!("/scheme/input/consumer/{vt}"))?; let fd = input_handle.as_raw_fd(); let written = libredox::call::fpath(fd as usize, &mut buffer) diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 4db9e1b5fc..7f0df69b69 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -41,7 +41,7 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { .create(true) .truncate(true) .custom_flags(O_NONBLOCK as i32) - .open(":fbcon") + .open("/scheme/fbcon") .expect("fbcond: failed to create fbcon scheme"); event_queue .subscribe( diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 3112964993..1747e02106 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -25,7 +25,7 @@ pub struct Handle(File); impl Handle { pub fn new>(device_name: S) -> Result { - let path = format!("input:handle/display/{}", device_name.into()); + let path = format!("/scheme/input/handle/display/{}", device_name.into()); Ok(Self(File::open(path)?)) } diff --git a/inputd/src/main.rs b/inputd/src/main.rs index e8b34c9585..27d7f0ad12 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -73,7 +73,7 @@ impl Vt { pub fn inner(&self) -> &Mutex { self.inner.call_once(|| { - let handle_file = File::open(format!("{}:handle", self.display)).unwrap(); + let handle_file = File::open(format!("/scheme/{}/handle", self.display)).unwrap(); Mutex::new(VtInner { handle_file, mode: VtMode::Default, @@ -531,7 +531,7 @@ pub fn main() { "-A" => { let vt = args.next().unwrap().parse::().unwrap(); - let handle = File::open(format!("input:consumer/{vt}")) + let handle = File::open(format!("/scheme/input/consumer/{vt}")) .expect("inputd: failed to open consumer handle"); let mut display_path = [0; 4096]; diff --git a/net/alxd/src/main.rs b/net/alxd/src/main.rs index 2ffce2e201..e6c54024aa 100644 --- a/net/alxd/src/main.rs +++ b/net/alxd/src/main.rs @@ -40,7 +40,7 @@ fn main() { daemon.ready().expect("alxd: failed to signal readiness"); - let mut irq_file = File::open(format!("irq:{}", irq)).expect("alxd: failed to open IRQ file"); + let mut irq_file = File::open(format!("/scheme/irq/{}", irq)).expect("alxd: failed to open IRQ file"); let address = unsafe { common::physmap(bar, 128*1024, common::Prot::RW, common::MemoryType::Uncacheable).expect("alxd: failed to map address") as usize }; { diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index 76e07b160f..e4ad270df9 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -95,7 +95,7 @@ fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box let device = VirtioNet::new(mac_address, rx_queue, tx_queue); let mut scheme = NetworkScheme::new(device, format!("network.{name}")); - let mut event_queue = File::open("event:")?; + let mut event_queue = File::open("/scheme/event")?; event_queue.write(&syscall::Event { id: scheme.event_handle() as usize, flags: syscall::EVENT_READ, diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index 894f4f448b..434f106020 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -126,7 +126,7 @@ struct PcieAllocs<'a>(&'a [PcieAlloc]); impl Mcfg { fn with(f: impl FnOnce(PcieAllocs<'_>) -> io::Result) -> io::Result { - let table_dir = fs::read_dir("acpi:tables")?; + let table_dir = fs::read_dir("/scheme/acpi/tables")?; // TODO: validate/print MCFG? diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index 82f444eabe..b900068456 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -1,7 +1,7 @@ //! IRQ helpers. //! -//! This module allows easy handling of the `irq:` scheme, and allocating interrupt vectors for use -//! by INTx#, MSI, or MSI-X. +//! This module allows easy handling of the `/scheme/irq` scheme, and allocating interrupt vectors +//! for use by INTx#, MSI, or MSI-X. use std::convert::TryFrom; use std::fs::{self, File}; @@ -14,7 +14,7 @@ use crate::driver_interface::msi::MsiAddrAndData; pub fn read_bsp_apic_id() -> io::Result { let mut buffer = [0u8; 8]; - let mut file = File::open("irq:bsp")?; + let mut file = File::open("/scheme/irq/bsp")?; let bytes_read = file.read(&mut buffer)?; (if bytes_read == 8 { @@ -25,7 +25,7 @@ pub fn read_bsp_apic_id() -> io::Result { ])) } else { panic!( - "`irq:` scheme responded with {} bytes, expected {}", + "`/scheme/irq` scheme responded with {} bytes, expected {}", bytes_read, std::mem::size_of::() ); @@ -41,7 +41,7 @@ pub fn read_bsp_apic_id() -> io::Result { /// capability structs or MSI-X tables. pub fn cpu_ids() -> io::Result> + 'static> { Ok( - fs::read_dir("irq:")?.filter_map(|entry| -> Option> { + fs::read_dir("/scheme/irq")?.filter_map(|entry| -> Option> { match entry { Ok(e) => { let path = e.path(); @@ -88,7 +88,7 @@ pub fn allocate_aligned_interrupt_vectors( return Ok(None); } - let available_irqs = fs::read_dir(format!("irq:cpu-{:02x}", cpu_id))?; + let available_irqs = fs::read_dir(format!("/scheme/irq/cpu-{:02x}", cpu_id))?; let mut available_irq_numbers = available_irqs.filter_map(|entry| -> Option> { let entry = match entry { Ok(e) => e, @@ -113,7 +113,7 @@ pub fn allocate_aligned_interrupt_vectors( } }); - // TODO: fcntl F_SETLK on `irq:/`? + // TODO: fcntl F_SETLK on `/scheme/irq/`? let mut handles = Vec::with_capacity(usize::from(count)); @@ -137,7 +137,7 @@ pub fn allocate_aligned_interrupt_vectors( } // if found, reserve the irq - let irq_handle = match File::create(format!("irq:cpu-{:02x}/{}", cpu_id, irq_number)) { + let irq_handle = match File::create(format!("/scheme/irq/cpu-{:02x}/{}", cpu_id, irq_number)) { Ok(handle) => handle, // return early if the entire range couldn't be allocated diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index ece101d3bb..2900a1e68c 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -26,7 +26,7 @@ pub struct LegacyInterruptLine(#[doc(hidden)] pub u8); impl LegacyInterruptLine { /// Get an IRQ handle for this interrupt line. pub fn irq_handle(self, driver: &str) -> File { - File::open(format!("irq:{}", self.0)) + File::open(format!("/scheme/irq/{}", self.0)) .unwrap_or_else(|err| panic!("{driver}: failed to open IRQ file: {err}")) } } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index aa4ec5df2c..64910d95ef 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -45,40 +45,40 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let input = OpenOptions::new() .write(true) - .open("input:producer") - .expect("ps2d: failed to open input:producer"); + .open("/scheme/input/producer") + .expect("ps2d: failed to open /scheme/input/producer"); let mut event_file = OpenOptions::new() .read(true) .write(true) - .open("event:") - .expect("ps2d: failed to open event:"); + .open("/scheme/event") + .expect("ps2d: failed to open /scheme/event"); let mut key_file = OpenOptions::new() .read(true) .write(true) .custom_flags(syscall::O_NONBLOCK as i32) - .open("serio:0") - .expect("ps2d: failed to open serio:0"); + .open("/scheme/serio/0") + .expect("ps2d: failed to open /scheme/serio/0"); event_file.write(&syscall::Event { id: key_file.as_raw_fd() as usize, flags: syscall::EVENT_READ, data: 0 - }).expect("ps2d: failed to event serio:0"); + }).expect("ps2d: failed to event /scheme/serio/0"); let mut mouse_file = OpenOptions::new() .read(true) .write(true) .custom_flags(syscall::O_NONBLOCK as i32) - .open("serio:1") - .expect("ps2d: failed to open serio:1"); + .open("/scheme/serio/1") + .expect("ps2d: failed to open /scheme/serio/1"); event_file.write(&syscall::Event { id: mouse_file.as_raw_fd() as usize, flags: syscall::EVENT_READ, data: 1 - }).expect("ps2d: failed to event irq:12"); + }).expect("ps2d: failed to event /scheme/serio/1"); libredox::call::setrens(0, 0).expect("ps2d: failed to enter null namespace"); diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index c4723fad54..c69ac46d18 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -238,14 +238,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("ided: failed to create disk scheme"); let primary_irq_fd = libredox::call::open( - &format!("irq:{}", primary_irq), + &format!("/scheme/irq/{}", primary_irq), flag::O_RDWR | flag::O_NONBLOCK, 0, ).expect("ided: failed to open irq file"); let mut primary_irq_file = unsafe { File::from_raw_fd(primary_irq_fd as RawFd) }; let secondary_irq_fd = libredox::call::open( - &format!("irq:{}", secondary_irq), + &format!("/scheme/irq/{}", secondary_irq), flag::O_RDWR | flag::O_NONBLOCK, 0, ).expect("ided: failed to open irq file"); diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index ce6dbd95ab..038b53388d 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -46,7 +46,7 @@ impl DiskScheme { let mut size = 0; // TODO: handle error - for line in std::fs::read_to_string("sys:env").context("failed to read env")?.lines() { + for line in std::fs::read_to_string("/scheme/sys/env").context("failed to read env")?.lines() { let mut parts = line.splitn(2, '='); let name = parts.next().unwrap_or(""); let value = parts.next().unwrap_or(""); @@ -69,7 +69,7 @@ impl DiskScheme { let size = end - start; let the_data = unsafe { - let file = File::open("memory:physical")?; + let file = File::open("/scheme/memory/physical")?; let base = libredox::call::mmap(MmapArgs { fd: file.as_raw_fd() as usize, addr: core::ptr::null_mut(), diff --git a/storage/nvmed/src/nvme/cq_reactor.rs b/storage/nvmed/src/nvme/cq_reactor.rs index a41f576f64..cf65635de7 100644 --- a/storage/nvmed/src/nvme/cq_reactor.rs +++ b/storage/nvmed/src/nvme/cq_reactor.rs @@ -66,7 +66,7 @@ struct CqReactor { impl CqReactor { fn create_event_queue(int_sources: &mut InterruptSources) -> Result { use libredox::flag::*; - let fd = libredox::call::open("event:", O_CLOEXEC | O_RDWR, 0)?; + let fd = libredox::call::open("/scheme/event", O_CLOEXEC | O_RDWR, 0)?; let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; for (num, irq_handle) in int_sources.iter_mut() { diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 5e338cfcbe..0551cd0953 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -313,7 +313,7 @@ fn main() { let report_id = 0; let mut display = - File::open("input:producer").expect("Failed to open orbital input socket"); + File::open("/scheme/input/producer").expect("Failed to open orbital input socket"); let mut endpoint_opt = match endpoint_num_opt { Some(endpoint_num) => match handle.open_endpoint(endpoint_num as u8) { Ok(ok) => Some(ok), diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index c850f252d6..a1eedb7381 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -414,7 +414,7 @@ impl XhciClientHandle { } pub fn get_standard_descs(&self) -> result::Result { - let path = format!("{}:port{}/descriptors", self.scheme, self.port); + let path = format!("/scheme/{}/port{}/descriptors", self.scheme, self.port); let json = std::fs::read(path)?; Ok(serde_json::from_slice(&json)?) } @@ -422,7 +422,7 @@ impl XhciClientHandle { &self, req: &ConfigureEndpointsReq, ) -> result::Result<(), XhciClientHandleError> { - let path = format!("{}:port{}/configure", self.scheme, self.port); + let path = format!("/scheme/{}/port{}/configure", self.scheme, self.port); let json = serde_json::to_vec(req)?; let mut file = OpenOptions::new().read(false).write(true).open(path)?; let json_bytes_written = file.write(&json)?; @@ -434,16 +434,16 @@ impl XhciClientHandle { Ok(()) } pub fn port_state(&self) -> result::Result { - let path = format!("{}:port{}/state", self.scheme, self.port); + let path = format!("/scheme/{}/port{}/state", self.scheme, self.port); let string = std::fs::read_to_string(path)?; Ok(string.parse()?) } pub fn open_endpoint_ctl(&self, num: u8) -> result::Result { - let path = format!("{}:port{}/endpoints/{}/ctl", self.scheme, self.port, num); + let path = format!("/scheme/{}/port{}/endpoints/{}/ctl", self.scheme, self.port, num); Ok(File::open(path)?) } pub fn open_endpoint_data(&self, num: u8) -> result::Result { - let path = format!("{}:port{}/endpoints/{}/data", self.scheme, self.port, num); + let path = format!("/scheme/{}/port{}/endpoints/{}/data", self.scheme, self.port, num); Ok(File::open(path)?) } pub fn open_endpoint(&self, num: u8) -> result::Result { @@ -476,7 +476,7 @@ impl XhciClientHandle { }; let json = serde_json::to_vec(&req)?; - let path = format!("{}:port{}/request", self.scheme, self.port); + let path = format!("/scheme/{}/port{}/request", self.scheme, self.port); let mut file = File::open(path)?; let json_bytes_written = file.write(&json)?; From 2fc3923d461a8c019a41cb7561de6c4fe78ee75a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 12 Jul 2024 12:05:31 +0200 Subject: [PATCH 0947/1301] Fix fbcon --- graphics/fbcond/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 7f0df69b69..4db9e1b5fc 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -41,7 +41,7 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { .create(true) .truncate(true) .custom_flags(O_NONBLOCK as i32) - .open("/scheme/fbcon") + .open(":fbcon") .expect("fbcond: failed to create fbcon scheme"); event_queue .subscribe( From d9e5c6644d1561e16489d2a2503c4a0b43d00304 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Tue, 16 Jul 2024 14:17:19 +0200 Subject: [PATCH 0948/1301] Update deps and fix inputd. Scheme names are not allowed to contain slashes, so it should look for a `.` in e.g. `display.vesa:/path/to/...`. --- Cargo.lock | 212 ++++++++++++++++++++++----------------------- inputd/src/main.rs | 2 +- 2 files changed, 107 insertions(+), 107 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 715a684924..c3bfee3bd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "spin", ] @@ -33,7 +33,7 @@ dependencies = [ "plain", "redox-daemon", "redox-log", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "rustc-hash", "serde_json", "thiserror", @@ -54,19 +54,19 @@ dependencies = [ "redox-log", "redox-scheme", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] name = "alxd" version = "0.1.0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "common", "libredox 0.1.3", "redox-daemon", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -159,7 +159,7 @@ dependencies = [ "fdt 0.1.5", "libredox 0.1.3", "redox-daemon", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -170,7 +170,7 @@ dependencies = [ "orbclient", "pcid", "redox-daemon", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -196,9 +196,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bitvec" @@ -226,9 +226,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.99" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" [[package]] name = "cfg-if" @@ -286,7 +286,7 @@ name = "common" version = "0.1.0" dependencies = [ "libredox 0.1.3", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -351,7 +351,7 @@ name = "driver-block" version = "0.1.0" dependencies = [ "partitionlib", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -359,21 +359,21 @@ name = "driver-network" version = "0.1.0" dependencies = [ "libredox 0.1.3", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] name = "e1000d" version = "0.1.0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "common", "driver-network", "libredox 0.1.3", "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -392,7 +392,7 @@ dependencies = [ "ransid", "redox-daemon", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -477,7 +477,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -527,7 +527,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8283e7331b8c93b9756e0cfdbcfb90312852f953c6faf9bf741e684cc3b6ad69" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "crc", "log", "uuid", @@ -593,14 +593,14 @@ dependencies = [ "redox-log", "redox-scheme", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] name = "ihdad" version = "0.1.0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "common", "libredox 0.1.3", "log", @@ -608,7 +608,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "spin", ] @@ -632,7 +632,7 @@ dependencies = [ "orbclient", "redox-daemon", "redox-log", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "spin", ] @@ -655,14 +655,14 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" name = "ixgbed" version = "1.0.0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "common", "driver-network", "libredox 0.1.3", "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -676,9 +676,9 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" @@ -692,7 +692,7 @@ version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", "redox_syscall 0.4.1", ] @@ -703,9 +703,9 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libc", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -717,7 +717,7 @@ dependencies = [ "redox-daemon", "redox-scheme", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -732,9 +732,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "maybe-uninit" @@ -792,7 +792,7 @@ dependencies = [ "redox-log", "redox-scheme", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "smallvec 1.13.2", ] @@ -919,7 +919,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4325c6aa3cca3373503b1527e75756f9fbfe5fd76be4b4c8a143ee47430b8e0" dependencies = [ "bit_field", - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -938,7 +938,7 @@ dependencies = [ "pci_types", "plain", "redox-log", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "serde", "serde_json", "structopt", @@ -952,7 +952,7 @@ version = "0.1.0" dependencies = [ "libredox 0.1.3", "redox-daemon", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -999,9 +999,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.85" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] @@ -1014,7 +1014,7 @@ dependencies = [ "libredox 0.1.3", "orbclient", "redox-daemon", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -1090,9 +1090,9 @@ dependencies = [ [[package]] name = "redox-log" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd7c67eb2d8e610a74a8f1e67eecd3042f87b1aebfa620de4b40257265a54f2" +checksum = "cacd9e83920c75b71b2ea740603d579179da055e8a8d72b25252874c28d513f0" dependencies = [ "chrono", "log", @@ -1102,11 +1102,11 @@ dependencies = [ [[package]] name = "redox-scheme" -version = "0.2.0" -source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#62aed6c712cca31bb18078adacd27b400f5ccf93" +version = "0.2.1" +source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#79d9d54f572f53386981fb9b6ef054fd9e45110c" dependencies = [ "libredox 0.1.3", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -1115,7 +1115,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69609faa5d5992247a4ef379917bb3e39be281405d6a0ccd4f942429400b956f" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "libredox 0.1.3", ] @@ -1139,11 +1139,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] @@ -1157,7 +1157,7 @@ name = "rehid" version = "0.1.0" source = "git+https://gitlab.redox-os.org/redox-os/rehid.git#ea48fff4901986903359cb616a9b0d0ff8d0d8b4" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "log", "ux", ] @@ -1166,7 +1166,7 @@ dependencies = [ name = "rtl8139d" version = "0.1.0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "common", "driver-network", "libredox 0.1.3", @@ -1175,14 +1175,14 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] name = "rtl8168d" version = "0.1.0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "common", "driver-network", "libredox 0.1.3", @@ -1191,7 +1191,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -1210,14 +1210,14 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" name = "sb16d" version = "0.1.0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "common", "libredox 0.1.3", "log", "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "spin", ] @@ -1272,29 +1272,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.203" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", @@ -1411,9 +1411,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.66" +version = "2.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" dependencies = [ "proc-macro2", "quote", @@ -1428,9 +1428,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "termion" -version = "2.0.3" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4648c7def6f2043b2568617b9f9b75eae88ca185dbc1f1fda30e95a85d49d7d" +checksum = "1ccce68e518d1173e80876edd54760b60b792750d0cab6444a79101c6ea03848" dependencies = [ "libc", "libredox 0.0.2", @@ -1449,22 +1449,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", ] [[package]] @@ -1540,11 +1540,11 @@ dependencies = [ name = "usbhidd" version = "0.1.0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "log", "orbclient", "redox-log", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "rehid", "xhcid", ] @@ -1555,7 +1555,7 @@ version = "0.1.0" dependencies = [ "log", "redox-log", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "xhcid", ] @@ -1568,7 +1568,7 @@ dependencies = [ "plain", "redox-daemon", "redox-scheme", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "thiserror", "xhcid", ] @@ -1581,9 +1581,9 @@ checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" [[package]] name = "uuid" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ "getrandom", ] @@ -1604,7 +1604,7 @@ dependencies = [ "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -1635,7 +1635,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", ] [[package]] @@ -1653,7 +1653,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox-scheme", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "spin", "static_assertions", "thiserror", @@ -1664,7 +1664,7 @@ dependencies = [ name = "virtio-core" version = "0.1.0" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "common", "crossbeam-queue", "futures", @@ -1673,7 +1673,7 @@ dependencies = [ "pcid", "redox-log", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "static_assertions", "thiserror", ] @@ -1692,7 +1692,7 @@ dependencies = [ "paste", "pcid", "redox-daemon", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "spin", "static_assertions", "virtio-core", @@ -1709,7 +1709,7 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "static_assertions", "virtio-core", ] @@ -1750,7 +1750,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", "wasm-bindgen-shared", ] @@ -1772,7 +1772,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.66", + "syn 2.0.71", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1816,9 +1816,9 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -1832,51 +1832,51 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" @@ -1913,7 +1913,7 @@ dependencies = [ "redox-daemon", "redox-log", "redox_event", - "redox_syscall 0.5.2", + "redox_syscall 0.5.3", "serde", "serde_json", "smallvec 1.13.2", diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 27d7f0ad12..f35f593c08 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -544,7 +544,7 @@ pub fn main() { let display_path = std::str::from_utf8(&display_path[..written]) .expect("inputd: display path UTF-8 validation failed"); let display_name = display_path - .split('/') + .split('.') .skip(1) .next() .expect("inputd: invalid display path"); From 1f25a69feb148c78c89f5dd4c6bce8012dd74107 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 16 Jul 2024 15:43:48 +0200 Subject: [PATCH 0949/1301] Fix UB in the ps2d vmmouse implementation The vm call will clobber edi, which is the register in which we saved the ebx value. Also make sure to preserve the entire rbx value, rather than just the lower half in ebx. --- ps2d/src/vm.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index 5d691cee86..c6c818e9f3 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -35,13 +35,27 @@ pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32) { // ebx can't be used as input or output constraint in rust as LLVM reserves it. // Use xchg to pass it through r9 instead while restoring the original value in - // rbx when leaving the inline asm block. + // rbx when leaving the inline asm block. si and di are clobbered too. + #[cfg(not(target_arch = "x86"))] asm!( - "xchg edi, ebx; in eax, dx; xchg edi, ebx", + "xchg r9, rbx; in eax, dx; xchg r9, rbx", inout("eax") MAGIC => a, - inout("edi") arg => b, + inout("r9") arg => b, inout("ecx") cmd => c, inout("edx") PORT as u32 => d, + out("rsi") _, + out("rdi") _, + ); + + // On x86 we don't have a spare register, so push ebx to the stack instead. + #[cfg(target_arch = "x86")] + asm!( + "push ebx; mov ebx, esi; in eax, dx; mov esi, ebx; pop ebx", + inout("eax") MAGIC => a, + inout("esi") arg => b, + inout("ecx") cmd => c, + inout("edx") PORT as u32 => d, + out("edi") _, ); (a, b, c, d) From 5f1fdec858062c66738239042ae7acb9f841f899 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jul 2024 21:11:02 +0200 Subject: [PATCH 0950/1301] Remove inputd -G Ever since fbcond got moved out of vesad it has been doing the exact same as inputd -A. --- inputd/src/main.rs | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index f35f593c08..cb2ee9c021 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -481,52 +481,6 @@ pub fn main() { if let Some(val) = args.next() { match val.as_ref() { - // Sets the VT mode of the specified VT to [`VtMode::Graphic`]. - "-G" => { - let vt = args.next().unwrap().parse::().unwrap(); - - // On startup, the VESA display driver is started which basically makes use of the framebuffer - // provided by the firmware. The GPU devices are latter started by `pcid` (such as `virtio-gpu`). - let mut devices = vec![]; - let schemes = std::fs::read_dir(":").unwrap(); - - for entry in schemes { - let path = entry.unwrap().path(); - let path_str = path - .into_os_string() - .into_string() - .expect("inputd: failed to convert path to string"); - - if path_str.contains("display") { - println!("inputd: found display scheme {}", path_str); - devices.push(path_str); - } - } - - if devices.is_empty() { - // No display devices found. - return; - } - - let device = devices - .iter() - .filter(|d| !d.contains("vesa")) - .collect::>(); - let device = if device.is_empty() { - "vesa" - } else { - // TODO: What should we do when there are multiple display devices? - device[0][2..].split('.').nth(1).unwrap() - }; - - let mut handle = - inputd::Handle::new(device).expect("inputd: failed to open display handle"); - - handle - .activate(vt, VtMode::Graphic) - .expect("inputd: failed to activate VT in graphic mode"); - } - // Activates a VT. "-A" => { let vt = args.next().unwrap().parse::().unwrap(); From ebb2243538d81f8dca53817673888ed515d2a684 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jul 2024 21:18:09 +0200 Subject: [PATCH 0951/1301] Remove all traces of VtMode It isn't used anywhere anymore. --- graphics/fbcond/src/main.rs | 5 +---- graphics/vesad/src/main.rs | 2 +- graphics/vesad/src/scheme.rs | 2 +- graphics/virtio-gpud/src/scheme.rs | 5 ++--- inputd/src/lib.rs | 22 +++++----------------- inputd/src/main.rs | 24 ++++++------------------ 6 files changed, 16 insertions(+), 44 deletions(-) diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 4db9e1b5fc..4393c9185c 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -57,10 +57,7 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { daemon.ready().expect("failed to notify parent"); - scheme - .inputd_handle - .activate(1, inputd::VtMode::Default) - .unwrap(); + scheme.inputd_handle.activate(1).unwrap(); let mut blocked = Vec::new(); diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 2b6fd953c4..3bdf8bb14f 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -92,7 +92,7 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( daemon.ready().expect("failed to notify parent"); - scheme.inputd_handle.activate(1, inputd::VtMode::Default).unwrap(); + scheme.inputd_handle.activate(1).unwrap(); let mut blocked = Vec::new(); loop { diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 4b94801b16..0ca9bc6c40 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -279,7 +279,7 @@ impl SchemeMut for DisplayScheme { let command = inputd::parse_command(buf).unwrap(); match command { - DisplayCommand::Activate { vt, mode: _ } => { + DisplayCommand::Activate { vt } => { let vt_i = VtIndex(vt); if let Some(screens) = self.vts.get_mut(&vt_i) { diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 4782dfca59..045602185d 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -409,13 +409,12 @@ impl<'a> SchemeMut for Scheme<'a> { } Handle::Input => { - use inputd::{Cmd as DisplayCommand, VtMode}; + use inputd::Cmd as DisplayCommand; let command = inputd::parse_command(buf).unwrap(); match command { - DisplayCommand::Activate { mode, vt } => { - assert!(mode == VtMode::Graphic || mode == VtMode::Default); + DisplayCommand::Activate { vt } => { let target_vt = vt; for handle in self.handles.values() { diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 1747e02106..6c55e96949 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -7,18 +7,10 @@ unsafe fn any_as_u8_slice(p: &T) -> &[u8] { ::core::slice::from_raw_parts((p as *const T) as *const u8, ::core::mem::size_of::()) } -#[derive(Debug, Copy, Clone, PartialEq)] -#[repr(usize)] -pub enum VtMode { - Graphic = 1, - Default = 2, -} - #[derive(Debug, Clone)] #[repr(C)] pub struct VtActivate { pub vt: usize, - pub mode: VtMode, } pub struct Handle(File); @@ -35,8 +27,8 @@ impl Handle { self.0.read(&mut []) } - pub fn activate(&mut self, vt: usize, mode: VtMode) -> Result { - let cmd = VtActivate { vt, mode }; + pub fn activate(&mut self, vt: usize) -> Result { + let cmd = VtActivate { vt }; self.0.write(unsafe { any_as_u8_slice(&cmd) }) } } @@ -67,7 +59,6 @@ pub enum Cmd { // TODO(andypython): #VT should really need to be a `u8`. Activate { vt: usize, - mode: VtMode, }, Deactivate(usize /* #VT */), @@ -98,8 +89,8 @@ pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), libredox::error: result.push(command.ty() as u8); match command { - Cmd::Activate { vt, mode } => { - let cmd = VtActivate { vt, mode }; + Cmd::Activate { vt } => { + let cmd = VtActivate { vt }; let bytes = unsafe { any_as_u8_slice(&cmd) }; result.extend_from_slice(bytes); @@ -138,10 +129,7 @@ pub fn parse_command(buffer: &[u8]) -> Option { match command { CmdTy::Activate => { let cmd = unsafe { &*buffer.as_ptr().offset(1).cast::() }; - Some(Cmd::Activate { - vt: cmd.vt, - mode: cmd.mode, - }) + Some(Cmd::Activate { vt: cmd.vt }) } CmdTy::Deactivate => Some(Cmd::Deactivate(vt)), diff --git a/inputd/src/main.rs b/inputd/src/main.rs index cb2ee9c021..db4ac50e83 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -18,7 +18,7 @@ use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -use inputd::{Cmd, VtActivate, VtMode}; +use inputd::{Cmd, VtActivate}; use spin::Mutex; @@ -50,7 +50,6 @@ impl Handle { /// requires the system call to return first. Otherwise, it will block indefinitely. struct VtInner { handle_file: File, - mode: VtMode, } struct Vt { @@ -74,10 +73,7 @@ impl Vt { pub fn inner(&self) -> &Mutex { self.inner.call_once(|| { let handle_file = File::open(format!("/scheme/{}/handle", self.display)).unwrap(); - Mutex::new(VtInner { - handle_file, - mode: VtMode::Default, - }) + Mutex::new(VtInner { handle_file }) }) } } @@ -292,7 +288,6 @@ impl SchemeMut for InputScheme { &mut vt_inner.handle_file, Cmd::Activate { vt: new_active.index, - mode: VtMode::Default, }, )?; self.active_vt = Some(new_active.clone()); @@ -379,17 +374,12 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut vt_inner = vt.inner().lock(); // Failing to activate a VT is not a fatal error. - if let Err(err) = inputd::send_comand( - &mut vt_inner.handle_file, - Cmd::Activate { - vt: vt.index, - mode: cmd.mode, - }, - ) { + if let Err(err) = + inputd::send_comand(&mut vt_inner.handle_file, Cmd::Activate { vt: vt.index }) + { log::error!("inputd: failed to activate VT #{}: {err}", vt.index) } - vt_inner.mode = cmd.mode; scheme.active_vt = Some(vt.clone()); } @@ -509,9 +499,7 @@ pub fn main() { let mut handle = inputd::Handle::new(display_scheme) .expect("inputd: failed to open display handle"); - handle - .activate(vt, VtMode::Default) - .expect("inputd: failed to activate VT"); + handle.activate(vt).expect("inputd: failed to activate VT"); } _ => panic!("inputd: invalid argument: {}", val), From 747898dfb278e168d8fe60cde2d19a44f27dac96 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jul 2024 21:24:48 +0200 Subject: [PATCH 0952/1301] Run rustfmt on the entire graphics subsystem --- graphics/bgad/src/scheme.rs | 15 +-- graphics/fbcond/src/display.rs | 17 ++-- graphics/fbcond/src/scheme.rs | 12 ++- graphics/vesad/src/framebuffer.rs | 15 ++- graphics/vesad/src/main.rs | 92 +++++++++-------- graphics/vesad/src/scheme.rs | 156 +++++++++++++++++------------ graphics/vesad/src/screen.rs | 43 ++++---- graphics/virtio-gpud/src/main.rs | 4 +- graphics/virtio-gpud/src/scheme.rs | 28 ++++-- 9 files changed, 225 insertions(+), 157 deletions(-) diff --git a/graphics/bgad/src/scheme.rs b/graphics/bgad/src/scheme.rs index 3ae8c48e9d..1a1315df0e 100644 --- a/graphics/bgad/src/scheme.rs +++ b/graphics/bgad/src/scheme.rs @@ -1,8 +1,8 @@ use std::fs::File; use std::io::Write; use std::str; -use syscall::{Error, Result, SchemeMut, EACCES, EINVAL, MODE_CHR}; use syscall::data::Stat; +use syscall::{Error, Result, SchemeMut, EACCES, EINVAL, MODE_CHR}; use crate::bga::Bga; @@ -14,10 +14,13 @@ pub struct BgaScheme { impl BgaScheme { pub fn update_size(&mut self) { if let Some(ref mut display) = self.display { - let _ = display.write(&orbclient::ResizeEvent { - width: self.bga.width() as u32, - height: self.bga.height() as u32, - }.to_event()); + let _ = display.write( + &orbclient::ResizeEvent { + width: self.bga.width() as u32, + height: self.bga.height() as u32, + } + .to_event(), + ); } } } @@ -32,7 +35,7 @@ impl SchemeMut for BgaScheme { } fn dup(&mut self, file: usize, buf: &[u8]) -> Result { - if ! buf.is_empty() { + if !buf.is_empty() { return Err(Error::new(EINVAL)); } diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 4a7e005ce2..4efedf8263 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,3 +1,4 @@ +use libredox::flag; use std::fs::OpenOptions; use std::mem; use std::os::unix::fs::OpenOptionsExt; @@ -8,7 +9,6 @@ use std::{ os::unix::io::{AsRawFd, FromRawFd}, slice, }; -use libredox::flag; use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; // Keep synced with vesad @@ -67,15 +67,16 @@ impl Display { let display_path = std::str::from_utf8(&buffer[..written]).expect("init: display path UTF-8 check failed"); - let display_file = libredox::call::open(display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) - .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) - .unwrap_or_else(|err| { - panic!("failed to open display {}: {}", display_path, err); - }); + let display_file = + libredox::call::open(display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) + .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) + .unwrap_or_else(|err| { + panic!("failed to open display {}: {}", display_path, err); + }); let mut buf: [u8; 4096] = [0; 4096]; - let count = - libredox::call::fpath(display_file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| { + let count = libredox::call::fpath(display_file.as_raw_fd() as usize, &mut buf) + .unwrap_or_else(|e| { panic!("Could not read display path with fpath(): {e}"); }); diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index a64a62cade..bd128f2e5a 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -47,11 +47,13 @@ impl FbconScheme { for &vt_i in vt_ids { let display = Display::open_vt(vt_i).expect("Failed to open display for vt"); - event_queue.subscribe( - display.input_handle.as_raw_fd().as_raw_fd() as usize, - VtIndex(vt_i), - event::EventFlags::READ, - ).expect("Failed to subscribe to input events for vt"); + event_queue + .subscribe( + display.input_handle.as_raw_fd().as_raw_fd() as usize, + VtIndex(vt_i), + event::EventFlags::READ, + ) + .expect("Failed to subscribe to input events for vt"); vts.insert(VtIndex(vt_i), TextScreen::new(display)); } diff --git a/graphics/vesad/src/framebuffer.rs b/graphics/vesad/src/framebuffer.rs index 28d30907ad..a3ca0ba769 100644 --- a/graphics/vesad/src/framebuffer.rs +++ b/graphics/vesad/src/framebuffer.rs @@ -1,7 +1,4 @@ -use std::{ - ptr, - slice -}; +use std::{ptr, slice}; pub struct FrameBuffer { pub phys: usize, @@ -49,15 +46,15 @@ impl FrameBuffer { let virt = common::physmap( self.phys, size * 4, - common::Prot { read: true, write: true }, + common::Prot { + read: true, + write: true, + }, common::MemoryType::WriteCombining, )? as *mut u32; //TODO: should we clear the framebuffer here? ptr::write_bytes(virt, 0, size); - Ok(slice::from_raw_parts_mut( - virt, - size - )) + Ok(slice::from_raw_parts_mut(virt, size)) } } diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 3bdf8bb14f..54e257ebd5 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -9,7 +9,7 @@ use syscall::{Packet, SchemeMut, EVENT_READ}; use crate::{ framebuffer::FrameBuffer, - scheme::{DisplayScheme, HandleKind} + scheme::{DisplayScheme, HandleKind}, }; mod display; @@ -25,38 +25,36 @@ fn main() { } let width = usize::from_str_radix( - &env::var("FRAMEBUFFER_WIDTH") - .expect("FRAMEBUFFER_WIDTH not set"), - 16 - ).expect("failed to parse FRAMEBUFFER_WIDTH"); + &env::var("FRAMEBUFFER_WIDTH").expect("FRAMEBUFFER_WIDTH not set"), + 16, + ) + .expect("failed to parse FRAMEBUFFER_WIDTH"); let height = usize::from_str_radix( - &env::var("FRAMEBUFFER_HEIGHT") - .expect("FRAMEBUFFER_HEIGHT not set"), - 16 - ).expect("failed to parse FRAMEBUFFER_HEIGHT"); + &env::var("FRAMEBUFFER_HEIGHT").expect("FRAMEBUFFER_HEIGHT not set"), + 16, + ) + .expect("failed to parse FRAMEBUFFER_HEIGHT"); let phys = usize::from_str_radix( - &env::var("FRAMEBUFFER_ADDR") - .expect("FRAMEBUFFER_ADDR not set"), - 16 - ).expect("failed to parse FRAMEBUFFER_ADDR"); + &env::var("FRAMEBUFFER_ADDR").expect("FRAMEBUFFER_ADDR not set"), + 16, + ) + .expect("failed to parse FRAMEBUFFER_ADDR"); let stride = usize::from_str_radix( - &env::var("FRAMEBUFFER_STRIDE") - .expect("FRAMEBUFFER_STRIDE not set"), - 16 - ).expect("failed to parse FRAMEBUFFER_STRIDE"); + &env::var("FRAMEBUFFER_STRIDE").expect("FRAMEBUFFER_STRIDE not set"), + 16, + ) + .expect("failed to parse FRAMEBUFFER_STRIDE"); - println!("vesad: {}x{} stride {} at 0x{:X}", width, height, stride, phys); + println!( + "vesad: {}x{} stride {} at 0x{:X}", + width, height, stride, phys + ); if phys == 0 { return; } - let mut framebuffers = vec![FrameBuffer::new( - phys, - width, - height, - stride, - )]; + let mut framebuffers = vec![FrameBuffer::new(phys, width, height, stride)]; //TODO: ideal maximum number of outputs? for i in 1..1024 { @@ -65,23 +63,20 @@ fn main() { Some(fb) => { println!( "vesad: framebuffer {}: {}x{} stride {} at 0x{:X}", - i, - fb.width, - fb.height, - fb.stride, - fb.phys + i, fb.width, fb.height, fb.stride, fb.phys ); framebuffers.push(fb); - }, + } None => { eprintln!("vesad: framebuffer {}: failed to parse '{}'", i, var); - }, + } }, Err(_err) => break, }; } - redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers, &spec)).expect("failed to create daemon"); + redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers, &spec)) + .expect("failed to create daemon"); } fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[()]) -> ! { let mut socket = File::create(":display.vesa").expect("vesad: failed to create display scheme"); @@ -97,17 +92,26 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( let mut blocked = Vec::new(); loop { let mut packet = Packet::default(); - if socket.read(&mut packet).expect("vesad: failed to read display scheme") == 0 { + if socket + .read(&mut packet) + .expect("vesad: failed to read display scheme") + == 0 + { //TODO: Handle blocked break; } // If it is a read packet, and there is no data, block it. Otherwise, handle packet - if packet.a == syscall::number::SYS_READ && packet.d > 0 && scheme.can_read(packet.b).is_none() { + if packet.a == syscall::number::SYS_READ + && packet.d > 0 + && scheme.can_read(packet.b).is_none() + { blocked.push(packet); } else { scheme.handle(&mut packet); - socket.write(&packet).expect("vesad: failed to write display scheme"); + socket + .write(&packet) + .expect("vesad: failed to write display scheme"); } // If there are blocked readers, and data is available, handle them @@ -117,7 +121,9 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( if scheme.can_read(blocked[i].b).is_some() { let mut packet = blocked.remove(i); scheme.handle(&mut packet); - socket.write(&packet).expect("vesad: failed to write display scheme"); + socket + .write(&packet) + .expect("vesad: failed to write display scheme"); } else { i += 1; } @@ -132,11 +138,15 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( // Can't use scheme.can_read() because we borrow handles as mutable. // (and because it'd treat O_NONBLOCK sockets differently) let count = if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - scheme.vts.get(&vt_i) + scheme + .vts + .get(&vt_i) .and_then(|screens| screens.get(&screen_i)) .and_then(|screen| screen.can_read()) .unwrap_or(0) - } else { 0 }; + } else { + 0 + }; if count > 0 { if !handle.notified_read { @@ -149,10 +159,12 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( a: syscall::number::SYS_FEVENT, b: *handle_id, c: EVENT_READ.bits(), - d: count + d: count, }; - socket.write(&event_packet).expect("vesad: failed to write display event"); + socket + .write(&event_packet) + .expect("vesad: failed to write display event"); } } else { handle.notified_read = false; diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 0ca9bc6c40..1db03b05f9 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -1,7 +1,9 @@ use std::collections::BTreeMap; use std::{mem, ptr, slice, str}; -use syscall::{Error, EventFlags, EBADF, EINVAL, ENOENT, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE, MapFlags}; +use syscall::{ + Error, EventFlags, MapFlags, Result, SchemeMut, EBADF, EINVAL, ENOENT, O_NONBLOCK, PAGE_SIZE, +}; use crate::{framebuffer::FrameBuffer, screen::GraphicScreen}; @@ -22,7 +24,7 @@ pub struct Handle { pub kind: HandleKind, pub flags: usize, pub events: EventFlags, - pub notified_read: bool + pub notified_read: bool, } pub struct DisplayScheme { @@ -33,18 +35,15 @@ pub struct DisplayScheme { next_id: usize, pub handles: BTreeMap, pub inputd_handle: inputd::Handle, - } impl DisplayScheme { pub fn new(mut framebuffers: Vec, spec: &[()]) -> DisplayScheme { - let mut inputd_handle = inputd::Handle::new("vesa").unwrap(); + let mut inputd_handle = inputd::Handle::new("vesa").unwrap(); let mut onscreens = Vec::new(); for fb in framebuffers.iter_mut() { - onscreens.push(unsafe { - fb.map().expect("vesad: failed to map framebuffer") - }); + onscreens.push(unsafe { fb.map().expect("vesad: failed to map framebuffer") }); } let mut vts = BTreeMap::>::new(); @@ -74,11 +73,13 @@ impl DisplayScheme { if let HandleKind::Screen(vt_i, screen_i) = handle.kind { if let Some(screens) = self.vts.get(&vt_i) { if let Some(screen) = screens.get(&screen_i) { - screen.can_read().or(if handle.flags & O_NONBLOCK == O_NONBLOCK { - Some(0) - } else { - None - }); + screen + .can_read() + .or(if handle.flags & O_NONBLOCK == O_NONBLOCK { + Some(0) + } else { + None + }); } } } @@ -90,12 +91,19 @@ impl DisplayScheme { fn resize(&mut self, width: usize, height: usize, stride: usize) { //TODO: support resizing other outputs? let fb_i = 0; - println!("Resizing framebuffer {} to {}, {} stride {}", fb_i, width, height, stride); + println!( + "Resizing framebuffer {} to {}, {} stride {}", + fb_i, width, height, stride + ); // Unmap old onscreen unsafe { let slice = mem::take(&mut self.onscreens[fb_i]); - libredox::call::munmap(slice.as_mut_ptr().cast(), (slice.len() * 4).next_multiple_of(PAGE_SIZE)).expect("vesad: failed to unmap framebuffer"); + libredox::call::munmap( + slice.as_mut_ptr().cast(), + (slice.len() * 4).next_multiple_of(PAGE_SIZE), + ) + .expect("vesad: failed to unmap framebuffer"); } // Map new onscreen @@ -104,15 +112,16 @@ impl DisplayScheme { let onscreen_ptr = common::physmap( self.framebuffers[fb_i].phys, size * 4, - common::Prot { read: true, write: true }, + common::Prot { + read: true, + write: true, + }, common::MemoryType::WriteCombining, - ).expect("vesad: failed to map framebuffer") as *mut u32; + ) + .expect("vesad: failed to map framebuffer") as *mut u32; ptr::write_bytes(onscreen_ptr, 0, size); - slice::from_raw_parts_mut( - onscreen_ptr, - size - ) + slice::from_raw_parts_mut(onscreen_ptr, size) }; // Update size @@ -139,34 +148,36 @@ impl SchemeMut for DisplayScheme { if path_str == "handle" { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle { - kind: HandleKind::Input, - flags, - events: EventFlags::empty(), - notified_read: false - }); + self.handles.insert( + id, + Handle { + kind: HandleKind::Input, + flags, + events: EventFlags::empty(), + notified_read: false, + }, + ); return Ok(id); } let mut parts = path_str.split('/'); let mut vt_screen = parts.next().unwrap_or("").split('.'); - let vt_i = VtIndex( - vt_screen.next().unwrap_or("").parse::().unwrap_or(1) - ); - let screen_i = ScreenIndex( - vt_screen.next().unwrap_or("").parse::().unwrap_or(0) - ); + let vt_i = VtIndex(vt_screen.next().unwrap_or("").parse::().unwrap_or(1)); + let screen_i = ScreenIndex(vt_screen.next().unwrap_or("").parse::().unwrap_or(0)); if let Some(screens) = self.vts.get_mut(&vt_i) { if screens.get_mut(&screen_i).is_some() { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle { - kind: HandleKind::Screen(vt_i, screen_i), - flags, - events: EventFlags::empty(), - notified_read: false - }); + self.handles.insert( + id, + Handle { + kind: HandleKind::Screen(vt_i, screen_i), + flags, + events: EventFlags::empty(), + notified_read: false, + }, + ); Ok(id) } else { @@ -182,7 +193,11 @@ impl SchemeMut for DisplayScheme { return Err(Error::new(EINVAL)); } - let handle = self.handles.get(&id).map(|handle| handle.clone()).ok_or(Error::new(EBADF))?; + let handle = self + .handles + .get(&id) + .map(|handle| handle.clone()) + .ok_or(Error::new(EBADF))?; let new_id = self.next_id; self.next_id += 1; @@ -211,16 +226,24 @@ impl SchemeMut for DisplayScheme { let path_str = match handle.kind { HandleKind::Input => { //TODO: allow inputs associated with other framebuffers? - format!("display:input/{}/{}", self.framebuffers[0].width, self.framebuffers[0].height) - }, - HandleKind::Screen(vt_i, screen_i) => if let Some(screens) = self.vts.get(&vt_i) { - if let Some(screen) = screens.get(&screen_i) { - format!("display:{}.{}/{}/{}", vt_i.0, screen_i.0, screen.width, screen.height) + format!( + "display:input/{}/{}", + self.framebuffers[0].width, self.framebuffers[0].height + ) + } + HandleKind::Screen(vt_i, screen_i) => { + if let Some(screens) = self.vts.get(&vt_i) { + if let Some(screen) = screens.get(&screen_i) { + format!( + "display:{}.{}/{}/{}", + vt_i.0, screen_i.0, screen.width, screen.height + ) + } else { + return Err(Error::new(EBADF)); + } } else { return Err(Error::new(EBADF)); } - } else { - return Err(Error::new(EBADF)); } }; @@ -244,7 +267,7 @@ impl SchemeMut for DisplayScheme { if vt_i == self.active { screen.sync( self.onscreens[screen_i.0], - self.framebuffers[screen_i.0].stride + self.framebuffers[screen_i.0].stride, ); } return Ok(0); @@ -286,40 +309,47 @@ impl SchemeMut for DisplayScheme { for (screen_i, screen) in screens.iter_mut() { screen.redraw( self.onscreens[screen_i.0], - self.framebuffers[screen_i.0].stride + self.framebuffers[screen_i.0].stride, ); } } self.active = vt_i; - }, + } - DisplayCommand::Resize { width, height, stride, .. } => { + DisplayCommand::Resize { + width, + height, + stride, + .. + } => { self.resize(width as usize, height as usize, stride as usize); } // Nothing to do for deactivate :) - DisplayCommand::Deactivate(_) => {}, + DisplayCommand::Deactivate(_) => {} } Ok(buf.len()) - }, + } - HandleKind::Screen(vt_i, screen_i) => if let Some(screens) = self.vts.get_mut(&vt_i) { - if let Some(screen) = screens.get_mut(&screen_i) { - let count = screen.write(buf)?; - if vt_i == self.active { - screen.sync( - self.onscreens[screen_i.0], - self.framebuffers[screen_i.0].stride - ); + HandleKind::Screen(vt_i, screen_i) => { + if let Some(screens) = self.vts.get_mut(&vt_i) { + if let Some(screen) = screens.get_mut(&screen_i) { + let count = screen.write(buf)?; + if vt_i == self.active { + screen.sync( + self.onscreens[screen_i.0], + self.framebuffers[screen_i.0].stride, + ); + } + Ok(count) + } else { + Err(Error::new(EBADF)) } - Ok(count) } else { Err(Error::new(EBADF)) } - } else { - Err(Error::new(EBADF)) } } } diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index 680c2bce9c..636fdfec42 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -1,6 +1,6 @@ use std::collections::VecDeque; use std::convert::TryInto; -use std::{mem, slice, cmp, ptr}; +use std::{cmp, mem, ptr, slice}; use orbclient::{Event, ResizeEvent}; use syscall::error::*; @@ -55,13 +55,13 @@ impl GraphicScreen { ptr::copy( old_ptr as *const u8, new_ptr as *mut u8, - cmp::min(width, self.width) * 4 + cmp::min(width, self.width) * 4, ); if width > self.width { ptr::write_bytes( new_ptr.offset(self.width as isize), 0, - width - self.width + width - self.width, ); } old_ptr = old_ptr.offset(self.width as isize); @@ -86,18 +86,26 @@ impl GraphicScreen { println!("Display is already {}, {}", width, height); }; - self.input.push_back(ResizeEvent { - width: width as u32, - height: height as u32, - }.to_event()); + self.input.push_back( + ResizeEvent { + width: width as u32, + height: height as u32, + } + .to_event(), + ); } pub fn read(&mut self, buf: &mut [u8]) -> Result { let mut i = 0; - let event_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Event, buf.len()/mem::size_of::()) }; + let event_buf = unsafe { + slice::from_raw_parts_mut( + buf.as_mut_ptr() as *mut Event, + buf.len() / mem::size_of::(), + ) + }; - while i < event_buf.len() && ! self.input.is_empty() { + while i < event_buf.len() && !self.input.is_empty() { event_buf[i] = self.input.pop_front().unwrap(); i += 1; } @@ -117,7 +125,7 @@ impl GraphicScreen { let sync_rects = unsafe { slice::from_raw_parts( buf.as_ptr() as *const SyncRect, - buf.len() / mem::size_of::() + buf.len() / mem::size_of::(), ) }; @@ -148,23 +156,24 @@ impl GraphicScreen { let mut rows = end_y - start_y; while rows > 0 { unsafe { - ptr::copy( - offscreen_ptr as *const u8, - onscreen_ptr as *mut u8, - len - ); + ptr::copy(offscreen_ptr as *const u8, onscreen_ptr as *mut u8, len); } offscreen_ptr += self.width * 4; onscreen_ptr += stride * 4; rows -= 1; - }; + } } } pub fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { let width = self.width.try_into().unwrap(); let height = self.height.try_into().unwrap(); - self.sync_rects.push(SyncRect { x: 0, y: 0, w: width, h: height }); + self.sync_rects.push(SyncRect { + x: 0, + y: 0, + w: width, + h: height, + }); self.sync(onscreen, stride); } } diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 938ec8c817..ebe9e8e0ed 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -453,7 +453,9 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { socket_file .read(&mut packet) .expect("virtio-gpud: failed to read disk scheme"); - unsafe { scheme.handle(&mut packet); } + unsafe { + scheme.handle(&mut packet); + } socket_file .write(&packet) .expect("virtio-gpud: failed to read disk scheme"); diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 045602185d..73bb2aab5f 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -4,8 +4,8 @@ use std::collections::BTreeMap; use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; use std::sync::Arc; -use inputd::Damage; use common::{dma::Dma, sgl}; +use inputd::Damage; use syscall::{Error as SysError, MapFlags, SchemeMut, EAGAIN, EINVAL, PAGE_SIZE}; @@ -117,7 +117,8 @@ impl<'a> Display<'a> { let fb_size = self.width as usize * self.height as usize * bpp / 8; let mapped = self.mapped.get().unwrap(); - self.map_screen_with(0, fb_size, mapped.as_ptr(), mapped.chunks()).await + self.map_screen_with(0, fb_size, mapped.as_ptr(), mapped.chunks()) + .await } async fn map_screen(&self, offset: usize) -> Result<*mut u8, Error> { @@ -135,7 +136,8 @@ impl<'a> Display<'a> { let _ = self.mapped.set(mapped); let mapped = self.mapped.get().unwrap(); - self.map_screen_with(offset, fb_size, mapped.as_ptr(), mapped.chunks()).await + self.map_screen_with(offset, fb_size, mapped.as_ptr(), mapped.chunks()) + .await } async fn map_screen_with( @@ -167,7 +169,10 @@ impl<'a> Display<'a> { }; } - let attach_request = Dma::new(AttachBacking::new(self.resource_id, mem_entries.len() as u32))?; + let attach_request = Dma::new(AttachBacking::new( + self.resource_id, + mem_entries.len() as u32, + ))?; let header = Dma::new(ControlHeader::default())?; let command = ChainBuilder::new() .chain(Buffer::new(&attach_request)) @@ -462,12 +467,19 @@ impl<'a> SchemeMut for Scheme<'a> { fn close(&mut self, _id: usize) -> syscall::Result { Ok(0) } - fn mmap_prep(&mut self, id: usize, offset: u64, size: usize, flags: MapFlags) -> syscall::Result { + fn mmap_prep( + &mut self, + id: usize, + offset: u64, + size: usize, + flags: MapFlags, + ) -> syscall::Result { log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { - Handle::Vt { display, .. } => { - Ok(futures::executor::block_on(display.map_screen(offset as usize)).unwrap() as usize) - } + Handle::Vt { display, .. } => Ok(futures::executor::block_on( + display.map_screen(offset as usize), + ) + .unwrap() as usize), _ => unreachable!(), } } From 8a91bae0a69ebf9df8d85876277c315a551a9e1e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jul 2024 21:25:52 +0200 Subject: [PATCH 0953/1301] Remove unnecessary unsafe block --- graphics/virtio-gpud/src/main.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index ebe9e8e0ed..da7deaa3a5 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -453,9 +453,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { socket_file .read(&mut packet) .expect("virtio-gpud: failed to read disk scheme"); - unsafe { - scheme.handle(&mut packet); - } + scheme.handle(&mut packet); socket_file .write(&packet) .expect("virtio-gpud: failed to read disk scheme"); From 1a41bcab14352e67042a03c1a3c57058542a8bfd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jul 2024 21:39:58 +0200 Subject: [PATCH 0954/1301] Enforce formatting in CI --- .gitlab-ci.yml | 19 ++++++++++++++ fmt.sh | 20 ++++++++++----- virtio-core/src/lib.rs | 5 ++-- virtio-core/src/transport.rs | 49 +++++++++++++++++++++++++++--------- 4 files changed, 72 insertions(+), 21 deletions(-) create mode 100644 .gitlab-ci.yml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000..047fd555bf --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,19 @@ +image: "redoxos/redoxer:latest" + +stages: + - build + + # TODO? + # - test + +# TODO check if all drivers build + +fmt: + stage: build + needs: [] + script: + - rustup component add rustfmt-preview + # TODO add more packages as they get formatted + - CHECK_ONLY=1 ./fmt.sh + +# TODO: unit tests diff --git a/fmt.sh b/fmt.sh index c9f29df18f..e867ac215f 100755 --- a/fmt.sh +++ b/fmt.sh @@ -1,17 +1,25 @@ #!/usr/bin/bash +set -eo pipefail + function fmt() { for dir in "$@" do pushd $dir printf "\e[1;32mFormatting\e[0m $dir\n" - cargo fmt + if [[ "$CHECK_ONLY" -eq "1" ]]; then + cargo fmt --check + else + cargo fmt + fi popd done } -fmt virtio-core \ - virtio-netd \ - virtio-blkd \ - virtio-gpud \ - inputd +fmt graphics/bgad \ + graphics/fbcond \ + graphics/vesad \ + graphics/virtio-gpud \ + inputd \ + net/virtio-netd \ + virtio-core diff --git a/virtio-core/src/lib.rs b/virtio-core/src/lib.rs index 817caaf913..6c2808d680 100644 --- a/virtio-core/src/lib.rs +++ b/virtio-core/src/lib.rs @@ -7,12 +7,11 @@ pub mod utils; mod probe; #[cfg(target_arch = "aarch64")] -#[path="arch/aarch64.rs"] +#[path = "arch/aarch64.rs"] mod arch; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -#[path="arch/x86.rs"] +#[path = "arch/x86.rs"] mod arch; - pub use probe::{probe_device, reinit, Device, MSIX_PRIMARY_VECTOR}; diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index c679dd8699..f7379abe43 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -69,7 +69,9 @@ pub fn spawn_irq_thread(irq_handle: &File, queue: &Arc>) { std::thread::spawn(move || { let mut event_queue = RawEventQueue::new().unwrap(); - event_queue.subscribe(irq_fd as usize, 0, event::EventFlags::READ).unwrap(); + event_queue + .subscribe(irq_fd as usize, 0, event::EventFlags::READ) + .unwrap(); for event in event_queue.map(Result::unwrap) { // Wake up the tasks waiting on the queue. @@ -275,13 +277,23 @@ impl<'a> Mem<'a> { pub fn as_ptr(&self) -> *const T { match *self { Self::Owned(ref dma) => dma.as_ptr().cast(), - Self::Borrowed(Borrowed { phys, virt, size, _unused }) => virt as *const T, + Self::Borrowed(Borrowed { + phys, + virt, + size, + _unused, + }) => virt as *const T, } } pub fn as_mut_ptr(&mut self) -> *mut T { match *self { Self::Owned(ref mut dma) => dma.as_mut_ptr().cast(), - Self::Borrowed(Borrowed { phys, virt, size, _unused }) => virt as *mut T, + Self::Borrowed(Borrowed { + phys, + virt, + size, + _unused, + }) => virt as *mut T, } } pub fn physical(&self) -> usize { @@ -301,17 +313,18 @@ impl<'a> Available<'a> { } pub fn new(queue_size: usize) -> Result { let (_, _, size) = queue_part_sizes(queue_size); - let mem = unsafe { Dma::zeroed_slice(size).map_err(Error::SyscallError)?.assume_init() }; + let mem = unsafe { + Dma::zeroed_slice(size) + .map_err(Error::SyscallError)? + .assume_init() + }; unsafe { Self::from_raw(Mem::Owned(mem), queue_size) } } /// `addr` is the physical address of the ring. pub unsafe fn from_raw(mem: Mem<'a>, queue_size: usize) -> Result { - let ring = Self { - mem, - queue_size, - }; + let ring = Self { mem, queue_size }; for i in 0..queue_size { // Setting them to `u16::MAX` helps with debugging since qemu reports them @@ -353,7 +366,10 @@ impl<'a> Available<'a> { impl<'a> Drop for Available<'a> { fn drop(&mut self) { - log::warn!("virtio-core: dropping 'available' ring at {:#x}", self.phys_addr()); + log::warn!( + "virtio-core: dropping 'available' ring at {:#x}", + self.phys_addr() + ); } } @@ -373,7 +389,11 @@ impl<'a> Used<'a> { pub fn new(queue_size: usize) -> Result { let (_, _, size) = queue_part_sizes(queue_size); - let mem = unsafe { Dma::zeroed_slice(size).map_err(Error::SyscallError)?.assume_init() }; + let mem = unsafe { + Dma::zeroed_slice(size) + .map_err(Error::SyscallError)? + .assume_init() + }; unsafe { Self::from_raw(Mem::Owned(mem), queue_size) } } @@ -439,7 +459,10 @@ impl<'a> Used<'a> { impl Drop for Used<'_> { fn drop(&mut self) { - log::warn!("virtio-core: dropping 'used' ring at {:#x}", self.phys_addr()); + log::warn!( + "virtio-core: dropping 'used' ring at {:#x}", + self.phys_addr() + ); } } @@ -597,7 +620,9 @@ impl Transport for StandardTransport<'_> { // Allocate memory for the queue structues. let descriptor = unsafe { - Dma::<[Descriptor]>::zeroed_slice(queue_size).map_err(Error::SyscallError)?.assume_init() + Dma::<[Descriptor]>::zeroed_slice(queue_size) + .map_err(Error::SyscallError)? + .assume_init() }; let avail = Available::new(queue_size)?; From b33ea2b53a6111687cde0b2f93c3cbaf3a5200ef Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jul 2024 21:50:15 +0200 Subject: [PATCH 0955/1301] Fix a FIXME in display_fd_unmap The len method on raw pointers has been stabilized. --- graphics/fbcond/src/display.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 4efedf8263..96ea7a144a 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -36,9 +36,8 @@ fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Re } } -unsafe fn display_fd_unmap(image: *mut [u32], size: usize) { - // FIXME use image.len() instead of size once it is stable. - let _ = libredox::call::munmap(image as *mut (), size * 4); +unsafe fn display_fd_unmap(image: *mut [u32]) { + let _ = libredox::call::munmap(image as *mut (), image.len()); } pub struct Display { @@ -125,7 +124,7 @@ impl Display { match display_fd_map(width, height, self.display_file.as_raw_fd() as usize) { Ok(ok) => { unsafe { - display_fd_unmap(self.offscreen, (self.width * self.height) as usize); + display_fd_unmap(self.offscreen); } self.offscreen = ok; self.width = width; @@ -154,7 +153,7 @@ impl Display { impl Drop for Display { fn drop(&mut self) { unsafe { - display_fd_unmap(self.offscreen, self.width * self.height); + display_fd_unmap(self.offscreen); } } } From ef29520cf567d53c2b8cc1bc8336fa55c7406a99 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jul 2024 21:51:51 +0200 Subject: [PATCH 0956/1301] Avoid ptr2int2ptr casts in GraphicScreen::sync Also use pointer arithmetic on *mut u32 over manual multiplication by 4. The ptr2int2ptr casts pessimize optimizations. --- graphics/vesad/src/screen.rs | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index 636fdfec42..2369aafae8 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -52,11 +52,7 @@ impl GraphicScreen { for _y in 0..cmp::min(height, self.height) { unsafe { - ptr::copy( - old_ptr as *const u8, - new_ptr as *mut u8, - cmp::min(width, self.width) * 4, - ); + ptr::copy(old_ptr, new_ptr, cmp::min(width, self.width)); if width > self.width { ptr::write_bytes( new_ptr.offset(self.width as isize), @@ -145,22 +141,22 @@ impl GraphicScreen { let end_y = cmp::min(self.height, y + h); let start_x = cmp::min(self.width, x); - let len = (cmp::min(self.width, x + w) - start_x) * 4; + let row_pixel_count = cmp::min(self.width, x + w) - start_x; - let mut offscreen_ptr = self.offscreen.as_mut_ptr() as usize; - let mut onscreen_ptr = onscreen.as_mut_ptr() as usize; + let mut offscreen_ptr = self.offscreen.as_mut_ptr(); + let mut onscreen_ptr = onscreen.as_mut_ptr(); - offscreen_ptr += (y * self.width + start_x) * 4; - onscreen_ptr += (y * stride + start_x) * 4; + unsafe { + offscreen_ptr = offscreen_ptr.add(y * self.width + start_x); + onscreen_ptr = onscreen_ptr.add(y * stride + start_x); - let mut rows = end_y - start_y; - while rows > 0 { - unsafe { - ptr::copy(offscreen_ptr as *const u8, onscreen_ptr as *mut u8, len); + let mut rows = end_y - start_y; + while rows > 0 { + ptr::copy(offscreen_ptr, onscreen_ptr, row_pixel_count); + offscreen_ptr = offscreen_ptr.add(self.width); + onscreen_ptr = onscreen_ptr.add(stride); + rows -= 1; } - offscreen_ptr += self.width * 4; - onscreen_ptr += stride * 4; - rows -= 1; } } } From 857773393d7041a4fbd13ecaf0133f3d40bc03ab Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jul 2024 21:56:56 +0200 Subject: [PATCH 0957/1301] Ensure fields of SyncRect are not reordered Without repr(C), repr(packed) technically allows reordering fields. --- graphics/fbcond/src/display.rs | 2 +- graphics/vesad/src/screen.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 96ea7a144a..01f58ed2c8 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -13,7 +13,7 @@ use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; // Keep synced with vesad #[derive(Clone, Copy)] -#[repr(packed)] +#[repr(C, packed)] pub struct SyncRect { pub x: i32, pub y: i32, diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index 2369aafae8..d77c095c9b 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -9,7 +9,7 @@ use crate::display::OffscreenBuffer; // Keep synced with orbital #[derive(Clone, Copy)] -#[repr(packed)] +#[repr(C, packed)] pub struct SyncRect { pub x: i32, pub y: i32, From 53c02b5322a2531cbc8bca10043a81e7cdd20ce7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:12:48 +0200 Subject: [PATCH 0958/1301] Move the framebuffer resizing code into a FrameBuffer method --- graphics/vesad/src/framebuffer.rs | 69 +++++++++++++++++++++++-------- graphics/vesad/src/main.rs | 4 +- graphics/vesad/src/scheme.rs | 40 +++--------------- 3 files changed, 59 insertions(+), 54 deletions(-) diff --git a/graphics/vesad/src/framebuffer.rs b/graphics/vesad/src/framebuffer.rs index a3ca0ba769..5e1da0d04b 100644 --- a/graphics/vesad/src/framebuffer.rs +++ b/graphics/vesad/src/framebuffer.rs @@ -1,6 +1,9 @@ -use std::{ptr, slice}; +use std::ptr; + +use syscall::PAGE_SIZE; pub struct FrameBuffer { + pub onscreen: *mut [u32], pub phys: usize, pub width: usize, pub height: usize, @@ -8,8 +11,25 @@ pub struct FrameBuffer { } impl FrameBuffer { - pub fn new(phys: usize, width: usize, height: usize, stride: usize) -> Self { + pub unsafe fn new(phys: usize, width: usize, height: usize, stride: usize) -> Self { + let size = stride * height; + let virt = common::physmap( + phys, + size * 4, + common::Prot { + read: true, + write: true, + }, + common::MemoryType::WriteCombining, + ) + .expect("vesad: failed to map framebuffer") as *mut u32; + //TODO: should we clear the framebuffer here? + ptr::write_bytes(virt, 0, size); + + let onscreen = ptr::slice_from_raw_parts_mut(virt, size); + Self { + onscreen, phys, width, height, @@ -17,7 +37,7 @@ impl FrameBuffer { } } - pub fn parse(var: &str) -> Option { + pub unsafe fn parse(var: &str) -> Option { fn parse_number(part: &str) -> Option { let (start, radix) = if part.starts_with("0x") { (2, 16) @@ -41,20 +61,35 @@ impl FrameBuffer { Some(Self::new(phys, width, height, stride)) } - pub unsafe fn map(&mut self) -> syscall::Result<&'static mut [u32]> { - let size = self.stride * self.height; - let virt = common::physmap( - self.phys, - size * 4, - common::Prot { - read: true, - write: true, - }, - common::MemoryType::WriteCombining, - )? as *mut u32; - //TODO: should we clear the framebuffer here? - ptr::write_bytes(virt, 0, size); + pub unsafe fn resize(&mut self, width: usize, height: usize, stride: usize) { + // Unmap old onscreen + unsafe { + let slice = self.onscreen; + libredox::call::munmap(slice.cast(), (slice.len() * 4).next_multiple_of(PAGE_SIZE)) + .expect("vesad: failed to unmap framebuffer"); + } - Ok(slice::from_raw_parts_mut(virt, size)) + // Map new onscreen + self.onscreen = unsafe { + let size = stride * height; + let onscreen_ptr = common::physmap( + self.phys, + size * 4, + common::Prot { + read: true, + write: true, + }, + common::MemoryType::WriteCombining, + ) + .expect("vesad: failed to map framebuffer") as *mut u32; + ptr::write_bytes(onscreen_ptr, 0, size); + + ptr::slice_from_raw_parts_mut(onscreen_ptr, size) + }; + + // Update size + self.width = width; + self.height = height; + self.stride = stride; } } diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 54e257ebd5..bb2bcc6985 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -54,12 +54,12 @@ fn main() { return; } - let mut framebuffers = vec![FrameBuffer::new(phys, width, height, stride)]; + let mut framebuffers = vec![unsafe { FrameBuffer::new(phys, width, height, stride) }]; //TODO: ideal maximum number of outputs? for i in 1..1024 { match env::var(&format!("FRAMEBUFFER{}", i)) { - Ok(var) => match FrameBuffer::parse(&var) { + Ok(var) => match unsafe { FrameBuffer::parse(&var) } { Some(fb) => { println!( "vesad: framebuffer {}: {}x{} stride {} at 0x{:X}", diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 1db03b05f9..c5221f95c3 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -1,9 +1,7 @@ use std::collections::BTreeMap; -use std::{mem, ptr, slice, str}; +use std::str; -use syscall::{ - Error, EventFlags, MapFlags, Result, SchemeMut, EBADF, EINVAL, ENOENT, O_NONBLOCK, PAGE_SIZE, -}; +use syscall::{Error, EventFlags, MapFlags, Result, SchemeMut, EBADF, EINVAL, ENOENT, O_NONBLOCK}; use crate::{framebuffer::FrameBuffer, screen::GraphicScreen}; @@ -43,7 +41,7 @@ impl DisplayScheme { let mut onscreens = Vec::new(); for fb in framebuffers.iter_mut() { - onscreens.push(unsafe { fb.map().expect("vesad: failed to map framebuffer") }); + onscreens.push(unsafe { &mut *fb.onscreen }); } let mut vts = BTreeMap::>::new(); @@ -96,39 +94,11 @@ impl DisplayScheme { fb_i, width, height, stride ); - // Unmap old onscreen unsafe { - let slice = mem::take(&mut self.onscreens[fb_i]); - libredox::call::munmap( - slice.as_mut_ptr().cast(), - (slice.len() * 4).next_multiple_of(PAGE_SIZE), - ) - .expect("vesad: failed to unmap framebuffer"); + self.framebuffers[fb_i].resize(width, height, stride); + self.onscreens[fb_i] = &mut *self.framebuffers[fb_i].onscreen; } - // Map new onscreen - self.onscreens[fb_i] = unsafe { - let size = stride * height; - let onscreen_ptr = common::physmap( - self.framebuffers[fb_i].phys, - size * 4, - common::Prot { - read: true, - write: true, - }, - common::MemoryType::WriteCombining, - ) - .expect("vesad: failed to map framebuffer") as *mut u32; - ptr::write_bytes(onscreen_ptr, 0, size); - - slice::from_raw_parts_mut(onscreen_ptr, size) - }; - - // Update size - self.framebuffers[fb_i].width = width; - self.framebuffers[fb_i].height = height; - self.framebuffers[fb_i].stride = stride; - // Resize screens for (vt_i, screens) in self.vts.iter_mut() { for (screen_i, screen) in screens.iter_mut() { From 2e341fa7426083820e16b2dfb6624d831afd15f2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:18:34 +0200 Subject: [PATCH 0959/1301] Directly pass FrameBuffer to redraw and sync This avoids creating an intermediate &'static mut [u32] of questionable soundness and simplifies the code a bit. --- graphics/vesad/src/scheme.rs | 27 +++++---------------------- graphics/vesad/src/screen.rs | 13 +++++++------ 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index c5221f95c3..1d4f7cb238 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -27,7 +27,6 @@ pub struct Handle { pub struct DisplayScheme { framebuffers: Vec, - onscreens: Vec<&'static mut [u32]>, active: VtIndex, pub vts: BTreeMap>, next_id: usize, @@ -36,14 +35,9 @@ pub struct DisplayScheme { } impl DisplayScheme { - pub fn new(mut framebuffers: Vec, spec: &[()]) -> DisplayScheme { + pub fn new(framebuffers: Vec, spec: &[()]) -> DisplayScheme { let mut inputd_handle = inputd::Handle::new("vesa").unwrap(); - let mut onscreens = Vec::new(); - for fb in framebuffers.iter_mut() { - onscreens.push(unsafe { &mut *fb.onscreen }); - } - let mut vts = BTreeMap::>::new(); for &() in spec.iter() { @@ -57,7 +51,6 @@ impl DisplayScheme { DisplayScheme { framebuffers, - onscreens, active: VtIndex(1), vts, next_id: 0, @@ -96,7 +89,6 @@ impl DisplayScheme { unsafe { self.framebuffers[fb_i].resize(width, height, stride); - self.onscreens[fb_i] = &mut *self.framebuffers[fb_i].onscreen; } // Resize screens @@ -105,7 +97,7 @@ impl DisplayScheme { if screen_i.0 == fb_i { screen.resize(width, height); if *vt_i == self.active { - screen.redraw(self.onscreens[fb_i], self.framebuffers[fb_i].stride); + screen.redraw(&mut self.framebuffers[screen_i.0]); } } } @@ -235,10 +227,7 @@ impl SchemeMut for DisplayScheme { if let Some(screens) = self.vts.get_mut(&vt_i) { if let Some(screen) = screens.get_mut(&screen_i) { if vt_i == self.active { - screen.sync( - self.onscreens[screen_i.0], - self.framebuffers[screen_i.0].stride, - ); + screen.sync(&mut self.framebuffers[screen_i.0]); } return Ok(0); } @@ -277,10 +266,7 @@ impl SchemeMut for DisplayScheme { if let Some(screens) = self.vts.get_mut(&vt_i) { for (screen_i, screen) in screens.iter_mut() { - screen.redraw( - self.onscreens[screen_i.0], - self.framebuffers[screen_i.0].stride, - ); + screen.redraw(&mut self.framebuffers[screen_i.0]); } } @@ -308,10 +294,7 @@ impl SchemeMut for DisplayScheme { if let Some(screen) = screens.get_mut(&screen_i) { let count = screen.write(buf)?; if vt_i == self.active { - screen.sync( - self.onscreens[screen_i.0], - self.framebuffers[screen_i.0].stride, - ); + screen.sync(&mut self.framebuffers[screen_i.0]); } Ok(count) } else { diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index d77c095c9b..50f2f05af2 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -6,6 +6,7 @@ use orbclient::{Event, ResizeEvent}; use syscall::error::*; use crate::display::OffscreenBuffer; +use crate::framebuffer::FrameBuffer; // Keep synced with orbital #[derive(Clone, Copy)] @@ -130,7 +131,7 @@ impl GraphicScreen { Ok(sync_rects.len() * mem::size_of::()) } - pub fn sync(&mut self, onscreen: &mut [u32], stride: usize) { + pub fn sync(&mut self, framebuffer: &mut FrameBuffer) { for sync_rect in self.sync_rects.drain(..) { let x = sync_rect.x.try_into().unwrap_or(0); let y = sync_rect.y.try_into().unwrap_or(0); @@ -144,24 +145,24 @@ impl GraphicScreen { let row_pixel_count = cmp::min(self.width, x + w) - start_x; let mut offscreen_ptr = self.offscreen.as_mut_ptr(); - let mut onscreen_ptr = onscreen.as_mut_ptr(); + let mut onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable unsafe { offscreen_ptr = offscreen_ptr.add(y * self.width + start_x); - onscreen_ptr = onscreen_ptr.add(y * stride + start_x); + onscreen_ptr = onscreen_ptr.add(y * framebuffer.stride + start_x); let mut rows = end_y - start_y; while rows > 0 { ptr::copy(offscreen_ptr, onscreen_ptr, row_pixel_count); offscreen_ptr = offscreen_ptr.add(self.width); - onscreen_ptr = onscreen_ptr.add(stride); + onscreen_ptr = onscreen_ptr.add(framebuffer.stride); rows -= 1; } } } } - pub fn redraw(&mut self, onscreen: &mut [u32], stride: usize) { + pub fn redraw(&mut self, framebuffer: &mut FrameBuffer) { let width = self.width.try_into().unwrap(); let height = self.height.try_into().unwrap(); self.sync_rects.push(SyncRect { @@ -170,6 +171,6 @@ impl GraphicScreen { w: width, h: height, }); - self.sync(onscreen, stride); + self.sync(framebuffer); } } From 15d2078a13dddb5f09d9313635ac39a432b788ad Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jul 2024 15:11:34 +0200 Subject: [PATCH 0960/1301] Handle daemonization of pcid in a better way Currently pcid exits the main thread once it is done spawning drivers and expects all background threads handling driver communication to stay around. This only works as exitting the main thread on redox os currently doesn't cause the whole process to die. This will have to be fixed at some point for compatibility with programs that expect that exitting the main thread kills all other threads in the process, at which point pcid would break without the changes in this commit. --- Cargo.lock | 1 + fmt.sh | 1 + pcid/Cargo.toml | 1 + pcid/src/driver_handler.rs | 7 +++---- pcid/src/driver_interface/cap.rs | 5 +---- pcid/src/driver_interface/irq_helpers.rs | 24 +++++++++++++++--------- pcid/src/main.rs | 8 ++++++++ 7 files changed, 30 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c3bfee3bd9..d971355db9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -937,6 +937,7 @@ dependencies = [ "paw", "pci_types", "plain", + "redox-daemon", "redox-log", "redox_syscall 0.5.3", "serde", diff --git a/fmt.sh b/fmt.sh index e867ac215f..f62b954766 100755 --- a/fmt.sh +++ b/fmt.sh @@ -22,4 +22,5 @@ fmt graphics/bgad \ graphics/virtio-gpud \ inputd \ net/virtio-netd \ + pcid \ virtio-core diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 8e7db297ac..a0b6fcc152 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -21,6 +21,7 @@ log = "0.4" paw = "1.0" pci_types = "0.10" plain = "0.2" +redox-daemon = "0.1" redox-log = "0.1" redox_syscall = "0.5" serde = { version = "1", features = ["derive"] } diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index d34a067d3c..cbaf221e54 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -74,18 +74,17 @@ impl DriverHandler { Ok(mut child) => { let driver_handler = DriverHandler { addr: func.addr, - state, + state: state.clone(), capabilities, }; - let _handle = thread::spawn(move || { + let handle = thread::spawn(move || { driver_handler.handle_spawn( pcid_to_client_write, pcid_from_client_read, subdriver_args, ); }); - // FIXME this currently deadlocks as pcid doesn't daemonize - //state.threads.lock().unwrap().push(handle); + state.threads.lock().unwrap().push(handle); match child.wait() { Ok(_status) => (), Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err), diff --git a/pcid/src/driver_interface/cap.rs b/pcid/src/driver_interface/cap.rs index aa3f5540de..4e1b746a6d 100644 --- a/pcid/src/driver_interface/cap.rs +++ b/pcid/src/driver_interface/cap.rs @@ -8,10 +8,7 @@ pub struct VendorSpecificCapability { } impl VendorSpecificCapability { - pub unsafe fn parse( - addr: PciCapabilityAddress, - access: &dyn ConfigRegionAccess, - ) -> Self { + pub unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { let dword = access.read(addr.address, addr.offset); let next = (dword >> 8) & 0xFF; let length = ((dword >> 16) & 0xFF) as u16; diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index b900068456..6c7b010485 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -137,14 +137,15 @@ pub fn allocate_aligned_interrupt_vectors( } // if found, reserve the irq - let irq_handle = match File::create(format!("/scheme/irq/cpu-{:02x}/{}", cpu_id, irq_number)) { - Ok(handle) => handle, + let irq_handle = + match File::create(format!("/scheme/irq/cpu-{:02x}/{}", cpu_id, irq_number)) { + Ok(handle) => handle, - // return early if the entire range couldn't be allocated - Err(err) if err.kind() == io::ErrorKind::NotFound => break, + // return early if the entire range couldn't be allocated + Err(err) if err.kind() == io::ErrorKind::NotFound => break, - Err(err) => return Err(err), - }; + Err(err) => return Err(err), + }; handles.push(irq_handle); index += 1; } @@ -191,8 +192,13 @@ pub fn allocate_single_interrupt_vector_for_msi(cpu_id: usize) -> (MsiAddrAndDat let (vector, interrupt_handle) = allocate_single_interrupt_vector(cpu_id) .expect("failed to allocate interrupt vector") .expect("no interrupt vectors left"); - let msg_data = - x86_msix::message_data_edge_triggered(x86_msix::DeliveryMode::Fixed, vector); + let msg_data = x86_msix::message_data_edge_triggered(x86_msix::DeliveryMode::Fixed, vector); - (MsiAddrAndData { addr, data: msg_data }, interrupt_handle) + ( + MsiAddrAndData { + addr, + data: msg_data, + }, + interrupt_handle, + ) } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index e392ba37b0..ca435e1635 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -248,6 +248,10 @@ fn main(args: Args) { let _logger_ref = setup_logging(args.verbose); + redox_daemon::Daemon::new(move |daemon| main_inner(config, daemon)).unwrap(); +} + +fn main_inner(config: Config, daemon: redox_daemon::Daemon) -> ! { let state = Arc::new(State { pcie: Pcie::new(), threads: Mutex::new(Vec::new()), @@ -312,7 +316,11 @@ fn main(args: Args) { } } + daemon.ready().unwrap(); + for thread in state.threads.lock().unwrap().drain(..) { thread.join().unwrap(); } + + std::process::exit(0); } From 4d0008a32b5929a38102cea1eebebae9d824e751 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jul 2024 15:13:43 +0200 Subject: [PATCH 0961/1301] Rustfmt the common crate --- common/src/dma.rs | 10 +++++++--- common/src/lib.rs | 2 +- common/src/sgl.rs | 14 +++++++++++--- fmt.sh | 3 ++- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/common/src/dma.rs b/common/src/dma.rs index fef60d04e0..fbeb74bf96 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -3,7 +3,7 @@ use std::ops::{Deref, DerefMut}; use std::ptr; use libredox::call::MmapArgs; -use libredox::{flag, error::Result, Fd}; +use libredox::{error::Result, flag, Fd}; use syscall::PAGE_SIZE; use crate::MemoryType; @@ -34,7 +34,7 @@ fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> { let fd = phys_contiguous_fd()?; let virt = libredox::call::mmap(MmapArgs { fd: fd.raw(), - offset: 0, // ignored + offset: 0, // ignored addr: core::ptr::null_mut(), // ignored length, flags: flag::MAP_PRIVATE, @@ -42,7 +42,11 @@ fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> { })?; let phys = syscall::virttophys(virt as usize)?; for i in 1..length.div_ceil(PAGE_SIZE) { - debug_assert_eq!(syscall::virttophys(virt as usize + i * PAGE_SIZE), Ok(phys + i * PAGE_SIZE), "NOT CONTIGUOUS"); + debug_assert_eq!( + syscall::virttophys(virt as usize + i * PAGE_SIZE), + Ok(phys + i * PAGE_SIZE), + "NOT CONTIGUOUS" + ); } Ok((phys, virt as *mut ())) } diff --git a/common/src/lib.rs b/common/src/lib.rs index c96e3e8c4e..7403ce4793 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,8 +1,8 @@ #![feature(int_roundings)] use libredox::call::MmapArgs; -use libredox::{Fd, error::*, errno::EINVAL}; use libredox::flag::{self, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; +use libredox::{errno::EINVAL, error::*, Fd}; use syscall::PAGE_SIZE; pub mod dma; diff --git a/common/src/sgl.rs b/common/src/sgl.rs index 236ab85a05..cdd043415c 100644 --- a/common/src/sgl.rs +++ b/common/src/sgl.rs @@ -35,7 +35,8 @@ impl Sgl { offset: 0, fd: !0, addr: core::ptr::null_mut(), - })?.cast::(); + })? + .cast::(); let mut this = Self { virt, @@ -51,7 +52,9 @@ impl Sgl { let mut offset = 0; while offset < unaligned_length.get() { - let chunk_length = (aligned_length - offset).min(MAX_ALLOC_SIZE).next_power_of_two(); + let chunk_length = (aligned_length - offset) + .min(MAX_ALLOC_SIZE) + .next_power_of_two(); libredox::call::mmap(MmapArgs { addr: virt.add(offset).cast(), flags: MAP_PRIVATE | (MAP_FIXED.bits() as u32), @@ -62,7 +65,12 @@ impl Sgl { offset: 0, })?; let phys = syscall::virttophys(virt as usize + offset)?; - this.chunks.push(Chunk { offset, phys, length: (unaligned_length.get() - offset).min(chunk_length), virt: virt.add(offset) }); + this.chunks.push(Chunk { + offset, + phys, + length: (unaligned_length.get() - offset).min(chunk_length), + virt: virt.add(offset), + }); offset += chunk_length; } diff --git a/fmt.sh b/fmt.sh index f62b954766..597ef30965 100755 --- a/fmt.sh +++ b/fmt.sh @@ -16,7 +16,8 @@ function fmt() { done } -fmt graphics/bgad \ +fmt common \ + graphics/bgad \ graphics/fbcond \ graphics/vesad \ graphics/virtio-gpud \ From 7eceaaa2bdec7e5cf2429c3e9174a910012beb5d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 20 Jul 2024 15:49:18 +0200 Subject: [PATCH 0962/1301] Rustfmt driver-network and driver-block --- fmt.sh | 2 ++ storage/driver-block/src/lib.rs | 9 ++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/fmt.sh b/fmt.sh index 597ef30965..78c3bebd52 100755 --- a/fmt.sh +++ b/fmt.sh @@ -22,6 +22,8 @@ fmt common \ graphics/vesad \ graphics/virtio-gpud \ inputd \ + net/driver-network \ net/virtio-netd \ pcid \ + storage/driver-block \ virtio-core diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index e9ac6c5dc0..2d40c69d57 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -126,13 +126,8 @@ impl DiskWrapper { } } }; - let bytes_read = block_read( - self.offset, - blksize, - buf, - self.block_bytes, - read_block, - )?; + let bytes_read = + block_read(self.offset, blksize, buf, self.block_bytes, read_block)?; self.offset += bytes_read as u64; Ok(bytes_read) From 10f6c161418b2396a637f7532882fded9ac9f017 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Jul 2024 21:26:05 +0200 Subject: [PATCH 0963/1301] Remove an incorrect assertion preventing access to PCI extended capabilities --- pcid/src/cfg_access/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index 434f106020..94f42b7d3c 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -310,8 +310,6 @@ impl Pcie { "multiple segments not yet implemented" ); - assert_eq!(offset & 0xFC, offset, "pci offset is not aligned"); - let bus_addr = self.bus_addr(address.segment(), address.bus())?; Some(unsafe { bus_addr.add(Self::bus_addr_offset_in_dwords(address, offset)) }) } From a8e16dbe6c6a4c493ee5ed971e8187cadd636082 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 21 Jul 2024 20:56:10 -0600 Subject: [PATCH 0964/1301] Fix ps2d compilation on i686 --- ps2d/src/vm.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index c6c818e9f3..3885c83ff0 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -50,12 +50,11 @@ pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32) { // On x86 we don't have a spare register, so push ebx to the stack instead. #[cfg(target_arch = "x86")] asm!( - "push ebx; mov ebx, esi; in eax, dx; mov esi, ebx; pop ebx", + "push ebx; mov ebx, edi; in eax, dx; mov edi, ebx; pop ebx", inout("eax") MAGIC => a, - inout("esi") arg => b, + inout("edi") arg => b, inout("ecx") cmd => c, inout("edx") PORT as u32 => d, - out("edi") _, ); (a, b, c, d) From 73c50db678488d429d5e0ab9ab386944570b76be Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 21 Jul 2024 21:20:25 +0200 Subject: [PATCH 0965/1301] Use redox-log in ps2d --- Cargo.lock | 2 ++ ps2d/Cargo.toml | 2 ++ ps2d/src/controller.rs | 46 ++++++++++++++++++------------------ ps2d/src/main.rs | 53 ++++++++++++++++++++++++++++++++++++++++-- ps2d/src/state.rs | 11 +++++---- ps2d/src/vm.rs | 24 +++++++++++-------- 6 files changed, 99 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d971355db9..a35f309c3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1013,8 +1013,10 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "libredox 0.1.3", + "log", "orbclient", "redox-daemon", + "redox-log", "redox_syscall 0.5.3", ] diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index fb629ea72a..013830a661 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -5,7 +5,9 @@ edition = "2018" [dependencies] bitflags = "1" +log = "0.4" orbclient = "0.3.27" redox_syscall = "0.5" redox-daemon = "0.1" +redox-log = "0.1.1" libredox = "0.1.3" diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 1b0ae6fecb..ecb9036794 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -1,3 +1,4 @@ +use log::{debug, error, info, trace}; use syscall::io::{Io, Pio, ReadOnly, WriteOnly}; use std::fmt; @@ -39,7 +40,7 @@ bitflags! { bitflags! { pub struct ConfigFlags: u8 { - const FIRST_INTERRUPT = 1; + const FIRST_INTERRUPT = 1 << 0; const SECOND_INTERRUPT = 1 << 1; const POST_PASSED = 1 << 2; // 1 << 3 should be zero @@ -153,7 +154,8 @@ impl Ps2 { let mut timeout = 100; while timeout > 0 { if self.status().contains(StatusFlags::OUTPUT_FULL) { - eprintln!("ps2d: flush {}: {:X}", message, self.data.read()); + let val = self.data.read(); + trace!("ps2d: flush {}: {:X}", message, val); } unsafe { pause(); } timeout -= 1; @@ -178,7 +180,7 @@ impl Ps2 { } fn retry Result>(&mut self, name: fmt::Arguments, retries: usize, f: F) -> Result { - eprintln!("ps2d: {}", name); + trace!("ps2d: {}", name); let mut res = Err(Error::NoMoreTries); for retry in 0..retries { res = f(self); @@ -187,7 +189,7 @@ impl Ps2 { return Ok(ok); }, Err(ref err) => { - eprintln!("ps2d: {}: retry {}/{}: {:?}", name, retry + 1, retries, err); + info!("ps2d: {}: retry {}/{}: {:?}", name, retry + 1, retries, err); } } } @@ -311,10 +313,10 @@ impl Ps2 { if b == 0xFA { b = self.read().unwrap_or(0); if b != 0xAA { - eprintln!("ps2d: keyboard failed self test: {:02X}", b); + error!("ps2d: keyboard failed self test: {:02X}", b); } } else { - eprintln!("ps2d: keyboard failed to reset: {:02X}", b); + error!("ps2d: keyboard failed to reset: {:02X}", b); } // Clear remaining data @@ -330,7 +332,7 @@ impl Ps2 { // Set defaults and disable scanning let b = x.keyboard_command(KeyboardCommand::SetDefaultsDisable)?; if b != 0xFA { - eprintln!("ps2d: keyboard failed to set defaults: {:02X}", b); + error!("ps2d: keyboard failed to set defaults: {:02X}", b); return Err(Error::CommandRetry); } @@ -346,7 +348,7 @@ impl Ps2 { let scancode_set = 2; b = self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set)?; if b != 0xFA { - eprintln!("ps2d: keyboard failed to set scancode set {}: {:02X}", scancode_set, b); + error!("ps2d: keyboard failed to set scancode set {}: {:02X}", scancode_set, b); } // Clear remaining data @@ -379,17 +381,17 @@ impl Ps2 { if b == 0xFA { b = x.read()?; if b != 0xAA { - eprintln!("ps2d: mouse failed self test 1: {:02X}", b); + error!("ps2d: mouse failed self test 1: {:02X}", b); return Err(Error::CommandRetry); } b = x.read()?; if b != 0x00 { - eprintln!("ps2d: mouse failed self test 2: {:02X}", b); + error!("ps2d: mouse failed self test 2: {:02X}", b); return Err(Error::CommandRetry); } } else { - eprintln!("ps2d: mouse failed to reset: {:02X}", b); + error!("ps2d: mouse failed to reset: {:02X}", b); return Err(Error::CommandRetry); } @@ -404,7 +406,7 @@ impl Ps2 { // Set defaults b = self.mouse_command(MouseCommand::SetDefaults)?; if b != 0xFA { - eprintln!("ps2d: mouse failed to set defaults: {:02X}", b); + error!("ps2d: mouse failed to set defaults: {:02X}", b); } // Clear remaining data @@ -417,7 +419,7 @@ impl Ps2 { if self.mouse_command_data(MouseCommandData::SetSampleRate, 200)? != 0xFA || self.mouse_command_data(MouseCommandData::SetSampleRate, 100)? != 0xFA || self.mouse_command_data(MouseCommandData::SetSampleRate, 80)? != 0xFA { - eprintln!("ps2d: mouse failed to enable extra packet"); + error!("ps2d: mouse failed to enable extra packet"); } // Clear remaining data @@ -428,7 +430,7 @@ impl Ps2 { let mouse_extra = if b == 0xFA { self.read()? == 3 } else { - eprintln!("ps2d: mouse failed to get device id: {:02X}", b); + error!("ps2d: mouse failed to get device id: {:02X}", b); false }; @@ -440,7 +442,7 @@ impl Ps2 { let resolution = 3; b = self.mouse_command_data(MouseCommandData::SetResolution, resolution)?; if b != 0xFA { - eprintln!("ps2d: mouse failed to set resolution to {}: {:02X}", resolution, b); + error!("ps2d: mouse failed to set resolution to {}: {:02X}", resolution, b); } // Clear remaining data @@ -451,7 +453,7 @@ impl Ps2 { // Set scaling to 1:1 b = self.mouse_command(MouseCommand::SetScaling1To1)?; if b != 0xFA { - eprintln!("ps2d: mouse failed to set scaling: {:02X}", b); + error!("ps2d: mouse failed to set scaling: {:02X}", b); } // Clear remaining data @@ -463,7 +465,7 @@ impl Ps2 { let sample_rate = 200; b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate)?; if b != 0xFA { - eprintln!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b); + error!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b); } // Clear remaining data @@ -473,13 +475,13 @@ impl Ps2 { { b = self.mouse_command(MouseCommand::StatusRequest)?; if b != 0xFA { - eprintln!("ps2d: mouse failed to request status: {:02X}", b); + error!("ps2d: mouse failed to request status: {:02X}", b); } else { let a = self.read()?; let b = self.read()?; let c = self.read()?; - eprintln!("ps2d: mouse status {:#x} resolution {:#x} sample rate {:#x}", a, b, c); + debug!("ps2d: mouse status {:#x} resolution {:#x} sample rate {:#x}", a, b, c); } } @@ -507,7 +509,7 @@ impl Ps2 { config = ConfigFlags::POST_PASSED | ConfigFlags::FIRST_DISABLED | ConfigFlags::SECOND_DISABLED; - eprintln!("ps2d: config set {:?}", config); + trace!("ps2d: config set {:?}", config); self.set_config(config)?; // Clear remaining data @@ -530,7 +532,7 @@ impl Ps2 { let (mouse_found, mouse_extra) = match self.init_mouse() { Ok(ok) => (true, ok), Err(err) => { - eprintln!("ps2d: failed to initialize mouse: {:?}", err); + error!("ps2d: failed to initialize mouse: {:?}", err); (false, false) } }; @@ -563,7 +565,7 @@ impl Ps2 { config.insert(ConfigFlags::SECOND_DISABLED); config.remove(ConfigFlags::SECOND_INTERRUPT); } - eprintln!("ps2d: config set {:?}", config); + trace!("ps2d: config set {:?}", config); self.set_config(config)?; } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 64910d95ef..15f3537903 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -6,11 +6,13 @@ extern crate orbclient; extern crate syscall; use std::{env, process}; -use std::fs::{File, OpenOptions}; +use std::fs::OpenOptions; use std::io::{Read, Write}; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; +use log::info; +use redox_log::{OutputBuilder, RedoxLogger}; use syscall::call::iopl; use crate::state::Ps2d; @@ -20,7 +22,54 @@ mod keymap; mod state; mod vm; + +fn setup_logging() -> Option<&'static RedoxLogger> { + let mut logger = RedoxLogger::new() + .with_output( + OutputBuilder::stderr() + .with_filter(log::LevelFilter::Info) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("misc", "ps2", "ps2.log") { + Ok(b) => logger = logger.with_output( + // TODO: Add a configuration file for this + b.with_filter(log::LevelFilter::Info) + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("ps2d: failed to create ps2.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme("misc", "ps2", "ps2.ansi.log") { + Ok(b) => logger = logger.with_output( + b.with_filter(log::LevelFilter::Info) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build() + ), + Err(error) => eprintln!("ps2d: failed to create ps2.ansi.log: {}", error), + } + + match logger.enable() { + Ok(logger_ref) => { + eprintln!("ps2d: enabled logger"); + Some(logger_ref) + } + Err(error) => { + eprintln!("ps2d: failed to set default logger: {}", error); + None + } + } +} + fn daemon(daemon: redox_daemon::Daemon) -> ! { + setup_logging(); + unsafe { iopl(3).expect("ps2d: failed to get I/O permission"); } @@ -41,7 +90,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { None => (keymap::us::get_char, "us"), }; - eprintln!("ps2d: using keymap '{}'", keymap_name); + info!("ps2d: using keymap '{}'", keymap_name); let input = OpenOptions::new() .write(true) diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 381b642d3f..22db4e26e0 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -3,6 +3,7 @@ use std::io::Write; use std::os::unix::io::AsRawFd; use std::str; +use log::{error, warn}; use orbclient::{KeyEvent, MouseEvent, MouseRelativeEvent, ButtonEvent, ScrollEvent}; use crate::controller::Ps2; @@ -115,7 +116,7 @@ impl char> Ps2d { /* 0x80 to 0xFF used for press/release detection */ _ => { if pressed { - println!("ps2d: unknown extended scancode {:02X}", ps2_scancode); + warn!("ps2d: unknown extended scancode {:02X}", ps2_scancode); } 0 } @@ -213,7 +214,7 @@ impl char> Ps2d { /* 0x80 to 0xFF used for press/release detection */ _ => { if pressed { - println!("ps2d: unknown scancode {:02X}", ps2_scancode); + warn!("ps2d: unknown scancode {:02X}", ps2_scancode); } 0 } @@ -245,7 +246,7 @@ impl char> Ps2d { } if queue_length % 4 != 0 { - eprintln!("ps2d: queue length not a multiple of 4: {}", queue_length); + error!("ps2d: queue length not a multiple of 4: {}", queue_length); break; } @@ -297,7 +298,7 @@ impl char> Ps2d { let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); if ! flags.contains(MousePacketFlags::ALWAYS_ON) { - eprintln!("ps2d: mouse misalign {:X}", self.packets[0]); + error!("ps2d: mouse misalign {:X}", self.packets[0]); self.packets = [0; 4]; self.packet_i = 0; @@ -350,7 +351,7 @@ impl char> Ps2d { }.to_event()).expect("ps2d: failed to write button event"); } } else { - eprintln!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); + warn!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); } self.packets = [0; 4]; diff --git a/ps2d/src/vm.rs b/ps2d/src/vm.rs index 3885c83ff0..8832dc0ac9 100644 --- a/ps2d/src/vm.rs +++ b/ps2d/src/vm.rs @@ -6,6 +6,8 @@ use core::arch::asm; +use log::{error, info, trace}; + const MAGIC: u32 = 0x564D5868; const PORT: u16 = 0x5658; @@ -58,38 +60,40 @@ pub unsafe fn cmd(cmd: u32, arg: u32) -> (u32, u32, u32, u32) { ); (a, b, c, d) - } pub fn enable(relative: bool) -> bool { - eprintln!("ps2d: Enable vmmouse"); + trace!("ps2d: Enable vmmouse"); unsafe { let (eax, ebx, _, _) = cmd(GETVERSION, 0); if ebx != MAGIC || eax == 0xFFFFFFFF { - eprintln!("ps2d: No vmmouse support"); + info!("ps2d: No vmmouse support"); return false; } let _ = cmd(ABSPOINTER_COMMAND, CMD_ENABLE); let (status, _, _, _) = cmd(ABSPOINTER_STATUS, 0); - if (status & 0x0000ffff) == 0 { - eprintln!("ps2d: No vmmouse"); - return false; - } + if (status & 0x0000ffff) == 0 { + info!("ps2d: No vmmouse"); + return false; + } let (version, _, _, _) = cmd(ABSPOINTER_DATA, 1); if version != VERSION { - eprintln!("ps2d: Invalid vmmouse version: {} instead of {}", version, VERSION); + error!( + "ps2d: Invalid vmmouse version: {} instead of {}", + version, VERSION + ); let _ = cmd(ABSPOINTER_COMMAND, CMD_DISABLE); return false; } if relative { - cmd(ABSPOINTER_COMMAND, CMD_REQUEST_RELATIVE); + cmd(ABSPOINTER_COMMAND, CMD_REQUEST_RELATIVE); } else { - cmd(ABSPOINTER_COMMAND, CMD_REQUEST_ABSOLUTE); + cmd(ABSPOINTER_COMMAND, CMD_REQUEST_ABSOLUTE); } } From 66c1d0fd88a0be1c9ef6bfc4946ab97109401a8a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:06:29 +0200 Subject: [PATCH 0966/1301] Tell the kernel to disable graphical_debug right before the first framebuffer write by userspace Also remove the framebuffer clear in FrameBuffer::new as the entire framebuffer will be overwritten anyway almost immediately after. --- graphics/vesad/src/framebuffer.rs | 2 -- graphics/vesad/src/main.rs | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/graphics/vesad/src/framebuffer.rs b/graphics/vesad/src/framebuffer.rs index 5e1da0d04b..74d5b1be89 100644 --- a/graphics/vesad/src/framebuffer.rs +++ b/graphics/vesad/src/framebuffer.rs @@ -23,8 +23,6 @@ impl FrameBuffer { common::MemoryType::WriteCombining, ) .expect("vesad: failed to map framebuffer") as *mut u32; - //TODO: should we clear the framebuffer here? - ptr::write_bytes(virt, 0, size); let onscreen = ptr::slice_from_raw_parts_mut(virt, size); diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index bb2bcc6985..8245a5c2b5 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -83,6 +83,8 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( let mut scheme = DisplayScheme::new(framebuffers, &spec); + let _ = File::open("/scheme/debug/disable-graphical-debug"); + libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); From 7935ed024881d437a960c2b9a4f4132e8ddd55c2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 24 Jul 2024 22:00:40 +0200 Subject: [PATCH 0967/1301] Deduplicate setup_logging between all drivers This will make it easier to change the way logging is done for all drivers. This also fixes the log category for a couple of drivers as well as makes failing to set the logger a fatal error. Only when a logger is already set is it impossible to set another logger. --- Cargo.lock | 23 ++++-------- acpid/Cargo.toml | 1 - acpid/src/main.rs | 56 ++++------------------------- audio/ac97d/Cargo.toml | 1 - audio/ac97d/src/main.rs | 53 ++++------------------------ audio/ihdad/Cargo.toml | 1 - audio/ihdad/src/main.rs | 53 ++++------------------------ audio/sb16d/Cargo.toml | 1 - audio/sb16d/src/main.rs | 53 ++++------------------------ common/Cargo.toml | 2 ++ common/src/lib.rs | 3 ++ common/src/logger.rs | 49 ++++++++++++++++++++++++++ graphics/virtio-gpud/src/main.rs | 9 +++-- inputd/Cargo.toml | 3 +- inputd/src/main.rs | 45 ++++-------------------- net/rtl8139d/Cargo.toml | 1 - net/rtl8139d/src/main.rs | 53 ++++------------------------ net/rtl8168d/Cargo.toml | 1 - net/rtl8168d/src/main.rs | 53 ++++------------------------ net/virtio-netd/src/main.rs | 9 +++-- pcid/Cargo.toml | 1 - pcid/src/main.rs | 60 ++++---------------------------- ps2d/Cargo.toml | 3 +- ps2d/src/main.rs | 53 ++++------------------------ storage/ahcid/Cargo.toml | 1 - storage/ahcid/src/main.rs | 53 ++++------------------------ storage/ided/Cargo.toml | 1 - storage/ided/src/main.rs | 53 ++++------------------------ storage/nvmed/Cargo.toml | 1 - storage/nvmed/src/main.rs | 53 ++++------------------------ storage/virtio-blkd/Cargo.toml | 1 - storage/virtio-blkd/src/main.rs | 9 +++-- usbhidd/Cargo.toml | 3 +- usbhidd/src/main.rs | 56 ++++------------------------- usbhubd/Cargo.toml | 3 +- usbhubd/src/main.rs | 56 ++++------------------------- virtio-core/Cargo.toml | 1 - virtio-core/src/utils.rs | 36 ------------------- xhcid/Cargo.toml | 1 - xhcid/src/main.rs | 53 ++++------------------------ 40 files changed, 194 insertions(+), 774 deletions(-) create mode 100644 common/src/logger.rs diff --git a/Cargo.lock b/Cargo.lock index a35f309c3d..516c895c52 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,7 +12,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-log", "redox_event", "redox_syscall 0.5.3", "spin", @@ -32,7 +31,6 @@ dependencies = [ "parking_lot 0.11.2", "plain", "redox-daemon", - "redox-log", "redox_syscall 0.5.3", "rustc-hash", "serde_json", @@ -51,7 +49,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-log", "redox-scheme", "redox_event", "redox_syscall 0.5.3", @@ -286,6 +283,8 @@ name = "common" version = "0.1.0" dependencies = [ "libredox 0.1.3", + "log", + "redox-log", "redox_syscall 0.5.3", ] @@ -590,7 +589,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-log", "redox-scheme", "redox_event", "redox_syscall 0.5.3", @@ -606,7 +604,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-log", "redox_event", "redox_syscall 0.5.3", "spin", @@ -627,11 +624,11 @@ name = "inputd" version = "0.1.0" dependencies = [ "anyhow", + "common", "libredox 0.1.3", "log", "orbclient", "redox-daemon", - "redox-log", "redox_syscall 0.5.3", "spin", ] @@ -789,7 +786,6 @@ dependencies = [ "partitionlib", "pcid", "redox-daemon", - "redox-log", "redox-scheme", "redox_event", "redox_syscall 0.5.3", @@ -938,7 +934,6 @@ dependencies = [ "pci_types", "plain", "redox-daemon", - "redox-log", "redox_syscall 0.5.3", "serde", "serde_json", @@ -1012,11 +1007,11 @@ name = "ps2d" version = "0.1.0" dependencies = [ "bitflags 1.3.2", + "common", "libredox 0.1.3", "log", "orbclient", "redox-daemon", - "redox-log", "redox_syscall 0.5.3", ] @@ -1176,7 +1171,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-log", "redox_event", "redox_syscall 0.5.3", ] @@ -1192,7 +1186,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-log", "redox_event", "redox_syscall 0.5.3", ] @@ -1218,7 +1211,6 @@ dependencies = [ "libredox 0.1.3", "log", "redox-daemon", - "redox-log", "redox_event", "redox_syscall 0.5.3", "spin", @@ -1544,9 +1536,9 @@ name = "usbhidd" version = "0.1.0" dependencies = [ "bitflags 2.6.0", + "common", "log", "orbclient", - "redox-log", "redox_syscall 0.5.3", "rehid", "xhcid", @@ -1556,8 +1548,8 @@ dependencies = [ name = "usbhubd" version = "0.1.0" dependencies = [ + "common", "log", - "redox-log", "redox_syscall 0.5.3", "xhcid", ] @@ -1654,7 +1646,6 @@ dependencies = [ "partitionlib", "pcid", "redox-daemon", - "redox-log", "redox-scheme", "redox_syscall 0.5.3", "spin", @@ -1674,7 +1665,6 @@ dependencies = [ "libredox 0.1.3", "log", "pcid", - "redox-log", "redox_event", "redox_syscall 0.5.3", "static_assertions", @@ -1914,7 +1904,6 @@ dependencies = [ "pcid", "plain", "redox-daemon", - "redox-log", "redox_event", "redox_syscall 0.5.3", "serde", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 4e03f757e7..0ba5a37b00 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -14,7 +14,6 @@ num-traits = "0.2" parking_lot = "0.11.1" plain = "0.2.3" redox-daemon = "0.1" -redox-log = "0.1.1" redox_syscall = "0.5" rustc-hash = "1.1.0" thiserror = "1" diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 1aebe40a97..4c7024522f 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -8,7 +8,6 @@ use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; -use redox_log::RedoxLogger; use syscall::scheme::SchemeMut; use syscall::data::{Event, Packet}; @@ -31,55 +30,14 @@ fn monotonic() -> (u64, u64) { (timespec.tv_sec as u64, timespec.tv_nsec as u64) } -fn setup_logging() -> Option<&'static RedoxLogger> { - use redox_log::OutputBuilder; - - #[allow(unused_mut)] - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.log") { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Warn) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("Failed to create acpid.log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("misc", "acpi", "acpid.ansi.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Warn) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("Failed to create acpid.ansi.log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("acpid: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("acpid: failed to set default logger: {}", error); - None - } - } -} - fn daemon(daemon: redox_daemon::Daemon) -> ! { - setup_logging(); + common::setup_logging( + "misc", + "acpi", + "acpid", + log::LevelFilter::Info, + log::LevelFilter::Warn, + ); let rxsdt_raw_data: Arc<[u8]> = std::fs::read("/scheme/kernel.acpi/rxsdt") .expect("acpid: failed to read `/scheme/kernel.acpi/rxsdt`") diff --git a/audio/ac97d/Cargo.toml b/audio/ac97d/Cargo.toml index 143a127079..2e97f0a1aa 100644 --- a/audio/ac97d/Cargo.toml +++ b/audio/ac97d/Cargo.toml @@ -9,7 +9,6 @@ common = { path = "../../common" } libredox = "0.1.3" log = "0.4" redox-daemon = "0.1" -redox-log = "0.1.2" redox_event = "0.4.1" redox_syscall = "0.5" spin = "0.9" diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index 9066acc52a..05cd1a0df9 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -15,55 +15,10 @@ use std::usize; use event::{user_data, EventQueue}; use libredox::flag; use pcid_interface::{PciBar, PciFunctionHandle}; -use redox_log::{OutputBuilder, RedoxLogger}; use syscall::{EventFlags, Packet, SchemeBlockMut}; pub mod device; -fn setup_logging() -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "ac97.log") { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("ac97d: failed to create ac97.log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "ac97.ansi.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("ac97d: failed to create ac97.ansi.log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("ac97d: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("ac97d: failed to set default logger: {}", error); - None - } - } -} - fn main() { let pcid_handle = PciFunctionHandle::connect_default().expect("ac97d: failed to setup channel to pcid"); @@ -81,7 +36,13 @@ fn main() { // Daemonize redox_daemon::Daemon::new(move |daemon| { - let _logger_ref = setup_logging(); + common::setup_logging( + "audio", + "pcie", + "ac97", + log::LevelFilter::Info, + log::LevelFilter::Info, + ); common::acquire_port_io_rights().expect("ac97d: failed to set I/O privilege level to Ring 3"); diff --git a/audio/ihdad/Cargo.toml b/audio/ihdad/Cargo.toml index c431a9cb2e..4bd093ad88 100644 --- a/audio/ihdad/Cargo.toml +++ b/audio/ihdad/Cargo.toml @@ -8,7 +8,6 @@ bitflags = "2" libredox = "0.1.3" log = "0.4" redox-daemon = "0.1" -redox-log = "0.1.2" redox_event = "0.4.1" redox_syscall = "0.5" spin = "0.9" diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 755a5bcc4e..9fd2c779fb 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -20,7 +20,6 @@ use pcid_interface::{MsiSetFeatureInfo, PciFunctionHandle, PciFeature, PciFeatur #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; -use redox_log::{OutputBuilder, RedoxLogger}; pub mod hda; @@ -31,50 +30,6 @@ pub mod hda; 82801H ICH8 8086:284B */ -fn setup_logging() -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Debug) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "ihda.log") { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("ihdad: failed to create ihda.log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "ihda.ansi.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("ihdad: failed to create ihda.ansi.log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("ihdad: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("ihdad: failed to set default logger: {}", error); - None - } - } -} - #[cfg(target_arch = "x86_64")] fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.config(); @@ -133,7 +88,13 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let _logger_ref = setup_logging(); + common::setup_logging( + "audio", + "pcie", + "ihda", + log::LevelFilter::Debug, + log::LevelFilter::Info, + ); let mut pcid_handle = PciFunctionHandle::connect_default().expect("ihdad: failed to setup channel to pcid"); diff --git a/audio/sb16d/Cargo.toml b/audio/sb16d/Cargo.toml index 84a7357bec..29ff243ab8 100644 --- a/audio/sb16d/Cargo.toml +++ b/audio/sb16d/Cargo.toml @@ -9,7 +9,6 @@ common = { path = "../../common" } libredox = "0.1.3" log = "0.4" redox-daemon = "0.1" -redox-log = "0.1.2" redox_event = "0.4.1" redox_syscall = "0.5" spin = "0.9" diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index 002c707974..ff7333a626 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -6,54 +6,9 @@ use libredox::{flag, Fd}; use syscall::{Packet, SchemeBlockMut}; use event::{user_data, EventQueue}; -use redox_log::{OutputBuilder, RedoxLogger}; pub mod device; -fn setup_logging() -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "sb16.log") { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("sb16d: failed to create sb16.log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("audio", "pcie", "sb16.ansi.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("sb16d: failed to create sb16.ansi.log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("sb16d: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("sb16d: failed to set default logger: {}", error); - None - } - } -} - fn main() { let mut args = env::args().skip(1); @@ -64,7 +19,13 @@ fn main() { // Daemonize redox_daemon::Daemon::new(move |daemon| { - let _logger_ref = setup_logging(); + common::setup_logging( + "audio", + "pcie", + "sb16", + log::LevelFilter::Info, + log::LevelFilter::Info, + ); common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights"); diff --git a/common/Cargo.toml b/common/Cargo.toml index c1a072fa5d..50437c7d4b 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -9,4 +9,6 @@ license = "MIT" [dependencies] libredox = "0.1.3" +log = "0.4" redox_syscall = "0.5" +redox-log = "0.1.2" diff --git a/common/src/lib.rs b/common/src/lib.rs index 7403ce4793..969f9d4422 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -6,8 +6,11 @@ use libredox::{errno::EINVAL, error::*, Fd}; use syscall::PAGE_SIZE; pub mod dma; +mod logger; pub mod sgl; +pub use logger::setup_logging; + #[derive(Clone, Copy, Debug)] pub enum MemoryType { Writeback, diff --git a/common/src/logger.rs b/common/src/logger.rs new file mode 100644 index 0000000000..4f39f253b9 --- /dev/null +++ b/common/src/logger.rs @@ -0,0 +1,49 @@ +use redox_log::{OutputBuilder, RedoxLogger}; + +#[cfg_attr(not(target_os = "redox"), allow(unused_variables, unused_mut))] +pub fn setup_logging( + category: &str, + subcategory: &str, + logfile_base: &str, + output_level: log::LevelFilter, + file_level: log::LevelFilter, +) { + let mut logger = RedoxLogger::new().with_output( + OutputBuilder::stderr() + .with_filter(output_level) // limit global output to important info + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ); + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme( + category, + subcategory, + format!("{logfile_base}.log"), + ) { + Ok(b) => { + logger = logger.with_output(b.with_filter(file_level).flush_on_newline(true).build()) + } + Err(error) => eprintln!("Failed to create {logfile_base}.log: {}", error), + } + + #[cfg(target_os = "redox")] + match OutputBuilder::in_redox_logging_scheme( + category, + subcategory, + format!("{logfile_base}.ansi.log"), + ) { + Ok(b) => { + logger = logger.with_output( + b.with_filter(file_level) + .with_ansi_escape_codes() + .flush_on_newline(true) + .build(), + ) + } + Err(error) => eprintln!("Failed to create {logfile_base}.ansi.log: {}", error), + } + + logger.enable().expect("failed to set default logger"); +} diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index da7deaa3a5..7ad1e13e08 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -466,7 +466,12 @@ fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { } pub fn main() { - #[cfg(target_os = "redox")] - virtio_core::utils::setup_logging(log::LevelFilter::Trace, "virtio-gpud"); + common::setup_logging( + "misc", + "pcie", + "virtio-gpud", + log::LevelFilter::Trace, + log::LevelFilter::Trace, + ); redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index 9b900edc13..0ba28069f3 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -8,8 +8,9 @@ authors = ["Anhad Singh "] anyhow = "1.0.71" log = "0.4.19" redox-daemon = "0.1.2" -redox-log = "0.1.1" redox_syscall = "0.5" orbclient = "0.3.27" spin = "0.9.8" libredox = "0.1.3" + +common = { path = "../common" } diff --git a/inputd/src/main.rs b/inputd/src/main.rs index db4ac50e83..870ce8a432 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -427,45 +427,14 @@ fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { unreachable!(); } -#[cfg(target_os = "redox")] -pub fn setup_logging(level: log::LevelFilter, name: &str) { - use redox_log::{OutputBuilder, RedoxLogger}; - - let mut logger = RedoxLogger::new().with_output( - OutputBuilder::stderr() - .with_filter(level) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ); - - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", format!("{name}.log")) { - Ok(builder) => { - logger = logger.with_output(builder.with_filter(level).flush_on_newline(true).build()) - } - Err(err) => eprintln!("inputd: failed to create log: {}", err), - } - - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", format!("{name}.ansi.log")) { - Ok(builder) => { - logger = logger.with_output( - builder - .with_filter(level) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ) - } - Err(err) => eprintln!("inputd: failed to create ANSI log: {}", err), - } - - logger.enable().unwrap(); - log::info!("inputd: enabled logger"); -} - pub fn main() { - #[cfg(target_os = "redox")] - setup_logging(log::LevelFilter::Trace, "inputd"); + common::setup_logging( + "misc", + "inputd", + "inputd", + log::LevelFilter::Trace, + log::LevelFilter::Trace, + ); let mut args = std::env::args().skip(1); diff --git a/net/rtl8139d/Cargo.toml b/net/rtl8139d/Cargo.toml index 432b562cb9..cd6ed71f17 100644 --- a/net/rtl8139d/Cargo.toml +++ b/net/rtl8139d/Cargo.toml @@ -10,7 +10,6 @@ log = "0.4" redox_event = "0.4.1" redox_syscall = "0.5" redox-daemon = "0.1" -redox-log = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 4c3d8d0073..4f85e1b96f 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -18,55 +18,10 @@ use pcid_interface::{ MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, SubdriverArguments, }; -use redox_log::{OutputBuilder, RedoxLogger}; use syscall::EventFlags; pub mod device; -fn setup_logging() -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("net", "pcie", "rtl8139.log") { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("Failed to create rtl8139.log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("net", "pcie", "rtl8139.ansi.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("Failed to create rtl8139.ansi.log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("rtl8139d: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("rtl8139d: failed to set default logger: {}", error); - None - } - } -} - use std::ops::{Add, Div, Rem}; pub fn div_round_up(a: T, b: T) -> T where @@ -208,7 +163,13 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let _logger_ref = setup_logging(); + common::setup_logging( + "net", + "pcie", + "rtl8139", + log::LevelFilter::Info, + log::LevelFilter::Info, + ); let mut pcid_handle = PciFunctionHandle::connect_default().expect("rtl8139d: failed to setup channel to pcid"); diff --git a/net/rtl8168d/Cargo.toml b/net/rtl8168d/Cargo.toml index 54a91855dd..a8aca0c7c2 100644 --- a/net/rtl8168d/Cargo.toml +++ b/net/rtl8168d/Cargo.toml @@ -10,7 +10,6 @@ log = "0.4" redox_event = "0.4.1" redox_syscall = "0.5" redox-daemon = "0.1" -redox-log = "0.1" common = { path = "../../common" } driver-network = { path = "../driver-network" } diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 7ba886d4c5..cdccf38c7b 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -13,55 +13,10 @@ use pcid_interface::{MsiSetFeatureInfo, PciFunctionHandle, PciFeature, PciFeatur use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixInfo, MsixTableEntry}; -use redox_log::{RedoxLogger, OutputBuilder}; use syscall::EventFlags; pub mod device; -fn setup_logging() -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("net", "pcie", "rtl8168.log") { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("Failed to create rtl8168.log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("net", "pcie", "rtl8168.ansi.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("Failed to create rtl8168.ansi.log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("rtl8168d: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("rtl8168d: failed to set default logger: {}", error); - None - } - } -} - use std::ops::{Add, Div, Rem}; pub fn div_round_up(a: T, b: T) -> T where @@ -203,7 +158,13 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let _logger_ref = setup_logging(); + common::setup_logging( + "net", + "pcie", + "rtl8168", + log::LevelFilter::Info, + log::LevelFilter::Info, + ); let mut pcid_handle = PciFunctionHandle::connect_default().expect("rtl8168d: failed to setup channel to pcid"); diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index e4ad270df9..b054534a7a 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -120,7 +120,12 @@ fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { } pub fn main() { - #[cfg(target_os = "redox")] - virtio_core::utils::setup_logging(log::LevelFilter::Trace, "virtio-netd"); + common::setup_logging( + "net", + "pcie", + "virtio-netd", + log::LevelFilter::Trace, + log::LevelFilter::Trace, + ); redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index a0b6fcc152..09416ac0bd 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -22,7 +22,6 @@ paw = "1.0" pci_types = "0.10" plain = "0.2" redox-daemon = "0.1" -redox-log = "0.1" redox_syscall = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index ca435e1635..f8d72fc910 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -10,7 +10,6 @@ use pci_types::{ Bar as TyBar, CommandRegister, EndpointHeader, HeaderType, PciAddress, PciHeader as TyPciHeader, PciPciBridgeHeader, }; -use redox_log::{OutputBuilder, RedoxLogger}; use structopt::StructOpt; use crate::cfg_access::Pcie; @@ -166,57 +165,6 @@ fn handle_parsed_header( } } -fn setup_logging(verbosity: u8) -> Option<&'static RedoxLogger> { - let log_level = match verbosity { - 0 => log::LevelFilter::Info, - 1 => log::LevelFilter::Debug, - _ => log::LevelFilter::Trace, - }; - let mut logger = RedoxLogger::new().with_output( - OutputBuilder::stderr() - .with_ansi_escape_codes() - .with_filter(log_level) - .flush_on_newline(true) - .build(), - ); - - #[cfg(target_os = "redox")] - { - match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.log") { - Ok(b) => { - logger = logger.with_output( - b.with_filter(log::LevelFilter::Trace) - .flush_on_newline(true) - .build(), - ) - } - Err(error) => eprintln!("pcid: failed to open pcid.log"), - } - match OutputBuilder::in_redox_logging_scheme("bus", "pci", "pcid.ansi.log") { - Ok(b) => { - logger = logger.with_output( - b.with_filter(log::LevelFilter::Trace) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ) - } - Err(error) => eprintln!("pcid: failed to open pcid.ansi.log"), - } - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("pcid: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("pcid: failed to set default logger: {}", error); - None - } - } -} - #[paw::main] fn main(args: Args) { let mut config = Config::default(); @@ -246,7 +194,13 @@ fn main(args: Args) { } } - let _logger_ref = setup_logging(args.verbose); + let log_level = match args.verbose { + 0 => log::LevelFilter::Info, + 1 => log::LevelFilter::Debug, + _ => log::LevelFilter::Trace, + }; + + common::setup_logging("bus", "pci", "pcid", log_level, log::LevelFilter::Trace); redox_daemon::Daemon::new(move |daemon| main_inner(config, daemon)).unwrap(); } diff --git a/ps2d/Cargo.toml b/ps2d/Cargo.toml index 013830a661..78f9dbe207 100644 --- a/ps2d/Cargo.toml +++ b/ps2d/Cargo.toml @@ -9,5 +9,6 @@ log = "0.4" orbclient = "0.3.27" redox_syscall = "0.5" redox-daemon = "0.1" -redox-log = "0.1.1" libredox = "0.1.3" + +common = { path = "../common" } diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 15f3537903..2b08b8fb97 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -12,7 +12,6 @@ use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; use log::info; -use redox_log::{OutputBuilder, RedoxLogger}; use syscall::call::iopl; use crate::state::Ps2d; @@ -23,52 +22,14 @@ mod state; mod vm; -fn setup_logging() -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("misc", "ps2", "ps2.log") { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("ps2d: failed to create ps2.log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("misc", "ps2", "ps2.ansi.log") { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("ps2d: failed to create ps2.ansi.log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("ps2d: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("ps2d: failed to set default logger: {}", error); - None - } - } -} - fn daemon(daemon: redox_daemon::Daemon) -> ! { - setup_logging(); + common::setup_logging( + "misc", + "ps2", + "ps2", + log::LevelFilter::Info, + log::LevelFilter::Info, + ); unsafe { iopl(3).expect("ps2d: failed to get I/O permission"); diff --git a/storage/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml index 0f9793e19a..5186da6460 100644 --- a/storage/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -8,7 +8,6 @@ bitflags = "1.2" byteorder = "1.2" log = "0.4" redox-daemon = "0.1" -redox-log = "0.1" redox_syscall = { version = "0.5", features = ["std"] } common = { path = "../../common" } diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index a3a8107729..e380d997c2 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -14,7 +14,6 @@ use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; use syscall::error::{Error, ENODEV}; use log::{error, info}; -use redox_log::{OutputBuilder, RedoxLogger}; use syscall::{EAGAIN, EWOULDBLOCK}; use crate::scheme::DiskScheme; @@ -22,50 +21,6 @@ use crate::scheme::DiskScheme; pub mod ahci; pub mod scheme; -fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.log", name)) { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("ahcid: failed to create log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.ansi.log", name)) { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("ahcid: failed to create ansi log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("ahcid: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("ahcid: failed to set default logger: {}", error); - None - } - } -} - fn main() { redox_daemon::Daemon::new(daemon).expect("ahcid: failed to daemonize"); } @@ -80,7 +35,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let irq = pci_config.func.legacy_interrupt_line.expect("ahcid: no legacy interrupts supported"); - let _logger_ref = setup_logging(&name); + common::setup_logging( + "disk", + "pcie", + &name, + log::LevelFilter::Info, + log::LevelFilter::Info, + ); info!(" + AHCI {}", pci_config.func.display()); diff --git a/storage/ided/Cargo.toml b/storage/ided/Cargo.toml index e590d22e97..3a0f34d5f7 100644 --- a/storage/ided/Cargo.toml +++ b/storage/ided/Cargo.toml @@ -10,7 +10,6 @@ libredox = "0.1.3" log = "0.4" pcid = { path = "../../pcid" } redox-daemon = "0.1" -redox-log = "0.1" redox_syscall = { version = "0.5", features = ["std"] } redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index c69ac46d18..28719cfddd 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -3,7 +3,6 @@ use event::{EventFlags, RawEventQueue}; use libredox::flag; use log::{error, info}; use pcid_interface::{PciBar, PciFunctionHandle}; -use redox_log::{OutputBuilder, RedoxLogger}; use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; use std::{ fs::File, @@ -25,50 +24,6 @@ use crate::{ pub mod ide; pub mod scheme; -fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.log", name)) { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("ided: failed to create log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.ansi.log", name)) { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("ided: failed to create ansi log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("ided: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("ided: failed to set default logger: {}", error); - None - } - } -} - fn main() { redox_daemon::Daemon::new(daemon).expect("ided: failed to daemonize"); } @@ -82,7 +37,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_ide"); - let _logger_ref = setup_logging(&name); + common::setup_logging( + "disk", + "pcie", + &name, + log::LevelFilter::Info, + log::LevelFilter::Info, + ); info!("IDE PCI CONFIG: {:?}", pci_config); diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index b4fe28398b..1a00ca727a 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -10,7 +10,6 @@ crossbeam-channel = "0.4" futures = "0.3" log = "0.4" redox-daemon = "0.1" -redox-log = "0.1" redox_syscall = { version = "0.5", features = ["std"] } redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index f3bc114106..28ff062e47 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -16,7 +16,6 @@ use syscall::{ Event, Mmio, Packet, Result, SchemeBlockMut, PAGE_SIZE, }; -use redox_log::{OutputBuilder, RedoxLogger}; use self::nvme::{InterruptMethod, InterruptSources, Nvme}; use self::scheme::DiskScheme; @@ -151,50 +150,6 @@ fn get_int_method( } } -fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.log", name)) { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("nvmed: failed to create log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", &format!("{}.ansi.log", name)) { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("nvmed: failed to create ansi log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("nvmed: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("nvmed: failed to set default logger: {}", error); - None - } - } -} - fn main() { redox_daemon::Daemon::new(daemon).expect("nvmed: failed to daemonize"); } @@ -205,7 +160,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let scheme_name = format!("disk.{}-nvme", pci_config.func.name()); - let _logger_ref = setup_logging(&scheme_name); + common::setup_logging( + "disk", + "pcie", + &scheme_name, + log::LevelFilter::Info, + log::LevelFilter::Info, + ); log::debug!("NVME PCI CONFIG: {:?}", pci_config); diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index 6ac79495d2..c9d09ad78d 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -13,7 +13,6 @@ futures = { version = "0.3.28", features = ["executor"] } spin = "*" redox-daemon = "0.1" -redox-log = "0.1" redox_syscall = { version = "0.5", features = ["std"] } redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 8d819db570..7fa906f017 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -35,8 +35,13 @@ pub enum Error { } pub fn main() -> anyhow::Result<()> { - #[cfg(target_os = "redox")] - virtio_core::utils::setup_logging(log::LevelFilter::Trace, "virtio-blkd"); + common::setup_logging( + "disk", + "pcie", + "virtio-blkd", + log::LevelFilter::Trace, + log::LevelFilter::Trace, + ); redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } diff --git a/usbhidd/Cargo.toml b/usbhidd/Cargo.toml index 54a80e1e2f..52a7b01ce9 100644 --- a/usbhidd/Cargo.toml +++ b/usbhidd/Cargo.toml @@ -11,7 +11,8 @@ license = "MIT" bitflags = "2" log = "0.4" orbclient = "0.3.47" -redox-log = "0.1" redox_syscall = "0.5" rehid = { git = "https://gitlab.redox-os.org/redox-os/rehid.git" } xhcid = { path = "../xhcid" } + +common = { path = "../common" } diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 0551cd0953..d63840715f 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -4,7 +4,6 @@ use std::fs::File; use std::io::{Read, Write}; use orbclient::KeyEvent as OrbKeyEvent; -use redox_log::{OutputBuilder, RedoxLogger}; use rehid::{ report_desc::{self, ReportTy, REPORT_DESC_TY}, report_handler::ReportHandler, @@ -15,53 +14,6 @@ use xhcid_interface::{ConfigureEndpointsReq, DevDesc, EndpDirection, EndpointTy, mod keymap; mod reqs; -fn setup_logging() -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new().with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "device", "hid.log") { - Ok(b) => { - logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build(), - ) - } - Err(error) => eprintln!("Failed to create hid.log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "device", "hid.ansi.log") { - Ok(b) => { - logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ) - } - Err(error) => eprintln!("Failed to create hid.ansi.log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("usbhidd: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("usbhidd: failed to set default logger: {}", error); - None - } - } -} - fn send_key_event( display: &mut File, usage_page: u32, @@ -214,7 +166,13 @@ fn send_key_event( } fn main() { - let _logger_ref = setup_logging(); + common::setup_logging( + "usb", + "device", + "hid", + log::LevelFilter::Info, + log::LevelFilter::Info, + ); let mut args = env::args().skip(1); diff --git a/usbhubd/Cargo.toml b/usbhubd/Cargo.toml index abc8eb8abc..708234e823 100644 --- a/usbhubd/Cargo.toml +++ b/usbhubd/Cargo.toml @@ -8,6 +8,7 @@ license = "MIT" [dependencies] log = "0.4" -redox-log = "0.1" redox_syscall = "0.5" xhcid = { path = "../xhcid" } + +common = { path = "../common" } diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index 21cccadd14..a3f5521310 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -3,58 +3,16 @@ use std::env; use std::fs::File; use std::io::{Read, Write}; -use redox_log::{OutputBuilder, RedoxLogger}; use xhcid_interface::{plain, usb, ConfigureEndpointsReq, DevDesc, DeviceReqData, EndpDirection, EndpointTy, PortReqRecipient, PortReqTy, XhciClientHandle}; -fn setup_logging() -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new().with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "device", "hub.log") { - Ok(b) => { - logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Info) - .flush_on_newline(true) - .build(), - ) - } - Err(error) => eprintln!("Failed to create hub.log: {}", error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "device", "hub.ansi.log") { - Ok(b) => { - logger = logger.with_output( - b.with_filter(log::LevelFilter::Info) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ) - } - Err(error) => eprintln!("Failed to create hub.ansi.log: {}", error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("usbhubd: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("usbhubd: failed to set default logger: {}", error); - None - } - } -} - fn main() { - let _logger_ref = setup_logging(); + common::setup_logging( + "usb", + "device", + "hub", + log::LevelFilter::Info, + log::LevelFilter::Info, + ); let mut args = env::args().skip(1); diff --git a/virtio-core/Cargo.toml b/virtio-core/Cargo.toml index 6568a5cc10..4a5630b53a 100644 --- a/virtio-core/Cargo.toml +++ b/virtio-core/Cargo.toml @@ -14,7 +14,6 @@ thiserror = "1.0.40" futures = { version = "0.3.28", features = ["executor"] } crossbeam-queue = "0.3.8" -redox-log = "0.1" redox_event = "0.4.1" common = { path = "../common" } diff --git a/virtio-core/src/utils.rs b/virtio-core/src/utils.rs index 07214248e5..76d8ff7eb7 100644 --- a/virtio-core/src/utils.rs +++ b/virtio-core/src/utils.rs @@ -78,39 +78,3 @@ pub const fn align(val: usize, align: usize) -> usize { pub const fn align_down(addr: usize) -> usize { addr & !(syscall::PAGE_SIZE - 1) } - -#[cfg(target_os = "redox")] -pub fn setup_logging(level: log::LevelFilter, name: &str) { - use redox_log::{OutputBuilder, RedoxLogger}; - - let mut logger = RedoxLogger::new().with_output( - OutputBuilder::stderr() - .with_filter(level) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ); - - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", format!("{name}.log")) { - Ok(builder) => { - logger = logger.with_output(builder.with_filter(level).flush_on_newline(true).build()) - } - Err(err) => eprintln!("virtio-core::utils: failed to create log: {}", err), - } - - match OutputBuilder::in_redox_logging_scheme("disk", "pcie", format!("{name}.ansi.log")) { - Ok(builder) => { - logger = logger.with_output( - builder - .with_filter(level) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build(), - ) - } - Err(err) => eprintln!("virtio-core::utils: failed to create ANSI log: {}", err), - } - - logger.enable().unwrap(); - log::info!("virtio-core::utils: enabled logger"); -} diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 94e09eb0b3..820d1e5291 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -21,7 +21,6 @@ lazy_static = "1.4" log = "0.4" redox-daemon = "0.1" redox_event = "0.4.1" -redox-log = "0.1" redox_syscall = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 6248e4264f..972884994a 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -19,7 +19,6 @@ use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::MsixTableEntry; use event::{Event, RawEventQueue}; -use redox_log::{RedoxLogger, OutputBuilder}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::EventFlags; @@ -40,50 +39,6 @@ async fn handle_packet(hci: Arc, packet: Packet) -> Packet { todo!() } -fn setup_logging(name: &str) -> Option<&'static RedoxLogger> { - let mut logger = RedoxLogger::new() - .with_output( - OutputBuilder::stderr() - .with_filter(log::LevelFilter::Info) // limit global output to important info - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ); - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "host", &format!("{}.log", name)) { - Ok(b) => logger = logger.with_output( - // TODO: Add a configuration file for this - b.with_filter(log::LevelFilter::Debug) - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("Failed to create {}.log: {}", name, error), - } - - #[cfg(target_os = "redox")] - match OutputBuilder::in_redox_logging_scheme("usb", "host", &format!("{}.ansi.log", name)) { - Ok(b) => logger = logger.with_output( - b.with_filter(log::LevelFilter::Debug) - .with_ansi_escape_codes() - .flush_on_newline(true) - .build() - ), - Err(error) => eprintln!("Failed to create {}.ansi.log: {}", name, error), - } - - match logger.enable() { - Ok(logger_ref) => { - eprintln!("xhcid: enabled logger"); - Some(logger_ref) - } - Err(error) => { - eprintln!("xhcid: failed to set default logger: {}", error); - None - } - } -} - #[cfg(target_arch = "x86_64")] fn get_int_method(pcid_handle: &mut PciFunctionHandle, bar0_address: usize) -> (Option, InterruptMethod) { let pci_config = pcid_handle.config(); @@ -191,7 +146,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_xhci"); - let _logger_ref = setup_logging(&name); + common::setup_logging( + "usb", + "host", + &name, + log::LevelFilter::Info, + log::LevelFilter::Debug, + ); log::debug!("XHCI PCI CONFIG: {:?}", pci_config); From 0afc2f9875986cfbe3306ec53e377369f69be9c1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 18 Aug 2024 21:20:49 +0200 Subject: [PATCH 0968/1301] Update redox-log This removes a couple of uses of the legacy scheme syntax --- Cargo.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 516c895c52..2430ad1b44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1088,9 +1088,9 @@ dependencies = [ [[package]] name = "redox-log" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cacd9e83920c75b71b2ea740603d579179da055e8a8d72b25252874c28d513f0" +checksum = "81460b1526438123d16f0c968dbe42ba7f61e99645109b70e57864a8b66710fb" dependencies = [ "chrono", "log", From ffb1f7dcd05564ee37385292e96c033ffddc0579 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Sat, 31 Aug 2024 12:09:25 -0700 Subject: [PATCH 0969/1301] Added various C/C++ and Rust editor directories to the gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 9b0fb7e2e1..69b918ab9a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ target/ # editor configs: -.vscode +.vscode/ +.idea/ +.vs/ +.devcontainer/ From 24c01b1760a48c4d65d30769388f5161049f4f45 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Sat, 31 Aug 2024 12:11:05 -0700 Subject: [PATCH 0970/1301] Added comments describing additions to the gitignore --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 69b918ab9a..d1adf4b7b0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ target/ -# editor configs: +# Local settings folder for Visual Studio Code .vscode/ +# Local settings folder for Jetbrains products (RustRover, IntelliJ, CLion) .idea/ +# Local settings folder for Visual Studio Professional .vs/ +# Local settings folder for the devcontainer extension that most IDEs support. .devcontainer/ From 32ba2f1f199200ac961d6064c74a75d1536b0c9d Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Sat, 31 Aug 2024 12:17:36 -0700 Subject: [PATCH 0971/1301] Copied the merge request templates from the core repo to the drivers repo such that PRs have those templates available to them --- .gitlab/issue_templates/Issue_template.md | 92 +++++++++++++++++++ .../Merge_request_template.md | 25 +++++ 2 files changed, 117 insertions(+) create mode 100644 .gitlab/issue_templates/Issue_template.md create mode 100644 .gitlab/merge_request_templates/Merge_request_template.md diff --git a/.gitlab/issue_templates/Issue_template.md b/.gitlab/issue_templates/Issue_template.md new file mode 100644 index 0000000000..42d653e2f0 --- /dev/null +++ b/.gitlab/issue_templates/Issue_template.md @@ -0,0 +1,92 @@ + + + + +- [ ] I agree that I have searched opened and closed issues to prevent duplicates. + +-------------------- + + + +## Description + +Replace me + + + +## Environment info + + + +- Redox OS Release: +0.0.0 Remove me + + +- Operating system: +Replace me +- `uname -a`: +`Replace me` +- `rustc -V`: +`Replace me` +- `git rev-parse HEAD`: +`Replace me` + +- Replace me: +Replace me + + + +## Steps to reproduce + +1. Replace me +2. Replace me +3. ... + + + +## Behavior + + + +- **Expected behavior**: +Replace me + + +- **Actual behavior**: +Replace me + + +``` +Replace me +``` + + +- **Proposed solution**: +Replace me + + + + + +## Optional references + + +Related to: +- #0000 Remove me +- Replace me +- ... + +Blocked by: +- #0000 Remove me +- ... + + + +## Optional extras + +Replace me + + + + + diff --git a/.gitlab/merge_request_templates/Merge_request_template.md b/.gitlab/merge_request_templates/Merge_request_template.md new file mode 100644 index 0000000000..be611fa3e4 --- /dev/null +++ b/.gitlab/merge_request_templates/Merge_request_template.md @@ -0,0 +1,25 @@ +**Problem**: [describe the problem you try to solve with this PR.] + +**Solution**: [describe carefully what you change by this PR.] + +**Changes introduced by this pull request**: + +- [...] +- [...] +- [...] + +**Drawbacks**: [if any, describe the drawbacks of this pull request.] + +**TODOs**: [what is not done yet.] + +**Fixes**: [what issues this fixes.] + +**State**: [the state of this PR, e.g. WIP, ready, etc.] + +**Blocking/related**: [issues or PRs blocking or being related to this issue.] + +**Other**: [optional: for other relevant information that should be known or cannot be described in the other fields.] + +------ + +_The above template is not necessary for smaller PRs._ From d7852b4836a1c91f29675273e56962673db38ed9 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Sat, 31 Aug 2024 14:48:35 -0700 Subject: [PATCH 0972/1301] Created docs for common/src/lib.rs --- common/src/lib.rs | 114 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) diff --git a/common/src/lib.rs b/common/src/lib.rs index 969f9d4422..7a8d91b5f8 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -1,21 +1,51 @@ +//! This crate provides various abstractions for use by all drivers in the Redox drivers repo. +//! +//! This includes direct memory access via [dma], and Scatter-Gather List support via [sgl]. It also +//! provides various memory management structures for use with drivers, and some logging support. #![feature(int_roundings)] +#![warn(missing_docs)] use libredox::call::MmapArgs; use libredox::flag::{self, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; use libredox::{errno::EINVAL, error::*, Fd}; use syscall::PAGE_SIZE; +/// The Direct Memory Access (DMA) API for drivers pub mod dma; mod logger; +/// The Scatter Gather List (SGL) API for drivers. pub mod sgl; pub use logger::setup_logging; +/// Specifies the write behavior for a specific region of memory +/// +/// These types indicate to the driver how writes to a specific memory region are handled by the +/// system. This usually refers to the caching behavior that the processor or I/O device responsible +/// for that memory implements. +/// +/// aarch64 and x86 have very different cache-coherency rules, so this API as written is likely +/// not sufficient to describe the memory caching behavior in a cross-platform manner. As such, +/// consider this API unstable. #[derive(Clone, Copy, Debug)] pub enum MemoryType { + /// A region of memory that implements Write-back caching. + /// + /// In write-back caching, the processor will first store data in its local cache, and then + /// flush it to the actual storage location at regular intervals, or as applications access + /// the data. Writeback, + /// A region of memory that does not implement caching. Writes to these regions are immediate. Uncacheable, - WriteCombining, + /// A region of memory that implements write combining. + /// + /// Write combining memory regions store all writes in a temporary buffer called a Write + /// Combine Buffer. Multiple writes to the location are stored in a single buffer, and then + /// released to the memory location in an unspecified order. Write-Combine memory does not + /// guarantee that the order at which you write to it is the order at which those writes are + /// committed to memory. + WriteCombining, /// Memory stored in an intermediate Write Combine Buffer and released later + /// Memory-Mapped I/O. This is an aarch64-specific term. DeviceMemory, } impl Default for MemoryType { @@ -24,20 +54,34 @@ impl Default for MemoryType { } } +/// Represents the protection level of an area of memory. +/// +/// This structure shouldn't be used directly -- instead, use the [Prot::RO] (Read-Only), +/// [Prot::WO] (Write-Only) and [Prot::RW] (Read-Write) constants to specify the memory's protection +/// level. #[derive(Clone, Copy, Debug)] pub struct Prot { + /// The memory is readable pub read: bool, + /// The memory is writeable pub write: bool, } + +/// Implements the memory protection level constants impl Prot { + /// A constant representing Read-Only memory. pub const RO: Self = Self { read: true, write: false, }; + + /// A constant representing Write-Only memory pub const WO: Self = Self { read: false, write: true, }; + + /// A constant representing Read-Write memory pub const RW: Self = Self { read: true, write: true, @@ -46,6 +90,34 @@ impl Prot { // TODO: Safe, as the kernel ensures it doesn't conflict with any other memory described in the // memory map for regular RAM. +/// Maps physical memory to virtual memory +/// +/// # Arguments +/// +/// * 'base_phys: [usize]' - The base address of the physical memory to map. +/// * 'len: [usize]' - The length of the physical memory to map (Should be a multiple of [PAGE_SIZE] +/// * '_: [Prot]' - The memory protection level of the mapping. +/// * 'type: [MemoryType]' - The caching behavior specification of the memory. +/// +/// # Returns +/// +/// A '[Result]<*mut ()>' which is: +/// - '[Ok]' containing a raw pointer to the mapped memory. +/// - '[Err]' which contains an error on failure. +/// +/// # Errors +/// +/// This function will return an error if: +/// - An invalid value is provided to 'read' or 'write' +/// - The system could not open a file descriptor to the memory scheme for the specified [MemoryType]. +/// - The system failed to map the physical address to a virtual address. See [libredox::call::mmap] +/// +/// +/// # Notes +/// - This function is unsafe, and upon using it you will be responsible for freeing the memory with +/// [libredox::call::munmap]. If you want a safe accessor, use [PhysBorrowed] instead. +/// - The MemoryType specified is used to tell the function which memory scheme to access. (i.e +/// /scheme/memory/physical@wb, /scheme/memory/physical@uc, etc). pub unsafe fn physmap( base_phys: usize, len: usize, @@ -102,11 +174,28 @@ impl std::fmt::Display for MemoryType { } } +/// A safe virtual mapping to physical memory that unmaps the memory when the structure goes out +/// of scope. +/// +/// This function provides a safe binding to [physmap]. It implements Drop to free the mapped memory +/// when the structure goes out of scope. pub struct PhysBorrowed { mem: *mut (), len: usize, } impl PhysBorrowed { + /// Constructs a PhysBorrowed instance. + /// + /// # Arguments + /// See [physmap] for a description of the parameters. + /// + /// # Returns + /// A '[Result]' which contains the following: + /// - A '[PhysBorrowed]' which represents the newly mapped region. + /// - An 'Err' if a memory mapping error occurs. + /// + /// # Errors + /// See [physmap] for a description of the error cases. pub fn map(base_phys: usize, len: usize, prot: Prot, ty: MemoryType) -> Result { let mem = unsafe { physmap(base_phys, len, prot, ty)? }; Ok(Self { @@ -114,14 +203,31 @@ impl PhysBorrowed { len: len.next_multiple_of(PAGE_SIZE), }) } + + /// Gets a raw pointer to the borrowed region. + /// + /// # Returns + /// - self.mem - A pointer to the mapped region in virtual memory. + /// + /// # Notes + /// - The pointer may live beyond the lifetime of [PhysBorrowed], so dereferences to the pointer + /// must be treated as unsafe. + /// pub fn as_ptr(&self) -> *mut () { self.mem } + + /// Gets the length of the mapped region. + /// + /// # Returns + /// - self.len - The length of the mapped region. It should be a multiple of [PAGE_SIZE] pub fn mapped_len(&self) -> usize { self.len } } + impl Drop for PhysBorrowed { + /// Frees the mapped memory region. fn drop(&mut self) { unsafe { let _ = libredox::call::munmap(self.mem, self.len); @@ -129,6 +235,12 @@ impl Drop for PhysBorrowed { } } +/// Uses the [syscall::iopl] system call to set the I/O privilege level of the current process +/// to 3. +/// +/// In Redox, x86 privilege ring 3 represents userspace. Most Redox drivers run in userspace to +/// prevent system instability caused by a faulty driver. Processes with ring 3 IOPL have access to +/// I/O ports. pub fn acquire_port_io_rights() -> Result<()> { unsafe { syscall::iopl(3)?; From e9e7e2934ee0a862960641e857d1d61a0d04b260 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Sat, 31 Aug 2024 16:16:35 -0700 Subject: [PATCH 0973/1301] Added documentation for the dma, logger, and sgl modules --- common/src/dma.rs | 89 ++++++++++++++++++++++++++++++++++++++++++++ common/src/logger.rs | 1 + common/src/sgl.rs | 21 +++++++++++ 3 files changed, 111 insertions(+) diff --git a/common/src/dma.rs b/common/src/dma.rs index fbeb74bf96..98233411d2 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -8,6 +8,10 @@ use syscall::PAGE_SIZE; use crate::MemoryType; +/// Defines the platform-specific memory type for DMA operations +/// +/// - On x86 systems, DMA uses Write-back memory ([MemoryType::Writeback]) +/// - On aarch64 systems, DMA uses uncacheable memory ([MemoryType::Uncacheable]) const DMA_MEMTY: MemoryType = { if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { // x86 ensures cache coherence with DMA memory @@ -20,6 +24,19 @@ const DMA_MEMTY: MemoryType = { } }; +/// Returns a file descriptor for zeroized physically-contiguous DMA memory. +/// +/// # Returns +/// +/// A [Result] containing: +/// - '[Ok]' - A [Fd] (file descriptor) to zeroized, physically continuous DMA usable memory +/// - '[Err]' - The error returned by the provider of the /scheme/memory/zeroed scheme. +/// +/// # Errors +/// +/// This function can return an error in the following case: +/// +/// - The request for the physical memory fails. pub(crate) fn phys_contiguous_fd() -> Result { Fd::open( &format!("/scheme/memory/zeroed@{DMA_MEMTY}?phys_contiguous"), @@ -28,6 +45,26 @@ pub(crate) fn phys_contiguous_fd() -> Result { ) } +/// Allocates a chunk of physical memory for DMA, and then maps it to virtual memory. +/// +/// # Arguments +/// 'length: [usize]' - The length of the memory region. Must be a multiple of [PAGE_SIZE] +/// +/// # Returns +/// +/// This function returns a [Result] containing the following: +/// - A '[Ok]([usize], *[mut] ())' containing a Tuple of the physical address of the region, and a raw pointer to that region in virtual memory. +/// - An '[Err]' - containing the error for the operation. +/// +/// # Errors +/// +/// This function asserts if: +/// - length is not a multiple of [PAGE_SIZE] +/// +/// This function returns an error if: +/// - A file descriptor to physically contiguous memory of type [DMA_MEMTY] could not be acquired +/// - A virtual mapping for the physically contiguous memory could not be created +/// - The virtual address returned by the memory manager was invalid. fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> { assert_eq!(length % PAGE_SIZE, 0); unsafe { @@ -52,13 +89,29 @@ fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> { } } +/// A safe accessor for DMA memory. pub struct Dma { + /// The physical address of the memory phys: usize, + /// The page-aligned length of the memory. Will be a multiple of [PAGE_SIZE] aligned_len: usize, + /// The pointer to the Dma memory in the virtual address space. virt: *mut T, } impl Dma { + /// [Dma] constructor that allocates and initializes a region of DMA memory with the page-aligned + /// size and initial value of some T + /// + /// # Arguments + /// 'value: T' - The initial value to write to the allocated region + /// + /// # Returns + /// + /// This function returns a [Result] containing the following: + /// + /// - A '[Ok] (`[Dma]`)' containing the initialized region + /// - An '[Err]' containing an error. pub fn new(value: T) -> Result { unsafe { let mut zeroed = Self::zeroed()?; @@ -66,6 +119,15 @@ impl Dma { Ok(zeroed.assume_init()) } } + + /// [Dma] constructor that allocates and zeroizes a memory region of the page-aligned size of T + /// + /// # Returns + /// + /// This function returns a [Result] containing the following: + /// + /// - A '[Ok] (`[Dma]<[MaybeUninit]>`)' containing the allocated and zeroized memory + /// - An '[Err]' containing an error. pub fn zeroed() -> Result>> { let aligned_len = size_of::().next_multiple_of(PAGE_SIZE); let (phys, virt) = alloc_and_map(aligned_len)?; @@ -78,6 +140,16 @@ impl Dma { } impl Dma> { + /// Assumes that possibly uninitialized DMA memory has been initialized, and returns a new + /// instance of an object of type `[Dma]`. + /// + /// # Returns + /// - `[Dma]` - The original structure without the [MaybeUninit] wrapper around its contents. + /// + /// # Notes + /// - This is unsafe because it assumes that the memory stored within the `[Dma]` is a valid + /// instance of T. If it isn't (for example -- if it was initialized with [Dma::zeroed]), + /// then the underlying memory may not contain the expected T structure. pub unsafe fn assume_init(self) -> Dma { let Dma { phys, @@ -94,12 +166,23 @@ impl Dma> { } } impl Dma { + /// Returns the physical address of the physical memory that this [Dma] structure references. + /// + /// # Returns + /// [usize] - The physical address of the memory. pub fn physical(&self) -> usize { self.phys } } impl Dma<[T]> { + /// Returns a [Dma] object containing a zeroized slice of T with a given count. + /// + /// # Arguments + /// + /// - 'count: [usize]' - The number of elements of type T in the allocated slice. + /// + /// pub fn zeroed_slice(count: usize) -> Result]>> { let aligned_len = count .checked_mul(size_of::()) @@ -113,6 +196,11 @@ impl Dma<[T]> { virt: ptr::slice_from_raw_parts_mut(virt.cast(), count), }) } + + /// Casts the slice from type T to type U. + /// + /// # Returns + /// '`[DMA]`' - A cast handle to the Dma memory. pub unsafe fn cast_slice(self) -> Dma<[U]> { let Dma { phys, @@ -129,6 +217,7 @@ impl Dma<[T]> { } } impl Dma<[MaybeUninit]> { + /// See [`Dma>::assume_init`] pub unsafe fn assume_init(self) -> Dma<[T]> { let &Dma { phys, diff --git a/common/src/logger.rs b/common/src/logger.rs index 4f39f253b9..6b62cf86fe 100644 --- a/common/src/logger.rs +++ b/common/src/logger.rs @@ -1,5 +1,6 @@ use redox_log::{OutputBuilder, RedoxLogger}; +/// Configures logging for a single driver. #[cfg_attr(not(target_os = "redox"), allow(unused_variables, unused_mut))] pub fn setup_logging( category: &str, diff --git a/common/src/sgl.rs b/common/src/sgl.rs index cdd043415c..541250fbe9 100644 --- a/common/src/sgl.rs +++ b/common/src/sgl.rs @@ -8,21 +8,38 @@ use syscall::{MAP_FIXED, PAGE_SIZE}; use crate::dma::phys_contiguous_fd; +/// A Scatter-Gather List data structure +/// +/// See: https://en.wikipedia.org/wiki/Gather/scatter_(vector_addressing) #[derive(Debug)] pub struct Sgl { + /// A raw pointer to the SGL in virtual memory virt: *mut u8, + /// The length of the allocated memory. This value is NOT guaranteed to be a multiple of [PAGE_SIZE] unaligned_length: NonZeroUsize, + /// The vector of chunks tracked by this [Sgl] object. This is the sparsely-populated vector in the SGL algorithm. chunks: Vec, } + +/// A structure representing a chunk of memory in the sparsely-populated vector of the SGL #[derive(Debug)] pub struct Chunk { + /// The offset of the chunk in the sparsely-populated vector. pub offset: usize, + /// The physical address of the chunk pub phys: usize, + /// A raw pointer to the chunk in virtual memory pub virt: *mut u8, + /// The length of the chunk in bytes. pub length: usize, } impl Sgl { + /// Constructor for the scatter/gather list. + /// + /// # Arguments + /// + /// 'unaligned_length: [usize]' - The length of the SGL, not aligned to the nearest page. pub fn new(unaligned_length: usize) -> Result { let unaligned_length = NonZeroUsize::new(unaligned_length).ok_or(Error::new(EINVAL))?; @@ -77,12 +94,16 @@ impl Sgl { Ok(this) } } + /// Returns an immutable reference to the vector of chunks pub fn chunks(&self) -> &[Chunk] { &self.chunks } + + /// Returns a raw pointer to the vector of chunks in virtual memory pub fn as_ptr(&self) -> *mut u8 { self.virt } + /// Returns the length of the scatter-gather list. pub fn len(&self) -> usize { self.unaligned_length.get() } From f2decff457bf75f80a8c49b0e82553977b0e4fb5 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Sat, 31 Aug 2024 16:17:13 -0700 Subject: [PATCH 0974/1301] Added link wrappers around the wikipedia link in SGL --- common/src/sgl.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/sgl.rs b/common/src/sgl.rs index 541250fbe9..ba26d3f00b 100644 --- a/common/src/sgl.rs +++ b/common/src/sgl.rs @@ -10,7 +10,7 @@ use crate::dma::phys_contiguous_fd; /// A Scatter-Gather List data structure /// -/// See: https://en.wikipedia.org/wiki/Gather/scatter_(vector_addressing) +/// See: #[derive(Debug)] pub struct Sgl { /// A raw pointer to the SGL in virtual memory From 1ce19494161f33de90e3ec8c01aa7bfa2ca3c0c9 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Sat, 31 Aug 2024 16:19:58 -0700 Subject: [PATCH 0975/1301] Ran rustfmt to re-format my changes --- common/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/common/src/lib.rs b/common/src/lib.rs index 7a8d91b5f8..66f3686530 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -44,7 +44,8 @@ pub enum MemoryType { /// released to the memory location in an unspecified order. Write-Combine memory does not /// guarantee that the order at which you write to it is the order at which those writes are /// committed to memory. - WriteCombining, /// Memory stored in an intermediate Write Combine Buffer and released later + WriteCombining, + /// Memory stored in an intermediate Write Combine Buffer and released later /// Memory-Mapped I/O. This is an aarch64-specific term. DeviceMemory, } From b29d2c7c9ed214e082743e58cb616cf594214306 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 4 Sep 2024 15:00:35 -0600 Subject: [PATCH 0976/1301] xhcid: switch back to interrupts --- xhcid/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 972884994a..4c5022ce6d 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -161,7 +161,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .ptr .as_ptr() as usize; - let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //TODO: get_int_method(&mut pcid_handle, address); + let (irq_file, interrupt_method) = get_int_method(&mut pcid_handle, address); println!(" + XHCI {}", pci_config.func.display()); From 897866d948ad54fd815ce3228f58565d9196391c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 6 Sep 2024 20:09:04 -0600 Subject: [PATCH 0977/1301] xhcid: switch back to polling and leave TODO --- xhcid/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 4c5022ce6d..c2fa344044 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -161,7 +161,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .ptr .as_ptr() as usize; - let (irq_file, interrupt_method) = get_int_method(&mut pcid_handle, address); + let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); + // TODO: fix interrutps: get_int_method(&mut pcid_handle, address); println!(" + XHCI {}", pci_config.func.display()); From 39f43a51a1e46de24c7387e242d80d396f8d8421 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Tue, 10 Sep 2024 00:43:42 +0000 Subject: [PATCH 0978/1301] Added some documentation to the XHCI daemon, clarified the scheme interface with a refactor --- Cargo.lock | 39 + xhcid/Cargo.toml | 1 + xhcid/src/driver_interface.rs | 20 +- xhcid/src/lib.rs | 25 + xhcid/src/main.rs | 105 ++- xhcid/src/usb/device.rs | 124 +++ xhcid/src/usb/endpoint.rs | 12 + xhcid/src/usb/hub.rs | 4 +- xhcid/src/usb/interface.rs | 1 + xhcid/src/usb/mod.rs | 26 + xhcid/src/xhci/capability.rs | 151 +++- xhcid/src/xhci/context.rs | 26 +- xhcid/src/xhci/event.rs | 10 +- xhcid/src/xhci/irq_reactor.rs | 195 +++-- xhcid/src/xhci/mod.rs | 261 +++++-- xhcid/src/xhci/operational.rs | 62 ++ xhcid/src/xhci/ring.rs | 33 +- xhcid/src/xhci/scheme.rs | 1353 +++++++++++++++++++++++---------- xhcid/src/xhci/trb.rs | 21 +- 19 files changed, 1896 insertions(+), 573 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2430ad1b44..aa9a3a5ccf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -54,6 +54,15 @@ dependencies = [ "redox_syscall 0.5.3", ] +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + [[package]] name = "alxd" version = "0.1.0" @@ -1150,6 +1159,35 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + [[package]] name = "rehid" version = "0.1.0" @@ -1906,6 +1944,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall 0.5.3", + "regex", "serde", "serde_json", "smallvec 1.13.2", diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 820d1e5291..865f4d9600 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -31,3 +31,4 @@ toml = "0.5" common = { path = "../common" } pcid = { path = "../pcid" } libredox = "0.1.3" +regex = "1.10.6" diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index a1eedb7381..37bc50d68d 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -188,7 +188,8 @@ impl EndpDesc { } else { None } - }).flatten() + }) + .flatten() } pub fn isoch_mult(&self, lec: bool) -> u8 { if !lec && self.is_isoch() { @@ -439,11 +440,17 @@ impl XhciClientHandle { Ok(string.parse()?) } pub fn open_endpoint_ctl(&self, num: u8) -> result::Result { - let path = format!("/scheme/{}/port{}/endpoints/{}/ctl", self.scheme, self.port, num); + let path = format!( + "/scheme/{}/port{}/endpoints/{}/ctl", + self.scheme, self.port, num + ); Ok(File::open(path)?) } pub fn open_endpoint_data(&self, num: u8) -> result::Result { - let path = format!("/scheme/{}/port{}/endpoints/{}/data", self.scheme, self.port, num); + let path = format!( + "/scheme/{}/port{}/endpoints/{}/data", + self.scheme, self.port, num + ); Ok(File::open(path)?) } pub fn open_endpoint(&self, num: u8) -> result::Result { @@ -653,9 +660,10 @@ impl XhciEndpHandle { let res = self.ctl_res()?; match res { - XhciEndpCtlRes::TransferResult(PortTransferStatus { kind: PortTransferStatusKind::Success, .. }) - if bytes_read != expected_len as usize => - { + XhciEndpCtlRes::TransferResult(PortTransferStatus { + kind: PortTransferStatusKind::Success, + .. + }) if bytes_read != expected_len as usize => { Err(Invalid("no short packet, but fewer bytes were read/written").into()) } XhciEndpCtlRes::TransferResult(r) => Ok(r), diff --git a/xhcid/src/lib.rs b/xhcid/src/lib.rs index 16b3d91b64..e1bfb5e222 100644 --- a/xhcid/src/lib.rs +++ b/xhcid/src/lib.rs @@ -1,3 +1,28 @@ +//! The eXtensible Host Controller Interface (XHCI) Daemon Interface +//! +//! This crate implements the driver interface for interacting with the Redox xhcid daemon from +//! another userspace process. +//! +//! XHCI is a standard for the USB Host Controller interface specified by Intel that provides a +//! common register interface for systems to use to interact with the Universal Serial Bus (USB) +//! subsystem. +//! +//! USB consists of three types of devices: The Host Controller/Root Hub, USB Hubs, and Endpoints. +//! Endpoints represent actual devices connected to the USB fabric. USB Hubs are intermediaries +//! between the Host Controller and the endpoints that report when devices have been connected/disconnected. +//! The Host Controller provides the interface to the USB subsystem that software running on the +//! system's CPU can interact with. It's a tree-like structure, which the Host Controller enumerating +//! and addressing all the hubs and endpoints in the tree. Data then flows through the fabric +//! using the USB protocol (2.0 or 3.2) as packets. Hubs have multiple ports that endpoints can +//! connect to, and they notify the Host Controller/Root Hub when devices are hot plugged or removed. +//! +//! This documentation will refer directly to the relevant standards, which are as follows: +//! +//! - XHCI - [eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf) +//! - USB2 - [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification) +//! - USB32 - [Universal Serial Bus 3.2 Specification Revision 1.1](https://usb.org/document-library/usb-32-revision-11-june-2022) +//! +#![warn(missing_docs)] pub extern crate plain; mod driver_interface; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index c2fa344044..e3798cd580 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -1,7 +1,33 @@ +//! The eXtensible Host Controller Interface (XHCI) Daemon +//! +//! This crate provides the executable xhcid daemon that implements the driver for interacting with +//! a PCIe XHCI device +//! +//! XHCI is a standard for the USB Host Controller interface specified by Intel that provides a +//! common register interface for systems to use to interact with the Universal Serial Bus (USB) +//! subsystem. +//! +//! USB consists of three types of devices: The Host Controller/Root Hub, USB Hubs, and Endpoints. +//! Endpoints represent actual devices connected to the USB fabric. USB Hubs are intermediaries +//! between the Host Controller and the endpoints that report when devices have been connected/disconnected. +//! The Host Controller provides the interface to the USB subsystem that software running on the +//! system's CPU can interact with. It's a tree-like structure, which the Host Controller enumerating +//! and addressing all the hubs and endpoints in the tree. Data then flows through the fabric +//! using the USB protocol (2.0 or 3.2) as packets. Hubs have multiple ports that endpoints can +//! connect to, and they notify the Host Controller/Root Hub when devices are hot plugged or removed. +//! +//! This documentation will refer directly to the relevant standards, which are as follows: +//! +//! - XHCI - [eXtensible Host Controller Interface for Universal Serial Bus (xHCI) Requirements Specification](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf) +//! - USB2 - [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification) +//! - USB32 - [Universal Serial Bus 3.2 Specification Revision 1.1](https://usb.org/document-library/usb-32-revision-11-june-2022) +//! +#![warn(missing_docs)] #[macro_use] extern crate bitflags; use std::convert::{TryFrom, TryInto}; +use std::env; use std::fs::{self, File}; use std::future::Future; use std::io::{self, Read, Write}; @@ -9,21 +35,22 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::pin::Pin; use std::ptr::NonNull; use std::sync::{Arc, Mutex}; -use std::env; use libredox::flag; -use pcid_interface::{MsiSetFeatureInfo, PciFunctionHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::MsixTableEntry; +use pcid_interface::{ + MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, +}; use event::{Event, RawEventQueue}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::EventFlags; -use syscall::scheme::Scheme; use syscall::io::Io; +use syscall::scheme::Scheme; use crate::xhci::{InterruptMethod, Xhci}; @@ -40,17 +67,25 @@ async fn handle_packet(hci: Arc, packet: Packet) -> Packet { } #[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PciFunctionHandle, bar0_address: usize) -> (Option, InterruptMethod) { +fn get_int_method( + pcid_handle: &mut PciFunctionHandle, + bar0_address: usize, +) -> (Option, InterruptMethod) { let pci_config = pcid_handle.config(); - let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features"); + let all_pci_features = pcid_handle + .fetch_all_features() + .expect("xhcid: failed to fetch pci features"); log::debug!("XHCI PCI FEATURES: {:?}", all_pci_features); let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); if has_msi && !has_msix { - let mut capability = match pcid_handle.feature_info(PciFeature::Msi).expect("xhcid: failed to retrieve the MSI capability structure from pcid") { + let mut capability = match pcid_handle + .feature_info(PciFeature::Msi) + .expect("xhcid: failed to retrieve the MSI capability structure from pcid") + { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), }; @@ -60,28 +95,37 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle, bar0_address: usize) -> ( // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = allocate_single_interrupt_vector_for_msi(destination_id); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); let set_feature_info = MsiSetFeatureInfo { multi_message_enable: Some(0), message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("xhcid: failed to set feature info"); + pcid_handle + .set_feature_info(SetFeatureInfo::Msi(set_feature_info)) + .expect("xhcid: failed to set feature info"); - pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI"); + pcid_handle + .enable_feature(PciFeature::Msi) + .expect("xhcid: failed to enable MSI"); log::debug!("Enabled MSI"); (Some(interrupt_handle), InterruptMethod::Msi) } else if has_msix { - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") { + let msix_info = match pcid_handle + .feature_info(PciFeature::MsiX) + .expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") + { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; msix_info.validate(pci_config.func.bars); assert_eq!(msix_info.table_bar, 0); - let virt_table_base = (bar0_address + msix_info.table_offset as usize) as *mut MsixTableEntry; + let virt_table_base = + (bar0_address + msix_info.table_offset as usize) as *mut MsixTableEntry; let mut info = xhci::MappedMsixRegs { virt_table_base: NonNull::new(virt_table_base).unwrap(), @@ -98,14 +142,20 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle, bar0_address: usize) -> ( let table_entry_pointer = info.table_entry_pointer(k); let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = allocate_single_interrupt_vector_for_msi(destination_id); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); table_entry_pointer.write_addr_and_data(msg_addr_and_data); table_entry_pointer.unmask(); - (Some(interrupt_handle), InterruptMethod::MsiX(Mutex::new(info))) + ( + Some(interrupt_handle), + InterruptMethod::MsiX(Mutex::new(info)), + ) }; - pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X"); + pcid_handle + .enable_feature(PciFeature::MsiX) + .expect("xhcid: failed to enable MSI-X"); log::debug!("Enabled MSI-X"); method @@ -122,7 +172,10 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle, bar0_address: usize) -> ( //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PciFunctionHandle, address: usize) -> (Option, InterruptMethod) { +fn get_int_method( + pcid_handle: &mut PciFunctionHandle, + address: usize, +) -> (Option, InterruptMethod) { let pci_config = pcid_handle.config(); if let Some(irq) = pci_config.func.legacy_interrupt_line { @@ -167,19 +220,17 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { println!(" + XHCI {}", pci_config.func.display()); let scheme_name = format!("usb.{}", name); - let socket_fd = libredox::call::open( - format!(":{}", scheme_name), - flag::O_RDWR | flag::O_CREAT, - 0, - ) - .expect("xhcid: failed to create usb scheme"); - let socket = Arc::new(Mutex::new(unsafe { - File::from_raw_fd(socket_fd as RawFd) - })); + let socket_fd = + libredox::call::open(format!(":{}", scheme_name), flag::O_RDWR | flag::O_CREAT, 0) + .expect("xhcid: failed to create usb scheme"); + let socket = Arc::new(Mutex::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); daemon.ready().expect("xhcid: failed to notify parent"); - let hci = Arc::new(Xhci::new(scheme_name, address, interrupt_method, pcid_handle).expect("xhcid: failed to allocate device")); + let hci = Arc::new( + Xhci::new(scheme_name, address, interrupt_method, pcid_handle) + .expect("xhcid: failed to allocate device"), + ); xhci::start_irq_reactor(&hci, irq_file); futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe"); @@ -212,7 +263,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { packet.a = a; todo.push(packet); } else { - socket.write(&packet).expect("xhcid failed to write to socket"); + socket + .write(&packet) + .expect("xhcid failed to write to socket"); } } diff --git a/xhcid/src/usb/device.rs b/xhcid/src/usb/device.rs index c7d1835cf7..59a09f1f98 100644 --- a/xhcid/src/usb/device.rs +++ b/xhcid/src/usb/device.rs @@ -1,66 +1,190 @@ +//! Implements the "Device" USB Descriptor. +//! +//! This descriptor is described in USB32 section 9.6.1 + +/// A USB Device Descriptor. +/// +/// This is common to all USB standards, and "provides information that applies globally to the +/// device and all the device's configurations" (USB32 9.6.1) +/// +/// A given device will only have one device descriptor. +/// +/// USB32 Table 9-11 describes the USB packet offsets of the fields described by this structure. #[repr(packed)] #[derive(Clone, Copy, Debug, Default)] pub struct DeviceDescriptor { + /// The length of this descriptor in bytes. + /// The bLength field in USB32 Table 9-11 pub length: u8, + /// The descriptor type. See [DescriptorKind] + /// The bDescriptorType field in USB32 Table 9-11. pub kind: u8, + /// The USB standard version in binary-coded decimal. + /// + /// USB 2.1 would be encoded as 210H, 3.2 would be 320H. + /// The bcdUSB field in USB32 Table 9-11 pub usb: u16, + /// The USB Class Code. + /// + /// bDeviceClass in USB32 Table 9-11. + /// + /// These are values assigned by USB-IF that describes the type of device connected via USB. + /// + /// A value of FF indicates a vendor-specific class. A value of 0 indicates that all the + /// interfaces in a configuration will provide their own class information. pub class: u8, + /// The USB Sub Device Class Code. + /// + /// bDeviceSubClass in USB32 Table 9-11 + /// + /// These specify subclasses of a device class specified by the 'class' field. pub sub_class: u8, + /// The USB Protocol code. + /// + /// bDeviceProtocol in USB32 Table 9-11 + /// + /// This qualified by the class and sub_class fields, and specifies the application-layer protocol + /// (the protocol encapsulated by USB) of this device. pub protocol: u8, + /// The maximum packet size for endpoint 0. + /// + /// bMaxPacketSize0 in USB32 Table 9-11 pub packet_size: u8, + /// The USB Vendor ID + /// + /// idVendor in USB32 Table 9-11 pub vendor: u16, + /// The USB Product ID + /// + /// idProduct in USB32 Table 9-11 pub product: u16, + /// The device release number in binary-coded decimal. + /// + /// bcdDevice in USB32 Table 9-11 pub release: u16, + /// Index of the String Descriptor describing the device manufacturer + /// + /// iManufacturer in USB32 Table 9-11 pub manufacturer_str: u8, + /// Index of the String Descriptor describing the product + /// + /// iProduct in Table 9-11 pub product_str: u8, + /// Index of the string descriptor describing the device's serial number + /// + /// iSerialNumber in USB32 Table 9-11 pub serial_str: u8, + /// The number of possible configurations (Configuration Descriptors) for this device. + /// + /// bNumConfigurations in USB32 Table 9-11 pub configurations: u8, } unsafe impl plain::Plain for DeviceDescriptor {} impl DeviceDescriptor { + /// Gets the USB Minor Version pub fn minor_usb_vers(&self) -> u8 { (self.usb & 0xFF) as u8 } + /// Gets the USB Major Version pub fn major_usb_vers(&self) -> u8 { ((self.usb >> 8) & 0xFF) as u8 } } +/// The 8-byte version of the Device Descriptor +/// +/// This is a subset of the full Device Descriptor. When the system is first performing device +/// enumeration, it will request only the first eight bytes of the DeviceDescriptor from each +/// device as this contains the crucial information, and then it will request the full descriptor +/// at a later point. +/// +/// See [DeviceDescriptor] #[repr(packed)] #[derive(Clone, Copy, Debug, Default)] pub struct DeviceDescriptor8Byte { + /// See [DeviceDescriptor] pub length: u8, + /// See [DeviceDescriptor] pub kind: u8, + /// See [DeviceDescriptor] pub usb: u16, + /// See [DeviceDescriptor] pub class: u8, + /// See [DeviceDescriptor] pub sub_class: u8, + /// See [DeviceDescriptor] pub protocol: u8, + /// See [DeviceDescriptor] pub packet_size: u8, } unsafe impl plain::Plain for DeviceDescriptor8Byte {} impl DeviceDescriptor8Byte { + /// Gets the USB Minor Version pub fn minor_usb_vers(&self) -> u8 { (self.usb & 0xFF) as u8 } + + /// Gets the USB Major Version pub fn major_usb_vers(&self) -> u8 { ((self.usb >> 8) & 0xFF) as u8 } } +/// A Device Qualifier Descriptor +/// +/// This is a descriptor specific to the USB2 standard, and was deprecated in USB3. USB2 devices +/// will still provide this value. +/// +/// A Device Qualifier is sent by a high-speed capable USB2 device to describe information in its +/// descriptor that would change if it was operating at the other speed. If it was at low speed, +/// the qualifier would describe the device at high speed. If it was at high speed, the qualifier +/// would describe the device at low speed. +/// +/// See USB2 section 9.6.2 +/// +/// The packet offsets are described in USB2 Table 9-9 #[repr(packed)] pub struct DeviceQualifier { + /// The size of the descriptor. + /// + /// bLength in USB2 Table 9-9 pub length: u8, + /// The Device Descriptor Type (see [xhci_interface::usb::DescriptorKind]) + /// + /// bDescriptorType in USB2 Table 9-9 pub kind: u8, + /// The USB specification version number in binary-coded decimal + /// + /// bDeviceClass in USB2 Table 9-9 pub usb: u16, + /// The USB Device Class Code + /// + /// bDeviceClass in USB2 Table 9-9 pub class: u8, + /// The USB Device Sub Class Code + /// + /// bDeviceSubClass in USB2 Table 9-9 pub sub_class: u8, + /// The USB Device Protocol Code + /// + /// bDeviceProtocol in USB2 Table 9-9 pub protocol: u8, + /// The maximum packet size for the other speed\ + /// + /// bMaxPacketSize0 in USB2 Table9-9 pub pkgsz_other_speed: u8, + /// The number of device configurations for the other speed + /// + /// bNumConfiguration in USB2 Table 9-9 pub num_other_speed_cfgs: u8, + /// Reserved for future use by the USB2 standard + /// + /// (DeviceQualifier was dropped in USB3, so it was never used!) + /// bReserved in USB2 Table 9-9 pub _rsvd: u8, } diff --git a/xhcid/src/usb/endpoint.rs b/xhcid/src/usb/endpoint.rs index 39e28eb6f4..c8f8163c62 100644 --- a/xhcid/src/usb/endpoint.rs +++ b/xhcid/src/usb/endpoint.rs @@ -1,5 +1,16 @@ use plain::Plain; +/// The descriptor for a USB Endpoint. +/// +/// Each endpoint for a particular interface has its own descriptor. The information in this +/// structure is used by the host to determine the bandwidth requirements of the endpoint. +/// +/// This is returned automatically when you send a request for a ConfigurationDescriptor, +/// and cannot be requested individually. +/// +/// See USB32 9.6.6 +/// +/// The offsets for the fields in the packet are described in USB32 Table 9-26 #[repr(packed)] #[derive(Clone, Copy, Debug, Default)] pub struct EndpointDescriptor { @@ -11,6 +22,7 @@ pub struct EndpointDescriptor { pub interval: u8, } +/// Mask that is ANDed to the [EndpointDescriptor].attributes buffer to get the endpoint type. pub const ENDP_ATTR_TY_MASK: u8 = 0x3; #[repr(u8)] diff --git a/xhcid/src/usb/hub.rs b/xhcid/src/usb/hub.rs index 854ff30a74..99022ec7a7 100644 --- a/xhcid/src/usb/hub.rs +++ b/xhcid/src/usb/hub.rs @@ -9,7 +9,7 @@ pub struct HubDescriptor { pub current: u8, // device_removable: bitmap of ports, maximum of 256 bits (32 bytes) // power_control_mask: bitmap of ports, maximum of 256 bits (32 bytes) - bitmaps: [u8; 64] + bitmaps: [u8; 64], } unsafe impl plain::Plain for HubDescriptor {} @@ -23,7 +23,7 @@ impl Default for HubDescriptor { characteristics: 0, power_on_good: 0, current: 0, - bitmaps: [0; 64] + bitmaps: [0; 64], } } } diff --git a/xhcid/src/usb/interface.rs b/xhcid/src/usb/interface.rs index 5931e71893..1030993bb8 100644 --- a/xhcid/src/usb/interface.rs +++ b/xhcid/src/usb/interface.rs @@ -1,5 +1,6 @@ use plain::Plain; +/// #[repr(packed)] #[derive(Clone, Copy, Debug, Default)] pub struct InterfaceDescriptor { diff --git a/xhcid/src/usb/mod.rs b/xhcid/src/usb/mod.rs index 246cc77f8b..d0d659882a 100644 --- a/xhcid/src/usb/mod.rs +++ b/xhcid/src/usb/mod.rs @@ -1,3 +1,13 @@ +//! The Universal Serial Bus (USB) Module +//! +//! The implementations in this module are common to all USB interfaces (though individual elements +//! may be specific to only 2.0 or 3.2), and are used by specialized driver components like [xhci] +//! to implement the driver interface. +//! +//! The [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification) and the [Universal Serial Bus 3.2 Specification](https://usb.org/document-library/usb-32-revision-11-june-2022) are +//! the documents that inform this implementation. +//! +//! See the crate-level documentation for the acronyms used to refer to specific documents. pub use self::bos::{bos_capability_descs, BosAnyDevDesc, BosDescriptor, BosSuperSpeedDesc}; pub use self::config::ConfigDescriptor; pub use self::device::{DeviceDescriptor, DeviceDescriptor8Byte}; @@ -9,22 +19,38 @@ pub use self::hub::*; pub use self::interface::InterfaceDescriptor; pub use self::setup::{Setup, SetupReq}; +/// Enumerates the list of descriptor kinds that can be reported by a USB device to report its +/// attributes to the system. (See USB32 Sections 9.5 and 9.6) #[derive(Clone, Copy, Debug)] #[repr(u8)] pub enum DescriptorKind { + /// No Descriptor TODO: Determine why this state exists, and what it does in the code. None = 0, + /// A Device Descriptor. See [DeviceDescriptor] Device = 1, + /// A Configuration Descriptor. See [ConfigDescriptor] Configuration = 2, + /// A String Descriptor. See (USB32 Section 9.6.9). String = 3, + /// An Interface Descriptor. See [InterfaceDescriptor] Interface = 4, + /// An Endpoint Descriptor. See [EndpointDescriptor] Endpoint = 5, + /// A Device Qualifier. USB2-specific. See [DeviceQualifier] DeviceQualifier = 6, + /// The "Other Speed Configuration" descriptor. USB2-specific. See (USB2 9.6.4] OtherSpeedConfiguration = 7, + /// TODO: Determine the standard that specifies this InterfacePower = 8, + /// TODO: Determine the standard that specifies this (Possibly USB-C?) OnTheGo = 9, + /// A Binary Device Object Store Descriptor. See [BosDescriptor] BinaryObjectStorage = 15, + /// TODO: Track down the HID standard for references Hid = 33, + /// A USB Hub Device Descriptor. See [HubDescriptor] Hub = 41, + /// A Super Speed Endpoint Companion Descriptor. See [SuperSpeedCompanionDescriptor] SuperSpeedCompanion = 48, } diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index 5479be88fb..ab3ffb8502 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -1,77 +1,216 @@ use syscall::io::{Io, Mmio}; +/// Represents the memory-mapped Capability Registers of the XHCI +/// +/// These are read-only registers that specify the capabilities +/// of the host controller implementation. +/// +/// They are used by the driver to determine what subsystems to +/// configure during initialization. +/// +/// See XHCI Section 5.3. Table 5-9 describes the offsets of the registers +/// in memory. #[repr(packed)] pub struct CapabilityRegs { + /// The length of the Capability Registers data structure in XHCI memory. + /// + /// While only the registers in this structure are defined by the XHCI standard, + /// the standard defines an arbitrary amount of space following those registers that + /// are reserved for the standard. As such, you need to know the offset to the operational + /// registers, which immediately follow. + /// + /// CAPLENGTH in XHC Table 5-9. See XHC 5.3.1 pub len: Mmio, + /// Reserved byte + /// + /// Rsvd in XHC Table 5-9 _rsvd: Mmio, + /// The XHCI interface version number in Binary-Encoded Decimal. + /// + /// This specifies the version of the XHCI specification that is supported by this controller. + /// HCIVERSION in XHC Table 5-9 pub hci_ver: Mmio, + /// The HCI Structural Parameters 1 Register. + /// + /// -Bits 0 - 7 describe the number of device slots supported by this controller + /// -Bits 8 - 18 describe the number of interrupters supported by this controller + /// -Bits 19-23 are reserved + /// -Bits 24-31 specify the maximum number of ports supported by this controller. + /// + /// HCPARAMS1 in XHC Table 5-9. See 5.3.3 pub hcs_params1: Mmio, + /// The HCI Structural Parameters 2 Register. + /// + /// - Bits 0-3 describe the Isochronus Scheduling Threshold (IST) + /// - Bits 4-7 describe the Event Ring Segment Table Max (ERST Max). The maximum number of event + /// ring segment table entries is 2^(ERST Max) + /// - Bits 8-20 are reserved + /// - Bits 25-21 describe the high order five bits of the maximum number of scratchpad buffers + /// - Bit 26 is the Scratchpad Restore Buffer (SPR). (See XHC 4.23.2) + /// - Bits 26-31 describe the low order five bits of the maximum number of scratchpad buffers + /// + /// HCPARAMS2 in XHC Table 5-9. See 5.3.4 pub hcs_params2: Mmio, + /// The HCI Structural Parameters 3 Register. + /// + /// - Bits 0-7 describes the worst-case U1 Device Exit Latency. Values are in microseconds, from 00h to 0Ah. 0B-FFh are reserved + /// - Bits 8-15 are reserved + /// - Bits 16-31 describe the worst-case U2 Device Exit Latency. Values are in microseconds, from 0000h to 07FFh. 0800-FFFFh are reserved + /// + /// HCPARAMS3 in XHC Table 5-9. See XHC 5.3.5 pub hcs_params3: Mmio, + /// The HCI Capability Parameters 1 Register. + /// + /// This register defines optional capabilities supported by the xHCI + /// + /// - Bit 0 is the 64-bit Address Capability Flag (AC64). 0 = 32-bit pointers, 1 = 64-bit pointers. + /// - Bit 1 is the Bandwidth Negotation Capability Flag (BNC) + /// - Bit 2 is the Context Size Flag (CSZ). 0 = 32-byte, 1 = 64-byte Context Data Structures + /// - Bit 3 is the Port Power Control Flag (PPC). Indicates whether the implementation supports port power control. + /// - Bit 4 is the Port Indicators Flag (PIND). Indicates whether the XHC root hub supports port indicator control + /// - Bit 5 is the Light Host Controller Reset Capability Flag (LHRC). Indicates whether the implementation supports a light reset + /// - Bit 6 is the Latency Tolerance Messaging Capability Flag (LTC). Indicates whether the implementation supports Latency Tolerance Messaging + /// - Bit 7 is the no Secondary SID Support Flag (NSS). Indicates whether secondary stream ids is supported. 1 = NO, 0 = YES + /// - Bit 8 is the Parse All Event Data Flag (PAE). (See XHC Table 5-13) + /// - Bit 9 is the Stopped - Short Packet Capability Flag (SPC). (See XHC 4.6.9) + /// - Bit 10 is the Stopped EDTLA Capability Flag (SEC). (See XHC 4.6.9, 4.12, and 6.4.4.1) + /// - Bit 11 is the Contiguous Frame ID Capability Flag (CFC). (See XHC 4.11.2.5) + /// - Bits 12-15 are the Maximum Primary Stream Array Size (MaxPSASize). Identifies the maximum size of PSA that the implementation supports. + /// - Bits 16-31 The xHCI Extended Capabilities Pointer (xECP). Points to an extended capabilities list. (See XHC Table 5-13 to see how to process this value) + /// + /// HCCPARAMS1 in XHC Table 5-9. See XHC 5.3.6 pub hcc_params1: Mmio, + /// The Doorbell Offset Register + /// + /// This register defines the offset of the Doorbell Array base address from the Base. + /// + /// Bits 0-1 are reserved. + /// Bits 2-31 contain the offset. + /// + /// DBOFF in XHC Table 5-9. See XHC 5.3.7 pub db_offset: Mmio, + /// The Runtime Register Space Offset + /// + /// The offset of the xHCI Runtime Registers from the Base. + /// + /// - Bits 0-4 are reserved. + /// - Bits 5-31 contain the offset. + /// + /// RTSOFF in XHC Table 5-9. See XHC 5.3.8 pub rts_offset: Mmio, + /// The HC Capability Parameters 2 Register + /// + /// This register defines optional capabilities supported by the xHCI + /// + /// - Bit 0 is the UC3 Entry Capability Flag (U3C). See XHC 4.15.1 + /// - Bit 1 is the Configure Endpoint Command Max Latency Too Large Capability Flag (CMC). See XHC 4.23.5.2 and 5.4.1 + /// - Bit 2 is the Force Save Context Capability (FCS). See XHC 4.23.2 and 5.4.1 + /// - Bit 3 is the Compliance Transition Capability (CTC). See XHC 4.19.2.4.1 + /// - Bit 4 is the Large ESIT Payload Capability (LEC). See XHC 6.2.3.8 + /// - Bit 5 is the Configuration Information Capability (CIC). See XHC 6.2.5.1 + /// - Bit 6 is the Extended TBC Capability (ETC). See XHC 4.11.2.3 + /// - Bit 7 is the Extended TBC TRB Status Capability (ETC_TSC). See XHC 4.11.2.3 + /// - Bit 8 is the Get/Set Extended Property Capability (GSC). See Sections XHC 4.6.17 and 4.6.18 + /// - Bits 10-31 are reserved. pub hcc_params2: Mmio, + //TODO: VTIOSOFF register for I/O virtualization } +/// The mask to use to get the AC64 bit from HCCPARAMS1. See [CapabilityRegs] pub const HCC_PARAMS1_AC64_BIT: u32 = 1 << HCC_PARAMS1_AC64_SHIFT; +/// The shift to use to get the AC64 bit from HCCParams1. See [CapabilityRegs] pub const HCC_PARAMS1_AC64_SHIFT: u8 = 0; +/// The Mask to use to get the MAXPSASIZE value from HCCParams1. See [CapabilityRegs] pub const HCC_PARAMS1_MAXPSASIZE_MASK: u32 = 0xF000; // 15:12 +/// The shift to use to get the MAXPSASIZE value from HCCParams1. See [CapabilityRegs] pub const HCC_PARAMS1_MAXPSASIZE_SHIFT: u8 = 12; +/// The mask to use to get the XECP value from HCCParams1. See [CapabilityRegs] pub const HCC_PARAMS1_XECP_MASK: u32 = 0xFFFF_0000; +/// The shift to use to get the XECP value from HCCParams1. See [CapabilityRegs] pub const HCC_PARAMS1_XECP_SHIFT: u8 = 16; +/// The mask to use to get the LEC bit from HCCParams2. See [CapabilityRegs] pub const HCC_PARAMS2_LEC_BIT: u32 = 1 << 4; +/// The mask to use to get the CIC bit from HCCParams2. See [CapabilityRegs] pub const HCC_PARAMS2_CIC_BIT: u32 = 1 << 5; - +/// The mask to use to get MAXPORTS from HCSParams1. See [CapabilityRegs] pub const HCS_PARAMS1_MAX_PORTS_MASK: u32 = 0xFF00_0000; +/// The shift to use to get MAXPORTS from HCSParams1. See [CapabilityRegs] pub const HCS_PARAMS1_MAX_PORTS_SHIFT: u8 = 24; +/// The shift to use to get MAXSLOTS from HCSParams1. See [CapabilityRegs] pub const HCS_PARAMS1_MAX_SLOTS_MASK: u32 = 0x0000_00FF; +/// The shift to use to get MAXSLOTS from HCSParams1. See [CapabilityRegs] pub const HCS_PARAMS1_MAX_SLOTS_SHIFT: u8 = 0; - +/// The mask to use to get MAXSCRATPADBUFS_LO from HCSParams2. See [CapabilityRegs] pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK: u32 = 0xF800_0000; +/// The shift to use to get MAXSCRATCHPADBUFS_LO from HCSParams2. See [CapabilityRegs] pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT: u8 = 27; +/// The mask to use to get the SPR bit from HCSParams2. See [CapabilityRegs] pub const HCS_PARAMS2_SPR_BIT: u32 = 1 << HCS_PARAMS2_SPR_SHIFT; +/// The shift to use to get the SPR bit from HCSParams2. See [CapabilityRegs] pub const HCS_PARAMS2_SPR_SHIFT: u8 = 26; +/// The mask to use to get MAXSCRATCHPADBUFS_HI from HCSParams2. See [CapabilityRegs] pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK: u32 = 0x03E0_0000; +/// The shift to use to get MAXSCRATCHPADBUFS_HI from HCSParams2. See [CapabilityRegs] + pub const HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT: u8 = 21; impl CapabilityRegs { + /// Gets the ACS64 bit from HCCParams1. pub fn ac64(&self) -> bool { self.hcc_params1.readf(HCC_PARAMS1_AC64_BIT) } + /// Gets the LEC bit from HCCParams2. pub fn lec(&self) -> bool { self.hcc_params2.readf(HCC_PARAMS2_LEC_BIT) } + /// Gets the CIC bit from HCCParams2. pub fn cic(&self) -> bool { self.hcc_params2.readf(HCC_PARAMS2_CIC_BIT) } + + /// Gets the Max PSA Size from HCCParams1 pub fn max_psa_size(&self) -> u8 { ((self.hcc_params1.read() & HCC_PARAMS1_MAXPSASIZE_MASK) >> HCC_PARAMS1_MAXPSASIZE_SHIFT) as u8 } + + /// Gets the maximum number of ports from HCCParams1 pub fn max_ports(&self) -> u8 { ((self.hcs_params1.read() & HCS_PARAMS1_MAX_PORTS_MASK) >> HCS_PARAMS1_MAX_PORTS_SHIFT) as u8 } + + /// Gets the maximum number of ports from HCCParams 2 pub fn max_slots(&self) -> u8 { (self.hcs_params1.read() & HCS_PARAMS1_MAX_SLOTS_MASK) as u8 } + + /// Gets the extended capability pointer from HCCParams1 in DWORDs. pub fn ext_caps_ptr_in_dwords(&self) -> u16 { ((self.hcc_params1.read() & HCC_PARAMS1_XECP_MASK) >> HCC_PARAMS1_XECP_SHIFT) as u16 } + + /// Gets the lower five bits from the Max Scratchpad Buffer Lo Register in HCSParams2 pub fn max_scratchpad_bufs_lo(&self) -> u8 { - ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) as u8 + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_MASK) + >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_LO_SHIFT) as u8 } + + /// Gets the SPR register from HCSParams2 pub fn spr(&self) -> bool { self.hcs_params2.readf(HCS_PARAMS2_SPR_BIT) } + + /// Gets the higher five bits from the Max Scratchpad Buffer Hi Register in HCSParams2 pub fn max_scratchpad_bufs_hi(&self) -> u8 { - ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) as u8 + ((self.hcs_params2.read() & HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_MASK) + >> HCS_PARAMS2_MAX_SCRATCHPAD_BUFS_HI_SHIFT) as u8 } + + /// Gets the maximum number of scratchpad buffers supported by this implementation. pub fn max_scratchpad_bufs(&self) -> u16 { - u16::from(self.max_scratchpad_bufs_lo()) - | (u16::from(self.max_scratchpad_bufs_hi()) << 5) + u16::from(self.max_scratchpad_bufs_lo()) | (u16::from(self.max_scratchpad_bufs_hi()) << 5) } } diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 5f364a5524..aabbeaf754 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -1,14 +1,14 @@ use std::collections::BTreeMap; use log::debug; -use syscall::PAGE_SIZE; use syscall::error::Result; use syscall::io::{Io, Mmio}; +use syscall::PAGE_SIZE; use common::dma::Dma; -use super::Xhci; use super::ring::Ring; +use super::Xhci; #[repr(packed)] pub struct SlotContext { @@ -185,17 +185,19 @@ impl ScratchpadBufferArray { pub fn new(ac64: bool, entries: u16) -> Result { let mut entries = unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? }; - let pages = entries.iter_mut().map(|entry: &mut ScratchpadBufferEntry| -> Result<_, syscall::Error> { - let dma = unsafe { Dma::<[u8; PAGE_SIZE]>::zeroed()?.assume_init() }; - assert_eq!(dma.physical() % PAGE_SIZE, 0); - entry.set_addr(dma.physical() as u64); - Ok(dma) - }).collect::, _>>()?; + let pages = entries + .iter_mut() + .map( + |entry: &mut ScratchpadBufferEntry| -> Result<_, syscall::Error> { + let dma = unsafe { Dma::<[u8; PAGE_SIZE]>::zeroed()?.assume_init() }; + assert_eq!(dma.physical() % PAGE_SIZE, 0); + entry.set_addr(dma.physical() as u64); + Ok(dma) + }, + ) + .collect::, _>>()?; - Ok(Self { - entries, - pages, - }) + Ok(Self { entries, pages }) } pub fn register(&self) -> usize { self.entries.physical() diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index b42a126ae7..c955d6488d 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -3,9 +3,9 @@ use syscall::io::{Io, Mmio}; use common::dma::Dma; -use super::Xhci; use super::ring::Ring; use super::trb::Trb; +use super::Xhci; #[repr(packed)] pub struct EventRingSte { @@ -29,8 +29,12 @@ impl EventRing { ring: Ring::new(ac64, 256, false)?, }; - ring.ste[0].address_low.write(ring.ring.trbs.physical() as u32); - ring.ste[0].address_high.write((ring.ring.trbs.physical() as u64 >> 32) as u32); + ring.ste[0] + .address_low + .write(ring.ring.trbs.physical() as u32); + ring.ste[0] + .address_high + .write((ring.ring.trbs.physical() as u64 >> 32) as u32); ring.ste[0].size.write(ring.ring.trbs.len() as u16); Ok(ring) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index f496280ed7..2de350cbba 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -3,24 +3,24 @@ use std::fs::File; use std::future::Future; use std::io::prelude::*; use std::pin::Pin; -use std::sync::{Arc, Mutex}; use std::sync::atomic::{self, AtomicUsize}; +use std::sync::{Arc, Mutex}; use std::{io, mem, task, thread}; use std::os::unix::io::AsRawFd; -use crossbeam_channel::{Sender, Receiver}; -use log::{debug, error, info, warn, trace}; +use crossbeam_channel::{Receiver, Sender}; use futures::Stream; +use log::{debug, error, info, trace, warn}; use syscall::Io; use event::{Event, EventQueue, RawEventQueue}; -use super::Xhci; use super::doorbell::Doorbell; +use super::event::EventRing; use super::ring::Ring; use super::trb::{Trb, TrbCompletionCode, TrbType}; -use super::event::EventRing; +use super::Xhci; /// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back /// by the future unless it completed). @@ -65,8 +65,14 @@ impl RingId { /// is lost. #[derive(Clone, Copy, Debug)] pub enum StateKind { - CommandCompletion { phys_ptr: u64 }, - Transfer { first_phys_ptr: u64, last_phys_ptr: u64, ring_id: RingId }, + CommandCompletion { + phys_ptr: u64, + }, + Transfer { + first_phys_ptr: u64, + last_phys_ptr: u64, + ring_id: RingId, + }, Other(TrbType), } @@ -80,14 +86,12 @@ impl StateKind { } } - pub struct IrqReactor { hci: Arc, irq_file: Option, receiver: Receiver, states: Vec, - // TODO: Since the IRQ reactor is the only part of this driver that gets event TRBs, perhaps // the event ring should be owned here? } @@ -111,7 +115,14 @@ impl IrqReactor { debug!("Running IRQ reactor in polling mode."); let hci_clone = Arc::clone(&self.hci); - let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() }; + let mut event_trb_index = { + hci_clone + .primary_event_ring + .lock() + .unwrap() + .ring + .next_index() + }; 'trb_loop: loop { self.pause(); @@ -146,17 +157,32 @@ impl IrqReactor { debug!("Running IRQ reactor with IRQ file and event queue"); let hci_clone = Arc::clone(&self.hci); - let mut event_queue = RawEventQueue::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); + let mut event_queue = + RawEventQueue::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); - event_queue.subscribe(irq_fd as usize, 0, event::EventFlags::READ).unwrap(); + event_queue + .subscribe(irq_fd as usize, 0, event::EventFlags::READ) + .unwrap(); - let mut event_trb_index = { hci_clone.primary_event_ring.lock().unwrap().ring.next_index() }; + let mut event_trb_index = { + hci_clone + .primary_event_ring + .lock() + .unwrap() + .ring + .next_index() + }; for _event in event_queue { trace!("IRQ event queue notified"); let mut buffer = [0u8; 8]; - let _ = self.irq_file.as_mut().unwrap().read(&mut buffer).expect("Failed to read from irq scheme"); + let _ = self + .irq_file + .as_mut() + .unwrap() + .read(&mut buffer) + .expect("Failed to read from irq scheme"); if !self.hci.received_irq() { // continue only when an IRQ to this device was received @@ -178,12 +204,20 @@ impl IrqReactor { let event_trb = &mut event_ring.ring.trbs[event_trb_index]; if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { - if count == 0 { warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } + if count == 0 { + warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") + } // no more events were found, continue the loop return; - } else { count += 1 } + } else { + count += 1 + } - trace!("Found event TRB type {}: {:?}", event_trb.trb_type(), event_trb); + trace!( + "Found event TRB type {}: {:?}", + event_trb.trb_type(), + event_trb + ); if self.check_event_ring_full(event_trb.clone()) { info!("Had to resize event TRB, retrying..."); @@ -205,15 +239,27 @@ impl IrqReactor { fn update_erdp(&self, event_ring: &EventRing) { let dequeue_pointer_and_dcs = event_ring.erdp(); let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; - assert_eq!(dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, dequeue_pointer, "unaligned ERDP received from primary event ring"); + assert_eq!( + dequeue_pointer & 0xFFFF_FFFF_FFFF_FFF0, + dequeue_pointer, + "unaligned ERDP received from primary event ring" + ); trace!("Updated ERDP to {:#0x}", dequeue_pointer); - self.hci.run.lock().unwrap().ints[0].erdp_low.write(dequeue_pointer as u32); - self.hci.run.lock().unwrap().ints[0].erdp_high.write((dequeue_pointer >> 32) as u32); + self.hci.run.lock().unwrap().ints[0] + .erdp_low + .write(dequeue_pointer as u32); + self.hci.run.lock().unwrap().ints[0] + .erdp_high + .write((dequeue_pointer >> 32) as u32); } fn handle_requests(&mut self) { - self.states.extend(self.receiver.try_iter().inspect(|req| trace!("Received request: {:X?}", req))); + self.states.extend( + self.receiver + .try_iter() + .inspect(|req| trace!("Received request: {:X?}", req)), + ); } fn acknowledge(&mut self, trb: Trb) { //TODO: handle TRBs without an attached state @@ -225,19 +271,27 @@ impl IrqReactor { trace!("ACK STATE {}: {:X?}", index, self.states[index].kind); match self.states[index].kind { - StateKind::CommandCompletion { phys_ptr } if trb.trb_type() == TrbType::CommandCompletion as u8 => { + StateKind::CommandCompletion { phys_ptr } + if trb.trb_type() == TrbType::CommandCompletion as u8 => + { if trb.completion_trb_pointer() == Some(phys_ptr) { trace!("Found matching command completion future"); let state = self.states.remove(index); // Before waking, it's crucial that the command TRB that generated this event // is fetched before removing this event TRB from the queue. - let command_trb = match self.hci.cmd.lock().unwrap().phys_addr_to_entry_mut(self.hci.cap.ac64(), phys_ptr) { + let command_trb = match self + .hci + .cmd + .lock() + .unwrap() + .phys_addr_to_entry_mut(self.hci.cap.ac64(), phys_ptr) + { Some(command_trb) => { let t = command_trb.clone(); command_trb.reserved(false); t - }, + } None => { warn!("The xHC supplied a pointer to a command TRB that was outside the known command ring bounds. Ignoring event TRB {:?}.", trb); continue; @@ -259,8 +313,16 @@ impl IrqReactor { } } - StateKind::Transfer { first_phys_ptr, last_phys_ptr, ring_id } if trb.trb_type() == TrbType::Transfer as u8 => { - if let Some(src_trb) = trb.transfer_event_trb_pointer().map(|ptr| self.hci.get_transfer_trb(ptr, ring_id)).flatten() { + StateKind::Transfer { + first_phys_ptr, + last_phys_ptr, + ring_id, + } if trb.trb_type() == TrbType::Transfer as u8 => { + if let Some(src_trb) = trb + .transfer_event_trb_pointer() + .map(|ptr| self.hci.get_transfer_trb(ptr, ring_id)) + .flatten() + { match trb.transfer_event_trb_pointer() { Some(phys_ptr) => { let matches = if first_phys_ptr <= last_phys_ptr { @@ -279,7 +341,7 @@ impl IrqReactor { state.waker.wake(); return; } - }, + } None => { // Ring Overrun, Ring Underrun, or Virtual Function Event Ring Full. // @@ -305,18 +367,23 @@ impl IrqReactor { return; } - _ => () + _ => (), } index += 1; } - warn!("Lost event TRB type {}, completion code: {}: {:X?}", trb.trb_type(), trb.completion_code(), trb); + warn!( + "Lost event TRB type {}, completion code: {}: {:X?}", + trb.trb_type(), + trb.completion_code(), + trb + ); } fn acknowledge_failed_transfer_trbs(&mut self, trb: Trb) { let mut index = 0; loop { - if ! self.states[index].is_isoch_or_vf { + if !self.states[index].is_isoch_or_vf { index += 1; if index >= self.states.len() { break; @@ -335,7 +402,8 @@ impl IrqReactor { /// Full. If so, it grows the event ring. The return value is whether the event ring was full, /// and then grown. fn check_event_ring_full(&mut self, event_trb: Trb) -> bool { - let had_event_ring_full_error = event_trb.trb_type() == TrbType::HostController as u8 && event_trb.completion_code() == TrbCompletionCode::EventRingFull as u8; + let had_event_ring_full_error = event_trb.trb_type() == TrbType::HostController as u8 + && event_trb.completion_code() == TrbCompletionCode::EventRingFull as u8; if had_event_ring_full_error { self.grow_event_ring(); @@ -386,7 +454,11 @@ impl EventDoorbell { } enum EventTrbFuture { - Pending { state: FutureState, sender: Sender, doorbell_opt: Option }, + Pending { + state: FutureState, + sender: Sender, + doorbell_opt: Option, + }, Finished, } @@ -397,18 +469,24 @@ impl Future for EventTrbFuture { let this = self.get_mut(); let message = match this { - &mut Self::Pending { ref state, ref sender, ref mut doorbell_opt } => match state.message.lock().unwrap().take() { + &mut Self::Pending { + ref state, + ref sender, + ref mut doorbell_opt, + } => match state.message.lock().unwrap().take() { Some(message) => message, None => { // Register state with IRQ reactor trace!("Send state {:X?}", state.state_kind); - sender.send(State { - message: Arc::clone(&state.message), - is_isoch_or_vf: state.is_isoch_or_vf, - kind: state.state_kind, - waker: context.waker().clone(), - }).expect("IRQ reactor thread unexpectedly stopped"); + sender + .send(State { + message: Arc::clone(&state.message), + is_isoch_or_vf: state.is_isoch_or_vf, + kind: state.state_kind, + waker: context.waker().clone(), + }) + .expect("IRQ reactor thread unexpectedly stopped"); // Doorbell must be rung after sending state if let Some(doorbell) = doorbell_opt.take() { @@ -417,7 +495,7 @@ impl Future for EventTrbFuture { return task::Poll::Pending; } - } + }, &mut Self::Finished => panic!("Polling finished EventTrbFuture again."), }; *this = Self::Finished; @@ -427,7 +505,8 @@ impl Future for EventTrbFuture { impl Xhci { pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option { - self.with_ring(id, |ring| ring.phys_addr_to_entry(self.cap.ac64(), paddr)).flatten() + self.with_ring(id, |ring| ring.phys_addr_to_entry(self.cap.ac64(), paddr)) + .flatten() } pub fn with_ring T>(&self, id: RingId, function: F) -> Option { use super::RingOrStreams; @@ -442,7 +521,11 @@ impl Xhci { Some(function(ring_ref)) } - pub fn with_ring_mut T>(&self, id: RingId, function: F) -> Option { + pub fn with_ring_mut T>( + &self, + id: RingId, + function: F, + ) -> Option { use super::RingOrStreams; let mut slot_state = self.port_states.get_mut(&(id.port as usize))?; @@ -455,8 +538,15 @@ impl Xhci { Some(function(ring_ref)) } - pub fn next_transfer_event_trb(&self, ring_id: RingId, ring: &Ring, first_trb: &Trb, last_trb: &Trb, doorbell: EventDoorbell) -> impl Future + Send + Sync + 'static { - if ! last_trb.is_transfer_trb() { + pub fn next_transfer_event_trb( + &self, + ring_id: RingId, + ring: &Ring, + first_trb: &Trb, + last_trb: &Trb, + doorbell: EventDoorbell, + ) -> impl Future + Send + Sync + 'static { + if !last_trb.is_transfer_trb() { panic!("Invalid TRB type given to next_transfer_event_trb(): {} (TRB {:?}. Expected transfer TRB.", last_trb.trb_type(), last_trb) } @@ -477,8 +567,13 @@ impl Xhci { doorbell_opt: Some(doorbell), } } - pub fn next_command_completion_event_trb(&self, command_ring: &Ring, trb: &Trb, doorbell: EventDoorbell) -> impl Future + Send + Sync + 'static { - if ! trb.is_command_trb() { + pub fn next_command_completion_event_trb( + &self, + command_ring: &Ring, + trb: &Trb, + doorbell: EventDoorbell, + ) -> impl Future + Send + Sync + 'static { + if !trb.is_command_trb() { panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb) } EventTrbFuture::Pending { @@ -494,7 +589,10 @@ impl Xhci { doorbell_opt: Some(doorbell), } } - pub fn next_misc_event_trb(&self, trb_type: TrbType) -> impl Future + Send + Sync + 'static { + pub fn next_misc_event_trb( + &self, + trb_type: TrbType, + ) -> impl Future + Send + Sync + 'static { let valid_trb_types = [ TrbType::PortStatusChange as u8, TrbType::BandwidthRequest as u8, @@ -503,7 +601,7 @@ impl Xhci { TrbType::DeviceNotification as u8, TrbType::MfindexWrap as u8, ]; - if ! valid_trb_types.contains(&(trb_type as u8)) { + if !valid_trb_types.contains(&(trb_type as u8)) { panic!("Invalid TRB type given to next_misc_event_trb(): {:?}. Only event TRB types that are neither transfer events or command completion events can be used.", trb_type) } EventTrbFuture::Pending { @@ -516,5 +614,4 @@ impl Xhci { doorbell_opt: None, } } - } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 52b582adea..07a6826bb1 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1,17 +1,28 @@ +//! The eXtensible Host Controller Interface (XHCI) Module +//! +//! This module implements the XHCI functionality of Redox's USB driver daemon. +//! +//! XHCI is a standard for the USB Host Controller interface specified by Intel that provides a +//! common register interface for systems to use to interact with the Universal Serial Bus (USB) +//! subsystem. +//! +//! The standard can be found [here](https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf). +//! The standard is referenced frequently throughout this documentation. The acronyms used for specific +//! documents are specified in the crate-level documentation. use std::collections::BTreeMap; use std::convert::TryFrom; use std::fs::File; use std::future::Future; use std::pin::Pin; use std::ptr::NonNull; -use std::sync::{Arc, Mutex, MutexGuard, Weak}; use std::sync::atomic::{AtomicBool, AtomicUsize}; +use std::sync::{Arc, Mutex, MutexGuard, Weak}; use std::{mem, process, slice, sync::atomic, task, thread}; -use syscall::PAGE_SIZE; -use syscall::error::{Error, Result, EBADF, EBADMSG, ENOENT, EIO}; +use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT}; use syscall::io::Io; +use syscall::PAGE_SIZE; use chashmap::CHashMap; use common::dma::Dma; @@ -22,7 +33,7 @@ use serde::Deserialize; use crate::usb; use pcid_interface::msi::{MsixInfo, MsixTableEntry}; -use pcid_interface::{PciFunctionHandle, PciFeature}; +use pcid_interface::{PciFeature, PciFunctionHandle}; mod capability; mod context; @@ -40,9 +51,9 @@ mod trb; use self::capability::CapabilityRegs; use self::context::{DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray}; use self::doorbell::Doorbell; -use self::irq_reactor::{EventDoorbell, IrqReactor, NewPendingTrb, RingId}; use self::event::EventRing; use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap}; +use self::irq_reactor::{EventDoorbell, IrqReactor, NewPendingTrb, RingId}; use self::operational::OperationalRegs; use self::port::Port; use self::ring::Ring; @@ -53,6 +64,8 @@ use self::scheme::EndpIfState; use crate::driver_interface::*; +/// Specifies the configurable interrupt mechanism used by the xhci subsystem for registering +/// device state change notifications. pub enum InterruptMethod { /// No interrupts whatsoever; the driver will instead rely on polling event rings. Polling, @@ -83,13 +96,32 @@ impl MappedMsixRegs { impl Xhci { /// Gets descriptors, before the port state is initiated. - async fn get_desc_raw(&self, port: usize, slot: u8, kind: usb::DescriptorKind, index: u8, desc: &mut Dma) -> Result<()> { + async fn get_desc_raw( + &self, + port: usize, + slot: u8, + kind: usb::DescriptorKind, + index: u8, + desc: &mut Dma, + ) -> Result<()> { let len = mem::size_of::(); - log::debug!("get_desc_raw port {} slot {} kind {:?} index {} len {}", port, slot, kind, index, len); + log::debug!( + "get_desc_raw port {} slot {} kind {:?} index {} len {}", + port, + slot, + kind, + index, + len + ); let future = { let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(ENOENT))?; - let ring = port_state.endpoint_states.get_mut(&0).ok_or(Error::new(EIO))?.ring().expect("no ring for the default control pipe"); + let ring = port_state + .endpoint_states + .get_mut(&0) + .ok_or(Error::new(EIO))? + .ring() + .expect("no ring for the default control pipe"); let first_index = ring.next_index(); let (cmd, cycle) = (&mut ring.trbs[first_index], ring.cycle); @@ -118,7 +150,7 @@ impl Xhci { &ring, &ring.trbs[first_index], &ring.trbs[last_index], - EventDoorbell::new(self, usize::from(slot), Self::def_control_endp_doorbell()) + EventDoorbell::new(self, usize::from(slot), Self::def_control_endp_doorbell()), ) }; @@ -132,33 +164,63 @@ impl Xhci { Ok(()) } - async fn fetch_dev_desc_8_byte(&self, port: usize, slot: u8) -> Result { + async fn fetch_dev_desc_8_byte( + &self, + port: usize, + slot: u8, + ) -> Result { let mut desc = unsafe { self.alloc_dma_zeroed::()? }; - self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?; + self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc) + .await?; Ok(*desc) } async fn fetch_dev_desc(&self, port: usize, slot: u8) -> Result { let mut desc = unsafe { self.alloc_dma_zeroed::()? }; - self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc).await?; + self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc) + .await?; Ok(*desc) } - async fn fetch_config_desc(&self, port: usize, slot: u8, config: u8) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { + async fn fetch_config_desc( + &self, + port: usize, + slot: u8, + config: u8, + ) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { let mut desc = unsafe { self.alloc_dma_zeroed::<(usb::ConfigDescriptor, [u8; 4087])>()? }; - self.get_desc_raw(port, slot, usb::DescriptorKind::Configuration, config, &mut desc).await?; + self.get_desc_raw( + port, + slot, + usb::DescriptorKind::Configuration, + config, + &mut desc, + ) + .await?; Ok(*desc) } - async fn fetch_bos_desc(&self, port: usize, slot: u8) -> Result<(usb::BosDescriptor, [u8; 4087])> { + async fn fetch_bos_desc( + &self, + port: usize, + slot: u8, + ) -> Result<(usb::BosDescriptor, [u8; 4087])> { let mut desc = unsafe { self.alloc_dma_zeroed::<(usb::BosDescriptor, [u8; 4087])>()? }; - self.get_desc_raw(port, slot, usb::DescriptorKind::BinaryObjectStorage, 0, &mut desc).await?; + self.get_desc_raw( + port, + slot, + usb::DescriptorKind::BinaryObjectStorage, + 0, + &mut desc, + ) + .await?; Ok(*desc) } async fn fetch_string_desc(&self, port: usize, slot: u8, index: u8) -> Result { let mut sdesc = unsafe { self.alloc_dma_zeroed::<(u8, u8, [u16; 127])>()? }; - self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, &mut sdesc).await?; + self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, &mut sdesc) + .await?; let len = sdesc.0 as usize; if len > 2 { @@ -169,16 +231,26 @@ impl Xhci { } } +/// The eXtensible Host Controller Interface (XHCI) data structure pub struct Xhci { // immutable + /// The Host Controller Interface Capability Registers. These read-only registers specify the + /// limits and capabilities of the host controller implementation (See XHCI section 5.3) cap: &'static CapabilityRegs, //page_size: usize, // XXX: It would be really useful to be able to mutably access individual elements of a slice, // without having to wrap every element in a lock (which wouldn't work since they're packed). + /// The Host Controller Interface Operational Registers. These registers provide the software + /// interface to configure and monitor the state of the XHCI (See XHCI section 5.4) op: Mutex<&'static mut OperationalRegs>, ports: Mutex<&'static mut [Port]>, + /// The Host Controller Interface Doorbell Registers. There is one register per device slot, + /// and these registers are used by system software to notify the XHC that it has work to perform + /// for a specific device slot. (See XHCI sections 4.7 and 5.6) dbs: Arc>, + /// The Host Controller Interface Runtime Registers. These handle interrupt and event processing, + /// and provide time-sensitive information such as the current microframe. (See XHCI section 5.5) run: Mutex<&'static mut RuntimeRegs>, cmd: Mutex, primary_event_ring: Mutex, @@ -224,8 +296,7 @@ impl PortState { //TODO: fetch using endpoint number instead fn get_endp_desc(&self, endp_idx: u8) -> Option<&EndpDesc> { let cfg_idx = self.cfg_idx?; - let config_desc = self.dev_desc.as_ref()? - .config_descs.get(cfg_idx as usize)?; + let config_desc = self.dev_desc.as_ref()?.config_descs.get(cfg_idx as usize)?; let mut endp_count = 0; for if_desc in config_desc.interface_descs.iter() { for endp_desc in if_desc.endpoints.iter() { @@ -258,16 +329,24 @@ impl EndpointState { } impl Xhci { - pub fn new(scheme_name: String, address: usize, interrupt_method: InterruptMethod, pcid_handle: PciFunctionHandle) -> Result { + pub fn new( + scheme_name: String, + address: usize, + interrupt_method: InterruptMethod, + pcid_handle: PciFunctionHandle, + ) -> Result { + //Locate the capability registers from the mapped PCI Bar let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; debug!("CAP REGS BASE {:X}", address); //let page_size = ... + //The operational registers appear immediately after the capability registers. let op_base = address + cap.len.read() as usize; let op = unsafe { &mut *(op_base as *mut OperationalRegs) }; debug!("OP REGS BASE {:X}", op_base); + //Reset the XHCI device let (max_slots, max_ports) = { debug!("Waiting for xHC becoming ready."); // Wait until controller is ready @@ -300,11 +379,13 @@ impl Xhci { (max_slots, max_ports) }; + //Get the address of the port register table let port_base = op_base + 0x400; let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut Port, max_ports as usize) }; debug!("PORT BASE {:X}", port_base); + //Get the address of the dorbell register table let db_base = address + cap.db_offset.read() as usize; let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut Doorbell, 256) }; debug!("DOORBELL REGS BASE {:X}", db_base); @@ -325,7 +406,6 @@ impl Xhci { cap, //page_size, - op: Mutex::new(op), ports: Mutex::new(ports), dbs: Arc::new(Mutex::new(dbs)), @@ -371,23 +451,37 @@ impl Xhci { // Set enabled slots debug!("Setting enabled slots to {}.", max_slots); self.op.get_mut().unwrap().config.write(max_slots as u32); - debug!("Enabled Slots: {}", self.op.get_mut().unwrap().config.read() & 0xFF); + debug!( + "Enabled Slots: {}", + self.op.get_mut().unwrap().config.read() & 0xFF + ); // Set device context address array pointer let dcbaap = self.dev_ctx.dcbaap(); debug!("Writing DCBAAP: {:X}", dcbaap); self.op.get_mut().unwrap().dcbaap_low.write(dcbaap as u32); - self.op.get_mut().unwrap().dcbaap_high.write((dcbaap as u64 >> 32) as u32); + self.op + .get_mut() + .unwrap() + .dcbaap_high + .write((dcbaap as u64 >> 32) as u32); // Set command ring control register let crcr = self.cmd.get_mut().unwrap().register(); assert_eq!(crcr & 0xFFFF_FFFF_FFFF_FFC1, crcr, "unaligned CRCR"); debug!("Writing CRCR: {:X}", crcr); self.op.get_mut().unwrap().crcr_low.write(crcr as u32); - self.op.get_mut().unwrap().crcr_high.write((crcr as u64 >> 32) as u32); + self.op + .get_mut() + .unwrap() + .crcr_high + .write((crcr as u64 >> 32) as u32); // Set event ring segment table registers - debug!("Interrupter 0: {:p}", self.run.get_mut().unwrap().ints.as_ptr()); + debug!( + "Interrupter 0: {:p}", + self.run.get_mut().unwrap().ints.as_ptr() + ); { let int = &mut self.run.get_mut().unwrap().ints[0]; @@ -410,7 +504,6 @@ impl Xhci { debug!("Enabling Primary Interrupter."); int.iman.writef(1 << 1 | 1, true); - } self.op.get_mut().unwrap().usb_cmd.writef(1 << 2, true); @@ -446,7 +539,7 @@ impl Xhci { port.portsc.writef(port::PortFlags::PORT_PR.bits(), true); while port.portsc.readf(port::PortFlags::PORT_PR.bits()) { - //while ! port.flags().contains(port::PortFlags::PORT_PRC) { + //while ! port.flags().contains(port::PortFlags::PORT_PRC) { if instant.elapsed().as_secs() >= 1 { warn!("timeout"); break; @@ -467,7 +560,11 @@ impl Xhci { } let scratchpad_buf_arr = ScratchpadBufferArray::new(self.cap.ac64(), buf_count)?; self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; - debug!("Setting up {} scratchpads, at {:#0x}", buf_count, scratchpad_buf_arr.register()); + debug!( + "Setting up {} scratchpads, at {:#0x}", + buf_count, + scratchpad_buf_arr.register() + ); self.scratchpad_buf_arr = Some(scratchpad_buf_arr); Ok(()) @@ -476,8 +573,9 @@ impl Xhci { pub async fn enable_port_slot(&self, slot_ty: u8) -> Result { assert_eq!(slot_ty & 0x1F, slot_ty); - let (event_trb, command_trb) = - self.execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)).await; + let (event_trb, command_trb) = self + .execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)) + .await; self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb)?; self.event_handler_finished(); @@ -485,7 +583,9 @@ impl Xhci { Ok(event_trb.event_slot()) } pub async fn disable_port_slot(&self, slot: u8) -> Result<()> { - let (event_trb, command_trb) = self.execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)).await; + let (event_trb, command_trb) = self + .execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)) + .await; self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb)?; self.event_handler_finished(); @@ -512,7 +612,10 @@ impl Xhci { } pub async fn probe(&self) -> Result<()> { - debug!("XHCI capabilities: {:?}", self.capabilities_iter().collect::>()); + debug!( + "XHCI capabilities: {:?}", + self.capabilities_iter().collect::>() + ); let port_count = { self.ports.lock().unwrap().len() }; @@ -548,7 +651,10 @@ impl Xhci { info!("Enabled port {}, which the xHC mapped to {}", i, slot); let mut input = unsafe { self.alloc_dma_zeroed::()? }; - let mut ring = match self.address_device(&mut input, i, slot_ty, slot, speed).await { + let mut ring = match self + .address_device(&mut input, i, slot_ty, slot, speed) + .await + { Ok(ok) => ok, Err(err) => { error!("Failed to address device for port {}: {}", i, err); @@ -582,7 +688,8 @@ impl Xhci { let mut input = port_state.input_context.lock().unwrap(); - self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte).await?; + self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte) + .await?; } let dev_desc = self.get_desc(i, slot).await?; @@ -594,7 +701,8 @@ impl Xhci { let mut input = port_state.input_context.lock().unwrap(); let dev_desc = port_state.dev_desc.as_ref().unwrap(); - self.update_default_control_pipe(&mut *input, slot, dev_desc).await?; + self.update_default_control_pipe(&mut *input, slot, dev_desc) + .await?; } match self.spawn_drivers(i) { @@ -611,7 +719,7 @@ impl Xhci { &self, input_context: &mut Dma, slot_id: u8, - dev_desc: usb::DeviceDescriptor8Byte + dev_desc: usb::DeviceDescriptor8Byte, ) -> Result<()> { let new_max_packet_size = if dev_desc.major_usb_vers() == 2 { u32::from(dev_desc.packet_size) @@ -624,9 +732,11 @@ impl Xhci { b |= (new_max_packet_size) << 16; endp_ctx.b.write(b); - let (event_trb, command_trb) = self.execute_command(|trb, cycle| { - trb.evaluate_context(slot_id, input_context.physical(), false, cycle) - }).await; + let (event_trb, command_trb) = self + .execute_command(|trb, cycle| { + trb.evaluate_context(slot_id, input_context.physical(), false, cycle) + }) + .await; self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; self.event_handler_finished(); @@ -654,9 +764,11 @@ impl Xhci { b |= (new_max_packet_size) << 16; endp_ctx.b.write(b); - let (event_trb, command_trb) = self.execute_command(|trb, cycle| { - trb.evaluate_context(slot_id, input_context.physical(), false, cycle) - }).await; + let (event_trb, command_trb) = self + .execute_command(|trb, cycle| { + trb.evaluate_context(slot_id, input_context.physical(), false, cycle) + }) + .await; self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; self.event_handler_finished(); @@ -753,12 +865,19 @@ impl Xhci { let input_context_physical = input_context.physical(); - let (event_trb, _) = self.execute_command(|trb, cycle| { - trb.address_device(slot, input_context_physical, false, cycle) - }).await; + let (event_trb, _) = self + .execute_command(|trb, cycle| { + trb.address_device(slot, input_context_physical, false, cycle) + }) + .await; if event_trb.completion_code() != TrbCompletionCode::Success as u8 { - error!("Failed to address device at slot {} (port {}), completion code 0x{:X}", slot, i, event_trb.completion_code()); + error!( + "Failed to address device at slot {} (port {}), completion code 0x{:X}", + slot, + i, + event_trb.completion_code() + ); self.event_handler_finished(); return Err(Error::new(EIO)); } @@ -768,10 +887,18 @@ impl Xhci { } pub fn uses_msi(&self) -> bool { - if let InterruptMethod::Msi = self.interrupt_method { true } else { false } + if let InterruptMethod::Msi = self.interrupt_method { + true + } else { + false + } } pub fn uses_msix(&self) -> bool { - if let InterruptMethod::MsiX(_) = self.interrupt_method { true } else { false } + if let InterruptMethod::MsiX(_) = self.interrupt_method { + true + } else { + false + } } // TODO: Perhaps use an rwlock? pub fn msix_info(&self) -> Option> { @@ -795,10 +922,18 @@ impl Xhci { if self.uses_msi() || self.uses_msix() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. - trace!("Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp_low.readf(3)); + trace!( + "Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", + runtime_regs.ints[0].iman.readf(1), + runtime_regs.ints[0].erdp_low.readf(3) + ); true } else if runtime_regs.ints[0].iman.readf(1) { - trace!("Successfully received INTx# interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), runtime_regs.ints[0].erdp_low.readf(3)); + trace!( + "Successfully received INTx# interrupt, IP={}, EHB={}", + runtime_regs.ints[0].iman.readf(1), + runtime_regs.ints[0].erdp_low.readf(3) + ); // If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is // a special register to specify whether the IRQ actually came from the xHC. runtime_regs.ints[0].iman.writef(1, true); @@ -809,7 +944,6 @@ impl Xhci { // The interrupt came from a different device. false } - } fn spawn_drivers(&self, port: usize) -> Result<()> { // TODO: There should probably be a way to select alternate interfaces, and not just the @@ -822,7 +956,8 @@ impl Xhci { //TODO: support choosing config? let config_desc = &ps .dev_desc - .as_ref().ok_or_else(|| { + .as_ref() + .ok_or_else(|| { log::warn!("Missing device descriptor"); Error::new(EBADF) })? @@ -868,7 +1003,10 @@ impl Xhci { .or(Err(Error::new(ENOENT)))?; self.drivers.insert(port, process); } else { - warn!("No driver for USB class {}.{}", ifdesc.class, ifdesc.sub_class); + warn!( + "No driver for USB class {}.{}", + ifdesc.class, ifdesc.sub_class + ); } } @@ -964,13 +1102,18 @@ impl Xhci { ]; match self.supported_protocol(port) { - Some(supp_proto) => if supp_proto.psic() != 0 { - unsafe { supp_proto.protocol_speeds().iter() } - } else { - DEFAULT_SUPP_PROTO_SPEEDS.iter() - }, + Some(supp_proto) => { + if supp_proto.psic() != 0 { + unsafe { supp_proto.protocol_speeds().iter() } + } else { + DEFAULT_SUPP_PROTO_SPEEDS.iter() + } + } None => { - log::warn!("falling back to default supported protocol speeds for port {}", port); + log::warn!( + "falling back to default supported protocol speeds for port {}", + port + ); DEFAULT_SUPP_PROTO_SPEEDS.iter() } } diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index 855de69808..4dcc760e9f 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -4,21 +4,83 @@ use syscall::io::{Io, Mmio}; use super::CapabilityRegs; +/// The XHCI Operational Registers +/// +/// These registers specify the operational state of the XHCI device, and are used to receive status +/// messages and transmit commands. These registers are offset from the XHCI base address by the +/// "length" field of the [CapabilityRegs] +/// +/// See XHCI section 5.4. Table 5-18 describes the offset of these registers in memory. #[repr(packed)] pub struct OperationalRegs { + /// The USB Command Register (USBCMD) + /// + /// Describes the command to be executed by the XHCI. Writes to this register case a command + /// to be executed. + /// + /// - Bit 0 is the Run/Stop bit (R/S). Writing a value of 1 stops the xHC from executing the schedule, 1 resumes. Latency is ~16ms at worst. (See XHCI Table 5-20) + /// - Bit 1 is the Host Controller Reset Bit (HCRST). Used by software to reset the host controller (See XHCI Table 5-20) + /// - Bit 2 is the Interrupter Enable Bit (INTE). Enables interrupting the host system. + /// - Bit 3 is the Host System Error Enable Bit (HSEE). Enables out-of-band error signalling to the host. + /// - Bits 4-6 are reserved. + /// - Bit 7 is the Light Host Controller Reset Bit (LHCRST). Resets the driver without affecting the state of the ports. Affected by [CapabilityRegs] + /// - Bit 8 is the Controller Save State Bit (CSS). See XHCI Table 5-20 + /// - Bit 9 is the Controller Restore State Bit (CRS). See XHCI Table 5-20 + /// - Bit 10 is the Enable Wrap Event Bit (EWE). See XHCI Table 5-20 + /// - Bit 11 is the Enable U3 MFINDEX Stop Bit (EU3S). See XHCI Table 5-20 + /// - Bit 12 is reserved. + /// - Bit 13 is the CEM Enable Bit (CME). See XHCI Table 5-20 + /// - Bit 14 is the Extended TBC Enable Bit (ETE). See XHCI Table 5-20 + /// - Bit 15 is the Extended TBC TRB Status Enable Bit (TSC_En). See XHCI Table 5-20 + /// - Bit 16 is the VTIO Enable Bit (VTIOE). Controls the enable state of the VTIO capability. + /// - Bits 17-31 are reserved. + /// pub usb_cmd: Mmio, + /// The USB Status Register (USBSTS) + /// + /// This register indicates pending interrupts and various states of the host controller. + /// + /// Software sets a bit to '0' in this register by writing a 1 to it. + /// + /// pub usb_sts: Mmio, + /// The PAGESIZE Register (PAGESIZE) + /// + /// pub page_size: Mmio, + /// Reserved bits (RsvdZ) _rsvd: [Mmio; 2], + /// The Device Notification Control Register (DNCTRL) + /// + /// pub dn_ctrl: Mmio, + /// The Command Ring Control Register Lower 32 bits (CRCR) + /// + /// pub crcr_low: Mmio, + /// The Command Ring Control Register Upper 32 bits (CRCR) + /// + /// pub crcr_high: Mmio, + /// Reserved bits (RsvdZ) _rsvd2: [Mmio; 4], + /// Device Context Base Address Array Pointer Lower 32 bits (DCBAAP) + /// + /// pub dcbaap_low: Mmio, + /// Device Context Base Address Array Pointer Upper 32 bits (DCBAAP) + /// + /// pub dcbaap_high: Mmio, + /// The Configure Register (CONFIG) + /// + /// pub config: Mmio, + // The standard has another set of reserved bits from 3C-3FFh here + // The standard has 400-13FFh has a Port Register Set here (likely defined in port.rs). } +/// The mask to get the CIE bit from the Config register. See [OperationalRegs] pub const OP_CONFIG_CIE_BIT: u32 = 1 << 9; impl OperationalRegs { diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index 0bb74f7098..e0e76d5228 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -4,8 +4,8 @@ use syscall::error::Result; use common::dma::Dma; -use super::Xhci; use super::trb::Trb; +use super::Xhci; pub struct Ring { pub link: bool, @@ -59,7 +59,10 @@ impl Ring { /// Endless iterator that iterates through the ring items, over and over again. The iterator /// doesn't enqueue or dequeue anything. pub fn iter(&self) -> impl Iterator + '_ { - Iter { ring: self, i: self.i } + Iter { + ring: self, + i: self.i, + } } /// Takes a physical address and returns the index into this ring, that the index represents. /// Returns `None` if the address is outside the bounds of this ring. @@ -67,10 +70,19 @@ impl Ring { /// # Panics /// Panics if paddr is not a multiple of 16 bytes, i.e. the size of a TRB. pub fn phys_addr_to_index(&self, ac64: bool, paddr: u64) -> Option { - let base = (self.trbs.physical() as u64) & if ac64 { 0xFFFF_FFFF_FFFF_FFFF } else { 0xFFFF_FFFF }; + let base = (self.trbs.physical() as u64) + & if ac64 { + 0xFFFF_FFFF_FFFF_FFFF + } else { + 0xFFFF_FFFF + }; let offset = paddr.checked_sub(base)? as usize; - assert_eq!(offset % mem::size_of::(), 0, "unaligned TRB physical address"); + assert_eq!( + offset % mem::size_of::(), + 0, + "unaligned TRB physical address" + ); let index = offset / mem::size_of::(); @@ -100,12 +112,20 @@ impl Ring { let trb_virt_pointer = trb as *const Trb; let trbs_base_virt_pointer = self.trbs.as_ptr(); - if (trb_virt_pointer as usize) < (trbs_base_virt_pointer as usize) || (trb_virt_pointer as usize) > (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::() { + if (trb_virt_pointer as usize) < (trbs_base_virt_pointer as usize) + || (trb_virt_pointer as usize) + > (trbs_base_virt_pointer as usize) + self.trbs.len() * mem::size_of::() + { panic!("Gave a TRB outside of the ring, when retrieving its physical address in that ring. TRB: {:?} (at address {:p})", trb, trb); } let trb_offset_from_base = trb_virt_pointer as u64 - trbs_base_virt_pointer as u64; - let trbs_base_phys_ptr = (self.trbs.physical() as u64) & if ac64 { 0xFFFF_FFFF_FFFF_FFFF } else { 0xFFFF_FFFF }; + let trbs_base_phys_ptr = (self.trbs.physical() as u64) + & if ac64 { + 0xFFFF_FFFF_FFFF_FFFF + } else { + 0xFFFF_FFFF + }; let trb_phys_ptr = trbs_base_phys_ptr + trb_offset_from_base; trb_phys_ptr } @@ -119,7 +139,6 @@ impl Ring { struct Iter<'ring> { ring: &'ring Ring, i: usize, - } impl<'ring> Iterator for Iter<'ring> { type Item = &'ring Trb; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index d3dec98d5a..b5824d5f61 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1,3 +1,21 @@ +//! Provides the File Descriptor Scheme Interface to the XHCI. +//! +//! This file implements the basic unix file operations that are used to interface with the XHCI +//! driver. While an external program could interact with the driver using this interface, a +//! higher-level abstraction can be found in driver_interface.rs. It is recommended that you use +//! the functions in that module to interact with the driver. +//! +//! The XHCI driver has the following set of schemes: +//! +//! port +//! port/configure +//! port/request +//! port/endpoints +//! port/descriptors +//! port/state +//! port/endpoints/ +//! port/endpoints//ctl +//! port/endpoints//data use std::convert::TryFrom; use std::io::prelude::*; use std::ops::Deref; @@ -6,7 +24,7 @@ use std::{cmp, fmt, io, mem, path, str}; use common::dma::Dma; use futures::executor::block_on; -use log::{debug, error, info, warn, trace}; +use log::{debug, error, info, trace, warn}; use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; @@ -36,6 +54,28 @@ use super::trb::{TransferKind, Trb, TrbCompletionCode, TrbType}; use super::usb::endpoint::{EndpointTy, ENDP_ATTR_TY_MASK}; use crate::driver_interface::*; +use regex::Regex; + +lazy_static! { + static ref REGEX_PORT_CONFIGURE: Regex = Regex::new(r"^port(\d{1,3})/configure$") + .expect("Failed to create the regex for the port/configure scheme."); + static ref REGEX_PORT_DESCRIPTORS: Regex = Regex::new(r"^port(\d{1,3})/descriptors$") + .expect("Failed to create the regex for the port/descriptors"); + static ref REGEX_PORT_STATE: Regex = Regex::new(r"^port(\d{1,3})/state$") + .expect("Failed to create the regex for the port/state scheme"); + static ref REGEX_PORT_REQUEST: Regex = Regex::new(r"^port(\d{1,3})/request$") + .expect("Failed to create the regex for the port/request scheme"); + static ref REGEX_PORT_ENDPOINTS: Regex = Regex::new(r"^port(\d{1,3})/endpoints$") + .expect("Failed to create the regex for the port/endpoints scheme"); + static ref REGEX_PORT_SPECIFIC_ENDPOINT: Regex = Regex::new(r"^port(\d{1,3})/endpoints/(\d{1,3})$") + .expect("Failed to create the regex for the port/endpoints/ scheme"); + static ref REGEX_PORT_SUB_ENDPOINT: Regex = Regex::new( + r"port(\d{1,3})/endpoints/(\d{1,3})/(ctl|data)$" + ) + .expect("Failed to create the regex for the port/endpoints// scheme"); + static ref REGEX_TOP_LEVEL: Regex = + Regex::new(r"^$").expect("Failed to create the regex for the top-level scheme"); +} pub enum ControlFlow { Continue, @@ -84,6 +124,9 @@ pub enum PortReqState { Tmp, } +/// The Handle to a specific scheme that is returned by an open() operation. +/// +/// Contains some information about the data requested via the handle. #[derive(Debug)] pub enum Handle { TopLevel(usize, Vec), // offset, contents (ports) @@ -96,6 +139,259 @@ pub enum Handle { ConfigureEndpoints(usize), // port } +/// The type of handle. +/// +/// This is used by fstat() to determine whether to return a: +/// - MODE_DIR +/// - MODE_FILE +/// - MODE_CHR +pub(crate) enum HandleType { + Directory, + File, + Character, +} + +/// Parameters to a handle that were extracted from a scheme. +/// +/// This structure is used to easily convert a scheme filesystem path to +/// the parameters that we care about when constructing a handle. +#[derive(Debug)] +enum SchemeParameters { + /// The scheme references the top-level XHCI driver endpoint + TopLevel, + /// /port + Port(usize), // port number + /// /port/descriptors + PortDesc(usize), // port number + /// /port/state + PortState(usize), // port number + /// /port/request + PortReq(usize), // port number + /// /port/endpoints + Endpoints(usize), // port number + /// /port/endpoints//(data|ctl) + /// + /// This can also represent + /// /port/endpoints/ + Endpoint(usize, u8, String), // port number, endpoint number, handle type + /// /port/configure + ConfigureEndpoints(usize), // port number +} + +impl Handle { + /// Converts a handle back into the scheme that generated it. + /// + /// This is useful for implementing fpath, as the input parameters for our existing schemes + /// are generally static for the lifetime of the driver and can easily be retrieved. + /// + /// # Returns + /// - A [String] containing the scheme path that the handle is associated with. + pub(crate) fn to_scheme(&self) -> String { + match self { + Handle::TopLevel(_, _) => String::from(""), + Handle::Port(port_num, _, _) => { + format!("port{}", port_num) + } + Handle::PortDesc(port_num, _, _) => { + format!("port{}/descriptors", port_num) + } + Handle::PortState(port_num, _) => { + format!("port{}/state", port_num) + } + Handle::PortReq(port_num, _) => { + format!("port{}/request", port_num) + } + Handle::Endpoints(port_num, _, _) => { + format!("port{}/endpoints", port_num) + } + Handle::Endpoint(port_num, endpoint_num, handle_type) => match handle_type { + EndpointHandleTy::Data => { + format!("port{}/endpoints/{}/data", port_num, endpoint_num) + } + EndpointHandleTy::Ctl => { + format!("port{}/endpoints/{}/ctl", port_num, endpoint_num) + } + EndpointHandleTy::Root(_, _) => { + format!("port{}/endpoints/{}", port_num, endpoint_num) + } + }, + Handle::ConfigureEndpoints(port_num) => { + format!("port{}/configure", port_num) + } + } + } + + /// Gets the access mode for this handle + /// + /// Handles can be a file, a directory, or a character interface. The mode that we use is + /// entirely dependent upon the functionality of the scheme endpoint, so this returns the value + /// that should be associated with that endpoint. + /// + /// # Returns + /// - [HandleType] - The access mode associated with the handle. + pub(crate) fn get_handle_type(&self) -> HandleType { + match self { + &Handle::TopLevel(_, _) => HandleType::Directory, + &Handle::Port(_, _, _) => HandleType::Directory, + &Handle::Endpoints(_, _, _) => HandleType::Directory, + &Handle::PortDesc(_, _, _) => HandleType::File, + &Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(_, _)) => HandleType::Character, + &Handle::PortReq(_, PortReqState::WaitingForHostBytes(_, _)) => HandleType::Character, + &Handle::PortReq(_, PortReqState::Tmp) => unreachable!(), + &Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(), + &Handle::PortState(_, _) => HandleType::Character, + &Handle::PortReq(_, _) => HandleType::Character, + &Handle::ConfigureEndpoints(_) => HandleType::Character, + &Handle::Endpoint(_, _, ref st) => match st { + EndpointHandleTy::Data => HandleType::Character, + EndpointHandleTy::Ctl => HandleType::Character, + EndpointHandleTy::Root(_, _) => HandleType::Directory, + }, + } + } + + /// Gets the length of the file buffer as returned by fstat in Stat.st_size + /// + /// As some of these endpoints did not return a length in the origin code, this + /// provides an Option + /// + /// # Returns + /// Either the size of the buffer, or [Option::None] if the buffer does not exist. + pub(crate) fn get_buf_len(&self) -> Option { + match self { + &Handle::TopLevel(_, ref buf) => Some(buf.len()), + &Handle::Port(_, _, ref buf) => Some(buf.len()), + &Handle::Endpoints(_, _, ref buf) => Some(buf.len()), + &Handle::PortDesc(_, _, ref buf) => Some(buf.len()), + &Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) => Some(buf.len()), + &Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => Some(buf.len()), + &Handle::PortReq(_, PortReqState::Tmp) => None, + &Handle::PortReq(_, PortReqState::TmpSetup(_)) => None, + &Handle::PortState(_, _) => None, + &Handle::PortReq(_, _) => None, + &Handle::ConfigureEndpoints(_) => None, + &Handle::Endpoint(_, _, ref st) => match st { + EndpointHandleTy::Data => None, + EndpointHandleTy::Ctl => None, + EndpointHandleTy::Root(_, ref buf) => Some(buf.len()), + }, + } + } +} + +impl SchemeParameters { + /// This function gets a partially populated handle from a scheme string. + /// + /// This function is intended to be used by the driver's 'open' filesystem + /// hook to determine if the given string value represents a valid scheme + /// + /// # Arguments + /// 'scheme: &[str]' - A scheme in string format. + /// + /// # Returns + /// A [Result] containing: + /// - A [SchemeParameters] object representing the scheme that was passed, populated with the input parameters + /// - [ENOENT] if the passed scheme path is not valid for this driver. + /// + /// # Notes + /// ENOENT is returned so that it can easily be forwarded to the caller of open(). It cleans + /// up the function considerably to be able to use the ? syntax. + pub fn from_scheme(scheme: &str) -> Result { + fn get_string_from_regex( + rgx: &Regex, + scheme: &str, + capture_idx: usize, + ) -> syscall::Result { + if let Some(capture_list) = rgx.captures(scheme) { + if let Some(value) = capture_list.get(capture_idx + 1) { + return Ok(value.as_str().to_string()); + } + } + + Err(Error::new(ENOENT)) + }; + + fn get_usize_from_regex( + rgx: &Regex, + scheme: &str, + capture_idx: usize, + ) -> syscall::Result { + if let Some(capture_list) = rgx.captures(scheme) { + if let Some(value) = capture_list.get(capture_idx + 1) { + if let Ok(integer) = value.as_str().parse::() { + return Ok(integer); + } + } + } + + Err(Error::new(ENOENT)) + }; + + fn get_u8_from_regex(rgx: &Regex, scheme: &str, capture_idx: usize) -> syscall::Result { + if let Some(capture_list) = rgx.captures(scheme) { + if let Some(value) = capture_list.get(capture_idx + 1) { + if let Ok(integer) = value.as_str().parse::() { + return Ok(integer); + } + } + } + + Err(Error::new(ENOENT)) + }; + + //We don't implement From::<&path::Path> because we don't want to make this a part of + //the public interface. This function does not guarantee that the handle is VALID, only + //that the scheme is valid. open() will validate the contents of the enumeration instance, + //and store it if it's valid. + + //Generate the regular expressions for all of our valid schemes. + + //Check if we have a match and either return a partially initialized scheme, OR ENOENT + if REGEX_PORT_CONFIGURE.is_match(scheme) { + let port_num = get_usize_from_regex(®EX_PORT_CONFIGURE, scheme, 0)?; + + Ok(Self::ConfigureEndpoints(port_num)) + } else if REGEX_PORT_DESCRIPTORS.is_match(scheme) { + + let port_num = get_usize_from_regex(®EX_PORT_DESCRIPTORS, scheme, 0)?; + + Ok(Self::PortDesc(port_num)) + } else if REGEX_PORT_STATE.is_match(scheme) { + + let port_num = get_usize_from_regex(®EX_PORT_STATE, scheme, 0)?; + + Ok(Self::PortState(port_num)) + } else if REGEX_PORT_REQUEST.is_match(scheme) { + + let port_num = get_usize_from_regex(®EX_PORT_REQUEST, scheme, 0)?; + + Ok(Self::PortReq(port_num)) + } else if REGEX_PORT_ENDPOINTS.is_match(scheme) { + + let port_num = get_usize_from_regex(®EX_PORT_ENDPOINTS, scheme, 0)?; + + Ok(Self::Endpoints(port_num)) + } else if REGEX_PORT_SPECIFIC_ENDPOINT.is_match(scheme) { + + let port_num = get_usize_from_regex(®EX_PORT_SPECIFIC_ENDPOINT, scheme, 0)?; + let endpoint_num = get_u8_from_regex(®EX_PORT_SPECIFIC_ENDPOINT, scheme, 1)?; + + Ok(Self::Endpoint(port_num, endpoint_num, String::from("root"))) + } else if REGEX_PORT_SUB_ENDPOINT.is_match(scheme) { + + let port_num = get_usize_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 0)?; + let endpoint_num = get_u8_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 1)?; + let handle_type = get_string_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 2)?; + + Ok(Self::Endpoint(port_num, endpoint_num, handle_type)) + } else if REGEX_TOP_LEVEL.is_match(scheme) { + Ok(Self::TopLevel) + } else { + Err(Error::new(ENOENT)) + } + } +} + #[derive(Clone, Copy)] struct DmaSliceDbg<'a, T>(&'a Dma<[T]>); @@ -115,15 +411,25 @@ impl fmt::Debug for PortReqState { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Self::Init => f.debug_struct("PortReqState::Init").finish(), - Self::WaitingForDeviceBytes(ref dma, setup) => f.debug_tuple("PortReqState::WaitingForDeviceBytes").field(&DmaSliceDbg(dma)).field(&setup).finish(), - Self::WaitingForHostBytes(ref dma, setup) => f.debug_tuple("PortReqState::WaitingForHostBytes").field(&DmaSliceDbg(dma)).field(&setup).finish(), - Self::TmpSetup(setup) => f.debug_tuple("PortReqState::TmpSetup").field(&setup).finish(), + Self::WaitingForDeviceBytes(ref dma, setup) => f + .debug_tuple("PortReqState::WaitingForDeviceBytes") + .field(&DmaSliceDbg(dma)) + .field(&setup) + .finish(), + Self::WaitingForHostBytes(ref dma, setup) => f + .debug_tuple("PortReqState::WaitingForHostBytes") + .field(&DmaSliceDbg(dma)) + .field(&setup) + .finish(), + Self::TmpSetup(setup) => f + .debug_tuple("PortReqState::TmpSetup") + .field(&setup) + .finish(), Self::Tmp => f.debug_struct("PortReqState::Init").finish(), } } } - // TODO: Even though the driver interface descriptors are originally intended for JSON, they should suffice... for // now. @@ -233,7 +539,10 @@ impl Xhci { alternate_setting: desc.alternate_setting, class: desc.class, interface_str: if desc.interface_str > 0 { - Some(self.fetch_string_desc(port_id, slot, desc.interface_str).await?) + Some( + self.fetch_string_desc(port_id, slot, desc.interface_str) + .await?, + ) } else { None }, @@ -250,10 +559,7 @@ impl Xhci { /// /// # Locking /// This function will lock `Xhci::cmd` and `Xhci::dbs`. - pub async fn execute_command( - &self, - f: F, - ) -> (Trb, Trb) { + pub async fn execute_command(&self, f: F) -> (Trb, Trb) { { // If ERDP EHB bit is set, clear it before sending command //TODO: find out why this bit is set earlier! @@ -278,7 +584,7 @@ impl Xhci { self.next_command_completion_event_trb( &*command_ring, command_trb, - EventDoorbell::new(self, 0, 0) + EventDoorbell::new(self, 0, 0), ) }; @@ -286,7 +592,11 @@ impl Xhci { let event_trb = trbs.event_trb; let command_trb = trbs.src_trb.expect("Command completion event TRBs shall always have a valid pointer to a valid source command TRB"); - assert_eq!(event_trb.trb_type(), TrbType::CommandCompletion as u8, "The IRQ reactor (or the xHC) gave an invalid event TRB"); + assert_eq!( + event_trb.trb_type(), + TrbType::CommandCompletion as u8, + "The IRQ reactor (or the xHC) gave an invalid event TRB" + ); (event_trb, command_trb) } @@ -307,12 +617,11 @@ impl Xhci { let mut endpoint_state = port_state .endpoint_states - .get_mut(&0).ok_or(Error::new(EIO))?; - - let ring = endpoint_state - .ring() + .get_mut(&0) .ok_or(Error::new(EIO))?; + let ring = endpoint_state.ring().ok_or(Error::new(EIO))?; + let first_index = ring.next_index(); let (cmd, cycle) = (&mut ring.trbs[first_index], ring.cycle); cmd.setup(setup, tk, cycle); @@ -343,7 +652,7 @@ impl Xhci { ring, &ring.trbs[first_index], &ring.trbs[last_index], - EventDoorbell::new(self, usize::from(slot), Self::def_control_endp_doorbell()) + EventDoorbell::new(self, usize::from(slot), Self::def_control_endp_doorbell()), ) }; @@ -378,20 +687,14 @@ impl Xhci { let slot = port_state.slot; let (doorbell_data_stream, doorbell_data_no_stream) = { - let endp_desc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state + .get_endp_desc(endp_idx) + .ok_or(Error::new(EBADFD))?; //TODO: clean this up ( - Self::endp_doorbell( - endp_num, - endp_desc, - stream_id, - ), - Self::endp_doorbell( - endp_num, - endp_desc, - 0, - ), + Self::endp_doorbell(endp_num, endp_desc, stream_id), + Self::endp_doorbell(endp_num, endp_desc, 0), ) }; @@ -408,10 +711,13 @@ impl Xhci { EndpointState { transfer: super::RingOrStreams::Streams(stream_ctx_array), .. - } => (true, stream_ctx_array - .rings - .get_mut(&1) - .ok_or(Error::new(EBADF))?), + } => ( + true, + stream_ctx_array + .rings + .get_mut(&1) + .ok_or(Error::new(EBADF))?, + ), }; let future = loop { @@ -421,16 +727,24 @@ impl Xhci { match d(trb, cycle) { ControlFlow::Break => { break self.next_transfer_event_trb( - super::irq_reactor::RingId { port: port_num as u8, endpoint_num: endp_num, stream_id }, + super::irq_reactor::RingId { + port: port_num as u8, + endpoint_num: endp_num, + stream_id, + }, ring, //TODO: find first TRB &ring.trbs[last_index], &ring.trbs[last_index], - EventDoorbell::new(self, usize::from(slot), if has_streams { - doorbell_data_stream - } else { - doorbell_data_no_stream - }), + EventDoorbell::new( + self, + usize::from(slot), + if has_streams { + doorbell_data_stream + } else { + doorbell_data_no_stream + }, + ), ); } ControlFlow::Continue => continue, @@ -449,9 +763,7 @@ impl Xhci { if event_trb.completion_code() != TrbCompletionCode::ShortPacket as u8 && event_trb.transfer_length() != 0 { - error!( - "Event trb didn't yield a short packet, but some bytes were not transferred" - ); + error!("Event trb didn't yield a short packet, but some bytes were not transferred"); return Err(Error::new(EIO)); } @@ -469,13 +781,15 @@ impl Xhci { TransferKind::NoData, "DEVICE_REQ_NO_DATA", |_, _| ControlFlow::Break, - ).await?; + ) + .await?; Ok(()) } async fn set_configuration(&self, port: usize, config: u8) -> Result<()> { debug!("Setting configuration value {} to port {}", config, port); - self.device_req_no_data(port, usb::Setup::set_configuration(config)).await + self.device_req_no_data(port, usb::Setup::set_configuration(config)) + .await } async fn set_interface( @@ -484,18 +798,24 @@ impl Xhci { interface_num: u8, alternate_setting: u8, ) -> Result<()> { - debug!("Setting interface value {} (alternate setting {}) to port {}", interface_num, alternate_setting, port); + debug!( + "Setting interface value {} (alternate setting {}) to port {}", + interface_num, alternate_setting, port + ); self.device_req_no_data( port, usb::Setup::set_interface(interface_num, alternate_setting), - ).await + ) + .await } async fn reset_endpoint(&self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?; let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; - let endp_desc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state + .get_endp_desc(endp_idx) + .ok_or(Error::new(EBADFD))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); let slot = self @@ -504,9 +824,11 @@ impl Xhci { .ok_or(Error::new(EBADF))? .slot; - let (event_trb, command_trb) = self.execute_command(|trb, cycle| { - trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle); - }).await; + let (event_trb, command_trb) = self + .execute_command(|trb, cycle| { + trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle); + }) + .await; self.event_handler_finished(); handle_event_trb("RESET_ENDPOINT", &event_trb, &command_trb) @@ -589,14 +911,20 @@ impl Xhci { fn port_state(&self, port: usize) -> Result> { self.port_states.get(&port).ok_or(Error::new(EBADF)) } - fn port_state_mut(&self, port: usize) -> Result> { + fn port_state_mut( + &self, + port: usize, + ) -> Result> { self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) } async fn configure_endpoints(&self, port: usize, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; - info!("Running configure endpoints command, at port {}, request: {:?}", port, req); + info!( + "Running configure endpoints command, at port {}, request: {:?}", + port, req + ); if req.interface_desc.is_some() != req.alternate_setting.is_some() { return Err(Error::new(EBADMSG)); @@ -607,7 +935,13 @@ impl Xhci { port_state.cfg_idx = Some(req.config_desc); - let config_desc = port_state.dev_desc.as_ref().unwrap().config_descs.get(usize::from(req.config_desc)).ok_or(Error::new(EBADFD))?; + let config_desc = port_state + .dev_desc + .as_ref() + .unwrap() + .config_descs + .get(usize::from(req.config_desc)) + .ok_or(Error::new(EBADFD))?; //TODO: USE ENDPOINTS FROM ALL INTERFACES let mut endp_desc_count = 0; @@ -638,9 +972,8 @@ impl Xhci { let log_max_psa_size = self.cap.max_psa_size(); let port_speed_id = self.ports.lock().unwrap()[port].speed(); - let speed_id: &ProtocolSpeed = self - .lookup_psiv(port as u8, port_speed_id) - .ok_or_else(|| { + let speed_id: &ProtocolSpeed = + self.lookup_psiv(port as u8, port_speed_id).ok_or_else(|| { warn!("no speed_id"); Error::new(EIO) })?; @@ -732,8 +1065,8 @@ impl Xhci { warn!("trying to use control endpoint"); return Err(Error::new(EIO)); // only endpoint zero is of type control, and is configured separately with the address device command. } - EndpointTy::Bulk | EndpointTy::Isoch => 3072, // 3 KiB - EndpointTy::Interrupt => 1024, // 1 KiB + EndpointTy::Bulk | EndpointTy::Isoch => 3072, // 3 KiB + EndpointTy::Interrupt => 1024, // 1 KiB }; assert_eq!(ep_ty & 0x7, ep_ty); @@ -742,7 +1075,8 @@ impl Xhci { assert_ne!(ep_ty, 0); // 0 means invalid. let ring_ptr = if usb_log_max_streams.is_some() { - let mut array = StreamContextArray::new(self.cap.ac64(), 1 << (primary_streams + 1))?; + let mut array = + StreamContextArray::new(self.cap.ac64(), 1 << (primary_streams + 1))?; // TODO: Use as many stream rings as needed. array.add_ring(self.cap.ac64(), 1, true)?; @@ -785,10 +1119,14 @@ impl Xhci { let mut input_context = port_state.input_context.lock().unwrap(); input_context.add_context.writef(1 << endp_num_xhc, true); - let endp_ctx = input_context.device.endpoints.get_mut(endp_num_xhc as usize - 1).ok_or_else(|| { - warn!("failed to find endpoint {}", endp_num_xhc - 1); - Error::new(EIO) - })?; + let endp_ctx = input_context + .device + .endpoints + .get_mut(endp_num_xhc as usize - 1) + .ok_or_else(|| { + warn!("failed to find endpoint {}", endp_num_xhc - 1); + Error::new(EIO) + })?; endp_ctx.a.write( u32::from(mult) << 8 @@ -818,9 +1156,11 @@ impl Xhci { let slot = port_state.slot; let input_context_physical = port_state.input_context.lock().unwrap().physical(); - let (event_trb, command_trb) = self.execute_command(|trb, cycle| { - trb.configure_endpoint(slot, input_context_physical, cycle) - }).await; + let (event_trb, command_trb) = self + .execute_command(|trb, cycle| { + trb.configure_endpoint(slot, input_context_physical, cycle) + }) + .await; self.event_handler_finished(); @@ -832,7 +1172,8 @@ impl Xhci { if let Some(interface_num) = req.interface_desc { if let Some(alternate_setting) = req.alternate_setting { - self.set_interface(port, interface_num, alternate_setting).await?; + self.set_interface(port, interface_num, alternate_setting) + .await?; } } @@ -849,31 +1190,47 @@ impl Xhci { } let dma_buffer = unsafe { self.alloc_dma_zeroed_unsized(buf.len())? }; - let (completion_code, bytes_transferred, dma_buffer) = self.transfer( - port_num, - endp_idx, - Some(dma_buffer), - PortReqDirection::DeviceToHost, - ).await?; + let (completion_code, bytes_transferred, dma_buffer) = self + .transfer( + port_num, + endp_idx, + Some(dma_buffer), + PortReqDirection::DeviceToHost, + ) + .await?; buf.copy_from_slice(&*dma_buffer.as_ref().unwrap()); Ok((completion_code, bytes_transferred)) } - async fn transfer_write(&self, port_num: usize, endp_idx: u8, sbuf: &[u8]) -> Result<(u8, u32)> { + async fn transfer_write( + &self, + port_num: usize, + endp_idx: u8, + sbuf: &[u8], + ) -> Result<(u8, u32)> { if sbuf.is_empty() { return Err(Error::new(EINVAL)); } let mut dma_buffer = unsafe { self.alloc_dma_zeroed_unsized(sbuf.len()) }?; dma_buffer.copy_from_slice(sbuf); - trace!("TRANSFER_WRITE port {} ep {}, buffer at {:p}, size {}, dma buffer {:?}", port_num, endp_idx + 1, sbuf.as_ptr(), sbuf.len(), DmaSliceDbg(&dma_buffer)); - - let (completion_code, bytes_transferred, _) = self.transfer( + trace!( + "TRANSFER_WRITE port {} ep {}, buffer at {:p}, size {}, dma buffer {:?}", port_num, - endp_idx, - Some(dma_buffer), - PortReqDirection::HostToDevice, - ).await?; + endp_idx + 1, + sbuf.as_ptr(), + sbuf.len(), + DmaSliceDbg(&dma_buffer) + ); + + let (completion_code, bytes_transferred, _) = self + .transfer( + port_num, + endp_idx, + Some(dma_buffer), + PortReqDirection::HostToDevice, + ) + .await?; Ok((completion_code, bytes_transferred)) } pub const fn def_control_endp_doorbell() -> u32 { @@ -916,7 +1273,9 @@ impl Xhci { .get_mut(&port_num) .ok_or(Error::new(EBADFD))?; - let endp_desc: &EndpDesc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?; + let endp_desc: &EndpDesc = port_state + .get_endp_desc(endp_idx) + .ok_or(Error::new(EBADFD))?; let direction = endp_desc.direction(); @@ -932,23 +1291,30 @@ impl Xhci { let max_transfer_size = 65536u32; let (buffer, idt, estimated_td_size) = { - let (buffer, idt) = - if dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0) <= 8 && max_packet_size >= 8 && direction != EndpDirection::In { - dma_buf.as_ref().map(|sbuf| { + let (buffer, idt) = if dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0) <= 8 + && max_packet_size >= 8 + && direction != EndpDirection::In + { + dma_buf + .as_ref() + .map(|sbuf| { let mut bytes = [0u8; 8]; bytes[..sbuf.len()].copy_from_slice(&sbuf); (u64::from_le_bytes(bytes), true) }) .unwrap_or((0, false)) - } else { - ( - dma_buf.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, - false, - ) - }; + } else { + ( + dma_buf.as_ref().map(|dma| dma.physical()).unwrap_or(0) as u64, + false, + ) + }; let estimated_td_size = cmp::min( u8::try_from( - div_round_up(dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0), max_transfer_size as usize) * mem::size_of::(), + div_round_up( + dma_buf.as_ref().map(|buf| buf.len()).unwrap_or(0), + max_transfer_size as usize, + ) * mem::size_of::(), ) .ok() .unwrap_or(0x1F), @@ -963,56 +1329,57 @@ impl Xhci { drop(port_state); - let event = self.execute_transfer( - port_num, - endp_num, - stream_id, - "CUSTOM_TRANSFER", - |trb, cycle| { - let len = cmp::min(bytes_left, max_transfer_size as usize) as u32; + let event = self + .execute_transfer( + port_num, + endp_num, + stream_id, + "CUSTOM_TRANSFER", + |trb, cycle| { + let len = cmp::min(bytes_left, max_transfer_size as usize) as u32; - // set the interrupt on completion (IOC) flag for the last trb. - let ioc = bytes_left <= max_transfer_size as usize; - let chain = !ioc; + // set the interrupt on completion (IOC) flag for the last trb. + let ioc = bytes_left <= max_transfer_size as usize; + let chain = !ioc; - let interrupter = 0; - let ent = false; - let isp = true; - let bei = false; - trb.normal( - buffer, - len, - cycle, - estimated_td_size, - interrupter, - ent, - isp, - chain, - ioc, - idt, - bei, - ); + let interrupter = 0; + let ent = false; + let isp = true; + let bei = false; + trb.normal( + buffer, + len, + cycle, + estimated_td_size, + interrupter, + ent, + isp, + chain, + ioc, + idt, + bei, + ); - bytes_left -= len as usize; + bytes_left -= len as usize; - if bytes_left != 0 { - ControlFlow::Continue - } else { - ControlFlow::Break - } - }, - ).await?; + if bytes_left != 0 { + ControlFlow::Continue + } else { + ControlFlow::Break + } + }, + ) + .await?; self.event_handler_finished(); - let bytes_transferred = dma_buf.as_ref().map(|buf| buf.len() as u32 - event.transfer_length()).unwrap_or(0); + let bytes_transferred = dma_buf + .as_ref() + .map(|buf| buf.len() as u32 - event.transfer_length()) + .unwrap_or(0); Ok((event.completion_code(), bytes_transferred, dma_buf)) } - pub async fn get_desc( - &self, - port_id: usize, - slot: u8, - ) -> Result { + pub async fn get_desc(&self, port_id: usize, slot: u8) -> Result { let ports = self.ports.lock().unwrap(); let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { @@ -1024,35 +1391,55 @@ impl Xhci { let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { - Some(self.fetch_string_desc(port_id, slot, raw_dd.manufacturer_str).await?) + Some( + self.fetch_string_desc(port_id, slot, raw_dd.manufacturer_str) + .await?, + ) } else { None }, if raw_dd.product_str > 0 { - Some(self.fetch_string_desc(port_id, slot, raw_dd.product_str).await?) + Some( + self.fetch_string_desc(port_id, slot, raw_dd.product_str) + .await?, + ) } else { None }, if raw_dd.serial_str > 0 { - Some(self.fetch_string_desc(port_id, slot, raw_dd.serial_str).await?) + Some( + self.fetch_string_desc(port_id, slot, raw_dd.serial_str) + .await?, + ) } else { None }, ); - log::debug!("manufacturer {:?} product {:?} serial {:?}", manufacturer_str, product_str, serial_str); + log::debug!( + "manufacturer {:?} product {:?} serial {:?}", + manufacturer_str, + product_str, + serial_str + ); //TODO let (bos_desc, bos_data) = self.fetch_bos_desc(port_id, slot).await?; let supports_superspeed = false; - //TODO usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); + //TODO usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeed()); let supports_superspeedplus = false; - //TODO usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus()); + //TODO usb::bos_capability_descs(bos_desc, &bos_data).any(|desc| desc.is_superspeedplus()); let mut config_descs = SmallVec::new(); for index in 0..raw_dd.configurations { let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?; - log::debug!("port {} slot {} config {} desc {:X?}", port_id, slot, index, desc); + log::debug!( + "port {} slot {} config {} desc {:X?}", + port_id, + slot, + index, + desc + ); let extra_length = desc.total_length as usize - mem::size_of_val(&desc); let data = &data[..extra_length]; @@ -1083,7 +1470,7 @@ impl Xhci { Some(unexpected) => { log::warn!("expected endpoint, got {:X?}", unexpected); break; - }, + } None => break, }; let mut endp = EndpDesc::from(next); @@ -1106,7 +1493,10 @@ impl Xhci { endpoints.push(endp); } - interface_descs.push(self.new_if_desc(port_id, slot, idesc, endpoints, hid_descs).await?); + interface_descs.push( + self.new_if_desc(port_id, slot, idesc, endpoints, hid_descs) + .await?, + ); } else { log::warn!("expected interface, got {:?}", item); // TODO @@ -1117,7 +1507,10 @@ impl Xhci { config_descs.push(ConfDesc { kind: desc.kind, configuration: if desc.configuration_str > 0 { - Some(self.fetch_string_desc(port_id, slot, desc.configuration_str).await?) + Some( + self.fetch_string_desc(port_id, slot, desc.configuration_str) + .await?, + ) } else { None }, @@ -1126,7 +1519,7 @@ impl Xhci { max_power: desc.max_power, interface_descs, }); - }; + } Ok(DevDesc { kind: raw_dd.kind, @@ -1182,7 +1575,8 @@ impl Xhci { ); ControlFlow::Break }, - ).await?; + ) + .await?; Ok(()) } fn port_req_init_st(&self, port_num: usize, req: &PortReq) -> Result { @@ -1219,8 +1613,13 @@ impl Xhci { }; Ok(match transfer_kind { - TransferKind::In => PortReqState::WaitingForDeviceBytes(data_buffer_opt.ok_or(Error::new(EINVAL))?, setup), - TransferKind::Out => PortReqState::WaitingForHostBytes(data_buffer_opt.ok_or(Error::new(EINVAL))?, setup), + TransferKind::In => PortReqState::WaitingForDeviceBytes( + data_buffer_opt.ok_or(Error::new(EINVAL))?, + setup, + ), + TransferKind::Out => { + PortReqState::WaitingForHostBytes(data_buffer_opt.ok_or(Error::new(EINVAL))?, setup) + } TransferKind::NoData => PortReqState::TmpSetup(setup), _ => unreachable!(), }) @@ -1242,7 +1641,8 @@ impl Xhci { if let PortReqState::TmpSetup(setup) = st { // No need for any additional reads or writes, before completing. - self.port_req_transfer(port_num, None, setup, TransferKind::NoData).await?; + self.port_req_transfer(port_num, None, setup, TransferKind::NoData) + .await?; st = PortReqState::Init; } @@ -1254,7 +1654,8 @@ impl Xhci { } dma_buffer.copy_from_slice(buf); - self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::Out).await?; + self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::Out) + .await?; st = PortReqState::Init; buf.len() @@ -1281,7 +1682,8 @@ impl Xhci { if buf.len() != dma_buffer.len() { return Err(Error::new(EINVAL)); } - self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::In).await?; + self.port_req_transfer(port_num, Some(&mut dma_buffer), setup, TransferKind::In) + .await?; buf.copy_from_slice(&dma_buffer); st = PortReqState::Init; @@ -1301,133 +1703,211 @@ impl Xhci { } Ok(bytes_read) } -} -impl Scheme for Xhci { - fn open(&self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result { - if uid != 0 { - return Err(Error::new(EACCES)); + /// Implements open() for the root level scheme + /// + /// # Arguments + /// - 'flags: [usize]' - The flags parameter passed to open() + /// + /// # Returns + /// This function returns a [Result] containing either + /// + /// - Handle::TopLevel - The file was opened. + /// - EISDIR - This is a directory endpoint, but neither O_DIRECTORY nor O_STAT were passed. + /// + fn open_handle_top_level(&self, flags: usize) -> Result { + if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { + let mut contents = Vec::new(); + + let ports_guard = self.ports.lock().unwrap(); + + for (index, _) in ports_guard + .iter() + .enumerate() + .filter(|(_, port)| port.flags().contains(port::PortFlags::PORT_CCS)) + { + write!(contents, "port{}\n", index).unwrap(); + } + + Ok(Handle::TopLevel(0, contents)) + } else { + Err(Error::new(EISDIR)) + } + } + + /// implements open() for /port/descriptors + /// + /// # Arguments + /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'flags: [usize]' - The flags parameter passed to open() + /// + /// # Returns + /// This function returns a [Result] containing either: + /// + /// - [Handle::PortDesc] - The handle was opened successfully + /// - [ENOTDIR] - Directory-specific flags were passed to open(), but this endpoint is not a directory. + fn open_handle_port_descriptors(&self, port_num: usize, flags: usize) -> Result { + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(ENOTDIR)); } - let path_str = path_str - .trim_start_matches('/'); + let contents = self.port_desc_json(port_num)?; + Ok(Handle::PortDesc(port_num, 0, contents)) + } - let components = path::Path::new(path_str) - .components() - .map(|component| -> Option<_> { - match component { - path::Component::Normal(n) => Some(n.to_str()?), - _ => None, - } - }) - .collect::>>() + /// implements open() for /port + /// + /// # Arguments + /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'flags: [usize]' - The flags parameter passed to open() + /// + /// # Returns + /// This function returns a [Result] containing either: + /// + /// - [Handle::Port] - The handle was opened successfully + /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num + /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open + fn open_handle_port(&self, port_num: usize, flags: usize) -> Result { + // The != here is unintuitive. You would assume that you could do + // flags & O_DIRECTORY || flags & O_STAT, but rust doesn't allow + // you to cast integers to booleans. + if (flags & O_DIRECTORY != 0) || (flags & O_STAT != 0) { + let mut contents = Vec::new(); + + write!(contents, "descriptors\nendpoints\n").unwrap(); + + if self.slot_state( + self.port_states + .get(&port_num) + .ok_or(Error::new(ENOENT))? + .slot as usize, + ) != SlotState::Configured as u8 + { + write!(contents, "configure\n").unwrap(); + } + + Ok(Handle::Port(port_num, 0, contents)) + } else { + Err(Error::new(EISDIR)) + } + } + + /// implements open() for /port/state + /// + /// # Arguments + /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'flags: [usize]' - The flags parameter passed to open() + /// + /// # Returns + /// This function returns a [Result] containing either: + /// + /// - [Handle::Port] - The handle was opened successfully + /// - [ENOTDIR] - open() was called on this scheme endpoint, but directory-specific flags were passed to open + fn open_handle_port_state(&self, port_num: usize, flags: usize) -> Result { + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(ENOTDIR)); + } + + Ok(Handle::PortState(port_num, 0)) + } + + /// implements open() for /port/endpoints + /// + /// # Arguments + /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'flags: [usize]' - The flags parameter passed to open() + /// + /// # Returns + /// This function returns a [Result] containing either: + /// + /// - [Handle::Port] - The handle was opened successfully + /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open + fn open_handle_port_endpoints(&self, port_num: usize, flags: usize) -> Result { + if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { + return Err(Error::new(EISDIR)); + }; + let mut contents = Vec::new(); + let ps = self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?; + + /*for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { + write!(contents, "{}\n", ep_num).unwrap(); + }*/ + + for ep_num in ps.endpoint_states.keys() { + write!(contents, "{}\n", ep_num).unwrap(); + } + + Ok(Handle::Endpoints(port_num, 0, contents)) + } + + /// implements open() for /port/endpoints/ + /// + /// # Arguments + /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'endpoint_num: [u8]' - The endpoint number to access + /// - 'flags: [usize]' - The flags parameter passed to open() + /// + /// # Returns + /// This function returns a [Result] containing either: + /// + /// - [Handle::Port] - The handle was opened successfully + /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open + /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num + fn open_handle_endpoint_root( + &self, + port_num: usize, + endpoint_num: u8, + flags: usize, + ) -> Result { + if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { + return Err(Error::new(EISDIR)); + } + + let port_state = self + .port_states + .get_mut(&port_num) .ok_or(Error::new(ENOENT))?; - let handle = match &components[..] { - &[] => { - if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { - let mut contents = Vec::new(); + /*if self.dev_ctx.contexts[port_state.slot as usize].endpoints.get(endpoint_num as usize).ok_or(Error::new(ENOENT))?.a.read() & 0b111 != 1 { + return Err(Error::new(ENXIO)); // TODO: Find a proper error code for "endpoint not initialized". + }*/ - let ports_guard = self.ports.lock().unwrap(); + if !port_state.endpoint_states.contains_key(&endpoint_num) { + return Err(Error::new(ENOENT)); + } + let contents = "ctl\ndata\n".as_bytes().to_owned(); - for (index, _) in ports_guard - .iter() - .enumerate() - .filter(|(_, port)| port.flags().contains(port::PortFlags::PORT_CCS)) - { - write!(contents, "port{}\n", index).unwrap(); - } - - Handle::TopLevel(0, contents) - } else { - return Err(Error::new(EISDIR)); - } - } - &[port, port_tl] if port.starts_with("port") => { - let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; - if !self.port_states.contains_key(&port_num) { - return Err(Error::new(ENOENT)); - } - - match port_tl { - "descriptors" => { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - - let contents = self.port_desc_json(port_num)?; - Handle::PortDesc(port_num, 0, contents) - } - "configure" => { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { - return Err(Error::new(EACCES)); - } - - Handle::ConfigureEndpoints(port_num) - } - "state" => { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - - Handle::PortState(port_num, 0) - } - "request" => { - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(ENOTDIR)); - } - Handle::PortReq(port_num, PortReqState::Init) - } - "endpoints" => { - if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { - return Err(Error::new(EISDIR)); - }; - let mut contents = Vec::new(); - let ps = self.port_states.get(&port_num).ok_or(Error::new(ENOENT))?; - - /*for (ep_num, _) in self.dev_ctx.contexts[ps.slot as usize].endpoints.iter().enumerate().filter(|(_, ep)| ep.a.read() & 0b111 == 1) { - write!(contents, "{}\n", ep_num).unwrap(); - }*/ - - for ep_num in ps.endpoint_states.keys() { - write!(contents, "{}\n", ep_num).unwrap(); - } - - Handle::Endpoints(port_num, 0, contents) - } - _ => return Err(Error::new(ENOENT)), - } - } - &[port, "endpoints", endpoint_num_str] if port.starts_with("port") => { - let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; - let endpoint_num = endpoint_num_str.parse::().or(Err(Error::new(ENOENT)))?; - - if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { - return Err(Error::new(EISDIR)); - } - - let port_state = self - .port_states - .get_mut(&port_num) - .ok_or(Error::new(ENOENT))?; - - /*if self.dev_ctx.contexts[port_state.slot as usize].endpoints.get(endpoint_num as usize).ok_or(Error::new(ENOENT))?.a.read() & 0b111 != 1 { - return Err(Error::new(ENXIO)); // TODO: Find a proper error code for "endpoint not initialized". - }*/ - if !port_state.endpoint_states.contains_key(&endpoint_num) { - return Err(Error::new(ENOENT)); - } - let contents = "ctl\ndata\n".as_bytes().to_owned(); - - Handle::Endpoint(port_num, endpoint_num, EndpointHandleTy::Root(0, contents)) - } - &[port, "endpoints", endpoint_num_str, sub] if port.starts_with("port") => { - let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; - let endpoint_num = endpoint_num_str.parse::().or(Err(Error::new(ENOENT)))?; + Ok(Handle::Endpoint( + port_num, + endpoint_num, + EndpointHandleTy::Root(0, contents), + )) + } + /// implements open() for /port/endpoints//data and /port/endpoints//ctl + /// + /// # Arguments + /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'endpoint_num: [u8]' - The endpoint number to access + /// - 'handle_type: [String]' - The type of the handle + /// - 'flags: [usize]' - The flags parameter passed to open() + /// + /// # Returns + /// This function returns a [Result] containing either: + /// + /// - [Handle::Port] - The handle was opened successfully + /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open + /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num, or no endpoint with the given endpoint_num + fn open_handle_single_endpoint( + &self, + port_num: usize, + endpoint_num: u8, + handle_type: String, + flags: usize, + ) -> Result { + match handle_type.as_str() { + "root" => self.open_handle_endpoint_root(port_num, endpoint_num, flags), + "ctl" | "data" => { if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { return Err(Error::new(EISDIR)); } @@ -1438,36 +1918,99 @@ impl Scheme for Xhci { return Err(Error::new(ENOENT)); } - let st = match sub { + let st = match handle_type.as_str() { "ctl" => EndpointHandleTy::Ctl, "data" => EndpointHandleTy::Data, _ => return Err(Error::new(ENOENT)), }; - Handle::Endpoint(port_num, endpoint_num, st) + Ok(Handle::Endpoint(port_num, endpoint_num, st)) } - &[port] if port.starts_with("port") => { - if flags & O_DIRECTORY != 0 || flags & O_STAT != 0 { - let port_num = port[4..].parse::().or(Err(Error::new(ENOENT)))?; - let mut contents = Vec::new(); + _ => panic!( + "Scheme parser returned an invalid string '{}' for the endpoint handle type", + handle_type + ), + } + } - write!(contents, "descriptors\nendpoints\n").unwrap(); + /// implements open() for /port/configure + /// + /// # Arguments + /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'endpoint_num: [u8]' - The endpoint number to access + /// - 'flags: [usize]' - The flags parameter passed to open() + /// + /// # Returns + /// This function returns a [Result] containing either: + /// + /// - [Handle::Port] - The handle was opened successfully + /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open + /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num, or no endpoint with the given endpoint_num + fn open_handle_configure_endpoints(&self, port_num: usize, flags: usize) -> Result { + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(ENOTDIR)); + } - if self.slot_state( - self.port_states - .get(&port_num) - .ok_or(Error::new(ENOENT))? - .slot as usize, - ) != SlotState::Configured as u8 - { - write!(contents, "configure\n").unwrap(); - } + if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { + return Err(Error::new(EACCES)); + } - Handle::Port(port_num, 0, contents) - } else { - return Err(Error::new(EISDIR)); - } + Ok(Handle::ConfigureEndpoints(port_num)) + } + + /// implements open() for /port/request + /// + /// # Arguments + /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'flags: [usize]' - The flags parameter passed to open() + /// + /// # Returns + /// This function returns a [Result] containing either: + /// + /// - [Handle::Port] - The handle was opened successfully + /// - [ENOTDIR] - open() was called on this scheme endpoint, but directory-specific flags were passed to open + fn open_handle_port_request(&self, port_num: usize, flags: usize) -> Result { + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(ENOTDIR)); + } + + Ok(Handle::PortReq(port_num, PortReqState::Init)) + } +} + +impl Scheme for Xhci { + fn open(&self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result { + if uid != 0 { + return Err(Error::new(EACCES)); + } + + //Parse the scheme, determine if it's in the valid format, return an error if not. + //This doesn't guarantee that the parameters themselves are valid (i.e. bounded correctly) + //only that the scheme itself was parseable. + let scheme_parameters = SchemeParameters::from_scheme(path_str)?; + + //Once we have our scheme parsed into parameters, we can match on those parameters to + //find the correct routine to open a handle + let handle = match scheme_parameters { + SchemeParameters::TopLevel => self.open_handle_top_level(flags)?, + SchemeParameters::Port(port_number) => self.open_handle_port(port_number, flags)?, + SchemeParameters::PortDesc(port_number) => { + self.open_handle_port_descriptors(port_number, flags)? + } + SchemeParameters::PortState(port_number) => { + self.open_handle_port_state(port_number, flags)? + } + SchemeParameters::PortReq(port_number) => { + self.open_handle_port_request(port_number, flags)? + } + SchemeParameters::Endpoints(port_number) => { + self.open_handle_port_endpoints(port_number, flags)? + } + SchemeParameters::Endpoint(port_number, endpoint_number, handle_type) => { + self.open_handle_single_endpoint(port_number, endpoint_number, handle_type, flags)? + } + SchemeParameters::ConfigureEndpoints(port_number) => { + self.open_handle_configure_endpoints(port_number, flags)? } - _ => return Err(Error::new(ENOENT)), }; let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed); @@ -1482,37 +2025,22 @@ impl Scheme for Xhci { fn fstat(&self, id: usize, stat: &mut Stat) -> Result { let mut guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; - match &*guard { - &Handle::TopLevel(_, ref buf) - | &Handle::Port(_, _, ref buf) - | &Handle::Endpoints(_, _, ref buf) => { - stat.st_mode = MODE_DIR; - stat.st_size = buf.len() as u64; - } - &Handle::PortDesc(_, _, ref buf) => { - stat.st_mode = MODE_FILE; - stat.st_size = buf.len() as u64; - } - &Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) - | &Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => { - stat.st_mode = MODE_CHR; - stat.st_size = buf.len() as u64; - } - &Handle::PortReq(_, PortReqState::Tmp) - | &Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(), + stat.st_mode = match (&*guard).get_handle_type() { + HandleType::Directory => MODE_DIR, + HandleType::File => MODE_FILE, + HandleType::Character => MODE_CHR, + }; - &Handle::PortState(_, _) | &Handle::PortReq(_, _) => stat.st_mode = MODE_CHR, - &Handle::Endpoint(_, _, ref st) => match st { - &EndpointHandleTy::Ctl | &EndpointHandleTy::Data => stat.st_mode = MODE_CHR, - &EndpointHandleTy::Root(_, ref buf) => { - stat.st_mode = MODE_DIR; - stat.st_size = buf.len() as u64; - } - }, - &Handle::ConfigureEndpoints(_) => { - stat.st_mode = MODE_CHR | 0o200; // write only - } + stat.st_size = match (&*guard).get_buf_len() { + None => stat.st_size, + Some(size) => size as u64, + }; + + //If we have a handle to the configure scheme, we need to mark it as write only. + if let &Handle::ConfigureEndpoints(_) = (&*guard) { + stat.st_mode = stat.st_mode | 0o200; } + Ok(0) } @@ -1520,33 +2048,16 @@ impl Scheme for Xhci { let mut cursor = io::Cursor::new(buffer); let guard = self.handles.get(&fd).ok_or(Error::new(EBADF))?; - match &*guard { - &Handle::TopLevel(_, _) => write!(cursor, "/").unwrap(), - &Handle::Port(port_num, _, _) => write!(cursor, "/port{}/", port_num).unwrap(), - &Handle::PortDesc(port_num, _, _) => { - write!(cursor, "/port{}/descriptors", port_num).unwrap() - } - &Handle::PortState(port_num, _) => write!(cursor, "/port{}/state", port_num).unwrap(), - &Handle::PortReq(port_num, _) => write!(cursor, "/port{}/request", port_num).unwrap(), - &Handle::Endpoints(port_num, _, _) => { - write!(cursor, "/port{}/endpoints/", port_num).unwrap() - } - &Handle::Endpoint(port_num, endp_num, ref st) => write!( - cursor, - "/port{}/endpoints/{}/{}", - port_num, - endp_num, - match st { - &EndpointHandleTy::Root(_, _) => "", - &EndpointHandleTy::Ctl => "ctl", - &EndpointHandleTy::Data => "data", - } + let scheme = (&*guard).to_scheme(); + + write!(cursor, "{}", scheme.as_str()).expect( + format!( + "Failed to convert the file descriptor with value {} to the associated file path", + fd ) - .unwrap(), - &Handle::ConfigureEndpoints(port_num) => { - write!(cursor, "/port{}/configure", port_num).unwrap() - } - } + .as_str(), + ); + let src_len = usize::try_from(cursor.seek(io::SeekFrom::End(0)).unwrap()).unwrap(); Ok(src_len) } @@ -1554,7 +2065,13 @@ impl Scheme for Xhci { fn seek(&self, fd: usize, pos: isize, whence: usize) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; - trace!("SEEK fd={}, handle={:?}, pos {}, whence {}", fd, guard, pos, whence); + trace!( + "SEEK fd={}, handle={:?}, pos {}, whence {}", + fd, + guard, + pos, + whence + ); match &mut *guard { // Directories, or fixed files @@ -1584,14 +2101,20 @@ impl Scheme for Xhci { } // Write-once configure or transfer Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) | Handle::PortReq(_, _) => { - return Err(Error::new(ESPIPE)) + Err(Error::new(ESPIPE)) } } } fn read(&self, fd: usize, buf: &mut [u8]) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; - trace!("READ fd={}, handle={:?}, buf=(addr {:p}, length {})", fd, guard, buf.as_ptr(), buf.len()); + trace!( + "READ fd={}, handle={:?}, buf=(addr {:p}, length {})", + fd, + guard, + buf.as_ptr(), + buf.len() + ); match &mut *guard { Handle::TopLevel(ref mut offset, ref src_buf) | Handle::Port(_, ref mut offset, ref src_buf) @@ -1606,12 +2129,12 @@ impl Scheme for Xhci { Ok(bytes_to_read) } - Handle::ConfigureEndpoints(_) => return Err(Error::new(EBADF)), + Handle::ConfigureEndpoints(_) => Err(Error::new(EBADF)), &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { EndpointHandleTy::Ctl => self.on_read_endp_ctl(port_num, endp_num, buf), EndpointHandleTy::Data => block_on(self.on_read_endp_data(port_num, endp_num, buf)), - EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), + EndpointHandleTy::Root(_, _) => Err(Error::new(EBADF)), }, &mut Handle::PortState(port_num, ref mut offset) => { let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?; @@ -1646,7 +2169,13 @@ impl Scheme for Xhci { } fn write(&self, fd: usize, buf: &[u8]) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; - trace!("WRITE fd={}, handle={:?}, buf=(addr {:p}, length {})", fd, guard, buf.as_ptr(), buf.len()); + trace!( + "WRITE fd={}, handle={:?}, buf=(addr {:p}, length {})", + fd, + guard, + buf.as_ptr(), + buf.len() + ); match &mut *guard { &mut Handle::ConfigureEndpoints(port_num) => { @@ -1655,8 +2184,10 @@ impl Scheme for Xhci { } &mut Handle::Endpoint(port_num, endp_num, ref ep_file_ty) => match ep_file_ty { EndpointHandleTy::Ctl => block_on(self.on_write_endp_ctl(port_num, endp_num, buf)), - EndpointHandleTy::Data => block_on(self.on_write_endp_data(port_num, endp_num, buf)), - EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), + EndpointHandleTy::Data => { + block_on(self.on_write_endp_data(port_num, endp_num, buf)) + } + EndpointHandleTy::Root(_, _) => Err(Error::new(EBADF)), }, &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); @@ -1665,7 +2196,7 @@ impl Scheme for Xhci { } // TODO: Introduce PortReqState::Waiting, which this write call changes to // PortReqState::ReadyToWrite when all bytes are written. - _ => return Err(Error::new(EBADF)), + _ => Err(Error::new(EBADF)), } } fn close(&self, fd: usize) -> Result { @@ -1677,16 +2208,14 @@ impl Scheme for Xhci { } impl Xhci { pub fn get_endp_status(&self, port_num: usize, endp_num: u8) -> Result { - let port_state = self - .port_states - .get(&port_num) - .ok_or(Error::new(EBADFD))?; + let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; let slot = port_state.slot; let endp_desc = port_state .dev_desc - .as_ref().unwrap() + .as_ref() + .unwrap() .config_descs .get(0) .ok_or(Error::new(EIO))? @@ -1748,7 +2277,8 @@ impl Xhci { index: 0, // TODO: interface num length: 0, }, - ).await?; + ) + .await?; } Ok(()) } @@ -1778,7 +2308,8 @@ impl Xhci { let endp_desc = port_state .dev_desc - .as_ref().unwrap() + .as_ref() + .unwrap() .config_descs .get(0) .ok_or(Error::new(EIO))? @@ -1792,18 +2323,15 @@ impl Xhci { let doorbell = if endp_num != 0 { let stream_id = 1u16; - Self::endp_doorbell( - endp_num, - endp_desc, - if has_streams { stream_id } else { 0 }, - ) + Self::endp_doorbell(endp_num, endp_desc, if has_streams { stream_id } else { 0 }) } else { Self::def_control_endp_doorbell() }; self.dbs.lock().unwrap()[slot as usize].write(doorbell); - self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle).await?; + self.set_tr_deque_ptr(port_num, endp_num, deque_ptr_and_cycle) + .await?; Ok(()) } @@ -1813,7 +2341,8 @@ impl Xhci { .get(&port_num) .ok_or(Error::new(EIO))? .dev_desc - .as_ref().unwrap() + .as_ref() + .unwrap() .config_descs .first() .ok_or(Error::new(EIO))? @@ -1838,19 +2367,23 @@ impl Xhci { let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; let slot = port_state.slot; - let endp_desc = port_state.get_endp_desc(endp_idx).ok_or(Error::new(EBADFD))?; + let endp_desc = port_state + .get_endp_desc(endp_idx) + .ok_or(Error::new(EBADFD))?; let endp_num_xhc = Self::endp_num_to_dci(endp_num, endp_desc); - let (event_trb, command_trb) = self.execute_command(|trb, cycle| { - trb.set_tr_deque_ptr( - deque_ptr_and_cycle, - cycle, - StreamContextType::PrimaryRing, - 1, - endp_num_xhc, - slot, - ) - }).await; + let (event_trb, command_trb) = self + .execute_command(|trb, cycle| { + trb.set_tr_deque_ptr( + deque_ptr_and_cycle, + cycle, + StreamContextType::PrimaryRing, + 1, + endp_num_xhc, + slot, + ) + }) + .await; self.event_handler_finished(); handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb) @@ -1881,7 +2414,10 @@ impl Xhci { } }, XhciEndpCtlReq::Reset { no_clear_feature } => match ep_if_state { - EndpIfState::Init => self.on_req_reset_device(port_num, endp_num, !no_clear_feature).await?, + EndpIfState::Init => { + self.on_req_reset_device(port_num, endp_num, !no_clear_feature) + .await? + } other => { return Err(Error::new(EBADF)); } @@ -1891,8 +2427,9 @@ impl Xhci { if direction == XhciEndpCtlDirection::NoData { // Yield the result directly because no bytes have to be sent or received // beforehand. - let (completion_code, bytes_transferred, _) = - self.transfer(port_num, endp_num - 1, None, PortReqDirection::DeviceToHost).await?; + let (completion_code, bytes_transferred, _) = self + .transfer(port_num, endp_num - 1, None, PortReqDirection::DeviceToHost) + .await?; if bytes_transferred > 0 { return Err(Error::new(EIO)); } @@ -1947,8 +2484,14 @@ impl Xhci { endp_num: u8, buf: &[u8], ) -> Result { - let mut port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; - let mut endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + let mut port_state = self + .port_states + .get_mut(&port_num) + .ok_or(Error::new(EBADFD))?; + let mut endpoint_state = port_state + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADFD))?; let ep_if_state = &mut endpoint_state.driver_if_state; @@ -1970,8 +2513,14 @@ impl Xhci { // invoking further data transfer calls if any single transfer returns fewer bytes // than requested. - let mut port_state = self.port_states.get_mut(&port_num).ok_or(Error::new(EBADFD))?; - let mut endpoint_state = port_state.endpoint_states.get_mut(&endp_num).ok_or(Error::new(EBADFD))?; + let mut port_state = self + .port_states + .get_mut(&port_num) + .ok_or(Error::new(EBADFD))?; + let mut endpoint_state = port_state + .endpoint_states + .get_mut(&endp_num) + .ok_or(Error::new(EBADFD))?; let ep_if_state = &mut endpoint_state.driver_if_state; if let &mut EndpIfState::WaitingForDataPipe { @@ -1980,7 +2529,9 @@ impl Xhci { ref mut bytes_transferred, } = ep_if_state { - if *bytes_transferred + some_bytes_transferred == bytes_to_transfer || completion_code != TrbCompletionCode::Success as u8 { + if *bytes_transferred + some_bytes_transferred == bytes_to_transfer + || completion_code != TrbCompletionCode::Success as u8 + { *ep_if_state = EndpIfState::WaitingForTransferResult(result); } else { *bytes_transferred += some_bytes_transferred; @@ -1993,12 +2544,7 @@ impl Xhci { _ => return Err(Error::new(EBADF)), } } - pub fn on_read_endp_ctl( - &self, - port_num: usize, - endp_num: u8, - buf: &mut [u8], - ) -> Result { + pub fn on_read_endp_ctl(&self, port_num: usize, endp_num: u8, buf: &mut [u8]) -> Result { let port_state = &mut self .port_states .get_mut(&port_num) @@ -2082,7 +2628,9 @@ impl Xhci { ref mut bytes_transferred, } = ep_if_state { - if *bytes_transferred + some_bytes_transferred == bytes_to_transfer || completion_code != TrbCompletionCode::Success as u8 { + if *bytes_transferred + some_bytes_transferred == bytes_to_transfer + || completion_code != TrbCompletionCode::Success as u8 + { *ep_if_state = EndpIfState::WaitingForTransferResult(result); } else { *bytes_transferred += some_bytes_transferred; @@ -2103,26 +2651,39 @@ impl Xhci { pub fn event_handler_finished(&self) { trace!("Event handler finished"); // write 1 to EHB to clear it - self.run.lock().unwrap().ints[0].erdp_low.writef(1 << 3, true); + self.run.lock().unwrap().ints[0] + .erdp_low + .writef(1 << 3, true); } } pub fn handle_event_trb(name: &str, event_trb: &Trb, command_trb: &Trb) -> Result<()> { if event_trb.completion_code() == TrbCompletionCode::Success as u8 { Ok(()) } else { - error!("{} command (TRB {:?}) failed with event trb {:?}", name, command_trb, event_trb); + error!( + "{} command (TRB {:?}) failed with event trb {:?}", + name, command_trb, event_trb + ); Err(Error::new(EIO)) } } pub fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb) -> Result<()> { - if event_trb.completion_code() == TrbCompletionCode::Success as u8 || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 { + if event_trb.completion_code() == TrbCompletionCode::Success as u8 + || event_trb.completion_code() == TrbCompletionCode::ShortPacket as u8 + { Ok(()) } else { - error!("{} transfer {:?} failed with event {:?}", name, transfer_trb, event_trb); + error!( + "{} transfer {:?} failed with event {:?}", + name, transfer_trb, event_trb + ); Err(Error::new(EIO)) } } +use lazy_static::lazy_static; use std::ops::{Add, Div, Rem}; +use std::path::Path; + pub fn div_round_up(a: T, b: T) -> T where T: Add + Div + Rem + PartialEq + From + Copy, diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 1072981503..37fee43a95 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -157,8 +157,7 @@ impl Trb { } pub fn read_data(&self) -> u64 { - (self.data_low.read() as u64) | - ((self.data_high.read() as u64) << 32) + (self.data_low.read() as u64) | ((self.data_high.read() as u64) << 32) } pub fn completion_code(&self) -> u8 { @@ -168,7 +167,9 @@ impl Trb { self.status.read() & TRB_STATUS_COMPLETION_PARAM_MASK } fn has_completion_trb_pointer(&self) -> bool { - if self.completion_code() == TrbCompletionCode::RingUnderrun as u8 || self.completion_code() == TrbCompletionCode::RingOverrun as u8 { + if self.completion_code() == TrbCompletionCode::RingUnderrun as u8 + || self.completion_code() == TrbCompletionCode::RingOverrun as u8 + { false } else if self.completion_code() == TrbCompletionCode::VfEventRingFull as u8 { false @@ -245,9 +246,7 @@ impl Trb { self.set( 0, 0, - (u32::from(slot) << 24) - | ((TrbType::DisableSlot as u32) << 10) - | u32::from(cycle) + (u32::from(slot) << 24) | ((TrbType::DisableSlot as u32) << 10) | u32::from(cycle), ); } @@ -382,7 +381,15 @@ impl Trb { ); } - pub fn status(&mut self, interrupter: u16, input: bool, ioc: bool, ch: bool, ent: bool, cycle: bool) { + pub fn status( + &mut self, + interrupter: u16, + input: bool, + ioc: bool, + ch: bool, + ent: bool, + cycle: bool, + ) { self.set( 0, u32::from(interrupter) << 22, From 306bb7d6989c4814838652596d9034604fc5a518 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Fri, 20 Sep 2024 18:39:25 -0700 Subject: [PATCH 0979/1301] Added an assertion to map_bar that causes the calling driver to panic rather than crash the kernel --- pcid/src/driver_interface/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 2900a1e68c..464e100535 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -373,6 +373,9 @@ impl PciFunctionHandle { Ok(mapped_bar) } else { let (bar, bar_size) = self.config.func.bars[bir as usize].expect_mem(); + + assert!(bar > 0); //Panic, rather than potentially crash the kernel if the bar isnt initialized. + let ptr = unsafe { common::physmap( bar, From 806e8b42b795de5195a48fb52a14476bb5fc6781 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Fri, 20 Sep 2024 18:42:03 -0700 Subject: [PATCH 0980/1301] Added an assertion to map_bar that causes the calling driver to panic rather than crash the kernel --- common/src/lib.rs | 6 ++++++ pcid/src/driver_interface/mod.rs | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/common/src/lib.rs b/common/src/lib.rs index 66f3686530..f90ed57454 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -126,6 +126,12 @@ pub unsafe fn physmap( ty: MemoryType, ) -> Result<*mut ()> { // TODO: arraystring? + + //Return an error rather than potentially crash the kernel. + if(base_phys == 0) { + return Err(Error::new(EINVAL)); + } + let path = format!( "/scheme/memory/physical@{}", match ty { diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 464e100535..6055fc74be 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -374,8 +374,6 @@ impl PciFunctionHandle { } else { let (bar, bar_size) = self.config.func.bars[bir as usize].expect_mem(); - assert!(bar > 0); //Panic, rather than potentially crash the kernel if the bar isnt initialized. - let ptr = unsafe { common::physmap( bar, From 897cf31893efcddfe4d544b0c191b2850b26eab7 Mon Sep 17 00:00:00 2001 From: Ivan Tan Date: Sun, 29 Sep 2024 09:36:36 +0000 Subject: [PATCH 0981/1301] migrate bcm2835-sdhcid to v2 scheme protocol --- storage/bcm2835-sdhcid/Cargo.toml | 4 +- storage/bcm2835-sdhcid/src/main.rs | 65 ++++++++---- storage/bcm2835-sdhcid/src/scheme.rs | 146 ++++++++++----------------- 3 files changed, 102 insertions(+), 113 deletions(-) diff --git a/storage/bcm2835-sdhcid/Cargo.toml b/storage/bcm2835-sdhcid/Cargo.toml index 78a350e29f..df313e6a93 100644 --- a/storage/bcm2835-sdhcid/Cargo.toml +++ b/storage/bcm2835-sdhcid/Cargo.toml @@ -7,9 +7,11 @@ edition = "2021" [dependencies] fdt = "0.1.5" -redox_syscall = "0.5" common = { path = "../../common" } driver-block = { path = "../driver-block" } redox-daemon = "0.1" libredox = "0.1.3" +redox_syscall = { version = "0.5", features = ["std"] } +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox_event = "0.4" diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index edcafbb4ea..60a151052c 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -1,8 +1,12 @@ use std::{fs::File, io::{Read, Write}, process}; use driver_block::Disk; +use event::{EventFlags, RawEventQueue}; use fdt::{Fdt, node::FdtNode}; -use syscall::{Packet, SchemeBlockMut}; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; +use syscall::{ + data::{Event, Packet}, error::{Error, ENODEV}, flag::EVENT_READ, io::Io, scheme::SchemeBlockMut, EAGAIN, EINTR, EWOULDBLOCK +}; use crate::scheme::DiskScheme; @@ -77,39 +81,64 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } - let scheme_name = ":disk.mmc"; - let mut socket = File::create(scheme_name).expect("mmc: failed to create disk scheme"); - libredox::call::setrens(0, 0).expect("mmc: failed to enter null namespace"); + let scheme_name = "disk.mmc"; + let socket_fd = Socket::::create(&scheme_name).expect("mmcd: failed to create disk scheme"); - daemon.ready().expect("mmc: failed to notify parent"); + let mut event_queue = RawEventQueue::new().expect("mmcd: failed to open event file"); + event_queue.subscribe(socket_fd.inner().raw(), 0, EventFlags::READ).expect("mmcd: failed to event disk scheme"); + + libredox::call::setrens(0, 0).expect("mmcd: failed to enter null namespace"); + daemon.ready().expect("mmcd: failed to notify parent"); let mut todo = Vec::new(); let mut disks = Vec::new(); disks.push(Box::new(sdhci) as Box); let mut scheme = DiskScheme::new(scheme_name.to_string(), disks); - loop { - let mut packet = Packet::default(); - if socket.read(&mut packet).expect("mmc: failed to read event") == 0 { - println!("zero, break"); + + 'outer: loop { + let Some(event) = event_queue.next().transpose().expect("mmcd: failed to read event file") else { break; - } - if let Some(a) = scheme.handle(&packet) { - packet.a = a; - socket.write(&packet).expect("mmcd: failed to write disk scheme"); + }; + if event.fd == socket_fd.inner().raw() { + loop { + let req = match socket_fd.next_request(SignalBehavior::Interrupt) { + Ok(None) => break 'outer, + Ok(Some(r)) => if let RequestKind::Call(c) = r.kind() { + c + } else { + continue; + }, + Err(err) => if matches!(err.errno, EAGAIN | EWOULDBLOCK | EINTR) { + break; + } else { + panic!("mmcd: failed to read disk scheme: {}", err); + } + }; + if let Some(resp) = req.handle_scheme_block_mut(&mut scheme) { + socket_fd.write_response(resp, SignalBehavior::Restart).expect("mmcd: failed to write disk scheme"); + } else { + todo.push(req); + } + } } else { - todo.push(packet); + println!("Unknown event {}", event.fd); } + + // Handle todos to start new packets if possible let mut i = 0; while i < todo.len() { - if let Some(a) = scheme.handle(&todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet).expect("mmcd: failed to write disk scheme"); + if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + socket_fd.write_response(resp, SignalBehavior::Restart).expect("mmcd: failed to write disk scheme"); } else { i += 1; } } + + for req in todo.drain(..) { + socket_fd.write_response(Response::new(&req, Err(Error::new(ENODEV))), SignalBehavior::Restart) + .expect("mmcd: failed to write disk scheme"); + } } process::exit(0); } diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs index 7f0e9f6e22..203c72ff40 100644 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ b/storage/bcm2835-sdhcid/src/scheme.rs @@ -1,21 +1,22 @@ use std::collections::BTreeMap; -use std::{cmp, str}; -use std::convert::{TryFrom}; +use std::str; use std::fmt::Write; -use std::io::prelude::*; use std::sync::{Arc, Mutex}; use driver_block::{Disk, DiskWrapper}; +use syscall::schemev2::NewFdFlags; use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, - Io, SchemeBlockMut, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, SEEK_CUR, SEEK_END, SEEK_SET}; + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Stat, MODE_DIR, + MODE_FILE, O_DIRECTORY, O_STAT, +}; + +use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; #[derive(Clone)] enum Handle { - List(Vec, usize), // Dir contents buffer, position - Disk(usize, usize), // Disk index, position - Partition(usize, u32, usize), // Disk index, partition index, position + List(Vec), // Dir contents buffer + Disk(usize), // Disk index + Partition(usize, u32), // Disk index, partition index } pub struct DiskScheme { @@ -28,7 +29,7 @@ pub struct DiskScheme { impl DiskScheme { pub fn new(scheme_name: String, disks: Vec>) -> DiskScheme { DiskScheme { - scheme_name: scheme_name, + scheme_name, disks: disks.into_iter().map(DiskWrapper::new).collect::>().into_boxed_slice(), handles: BTreeMap::new(), next_id: 0 @@ -39,10 +40,10 @@ impl DiskScheme { fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { for (_, handle) in self.handles.iter() { match handle { - Handle::Disk(i, _) => if disk_i == *i { + Handle::Disk(i) => if disk_i == *i { return Err(Error::new(ENOLCK)); }, - Handle::Partition(i, p, _) => if disk_i == *i { + Handle::Partition(i, p) => if disk_i == *i { match part_i_opt { Some(part_i) => if part_i == *p { return Err(Error::new(ENOLCK)); @@ -60,8 +61,8 @@ impl DiskScheme { } impl SchemeBlockMut for DiskScheme { - fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { + fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { + if ctx.uid == 0 { let path_str = path.trim_matches('/'); if path_str.is_empty() { if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { @@ -80,8 +81,8 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::List(list.into_bytes(), 0)); - Ok(Some(id)) + self.handles.insert(id, Handle::List(list.into_bytes())); + Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) } else { Err(Error::new(EISDIR)) } @@ -103,8 +104,8 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::Partition(i, p, 0)); - Ok(Some(id)) + self.handles.insert(id, Handle::Partition(i, p)); + Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) } else { Err(Error::new(ENOENT)) } @@ -116,8 +117,8 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; - self.handles.insert(id, Handle::Disk(i, 0)); - Ok(Some(id)) + self.handles.insert(id, Handle::Disk(i)); + Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) } else { Err(Error::new(ENOENT)) } @@ -145,19 +146,19 @@ impl SchemeBlockMut for DiskScheme { fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data, _) => { + Handle::List(ref data) => { stat.st_mode = MODE_DIR; stat.st_size = data.len() as u64; Ok(Some(0)) }, - Handle::Disk(number, _) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = disk.size(); stat.st_blksize = disk.block_length()?; Ok(Some(0)) } - Handle::Partition(disk_id, part_num, _) => { + Handle::Partition(disk_id, part_num) => { let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; let size = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; @@ -193,8 +194,8 @@ impl SchemeBlockMut for DiskScheme { } match *handle { - Handle::List(_, _) => (), - Handle::Disk(number, _) => { + Handle::List(_) => (), + Handle::Disk(number) => { let number_str = format!("{}", number); let number_bytes = number_str.as_bytes(); j = 0; @@ -204,7 +205,7 @@ impl SchemeBlockMut for DiskScheme { j += 1; } } - Handle::Partition(disk_num, part_num, _) => { + Handle::Partition(disk_num, part_num) => { let path = format!("{}p{}", disk_num, part_num); let path_bytes = path.as_bytes(); j = 0; @@ -219,29 +220,25 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(i)) } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _flags: u32) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle, ref mut size) => { - let count = (&handle[*size..]).read(buf).unwrap(); - *size += count; - Ok(Some(count)) + Handle::List(ref handle) => { + let src = usize::try_from(offset).ok().and_then(|o| handle.get(o..)).unwrap_or(&[]); + let bytes = src.len().min(buf.len()); + buf[..bytes].copy_from_slice(&src[..bytes]); + Ok(Some(bytes)) }, - Handle::Disk(number, ref mut size) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; - if let Some(count) = disk.read((*size as u64)/(blk_len as u64), buf)? { - *size += count; - Ok(Some(count)) - } else { - Ok(None) - } + disk.read(offset / u64::from(blk_len), buf) } - Handle::Partition(disk_num, part_num, ref mut position) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; let blksize = disk.block_length()?; // validate that we're actually reading within the bounds of the partition - let rel_block = *position as u64 / blksize as u64; + let rel_block = offset / u64::from(blksize); let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; @@ -254,36 +251,27 @@ impl SchemeBlockMut for DiskScheme { abs_block }; - if let Some(count) = disk.read(abs_block, buf)? { - Ok(Some(count)) - } else { - Ok(None) - } + disk.read(abs_block, buf) } } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_, _) => { + Handle::List(_) => { Err(Error::new(EBADF)) }, - Handle::Disk(number, ref mut size) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; - if let Some(count) = disk.write((*size as u64)/(blk_len as u64), buf)? { - *size += count; - Ok(Some(count)) - } else { - Ok(None) - } + disk.write(offset / u64::from(blk_len), buf) } - Handle::Partition(disk_num, part_num, ref mut position) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; let blksize = disk.block_length()?; // validate that we're actually reading within the bounds of the partition - let rel_block = *position as u64 / blksize as u64; + let rel_block = offset / u64::from(blksize as u64); let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; @@ -296,54 +284,24 @@ impl SchemeBlockMut for DiskScheme { abs_block }; - if let Some(count) = disk.write(abs_block, buf)? { - Ok(Some(count)) - } else { - Ok(None) - } + disk.write(abs_block, buf) } } } - fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { - let pos = pos as usize; - + fn fsize(&mut self, id: usize) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle, ref mut size) => { - let len = handle.len() as usize; - *size = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(Some(*size as isize)) + Handle::List(ref mut handle) => { + Ok(Some(handle.len() as u64)) }, - Handle::Disk(number, ref mut size) => { + Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let len = disk.size() as usize; - *size = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - - Ok(Some(*size as isize)) + Ok(Some(disk.size())) } - Handle::Partition(disk_num, part_num, ref mut position) => { + Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; let block_count = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?.size; - let len = u64::from(disk.block_length()?) * block_count; - - *position = match whence { - SEEK_SET => cmp::min(len as usize, pos) as usize, // Why isn't pos u64? - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *position as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)), - }; - Ok(Some(*position as isize)) + Ok(Some(u64::from(disk.block_length()?) * block_count)) } } } From d2c82add9d3bc4563637fd939f496b9d5c8be14c Mon Sep 17 00:00:00 2001 From: Kamil Koczurek Date: Fri, 27 Sep 2024 23:31:03 +0200 Subject: [PATCH 0982/1301] Move Io/Pio/Mmio from redox_syscall to common * Fix Mmio repr from transparent to packed. * Rename Mmio::from to Mmio::new. * Remove dead imports around affected code. * Minor formatting. --- Cargo.lock | 4 + Cargo.toml | 2 +- acpid/src/acpi.rs | 2 +- acpid/src/acpi/dmar/drhd.rs | 2 +- acpid/src/acpi/dmar/mod.rs | 2 +- acpid/src/aml_physmem.rs | 3 +- audio/ac97d/src/device.rs | 4 +- audio/ihdad/src/hda/cmdbuff.rs | 2 +- audio/ihdad/src/hda/device.rs | 2 +- audio/ihdad/src/hda/stream.rs | 2 +- audio/pcspkrd/Cargo.toml | 1 + audio/pcspkrd/src/pcspkr.rs | 2 +- audio/sb16d/src/device.rs | 3 +- common/src/io.rs | 95 +++++++++++++++ common/src/io/mmio.rs | 169 +++++++++++++++++++++++++++ common/src/io/pio.rs | 89 ++++++++++++++ common/src/lib.rs | 4 +- graphics/bgad/Cargo.toml | 1 + graphics/bgad/src/bga.rs | 2 +- net/alxd/src/device/mod.rs | 2 +- net/rtl8139d/src/device.rs | 2 +- net/rtl8168d/src/device.rs | 2 +- pcid/src/cfg_access/fallback.rs | 2 +- pcid/src/driver_interface/msi.rs | 2 +- ps2d/src/controller.rs | 2 +- storage/ahcid/src/ahci/fis.rs | 2 +- storage/ahcid/src/ahci/hba.rs | 2 +- storage/ahcid/src/ahci/mod.rs | 2 +- storage/ahcid/src/scheme.rs | 3 +- storage/bcm2835-sdhcid/src/sd/mod.rs | 5 +- storage/ided/src/ide.rs | 6 +- storage/ided/src/main.rs | 3 +- storage/nvmed/src/main.rs | 2 +- storage/nvmed/src/nvme/mod.rs | 2 +- storage/nvmed/src/scheme.rs | 2 +- vboxd/src/bga.rs | 2 +- vboxd/src/main.rs | 2 +- xhcid/src/main.rs | 2 +- xhcid/src/xhci/capability.rs | 2 +- xhcid/src/xhci/context.rs | 2 +- xhcid/src/xhci/doorbell.rs | 2 +- xhcid/src/xhci/event.rs | 2 +- xhcid/src/xhci/extended.rs | 4 +- xhcid/src/xhci/irq_reactor.rs | 10 +- xhcid/src/xhci/mod.rs | 2 +- xhcid/src/xhci/operational.rs | 2 +- xhcid/src/xhci/port.rs | 2 +- xhcid/src/xhci/runtime.rs | 2 +- xhcid/src/xhci/scheme.rs | 2 +- xhcid/src/xhci/trb.rs | 10 +- 50 files changed, 421 insertions(+), 59 deletions(-) create mode 100644 common/src/io.rs create mode 100644 common/src/io/mmio.rs create mode 100644 common/src/io/pio.rs diff --git a/Cargo.lock b/Cargo.lock index aa9a3a5ccf..583fab0341 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -165,6 +165,8 @@ dependencies = [ "fdt 0.1.5", "libredox 0.1.3", "redox-daemon", + "redox-scheme", + "redox_event", "redox_syscall 0.5.3", ] @@ -172,6 +174,7 @@ dependencies = [ name = "bgad" version = "0.1.0" dependencies = [ + "common", "libredox 0.1.3", "orbclient", "pcid", @@ -955,6 +958,7 @@ dependencies = [ name = "pcspkrd" version = "0.1.0" dependencies = [ + "common", "libredox 0.1.3", "redox-daemon", "redox_syscall 0.5.3", diff --git a/Cargo.toml b/Cargo.toml index 65715466f7..83a012f471 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ members = [ "storage/bcm2835-sdhcid", "storage/driver-block", "storage/ided", - "storage/lived", # TODO: not really a driver... + "storage/lived", # TODO: not really a driver... "storage/nvmed", "storage/usbscsid", "storage/virtio-blkd", diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 34edc263b9..2564825b15 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -6,7 +6,7 @@ use std::sync::{Arc, Mutex}; use std::{fmt, mem}; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use syscall::io::{Io, Pio}; +use common::io::{Io, Pio}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use thiserror::Error; diff --git a/acpid/src/acpi/dmar/drhd.rs b/acpid/src/acpi/dmar/drhd.rs index 70c8f8b42b..da51d4349c 100644 --- a/acpid/src/acpi/dmar/drhd.rs +++ b/acpid/src/acpi/dmar/drhd.rs @@ -1,6 +1,6 @@ use std::ops::{Deref, DerefMut}; -use syscall::io::Mmio; +use common::io::Mmio; // TODO: Only wrap with Mmio where there are hardware-registers. (Some of these structs seem to be // ring buffer entries, which are not to be treated the same way). diff --git a/acpid/src/acpi/dmar/mod.rs b/acpid/src/acpi/dmar/mod.rs index 6d59c25e99..f89eae95f2 100644 --- a/acpid/src/acpi/dmar/mod.rs +++ b/acpid/src/acpi/dmar/mod.rs @@ -10,7 +10,7 @@ use std::convert::TryFrom; use std::ops::Deref; use std::{fmt, mem}; -use syscall::io::Io as _; +use common::io::Io as _; use num_derive::FromPrimitive; use num_traits::FromPrimitive; diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 03d0eb5fef..e8f82d5f4c 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -3,7 +3,8 @@ use rustc_hash::FxHashMap; use std::fmt::LowerHex; use std::mem::size_of; use std::sync::{Arc, Mutex}; -use syscall::{Io, Pio, PAGE_SIZE}; +use syscall::PAGE_SIZE; +use common::io::{Io, Pio}; const PAGE_MASK: usize = !(PAGE_SIZE - 1); const OFFSET_MASK: usize = PAGE_SIZE - 1; diff --git a/audio/ac97d/src/device.rs b/audio/ac97d/src/device.rs index e5b747e8f9..1892d34fda 100644 --- a/audio/ac97d/src/device.rs +++ b/audio/ac97d/src/device.rs @@ -5,10 +5,10 @@ use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; use syscall::error::{Error, EACCES, EBADF, Result, EINVAL, ENOENT}; -use syscall::io::{Mmio, Pio, Io}; +use common::io::Pio; use syscall::scheme::SchemeBlockMut; -use common::dma::Dma; +use common::{dma::Dma, io::{Io, Mmio}}; use spin::Mutex; const NUM_SUB_BUFFS: usize = 32; diff --git a/audio/ihdad/src/hda/cmdbuff.rs b/audio/ihdad/src/hda/cmdbuff.rs index c06c448d65..93e771d01c 100644 --- a/audio/ihdad/src/hda/cmdbuff.rs +++ b/audio/ihdad/src/hda/cmdbuff.rs @@ -1,5 +1,5 @@ use common::dma::Dma; -use syscall::io::{Io, Mmio}; +use common::io::{Io, Mmio}; use super::common::*; diff --git a/audio/ihdad/src/hda/device.rs b/audio/ihdad/src/hda/device.rs index 09d2c56bfb..86847d3a00 100755 --- a/audio/ihdad/src/hda/device.rs +++ b/audio/ihdad/src/hda/device.rs @@ -8,9 +8,9 @@ use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; use common::dma::Dma; +use common::io::{Mmio, Io}; use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; -use syscall::io::{Mmio, Io}; use syscall::scheme::SchemeBlockMut; use spin::Mutex; diff --git a/audio/ihdad/src/hda/stream.rs b/audio/ihdad/src/hda/stream.rs index afad58a609..49fb4dd2f7 100644 --- a/audio/ihdad/src/hda/stream.rs +++ b/audio/ihdad/src/hda/stream.rs @@ -1,7 +1,7 @@ use common::dma::Dma; +use common::io::{Mmio, Io}; use syscall::PAGE_SIZE; use syscall::error::{Error, EIO, Result}; -use syscall::io::{Mmio, Io}; use std::result; use std::cmp::min; use std::ptr::copy_nonoverlapping; diff --git a/audio/pcspkrd/Cargo.toml b/audio/pcspkrd/Cargo.toml index 2ff4476a9a..555c25f566 100644 --- a/audio/pcspkrd/Cargo.toml +++ b/audio/pcspkrd/Cargo.toml @@ -5,6 +5,7 @@ authors = ["Tibor Nagy "] edition = "2018" [dependencies] +common = { path = "../../common" } redox_syscall = "0.5" redox-daemon = "0.1" libredox = "0.1.3" diff --git a/audio/pcspkrd/src/pcspkr.rs b/audio/pcspkrd/src/pcspkr.rs index f8c6760683..945421c2eb 100644 --- a/audio/pcspkrd/src/pcspkr.rs +++ b/audio/pcspkrd/src/pcspkr.rs @@ -1,4 +1,4 @@ -use syscall::io::{Io, Pio}; +use common::io::{Io, Pio}; pub struct Pcspkr { command: Pio, diff --git a/audio/sb16d/src/device.rs b/audio/sb16d/src/device.rs index ea0530d78f..47cf231f5a 100644 --- a/audio/sb16d/src/device.rs +++ b/audio/sb16d/src/device.rs @@ -4,8 +4,9 @@ use std::{thread, time}; use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; +use common::io::{Pio, Io, ReadOnly, WriteOnly}; + use syscall::error::{Error, EACCES, EBADF, Result, ENODEV}; -use syscall::io::{Pio, Io, ReadOnly, WriteOnly}; use syscall::scheme::SchemeBlockMut; use spin::Mutex; diff --git a/common/src/io.rs b/common/src/io.rs new file mode 100644 index 0000000000..955cf0a06f --- /dev/null +++ b/common/src/io.rs @@ -0,0 +1,95 @@ +use core::{ + cmp::PartialEq, + ops::{BitAnd, BitOr, Not}, +}; + +mod mmio; +mod pio; + +pub use mmio::*; +pub use pio::*; + +/// IO abstraction +pub trait Io { + /// Value type for IO, usually some unsigned number + type Value: Copy + + PartialEq + + BitAnd + + BitOr + + Not; + + /// Read the underlying valu2e + fn read(&self) -> Self::Value; + /// Write the underlying value + fn write(&mut self, value: Self::Value); + + /// Check whether the underlying value contains bit flags + #[inline(always)] + fn readf(&self, flags: Self::Value) -> bool { + (self.read() & flags) as Self::Value == flags + } + + /// Enable or disable specific bit flags + #[inline(always)] + fn writef(&mut self, flags: Self::Value, value: bool) { + let tmp: Self::Value = match value { + true => self.read() | flags, + false => self.read() & !flags, + }; + self.write(tmp); + } +} + +/// Read-only IO +#[repr(transparent)] +pub struct ReadOnly { + inner: I, +} + +impl ReadOnly { + /// Wraps IO + pub const fn new(inner: I) -> ReadOnly { + ReadOnly { inner } + } +} + +impl ReadOnly { + /// Calls [Io::read] + #[inline(always)] + pub fn read(&self) -> I::Value { + self.inner.read() + } + + /// Calls [Io::readf] + #[inline(always)] + pub fn readf(&self, flags: I::Value) -> bool { + self.inner.readf(flags) + } +} + +#[repr(transparent)] +/// Write-only IO +pub struct WriteOnly { + inner: I, +} + +impl WriteOnly { + /// Wraps IO + pub const fn new(inner: I) -> WriteOnly { + WriteOnly { inner } + } +} + +impl WriteOnly { + /// Calls [Io::write] + #[inline(always)] + pub fn write(&mut self, value: I::Value) { + self.inner.write(value) + } + + #[inline(always)] + /// Calls [Io::writef] + pub fn writef(&mut self, flags: I::Value, value: bool) { + self.inner.writef(flags, value) + } +} \ No newline at end of file diff --git a/common/src/io/mmio.rs b/common/src/io/mmio.rs new file mode 100644 index 0000000000..ca9d564ce2 --- /dev/null +++ b/common/src/io/mmio.rs @@ -0,0 +1,169 @@ +use core::{mem::MaybeUninit, ptr}; + +use super::Io; + +/// MMIO abstraction +#[repr(packed)] +pub struct Mmio { + value: MaybeUninit, +} + +impl Mmio { + /// Creates a zeroed instance + pub unsafe fn zeroed() -> Self { + Self { + value: MaybeUninit::zeroed(), + } + } + + /// Creates an unitialized instance + pub unsafe fn uninit() -> Self { + Self { + value: MaybeUninit::uninit(), + } + } + + /// Creates a new instance + pub const fn new(value: T) -> Self { + Self { + value: MaybeUninit::new(value), + } + } +} + +// Generic implementation (WARNING: requires aligned pointers!) +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +impl Io for Mmio +where + T: Copy + PartialEq + BitAnd + BitOr + Not, +{ + type Value = T; + + fn read(&self) -> T { + unsafe { ptr::read_volatile(ptr::addr_of!(self.value).cast::()) } + } + + fn write(&mut self, value: T) { + unsafe { ptr::write_volatile(ptr::addr_of_mut!(self.value).cast::(), value) }; + } +} + +// x86 u8 implementation +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +impl Io for Mmio { + type Value = u8; + + fn read(&self) -> Self::Value { + unsafe { + let value: Self::Value; + let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); + core::arch::asm!( + "mov {}, [{}]", + out(reg_byte) value, + in(reg) ptr + ); + value + } + } + + fn write(&mut self, value: Self::Value) { + unsafe { + let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); + core::arch::asm!( + "mov [{}], {}", + in(reg) ptr, + in(reg_byte) value, + ); + } + } +} + +// x86 u16 implementation +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +impl Io for Mmio { + type Value = u16; + + fn read(&self) -> Self::Value { + unsafe { + let value: Self::Value; + let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); + core::arch::asm!( + "mov {:x}, [{}]", + out(reg) value, + in(reg) ptr + ); + value + } + } + + fn write(&mut self, value: Self::Value) { + unsafe { + let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); + core::arch::asm!( + "mov [{}], {:x}", + in(reg) ptr, + in(reg) value, + ); + } + } +} + +// x86 u32 implementation +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +impl Io for Mmio { + type Value = u32; + + fn read(&self) -> Self::Value { + unsafe { + let value: Self::Value; + let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); + core::arch::asm!( + "mov {:e}, [{}]", + out(reg) value, + in(reg) ptr + ); + value + } + } + + fn write(&mut self, value: Self::Value) { + unsafe { + let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); + core::arch::asm!( + "mov [{}], {:e}", + in(reg) ptr, + in(reg) value, + ); + } + } +} + +// x86 u64 implementation (x86_64 only) +#[cfg(target_arch = "x86_64")] +impl Io for Mmio { + type Value = u64; + + fn read(&self) -> Self::Value { + unsafe { + let value: Self::Value; + let ptr: *const Self::Value = ptr::addr_of!(self.value).cast::(); + core::arch::asm!( + "mov {:r}, [{}]", + out(reg) value, + in(reg) ptr + ); + value + } + } + + fn write(&mut self, value: Self::Value) { + unsafe { + let ptr: *mut Self::Value = ptr::addr_of_mut!(self.value).cast::(); + core::arch::asm!( + "mov [{}], {:r}", + in(reg) ptr, + in(reg) value, + ); + } + } +} diff --git a/common/src/io/pio.rs b/common/src/io/pio.rs new file mode 100644 index 0000000000..187e4734c3 --- /dev/null +++ b/common/src/io/pio.rs @@ -0,0 +1,89 @@ +use core::{arch::asm, marker::PhantomData}; + +use super::Io; + +/// Generic PIO +#[derive(Copy, Clone)] +pub struct Pio { + port: u16, + value: PhantomData, +} + +impl Pio { + /// Create a PIO from a given port + pub const fn new(port: u16) -> Self { + Pio:: { + port, + value: PhantomData, + } + } +} + +/// Read/Write for byte PIO +impl Io for Pio { + type Value = u8; + + /// Read + #[inline(always)] + fn read(&self) -> u8 { + let value: u8; + unsafe { + asm!("in al, dx", in("dx") self.port, out("al") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u8) { + unsafe { + asm!("out dx, al", in("dx") self.port, in("al") value, options(nostack, nomem, preserves_flags)); + } + } +} + +/// Read/Write for word PIO +impl Io for Pio { + type Value = u16; + + /// Read + #[inline(always)] + fn read(&self) -> u16 { + let value: u16; + unsafe { + asm!("in ax, dx", in("dx") self.port, out("ax") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u16) { + unsafe { + asm!("out dx, ax", in("dx") self.port, in("ax") value, options(nostack, nomem, preserves_flags)); + } + } +} + +/// Read/Write for doubleword PIO +impl Io for Pio { + type Value = u32; + + /// Read + #[inline(always)] + fn read(&self) -> u32 { + let value: u32; + unsafe { + asm!("in eax, dx", in("dx") self.port, out("eax") value, options(nostack, nomem, preserves_flags)); + } + value + } + + /// Write + #[inline(always)] + fn write(&mut self, value: u32) { + unsafe { + asm!("out dx, eax", in("dx") self.port, in("eax") value, options(nostack, nomem, preserves_flags)); + } + } +} diff --git a/common/src/lib.rs b/common/src/lib.rs index f90ed57454..61fa6ced99 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -12,6 +12,8 @@ use syscall::PAGE_SIZE; /// The Direct Memory Access (DMA) API for drivers pub mod dma; +/// MMIO utilities +pub mod io; mod logger; /// The Scatter Gather List (SGL) API for drivers. pub mod sgl; @@ -128,7 +130,7 @@ pub unsafe fn physmap( // TODO: arraystring? //Return an error rather than potentially crash the kernel. - if(base_phys == 0) { + if base_phys == 0 { return Err(Error::new(EINVAL)); } diff --git a/graphics/bgad/Cargo.toml b/graphics/bgad/Cargo.toml index 76dc78b582..4e9fe1ae5f 100644 --- a/graphics/bgad/Cargo.toml +++ b/graphics/bgad/Cargo.toml @@ -8,5 +8,6 @@ orbclient = "0.3.47" redox-daemon = "0.1" redox_syscall = "0.5" +common = { path = "../../common" } pcid = { path = "../../pcid" } libredox = "0.1.3" diff --git a/graphics/bgad/src/bga.rs b/graphics/bgad/src/bga.rs index ee196f7f95..a498125c9a 100644 --- a/graphics/bgad/src/bga.rs +++ b/graphics/bgad/src/bga.rs @@ -1,4 +1,4 @@ -use syscall::io::{Io, Pio}; +use common::io::{Io, Pio}; const BGA_INDEX_XRES: u16 = 1; const BGA_INDEX_YRES: u16 = 2; diff --git a/net/alxd/src/device/mod.rs b/net/alxd/src/device/mod.rs index 0222cd1c27..baac6fc89d 100644 --- a/net/alxd/src/device/mod.rs +++ b/net/alxd/src/device/mod.rs @@ -3,7 +3,7 @@ use std::convert::TryInto; use syscall::error::{Error, EACCES, EINVAL, EIO, EWOULDBLOCK, Result}; use syscall::flag::{EventFlags, O_NONBLOCK}; -use syscall::io::{Io, Mmio}; +use common::io::{Io, Mmio}; use syscall::scheme; use common::dma::Dma; diff --git a/net/rtl8139d/src/device.rs b/net/rtl8139d/src/device.rs index e6ef45053b..d67a1b3078 100644 --- a/net/rtl8139d/src/device.rs +++ b/net/rtl8139d/src/device.rs @@ -3,8 +3,8 @@ use std::convert::TryInto; use driver_network::NetworkAdapter; use syscall::error::{Error, EIO, EMSGSIZE, Result}; -use syscall::io::{Mmio, Io, ReadOnly}; +use common::io::{Mmio, Io, ReadOnly}; use common::dma::Dma; const RX_BUFFER_SIZE: usize = 64 * 1024; diff --git a/net/rtl8168d/src/device.rs b/net/rtl8168d/src/device.rs index 717ac194e2..b2aef1889e 100644 --- a/net/rtl8168d/src/device.rs +++ b/net/rtl8168d/src/device.rs @@ -3,7 +3,7 @@ use std::convert::TryInto; use driver_network::NetworkAdapter; use syscall::error::{Error, Result, EMSGSIZE}; -use syscall::io::{Mmio, Io, ReadOnly}; +use common::io::{Mmio, Io, ReadOnly}; use common::dma::Dma; diff --git a/pcid/src/cfg_access/fallback.rs b/pcid/src/cfg_access/fallback.rs index 1f1e49a8ae..671d17f735 100644 --- a/pcid/src/cfg_access/fallback.rs +++ b/pcid/src/cfg_access/fallback.rs @@ -3,7 +3,7 @@ use std::convert::TryFrom; use std::sync::Mutex; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -use syscall::io::{Io as _, Pio}; +use common::io::{Io as _, Pio}; use log::info; use pci_types::{ConfigRegionAccess, PciAddress}; diff --git a/pcid/src/driver_interface/msi.rs b/pcid/src/driver_interface/msi.rs index cba4d21399..d95837eb77 100644 --- a/pcid/src/driver_interface/msi.rs +++ b/pcid/src/driver_interface/msi.rs @@ -3,7 +3,7 @@ use std::fmt; use crate::driver_interface::PciBar; use serde::{Deserialize, Serialize}; -use syscall::{Io, Mmio}; +use common::io::{Io, Mmio}; /// The address and data to use for MSI and MSI-X. /// diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index ecb9036794..24968b84a5 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -1,5 +1,5 @@ use log::{debug, error, info, trace}; -use syscall::io::{Io, Pio, ReadOnly, WriteOnly}; +use common::io::{Io, Pio, ReadOnly, WriteOnly}; use std::fmt; diff --git a/storage/ahcid/src/ahci/fis.rs b/storage/ahcid/src/ahci/fis.rs index 1d4013ae88..0e4b380271 100644 --- a/storage/ahcid/src/ahci/fis.rs +++ b/storage/ahcid/src/ahci/fis.rs @@ -1,4 +1,4 @@ -use syscall::io::Mmio; +use common::io::Mmio; #[repr(u8)] pub enum FisType { diff --git a/storage/ahcid/src/ahci/hba.rs b/storage/ahcid/src/ahci/hba.rs index 5ca6af72f7..b893fddc81 100644 --- a/storage/ahcid/src/ahci/hba.rs +++ b/storage/ahcid/src/ahci/hba.rs @@ -3,7 +3,7 @@ use std::mem::size_of; use std::ops::DerefMut; use std::{ptr, u32}; -use syscall::io::{Io, Mmio}; +use common::io::{Io, Mmio}; use syscall::error::{Error, Result, EIO}; use super::fis::{FisType, FisRegH2D}; diff --git a/storage/ahcid/src/ahci/mod.rs b/storage/ahcid/src/ahci/mod.rs index 3f63ca235e..aaf3b78523 100644 --- a/storage/ahcid/src/ahci/mod.rs +++ b/storage/ahcid/src/ahci/mod.rs @@ -1,6 +1,6 @@ use driver_block::Disk; use log::{error, info}; -use syscall::io::Io; +use common::io::Io; use self::disk_ata::DiskATA; use self::disk_atapi::DiskATAPI; diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index 8a6cc89480..c5f03d97b6 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -5,9 +5,10 @@ use std::fmt::Write; use driver_block::{Disk, DiskWrapper}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Io, Stat, MODE_DIR, + Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Stat, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, }; +use common::io::Io as _; use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; use crate::ahci::hba::HbaMem; diff --git a/storage/bcm2835-sdhcid/src/sd/mod.rs b/storage/bcm2835-sdhcid/src/sd/mod.rs index ece800a329..2e31b3ae19 100644 --- a/storage/bcm2835-sdhcid/src/sd/mod.rs +++ b/storage/bcm2835-sdhcid/src/sd/mod.rs @@ -1,6 +1,7 @@ -use std::{sync::{Mutex, RwLock}, time::{self, Duration}, thread}; -use syscall::{io::Mmio, Io, Error, Result, EINVAL}; +use common::io::{Io, Mmio}; use driver_block::Disk; +use std::{sync::RwLock, thread, time::Duration}; +use syscall::{Error, Result, EINVAL}; #[cfg(target_arch = "aarch64")] #[inline(always)] diff --git a/storage/ided/src/ide.rs b/storage/ided/src/ide.rs index 8428d92b60..f61003c1a2 100644 --- a/storage/ided/src/ide.rs +++ b/storage/ided/src/ide.rs @@ -6,12 +6,10 @@ use std::{ }; use driver_block::Disk; -use syscall::{ - error::{Error, Result, EIO}, - io::{Io, Pio, ReadOnly, WriteOnly}, -}; +use syscall::error::{Error, Result, EIO}; use common::dma::Dma; +use common::io::{Io, Pio, ReadOnly, WriteOnly}; static TIMEOUT: Duration = Duration::new(1, 0); diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 28719cfddd..73db90c14f 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -12,8 +12,9 @@ use std::{ thread::{self, sleep}, time::Duration, }; +use common::io::Io as _; use syscall::{ - data::{Event, Packet}, error::{Error, ENODEV}, flag::EVENT_READ, io::Io, scheme::SchemeBlockMut, EAGAIN, EINTR, EWOULDBLOCK + data::{Event, Packet}, error::{Error, ENODEV}, flag::EVENT_READ, scheme::SchemeBlockMut, EAGAIN, EINTR, EWOULDBLOCK }; use crate::{ diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 28ff062e47..0676d6a3be 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -13,7 +13,7 @@ use libredox::flag; use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PciFunctionHandle}; use redox_scheme::{CallRequest, RequestKind, SignalBehavior, Socket, V2}; use syscall::{ - Event, Mmio, Packet, Result, SchemeBlockMut, + Event, Packet, Result, SchemeBlockMut, PAGE_SIZE, }; diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 14e502777a..a4127a3b51 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -10,7 +10,7 @@ use crossbeam_channel::Sender; use smallvec::{smallvec, SmallVec}; use syscall::error::{Error, Result, EINVAL, EIO}; -use syscall::io::{Io, Mmio}; +use common::io::{Io, Mmio}; use common::dma::Dma; diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index a301a7fa98..a38fb1cada 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -8,7 +8,7 @@ use std::{cmp, str}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Io, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, + Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET, }; use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; diff --git a/vboxd/src/bga.rs b/vboxd/src/bga.rs index 21599f7fd0..d9fe280100 100644 --- a/vboxd/src/bga.rs +++ b/vboxd/src/bga.rs @@ -1,4 +1,4 @@ -use syscall::io::{Io, Pio}; +use common::io::{Io, Pio}; const BGA_INDEX_XRES: u16 = 1; const BGA_INDEX_YRES: u16 = 2; diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index fac9717351..8a50ccce82 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -8,7 +8,7 @@ use std::io::{Result, Read, Write}; use pcid_interface::{PciBar, PciFunctionHandle}; use syscall::flag::EventFlags; -use syscall::io::{Io, Mmio, Pio}; +use common::io::{Io, Mmio, Pio}; use common::dma::Dma; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index e3798cd580..e117f2a867 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -49,7 +49,7 @@ use event::{Event, RawEventQueue}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::EventFlags; -use syscall::io::Io; +use common::io::Io; use syscall::scheme::Scheme; use crate::xhci::{InterruptMethod, Xhci}; diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index ab3ffb8502..7dfd670448 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -1,4 +1,4 @@ -use syscall::io::{Io, Mmio}; +use common::io::{Io, Mmio}; /// Represents the memory-mapped Capability Registers of the XHCI /// diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index aabbeaf754..932fe6f202 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use log::debug; use syscall::error::Result; -use syscall::io::{Io, Mmio}; +use common::io::{Io, Mmio}; use syscall::PAGE_SIZE; use common::dma::Dma; diff --git a/xhcid/src/xhci/doorbell.rs b/xhcid/src/xhci/doorbell.rs index b464186b98..58c6cba36f 100644 --- a/xhcid/src/xhci/doorbell.rs +++ b/xhcid/src/xhci/doorbell.rs @@ -1,4 +1,4 @@ -use syscall::io::{Io, Mmio}; +use common::io::{Io, Mmio}; #[repr(packed)] pub struct Doorbell(Mmio); diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index c955d6488d..f2da331a95 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -1,5 +1,5 @@ use syscall::error::Result; -use syscall::io::{Io, Mmio}; +use common::io::{Io, Mmio}; use common::dma::Dma; diff --git a/xhcid/src/xhci/extended.rs b/xhcid/src/xhci/extended.rs index 6e303c30b7..1f8115b7e5 100644 --- a/xhcid/src/xhci/extended.rs +++ b/xhcid/src/xhci/extended.rs @@ -1,7 +1,7 @@ use std::ops::Range; use std::ptr::NonNull; use std::{fmt, mem, ptr, slice}; -use syscall::{Io, Mmio}; +use common::io::{Io, Mmio}; pub struct ExtendedCapabilitiesIter { base: *const u8, @@ -111,7 +111,7 @@ pub enum Lp { impl ProtocolSpeed { pub const fn from_raw(raw: u32) -> Self { - Self { a: Mmio::from(raw) } + Self { a: Mmio::new(raw) } } pub fn is_lowspeed(&self) -> bool { self.psim() == 1500 && self.psie() == Psie::Kbps && !self.pfd() diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 2de350cbba..a42728d4cc 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -1,20 +1,16 @@ -use std::collections::BTreeMap; use std::fs::File; use std::future::Future; use std::io::prelude::*; use std::pin::Pin; -use std::sync::atomic::{self, AtomicUsize}; use std::sync::{Arc, Mutex}; -use std::{io, mem, task, thread}; +use std::task; use std::os::unix::io::AsRawFd; use crossbeam_channel::{Receiver, Sender}; -use futures::Stream; use log::{debug, error, info, trace, warn}; -use syscall::Io; -use event::{Event, EventQueue, RawEventQueue}; +use event::RawEventQueue; use super::doorbell::Doorbell; use super::event::EventRing; @@ -22,6 +18,8 @@ use super::ring::Ring; use super::trb::{Trb, TrbCompletionCode, TrbType}; use super::Xhci; +use common::io::Io as _; + /// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back /// by the future unless it completed). #[derive(Debug)] diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 07a6826bb1..a0a72f296a 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -21,7 +21,7 @@ use std::sync::{Arc, Mutex, MutexGuard, Weak}; use std::{mem, process, slice, sync::atomic, task, thread}; use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT}; -use syscall::io::Io; +use common::io::Io; use syscall::PAGE_SIZE; use chashmap::CHashMap; diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index 4dcc760e9f..42918c922c 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -1,6 +1,6 @@ use std::num::NonZeroU8; use std::slice; -use syscall::io::{Io, Mmio}; +use common::io::{Io, Mmio}; use super::CapabilityRegs; diff --git a/xhcid/src/xhci/port.rs b/xhcid/src/xhci/port.rs index 674a79332a..d1b4e37187 100644 --- a/xhcid/src/xhci/port.rs +++ b/xhcid/src/xhci/port.rs @@ -1,4 +1,4 @@ -use syscall::io::{Io, Mmio}; +use common::io::{Io, Mmio}; bitflags! { pub struct PortFlags: u32 { diff --git a/xhcid/src/xhci/runtime.rs b/xhcid/src/xhci/runtime.rs index b18fb482e9..deeb96f401 100644 --- a/xhcid/src/xhci/runtime.rs +++ b/xhcid/src/xhci/runtime.rs @@ -1,4 +1,4 @@ -use syscall::io::Mmio; +use common::io::Mmio; #[repr(packed)] pub struct Interrupter { diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index b5824d5f61..47914b8769 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -28,7 +28,7 @@ use log::{debug, error, info, trace, warn}; use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; -use syscall::io::Io; +use common::io::Io; use syscall::scheme::Scheme; use syscall::{ Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 37fee43a95..f30443a5f4 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -1,6 +1,6 @@ use crate::usb; use std::{fmt, mem}; -use syscall::io::{Io, Mmio}; +use common::io::{Io, Mmio}; use super::context::StreamContextType; @@ -118,10 +118,10 @@ pub struct Trb { impl Clone for Trb { fn clone(&self) -> Self { Self { - data_low: Mmio::from(self.data_low.read()), - data_high: Mmio::from(self.data_high.read()), - status: Mmio::from(self.status.read()), - control: Mmio::from(self.control.read()), + data_low: Mmio::new(self.data_low.read()), + data_high: Mmio::new(self.data_high.read()), + status: Mmio::new(self.status.read()), + control: Mmio::new(self.control.read()), } } } From 56bfd631733fe1a121a6aa12a2355ad897cacf42 Mon Sep 17 00:00:00 2001 From: Kamil Koczurek Date: Thu, 26 Sep 2024 17:01:55 +0200 Subject: [PATCH 0983/1301] acpid: update to redox_scheme * Change symbol serialization to RON --- Cargo.lock | 134 +++++++++++------- acpid/Cargo.toml | 7 +- acpid/src/acpi.rs | 15 +- acpid/src/acpi/dmar/drhd.rs | 13 +- acpid/src/main.rs | 162 ++++++++-------------- acpid/src/scheme.rs | 266 ++++++++++++++++++++---------------- 6 files changed, 311 insertions(+), 286 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 583fab0341..a9d3c51e67 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,7 +13,7 @@ dependencies = [ "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "spin", ] @@ -23,6 +23,7 @@ version = "0.1.0" dependencies = [ "aml", "amlserde", + "arrayvec 0.7.6", "common", "libredox 0.1.3", "log", @@ -31,9 +32,11 @@ dependencies = [ "parking_lot 0.11.2", "plain", "redox-daemon", - "redox_syscall 0.5.3", + "redox-scheme 0.2.2", + "redox_event", + "redox_syscall 0.5.6", + "ron", "rustc-hash", - "serde_json", "thiserror", ] @@ -49,9 +52,9 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.2.1", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -72,7 +75,7 @@ dependencies = [ "libredox 0.1.3", "redox-daemon", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -133,6 +136,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + [[package]] name = "atty" version = "0.2.14" @@ -156,6 +165,12 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + [[package]] name = "bcm2835-sdhcid" version = "0.1.0" @@ -165,9 +180,9 @@ dependencies = [ "fdt 0.1.5", "libredox 0.1.3", "redox-daemon", - "redox-scheme", + "redox-scheme 0.2.1", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -179,7 +194,7 @@ dependencies = [ "orbclient", "pcid", "redox-daemon", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -208,6 +223,9 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "bitvec" @@ -297,7 +315,7 @@ dependencies = [ "libredox 0.1.3", "log", "redox-log", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -362,7 +380,7 @@ name = "driver-block" version = "0.1.0" dependencies = [ "partitionlib", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -370,7 +388,7 @@ name = "driver-network" version = "0.1.0" dependencies = [ "libredox 0.1.3", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -384,7 +402,7 @@ dependencies = [ "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -403,7 +421,7 @@ dependencies = [ "ransid", "redox-daemon", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -601,9 +619,9 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.2.1", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -617,7 +635,7 @@ dependencies = [ "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "spin", ] @@ -641,7 +659,7 @@ dependencies = [ "log", "orbclient", "redox-daemon", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "spin", ] @@ -671,7 +689,7 @@ dependencies = [ "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -714,7 +732,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -724,9 +742,9 @@ dependencies = [ "anyhow", "libredox 0.1.3", "redox-daemon", - "redox-scheme", + "redox-scheme 0.2.1", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -787,7 +805,7 @@ checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" name = "nvmed" version = "0.1.0" dependencies = [ - "arrayvec", + "arrayvec 0.5.2", "bitflags 1.3.2", "common", "crossbeam-channel", @@ -798,9 +816,9 @@ dependencies = [ "partitionlib", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.2.1", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "smallvec 1.13.2", ] @@ -946,7 +964,7 @@ dependencies = [ "pci_types", "plain", "redox-daemon", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "serde", "serde_json", "structopt", @@ -961,7 +979,7 @@ dependencies = [ "common", "libredox 0.1.3", "redox-daemon", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -1025,7 +1043,7 @@ dependencies = [ "log", "orbclient", "redox-daemon", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -1117,7 +1135,17 @@ version = "0.2.1" source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#79d9d54f572f53386981fb9b6ef054fd9e45110c" dependencies = [ "libredox 0.1.3", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", +] + +[[package]] +name = "redox-scheme" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98d040cfa6370d9c6b1a5987247272f19ea4722f1064e66ad2e077c152b82ea3" +dependencies = [ + "libredox 0.1.3", + "redox_syscall 0.5.6", ] [[package]] @@ -1150,9 +1178,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" dependencies = [ "bitflags 2.6.0", ] @@ -1202,6 +1230,18 @@ dependencies = [ "ux", ] +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.6.0", + "serde", + "serde_derive", +] + [[package]] name = "rtl8139d" version = "0.1.0" @@ -1214,7 +1254,7 @@ dependencies = [ "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -1229,7 +1269,7 @@ dependencies = [ "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -1254,7 +1294,7 @@ dependencies = [ "log", "redox-daemon", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "spin", ] @@ -1581,7 +1621,7 @@ dependencies = [ "common", "log", "orbclient", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "rehid", "xhcid", ] @@ -1592,7 +1632,7 @@ version = "0.1.0" dependencies = [ "common", "log", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "xhcid", ] @@ -1600,12 +1640,12 @@ dependencies = [ name = "usbscsid" version = "0.1.0" dependencies = [ - "base64", + "base64 0.11.0", "libredox 0.1.3", "plain", "redox-daemon", - "redox-scheme", - "redox_syscall 0.5.3", + "redox-scheme 0.2.1", + "redox_syscall 0.5.6", "thiserror", "xhcid", ] @@ -1641,7 +1681,7 @@ dependencies = [ "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -1672,7 +1712,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", ] [[package]] @@ -1688,8 +1728,8 @@ dependencies = [ "partitionlib", "pcid", "redox-daemon", - "redox-scheme", - "redox_syscall 0.5.3", + "redox-scheme 0.2.1", + "redox_syscall 0.5.6", "spin", "static_assertions", "thiserror", @@ -1708,7 +1748,7 @@ dependencies = [ "log", "pcid", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "static_assertions", "thiserror", ] @@ -1727,7 +1767,7 @@ dependencies = [ "paste", "pcid", "redox-daemon", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "spin", "static_assertions", "virtio-core", @@ -1744,7 +1784,7 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "static_assertions", "virtio-core", ] @@ -1947,7 +1987,7 @@ dependencies = [ "plain", "redox-daemon", "redox_event", - "redox_syscall 0.5.3", + "redox_syscall 0.5.6", "regex", "serde", "serde_json", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 0ba5a37b00..21b4f4268b 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -14,11 +14,14 @@ num-traits = "0.2" parking_lot = "0.11.1" plain = "0.2.3" redox-daemon = "0.1" -redox_syscall = "0.5" +redox_syscall = "0.5.6" +redox_event = "0.4.1" rustc-hash = "1.1.0" thiserror = "1" -serde_json = "1.0.94" +ron = "0.8.1" amlserde = { path = "../amlserde" } common = { path = "../common" } libredox = "0.1.3" +redox-scheme = "0.2.2" +arrayvec = "0.7.6" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 2564825b15..4071c92902 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -16,7 +16,6 @@ use amlserde::aml_serde_name::aml_to_symbol; use amlserde::{AmlHandleLookup, AmlSerde}; pub mod dmar; -use self::dmar::Dmar; use crate::aml_physmem::{AmlPageCache, AmlPhysMemHandler}; #[cfg(target_arch = "aarch64")] @@ -245,7 +244,6 @@ pub struct AmlSymbols { // k = name, v = description symbol_cache: FxHashMap, page_cache: Arc>, - list: String, } impl AmlSymbols { @@ -258,7 +256,6 @@ impl AmlSymbols { ), symbol_cache: FxHashMap::default(), page_cache, - list: "".to_string(), } } @@ -266,10 +263,6 @@ impl AmlSymbols { &mut self.aml_context } - pub fn symbols_str(&self) -> &String { - &self.list - } - pub fn symbols_cache(&self) -> &FxHashMap { &self.symbol_cache } @@ -315,16 +308,12 @@ impl AmlSymbols { return; } - let mut symbols_str = String::with_capacity(symbol_list.len() * 10); let mut handle_lookup = AmlHandleLookup::new(); for (aml_name, name, handle) in &symbol_list { - let _ = writeln!(symbols_str, "{}", &name); handle_lookup.insert(handle.to_owned(), aml_name.to_owned()); } - symbols_str.shrink_to_fit(); - let mut symbol_cache: FxHashMap = FxHashMap::default(); for (aml_name, name, handle) in &symbol_list { @@ -337,7 +326,7 @@ impl AmlSymbols { aml_name, handle, ) { - if let Ok(ser_string) = serde_json::to_string_pretty(&ser_value) { + if let Ok(ser_string) = ron::ser::to_string_pretty(&ser_value, Default::default()) { // replace the empty entry symbol_cache.insert(name.to_owned(), ser_string); } @@ -347,7 +336,6 @@ impl AmlSymbols { // Cache the new list log::trace!("Updating symbols list"); - self.list = symbols_str; self.symbol_cache = symbol_cache; } } @@ -533,7 +521,6 @@ impl AcpiContext { pub fn aml_symbols_reset(&self) { let mut aml_symbols = self.aml_symbols.write(); aml_symbols.symbol_cache = FxHashMap::default(); - aml_symbols.list = "".to_string(); } /// Set Power State diff --git a/acpid/src/acpi/dmar/drhd.rs b/acpid/src/acpi/dmar/drhd.rs index da51d4349c..cce735d0dd 100644 --- a/acpid/src/acpi/dmar/drhd.rs +++ b/acpid/src/acpi/dmar/drhd.rs @@ -10,11 +10,20 @@ pub struct DrhdPage { } impl DrhdPage { pub fn map(base_phys: usize) -> syscall::Result { - assert_eq!(base_phys % crate::acpi::PAGE_SIZE, 0, "DRHD registers must be page-aligned"); + assert_eq!( + base_phys % crate::acpi::PAGE_SIZE, + 0, + "DRHD registers must be page-aligned" + ); // TODO: Uncachable? Can reads have side-effects? let virt = unsafe { - common::physmap(base_phys, crate::acpi::PAGE_SIZE, common::Prot::RO, common::MemoryType::default())? + common::physmap( + base_phys, + crate::acpi::PAGE_SIZE, + common::Prot::RO, + common::MemoryType::default(), + )? } as *mut Drhd; Ok(Self { virt }) diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 4c7024522f..a0b07ec895 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -1,34 +1,18 @@ #![feature(if_let_guard, int_roundings)] use std::convert::TryFrom; -use std::io::{self, prelude::*}; -use std::fs::{File, OpenOptions}; +use std::fs::File; use std::mem; -use std::os::unix::fs::OpenOptionsExt; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::os::unix::io::AsRawFd; use std::sync::Arc; -use syscall::scheme::SchemeMut; - -use syscall::data::{Event, Packet}; -use syscall::flag::{EventFlags, O_NONBLOCK}; +use event::{EventFlags, RawEventQueue}; +use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; +use syscall::{EAGAIN, EWOULDBLOCK}; mod acpi; -mod scheme; mod aml_physmem; - -fn monotonic() -> (u64, u64) { - use syscall::call::clock_gettime; - use syscall::data::TimeSpec; - use syscall::flag::CLOCK_MONOTONIC; - - let mut timespec = TimeSpec::default(); - - clock_gettime(CLOCK_MONOTONIC, &mut timespec) - .expect("failed to fetch monotonic time"); - - (timespec.tv_sec as u64, timespec.tv_nsec as u64) -} +mod scheme; fn daemon(daemon: redox_daemon::Daemon) -> ! { common::setup_logging( @@ -43,15 +27,16 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("acpid: failed to read `/scheme/kernel.acpi/rxsdt`") .into(); - let sdt = self::acpi::Sdt::new(rxsdt_raw_data) - .expect("acpid: failed to parse [RX]SDT"); + let sdt = self::acpi::Sdt::new(rxsdt_raw_data).expect("acpid: failed to parse [RX]SDT"); let mut thirty_two_bit; let mut sixty_four_bit; let physaddrs_iter = match &sdt.signature { b"RSDT" => { - thirty_two_bit = sdt.data().chunks(mem::size_of::()) + thirty_two_bit = sdt + .data() + .chunks(mem::size_of::()) // TODO: With const generics, the compiler has some way of doing this for static sizes. .map(|chunk| <[u8; mem::size_of::()]>::try_from(chunk).unwrap()) .map(|chunk| u32::from_le_bytes(chunk)) @@ -60,12 +45,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { &mut thirty_two_bit as &mut dyn Iterator } b"XSDT" => { - sixty_four_bit = sdt.data().chunks(mem::size_of::()) + sixty_four_bit = sdt + .data() + .chunks(mem::size_of::()) .map(|chunk| <[u8; mem::size_of::()]>::try_from(chunk).unwrap()) .map(|chunk| u64::from_le_bytes(chunk)); &mut sixty_four_bit as &mut dyn Iterator - }, + } _ => panic!("acpid: expected [RX]SDT from kernel to be either of those"), }; @@ -77,95 +64,66 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let shutdown_pipe = File::open("/scheme/kernel.acpi/kstop") .expect("acpid: failed to open `/scheme/kernel.acpi/kstop`"); - let mut event_queue = OpenOptions::new() - .write(true) - .read(true) - .create(false) - .open("/scheme/event") - .expect("acpid: failed to open event queue"); - - let mut scheme_socket = OpenOptions::new() - .write(true) - .read(true) - .create(true) - .custom_flags(O_NONBLOCK as i32) - .open(":acpi") - .expect("acpid: failed to open scheme socket"); + let mut event_queue = RawEventQueue::new().expect("acpid: failed to create event queue"); + let socket = Socket::::nonblock("acpi").expect("acpid: failed to create disk scheme"); daemon.ready().expect("acpid: failed to notify parent"); libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace"); - let _ = event_queue.write(&Event { - id: shutdown_pipe.as_raw_fd() as usize, - flags: EventFlags::EVENT_READ, - data: 0, - }).expect("acpid: failed to register shutdown pipe for event queue"); - - let _ = event_queue.write(&Event { - id: scheme_socket.as_raw_fd() as usize, - flags: EventFlags::EVENT_READ, - data: 1, - }).expect("acpid: failed to register scheme socket for event queue"); + event_queue + .subscribe(shutdown_pipe.as_raw_fd() as usize, 0, EventFlags::READ) + .expect("acpid: failed to register shutdown pipe for event queue"); + event_queue + .subscribe(socket.inner().raw(), 1, EventFlags::READ) + .expect("acpid: failed to register scheme socket for event queue"); let mut scheme = self::scheme::AcpiScheme::new(&acpi_context); - let mut event = Event::default(); - let mut packet = Packet::default(); + let mut mounted = true; + while mounted { + let Some(event) = event_queue + .next() + .transpose() + .expect("acpid: failed to read event file") + else { + break; + }; - 'events: loop { - 'packets: loop { - let bytes_read = 'eintr1: loop { - match scheme_socket.read(&mut packet) { - Ok(0) => { - log::info!("Terminating acpid driver, without shutting down the main system."); - break 'events; + if event.fd == socket.inner().raw() { + loop { + let sqe = match socket.next_request(SignalBehavior::Interrupt) { + Ok(None) => { + mounted = false; + break; } - Ok(n) => break 'eintr1 n, - Err(error) if error.kind() == io::ErrorKind::Interrupted => continue 'eintr1, - Err(error) if error.kind() == io::ErrorKind::WouldBlock => break 'packets, - Err(other) => { - log::error!("failed to read from scheme socket: {}", other); - break 'events; + Ok(Some(s)) => { + if let RequestKind::Call(call) = s.kind() { + call + } else { + continue; + } } - } - }; + Err(err) => { + if err.errno == EWOULDBLOCK || err.errno == EAGAIN { + break; + } else { + panic!("acpid: failed to read next request: {}", err); + } + } + }; - if bytes_read < mem::size_of::() { - log::error!("Scheme socket read less than a single packet."); + let response = sqe.handle_scheme_mut(&mut scheme); + socket + .write_response(response, SignalBehavior::Restart) + .expect("acpid: failed to write response"); } - - scheme.handle(&mut packet); - - let bytes_written = 'eintr2: loop { - match scheme_socket.write(&packet) { - Ok(0) => { - log::info!("Terminating acpid driver, without shutting down the main system."); - break 'events; - } - Ok(n) => break 'eintr2 n, - Err(error) if error.kind() == io::ErrorKind::Interrupted => continue 'eintr2, - Err(error) if error.kind() == io::ErrorKind::WouldBlock => break 'packets, - Err(other) => { - log::error!("failed to read from scheme socket: {}", other); - break 'events; - } - } - }; - - if bytes_written < mem::size_of::() { - log::error!("Scheme socket read less than a single packet."); - } - } - - let _ = event_queue.read(&mut event).expect("acpid: failed to read from event queue"); - - if event.flags.contains(EventFlags::EVENT_READ) && event.id == shutdown_pipe.as_raw_fd() as usize { + } else if event.fd == shutdown_pipe.as_raw_fd() as usize { log::info!("Received shutdown request from kernel."); - break 'events; - } - if !event.flags.contains(EventFlags::EVENT_READ) || event.id != scheme_socket.as_raw_fd() as usize { - continue 'events; + mounted = false; + } else { + log::debug!("Received request to unknown fd: {}", event.fd); + continue; } } diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index a4d598fbc5..fec64bacee 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -1,15 +1,19 @@ +use core::str; +use parking_lot::RwLockReadGuard; +use redox_scheme::{CallerCtx, OpenResult, SchemeMut}; use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; -use parking_lot::RwLockReadGuard; +use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; +use syscall::schemev2::NewFdFlags; use syscall::data::Stat; -use syscall::error::{EIO, EBADF, EBADFD, EINVAL, EISDIR, ENOENT, ENOTDIR, EOVERFLOW}; use syscall::error::{Error, Result}; +use syscall::error::{EBADF, EBADFD, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR}; +use syscall::flag::{MODE_DIR, MODE_FILE}; use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDONLY, O_STAT, O_SYMLINK}; -use syscall::flag::{MODE_FILE, MODE_DIR, SEEK_CUR, SEEK_END, SEEK_SET}; -use syscall::scheme::SchemeMut; +use syscall::EOPNOTSUPP; -use crate::acpi::{AcpiContext, SdtSignature, AmlSymbols}; +use crate::acpi::{AcpiContext, AmlSymbols, SdtSignature}; pub struct AcpiScheme<'acpi> { ctx: &'acpi AcpiContext, @@ -18,7 +22,6 @@ pub struct AcpiScheme<'acpi> { } struct Handle<'a> { - offset: usize, kind: HandleKind<'a>, stat: bool, } @@ -42,11 +45,14 @@ impl HandleKind<'_> { } fn len(&self, acpi_ctx: &AcpiContext) -> Result { Ok(match self { - Self::TopLevel => TOPLEVEL_CONTENTS.len(), - Self::Tables => acpi_ctx.tables().len().checked_mul(TABLE_DENTRY_LENGTH).unwrap_or(usize::max_value()), - Self::Table(signature) => acpi_ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.length(), - Self::Symbols(aml_symbols) => aml_symbols.symbols_str().len(), + // Files + Self::Table(signature) => acpi_ctx + .sdt_from_signature(signature) + .ok_or(Error::new(EBADFD))? + .length(), Self::Symbol(description) => description.len(), + // Directories + Self::TopLevel | Self::Symbols(_) | Self::Tables => 0, }) } } @@ -61,10 +67,6 @@ impl<'acpi> AcpiScheme<'acpi> { } } -const TOPLEVEL_CONTENTS: &[u8] = b"tables\nsymbols\n"; - -const TABLE_DENTRY_LENGTH: usize = 35; - fn parse_hex_digit(hex: u8) -> Option { let hex = hex.to_ascii_lowercase(); @@ -78,7 +80,8 @@ fn parse_hex_digit(hex: u8) -> Option { } fn parse_hex_2digit(hex: &[u8]) -> Option { - parse_hex_digit(hex[0]).and_then(|most_significant| Some((most_significant << 4) | parse_hex_digit(hex[1])?)) + parse_hex_digit(hex[0]) + .and_then(|most_significant| Some((most_significant << 4) | parse_hex_digit(hex[1])?)) } fn parse_oem_id(hex: [u8; 12]) -> Option<[u8; 6]> { @@ -123,27 +126,38 @@ fn parse_table(table: &[u8]) -> Option { } Some(SdtSignature { - signature: <[u8; 4]>::try_from(signature_part).expect("expected 4-byte slice to be convertible into [u8; 4]"), + signature: <[u8; 4]>::try_from(signature_part) + .expect("expected 4-byte slice to be convertible into [u8; 4]"), oem_id: { - let hex = <[u8; 12]>::try_from(oem_id_part).expect("expected 12-byte slice to be convertible into [u8; 12]"); + let hex = <[u8; 12]>::try_from(oem_id_part) + .expect("expected 12-byte slice to be convertible into [u8; 12]"); parse_oem_id(hex)? }, oem_table_id: { - let hex = <[u8; 16]>::try_from(oem_table_part).expect("expected 16-byte slice to be convertible into [u8; 16]"); + let hex = <[u8; 16]>::try_from(oem_table_part) + .expect("expected 16-byte slice to be convertible into [u8; 16]"); parse_oem_table_id(hex)? }, }) } impl SchemeMut for AcpiScheme<'_> { - fn open(&mut self, path: &str, flags: usize, _uid: u32, _gid: u32) -> Result { + fn xopen(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result { let path = path.trim_start_matches('/'); let flag_stat = flags & O_STAT == O_STAT; let flag_dir = flags & O_DIRECTORY == O_DIRECTORY; // TODO: arrayvec - let components = path.split('/').collect::>(); + let components = { + let mut v = arrayvec::ArrayVec::<&str, 3>::new(); + let it = path.split('/'); + for component in it.take(3) { + v.push(component); + } + + v + }; let kind = match &*components { [""] => HandleKind::TopLevel, @@ -154,11 +168,13 @@ impl SchemeMut for AcpiScheme<'_> { HandleKind::Table(signature) } - ["symbols"] => if let Ok(aml_symbols) = self.ctx.aml_symbols() { - HandleKind::Symbols(aml_symbols) - } else { - return Err(Error::new(EIO)) - }, + ["symbols"] => { + if let Ok(aml_symbols) = self.ctx.aml_symbols() { + HandleKind::Symbols(aml_symbols) + } else { + return Err(Error::new(EIO)); + } + } ["symbols", symbol] => { if let Some(description) = self.ctx.aml_lookup(symbol) { @@ -188,18 +204,28 @@ impl SchemeMut for AcpiScheme<'_> { let fd = self.next_fd; self.next_fd += 1; - self.handles.insert(fd, Handle { - offset: 0, - stat: flag_stat, - kind, - }); + self.handles.insert( + fd, + Handle { + stat: flag_stat, + kind, + }, + ); - Ok(fd) + Ok(OpenResult::ThisScheme { + number: fd, + flags: NewFdFlags::POSITIONED, + }) } + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - stat.st_size = handle.kind.len(self.ctx)?.try_into().unwrap_or(u64::max_value()); + + stat.st_size = handle + .kind + .len(self.ctx)? + .try_into() + .unwrap_or(u64::max_value()); if handle.kind.is_dir() { stat.st_mode = MODE_DIR; @@ -209,35 +235,10 @@ impl SchemeMut for AcpiScheme<'_> { Ok(0) } - fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result { - let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; - if handle.stat { - return Err(Error::new(EBADF)); - } + fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _fcntl: u32) -> Result { + let offset: usize = offset.try_into().map_err(|_| Error::new(EINVAL))?; - let file_len = handle.kind.len(self.ctx)?; - - let new_offset = match whence { - SEEK_SET => pos as usize, - SEEK_CUR => if pos < 0 { - handle.offset.checked_sub((-pos) as usize).ok_or(Error::new(EINVAL))? - } else { - handle.offset.saturating_add(pos as usize) - }, - SEEK_END => if pos < 0 { - file_len.checked_sub((-pos) as usize).ok_or(Error::new(EINVAL))? - } else { - file_len - } - - _ => return Err(Error::new(EINVAL)), - }; - - handle.offset = new_offset; - Ok(new_offset as isize) - } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; if handle.stat { @@ -245,77 +246,104 @@ impl SchemeMut for AcpiScheme<'_> { } let src_buf = match &handle.kind { - HandleKind::TopLevel => TOPLEVEL_CONTENTS, - HandleKind::Table(ref signature) => self.ctx.sdt_from_signature(signature).ok_or(Error::new(EBADFD))?.as_slice(), - - HandleKind::Tables => { - use std::io::prelude::*; - - let tables_to_skip = handle.offset / TABLE_DENTRY_LENGTH; - let max_tables_to_fill = (buf.len() + TABLE_DENTRY_LENGTH - 1) / TABLE_DENTRY_LENGTH; - - let mut bytes_to_skip = handle.offset % TABLE_DENTRY_LENGTH; - - let mut src_buf = [0_u8; TABLE_DENTRY_LENGTH]; - let mut bytes_written = 0; - - for table in self.ctx.tables().iter().skip(tables_to_skip).take(max_tables_to_fill) { - let mut cursor = std::io::Cursor::new(&mut src_buf[..]); - cursor.write_all(&table.signature).unwrap(); - cursor.write_all(&[b'-']).unwrap(); - // TODO: Treat these IDs as strings? - for byte in table.oem_id.iter() { - write!(cursor, "{:>02X}", byte).unwrap(); - } - cursor.write_all(&[b'-']).unwrap(); - for byte in table.oem_table_id.iter() { - write!(cursor, "{:>02X}", byte).unwrap(); - } - cursor.write_all(&[b'\n']).unwrap(); - - let src_buf = &src_buf[bytes_to_skip..]; - let dst_buf = &mut buf[bytes_written..]; - let to_copy = std::cmp::min(src_buf.len(), dst_buf.len()); - dst_buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); - bytes_written += to_copy; - bytes_to_skip = 0; - } - - handle.offset = handle.offset.checked_add(bytes_written).ok_or(Error::new(EOVERFLOW))?; - - return Ok(bytes_written); - } - - HandleKind::Symbols(aml_symbols) => { - let symbols = aml_symbols.symbols_str(); - let offset = std::cmp::min(symbols.len(), handle.offset); - let src_buf = &symbols.as_bytes()[offset..]; - - let to_copy = std::cmp::min(src_buf.len(), buf.len()); - buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); - - handle.offset = handle.offset.checked_add(to_copy).ok_or(Error::new(EOVERFLOW))?; - - return Ok(to_copy); - } - + HandleKind::Table(ref signature) => self + .ctx + .sdt_from_signature(signature) + .ok_or(Error::new(EBADFD))? + .as_slice(), HandleKind::Symbol(description) => description.as_bytes(), - + _ => return Err(Error::new(EINVAL)), }; - let offset = std::cmp::min(src_buf.len(), handle.offset); + let offset = std::cmp::min(src_buf.len(), offset); let src_buf = &src_buf[offset..]; let to_copy = std::cmp::min(src_buf.len(), buf.len()); - buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); - handle.offset = handle.offset.checked_add(to_copy).ok_or(Error::new(EOVERFLOW))?; + buf[..to_copy].copy_from_slice(&src_buf[..to_copy]); Ok(to_copy) } - fn write(&mut self, _id: usize, _buf: &[u8]) -> Result { + + fn getdents<'buf>( + &mut self, + id: usize, + mut buf: DirentBuf<&'buf mut [u8]>, + opaque_offset: u64, + ) -> Result> { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EOPNOTSUPP))?; + + match &handle.kind { + HandleKind::TopLevel => { + const TOPLEVEL_ENTRIES: &[&str] = &["tables", "symbols"]; + + for (idx, name) in TOPLEVEL_ENTRIES + .iter() + .enumerate() + .skip(opaque_offset as usize) + { + buf.entry(DirEntry { + inode: 0, + next_opaque_id: idx as u64 + 1, + name, + kind: DirentKind::Directory, + })?; + } + } + HandleKind::Symbols(aml_symbols) => { + for (idx, (symbol_name, _value)) in aml_symbols + .symbols_cache() + .iter() + .enumerate() + .skip(opaque_offset as usize) + { + buf.entry(DirEntry { + inode: 0, + next_opaque_id: idx as u64 + 1, + name: symbol_name.as_str(), + kind: DirentKind::Regular, + })?; + } + } + HandleKind::Tables => { + for (idx, table) in self + .ctx + .tables() + .iter() + .enumerate() + .skip(opaque_offset as usize) + { + let utf8_or_eio = |bytes| str::from_utf8(bytes).map_err(|_| Error::new(EIO)); + + let mut name = String::new(); + name.push_str(utf8_or_eio(&table.signature[..])?); + name.push('-'); + for byte in table.oem_id.iter() { + std::fmt::write(&mut name, format_args!("{:>02X}", byte)).unwrap(); + } + name.push('-'); + for byte in table.oem_table_id.iter() { + std::fmt::write(&mut name, format_args!("{:>02X}", byte)).unwrap(); + } + + buf.entry(DirEntry { + inode: 0, + next_opaque_id: idx as u64 + 1, + name: &name, + kind: DirentKind::Regular, + })?; + } + } + _ => return Err(Error::new(EIO)), + } + + Ok(buf) + } + + fn write(&mut self, _id: usize, _buf: &[u8], _offset: u64, _fcntl: u32) -> Result { Err(Error::new(EBADF)) } + fn close(&mut self, id: usize) -> Result { if self.handles.remove(&id).is_none() { return Err(Error::new(EBADF)); From e49fae653349e9aaa11f4511f558c769a99135d0 Mon Sep 17 00:00:00 2001 From: Kamil Koczurek Date: Fri, 27 Sep 2024 23:40:42 +0200 Subject: [PATCH 0984/1301] chore: fmt.sh --- common/src/io.rs | 2 +- pcid/src/driver_interface/msi.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/common/src/io.rs b/common/src/io.rs index 955cf0a06f..698b23fb02 100644 --- a/common/src/io.rs +++ b/common/src/io.rs @@ -92,4 +92,4 @@ impl WriteOnly { pub fn writef(&mut self, flags: I::Value, value: bool) { self.inner.writef(flags, value) } -} \ No newline at end of file +} diff --git a/pcid/src/driver_interface/msi.rs b/pcid/src/driver_interface/msi.rs index d95837eb77..3168c61cda 100644 --- a/pcid/src/driver_interface/msi.rs +++ b/pcid/src/driver_interface/msi.rs @@ -2,8 +2,8 @@ use std::fmt; use crate::driver_interface::PciBar; -use serde::{Deserialize, Serialize}; use common::io::{Io, Mmio}; +use serde::{Deserialize, Serialize}; /// The address and data to use for MSI and MSI-X. /// From fb06d3782fafa1c1bbfd1b3c743d370d2e78597a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 6 Oct 2024 09:58:37 -0600 Subject: [PATCH 0985/1301] Fix build on aarch64 --- common/src/io.rs | 2 ++ common/src/io/mmio.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/common/src/io.rs b/common/src/io.rs index 698b23fb02..b79d4cabe8 100644 --- a/common/src/io.rs +++ b/common/src/io.rs @@ -4,9 +4,11 @@ use core::{ }; mod mmio; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] mod pio; pub use mmio::*; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub use pio::*; /// IO abstraction diff --git a/common/src/io/mmio.rs b/common/src/io/mmio.rs index ca9d564ce2..c20cf52716 100644 --- a/common/src/io/mmio.rs +++ b/common/src/io/mmio.rs @@ -35,7 +35,7 @@ impl Mmio { #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] impl Io for Mmio where - T: Copy + PartialEq + BitAnd + BitOr + Not, + T: Copy + PartialEq + core::ops::BitAnd + core::ops::BitOr + core::ops::Not, { type Value = T; From c5c87169efc04b17444e051dd516365a32aac27a Mon Sep 17 00:00:00 2001 From: Ribbon Date: Thu, 10 Oct 2024 14:12:02 +0000 Subject: [PATCH 0986/1301] Move the community hardware tracking issue to the "COMMUNITY-HW.md" document --- COMMUNITY-HW.md | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 COMMUNITY-HW.md diff --git a/COMMUNITY-HW.md b/COMMUNITY-HW.md new file mode 100644 index 0000000000..8f2972f1f9 --- /dev/null +++ b/COMMUNITY-HW.md @@ -0,0 +1,54 @@ +This document covers the devices from the community that needs a driver. + +Unfortunately we can't know the most sold device models of the world to measure our device porting priority, thus we will use our community data to measure our device priorities, if you find a "device model users" survey (similar to [Debian Popularity Contest](https://popcon.debian.org/) and [Steam Hardware/Software Survey](https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam)), please comment. + +If you want to contribute to this table, install [pciutils](https://mj.ucw.cz/sw/pciutils/) on your Linux distribution (it should have a package on your distribution), run `lspci -v` to see your hardware devices, their kernel drivers and give the results of these items on each device: + +- The first field (each device has an unique name for this item) +- Kernel driver in use +- Kernel modules + +If you are unsure of what to do, you can talk with us on the [chat](https://doc.redox-os.org/book/chat.html). + +| **Device model** | **Kernel driver** | **Kernel module** | **There's a Redox driver?** | +|------------------|-------------------|-------------------|-----------------------------| +| Realtek RTL8821CE 802.11ac (Wi-Fi) | rtw_8821ce | rtw88_8821ce | No | +| Intel Ice Lake-LP SPI Controller | intel-spi | spi_intel_pci | No | +| Intel Ice Lake-LP SMBus Controller | i801_smbus | i2c_i801 | No | +| Intel Ice Lake-LP Smart Sound Technology Audio Controller | snd_hda_intel | snd_hda_intel, snd_sof_pci_intel_icl | No | +| Intel Ice Lake-LP Serial IO SPI Controller | intel-lpss | No | No | +| Intel Ice Lake-LP Serial IO UART Controller | intel-lpss | No | No | +| Intel Ice Lake-LP Serial IO I2C Controller | intel-lpss | No | No | +| Ice Lake-LP USB 3.1 xHCI Host Controller | xhci_hcd | No | No | +| Intel Processor Power and Thermal Controller | proc_thermal | processor_thermal_device_pci_legacy | No | +| Intel Device 8a02 | icl_uncore | No | No | +| Iris Plus Graphics G1 (Ice Lake) | i915 | i915 | No | +| Intel Corporation Raptor Lake-P 6p+8e cores Host Bridge/DRAM Controller | No | No | No | +| Intel Corporation Raptor Lake PCI Express 5.0 Graphics Port (PEG010) (prog-if 00 [Normal decode]) | pcieport | No | No | +| Intel Corporation Raptor Lake-P [UHD Graphics] (rev 04) (prog-if 00 [VGA controller]) | i915 | i915 | No | +| Intel Corporation Raptor Lake Dynamic Platform and Thermal Framework Processor Participant | proc_thermal_pci | processor_thermal_device_pci | No | +| Intel Corporation Raptor Lake PCIe 4.0 Graphics Port (prog-if 00 [Normal decode]) | pcieport | No | No | +| Intel Corporation Raptor Lake-P Thunderbolt 4 PCI Express Root Port #0 (prog-if 00 [Normal decode]) | pcieport | No | No | +| Intel Corporation GNA Scoring Accelerator module | No | No | No | +| Intel Corporation Raptor Lake-P Thunderbolt 4 USB Controller (prog-if 30 [XHCI]) | xhci_hcd | xhci_pci | No | +| Intel Corporation Raptor Lake-P Thunderbolt 4 NHI #0 (prog-if 40 [USB4 Host Interface]) | thunderbolt | thunderbolt | No | +| Intel Corporation Raptor Lake-P Thunderbolt 4 NHI #1 (prog-if 40 [USB4 Host Interface]) | thunderbolt | thunderbolt | No | +| Intel Corporation Alder Lake PCH USB 3.2 xHCI Host Controller (rev 01) (prog-if 30 [XHCI]) | xhci_hcd | xhci_pci | No | +| Intel Corporation Alder Lake PCH Shared SRAM (rev 01) | No | No | No | +| Intel Corporation Raptor Lake PCH CNVi WiFi (rev 01) | iwlwifi | iwlwifi | No | +| Intel Corporation Alder Lake PCH Serial IO I2C Controller #0 (rev 01) | intel-lpss | intel_lpss_pci | No | +| Intel Corporation Alder Lake PCH HECI Controller (rev 01) | mei_me | mei_me | No | +| Intel Corporation Device 51b8 (rev 01) (prog-if 00 [Normal decode]) | pcieport | No | No | +| Intel Corporation Alder Lake-P PCH PCIe Root Port #6 (rev 01) (prog-if 00 [Normal decode]) | pcieport | No | No | +| Intel Corporation Raptor Lake LPC/eSPI Controller (rev 01) | No | No | No | +| Intel Corporation Raptor Lake-P/U/H cAVS (rev 01) (prog-if 80) | sof-audio-pci-intel-tgl | snd_hda_intel, snd_sof_pci_intel_tgl | No | +| Intel Corporation Alder Lake PCH-P SMBus Host Controller | i801_smbus | i2c_i801 | No | +| Intel Corporation Alder Lake-P PCH SPI Controller (rev 01) | intel-spi | spi_intel_pci | No | +| NVIDIA Corporation GA107GLM [RTX A1000 6GB Laptop GPU] (rev a1) | nvidia | nouveau, nvidia_drm, nvidia | No | +| SK hynix Platinum P41/PC801 NVMe Solid State Drive (prog-if 02 [NVM Express]) | nvme | nvme | No | +| Realtek Semiconductor Co., Ltd. RTS5261 PCI Express Card Reader (rev 01) | rtsx_pci | rtsx_pci | No | + + From 17b2f5eab1592d32ccd395975f55adafb3c7988e Mon Sep 17 00:00:00 2001 From: Ribbon Date: Thu, 10 Oct 2024 14:30:33 +0000 Subject: [PATCH 0987/1301] Add a description section and a template on the "COMMUNITY-HW.md" document --- COMMUNITY-HW.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/COMMUNITY-HW.md b/COMMUNITY-HW.md index 8f2972f1f9..62fa6c26ae 100644 --- a/COMMUNITY-HW.md +++ b/COMMUNITY-HW.md @@ -1,3 +1,5 @@ +# Community Hardware + This document covers the devices from the community that needs a driver. Unfortunately we can't know the most sold device models of the world to measure our device porting priority, thus we will use our community data to measure our device priorities, if you find a "device model users" survey (similar to [Debian Popularity Contest](https://popcon.debian.org/) and [Steam Hardware/Software Survey](https://store.steampowered.com/hwsurvey/Steam-Hardware-Software-Survey-Welcome-to-Steam)), please comment. @@ -10,6 +12,14 @@ If you want to contribute to this table, install [pciutils](https://mj.ucw.cz/sw If you are unsure of what to do, you can talk with us on the [chat](https://doc.redox-os.org/book/chat.html). +## Template + +You will use this template to insert your devices on the table. + +``` +| | | | No | +``` + | **Device model** | **Kernel driver** | **Kernel module** | **There's a Redox driver?** | |------------------|-------------------|-------------------|-----------------------------| | Realtek RTL8821CE 802.11ac (Wi-Fi) | rtw_8821ce | rtw88_8821ce | No | From 09b5033fbd2dcd13e84bc888a8ef06499704a97c Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Thu, 17 Oct 2024 20:07:05 +0300 Subject: [PATCH 0988/1301] Wholesale cargo fmt to get CI back to green --- acpid/src/acpi/dmar/mod.rs | 40 +- acpid/src/aml_physmem.rs | 11 +- audio/ac97d/src/device.rs | 435 ++++--- audio/ac97d/src/main.rs | 79 +- audio/ihdad/src/hda/cmdbuff.rs | 20 +- audio/ihdad/src/hda/device.rs | 1757 +++++++++++++------------ audio/ihdad/src/hda/mod.rs | 19 +- audio/ihdad/src/hda/node.rs | 164 +-- audio/ihdad/src/hda/stream.rs | 539 ++++---- audio/ihdad/src/main.rs | 114 +- audio/pcspkrd/src/main.rs | 3 +- audio/sb16d/src/device.rs | 13 +- audio/sb16d/src/main.rs | 70 +- common/src/io/mmio.rs | 6 +- net/alxd/src/device/mod.rs | 1765 +++++++++++++------------- net/alxd/src/device/regs.rs | 40 +- net/alxd/src/main.rs | 63 +- net/e1000d/src/main.rs | 14 +- net/ixgbed/src/device.rs | 33 +- net/ixgbed/src/main.rs | 19 +- net/rtl8139d/src/device.rs | 53 +- net/rtl8139d/src/main.rs | 77 +- net/rtl8168d/src/device.rs | 50 +- net/rtl8168d/src/main.rs | 82 +- ps2d/src/controller.rs | 215 ++-- ps2d/src/keymap.rs | 10 +- ps2d/src/main.rs | 42 +- ps2d/src/state.rs | 123 +- storage/ahcid/src/ahci/disk_ata.rs | 57 +- storage/ahcid/src/ahci/disk_atapi.rs | 49 +- storage/ahcid/src/ahci/fis.rs | 50 +- storage/ahcid/src/ahci/hba.rs | 254 ++-- storage/ahcid/src/ahci/mod.rs | 56 +- storage/ahcid/src/main.rs | 85 +- storage/ahcid/src/scheme.rs | 162 ++- storage/bcm2835-sdhcid/src/main.rs | 83 +- storage/bcm2835-sdhcid/src/scheme.rs | 129 +- storage/bcm2835-sdhcid/src/sd/mod.rs | 119 +- storage/ided/src/ide.rs | 37 +- storage/ided/src/main.rs | 120 +- storage/ided/src/scheme.rs | 137 +- storage/lived/src/main.rs | 79 +- storage/nvmed/src/main.rs | 60 +- storage/nvmed/src/nvme/cq_reactor.rs | 151 ++- storage/nvmed/src/nvme/identify.rs | 35 +- storage/nvmed/src/nvme/mod.rs | 128 +- storage/nvmed/src/nvme/queues.rs | 8 +- storage/nvmed/src/scheme.rs | 122 +- storage/usbscsid/src/main.rs | 22 +- storage/usbscsid/src/protocol/bot.rs | 81 +- storage/usbscsid/src/scheme.rs | 13 +- storage/usbscsid/src/scsi/cmds.rs | 8 +- storage/usbscsid/src/scsi/mod.rs | 63 +- storage/virtio-blkd/src/main.rs | 20 +- storage/virtio-blkd/src/scheme.rs | 223 ++-- usbhidd/src/main.rs | 73 +- usbhubd/src/main.rs | 11 +- vboxd/src/bga.rs | 2 +- vboxd/src/main.rs | 99 +- xhcid/src/main.rs | 2 +- xhcid/src/xhci/context.rs | 2 +- xhcid/src/xhci/event.rs | 2 +- xhcid/src/xhci/extended.rs | 2 +- xhcid/src/xhci/mod.rs | 2 +- xhcid/src/xhci/operational.rs | 2 +- xhcid/src/xhci/scheme.rs | 11 +- xhcid/src/xhci/trb.rs | 2 +- 67 files changed, 4804 insertions(+), 3613 deletions(-) diff --git a/acpid/src/acpi/dmar/mod.rs b/acpid/src/acpi/dmar/mod.rs index f89eae95f2..b6a350d44f 100644 --- a/acpid/src/acpi/dmar/mod.rs +++ b/acpid/src/acpi/dmar/mod.rs @@ -26,7 +26,6 @@ pub struct DmarStruct { pub host_addr_width: u8, pub flags: u8, pub _rsvd: [u8; 10], - // This header is followed by N remapping structures. } unsafe impl plain::Plain for DmarStruct {} @@ -84,16 +83,23 @@ impl Dmar { log::debug!("GCMD: {:X}", drhd.gl_cmd.read()); log::debug!("GSTS: {:X}", drhd.gl_sts.read()); log::debug!("RT: {:X}", drhd.root_table.read()); - }, - _ => () + } + _ => (), } } } fn new(sdt: Sdt) -> Option { - assert_eq!(sdt.signature, *b"DMAR", "signature already checked against `DMAR`"); + assert_eq!( + sdt.signature, *b"DMAR", + "signature already checked against `DMAR`" + ); if sdt.length() < mem::size_of::() { - log::error!("The DMAR table was too small ({} B < {} B).", sdt.length(), mem::size_of::()); + log::error!( + "The DMAR table was too small ({} B < {} B).", + sdt.length(), + mem::size_of::() + ); return None; } // No need to check alignment for #[repr(packed)] structs. @@ -102,7 +108,9 @@ impl Dmar { } pub fn iter(&self) -> DmarIter<'_> { - DmarIter(DmarRawIter { bytes: self.remmapping_structs_area() }) + DmarIter(DmarRawIter { + bytes: self.remmapping_structs_area(), + }) } } @@ -128,7 +136,6 @@ pub struct DeviceScopeHeader { pub _rsvd: u16, pub enumeration_id: u8, pub start_bus_num: u8, - // The variable-sized path comes after. } unsafe impl plain::Plain for DeviceScopeHeader {} @@ -196,8 +203,7 @@ impl DmarDrhd { pub fn map(&self) -> DrhdPage { let base = usize::try_from(self.base).expect("expected u64 to fit within usize"); - DrhdPage::map(base) - .expect("failed to map DRHD registers") + DrhdPage::map(base).expect("failed to map DRHD registers") } } impl Deref for DmarDrhd { @@ -227,7 +233,6 @@ pub struct DmarRmrrHeader { pub segment: u16, pub base: u64, pub limit: u64, - // The device scopes come after. } unsafe impl plain::Plain for DmarRmrrHeader {} @@ -269,7 +274,6 @@ pub struct DmarAtsrHeader { flags: u8, _rsv: u8, segment: u16, - // The device scopes come after. } unsafe impl plain::Plain for DmarAtsrHeader {} @@ -334,7 +338,6 @@ pub struct DmarAnddHeader { pub _rsv: [u8; 3], pub acpi_dev: u8, - // The device scopes come after. } unsafe impl plain::Plain for DmarAnddHeader {} @@ -377,7 +380,6 @@ pub struct DmarSatcHeader { pub flags: u8, pub _rsvd: u8, pub seg_num: u16, - // The device scopes come after. } unsafe impl plain::Plain for DmarSatcHeader {} @@ -467,8 +469,10 @@ impl<'sdt> Iterator for DmarRawIter<'sdt> { }; let remainder = &self.bytes[4..]; - let type_bytes = <[u8; 2]>::try_from(type_bytes).expect("expected a 2-byte slice to be convertible to [u8; 2]"); - let len_bytes = <[u8; 2]>::try_from(type_bytes).expect("expected a 2-byte slice to be convertible to [u8; 2]"); + let type_bytes = <[u8; 2]>::try_from(type_bytes) + .expect("expected a 2-byte slice to be convertible to [u8; 2]"); + let len_bytes = <[u8; 2]>::try_from(type_bytes) + .expect("expected a 2-byte slice to be convertible to [u8; 2]"); let ty = u16::from_ne_bytes(type_bytes); let len = u16::from_ne_bytes(len_bytes); @@ -500,7 +504,11 @@ impl Iterator for DmarIter<'_> { let entry_type = match EntryType::from_u16(raw_type) { Some(ty) => ty, None => { - log::warn!("Encountered invalid entry type {} (length {})", raw_type, raw.len()); + log::warn!( + "Encountered invalid entry type {} (length {})", + raw_type, + raw.len() + ); return Some(DmarEntry::Unknown(raw_type)); } }; diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index e8f82d5f4c..8f39880279 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -1,10 +1,10 @@ +use common::io::{Io, Pio}; use num_traits::PrimInt; use rustc_hash::FxHashMap; use std::fmt::LowerHex; use std::mem::size_of; use std::sync::{Arc, Mutex}; use syscall::PAGE_SIZE; -use common::io::{Io, Pio}; const PAGE_MASK: usize = !(PAGE_SIZE - 1); const OFFSET_MASK: usize = PAGE_SIZE - 1; @@ -17,8 +17,13 @@ struct MappedPage { impl MappedPage { fn new(phys_page: usize) -> std::io::Result { let virt_page = unsafe { - common::physmap(phys_page, PAGE_SIZE, common::Prot::RO, common::MemoryType::default()) - .map_err(|error| std::io::Error::from_raw_os_error(error.errno()))? + common::physmap( + phys_page, + PAGE_SIZE, + common::Prot::RO, + common::MemoryType::default(), + ) + .map_err(|error| std::io::Error::from_raw_os_error(error.errno()))? } as usize; Ok(Self { phys_page, diff --git a/audio/ac97d/src/device.rs b/audio/ac97d/src/device.rs index 1892d34fda..de182de2ba 100644 --- a/audio/ac97d/src/device.rs +++ b/audio/ac97d/src/device.rs @@ -1,276 +1,300 @@ #![allow(dead_code)] -use std::mem; use std::collections::BTreeMap; +use std::mem; use std::sync::atomic::{AtomicUsize, Ordering}; -use syscall::error::{Error, EACCES, EBADF, Result, EINVAL, ENOENT}; use common::io::Pio; +use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, ENOENT}; use syscall::scheme::SchemeBlockMut; -use common::{dma::Dma, io::{Io, Mmio}}; +use common::{ + dma::Dma, + io::{Io, Mmio}, +}; use spin::Mutex; const NUM_SUB_BUFFS: usize = 32; const SUB_BUFF_SIZE: usize = 2048; enum Handle { - Todo, + Todo, } #[allow(dead_code)] struct MixerRegs { - /* 0x00 */ reset: Pio, - /* 0x02 */ master_volume: Pio, - /* 0x04 */ aux_out_volume: Pio, - /* 0x06 */ mono_volume: Pio, - /* 0x08 */ master_tone: Pio, - /* 0x0A */ pc_beep_volume: Pio, - /* 0x0C */ phone_volume: Pio, - /* 0x0E */ mic_volume: Pio, - /* 0x10 */ line_in_volume: Pio, - /* 0x12 */ cd_volume: Pio, - /* 0x14 */ video_volume: Pio, - /* 0x16 */ aux_in_volume: Pio, - /* 0x18 */ pcm_out_volume: Pio, - /* 0x1A */ record_select: Pio, - /* 0x1C */ record_gain: Pio, - /* 0x1E */ record_gain_mic: Pio, - /* 0x20 */ general_purpose: Pio, - /* 0x22 */ control_3d: Pio, - /* 0x24 */ audio_int_paging: Pio, - /* 0x26 */ powerdown: Pio, - /* 0x28 */ extended_id: Pio, - /* 0x2A */ extended_ctrl: Pio, - /* 0x2C */ vra_pcm_front: Pio, + /* 0x00 */ reset: Pio, + /* 0x02 */ master_volume: Pio, + /* 0x04 */ aux_out_volume: Pio, + /* 0x06 */ mono_volume: Pio, + /* 0x08 */ master_tone: Pio, + /* 0x0A */ pc_beep_volume: Pio, + /* 0x0C */ phone_volume: Pio, + /* 0x0E */ mic_volume: Pio, + /* 0x10 */ line_in_volume: Pio, + /* 0x12 */ cd_volume: Pio, + /* 0x14 */ video_volume: Pio, + /* 0x16 */ aux_in_volume: Pio, + /* 0x18 */ pcm_out_volume: Pio, + /* 0x1A */ record_select: Pio, + /* 0x1C */ record_gain: Pio, + /* 0x1E */ record_gain_mic: Pio, + /* 0x20 */ general_purpose: Pio, + /* 0x22 */ control_3d: Pio, + /* 0x24 */ audio_int_paging: Pio, + /* 0x26 */ powerdown: Pio, + /* 0x28 */ extended_id: Pio, + /* 0x2A */ extended_ctrl: Pio, + /* 0x2C */ vra_pcm_front: Pio, } impl MixerRegs { - fn new(bar0: u16) -> Self { - Self { - reset: Pio::new(bar0 + 0x00), - master_volume: Pio::new(bar0 + 0x02), - aux_out_volume: Pio::new(bar0 + 0x04), - mono_volume: Pio::new(bar0 + 0x06), - master_tone: Pio::new(bar0 + 0x08), - pc_beep_volume: Pio::new(bar0 + 0x0A), - phone_volume: Pio::new(bar0 + 0x0C), - mic_volume: Pio::new(bar0 + 0x0E), - line_in_volume: Pio::new(bar0 + 0x10), - cd_volume: Pio::new(bar0 + 0x12), - video_volume: Pio::new(bar0 + 0x14), - aux_in_volume: Pio::new(bar0 + 0x16), - pcm_out_volume: Pio::new(bar0 + 0x18), - record_select: Pio::new(bar0 + 0x1A), - record_gain: Pio::new(bar0 + 0x1C), - record_gain_mic: Pio::new(bar0 + 0x1E), - general_purpose: Pio::new(bar0 + 0x20), - control_3d: Pio::new(bar0 + 0x22), - audio_int_paging: Pio::new(bar0 + 0x24), - powerdown: Pio::new(bar0 + 0x26), - extended_id: Pio::new(bar0 + 0x28), - extended_ctrl: Pio::new(bar0 + 0x2A), - vra_pcm_front: Pio::new(bar0 + 0x2C), - } - } + fn new(bar0: u16) -> Self { + Self { + reset: Pio::new(bar0 + 0x00), + master_volume: Pio::new(bar0 + 0x02), + aux_out_volume: Pio::new(bar0 + 0x04), + mono_volume: Pio::new(bar0 + 0x06), + master_tone: Pio::new(bar0 + 0x08), + pc_beep_volume: Pio::new(bar0 + 0x0A), + phone_volume: Pio::new(bar0 + 0x0C), + mic_volume: Pio::new(bar0 + 0x0E), + line_in_volume: Pio::new(bar0 + 0x10), + cd_volume: Pio::new(bar0 + 0x12), + video_volume: Pio::new(bar0 + 0x14), + aux_in_volume: Pio::new(bar0 + 0x16), + pcm_out_volume: Pio::new(bar0 + 0x18), + record_select: Pio::new(bar0 + 0x1A), + record_gain: Pio::new(bar0 + 0x1C), + record_gain_mic: Pio::new(bar0 + 0x1E), + general_purpose: Pio::new(bar0 + 0x20), + control_3d: Pio::new(bar0 + 0x22), + audio_int_paging: Pio::new(bar0 + 0x24), + powerdown: Pio::new(bar0 + 0x26), + extended_id: Pio::new(bar0 + 0x28), + extended_ctrl: Pio::new(bar0 + 0x2A), + vra_pcm_front: Pio::new(bar0 + 0x2C), + } + } } #[allow(dead_code)] struct BusBoxRegs { - /// Buffer descriptor list base address - /* 0x00 */ bdbar: Pio, - /// Current index value - /* 0x04 */ civ: Pio, - /// Last valid index - /* 0x05 */ lvi: Pio, - /// Status - /* 0x06 */ sr: Pio, - /// Position in current buffer - /* 0x08 */ picb: Pio, - /// Prefetched index value - /* 0x0A */ piv: Pio, - /// Control - /* 0x0B */ cr: Pio, + /// Buffer descriptor list base address + /* 0x00 */ + bdbar: Pio, + /// Current index value + /* 0x04 */ + civ: Pio, + /// Last valid index + /* 0x05 */ + lvi: Pio, + /// Status + /* 0x06 */ + sr: Pio, + /// Position in current buffer + /* 0x08 */ + picb: Pio, + /// Prefetched index value + /* 0x0A */ + piv: Pio, + /// Control + /* 0x0B */ + cr: Pio, } impl BusBoxRegs { - fn new(base: u16) -> Self { - Self { - bdbar: Pio::new(base + 0x00), - civ: Pio::new(base + 0x04), - lvi: Pio::new(base + 0x05), - sr: Pio::new(base + 0x06), - picb: Pio::new(base + 0x08), - piv: Pio::new(base + 0x0A), - cr: Pio::new(base + 0x0B), - } - } + fn new(base: u16) -> Self { + Self { + bdbar: Pio::new(base + 0x00), + civ: Pio::new(base + 0x04), + lvi: Pio::new(base + 0x05), + sr: Pio::new(base + 0x06), + picb: Pio::new(base + 0x08), + piv: Pio::new(base + 0x0A), + cr: Pio::new(base + 0x0B), + } + } } #[allow(dead_code)] struct BusRegs { - /// PCM in register box - /* 0x00 */ pi: BusBoxRegs, - /// PCM out register box - /* 0x10 */ po: BusBoxRegs, - /// Microphone register box - /* 0x20 */ mc: BusBoxRegs, + /// PCM in register box + /* 0x00 */ + pi: BusBoxRegs, + /// PCM out register box + /* 0x10 */ + po: BusBoxRegs, + /// Microphone register box + /* 0x20 */ + mc: BusBoxRegs, } impl BusRegs { - fn new(bar1: u16) -> Self { - Self { - pi: BusBoxRegs::new(bar1 + 0x00), - po: BusBoxRegs::new(bar1 + 0x10), - mc: BusBoxRegs::new(bar1 + 0x20), - } - } + fn new(bar1: u16) -> Self { + Self { + pi: BusBoxRegs::new(bar1 + 0x00), + po: BusBoxRegs::new(bar1 + 0x10), + mc: BusBoxRegs::new(bar1 + 0x20), + } + } } #[repr(packed)] pub struct BufferDescriptor { - /* 0x00 */ addr: Mmio, - /* 0x04 */ samples: Mmio, - /* 0x06 */ flags: Mmio, + /* 0x00 */ addr: Mmio, + /* 0x04 */ samples: Mmio, + /* 0x06 */ flags: Mmio, } pub struct Ac97 { - mixer: MixerRegs, - bus: BusRegs, - bdl: Dma<[BufferDescriptor; NUM_SUB_BUFFS]>, + mixer: MixerRegs, + bus: BusRegs, + bdl: Dma<[BufferDescriptor; NUM_SUB_BUFFS]>, buf: Dma<[u8; NUM_SUB_BUFFS * SUB_BUFF_SIZE]>, - handles: Mutex>, - next_id: AtomicUsize, + handles: Mutex>, + next_id: AtomicUsize, } impl Ac97 { - pub unsafe fn new(bar0: u16, bar1: u16) -> Result { - let mut module = Ac97 { - mixer: MixerRegs::new(bar0), - bus: BusRegs::new(bar1), + pub unsafe fn new(bar0: u16, bar1: u16) -> Result { + let mut module = Ac97 { + mixer: MixerRegs::new(bar0), + bus: BusRegs::new(bar1), bdl: Dma::zeroed( //TODO: PhysBox::new_in_32bit_space(bdl_size)? - )?.assume_init(), + )? + .assume_init(), buf: Dma::zeroed( //TODO: PhysBox::new_in_32bit_space(buf_size)? - )?.assume_init(), - handles: Mutex::new(BTreeMap::new()), - next_id: AtomicUsize::new(0), - }; + )? + .assume_init(), + handles: Mutex::new(BTreeMap::new()), + next_id: AtomicUsize::new(0), + }; - module.init()?; + module.init()?; - Ok(module) - } + Ok(module) + } - fn init(&mut self) -> Result<()> { - //TODO: support other sample rates, or just the default of 48000 Hz - { - // Check if VRA is supported - if ! self.mixer.extended_id.readf(1 << 0) { - println!("ac97d: VRA not supported and is currently required"); - return Err(Error::new(ENOENT)); - } + fn init(&mut self) -> Result<()> { + //TODO: support other sample rates, or just the default of 48000 Hz + { + // Check if VRA is supported + if !self.mixer.extended_id.readf(1 << 0) { + println!("ac97d: VRA not supported and is currently required"); + return Err(Error::new(ENOENT)); + } - // Enable VRA - self.mixer.extended_ctrl.writef(1 << 0, true); + // Enable VRA + self.mixer.extended_ctrl.writef(1 << 0, true); - // Attempt to set sample rate for PCM front to 44100 Hz - let desired_sample_rate = 44100; - self.mixer.vra_pcm_front.write(desired_sample_rate); + // Attempt to set sample rate for PCM front to 44100 Hz + let desired_sample_rate = 44100; + self.mixer.vra_pcm_front.write(desired_sample_rate); - // Read back real sample rate - let real_sample_rate = self.mixer.vra_pcm_front.read(); - println!("ac97d: set sample rate to {}", real_sample_rate); + // Read back real sample rate + let real_sample_rate = self.mixer.vra_pcm_front.read(); + println!("ac97d: set sample rate to {}", real_sample_rate); - // Error if we cannot set the sample rate as desired - if real_sample_rate != desired_sample_rate { - println!("ac97d: sample rate is {} but only {} is supported", real_sample_rate, desired_sample_rate); - return Err(Error::new(ENOENT)); - } - } + // Error if we cannot set the sample rate as desired + if real_sample_rate != desired_sample_rate { + println!( + "ac97d: sample rate is {} but only {} is supported", + real_sample_rate, desired_sample_rate + ); + return Err(Error::new(ENOENT)); + } + } - // Ensure PCM out is stopped - self.bus.po.cr.writef(1, false); + // Ensure PCM out is stopped + self.bus.po.cr.writef(1, false); - // Reset PCM out - self.bus.po.cr.writef(1 << 1, true); - while self.bus.po.cr.readf(1 << 1) { - // Spinning on resetting PCM out - //TODO: relax - } + // Reset PCM out + self.bus.po.cr.writef(1 << 1, true); + while self.bus.po.cr.readf(1 << 1) { + // Spinning on resetting PCM out + //TODO: relax + } - // Initialize BDL for PCM out - for i in 0..NUM_SUB_BUFFS { - self.bdl[i].addr.write((self.buf.physical() + i * SUB_BUFF_SIZE) as u32); - self.bdl[i].samples.write((SUB_BUFF_SIZE / 2 /* Each sample is i16 or 2 bytes */) as u16); - self.bdl[i].flags.write(1 << 15 /* Interrupt on completion */); - } - self.bus.po.bdbar.write(self.bdl.physical() as u32); + // Initialize BDL for PCM out + for i in 0..NUM_SUB_BUFFS { + self.bdl[i] + .addr + .write((self.buf.physical() + i * SUB_BUFF_SIZE) as u32); + self.bdl[i] + .samples + .write((SUB_BUFF_SIZE / 2/* Each sample is i16 or 2 bytes */) as u16); + self.bdl[i] + .flags + .write(1 << 15 /* Interrupt on completion */); + } + self.bus.po.bdbar.write(self.bdl.physical() as u32); - // Enable interrupt on completion - self.bus.po.cr.writef(1 << 4, true); + // Enable interrupt on completion + self.bus.po.cr.writef(1 << 4, true); - // Start bus master - self.bus.po.cr.writef(1 << 0, true); + // Start bus master + self.bus.po.cr.writef(1 << 0, true); - // Set master volume to 0 db (loudest output, DANGER!) - self.mixer.master_volume.write(0); + // Set master volume to 0 db (loudest output, DANGER!) + self.mixer.master_volume.write(0); - // Set PCM output volume to 0 db (medium) - self.mixer.pcm_out_volume.write(0x808); + // Set PCM output volume to 0 db (medium) + self.mixer.pcm_out_volume.write(0x808); - Ok(()) - } + Ok(()) + } - pub fn irq(&mut self) -> bool { - let ints = self.bus.po.sr.read() & 0b11100; - if ints != 0 { - self.bus.po.sr.write(ints); - true - } else { - false - } - } + pub fn irq(&mut self) -> bool { + let ints = self.bus.po.sr.read() & 0b11100; + if ints != 0 { + self.bus.po.sr.write(ints); + true + } else { + false + } + } } impl SchemeBlockMut for Ac97 { - fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, Handle::Todo); - Ok(Some(id)) - } else { - Err(Error::new(EACCES)) - } - } + fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { + if uid == 0 { + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, Handle::Todo); + Ok(Some(id)) + } else { + Err(Error::new(EACCES)) + } + } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - { - let mut handles = self.handles.lock(); - let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; - } + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + { + let mut handles = self.handles.lock(); + let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; + } - if buf.len() != SUB_BUFF_SIZE { - return Err(Error::new(EINVAL)); - } + if buf.len() != SUB_BUFF_SIZE { + return Err(Error::new(EINVAL)); + } - let civ = self.bus.po.civ.read() as usize; - let mut lvi = self.bus.po.lvi.read() as usize; - if lvi == (civ + 3) % NUM_SUB_BUFFS { - // Block if we already are 3 buffers ahead - Ok(None) - } else { - // Fill next buffer - lvi = (lvi + 1) % NUM_SUB_BUFFS; - for i in 0..SUB_BUFF_SIZE { - self.buf[lvi * SUB_BUFF_SIZE + i] = buf[i]; - } - self.bus.po.lvi.write(lvi as u8); + let civ = self.bus.po.civ.read() as usize; + let mut lvi = self.bus.po.lvi.read() as usize; + if lvi == (civ + 3) % NUM_SUB_BUFFS { + // Block if we already are 3 buffers ahead + Ok(None) + } else { + // Fill next buffer + lvi = (lvi + 1) % NUM_SUB_BUFFS; + for i in 0..SUB_BUFF_SIZE { + self.buf[lvi * SUB_BUFF_SIZE + i] = buf[i]; + } + self.bus.po.lvi.write(lvi as u8); - Ok(Some(SUB_BUFF_SIZE)) - } - } + Ok(Some(SUB_BUFF_SIZE)) + } + } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let mut handles = self.handles.lock(); @@ -285,8 +309,11 @@ impl SchemeBlockMut for Ac97 { Ok(Some(i)) } - fn close(&mut self, id: usize) -> Result> { - let mut handles = self.handles.lock(); - handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) - } + fn close(&mut self, id: usize) -> Result> { + let mut handles = self.handles.lock(); + handles + .remove(&id) + .ok_or(Error::new(EBADF)) + .and(Ok(Some(0))) + } } diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index 05cd1a0df9..3b848481fe 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -1,14 +1,14 @@ //#![deny(warnings)] extern crate bitflags; +extern crate event; extern crate spin; extern crate syscall; -extern crate event; -use std::fs::File; -use std::io::{ErrorKind, Read, Write, Result}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::cell::RefCell; +use std::fs::File; +use std::io::{ErrorKind, Read, Result, Write}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; use std::usize; @@ -30,7 +30,10 @@ fn main() { let bar0 = pci_config.func.bars[0].expect_port(); let bar1 = pci_config.func.bars[1].expect_port(); - let irq = pci_config.func.legacy_interrupt_line.expect("ac97d: no legacy interrupts supported"); + let irq = pci_config + .func + .legacy_interrupt_line + .expect("ac97d: no legacy interrupts supported"); println!(" + ac97 {}", pci_config.func.display()); @@ -44,12 +47,19 @@ fn main() { log::LevelFilter::Info, ); - common::acquire_port_io_rights().expect("ac97d: failed to set I/O privilege level to Ring 3"); + common::acquire_port_io_rights() + .expect("ac97d: failed to set I/O privilege level to Ring 3"); let mut irq_file = irq.irq_handle("ac97d"); - let mut device = unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") }; - let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ac97d: failed to create hda scheme"); + let mut device = + unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") }; + let socket_fd = libredox::call::open( + ":audiohw", + flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, + 0, + ) + .expect("ac97d: failed to create hda scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; user_data! { @@ -59,9 +69,18 @@ fn main() { } } - let mut event_queue = EventQueue::::new().expect("ac97d: Could not create event queue."); - event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); - event_queue.subscribe(socket_fd, Source::Scheme, event::EventFlags::READ).unwrap(); + let mut event_queue = + EventQueue::::new().expect("ac97d: Could not create event queue."); + event_queue + .subscribe( + irq_file.as_raw_fd() as usize, + Source::Irq, + event::EventFlags::READ, + ) + .unwrap(); + event_queue + .subscribe(socket_fd, Source::Scheme, event::EventFlags::READ) + .unwrap(); daemon.ready().expect("ac97d: failed to signal readiness"); @@ -70,7 +89,10 @@ fn main() { let mut todo = Vec::::new(); let all = [Source::Irq, Source::Scheme]; - 'events: for event in all.into_iter().chain(event_queue.map(|e| e.expect("ac97d: failed to get next event").user_data)) { + 'events: for event in all + .into_iter() + .chain(event_queue.map(|e| e.expect("ac97d: failed to get next event").user_data)) + { match event { Source::Irq => { let mut irq = [0; 8]; @@ -91,11 +113,11 @@ fn main() { } /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ } } Source::Scheme => { @@ -104,10 +126,12 @@ fn main() { match socket.read(&mut packet) { Ok(0) => break 'events, Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { - break; - } else { - panic!("ac97d: failed to read socket: {err}"); + Err(err) => { + if err.kind() == ErrorKind::WouldBlock { + break; + } else { + panic!("ac97d: failed to read socket: {err}"); + } } } @@ -120,15 +144,16 @@ fn main() { } /* - let next_read = device.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ } } } std::process::exit(0); - }).expect("ac97d: failed to daemonize"); + }) + .expect("ac97d: failed to daemonize"); } diff --git a/audio/ihdad/src/hda/cmdbuff.rs b/audio/ihdad/src/hda/cmdbuff.rs index 93e771d01c..aec6c2dde7 100644 --- a/audio/ihdad/src/hda/cmdbuff.rs +++ b/audio/ihdad/src/hda/cmdbuff.rs @@ -177,8 +177,7 @@ impl Corb { fn send_command(&mut self, cmd: u32) { // wait for the commands to finish while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {} - let write_pos: usize = - ((self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count; + let write_pos: usize = ((self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count; unsafe { *self.corb_base.offset(write_pos as isize) = cmd; } @@ -348,15 +347,20 @@ pub struct CommandBuffer { } impl CommandBuffer { - pub fn new( - regs_addr: usize, - mut cmd_buff: Dma<[u8; 0x1000]>, - ) -> CommandBuffer { - let corb = Corb::new(regs_addr + CORB_OFFSET, cmd_buff.physical(), cmd_buff.as_mut_ptr().cast()); + pub fn new(regs_addr: usize, mut cmd_buff: Dma<[u8; 0x1000]>) -> CommandBuffer { + let corb = Corb::new( + regs_addr + CORB_OFFSET, + cmd_buff.physical(), + cmd_buff.as_mut_ptr().cast(), + ); let rirb = Rirb::new( regs_addr + RIRB_OFFSET, cmd_buff.physical() + CORB_BUFF_MAX_SIZE, - cmd_buff.as_mut_ptr().cast::().wrapping_add(CORB_BUFF_MAX_SIZE).cast(), + cmd_buff + .as_mut_ptr() + .cast::() + .wrapping_add(CORB_BUFF_MAX_SIZE) + .cast(), ); let icmd = ImmediateCommand::new(regs_addr + ICMD_OFFSET); diff --git a/audio/ihdad/src/hda/device.rs b/audio/ihdad/src/hda/device.rs index 86847d3a00..13b1bb7e73 100755 --- a/audio/ihdad/src/hda/device.rs +++ b/audio/ihdad/src/hda/device.rs @@ -1,41 +1,41 @@ #![allow(dead_code)] use std::cmp; +use std::collections::BTreeMap; use std::collections::HashMap; use std::fmt::Write; use std::str; -use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; use common::dma::Dma; -use common::io::{Mmio, Io}; -use syscall::error::{Error, EACCES, EBADF, Result, EINVAL}; -use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END}; +use common::io::{Io, Mmio}; +use syscall::error::{Error, Result, EACCES, EBADF, EINVAL}; +use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET}; use syscall::scheme::SchemeBlockMut; use spin::Mutex; -use super::BufferDescriptorListEntry; use super::common::*; -use super::StreamDescriptorRegs; -use super::StreamBuffer; use super::BitsPerSample; +use super::BufferDescriptorListEntry; use super::CommandBuffer; use super::HDANode; use super::OutputStream; +use super::StreamBuffer; +use super::StreamDescriptorRegs; // GCTL - Global Control -const CRST: u32 = 1 << 0; // 1 bit +const CRST: u32 = 1 << 0; // 1 bit const FNCTRL: u32 = 1 << 1; // 1 bit -const UNSOL: u32 = 1 << 8; // 1 bit +const UNSOL: u32 = 1 << 8; // 1 bit // CORBCTL -const CMEIE: u8 = 1 << 0; // 1 bit +const CMEIE: u8 = 1 << 0; // 1 bit const CORBRUN: u8 = 1 << 1; // 1 bit // CORBSIZE -const CORBSZCAP: (u8,u8) = (4, 4); -const CORBSIZE: (u8,u8) = (0, 2); +const CORBSZCAP: (u8, u8) = (4, 4); +const CORBSIZE: (u8, u8) = (0, 2); // CORBRP const CORBRPRST: u16 = 1 << 15; @@ -44,12 +44,12 @@ const CORBRPRST: u16 = 1 << 15; const RIRBWPRST: u16 = 1 << 15; // RIRBCTL -const RINTCTL: u8 = 1 << 0; // 1 bit +const RINTCTL: u8 = 1 << 0; // 1 bit const RIRBDMAEN: u8 = 1 << 1; // 1 bit // ICS -const ICB: u16 = 1 << 0; -const IRV: u16 = 1 << 1; +const ICB: u16 = 1 << 0; +const IRV: u16 = 1 << 1; // CORB and RIRB offset @@ -59,922 +59,984 @@ const NUM_SUB_BUFFS: usize = 32; const SUB_BUFF_SIZE: usize = 2048; enum Handle { - Todo, - Pcmout(usize, usize, usize), // Card, index, block_ptr - Pcmin(usize, usize, usize), // Card, index, block_ptr - StrBuf(Vec,usize), + Todo, + Pcmout(usize, usize, usize), // Card, index, block_ptr + Pcmin(usize, usize, usize), // Card, index, block_ptr + StrBuf(Vec, usize), } #[repr(packed)] #[allow(dead_code)] struct Regs { - gcap: Mmio, - vmin: Mmio, - vmaj: Mmio, - outpay: Mmio, - inpay: Mmio, - gctl: Mmio, - wakeen: Mmio, - statests: Mmio, - gsts: Mmio, - rsvd0: [Mmio; 6], - outstrmpay: Mmio, - instrmpay: Mmio, - rsvd1: [Mmio; 4], - intctl: Mmio, - intsts: Mmio, - rsvd2: [Mmio; 8], - walclk: Mmio, - rsvd3: Mmio, - ssync: Mmio, - rsvd4: Mmio, + gcap: Mmio, + vmin: Mmio, + vmaj: Mmio, + outpay: Mmio, + inpay: Mmio, + gctl: Mmio, + wakeen: Mmio, + statests: Mmio, + gsts: Mmio, + rsvd0: [Mmio; 6], + outstrmpay: Mmio, + instrmpay: Mmio, + rsvd1: [Mmio; 4], + intctl: Mmio, + intsts: Mmio, + rsvd2: [Mmio; 8], + walclk: Mmio, + rsvd3: Mmio, + ssync: Mmio, + rsvd4: Mmio, - corblbase: Mmio, - corbubase: Mmio, - corbwp: Mmio, - corbrp: Mmio, - corbctl: Mmio, - corbsts: Mmio, - corbsize: Mmio, - rsvd5: Mmio, + corblbase: Mmio, + corbubase: Mmio, + corbwp: Mmio, + corbrp: Mmio, + corbctl: Mmio, + corbsts: Mmio, + corbsize: Mmio, + rsvd5: Mmio, - rirblbase: Mmio, - rirbubase: Mmio, - rirbwp: Mmio, - rintcnt: Mmio, - rirbctl: Mmio, - rirbsts: Mmio, - rirbsize: Mmio, - rsvd6: Mmio, + rirblbase: Mmio, + rirbubase: Mmio, + rirbwp: Mmio, + rintcnt: Mmio, + rirbctl: Mmio, + rirbsts: Mmio, + rirbsize: Mmio, + rsvd6: Mmio, - icoi: Mmio, - irii: Mmio, - ics: Mmio, - rsvd7: [Mmio; 6], + icoi: Mmio, + irii: Mmio, + ics: Mmio, + rsvd7: [Mmio; 6], - dplbase: Mmio, // 0x70 - dpubase: Mmio, // 0x74 + dplbase: Mmio, // 0x70 + dpubase: Mmio, // 0x74 } pub struct IntelHDA { - vend_prod: u32, + vend_prod: u32, - base: usize, - regs: &'static mut Regs, + base: usize, + regs: &'static mut Regs, - //corb_rirb_base_phys: usize, + //corb_rirb_base_phys: usize, + cmd: CommandBuffer, - cmd: CommandBuffer, + codecs: Vec, - codecs: Vec, + outputs: Vec, + inputs: Vec, - outputs: Vec, - inputs: Vec, + widget_map: HashMap, - widget_map: HashMap, + output_pins: Vec, + input_pins: Vec, - output_pins: Vec, - input_pins: Vec, + beep_addr: WidgetAddr, - beep_addr: WidgetAddr, + buff_desc: Dma<[BufferDescriptorListEntry; 256]>, - buff_desc: Dma<[BufferDescriptorListEntry; 256]>, + output_streams: Vec, - output_streams: Vec, + buffs: Vec>, - buffs: Vec>, - - int_counter: usize, - handles: Mutex>, - next_id: AtomicUsize, + int_counter: usize, + handles: Mutex>, + next_id: AtomicUsize, } impl IntelHDA { - pub unsafe fn new(base: usize, vend_prod:u32) -> Result { - let regs = &mut *(base as *mut Regs); + pub unsafe fn new(base: usize, vend_prod: u32) -> Result { + let regs = &mut *(base as *mut Regs); - let buff_desc = Dma::<[BufferDescriptorListEntry; 256]>::zeroed() - .expect("Could not allocate physical memory for buffer descriptor list.") - .assume_init(); + let buff_desc = Dma::<[BufferDescriptorListEntry; 256]>::zeroed() + .expect("Could not allocate physical memory for buffer descriptor list.") + .assume_init(); - log::debug!("Virt: {:016X}, Phys: {:016X}", buff_desc.as_ptr() as usize, buff_desc.physical()); + log::debug!( + "Virt: {:016X}, Phys: {:016X}", + buff_desc.as_ptr() as usize, + buff_desc.physical() + ); - let cmd_buff = Dma::<[u8; 0x1000]>::zeroed() - .expect("Could not allocate physical memory for CORB and RIRB.") - .assume_init(); + let cmd_buff = Dma::<[u8; 0x1000]>::zeroed() + .expect("Could not allocate physical memory for CORB and RIRB.") + .assume_init(); - log::debug!("Virt: {:016X}, Phys: {:016X}", cmd_buff.as_ptr() as usize, cmd_buff.physical()); - let mut module = IntelHDA { - vend_prod, - base, - regs, + log::debug!( + "Virt: {:016X}, Phys: {:016X}", + cmd_buff.as_ptr() as usize, + cmd_buff.physical() + ); + let mut module = IntelHDA { + vend_prod, + base, + regs, - cmd: CommandBuffer::new(base + COMMAND_BUFFER_OFFSET, cmd_buff), + cmd: CommandBuffer::new(base + COMMAND_BUFFER_OFFSET, cmd_buff), - beep_addr: (0,0), + beep_addr: (0, 0), - widget_map: HashMap::::new(), + widget_map: HashMap::::new(), - codecs: Vec::::new(), + codecs: Vec::::new(), - outputs: Vec::::new(), - inputs: Vec::::new(), + outputs: Vec::::new(), + inputs: Vec::::new(), - output_pins: Vec::::new(), - input_pins: Vec::::new(), + output_pins: Vec::::new(), + input_pins: Vec::::new(), - buff_desc, + buff_desc, - output_streams: Vec::::new(), + output_streams: Vec::::new(), - buffs: Vec::>::new(), + buffs: Vec::>::new(), - int_counter: 0, - handles: Mutex::new(BTreeMap::new()), - next_id: AtomicUsize::new(0), - }; + int_counter: 0, + handles: Mutex::new(BTreeMap::new()), + next_id: AtomicUsize::new(0), + }; - module.init(); + module.init(); - module.info(); - module.enumerate(); + module.info(); + module.enumerate(); - module.configure(); - log::info!("IHDA: Initialization finished."); - Ok(module) + module.configure(); + log::info!("IHDA: Initialization finished."); + Ok(module) + } - } + pub fn init(&mut self) -> bool { + self.reset_controller(); - pub fn init(&mut self) -> bool { - self.reset_controller(); + let use_immediate_command_interface = match self.vend_prod { + 0x8086_2668 => false, + _ => true, + }; - let use_immediate_command_interface = match self.vend_prod { + self.cmd.init(use_immediate_command_interface); + self.init_interrupts(); - 0x8086_2668 => false, - _ => true, - }; + true + } - self.cmd.init(use_immediate_command_interface); - self.init_interrupts(); + pub fn init_interrupts(&mut self) { + // TODO: provide a function to enable certain interrupts + // This just enables the first output stream interupt and the global interrupt - true - } + let iss = self.num_input_streams(); + self.regs + .intctl + .write((1 << 31) | /* (1 << 30) |*/ (1 << iss)); + } - pub fn init_interrupts(&mut self) { - // TODO: provide a function to enable certain interrupts - // This just enables the first output stream interupt and the global interrupt + pub fn irq(&mut self) -> bool { + self.int_counter += 1; - let iss = self.num_input_streams(); - self.regs.intctl.write((1 << 31) | /* (1 << 30) |*/ (1 << iss)); - } + self.handle_interrupts() + } - pub fn irq(&mut self) -> bool { - self.int_counter += 1; + pub fn int_count(&self) -> usize { + self.int_counter + } - self.handle_interrupts() - } + pub fn read_node(&mut self, addr: WidgetAddr) -> HDANode { + let mut node = HDANode::new(); + let mut temp: u64; - pub fn int_count(&self) -> usize { - self.int_counter - } + node.addr = addr; - pub fn read_node(&mut self, addr: WidgetAddr) -> HDANode { - let mut node = HDANode::new(); - let mut temp:u64; + temp = self.cmd.cmd12(addr, 0xF00, 0x04); - node.addr = addr; + node.subnode_count = (temp & 0xff) as u16; + node.subnode_start = ((temp >> 16) & 0xff) as u16; - temp = self.cmd.cmd12( addr, 0xF00, 0x04); + if addr == (0, 0) { + return node; + } + temp = self.cmd.cmd12(addr, 0xF00, 0x04); - node.subnode_count = (temp & 0xff) as u16; - node.subnode_start = ((temp >> 16) & 0xff) as u16; + node.function_group_type = (temp & 0xff) as u8; - if addr == (0,0) { - return node; - } - temp = self.cmd.cmd12(addr, 0xF00, 0x04); + temp = self.cmd.cmd12(addr, 0xF00, 0x09); + node.capabilities = temp as u32; - node.function_group_type = (temp & 0xff) as u8; + temp = self.cmd.cmd12(addr, 0xF00, 0x0E); - temp = self.cmd.cmd12(addr, 0xF00, 0x09); - node.capabilities = temp as u32; + node.conn_list_len = (temp & 0xFF) as u8; - temp = self.cmd.cmd12(addr, 0xF00, 0x0E); + node.connections = self.node_get_connection_list(&node); - node.conn_list_len = (temp & 0xFF) as u8; + node.connection_default = self.cmd.cmd12(addr, 0xF01, 0x00) as u8; - node.connections = self.node_get_connection_list(&node); + node.config_default = self.cmd.cmd12(addr, 0xF1C, 0x00) as u32; - node.connection_default = self.cmd.cmd12(addr, 0xF01, 0x00) as u8; + node + } - node.config_default = self.cmd.cmd12(addr, 0xF1C, 0x00) as u32; + pub fn node_get_connection_list(&mut self, node: &HDANode) -> Vec { + let len_field: u8 = (self.cmd.cmd12(node.addr, 0xF00, 0x0E) & 0xFF) as u8; - node - } + // Highest bit is if addresses are represented in longer notation + // lower 7 is actual count - pub fn node_get_connection_list(&mut self, node: &HDANode) -> Vec { - let len_field: u8 = (self.cmd.cmd12(node.addr, 0xF00, 0x0E) & 0xFF) as u8; + let count: u8 = len_field & 0x7F; + let use_long_addr: bool = (len_field >> 7) & 0x1 == 1; - // Highest bit is if addresses are represented in longer notation - // lower 7 is actual count + let mut current: u8 = 0; - let count:u8 = len_field & 0x7F; - let use_long_addr: bool = (len_field >> 7) & 0x1 == 1; + let mut list = Vec::::new(); - let mut current: u8 = 0; + while current < count { + let response: u32 = (self.cmd.cmd12(node.addr, 0xF02, current) & 0xFFFFFFFF) as u32; + + if use_long_addr { + for i in 0..2 { + let addr_field = ((response >> (16 * i)) & 0xFFFF) as u16; + let addr = addr_field & 0x7FFF; + + if addr == 0 { + break; + } + + if (addr_field >> 15) & 0x1 == 0x1 { + for i in list.pop().unwrap().1..(addr + 1) { + list.push((node.addr.0, i)); + } + } else { + list.push((node.addr.0, addr)); + } + } + } else { + for i in 0..4 { + let addr_field = ((response >> (8 * i)) & 0xff) as u16; + let addr = addr_field & 0x7F; + + if addr == 0 { + break; + } + + if (addr_field >> 7) & 0x1 == 0x1 { + for i in list.pop().unwrap().1..(addr + 1) { + list.push((node.addr.0, i)); + } + } else { + list.push((node.addr.0, addr)); + } + } + } + + current = list.len() as u8; + } + + list + } + + pub fn enumerate(&mut self) { + self.output_pins.clear(); + self.input_pins.clear(); + + let codec: u8 = 0; + + let root = self.read_node((codec, 0)); + + log::debug!("{}", root); + + let root_count = root.subnode_count; + let root_start = root.subnode_start; + + //FIXME: So basically the way this is set up is to only support one codec and hopes the first one is an audio + for i in 0..root_count { + let afg = self.read_node((codec, root_start + i)); + log::debug!("{}", afg); + let afg_count = afg.subnode_count; + let afg_start = afg.subnode_start; + + for j in 0..afg_count { + let mut widget = self.read_node((codec, afg_start + j)); + widget.is_widget = true; + match widget.widget_type() { + HDAWidgetType::AudioOutput => self.outputs.push(widget.addr), + HDAWidgetType::AudioInput => self.inputs.push(widget.addr), + HDAWidgetType::BeepGenerator => self.beep_addr = widget.addr, + HDAWidgetType::PinComplex => { + let config = widget.configuration_default(); + if config.is_output() { + self.output_pins.push(widget.addr); + } else if config.is_input() { + self.input_pins.push(widget.addr); + } + } + _ => {} + } + + log::debug!("{}", widget); + self.widget_map.insert(widget.addr(), widget); + } + } + } + + pub fn find_best_output_pin(&mut self) -> Option { + let outs = &self.output_pins; + if outs.len() == 0 { + None + } else if outs.len() == 1 { + Some(outs[0]) + } else { + //TODO: change output based on "unsolicited response" interrupts + // Check for devices in this order: Headphone, Speaker, Line Out + for supported_device in &[DefaultDevice::HPOut, DefaultDevice::Speaker] { + for &out in outs { + let widget = self.widget_map.get(&out).unwrap(); + let cd = widget.configuration_default(); + if cd.sequence() == 0 && &cd.default_device() == supported_device { + // Check for jack detect bit + let pin_caps = self.cmd.cmd12(widget.addr, 0xF00, 0x0C); + if pin_caps & (1 << 2) != 0 { + // Check for presence + let pin_sense = self.cmd.cmd12(widget.addr, 0xF09, 0); + if pin_sense & (1 << 31) == 0 { + // Skip if nothing is plugged in + continue; + } + } + return Some(out); + } + } + } + + None + } + } + + pub fn find_path_to_dac(&self, addr: WidgetAddr) -> Option> { + let widget = self.widget_map.get(&addr).unwrap(); + if widget.widget_type() == HDAWidgetType::AudioOutput { + Some(vec![addr]) + } else { + let connection = widget.connections.get(widget.connection_default as usize)?; + let mut path = self.find_path_to_dac(*connection)?; + path.insert(0, addr); + Some(path) + } + } + + /* + Here we update the buffers and split them into 128 byte sub chunks + because each BufferDescriptorList needs to be 128 byte aligned, + this makes it so each of the streams can have up to 128/16 (8) buffer descriptors + */ + /* + Vec of a Vec was doing something weird and causing the driver to hang. + So now we have a set of variables instead. + + + Fixed? + */ + + pub fn update_sound_buffers(&mut self) { + /* + for i in 0..self.buffs.len(){ + for j in 0.. min(self.buffs[i].len(), 128/16 ) { + self.buff_desc[i * 128/16 + j].set_address(self.buffs[i][j].phys()); + self.buff_desc[i * 128/16 + j].set_length(self.buffs[i][j].length() as u32); + self.buff_desc[i * 128/16 + j].set_interrupt_on_complete(true); + } + }*/ + + let r = self.get_output_stream_descriptor(0).unwrap(); + + self.output_streams + .push(OutputStream::new(NUM_SUB_BUFFS, SUB_BUFF_SIZE, r)); + + let o = self.output_streams.get_mut(0).unwrap(); + + for i in 0..NUM_SUB_BUFFS { + self.buff_desc[i].set_address((o.phys() + o.block_size() * i) as u64); + self.buff_desc[i].set_length(o.block_size() as u32); + self.buff_desc[i].set_interrupt_on_complete(true); + } + } + + pub fn configure(&mut self) { + let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); + + log::debug!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); + + let path = self.find_path_to_dac(outpin).unwrap(); + + let dac = *path.last().unwrap(); + let pin = *path.first().unwrap(); + + log::debug!("Path to DAC: {:X?}", path); + + // Set power state 0 (on) for all widgets in path + for &addr in &path { + self.set_power_state(addr, 0); + } + + // Pin enable (0x80 = headphone amp enable, 0x40 = output enable) + self.cmd.cmd12(pin, 0x707, 0xC0); + + // EAPD enable + self.cmd.cmd12(pin, 0x70C, 2); + + // Set DAC stream and channel + self.set_stream_channel(dac, 1, 0); + + self.update_sound_buffers(); + + log::debug!( + "Supported Formats: {:08X}", + self.get_supported_formats((0, 0x1)) + ); + log::debug!("Capabilities: {:08X}", self.get_capabilities(path[0])); + + // Create output stream + let output = self.get_output_stream_descriptor(0).unwrap(); + output.set_address(self.buff_desc.physical()); + output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); + output.set_cyclic_buffer_length((NUM_SUB_BUFFS * SUB_BUFF_SIZE) as u32); // number of bytes + output.set_stream_number(1); + output.set_last_valid_index((NUM_SUB_BUFFS - 1) as u16); + output.set_interrupt_on_completion(true); + + // Set DAC converter format + self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2); + + // Get DAC converter format + //TODO: should validate? + self.cmd.cmd12(dac, 0xA00, 0); + + // Unmute and set gain to 0db for input and output amplifiers on all widgets in path + for &addr in &path { + // Read widget capabilities + let caps = self.cmd.cmd12(addr, 0xF00, 0x09); - let mut list = Vec::::new(); + //TODO: do we need to set any other indexes? + let left = true; + let right = true; + let index = 0; + let mute = false; - while current < count { + // Check for input amp + if (caps & (1 << 1)) != 0 { + // Read input capabilities + let in_caps = self.cmd.cmd12(addr, 0xF00, 0x0D); + let in_gain = (in_caps & 0x7f) as u8; + // Set input gain + let output = false; + let input = true; + self.set_amplifier_gain_mute( + addr, output, input, left, right, index, mute, in_gain, + ); + log::debug!("Set {:X?} input gain to 0x{:X}", addr, in_gain); + } - let response: u32 = (self.cmd.cmd12(node.addr, 0xF02, current) & 0xFFFFFFFF) as u32; + // Check for output amp + if (caps & (1 << 2)) != 0 { + // Read output capabilities + let out_caps = self.cmd.cmd12(addr, 0xF00, 0x12); + let out_gain = (out_caps & 0x7f) as u8; + // Set output gain + let output = true; + let input = false; + self.set_amplifier_gain_mute( + addr, output, input, left, right, index, mute, out_gain, + ); + log::debug!("Set {:X?} output gain to 0x{:X}", addr, out_gain); + } + } - if use_long_addr { - for i in 0..2 { - let addr_field = ((response >> (16 * i)) & 0xFFFF) as u16; - let addr = addr_field & 0x7FFF; + //TODO: implement hda-verb? - if addr == 0 { break; } + output.run(); + log::debug!("Waiting for output 0 to start running..."); + while output.control() & (1 << 1) == 0 { + //TODO: relax + } - if (addr_field >> 15) & 0x1 == 0x1 { - for i in list.pop().unwrap().1 .. (addr + 1) { - list.push((node.addr.0, i)); - } - } else { - list.push((node.addr.0, addr)); - } - } - - } else { - for i in 0..4 { - let addr_field = ((response >> (8 * i)) & 0xff) as u16; - let addr = addr_field & 0x7F; - - if addr == 0 { break; } - - if (addr_field >> 7) & 0x1 == 0x1 { - for i in list.pop().unwrap().1 .. (addr + 1) { - list.push((node.addr.0, i)); - } - } else { - list.push((node.addr.0, addr)); - } - } - } - - current = list.len() as u8; - } - - list - } - - pub fn enumerate(&mut self) { - self.output_pins.clear(); - self.input_pins.clear(); - - let codec:u8 = 0; - - let root = self.read_node((codec,0)); - - log::debug!("{}", root); - - let root_count = root.subnode_count; - let root_start = root.subnode_start; - - //FIXME: So basically the way this is set up is to only support one codec and hopes the first one is an audio - for i in 0..root_count { - let afg = self.read_node((codec, root_start + i)); - log::debug!("{}", afg); - let afg_count = afg.subnode_count; - let afg_start = afg.subnode_start; - - for j in 0..afg_count { - let mut widget = self.read_node((codec, afg_start + j)); - widget.is_widget = true; - match widget.widget_type() { - HDAWidgetType::AudioOutput => {self.outputs.push(widget.addr)}, - HDAWidgetType::AudioInput => {self.inputs.push(widget.addr)}, - HDAWidgetType::BeepGenerator => {self.beep_addr = widget.addr }, - HDAWidgetType::PinComplex => { - let config = widget.configuration_default(); - if config.is_output() { - self.output_pins.push(widget.addr); - } else if config.is_input() { - self.input_pins.push(widget.addr); - } - }, - _ => {}, - } - - log::debug!("{}", widget); - self.widget_map.insert(widget.addr(), widget); - } - } - } - - pub fn find_best_output_pin(&mut self) -> Option{ - let outs = &self.output_pins; - if outs.len() == 0 { - None - } else if outs.len() == 1 { - Some(outs[0]) - } else { - //TODO: change output based on "unsolicited response" interrupts - // Check for devices in this order: Headphone, Speaker, Line Out - for supported_device in &[ - DefaultDevice::HPOut, - DefaultDevice::Speaker, - ] { - for &out in outs { - let widget = self.widget_map.get(&out).unwrap(); - let cd = widget.configuration_default(); - if cd.sequence() == 0 && &cd.default_device() == supported_device { - // Check for jack detect bit - let pin_caps = self.cmd.cmd12(widget.addr, 0xF00, 0x0C); - if pin_caps & (1 << 2) != 0 { - // Check for presence - let pin_sense = self.cmd.cmd12(widget.addr, 0xF09, 0); - if pin_sense & (1 << 31) == 0 { - // Skip if nothing is plugged in - continue; - } - } - return Some(out); - } - } - } - - None - } - } - - pub fn find_path_to_dac(&self, addr: WidgetAddr) -> Option>{ - let widget = self.widget_map.get(&addr).unwrap(); - if widget.widget_type() == HDAWidgetType::AudioOutput { - Some(vec![addr]) - } else { - let connection = widget.connections.get(widget.connection_default as usize)?; - let mut path = self.find_path_to_dac(*connection)?; - path.insert(0, addr); - Some(path) - } - } - - /* - Here we update the buffers and split them into 128 byte sub chunks - because each BufferDescriptorList needs to be 128 byte aligned, - this makes it so each of the streams can have up to 128/16 (8) buffer descriptors - */ - /* - Vec of a Vec was doing something weird and causing the driver to hang. - So now we have a set of variables instead. - - - Fixed? - */ - - pub fn update_sound_buffers(&mut self) { - /* - for i in 0..self.buffs.len(){ - for j in 0.. min(self.buffs[i].len(), 128/16 ) { - self.buff_desc[i * 128/16 + j].set_address(self.buffs[i][j].phys()); - self.buff_desc[i * 128/16 + j].set_length(self.buffs[i][j].length() as u32); - self.buff_desc[i * 128/16 + j].set_interrupt_on_complete(true); - } - }*/ - - let r = self.get_output_stream_descriptor(0).unwrap(); - - self.output_streams.push(OutputStream::new(NUM_SUB_BUFFS, SUB_BUFF_SIZE, r)); - - let o = self.output_streams.get_mut(0).unwrap(); - - for i in 0..NUM_SUB_BUFFS { - self.buff_desc[i].set_address((o.phys() + o.block_size() * i) as u64); - self.buff_desc[i].set_length(o.block_size() as u32); - self.buff_desc[i].set_interrupt_on_complete(true); - } - } - - pub fn configure(&mut self) { - let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); - - log::debug!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); - - let path = self.find_path_to_dac(outpin).unwrap(); - - let dac = *path.last().unwrap(); - let pin = *path.first().unwrap(); - - log::debug!("Path to DAC: {:X?}", path); - - // Set power state 0 (on) for all widgets in path - for &addr in &path { - self.set_power_state(addr, 0); - } - - // Pin enable (0x80 = headphone amp enable, 0x40 = output enable) - self.cmd.cmd12(pin, 0x707, 0xC0); - - // EAPD enable - self.cmd.cmd12(pin, 0x70C, 2); - - // Set DAC stream and channel - self.set_stream_channel(dac, 1, 0); - - self.update_sound_buffers(); - - log::debug!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); - log::debug!("Capabilities: {:08X}", self.get_capabilities(path[0])); - - // Create output stream - let output = self.get_output_stream_descriptor(0).unwrap(); - output.set_address(self.buff_desc.physical()); - output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); - output.set_cyclic_buffer_length((NUM_SUB_BUFFS * SUB_BUFF_SIZE) as u32); // number of bytes - output.set_stream_number(1); - output.set_last_valid_index((NUM_SUB_BUFFS - 1) as u16); - output.set_interrupt_on_completion(true); - - // Set DAC converter format - self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2); - - // Get DAC converter format - //TODO: should validate? - self.cmd.cmd12(dac, 0xA00, 0); - - // Unmute and set gain to 0db for input and output amplifiers on all widgets in path - for &addr in &path { - // Read widget capabilities - let caps = self.cmd.cmd12(addr, 0xF00, 0x09); - - //TODO: do we need to set any other indexes? - let left = true; - let right = true; - let index = 0; - let mute = false; - - // Check for input amp - if (caps & (1 << 1)) != 0 { - // Read input capabilities - let in_caps = self.cmd.cmd12(addr, 0xF00, 0x0D); - let in_gain = (in_caps & 0x7f) as u8; - // Set input gain - let output = false; - let input = true; - self.set_amplifier_gain_mute(addr, output, input, left, right, index, mute, in_gain); - log::debug!("Set {:X?} input gain to 0x{:X}", addr, in_gain); - } - - // Check for output amp - if (caps & (1 << 2)) != 0 { - // Read output capabilities - let out_caps = self.cmd.cmd12(addr, 0xF00, 0x12); - let out_gain = (out_caps & 0x7f) as u8; - // Set output gain - let output = true; - let input = false; - self.set_amplifier_gain_mute(addr, output, input, left, right, index, mute, out_gain); - log::debug!("Set {:X?} output gain to 0x{:X}", addr, out_gain); - } - } - - //TODO: implement hda-verb? - - output.run(); - log::debug!("Waiting for output 0 to start running..."); - while output.control() & (1 << 1) == 0 { - //TODO: relax - } - - log::debug!("Output 0 CONTROL {:#X} STATUS {:#X} POS {:#X}", output.control(), output.status(), output.link_position()); - } - /* - - pub fn configure_vbox(&mut self) { - - let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); - - log::debug!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); - - let path = self.find_path_to_dac(outpin).unwrap(); - log::debug!("Path to DAC: {:X?}", path); - - // Pin enable - self.cmd.cmd12((0,0xC), 0x707, 0x40); - - - // EAPD enable - self.cmd.cmd12((0,0xC), 0x70C, 2); - - self.set_stream_channel((0,0x3), 1, 0); - - self.update_sound_buffers(); - - - log::debug!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); - log::debug!("Capabilities: {:08X}", self.get_capabilities((0,0x1))); - - let output = self.get_output_stream_descriptor(0).unwrap(); - - output.set_address(self.buff_desc_phys); - - output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); - output.set_cyclic_buffer_length((NUM_SUB_BUFFS * SUB_BUFF_SIZE) as u32); - output.set_stream_number(1); - output.set_last_valid_index((NUM_SUB_BUFFS - 1) as u16); - output.set_interrupt_on_completion(true); - - - self.set_power_state((0,0x3), 0); // Power state 0 is fully on - self.set_converter_format((0,0x3), &super::SR_44_1, BitsPerSample::Bits16, 2); - - - self.cmd.cmd12((0,0x3), 0xA00, 0); - - // Unmute and set gain for pin complex and DAC - self.set_amplifier_gain_mute((0,0x3), true, true, true, true, 0, false, 0x7f); - self.set_amplifier_gain_mute((0,0xC), true, true, true, true, 0, false, 0x7f); - - output.run(); - - self.beep(1); - - } - - */ - - pub fn dump_codec(&self, codec:u8) -> String { - let mut string = String::new(); - - for (_, widget) in self.widget_map.iter() { - let _ = writeln!(string, "{}", widget); - } - - string - } - - // BEEP!! - pub fn beep(&mut self, div:u8) { - let addr = self.beep_addr; - if addr != (0,0) { - let _ = self.cmd.cmd12(addr, 0xF0A, div); - } - } - - pub fn read_beep(&mut self) -> u8 { - let addr = self.beep_addr; - if addr != (0,0) { - self.cmd.cmd12(addr, 0x70A, 0) as u8 - }else{ - 0 - } - } - - pub fn reset_controller(&mut self) -> bool { - self.regs.statests.write(0xFFFF); - - // 3.3.7 - self.regs.gctl.writef(CRST, false); - loop { - if ! self.regs.gctl.readf(CRST) { - break; - } - } - self.regs.gctl.writef(CRST, true); - loop { - if self.regs.gctl.readf(CRST) { - break; - } - } - - let mut ticks:u32 = 0; - while self.regs.statests.read() == 0 { - ticks += 1; - if ticks > 10000 { break;} - - } - - let statests = self.regs.statests.read(); - log::debug!("Statests: {:04X}", statests); - - for i in 0..15 { - if (statests >> i) & 0x1 == 1 { - self.codecs.push(i as CodecAddr); - } - } - true - - } - - pub fn num_output_streams(&self) -> usize{ - let gcap = self.regs.gcap.read(); - ((gcap >> 12) & 0xF) as usize - } - - pub fn num_input_streams(&self) -> usize{ - let gcap = self.regs.gcap.read(); - ((gcap >> 8) & 0xF) as usize - } - - pub fn num_bidirectional_streams(&self) -> usize{ - let gcap = self.regs.gcap.read(); - ((gcap >> 3) & 0xF) as usize - } - - pub fn num_serial_data_out(&self) -> usize{ - let gcap = self.regs.gcap.read(); - ((gcap >> 1) & 0x3) as usize - } - - pub fn info(&self) { - log::info!("Intel HD Audio Version {}.{}", self.regs.vmaj.read(), self.regs.vmin.read()); - log::debug!("IHDA: Input Streams: {}", self.num_input_streams()); - log::debug!("IHDA: Output Streams: {}", self.num_output_streams()); - log::debug!("IHDA: Bidirectional Streams: {}", self.num_bidirectional_streams()); - log::debug!("IHDA: Serial Data Outputs: {}", self.num_serial_data_out()); - log::debug!("IHDA: 64-Bit: {}", self.regs.gcap.read() & 1 == 1); - } - - fn get_input_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { - unsafe { - if index < self.num_input_streams() { - Some(&mut *((self.base + 0x80 + index * 0x20) as *mut StreamDescriptorRegs)) - }else{ - None - } - } - } - - fn get_output_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { - unsafe { - if index < self.num_output_streams() { - Some(&mut *((self.base + 0x80 + - self.num_input_streams() * 0x20 + - index * 0x20) as *mut StreamDescriptorRegs)) - }else{ - None - } - } - } - - - fn get_bidirectional_stream_descriptor(&self, index: usize) -> Option<&'static mut StreamDescriptorRegs> { - unsafe { - if index < self.num_bidirectional_streams() { - Some(&mut *((self.base + 0x80 + - self.num_input_streams() * 0x20 + - self.num_output_streams() * 0x20 + - index * 0x20) as *mut StreamDescriptorRegs)) - }else{ - None - } - } - } - - fn set_dma_position_buff_addr(&mut self, addr: u64) { - let addr_val = addr & !0x7F; - self.regs.dplbase.write((addr_val & 0xFFFFFFFF) as u32); - self.regs.dpubase.write((addr_val >> 32) as u32); - } - - - fn set_stream_channel(&mut self, addr: WidgetAddr, stream: u8, channel:u8) { - let val = ((stream & 0xF) << 4) | (channel & 0xF); - self.cmd.cmd12(addr, 0x706, val); - } - - fn set_power_state(&mut self, addr:WidgetAddr, state:u8) { - self.cmd.cmd12(addr, 0x705, state & 0xF) as u32; - } - - fn get_supported_formats(&mut self, addr: WidgetAddr) -> u32 { - self.cmd.cmd12(addr, 0xF00, 0x0A) as u32 - } - - fn get_capabilities(&mut self, addr: WidgetAddr) -> u32 { - self.cmd.cmd12(addr, 0xF00, 0x09) as u32 - } - - fn set_converter_format(&mut self, addr:WidgetAddr, sr: &super::SampleRate, bps: BitsPerSample, channels:u8) { - let fmt = super::format_to_u16(sr, bps, channels); - self.cmd.cmd4(addr, 0x2, fmt); - } - - fn set_amplifier_gain_mute(&mut self, addr: WidgetAddr, output:bool, input:bool, left:bool, right:bool, index:u8, mute:bool, gain: u8) { - let mut payload: u16 = 0; - - if output { payload |= 1 << 15; } - if input { payload |= 1 << 14; } - if left { payload |= 1 << 13; } - if right { payload |= 1 << 12; } - if mute { payload |= 1 << 7; } - payload |= ((index as u16) & 0x0F) << 8; - payload |= (gain as u16) & 0x7F; - - self.cmd.cmd4(addr, 0x3, payload); - } - - pub fn write_to_output(&mut self, index:u8, buf: &[u8]) -> Result> { - let output = self.get_output_stream_descriptor(index as usize).unwrap(); - let os = self.output_streams.get_mut(index as usize).unwrap(); - - //let sample_size:usize = output.sample_size(); - let open_block = (output.link_position() as usize) / os.block_size(); - - //log::trace!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}", output.status(), output.link_position(), output.control()); - - if os.current_block() == (open_block + 3) % NUM_SUB_BUFFS { - // Block if we already are 3 buffers ahead - Ok(None) - } else { - os.write_block(buf).map(|count| Some(count)) - } - } - - pub fn handle_interrupts(&mut self) -> bool { - let intsts = self.regs.intsts.read(); - if ((intsts >> 31) & 1) == 1 { // Global Interrupt Status - if ((intsts >> 30) & 1) == 1 { // Controller Interrupt Status - self.handle_controller_interrupt(); - } - - let sis = intsts & 0x3FFFFFFF; - if sis != 0 { - self.handle_stream_interrupts(sis); - } - } - intsts != 0 - } - - pub fn handle_controller_interrupt(&mut self) { - - } - - pub fn handle_stream_interrupts(&mut self, sis: u32) { - let iss = self.num_input_streams(); - let oss = self.num_output_streams(); - let bss = self.num_bidirectional_streams(); - - for i in 0..iss { - if ((sis >> i) & 1 ) == 1 { - let input = self.get_input_stream_descriptor(i).unwrap(); - input.clear_interrupts(); - } - } - - for i in 0..oss { - if ((sis >> (i + iss)) & 1 ) == 1 { - let output = self.get_output_stream_descriptor(i).unwrap(); - output.clear_interrupts(); - } - } - - for i in 0..bss { - if ((sis >> (i + iss + oss)) & 1 ) == 1 { - let bid = self.get_bidirectional_stream_descriptor(i).unwrap(); - bid.clear_interrupts(); - } - } - } - - fn validate_path(&mut self, path: &Vec<&str>) -> bool { - log::debug!("Path: {:?}", path); - let mut it = path.iter(); - match it.next() { - Some(card_str) if (*card_str).starts_with("card") => { - match usize::from_str_radix(&(*card_str)[4..], 10) { - Ok(card_num) => { - log::debug!("Card# {}", card_num); - match it.next() { - Some(codec_str) if (*codec_str).starts_with("codec#") => { - match usize::from_str_radix(&(*codec_str)[6..], 10) { - Ok(_codec_num) => { - //let id = self.next_id.fetch_add(1, Ordering::SeqCst); - //self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0)); - true - - }, - _ => false, - } - }, - Some(pcmout_str) if (*pcmout_str).starts_with("pcmout") => { - match usize::from_str_radix(&(*pcmout_str)[6..], 10) { - Ok(pcmout_num) => { - log::debug!("pcmout {}", pcmout_num); - true - }, - _ => false, - } - }, - Some(pcmin_str) if (*pcmin_str).starts_with("pcmin") => { - match usize::from_str_radix(&(*pcmin_str)[6..], 10) { - Ok(pcmin_num) => { - log::debug!("pcmin {}", pcmin_num); - true - }, - _ => false, - } - }, - _ => false, - } - }, - _ => false, - } - }, - Some(cards_str) if *cards_str == "cards" => { - true - }, - _ => false, - } - } + log::debug!( + "Output 0 CONTROL {:#X} STATUS {:#X} POS {:#X}", + output.control(), + output.status(), + output.link_position() + ); + } + /* + + pub fn configure_vbox(&mut self) { + + let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); + + log::debug!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); + + let path = self.find_path_to_dac(outpin).unwrap(); + log::debug!("Path to DAC: {:X?}", path); + + // Pin enable + self.cmd.cmd12((0,0xC), 0x707, 0x40); + + + // EAPD enable + self.cmd.cmd12((0,0xC), 0x70C, 2); + + self.set_stream_channel((0,0x3), 1, 0); + + self.update_sound_buffers(); + + + log::debug!("Supported Formats: {:08X}", self.get_supported_formats((0,0x1))); + log::debug!("Capabilities: {:08X}", self.get_capabilities((0,0x1))); + + let output = self.get_output_stream_descriptor(0).unwrap(); + + output.set_address(self.buff_desc_phys); + + output.set_pcm_format(&super::SR_44_1, BitsPerSample::Bits16, 2); + output.set_cyclic_buffer_length((NUM_SUB_BUFFS * SUB_BUFF_SIZE) as u32); + output.set_stream_number(1); + output.set_last_valid_index((NUM_SUB_BUFFS - 1) as u16); + output.set_interrupt_on_completion(true); + + + self.set_power_state((0,0x3), 0); // Power state 0 is fully on + self.set_converter_format((0,0x3), &super::SR_44_1, BitsPerSample::Bits16, 2); + + + self.cmd.cmd12((0,0x3), 0xA00, 0); + + // Unmute and set gain for pin complex and DAC + self.set_amplifier_gain_mute((0,0x3), true, true, true, true, 0, false, 0x7f); + self.set_amplifier_gain_mute((0,0xC), true, true, true, true, 0, false, 0x7f); + + output.run(); + + self.beep(1); + + } + + */ + + pub fn dump_codec(&self, codec: u8) -> String { + let mut string = String::new(); + + for (_, widget) in self.widget_map.iter() { + let _ = writeln!(string, "{}", widget); + } + + string + } + + // BEEP!! + pub fn beep(&mut self, div: u8) { + let addr = self.beep_addr; + if addr != (0, 0) { + let _ = self.cmd.cmd12(addr, 0xF0A, div); + } + } + + pub fn read_beep(&mut self) -> u8 { + let addr = self.beep_addr; + if addr != (0, 0) { + self.cmd.cmd12(addr, 0x70A, 0) as u8 + } else { + 0 + } + } + + pub fn reset_controller(&mut self) -> bool { + self.regs.statests.write(0xFFFF); + + // 3.3.7 + self.regs.gctl.writef(CRST, false); + loop { + if !self.regs.gctl.readf(CRST) { + break; + } + } + self.regs.gctl.writef(CRST, true); + loop { + if self.regs.gctl.readf(CRST) { + break; + } + } + + let mut ticks: u32 = 0; + while self.regs.statests.read() == 0 { + ticks += 1; + if ticks > 10000 { + break; + } + } + + let statests = self.regs.statests.read(); + log::debug!("Statests: {:04X}", statests); + + for i in 0..15 { + if (statests >> i) & 0x1 == 1 { + self.codecs.push(i as CodecAddr); + } + } + true + } + + pub fn num_output_streams(&self) -> usize { + let gcap = self.regs.gcap.read(); + ((gcap >> 12) & 0xF) as usize + } + + pub fn num_input_streams(&self) -> usize { + let gcap = self.regs.gcap.read(); + ((gcap >> 8) & 0xF) as usize + } + + pub fn num_bidirectional_streams(&self) -> usize { + let gcap = self.regs.gcap.read(); + ((gcap >> 3) & 0xF) as usize + } + + pub fn num_serial_data_out(&self) -> usize { + let gcap = self.regs.gcap.read(); + ((gcap >> 1) & 0x3) as usize + } + + pub fn info(&self) { + log::info!( + "Intel HD Audio Version {}.{}", + self.regs.vmaj.read(), + self.regs.vmin.read() + ); + log::debug!("IHDA: Input Streams: {}", self.num_input_streams()); + log::debug!("IHDA: Output Streams: {}", self.num_output_streams()); + log::debug!( + "IHDA: Bidirectional Streams: {}", + self.num_bidirectional_streams() + ); + log::debug!("IHDA: Serial Data Outputs: {}", self.num_serial_data_out()); + log::debug!("IHDA: 64-Bit: {}", self.regs.gcap.read() & 1 == 1); + } + + fn get_input_stream_descriptor( + &self, + index: usize, + ) -> Option<&'static mut StreamDescriptorRegs> { + unsafe { + if index < self.num_input_streams() { + Some(&mut *((self.base + 0x80 + index * 0x20) as *mut StreamDescriptorRegs)) + } else { + None + } + } + } + + fn get_output_stream_descriptor( + &self, + index: usize, + ) -> Option<&'static mut StreamDescriptorRegs> { + unsafe { + if index < self.num_output_streams() { + Some( + &mut *((self.base + 0x80 + self.num_input_streams() * 0x20 + index * 0x20) + as *mut StreamDescriptorRegs), + ) + } else { + None + } + } + } + + fn get_bidirectional_stream_descriptor( + &self, + index: usize, + ) -> Option<&'static mut StreamDescriptorRegs> { + unsafe { + if index < self.num_bidirectional_streams() { + Some( + &mut *((self.base + + 0x80 + + self.num_input_streams() * 0x20 + + self.num_output_streams() * 0x20 + + index * 0x20) as *mut StreamDescriptorRegs), + ) + } else { + None + } + } + } + + fn set_dma_position_buff_addr(&mut self, addr: u64) { + let addr_val = addr & !0x7F; + self.regs.dplbase.write((addr_val & 0xFFFFFFFF) as u32); + self.regs.dpubase.write((addr_val >> 32) as u32); + } + + fn set_stream_channel(&mut self, addr: WidgetAddr, stream: u8, channel: u8) { + let val = ((stream & 0xF) << 4) | (channel & 0xF); + self.cmd.cmd12(addr, 0x706, val); + } + + fn set_power_state(&mut self, addr: WidgetAddr, state: u8) { + self.cmd.cmd12(addr, 0x705, state & 0xF) as u32; + } + + fn get_supported_formats(&mut self, addr: WidgetAddr) -> u32 { + self.cmd.cmd12(addr, 0xF00, 0x0A) as u32 + } + + fn get_capabilities(&mut self, addr: WidgetAddr) -> u32 { + self.cmd.cmd12(addr, 0xF00, 0x09) as u32 + } + + fn set_converter_format( + &mut self, + addr: WidgetAddr, + sr: &super::SampleRate, + bps: BitsPerSample, + channels: u8, + ) { + let fmt = super::format_to_u16(sr, bps, channels); + self.cmd.cmd4(addr, 0x2, fmt); + } + + fn set_amplifier_gain_mute( + &mut self, + addr: WidgetAddr, + output: bool, + input: bool, + left: bool, + right: bool, + index: u8, + mute: bool, + gain: u8, + ) { + let mut payload: u16 = 0; + + if output { + payload |= 1 << 15; + } + if input { + payload |= 1 << 14; + } + if left { + payload |= 1 << 13; + } + if right { + payload |= 1 << 12; + } + if mute { + payload |= 1 << 7; + } + payload |= ((index as u16) & 0x0F) << 8; + payload |= (gain as u16) & 0x7F; + + self.cmd.cmd4(addr, 0x3, payload); + } + + pub fn write_to_output(&mut self, index: u8, buf: &[u8]) -> Result> { + let output = self.get_output_stream_descriptor(index as usize).unwrap(); + let os = self.output_streams.get_mut(index as usize).unwrap(); + + //let sample_size:usize = output.sample_size(); + let open_block = (output.link_position() as usize) / os.block_size(); + + //log::trace!("Status: {:02X} Pos: {:08X} Output CTL: {:06X}", output.status(), output.link_position(), output.control()); + + if os.current_block() == (open_block + 3) % NUM_SUB_BUFFS { + // Block if we already are 3 buffers ahead + Ok(None) + } else { + os.write_block(buf).map(|count| Some(count)) + } + } + + pub fn handle_interrupts(&mut self) -> bool { + let intsts = self.regs.intsts.read(); + if ((intsts >> 31) & 1) == 1 { + // Global Interrupt Status + if ((intsts >> 30) & 1) == 1 { + // Controller Interrupt Status + self.handle_controller_interrupt(); + } + + let sis = intsts & 0x3FFFFFFF; + if sis != 0 { + self.handle_stream_interrupts(sis); + } + } + intsts != 0 + } + + pub fn handle_controller_interrupt(&mut self) {} + + pub fn handle_stream_interrupts(&mut self, sis: u32) { + let iss = self.num_input_streams(); + let oss = self.num_output_streams(); + let bss = self.num_bidirectional_streams(); + + for i in 0..iss { + if ((sis >> i) & 1) == 1 { + let input = self.get_input_stream_descriptor(i).unwrap(); + input.clear_interrupts(); + } + } + + for i in 0..oss { + if ((sis >> (i + iss)) & 1) == 1 { + let output = self.get_output_stream_descriptor(i).unwrap(); + output.clear_interrupts(); + } + } + + for i in 0..bss { + if ((sis >> (i + iss + oss)) & 1) == 1 { + let bid = self.get_bidirectional_stream_descriptor(i).unwrap(); + bid.clear_interrupts(); + } + } + } + + fn validate_path(&mut self, path: &Vec<&str>) -> bool { + log::debug!("Path: {:?}", path); + let mut it = path.iter(); + match it.next() { + Some(card_str) if (*card_str).starts_with("card") => { + match usize::from_str_radix(&(*card_str)[4..], 10) { + Ok(card_num) => { + log::debug!("Card# {}", card_num); + match it.next() { + Some(codec_str) if (*codec_str).starts_with("codec#") => { + match usize::from_str_radix(&(*codec_str)[6..], 10) { + Ok(_codec_num) => { + //let id = self.next_id.fetch_add(1, Ordering::SeqCst); + //self.handles.lock().insert(id, Handle::Disk(disk.clone(), 0)); + true + } + _ => false, + } + } + Some(pcmout_str) if (*pcmout_str).starts_with("pcmout") => { + match usize::from_str_radix(&(*pcmout_str)[6..], 10) { + Ok(pcmout_num) => { + log::debug!("pcmout {}", pcmout_num); + true + } + _ => false, + } + } + Some(pcmin_str) if (*pcmin_str).starts_with("pcmin") => { + match usize::from_str_radix(&(*pcmin_str)[6..], 10) { + Ok(pcmin_num) => { + log::debug!("pcmin {}", pcmin_num); + true + } + _ => false, + } + } + _ => false, + } + } + _ => false, + } + } + Some(cards_str) if *cards_str == "cards" => true, + _ => false, + } + } } - impl Drop for IntelHDA { - fn drop(&mut self) { - log::info!("IHDA: Deallocating IHDA driver."); - - } + fn drop(&mut self) { + log::info!("IHDA: Deallocating IHDA driver."); + } } impl SchemeBlockMut for IntelHDA { - fn open(&mut self, path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { - //let path: Vec<&str>; - /* - match str::from_utf8(_path) { - Ok(p) => { - path = p.split("/").collect(); - if !self.validate_path(&path) { - return Err(Error::new(EINVAL)); + fn open(&mut self, path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { + //let path: Vec<&str>; + /* + match str::from_utf8(_path) { + Ok(p) => { + path = p.split("/").collect(); + if !self.validate_path(&path) { + return Err(Error::new(EINVAL)); - }, - Err(_) => {return Err(Error::new(EINVAL));}, - }*/ + }, + Err(_) => {return Err(Error::new(EINVAL));}, + }*/ - // TODO: - if uid == 0 { - let handle = match path.trim_matches('/') { - //TODO: allow multiple codecs - "codec" => Handle::StrBuf(self.dump_codec(0).into_bytes(), 0), - _ => Handle::Todo, - }; - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, handle); - Ok(Some(id)) - } else { - Err(Error::new(EACCES)) - } - } + // TODO: + if uid == 0 { + let handle = match path.trim_matches('/') { + //TODO: allow multiple codecs + "codec" => Handle::StrBuf(self.dump_codec(0).into_bytes(), 0), + _ => Handle::Todo, + }; + let id = self.next_id.fetch_add(1, Ordering::SeqCst); + self.handles.lock().insert(id, handle); + Ok(Some(id)) + } else { + Err(Error::new(EACCES)) + } + } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { let mut handles = self.handles.lock(); match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::StrBuf(ref strbuf, ref mut size) => { - let mut i = 0; - while i < buf.len() && *size < strbuf.len() { - buf[i] = strbuf[*size]; - i += 1; - *size += 1; - } - Ok(Some(i)) - }, - _ => Err(Error::new(EBADF)), - } - } - - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { - let index = { - let mut handles = self.handles.lock(); - match handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::Todo => 0, - _ => return Err(Error::new(EBADF)), - } - }; - - //log::info!("Int count: {}", self.int_counter); - - self.write_to_output(index, buf) - } - - fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { - let pos = pos as usize; - let mut handles = self.handles.lock(); - match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::StrBuf(ref mut strbuf, ref mut size) => { - let len = strbuf.len() as usize; - *size = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize, - SEEK_END => cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize, - _ => return Err(Error::new(EINVAL)) - }; - Ok(Some(*size as isize)) - }, - - _ => Err(Error::new(EINVAL)), + Handle::StrBuf(ref strbuf, ref mut size) => { + let mut i = 0; + while i < buf.len() && *size < strbuf.len() { + buf[i] = strbuf[*size]; + i += 1; + *size += 1; + } + Ok(Some(i)) + } + _ => Err(Error::new(EBADF)), } - } + } + + fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + let index = { + let mut handles = self.handles.lock(); + match handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::Todo => 0, + _ => return Err(Error::new(EBADF)), + } + }; + + //log::info!("Int count: {}", self.int_counter); + + self.write_to_output(index, buf) + } + + fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { + let pos = pos as usize; + let mut handles = self.handles.lock(); + match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::StrBuf(ref mut strbuf, ref mut size) => { + let len = strbuf.len() as usize; + *size = match whence { + SEEK_SET => cmp::min(len, pos), + SEEK_CUR => { + cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize + } + SEEK_END => { + cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize + } + _ => return Err(Error::new(EINVAL)), + }; + Ok(Some(*size as isize)) + } + + _ => Err(Error::new(EINVAL)), + } + } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let mut handles = self.handles.lock(); @@ -989,8 +1051,11 @@ impl SchemeBlockMut for IntelHDA { Ok(Some(i)) } - fn close(&mut self, id: usize) -> Result> { - let mut handles = self.handles.lock(); - handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) - } + fn close(&mut self, id: usize) -> Result> { + let mut handles = self.handles.lock(); + handles + .remove(&id) + .ok_or(Error::new(EBADF)) + .and(Ok(Some(0))) + } } diff --git a/audio/ihdad/src/hda/mod.rs b/audio/ihdad/src/hda/mod.rs index 36b40d3fa3..7f01daf8ca 100644 --- a/audio/ihdad/src/hda/mod.rs +++ b/audio/ihdad/src/hda/mod.rs @@ -1,17 +1,16 @@ #![allow(dead_code)] -pub mod device; -pub mod stream; -pub mod common; -pub mod node; pub mod cmdbuff; +pub mod common; +pub mod device; +pub mod node; +pub mod stream; -pub use self::stream::*; pub use self::node::*; - +pub use self::stream::*; pub use self::cmdbuff::*; -pub use self::stream::StreamDescriptorRegs; -pub use self::stream::BufferDescriptorListEntry; -pub use self::stream::BitsPerSample; -pub use self::stream::StreamBuffer; pub use self::device::IntelHDA; +pub use self::stream::BitsPerSample; +pub use self::stream::BufferDescriptorListEntry; +pub use self::stream::StreamBuffer; +pub use self::stream::StreamDescriptorRegs; diff --git a/audio/ihdad/src/hda/node.rs b/audio/ihdad/src/hda/node.rs index 223170b2e8..06c5121fd7 100644 --- a/audio/ihdad/src/hda/node.rs +++ b/audio/ihdad/src/hda/node.rs @@ -1,108 +1,108 @@ -use std::{mem, fmt}; use super::common::*; +use std::{fmt, mem}; #[derive(Clone)] pub struct HDANode { - pub addr: WidgetAddr, + pub addr: WidgetAddr, - // 0x4 - pub subnode_count: u16, - pub subnode_start: u16, + // 0x4 + pub subnode_count: u16, + pub subnode_start: u16, - // 0x5 - pub function_group_type: u8, + // 0x5 + pub function_group_type: u8, - // 0x9 - pub capabilities: u32, + // 0x9 + pub capabilities: u32, - // 0xE - pub conn_list_len: u8, + // 0xE + pub conn_list_len: u8, - pub connections: Vec, + pub connections: Vec, - pub connection_default: u8, + pub connection_default: u8, - pub is_widget: bool, + pub is_widget: bool, - pub config_default: u32, + pub config_default: u32, } impl HDANode { - pub fn new() -> HDANode { - HDANode { - addr: (0,0), - subnode_count: 0, - subnode_start: 0, - function_group_type: 0, - capabilities: 0, - conn_list_len: 0, + pub fn new() -> HDANode { + HDANode { + addr: (0, 0), + subnode_count: 0, + subnode_start: 0, + function_group_type: 0, + capabilities: 0, + conn_list_len: 0, - config_default: 0, - is_widget: false, - connections: Vec::::new(), - connection_default: 0, - } - } + config_default: 0, + is_widget: false, + connections: Vec::::new(), + connection_default: 0, + } + } - pub fn widget_type(&self) -> HDAWidgetType { - unsafe { mem::transmute( ((self.capabilities >> 20) & 0xF) as u8 )} + pub fn widget_type(&self) -> HDAWidgetType { + unsafe { mem::transmute(((self.capabilities >> 20) & 0xF) as u8) } + } - } + pub fn device_default(&self) -> Option { + if self.widget_type() != HDAWidgetType::PinComplex { + None + } else { + Some(unsafe { mem::transmute(((self.config_default >> 20) & 0xF) as u8) }) + } + } - pub fn device_default(&self) -> Option { - if self.widget_type() != HDAWidgetType::PinComplex { - None - } else { - Some(unsafe { mem::transmute( ((self.config_default >> 20) & 0xF) as u8 )} ) - } - } + pub fn configuration_default(&self) -> ConfigurationDefault { + ConfigurationDefault::from_u32(self.config_default) + } - pub fn configuration_default(&self) -> ConfigurationDefault { - ConfigurationDefault::from_u32(self.config_default) - } - - pub fn addr(&self) -> WidgetAddr { - self.addr - } + pub fn addr(&self) -> WidgetAddr { + self.addr + } } impl fmt::Display for HDANode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.addr == (0,0) { - write!(f, "Addr: {:02X}:{:02X}, Root Node.", self.addr.0, self.addr.1) - } else if self.is_widget { - match self.widget_type() { - HDAWidgetType::PinComplex => write!( - f, - "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {}/{}: {:X?}.", - self.addr.0, - self.addr.1, - self.widget_type(), - self.device_default().unwrap(), - self.connection_default, - self.conn_list_len, - self.connections - ), - _ => write!( - f, - "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {}/{}: {:X?}.", - self.addr.0, - self.addr.1, - self.widget_type(), - self.connection_default, - self.conn_list_len, - self.connections - ), - } - } else { - write!( - f, - "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", - self.addr.0, - self.addr.1, - self.function_group_type, - self.subnode_count - ) - } + if self.addr == (0, 0) { + write!( + f, + "Addr: {:02X}:{:02X}, Root Node.", + self.addr.0, self.addr.1 + ) + } else if self.is_widget { + match self.widget_type() { + HDAWidgetType::PinComplex => write!( + f, + "Addr: {:02X}:{:02X}, Type: {:?}: {:?}, Inputs: {}/{}: {:X?}.", + self.addr.0, + self.addr.1, + self.widget_type(), + self.device_default().unwrap(), + self.connection_default, + self.conn_list_len, + self.connections + ), + _ => write!( + f, + "Addr: {:02X}:{:02X}, Type: {:?}, Inputs: {}/{}: {:X?}.", + self.addr.0, + self.addr.1, + self.widget_type(), + self.connection_default, + self.conn_list_len, + self.connections + ), + } + } else { + write!( + f, + "Addr: {:02X}:{:02X}, AFG: {}, Widget count {}.", + self.addr.0, self.addr.1, self.function_group_type, self.subnode_count + ) + } } } diff --git a/audio/ihdad/src/hda/stream.rs b/audio/ihdad/src/hda/stream.rs index 49fb4dd2f7..dfc72abc8d 100644 --- a/audio/ihdad/src/hda/stream.rs +++ b/audio/ihdad/src/hda/stream.rs @@ -1,353 +1,388 @@ use common::dma::Dma; -use common::io::{Mmio, Io}; -use syscall::PAGE_SIZE; -use syscall::error::{Error, EIO, Result}; -use std::result; +use common::io::{Io, Mmio}; use std::cmp::min; -use std::ptr::copy_nonoverlapping; use std::ptr; +use std::ptr::copy_nonoverlapping; +use std::result; +use syscall::error::{Error, Result, EIO}; +use syscall::PAGE_SIZE; extern crate syscall; pub enum BaseRate { - BR44_1, - BR48, + BR44_1, + BR48, } - pub struct SampleRate { - base: BaseRate, - mult: u16, - div: u16, + base: BaseRate, + mult: u16, + div: u16, } use self::BaseRate::{BR44_1, BR48}; -pub const SR_8: SampleRate = SampleRate {base: BR48 , mult: 1, div: 6}; -pub const SR_11_025: SampleRate = SampleRate {base: BR44_1, mult: 1, div: 4}; -pub const SR_16: SampleRate = SampleRate {base: BR48 , mult: 1, div: 3}; -pub const SR_22_05: SampleRate = SampleRate {base: BR44_1, mult: 1, div: 2}; -pub const SR_32: SampleRate = SampleRate {base: BR48 , mult: 2, div: 3}; - -pub const SR_44_1: SampleRate = SampleRate {base: BR44_1, mult: 1, div: 1}; -pub const SR_48: SampleRate = SampleRate {base: BR48 , mult: 1, div: 1}; -pub const SR_88_1: SampleRate = SampleRate {base: BR44_1, mult: 2, div: 1}; -pub const SR_96: SampleRate = SampleRate {base: BR48 , mult: 2, div: 1}; -pub const SR_176_4: SampleRate = SampleRate {base: BR44_1, mult: 4, div: 1}; -pub const SR_192: SampleRate = SampleRate {base: BR48 , mult: 4, div: 1}; - - - +pub const SR_8: SampleRate = SampleRate { + base: BR48, + mult: 1, + div: 6, +}; +pub const SR_11_025: SampleRate = SampleRate { + base: BR44_1, + mult: 1, + div: 4, +}; +pub const SR_16: SampleRate = SampleRate { + base: BR48, + mult: 1, + div: 3, +}; +pub const SR_22_05: SampleRate = SampleRate { + base: BR44_1, + mult: 1, + div: 2, +}; +pub const SR_32: SampleRate = SampleRate { + base: BR48, + mult: 2, + div: 3, +}; +pub const SR_44_1: SampleRate = SampleRate { + base: BR44_1, + mult: 1, + div: 1, +}; +pub const SR_48: SampleRate = SampleRate { + base: BR48, + mult: 1, + div: 1, +}; +pub const SR_88_1: SampleRate = SampleRate { + base: BR44_1, + mult: 2, + div: 1, +}; +pub const SR_96: SampleRate = SampleRate { + base: BR48, + mult: 2, + div: 1, +}; +pub const SR_176_4: SampleRate = SampleRate { + base: BR44_1, + mult: 4, + div: 1, +}; +pub const SR_192: SampleRate = SampleRate { + base: BR48, + mult: 4, + div: 1, +}; #[repr(u8)] pub enum BitsPerSample { - Bits8 = 0, - Bits16 = 1, - Bits20 = 2, - Bits24 = 3, - Bits32 = 4, + Bits8 = 0, + Bits16 = 1, + Bits20 = 2, + Bits24 = 3, + Bits32 = 4, } +pub fn format_to_u16(sr: &SampleRate, bps: BitsPerSample, channels: u8) -> u16 { + // 3.3.41 + let base: u16 = match sr.base { + BaseRate::BR44_1 => 1 << 14, + BaseRate::BR48 => 0, + }; -pub fn format_to_u16(sr: &SampleRate, bps: BitsPerSample, channels:u8) -> u16{ + let mult = ((sr.mult - 1) & 0x7) << 11; + let div = ((sr.div - 1) & 0x7) << 8; - // 3.3.41 + let bits = (bps as u16) << 4; - let base:u16 = match sr.base { - BaseRate::BR44_1 => { 1 << 14}, - BaseRate::BR48 => { 0 }, - }; + let chan = ((channels - 1) & 0xF) as u16; - let mult = ((sr.mult - 1) & 0x7) << 11; - - let div = ((sr.div - 1) & 0x7) << 8; - - let bits = (bps as u16) << 4; - - let chan = ((channels - 1) & 0xF) as u16; - - let val:u16 = base | mult | div | bits | chan; - - val + let val: u16 = base | mult | div | bits | chan; + val } - #[repr(packed)] pub struct StreamDescriptorRegs { - ctrl_lo: Mmio, - ctrl_hi: Mmio, - status: Mmio, - link_pos: Mmio, - buff_length: Mmio, - last_valid_index: Mmio, - resv1: Mmio, - fifo_size_: Mmio, - format: Mmio, - resv2: Mmio, - buff_desc_list_lo: Mmio, - buff_desc_list_hi: Mmio, - + ctrl_lo: Mmio, + ctrl_hi: Mmio, + status: Mmio, + link_pos: Mmio, + buff_length: Mmio, + last_valid_index: Mmio, + resv1: Mmio, + fifo_size_: Mmio, + format: Mmio, + resv2: Mmio, + buff_desc_list_lo: Mmio, + buff_desc_list_hi: Mmio, } - impl StreamDescriptorRegs { - pub fn status(&self) -> u8 { - self.status.read() - } + pub fn status(&self) -> u8 { + self.status.read() + } - pub fn set_status(&mut self, status: u8){ - self.status.write(status); - } + pub fn set_status(&mut self, status: u8) { + self.status.write(status); + } - pub fn control(&self) -> u32 { - let mut ctrl = self.ctrl_lo.read() as u32; - ctrl |= (self.ctrl_hi.read() as u32) << 16; - ctrl - } + pub fn control(&self) -> u32 { + let mut ctrl = self.ctrl_lo.read() as u32; + ctrl |= (self.ctrl_hi.read() as u32) << 16; + ctrl + } - pub fn set_control(&mut self, control:u32) { - self.ctrl_lo.write((control & 0xFFFF) as u16); - self.ctrl_hi.write(((control >> 16) & 0xFF) as u8); - } + pub fn set_control(&mut self, control: u32) { + self.ctrl_lo.write((control & 0xFFFF) as u16); + self.ctrl_hi.write(((control >> 16) & 0xFF) as u8); + } - pub fn set_pcm_format(&mut self, sr: &SampleRate, bps: BitsPerSample, channels:u8) { + pub fn set_pcm_format(&mut self, sr: &SampleRate, bps: BitsPerSample, channels: u8) { + // 3.3.41 + let val = format_to_u16(sr, bps, channels); + self.format.write(val); + } - // 3.3.41 + pub fn fifo_size(&self) -> u16 { + self.fifo_size_.read() + } - let val = format_to_u16(sr,bps,channels); - self.format.write(val); + pub fn set_cyclic_buffer_length(&mut self, length: u32) { + self.buff_length.write(length); + } - } + pub fn cyclic_buffer_length(&self) -> u32 { + self.buff_length.read() + } - pub fn fifo_size(&self) -> u16 { - self.fifo_size_.read() - } + pub fn run(&mut self) { + let val = self.control() | (1 << 1); + self.set_control(val); + } - pub fn set_cyclic_buffer_length(&mut self, length: u32) { - self.buff_length.write(length); - } + pub fn stop(&mut self) { + let val = self.control() & !(1 << 1); + self.set_control(val); + } - pub fn cyclic_buffer_length(&self) -> u32 { - self.buff_length.read() - } + pub fn stream_number(&self) -> u8 { + ((self.control() >> 20) & 0xF) as u8 + } - pub fn run(&mut self) { - let val = self.control() | (1 << 1); - self.set_control(val); - } + pub fn set_stream_number(&mut self, stream_number: u8) { + let val = (self.control() & 0x00FFFF) | (((stream_number & 0xF) as u32) << 20); + self.set_control(val); + } - pub fn stop(&mut self) { - let val = self.control() & !(1 << 1); - self.set_control(val); - } + pub fn set_address(&mut self, addr: usize) { + self.buff_desc_list_lo.write((addr & 0xFFFFFFFF) as u32); + self.buff_desc_list_hi + .write((((addr as u64) >> 32) & 0xFFFFFFFF) as u32); + } - pub fn stream_number(&self) -> u8 { - ((self.control() >> 20) & 0xF) as u8 - } + pub fn set_last_valid_index(&mut self, index: u16) { + self.last_valid_index.write(index); + } - pub fn set_stream_number(&mut self, stream_number: u8) { - let val = (self.control() & 0x00FFFF ) | (((stream_number & 0xF ) as u32) << 20); - self.set_control(val); - } + pub fn link_position(&self) -> u32 { + self.link_pos.read() + } - pub fn set_address(&mut self, addr: usize) { - self.buff_desc_list_lo.write( (addr & 0xFFFFFFFF) as u32); - self.buff_desc_list_hi.write( ( ((addr as u64) >> 32) & 0xFFFFFFFF) as u32); - } + pub fn set_interrupt_on_completion(&mut self, enable: bool) { + let mut ctrl = self.control(); + if enable { + ctrl |= 1 << 2; + } else { + ctrl &= !(1 << 2); + } + self.set_control(ctrl); + } - pub fn set_last_valid_index(&mut self, index:u16) { - self.last_valid_index.write(index); - } - - pub fn link_position(&self) -> u32 { - self.link_pos.read() - } - - pub fn set_interrupt_on_completion(&mut self, enable:bool) { - let mut ctrl = self.control(); - if enable { - ctrl |= 1 << 2; - } else { - ctrl &= !(1 << 2); - } - self.set_control(ctrl); - } - - pub fn buffer_complete(&self) -> bool { - self.status.readf(1 << 2) - } - - pub fn clear_interrupts(&mut self) { - self.status.write(0x7 << 2); - } - - // get sample size in bytes - pub fn sample_size(&self) -> usize { - let format = self.format.read(); - let chan = (format & 0xF) as usize; - let bits = ((format >> 4) & 0xF) as usize; - match bits { - 0 => 1 * (chan + 1), - 1 => 2 * (chan + 1), - _ => 4 * (chan + 1), - } - } + pub fn buffer_complete(&self) -> bool { + self.status.readf(1 << 2) + } + pub fn clear_interrupts(&mut self) { + self.status.write(0x7 << 2); + } + // get sample size in bytes + pub fn sample_size(&self) -> usize { + let format = self.format.read(); + let chan = (format & 0xF) as usize; + let bits = ((format >> 4) & 0xF) as usize; + match bits { + 0 => 1 * (chan + 1), + 1 => 2 * (chan + 1), + _ => 4 * (chan + 1), + } + } } pub struct OutputStream { - buff: StreamBuffer, + buff: StreamBuffer, - desc_regs: &'static mut StreamDescriptorRegs, + desc_regs: &'static mut StreamDescriptorRegs, } - impl OutputStream { - pub fn new(block_count: usize, block_length: usize, regs: &'static mut StreamDescriptorRegs) -> OutputStream { - OutputStream { - buff: StreamBuffer::new(block_length, block_count).unwrap(), + pub fn new( + block_count: usize, + block_length: usize, + regs: &'static mut StreamDescriptorRegs, + ) -> OutputStream { + OutputStream { + buff: StreamBuffer::new(block_length, block_count).unwrap(), - desc_regs: regs, - } - } + desc_regs: regs, + } + } - pub fn write_block(&mut self, buf: &[u8]) -> Result { - self.buff.write_block(buf) - } + pub fn write_block(&mut self, buf: &[u8]) -> Result { + self.buff.write_block(buf) + } - pub fn block_size(&self) -> usize { - self.buff.block_size() - } + pub fn block_size(&self) -> usize { + self.buff.block_size() + } - pub fn block_count(&self) -> usize { - self.buff.block_count() - } + pub fn block_count(&self) -> usize { + self.buff.block_count() + } - pub fn current_block(&self) -> usize { - self.buff.current_block() - } + pub fn current_block(&self) -> usize { + self.buff.current_block() + } - pub fn addr(&self) -> usize { - self.buff.addr() - } + pub fn addr(&self) -> usize { + self.buff.addr() + } - pub fn phys(&self) -> usize { - self.buff.phys() - } + pub fn phys(&self) -> usize { + self.buff.phys() + } } - - - #[repr(packed)] pub struct BufferDescriptorListEntry { - addr_low: Mmio, - addr_high: Mmio, - len: Mmio, - ioc_resv: Mmio, + addr_low: Mmio, + addr_high: Mmio, + len: Mmio, + ioc_resv: Mmio, } impl BufferDescriptorListEntry { - pub fn address(&self) -> u64 { - (self.addr_low.read() as u64) | - ((self.addr_high.read() as u64) << 32) - } + pub fn address(&self) -> u64 { + (self.addr_low.read() as u64) | ((self.addr_high.read() as u64) << 32) + } - pub fn set_address(&mut self, addr: u64) { - self.addr_low.write(addr as u32); - self.addr_high.write((addr >> 32) as u32); - } + pub fn set_address(&mut self, addr: u64) { + self.addr_low.write(addr as u32); + self.addr_high.write((addr >> 32) as u32); + } - pub fn length(&self) -> u32 { - self.len.read() - } + pub fn length(&self) -> u32 { + self.len.read() + } - pub fn set_length(&mut self, length: u32) { - self.len.write(length) - } + pub fn set_length(&mut self, length: u32) { + self.len.write(length) + } - pub fn interrupt_on_completion(&self) -> bool { - (self.ioc_resv.read() & 0x1) == 0x1 - } + pub fn interrupt_on_completion(&self) -> bool { + (self.ioc_resv.read() & 0x1) == 0x1 + } - pub fn set_interrupt_on_complete(&mut self, ioc: bool) { - self.ioc_resv.writef(1, ioc); - } + pub fn set_interrupt_on_complete(&mut self, ioc: bool) { + self.ioc_resv.writef(1, ioc); + } } pub struct StreamBuffer { - mem: Dma<[u8]>, + mem: Dma<[u8]>, - block_cnt: usize, - block_len: usize, + block_cnt: usize, + block_len: usize, - cur_pos: usize, + cur_pos: usize, } impl StreamBuffer { - pub fn new(block_length: usize, block_count: usize) -> result::Result { - let page_aligned_size = (block_length * block_count).next_multiple_of(PAGE_SIZE); - let mem = unsafe { Dma::zeroed_slice(page_aligned_size).map_err(|_| "Could not allocate physical memory for buffer.")?.assume_init() }; + pub fn new( + block_length: usize, + block_count: usize, + ) -> result::Result { + let page_aligned_size = (block_length * block_count).next_multiple_of(PAGE_SIZE); + let mem = unsafe { + Dma::zeroed_slice(page_aligned_size) + .map_err(|_| "Could not allocate physical memory for buffer.")? + .assume_init() + }; - Ok(StreamBuffer { - mem, - block_len: block_length, - block_cnt: block_count, - cur_pos: 0, - }) - } + Ok(StreamBuffer { + mem, + block_len: block_length, + block_cnt: block_count, + cur_pos: 0, + }) + } - pub fn length(&self) -> usize { - self.block_len * self.block_cnt - } + pub fn length(&self) -> usize { + self.block_len * self.block_cnt + } - pub fn addr(&self) -> usize { - self.mem.as_ptr() as usize - } + pub fn addr(&self) -> usize { + self.mem.as_ptr() as usize + } - pub fn phys(&self) -> usize { - self.mem.physical() - } + pub fn phys(&self) -> usize { + self.mem.physical() + } - pub fn block_size(&self) -> usize { - self.block_len - } + pub fn block_size(&self) -> usize { + self.block_len + } - pub fn block_count(&self) -> usize { - self.block_cnt - } + pub fn block_count(&self) -> usize { + self.block_cnt + } - pub fn current_block(&self) -> usize { - self.cur_pos - } + pub fn current_block(&self) -> usize { + self.cur_pos + } - pub fn write_block(&mut self, buf: &[u8]) -> Result { - if buf.len() != self.block_size() { - return Err(Error::new(EIO)) - } - let len = min(self.block_size(), buf.len()); + pub fn write_block(&mut self, buf: &[u8]) -> Result { + if buf.len() != self.block_size() { + return Err(Error::new(EIO)); + } + let len = min(self.block_size(), buf.len()); + //log::trace!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}", self.phys(), self.addr(), self.current_block() * self.block_size(), len); + unsafe { + copy_nonoverlapping( + buf.as_ptr(), + (self.addr() + self.current_block() * self.block_size()) as *mut u8, + len, + ); + } - //log::trace!("Phys: {:X} Virt: {:X} Offset: {:X} Len: {:X}", self.phys(), self.addr(), self.current_block() * self.block_size(), len); - unsafe { - copy_nonoverlapping(buf.as_ptr(), (self.addr() + self.current_block() * self.block_size()) as * mut u8, len); - } + self.cur_pos += 1; + self.cur_pos %= self.block_count(); - self.cur_pos += 1; - self.cur_pos %= self.block_count(); - - Ok(len) - - } + Ok(len) + } } impl Drop for StreamBuffer { - fn drop(&mut self) { - log::debug!("IHDA: Deallocating buffer."); - } + fn drop(&mut self) { + log::debug!("IHDA: Deallocating buffer."); + } } diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 9fd2c779fb..e79ee9a18f 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -2,46 +2,53 @@ #![feature(int_roundings)] extern crate bitflags; +extern crate event; extern crate spin; extern crate syscall; -extern crate event; -use std::usize; -use std::fs::File; -use std::io::{ErrorKind, Read, Write, Result}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use libredox::flag; -use syscall::{Packet, SchemeBlockMut, EventFlags}; use std::cell::RefCell; +use std::fs::File; +use std::io::{ErrorKind, Read, Result, Write}; +use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; +use std::usize; +use syscall::{EventFlags, Packet, SchemeBlockMut}; use event::{user_data, EventQueue}; -use pcid_interface::{MsiSetFeatureInfo, PciFunctionHandle, PciFeature, PciFeatureInfo, SetFeatureInfo}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; +use pcid_interface::{ + MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, +}; pub mod hda; /* - VEND:PROD - Virtualbox 8086:2668 - QEMU ICH9 8086:293E - 82801H ICH8 8086:284B - */ +VEND:PROD +Virtualbox 8086:2668 +QEMU ICH9 8086:293E +82801H ICH8 8086:284B +*/ #[cfg(target_arch = "x86_64")] fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.config(); - let all_pci_features = pcid_handle.fetch_all_features().expect("ihdad: failed to fetch pci features"); + let all_pci_features = pcid_handle + .fetch_all_features() + .expect("ihdad: failed to fetch pci features"); log::debug!("PCI FEATURES: {:?}", all_pci_features); let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); if has_msi && !has_msix { - let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("ihdad: failed to retrieve the MSI capability structure from pcid") { + let capability = match pcid_handle + .feature_info(PciFeature::Msi) + .expect("ihdad: failed to retrieve the MSI capability structure from pcid") + { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), }; @@ -51,16 +58,21 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. let destination_id = read_bsp_apic_id().expect("ihdad: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = allocate_single_interrupt_vector_for_msi(destination_id); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); let set_feature_info = MsiSetFeatureInfo { multi_message_enable: Some(0), message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("ihdad: failed to set feature info"); + pcid_handle + .set_feature_info(SetFeatureInfo::Msi(set_feature_info)) + .expect("ihdad: failed to set feature info"); - pcid_handle.enable_feature(PciFeature::Msi).expect("ihdad: failed to enable MSI"); + pcid_handle + .enable_feature(PciFeature::Msi) + .expect("ihdad: failed to enable MSI"); log::debug!("Enabled MSI"); interrupt_handle @@ -96,7 +108,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::LevelFilter::Info, ); - let mut pcid_handle = PciFunctionHandle::connect_default().expect("ihdad: failed to setup channel to pcid"); + let mut pcid_handle = + PciFunctionHandle::connect_default().expect("ihdad: failed to setup channel to pcid"); let pci_config = pcid_handle.config(); @@ -105,7 +118,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::info!(" + IHDA {}", pci_config.func.display()); - let address = unsafe { pcid_handle.map_bar(0).expect("ihdad") }.ptr.as_ptr() as usize; + let address = unsafe { pcid_handle.map_bar(0).expect("ihdad") } + .ptr + .as_ptr() as usize; //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); @@ -121,13 +136,29 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - let mut event_queue = EventQueue::::new().expect("ihdad: Could not create event queue."); - let mut device = unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") }; - let socket_fd = libredox::call::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("ihdad: failed to create hda scheme"); + let mut event_queue = + EventQueue::::new().expect("ihdad: Could not create event queue."); + let mut device = unsafe { + hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") + }; + let socket_fd = libredox::call::open( + ":audiohw", + flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, + 0, + ) + .expect("ihdad: failed to create hda scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; - event_queue.subscribe(socket_fd, Source::Scheme, event::EventFlags::READ).unwrap(); - event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); + event_queue + .subscribe(socket_fd, Source::Scheme, event::EventFlags::READ) + .unwrap(); + event_queue + .subscribe( + irq_file.as_raw_fd() as usize, + Source::Irq, + event::EventFlags::READ, + ) + .unwrap(); daemon.ready().expect("ihdad: failed to signal readiness"); @@ -137,7 +168,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let all = [Source::Irq, Source::Scheme]; - 'events: for event in all.into_iter().chain(event_queue.map(|e| e.expect("failed to get next event").user_data)) { + 'events: for event in all + .into_iter() + .chain(event_queue.map(|e| e.expect("failed to get next event").user_data)) + { match event { Source::Irq => { let mut irq = [0; 8]; @@ -158,11 +192,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ } } Source::Scheme => { @@ -171,10 +205,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { match socket.read(&mut packet) { Ok(0) => break 'events, Ok(_) => (), - Err(err) => if err.kind() == ErrorKind::WouldBlock { - break; - } else { - panic!("ihdad: failed to read from socket: {err}"); + Err(err) => { + if err.kind() == ErrorKind::WouldBlock { + break; + } else { + panic!("ihdad: failed to read from socket: {err}"); + } } } @@ -187,11 +223,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } /* - let next_read = device.borrow().next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ + let next_read = device.borrow().next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ } } } diff --git a/audio/pcspkrd/src/main.rs b/audio/pcspkrd/src/main.rs index 75957745c3..d021257710 100644 --- a/audio/pcspkrd/src/main.rs +++ b/audio/pcspkrd/src/main.rs @@ -41,5 +41,6 @@ fn main() { .write(&packet) .expect("pcspkrd: failed to write responses to pcspkr scheme"); } - }).expect("pcspkrd: failed to daemonize"); + }) + .expect("pcspkrd: failed to daemonize"); } diff --git a/audio/sb16d/src/device.rs b/audio/sb16d/src/device.rs index 47cf231f5a..36a6e94b8c 100644 --- a/audio/sb16d/src/device.rs +++ b/audio/sb16d/src/device.rs @@ -1,12 +1,12 @@ #![allow(dead_code)] -use std::{thread, time}; use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::{thread, time}; -use common::io::{Pio, Io, ReadOnly, WriteOnly}; +use common::io::{Io, Pio, ReadOnly, WriteOnly}; -use syscall::error::{Error, EACCES, EBADF, Result, ENODEV}; +use syscall::error::{Error, Result, EACCES, EBADF, ENODEV}; use syscall::scheme::SchemeBlockMut; use spin::Mutex; @@ -68,7 +68,7 @@ impl Sb16 { fn dsp_read(&mut self) -> Result { // Bit 7 must be 1 before data can be sent - while ! self.dsp_read_status.readf(1 << 7) { + while !self.dsp_read_status.readf(1 << 7) { //TODO: timeout! std::thread::yield_now(); } @@ -212,6 +212,9 @@ impl SchemeBlockMut for Sb16 { fn close(&mut self, id: usize) -> Result> { let mut handles = self.handles.lock(); - handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + handles + .remove(&id) + .ok_or(Error::new(EBADF)) + .and(Ok(Some(0))) } } diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index ff7333a626..dfa863a7e1 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -1,8 +1,8 @@ //#![deny(warnings)] -use std::{env, usize}; use libredox::errno::{EAGAIN, EWOULDBLOCK}; use libredox::{flag, Fd}; +use std::{env, usize}; use syscall::{Packet, SchemeBlockMut}; use event::{user_data, EventQueue}; @@ -29,12 +29,19 @@ fn main() { common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights"); - let mut device = unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") }; - let socket = Fd::open(":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("sb16d: failed to create hda scheme"); + let mut device = + unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") }; + let socket = Fd::open( + ":audiohw", + flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, + 0, + ) + .expect("sb16d: failed to create hda scheme"); //TODO: error on multiple IRQs? let irq_file = match device.irqs.first() { - Some(irq) => Fd::open(&format!("/scheme/irq/{}", irq), flag::O_RDWR, 0).expect("sb16d: failed to open IRQ file"), + Some(irq) => Fd::open(&format!("/scheme/irq/{}", irq), flag::O_RDWR, 0) + .expect("sb16d: failed to open IRQ file"), None => panic!("sb16d: no IRQs found"), }; user_data! { @@ -44,9 +51,14 @@ fn main() { } } - let event_queue = EventQueue::::new().expect("sb16d: Could not create event queue."); - event_queue.subscribe(irq_file.raw(), Source::Irq, event::EventFlags::READ).unwrap(); - event_queue.subscribe(socket.raw(), Source::Scheme, event::EventFlags::READ).unwrap(); + let event_queue = + EventQueue::::new().expect("sb16d: Could not create event queue."); + event_queue + .subscribe(irq_file.raw(), Source::Irq, event::EventFlags::READ) + .unwrap(); + event_queue + .subscribe(socket.raw(), Source::Scheme, event::EventFlags::READ) + .unwrap(); daemon.ready().expect("sb16d: failed to signal readiness"); @@ -56,7 +68,10 @@ fn main() { let all = [Source::Irq, Source::Scheme]; - 'events: for event in all.into_iter().chain(event_queue.map(|e| e.expect("sb16d: failed to get next event").user_data)) { + 'events: for event in all + .into_iter() + .chain(event_queue.map(|e| e.expect("sb16d: failed to get next event").user_data)) + { match event { Source::Irq => { let mut irq = [0; 8]; @@ -70,7 +85,9 @@ fn main() { if let Some(a) = device.handle(&mut todo[i]) { let mut packet = todo.remove(i); packet.a = a; - socket.write(&packet).expect("sb16d: failed to write to socket"); + socket + .write(&packet) + .expect("sb16d: failed to write to socket"); } else { i += 1; } @@ -84,30 +101,33 @@ fn main() { */ } } - Source::Scheme => { - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => break 'events, - Ok(_) => (), - Err(err) => if err.errno() == EWOULDBLOCK || err.errno() == EAGAIN { + Source::Scheme => loop { + let mut packet = Packet::default(); + match socket.read(&mut packet) { + Ok(0) => break 'events, + Ok(_) => (), + Err(err) => { + if err.errno() == EWOULDBLOCK || err.errno() == EAGAIN { break; } else { panic!("sb16d: failed to read from scheme socket"); } } - - if let Some(a) = device.handle(&mut packet) { - packet.a = a; - socket.write(&packet).expect("sb16d: failed to write to scheme socket"); - } else { - todo.push(packet); - } } - } + + if let Some(a) = device.handle(&mut packet) { + packet.a = a; + socket + .write(&packet) + .expect("sb16d: failed to write to scheme socket"); + } else { + todo.push(packet); + } + }, } } std::process::exit(0); - }).expect("sb16d: failed to daemonize"); + }) + .expect("sb16d: failed to daemonize"); } diff --git a/common/src/io/mmio.rs b/common/src/io/mmio.rs index c20cf52716..6b21b66ed5 100644 --- a/common/src/io/mmio.rs +++ b/common/src/io/mmio.rs @@ -35,7 +35,11 @@ impl Mmio { #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] impl Io for Mmio where - T: Copy + PartialEq + core::ops::BitAnd + core::ops::BitOr + core::ops::Not, + T: Copy + + PartialEq + + core::ops::BitAnd + + core::ops::BitOr + + core::ops::Not, { type Value = T; diff --git a/net/alxd/src/device/mod.rs b/net/alxd/src/device/mod.rs index baac6fc89d..64415b1887 100644 --- a/net/alxd/src/device/mod.rs +++ b/net/alxd/src/device/mod.rs @@ -1,9 +1,9 @@ -use std::{ptr, thread, time}; use std::convert::TryInto; +use std::{ptr, thread, time}; -use syscall::error::{Error, EACCES, EINVAL, EIO, EWOULDBLOCK, Result}; -use syscall::flag::{EventFlags, O_NONBLOCK}; use common::io::{Io, Mmio}; +use syscall::error::{Error, Result, EACCES, EINVAL, EIO, EWOULDBLOCK}; +use syscall::flag::{EventFlags, O_NONBLOCK}; use syscall::scheme; use common::dma::Dma; @@ -48,61 +48,48 @@ const CAP_MTQ: u32 = 1 << 8; /* support Multi-RX-Q */ const CAP_MRQ: u32 = 1 << 9; -const ISR_MISC: u32 = - ISR_PCIE_LNKDOWN | - ISR_DMAW | - ISR_DMAR | - ISR_SMB | - ISR_MANU | - ISR_TIMER; +const ISR_MISC: u32 = ISR_PCIE_LNKDOWN | ISR_DMAW | ISR_DMAR | ISR_SMB | ISR_MANU | ISR_TIMER; -const ISR_FATAL: u32 = - ISR_PCIE_LNKDOWN | - ISR_DMAW | - ISR_DMAR; +const ISR_FATAL: u32 = ISR_PCIE_LNKDOWN | ISR_DMAW | ISR_DMAR; -const ISR_ALERT: u32 = - ISR_RXF_OV | - ISR_TXF_UR | - ISR_RFD_UR; +const ISR_ALERT: u32 = ISR_RXF_OV | ISR_TXF_UR | ISR_RFD_UR; -const ISR_ALL_QUEUES: u32 = - ISR_TX_Q0 | - ISR_TX_Q1 | - ISR_TX_Q2 | - ISR_TX_Q3 | - ISR_RX_Q0 | - ISR_RX_Q1 | - ISR_RX_Q2 | - ISR_RX_Q3 | - ISR_RX_Q4 | - ISR_RX_Q5 | - ISR_RX_Q6 | - ISR_RX_Q7; +const ISR_ALL_QUEUES: u32 = ISR_TX_Q0 + | ISR_TX_Q1 + | ISR_TX_Q2 + | ISR_TX_Q3 + | ISR_RX_Q0 + | ISR_RX_Q1 + | ISR_RX_Q2 + | ISR_RX_Q3 + | ISR_RX_Q4 + | ISR_RX_Q5 + | ISR_RX_Q6 + | ISR_RX_Q7; -const PCI_COMMAND_IO: u16 = 0x1; /* Enable response in I/O space */ -const PCI_COMMAND_MEMORY: u16 = 0x2; /* Enable response in Memory space */ -const PCI_COMMAND_MASTER: u16 = 0x4; /* Enable bus mastering */ -const PCI_COMMAND_SPECIAL: u16 = 0x8; /* Enable response to special cycles */ -const PCI_COMMAND_INVALIDATE: u16 = 0x10; /* Use memory write and invalidate */ -const PCI_COMMAND_VGA_PALETTE: u16 = 0x20; /* Enable palette snooping */ -const PCI_COMMAND_PARITY: u16 = 0x40; /* Enable parity checking */ -const PCI_COMMAND_WAIT: u16 = 0x80; /* Enable address/data stepping */ -const PCI_COMMAND_SERR: u16 = 0x100; /* Enable SERR */ -const PCI_COMMAND_FAST_BACK: u16 = 0x200; /* Enable back-to-back writes */ -const PCI_COMMAND_INTX_DISABLE: u16 = 0x400;/* INTx Emulation Disable */ +const PCI_COMMAND_IO: u16 = 0x1; /* Enable response in I/O space */ +const PCI_COMMAND_MEMORY: u16 = 0x2; /* Enable response in Memory space */ +const PCI_COMMAND_MASTER: u16 = 0x4; /* Enable bus mastering */ +const PCI_COMMAND_SPECIAL: u16 = 0x8; /* Enable response to special cycles */ +const PCI_COMMAND_INVALIDATE: u16 = 0x10; /* Use memory write and invalidate */ +const PCI_COMMAND_VGA_PALETTE: u16 = 0x20; /* Enable palette snooping */ +const PCI_COMMAND_PARITY: u16 = 0x40; /* Enable parity checking */ +const PCI_COMMAND_WAIT: u16 = 0x80; /* Enable address/data stepping */ +const PCI_COMMAND_SERR: u16 = 0x100; /* Enable SERR */ +const PCI_COMMAND_FAST_BACK: u16 = 0x200; /* Enable back-to-back writes */ +const PCI_COMMAND_INTX_DISABLE: u16 = 0x400; /* INTx Emulation Disable */ /// MII basic mode control register const MII_BMCR: u16 = 0x00; - const BMCR_FULLDPLX: u16 = 0x0100; - const BMCR_ANRESTART: u16 = 0x0200; - const BMCR_ANENABLE: u16 = 0x1000; - const BMCR_SPEED100: u16 = 0x2000; - const BMCR_RESET: u16 = 0x8000; +const BMCR_FULLDPLX: u16 = 0x0100; +const BMCR_ANRESTART: u16 = 0x0200; +const BMCR_ANENABLE: u16 = 0x1000; +const BMCR_SPEED100: u16 = 0x2000; +const BMCR_RESET: u16 = 0x8000; /// MII basic mode status register const MII_BMSR: u16 = 0x01; - const BMSR_LSTATUS: u16 = 0x0004; +const BMSR_LSTATUS: u16 = 0x0004; /// MII advertisement register const MII_ADVERTISE: u16 = 0x04; @@ -122,46 +109,46 @@ const ADVERTISED_Autoneg: u32 = 1 << 6; const ADVERTISED_Pause: u32 = 1 << 13; const ADVERTISED_Asym_Pause: u32 = 1 << 14; -const ADVERTISE_CSMA: u32 = 0x0001; /* Only selector supported */ -const ADVERTISE_10HALF: u32 = 0x0020; /* Try for 10mbps half-duplex */ -const ADVERTISE_1000XFULL: u32 = 0x0020; /* Try for 1000BASE-X full-duplex */ -const ADVERTISE_10FULL: u32 = 0x0040; /* Try for 10mbps full-duplex */ -const ADVERTISE_1000XHALF: u32 = 0x0040; /* Try for 1000BASE-X half-duplex */ -const ADVERTISE_100HALF: u32 = 0x0080; /* Try for 100mbps half-duplex */ -const ADVERTISE_1000XPAUSE: u32 = 0x0080; /* Try for 1000BASE-X pause */ -const ADVERTISE_100FULL: u32 = 0x0100; /* Try for 100mbps full-duplex */ -const ADVERTISE_1000XPSE_ASYM: u32 = 0x0100; /* Try for 1000BASE-X asym pause */ -const ADVERTISE_100BASE4: u32 = 0x0200; /* Try for 100mbps 4k packets */ -const ADVERTISE_PAUSE_CAP: u32 = 0x0400; /* Try for pause */ -const ADVERTISE_PAUSE_ASYM: u32 = 0x0800; /* Try for asymetric pause */ +const ADVERTISE_CSMA: u32 = 0x0001; /* Only selector supported */ +const ADVERTISE_10HALF: u32 = 0x0020; /* Try for 10mbps half-duplex */ +const ADVERTISE_1000XFULL: u32 = 0x0020; /* Try for 1000BASE-X full-duplex */ +const ADVERTISE_10FULL: u32 = 0x0040; /* Try for 10mbps full-duplex */ +const ADVERTISE_1000XHALF: u32 = 0x0040; /* Try for 1000BASE-X half-duplex */ +const ADVERTISE_100HALF: u32 = 0x0080; /* Try for 100mbps half-duplex */ +const ADVERTISE_1000XPAUSE: u32 = 0x0080; /* Try for 1000BASE-X pause */ +const ADVERTISE_100FULL: u32 = 0x0100; /* Try for 100mbps full-duplex */ +const ADVERTISE_1000XPSE_ASYM: u32 = 0x0100; /* Try for 1000BASE-X asym pause */ +const ADVERTISE_100BASE4: u32 = 0x0200; /* Try for 100mbps 4k packets */ +const ADVERTISE_PAUSE_CAP: u32 = 0x0400; /* Try for pause */ +const ADVERTISE_PAUSE_ASYM: u32 = 0x0800; /* Try for asymetric pause */ const ADVERTISE_1000HALF: u32 = 0x0100; const ADVERTISE_1000FULL: u32 = 0x0200; macro_rules! FIELD_GETX { - ($x:expr, $name:ident) => (( + ($x:expr, $name:ident) => { ((($x) >> concat_idents!($name, _SHIFT)) & concat_idents!($name, _MASK)) - )) + }; } macro_rules! FIELDX { - ($name:ident, $v:expr) => (( - ((($v) as u32) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT) - )) + ($name:ident, $v:expr) => { + (((($v) as u32) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT)) + }; } macro_rules! FIELD_SETS { ($x:expr, $name:ident, $v:expr) => {{ ($x) = (($x) & !(concat_idents!($name, _MASK) << concat_idents!($name, _SHIFT))) - | (((($v) as u16) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT)) - }} + | (((($v) as u16) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT)) + }}; } macro_rules! FIELD_SET32 { ($x:expr, $name:ident, $v:expr) => {{ ($x) = (($x) & !(concat_idents!($name, _MASK) << concat_idents!($name, _SHIFT))) - | (((($v) as u32) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT)) - }} + | (((($v) as u32) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT)) + }}; } fn udelay(micros: u32) { @@ -316,22 +303,22 @@ impl Alx { link_speed: 0, link_duplex: 0, - adv_cfg: ADVERTISED_Autoneg | - ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full | - ADVERTISED_100baseT_Full | - ADVERTISED_100baseT_Half | - ADVERTISED_1000baseT_Full, + adv_cfg: ADVERTISED_Autoneg + | ADVERTISED_10baseT_Half + | ADVERTISED_10baseT_Full + | ADVERTISED_100baseT_Full + | ADVERTISED_100baseT_Half + | ADVERTISED_1000baseT_Full, flowctrl: FC_ANEG | FC_RX | FC_TX, - rx_ctrl: MAC_CTRL_WOLSPED_SWEN | - MAC_CTRL_MHASH_ALG_HI5B | - MAC_CTRL_BRD_EN | - MAC_CTRL_PCRCE | - MAC_CTRL_CRCE | - MAC_CTRL_RXFC_EN | - MAC_CTRL_TXFC_EN | - FIELDX!(MAC_CTRL_PRMBLEN, 7), + rx_ctrl: MAC_CTRL_WOLSPED_SWEN + | MAC_CTRL_MHASH_ALG_HI5B + | MAC_CTRL_BRD_EN + | MAC_CTRL_PCRCE + | MAC_CTRL_CRCE + | MAC_CTRL_RXFC_EN + | MAC_CTRL_TXFC_EN + | FIELDX!(MAC_CTRL_PRMBLEN, 7), lnk_patch: false, hib_patch: false, @@ -358,72 +345,75 @@ impl Alx { } unsafe fn handle_intr_misc(&mut self, intr: u32) -> bool { - if (intr & ISR_FATAL > 0) { + if (intr & ISR_FATAL > 0) { println!("intr-fatal: {:X}", intr); self.flag |= FLAG_TASK_RESET; self.task(); - return true; - } - - if (intr & ISR_ALERT > 0) { - println!("interrupt alert: {:X}", intr); + return true; } - if (intr & ISR_SMB > 0) { - self.flag |= FLAG_TASK_UPDATE_SMB; - self.task(); - } + if (intr & ISR_ALERT > 0) { + println!("interrupt alert: {:X}", intr); + } - if (intr & ISR_PHY > 0) { - /* suppress PHY interrupt, because the source - * is from PHY internal. only the internal status - * is cleared, the interrupt status could be cleared. - */ - self.imask &= !ISR_PHY; + if (intr & ISR_SMB > 0) { + self.flag |= FLAG_TASK_UPDATE_SMB; + self.task(); + } + + if (intr & ISR_PHY > 0) { + /* suppress PHY interrupt, because the source + * is from PHY internal. only the internal status + * is cleared, the interrupt status could be cleared. + */ + self.imask &= !ISR_PHY; let imask = self.imask; self.write(IMR, imask); self.flag |= FLAG_TASK_CHK_LINK; self.task(); - } + } - return false; + return false; } unsafe fn intr_1(&mut self, mut intr: u32) -> bool { - /* ACK interrupt */ - println!("ACK interrupt: {:X}", intr | ISR_DIS); - self.write(ISR, intr | ISR_DIS); - intr &= self.imask; + /* ACK interrupt */ + println!("ACK interrupt: {:X}", intr | ISR_DIS); + self.write(ISR, intr | ISR_DIS); + intr &= self.imask; - if (self.handle_intr_misc(intr)) { - return true; + if (self.handle_intr_misc(intr)) { + return true; } - if (intr & (ISR_TX_Q0 | ISR_RX_Q0) > 0) { + if (intr & (ISR_TX_Q0 | ISR_RX_Q0) > 0) { println!("TX | RX"); - //TODO: napi_schedule(&adpt->qnapi[0]->napi); - /* mask rx/tx interrupt, enable them when napi complete */ - self.imask &= !ISR_ALL_QUEUES; + //TODO: napi_schedule(&adpt->qnapi[0]->napi); + /* mask rx/tx interrupt, enable them when napi complete */ + self.imask &= !ISR_ALL_QUEUES; let imask = self.imask; - self.write(IMR, imask); - } + self.write(IMR, imask); + } - self.write(ISR, 0); + self.write(ISR, 0); - return true; + return true; } pub unsafe fn intr_legacy(&mut self) -> bool { - /* read interrupt status */ - let intr = self.read(ISR); - if (intr & ISR_DIS > 0 || intr & self.imask == 0) { - let mask = self.read(IMR); - println!("seems a wild interrupt, intr={:X}, imask={:X}, mask={:X}", intr, self.imask, mask); + /* read interrupt status */ + let intr = self.read(ISR); + if (intr & ISR_DIS > 0 || intr & self.imask == 0) { + let mask = self.read(IMR); + println!( + "seems a wild interrupt, intr={:X}, imask={:X}, mask={:X}", + intr, self.imask, mask + ); - return false; - } + return false; + } - return self.intr_1(intr); + return self.intr_1(intr); } pub fn next_read(&self) -> usize { @@ -459,46 +449,46 @@ impl Alx { unsafe fn wait_mdio_idle(&mut self) -> bool { let mut val: u32; - let mut i: u32 = 0; + let mut i: u32 = 0; - while (i < MDIO_MAX_AC_TO) { - val = self.read(MDIO); - if (val & MDIO_BUSY == 0) { - break; + while (i < MDIO_MAX_AC_TO) { + val = self.read(MDIO); + if (val & MDIO_BUSY == 0) { + break; } - udelay(10); + udelay(10); i += 1; - } - return i != MDIO_MAX_AC_TO; + } + return i != MDIO_MAX_AC_TO; } unsafe fn stop_phy_polling(&mut self) { if (!self.is_fpga) { - return; + return; } - self.write(MDIO, 0); - self.wait_mdio_idle(); + self.write(MDIO, 0); + self.wait_mdio_idle(); } unsafe fn start_phy_polling(&mut self, clk_sel: u16) { let mut val: u32; - if (!self.is_fpga) { - return; + if (!self.is_fpga) { + return; } - val = MDIO_SPRES_PRMBL | - FIELDX!(MDIO_CLK_SEL, clk_sel) | - FIELDX!(MDIO_REG, 1) | - MDIO_START | - MDIO_OP_READ; - self.write(MDIO, val); - self.wait_mdio_idle(); - val |= MDIO_AUTO_POLLING; - val &= !MDIO_START; - self.write(MDIO, val); - udelay(30); + val = MDIO_SPRES_PRMBL + | FIELDX!(MDIO_CLK_SEL, clk_sel) + | FIELDX!(MDIO_REG, 1) + | MDIO_START + | MDIO_OP_READ; + self.write(MDIO, val); + self.wait_mdio_idle(); + val |= MDIO_AUTO_POLLING; + val &= !MDIO_START; + self.write(MDIO, val); + udelay(30); } unsafe fn read_phy_core(&mut self, ext: bool, dev: u8, reg: u16, phy_data: &mut u16) -> usize { @@ -506,43 +496,46 @@ impl Alx { let clk_sel: u16; let err: usize; - self.stop_phy_polling(); + self.stop_phy_polling(); - *phy_data = 0; + *phy_data = 0; - /* use slow clock when it's in hibernation status */ - clk_sel = if !self.link_up { MDIO_CLK_SEL_25MD128 } else { MDIO_CLK_SEL_25MD4 }; - - if (ext) { - val = FIELDX!(MDIO_EXTN_DEVAD, dev) | - FIELDX!(MDIO_EXTN_REG, reg); - self.write(MDIO_EXTN, val); - - val = MDIO_SPRES_PRMBL | - FIELDX!(MDIO_CLK_SEL, clk_sel) | - MDIO_START | - MDIO_MODE_EXT | - MDIO_OP_READ; - } else { - val = MDIO_SPRES_PRMBL | - FIELDX!(MDIO_CLK_SEL, clk_sel) | - FIELDX!(MDIO_REG, reg) | - MDIO_START | - MDIO_OP_READ; - } - self.write(MDIO, val); - - if (! self.wait_mdio_idle()) { - err = ERR_MIIBUSY; + /* use slow clock when it's in hibernation status */ + clk_sel = if !self.link_up { + MDIO_CLK_SEL_25MD128 } else { - val = self.read(MDIO); - *phy_data = FIELD_GETX!(val, MDIO_DATA) as u16; - err = 0; - } + MDIO_CLK_SEL_25MD4 + }; - self.start_phy_polling(clk_sel); + if (ext) { + val = FIELDX!(MDIO_EXTN_DEVAD, dev) | FIELDX!(MDIO_EXTN_REG, reg); + self.write(MDIO_EXTN, val); - return err; + val = MDIO_SPRES_PRMBL + | FIELDX!(MDIO_CLK_SEL, clk_sel) + | MDIO_START + | MDIO_MODE_EXT + | MDIO_OP_READ; + } else { + val = MDIO_SPRES_PRMBL + | FIELDX!(MDIO_CLK_SEL, clk_sel) + | FIELDX!(MDIO_REG, reg) + | MDIO_START + | MDIO_OP_READ; + } + self.write(MDIO, val); + + if (!self.wait_mdio_idle()) { + err = ERR_MIIBUSY; + } else { + val = self.read(MDIO); + *phy_data = FIELD_GETX!(val, MDIO_DATA) as u16; + err = 0; + } + + self.start_phy_polling(clk_sel); + + return err; } unsafe fn write_phy_core(&mut self, ext: bool, dev: u8, reg: u16, phy_data: u16) -> usize { @@ -550,41 +543,44 @@ impl Alx { let clk_sel: u16; let mut err: usize = 0; - self.stop_phy_polling(); + self.stop_phy_polling(); - /* use slow clock when it's in hibernation status */ - clk_sel = if ! self.link_up { MDIO_CLK_SEL_25MD128 } else { MDIO_CLK_SEL_25MD4 }; + /* use slow clock when it's in hibernation status */ + clk_sel = if !self.link_up { + MDIO_CLK_SEL_25MD128 + } else { + MDIO_CLK_SEL_25MD4 + }; - if (ext) { - val = FIELDX!(MDIO_EXTN_DEVAD, dev) | - FIELDX!(MDIO_EXTN_REG, reg); - self.write(MDIO_EXTN, val); + if (ext) { + val = FIELDX!(MDIO_EXTN_DEVAD, dev) | FIELDX!(MDIO_EXTN_REG, reg); + self.write(MDIO_EXTN, val); - val = MDIO_SPRES_PRMBL | - FIELDX!(MDIO_CLK_SEL, clk_sel) | - FIELDX!(MDIO_DATA, phy_data) | - MDIO_START | - MDIO_MODE_EXT; - } else { - val = MDIO_SPRES_PRMBL | - FIELDX!(MDIO_CLK_SEL, clk_sel) | - FIELDX!(MDIO_REG, reg) | - FIELDX!(MDIO_DATA, phy_data) | - MDIO_START; - } - self.write(MDIO, val); + val = MDIO_SPRES_PRMBL + | FIELDX!(MDIO_CLK_SEL, clk_sel) + | FIELDX!(MDIO_DATA, phy_data) + | MDIO_START + | MDIO_MODE_EXT; + } else { + val = MDIO_SPRES_PRMBL + | FIELDX!(MDIO_CLK_SEL, clk_sel) + | FIELDX!(MDIO_REG, reg) + | FIELDX!(MDIO_DATA, phy_data) + | MDIO_START; + } + self.write(MDIO, val); - if ! self.wait_mdio_idle() { - err = ERR_MIIBUSY; + if !self.wait_mdio_idle() { + err = ERR_MIIBUSY; } - self.start_phy_polling(clk_sel); + self.start_phy_polling(clk_sel); - return err; + return err; } unsafe fn read_phy_reg(&mut self, reg: u16, phy_data: &mut u16) -> usize { - self.read_phy_core(false, 0, reg, phy_data) + self.read_phy_core(false, 0, reg, phy_data) } unsafe fn write_phy_reg(&mut self, reg: u16, phy_data: u16) -> usize { @@ -592,7 +588,7 @@ impl Alx { } unsafe fn read_phy_ext(&mut self, dev: u8, reg: u16, data: &mut u16) -> usize { - self.read_phy_core(true, dev, reg, data) + self.read_phy_core(true, dev, reg, data) } unsafe fn write_phy_ext(&mut self, dev: u8, reg: u16, data: u16) -> usize { @@ -601,109 +597,102 @@ impl Alx { unsafe fn read_phy_dbg(&mut self, reg: u16, data: &mut u16) -> usize { let err = self.write_phy_reg(MII_DBG_ADDR, reg); - if (err > 0) { - return err; + if (err > 0) { + return err; } self.read_phy_reg(MII_DBG_DATA, data) } unsafe fn write_phy_dbg(&mut self, reg: u16, data: u16) -> usize { - let err = self.write_phy_reg(MII_DBG_ADDR, reg); - if (err > 0) { - return err; - } + let err = self.write_phy_reg(MII_DBG_ADDR, reg); + if (err > 0) { + return err; + } - self.write_phy_reg(MII_DBG_DATA, data) + self.write_phy_reg(MII_DBG_DATA, data) } unsafe fn enable_aspm(&mut self, l0s_en: bool, l1_en: bool) { let mut pmctrl: u32; - let rev: u8 = self.revid(); + let rev: u8 = self.revid(); - pmctrl = self.read(PMCTRL); + pmctrl = self.read(PMCTRL); - FIELD_SET32!(pmctrl, PMCTRL_LCKDET_TIMER, PMCTRL_LCKDET_TIMER_DEF); - pmctrl |= PMCTRL_RCVR_WT_1US | - PMCTRL_L1_CLKSW_EN | - PMCTRL_L1_SRDSRX_PWD ; - FIELD_SET32!(pmctrl, PMCTRL_L1REQ_TO, PMCTRL_L1REG_TO_DEF); - FIELD_SET32!(pmctrl, PMCTRL_L1_TIMER, PMCTRL_L1_TIMER_16US); - pmctrl &= !(PMCTRL_L1_SRDS_EN | - PMCTRL_L1_SRDSPLL_EN | - PMCTRL_L1_BUFSRX_EN | - PMCTRL_SADLY_EN | - PMCTRL_HOTRST_WTEN| - PMCTRL_L0S_EN | - PMCTRL_L1_EN | - PMCTRL_ASPM_FCEN | - PMCTRL_TXL1_AFTER_L0S | - PMCTRL_RXL1_AFTER_L0S - ); - if ((rev == REV_A0 || rev == REV_A1) && self.with_cr()) { - pmctrl |= PMCTRL_L1_SRDS_EN | PMCTRL_L1_SRDSPLL_EN; + FIELD_SET32!(pmctrl, PMCTRL_LCKDET_TIMER, PMCTRL_LCKDET_TIMER_DEF); + pmctrl |= PMCTRL_RCVR_WT_1US | PMCTRL_L1_CLKSW_EN | PMCTRL_L1_SRDSRX_PWD; + FIELD_SET32!(pmctrl, PMCTRL_L1REQ_TO, PMCTRL_L1REG_TO_DEF); + FIELD_SET32!(pmctrl, PMCTRL_L1_TIMER, PMCTRL_L1_TIMER_16US); + pmctrl &= !(PMCTRL_L1_SRDS_EN + | PMCTRL_L1_SRDSPLL_EN + | PMCTRL_L1_BUFSRX_EN + | PMCTRL_SADLY_EN + | PMCTRL_HOTRST_WTEN + | PMCTRL_L0S_EN + | PMCTRL_L1_EN + | PMCTRL_ASPM_FCEN + | PMCTRL_TXL1_AFTER_L0S + | PMCTRL_RXL1_AFTER_L0S); + if ((rev == REV_A0 || rev == REV_A1) && self.with_cr()) { + pmctrl |= PMCTRL_L1_SRDS_EN | PMCTRL_L1_SRDSPLL_EN; } - if (l0s_en) { - pmctrl |= (PMCTRL_L0S_EN | PMCTRL_ASPM_FCEN); + if (l0s_en) { + pmctrl |= (PMCTRL_L0S_EN | PMCTRL_ASPM_FCEN); } - if (l1_en) { - pmctrl |= (PMCTRL_L1_EN | PMCTRL_ASPM_FCEN); + if (l1_en) { + pmctrl |= (PMCTRL_L1_EN | PMCTRL_ASPM_FCEN); } - self.write(PMCTRL, pmctrl); + self.write(PMCTRL, pmctrl); } unsafe fn reset_pcie(&mut self) { let mut val: u32; - let rev: u8 = self.revid(); + let rev: u8 = self.revid(); - /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */ + /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */ let mut val16 = ptr::read((self.base + 4) as *const u16); - if (val16 & (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO) == 0 - || val16 & PCI_COMMAND_INTX_DISABLE > 0) { + if (val16 & (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO) == 0 + || val16 & PCI_COMMAND_INTX_DISABLE > 0) + { println!("Fix PCI_COMMAND_INTX_DISABLE"); - val16 = (val16 | (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) & !PCI_COMMAND_INTX_DISABLE; + val16 = (val16 | (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO)) + & !PCI_COMMAND_INTX_DISABLE; ptr::write((self.base + 4) as *mut u16, val16); - } + } - /* clear WoL setting/status */ - val = self.read(WOL0); - self.write(WOL0, 0); + /* clear WoL setting/status */ + val = self.read(WOL0); + self.write(WOL0, 0); - /* deflt val of PDLL D3PLLOFF */ - val = self.read(PDLL_TRNS1); - self.write(PDLL_TRNS1, val & !PDLL_TRNS1_D3PLLOFF_EN); + /* deflt val of PDLL D3PLLOFF */ + val = self.read(PDLL_TRNS1); + self.write(PDLL_TRNS1, val & !PDLL_TRNS1_D3PLLOFF_EN); - /* mask some pcie error bits */ - val = self.read(UE_SVRT); - val &= !(UE_SVRT_DLPROTERR | UE_SVRT_FCPROTERR); - self.write(UE_SVRT, val); + /* mask some pcie error bits */ + val = self.read(UE_SVRT); + val &= !(UE_SVRT_DLPROTERR | UE_SVRT_FCPROTERR); + self.write(UE_SVRT, val); - /* wol 25M & pclk */ - val = self.read(MASTER); - if ((rev == REV_A0 || rev == REV_A1) && self.with_cr()) { - if ((val & MASTER_WAKEN_25M) == 0 || - (val & MASTER_PCLKSEL_SRDS) == 0) { - self.write(MASTER, - val | MASTER_PCLKSEL_SRDS | - MASTER_WAKEN_25M); - } - } else { - if ((val & MASTER_WAKEN_25M) == 0 || - (val & MASTER_PCLKSEL_SRDS) != 0) { - self.write(MASTER, - (val & !MASTER_PCLKSEL_SRDS) | - MASTER_WAKEN_25M); - } - } + /* wol 25M & pclk */ + val = self.read(MASTER); + if ((rev == REV_A0 || rev == REV_A1) && self.with_cr()) { + if ((val & MASTER_WAKEN_25M) == 0 || (val & MASTER_PCLKSEL_SRDS) == 0) { + self.write(MASTER, val | MASTER_PCLKSEL_SRDS | MASTER_WAKEN_25M); + } + } else { + if ((val & MASTER_WAKEN_25M) == 0 || (val & MASTER_PCLKSEL_SRDS) != 0) { + self.write(MASTER, (val & !MASTER_PCLKSEL_SRDS) | MASTER_WAKEN_25M); + } + } - /* ASPM setting */ + /* ASPM setting */ let l0s_en = self.cap & CAP_L0S > 0; let l1_en = self.cap & CAP_L1 > 0; - self.enable_aspm(l0s_en, l1_en); + self.enable_aspm(l0s_en, l1_en); - udelay(10); + udelay(10); } unsafe fn reset_phy(&mut self) { @@ -711,117 +700,126 @@ impl Alx { let mut val: u32; let mut phy_val: u16 = 0; - /* (DSP)reset PHY core */ - val = self.read(PHY_CTRL); - val &= !(PHY_CTRL_DSPRST_OUT | PHY_CTRL_IDDQ | - PHY_CTRL_GATE_25M | PHY_CTRL_POWER_DOWN | - PHY_CTRL_CLS); - val |= PHY_CTRL_RST_ANALOG; + /* (DSP)reset PHY core */ + val = self.read(PHY_CTRL); + val &= !(PHY_CTRL_DSPRST_OUT + | PHY_CTRL_IDDQ + | PHY_CTRL_GATE_25M + | PHY_CTRL_POWER_DOWN + | PHY_CTRL_CLS); + val |= PHY_CTRL_RST_ANALOG; - if (! self.hib_patch) { - val |= (PHY_CTRL_HIB_PULSE | PHY_CTRL_HIB_EN); - } else { - val &= !(PHY_CTRL_HIB_PULSE | PHY_CTRL_HIB_EN); + if (!self.hib_patch) { + val |= (PHY_CTRL_HIB_PULSE | PHY_CTRL_HIB_EN); + } else { + val &= !(PHY_CTRL_HIB_PULSE | PHY_CTRL_HIB_EN); } - self.write(PHY_CTRL, val); - udelay(10); - self.write(PHY_CTRL, val | PHY_CTRL_DSPRST_OUT); + self.write(PHY_CTRL, val); + udelay(10); + self.write(PHY_CTRL, val | PHY_CTRL_DSPRST_OUT); - /* delay 800us */ + /* delay 800us */ i = 0; - while (i < PHY_CTRL_DSPRST_TO) { - udelay(10); + while (i < PHY_CTRL_DSPRST_TO) { + udelay(10); i += 1; } - if ! self.is_fpga { - /* phy power saving & hib */ - if (! self.hib_patch) { - self.write_phy_dbg(MIIDBG_LEGCYPS, LEGCYPS_DEF); - self.write_phy_dbg(MIIDBG_SYSMODCTRL, - SYSMODCTRL_IECHOADJ_DEF); - self.write_phy_ext(MIIEXT_PCS, MIIEXT_VDRVBIAS, VDRVBIAS_DEF); - } else { - self.write_phy_dbg(MIIDBG_LEGCYPS, - LEGCYPS_DEF & !LEGCYPS_EN); - self.write_phy_dbg(MIIDBG_HIBNEG, HIBNEG_NOHIB); - self.write_phy_dbg(MIIDBG_GREENCFG, GREENCFG_DEF); - } + if !self.is_fpga { + /* phy power saving & hib */ + if (!self.hib_patch) { + self.write_phy_dbg(MIIDBG_LEGCYPS, LEGCYPS_DEF); + self.write_phy_dbg(MIIDBG_SYSMODCTRL, SYSMODCTRL_IECHOADJ_DEF); + self.write_phy_ext(MIIEXT_PCS, MIIEXT_VDRVBIAS, VDRVBIAS_DEF); + } else { + self.write_phy_dbg(MIIDBG_LEGCYPS, LEGCYPS_DEF & !LEGCYPS_EN); + self.write_phy_dbg(MIIDBG_HIBNEG, HIBNEG_NOHIB); + self.write_phy_dbg(MIIDBG_GREENCFG, GREENCFG_DEF); + } - /* EEE advertisement */ - if (self.cap & CAP_AZ > 0) { + /* EEE advertisement */ + if (self.cap & CAP_AZ > 0) { let eeeadv = if self.cap & CAP_GIGA > 0 { LOCAL_EEEADV_1000BT | LOCAL_EEEADV_100BT } else { LOCAL_EEEADV_100BT }; - self.write_phy_ext(MIIEXT_ANEG, MIIEXT_LOCAL_EEEADV, eeeadv); - /* half amplify */ - self.write_phy_dbg(MIIDBG_AZ_ANADECT, - AZ_ANADECT_DEF); - } else { - val = self.read(LPI_CTRL); - self.write(LPI_CTRL, val & (!LPI_CTRL_EN)); - self.write_phy_ext(MIIEXT_ANEG, - MIIEXT_LOCAL_EEEADV, 0); - } + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_LOCAL_EEEADV, eeeadv); + /* half amplify */ + self.write_phy_dbg(MIIDBG_AZ_ANADECT, AZ_ANADECT_DEF); + } else { + val = self.read(LPI_CTRL); + self.write(LPI_CTRL, val & (!LPI_CTRL_EN)); + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_LOCAL_EEEADV, 0); + } - /* phy power saving */ - self.write_phy_dbg(MIIDBG_TST10BTCFG, TST10BTCFG_DEF); - self.write_phy_dbg(MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF); - self.write_phy_dbg(MIIDBG_TST100BTCFG, TST100BTCFG_DEF); - self.write_phy_dbg(MIIDBG_ANACTRL, ANACTRL_DEF); - self.read_phy_dbg(MIIDBG_GREENCFG2, &mut phy_val); - self.write_phy_dbg(MIIDBG_GREENCFG2, phy_val & (!GREENCFG2_GATE_DFSE_EN)); - /* rtl8139c, 120m issue */ - self.write_phy_ext(MIIEXT_ANEG, MIIEXT_NLP78, MIIEXT_NLP78_120M_DEF); - self.write_phy_ext(MIIEXT_ANEG, MIIEXT_S3DIG10, MIIEXT_S3DIG10_DEF); + /* phy power saving */ + self.write_phy_dbg(MIIDBG_TST10BTCFG, TST10BTCFG_DEF); + self.write_phy_dbg(MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF); + self.write_phy_dbg(MIIDBG_TST100BTCFG, TST100BTCFG_DEF); + self.write_phy_dbg(MIIDBG_ANACTRL, ANACTRL_DEF); + self.read_phy_dbg(MIIDBG_GREENCFG2, &mut phy_val); + self.write_phy_dbg(MIIDBG_GREENCFG2, phy_val & (!GREENCFG2_GATE_DFSE_EN)); + /* rtl8139c, 120m issue */ + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_NLP78, MIIEXT_NLP78_120M_DEF); + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_S3DIG10, MIIEXT_S3DIG10_DEF); - if (self.lnk_patch) { - /* Turn off half amplitude */ - self.read_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL3, &mut phy_val); - self.write_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL3, phy_val | CLDCTRL3_BP_CABLE1TH_DET_GT); - /* Turn off Green feature */ - self.read_phy_dbg(MIIDBG_GREENCFG2, &mut phy_val); - self.write_phy_dbg(MIIDBG_GREENCFG2, phy_val | GREENCFG2_BP_GREEN); - /* Turn off half Bias */ - self.read_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL5, &mut phy_val); - self.write_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL5, phy_val | CLDCTRL5_BP_VD_HLFBIAS); - } + if (self.lnk_patch) { + /* Turn off half amplitude */ + self.read_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL3, &mut phy_val); + self.write_phy_ext( + MIIEXT_PCS, + MIIEXT_CLDCTRL3, + phy_val | CLDCTRL3_BP_CABLE1TH_DET_GT, + ); + /* Turn off Green feature */ + self.read_phy_dbg(MIIDBG_GREENCFG2, &mut phy_val); + self.write_phy_dbg(MIIDBG_GREENCFG2, phy_val | GREENCFG2_BP_GREEN); + /* Turn off half Bias */ + self.read_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL5, &mut phy_val); + self.write_phy_ext( + MIIEXT_PCS, + MIIEXT_CLDCTRL5, + phy_val | CLDCTRL5_BP_VD_HLFBIAS, + ); + } } - /* set phy interrupt mask */ - self.write_phy_reg(MII_IER, IER_LINK_UP | IER_LINK_DOWN); + /* set phy interrupt mask */ + self.write_phy_reg(MII_IER, IER_LINK_UP | IER_LINK_DOWN); } - unsafe fn stop_mac(&mut self) -> usize { let txq: u32; let rxq: u32; let mut val: u32; let mut i: u32; - rxq = self.read(RXQ0); - self.write(RXQ0, rxq & (!RXQ0_EN)); - txq = self.read(TXQ0); - self.write(TXQ0, txq & (!TXQ0_EN)); + rxq = self.read(RXQ0); + self.write(RXQ0, rxq & (!RXQ0_EN)); + txq = self.read(TXQ0); + self.write(TXQ0, txq & (!TXQ0_EN)); - udelay(40); + udelay(40); - self.rx_ctrl &= !(MAC_CTRL_RX_EN | MAC_CTRL_TX_EN); - self.write(MAC_CTRL, self.rx_ctrl); + self.rx_ctrl &= !(MAC_CTRL_RX_EN | MAC_CTRL_TX_EN); + self.write(MAC_CTRL, self.rx_ctrl); i = 0; - while i < DMA_MAC_RST_TO { - val = self.read(MAC_STS); - if (val & MAC_STS_IDLE == 0) { - break; + while i < DMA_MAC_RST_TO { + val = self.read(MAC_STS); + if (val & MAC_STS_IDLE == 0) { + break; } - udelay(10); + udelay(10); i += 1; - } + } - return if (DMA_MAC_RST_TO == i) { ERR_RSTMAC as usize } else { 0 }; + return if (DMA_MAC_RST_TO == i) { + ERR_RSTMAC as usize + } else { + 0 + }; } unsafe fn start_mac(&mut self) { @@ -829,66 +827,69 @@ impl Alx { let txq: u32; let rxq: u32; - rxq = self.read(RXQ0); - self.write(RXQ0, rxq | RXQ0_EN); - txq = self.read(TXQ0); - self.write(TXQ0, txq | TXQ0_EN); + rxq = self.read(RXQ0); + self.write(RXQ0, rxq | RXQ0_EN); + txq = self.read(TXQ0); + self.write(TXQ0, txq | TXQ0_EN); - mac = self.rx_ctrl; - if (self.link_duplex == FULL_DUPLEX) { - mac |= MAC_CTRL_FULLD; - } else { - mac &= !MAC_CTRL_FULLD; - } - FIELD_SET32!(mac, MAC_CTRL_SPEED, if self.link_speed == 1000 { - MAC_CTRL_SPEED_1000 + mac = self.rx_ctrl; + if (self.link_duplex == FULL_DUPLEX) { + mac |= MAC_CTRL_FULLD; } else { - MAC_CTRL_SPEED_10_100 - }); - mac |= MAC_CTRL_TX_EN | MAC_CTRL_RX_EN; - self.rx_ctrl = mac; - self.write(MAC_CTRL, mac); + mac &= !MAC_CTRL_FULLD; + } + FIELD_SET32!( + mac, + MAC_CTRL_SPEED, + if self.link_speed == 1000 { + MAC_CTRL_SPEED_1000 + } else { + MAC_CTRL_SPEED_10_100 + } + ); + mac |= MAC_CTRL_TX_EN | MAC_CTRL_RX_EN; + self.rx_ctrl = mac; + self.write(MAC_CTRL, mac); } unsafe fn reset_osc(&mut self, rev: u8) { let mut val: u32; let mut val2: u32; - /* clear Internal OSC settings, switching OSC by hw itself */ - val = self.read(MISC3); - self.write(MISC3, - (val & !MISC3_25M_BY_SW) | MISC3_25M_NOTO_INTNL); + /* clear Internal OSC settings, switching OSC by hw itself */ + val = self.read(MISC3); + self.write(MISC3, (val & !MISC3_25M_BY_SW) | MISC3_25M_NOTO_INTNL); - /* 25M clk from chipset may be unstable 1s after de-assert of - * PERST, driver need re-calibrate before enter Sleep for WoL - */ - val = self.read(MISC); - if (rev >= REV_B0) { - /* restore over current protection def-val, - * this val could be reset by MAC-RST - */ - FIELD_SET32!(val, MISC_PSW_OCP, MISC_PSW_OCP_DEF); - /* a 0->1 change will update the internal val of osc */ - val &= !MISC_INTNLOSC_OPEN; - self.write(MISC, val); - self.write(MISC, val | MISC_INTNLOSC_OPEN); - /* hw will automatically dis OSC after cab. */ - val2 = self.read(MSIC2); - val2 &= !MSIC2_CALB_START; - self.write(MSIC2, val2); - self.write(MSIC2, val2 | MSIC2_CALB_START); - } else { - val &= !MISC_INTNLOSC_OPEN; - /* disable isoloate for A0 */ - if ((rev == REV_A0 || rev == REV_A1)) { - val &= !MISC_ISO_EN; + /* 25M clk from chipset may be unstable 1s after de-assert of + * PERST, driver need re-calibrate before enter Sleep for WoL + */ + val = self.read(MISC); + if (rev >= REV_B0) { + /* restore over current protection def-val, + * this val could be reset by MAC-RST + */ + FIELD_SET32!(val, MISC_PSW_OCP, MISC_PSW_OCP_DEF); + /* a 0->1 change will update the internal val of osc */ + val &= !MISC_INTNLOSC_OPEN; + self.write(MISC, val); + self.write(MISC, val | MISC_INTNLOSC_OPEN); + /* hw will automatically dis OSC after cab. */ + val2 = self.read(MSIC2); + val2 &= !MSIC2_CALB_START; + self.write(MSIC2, val2); + self.write(MSIC2, val2 | MSIC2_CALB_START); + } else { + val &= !MISC_INTNLOSC_OPEN; + /* disable isoloate for A0 */ + if (rev == REV_A0 || rev == REV_A1) { + val &= !MISC_ISO_EN; } - self.write(MISC, val | MISC_INTNLOSC_OPEN); - self.write(MISC, val); - } + self.write(MISC, val | MISC_INTNLOSC_OPEN); + self.write(MISC, val); + } - udelay(20); + udelay(20); } unsafe fn reset_mac(&mut self) -> usize { @@ -899,213 +900,210 @@ impl Alx { let rev: u8; let a_cr: bool; - pmctrl = 0; - rev = self.revid(); - a_cr = (rev == REV_A0 || rev == REV_A1) && self.with_cr(); + pmctrl = 0; + rev = self.revid(); + a_cr = (rev == REV_A0 || rev == REV_A1) && self.with_cr(); - /* disable all interrupts, RXQ/TXQ */ - self.write(MSIX_MASK, 0xFFFFFFFF); - self.write(IMR, 0); - self.write(ISR, ISR_DIS); + /* disable all interrupts, RXQ/TXQ */ + self.write(MSIX_MASK, 0xFFFFFFFF); + self.write(IMR, 0); + self.write(ISR, ISR_DIS); - ret = self.stop_mac(); - if (ret > 0) { - return ret; + ret = self.stop_mac(); + if (ret > 0) { + return ret; } - /* mac reset workaroud */ - self.write(RFD_PIDX, 1); + /* mac reset workaroud */ + self.write(RFD_PIDX, 1); - /* dis l0s/l1 before mac reset */ - if (a_cr) { - pmctrl = self.read(PMCTRL); - if ((pmctrl & (PMCTRL_L1_EN | PMCTRL_L0S_EN)) != 0) { - self.write(PMCTRL, pmctrl & !(PMCTRL_L1_EN | PMCTRL_L0S_EN)); - } - } + /* dis l0s/l1 before mac reset */ + if (a_cr) { + pmctrl = self.read(PMCTRL); + if ((pmctrl & (PMCTRL_L1_EN | PMCTRL_L0S_EN)) != 0) { + self.write(PMCTRL, pmctrl & !(PMCTRL_L1_EN | PMCTRL_L0S_EN)); + } + } - /* reset whole mac safely */ - val = self.read(MASTER); - self.write(MASTER, val | MASTER_DMA_MAC_RST | MASTER_OOB_DIS); + /* reset whole mac safely */ + val = self.read(MASTER); + self.write(MASTER, val | MASTER_DMA_MAC_RST | MASTER_OOB_DIS); - /* make sure it's real idle */ - udelay(10); + /* make sure it's real idle */ + udelay(10); i = 0; - while (i < DMA_MAC_RST_TO) { - val = self.read(RFD_PIDX); - if (val == 0) { - break; - } - udelay(10); - i += 1; - } while (i < DMA_MAC_RST_TO) { - val = self.read(MASTER); - if ((val & MASTER_DMA_MAC_RST) == 0) { - break; + val = self.read(RFD_PIDX); + if (val == 0) { + break; } - udelay(10); + udelay(10); i += 1; - } - if (i == DMA_MAC_RST_TO) { - return ERR_RSTMAC; } - udelay(10); - - if (a_cr) { - /* set MASTER_PCLKSEL_SRDS (affect by soft-rst, PERST) */ - self.write(MASTER, val | MASTER_PCLKSEL_SRDS); - /* resoter l0s / l1 */ - if (pmctrl & (PMCTRL_L1_EN | PMCTRL_L0S_EN) > 0) { - self.write(PMCTRL, pmctrl); + while (i < DMA_MAC_RST_TO) { + val = self.read(MASTER); + if ((val & MASTER_DMA_MAC_RST) == 0) { + break; } - } - - self.reset_osc(rev); - /* clear Internal OSC settings, switching OSC by hw itself, - * disable isoloate for A version - */ - val = self.read(MISC3); - self.write(MISC3, (val & !MISC3_25M_BY_SW) | MISC3_25M_NOTO_INTNL); - val = self.read(MISC); - val &= !MISC_INTNLOSC_OPEN; - if ((rev == REV_A0 || rev == REV_A1)) { - val &= !MISC_ISO_EN; + udelay(10); + i += 1; } - self.write(MISC, val); - udelay(20); + if (i == DMA_MAC_RST_TO) { + return ERR_RSTMAC; + } + udelay(10); - /* driver control speed/duplex, hash-alg */ - self.write(MAC_CTRL, self.rx_ctrl); - - /* clk sw */ - val = self.read(SERDES); - self.write(SERDES, - val | SERDES_MACCLK_SLWDWN | SERDES_PHYCLK_SLWDWN); - - /* mac reset cause MDIO ctrl restore non-polling status */ - if (self.is_fpga) { - self.start_phy_polling(MDIO_CLK_SEL_25MD128); + if (a_cr) { + /* set MASTER_PCLKSEL_SRDS (affect by soft-rst, PERST) */ + self.write(MASTER, val | MASTER_PCLKSEL_SRDS); + /* resoter l0s / l1 */ + if (pmctrl & (PMCTRL_L1_EN | PMCTRL_L0S_EN) > 0) { + self.write(PMCTRL, pmctrl); + } } + self.reset_osc(rev); + /* clear Internal OSC settings, switching OSC by hw itself, + * disable isoloate for A version + */ + val = self.read(MISC3); + self.write(MISC3, (val & !MISC3_25M_BY_SW) | MISC3_25M_NOTO_INTNL); + val = self.read(MISC); + val &= !MISC_INTNLOSC_OPEN; + if (rev == REV_A0 || rev == REV_A1) { + val &= !MISC_ISO_EN; + } + self.write(MISC, val); + udelay(20); - return ret; + /* driver control speed/duplex, hash-alg */ + self.write(MAC_CTRL, self.rx_ctrl); + + /* clk sw */ + val = self.read(SERDES); + self.write(SERDES, val | SERDES_MACCLK_SLWDWN | SERDES_PHYCLK_SLWDWN); + + /* mac reset cause MDIO ctrl restore non-polling status */ + if (self.is_fpga) { + self.start_phy_polling(MDIO_CLK_SEL_25MD128); + } + + return ret; } unsafe fn ethadv_to_hw_cfg(&self, ethadv_cfg: u32) -> u32 { - let mut cfg: u32 = 0; + let mut cfg: u32 = 0; - if (ethadv_cfg & ADVERTISED_Autoneg > 0) { - cfg |= DRV_PHY_AUTO; - if (ethadv_cfg & ADVERTISED_10baseT_Half > 0) { - cfg |= DRV_PHY_10; + if (ethadv_cfg & ADVERTISED_Autoneg > 0) { + cfg |= DRV_PHY_AUTO; + if (ethadv_cfg & ADVERTISED_10baseT_Half > 0) { + cfg |= DRV_PHY_10; } - if (ethadv_cfg & ADVERTISED_10baseT_Full > 0) { - cfg |= DRV_PHY_10 | DRV_PHY_DUPLEX; + if (ethadv_cfg & ADVERTISED_10baseT_Full > 0) { + cfg |= DRV_PHY_10 | DRV_PHY_DUPLEX; } - if (ethadv_cfg & ADVERTISED_100baseT_Half > 0) { - cfg |= DRV_PHY_100; + if (ethadv_cfg & ADVERTISED_100baseT_Half > 0) { + cfg |= DRV_PHY_100; } - if (ethadv_cfg & ADVERTISED_100baseT_Full > 0) { - cfg |= DRV_PHY_100 | DRV_PHY_DUPLEX; + if (ethadv_cfg & ADVERTISED_100baseT_Full > 0) { + cfg |= DRV_PHY_100 | DRV_PHY_DUPLEX; } - if (ethadv_cfg & ADVERTISED_1000baseT_Half > 0) { - cfg |= DRV_PHY_1000; + if (ethadv_cfg & ADVERTISED_1000baseT_Half > 0) { + cfg |= DRV_PHY_1000; } - if (ethadv_cfg & ADVERTISED_1000baseT_Full > 0) { - cfg |= DRV_PHY_100 | DRV_PHY_DUPLEX; + if (ethadv_cfg & ADVERTISED_1000baseT_Full > 0) { + cfg |= DRV_PHY_100 | DRV_PHY_DUPLEX; } - if (ethadv_cfg & ADVERTISED_Pause > 0) { - cfg |= ADVERTISE_PAUSE_CAP; + if (ethadv_cfg & ADVERTISED_Pause > 0) { + cfg |= ADVERTISE_PAUSE_CAP; } - if (ethadv_cfg & ADVERTISED_Asym_Pause > 0) { - cfg |= ADVERTISE_PAUSE_ASYM; + if (ethadv_cfg & ADVERTISED_Asym_Pause > 0) { + cfg |= ADVERTISE_PAUSE_ASYM; } - if (self.cap & CAP_AZ > 0) { - cfg |= DRV_PHY_EEE; + if (self.cap & CAP_AZ > 0) { + cfg |= DRV_PHY_EEE; } - } else { - match (ethadv_cfg) { - ADVERTISED_10baseT_Half => { - cfg |= DRV_PHY_10; - }, - ADVERTISED_100baseT_Half => { - cfg |= DRV_PHY_100; - }, - ADVERTISED_10baseT_Full => { - cfg |= DRV_PHY_10 | DRV_PHY_DUPLEX; - }, - ADVERTISED_100baseT_Full => { - cfg |= DRV_PHY_100 | DRV_PHY_DUPLEX; - }, - _ => () - } - } + } else { + match (ethadv_cfg) { + ADVERTISED_10baseT_Half => { + cfg |= DRV_PHY_10; + } + ADVERTISED_100baseT_Half => { + cfg |= DRV_PHY_100; + } + ADVERTISED_10baseT_Full => { + cfg |= DRV_PHY_10 | DRV_PHY_DUPLEX; + } + ADVERTISED_100baseT_Full => { + cfg |= DRV_PHY_100 | DRV_PHY_DUPLEX; + } + _ => (), + } + } - return cfg; + return cfg; } unsafe fn setup_speed_duplex(&mut self, ethadv: u32, flowctrl: u8) -> usize { let mut adv: u32; let mut giga: u16; let mut cr: u16; - let mut val: u32; - let mut err: usize = 0; + let mut val: u32; + let mut err: usize = 0; - /* clear flag */ - self.write_phy_reg(MII_DBG_ADDR, 0); - val = self.read(DRV); - FIELD_SET32!(val, DRV_PHY, 0); + /* clear flag */ + self.write_phy_reg(MII_DBG_ADDR, 0); + val = self.read(DRV); + FIELD_SET32!(val, DRV_PHY, 0); - if (ethadv & ADVERTISED_Autoneg > 0) { - adv = ADVERTISE_CSMA; - adv |= ethtool_adv_to_mii_adv_t(ethadv); + if (ethadv & ADVERTISED_Autoneg > 0) { + adv = ADVERTISE_CSMA; + adv |= ethtool_adv_to_mii_adv_t(ethadv); - if (flowctrl & FC_ANEG == FC_ANEG) { - if (flowctrl & FC_RX > 0) { - adv |= ADVERTISED_Pause; - if (flowctrl & FC_TX == 0) { - adv |= ADVERTISED_Asym_Pause; + if (flowctrl & FC_ANEG == FC_ANEG) { + if (flowctrl & FC_RX > 0) { + adv |= ADVERTISED_Pause; + if (flowctrl & FC_TX == 0) { + adv |= ADVERTISED_Asym_Pause; } - } else if (flowctrl & FC_TX > 0) { - adv |= ADVERTISED_Asym_Pause; + } else if (flowctrl & FC_TX > 0) { + adv |= ADVERTISED_Asym_Pause; } - } - giga = 0; - if (self.cap & CAP_GIGA > 0) { - giga = ethtool_adv_to_mii_ctrl1000_t(ethadv) as u16; + } + giga = 0; + if (self.cap & CAP_GIGA > 0) { + giga = ethtool_adv_to_mii_ctrl1000_t(ethadv) as u16; } - cr = BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART; + cr = BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART; - if (self.write_phy_reg(MII_ADVERTISE, adv as u16) > 0 || - self.write_phy_reg(MII_CTRL1000, giga) > 0 || - self.write_phy_reg(MII_BMCR, cr) > 0) { - err = ERR_MIIBUSY; + if (self.write_phy_reg(MII_ADVERTISE, adv as u16) > 0 + || self.write_phy_reg(MII_CTRL1000, giga) > 0 + || self.write_phy_reg(MII_BMCR, cr) > 0) + { + err = ERR_MIIBUSY; } - } else { - cr = BMCR_RESET; - if (ethadv == ADVERTISED_100baseT_Half || - ethadv == ADVERTISED_100baseT_Full) { - cr |= BMCR_SPEED100; + } else { + cr = BMCR_RESET; + if (ethadv == ADVERTISED_100baseT_Half || ethadv == ADVERTISED_100baseT_Full) { + cr |= BMCR_SPEED100; } - if (ethadv == ADVERTISED_10baseT_Full || - ethadv == ADVERTISED_100baseT_Full) { - cr |= BMCR_FULLDPLX; + if (ethadv == ADVERTISED_10baseT_Full || ethadv == ADVERTISED_100baseT_Full) { + cr |= BMCR_FULLDPLX; } - err = self.write_phy_reg(MII_BMCR, cr); - } + err = self.write_phy_reg(MII_BMCR, cr); + } - if (err == 0) { - self.write_phy_reg(MII_DBG_ADDR, PHY_INITED); - /* save config to HW */ - val |= self.ethadv_to_hw_cfg(ethadv); - } + if (err == 0) { + self.write_phy_reg(MII_DBG_ADDR, PHY_INITED); + /* save config to HW */ + val |= self.ethadv_to_hw_cfg(ethadv); + } - self.write(DRV, val); + self.write(DRV, val); - return err; + return err; } unsafe fn get_perm_macaddr(&mut self) -> [u8; 6] { @@ -1117,55 +1115,59 @@ impl Alx { (mac_low >> 16) as u8, (mac_low >> 24) as u8, mac_high as u8, - (mac_high >> 8) as u8 + (mac_high >> 8) as u8, ] } unsafe fn get_phy_link(&mut self, link_up: &mut bool, speed: &mut u16) -> usize { let mut bmsr: u16 = 0; let mut giga: u16 = 0; - let mut err: usize; + let mut err: usize; - err = self.read_phy_reg(MII_BMSR, &mut bmsr); - err = self.read_phy_reg(MII_BMSR, &mut bmsr); - if (err > 0) { - return err; - } - - if (bmsr & BMSR_LSTATUS == 0) { - *link_up = false; - return err; - } - - *link_up = true; - - /* speed/duplex result is saved in PHY Specific Status Register */ - err = self.read_phy_reg(MII_GIGA_PSSR, &mut giga); - if (err > 0) { + err = self.read_phy_reg(MII_BMSR, &mut bmsr); + err = self.read_phy_reg(MII_BMSR, &mut bmsr); + if (err > 0) { return err; } - if (giga & GIGA_PSSR_SPD_DPLX_RESOLVED == 0) { + if (bmsr & BMSR_LSTATUS == 0) { + *link_up = false; + return err; + } + + *link_up = true; + + /* speed/duplex result is saved in PHY Specific Status Register */ + err = self.read_phy_reg(MII_GIGA_PSSR, &mut giga); + if (err > 0) { + return err; + } + + if (giga & GIGA_PSSR_SPD_DPLX_RESOLVED == 0) { println!("PHY SPD/DPLX unresolved: {:X}", giga); - err = (-EINVAL) as usize; + err = (-EINVAL) as usize; } else { - match (giga & GIGA_PSSR_SPEED) { - GIGA_PSSR_1000MBS => *speed = SPEED_1000, - GIGA_PSSR_100MBS => *speed = SPEED_100, - GIGA_PSSR_10MBS => *speed = SPEED_10, - _ => { + match (giga & GIGA_PSSR_SPEED) { + GIGA_PSSR_1000MBS => *speed = SPEED_1000, + GIGA_PSSR_100MBS => *speed = SPEED_100, + GIGA_PSSR_10MBS => *speed = SPEED_10, + _ => { println!("PHY SPD/DPLX unresolved: {:X}", giga); - err = (-EINVAL) as usize; + err = (-EINVAL) as usize; } - } - *speed += if (giga & GIGA_PSSR_DPLX > 0) { FULL_DUPLEX as u16 } else { HALF_DUPLEX as u16 }; + } + *speed += if (giga & GIGA_PSSR_DPLX > 0) { + FULL_DUPLEX as u16 + } else { + HALF_DUPLEX as u16 + }; } - return err; + return err; } fn show_speed(&self, speed: u16) { - let desc = if speed == SPEED_1000 + FULL_DUPLEX as u16 { + let desc = if speed == SPEED_1000 + FULL_DUPLEX as u16 { "1 Gbps Full" } else if speed == SPEED_100 + FULL_DUPLEX as u16 { "100 Mbps Full" @@ -1189,188 +1191,185 @@ impl Alx { let val16: u16; let chip_rev = self.revid(); - /* mac address */ - //TODO alx_set_macaddr(hw, self.mac_addr); + /* mac address */ + //TODO alx_set_macaddr(hw, self.mac_addr); - /* clk gating */ - self.write(CLK_GATE, CLK_GATE_ALL_A0); + /* clk gating */ + self.write(CLK_GATE, CLK_GATE_ALL_A0); - /* idle timeout to switch clk_125M */ - if (chip_rev >= REV_B0) { - self.write(IDLE_DECISN_TIMER, - IDLE_DECISN_TIMER_DEF); - } - - /* stats refresh timeout */ - self.write(SMB_TIMER, self.smb_timer * 500); - - /* intr moduration */ - val = self.read(MASTER); - val = val | MASTER_IRQMOD2_EN | - MASTER_IRQMOD1_EN | - MASTER_SYSALVTIMER_EN; - self.write(MASTER, val); - self.write(IRQ_MODU_TIMER, - FIELDX!(IRQ_MODU_TIMER1, self.imt >> 1)); - /* intr re-trig timeout */ - self.write(INT_RETRIG, INT_RETRIG_TO); - /* tpd threshold to trig int */ - self.write(TINT_TPD_THRSHLD, self.ith_tpd); - self.write(TINT_TIMER, self.imt as u32); - - /* mtu, 8:fcs+vlan */ - raw_mtu = (self.mtu + ETH_HLEN) as u32; - self.write(MTU, raw_mtu + 8); - if (raw_mtu > MTU_JUMBO_TH) { - self.rx_ctrl &= !MAC_CTRL_FAST_PAUSE; + /* idle timeout to switch clk_125M */ + if (chip_rev >= REV_B0) { + self.write(IDLE_DECISN_TIMER, IDLE_DECISN_TIMER_DEF); } - /* txq */ - if ((raw_mtu + 8) < TXQ1_JUMBO_TSO_TH) { - val = (raw_mtu + 8 + 7) >> 3; + /* stats refresh timeout */ + self.write(SMB_TIMER, self.smb_timer * 500); + + /* intr moduration */ + val = self.read(MASTER); + val = val | MASTER_IRQMOD2_EN | MASTER_IRQMOD1_EN | MASTER_SYSALVTIMER_EN; + self.write(MASTER, val); + self.write(IRQ_MODU_TIMER, FIELDX!(IRQ_MODU_TIMER1, self.imt >> 1)); + /* intr re-trig timeout */ + self.write(INT_RETRIG, INT_RETRIG_TO); + /* tpd threshold to trig int */ + self.write(TINT_TPD_THRSHLD, self.ith_tpd); + self.write(TINT_TIMER, self.imt as u32); + + /* mtu, 8:fcs+vlan */ + raw_mtu = (self.mtu + ETH_HLEN) as u32; + self.write(MTU, raw_mtu + 8); + if (raw_mtu > MTU_JUMBO_TH) { + self.rx_ctrl &= !MAC_CTRL_FAST_PAUSE; + } + + /* txq */ + if ((raw_mtu + 8) < TXQ1_JUMBO_TSO_TH) { + val = (raw_mtu + 8 + 7) >> 3; } else { - val = TXQ1_JUMBO_TSO_TH >> 3; + val = TXQ1_JUMBO_TSO_TH >> 3; } - self.write(TXQ1, val | TXQ1_ERRLGPKT_DROP_EN); + self.write(TXQ1, val | TXQ1_ERRLGPKT_DROP_EN); /* TODO - max_payload = alx_get_readrq(hw) >> 8; - /* - * if BIOS had changed the default dma read max length, - * restore it to default value - */ - if (max_payload < DEV_CTRL_MAXRRS_MIN) - alx_set_readrq(hw, 128 << DEV_CTRL_MAXRRS_MIN); + max_payload = alx_get_readrq(hw) >> 8; + /* + * if BIOS had changed the default dma read max length, + * restore it to default value + */ + if (max_payload < DEV_CTRL_MAXRRS_MIN) + alx_set_readrq(hw, 128 << DEV_CTRL_MAXRRS_MIN); */ max_payload = 128 << DEV_CTRL_MAXRRS_MIN; - val = FIELDX!(TXQ0_TPD_BURSTPREF, TXQ_TPD_BURSTPREF_DEF) | - TXQ0_MODE_ENHANCE | - TXQ0_LSO_8023_EN | - TXQ0_SUPT_IPOPT | - FIELDX!(TXQ0_TXF_BURST_PREF, TXQ_TXF_BURST_PREF_DEF); - self.write(TXQ0, val); - val = FIELDX!(HQTPD_Q1_NUMPREF, TXQ_TPD_BURSTPREF_DEF) | - FIELDX!(HQTPD_Q2_NUMPREF, TXQ_TPD_BURSTPREF_DEF) | - FIELDX!(HQTPD_Q3_NUMPREF, TXQ_TPD_BURSTPREF_DEF) | - HQTPD_BURST_EN; - self.write(HQTPD, val); + val = FIELDX!(TXQ0_TPD_BURSTPREF, TXQ_TPD_BURSTPREF_DEF) + | TXQ0_MODE_ENHANCE + | TXQ0_LSO_8023_EN + | TXQ0_SUPT_IPOPT + | FIELDX!(TXQ0_TXF_BURST_PREF, TXQ_TXF_BURST_PREF_DEF); + self.write(TXQ0, val); + val = FIELDX!(HQTPD_Q1_NUMPREF, TXQ_TPD_BURSTPREF_DEF) + | FIELDX!(HQTPD_Q2_NUMPREF, TXQ_TPD_BURSTPREF_DEF) + | FIELDX!(HQTPD_Q3_NUMPREF, TXQ_TPD_BURSTPREF_DEF) + | HQTPD_BURST_EN; + self.write(HQTPD, val); - /* rxq, flow control */ - val = self.read(SRAM5); - val = FIELD_GETX!(val, SRAM_RXF_LEN) << 3; - if (val > SRAM_RXF_LEN_8K) { - val16 = (MTU_STD_ALGN >> 3) as u16; - val = (val - RXQ2_RXF_FLOW_CTRL_RSVD) >> 3; - } else { - val16 = (MTU_STD_ALGN >> 3) as u16; - val = (val - MTU_STD_ALGN) >> 3; - } - self.write(RXQ2, - FIELDX!(RXQ2_RXF_XOFF_THRESH, val16) | - FIELDX!(RXQ2_RXF_XON_THRESH, val)); - val = FIELDX!(RXQ0_NUM_RFD_PREF, RXQ0_NUM_RFD_PREF_DEF) | - FIELDX!(RXQ0_RSS_MODE, RXQ0_RSS_MODE_DIS) | - FIELDX!(RXQ0_IDT_TBL_SIZE, RXQ0_IDT_TBL_SIZE_DEF) | - RXQ0_RSS_HSTYP_ALL | - RXQ0_RSS_HASH_EN | - RXQ0_IPV6_PARSE_EN; - if (self.cap & CAP_GIGA > 0) { - FIELD_SET32!(val, RXQ0_ASPM_THRESH, RXQ0_ASPM_THRESH_100M); - } - self.write(RXQ0, val); + /* rxq, flow control */ + val = self.read(SRAM5); + val = FIELD_GETX!(val, SRAM_RXF_LEN) << 3; + if (val > SRAM_RXF_LEN_8K) { + val16 = (MTU_STD_ALGN >> 3) as u16; + val = (val - RXQ2_RXF_FLOW_CTRL_RSVD) >> 3; + } else { + val16 = (MTU_STD_ALGN >> 3) as u16; + val = (val - MTU_STD_ALGN) >> 3; + } + self.write( + RXQ2, + FIELDX!(RXQ2_RXF_XOFF_THRESH, val16) | FIELDX!(RXQ2_RXF_XON_THRESH, val), + ); + val = FIELDX!(RXQ0_NUM_RFD_PREF, RXQ0_NUM_RFD_PREF_DEF) + | FIELDX!(RXQ0_RSS_MODE, RXQ0_RSS_MODE_DIS) + | FIELDX!(RXQ0_IDT_TBL_SIZE, RXQ0_IDT_TBL_SIZE_DEF) + | RXQ0_RSS_HSTYP_ALL + | RXQ0_RSS_HASH_EN + | RXQ0_IPV6_PARSE_EN; + if (self.cap & CAP_GIGA > 0) { + FIELD_SET32!(val, RXQ0_ASPM_THRESH, RXQ0_ASPM_THRESH_100M); + } + self.write(RXQ0, val); - /* DMA */ - val = self.read(DMA); - val = FIELDX!(DMA_RORDER_MODE, DMA_RORDER_MODE_OUT) | - DMA_RREQ_PRI_DATA | - FIELDX!(DMA_RREQ_BLEN, max_payload) | - FIELDX!(DMA_WDLY_CNT, DMA_WDLY_CNT_DEF) | - FIELDX!(DMA_RDLY_CNT, DMA_RDLY_CNT_DEF) | - FIELDX!(DMA_RCHNL_SEL, self.dma_chnl - 1); - self.write(DMA, val); + /* DMA */ + val = self.read(DMA); + val = FIELDX!(DMA_RORDER_MODE, DMA_RORDER_MODE_OUT) + | DMA_RREQ_PRI_DATA + | FIELDX!(DMA_RREQ_BLEN, max_payload) + | FIELDX!(DMA_WDLY_CNT, DMA_WDLY_CNT_DEF) + | FIELDX!(DMA_RDLY_CNT, DMA_RDLY_CNT_DEF) + | FIELDX!(DMA_RCHNL_SEL, self.dma_chnl - 1); + self.write(DMA, val); - /* multi-tx-q weight */ - if (self.cap & CAP_MTQ > 0) { - val = FIELDX!(WRR_PRI, self.wrr_ctrl) | - FIELDX!(WRR_PRI0, self.wrr[0]) | - FIELDX!(WRR_PRI1, self.wrr[1]) | - FIELDX!(WRR_PRI2, self.wrr[2]) | - FIELDX!(WRR_PRI3, self.wrr[3]); - self.write(WRR, val); - } + /* multi-tx-q weight */ + if (self.cap & CAP_MTQ > 0) { + val = FIELDX!(WRR_PRI, self.wrr_ctrl) + | FIELDX!(WRR_PRI0, self.wrr[0]) + | FIELDX!(WRR_PRI1, self.wrr[1]) + | FIELDX!(WRR_PRI2, self.wrr[2]) + | FIELDX!(WRR_PRI3, self.wrr[3]); + self.write(WRR, val); + } } unsafe fn set_rx_mode(&mut self) { /* TODO struct alx_adapter *adpt = netdev_priv(netdev); - struct alx_hw *hw = &adpt->hw; - struct netdev_hw_addr *ha; + struct alx_hw *hw = &adpt->hw; + struct netdev_hw_addr *ha; - /* comoute mc addresses' hash value ,and put it into hash table */ - netdev_for_each_mc_addr(ha, netdev) - alx_add_mc_addr(hw, ha->addr); + /* comoute mc addresses' hash value ,and put it into hash table */ + netdev_for_each_mc_addr(ha, netdev) + alx_add_mc_addr(hw, ha->addr); */ - self.write(HASH_TBL0, self.mc_hash[0]); - self.write(HASH_TBL1, self.mc_hash[1]); + self.write(HASH_TBL0, self.mc_hash[0]); + self.write(HASH_TBL1, self.mc_hash[1]); - /* check for Promiscuous and All Multicast modes */ - self.rx_ctrl &= !(MAC_CTRL_MULTIALL_EN | MAC_CTRL_PROMISC_EN); + /* check for Promiscuous and All Multicast modes */ + self.rx_ctrl &= !(MAC_CTRL_MULTIALL_EN | MAC_CTRL_PROMISC_EN); /* TODO - if (netdev->flags & IFF_PROMISC) { - self.rx_ctrl |= MAC_CTRL_PROMISC_EN; + if (netdev->flags & IFF_PROMISC) { + self.rx_ctrl |= MAC_CTRL_PROMISC_EN; } - if (netdev->flags & IFF_ALLMULTI) { - self.rx_ctrl |= MAC_CTRL_MULTIALL_EN; + if (netdev->flags & IFF_ALLMULTI) { + self.rx_ctrl |= MAC_CTRL_MULTIALL_EN; } */ - self.write(MAC_CTRL, self.rx_ctrl); + self.write(MAC_CTRL, self.rx_ctrl); } unsafe fn set_vlan_mode(&mut self, vlan_rx: bool) { if (vlan_rx) { - self.rx_ctrl |= MAC_CTRL_VLANSTRIP; + self.rx_ctrl |= MAC_CTRL_VLANSTRIP; } else { - self.rx_ctrl &= !MAC_CTRL_VLANSTRIP; + self.rx_ctrl &= !MAC_CTRL_VLANSTRIP; } - self.write(MAC_CTRL, self.rx_ctrl); + self.write(MAC_CTRL, self.rx_ctrl); } unsafe fn configure_rss(&mut self, en: bool) { let mut ctrl: u32; - ctrl = self.read(RXQ0); + ctrl = self.read(RXQ0); - if (en) { + if (en) { unimplemented!(); /* - for (i = 0; i < sizeof(self.rss_key); i++) { - /* rss key should be saved in chip with - * reversed order. - */ - int j = sizeof(self.rss_key) - i - 1; + for (i = 0; i < sizeof(self.rss_key); i++) { + /* rss key should be saved in chip with + * reversed order. + */ + int j = sizeof(self.rss_key) - i - 1; - MEM_W8(hw, RSS_KEY0 + j, self.rss_key[i]); - } + MEM_W8(hw, RSS_KEY0 + j, self.rss_key[i]); + } - for (i = 0; i < ARRAY_SIZE(self.rss_idt); i++) - self.write(RSS_IDT_TBL0 + i * 4, - self.rss_idt[i]); + for (i = 0; i < ARRAY_SIZE(self.rss_idt); i++) + self.write(RSS_IDT_TBL0 + i * 4, + self.rss_idt[i]); - FIELD_SET32(ctrl, RXQ0_RSS_HSTYP, self.rss_hash_type); - FIELD_SET32(ctrl, RXQ0_RSS_MODE, RXQ0_RSS_MODE_MQMI); - FIELD_SET32(ctrl, RXQ0_IDT_TBL_SIZE, self.rss_idt_size); - ctrl |= RXQ0_RSS_HASH_EN; + FIELD_SET32(ctrl, RXQ0_RSS_HSTYP, self.rss_hash_type); + FIELD_SET32(ctrl, RXQ0_RSS_MODE, RXQ0_RSS_MODE_MQMI); + FIELD_SET32(ctrl, RXQ0_IDT_TBL_SIZE, self.rss_idt_size); + ctrl |= RXQ0_RSS_HASH_EN; */ - } else { - ctrl &= !RXQ0_RSS_HASH_EN; - } + } else { + ctrl &= !RXQ0_RSS_HASH_EN; + } - self.write(RXQ0, ctrl); + self.write(RXQ0, ctrl); } unsafe fn configure(&mut self) { @@ -1381,89 +1380,86 @@ impl Alx { } unsafe fn irq_enable(&mut self) { - self.write(ISR, 0); + self.write(ISR, 0); let imask = self.imask; self.write(IMR, imask); } unsafe fn irq_disable(&mut self) { self.write(ISR, ISR_DIS); - self.write(IMR, 0); + self.write(IMR, 0); } unsafe fn clear_phy_intr(&mut self) -> usize { - let mut isr: u16 = 0; - self.read_phy_reg(MII_ISR, &mut isr) + let mut isr: u16 = 0; + self.read_phy_reg(MII_ISR, &mut isr) } unsafe fn post_phy_link(&mut self, speed: u16, az_en: bool) { let mut phy_val: u16 = 0; let len: u16; let agc: u16; - let revid: u8 = self.revid(); - let adj_th: bool; + let revid: u8 = self.revid(); + let adj_th: bool; - if (revid != REV_B0 && - revid != REV_A1 && - revid != REV_A0) { - return; - } - adj_th = if (revid == REV_B0) { true } else { false }; + if (revid != REV_B0 && revid != REV_A1 && revid != REV_A0) { + return; + } + adj_th = if (revid == REV_B0) { true } else { false }; - /* 1000BT/AZ, wrong cable length */ - if (speed != SPEED_0) { - self.read_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL6, &mut phy_val); - len = FIELD_GETX!(phy_val, CLDCTRL6_CAB_LEN); - self.read_phy_dbg(MIIDBG_AGC, &mut phy_val); - agc = FIELD_GETX!(phy_val, AGC_2_VGA); + /* 1000BT/AZ, wrong cable length */ + if (speed != SPEED_0) { + self.read_phy_ext(MIIEXT_PCS, MIIEXT_CLDCTRL6, &mut phy_val); + len = FIELD_GETX!(phy_val, CLDCTRL6_CAB_LEN); + self.read_phy_dbg(MIIDBG_AGC, &mut phy_val); + agc = FIELD_GETX!(phy_val, AGC_2_VGA); - if ((speed == SPEED_1000 && - (len > CLDCTRL6_CAB_LEN_SHORT1G || - (0 == len && agc > AGC_LONG1G_LIMT))) || - (speed == SPEED_100 && - (len > CLDCTRL6_CAB_LEN_SHORT100M || - (0 == len && agc > AGC_LONG100M_LIMT)))) { - self.write_phy_dbg(MIIDBG_AZ_ANADECT, AZ_ANADECT_LONG); - self.read_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, &mut phy_val); - self.write_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, phy_val | AFE_10BT_100M_TH); - } else { - self.write_phy_dbg(MIIDBG_AZ_ANADECT, AZ_ANADECT_DEF); - self.read_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, &mut phy_val); - self.write_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, phy_val & !AFE_10BT_100M_TH); - } + if ((speed == SPEED_1000 + && (len > CLDCTRL6_CAB_LEN_SHORT1G || (0 == len && agc > AGC_LONG1G_LIMT))) + || (speed == SPEED_100 + && (len > CLDCTRL6_CAB_LEN_SHORT100M || (0 == len && agc > AGC_LONG100M_LIMT)))) + { + self.write_phy_dbg(MIIDBG_AZ_ANADECT, AZ_ANADECT_LONG); + self.read_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, &mut phy_val); + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, phy_val | AFE_10BT_100M_TH); + } else { + self.write_phy_dbg(MIIDBG_AZ_ANADECT, AZ_ANADECT_DEF); + self.read_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, &mut phy_val); + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, phy_val & !AFE_10BT_100M_TH); + } - /* threashold adjust */ - if (adj_th && self.lnk_patch) { - if (speed == SPEED_100) { - self.write_phy_dbg(MIIDBG_MSE16DB, MSE16DB_UP); - } else if (speed == SPEED_1000) { - /* - * Giga link threshold, raise the tolerance of - * noise 50% - */ - self.read_phy_dbg(MIIDBG_MSE20DB, &mut phy_val); - FIELD_SETS!(phy_val, MSE20DB_TH, MSE20DB_TH_HI); - self.write_phy_dbg(MIIDBG_MSE20DB, phy_val); - } - } - /* phy link-down in 1000BT/AZ mode */ - if (az_en && revid == REV_B0 && speed == SPEED_1000) { - self.write_phy_dbg(MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF & !SRDSYSMOD_DEEMP_EN); - } - } else { - self.read_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, &mut phy_val); - self.write_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, phy_val & !AFE_10BT_100M_TH); + /* threashold adjust */ + if (adj_th && self.lnk_patch) { + if (speed == SPEED_100) { + self.write_phy_dbg(MIIDBG_MSE16DB, MSE16DB_UP); + } else if (speed == SPEED_1000) { + /* + * Giga link threshold, raise the tolerance of + * noise 50% + */ + self.read_phy_dbg(MIIDBG_MSE20DB, &mut phy_val); + FIELD_SETS!(phy_val, MSE20DB_TH, MSE20DB_TH_HI); + self.write_phy_dbg(MIIDBG_MSE20DB, phy_val); + } + } + /* phy link-down in 1000BT/AZ mode */ + if (az_en && revid == REV_B0 && speed == SPEED_1000) { + self.write_phy_dbg(MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF & !SRDSYSMOD_DEEMP_EN); + } + } else { + self.read_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, &mut phy_val); + self.write_phy_ext(MIIEXT_ANEG, MIIEXT_AFE, phy_val & !AFE_10BT_100M_TH); - if (adj_th && self.lnk_patch) { - self.write_phy_dbg(MIIDBG_MSE16DB, MSE16DB_DOWN); - self.read_phy_dbg(MIIDBG_MSE20DB, &mut phy_val); - FIELD_SETS!(phy_val, MSE20DB_TH, MSE20DB_TH_DEF); - self.write_phy_dbg(MIIDBG_MSE20DB, phy_val); - } - if (az_en && revid == REV_B0) { - self.write_phy_dbg(MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF); - } - } + if (adj_th && self.lnk_patch) { + self.write_phy_dbg(MIIDBG_MSE16DB, MSE16DB_DOWN); + self.read_phy_dbg(MIIDBG_MSE20DB, &mut phy_val); + FIELD_SETS!(phy_val, MSE20DB_TH, MSE20DB_TH_DEF); + self.write_phy_dbg(MIIDBG_MSE20DB, phy_val); + } + if (az_en && revid == REV_B0) { + self.write_phy_dbg(MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF); + } + } } unsafe fn task(&mut self) { @@ -1502,25 +1498,25 @@ impl Alx { unsafe fn activate(&mut self) { /* hardware setting lost, restore it */ self.init_ring_ptrs(); - self.configure(); + self.configure(); self.flag &= !FLAG_HALT; - /* clear old interrupts */ + /* clear old interrupts */ self.write(ISR, !ISR_DIS); - self.irq_enable(); + self.irq_enable(); self.flag |= FLAG_TASK_CHK_LINK; self.task(); } unsafe fn reinit(&mut self) { - if self.flag & FLAG_HALT > 0 { - return; + if self.flag & FLAG_HALT > 0 { + return; } - self.halt(); - self.activate(); + self.halt(); + self.activate(); } unsafe fn init_ring_ptrs(&mut self) { @@ -1530,8 +1526,12 @@ impl Alx { // RFD ring for i in 0..self.rfd_ring.len() { - self.rfd_ring[i].addr_low.write(self.rfd_buffer[i].physical() as u32); - self.rfd_ring[i].addr_high.write(((self.rfd_buffer[i].physical() as u64) >> 32) as u32); + self.rfd_ring[i] + .addr_low + .write(self.rfd_buffer[i].physical() as u32); + self.rfd_ring[i] + .addr_high + .write(((self.rfd_buffer[i].physical() as u64) >> 32) as u32); } self.write(RFD_ADDR_LO, self.rfd_ring.physical() as u32); self.write(RFD_RING_SZ, self.rfd_ring.len() as u32); @@ -1555,104 +1555,104 @@ impl Alx { unsafe fn check_link(&mut self) { let mut speed: u16 = SPEED_0; let old_speed: u16; - let mut link_up: bool = false; + let mut link_up: bool = false; let old_link_up: bool; - let mut err: usize; + let mut err: usize; - if (self.flag & FLAG_HALT > 0) { - return; + if (self.flag & FLAG_HALT > 0) { + return; } macro_rules! goto_out { () => { if (err > 0) { self.flag |= FLAG_TASK_RESET; - self.task(); - } + self.task(); + } return; - } + }; } - /* clear PHY internal interrupt status, - * otherwise the Main interrupt status will be asserted - * for ever. - */ + /* clear PHY internal interrupt status, + * otherwise the Main interrupt status will be asserted + * for ever. + */ self.clear_phy_intr(); - err = self.get_phy_link(&mut link_up, &mut speed); - if (err > 0) { + err = self.get_phy_link(&mut link_up, &mut speed); + if (err > 0) { goto_out!(); } - /* open interrutp mask */ - self.imask |= ISR_PHY; + /* open interrutp mask */ + self.imask |= ISR_PHY; let imask = self.imask; - self.write(IMR, imask); + self.write(IMR, imask); - if (!link_up && !self.link_up) { - goto_out!(); + if (!link_up && !self.link_up) { + goto_out!(); } - old_speed = self.link_speed + self.link_duplex as u16; - old_link_up = self.link_up; + old_speed = self.link_speed + self.link_duplex as u16; + old_link_up = self.link_up; - if (link_up) { - /* same speed ? */ - if (old_link_up && old_speed == speed) { - goto_out!(); + if (link_up) { + /* same speed ? */ + if (old_link_up && old_speed == speed) { + goto_out!(); } - self.show_speed(speed); - self.link_duplex = (speed % 10) as u8; - self.link_speed = speed - self.link_duplex as u16; - self.link_up = true; + self.show_speed(speed); + self.link_duplex = (speed % 10) as u8; + self.link_speed = speed - self.link_duplex as u16; + self.link_up = true; let link_speed = self.link_speed; let az_en = self.cap & CAP_AZ > 0; - self.post_phy_link(link_speed, az_en); + self.post_phy_link(link_speed, az_en); let l0s_en = self.cap & CAP_L0S > 0; let l1_en = self.cap & CAP_L1 > 0; - self.enable_aspm(l0s_en, l1_en); - self.start_mac(); + self.enable_aspm(l0s_en, l1_en); + self.start_mac(); - /* link kept, just speed changed */ - if (old_link_up) { - goto_out!(); + /* link kept, just speed changed */ + if (old_link_up) { + goto_out!(); } - /* link changed from 'down' to 'up' */ - // TODO self.netif_start(); - goto_out!(); - } + /* link changed from 'down' to 'up' */ + // TODO self.netif_start(); + goto_out!(); + } - /* link changed from 'up' to 'down' */ - // TODO self.netif_stop(); - self.link_up = false; - self.link_speed = SPEED_0; - println!("NIC Link Down"); - err = self.reset_mac(); - if (err > 0) { - println!("linkdown:reset_mac fail {}", err); - err = (-EIO) as usize; - goto_out!(); - } - self.irq_disable(); + /* link changed from 'up' to 'down' */ + // TODO self.netif_stop(); + self.link_up = false; + self.link_speed = SPEED_0; + println!("NIC Link Down"); + err = self.reset_mac(); + if (err > 0) { + println!("linkdown:reset_mac fail {}", err); + err = (-EIO) as usize; + goto_out!(); + } + self.irq_disable(); - /* reset-mac cause all settings on HW lost, - * following steps restore all of them and - * refresh whole RX/TX rings - */ - self.init_ring_ptrs(); + /* reset-mac cause all settings on HW lost, + * following steps restore all of them and + * refresh whole RX/TX rings + */ + self.init_ring_ptrs(); - self.configure(); + self.configure(); let l1_en = self.cap & CAP_L1 > 0; - self.enable_aspm(false, l1_en); + self.enable_aspm(false, l1_en); let cap_az = self.cap & CAP_AZ > 0; - self.post_phy_link(SPEED_0, cap_az); + self.post_phy_link(SPEED_0, cap_az); - self.irq_enable(); + self.irq_enable(); - goto_out!(); + goto_out!(); } unsafe fn get_phy_info(&mut self) -> bool { @@ -1660,22 +1660,22 @@ impl Alx { let mut devs1: u16 = 0; let mut devs2: u16 = 0; - if (self.read_phy_reg(MII_PHYSID1, &mut self.phy_id[0]) > 0 || - self.read_phy_reg(MII_PHYSID2, &mut self.phy_id[1]) > 0) { - return false; + if (self.read_phy_reg(MII_PHYSID1, &mut self.phy_id[0]) > 0 || + self.read_phy_reg(MII_PHYSID2, &mut self.phy_id[1]) > 0) { + return false; } - /* since we haven't PMA/PMD status2 register, we can't - * use mdio45_probe function for prtad and mmds. - * use fixed MMD3 to get mmds. - */ - if (self.read_phy_ext(3, MDIO_DEVS1, &devs1) || - self.read_phy_ext(3, MDIO_DEVS2, &devs2)) { - return false; + /* since we haven't PMA/PMD status2 register, we can't + * use mdio45_probe function for prtad and mmds. + * use fixed MMD3 to get mmds. + */ + if (self.read_phy_ext(3, MDIO_DEVS1, &devs1) || + self.read_phy_ext(3, MDIO_DEVS2, &devs2)) { + return false; } - self.mdio.mmds = devs1 | devs2 << 16; + self.mdio.mmds = devs1 | devs2 << 16; - return true; + return true; */ return true; } @@ -1704,9 +1704,12 @@ impl Alx { } let mac = self.get_perm_macaddr(); - println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + println!( + " - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + ); - if ! self.get_phy_info() { + if !self.get_phy_info() { println!(" - Identify PHY failed"); return Err(Error::new(EIO)); } @@ -1727,28 +1730,28 @@ impl Alx { macro_rules! goto_out { () => {{ - self.free_all_ring_resources(); - self.disable_advanced_intr(); - return err; - }} + self.free_all_ring_resources(); + self.disable_advanced_intr(); + return err; + }}; } - /* allocate all memory resources */ - self.init_ring_ptrs(); + /* allocate all memory resources */ + self.init_ring_ptrs(); - /* make hardware ready before allocate interrupt */ - self.configure(); + /* make hardware ready before allocate interrupt */ + self.configure(); self.flag &= !FLAG_HALT; - /* clear old interrupts */ + /* clear old interrupts */ self.write(ISR, !ISR_DIS); - self.irq_enable(); + self.irq_enable(); self.flag |= FLAG_TASK_CHK_LINK; - self.task(); - return 0; + self.task(); + return 0; } unsafe fn init(&mut self) -> Result<()> { @@ -1773,10 +1776,10 @@ impl Alx { self.dma_chnl = if self.revid() >= REV_B0 { 4 } else { 2 }; } - println!(" - ID: {:>04X}:{:>04X} SUB: {:>04X}:{:>04X} REV: {:>02X}", - self.vendor_id, self.device_id, - self.subven_id, self.subdev_id, - self.revision); + println!( + " - ID: {:>04X}:{:>04X} SUB: {:>04X}:{:>04X} REV: {:>02X}", + self.vendor_id, self.device_id, self.subven_id, self.subdev_id, self.revision + ); self.probe()?; @@ -1800,7 +1803,7 @@ impl scheme::SchemeMut for Alx { } fn dup(&mut self, id: usize, buf: &[u8]) -> Result { - if ! buf.is_empty() { + if !buf.is_empty() { return Err(Error::new(EINVAL)); } diff --git a/net/alxd/src/device/regs.rs b/net/alxd/src/device/regs.rs index fed2169067..774c1aca48 100644 --- a/net/alxd/src/device/regs.rs +++ b/net/alxd/src/device/regs.rs @@ -421,10 +421,7 @@ pub const PHY_CTRL_RTL_MODE: u32 = 1 << 1; /* bit0: out of dsp RST state */ pub const PHY_CTRL_DSPRST_OUT: u32 = 1 << 0; pub const PHY_CTRL_DSPRST_TO: u32 = 80; -pub const PHY_CTRL_CLS: u32 = - PHY_CTRL_LED_MODE | - PHY_CTRL_100AB_EN | - PHY_CTRL_PLL_ON; +pub const PHY_CTRL_CLS: u32 = PHY_CTRL_LED_MODE | PHY_CTRL_100AB_EN | PHY_CTRL_PLL_ON; pub const MAC_STS: u32 = 0x1410; pub const MAC_STS_SFORCE_MASK: u32 = 0xF; @@ -439,10 +436,7 @@ pub const MAC_STS_RXQ_BUSY: u32 = 1 << 2; pub const MAC_STS_TXMAC_BUSY: u32 = 1 << 1; pub const MAC_STS_RXMAC_BUSY: u32 = 1 << 0; pub const MAC_STS_IDLE: u32 = - MAC_STS_TXQ_BUSY | - MAC_STS_RXQ_BUSY | - MAC_STS_TXMAC_BUSY | - MAC_STS_RXMAC_BUSY; + MAC_STS_TXQ_BUSY | MAC_STS_RXQ_BUSY | MAC_STS_TXMAC_BUSY | MAC_STS_RXMAC_BUSY; pub const MDIO: u32 = 0x1414; pub const MDIO_MODE_EXT: u32 = 1 << 30; @@ -876,7 +870,7 @@ pub const SRAM_RXF_HEAD_ADDR_SHIFT: u32 = 0; pub const SRAM5: u32 = 0x1524; pub const SRAM_RXF_LEN_MASK: u32 = 0xFFF; pub const SRAM_RXF_LEN_SHIFT: u32 = 0; -pub const SRAM_RXF_LEN_8K: u32 = (8*1024); +pub const SRAM_RXF_LEN_8K: u32 = (8 * 1024); pub const SRAM6: u32 = 0x1528; pub const SRAM_TXF_TAIL_ADDR_MASK: u32 = 0xFFF; @@ -955,7 +949,7 @@ pub const TXQ1_ERRLGPKT_DROP_EN: u32 = 1 << 11; /* bit[9:0]:: u32 = 8bytes unit */ pub const TXQ1_JUMBO_TSOTHR_MASK: u32 = 0x7FF; pub const TXQ1_JUMBO_TSOTHR_SHIFT: u32 = 0; -pub const TXQ1_JUMBO_TSO_TH: u32 = (7*1024); +pub const TXQ1_JUMBO_TSO_TH: u32 = (7 * 1024); /* L1 entrance control */ pub const TXQ2: u32 = 0x1598; @@ -990,11 +984,10 @@ pub const RXQ0_RSS_HSTYP_IPV6_TCP_EN: u32 = 1 << 5; pub const RXQ0_RSS_HSTYP_IPV6_EN: u32 = 1 << 4; pub const RXQ0_RSS_HSTYP_IPV4_TCP_EN: u32 = 1 << 3; pub const RXQ0_RSS_HSTYP_IPV4_EN: u32 = 1 << 2; -pub const RXQ0_RSS_HSTYP_ALL: u32 = - RXQ0_RSS_HSTYP_IPV6_TCP_EN | - RXQ0_RSS_HSTYP_IPV4_TCP_EN | - RXQ0_RSS_HSTYP_IPV6_EN | - RXQ0_RSS_HSTYP_IPV4_EN; +pub const RXQ0_RSS_HSTYP_ALL: u32 = RXQ0_RSS_HSTYP_IPV6_TCP_EN + | RXQ0_RSS_HSTYP_IPV4_TCP_EN + | RXQ0_RSS_HSTYP_IPV6_EN + | RXQ0_RSS_HSTYP_IPV4_EN; pub const RXQ0_ASPM_THRESH_MASK: u32 = 0x3; pub const RXQ0_ASPM_THRESH_SHIFT: u32 = 0; pub const RXQ0_ASPM_THRESH_NO: u32 = 0; @@ -1223,7 +1216,6 @@ pub const INT_DEASST_TIMER: u32 = 0x1614; pub const PATTERN_MASK: u32 = 0x1620; pub const PATTERN_MASK_LEN: u32 = 128; - pub const FLT1_SRC_IP0: u32 = 0x1A00; pub const FLT1_SRC_IP1: u32 = 0x1A04; pub const FLT1_SRC_IP2: u32 = 0x1A08; @@ -1392,12 +1384,7 @@ pub const CLK_GATE_TXQ: u32 = 1 << 2; pub const CLK_GATE_DMAR: u32 = 1 << 1; pub const CLK_GATE_DMAW: u32 = 1 << 0; pub const CLK_GATE_ALL_A0: u32 = - CLK_GATE_RXMAC | - CLK_GATE_TXMAC | - CLK_GATE_RXQ | - CLK_GATE_TXQ | - CLK_GATE_DMAR | - CLK_GATE_DMAW; + CLK_GATE_RXMAC | CLK_GATE_TXMAC | CLK_GATE_RXQ | CLK_GATE_TXQ | CLK_GATE_DMAR | CLK_GATE_DMAW; pub const CLK_GATE_ALL_B0: u32 = CLK_GATE_ALL_A0; /* PORST affect */ @@ -1834,7 +1821,6 @@ pub const CR_DMA_CTRL_WEARLY_EN: u32 = 1 << 8; pub const CR_DMA_CTRL_RXTH_MASK: u32 = 0xF; pub const CR_DMA_CTRL_WTH_MASK: u32 = 0xF; - pub const EFUSE_BIST: u32 = 0x1934; pub const EFUSE_BIST_COL_MASK: u32 = 0x3F; pub const EFUSE_BIST_COL_SHIFT: u32 = 24; @@ -1988,7 +1974,6 @@ pub const IO_MDIO: u32 = 0x38; /* same as reg140C */ pub const IO_PHY_CTRL: u32 = 0x3C; - /********************* PHY regs definition ***************************/ /* Autoneg Advertisement Register */ @@ -2043,7 +2028,6 @@ pub const CDTC_EN: u16 = 1; pub const CDTC_PAIR_MASK: u16 = 0x3; pub const CDTC_PAIR_SHIFT: u16 = 8; - /* Cable-Detect-Test Status Register */ pub const MII_CDTS: u16 = 0x1C; pub const CDTS_STATUS_MASK: u16 = 0x3; @@ -2080,7 +2064,6 @@ pub const ANACTRL_MANUSWON_BW3_4M: u16 = 0x0002; pub const ANACTRL_RESTART_CAL: u16 = 0x0001; pub const ANACTRL_DEF: u16 = 0x02EF; - pub const MIIDBG_SYSMODCTRL: u16 = 0x04; pub const SYSMODCTRL_IECHOADJ_PFMH_PHY: u16 = 0x8000; pub const SYSMODCTRL_IECHOADJ_BIASGEN: u16 = 0x4000; @@ -2100,7 +2083,6 @@ pub const SYSMODCTRL_IECHOADJ_VDLANSW: u16 = 0x0001; /* en half bias */ pub const SYSMODCTRL_IECHOADJ_DEF: u16 = 0xBB8B; - pub const MIIDBG_SRDSYSMOD: u16 = 0x05; pub const SRDSYSMOD_LCKDET_EN: u16 = 0x2000; pub const SRDSYSMOD_PLL_EN: u16 = 0x0800; @@ -2114,7 +2096,6 @@ pub const SRDSYSMOD_CDR_ADC_VLTG: u16 = 0x0002; pub const SRDSYSMOD_CDR_DAC_1MA: u16 = 0x0001; pub const SRDSYSMOD_DEF: u16 = 0x2C46; - pub const MIIDBG_HIBNEG: u16 = 0x0B; pub const HIBNEG_PSHIB_EN: u16 = 0x8000; pub const HIBNEG_WAKE_BOTH: u16 = 0x4000; @@ -2204,7 +2185,6 @@ pub const MIIDBG_GREENCFG2: u16 = 0x3D; pub const GREENCFG2_BP_GREEN: u16 = 0x8000; pub const GREENCFG2_GATE_DFSE_EN: u16 = 0x0080; - /***************************** extension **************************************/ /******* dev 3 *********/ @@ -2292,4 +2272,4 @@ pub const MIIEXT_NLP56_DEF: u16 = 0x1010; pub const MIIEXT_NLP78: u16 = 0x8027; /* for: u16 = 160m */ pub const MIIEXT_NLP78_160M_DEF: u16 = 0x8D05; -pub const MIIEXT_NLP78_120M_DEF : u16 = 0x8A05; +pub const MIIEXT_NLP78_120M_DEF: u16 = 0x8A05; diff --git a/net/alxd/src/main.rs b/net/alxd/src/main.rs index e6c54024aa..f87d256dba 100644 --- a/net/alxd/src/main.rs +++ b/net/alxd/src/main.rs @@ -6,16 +6,16 @@ extern crate event; extern crate syscall; -use std::{env, iter}; use std::fs::File; use std::io::{Read, Write}; use std::os::fd::AsRawFd; use std::os::unix::io::{FromRawFd, RawFd}; +use std::{env, iter}; use event::{user_data, EventQueue}; use libredox::flag; -use syscall::{Packet, SchemeMut}; use syscall::error::EWOULDBLOCK; +use syscall::{Packet, SchemeMut}; pub mod device; @@ -35,16 +35,31 @@ fn main() { // Daemonize redox_daemon::Daemon::new(move |daemon| { - let socket_fd = libredox::call::open(":network", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, 0).expect("alxd: failed to create network scheme"); + let socket_fd = libredox::call::open( + ":network", + flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, + 0, + ) + .expect("alxd: failed to create network scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; daemon.ready().expect("alxd: failed to signal readiness"); - let mut irq_file = File::open(format!("/scheme/irq/{}", irq)).expect("alxd: failed to open IRQ file"); + let mut irq_file = + File::open(format!("/scheme/irq/{}", irq)).expect("alxd: failed to open IRQ file"); - let address = unsafe { common::physmap(bar, 128*1024, common::Prot::RW, common::MemoryType::Uncacheable).expect("alxd: failed to map address") as usize }; + let address = unsafe { + common::physmap( + bar, + 128 * 1024, + common::Prot::RW, + common::MemoryType::Uncacheable, + ) + .expect("alxd: failed to map address") as usize + }; { - let mut device = unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") }; + let mut device = + unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") }; user_data! { enum Source { @@ -53,15 +68,26 @@ fn main() { } } - let event_queue = EventQueue::::new().expect("alxd: failed to create event queue"); - event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); - event_queue.subscribe(socket_fd, Source::Scheme, event::EventFlags::READ).unwrap(); + let event_queue = + EventQueue::::new().expect("alxd: failed to create event queue"); + event_queue + .subscribe( + irq_file.as_raw_fd() as usize, + Source::Irq, + event::EventFlags::READ, + ) + .unwrap(); + event_queue + .subscribe(socket_fd, Source::Scheme, event::EventFlags::READ) + .unwrap(); libredox::call::setrens(0, 0).expect("alxd: failed to enter null namespace"); let mut todo = Vec::::new(); - for event in iter::once(Source::Scheme).chain(event_queue.map(|e| e.expect("alxd: failed to get next event").user_data)) { + for event in iter::once(Source::Scheme) + .chain(event_queue.map(|e| e.expect("alxd: failed to get next event").user_data)) + { match event { Source::Irq => { let mut irq = [0; 8]; @@ -77,7 +103,9 @@ fn main() { todo[i].a = a; i += 1; } else { - socket.write(&mut todo[i]).expect("alxd: failed to write to socket"); + socket + .write(&mut todo[i]) + .expect("alxd: failed to write to socket"); todo.remove(i); } } @@ -93,7 +121,11 @@ fn main() { Source::Scheme => { loop { let mut packet = Packet::default(); - if socket.read(&mut packet).expect("alxd: failed read from socket") == 0 { + if socket + .read(&mut packet) + .expect("alxd: failed read from socket") + == 0 + { break; } @@ -103,7 +135,9 @@ fn main() { packet.a = a; todo.push(packet); } else { - socket.write(&mut packet).expect("alxd: failed to write to socket"); + socket + .write(&mut packet) + .expect("alxd: failed to write to socket"); } } @@ -119,5 +153,6 @@ fn main() { } } std::process::exit(0); - }).expect("alxd: failed to daemonize"); + }) + .expect("alxd: failed to daemonize"); } diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index 1ed1608237..ca506185c3 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -49,9 +49,19 @@ fn main() { let mut event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); - event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ) + event_queue + .subscribe( + irq_file.as_raw_fd() as usize, + Source::Irq, + event::EventFlags::READ, + ) .expect("e1000d: failed to subscribe to IRQ fd"); - event_queue.subscribe(scheme.event_handle() as usize, Source::Scheme, event::EventFlags::READ) + event_queue + .subscribe( + scheme.event_handle() as usize, + Source::Scheme, + event::EventFlags::READ, + ) .expect("e1000d: failed to subscribe to scheme fd"); libredox::call::setrens(0, 0).expect("e1000d: failed to enter null namespace"); diff --git a/net/ixgbed/src/device.rs b/net/ixgbed/src/device.rs index a61441bca3..0d59b46d34 100644 --- a/net/ixgbed/src/device.rs +++ b/net/ixgbed/src/device.rs @@ -55,8 +55,8 @@ impl NetworkAdapter for Intel8259x { let i = cmp::min(buf.len(), data.len()); buf[..i].copy_from_slice(&data[..i]); - desc.read.pkt_addr = self.receive_buffer[self.receive_index].physical() as u64; - desc.read.hdr_addr = 0; + desc.read.pkt_addr = self.receive_buffer[self.receive_index].physical() as u64; + desc.read.hdr_addr = 0; self.write_reg(IXGBE_RDT(0), self.receive_index as u32); self.receive_index = wrap_ring(self.receive_index, self.receive_ring.len()); @@ -103,14 +103,14 @@ impl NetworkAdapter for Intel8259x { let i = cmp::min(buf.len(), data.len()); data[..i].copy_from_slice(&buf[..i]); - desc.read.cmd_type_len = IXGBE_ADVTXD_DCMD_EOP - | IXGBE_ADVTXD_DCMD_RS - | IXGBE_ADVTXD_DCMD_IFCS - | IXGBE_ADVTXD_DCMD_DEXT - | IXGBE_ADVTXD_DTYP_DATA - | buf.len() as u32; + desc.read.cmd_type_len = IXGBE_ADVTXD_DCMD_EOP + | IXGBE_ADVTXD_DCMD_RS + | IXGBE_ADVTXD_DCMD_IFCS + | IXGBE_ADVTXD_DCMD_DEXT + | IXGBE_ADVTXD_DTYP_DATA + | buf.len() as u32; - desc.read.olinfo_status = (buf.len() as u32) << IXGBE_ADVTXD_PAYLEN_SHIFT; + desc.read.olinfo_status = (buf.len() as u32) << IXGBE_ADVTXD_PAYLEN_SHIFT; self.transmit_index = wrap_ring(self.transmit_index, self.transmit_ring.len()); self.transmit_ring_free -= 1; @@ -290,7 +290,10 @@ impl Intel8259x { self.wait_write_reg(IXGBE_EEC, IXGBE_EEC_ARD); // section 4.6.3 - wait for dma initialization done - self.wait_write_reg(IXGBE_RDRXCTL, IXGBE_RDRXCTL_DMAIDONE | IXGBE_RDRXCTL_RESERVED_BITS); + self.wait_write_reg( + IXGBE_RDRXCTL, + IXGBE_RDRXCTL_DMAIDONE | IXGBE_RDRXCTL_RESERVED_BITS, + ); // section 4.6.4 - initialize link (auto negotiation) self.init_link(); @@ -361,7 +364,10 @@ impl Intel8259x { self.write_reg(IXGBE_RDBAL(i), self.receive_ring.physical() as u32); - self.write_reg(IXGBE_RDBAH(i), ((self.receive_ring.physical() as u64) >> 32) as u32); + self.write_reg( + IXGBE_RDBAH(i), + ((self.receive_ring.physical() as u64) >> 32) as u32, + ); self.write_reg( IXGBE_RDLEN(i), (self.receive_ring.len() * mem::size_of::()) as u32, @@ -407,7 +413,10 @@ impl Intel8259x { // section 7.1.9 - setup descriptor ring self.write_reg(IXGBE_TDBAL(i), self.transmit_ring.physical() as u32); - self.write_reg(IXGBE_TDBAH(i), ((self.transmit_ring.physical() as u64) >> 32) as u32); + self.write_reg( + IXGBE_TDBAH(i), + ((self.transmit_ring.physical() as u64) >> 32) as u32, + ); self.write_reg( IXGBE_TDLEN(i), (self.transmit_ring.len() * mem::size_of::()) as u32, diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index 8382823230..cd4090c319 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -47,9 +47,22 @@ fn main() { } } - let mut event_queue = EventQueue::::new().expect("ixgbed: Could not create event queue."); - event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); - event_queue.subscribe(scheme.event_handle() as usize, Source::Scheme, event::EventFlags::READ).unwrap(); + let mut event_queue = + EventQueue::::new().expect("ixgbed: Could not create event queue."); + event_queue + .subscribe( + irq_file.as_raw_fd() as usize, + Source::Irq, + event::EventFlags::READ, + ) + .unwrap(); + event_queue + .subscribe( + scheme.event_handle() as usize, + Source::Scheme, + event::EventFlags::READ, + ) + .unwrap(); libredox::call::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); diff --git a/net/rtl8139d/src/device.rs b/net/rtl8139d/src/device.rs index d67a1b3078..43ce16d26c 100644 --- a/net/rtl8139d/src/device.rs +++ b/net/rtl8139d/src/device.rs @@ -1,11 +1,11 @@ -use std::mem; use std::convert::TryInto; +use std::mem; use driver_network::NetworkAdapter; -use syscall::error::{Error, EIO, EMSGSIZE, Result}; +use syscall::error::{Error, Result, EIO, EMSGSIZE}; -use common::io::{Mmio, Io, ReadOnly}; use common::dma::Dma; +use common::io::{Io, Mmio, ReadOnly}; const RX_BUFFER_SIZE: usize = 64 * 1024; @@ -135,16 +135,11 @@ impl NetworkAdapter for Rtl8139 { self.next_read() } - fn read_packet(&mut self, buf: &mut [u8]) -> Result> { if !self.regs.cr.readf(CR_BUFE) { - let rxsts = - (self.rx(0) as u16) | - (self.rx(1) as u16) << 8; + let rxsts = (self.rx(0) as u16) | (self.rx(1) as u16) << 8; - let size_with_crc = - (self.rx(2) as usize) | - (self.rx(3) as usize) << 8; + let size_with_crc = (self.rx(2) as usize) | (self.rx(3) as usize) << 8; let res = if (rxsts & RXSTS_ROK) == RXSTS_ROK { let mut i = 0; @@ -159,7 +154,8 @@ impl NetworkAdapter for Rtl8139 { Err(Error::new(EIO)) }; - self.receive_i = (self.receive_i + 4 + size_with_crc).next_multiple_of(4) % RX_BUFFER_SIZE; + self.receive_i = + (self.receive_i + 4 + size_with_crc).next_multiple_of(4) % RX_BUFFER_SIZE; let capr = self.receive_i.wrapping_sub(16) as u16; self.regs.capr.write(capr); @@ -243,13 +239,9 @@ impl Rtl8139 { pub fn next_read(&self) -> usize { if !self.regs.cr.readf(CR_BUFE) { - let rxsts = - (self.rx(0) as u16) | - (self.rx(1) as u16) << 8; + let rxsts = (self.rx(0) as u16) | (self.rx(1) as u16) << 8; - let size_with_crc = - (self.rx(2) as usize) | - (self.rx(3) as usize) << 8; + let size_with_crc = (self.rx(2) as usize) | (self.rx(3) as usize) << 8; if (rxsts & RXSTS_ROK) == RXSTS_ROK { size_with_crc.saturating_sub(4) @@ -264,13 +256,18 @@ impl Rtl8139 { pub unsafe fn init(&mut self) { let mac_low = self.regs.mac[0].read(); let mac_high = self.regs.mac[1].read(); - let mac = [mac_low as u8, - (mac_low >> 8) as u8, - (mac_low >> 16) as u8, - (mac_low >> 24) as u8, - mac_high as u8, - (mac_high >> 8) as u8]; - println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + let mac = [ + mac_low as u8, + (mac_low >> 8) as u8, + (mac_low >> 16) as u8, + (mac_low >> 24) as u8, + mac_high as u8, + (mac_high >> 8) as u8, + ]; + println!( + " - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + ); self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value @@ -282,13 +279,17 @@ impl Rtl8139 { // Set up rx buffer println!(" - Receive buffer"); - self.regs.rbstart.write(self.receive_buffer.physical() as u32); + self.regs + .rbstart + .write(self.receive_buffer.physical() as u32); println!(" - Interrupt mask"); self.regs.imr.write(IMR_TOK | IMR_ROK); println!(" - Receive configuration"); - self.regs.rcr.write(RCR_RBLEN_64K | RCR_AB | RCR_AM | RCR_APM | RCR_AAP); + self.regs + .rcr + .write(RCR_RBLEN_64K | RCR_AB | RCR_AM | RCR_APM | RCR_AAP); println!(" - Enable RX and TX"); self.regs.cr.writef(CR_RE | CR_TE, true); diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 4f85e1b96f..c6db719c9d 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -53,14 +53,19 @@ impl MappedMsixRegs { fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.config(); - let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8139d: failed to fetch pci features"); + let all_pci_features = pcid_handle + .fetch_all_features() + .expect("rtl8139d: failed to fetch pci features"); log::info!("PCI FEATURES: {:?}", all_pci_features); let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); if has_msi && !has_msix { - let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("rtl8139d: failed to retrieve the MSI capability structure from pcid") { + let capability = match pcid_handle + .feature_info(PciFeature::Msi) + .expect("rtl8139d: failed to retrieve the MSI capability structure from pcid") + { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), }; @@ -70,21 +75,29 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. let destination_id = read_bsp_apic_id().expect("rtl8139d: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = allocate_single_interrupt_vector_for_msi(destination_id); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); let set_feature_info = MsiSetFeatureInfo { multi_message_enable: Some(0), message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("rtl8139d: failed to set feature info"); + pcid_handle + .set_feature_info(SetFeatureInfo::Msi(set_feature_info)) + .expect("rtl8139d: failed to set feature info"); - pcid_handle.enable_feature(PciFeature::Msi).expect("rtl8139d: failed to enable MSI"); + pcid_handle + .enable_feature(PciFeature::Msi) + .expect("rtl8139d: failed to enable MSI"); log::info!("Enabled MSI"); interrupt_handle } else if has_msix { - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8139d: failed to retrieve the MSI-X capability structure from pcid") { + let msix_info = match pcid_handle + .feature_info(PciFeature::MsiX) + .expect("rtl8139d: failed to retrieve the MSI-X capability structure from pcid") + { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; @@ -94,7 +107,8 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { .ptr .as_ptr() as usize; - let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; + let virt_table_base = + (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; let mut info = MappedMsixRegs { virt_table_base: NonNull::new(virt_table_base).unwrap(), @@ -119,7 +133,9 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { interrupt_handle }; - pcid_handle.enable_feature(PciFeature::MsiX).expect("rtl8139d: failed to enable MSI-X"); + pcid_handle + .enable_feature(PciFeature::MsiX) + .expect("rtl8139d: failed to enable MSI-X"); log::info!("Enabled MSI-X"); method @@ -148,14 +164,12 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { // RTL8139 uses BAR2, RTL8169 uses BAR1, search in that order for &barnum in &[2, 1] { match pci_config.func.bars[barnum] { - pcid_interface::PciBar::Memory32 { addr, size } => return Some(( - addr.try_into().unwrap(), - size.try_into().unwrap() - )), - pcid_interface::PciBar::Memory64 { addr, size } => return Some(( - addr.try_into().unwrap(), - size.try_into().unwrap() - )), + pcid_interface::PciBar::Memory32 { addr, size } => { + return Some((addr.try_into().unwrap(), size.try_into().unwrap())) + } + pcid_interface::PciBar::Memory64 { addr, size } => { + return Some((addr.try_into().unwrap(), size.try_into().unwrap())) + } other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), } } @@ -171,7 +185,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::LevelFilter::Info, ); - let mut pcid_handle = PciFunctionHandle::connect_default().expect("rtl8139d: failed to setup channel to pcid"); + let mut pcid_handle = + PciFunctionHandle::connect_default().expect("rtl8139d: failed to setup channel to pcid"); let pci_config = pcid_handle.config(); @@ -182,8 +197,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::info!(" + RTL8139 {}", pci_config.func.display()); let address = unsafe { - common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) - .expect("rtl8139d: failed to map address") as usize + common::physmap( + bar_ptr, + bar_size, + common::Prot::RW, + common::MemoryType::Uncacheable, + ) + .expect("rtl8139d: failed to map address") as usize }; //TODO: MSI-X @@ -201,9 +221,22 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - let mut event_queue = EventQueue::::new().expect("rtl8139d: Could not create event queue."); - event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); - event_queue.subscribe(scheme.event_handle() as usize, Source::Scheme, event::EventFlags::READ).unwrap(); + let mut event_queue = + EventQueue::::new().expect("rtl8139d: Could not create event queue."); + event_queue + .subscribe( + irq_file.as_raw_fd() as usize, + Source::Irq, + event::EventFlags::READ, + ) + .unwrap(); + event_queue + .subscribe( + scheme.event_handle() as usize, + Source::Scheme, + event::EventFlags::READ, + ) + .unwrap(); libredox::call::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); diff --git a/net/rtl8168d/src/device.rs b/net/rtl8168d/src/device.rs index b2aef1889e..c813f06b80 100644 --- a/net/rtl8168d/src/device.rs +++ b/net/rtl8168d/src/device.rs @@ -1,9 +1,9 @@ -use std::mem; use std::convert::TryInto; +use std::mem; +use common::io::{Io, Mmio, ReadOnly}; use driver_network::NetworkAdapter; use syscall::error::{Error, Result, EMSGSIZE}; -use common::io::{Mmio, Io, ReadOnly}; use common::dma::Dma; @@ -89,14 +89,13 @@ impl NetworkAdapter for Rtl8168 { self.next_read() } - fn read_packet(&mut self, buf: &mut [u8]) -> Result> { if self.receive_i >= self.receive_ring.len() { self.receive_i = 0; } let rd = &mut self.receive_ring[self.receive_i]; - if ! rd.ctrl.readf(OWN) { + if !rd.ctrl.readf(OWN) { let rd_len = rd.ctrl.read() & 0x3FFF; let data = &self.receive_buffer[self.receive_i]; @@ -125,7 +124,7 @@ impl NetworkAdapter for Rtl8168 { } let td = &mut self.transmit_ring[self.transmit_i]; - if ! td.ctrl.readf(OWN) { + if !td.ctrl.readf(OWN) { let data = &mut self.transmit_buffer[self.transmit_i]; if buf.len() > data.len() { @@ -214,7 +213,7 @@ impl Rtl8168 { } let rd = &self.receive_ring[receive_i]; - if ! rd.ctrl.readf(OWN) { + if !rd.ctrl.readf(OWN) { (rd.ctrl.read() & 0x3FFF) as usize } else { 0 @@ -224,13 +223,18 @@ impl Rtl8168 { pub unsafe fn init(&mut self) { let mac_low = self.regs.mac[0].read(); let mac_high = self.regs.mac[1].read(); - let mac = [mac_low as u8, - (mac_low >> 8) as u8, - (mac_low >> 16) as u8, - (mac_low >> 24) as u8, - mac_high as u8, - (mac_high >> 8) as u8]; - println!(" - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + let mac = [ + mac_low as u8, + (mac_low >> 8) as u8, + (mac_low >> 16) as u8, + (mac_low >> 24) as u8, + mac_high as u8, + (mac_high >> 8) as u8, + ]; + println!( + " - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + ); self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value @@ -256,8 +260,12 @@ impl Rtl8168 { // Set up normal priority tx buffers println!(" - Transmit buffers (normal priority)"); for i in 0..self.transmit_ring.len() { - self.transmit_ring[i].buffer_low.write(self.transmit_buffer[i].physical() as u32); - self.transmit_ring[i].buffer_high.write((self.transmit_buffer[i].physical() as u64 >> 32) as u32); + self.transmit_ring[i] + .buffer_low + .write(self.transmit_buffer[i].physical() as u32); + self.transmit_ring[i] + .buffer_high + .write((self.transmit_buffer[i].physical() as u64 >> 32) as u32); } if let Some(td) = self.transmit_ring.last_mut() { td.ctrl.writef(EOR, true); @@ -266,8 +274,12 @@ impl Rtl8168 { // Set up high priority tx buffers println!(" - Transmit buffers (high priority)"); for i in 0..self.transmit_ring_h.len() { - self.transmit_ring_h[i].buffer_low.write(self.transmit_buffer_h[i].physical() as u32); - self.transmit_ring_h[i].buffer_high.write((self.transmit_buffer_h[i].physical() as u64 >> 32) as u32); + self.transmit_ring_h[i] + .buffer_low + .write(self.transmit_buffer_h[i].physical() as u32); + self.transmit_ring_h[i] + .buffer_high + .write((self.transmit_buffer_h[i].physical() as u64 >> 32) as u32); } if let Some(td) = self.transmit_ring_h.last_mut() { td.ctrl.writef(EOR, true); @@ -306,7 +318,9 @@ impl Rtl8168 { self.regs.isr.write(isr); // Interrupt on tx error (bit 3), tx ok (bit 2), rx error(bit 1), and rx ok (bit 0) - self.regs.imr.write(1 << 15 | 1 << 14 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1); + self.regs.imr.write( + 1 << 15 | 1 << 14 | 1 << 7 | 1 << 6 | 1 << 5 | 1 << 4 | 1 << 3 | 1 << 2 | 1 << 1 | 1, + ); // Set TX config self.regs.tcr.write(0b11 << 24 | 0b111 << 8); diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index cdccf38c7b..49ebc8491c 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -8,11 +8,14 @@ use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; -use pcid_interface::{MsiSetFeatureInfo, PciFunctionHandle, PciFeature, PciFeatureInfo, SetFeatureInfo, SubdriverArguments}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixInfo, MsixTableEntry}; +use pcid_interface::{ + MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, + SubdriverArguments, +}; use syscall::EventFlags; pub mod device; @@ -48,14 +51,19 @@ impl MappedMsixRegs { fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.config(); - let all_pci_features = pcid_handle.fetch_all_features().expect("rtl8168d: failed to fetch pci features"); + let all_pci_features = pcid_handle + .fetch_all_features() + .expect("rtl8168d: failed to fetch pci features"); log::info!("PCI FEATURES: {:?}", all_pci_features); let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); if has_msi && !has_msix { - let capability = match pcid_handle.feature_info(PciFeature::Msi).expect("rtl8168d: failed to retrieve the MSI capability structure from pcid") { + let capability = match pcid_handle + .feature_info(PciFeature::Msi) + .expect("rtl8168d: failed to retrieve the MSI capability structure from pcid") + { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), }; @@ -65,21 +73,29 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. let destination_id = read_bsp_apic_id().expect("rtl8168d: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = allocate_single_interrupt_vector_for_msi(destination_id); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); let set_feature_info = MsiSetFeatureInfo { multi_message_enable: Some(0), message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)).expect("rtl8168d: failed to set feature info"); + pcid_handle + .set_feature_info(SetFeatureInfo::Msi(set_feature_info)) + .expect("rtl8168d: failed to set feature info"); - pcid_handle.enable_feature(PciFeature::Msi).expect("rtl8168d: failed to enable MSI"); + pcid_handle + .enable_feature(PciFeature::Msi) + .expect("rtl8168d: failed to enable MSI"); log::info!("Enabled MSI"); interrupt_handle } else if has_msix { - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).expect("rtl8168d: failed to retrieve the MSI-X capability structure from pcid") { + let msix_info = match pcid_handle + .feature_info(PciFeature::MsiX) + .expect("rtl8168d: failed to retrieve the MSI-X capability structure from pcid") + { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; @@ -89,7 +105,8 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { .ptr .as_ptr() as usize; - let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; + let virt_table_base = + (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; let mut info = MappedMsixRegs { virt_table_base: NonNull::new(virt_table_base).unwrap(), @@ -114,7 +131,9 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { interrupt_handle }; - pcid_handle.enable_feature(PciFeature::MsiX).expect("rtl8168d: failed to enable MSI-X"); + pcid_handle + .enable_feature(PciFeature::MsiX) + .expect("rtl8168d: failed to enable MSI-X"); log::info!("Enabled MSI-X"); method @@ -143,14 +162,12 @@ fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { // RTL8168 uses BAR2, RTL8169 uses BAR1, search in that order for &barnum in &[2, 1] { match pci_config.func.bars[barnum] { - pcid_interface::PciBar::Memory32 { addr, size } => return Some(( - addr.try_into().unwrap(), - size.try_into().unwrap() - )), - pcid_interface::PciBar::Memory64 { addr, size } => return Some(( - addr.try_into().unwrap(), - size.try_into().unwrap() - )), + pcid_interface::PciBar::Memory32 { addr, size } => { + return Some((addr.try_into().unwrap(), size.try_into().unwrap())) + } + pcid_interface::PciBar::Memory64 { addr, size } => { + return Some((addr.try_into().unwrap(), size.try_into().unwrap())) + } other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), } } @@ -166,7 +183,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::LevelFilter::Info, ); - let mut pcid_handle = PciFunctionHandle::connect_default().expect("rtl8168d: failed to setup channel to pcid"); + let mut pcid_handle = + PciFunctionHandle::connect_default().expect("rtl8168d: failed to setup channel to pcid"); let pci_config = pcid_handle.config(); @@ -177,8 +195,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::info!(" + RTL8168 {}", pci_config.func.display()); let address = unsafe { - common::physmap(bar_ptr, bar_size, common::Prot::RW, common::MemoryType::Uncacheable) - .expect("rtl8168d: failed to map address") as usize + common::physmap( + bar_ptr, + bar_size, + common::Prot::RW, + common::MemoryType::Uncacheable, + ) + .expect("rtl8168d: failed to map address") as usize }; //TODO: MSI-X @@ -196,9 +219,22 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - let mut event_queue = EventQueue::::new().expect("rtl8168d: Could not create event queue."); - event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); - event_queue.subscribe(scheme.event_handle() as usize, Source::Scheme, event::EventFlags::READ).unwrap(); + let mut event_queue = + EventQueue::::new().expect("rtl8168d: Could not create event queue."); + event_queue + .subscribe( + irq_file.as_raw_fd() as usize, + Source::Irq, + event::EventFlags::READ, + ) + .unwrap(); + event_queue + .subscribe( + scheme.event_handle() as usize, + Source::Scheme, + event::EventFlags::READ, + ) + .unwrap(); libredox::call::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); diff --git a/ps2d/src/controller.rs b/ps2d/src/controller.rs index 24968b84a5..9172fa5ee3 100644 --- a/ps2d/src/controller.rs +++ b/ps2d/src/controller.rs @@ -1,19 +1,25 @@ -use log::{debug, error, info, trace}; use common::io::{Io, Pio, ReadOnly, WriteOnly}; +use log::{debug, error, info, trace}; use std::fmt; #[cfg(target_arch = "aarch64")] #[inline(always)] -pub(crate) unsafe fn pause() { std::arch::aarch64::__yield(); } +pub(crate) unsafe fn pause() { + std::arch::aarch64::__yield(); +} #[cfg(target_arch = "x86")] #[inline(always)] -pub(crate) unsafe fn pause() { std::arch::x86::_mm_pause(); } +pub(crate) unsafe fn pause() { + std::arch::x86::_mm_pause(); +} #[cfg(target_arch = "x86_64")] #[inline(always)] -pub(crate) unsafe fn pause() { std::arch::x86_64::_mm_pause(); } +pub(crate) unsafe fn pause() { + std::arch::x86_64::_mm_pause(); +} #[derive(Debug)] pub enum Error { @@ -67,7 +73,7 @@ enum Command { Diagnostic = 0xAC, DisableFirst = 0xAD, EnableFirst = 0xAE, - WriteSecond = 0xD4 + WriteSecond = 0xD4, } #[derive(Clone, Copy, Debug)] @@ -77,13 +83,13 @@ enum KeyboardCommand { EnableReporting = 0xF4, SetDefaultsDisable = 0xF5, SetDefaults = 0xF6, - Reset = 0xFF + Reset = 0xFF, } #[derive(Clone, Copy, Debug)] #[repr(u8)] enum KeyboardCommandData { - ScancodeSet = 0xF0 + ScancodeSet = 0xF0, } #[derive(Clone, Copy, Debug)] @@ -97,7 +103,7 @@ enum MouseCommand { EnableReporting = 0xF4, SetDefaultsDisable = 0xF5, SetDefaults = 0xF6, - Reset = 0xFF + Reset = 0xFF, } #[derive(Clone, Copy, Debug)] @@ -132,7 +138,9 @@ impl Ps2 { if self.status().contains(StatusFlags::OUTPUT_FULL) { return Ok(()); } - unsafe { pause(); } + unsafe { + pause(); + } timeout -= 1; } Err(Error::ReadTimeout) @@ -141,10 +149,12 @@ impl Ps2 { fn wait_write(&mut self) -> Result<(), Error> { let mut timeout = 100_000; while timeout > 0 { - if ! self.status().contains(StatusFlags::INPUT_FULL) { + if !self.status().contains(StatusFlags::INPUT_FULL) { return Ok(()); } - unsafe { pause(); } + unsafe { + pause(); + } timeout -= 1; } Err(Error::WriteTimeout) @@ -157,7 +167,9 @@ impl Ps2 { let val = self.data.read(); trace!("ps2d: flush {}: {:X}", message, val); } - unsafe { pause(); } + unsafe { + pause(); + } timeout -= 1; } } @@ -179,7 +191,12 @@ impl Ps2 { Ok(()) } - fn retry Result>(&mut self, name: fmt::Arguments, retries: usize, f: F) -> Result { + fn retry Result>( + &mut self, + name: fmt::Arguments, + retries: usize, + f: F, + ) -> Result { trace!("ps2d: {}", name); let mut res = Err(Error::NoMoreTries); for retry in 0..retries { @@ -187,7 +204,7 @@ impl Ps2 { match res { Ok(ok) => { return Ok(ok); - }, + } Err(ref err) => { info!("ps2d: {}: retry {}/{}: {:?}", name, retry + 1, retries, err); } @@ -197,26 +214,19 @@ impl Ps2 { } fn config(&mut self) -> Result { - self.retry( - format_args!("read config"), - 4, - |x| { - x.command(Command::ReadConfig)?; - x.read() - } - ).map(ConfigFlags::from_bits_truncate) + self.retry(format_args!("read config"), 4, |x| { + x.command(Command::ReadConfig)?; + x.read() + }) + .map(ConfigFlags::from_bits_truncate) } fn set_config(&mut self, config: ConfigFlags) -> Result<(), Error> { - self.retry( - format_args!("write config"), - 4, - |x| { - x.command(Command::WriteConfig)?; - x.write(config.bits())?; - Ok(0) - } - )?; + self.retry(format_args!("write config"), 4, |x| { + x.command(Command::WriteConfig)?; + x.write(config.bits())?; + Ok(0) + })?; Ok(()) } @@ -229,14 +239,16 @@ impl Ps2 { } fn keyboard_command(&mut self, command: KeyboardCommand) -> Result { - self.retry( - format_args!("keyboard command {:?}", command), - 4, - |x| x.keyboard_command_inner(command as u8) - ) + self.retry(format_args!("keyboard command {:?}", command), 4, |x| { + x.keyboard_command_inner(command as u8) + }) } - fn keyboard_command_data(&mut self, command: KeyboardCommandData, data: u8) -> Result { + fn keyboard_command_data( + &mut self, + command: KeyboardCommandData, + data: u8, + ) -> Result { self.retry( format_args!("keyboard command {:?} {:#x}", command, data), 4, @@ -248,7 +260,7 @@ impl Ps2 { } x.write(data); x.read() - } + }, ) } @@ -262,11 +274,9 @@ impl Ps2 { } fn mouse_command(&mut self, command: MouseCommand) -> Result { - self.retry( - format_args!("mouse command {:?}", command), - 4, - |x| x.mouse_command_inner(command as u8) - ) + self.retry(format_args!("mouse command {:?}", command), 4, |x| { + x.mouse_command_inner(command as u8) + }) } fn mouse_command_data(&mut self, command: MouseCommandData, data: u8) -> Result { @@ -282,7 +292,7 @@ impl Ps2 { x.command(Command::WriteSecond)?; x.write(data as u8)?; x.read() - } + }, ) } @@ -290,7 +300,7 @@ impl Ps2 { let status = self.status(); if status.contains(StatusFlags::OUTPUT_FULL) { let data = self.data.read(); - Some((! status.contains(StatusFlags::SECOND_OUTPUT_FULL), data)) + Some((!status.contains(StatusFlags::SECOND_OUTPUT_FULL), data)) } else { None } @@ -323,32 +333,31 @@ impl Ps2 { self.flush_read("keyboard reset"); } - self.retry( - format_args!("keyboard defaults"), - 4, - |x| { - x.flush_read("keyboard before defaults"); + self.retry(format_args!("keyboard defaults"), 4, |x| { + x.flush_read("keyboard before defaults"); - // Set defaults and disable scanning - let b = x.keyboard_command(KeyboardCommand::SetDefaultsDisable)?; - if b != 0xFA { - error!("ps2d: keyboard failed to set defaults: {:02X}", b); - return Err(Error::CommandRetry); - } - - // Clear remaining data - x.flush_read("keyboard after defaults"); - - Ok(b) + // Set defaults and disable scanning + let b = x.keyboard_command(KeyboardCommand::SetDefaultsDisable)?; + if b != 0xFA { + error!("ps2d: keyboard failed to set defaults: {:02X}", b); + return Err(Error::CommandRetry); } - )?; + + // Clear remaining data + x.flush_read("keyboard after defaults"); + + Ok(b) + })?; { // Set scancode set to 2 let scancode_set = 2; b = self.keyboard_command_data(KeyboardCommandData::ScancodeSet, scancode_set)?; if b != 0xFA { - error!("ps2d: keyboard failed to set scancode set {}: {:02X}", scancode_set, b); + error!( + "ps2d: keyboard failed to set scancode set {}: {:02X}", + scancode_set, b + ); } // Clear remaining data @@ -369,38 +378,34 @@ impl Ps2 { self.flush_read("enable second"); } - self.retry( - format_args!("mouse reset"), - 4, - |x| { - // Clear remaining data - x.flush_read("mouse before reset"); + self.retry(format_args!("mouse reset"), 4, |x| { + // Clear remaining data + x.flush_read("mouse before reset"); - // Reset mouse - let mut b = x.mouse_command(MouseCommand::Reset)?; - if b == 0xFA { - b = x.read()?; - if b != 0xAA { - error!("ps2d: mouse failed self test 1: {:02X}", b); - return Err(Error::CommandRetry); - } - - b = x.read()?; - if b != 0x00 { - error!("ps2d: mouse failed self test 2: {:02X}", b); - return Err(Error::CommandRetry); - } - } else { - error!("ps2d: mouse failed to reset: {:02X}", b); + // Reset mouse + let mut b = x.mouse_command(MouseCommand::Reset)?; + if b == 0xFA { + b = x.read()?; + if b != 0xAA { + error!("ps2d: mouse failed self test 1: {:02X}", b); return Err(Error::CommandRetry); } - // Clear remaining data - x.flush_read("mouse after reset"); - - Ok(b) + b = x.read()?; + if b != 0x00 { + error!("ps2d: mouse failed self test 2: {:02X}", b); + return Err(Error::CommandRetry); + } + } else { + error!("ps2d: mouse failed to reset: {:02X}", b); + return Err(Error::CommandRetry); } - )?; + + // Clear remaining data + x.flush_read("mouse after reset"); + + Ok(b) + })?; { // Set defaults @@ -417,8 +422,9 @@ impl Ps2 { // Enable extra packet on mouse //TODO: show error return values if self.mouse_command_data(MouseCommandData::SetSampleRate, 200)? != 0xFA - || self.mouse_command_data(MouseCommandData::SetSampleRate, 100)? != 0xFA - || self.mouse_command_data(MouseCommandData::SetSampleRate, 80)? != 0xFA { + || self.mouse_command_data(MouseCommandData::SetSampleRate, 100)? != 0xFA + || self.mouse_command_data(MouseCommandData::SetSampleRate, 80)? != 0xFA + { error!("ps2d: mouse failed to enable extra packet"); } @@ -442,7 +448,10 @@ impl Ps2 { let resolution = 3; b = self.mouse_command_data(MouseCommandData::SetResolution, resolution)?; if b != 0xFA { - error!("ps2d: mouse failed to set resolution to {}: {:02X}", resolution, b); + error!( + "ps2d: mouse failed to set resolution to {}: {:02X}", + resolution, b + ); } // Clear remaining data @@ -453,7 +462,7 @@ impl Ps2 { // Set scaling to 1:1 b = self.mouse_command(MouseCommand::SetScaling1To1)?; if b != 0xFA { - error!("ps2d: mouse failed to set scaling: {:02X}", b); + error!("ps2d: mouse failed to set scaling: {:02X}", b); } // Clear remaining data @@ -465,7 +474,10 @@ impl Ps2 { let sample_rate = 200; b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate)?; if b != 0xFA { - error!("ps2d: mouse failed to set sample rate to {}: {:02X}", sample_rate, b); + error!( + "ps2d: mouse failed to set sample rate to {}: {:02X}", + sample_rate, b + ); } // Clear remaining data @@ -475,13 +487,16 @@ impl Ps2 { { b = self.mouse_command(MouseCommand::StatusRequest)?; if b != 0xFA { - error!("ps2d: mouse failed to request status: {:02X}", b); + error!("ps2d: mouse failed to request status: {:02X}", b); } else { let a = self.read()?; let b = self.read()?; let c = self.read()?; - debug!("ps2d: mouse status {:#x} resolution {:#x} sample rate {:#x}", a, b, c); + debug!( + "ps2d: mouse status {:#x} resolution {:#x} sample rate {:#x}", + a, b, c + ); } } @@ -506,9 +521,9 @@ impl Ps2 { { // Since the default config may have interrupts enabled, and the kernel may eat up // our data in that case, we will write a config without reading the current one - config = ConfigFlags::POST_PASSED | - ConfigFlags::FIRST_DISABLED | - ConfigFlags::SECOND_DISABLED; + config = ConfigFlags::POST_PASSED + | ConfigFlags::FIRST_DISABLED + | ConfigFlags::SECOND_DISABLED; trace!("ps2d: config set {:?}", config); self.set_config(config)?; diff --git a/ps2d/src/keymap.rs b/ps2d/src/keymap.rs index 236e7caa07..46264606a7 100644 --- a/ps2d/src/keymap.rs +++ b/ps2d/src/keymap.rs @@ -57,7 +57,7 @@ pub mod us { ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], - [' ', ' '] + [' ', ' '], ]; pub fn get_char(scancode: u8, shift: bool) -> char { @@ -236,7 +236,7 @@ pub mod dvorak { ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], - [' ', ' '] + [' ', ' '], ]; pub fn get_char(scancode: u8, shift: bool) -> char { @@ -311,7 +311,7 @@ pub mod azerty { ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], - [' ', ' '] + [' ', ' '], ]; pub fn get_char(scancode: u8, shift: bool) -> char { @@ -386,7 +386,7 @@ pub mod bepo { ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], - [' ', ' '] + [' ', ' '], ]; pub fn get_char(scancode: u8, shift: bool) -> char { @@ -461,7 +461,7 @@ pub mod it { ['\0', '\0'], ['\0', '\0'], ['\0', '\0'], - [' ', ' '] + [' ', ' '], ]; pub fn get_char(scancode: u8, shift: bool) -> char { diff --git a/ps2d/src/main.rs b/ps2d/src/main.rs index 2b08b8fb97..5455aaa161 100644 --- a/ps2d/src/main.rs +++ b/ps2d/src/main.rs @@ -5,11 +5,11 @@ extern crate bitflags; extern crate orbclient; extern crate syscall; -use std::{env, process}; use std::fs::OpenOptions; use std::io::{Read, Write}; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; +use std::{env, process}; use log::info; use syscall::call::iopl; @@ -21,7 +21,6 @@ mod keymap; mod state; mod vm; - fn daemon(daemon: redox_daemon::Daemon) -> ! { common::setup_logging( "misc", @@ -35,10 +34,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { iopl(3).expect("ps2d: failed to get I/O permission"); } - let (keymap, keymap_name): ( - fn(u8, bool) -> char, - &str - ) = match env::args().skip(1).next() { + let (keymap, keymap_name): (fn(u8, bool) -> char, &str) = match env::args().skip(1).next() { Some(k) => match k.to_lowercase().as_ref() { "dvorak" => (keymap::dvorak::get_char, "dvorak"), "us" => (keymap::us::get_char, "us"), @@ -71,11 +67,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .open("/scheme/serio/0") .expect("ps2d: failed to open /scheme/serio/0"); - event_file.write(&syscall::Event { - id: key_file.as_raw_fd() as usize, - flags: syscall::EVENT_READ, - data: 0 - }).expect("ps2d: failed to event /scheme/serio/0"); + event_file + .write(&syscall::Event { + id: key_file.as_raw_fd() as usize, + flags: syscall::EVENT_READ, + data: 0, + }) + .expect("ps2d: failed to event /scheme/serio/0"); let mut mouse_file = OpenOptions::new() .read(true) @@ -84,15 +82,19 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .open("/scheme/serio/1") .expect("ps2d: failed to open /scheme/serio/1"); - event_file.write(&syscall::Event { - id: mouse_file.as_raw_fd() as usize, - flags: syscall::EVENT_READ, - data: 1 - }).expect("ps2d: failed to event /scheme/serio/1"); + event_file + .write(&syscall::Event { + id: mouse_file.as_raw_fd() as usize, + flags: syscall::EVENT_READ, + data: 1, + }) + .expect("ps2d: failed to event /scheme/serio/1"); libredox::call::setrens(0, 0).expect("ps2d: failed to enter null namespace"); - daemon.ready().expect("ps2d: failed to mark daemon as ready"); + daemon + .ready() + .expect("ps2d: failed to mark daemon as ready"); let mut ps2d = Ps2d::new(input, keymap); @@ -108,7 +110,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // to grab bytes and sort them based on the source let mut event = syscall::Event::default(); - if event_file.read(&mut event).expect("ps2d: failed to read event file") == 0 { + if event_file + .read(&mut event) + .expect("ps2d: failed to read event file") + == 0 + { break; } diff --git a/ps2d/src/state.rs b/ps2d/src/state.rs index 22db4e26e0..b25cec9455 100644 --- a/ps2d/src/state.rs +++ b/ps2d/src/state.rs @@ -4,7 +4,7 @@ use std::os::unix::io::AsRawFd; use std::str; use log::{error, warn}; -use orbclient::{KeyEvent, MouseEvent, MouseRelativeEvent, ButtonEvent, ScrollEvent}; +use orbclient::{ButtonEvent, KeyEvent, MouseEvent, MouseRelativeEvent, ScrollEvent}; use crate::controller::Ps2; use crate::vm; @@ -22,7 +22,7 @@ bitflags! { } } -pub struct Ps2d char> { +pub struct Ps2d char> { ps2: Ps2, vmmouse: bool, vmmouse_relative: bool, @@ -39,10 +39,10 @@ pub struct Ps2d char> { packet_i: usize, extra_packet: bool, //Keymap function - get_char: F + get_char: F, } -impl char> Ps2d { +impl char> Ps2d { pub fn new(input: File, keymap: F) -> Self { let mut ps2 = Ps2::new(); let extra_packet = ps2.init().expect("ps2d: failed to initialize"); @@ -67,7 +67,7 @@ impl char> Ps2d { packets: [0; 4], packet_i: 0, extra_packet, - get_char: keymap + get_char: keymap, } } @@ -228,11 +228,19 @@ impl char> Ps2d { } if scancode != 0 { - self.input.write(&KeyEvent { - character: (self.get_char)(ps2_scancode, self.lshift || self.rshift), - scancode, - pressed - }.to_event()).expect("ps2d: failed to write key event"); + self.input + .write( + &KeyEvent { + character: (self.get_char)( + ps2_scancode, + self.lshift || self.rshift, + ), + scancode, + pressed, + } + .to_event(), + ) + .expect("ps2d: failed to write key event"); } } } else if self.vmmouse { @@ -254,10 +262,15 @@ impl char> Ps2d { if self.vmmouse_relative { if dx != 0 || dy != 0 { - self.input.write(&MouseRelativeEvent { - dx: dx as i32, - dy: dy as i32, - }.to_event()).expect("ps2d: failed to write mouse event"); + self.input + .write( + &MouseRelativeEvent { + dx: dx as i32, + dy: dy as i32, + } + .to_event(), + ) + .expect("ps2d: failed to write mouse event"); } } else { let x = dx as i32; @@ -272,24 +285,37 @@ impl char> Ps2d { }; if dz != 0 { - self.input.write(&ScrollEvent { - x: 0, - y: -(dz as i32), - }.to_event()).expect("ps2d: failed to write scroll event"); + self.input + .write( + &ScrollEvent { + x: 0, + y: -(dz as i32), + } + .to_event(), + ) + .expect("ps2d: failed to write scroll event"); } let left = status & vm::LEFT_BUTTON == vm::LEFT_BUTTON; let middle = status & vm::MIDDLE_BUTTON == vm::MIDDLE_BUTTON; let right = status & vm::RIGHT_BUTTON == vm::RIGHT_BUTTON; - if left != self.mouse_left || middle != self.mouse_middle || right != self.mouse_right { + if left != self.mouse_left + || middle != self.mouse_middle + || right != self.mouse_right + { self.mouse_left = left; self.mouse_middle = middle; self.mouse_right = right; - self.input.write(&ButtonEvent { - left: left, - middle: middle, - right: right, - }.to_event()).expect("ps2d: failed to write button event"); + self.input + .write( + &ButtonEvent { + left: left, + middle: middle, + right: right, + } + .to_event(), + ) + .expect("ps2d: failed to write button event"); } } } else { @@ -297,13 +323,17 @@ impl char> Ps2d { self.packet_i += 1; let flags = MousePacketFlags::from_bits_truncate(self.packets[0]); - if ! flags.contains(MousePacketFlags::ALWAYS_ON) { + if !flags.contains(MousePacketFlags::ALWAYS_ON) { error!("ps2d: mouse misalign {:X}", self.packets[0]); self.packets = [0; 4]; self.packet_i = 0; - } else if self.packet_i >= self.packets.len() || (!self.extra_packet && self.packet_i >= 3) { - if ! flags.contains(MousePacketFlags::X_OVERFLOW) && ! flags.contains(MousePacketFlags::Y_OVERFLOW) { + } else if self.packet_i >= self.packets.len() + || (!self.extra_packet && self.packet_i >= 3) + { + if !flags.contains(MousePacketFlags::X_OVERFLOW) + && !flags.contains(MousePacketFlags::Y_OVERFLOW) + { let mut dx = self.packets[1] as i32; if flags.contains(MousePacketFlags::X_SIGN) { dx -= 0x100; @@ -324,34 +354,43 @@ impl char> Ps2d { } if dx != 0 || dy != 0 { - self.input.write(&MouseRelativeEvent { - dx: dx, - dy: dy, - }.to_event()).expect("ps2d: failed to write mouse event"); + self.input + .write(&MouseRelativeEvent { dx: dx, dy: dy }.to_event()) + .expect("ps2d: failed to write mouse event"); } if dz != 0 { - self.input.write(&ScrollEvent { - x: 0, - y: dz, - }.to_event()).expect("ps2d: failed to write scroll event"); + self.input + .write(&ScrollEvent { x: 0, y: dz }.to_event()) + .expect("ps2d: failed to write scroll event"); } let left = flags.contains(MousePacketFlags::LEFT_BUTTON); let middle = flags.contains(MousePacketFlags::MIDDLE_BUTTON); let right = flags.contains(MousePacketFlags::RIGHT_BUTTON); - if left != self.mouse_left || middle != self.mouse_middle || right != self.mouse_right { + if left != self.mouse_left + || middle != self.mouse_middle + || right != self.mouse_right + { self.mouse_left = left; self.mouse_middle = middle; self.mouse_right = right; - self.input.write(&ButtonEvent { - left: left, - middle: middle, - right: right, - }.to_event()).expect("ps2d: failed to write button event"); + self.input + .write( + &ButtonEvent { + left: left, + middle: middle, + right: right, + } + .to_event(), + ) + .expect("ps2d: failed to write button event"); } } else { - warn!("ps2d: overflow {:X} {:X} {:X} {:X}", self.packets[0], self.packets[1], self.packets[2], self.packets[3]); + warn!( + "ps2d: overflow {:X} {:X} {:X} {:X}", + self.packets[0], self.packets[1], self.packets[2], self.packets[3] + ); } self.packets = [0; 4]; diff --git a/storage/ahcid/src/ahci/disk_ata.rs b/storage/ahcid/src/ahci/disk_ata.rs index 394b61dd35..2dc2a1f190 100644 --- a/storage/ahcid/src/ahci/disk_ata.rs +++ b/storage/ahcid/src/ahci/disk_ata.rs @@ -5,7 +5,7 @@ use syscall::error::Result; use common::dma::Dma; -use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; +use super::hba::{HbaCmdHeader, HbaCmdTable, HbaPort}; use super::Disk; enum BufferKind<'a> { @@ -28,7 +28,7 @@ pub struct DiskATA { clb: Dma<[HbaCmdHeader; 32]>, ctbas: [Dma; 32], _fb: Dma<[u8; 256]>, - buf: Dma<[u8; 256 * 512]> + buf: Dma<[u8; 256 * 512]>, } impl DiskATA { @@ -56,26 +56,28 @@ impl DiskATA { clb: clb, ctbas, _fb: fb, - buf: buf + buf: buf, }) } fn request(&mut self, block: u64, mut buffer_kind: BufferKind) -> Result> { let (write, address, total_sectors) = match buffer_kind { - BufferKind::Read(ref buffer) => (false, buffer.as_ptr() as usize, buffer.len()/512), - BufferKind::Write(ref buffer) => (true, buffer.as_ptr() as usize, buffer.len()/512), + BufferKind::Read(ref buffer) => (false, buffer.as_ptr() as usize, buffer.len() / 512), + BufferKind::Write(ref buffer) => (true, buffer.as_ptr() as usize, buffer.len() / 512), }; loop { let mut request = match self.request_opt.take() { - Some(request) => if address == request.address && total_sectors == request.total_sectors { - // Keep servicing current request - request - } else { - // Have to wait for another request to finish - self.request_opt = Some(request); - return Ok(None); - }, + Some(request) => { + if address == request.address && total_sectors == request.total_sectors { + // Keep servicing current request + request + } else { + // Have to wait for another request to finish + self.request_opt = Some(request); + return Ok(None); + } + } None => { // Create new request Request { @@ -99,7 +101,13 @@ impl DiskATA { self.port.ata_stop(running.0)?; if let BufferKind::Read(ref mut buffer) = buffer_kind { - unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().add(request.sector * 512), running.1 * 512); } + unsafe { + ptr::copy( + self.buf.as_ptr(), + buffer.as_mut_ptr().add(request.sector * 512), + running.1 * 512, + ); + } } request.sector += running.1; @@ -114,10 +122,23 @@ impl DiskATA { }; if let BufferKind::Write(ref buffer) = buffer_kind { - unsafe { ptr::copy(buffer.as_ptr().add(request.sector * 512), self.buf.as_mut_ptr(), sectors * 512); } + unsafe { + ptr::copy( + buffer.as_ptr().add(request.sector * 512), + self.buf.as_mut_ptr(), + sectors * 512, + ); + } } - if let Some(slot) = self.port.ata_dma(block + request.sector as u64, sectors, write, &mut self.clb, &mut self.ctbas, &mut self.buf) { + if let Some(slot) = self.port.ata_dma( + block + request.sector as u64, + sectors, + write, + &mut self.clb, + &mut self.ctbas, + &mut self.buf, + ) { request.running_opt = Some((slot, sectors)); } @@ -146,7 +167,7 @@ impl Disk for DiskATA { loop { match self.request(block, BufferKind::Read(buffer))? { Some(count) => return Ok(Some(count)), - None => std::thread::yield_now() + None => std::thread::yield_now(), } } } @@ -156,7 +177,7 @@ impl Disk for DiskATA { loop { match self.request(block, BufferKind::Write(buffer))? { Some(count) => return Ok(Some(count)), - None => std::thread::yield_now() + None => std::thread::yield_now(), } } } diff --git a/storage/ahcid/src/ahci/disk_atapi.rs b/storage/ahcid/src/ahci/disk_atapi.rs index a3c63f7abb..29ae47996c 100644 --- a/storage/ahcid/src/ahci/disk_atapi.rs +++ b/storage/ahcid/src/ahci/disk_atapi.rs @@ -3,13 +3,13 @@ use std::convert::TryInto; use std::ptr; -use byteorder::{ByteOrder, BigEndian}; +use byteorder::{BigEndian, ByteOrder}; -use syscall::error::{Result, EBADF, Error}; +use syscall::error::{Error, Result, EBADF}; use common::dma::Dma; -use super::hba::{HbaPort, HbaCmdTable, HbaCmdHeader}; +use super::hba::{HbaCmdHeader, HbaCmdTable, HbaPort}; use super::Disk; const SCSI_READ_CAPACITY: u8 = 0x25; @@ -24,7 +24,7 @@ pub struct DiskATAPI { _fb: Dma<[u8; 256]>, // Just using the same buffer size as DiskATA // Although the sector size is different (and varies) - buf: Dma<[u8; 256 * 512]> + buf: Dma<[u8; 256 * 512]>, } impl DiskATAPI { @@ -60,7 +60,8 @@ impl DiskATAPI { let mut cmd = [0; 16]; cmd[0] = SCSI_READ_CAPACITY; - self.port.atapi_dma(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + self.port + .atapi_dma(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf)?; // Instead of a count, contains number of last LBA, so add 1 let blk_count = BigEndian::read_u32(&self.buf[0..4]) + 1; @@ -78,7 +79,7 @@ impl Disk for DiskATAPI { fn size(&mut self) -> u64 { match self.read_capacity() { Ok((blk_count, blk_size)) => (blk_count as u64) * (blk_size as u64), - Err(_) => 0 // XXX + Err(_) => 0, // XXX } } @@ -101,17 +102,45 @@ impl Disk for DiskATAPI { let buf_size = buf_len * blk_len; while sectors - sector >= buf_len { let cmd = read10_cmd(block as u32 + sector, buf_len as u16); - self.port.atapi_dma(&cmd, buf_size, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + self.port.atapi_dma( + &cmd, + buf_size, + &mut self.clb, + &mut self.ctbas, + &mut self.buf, + )?; - unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * blk_len as isize), buf_size as usize); } + unsafe { + ptr::copy( + self.buf.as_ptr(), + buffer + .as_mut_ptr() + .offset(sector as isize * blk_len as isize), + buf_size as usize, + ); + } sector += blk_len; } if sector < sectors { let cmd = read10_cmd(block as u32 + sector, (sectors - sector) as u16); - self.port.atapi_dma(&cmd, buf_size, &mut self.clb, &mut self.ctbas, &mut self.buf)?; + self.port.atapi_dma( + &cmd, + buf_size, + &mut self.clb, + &mut self.ctbas, + &mut self.buf, + )?; - unsafe { ptr::copy(self.buf.as_ptr(), buffer.as_mut_ptr().offset(sector as isize * blk_len as isize), ((sectors - sector) * blk_len) as usize); } + unsafe { + ptr::copy( + self.buf.as_ptr(), + buffer + .as_mut_ptr() + .offset(sector as isize * blk_len as isize), + ((sectors - sector) * blk_len) as usize, + ); + } sector += sectors - sector; } diff --git a/storage/ahcid/src/ahci/fis.rs b/storage/ahcid/src/ahci/fis.rs index 0e4b380271..5c1f69b78d 100644 --- a/storage/ahcid/src/ahci/fis.rs +++ b/storage/ahcid/src/ahci/fis.rs @@ -17,7 +17,7 @@ pub enum FisType { /// PIO setup FIS - device to host PioSetup = 0x5F, /// Set device bits FIS - device to host - DevBits = 0xA1 + DevBits = 0xA1, } #[repr(packed)] @@ -27,25 +27,25 @@ pub struct FisRegH2D { pub pm: Mmio, // Port multiplier, 1: Command, 0: Control - pub command: Mmio, // Command register + pub command: Mmio, // Command register pub featurel: Mmio, // Feature register, 7:0 // DWORD 1 - pub lba0: Mmio, // LBA low register, 7:0 - pub lba1: Mmio, // LBA mid register, 15:8 - pub lba2: Mmio, // LBA high register, 23:16 + pub lba0: Mmio, // LBA low register, 7:0 + pub lba1: Mmio, // LBA mid register, 15:8 + pub lba2: Mmio, // LBA high register, 23:16 pub device: Mmio, // Device register // DWORD 2 - pub lba3: Mmio, // LBA register, 31:24 - pub lba4: Mmio, // LBA register, 39:32 - pub lba5: Mmio, // LBA register, 47:40 + pub lba3: Mmio, // LBA register, 31:24 + pub lba4: Mmio, // LBA register, 39:32 + pub lba5: Mmio, // LBA register, 47:40 pub featureh: Mmio, // Feature register, 15:8 // DWORD 3 - pub countl: Mmio, // Count register, 7:0 - pub counth: Mmio, // Count register, 15:8 - pub icc: Mmio, // Isochronous command completion + pub countl: Mmio, // Count register, 7:0 + pub counth: Mmio, // Count register, 15:8 + pub icc: Mmio, // Isochronous command completion pub control: Mmio, // Control register // DWORD 4 @@ -60,12 +60,12 @@ pub struct FisRegD2H { pub pm: Mmio, // Port multiplier, Interrupt bit: 2 pub status: Mmio, // Status register - pub error: Mmio, // Error register + pub error: Mmio, // Error register // DWORD 1 - pub lba0: Mmio, // LBA low register, 7:0 - pub lba1: Mmio, // LBA mid register, 15:8 - pub lba2: Mmio, // LBA high register, 23:16 + pub lba0: Mmio, // LBA low register, 7:0 + pub lba1: Mmio, // LBA mid register, 15:8 + pub lba2: Mmio, // LBA high register, 23:16 pub device: Mmio, // Device register // DWORD 2 @@ -75,8 +75,8 @@ pub struct FisRegD2H { pub rsv2: Mmio, // Reserved // DWORD 3 - pub countl: Mmio, // Count register, 7:0 - pub counth: Mmio, // Count register, 15:8 + pub countl: Mmio, // Count register, 7:0 + pub counth: Mmio, // Count register, 15:8 pub rsv3: [Mmio; 2], // Reserved // DWORD 4 @@ -104,12 +104,12 @@ pub struct FisPioSetup { pub pm: Mmio, // Port multiplier, direction: 4 - device to host, interrupt: 2 pub status: Mmio, // Status register - pub error: Mmio, // Error register + pub error: Mmio, // Error register // DWORD 1 - pub lba0: Mmio, // LBA low register, 7:0 - pub lba1: Mmio, // LBA mid register, 15:8 - pub lba2: Mmio, // LBA high register, 23:16 + pub lba0: Mmio, // LBA low register, 7:0 + pub lba1: Mmio, // LBA mid register, 15:8 + pub lba2: Mmio, // LBA high register, 23:16 pub device: Mmio, // Device register // DWORD 2 @@ -119,13 +119,13 @@ pub struct FisPioSetup { pub rsv2: Mmio, // Reserved // DWORD 3 - pub countl: Mmio, // Count register, 7:0 - pub counth: Mmio, // Count register, 15:8 - pub rsv3: Mmio, // Reserved + pub countl: Mmio, // Count register, 7:0 + pub counth: Mmio, // Count register, 15:8 + pub rsv3: Mmio, // Reserved pub e_status: Mmio, // New value of status register // DWORD 4 - pub tc: Mmio, // Transfer count + pub tc: Mmio, // Transfer count pub rsv4: [Mmio; 2], // Reserved } diff --git a/storage/ahcid/src/ahci/hba.rs b/storage/ahcid/src/ahci/hba.rs index b893fddc81..00e80f37e4 100644 --- a/storage/ahcid/src/ahci/hba.rs +++ b/storage/ahcid/src/ahci/hba.rs @@ -6,7 +6,7 @@ use std::{ptr, u32}; use common::io::{Io, Mmio}; use syscall::error::{Error, Result, EIO}; -use super::fis::{FisType, FisRegH2D}; +use super::fis::{FisRegH2D, FisType}; use common::dma::Dma; @@ -42,20 +42,20 @@ pub enum HbaPortType { #[repr(packed)] pub struct HbaPort { pub clb: [Mmio; 2], // 0x00, command list base address, 1K-byte aligned - pub fb: [Mmio; 2], // 0x08, FIS base address, 256-byte aligned - pub is: Mmio, // 0x10, interrupt status - pub ie: Mmio, // 0x14, interrupt enable - pub cmd: Mmio, // 0x18, command and status - pub _rsv0: Mmio, // 0x1C, Reserved - pub tfd: Mmio, // 0x20, task file data - pub sig: Mmio, // 0x24, signature - pub ssts: Mmio, // 0x28, SATA status (SCR0:SStatus) - pub sctl: Mmio, // 0x2C, SATA control (SCR2:SControl) - pub serr: Mmio, // 0x30, SATA error (SCR1:SError) - pub sact: Mmio, // 0x34, SATA active (SCR3:SActive) - pub ci: Mmio, // 0x38, command issue - pub sntf: Mmio, // 0x3C, SATA notification (SCR4:SNotification) - pub fbs: Mmio, // 0x40, FIS-based switch control + pub fb: [Mmio; 2], // 0x08, FIS base address, 256-byte aligned + pub is: Mmio, // 0x10, interrupt status + pub ie: Mmio, // 0x14, interrupt enable + pub cmd: Mmio, // 0x18, command and status + pub _rsv0: Mmio, // 0x1C, Reserved + pub tfd: Mmio, // 0x20, task file data + pub sig: Mmio, // 0x24, signature + pub ssts: Mmio, // 0x28, SATA status (SCR0:SStatus) + pub sctl: Mmio, // 0x2C, SATA control (SCR2:SControl) + pub serr: Mmio, // 0x30, SATA error (SCR1:SError) + pub sact: Mmio, // 0x34, SATA active (SCR3:SActive) + pub ci: Mmio, // 0x38, command issue + pub sntf: Mmio, // 0x3C, SATA notification (SCR4:SNotification) + pub fbs: Mmio, // 0x40, FIS-based switch control pub _rsv1: [Mmio; 11], // 0x44 ~ 0x6F, Reserved pub vendor: [Mmio; 4], // 0x70 ~ 0x7F, vendor specific } @@ -104,13 +104,20 @@ impl HbaPort { None } - pub fn init(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], fb: &mut Dma<[u8; 256]>) { + pub fn init( + &mut self, + clb: &mut Dma<[HbaCmdHeader; 32]>, + ctbas: &mut [Dma; 32], + fb: &mut Dma<[u8; 256]>, + ) { self.stop(); for i in 0..32 { let cmdheader = &mut clb[i]; cmdheader.ctba_low.write(ctbas[i].physical() as u32); - cmdheader.ctba_high.write((ctbas[i].physical() as u64 >> 32) as u32); + cmdheader + .ctba_high + .write((ctbas[i].physical() as u64 >> 32) as u32); cmdheader.prdtl.write(0); } @@ -125,7 +132,7 @@ impl HbaPort { self.serr.write(serr); // Disable power management - let sctl = self.sctl.read() ; + let sctl = self.sctl.read(); self.sctl.write(sctl | 7 << 8); // Power on and spin up device @@ -134,16 +141,29 @@ impl HbaPort { debug!(" - AHCI init {:X}", self.cmd.read()); } - pub unsafe fn identify(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { + pub unsafe fn identify( + &mut self, + clb: &mut Dma<[HbaCmdHeader; 32]>, + ctbas: &mut [Dma; 32], + ) -> Option { self.identify_inner(ATA_CMD_IDENTIFY, clb, ctbas) } - pub unsafe fn identify_packet(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { + pub unsafe fn identify_packet( + &mut self, + clb: &mut Dma<[HbaCmdHeader; 32]>, + ctbas: &mut [Dma; 32], + ) -> Option { self.identify_inner(ATA_CMD_IDENTIFY_PACKET, clb, ctbas) } // Shared between identify() and identify_packet() - unsafe fn identify_inner(&mut self, cmd: u8, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32]) -> Option { + unsafe fn identify_inner( + &mut self, + cmd: u8, + clb: &mut Dma<[HbaCmdHeader; 32]>, + ctbas: &mut [Dma; 32], + ) -> Option { let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); let slot = self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { @@ -151,7 +171,9 @@ impl HbaPort { let prdt_entry = &mut prdt_entries[0]; prdt_entry.dba_low.write(dest.physical() as u32); - prdt_entry.dba_high.write((dest.physical() as u64 >> 32) as u32); + prdt_entry + .dba_high + .write((dest.physical() as u64 >> 32) as u32); prdt_entry.dbc.write(512 | 1); cmdfis.pm.write(1 << 7); @@ -201,10 +223,10 @@ impl HbaPort { } } - let mut sectors = (dest[100] as u64) | - ((dest[101] as u64) << 16) | - ((dest[102] as u64) << 32) | - ((dest[103] as u64) << 48); + let mut sectors = (dest[100] as u64) + | ((dest[101] as u64) << 16) + | ((dest[102] as u64) << 32) + | ((dest[103] as u64) << 48); let lba_bits = if sectors == 0 { sectors = (dest[60] as u64) | ((dest[61] as u64) << 16); @@ -213,8 +235,14 @@ impl HbaPort { 48 }; - info!(" + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", - serial.trim(), firmware.trim(), model.trim(), lba_bits, sectors / 2048); + info!( + " + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", + serial.trim(), + firmware.trim(), + model.trim(), + lba_bits, + sectors / 2048 + ); Some(sectors * 512) } else { @@ -222,8 +250,22 @@ impl HbaPort { } } - pub fn ata_dma(&mut self, block: u64, sectors: usize, write: bool, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Option { - trace!("AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}", (self as *mut HbaPort) as usize, block, sectors, write); + pub fn ata_dma( + &mut self, + block: u64, + sectors: usize, + write: bool, + clb: &mut Dma<[HbaCmdHeader; 32]>, + ctbas: &mut [Dma; 32], + buf: &mut Dma<[u8; 256 * 512]>, + ) -> Option { + trace!( + "AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}", + (self as *mut HbaPort) as usize, + block, + sectors, + write + ); assert!(sectors > 0 && sectors < 256); @@ -237,7 +279,9 @@ impl HbaPort { let prdt_entry = &mut prdt_entries[0]; prdt_entry.dba_low.write(buf.physical() as u32); - prdt_entry.dba_high.write((buf.physical() as u64 >> 32) as u32); + prdt_entry + .dba_high + .write((buf.physical() as u64 >> 32) as u32); prdt_entry.dbc.write(((sectors * 512) as u32) | 1); cmdfis.pm.write(1 << 7); @@ -263,44 +307,74 @@ impl HbaPort { } /// Send ATAPI packet - pub fn atapi_dma(&mut self, cmd: &[u8; 16], size: u32, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>) -> Result<()> { - let slot = self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, acmd| { - let cfl = cmdheader.cfl.read(); - cmdheader.cfl.write(cfl | 1 << 5); + pub fn atapi_dma( + &mut self, + cmd: &[u8; 16], + size: u32, + clb: &mut Dma<[HbaCmdHeader; 32]>, + ctbas: &mut [Dma; 32], + buf: &mut Dma<[u8; 256 * 512]>, + ) -> Result<()> { + let slot = self + .ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, acmd| { + let cfl = cmdheader.cfl.read(); + cmdheader.cfl.write(cfl | 1 << 5); - cmdheader.prdtl.write(1); + cmdheader.prdtl.write(1); - let prdt_entry = &mut prdt_entries[0]; - prdt_entry.dba_low.write(buf.physical() as u32); - prdt_entry.dba_high.write((buf.physical() as u64 >> 32) as u32); - prdt_entry.dbc.write(size - 1); + let prdt_entry = &mut prdt_entries[0]; + prdt_entry.dba_low.write(buf.physical() as u32); + prdt_entry + .dba_high + .write((buf.physical() as u64 >> 32) as u32); + prdt_entry.dbc.write(size - 1); - cmdfis.pm.write(1 << 7); - cmdfis.command.write(ATA_CMD_PACKET); - cmdfis.device.write(0); - cmdfis.lba1.write(0); - cmdfis.lba2.write(0); - cmdfis.featurel.write(1); - cmdfis.featureh.write(0); + cmdfis.pm.write(1 << 7); + cmdfis.command.write(ATA_CMD_PACKET); + cmdfis.device.write(0); + cmdfis.lba1.write(0); + cmdfis.lba2.write(0); + cmdfis.featurel.write(1); + cmdfis.featureh.write(0); - unsafe { ptr::write_volatile(acmd.as_mut_ptr() as *mut [u8; 16], *cmd) }; - }).ok_or(Error::new(EIO))?; + unsafe { ptr::write_volatile(acmd.as_mut_ptr() as *mut [u8; 16], *cmd) }; + }) + .ok_or(Error::new(EIO))?; self.ata_stop(slot) } - pub fn ata_start(&mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], callback: F) -> Option - where F: FnOnce(&mut HbaCmdHeader, &mut FisRegH2D, &mut [HbaPrdtEntry; PRDT_ENTRIES], &mut [Mmio; 16]) { - + pub fn ata_start( + &mut self, + clb: &mut Dma<[HbaCmdHeader; 32]>, + ctbas: &mut [Dma; 32], + callback: F, + ) -> Option + where + F: FnOnce( + &mut HbaCmdHeader, + &mut FisRegH2D, + &mut [HbaPrdtEntry; PRDT_ENTRIES], + &mut [Mmio; 16], + ), + { //TODO: Should probably remove self.is.write(u32::MAX); if let Some(slot) = self.slot() { { let cmdheader = &mut clb[slot as usize]; - cmdheader.cfl.write((size_of::() / size_of::()) as u8); + cmdheader + .cfl + .write((size_of::() / size_of::()) as u8); let cmdtbl = &mut ctbas[slot as usize]; - unsafe { ptr::write_bytes(cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, 0, size_of::()); } + unsafe { + ptr::write_bytes( + cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, + 0, + size_of::(), + ); + } let cmdfis = unsafe { &mut *(cmdtbl.cfis.as_mut_ptr() as *mut FisRegH2D) }; cmdfis.fis_type.write(FisType::RegH2D as u8); @@ -338,18 +412,25 @@ impl HbaPort { self.stop(); if self.is.read() & HBA_PORT_IS_ERR != 0 { - let ( - is, ie, cmd, tfd, - ssts, sctl, serr, sact, - ci, sntf, fbs - ) = ( - self.is.read(), self.ie.read(), self.cmd.read(), self.tfd.read(), - self.ssts.read(), self.sctl.read(), self.serr.read(), self.sact.read(), - self.ci.read(), self.sntf.read(), self.fbs.read() + let (is, ie, cmd, tfd, ssts, sctl, serr, sact, ci, sntf, fbs) = ( + self.is.read(), + self.ie.read(), + self.cmd.read(), + self.tfd.read(), + self.ssts.read(), + self.sctl.read(), + self.serr.read(), + self.sact.read(), + self.ci.read(), + self.sntf.read(), + self.fbs.read(), ); error!("IS {:X} IE {:X} CMD {:X} TFD {:X}", is, ie, cmd, tfd); - error!("SSTS {:X} SCTL {:X} SERR {:X} SACT {:X}", ssts, sctl, serr, sact); + error!( + "SSTS {:X} SCTL {:X} SERR {:X} SACT {:X}", + ssts, sctl, serr, sact + ); error!("CI {:X} SNTF {:X} FBS {:X}", ci, sntf, fbs); self.is.write(u32::MAX); @@ -362,20 +443,20 @@ impl HbaPort { #[repr(packed)] pub struct HbaMem { - pub cap: Mmio, // 0x00, Host capability - pub ghc: Mmio, // 0x04, Global host control - pub is: Mmio, // 0x08, Interrupt status - pub pi: Mmio, // 0x0C, Port implemented - pub vs: Mmio, // 0x10, Version - pub ccc_ctl: Mmio, // 0x14, Command completion coalescing control - pub ccc_pts: Mmio, // 0x18, Command completion coalescing ports - pub em_loc: Mmio, // 0x1C, Enclosure management location - pub em_ctl: Mmio, // 0x20, Enclosure management control - pub cap2: Mmio, // 0x24, Host capabilities extended - pub bohc: Mmio, // 0x28, BIOS/OS handoff control and status - pub _rsv: [Mmio; 116], // 0x2C - 0x9F, Reserved + pub cap: Mmio, // 0x00, Host capability + pub ghc: Mmio, // 0x04, Global host control + pub is: Mmio, // 0x08, Interrupt status + pub pi: Mmio, // 0x0C, Port implemented + pub vs: Mmio, // 0x10, Version + pub ccc_ctl: Mmio, // 0x14, Command completion coalescing control + pub ccc_pts: Mmio, // 0x18, Command completion coalescing ports + pub em_loc: Mmio, // 0x1C, Enclosure management location + pub em_ctl: Mmio, // 0x20, Enclosure management control + pub cap2: Mmio, // 0x24, Host capabilities extended + pub bohc: Mmio, // 0x28, BIOS/OS handoff control and status + pub _rsv: [Mmio; 116], // 0x2C - 0x9F, Reserved pub vendor: [Mmio; 96], // 0xA0 - 0xFF, Vendor specific registers - pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers + pub ports: [HbaPort; 32], // 0x100 - 0x10FF, Port control registers } impl HbaMem { @@ -388,18 +469,25 @@ impl HbaMem { */ self.ghc.write(1 << 31 | 1 << 1); - debug!(" - AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}", - self.cap.read(), self.ghc.read(), self.is.read(), self.pi.read(), - self.vs.read(), self.cap2.read(), self.bohc.read()); + debug!( + " - AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}", + self.cap.read(), + self.ghc.read(), + self.is.read(), + self.pi.read(), + self.vs.read(), + self.cap2.read(), + self.bohc.read() + ); } } #[repr(packed)] pub struct HbaPrdtEntry { - dba_low: Mmio, // Data base address (low + dba_low: Mmio, // Data base address (low dba_high: Mmio, // Data base address (high) - _rsv0: Mmio, // Reserved - dbc: Mmio, // Byte count, 4M max, interrupt = 1 + _rsv0: Mmio, // Reserved + dbc: Mmio, // Byte count, 4M max, interrupt = 1 } #[repr(packed)] @@ -431,7 +519,7 @@ pub struct HbaCmdHeader { _prdbc: Mmio, // Physical region descriptor byte count transferred // DW2, 3 - ctba_low: Mmio, // Command table descriptor base address (low) + ctba_low: Mmio, // Command table descriptor base address (low) ctba_high: Mmio, // Command table descriptor base address (high) // DW4 - 7 diff --git a/storage/ahcid/src/ahci/mod.rs b/storage/ahcid/src/ahci/mod.rs index aaf3b78523..73e66c5ec5 100644 --- a/storage/ahcid/src/ahci/mod.rs +++ b/storage/ahcid/src/ahci/mod.rs @@ -1,6 +1,6 @@ +use common::io::Io; use driver_block::Disk; use log::{error, info}; -use common::io::Io; use self::disk_ata::DiskATA; use self::disk_atapi::DiskATAPI; @@ -16,37 +16,33 @@ pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec hba_mem.init(); let pi = hba_mem.pi.read(); let disks: Vec> = (0..hba_mem.ports.len()) - .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) - .filter_map(|i| { - let port = unsafe { &mut *hba_mem.ports.as_mut_ptr().add(i) }; - let port_type = port.probe(); - info!("{}-{}: {:?}", name, i, port_type); + .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) + .filter_map(|i| { + let port = unsafe { &mut *hba_mem.ports.as_mut_ptr().add(i) }; + let port_type = port.probe(); + info!("{}-{}: {:?}", name, i, port_type); - let disk: Option> = match port_type { - HbaPortType::SATA => { - match DiskATA::new(i, port) { - Ok(disk) => Some(Box::new(disk)), - Err(err) => { - error!("{}: {}", i, err); - None - } - } - } - HbaPortType::SATAPI => { - match DiskATAPI::new(i, port) { - Ok(disk) => Some(Box::new(disk)), - Err(err) => { - error!("{}: {}", i, err); - None - } - } - } - _ => None, - }; + let disk: Option> = match port_type { + HbaPortType::SATA => match DiskATA::new(i, port) { + Ok(disk) => Some(Box::new(disk)), + Err(err) => { + error!("{}: {}", i, err); + None + } + }, + HbaPortType::SATAPI => match DiskATAPI::new(i, port) { + Ok(disk) => Some(Box::new(disk)), + Err(err) => { + error!("{}: {}", i, err); + None + } + }, + _ => None, + }; - disk - }) - .collect(); + disk + }) + .collect(); (hba_mem, disks) } diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index e380d997c2..3cfb63a435 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -1,8 +1,8 @@ #![cfg_attr(target_arch = "aarch64", feature(stdsimd))] // Required for yield instruction #![feature(int_roundings)] -extern crate syscall; extern crate byteorder; +extern crate syscall; use std::io::{Read, Write}; use std::os::fd::AsRawFd; @@ -33,7 +33,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_ahci"); - let irq = pci_config.func.legacy_interrupt_line.expect("ahcid: no legacy interrupts supported"); + let irq = pci_config + .func + .legacy_interrupt_line + .expect("ahcid: no legacy interrupts supported"); common::setup_logging( "disk", @@ -45,10 +48,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { info!(" + AHCI {}", pci_config.func.display()); - let address = unsafe { pcid_handle.map_bar(5).expect("ahcid") }.ptr.as_ptr() as usize; + let address = unsafe { pcid_handle.map_bar(5).expect("ahcid") } + .ptr + .as_ptr() as usize; { let scheme_name = format!("disk.{}", name); - let socket = Socket::::nonblock(&scheme_name).expect("ahcid: failed to create disk scheme"); + let socket = + Socket::::nonblock(&scheme_name).expect("ahcid: failed to create disk scheme"); let mut irq_file = irq.irq_handle("ahcid"); let irq_fd = irq_file.as_raw_fd() as usize; @@ -57,8 +63,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { libredox::call::setrens(0, 0).expect("ahcid: failed to enter null namespace"); - event_queue.subscribe(socket.inner().raw(), 1, EventFlags::READ).expect("ahcid: failed to event scheme socket"); - event_queue.subscribe(irq_fd, 1, EventFlags::READ).expect("ahcid: failed to event irq scheme"); + event_queue + .subscribe(socket.inner().raw(), 1, EventFlags::READ) + .expect("ahcid: failed to event scheme socket"); + event_queue + .subscribe(irq_fd, 1, EventFlags::READ) + .expect("ahcid: failed to event irq scheme"); daemon.ready().expect("ahcid: failed to notify parent"); @@ -68,7 +78,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut mounted = true; let mut todo = Vec::new(); while mounted { - let Some(event) = event_queue.next().transpose().expect("ahcid: failed to read event file") else { + let Some(event) = event_queue + .next() + .transpose() + .expect("ahcid: failed to read event file") + else { break; }; if event.fd == socket.inner().raw() { @@ -77,39 +91,53 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { Ok(None) => { mounted = false; break; - }, - Ok(Some(s)) => if let RequestKind::Call(call) = s.kind() { - call - } else { - // TODO: Support e.g. cancellation - continue; - }, - Err(err) => if err.errno == EWOULDBLOCK || err.errno == EAGAIN { - break; - } else { - panic!("ahcid: failed to read disk scheme: {}", err); + } + Ok(Some(s)) => { + if let RequestKind::Call(call) = s.kind() { + call + } else { + // TODO: Support e.g. cancellation + continue; + } + } + Err(err) => { + if err.errno == EWOULDBLOCK || err.errno == EAGAIN { + break; + } else { + panic!("ahcid: failed to read disk scheme: {}", err); + } } }; if let Some(response) = sqe.handle_scheme_block_mut(&mut scheme) { // TODO: handle full CQE? - socket.write_response(response, SignalBehavior::Restart).expect("ahcid: failed to write disk scheme"); + socket + .write_response(response, SignalBehavior::Restart) + .expect("ahcid: failed to write disk scheme"); } else { todo.push(sqe); } } } else if event.fd == irq_fd { let mut irq = [0; 8]; - if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() { + if irq_file + .read(&mut irq) + .expect("ahcid: failed to read irq file") + >= irq.len() + { if scheme.irq() { - irq_file.write(&irq).expect("ahcid: failed to write irq file"); + irq_file + .write(&irq) + .expect("ahcid: failed to write irq file"); // Handle todos in order to finish previous packets if possible let mut i = 0; while i < todo.len() { if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { let _sqe = todo.remove(i); - socket.write_response(resp, SignalBehavior::Restart).expect("ahcid: failed to write disk scheme"); + socket + .write_response(resp, SignalBehavior::Restart) + .expect("ahcid: failed to write disk scheme"); } else { i += 1; } @@ -125,15 +153,22 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { while i < todo.len() { if let Some(response) = todo[i].handle_scheme_block_mut(&mut scheme) { let _sqe = todo.remove(i); - socket.write_response(response, SignalBehavior::Restart).expect("ahcid: failed to write disk scheme"); + socket + .write_response(response, SignalBehavior::Restart) + .expect("ahcid: failed to write disk scheme"); } else { i += 1; } } - if ! mounted { + if !mounted { for sqe in todo.drain(..) { - socket.write_response(Response::new(&sqe, Err(Error::new(ENODEV))), SignalBehavior::Restart).expect("ahcid: failed to write disk scheme"); + socket + .write_response( + Response::new(&sqe, Err(Error::new(ENODEV))), + SignalBehavior::Restart, + ) + .expect("ahcid: failed to write disk scheme"); } } } diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index c5f03d97b6..67ea31262e 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -1,22 +1,22 @@ use std::collections::BTreeMap; -use std::str; use std::fmt::Write; +use std::str; +use common::io::Io as _; use driver_block::{Disk, DiskWrapper}; +use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Stat, MODE_DIR, + Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, }; -use common::io::Io as _; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; use crate::ahci::hba::HbaMem; #[derive(Clone)] enum Handle { - List(Vec), // Dir contents buffer - Disk(usize), // Disk index + List(Vec), // Dir contents buffer + Disk(usize), // Disk index Partition(usize, u32), // Disk index, partition index } @@ -25,17 +25,25 @@ pub struct DiskScheme { hba_mem: &'static mut HbaMem, disks: Box<[DiskWrapper]>, handles: BTreeMap, - next_id: usize + next_id: usize, } impl DiskScheme { - pub fn new(scheme_name: String, hba_mem: &'static mut HbaMem, disks: Vec>) -> DiskScheme { + pub fn new( + scheme_name: String, + hba_mem: &'static mut HbaMem, + disks: Vec>, + ) -> DiskScheme { DiskScheme { scheme_name, hba_mem, - disks: disks.into_iter().map(DiskWrapper::new).collect::>().into_boxed_slice(), + disks: disks + .into_iter() + .map(DiskWrapper::new) + .collect::>() + .into_boxed_slice(), handles: BTreeMap::new(), - next_id: 0 + next_id: 0, } } @@ -62,19 +70,25 @@ impl DiskScheme { fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { for (_, handle) in self.handles.iter() { match handle { - Handle::Disk(i) => if disk_i == *i { - return Err(Error::new(ENOLCK)); - }, - Handle::Partition(i, p) => if disk_i == *i { - match part_i_opt { - Some(part_i) => if part_i == *p { - return Err(Error::new(ENOLCK)); - }, - None => { - return Err(Error::new(ENOLCK)); + Handle::Disk(i) => { + if disk_i == *i { + return Err(Error::new(ENOLCK)); + } + } + Handle::Partition(i, p) => { + if disk_i == *i { + match part_i_opt { + Some(part_i) => { + if part_i == *p { + return Err(Error::new(ENOLCK)); + } + } + None => { + return Err(Error::new(ENOLCK)); + } } } - }, + } _ => (), } } @@ -99,7 +113,7 @@ impl SchemeBlockMut for DiskScheme { write!(list, "{}\n", disk_index).unwrap(); if disk.pt.is_none() { - continue + continue; } for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { write!(list, "{}p{}\n", disk_index, part_index).unwrap(); @@ -117,7 +131,15 @@ impl SchemeBlockMut for DiskScheme { let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; let disk = self.disks.get(i).ok_or(Error::new(ENOENT))?; - if disk.pt.is_none() || disk.pt.as_ref().unwrap().partitions.get(p as usize).is_none() { + if disk.pt.is_none() + || disk + .pt + .as_ref() + .unwrap() + .partitions + .get(p as usize) + .is_none() + { return Err(Error::new(ENOENT)); } @@ -137,11 +159,14 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; self.handles.insert(id, handle); - Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) } fn xdup(&mut self, id: usize, buf: &[u8], _: &CallerCtx) -> Result> { - if ! buf.is_empty() { + if !buf.is_empty() { return Err(Error::new(EINVAL)); } @@ -153,7 +178,10 @@ impl SchemeBlockMut for DiskScheme { let new_id = self.next_id; self.next_id += 1; self.handles.insert(new_id, new_handle); - Ok(Some(OpenResult::ThisScheme { number: new_id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: new_id, + flags: NewFdFlags::POSITIONED, + })) } fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { @@ -162,7 +190,7 @@ impl SchemeBlockMut for DiskScheme { stat.st_mode = MODE_DIR; stat.st_size = data.len() as u64; Ok(Some(0)) - }, + } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; @@ -174,7 +202,10 @@ impl SchemeBlockMut for DiskScheme { let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; let size = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let partition = pt + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; partition.size }; @@ -232,15 +263,24 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(i)) } - fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result> { + fn read( + &mut self, + id: usize, + buf: &mut [u8], + offset: u64, + _fcntl_flags: u32, + ) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(ref handle) => { - let src = usize::try_from(offset).ok().and_then(|o| handle.get(o..)).unwrap_or(&[]); + let src = usize::try_from(offset) + .ok() + .and_then(|o| handle.get(o..)) + .unwrap_or(&[]); let byte_count = core::cmp::min(src.len(), buf.len()); buf[..byte_count].copy_from_slice(&src[..byte_count]); Ok(Some(byte_count)) - }, + } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; @@ -255,7 +295,10 @@ impl SchemeBlockMut for DiskScheme { let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let partition = pt + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; let abs_block = partition.start_lba + rel_block; // TODO: This shouldn't return EOVERFLOW? @@ -270,11 +313,15 @@ impl SchemeBlockMut for DiskScheme { } } - fn write(&mut self, id: usize, buf: &[u8], offset: u64, _fcntl_flags: u32) -> Result> { + fn write( + &mut self, + id: usize, + buf: &[u8], + offset: u64, + _fcntl_flags: u32, + ) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => { - Err(Error::new(EBADF)) - }, + Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; @@ -289,7 +336,10 @@ impl SchemeBlockMut for DiskScheme { let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let partition = pt + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; let abs_block = partition.start_lba + rel_block; if rel_block >= partition.size { @@ -304,21 +354,33 @@ impl SchemeBlockMut for DiskScheme { } fn fsize(&mut self, id: usize) -> Result> { - Ok(Some(match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle) => handle.len() as u64, - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - disk.size() - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block_count = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?.size; - u64::from(disk.block_length()?) * block_count - } - })) + Ok(Some( + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref mut handle) => handle.len() as u64, + Handle::Disk(number) => { + let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; + disk.size() + } + Handle::Partition(disk_num, part_num) => { + let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; + let block_count = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))? + .size; + u64::from(disk.block_length()?) * block_count + } + }, + )) } fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + self.handles + .remove(&id) + .ok_or(Error::new(EBADF)) + .and(Ok(Some(0))) } } diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index 60a151052c..878604a0a4 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -1,17 +1,26 @@ -use std::{fs::File, io::{Read, Write}, process}; +use std::{ + fs::File, + io::{Read, Write}, + process, +}; use driver_block::Disk; use event::{EventFlags, RawEventQueue}; -use fdt::{Fdt, node::FdtNode}; +use fdt::{node::FdtNode, Fdt}; use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; use syscall::{ - data::{Event, Packet}, error::{Error, ENODEV}, flag::EVENT_READ, io::Io, scheme::SchemeBlockMut, EAGAIN, EINTR, EWOULDBLOCK + data::{Event, Packet}, + error::{Error, ENODEV}, + flag::EVENT_READ, + io::Io, + scheme::SchemeBlockMut, + EAGAIN, EINTR, EWOULDBLOCK, }; use crate::scheme::DiskScheme; -mod sd; mod scheme; +mod sd; #[cfg(target_os = "redox")] fn get_dtb() -> Vec { @@ -45,12 +54,23 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let compat_node = fdt.find_compatible(&with).unwrap(); let reg = compat_node.reg().unwrap().next().unwrap(); let reg_size = reg.size.unwrap(); - println!("DeviceMemory start = 0x{:08x}, size = 0x{:08x}", reg.starting_address as usize, reg_size); + println!( + "DeviceMemory start = 0x{:08x}, size = 0x{:08x}", + reg.starting_address as usize, reg_size + ); let addr = unsafe { - common::physmap(reg.starting_address as usize, reg_size, common::Prot::RW, common::MemoryType::DeviceMemory) - .expect("bcm2835-sdhcid: failed to map address") as usize + common::physmap( + reg.starting_address as usize, + reg_size, + common::Prot::RW, + common::MemoryType::DeviceMemory, + ) + .expect("bcm2835-sdhcid: failed to map address") as usize }; - println!("ioremap 0x{:08x} to 0x{:08x} 2222", reg.starting_address as usize, addr); + println!( + "ioremap 0x{:08x} to 0x{:08x} 2222", + reg.starting_address as usize, addr + ); let mut sdhci = sd::SdHostCtrl::new(addr); unsafe { sdhci.init(); @@ -80,12 +100,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { */ } - let scheme_name = "disk.mmc"; let socket_fd = Socket::::create(&scheme_name).expect("mmcd: failed to create disk scheme"); let mut event_queue = RawEventQueue::new().expect("mmcd: failed to open event file"); - event_queue.subscribe(socket_fd.inner().raw(), 0, EventFlags::READ).expect("mmcd: failed to event disk scheme"); + event_queue + .subscribe(socket_fd.inner().raw(), 0, EventFlags::READ) + .expect("mmcd: failed to event disk scheme"); libredox::call::setrens(0, 0).expect("mmcd: failed to enter null namespace"); daemon.ready().expect("mmcd: failed to notify parent"); @@ -97,26 +118,36 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut scheme = DiskScheme::new(scheme_name.to_string(), disks); 'outer: loop { - let Some(event) = event_queue.next().transpose().expect("mmcd: failed to read event file") else { + let Some(event) = event_queue + .next() + .transpose() + .expect("mmcd: failed to read event file") + else { break; }; if event.fd == socket_fd.inner().raw() { loop { let req = match socket_fd.next_request(SignalBehavior::Interrupt) { Ok(None) => break 'outer, - Ok(Some(r)) => if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - }, - Err(err) => if matches!(err.errno, EAGAIN | EWOULDBLOCK | EINTR) { - break; - } else { - panic!("mmcd: failed to read disk scheme: {}", err); + Ok(Some(r)) => { + if let RequestKind::Call(c) = r.kind() { + c + } else { + continue; + } + } + Err(err) => { + if matches!(err.errno, EAGAIN | EWOULDBLOCK | EINTR) { + break; + } else { + panic!("mmcd: failed to read disk scheme: {}", err); + } } }; if let Some(resp) = req.handle_scheme_block_mut(&mut scheme) { - socket_fd.write_response(resp, SignalBehavior::Restart).expect("mmcd: failed to write disk scheme"); + socket_fd + .write_response(resp, SignalBehavior::Restart) + .expect("mmcd: failed to write disk scheme"); } else { todo.push(req); } @@ -129,14 +160,20 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut i = 0; while i < todo.len() { if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { - socket_fd.write_response(resp, SignalBehavior::Restart).expect("mmcd: failed to write disk scheme"); + socket_fd + .write_response(resp, SignalBehavior::Restart) + .expect("mmcd: failed to write disk scheme"); } else { i += 1; } } for req in todo.drain(..) { - socket_fd.write_response(Response::new(&req, Err(Error::new(ENODEV))), SignalBehavior::Restart) + socket_fd + .write_response( + Response::new(&req, Err(Error::new(ENODEV))), + SignalBehavior::Restart, + ) .expect("mmcd: failed to write disk scheme"); } } diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs index 203c72ff40..18e8d28a3f 100644 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ b/storage/bcm2835-sdhcid/src/scheme.rs @@ -1,12 +1,12 @@ use std::collections::BTreeMap; -use std::str; use std::fmt::Write; +use std::str; use std::sync::{Arc, Mutex}; use driver_block::{Disk, DiskWrapper}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Stat, MODE_DIR, + Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, }; @@ -14,8 +14,8 @@ use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; #[derive(Clone)] enum Handle { - List(Vec), // Dir contents buffer - Disk(usize), // Disk index + List(Vec), // Dir contents buffer + Disk(usize), // Disk index Partition(usize, u32), // Disk index, partition index } @@ -23,16 +23,20 @@ pub struct DiskScheme { scheme_name: String, disks: Box<[DiskWrapper]>, handles: BTreeMap, - next_id: usize + next_id: usize, } impl DiskScheme { pub fn new(scheme_name: String, disks: Vec>) -> DiskScheme { DiskScheme { scheme_name, - disks: disks.into_iter().map(DiskWrapper::new).collect::>().into_boxed_slice(), + disks: disks + .into_iter() + .map(DiskWrapper::new) + .collect::>() + .into_boxed_slice(), handles: BTreeMap::new(), - next_id: 0 + next_id: 0, } } @@ -40,19 +44,25 @@ impl DiskScheme { fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { for (_, handle) in self.handles.iter() { match handle { - Handle::Disk(i) => if disk_i == *i { - return Err(Error::new(ENOLCK)); - }, - Handle::Partition(i, p) => if disk_i == *i { - match part_i_opt { - Some(part_i) => if part_i == *p { - return Err(Error::new(ENOLCK)); - }, - None => { - return Err(Error::new(ENOLCK)); + Handle::Disk(i) => { + if disk_i == *i { + return Err(Error::new(ENOLCK)); + } + } + Handle::Partition(i, p) => { + if disk_i == *i { + match part_i_opt { + Some(part_i) => { + if part_i == *p { + return Err(Error::new(ENOLCK)); + } + } + None => { + return Err(Error::new(ENOLCK)); + } } } - }, + } _ => (), } } @@ -72,7 +82,7 @@ impl SchemeBlockMut for DiskScheme { write!(list, "{}\n", disk_index).unwrap(); if disk.pt.is_none() { - continue + continue; } for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { write!(list, "{}p{}\n", disk_index, part_index).unwrap(); @@ -82,7 +92,10 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle::List(list.into_bytes())); - Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) } else { Err(Error::new(EISDIR)) } @@ -96,7 +109,15 @@ impl SchemeBlockMut for DiskScheme { let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; if let Some(disk) = self.disks.get(i) { - if disk.pt.is_none() || disk.pt.as_ref().unwrap().partitions.get(p as usize).is_none() { + if disk.pt.is_none() + || disk + .pt + .as_ref() + .unwrap() + .partitions + .get(p as usize) + .is_none() + { return Err(Error::new(ENOENT)); } @@ -105,7 +126,10 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle::Partition(i, p)); - Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) } else { Err(Error::new(ENOENT)) } @@ -118,7 +142,10 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle::Disk(i)); - Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) } else { Err(Error::new(ENOENT)) } @@ -129,7 +156,7 @@ impl SchemeBlockMut for DiskScheme { } fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if ! buf.is_empty() { + if !buf.is_empty() { return Err(Error::new(EINVAL)); } @@ -150,7 +177,7 @@ impl SchemeBlockMut for DiskScheme { stat.st_mode = MODE_DIR; stat.st_size = data.len() as u64; Ok(Some(0)) - }, + } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; @@ -162,7 +189,10 @@ impl SchemeBlockMut for DiskScheme { let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; let size = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let partition = pt + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; partition.size }; @@ -220,14 +250,23 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(i)) } - fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _flags: u32) -> Result> { + fn read( + &mut self, + id: usize, + buf: &mut [u8], + offset: u64, + _flags: u32, + ) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(ref handle) => { - let src = usize::try_from(offset).ok().and_then(|o| handle.get(o..)).unwrap_or(&[]); + let src = usize::try_from(offset) + .ok() + .and_then(|o| handle.get(o..)) + .unwrap_or(&[]); let bytes = src.len().min(buf.len()); buf[..bytes].copy_from_slice(&src[..bytes]); Ok(Some(bytes)) - }, + } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; @@ -242,7 +281,10 @@ impl SchemeBlockMut for DiskScheme { let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let partition = pt + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; let abs_block = partition.start_lba + rel_block; if rel_block >= partition.size { @@ -258,9 +300,7 @@ impl SchemeBlockMut for DiskScheme { fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => { - Err(Error::new(EBADF)) - }, + Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; @@ -275,7 +315,10 @@ impl SchemeBlockMut for DiskScheme { let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let partition = pt + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; let abs_block = partition.start_lba + rel_block; if rel_block >= partition.size { @@ -291,22 +334,30 @@ impl SchemeBlockMut for DiskScheme { fn fsize(&mut self, id: usize) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle) => { - Ok(Some(handle.len() as u64)) - }, + Handle::List(ref mut handle) => Ok(Some(handle.len() as u64)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; Ok(Some(disk.size())) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block_count = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?.size; + let block_count = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))? + .size; Ok(Some(u64::from(disk.block_length()?) * block_count)) } } } fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + self.handles + .remove(&id) + .ok_or(Error::new(EBADF)) + .and(Ok(Some(0))) } } diff --git a/storage/bcm2835-sdhcid/src/sd/mod.rs b/storage/bcm2835-sdhcid/src/sd/mod.rs index 2e31b3ae19..00d967725c 100644 --- a/storage/bcm2835-sdhcid/src/sd/mod.rs +++ b/storage/bcm2835-sdhcid/src/sd/mod.rs @@ -26,7 +26,6 @@ pub(crate) unsafe fn wait_msec(mut n: usize) { asm!("mrs {0}, cntfrq_el0", out(reg) f); asm!("mrs {0}, cntpct_el0", out(reg) t); - t += ((f / 1000) * n) / 1000; loop { @@ -34,7 +33,7 @@ pub(crate) unsafe fn wait_msec(mut n: usize) { if r >= t { break; } - }; + } } #[cfg(target_arch = "x86_64")] @@ -60,15 +59,13 @@ const CMD_STOP_TRANS: u32 = 0x0c03_0000; const CMD_READ_SINGLE: u32 = 0x1122_0010; const CMD_READ_MULTI: u32 = 0x1222_0032; const CMD_SET_BLOCKCNT: u32 = 0x1702_0000; -const CMD_WRITE_SINGLE:u32 = 0x1822_0000; -const CMD_WRITE_MULTI:u32 = 0x1922_0022; +const CMD_WRITE_SINGLE: u32 = 0x1822_0000; +const CMD_WRITE_MULTI: u32 = 0x1922_0022; const CMD_APP_CMD: u32 = 0x3700_0000; -const CMD_SET_BUS_WIDTH: u32 = 0x0602_0000|CMD_NEED_APP; -const CMD_SEND_OP_COND: u32 = 0x2902_0000|CMD_NEED_APP; -const CMD_SEND_SCR: u32 = 0x3322_0010|CMD_NEED_APP; - - +const CMD_SET_BUS_WIDTH: u32 = 0x0602_0000 | CMD_NEED_APP; +const CMD_SEND_OP_COND: u32 = 0x2902_0000 | CMD_NEED_APP; +const CMD_SEND_SCR: u32 = 0x3322_0010 | CMD_NEED_APP; //STATUS register settings const SR_READ_AVAILABLE: u32 = 0x0000_0800; @@ -93,7 +90,6 @@ const C1_CLK_EN: u32 = 0x0000_0004; const C1_CLK_STABLE: u32 = 0x0000_0002; const C1_CLK_INTLEN: u32 = 0x0000_0001; - //INTERRUPT register settings const INT_DATA_TIMEOUT: u32 = 0x0010_0000; const INT_CMD_TIMEOUT: u32 = 0x0001_0000; @@ -168,7 +164,7 @@ pub struct SdHostCtrlRegs { _rsvd: [Mmio; 47], //Slot Interrupt Status and Version - slotisr_ver: Mmio + slotisr_ver: Mmio, } //TODO: refactor, sd/sdhci/bcmh2835-sdhci three different modules. @@ -180,13 +176,13 @@ pub struct SdHostCtrl { rca: u32, //relative card address scr: [u32; 2], ocr: u32, - size: u64 + size: u64, } impl SdHostCtrl { pub fn new(address: usize) -> Self { SdHostCtrl { - regs: RwLock::new(unsafe { &mut *(address as *mut SdHostCtrlRegs)}), + regs: RwLock::new(unsafe { &mut *(address as *mut SdHostCtrlRegs) }), host_spec_ver: 0, cid: [0; 4], csd: [0; 4], @@ -207,15 +203,14 @@ impl SdHostCtrl { reg_val = regs.control1.read(); regs.control1.write(reg_val | C1_SRST_HC); let mut cnt = 1000; - while (cnt >= 0) && - ((regs.control1.read() & C1_SRST_HC) == C1_SRST_HC) { + while (cnt >= 0) && ((regs.control1.read() & C1_SRST_HC) == C1_SRST_HC) { cnt -= 1; wait_msec(10); } if cnt < 0 { println!("ERROR: failed to reset EMMC"); - return ; + return; } println!("EMMC: reset OK"); reg_val = regs.control1.read(); @@ -226,7 +221,7 @@ impl SdHostCtrl { { if let Err(_) = self.set_clock(40_0000) { println!("ERROR: failed to set clock {}", 40_0000); - return ; + return; } } @@ -236,12 +231,12 @@ impl SdHostCtrl { if let Err(_) = self.sd_cmd(CMD_GO_IDLE, 0) { println!("failed to go idle"); - return ; + return; } if let Err(_) = self.sd_cmd(CMD_SEND_IF_COND, 0x0000_01aa) { println!("failed to send if cond"); - return ; + return; } cnt = 6; @@ -268,21 +263,25 @@ impl SdHostCtrl { print!("\n"); } else { println!("ERROR: EMMC ACMD41 returned error"); - return ; + return; } } if (reg_val & ACMD41_CMD_COMPLETE) == 0 || cnt <= 0 { println!("ACMD41 TIMEOUT"); - return ; + return; } if (reg_val & ACMD41_VOLTAGE) == 0 { println!("ACMD41 VOLTAGE NOT FOUND!"); - return ; + return; } - let ccs = if (reg_val & ACMD41_CMD_CCS) != 0 { SCR_SUPP_CCS } else { 0 }; + let ccs = if (reg_val & ACMD41_CMD_CCS) != 0 { + SCR_SUPP_CCS + } else { + 0 + }; if let Err(_) = self.sd_cmd(CMD_ALL_SEND_CID, 0) { println!("CMD_ALL_SEND_CID ERROR, IGNORE!"); @@ -294,7 +293,7 @@ impl SdHostCtrl { if let Err(_) = self.sd_cmd(CMD_SEND_CSD, sd_rca) { println!("failed to get csd"); - return ; + return; } let (csize, cmult) = if (self.ocr & ACMD41_CMD_CCS) != 0 { @@ -309,20 +308,19 @@ impl SdHostCtrl { self.size = ((csize + 1) << (cmult + 2)) * 512; println!("mmc size = 0x{:08x}", self.size); - if let Err(_) = self.set_clock(2500_0000) { println!("failed to set clock 2500_0000 Hz"); - return ; + return; } if let Err(_) = self.sd_cmd(CMD_CARD_SELECT, sd_rca) { println!("failed to CMD_CARD_SELECT 0x{:08x}", sd_rca); - return ; + return; } if let Err(_) = self.sd_status(SR_DAT_INHIBIT) { println!("SR_DAT_INHIBIT return"); - return ; + return; } let regs = self.regs.get_mut().unwrap(); @@ -330,12 +328,12 @@ impl SdHostCtrl { if let Err(_) = self.sd_cmd(CMD_SEND_SCR, 0) { println!("failed to CMD_SEND_SCR"); - return ; + return; } if let Err(_) = self.sd_int(INT_READ_RDY) { println!("failed to INT_READ_RDY"); - return ; + return; } cnt = 10000; @@ -354,13 +352,13 @@ impl SdHostCtrl { } if i != 2 { println!("SD TIMEOUT FOR SCR[; 2]"); - return ; + return; } if (self.scr[0] & SCR_SD_BUS_WIDTH_4) != 0 { if let Err(_) = self.sd_cmd(CMD_SET_BUS_WIDTH, sd_rca | 2) { println!("failed to set bus width, {}", sd_rca | 2); - return ; + return; } let regs = self.regs.get_mut().unwrap(); regs.control0.write(C0_HCTL_DWITDH); @@ -411,13 +409,32 @@ impl SdHostCtrl { if x == 0 { s = 0; } else { - if (x & 0xffff_0000) == 0 { x <<= 16; s -= 16; } - if (x & 0xff00_0000) == 0 { x <<= 8; s -= 8; } - if (x & 0xf000_0000) == 0 { x <<= 4; s -= 4; } - if (x & 0xc000_0000) == 0 { x <<= 2; s -= 2; } - if (x & 0x8000_0000) == 0 { x <<= 1; s -= 1; } - if s > 0 { s -= 1; } - if s > 7 { s = 7; } + if (x & 0xffff_0000) == 0 { + x <<= 16; + s -= 16; + } + if (x & 0xff00_0000) == 0 { + x <<= 8; + s -= 8; + } + if (x & 0xf000_0000) == 0 { + x <<= 4; + s -= 4; + } + if (x & 0xc000_0000) == 0 { + x <<= 2; + s -= 2; + } + if (x & 0x8000_0000) == 0 { + x <<= 1; + s -= 1; + } + if s > 0 { + s -= 1; + } + if s > 7 { + s = 7; + } } let mut d = 0; if self.host_spec_ver > HOST_SPEC_V2 { @@ -437,7 +454,7 @@ impl SdHostCtrl { h = (d & 0x300) >> 2; } - d = ( ((d & 0xff) << 8)| h); + d = (((d & 0xff) << 8) | h); reg_val = regs.control1.read() & 0xffff_003f; regs.control1.write(reg_val | d); wait_msec(10); @@ -550,7 +567,6 @@ impl SdHostCtrl { } else { return Ok(reg_val & CMD_ERRORS_MASK); } - } pub unsafe fn sd_status(&mut self, mask: u32) -> Result<()> { @@ -647,7 +663,8 @@ impl SdHostCtrl { cnt += 1; } - if num > 1 && (self.scr[0] & SCR_SUPP_SET_BLKCNT) == 0 && (self.scr[0] & SCR_SUPP_CCS) != 0 { + if num > 1 && (self.scr[0] & SCR_SUPP_SET_BLKCNT) == 0 && (self.scr[0] & SCR_SUPP_CCS) != 0 + { self.sd_cmd(CMD_STOP_TRANS, 0).unwrap(); } Ok((num * 512) as usize) @@ -707,7 +724,8 @@ impl SdHostCtrl { return Err(Error::new(EINVAL)); } - if num > 1 && (self.scr[0] & SCR_SUPP_SET_BLKCNT) == 0 && (self.scr[0] & SCR_SUPP_CCS) != 0 { + if num > 1 && (self.scr[0] & SCR_SUPP_SET_BLKCNT) == 0 && (self.scr[0] & SCR_SUPP_CCS) != 0 + { self.sd_cmd(CMD_STOP_TRANS, 0).unwrap(); } Ok((num * 512) as usize) @@ -724,10 +742,9 @@ impl Disk for SdHostCtrl { self.size } - fn read(&mut self, block:u64, buffer: &mut [u8]) -> Result> { + fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result> { if (buffer.len() % 512) != 0 { - println!("buffer.len {} should be aligned to {}", - buffer.len(), 512); + println!("buffer.len {} should be aligned to {}", buffer.len(), 512); return Err(Error::new(EINVAL)); } let u32_len = buffer.len() / core::mem::size_of::(); @@ -739,14 +756,13 @@ impl Disk for SdHostCtrl { }; match ret { Ok(cnt) => Ok(Some(cnt)), - Err(err) => Err(err) + Err(err) => Err(err), } } - fn write(&mut self, block:u64, buffer: &[u8]) -> Result> { + fn write(&mut self, block: u64, buffer: &[u8]) -> Result> { if (buffer.len() % 512) != 0 { - println!("buffer.len {} should be aligned to {}", - buffer.len(), 512); + println!("buffer.len {} should be aligned to {}", buffer.len(), 512); return Err(Error::new(EINVAL)); } let u32_len = buffer.len() / core::mem::size_of::(); @@ -758,12 +774,11 @@ impl Disk for SdHostCtrl { }; match ret { Ok(cnt) => Ok(Some(cnt)), - Err(err) => Err(err) + Err(err) => Err(err), } } fn block_length(&mut self) -> Result { Ok(512) } - } diff --git a/storage/ided/src/ide.rs b/storage/ided/src/ide.rs index f61003c1a2..c63cedfc38 100644 --- a/storage/ided/src/ide.rs +++ b/storage/ided/src/ide.rs @@ -80,12 +80,14 @@ impl Channel { prdt: unsafe { Dma::zeroed( //TODO: PhysBox::new_in_32bit_space(4096)? - )?.assume_init() + )? + .assume_init() }, buf: unsafe { Dma::zeroed( //TODO: PhysBox::new_in_32bit_space(16 * 4096)? - )?.assume_init() + )? + .assume_init() }, }) } @@ -142,7 +144,12 @@ impl Channel { break; } if start.elapsed() >= TIMEOUT { - log::error!("line {} polling {} timeout with status 0x{:02X}", line, if read { "read" } else { "write" }, status); + log::error!( + "line {} polling {} timeout with status 0x{:02X}", + line, + if read { "read" } else { "write" }, + status + ); return Err(Error::new(EIO)); } thread::yield_now(); @@ -181,7 +188,13 @@ impl Disk for AtaDisk { let sectors = (chunk.len() + 511) / 512; assert!(sectors <= 128); - log::trace!("IDE read chan {} dev {} block {:#x} count {:#x}", self.chan_i, self.dev, block, sectors); + log::trace!( + "IDE read chan {} dev {} block {:#x} count {:#x}", + self.chan_i, + self.dev, + block, + sectors + ); let mut chan = self.chan.lock().unwrap(); @@ -315,7 +328,13 @@ impl Disk for AtaDisk { let sectors = (chunk.len() + 511) / 512; assert!(sectors <= 128); - log::trace!("IDE write chan {} dev {} block {:#x} count {:#x}", self.chan_i, self.dev, block, sectors); + log::trace!( + "IDE write chan {} dev {} block {:#x} count {:#x}", + self.chan_i, + self.dev, + block, + sectors + ); let mut chan = self.chan.lock().unwrap(); @@ -424,10 +443,10 @@ impl Disk for AtaDisk { for i in 0..128 { chan.data32.write( - ((chunk[sector * 512 + i * 4 + 0] as u32) << 0) | - ((chunk[sector * 512 + i * 4 + 1] as u32) << 8) | - ((chunk[sector * 512 + i * 4 + 2] as u32) << 16) | - ((chunk[sector * 512 + i * 4 + 3] as u32) << 24) + ((chunk[sector * 512 + i * 4 + 0] as u32) << 0) + | ((chunk[sector * 512 + i * 4 + 1] as u32) << 8) + | ((chunk[sector * 512 + i * 4 + 2] as u32) << 16) + | ((chunk[sector * 512 + i * 4 + 3] as u32) << 24), ); } } diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 73db90c14f..cc8abb79f2 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -1,3 +1,4 @@ +use common::io::Io as _; use driver_block::Disk; use event::{EventFlags, RawEventQueue}; use libredox::flag; @@ -12,9 +13,12 @@ use std::{ thread::{self, sleep}, time::Duration, }; -use common::io::Io as _; use syscall::{ - data::{Event, Packet}, error::{Error, ENODEV}, flag::EVENT_READ, scheme::SchemeBlockMut, EAGAIN, EINTR, EWOULDBLOCK + data::{Event, Packet}, + error::{Error, ENODEV}, + flag::EVENT_READ, + scheme::SchemeBlockMut, + EAGAIN, EINTR, EWOULDBLOCK, }; use crate::{ @@ -164,10 +168,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - let mut sectors = (dest[100] as u64) | - ((dest[101] as u64) << 16) | - ((dest[102] as u64) << 32) | - ((dest[103] as u64) << 48); + let mut sectors = (dest[100] as u64) + | ((dest[101] as u64) << 16) + | ((dest[102] as u64) << 32) + | ((dest[103] as u64) << 48); let lba_bits = if sectors == 0 { sectors = (dest[60] as u64) | ((dest[61] as u64) << 16); @@ -196,21 +200,23 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } let scheme_name = format!("disk.{}", name); - let socket_fd = Socket::::nonblock(&scheme_name) - .expect("ided: failed to create disk scheme"); + let socket_fd = + Socket::::nonblock(&scheme_name).expect("ided: failed to create disk scheme"); let primary_irq_fd = libredox::call::open( &format!("/scheme/irq/{}", primary_irq), flag::O_RDWR | flag::O_NONBLOCK, 0, - ).expect("ided: failed to open irq file"); + ) + .expect("ided: failed to open irq file"); let mut primary_irq_file = unsafe { File::from_raw_fd(primary_irq_fd as RawFd) }; let secondary_irq_fd = libredox::call::open( &format!("/scheme/irq/{}", secondary_irq), flag::O_RDWR | flag::O_NONBLOCK, 0, - ).expect("ided: failed to open irq file"); + ) + .expect("ided: failed to open irq file"); let mut secondary_irq_file = unsafe { File::from_raw_fd(secondary_irq_fd as RawFd) }; let mut event_queue = RawEventQueue::new().expect("ided: failed to open event file"); @@ -219,63 +225,75 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("ided: failed to notify parent"); - event_queue.subscribe( - socket_fd.inner().raw(), - 0, - EventFlags::READ, - ).expect("ided: failed to event disk scheme"); + event_queue + .subscribe(socket_fd.inner().raw(), 0, EventFlags::READ) + .expect("ided: failed to event disk scheme"); - event_queue.subscribe( - primary_irq_fd, - 0, - EventFlags::READ, - ).expect("ided: failed to event irq scheme"); + event_queue + .subscribe(primary_irq_fd, 0, EventFlags::READ) + .expect("ided: failed to event irq scheme"); - event_queue.subscribe( - secondary_irq_fd, - 0, - EventFlags::READ, - ).expect("ided: failed to event irq scheme"); + event_queue + .subscribe(secondary_irq_fd, 0, EventFlags::READ) + .expect("ided: failed to event irq scheme"); let mut scheme = DiskScheme::new(scheme_name, chans, disks); let mut todo = Vec::new(); 'outer: loop { - let Some(event) = event_queue.next().transpose().expect("ided: failed to read event file") else { + let Some(event) = event_queue + .next() + .transpose() + .expect("ided: failed to read event file") + else { break; }; if event.fd == socket_fd.inner().raw() { loop { let req = match socket_fd.next_request(SignalBehavior::Interrupt) { Ok(None) => break 'outer, - Ok(Some(r)) => if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - }, - Err(err) => if matches!(err.errno, EAGAIN | EWOULDBLOCK | EINTR) { - break; - } else { - panic!("ided: failed to read disk scheme: {}", err); + Ok(Some(r)) => { + if let RequestKind::Call(c) = r.kind() { + c + } else { + continue; + } + } + Err(err) => { + if matches!(err.errno, EAGAIN | EWOULDBLOCK | EINTR) { + break; + } else { + panic!("ided: failed to read disk scheme: {}", err); + } } }; if let Some(resp) = req.handle_scheme_block_mut(&mut scheme) { - socket_fd.write_response(resp, SignalBehavior::Restart).expect("ided: failed to write disk scheme"); + socket_fd + .write_response(resp, SignalBehavior::Restart) + .expect("ided: failed to write disk scheme"); } else { todo.push(req); } } } else if event.fd == primary_irq_fd { let mut irq = [0; 8]; - if primary_irq_file.read(&mut irq).expect("ided: failed to read irq file") >= irq.len() { + if primary_irq_file + .read(&mut irq) + .expect("ided: failed to read irq file") + >= irq.len() + { if scheme.irq(0) { - primary_irq_file.write(&irq).expect("ided: failed to write irq file"); + primary_irq_file + .write(&irq) + .expect("ided: failed to write irq file"); // Handle todos in order to finish previous packets if possible let mut i = 0; while i < todo.len() { if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { - socket_fd.write_response(resp, SignalBehavior::Restart).expect("ided: failed to write disk scheme"); + socket_fd + .write_response(resp, SignalBehavior::Restart) + .expect("ided: failed to write disk scheme"); } else { i += 1; } @@ -284,15 +302,23 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } else if event.fd == secondary_irq_fd { let mut irq = [0; 8]; - if secondary_irq_file.read(&mut irq).expect("ided: failed to read irq file") >= irq.len() { + if secondary_irq_file + .read(&mut irq) + .expect("ided: failed to read irq file") + >= irq.len() + { if scheme.irq(1) { - secondary_irq_file.write(&irq).expect("ided: failed to write irq file"); + secondary_irq_file + .write(&irq) + .expect("ided: failed to write irq file"); // Handle todos in order to finish previous packets if possible let mut i = 0; while i < todo.len() { if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { - socket_fd.write_response(resp, SignalBehavior::Restart).expect("ided: failed to write disk scheme"); + socket_fd + .write_response(resp, SignalBehavior::Restart) + .expect("ided: failed to write disk scheme"); } else { i += 1; } @@ -307,14 +333,20 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut i = 0; while i < todo.len() { if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { - socket_fd.write_response(resp, SignalBehavior::Restart).expect("ided: failed to write disk scheme"); + socket_fd + .write_response(resp, SignalBehavior::Restart) + .expect("ided: failed to write disk scheme"); } else { i += 1; } } for req in todo.drain(..) { - socket_fd.write_response(Response::new(&req, Err(Error::new(ENODEV))), SignalBehavior::Restart) + socket_fd + .write_response( + Response::new(&req, Err(Error::new(ENODEV))), + SignalBehavior::Restart, + ) .expect("ided: failed to write disk scheme"); } } diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs index bb46d11082..0248cae6c5 100644 --- a/storage/ided/src/scheme.rs +++ b/storage/ided/src/scheme.rs @@ -1,22 +1,22 @@ use std::collections::BTreeMap; -use std::str; use std::fmt::Write; +use std::str; use std::sync::{Arc, Mutex}; use driver_block::{Disk, DiskWrapper}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, Result, Stat, MODE_DIR, + Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, }; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; use crate::ide::Channel; +use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; #[derive(Clone)] enum Handle { - List(Vec), // Dir contents buffer - Disk(usize), // Disk index + List(Vec), // Dir contents buffer + Disk(usize), // Disk index Partition(usize, u32), // Disk index, partition index } @@ -25,17 +25,25 @@ pub struct DiskScheme { chans: Box<[Arc>]>, disks: Box<[DiskWrapper]>, handles: BTreeMap, - next_id: usize + next_id: usize, } impl DiskScheme { - pub fn new(scheme_name: String, chans: Vec>>, disks: Vec>) -> DiskScheme { + pub fn new( + scheme_name: String, + chans: Vec>>, + disks: Vec>, + ) -> DiskScheme { DiskScheme { scheme_name, chans: chans.into_boxed_slice(), - disks: disks.into_iter().map(DiskWrapper::new).collect::>().into_boxed_slice(), + disks: disks + .into_iter() + .map(DiskWrapper::new) + .collect::>() + .into_boxed_slice(), handles: BTreeMap::new(), - next_id: 0 + next_id: 0, } } @@ -49,19 +57,25 @@ impl DiskScheme { fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { for (_, handle) in self.handles.iter() { match handle { - Handle::Disk(i) => if disk_i == *i { - return Err(Error::new(ENOLCK)); - }, - Handle::Partition(i, p) => if disk_i == *i { - match part_i_opt { - Some(part_i) => if part_i == *p { - return Err(Error::new(ENOLCK)); - }, - None => { - return Err(Error::new(ENOLCK)); + Handle::Disk(i) => { + if disk_i == *i { + return Err(Error::new(ENOLCK)); + } + } + Handle::Partition(i, p) => { + if disk_i == *i { + match part_i_opt { + Some(part_i) => { + if part_i == *p { + return Err(Error::new(ENOLCK)); + } + } + None => { + return Err(Error::new(ENOLCK)); + } } } - }, + } _ => (), } } @@ -81,7 +95,7 @@ impl SchemeBlockMut for DiskScheme { write!(list, "{}\n", disk_index).unwrap(); if disk.pt.is_none() { - continue + continue; } for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { write!(list, "{}p{}\n", disk_index, part_index).unwrap(); @@ -91,7 +105,10 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle::List(list.into_bytes())); - Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) } else { Err(Error::new(EISDIR)) } @@ -105,7 +122,15 @@ impl SchemeBlockMut for DiskScheme { let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; if let Some(disk) = self.disks.get(i) { - if disk.pt.is_none() || disk.pt.as_ref().unwrap().partitions.get(p as usize).is_none() { + if disk.pt.is_none() + || disk + .pt + .as_ref() + .unwrap() + .partitions + .get(p as usize) + .is_none() + { return Err(Error::new(ENOENT)); } @@ -114,7 +139,10 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle::Partition(i, p)); - Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) } else { Err(Error::new(ENOENT)) } @@ -127,7 +155,10 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle::Disk(i)); - Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) } else { Err(Error::new(ENOENT)) } @@ -138,7 +169,7 @@ impl SchemeBlockMut for DiskScheme { } fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if ! buf.is_empty() { + if !buf.is_empty() { return Err(Error::new(EINVAL)); } @@ -159,7 +190,7 @@ impl SchemeBlockMut for DiskScheme { stat.st_mode = MODE_DIR; stat.st_size = data.len() as u64; Ok(Some(0)) - }, + } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; @@ -171,7 +202,10 @@ impl SchemeBlockMut for DiskScheme { let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; let size = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let partition = pt + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; partition.size }; @@ -229,14 +263,23 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(i)) } - fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _flags: u32) -> Result> { + fn read( + &mut self, + id: usize, + buf: &mut [u8], + offset: u64, + _flags: u32, + ) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(ref handle) => { - let src = usize::try_from(offset).ok().and_then(|o| handle.get(o..)).unwrap_or(&[]); + let src = usize::try_from(offset) + .ok() + .and_then(|o| handle.get(o..)) + .unwrap_or(&[]); let bytes = src.len().min(buf.len()); buf[..bytes].copy_from_slice(&src[..bytes]); Ok(Some(bytes)) - }, + } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; @@ -251,7 +294,10 @@ impl SchemeBlockMut for DiskScheme { let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let partition = pt + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; let abs_block = partition.start_lba + rel_block; if rel_block >= partition.size { @@ -267,9 +313,7 @@ impl SchemeBlockMut for DiskScheme { fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => { - Err(Error::new(EBADF)) - }, + Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; let blk_len = disk.block_length()?; @@ -284,7 +328,10 @@ impl SchemeBlockMut for DiskScheme { let abs_block = { let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?; + let partition = pt + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; let abs_block = partition.start_lba + rel_block; if rel_block >= partition.size { @@ -300,22 +347,30 @@ impl SchemeBlockMut for DiskScheme { fn fsize(&mut self, id: usize) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle) => { - Ok(Some(handle.len() as u64)) - }, + Handle::List(ref mut handle) => Ok(Some(handle.len() as u64)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; Ok(Some(disk.size())) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block_count = disk.pt.as_ref().ok_or(Error::new(EBADF))?.partitions.get(part_num as usize).ok_or(Error::new(EBADF))?.size; + let block_count = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))? + .size; Ok(Some(u64::from(disk.block_length()?) * block_count)) } } } fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF)).and(Ok(Some(0))) + self.handles + .remove(&id) + .ok_or(Error::new(EBADF)) + .and(Ok(Some(0))) } } diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index 038b53388d..2a611690f6 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -12,12 +12,12 @@ use libredox::flag; use redox_scheme::{CallerCtx, OpenResult, RequestKind, SchemeMut, SignalBehavior, Socket, V2}; use syscall::data::Stat; -use syscall::schemev2::NewFdFlags; use syscall::error::*; use syscall::flag::{MODE_DIR, MODE_FILE}; +use syscall::schemev2::NewFdFlags; use syscall::PAGE_SIZE; -use anyhow::{anyhow, Context, bail}; +use anyhow::{anyhow, bail, Context}; const LIST: [u8; 2] = *b"0\n"; @@ -46,7 +46,10 @@ impl DiskScheme { let mut size = 0; // TODO: handle error - for line in std::fs::read_to_string("/scheme/sys/env").context("failed to read env")?.lines() { + for line in std::fs::read_to_string("/scheme/sys/env") + .context("failed to read env")? + .lines() + { let mut parts = line.splitn(2, '='); let name = parts.next().unwrap_or(""); let value = parts.next().unwrap_or(""); @@ -61,11 +64,18 @@ impl DiskScheme { } if phys == 0 || size == 0 { - bail!("either livedisk phys ({}) or size ({}) was zero", phys, size); + bail!( + "either livedisk phys ({}) or size ({}) was zero", + phys, + size + ); } let start = phys.div_floor(PAGE_SIZE) * PAGE_SIZE; - let end = phys.checked_add(size).context("phys + size overflow")?.next_multiple_of(PAGE_SIZE); + let end = phys + .checked_add(size) + .context("phys + size overflow")? + .next_multiple_of(PAGE_SIZE); let size = end - start; let the_data = unsafe { @@ -77,23 +87,24 @@ impl DiskScheme { length: size, prot: flag::PROT_READ | flag::PROT_WRITE, flags: flag::MAP_SHARED, - }).map_err(|err| anyhow!("failed to mmap livedisk: {}", err))?; + }) + .map_err(|err| anyhow!("failed to mmap livedisk: {}", err))?; std::slice::from_raw_parts_mut(base as *mut u8, size) }; - Ok(DiskScheme { - the_data, - }) + Ok(DiskScheme { the_data }) } } impl SchemeMut for DiskScheme { fn fsize(&mut self, id: usize) -> Result { - Ok(match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { - HandleType::TopLevel => LIST.len() as u64, - HandleType::TheData => self.the_data.len() as u64, - }) + Ok( + match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { + HandleType::TopLevel => LIST.len() as u64, + HandleType::TheData => self.the_data.len() as u64, + }, + ) } fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize) -> Result { @@ -116,12 +127,8 @@ impl SchemeMut for DiskScheme { Ok(OpenResult::ThisScheme { number: match path_trimmed { - "" => { - HandleType::TopLevel as usize - }, - "0" => { - HandleType::TheData as usize - } + "" => HandleType::TopLevel as usize, + "0" => HandleType::TheData as usize, _ => return Err(Error::new(ENOENT)), }, flags: NewFdFlags::POSITIONED, @@ -133,7 +140,10 @@ impl SchemeMut for DiskScheme { HandleType::TopLevel => &LIST, }; - let src = usize::try_from(offset).ok().and_then(|o| data.get(o..)).unwrap_or(&[]); + let src = usize::try_from(offset) + .ok() + .and_then(|o| data.get(o..)) + .unwrap_or(&[]); let byte_count = std::cmp::min(src.len(), buf.len()); buf[..byte_count].copy_from_slice(&src[..byte_count]); Ok(byte_count) @@ -144,7 +154,10 @@ impl SchemeMut for DiskScheme { HandleType::TopLevel => return Err(Error::new(EBADF)), }; - let dst = usize::try_from(offset).ok().and_then(|o| data.get_mut(o..)).unwrap_or(&mut []); + let dst = usize::try_from(offset) + .ok() + .and_then(|o| data.get_mut(o..)) + .unwrap_or(&mut []); let byte_count = std::cmp::min(dst.len(), buf.len()); dst[..byte_count].copy_from_slice(&buf[..byte_count]); Ok(byte_count) @@ -190,18 +203,26 @@ fn main() -> anyhow::Result<()> { daemon.ready().expect("failed to signal readiness"); loop { - let req = match socket_fd.next_request(SignalBehavior::Restart).expect("failed to get next request") { - Some(r) => if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - }, + let req = match socket_fd + .next_request(SignalBehavior::Restart) + .expect("failed to get next request") + { + Some(r) => { + if let RequestKind::Call(c) = r.kind() { + c + } else { + continue; + } + } None => break, }; let resp = req.handle_scheme_mut(&mut scheme); - socket_fd.write_response(resp, SignalBehavior::Restart).expect("failed to write packet"); + socket_fd + .write_response(resp, SignalBehavior::Restart) + .expect("failed to write packet"); } std::process::exit(0); - }).map_err(|err| anyhow!("failed to start daemon: {}", err))?; + }) + .map_err(|err| anyhow!("failed to start daemon: {}", err))?; } diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 0676d6a3be..d969a51af3 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -12,10 +12,7 @@ use std::{slice, usize}; use libredox::flag; use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PciFunctionHandle}; use redox_scheme::{CallRequest, RequestKind, SignalBehavior, Socket, V2}; -use syscall::{ - Event, Packet, Result, SchemeBlockMut, - PAGE_SIZE, -}; +use syscall::{Event, Packet, Result, SchemeBlockMut, PAGE_SIZE}; use self::nvme::{InterruptMethod, InterruptSources, Nvme}; use self::scheme::DiskScheme; @@ -53,10 +50,8 @@ fn get_int_method( fn bar_base(pcid_handle: &mut PciFunctionHandle, bir: u8) -> Result> { Ok(unsafe { pcid_handle.map_bar(bir) }.expect("nvmed").ptr) } - let table_bar_base: *mut u8 = - bar_base(pcid_handle, msix_info.table_bar)?.as_ptr(); - let table_base = - unsafe { table_bar_base.offset(msix_info.table_offset as isize) }; + let table_bar_base: *mut u8 = bar_base(pcid_handle, msix_info.table_bar)?.as_ptr(); + let table_base = unsafe { table_bar_base.offset(msix_info.table_offset as isize) }; let vector_count = msix_info.table_size; let table_entries: &'static mut [MsixTableEntry] = unsafe { @@ -107,11 +102,13 @@ fn get_int_method( let (msg_addr_and_data, irq_handle) = irq_helpers::allocate_single_interrupt_vector_for_msi(bsp_cpu_id); - pcid_handle.set_feature_info(SetFeatureInfo::Msi(MsiSetFeatureInfo { - message_address_and_data: Some(msg_addr_and_data), - multi_message_enable: Some(0), // enable 2^0=1 vectors - mask_bits: None, - })).unwrap(); + pcid_handle + .set_feature_info(SetFeatureInfo::Msi(MsiSetFeatureInfo { + message_address_and_data: Some(msg_addr_and_data), + multi_message_enable: Some(0), // enable 2^0=1 vectors + mask_bits: None, + })) + .unwrap(); (0, irq_handle) }; @@ -177,9 +174,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("nvmed: failed to signal readiness"); let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); - let (interrupt_method, interrupt_sources) = - get_int_method(&mut pcid_handle, &pci_config.func) - .expect("nvmed: failed to find a suitable interrupt method"); + let (interrupt_method, interrupt_sources) = get_int_method(&mut pcid_handle, &pci_config.func) + .expect("nvmed: failed to find a suitable interrupt method"); let mut nvme = Nvme::new( address.as_ptr() as usize, interrupt_method, @@ -191,7 +187,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::debug!("Finished base initialization"); let nvme = Arc::new(nvme); #[cfg(feature = "async")] - let reactor_thread = nvme::cq_reactor::start_cq_reactor_thread(Arc::clone(&nvme), interrupt_sources, reactor_receiver); + let reactor_thread = nvme::cq_reactor::start_cq_reactor_thread( + Arc::clone(&nvme), + interrupt_sources, + reactor_receiver, + ); let namespaces = nvme.init_with_queues(); libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); @@ -200,15 +200,20 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut todo = Vec::new(); loop { // TODO: Use a proper event queue once interrupt support is back. - match socket.next_request(SignalBehavior::Restart).expect("nvmed: failed to read disk scheme") { + match socket + .next_request(SignalBehavior::Restart) + .expect("nvmed: failed to read disk scheme") + { None => { break; - }, - Some(req) => if let RequestKind::Call(c) = req.kind() { - todo.push(c); - } else { - // TODO: cancellation - continue; + } + Some(req) => { + if let RequestKind::Call(c) = req.kind() { + todo.push(c); + } else { + // TODO: cancellation + continue; + } } } @@ -216,7 +221,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { while i < todo.len() { if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { let _req = todo.remove(i); - socket.write_response(resp, SignalBehavior::Restart) + socket + .write_response(resp, SignalBehavior::Restart) .expect("nvmed: failed to write disk scheme"); } else { i += 1; @@ -226,7 +232,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { //TODO: destroy NVMe stuff #[cfg(feature = "async")] - reactor_thread.join().expect("nvmed: failed to join reactor thread"); + reactor_thread + .join() + .expect("nvmed: failed to join reactor thread"); std::process::exit(0); } diff --git a/storage/nvmed/src/nvme/cq_reactor.rs b/storage/nvmed/src/nvme/cq_reactor.rs index cf65635de7..3a10c136ef 100644 --- a/storage/nvmed/src/nvme/cq_reactor.rs +++ b/storage/nvmed/src/nvme/cq_reactor.rs @@ -19,7 +19,7 @@ use syscall::Result; use crossbeam_channel::Receiver; -use super::{CmdId, CqId, InterruptSources, Nvme, NvmeComp, NvmeCmd, SqId}; +use super::{CmdId, CqId, InterruptSources, Nvme, NvmeCmd, NvmeComp, SqId}; /// A notification request, sent by the future in order to tell the completion thread that the /// current task wants a notification when a matching completion queue entry has been seen. @@ -39,7 +39,7 @@ pub enum NotifReq { RequestAvailSubmission { sq_id: SqId, waker: task::Waker, - } + }, } enum PendingReq { @@ -97,7 +97,11 @@ impl CqReactor { receiver, }) } - fn handle_notif_reqs_raw(pending_reqs: &mut Vec, receiver: &Receiver, block_until_first: bool) { + fn handle_notif_reqs_raw( + pending_reqs: &mut Vec, + receiver: &Receiver, + block_until_first: bool, + ) { let mut blocking_iter; let mut nonblocking_iter; @@ -125,7 +129,9 @@ impl CqReactor { message, waker, }), - NotifReq::RequestAvailSubmission { sq_id, waker } => pending_reqs.push(PendingReq::PendingAvailSubmission { sq_id, waker, }), + NotifReq::RequestAvailSubmission { sq_id, waker } => { + pending_reqs.push(PendingReq::PendingAvailSubmission { sq_id, waker }) + } } } } @@ -144,14 +150,22 @@ impl CqReactor { while let Some((head, entry)) = completion_queue.complete(None) { unsafe { self.nvme.completion_queue_head(cq_id, head) }; - log::trace!("Got completion queue entry (CQID {}): {:?} at {}", cq_id, entry, head); + log::trace!( + "Got completion queue entry (CQID {}): {:?} at {}", + cq_id, + entry, + head + ); { let submission_queues_read_lock = self.nvme.submission_queues.read().unwrap(); // this lock is actually important, since it will block during submission from other // threads. the lock won't be held for long by the submitters, but it still prevents // the entry being lost before this reactor is actually able to respond: - let &(ref sq_lock, corresponding_cq_id) = submission_queues_read_lock.get(&{entry.sq_id}).expect("nvmed: internal error: queue returned from controller doesn't exist"); + let &(ref sq_lock, corresponding_cq_id) = + submission_queues_read_lock.get(&{ entry.sq_id }).expect( + "nvmed: internal error: queue returned from controller doesn't exist", + ); assert_eq!(cq_id, corresponding_cq_id); let mut sq_guard = sq_lock.lock().unwrap(); sq_guard.head = entry.sq_head; @@ -159,7 +173,6 @@ impl CqReactor { Self::handle_notif_reqs_raw(&mut self.pending_reqs, &self.receiver, false); } - Self::try_notify_futures(&mut self.pending_reqs, cq_id, &entry); entry_count += 1; @@ -169,11 +182,16 @@ impl CqReactor { Some(()) } - fn finish_pending_completion(pending_reqs: &mut Vec, req_cq_id: CqId, cq_id: CqId, sq_id: SqId, cmd_id: CmdId, entry: &NvmeComp, i: usize) -> bool { - if req_cq_id == cq_id - && sq_id == entry.sq_id - && cmd_id == entry.cid - { + fn finish_pending_completion( + pending_reqs: &mut Vec, + req_cq_id: CqId, + cq_id: CqId, + sq_id: SqId, + cmd_id: CmdId, + entry: &NvmeComp, + i: usize, + ) -> bool { + if req_cq_id == cq_id && sq_id == entry.sq_id && cmd_id == entry.cid { let (waker, message) = match pending_reqs.remove(i) { PendingReq::PendingCompletion { waker, message, .. } => (waker, message), _ => unreachable!(), @@ -187,7 +205,12 @@ impl CqReactor { false } } - fn finish_pending_avail_submission(pending_reqs: &mut Vec, sq_id: SqId, entry: &NvmeComp, i: usize) -> bool { + fn finish_pending_avail_submission( + pending_reqs: &mut Vec, + sq_id: SqId, + entry: &NvmeComp, + i: usize, + ) -> bool { if sq_id == entry.sq_id { let waker = match pending_reqs.remove(i) { PendingReq::PendingAvailSubmission { waker, .. } => waker, @@ -200,22 +223,43 @@ impl CqReactor { false } } - fn try_notify_futures(pending_reqs: &mut Vec, cq_id: CqId, entry: &NvmeComp) -> Option<()> { + fn try_notify_futures( + pending_reqs: &mut Vec, + cq_id: CqId, + entry: &NvmeComp, + ) -> Option<()> { let mut i = 0usize; let mut futures_notified = 0; while i < pending_reqs.len() { match &pending_reqs[i] { - &PendingReq::PendingCompletion { cq_id: req_cq_id, sq_id, cmd_id, .. } => if Self::finish_pending_completion(pending_reqs, req_cq_id, cq_id, sq_id, cmd_id, entry, i) { - futures_notified += 1; - } else { - i += 1; + &PendingReq::PendingCompletion { + cq_id: req_cq_id, + sq_id, + cmd_id, + .. + } => { + if Self::finish_pending_completion( + pending_reqs, + req_cq_id, + cq_id, + sq_id, + cmd_id, + entry, + i, + ) { + futures_notified += 1; + } else { + i += 1; + } } - &PendingReq::PendingAvailSubmission { sq_id, .. } => if Self::finish_pending_avail_submission(pending_reqs, sq_id, entry, i) { - futures_notified += 1; - } else { - i += 1; + &PendingReq::PendingAvailSubmission { sq_id, .. } => { + if Self::finish_pending_avail_submission(pending_reqs, sq_id, entry, i) { + futures_notified += 1; + } else { + i += 1; + } } } } @@ -272,7 +316,7 @@ pub fn start_cq_reactor_thread( // multiple vectors to point to different CPUs, so that the load can be balanced across the // logical processors. let reactor = CqReactor::new(nvme, interrupt_sources, receiver) - .expect("nvmed: failed to setup CQ reactor"); + .expect("nvmed: failed to setup CQ reactor"); thread::spawn(move || reactor.run()) } @@ -317,7 +361,11 @@ where let this = &mut self.get_mut().state; match mem::replace(this, CompletionFutureState::Placeholder) { - CompletionFutureState::PendingSubmission { cmd_init, nvme, sq_id } => { + CompletionFutureState::PendingSubmission { + cmd_init, + nvme, + sq_id, + } => { let sqs_read_guard = nvme.submission_queues.read().unwrap(); let &(ref sq_lock, cq_id) = sqs_read_guard .get(&sq_id) @@ -329,20 +377,43 @@ where // when the CQ reactor gets a new completion queue entry, it'll lock the // submisson queue it came from. since we're holding the same lock, this // message will always be sent before the reactor is done with the entry. - nvme.reactor_sender.send(NotifReq::RequestAvailSubmission { sq_id, waker: context.waker().clone() }).unwrap(); - *this = CompletionFutureState::PendingSubmission { cmd_init, nvme, sq_id }; + nvme.reactor_sender + .send(NotifReq::RequestAvailSubmission { + sq_id, + waker: context.waker().clone(), + }) + .unwrap(); + *this = CompletionFutureState::PendingSubmission { + cmd_init, + nvme, + sq_id, + }; return task::Poll::Pending; } - let cmd_id = - u16::try_from(sq.tail).expect("nvmed: internal error: CQ has more than 2^16 entries"); + let cmd_id = u16::try_from(sq.tail) + .expect("nvmed: internal error: CQ has more than 2^16 entries"); let tail = sq.submit_unchecked(cmd_init(cmd_id)); let tail = u16::try_from(tail).unwrap(); // make sure that we register interest before the reactor can get notified let message = Arc::new(Mutex::new(None)); - *this = CompletionFutureState::PendingCompletion { nvme, cq_id, cmd_id, sq_id, message: Arc::clone(&message), }; - nvme.reactor_sender.send(NotifReq::RequestCompletion { cq_id, sq_id, cmd_id, message, waker: context.waker().clone() }).expect("reactor dead"); + *this = CompletionFutureState::PendingCompletion { + nvme, + cq_id, + cmd_id, + sq_id, + message: Arc::clone(&message), + }; + nvme.reactor_sender + .send(NotifReq::RequestCompletion { + cq_id, + sq_id, + cmd_id, + message, + waker: context.waker().clone(), + }) + .expect("reactor dead"); unsafe { nvme.submission_queue_tail(sq_id, tail) }; task::Poll::Pending } @@ -357,14 +428,22 @@ where *this = CompletionFutureState::Finished; return task::Poll::Ready(value.cq_entry); } - nvme.reactor_sender.send(NotifReq::RequestCompletion { + nvme.reactor_sender + .send(NotifReq::RequestCompletion { + cq_id, + sq_id, + cmd_id, + waker: context.waker().clone(), + message: Arc::clone(&message), + }) + .expect("reactor dead"); + *this = CompletionFutureState::PendingCompletion { + message, cq_id, - sq_id, cmd_id, - waker: context.waker().clone(), - message: Arc::clone(&message), - }).expect("reactor dead"); - *this = CompletionFutureState::PendingCompletion { message, cq_id, cmd_id, sq_id, nvme }; + sq_id, + nvme, + }; task::Poll::Pending } CompletionFutureState::Finished => { diff --git a/storage/nvmed/src/nvme/identify.rs b/storage/nvmed/src/nvme/identify.rs index 6f22a1fe40..af82008f17 100644 --- a/storage/nvmed/src/nvme/identify.rs +++ b/storage/nvmed/src/nvme/identify.rs @@ -61,7 +61,6 @@ pub struct IdentifyNamespaceData { pub nows: u16, pub _rsvd1: [u8; 18], // 92 - pub anagrpid: u32, pub _rsvd2: [u8; 3], pub nsattr: u8, @@ -137,8 +136,12 @@ impl LbaFormat { ((self.0 >> 16) & 0xFF) as u8 } pub fn lba_data_size(&self) -> Option { - if self.log_lba_data_size() < 9 { return None } - if self.log_lba_data_size() >= 32 { return None } + if self.log_lba_data_size() < 9 { + return None; + } + if self.log_lba_data_size() >= 32 { + return None; + } Some(1u64 << self.log_lba_data_size()) } pub fn metadata_size(&self) -> u16 { @@ -153,8 +156,9 @@ impl Nvme { let data: Dma = unsafe { Dma::zeroed().unwrap().assume_init() }; // println!(" - Attempting to identify controller"); - let comp = self - .submit_and_complete_admin_command(|cid| NvmeCmd::identify_controller(cid, data.physical())); + let comp = self.submit_and_complete_admin_command(|cid| { + NvmeCmd::identify_controller(cid, data.physical()) + }); log::trace!("Completion: {:?}", comp); // println!(" - Dumping identify controller"); @@ -169,7 +173,9 @@ impl Nvme { log::info!( " - Model: {} Serial: {} Firmware: {}", - model, serial, firmware, + model, + serial, + firmware, ); } pub fn identify_namespace_list(&self, base: u32) -> Vec { @@ -177,10 +183,9 @@ impl Nvme { let data: Dma<[u32; 1024]> = unsafe { Dma::zeroed().unwrap().assume_init() }; // println!(" - Attempting to retrieve namespace ID list"); - let comp = self - .submit_and_complete_admin_command(|cid| { - NvmeCmd::identify_namespace_list(cid, data.physical(), base) - }); + let comp = self.submit_and_complete_admin_command(|cid| { + NvmeCmd::identify_namespace_list(cid, data.physical(), base) + }); log::trace!("Completion2: {:?}", comp); @@ -192,8 +197,9 @@ impl Nvme { let data: Dma = unsafe { Dma::zeroed().unwrap().assume_init() }; // println!(" - Attempting to identify namespace {}", nsid); - let comp = self - .submit_and_complete_admin_command(|cid| NvmeCmd::identify_namespace(cid, data.physical(), nsid)); + let comp = self.submit_and_complete_admin_command(|cid| { + NvmeCmd::identify_namespace(cid, data.physical(), nsid) + }); // println!(" - Dumping identify namespace"); @@ -201,7 +207,10 @@ impl Nvme { let capacity = data.capacity_in_blocks(); log::info!("NSID: {} Size: {} Capacity: {}", nsid, size, capacity); - let block_size = data.formatted_lba_size().lba_data_size().expect("nvmed: error: size outside 512-2^64 range"); + let block_size = data + .formatted_lba_size() + .lba_data_size() + .expect("nvmed: error: size outside 512-2^64 range"); log::debug!("NVME block size: {}", block_size); NvmeNamespace { diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index a4127a3b51..4ef6c13b77 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -9,8 +9,8 @@ use std::thread; use crossbeam_channel::Sender; use smallvec::{smallvec, SmallVec}; -use syscall::error::{Error, Result, EINVAL, EIO}; use common::io::{Io, Mmio}; +use syscall::error::{Error, Result, EINVAL, EIO}; use common::dma::Dma; @@ -27,15 +27,21 @@ use pcid_interface::PciFunctionHandle; #[cfg(target_arch = "aarch64")] #[inline(always)] -pub(crate) unsafe fn pause() { std::arch::aarch64::__yield(); } +pub(crate) unsafe fn pause() { + std::arch::aarch64::__yield(); +} #[cfg(target_arch = "x86")] #[inline(always)] -pub(crate) unsafe fn pause() { std::arch::x86::_mm_pause(); } +pub(crate) unsafe fn pause() { + std::arch::x86::_mm_pause(); +} #[cfg(target_arch = "x86_64")] #[inline(always)] -pub(crate) unsafe fn pause() { std::arch::x86_64::_mm_pause(); } +pub(crate) unsafe fn pause() { + std::arch::x86_64::_mm_pause(); +} /// Used in conjunction with `InterruptMethod`, primarily by the CQ reactor. #[derive(Debug)] @@ -91,7 +97,10 @@ pub enum InterruptMethod { /// Traditional level-triggered, INTx# interrupt pins. Intx, /// Message signaled interrupts - Msi { msi_info: MsiInfo, log2_multiple_message_enabled: u8 }, + Msi { + msi_info: MsiInfo, + log2_multiple_message_enabled: u8, + }, /// Extended message signaled interrupts MsiX(MappedMsixRegs), } @@ -218,7 +227,8 @@ impl Nvme { std::iter::once((0u16, (Mutex::new(NvmeCmdQueue::new()?), 0u16))).collect(), ), completion_queues: RwLock::new( - std::iter::once((0u16, Mutex::new((NvmeCompQueue::new()?, smallvec!(0))))).collect(), + std::iter::once((0u16, Mutex::new((NvmeCompQueue::new()?, smallvec!(0))))) + .collect(), ), // map the zero interrupt vector (which according to the spec shall always point to the // admin completion queue) to CQID 0 (admin completion queue) @@ -301,12 +311,24 @@ impl Nvme { for (qid, queue) in self.completion_queues.get_mut().unwrap().iter_mut() { let &(ref cq, ref sq_ids) = &*queue.get_mut().unwrap(); let data = &cq.data; - log::debug!("completion queue {}: {:X}, {}, (submission queue ids: {:?}", qid, data.physical(), data.len(), sq_ids); + log::debug!( + "completion queue {}: {:X}, {}, (submission queue ids: {:?}", + qid, + data.physical(), + data.len(), + sq_ids + ); } for (qid, (queue, cq_id)) in self.submission_queues.get_mut().unwrap().iter_mut() { let data = &queue.get_mut().unwrap().data; - log::debug!("submission queue {}: {:X}, {}, attached to CQID: {}", qid, data.physical(), data.len(), cq_id); + log::debug!( + "submission queue {}: {:X}, {}, attached to CQID: {}", + qid, + data.physical(), + data.len(), + cq_id + ); } { @@ -319,9 +341,11 @@ impl Nvme { regs.aqa .write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1)); regs.asq_low.write(asq.data.physical() as u32); - regs.asq_high.write((asq.data.physical() as u64 >> 32) as u32); + regs.asq_high + .write((asq.data.physical() as u64 >> 32) as u32); regs.acq_low.write(acq.data.physical() as u32); - regs.acq_high.write((acq.data.physical() as u64 >> 32) as u32); + regs.acq_high + .write((acq.data.physical() as u64 >> 32) as u32); // Set IOCQES, IOSQES, AMS, MPS, and CSS let mut cc = regs.cc.read(); @@ -371,7 +395,10 @@ impl Nvme { self.regs.write().unwrap().intmc.write(0x0000_0001); } } - &mut InterruptMethod::Msi { msi_info: _, log2_multiple_message_enabled: log2_enabled_messages } => { + &mut InterruptMethod::Msi { + msi_info: _, + log2_multiple_message_enabled: log2_enabled_messages, + } => { let mut to_mask = 0x0000_0000; let mut to_clear = 0x0000_0000; @@ -421,7 +448,11 @@ impl Nvme { } #[cfg(not(feature = "async"))] - pub fn submit_and_complete_command NvmeCmd>(&self, sq_id: SqId, cmd_init: F) -> NvmeComp { + pub fn submit_and_complete_command NvmeCmd>( + &self, + sq_id: SqId, + cmd_init: F, + ) -> NvmeComp { // Submit command let cmd = { let sqs_read_guard = self.submission_queues.read().unwrap(); @@ -433,10 +464,15 @@ impl Nvme { assert!(!sq.is_full()); - let cmd_id = - u16::try_from(sq.tail).expect("nvmed: internal error: CQ has more than 2^16 entries"); + let cmd_id = u16::try_from(sq.tail) + .expect("nvmed: internal error: CQ has more than 2^16 entries"); let cmd = cmd_init(cmd_id); - log::trace!("Sent submission queue entry (SQID {}): {:?} at {}", sq_id, cmd, cmd_id); + log::trace!( + "Sent submission queue entry (SQID {}): {:?} at {}", + sq_id, + cmd, + cmd_id + ); let tail = sq.submit_unchecked(cmd); let tail = u16::try_from(tail).unwrap(); @@ -460,7 +496,12 @@ impl Nvme { while let Some((head, entry)) = completion_queue.complete(Some((sq_id, cmd))) { unsafe { self.completion_queue_head(*cq_id, head) }; - log::trace!("Got completion queue entry (CQID {}): {:?} at {}", cq_id, entry, head); + log::trace!( + "Got completion queue entry (CQID {}): {:?} at {}", + cq_id, + entry, + head + ); assert_eq!(sq_id, { entry.sq_id }); assert_eq!({ cmd.cid }, { entry.cid }); @@ -484,16 +525,25 @@ impl Nvme { } #[cfg(feature = "async")] - pub fn submit_and_complete_command NvmeCmd>(&self, sq_id: SqId, cmd_init: F) -> NvmeComp { + pub fn submit_and_complete_command NvmeCmd>( + &self, + sq_id: SqId, + cmd_init: F, + ) -> NvmeComp { use crate::nvme::cq_reactor::{CompletionFuture, CompletionFutureState}; - futures::executor::block_on( - CompletionFuture { - state: CompletionFutureState::PendingSubmission { cmd_init, nvme: &self, sq_id }, - } - ) + futures::executor::block_on(CompletionFuture { + state: CompletionFutureState::PendingSubmission { + cmd_init, + nvme: &self, + sq_id, + }, + }) } - pub fn submit_and_complete_admin_command NvmeCmd>(&self, cmd_init: F) -> NvmeComp { + pub fn submit_and_complete_admin_command NvmeCmd>( + &self, + cmd_init: F, + ) -> NvmeComp { self.submit_and_complete_command(0, cmd_init) } @@ -522,10 +572,9 @@ impl Nvme { .checked_sub(1) .expect("nvmed: internal error: CQID 0 for I/O CQ"); - let comp = self - .submit_and_complete_admin_command(|cid| { - NvmeCmd::create_io_completion_queue(cid, io_cq_id, ptr, raw_len, vector) - }); + let comp = self.submit_and_complete_admin_command(|cid| { + NvmeCmd::create_io_completion_queue(cid, io_cq_id, ptr, raw_len, vector) + }); if let Some(vector) = vector { self.cqs_for_ivs @@ -540,14 +589,15 @@ impl Nvme { let (ptr, len) = { let mut submission_queues_guard = self.submission_queues.write().unwrap(); - let (queue_lock, _) = submission_queues_guard - .entry(io_sq_id) - .or_insert_with(|| { - (Mutex::new( + let (queue_lock, _) = submission_queues_guard.entry(io_sq_id).or_insert_with(|| { + ( + Mutex::new( NvmeCmdQueue::new() .expect("nvmed: failed to allocate I/O completion queue"), - ), io_cq_id) - }); + ), + io_cq_id, + ) + }); let queue = queue_lock.get_mut().unwrap(); (queue.data.physical(), queue.data.len()) @@ -559,10 +609,9 @@ impl Nvme { .checked_sub(1) .expect("nvmed: internal error: SQID 0 for I/O SQ"); - let comp = self - .submit_and_complete_admin_command(|cid| { - NvmeCmd::create_io_submission_queue(cid, io_sq_id, ptr, raw_len, io_cq_id) - }); + let comp = self.submit_and_complete_admin_command(|cid| { + NvmeCmd::create_io_submission_queue(cid, io_sq_id, ptr, raw_len, io_cq_id) + }); } pub fn init_with_queues(&self) -> BTreeMap { @@ -604,7 +653,10 @@ impl Nvme { } else if bytes <= 8192 { (buffer_prp_guard[0], buffer_prp_guard[1]) } else { - (buffer_prp_guard[0], (buffer_prp_guard.physical() + 8) as u64) + ( + buffer_prp_guard[0], + (buffer_prp_guard.physical() + 8) as u64, + ) }; let mut cmd = NvmeCmd::default(); diff --git a/storage/nvmed/src/nvme/queues.rs b/storage/nvmed/src/nvme/queues.rs index 3fd1b23adf..836ec89a6a 100644 --- a/storage/nvmed/src/nvme/queues.rs +++ b/storage/nvmed/src/nvme/queues.rs @@ -69,9 +69,7 @@ impl NvmeCompQueue { //HACK FOR SOMETIMES RETURNING INVALID DATA ON QEMU! if let Some((sq_id, cmd)) = cmd_opt { - if entry.sq_id != sq_id - || entry.cid != cmd.cid - { + if entry.sq_id != sq_id || entry.cid != cmd.cid { return None; } } @@ -94,7 +92,9 @@ impl NvmeCompQueue { if let Some(some) = self.complete(cmd_opt) { return some; } else { - unsafe { super::pause(); } + unsafe { + super::pause(); + } } } } diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index a38fb1cada..4c63169ce0 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -6,12 +6,12 @@ use std::io::prelude::*; use std::sync::Arc; use std::{cmp, str}; +use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; use syscall::schemev2::NewFdFlags; use syscall::{ Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET, }; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; use crate::nvme::{Nvme, NvmeNamespace}; @@ -84,8 +84,10 @@ impl DiskWrapper { return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); } loop { - match nvme.namespace_read(disk, disk.id, block, block_bytes) - .map_err(|err| io::Error::from_raw_os_error(err.errno))? { + match nvme + .namespace_read(disk, disk.id, block, block_bytes) + .map_err(|err| io::Error::from_raw_os_error(err.errno))? + { Some(bytes) => { assert_eq!(bytes, block_bytes.len()); assert_eq!(bytes, blksize as usize); @@ -164,19 +166,25 @@ impl DiskScheme { fn check_locks(&self, disk_i: u32, part_i_opt: Option) -> Result<()> { for (_, handle) in self.handles.iter() { match handle { - Handle::Disk(i) => if disk_i == *i { - return Err(Error::new(ENOLCK)); - }, - Handle::Partition(i, p) => if disk_i == *i { - match part_i_opt { - Some(part_i) => if part_i == *p { - return Err(Error::new(ENOLCK)); - }, - None => { - return Err(Error::new(ENOLCK)); + Handle::Disk(i) => { + if disk_i == *i { + return Err(Error::new(ENOLCK)); + } + } + Handle::Partition(i, p) => { + if disk_i == *i { + match part_i_opt { + Some(part_i) => { + if part_i == *p { + return Err(Error::new(ENOLCK)); + } + } + None => { + return Err(Error::new(ENOLCK)); + } } } - }, + } _ => (), } } @@ -185,12 +193,16 @@ impl DiskScheme { } impl SchemeBlockMut for DiskScheme { - fn xopen(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result> { + fn xopen( + &mut self, + path_str: &str, + flags: usize, + ctx: &CallerCtx, + ) -> Result> { if ctx.uid != 0 { return Err(Error::new(EACCES)); } - let path_str = path_str - .trim_matches('/'); + let path_str = path_str.trim_matches('/'); let handle = if path_str.is_empty() { if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { @@ -253,7 +265,10 @@ impl SchemeBlockMut for DiskScheme { let id = self.next_id; self.next_id += 1; self.handles.insert(id, handle); - Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) } fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { @@ -358,10 +373,19 @@ impl SchemeBlockMut for DiskScheme { Ok(Some(i)) } - fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result> { + fn read( + &mut self, + id: usize, + buf: &mut [u8], + offset: u64, + _fcntl_flags: u32, + ) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(ref handle) => { - let src = usize::try_from(offset).ok().and_then(|o| handle.get(o..)).unwrap_or(&[]); + let src = usize::try_from(offset) + .ok() + .and_then(|o| handle.get(o..)) + .unwrap_or(&[]); let count = core::cmp::min(src.len(), buf.len()); buf[..count].copy_from_slice(&src[..count]); Ok(Some(count)) @@ -369,7 +393,8 @@ impl SchemeBlockMut for DiskScheme { Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; - self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, offset / block_size, buf) + self.nvme + .namespace_read(disk.as_ref(), disk.as_ref().id, offset / block_size, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; @@ -389,18 +414,26 @@ impl SchemeBlockMut for DiskScheme { let abs_block = part.start_lba + rel_block; - self.nvme.namespace_read(disk.as_ref(), disk.as_ref().id, abs_block, buf) + self.nvme + .namespace_read(disk.as_ref(), disk.as_ref().id, abs_block, buf) } } } - fn write(&mut self, id: usize, buf: &[u8], offset: u64, _fcntl_flags: u32) -> Result> { + fn write( + &mut self, + id: usize, + buf: &[u8], + offset: u64, + _fcntl_flags: u32, + ) -> Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; - self.nvme.namespace_write(disk.as_ref(), disk.as_ref().id, offset / block_size, buf) + self.nvme + .namespace_write(disk.as_ref(), disk.as_ref().id, offset / block_size, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; @@ -420,31 +453,34 @@ impl SchemeBlockMut for DiskScheme { let abs_block = part.start_lba + rel_block; - self.nvme.namespace_write(disk.as_ref(), disk.as_ref().id, abs_block, buf) + self.nvme + .namespace_write(disk.as_ref(), disk.as_ref().id, abs_block, buf) } } } fn fsize(&mut self, id: usize) -> Result> { - Ok(Some(match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => handle.len() as u64, - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - disk.as_ref().blocks * disk.as_ref().block_size - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; + Ok(Some( + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref handle) => handle.len() as u64, + Handle::Disk(number) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + disk.as_ref().blocks * disk.as_ref().block_size + } + Handle::Partition(disk_num, part_num) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let part = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; - part.size * disk.as_ref().block_size - } - })) + part.size * disk.as_ref().block_size + } + }, + )) } fn close(&mut self, id: usize) -> Result> { diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index 39cc0e9771..4f15115c55 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -33,7 +33,8 @@ fn main() { scheme, port, protocol ); - redox_daemon::Daemon::new(move |d| daemon(d, scheme, port, protocol)).expect("usbscsid: failed to daemonize"); + redox_daemon::Daemon::new(move |d| daemon(d, scheme, port, protocol)) + .expect("usbscsid: failed to daemonize"); } fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u8) -> ! { let disk_scheme_name = format!(":disk.usb-{scheme}+{port}-scsi"); @@ -81,8 +82,8 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u // TODO: Let all of the USB drivers fork or be managed externally, and xhcid won't have to keep // track of all the drivers. - let socket_fd = Socket::::create(&disk_scheme_name) - .expect("usbscsid: failed to create disk scheme"); + let socket_fd = + Socket::::create(&disk_scheme_name).expect("usbscsid: failed to create disk scheme"); //libredox::call::setrens(0, 0).expect("scsid: failed to enter null namespace"); let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI"); @@ -95,11 +96,16 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u // TODO: Use nonblocking and put all pending calls in a todo VecDeque. Use an eventfd as well. loop { - let req = match socket_fd.next_request(SignalBehavior::Restart).expect("scsid: failed to read disk scheme") { - Some(r) => if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; + let req = match socket_fd + .next_request(SignalBehavior::Restart) + .expect("scsid: failed to read disk scheme") + { + Some(r) => { + if let RequestKind::Call(c) = r.kind() { + c + } else { + continue; + } } None => break, }; diff --git a/storage/usbscsid/src/protocol/bot.rs b/storage/usbscsid/src/protocol/bot.rs index 17e2432b9f..6f1f847db2 100644 --- a/storage/usbscsid/src/protocol/bot.rs +++ b/storage/usbscsid/src/protocol/bot.rs @@ -3,8 +3,8 @@ use std::slice; use xhcid_interface::{ ConfDesc, DeviceReqData, EndpBinaryDirection, EndpDirection, EndpointStatus, IfDesc, Invalid, - PortReqRecipient, PortReqTy, PortTransferStatus, PortTransferStatusKind, XhciClientHandle, XhciClientHandleError, - XhciEndpHandle, + PortReqRecipient, PortReqTy, PortTransferStatus, PortTransferStatusKind, XhciClientHandle, + XhciClientHandleError, XhciEndpHandle, }; use super::{Protocol, ProtocolError, SendCommandStatus, SendCommandStatusKind}; @@ -162,9 +162,16 @@ impl<'a> BulkOnlyTransport<'a> { } Ok(()) } - fn read_csw_raw(&mut self, csw_buffer: &mut [u8; 13], already: bool) -> Result<(), ProtocolError> { + fn read_csw_raw( + &mut self, + csw_buffer: &mut [u8; 13], + already: bool, + ) -> Result<(), ProtocolError> { match self.bulk_in.transfer_read(&mut csw_buffer[..])? { - PortTransferStatus { kind: PortTransferStatusKind::Stalled, .. } => { + PortTransferStatus { + kind: PortTransferStatusKind::Stalled, + .. + } => { if already { self.reset_recovery()?; } @@ -172,8 +179,14 @@ impl<'a> BulkOnlyTransport<'a> { self.clear_stall_in()?; self.read_csw_raw(csw_buffer, true)?; } - PortTransferStatus { kind: PortTransferStatusKind::ShortPacket, bytes_transferred } if bytes_transferred != 13 => { - panic!("received a short packet when reading CSW ({} != 13)", bytes_transferred) + PortTransferStatus { + kind: PortTransferStatusKind::ShortPacket, + bytes_transferred, + } if bytes_transferred != 13 => { + panic!( + "received a short packet when reading CSW ({} != 13)", + bytes_transferred + ) } _ => (), } @@ -199,24 +212,38 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { let cbw = *cbw; match self.bulk_out.transfer_write(&cbw_bytes)? { - PortTransferStatus { kind: PortTransferStatusKind::Stalled, .. } => { + PortTransferStatus { + kind: PortTransferStatusKind::Stalled, + .. + } => { // TODO: Error handling panic!("bulk out endpoint stalled when sending CBW {:?}", cbw); //self.clear_stall_out()?; //dbg!(self.bulk_in.status()?, self.bulk_out.status()?); } - PortTransferStatus { bytes_transferred, .. } if bytes_transferred != 31 => { - panic!("received short packet when sending CBW ({} != 31)", bytes_transferred); + PortTransferStatus { + bytes_transferred, .. + } if bytes_transferred != 31 => { + panic!( + "received short packet when sending CBW ({} != 31)", + bytes_transferred + ); } _ => (), } let early_residue: Option = match data { DeviceReqData::In(buffer) => match self.bulk_in.transfer_read(buffer)? { - PortTransferStatus { kind, bytes_transferred } => match kind { + PortTransferStatus { + kind, + bytes_transferred, + } => match kind { PortTransferStatusKind::Success => None, PortTransferStatusKind::ShortPacket => { - println!("received short packet (len {}) when transferring data", bytes_transferred); + println!( + "received short packet (len {}) when transferring data", + bytes_transferred + ); NonZeroU32::new(bytes_transferred) } PortTransferStatusKind::Stalled => { @@ -230,13 +257,19 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { )), )); } - } - } + }, + }, DeviceReqData::Out(buffer) => match self.bulk_out.transfer_write(buffer)? { - PortTransferStatus { kind, bytes_transferred } => match kind { + PortTransferStatus { + kind, + bytes_transferred, + } => match kind { PortTransferStatusKind::Success => None, PortTransferStatusKind::ShortPacket => { - println!("received short packet (len {}) when transferring data", bytes_transferred); + println!( + "received short packet (len {}) when transferring data", + bytes_transferred + ); NonZeroU32::new(bytes_transferred) } PortTransferStatusKind::Stalled => { @@ -245,10 +278,12 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { } PortTransferStatusKind::Unknown => { return Err(ProtocolError::XhciError( - XhciClientHandleError::InvalidResponse(Invalid("unknown transfer status")), + XhciClientHandleError::InvalidResponse(Invalid( + "unknown transfer status", + )), )); } - } + }, }, DeviceReqData::NoData => None, }; @@ -266,10 +301,16 @@ impl<'a> Protocol for BulkOnlyTransport<'a> { if !csw.is_valid() || csw.tag != cbw.tag { println!("Invald CSW {:?} (for CBW {:?})", csw, cbw); self.reset_recovery()?; - if self.bulk_in.status()? == EndpointStatus::Halted || self.bulk_out.status()? == EndpointStatus::Halted { - return Err(ProtocolError::ProtocolError("Reset Recovery didn't reset endpoints")); + if self.bulk_in.status()? == EndpointStatus::Halted + || self.bulk_out.status()? == EndpointStatus::Halted + { + return Err(ProtocolError::ProtocolError( + "Reset Recovery didn't reset endpoints", + )); } - return Err(ProtocolError::ProtocolError("CSW invalid, but a recover was successful")); + return Err(ProtocolError::ProtocolError( + "CSW invalid, but a recover was successful", + )); } /*if self.bulk_in.status()? == EndpointStatus::Halted diff --git a/storage/usbscsid/src/scheme.rs b/storage/usbscsid/src/scheme.rs index a175780958..ed89dd2254 100644 --- a/storage/usbscsid/src/scheme.rs +++ b/storage/usbscsid/src/scheme.rs @@ -47,8 +47,7 @@ impl SchemeMut for ScsiScheme<'_> { if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { return Err(Error::new(EACCES)); } - let path_str = path_str - .trim_start_matches('/'); + let path_str = path_str.trim_start_matches('/'); let handle = if path_str.is_empty() { // List Handle::List @@ -60,7 +59,10 @@ impl SchemeMut for ScsiScheme<'_> { }; self.next_fd += 1; self.handles.insert(self.next_fd, handle); - Ok(OpenResult::ThisScheme { number: self.next_fd, flags: NewFdFlags::POSITIONED }) + Ok(OpenResult::ThisScheme { + number: self.next_fd, + flags: NewFdFlags::POSITIONED, + }) } fn fstat(&mut self, fd: usize, stat: &mut syscall::Stat) -> Result { match self.handles.get(&fd).ok_or(Error::new(EBADF))? { @@ -111,7 +113,10 @@ impl SchemeMut for ScsiScheme<'_> { } } Handle::List => { - let src = usize::try_from(offset).ok().and_then(|o| LIST_CONTENTS.get(o..)).unwrap_or(&[]); + let src = usize::try_from(offset) + .ok() + .and_then(|o| LIST_CONTENTS.get(o..)) + .unwrap_or(&[]); let min = core::cmp::min(src.len(), buf.len()); buf[..min].copy_from_slice(&src[..min]); diff --git a/storage/usbscsid/src/scsi/cmds.rs b/storage/usbscsid/src/scsi/cmds.rs index 8eb58a0cb6..3868f57eae 100644 --- a/storage/usbscsid/src/scsi/cmds.rs +++ b/storage/usbscsid/src/scsi/cmds.rs @@ -1,6 +1,6 @@ use super::opcodes::Opcode; -use std::{fmt, mem, slice}; use std::convert::TryInto; +use std::{fmt, mem, slice}; #[repr(packed)] pub struct Inquiry { @@ -517,7 +517,7 @@ impl<'a> Iterator for ModePageIterRaw<'a> { #[derive(Clone, Copy, Debug)] pub enum AnyModePage<'a> { RwErrorRecovery(&'a RwErrorRecoveryPage), - Caching(&'a CachingModePage) + Caching(&'a CachingModePage), } struct ModePageIter<'a> { @@ -540,9 +540,7 @@ impl<'a> Iterator for ModePageIter<'a> { plain::from_bytes(next_buf).ok()?, )) } else if page_code == 0x08 { - Some(AnyModePage::Caching( - plain::from_bytes(next_buf).ok()?, - )) + Some(AnyModePage::Caching(plain::from_bytes(next_buf).ok()?)) } else { println!("Unimplemented sub_page {}", base64::encode(next_buf)); None diff --git a/storage/usbscsid/src/scsi/mod.rs b/storage/usbscsid/src/scsi/mod.rs index ad818421a9..b5741fbd81 100644 --- a/storage/usbscsid/src/scsi/mod.rs +++ b/storage/usbscsid/src/scsi/mod.rs @@ -56,7 +56,7 @@ impl Scsi { let max_inquiry_len = this.get_inquiry_alloc_len(protocol)?; // Get the Standard Inquiry Data. this.get_standard_inquiry_data(protocol, max_inquiry_len)?; - + let version = this.res_standard_inquiry_data().version(); println!("Inquiry version: {}", version); @@ -89,50 +89,52 @@ impl Scsi { let standard_inquiry_data = self.res_standard_inquiry_data(); Ok(4 + u16::from(standard_inquiry_data.additional_len)) } - pub fn get_standard_inquiry_data(&mut self, protocol: &mut dyn Protocol, max_inquiry_len: u16) -> Result<()> { + pub fn get_standard_inquiry_data( + &mut self, + protocol: &mut dyn Protocol, + max_inquiry_len: u16, + ) -> Result<()> { let inquiry = self.cmd_inquiry(); *inquiry = cmds::Inquiry::new(false, 0, max_inquiry_len, 0); - protocol - .send_command( - &self.command_buffer[..INQUIRY_CMD_LEN as usize], - DeviceReqData::In(&mut self.inquiry_buffer[..max_inquiry_len as usize]), - )?; + protocol.send_command( + &self.command_buffer[..INQUIRY_CMD_LEN as usize], + DeviceReqData::In(&mut self.inquiry_buffer[..max_inquiry_len as usize]), + )?; Ok(()) } pub fn get_ff_sense(&mut self, protocol: &mut dyn Protocol, alloc_len: u8) -> Result<()> { let request_sense = self.cmd_request_sense(); *request_sense = cmds::RequestSense::new(false, alloc_len, 0); self.data_buffer.resize(alloc_len.into(), 0); - protocol - .send_command( - &self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize], - DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize]), - )?; + protocol.send_command( + &self.command_buffer[..REQUEST_SENSE_CMD_LEN as usize], + DeviceReqData::In(&mut self.data_buffer[..alloc_len as usize]), + )?; Ok(()) } - pub fn read_capacity(&mut self, protocol: &mut dyn Protocol) -> Result<&cmds::ReadCapacity10ParamData> { + pub fn read_capacity( + &mut self, + protocol: &mut dyn Protocol, + ) -> Result<&cmds::ReadCapacity10ParamData> { // The spec explicitly states that the allocation length is 8 bytes. let read_capacity10 = self.cmd_read_capacity10(); *read_capacity10 = cmds::ReadCapacity10::new(0); self.data_buffer.resize(10usize, 0u8); - protocol - .send_command( - &self.command_buffer[..10], - DeviceReqData::In(&mut self.data_buffer[..8]), - )?; + protocol.send_command( + &self.command_buffer[..10], + DeviceReqData::In(&mut self.data_buffer[..8]), + )?; Ok(self.res_read_capacity10()) } pub fn get_mode_sense10( &mut self, protocol: &mut dyn Protocol, - ) -> Result< - ( - &cmds::ModeParamHeader10, - BlkDescSlice, - impl Iterator, - ) - > { + ) -> Result<( + &cmds::ModeParamHeader10, + BlkDescSlice, + impl Iterator, + )> { let initial_alloc_len = mem::size_of::() as u16; // covers both mode_data_len and blk_desc_len. let mode_sense10 = self.cmd_mode_sense10(); *mode_sense10 = cmds::ModeSense10::get_block_desc(initial_alloc_len, 0); @@ -149,9 +151,7 @@ impl Scsi { panic!("{:?}", self.res_ff_sense_data()); } - let optimal_alloc_len = - self.res_mode_param_header10().mode_data_len() - + 2; // the length of the mode data field itself + let optimal_alloc_len = self.res_mode_param_header10().mode_data_len() + 2; // the length of the mode data field itself let mode_sense10 = self.cmd_mode_sense10(); *mode_sense10 = cmds::ModeSense10::get_block_desc(optimal_alloc_len, 0); @@ -278,12 +278,7 @@ impl Scsi { buffer[..bytes_to_read].copy_from_slice(&self.data_buffer[..bytes_to_read]); Ok(status.bytes_transferred(bytes_to_read as u32)) } - pub fn write( - &mut self, - protocol: &mut dyn Protocol, - lba: u64, - buffer: &[u8], - ) -> Result { + pub fn write(&mut self, protocol: &mut dyn Protocol, lba: u64, buffer: &[u8]) -> Result { let blocks_to_write = buffer.len() as u64 / u64::from(self.block_size); let bytes_to_write = blocks_to_write as usize * self.block_size as usize; let transfer_len = u32::try_from(blocks_to_write).or(Err(ScsiError::Overflow( diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 7fa906f017..df5cda91a5 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -154,12 +154,22 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { deamon.ready().expect("virtio-blkd: failed to deamonize"); loop { - let req = match socket_fd.next_request(SignalBehavior::Restart) - .expect("virtio-blkd: failed to read disk scheme") { - Some(r) => if let RequestKind::Call(c) = r.kind() { c } else { continue }, - None => break, + let req = match socket_fd + .next_request(SignalBehavior::Restart) + .expect("virtio-blkd: failed to read disk scheme") + { + Some(r) => { + if let RequestKind::Call(c) = r.kind() { + c + } else { + continue; + } + } + None => break, }; - let resp = req.handle_scheme_block_mut(&mut scheme).expect("TODO: block?"); + let resp = req + .handle_scheme_block_mut(&mut scheme) + .expect("TODO: block?"); socket_fd .write_response(resp, SignalBehavior::Restart) .expect("virtio-blkd: failed to write to disk scheme"); diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index fe24c5b813..79d116db03 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -14,8 +14,8 @@ use partitionlib::PartitionTable; use redox_scheme::CallerCtx; use redox_scheme::OpenResult; use redox_scheme::SchemeBlockMut; -use syscall::flag::*; use syscall::error::*; +use syscall::flag::*; use syscall::schemev2::NewFdFlags; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::Queue; @@ -40,7 +40,11 @@ impl BlkExtension for Queue<'_> { }) .unwrap(); - let result = unsafe { Dma::<[u8]>::zeroed_slice(target.len()).unwrap().assume_init() }; + let result = unsafe { + Dma::<[u8]>::zeroed_slice(target.len()) + .unwrap() + .assume_init() + }; let status = Dma::new(u8::MAX).unwrap(); let chain = ChainBuilder::new() @@ -65,7 +69,11 @@ impl BlkExtension for Queue<'_> { }) .unwrap(); - let mut result = unsafe { Dma::<[u8]>::zeroed_slice(target.len()).unwrap().assume_init() }; + let mut result = unsafe { + Dma::<[u8]>::zeroed_slice(target.len()) + .unwrap() + .assume_init() + }; result.copy_from_slice(target.as_ref()); let status = Dma::new(u8::MAX).unwrap(); @@ -122,30 +130,31 @@ impl<'a> DiskScheme<'a> { impl<'a, 'b> Read for VirtioShim<'a, 'b> { fn read(&mut self, buf: &mut [u8]) -> IoResult { - let read_block = |block: u64, block_bytes: &mut [u8]| -> Result<(), std::io::Error> { - let req = Dma::new(BlockVirtRequest { - ty: BlockRequestTy::In, - reserved: 0, - sector: block, - }) - .unwrap(); + let read_block = + |block: u64, block_bytes: &mut [u8]| -> Result<(), std::io::Error> { + let req = Dma::new(BlockVirtRequest { + ty: BlockRequestTy::In, + reserved: 0, + sector: block, + }) + .unwrap(); - let result = Dma::new([0u8; 512]).unwrap(); - let status = Dma::new(u8::MAX).unwrap(); + let result = Dma::new([0u8; 512]).unwrap(); + let status = Dma::new(u8::MAX).unwrap(); - let chain = ChainBuilder::new() - .chain(Buffer::new(&req)) - .chain(Buffer::new(&result).flags(DescriptorFlags::WRITE_ONLY)) - .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) - .build(); + let chain = ChainBuilder::new() + .chain(Buffer::new(&req)) + .chain(Buffer::new(&result).flags(DescriptorFlags::WRITE_ONLY)) + .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) + .build(); - futures::executor::block_on(self.scheme.queue.send(chain)); - assert_eq!(*status, 0); + futures::executor::block_on(self.scheme.queue.send(chain)); + assert_eq!(*status, 0); - let size = core::cmp::min(block_bytes.len(), result.len()); - block_bytes[..size].copy_from_slice(&result.as_slice()[..size]); - Ok(()) - }; + let size = core::cmp::min(block_bytes.len(), result.len()); + block_bytes[..size].copy_from_slice(&result.as_slice()[..size]); + Ok(()) + }; let bytes_read = driver_block::block_read(self.offset, 512, buf, self.block_bytes, read_block) @@ -224,7 +233,10 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { }, ); - Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) } else { return Err(syscall::Error::new(EISDIR)); } @@ -242,14 +254,13 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { let id = self.next_id; self.next_id += 1; - self.handles.insert( - id, - Handle::Partition { - number: part_num, - }, - ); + self.handles + .insert(id, Handle::Partition { number: part_num }); - Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) } else { let nsid = path_str.parse::().unwrap(); assert_eq!(nsid, 0); @@ -257,94 +268,110 @@ impl<'a> SchemeBlockMut for DiskScheme<'a> { let id = self.next_id; self.next_id += 1; self.handles.insert(id, Handle::Disk); - Ok(Some(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED })) + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) } } - fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> syscall::Result> { - Ok(Some(match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List { - ref mut entries, - } => { - let src = usize::try_from(offset).ok().and_then(|o| entries.get(o..)).unwrap_or(&[]); - let count = core::cmp::min(src.len(), buf.len()); - buf[..count].copy_from_slice(&src[..count]); - count - } + fn read( + &mut self, + id: usize, + buf: &mut [u8], + offset: u64, + _fcntl_flags: u32, + ) -> syscall::Result> { + Ok(Some( + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List { ref mut entries } => { + let src = usize::try_from(offset) + .ok() + .and_then(|o| entries.get(o..)) + .unwrap_or(&[]); + let count = core::cmp::min(src.len(), buf.len()); + buf[..count].copy_from_slice(&src[..count]); + count + } - Handle::Partition { - number, - } => { - let part_table = self.part_table.as_ref().unwrap(); - let part = part_table - .partitions - .get(number as usize) - .ok_or(Error::new(EBADF))?; + Handle::Partition { number } => { + let part_table = self.part_table.as_ref().unwrap(); + let part = part_table + .partitions + .get(number as usize) + .ok_or(Error::new(EBADF))?; - // Get the offset in sectors. - let rel_block = offset / BLK_SIZE; - // if rel_block >= part.size { - // return Err(Error::new(EOVERFLOW)); - // } + // Get the offset in sectors. + let rel_block = offset / BLK_SIZE; + // if rel_block >= part.size { + // return Err(Error::new(EOVERFLOW)); + // } - let abs_block = part.start_lba + rel_block; + let abs_block = part.start_lba + rel_block; - futures::executor::block_on(self.queue.read(abs_block, buf)) - } + futures::executor::block_on(self.queue.read(abs_block, buf)) + } - Handle::Disk => { - let block_size = self.cfg.block_size(); + Handle::Disk => { + let block_size = self.cfg.block_size(); - futures::executor::block_on( - self.queue.read(offset / u64::from(block_size), buf), - ) - } - })) + futures::executor::block_on( + self.queue.read(offset / u64::from(block_size), buf), + ) + } + }, + )) } - fn write(&mut self, id: usize, buf: &[u8], offset: u64, _fcntl_flags: u32) -> syscall::Result> { - Ok(Some(match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::Disk => { - let block_size = self.cfg.block_size(); - futures::executor::block_on( - self.queue.write(offset / u64::from(block_size), buf), - ) - } + fn write( + &mut self, + id: usize, + buf: &[u8], + offset: u64, + _fcntl_flags: u32, + ) -> syscall::Result> { + Ok(Some( + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::Disk => { + let block_size = self.cfg.block_size(); + futures::executor::block_on( + self.queue.write(offset / u64::from(block_size), buf), + ) + } - _ => todo!(), - })) + _ => todo!(), + }, + )) } fn fsize(&mut self, id: usize) -> syscall::Result> { - Ok(Some(match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List { - ref entries, - } => { - let len = entries.len() as u64; - log::debug!("list: part_len={len:?}"); + Ok(Some( + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List { ref entries } => { + let len = entries.len() as u64; + log::debug!("list: part_len={len:?}"); - len - } + len + } - Handle::Partition { - number, - } => { - let part_table = self.part_table.as_ref().unwrap(); - let part = part_table - .partitions - .get(number as usize) - .ok_or(Error::new(EBADF))?; + Handle::Partition { number } => { + let part_table = self.part_table.as_ref().unwrap(); + let part = part_table + .partitions + .get(number as usize) + .ok_or(Error::new(EBADF))?; - // Partition size in bytes. - let len = part.size * BLK_SIZE; + // Partition size in bytes. + let len = part.size * BLK_SIZE; - log::debug!("part: part_len={len:?}"); + log::debug!("part: part_len={len:?}"); - len - } + len + } - Handle::Disk => self.cfg.capacity() * u64::from(self.cfg.block_size()), - })) + Handle::Disk => self.cfg.capacity() * u64::from(self.cfg.block_size()), + }, + )) } fn fpath(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result> { diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index d63840715f..f34b0f692d 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -9,7 +9,9 @@ use rehid::{ report_handler::ReportHandler, usage_tables::{GenericDesktopUsage, UsagePage}, }; -use xhcid_interface::{ConfigureEndpointsReq, DevDesc, EndpDirection, EndpointTy, PortReqRecipient, XhciClientHandle}; +use xhcid_interface::{ + ConfigureEndpointsReq, DevDesc, EndpDirection, EndpointTy, PortReqRecipient, XhciClientHandle, +}; mod keymap; mod reqs; @@ -203,36 +205,36 @@ fn main() { .expect("Failed to get standard descriptors"); log::info!("{:X?}", desc); - let (conf_desc, conf_num, (if_desc, endpoint_num_opt, hid_desc)) = desc - .config_descs - .iter() - .enumerate() - .find_map(|(conf_num, conf_desc)| { - let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { - if if_desc.number == interface_num { - let endpoint_num_opt = if_desc.endpoints.iter().enumerate().find_map(|(endpoint_i, endpoint)| { - if endpoint.ty() == EndpointTy::Interrupt && endpoint.direction() == EndpDirection::In { - Some(endpoint_i + 1) - } else { - None - } - }); - let hid_desc = if_desc.hid_descs.iter().find_map(|hid_desc| { - //TODO: should we do any filtering? - Some(hid_desc) - })?; - Some((if_desc.clone(), endpoint_num_opt, hid_desc)) - } else { - None - } - })?; - Some(( - conf_desc.clone(), - conf_num, - if_desc, - )) - }) - .expect("Failed to find suitable configuration"); + let (conf_desc, conf_num, (if_desc, endpoint_num_opt, hid_desc)) = + desc.config_descs + .iter() + .enumerate() + .find_map(|(conf_num, conf_desc)| { + let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { + if if_desc.number == interface_num { + let endpoint_num_opt = if_desc.endpoints.iter().enumerate().find_map( + |(endpoint_i, endpoint)| { + if endpoint.ty() == EndpointTy::Interrupt + && endpoint.direction() == EndpDirection::In + { + Some(endpoint_i + 1) + } else { + None + } + }, + ); + let hid_desc = if_desc.hid_descs.iter().find_map(|hid_desc| { + //TODO: should we do any filtering? + Some(hid_desc) + })?; + Some((if_desc.clone(), endpoint_num_opt, hid_desc)) + } else { + None + } + })?; + Some((conf_desc.clone(), conf_num, if_desc)) + }) + .expect("Failed to find suitable configuration"); handle .configure_endpoints(&ConfigureEndpointsReq { @@ -292,7 +294,9 @@ fn main() { if let Some(endpoint) = &mut endpoint_opt { // interrupt transfer - endpoint.transfer_read(&mut report_buffer).expect("failed to get report"); + endpoint + .transfer_read(&mut report_buffer) + .expect("failed to get report"); } else { // control transfer reqs::get_report( @@ -419,10 +423,7 @@ fn main() { } if scroll_y != 0 { - let scroll_event = orbclient::event::ScrollEvent { - x: 0, - y: scroll_y, - }; + let scroll_event = orbclient::event::ScrollEvent { x: 0, y: scroll_y }; match display.write(&scroll_event.to_event()) { Ok(_) => (), diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index a3f5521310..2f32ba8c70 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -3,7 +3,10 @@ use std::env; use std::fs::File; use std::io::{Read, Write}; -use xhcid_interface::{plain, usb, ConfigureEndpointsReq, DevDesc, DeviceReqData, EndpDirection, EndpointTy, PortReqRecipient, PortReqTy, XhciClientHandle}; +use xhcid_interface::{ + plain, usb, ConfigureEndpointsReq, DevDesc, DeviceReqData, EndpDirection, EndpointTy, + PortReqRecipient, PortReqTy, XhciClientHandle, +}; fn main() { common::setup_logging( @@ -55,11 +58,7 @@ fn main() { None } })?; - Some(( - conf_desc.clone(), - conf_num, - if_desc, - )) + Some((conf_desc.clone(), conf_num, if_desc)) }) .expect("Failed to find suitable configuration"); diff --git a/vboxd/src/bga.rs b/vboxd/src/bga.rs index d9fe280100..264c9c568c 100644 --- a/vboxd/src/bga.rs +++ b/vboxd/src/bga.rs @@ -43,4 +43,4 @@ impl Bga { self.write(BGA_INDEX_BPP, 32); self.write(BGA_INDEX_ENABLE, 0x41); } -} \ No newline at end of file +} diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 8a50ccce82..4c29c5260a 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -1,14 +1,14 @@ //#![deny(warnings)] use event::{user_data, EventQueue}; -use std::{iter, mem}; -use std::os::unix::io::AsRawFd; use std::fs::File; -use std::io::{Result, Read, Write}; +use std::io::{Read, Result, Write}; +use std::os::unix::io::AsRawFd; +use std::{iter, mem}; +use common::io::{Io, Mmio, Pio}; use pcid_interface::{PciBar, PciFunctionHandle}; use syscall::flag::EventFlags; -use common::io::{Io, Mmio, Pio}; use common::dma::Dma; @@ -56,7 +56,9 @@ struct VboxGetMouse { } impl VboxGetMouse { - fn request() -> u32 { 1 } + fn request() -> u32 { + 1 + } fn new() -> syscall::Result> { let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; @@ -79,7 +81,9 @@ struct VboxSetMouse { } impl VboxSetMouse { - fn request() -> u32 { 2 } + fn request() -> u32 { + 2 + } fn new() -> syscall::Result> { let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; @@ -100,7 +104,9 @@ struct VboxAckEvents { } impl VboxAckEvents { - fn request() -> u32 { 41 } + fn request() -> u32 { + 41 + } fn new() -> syscall::Result> { let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; @@ -121,7 +127,9 @@ struct VboxGuestCaps { } impl VboxGuestCaps { - fn request() -> u32 { 55 } + fn request() -> u32 { + 55 + } fn new() -> syscall::Result> { let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; @@ -144,7 +152,9 @@ struct VboxDisplayChange { } impl VboxDisplayChange { - fn request() -> u32 { 51 } + fn request() -> u32 { + 51 + } fn new() -> syscall::Result> { let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; @@ -166,7 +176,9 @@ struct VboxGuestInfo { } impl VboxGuestInfo { - fn request() -> u32 { 50 } + fn request() -> u32 { + 50 + } fn new() -> syscall::Result> { let mut packet = unsafe { Dma::::zeroed()?.assume_init() }; @@ -189,7 +201,10 @@ fn main() { let bar0 = pci_config.func.bars[0].expect_port(); - let irq = pci_config.func.legacy_interrupt_line.expect("vboxd: no legacy interrupts supported"); + let irq = pci_config + .func + .legacy_interrupt_line + .expect("vboxd: no legacy interrupts supported"); println!(" + VirtualBox {}", pci_config.func.display()); @@ -205,15 +220,28 @@ fn main() { if let Ok(count) = libredox::call::fpath(display.as_raw_fd() as usize, &mut buf) { let path = unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }; let res = path.split(":").nth(1).unwrap_or(""); - width = res.split("/").nth(1).unwrap_or("").parse::().unwrap_or(0); - height = res.split("/").nth(2).unwrap_or("").parse::().unwrap_or(0); + width = res + .split("/") + .nth(1) + .unwrap_or("") + .parse::() + .unwrap_or(0); + height = res + .split("/") + .nth(2) + .unwrap_or("") + .parse::() + .unwrap_or(0); } } let mut irq_file = irq.irq_handle("vboxd"); let mut port = Pio::::new(bar0 as u16); - let address = unsafe { pcid_handle.map_bar(1) }.expect("vboxd").ptr.as_ptr(); + let address = unsafe { pcid_handle.map_bar(1) } + .expect("vboxd") + .ptr + .as_ptr(); { let vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; @@ -230,7 +258,9 @@ fn main() { set_mouse.features.write(1 << 4 | 1); port.write(set_mouse.physical() as u32); - vmmdev.guest_events.write(VBOX_EVENT_DISPLAY | VBOX_EVENT_MOUSE); + vmmdev + .guest_events + .write(VBOX_EVENT_DISPLAY | VBOX_EVENT_MOUSE); user_data! { enum Source { @@ -238,8 +268,15 @@ fn main() { } } - let event_queue = EventQueue::::new().expect("vboxd: Could not create event queue."); - event_queue.subscribe(irq_file.as_raw_fd() as usize, Source::Irq, event::EventFlags::READ).unwrap(); + let event_queue = + EventQueue::::new().expect("vboxd: Could not create event queue."); + event_queue + .subscribe( + irq_file.as_raw_fd() as usize, + Source::Irq, + event::EventFlags::READ, + ) + .unwrap(); daemon.ready().expect("failed to signal readiness"); @@ -247,10 +284,13 @@ fn main() { let mut bga = Bga::new(); let get_mouse = VboxGetMouse::new().expect("vboxd: failed to map GetMouse"); - let display_change = VboxDisplayChange::new().expect("vboxd: failed to map DisplayChange"); + let display_change = + VboxDisplayChange::new().expect("vboxd: failed to map DisplayChange"); let ack_events = VboxAckEvents::new().expect("vboxd: failed to map AckEvents"); - for Source::Irq in iter::once(Source::Irq).chain(event_queue.map(|e| e.expect("vboxd: failed to get next event").user_data)) { + for Source::Irq in iter::once(Source::Irq) + .chain(event_queue.map(|e| e.expect("vboxd: failed to get next event").user_data)) + { let mut irq = [0; 8]; if irq_file.read(&mut irq).unwrap() >= irq.len() { let host_events = vmmdev.host_events.read(); @@ -268,10 +308,9 @@ fn main() { height = new_height; println!("Display {}, {}", width, height); bga.set_size(width as u16, height as u16); - let _ = display.write(&orbclient::ResizeEvent { - width, - height, - }.to_event()); + let _ = display.write( + &orbclient::ResizeEvent { width, height }.to_event(), + ); } } } @@ -281,10 +320,13 @@ fn main() { if let Some(ref mut display) = display_opt { let x = get_mouse.x.read() * width / 0x10000; let y = get_mouse.y.read() * height / 0x10000; - let _ = display.write(&orbclient::MouseEvent { - x: x as i32, - y: y as i32, - }.to_event()); + let _ = display.write( + &orbclient::MouseEvent { + x: x as i32, + y: y as i32, + } + .to_event(), + ); } } } @@ -293,5 +335,6 @@ fn main() { } std::process::exit(0); - }).expect("vboxd: failed to daemonize"); + }) + .expect("vboxd: failed to daemonize"); } diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index e117f2a867..dc280e6636 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -45,11 +45,11 @@ use pcid_interface::{ MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, }; +use common::io::Io; use event::{Event, RawEventQueue}; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::EventFlags; -use common::io::Io; use syscall::scheme::Scheme; use crate::xhci::{InterruptMethod, Xhci}; diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 932fe6f202..a866886800 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -1,8 +1,8 @@ use std::collections::BTreeMap; +use common::io::{Io, Mmio}; use log::debug; use syscall::error::Result; -use common::io::{Io, Mmio}; use syscall::PAGE_SIZE; use common::dma::Dma; diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index f2da331a95..13bdeff7d1 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -1,5 +1,5 @@ -use syscall::error::Result; use common::io::{Io, Mmio}; +use syscall::error::Result; use common::dma::Dma; diff --git a/xhcid/src/xhci/extended.rs b/xhcid/src/xhci/extended.rs index 1f8115b7e5..2ef900cf41 100644 --- a/xhcid/src/xhci/extended.rs +++ b/xhcid/src/xhci/extended.rs @@ -1,7 +1,7 @@ +use common::io::{Io, Mmio}; use std::ops::Range; use std::ptr::NonNull; use std::{fmt, mem, ptr, slice}; -use common::io::{Io, Mmio}; pub struct ExtendedCapabilitiesIter { base: *const u8, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index a0a72f296a..5a2d17f2be 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -20,8 +20,8 @@ use std::sync::{Arc, Mutex, MutexGuard, Weak}; use std::{mem, process, slice, sync::atomic, task, thread}; -use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT}; use common::io::Io; +use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT}; use syscall::PAGE_SIZE; use chashmap::CHashMap; diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index 42918c922c..cfe1dc5878 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -1,6 +1,6 @@ +use common::io::{Io, Mmio}; use std::num::NonZeroU8; use std::slice; -use common::io::{Io, Mmio}; use super::CapabilityRegs; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 47914b8769..dd011c9736 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -67,8 +67,9 @@ lazy_static! { .expect("Failed to create the regex for the port/request scheme"); static ref REGEX_PORT_ENDPOINTS: Regex = Regex::new(r"^port(\d{1,3})/endpoints$") .expect("Failed to create the regex for the port/endpoints scheme"); - static ref REGEX_PORT_SPECIFIC_ENDPOINT: Regex = Regex::new(r"^port(\d{1,3})/endpoints/(\d{1,3})$") - .expect("Failed to create the regex for the port/endpoints/ scheme"); + static ref REGEX_PORT_SPECIFIC_ENDPOINT: Regex = + Regex::new(r"^port(\d{1,3})/endpoints/(\d{1,3})$") + .expect("Failed to create the regex for the port/endpoints/ scheme"); static ref REGEX_PORT_SUB_ENDPOINT: Regex = Regex::new( r"port(\d{1,3})/endpoints/(\d{1,3})/(ctl|data)$" ) @@ -352,33 +353,27 @@ impl SchemeParameters { Ok(Self::ConfigureEndpoints(port_num)) } else if REGEX_PORT_DESCRIPTORS.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_DESCRIPTORS, scheme, 0)?; Ok(Self::PortDesc(port_num)) } else if REGEX_PORT_STATE.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_STATE, scheme, 0)?; Ok(Self::PortState(port_num)) } else if REGEX_PORT_REQUEST.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_REQUEST, scheme, 0)?; Ok(Self::PortReq(port_num)) } else if REGEX_PORT_ENDPOINTS.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_ENDPOINTS, scheme, 0)?; Ok(Self::Endpoints(port_num)) } else if REGEX_PORT_SPECIFIC_ENDPOINT.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_SPECIFIC_ENDPOINT, scheme, 0)?; let endpoint_num = get_u8_from_regex(®EX_PORT_SPECIFIC_ENDPOINT, scheme, 1)?; Ok(Self::Endpoint(port_num, endpoint_num, String::from("root"))) } else if REGEX_PORT_SUB_ENDPOINT.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 0)?; let endpoint_num = get_u8_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 1)?; let handle_type = get_string_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 2)?; diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index f30443a5f4..0705468d14 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -1,6 +1,6 @@ use crate::usb; -use std::{fmt, mem}; use common::io::{Io, Mmio}; +use std::{fmt, mem}; use super::context::StreamContextType; From 18b688a49c9956634d3b70ccc76b9a2d29b644c9 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Thu, 17 Oct 2024 16:23:24 +0300 Subject: [PATCH 0989/1301] Partial risc-v support --- Cargo.lock | 443 +++++++++++++++----------------- acpid/Cargo.toml | 2 +- common/src/dma.rs | 3 + pcid/Cargo.toml | 2 +- pcid/src/cfg_access/mod.rs | 74 ++---- storage/nvmed/src/main.rs | 1 + storage/nvmed/src/nvme/mod.rs | 6 + virtio-core/src/arch/riscv64.rs | 9 + virtio-core/src/lib.rs | 4 + virtio-core/src/probe.rs | 5 - 10 files changed, 244 insertions(+), 305 deletions(-) create mode 100644 virtio-core/src/arch/riscv64.rs diff --git a/Cargo.lock b/Cargo.lock index a9d3c51e67..badf40783f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,12 +8,12 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", - "libredox 0.1.3", + "libredox", "log", "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", "spin", ] @@ -25,16 +25,16 @@ dependencies = [ "amlserde", "arrayvec 0.7.6", "common", - "libredox 0.1.3", + "libredox", "log", "num-derive", "num-traits", - "parking_lot 0.11.2", + "parking_lot 0.12.3", "plain", "redox-daemon", - "redox-scheme 0.2.2", + "redox-scheme 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", "ron", "rustc-hash", "thiserror", @@ -48,13 +48,13 @@ dependencies = [ "byteorder", "common", "driver-block", - "libredox 0.1.3", + "libredox", "log", "pcid", "redox-daemon", - "redox-scheme 0.2.1", + "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -72,10 +72,10 @@ version = "0.1.0" dependencies = [ "bitflags 2.6.0", "common", - "libredox 0.1.3", + "libredox", "redox-daemon", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -126,9 +126,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" [[package]] name = "arrayvec" @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "base64" @@ -177,12 +177,12 @@ version = "0.1.0" dependencies = [ "common", "driver-block", - "fdt 0.1.5", - "libredox 0.1.3", + "fdt", + "libredox", "redox-daemon", - "redox-scheme 0.2.1", + "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -190,11 +190,11 @@ name = "bgad" version = "0.1.0" dependencies = [ "common", - "libredox 0.1.3", + "libredox", "orbclient", "pcid", "redox-daemon", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -253,9 +253,12 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.5" +version = "1.1.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "324c74f2155653c90b04f25b2a47a8a631360cb908f92a772695f430c7e31052" +checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -312,17 +315,17 @@ dependencies = [ name = "common" version = "0.1.0" dependencies = [ - "libredox 0.1.3", + "libredox", "log", "redox-log", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "crc" @@ -380,15 +383,15 @@ name = "driver-block" version = "0.1.0" dependencies = [ "partitionlib", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] name = "driver-network" version = "0.1.0" dependencies = [ - "libredox 0.1.3", - "redox_syscall 0.5.6", + "libredox", + "redox_syscall", ] [[package]] @@ -398,11 +401,11 @@ dependencies = [ "bitflags 2.6.0", "common", "driver-network", - "libredox 0.1.3", + "libredox", "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -416,20 +419,12 @@ name = "fbcond" version = "0.1.0" dependencies = [ "inputd", - "libredox 0.1.3", + "libredox", "orbclient", "ransid", "redox-daemon", "redox_event", - "redox_syscall 0.5.6", -] - -[[package]] -name = "fdt" -version = "0.1.0" -source = "git+https://gitlab.redox-os.org/rosehuds/fdt.git#7358607679114ccab5f97e14894ed3b59c5d42d6" -dependencies = [ - "byteorder", + "redox_syscall", ] [[package]] @@ -452,9 +447,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -467,9 +462,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -477,15 +472,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -494,38 +489,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.79", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -564,9 +559,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" [[package]] name = "heck" @@ -588,9 +583,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -615,13 +610,13 @@ version = "0.1.0" dependencies = [ "common", "driver-block", - "libredox 0.1.3", + "libredox", "log", "pcid", "redox-daemon", - "redox-scheme 0.2.1", + "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -630,20 +625,20 @@ version = "0.1.0" dependencies = [ "bitflags 2.6.0", "common", - "libredox 0.1.3", + "libredox", "log", "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", "spin", ] [[package]] name = "indexmap" -version = "2.2.6" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", "hashbrown", @@ -655,23 +650,14 @@ version = "0.1.0" dependencies = [ "anyhow", "common", - "libredox 0.1.3", + "libredox", "log", "orbclient", "redox-daemon", - "redox_syscall 0.5.6", + "redox_syscall", "spin", ] -[[package]] -name = "instant" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if 1.0.0", -] - [[package]] name = "itoa" version = "1.0.11" @@ -685,18 +671,18 @@ dependencies = [ "bitflags 2.6.0", "common", "driver-network", - "libredox 0.1.3", + "libredox", "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -709,20 +695,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" - -[[package]] -name = "libredox" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" -dependencies = [ - "bitflags 2.6.0", - "libc", - "redox_syscall 0.4.1", -] +checksum = "f0b21006cd1874ae9e650973c565615676dc4a274c965bb0a73796dac838ce4f" [[package]] name = "libredox" @@ -732,7 +707,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -740,11 +715,11 @@ name = "lived" version = "0.1.0" dependencies = [ "anyhow", - "libredox 0.1.3", + "libredox", "redox-daemon", - "redox-scheme 0.2.1", + "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -797,9 +772,9 @@ dependencies = [ [[package]] name = "numtoa" -version = "0.1.0" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" +checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" [[package]] name = "nvmed" @@ -811,30 +786,30 @@ dependencies = [ "crossbeam-channel", "driver-block", "futures", - "libredox 0.1.3", + "libredox", "log", "partitionlib", "pcid", "redox-daemon", - "redox-scheme 0.2.1", + "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", "smallvec 1.13.2", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "orbclient" -version = "0.3.47" -source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#563f1457890be4a81e9613bc803617482d38aa3b" +version = "0.3.48" +source = "git+https://gitlab.redox-os.org/redox-os/orbclient.git#4ba79212632aedad156de15d8cf7fa779f0ad3c8" dependencies = [ "libc", - "libredox 0.0.2", + "libredox", "sdl2", "sdl2-sys", ] @@ -860,13 +835,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ - "instant", "lock_api", - "parking_lot_core 0.8.6", + "parking_lot_core 0.9.10", ] [[package]] @@ -883,16 +857,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.6" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if 1.0.0", - "instant", "libc", - "redox_syscall 0.2.16", + "redox_syscall", "smallvec 1.13.2", - "winapi", + "windows-targets", ] [[package]] @@ -956,15 +929,15 @@ dependencies = [ "bit_field", "bitflags 1.3.2", "common", - "fdt 0.1.0", + "fdt", "libc", - "libredox 0.1.3", + "libredox", "log", "paw", "pci_types", "plain", "redox-daemon", - "redox_syscall 0.5.6", + "redox_syscall", "serde", "serde_json", "structopt", @@ -977,9 +950,9 @@ name = "pcspkrd" version = "0.1.0" dependencies = [ "common", - "libredox 0.1.3", + "libredox", "redox-daemon", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -1026,9 +999,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" dependencies = [ "unicode-ident", ] @@ -1039,18 +1012,18 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", - "libredox 0.1.3", + "libredox", "log", "orbclient", "redox-daemon", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -1114,7 +1087,7 @@ version = "0.1.3" source = "git+https://gitlab.redox-os.org/redox-os/redox-daemon.git#31ab115cf17d6fe333515bfe19ac477352a1dcc0" dependencies = [ "libc", - "libredox 0.1.3", + "libredox", ] [[package]] @@ -1131,21 +1104,21 @@ dependencies = [ [[package]] name = "redox-scheme" -version = "0.2.1" -source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#79d9d54f572f53386981fb9b6ef054fd9e45110c" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95624e20d2c1808f7ca0820720d30aad9f5d2fc404e1ef379431ad7a790c3f7e" dependencies = [ - "libredox 0.1.3", - "redox_syscall 0.5.6", + "libredox", + "redox_syscall", ] [[package]] name = "redox-scheme" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98d040cfa6370d9c6b1a5987247272f19ea4722f1064e66ad2e077c152b82ea3" +version = "0.2.3" +source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#dc6a047842353ed49c1788396d9135de2c3d7382" dependencies = [ - "libredox 0.1.3", - "redox_syscall 0.5.6", + "libredox", + "redox_syscall", ] [[package]] @@ -1155,32 +1128,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69609faa5d5992247a4ef379917bb3e39be281405d6a0ccd4f942429400b956f" dependencies = [ "bitflags 2.6.0", - "libredox 0.1.3", + "libredox", ] [[package]] name = "redox_syscall" -version = "0.2.16" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] @@ -1193,9 +1148,9 @@ checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", @@ -1205,9 +1160,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", @@ -1216,9 +1171,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rehid" @@ -1249,12 +1204,12 @@ dependencies = [ "bitflags 2.6.0", "common", "driver-network", - "libredox 0.1.3", + "libredox", "log", "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -1264,12 +1219,12 @@ dependencies = [ "bitflags 2.6.0", "common", "driver-network", - "libredox 0.1.3", + "libredox", "log", "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -1290,11 +1245,11 @@ version = "0.1.0" dependencies = [ "bitflags 2.6.0", "common", - "libredox 0.1.3", + "libredox", "log", "redox-daemon", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", "spin", ] @@ -1349,44 +1304,51 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.79", ] [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ "serde", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "slab" version = "0.4.9" @@ -1488,9 +1450,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.71" +version = "2.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" dependencies = [ "proc-macro2", "quote", @@ -1505,12 +1467,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "termion" -version = "4.0.2" +version = "4.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ccce68e518d1173e80876edd54760b60b792750d0cab6444a79101c6ea03848" +checksum = "7eaa98560e51a2cf4f0bb884d8b2098a9ea11ecf3b7078e9c68242c74cc923a7" dependencies = [ "libc", - "libredox 0.0.2", + "libredox", "numtoa", "redox_termios", ] @@ -1526,22 +1488,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.62" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" +checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.62" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" +checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.79", ] [[package]] @@ -1567,9 +1529,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] @@ -1589,21 +1551,21 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "usbctl" @@ -1621,7 +1583,7 @@ dependencies = [ "common", "log", "orbclient", - "redox_syscall 0.5.6", + "redox_syscall", "rehid", "xhcid", ] @@ -1632,7 +1594,7 @@ version = "0.1.0" dependencies = [ "common", "log", - "redox_syscall 0.5.6", + "redox_syscall", "xhcid", ] @@ -1641,11 +1603,11 @@ name = "usbscsid" version = "0.1.0" dependencies = [ "base64 0.11.0", - "libredox 0.1.3", + "libredox", "plain", "redox-daemon", - "redox-scheme 0.2.1", - "redox_syscall 0.5.6", + "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", + "redox_syscall", "thiserror", "xhcid", ] @@ -1658,9 +1620,9 @@ checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", ] @@ -1676,12 +1638,12 @@ name = "vboxd" version = "0.1.0" dependencies = [ "common", - "libredox 0.1.3", + "libredox", "orbclient", "pcid", "redox-daemon", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -1698,9 +1660,9 @@ checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vesad" @@ -1708,11 +1670,11 @@ version = "0.1.0" dependencies = [ "common", "inputd", - "libredox 0.1.3", + "libredox", "orbclient", "ransid", "redox-daemon", - "redox_syscall 0.5.6", + "redox_syscall", ] [[package]] @@ -1723,13 +1685,13 @@ dependencies = [ "common", "driver-block", "futures", - "libredox 0.1.3", + "libredox", "log", "partitionlib", "pcid", "redox-daemon", - "redox-scheme 0.2.1", - "redox_syscall 0.5.6", + "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", + "redox_syscall", "spin", "static_assertions", "thiserror", @@ -1744,11 +1706,11 @@ dependencies = [ "common", "crossbeam-queue", "futures", - "libredox 0.1.3", + "libredox", "log", "pcid", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", "static_assertions", "thiserror", ] @@ -1761,13 +1723,13 @@ dependencies = [ "common", "futures", "inputd", - "libredox 0.1.3", + "libredox", "log", "orbclient", "paste", "pcid", "redox-daemon", - "redox_syscall 0.5.6", + "redox_syscall", "spin", "static_assertions", "virtio-core", @@ -1780,11 +1742,11 @@ dependencies = [ "common", "driver-network", "futures", - "libredox 0.1.3", + "libredox", "log", "pcid", "redox-daemon", - "redox_syscall 0.5.6", + "redox_syscall", "static_assertions", "virtio-core", ] @@ -1806,34 +1768,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if 1.0.0", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.79", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1841,22 +1804,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.71", + "syn 2.0.79", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "winapi" @@ -1981,13 +1944,13 @@ dependencies = [ "crossbeam-channel", "futures", "lazy_static", - "libredox 0.1.3", + "libredox", "log", "pcid", "plain", "redox-daemon", "redox_event", - "redox_syscall 0.5.6", + "redox_syscall", "regex", "serde", "serde_json", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 21b4f4268b..51c65d60b5 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -11,7 +11,7 @@ aml = { git = "https://github.com/rw-vanc/acpi.git", branch = "cumulative" } log = "0.4" num-derive = "0.3" num-traits = "0.2" -parking_lot = "0.11.1" +parking_lot = "0.12" plain = "0.2.3" redox-daemon = "0.1" redox_syscall = "0.5.6" diff --git a/common/src/dma.rs b/common/src/dma.rs index 98233411d2..9b413b5bcd 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -19,6 +19,9 @@ const DMA_MEMTY: MemoryType = { } else if cfg!(target_arch = "aarch64") { // aarch64 currently must map DMA memory without caching to ensure coherence MemoryType::Uncacheable + } else if cfg!(target_arch = "riscv64") { + // FIXME check this out more + MemoryType::Uncacheable } else { panic!("invalid arch") } diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 09416ac0bd..1bf295f8d4 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -15,7 +15,7 @@ path = "src/lib.rs" bincode = "1.2" bitflags = "1" bit_field = "0.10" -fdt = { git = "https://gitlab.redox-os.org/rosehuds/fdt.git" } +fdt = "0.1.5" libc = "0.2" log = "0.4" paw = "1.0" diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index 94f42b7d3c..171ea66ac9 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -2,81 +2,39 @@ use std::sync::Mutex; use std::{fs, io, mem}; use common::{MemoryType, PhysBorrowed, Prot}; -use fdt::{DeviceTree, Node}; +use fdt::node::CellSizes; +use fdt::Fdt; use pci_types::{ConfigRegionAccess, PciAddress}; use fallback::Pci; mod fallback; -pub fn root_cell_sz(dt: &fdt::DeviceTree) -> Option<(u32, u32)> { - let root_node = dt.nodes().nth(0).unwrap(); - let address_cells = root_node - .properties() - .find(|p| p.name.contains("#address-cells")) - .unwrap(); - let size_cells = root_node - .properties() - .find(|p| p.name.contains("#size-cells")) - .unwrap(); - - Some(( - u32::from_be_bytes(<[u8; 4]>::try_from(address_cells.data).unwrap()), - u32::from_be_bytes(<[u8; 4]>::try_from(size_cells.data).unwrap()), - )) -} - -pub fn find_compatible_fdt_node<'a>( - dt: &'a fdt::DeviceTree<'a>, - compat_string: &str, -) -> Option> { - for node in dt.nodes() { - if let Some(compatible) = node.properties().find(|p| p.name.contains("compatible")) { - let s = core::str::from_utf8(compatible.data).unwrap(); - if s.contains(compat_string) { - return Some(node); - } - } - } - None -} - // https://elinux.org/Device_Tree_Usage has a lot of useful information fn locate_ecam_dtb(f: impl FnOnce(PcieAllocs<'_>) -> io::Result) -> io::Result { let dtb = fs::read("kernel.dtb:")?; - let dt = DeviceTree::new(&dtb).map_err(|err| { + let dt = Fdt::new(&dtb).map_err(|err| { io::Error::new( io::ErrorKind::InvalidData, format!("invalid device tree: {err:?}"), ) })?; - let node = find_compatible_fdt_node(&dt, "pci-host-ecam-generic").ok_or_else(|| { - io::Error::new( - io::ErrorKind::NotFound, - "couldn't find pci-host-ecam-generic node in device tree", - ) - })?; + let node = dt + .find_compatible(&["pci-host-ecam-generic"]) + .ok_or_else(|| { + io::Error::new( + io::ErrorKind::NotFound, + "couldn't find pci-host-ecam-generic node in device tree", + ) + })?; - let (address_cells, size_cells) = root_cell_sz(&dt).unwrap(); - let reg = node.properties().find(|p| p.name.contains("reg")).unwrap(); - assert_eq!(reg.data.len(), ((address_cells + size_cells) * 4) as usize); + let address = node.reg().unwrap().next().unwrap().starting_address as u64; - let address = if address_cells == 1 { - u32::from_be_bytes(<[u8; 4]>::try_from(®.data[0..4]).unwrap()).into() - } else if address_cells == 2 { - u64::from_be_bytes(<[u8; 8]>::try_from(®.data[0..8]).unwrap()) - } else { - panic!(); - }; - - let bus_range = node - .properties() - .find(|p| p.name.contains("bus-range")) - .unwrap(); - assert_eq!(bus_range.data.len(), 8); - let start_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.data[0..4]).unwrap()); - let end_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.data[4..8]).unwrap()); + let bus_range = node.property("bus-range").unwrap(); + assert_eq!(bus_range.value.len(), 8); + let start_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.value[0..4]).unwrap()); + let end_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.value[4..8]).unwrap()); // FIXME respect the BAR remappings in the ranges property diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index d969a51af3..2a1040192c 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -1,4 +1,5 @@ #![cfg_attr(target_arch = "aarch64", feature(stdarch_arm_hints))] // Required for yield instruction +#![cfg_attr(target_arch = "riscv64", feature(riscv_ext_intrinsics))] // Required for pause instruction #![feature(int_roundings)] use std::convert::TryInto; diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 4ef6c13b77..afb1bebcd9 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -43,6 +43,12 @@ pub(crate) unsafe fn pause() { std::arch::x86_64::_mm_pause(); } +#[cfg(target_arch = "riscv64")] +#[inline(always)] +pub(crate) unsafe fn pause() { + std::arch::riscv64::pause(); +} + /// Used in conjunction with `InterruptMethod`, primarily by the CQ reactor. #[derive(Debug)] pub enum InterruptSources { diff --git a/virtio-core/src/arch/riscv64.rs b/virtio-core/src/arch/riscv64.rs new file mode 100644 index 0000000000..2551479f52 --- /dev/null +++ b/virtio-core/src/arch/riscv64.rs @@ -0,0 +1,9 @@ +use std::fs::File; + +use pcid_interface::*; + +use crate::{transport::Error, Device}; + +pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { + unimplemented!("virtio_core: enable_msix") +} diff --git a/virtio-core/src/lib.rs b/virtio-core/src/lib.rs index 6c2808d680..cc46d36ff8 100644 --- a/virtio-core/src/lib.rs +++ b/virtio-core/src/lib.rs @@ -14,4 +14,8 @@ mod arch; #[path = "arch/x86.rs"] mod arch; +#[cfg(target_arch = "riscv64")] +#[path = "arch/riscv64.rs"] +mod arch; + pub use probe::{probe_device, reinit, Device, MSIX_PRIMARY_VECTOR}; diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 9ecdd01ab4..aa67b2e71c 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -40,11 +40,6 @@ static_assertions::const_assert_eq!(std::mem::size_of::(), 16); pub const MSIX_PRIMARY_VECTOR: u16 = 0; -#[cfg(not(target_arch = "x86_64"))] -fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { - panic!("Msi-X only supported on x86_64"); -} - /// VirtIO Device Probe /// /// ## Device State From 67f4ca3d73faabc7a94546f49532933ab6191fd6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 18 Oct 2024 07:32:38 -0600 Subject: [PATCH 0990/1301] Update redox-scheme --- Cargo.lock | 38 ++++++++++++++------------------------ acpid/Cargo.toml | 2 +- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index badf40783f..d88f9f3acc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,7 +32,7 @@ dependencies = [ "parking_lot 0.12.3", "plain", "redox-daemon", - "redox-scheme 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox-scheme", "redox_event", "redox_syscall", "ron", @@ -52,7 +52,7 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", + "redox-scheme", "redox_event", "redox_syscall", ] @@ -180,7 +180,7 @@ dependencies = [ "fdt", "libredox", "redox-daemon", - "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", + "redox-scheme", "redox_event", "redox_syscall", ] @@ -614,7 +614,7 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", + "redox-scheme", "redox_event", "redox_syscall", ] @@ -695,9 +695,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.160" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b21006cd1874ae9e650973c565615676dc4a274c965bb0a73796dac838ce4f" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libredox" @@ -717,7 +717,7 @@ dependencies = [ "anyhow", "libredox", "redox-daemon", - "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", + "redox-scheme", "redox_event", "redox_syscall", ] @@ -791,7 +791,7 @@ dependencies = [ "partitionlib", "pcid", "redox-daemon", - "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", + "redox-scheme", "redox_event", "redox_syscall", "smallvec 1.13.2", @@ -1104,18 +1104,8 @@ dependencies = [ [[package]] name = "redox-scheme" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95624e20d2c1808f7ca0820720d30aad9f5d2fc404e1ef379431ad7a790c3f7e" -dependencies = [ - "libredox", - "redox_syscall", -] - -[[package]] -name = "redox-scheme" -version = "0.2.3" -source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#dc6a047842353ed49c1788396d9135de2c3d7382" +version = "0.2.4" +source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#efe7addc3d6c54149694f875ed51467f8c4aa8b9" dependencies = [ "libredox", "redox_syscall", @@ -1324,9 +1314,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "6dbcf9b78a125ee667ae19388837dd12294b858d101fdd393cb9d5501ef09eb2" dependencies = [ "itoa", "memchr", @@ -1606,7 +1596,7 @@ dependencies = [ "libredox", "plain", "redox-daemon", - "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", + "redox-scheme", "redox_syscall", "thiserror", "xhcid", @@ -1690,7 +1680,7 @@ dependencies = [ "partitionlib", "pcid", "redox-daemon", - "redox-scheme 0.2.3 (git+https://gitlab.redox-os.org/redox-os/redox-scheme.git)", + "redox-scheme", "redox_syscall", "spin", "static_assertions", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 51c65d60b5..cf55061667 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -23,5 +23,5 @@ ron = "0.8.1" amlserde = { path = "../amlserde" } common = { path = "../common" } libredox = "0.1.3" -redox-scheme = "0.2.2" +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } arrayvec = "0.7.6" From 8152de14a9c73790836dd95570a331e5abfa5f33 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Fri, 18 Oct 2024 05:14:37 +0300 Subject: [PATCH 0991/1301] Remap PCI IRQs as instructed in FDT --- pcid/src/cfg_access/mod.rs | 83 +++++++++++++++++++++++++++----- pcid/src/driver_interface/mod.rs | 23 +++++++-- pcid/src/main.rs | 30 +++++++++++- 3 files changed, 120 insertions(+), 16 deletions(-) diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index 171ea66ac9..72c0c6b001 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -10,8 +10,17 @@ use fallback::Pci; mod fallback; +pub struct InterruptMap { + pub addr: [u32; 3], + pub interrupt: u32, + pub parent_phandle: u32, + pub parent_interrupt: [u32; 3], +} + // https://elinux.org/Device_Tree_Usage has a lot of useful information -fn locate_ecam_dtb(f: impl FnOnce(PcieAllocs<'_>) -> io::Result) -> io::Result { +fn locate_ecam_dtb( + f: impl FnOnce(PcieAllocs<'_>, Vec, [u32; 4]) -> io::Result, +) -> io::Result { let dtb = fs::read("kernel.dtb:")?; let dt = Fdt::new(&dtb).map_err(|err| { io::Error::new( @@ -36,15 +45,53 @@ fn locate_ecam_dtb(f: impl FnOnce(PcieAllocs<'_>) -> io::Result) -> io::Re let start_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.value[0..4]).unwrap()); let end_bus = u32::from_be_bytes(<[u8; 4]>::try_from(&bus_range.value[4..8]).unwrap()); - // FIXME respect the BAR remappings in the ranges property + // address-cells == 3, size-cells == 2, interrupt-cells == 1 + let mut interrupt_map_data = node + .property("interrupt-map") + .unwrap() + .value + .chunks_exact(4) + .map(|x| u32::from_be_bytes(<[u8; 4]>::try_from(x).unwrap())); + let mut interrupt_map = Vec::::new(); + while let Ok([addr1, addr2, addr3, int1, phandle]) = interrupt_map_data.next_chunk::<5>() { + let parent = dt.find_phandle(phandle).unwrap(); + let interrupt_cells = parent.interrupt_cells().unwrap(); + let parent_interrupt = match interrupt_cells { + 1 if let Some(a) = interrupt_map_data.next() => [a, 0, 0], + 2 if let Ok([a, b]) = interrupt_map_data.next_chunk::<2>() => [a, b, 0], + 2 if let Ok([a, b, c]) = interrupt_map_data.next_chunk::<3>() => [a, b, c], + _ => break, + }; + interrupt_map.push(InterruptMap { + addr: [addr1, addr2, addr3], + interrupt: int1, + parent_phandle: phandle, + parent_interrupt, + }); + } - f(PcieAllocs(&[PcieAlloc { - base_addr: address, - seg_group_num: 0, - start_bus: start_bus.try_into().unwrap(), - end_bus: end_bus.try_into().unwrap(), - _rsvd: [0; 4], - }])) + let interrupt_map_mask = if let Some(interrupt_mask_node) = node.property("interrupt-map-mask") + { + let mut cells = interrupt_mask_node + .value + .chunks_exact(4) + .map(|x| u32::from_be_bytes(<[u8; 4]>::try_from(x).unwrap())); + cells.next_chunk::<4>().unwrap().to_owned() + } else { + [u32::MAX, u32::MAX, u32::MAX, u32::MAX] + }; + + f( + PcieAllocs(&[PcieAlloc { + base_addr: address, + seg_group_num: 0, + start_bus: start_bus.try_into().unwrap(), + end_bus: end_bus.try_into().unwrap(), + _rsvd: [0; 4], + }]), + interrupt_map, + interrupt_map_mask, + ) } pub const MCFG_NAME: [u8; 4] = *b"MCFG"; @@ -83,7 +130,9 @@ unsafe impl plain::Plain for PcieAlloc {} struct PcieAllocs<'a>(&'a [PcieAlloc]); impl Mcfg { - fn with(f: impl FnOnce(PcieAllocs<'_>) -> io::Result) -> io::Result { + fn with( + f: impl FnOnce(PcieAllocs<'_>, Vec, [u32; 4]) -> io::Result, + ) -> io::Result { let table_dir = fs::read_dir("/scheme/acpi/tables")?; // TODO: validate/print MCFG? @@ -103,7 +152,7 @@ impl Mcfg { match Mcfg::parse(&*bytes) { Some((mcfg, allocs)) => { log::info!("MCFG {mcfg:?} ALLOCS {allocs:?}"); - return f(allocs); + return f(allocs, Vec::new(), [u32::MAX, u32::MAX, u32::MAX, u32::MAX]); } None => { return Err(io::Error::new( @@ -147,6 +196,8 @@ impl Mcfg { pub struct Pcie { lock: Mutex<()>, allocs: Vec, + pub interrupt_map: Vec, + pub interrupt_map_mask: [u32; 4], fallback: Pci, } struct Alloc { @@ -179,13 +230,19 @@ impl Pcie { lock: Mutex::new(()), allocs: Vec::new(), fallback: Pci::new(), + interrupt_map: Vec::new(), + interrupt_map_mask: [u32::MAX, u32::MAX, u32::MAX, u32::MAX], } } }, } } - fn from_allocs(allocs: PcieAllocs<'_>) -> Result { + fn from_allocs( + allocs: PcieAllocs<'_>, + interrupt_map: Vec, + interrupt_map_mask: [u32; 4], + ) -> Result { let mut allocs = allocs .0 .iter() @@ -220,6 +277,8 @@ impl Pcie { Ok(Self { lock: Mutex::new(()), allocs, + interrupt_map, + interrupt_map_mask, fallback: Pci::new(), }) } diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 6055fc74be..2b103353c5 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -4,6 +4,7 @@ use std::io::prelude::*; use std::ptr::NonNull; use std::{env, io}; +use log::info; use std::os::unix::io::{FromRawFd, RawFd}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; @@ -21,19 +22,35 @@ pub mod irq_helpers; pub mod msi; #[derive(Clone, Copy, Debug, Serialize, Deserialize)] -pub struct LegacyInterruptLine(#[doc(hidden)] pub u8); +pub struct LegacyInterruptLine { + #[doc(hidden)] + pub irq: u8, + pub phandled: Option<(u32, [u32; 3])>, +} impl LegacyInterruptLine { /// Get an IRQ handle for this interrupt line. pub fn irq_handle(self, driver: &str) -> File { - File::open(format!("/scheme/irq/{}", self.0)) + if let Some((phandle, addr)) = self.phandled { + File::create(format!( + "/scheme/irq/phandle-{}/{},{},{}", + phandle, addr[0], addr[1], addr[2] + )) .unwrap_or_else(|err| panic!("{driver}: failed to open IRQ file: {err}")) + } else { + File::open(format!("/scheme/irq/{}", self.irq)) + .unwrap_or_else(|err| panic!("{driver}: failed to open IRQ file: {err}")) + } } } impl fmt::Display for LegacyInterruptLine { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) + if let Some((phandle, addr)) = self.phandled { + write!(f, "(phandle {}, {:?})", phandle, addr) + } else { + write!(f, "{}", self.irq) + } } } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index f8d72fc910..2b7f120b1d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,4 +1,6 @@ #![feature(non_exhaustive_omitted_patterns_lint)] +#![feature(iter_next_chunk)] +#![feature(if_let_guard)] use std::fs::{metadata, read_dir, File}; use std::io::prelude::*; @@ -134,6 +136,32 @@ fn handle_parsed_header( } }; + let mut phandled: Option<(u32, [u32; 3])> = None; + if legacy_interrupt_enabled { + let pci_address = endpoint_header.header().address(); + let dt_address = ((pci_address.bus() as u32) << 16) + | ((pci_address.device() as u32) << 11) + | ((pci_address.function() as u32) << 8); + let addr = [ + dt_address & state.pcie.interrupt_map_mask[0], + 0u32, + 0u32, + interrupt_pin as u32 & state.pcie.interrupt_map_mask[3], + ]; + let mapping = state + .pcie + .interrupt_map + .iter() + .find(|x| x.addr == addr[0..3] && x.interrupt == addr[3]); + if let Some(mapping) = mapping { + debug!( + "found mapping: addr={:?} => (phandle={} irq={:?})", + addr, mapping.parent_phandle, mapping.parent_interrupt + ); + phandled = Some((mapping.parent_phandle, mapping.parent_interrupt)); + } + } + let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { endpoint_header .capabilities(&state.pcie) @@ -154,7 +182,7 @@ fn handle_parsed_header( bars, addr: endpoint_header.header().address(), legacy_interrupt_line: if legacy_interrupt_enabled { - Some(LegacyInterruptLine(irq)) + Some(LegacyInterruptLine { irq, phandled }) } else { None }, From 382b298453d20f8f81147ebff0ad3cb544ab7bfd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 29 Oct 2024 18:34:27 -0600 Subject: [PATCH 0992/1301] acpid: provide buffer contents from amlserde --- amlserde/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/amlserde/src/lib.rs b/amlserde/src/lib.rs index ae76fee781..1336f5778d 100644 --- a/amlserde/src/lib.rs +++ b/amlserde/src/lib.rs @@ -32,10 +32,11 @@ pub enum AmlSerdeValue { serialize: bool, sync_level: u8, }, - Buffer, + Buffer(Vec), BufferField { offset: u64, length: u64, + data: Vec, }, Processor { id: u8, @@ -210,14 +211,15 @@ impl AmlSerdeValue { serialize: flags.serialize(), sync_level: flags.sync_level(), }, - AmlValue::Buffer(_) => AmlSerdeValue::Buffer, + AmlValue::Buffer(buffer_data) => AmlSerdeValue::Buffer({ buffer_data.lock().to_owned() }), AmlValue::BufferField { - buffer_data: _, + buffer_data, offset, length, } => AmlSerdeValue::BufferField { offset: offset.to_owned(), length: length.to_owned(), + data: { buffer_data.lock().to_owned() } }, AmlValue::Processor { id, From 42970953fc7d8bb60e227dddbc7b43a0b5b937ea Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 30 Oct 2024 13:52:19 -0600 Subject: [PATCH 0993/1301] Fix acpid compilation on non-x86 --- acpid/src/aml_physmem.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 8f39880279..85aac85b20 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -1,3 +1,4 @@ +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use common::io::{Io, Pio}; use num_traits::PrimInt; use rustc_hash::FxHashMap; @@ -219,22 +220,28 @@ impl aml::Handler for AmlPhysMemHandler { } // Pio must be enabled via syscall::iopl + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn read_io_u8(&self, port: u16) -> u8 { Pio::::new(port).read() } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn read_io_u16(&self, port: u16) -> u16 { Pio::::new(port).read() } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn read_io_u32(&self, port: u16) -> u32 { Pio::::new(port).read() } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn write_io_u8(&self, port: u16, value: u8) { Pio::::new(port).write(value) } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn write_io_u16(&self, port: u16, value: u16) { Pio::::new(port).write(value) } + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] fn write_io_u32(&self, port: u16, value: u32) { Pio::::new(port).write(value) } From 71b70482d375f48e55dc6a0781e76877699ab4aa Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 30 Oct 2024 14:01:20 -0600 Subject: [PATCH 0994/1301] acpid: Only acquire I/O port rights on x86 --- acpid/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/acpid/src/main.rs b/acpid/src/main.rs index a0b07ec895..9ddd3ca01d 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -59,6 +59,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let acpi_context = self::acpi::AcpiContext::init(physaddrs_iter); // TODO: I/O permission bitmap? + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] common::acquire_port_io_rights().expect("acpid: failed to set I/O privilege level to Ring 3"); let shutdown_pipe = File::open("/scheme/kernel.acpi/kstop") From e765d9c8e11428512aa2afc6393daa7199d068c6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 30 Oct 2024 20:43:46 -0600 Subject: [PATCH 0995/1301] acpid: only build dmar for x86_64 --- acpid/src/acpi.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 4071c92902..c3ec97a9b1 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -15,6 +15,7 @@ use aml::{AmlContext, AmlError, AmlHandle, AmlName}; use amlserde::aml_serde_name::aml_to_symbol; use amlserde::{AmlHandleLookup, AmlSerde}; +#[cfg(target_arch = "x86_64")] pub mod dmar; use crate::aml_physmem::{AmlPageCache, AmlPhysMemHandler}; From 2975f93f300dd9d1917ebc0ae2c42d342c27f1a8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 31 Oct 2024 10:53:05 -0600 Subject: [PATCH 0996/1301] acpid: fix compilation on riscv64gc --- acpid/src/acpi.rs | 10 +--------- acpid/src/aml_physmem.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index c3ec97a9b1..de268e6043 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -4,6 +4,7 @@ use std::fmt::Write; use std::ops::Deref; use std::sync::{Arc, Mutex}; use std::{fmt, mem}; +use syscall::PAGE_SIZE; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use common::io::{Io, Pio}; @@ -19,15 +20,6 @@ use amlserde::{AmlHandleLookup, AmlSerde}; pub mod dmar; use crate::aml_physmem::{AmlPageCache, AmlPhysMemHandler}; -#[cfg(target_arch = "aarch64")] -pub const PAGE_SIZE: usize = 4096; - -#[cfg(target_arch = "x86")] -pub const PAGE_SIZE: usize = 4096; - -#[cfg(target_arch = "x86_64")] -pub const PAGE_SIZE: usize = 4096; - /// The raw SDT header struct, as defined by the ACPI specification. #[derive(Copy, Clone, Debug)] #[repr(packed)] diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 85aac85b20..f7b969b884 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -247,7 +247,7 @@ impl aml::Handler for AmlPhysMemHandler { } fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { - log::error!("read pci u8 {:X}", _device); + log::error!("read pci u8 {:X}, {:X}, {:X}, {:X}, {:X}", _segment, _bus, _device, _function, _offset); 0 } @@ -259,7 +259,7 @@ impl aml::Handler for AmlPhysMemHandler { _function: u8, _offset: u16, ) -> u16 { - log::error!("read pci u16 {:X}", _device); + log::error!("read pci u16 {:X}, {:X}, {:X}, {:X}, {:X}", _segment, _bus, _device, _function, _offset); 0 } @@ -271,7 +271,7 @@ impl aml::Handler for AmlPhysMemHandler { _function: u8, _offset: u16, ) -> u32 { - log::error!("read pci u32 {:X}", _device); + log::error!("read pci u32 {:X}, {:X}, {:X}, {:X}, {:X}", _segment, _bus, _device, _function, _offset); 0 } @@ -284,7 +284,7 @@ impl aml::Handler for AmlPhysMemHandler { _offset: u16, _value: u8, ) { - log::error!("write pci u8 {:X}", _device); + log::error!("write pci u8 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", _segment, _bus, _device, _function, _offset, _value); } fn write_pci_u16( &self, @@ -295,7 +295,7 @@ impl aml::Handler for AmlPhysMemHandler { _offset: u16, _value: u16, ) { - log::error!("write pci u16 {:X}", _device); + log::error!("write pci u16 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", _segment, _bus, _device, _function, _offset, _value); } fn write_pci_u32( &self, @@ -306,7 +306,7 @@ impl aml::Handler for AmlPhysMemHandler { _offset: u16, _value: u32, ) { - log::error!("write pci u32 {:X}", _device); + log::error!("write pci u32 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", _segment, _bus, _device, _function, _offset, _value); } } From 6ff633863e5fa5aa75be318de0b16af1f2eb1f34 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 4 Nov 2024 16:15:53 -0700 Subject: [PATCH 0997/1301] Allow usbhidd to run on multiple interfaces --- usbhidd/src/main.rs | 29 ++++++++++++++++++----------- xhcid/src/xhci/mod.rs | 3 +-- xhcid/src/xhci/scheme.rs | 40 ++++++++++++++++++++++++++++------------ 3 files changed, 47 insertions(+), 25 deletions(-) diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index f34b0f692d..423ab4b51b 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -205,19 +205,21 @@ fn main() { .expect("Failed to get standard descriptors"); log::info!("{:X?}", desc); - let (conf_desc, conf_num, (if_desc, endpoint_num_opt, hid_desc)) = + let mut endp_count = 0; + let (conf_desc, conf_num, (if_desc, endp_desc_opt, hid_desc)) = desc.config_descs .iter() .enumerate() .find_map(|(conf_num, conf_desc)| { let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { if if_desc.number == interface_num { - let endpoint_num_opt = if_desc.endpoints.iter().enumerate().find_map( - |(endpoint_i, endpoint)| { - if endpoint.ty() == EndpointTy::Interrupt - && endpoint.direction() == EndpDirection::In + let endp_desc_opt = if_desc.endpoints.iter().find_map( + |endp_desc| { + endp_count += 1; + if endp_desc.ty() == EndpointTy::Interrupt + && endp_desc.direction() == EndpDirection::In { - Some(endpoint_i + 1) + Some((endp_count, endp_desc.clone())) } else { None } @@ -227,8 +229,9 @@ fn main() { //TODO: should we do any filtering? Some(hid_desc) })?; - Some((if_desc.clone(), endpoint_num_opt, hid_desc)) + Some((if_desc.clone(), endp_desc_opt, hid_desc)) } else { + endp_count += if_desc.endpoints.len(); None } })?; @@ -268,17 +271,21 @@ fn main() { let mut handler = ReportHandler::new(&report_desc_bytes).expect("failed to parse report descriptor"); - let mut report_buffer = vec![0u8; handler.total_byte_length]; + let report_len = match endp_desc_opt { + Some((_endp_num, endp_desc)) => endp_desc.max_packet_size as usize, + None => handler.total_byte_length as usize, + }; + let mut report_buffer = vec![0u8; report_len]; let report_ty = ReportTy::Input; let report_id = 0; let mut display = File::open("/scheme/input/producer").expect("Failed to open orbital input socket"); - let mut endpoint_opt = match endpoint_num_opt { - Some(endpoint_num) => match handle.open_endpoint(endpoint_num as u8) { + let mut endpoint_opt = match endp_desc_opt { + Some((endp_num, _endp_desc)) => match handle.open_endpoint(endp_num as u8) { Ok(ok) => Some(ok), Err(err) => { - log::warn!("failed to open endpoint {endpoint_num}: {err}"); + log::warn!("failed to open endpoint {endp_num}: {err}"); None } }, diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 5a2d17f2be..04e2f1717d 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -970,8 +970,7 @@ impl Xhci { let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; - //TODO: allow spawning on all interfaces (will require fixing port state) - for ifdesc in config_desc.interface_descs.iter().take(1) { + for ifdesc in config_desc.interface_descs.iter() { if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| { driver.class == ifdesc.class && driver diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index dd011c9736..4637672bc3 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -912,19 +912,8 @@ impl Xhci { ) -> Result> { self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) } - async fn configure_endpoints(&self, port: usize, json_buf: &[u8]) -> Result<()> { - let mut req: ConfigureEndpointsReq = - serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; - - info!( - "Running configure endpoints command, at port {}, request: {:?}", - port, req - ); - - if req.interface_desc.is_some() != req.alternate_setting.is_some() { - return Err(Error::new(EBADMSG)); - } + async fn configure_endpoints_once(&self, port: usize, req: &ConfigureEndpointsReq) -> Result<()> { let (endp_desc_count, new_context_entries, configuration_value) = { let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; @@ -1144,6 +1133,8 @@ impl Xhci { endp_ctx .c .write(u32::from(avg_trb_len) | (u32::from(max_esit_payload_lo) << 16)); + + log::info!("INITIALIZED ENDPOINT {}", endp_num); } { @@ -1165,6 +1156,31 @@ impl Xhci { // Tell the device about this configuration. self.set_configuration(port, configuration_value).await?; + Ok(()) + } + + async fn configure_endpoints(&self, port: usize, json_buf: &[u8]) -> Result<()> { + let mut req: ConfigureEndpointsReq = + serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; + + info!( + "Running configure endpoints command, at port {}, request: {:?}", + port, req + ); + + if req.interface_desc.is_some() != req.alternate_setting.is_some() { + return Err(Error::new(EBADMSG)); + } + + let already_configured = { + let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; + port_state.cfg_idx == Some(req.config_desc) + }; + + if ! already_configured { + self.configure_endpoints_once(port, &req).await?; + } + if let Some(interface_num) = req.interface_desc { if let Some(alternate_setting) = req.alternate_setting { self.set_interface(port, interface_num, alternate_setting) From 8a36c994e11fbb1094de25e9cbc1b654c6795d61 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 4 Nov 2024 20:19:08 -0700 Subject: [PATCH 0998/1301] Add hwd --- Cargo.toml | 1 + hwd/.gitignore | 1 + hwd/Cargo.toml | 11 +++++++++++ hwd/src/main.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 hwd/.gitignore create mode 100644 hwd/Cargo.toml create mode 100644 hwd/src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 83a012f471..ed8c1bd82f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "acpid", "common", + "hwd", "pcid", "ps2d", "vboxd", diff --git a/hwd/.gitignore b/hwd/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/hwd/.gitignore @@ -0,0 +1 @@ +/target diff --git a/hwd/Cargo.toml b/hwd/Cargo.toml new file mode 100644 index 0000000000..6f6dd6a9d7 --- /dev/null +++ b/hwd/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "hwd" +version = "0.1.0" +edition = "2018" + +[dependencies] +log = "0.4" +ron = "0.8.1" + +amlserde = { path = "../amlserde" } +common = { path = "../common" } diff --git a/hwd/src/main.rs b/hwd/src/main.rs new file mode 100644 index 0000000000..7b50c43153 --- /dev/null +++ b/hwd/src/main.rs @@ -0,0 +1,47 @@ +use amlserde::{AmlSerde, AmlSerdeValue}; +use std::{error::Error, fs}; + +fn acpi() -> Result<(), Box> { + for entry_res in fs::read_dir("/scheme/acpi/symbols")? { + let entry = entry_res?; + if let Some(file_name) = entry.file_name().to_str() { + if file_name.ends_with("_CID") || file_name.ends_with("_HID") { + let ron = fs::read_to_string(entry.path())?; + let AmlSerde { name, value } = ron::from_str(&ron)?; + let id = match value { + AmlSerdeValue::Integer(integer) => { + let vendor = integer & 0xFFFF; + let device = (integer >> 16) & 0xFFFF; + let vendor_rev = ((vendor & 0xFF) << 8) | vendor >> 8; + let vendor_1 = (((vendor_rev >> 10) & 0x1f) as u8 + 64) as char; + let vendor_2 = (((vendor_rev >> 5) & 0x1f) as u8 + 64) as char; + let vendor_3 = (((vendor_rev >> 0) & 0x1f) as u8 + 64) as char; + format!("{}{}{}{:04X}", vendor_1, vendor_2, vendor_3, device) + } + AmlSerdeValue::String(string) => { + string + }, + _ => { + log::warn!("{}: unsupported value {:x?}", name, value); + continue; + } + }; + log::debug!("{}: {}", name, id); + } + } + } + Ok(()) +} + +fn main() { + common::setup_logging( + "misc", + "hwd", + "hwd", + log::LevelFilter::Info, + log::LevelFilter::Info, + ); + + //TODO: HWD is meant to locate PCI/XHCI/etc devices in ACPI and DeviceTree definitions and start their drivers + acpi().unwrap(); +} From 3f33cb96e72936b3405454825826fc6086f43b55 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 4 Nov 2024 20:19:18 -0700 Subject: [PATCH 0999/1301] usbhidd: update rehid --- Cargo.lock | 87 ++++++++++++++++++++++++-------------------- usbhidd/src/main.rs | 88 ++++++++++++++++++++++----------------------- 2 files changed, 92 insertions(+), 83 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d88f9f3acc..14a3c617fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,9 +126,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6" +checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" [[package]] name = "arrayvec" @@ -253,9 +253,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.30" +version = "1.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16803a61b81d9eabb7eae2588776c4c1e584b738ede45fdbb4c972cec1e9945" +checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" dependencies = [ "shlex", ] @@ -501,7 +501,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -559,9 +559,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.0" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" +checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" [[package]] name = "heck" @@ -581,6 +581,24 @@ dependencies = [ "libc", ] +[[package]] +name = "hidreport" +version = "0.4.1" +source = "git+https://github.com/jackpot51/hidreport#1cf47ffcd30f1b18b636d699de8ed76a45a813e3" +dependencies = [ + "thiserror", +] + +[[package]] +name = "hwd" +version = "0.1.0" +dependencies = [ + "amlserde", + "common", + "log", + "ron", +] + [[package]] name = "iana-time-zone" version = "0.1.61" @@ -957,9 +975,9 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "pin-utils" @@ -999,9 +1017,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.88" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c3a7fc5db1e57d5a779a352c8cdb57b29aa4c40cc69c3a68a7fedc815fbf2f9" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -1138,9 +1156,9 @@ checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" [[package]] name = "regex" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -1168,11 +1186,10 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rehid" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/rehid.git#ea48fff4901986903359cb616a9b0d0ff8d0d8b4" +source = "git+https://gitlab.redox-os.org/redox-os/rehid.git#43fe46199b2948cac2d4adee5c4f381d6639ab24" dependencies = [ - "bitflags 2.6.0", + "hidreport", "log", - "ux", ] [[package]] @@ -1294,29 +1311,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.214" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] name = "serde_json" -version = "1.0.129" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbcf9b78a125ee667ae19388837dd12294b858d101fdd393cb9d5501ef09eb2" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -1440,9 +1457,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.79" +version = "2.0.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" dependencies = [ "proc-macro2", "quote", @@ -1478,22 +1495,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.64" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84" +checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.64" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3" +checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", ] [[package]] @@ -1617,12 +1634,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "ux" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b59fc5417e036e53226bbebd90196825d358624fd5577432c4e486c95b1b096" - [[package]] name = "vboxd" version = "0.1.0" @@ -1778,7 +1789,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-shared", ] @@ -1800,7 +1811,7 @@ checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.79", + "syn 2.0.87", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 423ab4b51b..ca19f1905d 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -18,8 +18,8 @@ mod reqs; fn send_key_event( display: &mut File, - usage_page: u32, - usage: u32, + usage_page: u16, + usage: u16, pressed: bool, shift_opt: Option, ) { @@ -206,38 +206,36 @@ fn main() { log::info!("{:X?}", desc); let mut endp_count = 0; - let (conf_desc, conf_num, (if_desc, endp_desc_opt, hid_desc)) = - desc.config_descs - .iter() - .enumerate() - .find_map(|(conf_num, conf_desc)| { - let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { - if if_desc.number == interface_num { - let endp_desc_opt = if_desc.endpoints.iter().find_map( - |endp_desc| { - endp_count += 1; - if endp_desc.ty() == EndpointTy::Interrupt - && endp_desc.direction() == EndpDirection::In - { - Some((endp_count, endp_desc.clone())) - } else { - None - } - }, - ); - let hid_desc = if_desc.hid_descs.iter().find_map(|hid_desc| { - //TODO: should we do any filtering? - Some(hid_desc) - })?; - Some((if_desc.clone(), endp_desc_opt, hid_desc)) - } else { - endp_count += if_desc.endpoints.len(); - None - } - })?; - Some((conf_desc.clone(), conf_num, if_desc)) - }) - .expect("Failed to find suitable configuration"); + let (conf_desc, conf_num, (if_desc, endp_desc_opt, hid_desc)) = desc + .config_descs + .iter() + .enumerate() + .find_map(|(conf_num, conf_desc)| { + let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { + if if_desc.number == interface_num { + let endp_desc_opt = if_desc.endpoints.iter().find_map(|endp_desc| { + endp_count += 1; + if endp_desc.ty() == EndpointTy::Interrupt + && endp_desc.direction() == EndpDirection::In + { + Some((endp_count, endp_desc.clone())) + } else { + None + } + }); + let hid_desc = if_desc.hid_descs.iter().find_map(|hid_desc| { + //TODO: should we do any filtering? + Some(hid_desc) + })?; + Some((if_desc.clone(), endp_desc_opt, hid_desc)) + } else { + endp_count += if_desc.endpoints.len(); + None + } + })?; + Some((conf_desc.clone(), conf_num, if_desc)) + }) + .expect("Failed to find suitable configuration"); handle .configure_endpoints(&ConfigureEndpointsReq { @@ -327,23 +325,23 @@ fn main() { .expect("failed to parse report") { log::debug!("{:X?}", event); - if event.usage_page == UsagePage::GenericDesktop as u32 { - if event.usage == GenericDesktopUsage::X as u32 { + if event.usage_page == UsagePage::GenericDesktop as u16 { + if event.usage == GenericDesktopUsage::X as u16 { if event.relative { - mouse_dx += event.value; + mouse_dx += event.value as i32; } else { - mouse_pos.0 = event.value; + mouse_pos.0 = event.value as i32; } - } else if event.usage == GenericDesktopUsage::Y as u32 { + } else if event.usage == GenericDesktopUsage::Y as u16 { if event.relative { - mouse_dy += event.value; + mouse_dy += event.value as i32; } else { - mouse_pos.1 = event.value; + mouse_pos.1 = event.value as i32; } - } else if event.usage == GenericDesktopUsage::Wheel as u32 { + } else if event.usage == GenericDesktopUsage::Wheel as u16 { //TODO: what is X scroll? if event.relative { - scroll_y += event.value; + scroll_y += event.value as i32; } else { log::warn!("absolute mouse wheel not supported"); } @@ -355,7 +353,7 @@ fn main() { event.value ); } - } else if event.usage_page == UsagePage::KeyboardOrKeypad as u32 { + } else if event.usage_page == UsagePage::KeyboardOrKeypad as u16 { let (pressed, shift_opt) = if event.value != 0 { (true, Some(left_shift | right_shift)) } else { @@ -373,7 +371,7 @@ fn main() { pressed, shift_opt, ); - } else if event.usage_page == UsagePage::Button as u32 { + } else if event.usage_page == UsagePage::Button as u16 { if event.usage > 0 && event.usage as usize <= buttons.len() { buttons[event.usage as usize - 1] = event.value != 0; } else { From 4dedbac4e550b9794b44ba68e8e79e720ff02526 Mon Sep 17 00:00:00 2001 From: Timothy Finnegan Date: Tue, 5 Nov 2024 17:35:57 +0000 Subject: [PATCH 1000/1301] Fixed the deadlock by only addressing devices in response to attach requests.... --- audio/ihdad/src/main.rs | 2 +- inputd/src/main.rs | 4 +- xhcid/src/main.rs | 16 +- xhcid/src/xhci/device_enumerator.rs | 221 +++++++++++++ xhcid/src/xhci/irq_reactor.rs | 151 +++++++-- xhcid/src/xhci/mod.rs | 474 +++++++++++++++++++--------- xhcid/src/xhci/port.rs | 1 + xhcid/src/xhci/scheme.rs | 35 +- xhcid/src/xhci/trb.rs | 25 +- 9 files changed, 733 insertions(+), 196 deletions(-) create mode 100644 xhcid/src/xhci/device_enumerator.rs diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index e79ee9a18f..b467e33699 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -104,7 +104,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "audio", "pcie", "ihda", - log::LevelFilter::Debug, + log::LevelFilter::Info, log::LevelFilter::Info, ); diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 870ce8a432..be8ae15f6b 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -432,8 +432,8 @@ pub fn main() { "misc", "inputd", "inputd", - log::LevelFilter::Trace, - log::LevelFilter::Trace, + log::LevelFilter::Info, + log::LevelFilter::Debug, ); let mut args = std::env::args().skip(1); diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index dc280e6636..ae876f9643 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -47,6 +47,7 @@ use pcid_interface::{ use common::io::Io; use event::{Event, RawEventQueue}; +use log::info; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; use syscall::flag::EventFlags; @@ -204,7 +205,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "host", &name, log::LevelFilter::Info, - log::LevelFilter::Debug, + log::LevelFilter::Info, ); log::debug!("XHCI PCI CONFIG: {:?}", pci_config); @@ -214,8 +215,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .ptr .as_ptr() as usize; - let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); - // TODO: fix interrutps: get_int_method(&mut pcid_handle, address); + let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle, address); + //TODO: Fix interrupts. println!(" + XHCI {}", pci_config.func.display()); @@ -227,17 +228,18 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("xhcid: failed to notify parent"); - let hci = Arc::new( + let mut hci = Arc::new( Xhci::new(scheme_name, address, interrupt_method, pcid_handle) .expect("xhcid: failed to allocate device"), ); + xhci::start_irq_reactor(&hci, irq_file); - futures::executor::block_on(hci.probe()).expect("xhcid: failed to probe"); + xhci::start_device_enumerator(&hci); + + hci.poll(); //let event_queue = RawEventQueue::new().expect("xhcid: failed to create event queue"); - libredox::call::setrens(0, 0).expect("xhcid: failed to enter null namespace"); - let todo = Arc::new(Mutex::new(Vec::::new())); //let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); diff --git a/xhcid/src/xhci/device_enumerator.rs b/xhcid/src/xhci/device_enumerator.rs new file mode 100644 index 0000000000..9109ee4c56 --- /dev/null +++ b/xhcid/src/xhci/device_enumerator.rs @@ -0,0 +1,221 @@ +use crate::xhci::port::PortFlags; +use crate::xhci::scheme::Handle::Port; +use crate::xhci::Xhci; +use common::io::Io; +use crossbeam_channel; +use crossbeam_channel::RecvError; +use log::{debug, error, info, trace, warn}; +use std::sync::{Arc, Mutex}; +use std::time::Duration; +use syscall::EAGAIN; + +//enum HubPortState{ +// PoweredOff, +// Disabled, +// Disconnected, +// Reset, +// Enabled, +// Error, +// Polling, +// Compliance, +// Loopback +//} +// +//impl HubPortState{ +// pub fn from_port_flags(flags: PortFlags, protocol_version: (u8, u8)) -> Self{ +// let pp = flags.contains(PortFlags::PORT_PP); +// let ccs = flags.contains(PortFlags::PORT_CCS); +// let ped = flags.contains(PortFlags::PORT_PED); +// let pr = flags.contains(PortFlags::PORT_PR); +// +// match protocol_version { +// (2, _) | (1, _) => { +// match (pp, ccs, ped, pr) { +// (false, false, false, false) => { HubPortState::PoweredOff }, +// (true, false, false, false) => { HubPortState::Disconnected }, +// (true, true, false, true) => { HubPortState::Reset }, +// (true, true, false, false) => { HubPortState::Disabled }, +// (true, true, true, false) => { HubPortState::Enabled }, +// (true, true, true, true) => unreachable!(), //PED shouldnt be set when PR is set +// (false, _, _, _) => unreachable!(), //None of the other bits should be set when the port is off +// _ => unreachable!() //This state shouldn't be valid. +// } +// } +// (3, _) => { +// //TO-DO: USB3 state machine. +// HubPortState::PoweredOff +// }, +// (_, _) => unreachable!() //We don't support protocols > 3 yet. +// } +// } +//} +// +//struct RootHubPortStateMachine{ +// hci: Arc, +// port_num: u8, +// port_index: usize, +// protocol_major_version: u8, +// protocol_minor_version: u8, +// state: HubPortState +//} +// +//impl RootHubPortStateMachine{ +// fn new(port_num: u8, hci: Arc) -> Self{ +// +// let hci = hci.clone(); +// let port_index = (port_num - 1) as usize; +// +// //TODO: Get actual protocol version +// let (maj, min) = (2u8, 0u8); +// +// //TODO: Get actual flags +// let flags = PortFlags::all(); +// +// RootHubPortStateMachine{ +// hci, +// port_num, +// port_index, +// protocol_major_version: maj, +// protocol_minor_version: min, +// state: HubPortState::from_port_flags(flags, (maj, min)) +// } +// } +// +// fn execute(&mut self, port_num: u8){ +// //TO-DO: Implement the state machine. +// } +//} + +pub struct DeviceEnumerationRequest { + pub port_number: u8, +} + +pub struct DeviceEnumerator { + hci: Arc, + request_queue: crossbeam_channel::Receiver, +} + +impl DeviceEnumerator { + pub fn new(hci: Arc) -> Self { + let request_queue = hci.device_enumerator_receiver.clone(); + DeviceEnumerator { hci, request_queue } + } + + pub fn run(&mut self) { + loop { + trace!("Start Device Enumerator Loop"); + let request = match self.request_queue.recv() { + Ok(req) => req, + Err(err) => { + panic!("Failed to received an enumeration request! error: {}", err) + } + }; + + let port_array_index = request.port_number - 1; + + let (len, flags) = { + let ports = self.hci.ports.lock().unwrap(); + + let len = ports.len(); + + if port_array_index as usize >= len { + warn!( + "Received out of bounds Device Enumeration request for port {}", + request.port_number + ); + continue; + } + + (len, ports[port_array_index as usize].flags()) + }; + + if flags.contains(PortFlags::PORT_CCS) { + info!( + "Received Device Connect Port Status Change Event with port flags {:?}", + flags + ); + //If the port isn't enabled (i.e. it's a USB2 port), we need to reset it if it isn't resetting already + //A USB3 port won't generate a Connect Status Change until it's already enabled, so this check + //will always be skipped for USB3 ports + if !flags.contains(PortFlags::PORT_PED) { + let disabled_state = flags.contains(PortFlags::PORT_PP) + && flags.contains(PortFlags::PORT_CCS) + && !flags.contains(PortFlags::PORT_PED) + && !flags.contains(PortFlags::PORT_PR); + + if !disabled_state { + panic!( + "Port {} isn't in the disabled state! Current flags: {:?}", + request.port_number, flags + ); + } else { + debug!( + "Port {} has entered the disabled state.", + request.port_number + ); + } + + //THIS LOCKS THE PORTS. DO NOT LOCK PORTS BEFORE THIS POINT + info!("Received a device connect on port {}, but it's not enabled. Resetting the port.", request.port_number); + self.hci.reset_port((port_array_index as usize)); + + let mut ports = self.hci.ports.lock().unwrap(); + let port = &mut ports[port_array_index as usize]; + + port.portsc.writef(PortFlags::PORT_PRC.bits(), true); + + std::thread::sleep(Duration::from_millis(16)); //Some controllers need some extra time to make the transition. + + let flags = port.flags(); + + let enabled_state = flags.contains(PortFlags::PORT_PP) + && flags.contains(PortFlags::PORT_CCS) + && flags.contains(PortFlags::PORT_PED) + && !flags.contains(PortFlags::PORT_PR); + + if !enabled_state { + warn!( + "Port {} isn't in the enabled state! Current flags: {:?}", + request.port_number, flags + ); + } else { + debug!( + "Port {} is in the enabled state. Proceeding with enumeration", + request.port_number + ); + } + } + + let result = futures::executor::block_on(self.hci.attach_device(port_array_index)); + match result { + Ok(_) => { + info!("Device on port {} was attached", port_array_index); + } + Err(err) => { + if err.errno == EAGAIN { + info!("Received a device connect notification for an already connected device. Ignoring...") + } else { + warn!("processing of device attach request failed! Error: {}", err); + } + } + } + } else { + info!( + "Device Enumerator received Detach request on port {} which is in state {}", + request.port_number, + self.hci.get_pls((port_array_index) as usize) + ); + let result = + futures::executor::block_on(self.hci.detach_device(port_array_index as usize)); + match result { + Ok(_) => { + info!("Device on port {} was detached", port_array_index); + } + Err(err) => { + warn!("processing of device attach request failed! Error: {}", err); + } + } + } + } + } +} diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index a42728d4cc..6a1bd86908 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -1,24 +1,28 @@ +use std::collections::BTreeMap; use std::fs::File; use std::future::Future; use std::io::prelude::*; use std::pin::Pin; +use std::sync::atomic::{self, AtomicUsize}; use std::sync::{Arc, Mutex}; -use std::task; +use std::{io, mem, task, thread}; use std::os::unix::io::AsRawFd; use crossbeam_channel::{Receiver, Sender}; +use futures::Stream; use log::{debug, error, info, trace, warn}; -use event::RawEventQueue; - use super::doorbell::Doorbell; use super::event::EventRing; use super::ring::Ring; use super::trb::{Trb, TrbCompletionCode, TrbType}; -use super::Xhci; - +use super::{port, Xhci}; +use crate::xhci::device_enumerator::DeviceEnumerationRequest; +use crate::xhci::port::PortFlags; +use crate::xhci::scheme::AnyDescriptor::Device; use common::io::Io as _; +use event::{Event, EventQueue, RawEventQueue}; /// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back /// by the future unless it completed). @@ -87,8 +91,8 @@ impl StateKind { pub struct IrqReactor { hci: Arc, irq_file: Option, - receiver: Receiver, - + irq_receiver: Receiver, + device_enumerator_sender: Sender, states: Vec, // TODO: Since the IRQ reactor is the only part of this driver that gets event TRBs, perhaps // the event ring should be owned here? @@ -97,11 +101,15 @@ pub struct IrqReactor { pub type NewPendingTrb = State; impl IrqReactor { - pub fn new(hci: Arc, receiver: Receiver, irq_file: Option) -> Self { + pub fn new(hci: Arc, irq_file: Option) -> Self { + let device_enumerator_sender = hci.device_enumerator_sender.clone(); + let irq_receiver = hci.irq_reactor_receiver.clone(); + Self { hci, irq_file, - receiver, + irq_receiver, + device_enumerator_sender, states: Vec::new(), } } @@ -133,24 +141,65 @@ impl IrqReactor { continue 'trb_loop; } - trace!("Found event TRB: {:?}", event_trb); + trace!( + "Found event TRB at index {} with type {} and cycle bit {}: {:?}", + event_trb_index, + event_trb.trb_type(), + event_trb.cycle() as u8, + event_trb + ); if self.check_event_ring_full(event_trb.clone()) { info!("Had to resize event TRB, retrying..."); - hci_clone.event_handler_finished(); continue 'trb_loop; } + trace!("Handling requests"); self.handle_requests(); - self.acknowledge(event_trb.clone()); + trace!("Requests handled"); + + match event_trb.trb_type() { + _ if event_trb.trb_type() == TrbType::PortStatusChange as u8 => { + trace!("Received a port status change!"); + self.handle_port_status_change(event_trb.clone()) + } //TODO Handle the other unprompted events + _ => { + self.acknowledge(event_trb.clone()); + } + } event_trb.reserved(false); self.update_erdp(&*event_ring); + hci_clone.event_handler_finished(); event_trb_index = event_ring.ring.next_index(); } } + + fn mask_interrupts(&mut self) { + let mut run = self.hci.run.lock().unwrap(); + + debug!("Masking interrupts!"); + + if !run.ints[0].iman.readf(1 << 1) { + warn!("Attempted to mask interrupts when they were already disabled!") + } + + run.ints[0].iman.writef(1 << 1, false); + } + + fn unmask_interrupts(&mut self) { + let mut run = self.hci.run.lock().unwrap(); + + debug!("unmasking interrupts!"); + if run.ints[0].iman.readf(1 << 1) { + warn!("Attempted to unmask interrupts when they were already enabled!") + } + + run.ints[0].iman.writef(1 << 1, true); + } + fn run_with_irq_file(mut self) { debug!("Running IRQ reactor with IRQ file and event queue"); @@ -162,6 +211,7 @@ impl IrqReactor { .subscribe(irq_fd as usize, 0, event::EventFlags::READ) .unwrap(); + trace!("IRQ Reactor has created its event queue."); let mut event_trb_index = { hci_clone .primary_event_ring @@ -171,6 +221,7 @@ impl IrqReactor { .next_index() }; + trace!("IRQ reactor has grabbed the next index in the event ring."); for _event in event_queue { trace!("IRQ event queue notified"); let mut buffer = [0u8; 8]; @@ -188,6 +239,8 @@ impl IrqReactor { break; } + self.mask_interrupts(); + trace!("IRQ reactor received an IRQ"); let _ = self.irq_file.as_mut().unwrap().write(&buffer); @@ -199,41 +252,92 @@ impl IrqReactor { let mut count = 0; loop { + trace!("count: {}", count); let event_trb = &mut event_ring.ring.trbs[event_trb_index]; if event_trb.completion_code() == TrbCompletionCode::Invalid as u8 { if count == 0 { warn!("xhci: Received interrupt, but no event was found in the event ring. Ignoring interrupt.") } - // no more events were found, continue the loop + //hci_clone.event_handler_finished(); + self.unmask_interrupts(); return; } else { count += 1 } - trace!( - "Found event TRB type {}: {:?}", + info!( + "Found event TRB at index {} with type {} and cycle bit {}: {:?}", + event_trb_index, event_trb.trb_type(), + event_trb.cycle() as u8, event_trb ); if self.check_event_ring_full(event_trb.clone()) { info!("Had to resize event TRB, retrying..."); - hci_clone.event_handler_finished(); + //hci_clone.event_handler_finished(); + if self.hci.interrupt_is_pending(0) { + warn!("After incrementing the dequeue pointer, the interrupt bit is still pending.") + } else { + debug!("The interrupt bit is no longer pending."); + } + self.unmask_interrupts(); return; } - self.handle_requests(); - self.acknowledge(event_trb.clone()); + + match event_trb.trb_type() { + _ if event_trb.trb_type() == TrbType::PortStatusChange as u8 => { + trace!("Received a port status change!"); + self.handle_port_status_change(event_trb.clone()) + } //TODO Handle the other unprompted events + _ => { + trace!("Received a non-status trb"); + self.acknowledge(event_trb.clone()); + } + } event_trb.reserved(false); self.update_erdp(&*event_ring); + self.hci.event_handler_finished(); event_trb_index = event_ring.ring.next_index(); } + trace!("Exited event loop!"); + } + trace!("IRQ Reactor has finished handling the interrupt"); + } + + /// Handles device attach/detach events as indicated by a PortStatusChange + fn handle_port_status_change(&mut self, trb: Trb) { + if let Some(port_num) = trb.port_status_change_port_id() { + trace!("Received Port Status Change Request on port {}", port_num); + self.device_enumerator_sender + .send(DeviceEnumerationRequest { + port_number: port_num, + }) + .expect( + format!( + "Failed to transmit device numeration request on port {}", + port_num + ) + .as_str(), + ); + { + let mut ports = self.hci.ports.lock().unwrap(); + let port = &mut ports[(port_num - 1) as usize]; + port.portsc.writef(PortFlags::PORT_CSC.bits(), true); + } + } else { + warn!( + "Received a TRB of type {}, which was unexpected", + trb.trb_type() + ) } } + fn update_erdp(&self, event_ring: &EventRing) { let dequeue_pointer_and_dcs = event_ring.erdp(); let dequeue_pointer = dequeue_pointer_and_dcs & 0xFFFF_FFFF_FFFF_FFFE; @@ -254,7 +358,7 @@ impl IrqReactor { } fn handle_requests(&mut self) { self.states.extend( - self.receiver + self.irq_receiver .try_iter() .inspect(|req| trace!("Received request: {:X?}", req)), ); @@ -448,6 +552,7 @@ impl EventDoorbell { pub fn ring(self) { trace!("Ring doorbell {} with data {}", self.index, self.data); self.dbs.lock().unwrap()[self.index].write(self.data); + trace!("Doorbell was rung."); } } @@ -465,7 +570,7 @@ impl Future for EventTrbFuture { fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { let this = self.get_mut(); - + trace!("Start poll!"); let message = match this { &mut Self::Pending { ref state, @@ -490,12 +595,12 @@ impl Future for EventTrbFuture { if let Some(doorbell) = doorbell_opt.take() { doorbell.ring(); } - return task::Poll::Pending; } }, &mut Self::Finished => panic!("Polling finished EventTrbFuture again."), }; + trace!("finished!"); *this = Self::Finished; task::Poll::Ready(message) } @@ -571,6 +676,10 @@ impl Xhci { trb: &Trb, doorbell: EventDoorbell, ) -> impl Future + Send + Sync + 'static { + trace!( + "Sending command at phys_ptr {:X}", + command_ring.trb_phys_ptr(self.cap.ac64(), trb) + ); if !trb.is_command_trb() { panic!("Invalid TRB type given to next_command_completion_event_trb(): {} (TRB {:?}. Expected command TRB.", trb.trb_type(), trb) } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 04e2f1717d..2cc2dcf0ba 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -18,15 +18,15 @@ use std::ptr::NonNull; use std::sync::atomic::{AtomicBool, AtomicUsize}; use std::sync::{Arc, Mutex, MutexGuard, Weak}; +use std::time::Duration; use std::{mem, process, slice, sync::atomic, task, thread}; - -use common::io::Io; use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT}; -use syscall::PAGE_SIZE; +use syscall::{EAGAIN, PAGE_SIZE}; use chashmap::CHashMap; -use common::dma::Dma; +use common::{dma::Dma, io::Io}; use crossbeam_channel::{Receiver, Sender}; +use futures::AsyncReadExt; use log::{debug, error, info, trace, warn}; use serde::Deserialize; @@ -37,6 +37,7 @@ use pcid_interface::{PciFeature, PciFunctionHandle}; mod capability; mod context; +mod device_enumerator; mod doorbell; mod event; mod extended; @@ -104,6 +105,10 @@ impl Xhci { index: u8, desc: &mut Dma, ) -> Result<()> { + if self.interrupt_is_pending(0) { + warn!("EHB is already set!"); + self.force_clear_interrupt(0); + } let len = mem::size_of::(); log::debug!( "get_desc_raw port {} slot {} kind {:?} index {} len {}", @@ -154,13 +159,14 @@ impl Xhci { ) }; + debug!("Waiting for the next transfer event TRB..."); let trbs = future.await; let event_trb = trbs.event_trb; let status_trb = trbs.src_trb.unwrap(); - + trace!("Handling the transfer event TRB!"); self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(()) } @@ -265,8 +271,7 @@ pub struct Xhci { handles: CHashMap, next_handle: AtomicUsize, port_states: CHashMap, - - drivers: CHashMap, + drivers: CHashMap>, scheme_name: String, interrupt_method: InterruptMethod, @@ -279,6 +284,9 @@ pub struct Xhci { // not used, but still stored so that the thread, when created, can get the channel without the // channel being in a mutex. irq_reactor_receiver: Receiver, + device_enumerator: Mutex>>, + device_enumerator_sender: Sender, + device_enumerator_receiver: Receiver, } unsafe impl Send for Xhci {} @@ -401,6 +409,8 @@ impl Xhci { let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded(); + let (device_enumerator_sender, device_enumerator_receiver) = crossbeam_channel::unbounded(); + let mut xhci = Self { base: address as *const u8, @@ -419,7 +429,6 @@ impl Xhci { handles: CHashMap::new(), next_handle: AtomicUsize::new(0), port_states: CHashMap::new(), - drivers: CHashMap::new(), scheme_name, @@ -429,6 +438,9 @@ impl Xhci { irq_reactor: Mutex::new(None), irq_reactor_sender, irq_reactor_receiver, + device_enumerator: Mutex::new(None), + device_enumerator_sender, + device_enumerator_receiver, }; xhci.init(max_slots)?; @@ -528,28 +540,109 @@ impl Xhci { self.op.get_mut().unwrap().set_cie(self.cap.cic()); - // Reset ports - { - let mut ports = self.ports.lock().unwrap(); - for (i, port) in ports.iter_mut().enumerate() { - //TODO: only reset if USB 2.0? - debug!("XHCI Port {} reset", i); + self.print_port_capabilities(); - let instant = std::time::Instant::now(); + Ok(()) + } - port.portsc.writef(port::PortFlags::PORT_PR.bits(), true); - while port.portsc.readf(port::PortFlags::PORT_PR.bits()) { - //while ! port.flags().contains(port::PortFlags::PORT_PRC) { - if instant.elapsed().as_secs() >= 1 { - warn!("timeout"); - break; - } - std::thread::yield_now(); + pub fn get_pls(&self, port_num: usize) -> u32 { + let mut ports = self.ports.lock().unwrap(); + let port = ports.get_mut(port_num).unwrap(); + let state = port.portsc.read(); + (state >> 5) & 4 + } + + pub fn poll(&self) { + debug!("Polling Initial Devices!"); + + let len = self.ports.lock().unwrap().len(); + + for index in 0..len { + //Get the CCS and CSC flags + let (ccs, csc, flags) = { + let mut ports = self.ports.lock().unwrap(); + let port = &mut ports[index]; + let ccs = port.portsc.readf(PortFlags::PORT_CCS.bits()); + let csc = port.portsc.readf(PortFlags::PORT_CSC.bits()); + + (ccs, csc, port.flags()) + }; + + debug!("Port {} has flags {:?}", index + 1, flags); + + match (ccs, csc) { + (false, false) => { // Nothing is connected, and there was no port status change + //Do nothing + } + _ => { + //Either something is connected, or nothing is connected and a port status change was asserted. + self.device_enumerator_sender + .send(DeviceEnumerationRequest { + port_number: (index + 1) as u8, + }) + .expect("Failed to generate the port enumeration request!"); } } } + } - Ok(()) + pub fn print_port_capabilities(&self) { + let len; + { + let mut ports = self.ports.lock().unwrap(); + len = ports.len(); + } + + for port in 0..len { + let state = self.get_pls(port); + let mut flags; + { + let mut ports = self.ports.lock().unwrap(); + + flags = ports[port].flags(); + } + + match self.supported_protocol(port as u8) { + None => { + warn!("No detected supported protocol for port {}", port); + } + Some(protocol) => { + info!( + "Port {} is a USB {}.{} port with slot type {} and in current state {}: {:?}", + port + 1, + protocol.rev_major(), + protocol.rev_minor(), + protocol.proto_slot_ty(), + state, + flags + ); + } + }; + } + } + pub fn reset_port(&self, port_num: usize) { + debug!("XHCI Port {} reset", port_num); + + //TODO handle the second unwrap + let mut ports = self.ports.lock().unwrap(); + let port = ports.get_mut(port_num).unwrap(); + let instant = std::time::Instant::now(); + + let state = port.portsc.read(); + let pls = (state >> 5) & 4; + + debug!("Port Link State: {}", pls); + + port.portsc.writef(port::PortFlags::PORT_PR.bits(), true); + debug!("Flags after setting port reset: {:?}", port.flags()); + while !port.portsc.readf(port::PortFlags::PORT_PRC.bits()) { + debug!("Ran at least once!"); + if instant.elapsed().as_secs() >= 1 { + warn!("timeout"); + break; + } + //std::thread::yield_now(); + } } pub fn setup_scratchpads(&mut self) -> Result<()> { @@ -570,6 +663,27 @@ impl Xhci { Ok(()) } + pub fn force_clear_interrupt(&self, index: usize) { + { + // If ERDP EHB bit is set, clear it before sending command + //TODO: find out why this bit is set earlier! + let mut run = self.run.lock().unwrap(); + let mut int = &mut run.ints[index]; + + if int.erdp_low.readf(1 << 3) { + int.erdp_low.writef(1 << 3, true); + } else { + warn!("Attempted to clear the interrupt bit when no interrupt was pending"); + } + } + } + + pub fn interrupt_is_pending(&self, index: usize) -> bool { + let mut run = self.run.lock().unwrap(); + let mut int = &mut run.ints[index]; + int.erdp_low.readf(1 << 3) + } + pub async fn enable_port_slot(&self, slot_ty: u8) -> Result { assert_eq!(slot_ty & 0x1F, slot_ty); @@ -577,8 +691,9 @@ impl Xhci { .execute_command(|cmd, cycle| cmd.enable_slot(slot_ty, cycle)) .await; + trace!("Slot is enabled!"); self::scheme::handle_event_trb("ENABLE_SLOT", &event_trb, &command_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(event_trb.event_slot()) } @@ -588,7 +703,7 @@ impl Xhci { .await; self::scheme::handle_event_trb("DISABLE_SLOT", &event_trb, &command_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(()) } @@ -611,121 +726,171 @@ impl Xhci { Self::alloc_dma_zeroed_unsized_raw(self.cap.ac64(), count) } - pub async fn probe(&self) -> Result<()> { - debug!( - "XHCI capabilities: {:?}", - self.capabilities_iter().collect::>() + pub async fn attach_device(&self, port_number: u8) -> syscall::Result<()> { + let i = port_number as usize; + + if self.port_states.contains_key(&i) { + return Err(syscall::Error::new(EAGAIN)); + } + + let (data, state, speed, flags) = { + let port = &self.ports.lock().unwrap()[i]; + (port.read(), port.state(), port.speed(), port.flags()) + }; + + info!( + "XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", + i, data, state, speed, flags ); - let port_count = { self.ports.lock().unwrap().len() }; - - for i in 0..port_count { - let (data, state, speed, flags) = { - let port = &self.ports.lock().unwrap()[i]; - (port.read(), port.state(), port.speed(), port.flags()) + if flags.contains(port::PortFlags::PORT_CCS) { + let slot_ty = match self.supported_protocol(i as u8) { + Some(protocol) => protocol.proto_slot_ty(), + None => { + warn!("Failed to find supported protocol information for port"); + 0 + } }; - info!( - "XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", - i, data, state, speed, flags - ); - if flags.contains(port::PortFlags::PORT_CCS) { - let slot_ty = match self.supported_protocol(i as u8) { - Some(protocol) => protocol.proto_slot_ty(), - None => { - warn!("Failed to find supported protocol information for port"); - 0 - } - }; - - debug!("Slot type: {}", slot_ty); - debug!("Enabling slot."); - let slot = match self.enable_port_slot(slot_ty).await { - Ok(ok) => ok, - Err(err) => { - error!("Failed to enable slot for port {}: {}", i, err); - continue; - } - }; - - info!("Enabled port {}, which the xHC mapped to {}", i, slot); - - let mut input = unsafe { self.alloc_dma_zeroed::()? }; - let mut ring = match self - .address_device(&mut input, i, slot_ty, slot, speed) - .await - { - Ok(ok) => ok, - Err(err) => { - error!("Failed to address device for port {}: {}", i, err); - continue; - } - }; - debug!("Addressed device"); - - // TODO: Should the descriptors be cached in PortState, or refetched? - - let mut port_state = PortState { - slot, - input_context: Mutex::new(input), - dev_desc: None, - cfg_idx: None, - endpoint_states: std::iter::once(( - 0, - EndpointState { - transfer: RingOrStreams::Ring(ring), - driver_if_state: EndpIfState::Init, - }, - )) - .collect::>(), - }; - self.port_states.insert(i, port_state); - - // Ensure correct packet size is used - let dev_desc_8_byte = self.fetch_dev_desc_8_byte(i, slot).await?; - { - let mut port_state = self.port_states.get_mut(&i).unwrap(); - - let mut input = port_state.input_context.lock().unwrap(); - - self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte) - .await?; + debug!("Slot type: {}", slot_ty); + debug!("Enabling slot."); + let slot = match self.enable_port_slot(slot_ty).await { + Ok(ok) => ok, + Err(err) => { + error!("Failed to enable slot for port {}: {}", i, err); + return Err(err); } + }; - let dev_desc = self.get_desc(i, slot).await?; - self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc); + info!("Enabled port {}, which the xHC mapped to {}", i, slot); - { - let mut port_state = self.port_states.get_mut(&i).unwrap(); + let mut input = unsafe { self.alloc_dma_zeroed::()? }; - let mut input = port_state.input_context.lock().unwrap(); - let dev_desc = port_state.dev_desc.as_ref().unwrap(); - - self.update_default_control_pipe(&mut *input, slot, dev_desc) - .await?; + info!("Attempting to address the device"); + let mut ring = match self + .address_device(&mut input, i, slot_ty, slot, speed) + .await + { + Ok(device_ring) => device_ring, + Err(err) => { + error!("Failed to spawn driver for port {}: `{}`", i, err); + return Err(err); } + }; - match self.spawn_drivers(i) { - Ok(()) => (), - Err(err) => error!("Failed to spawn driver for port {}: `{}`", i, err), + debug!("Addressed device"); + + // TODO: Should the descriptors be cached in PortState, or refetched? + + let mut port_state = PortState { + slot, + input_context: Mutex::new(input), + dev_desc: None, + cfg_idx: None, + endpoint_states: std::iter::once(( + 0, + EndpointState { + transfer: RingOrStreams::Ring(ring), + driver_if_state: EndpIfState::Init, + }, + )) + .collect::>(), + }; + self.port_states.insert(i, port_state); + debug!("Got port states!"); + + // Ensure correct packet size is used + let dev_desc_8_byte = self.fetch_dev_desc_8_byte(i, slot).await?; + { + let mut port_state = self.port_states.get_mut(&i).unwrap(); + + let mut input = port_state.input_context.lock().unwrap(); + + self.update_max_packet_size(&mut *input, slot, dev_desc_8_byte) + .await?; + } + + debug!("Got the 8 byte dev descriptor"); + + let dev_desc = self.get_desc(i, slot).await?; + debug!("Got the full device descriptor!"); + self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc); + + debug!("Got the port states again!"); + { + let mut port_state = self.port_states.get_mut(&i).unwrap(); + + let mut input = port_state.input_context.lock().unwrap(); + debug!("Got the input context!"); + let dev_desc = port_state.dev_desc.as_ref().unwrap(); + + self.update_default_control_pipe(&mut *input, slot, dev_desc) + .await?; + } + + debug!("Updated the default control pipe"); + + match self.spawn_drivers(i) { + Ok(()) => (), + Err(err) => { + error!("Failed to spawn driver for port {}: `{}`", i, err) } } + } else { + warn!("Attempted to attach a device that didnt have CCS=1"); } Ok(()) } + pub async fn detach_device(&self, port_number: usize) -> Result<()> { + let port_state = self.port_states.get(&port_number); + let mut driver_process = self.drivers.get(&port_number); + + if let Some(state) = port_state { + let result = self.disable_port_slot(state.slot).await; + self.port_states.remove(&port_number); + + //TODO handle killing the child process properly. I'm not sure how + //to get a mutable reference that I can kill. + + if let Some(mutex) = driver_process { + let mut child = mutex.lock().unwrap(); + + match child.kill() { + Ok(_) => { + info!("Killing {:?}", child) + } + Err(_) => { + warn!("Failed to kill the child process!"); + } + } + } + + self.drivers.remove(&port_number); + + result + } else { + warn!( + "Attempted to detach from port {}, which wasn't previously attached.", + port_number + ); + Ok(()) + } + } + pub async fn update_max_packet_size( &self, input_context: &mut Dma, slot_id: u8, dev_desc: usb::DeviceDescriptor8Byte, ) -> Result<()> { - let new_max_packet_size = if dev_desc.major_usb_vers() == 2 { - u32::from(dev_desc.packet_size) - } else { - 1u32 << dev_desc.packet_size - }; + let new_max_packet_size = u32::from(dev_desc.packet_size); //if dev_desc.major_usb_vers() == 2 { + //u32::from(dev_desc.packet_size) + //} else { + // info!("USB 2 device detected. Packet size is: {}", dev_desc.packet_size); + // 1u32 << dev_desc.packet_size + //}; let endp_ctx = &mut input_context.device.endpoints[0]; let mut b = endp_ctx.b.read(); b &= 0x0000_FFFF; @@ -739,7 +904,7 @@ impl Xhci { .await; self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(()) } @@ -750,14 +915,15 @@ impl Xhci { slot_id: u8, dev_desc: &DevDesc, ) -> Result<()> { + debug!("Updating default control pipe!"); input_context.add_context.write(1 << 1); input_context.drop_context.write(0); - let new_max_packet_size = if dev_desc.major_version() == 2 { - u32::from(dev_desc.packet_size) - } else { - 1u32 << dev_desc.packet_size - }; + let new_max_packet_size = u32::from(dev_desc.packet_size); //if dev_desc.major_version() == 2 { + // u32::from(dev_desc.packet_size) + //} else { + // 1u32 << dev_desc.packet_size + //}; let endp_ctx = &mut input_context.device.endpoints[0]; let mut b = endp_ctx.b.read(); b &= 0x0000_FFFF; @@ -769,9 +935,10 @@ impl Xhci { trb.evaluate_context(slot_id, input_context.physical(), false, cycle) }) .await; + debug!("Completed the command to update the default control pipe"); self::scheme::handle_event_trb("EVALUATE_CONTEXT", &event_trb, &command_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(()) } @@ -878,10 +1045,10 @@ impl Xhci { i, event_trb.completion_code() ); - self.event_handler_finished(); + //self.event_handler_finished(); return Err(Error::new(EIO)); } - self.event_handler_finished(); + //self.event_handler_finished(); Ok(ring) } @@ -952,6 +1119,7 @@ impl Xhci { // suitable here. let ps = self.port_states.get(&port).unwrap(); + trace!("Spawning driver on port: {}", port + 1); //TODO: support choosing config? let config_desc = &ps @@ -968,6 +1136,7 @@ impl Xhci { Error::new(EBADF) })?; + trace!("Got config and device descriptors on port {}", port + 1); let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; for ifdesc in config_desc.interface_descs.iter() { @@ -986,20 +1155,22 @@ impl Xhci { } else { "/usr/lib/drivers/".to_owned() + command }; - let process = process::Command::new(command) - .args( - args.into_iter() - .map(|arg| { - arg.replace("$SCHEME", &self.scheme_name) - .replace("$PORT", &format!("{}", port)) - .replace("$IF_NUM", &format!("{}", ifdesc.number)) - .replace("$IF_PROTO", &format!("{}", ifdesc.protocol)) - }) - .collect::>(), - ) - .stdin(process::Stdio::null()) - .spawn() - .or(Err(Error::new(ENOENT)))?; + let process = Mutex::new( + process::Command::new(command) + .args( + args.into_iter() + .map(|arg| { + arg.replace("$SCHEME", &self.scheme_name) + .replace("$PORT", &format!("{}", port)) + .replace("$IF_NUM", &format!("{}", ifdesc.number)) + .replace("$IF_PROTO", &format!("{}", ifdesc.protocol)) + }) + .collect::>(), + ) + .stdin(process::Stdio::null()) + .spawn() + .or(Err(Error::new(ENOENT)))?, + ); self.drivers.insert(port, process); } else { warn!( @@ -1030,7 +1201,8 @@ impl Xhci { } pub fn supported_protocol(&self, port: u8) -> Option<&'static SupportedProtoCap> { self.supported_protocols_iter() - .find(|supp_proto| supp_proto.compat_port_range().contains(&port)) + .find(|supp_proto| supp_proto.compat_port_range().contains(&(port + 1))) + //Increment by 1, because USB ports index themselves by 1. } pub fn supported_protocol_speeds( &self, @@ -1123,14 +1295,24 @@ impl Xhci { } } pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { - let receiver = hci.irq_reactor_receiver.clone(); let hci_clone = Arc::clone(&hci); debug!("About to start IRQ reactor"); *hci.irq_reactor.lock().unwrap() = Some(thread::spawn(move || { debug!("Started IRQ reactor thread"); - IrqReactor::new(hci_clone, receiver, irq_file).run() + IrqReactor::new(hci_clone, irq_file).run() + })); +} + +pub fn start_device_enumerator(hci: &Arc) { + let hci_clone = Arc::clone(&hci); + + debug!("About to start Device Enumerator"); + + *hci.device_enumerator.lock().unwrap() = Some(thread::spawn(move || { + debug!("Started Device Enumerator"); + DeviceEnumerator::new(hci_clone).run(); })); } @@ -1151,6 +1333,8 @@ struct DriversConfig { drivers: Vec, } +use crate::xhci::device_enumerator::{DeviceEnumerationRequest, DeviceEnumerator}; +use crate::xhci::port::PortFlags; use lazy_static::lazy_static; lazy_static! { diff --git a/xhcid/src/xhci/port.rs b/xhcid/src/xhci/port.rs index d1b4e37187..64840c438a 100644 --- a/xhcid/src/xhci/port.rs +++ b/xhcid/src/xhci/port.rs @@ -6,6 +6,7 @@ bitflags! { const PORT_PED = 1 << 1; const PORT_OCA = 1 << 3; const PORT_PR = 1 << 4; + const PORT_PLS = 1 << 5; const PORT_PP = 1 << 9; const PORT_PIC_AMB = 1 << 14; const PORT_PIC_GRN = 1 << 15; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 4637672bc3..a2f780dce7 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -555,20 +555,18 @@ impl Xhci { /// # Locking /// This function will lock `Xhci::cmd` and `Xhci::dbs`. pub async fn execute_command(&self, f: F) -> (Trb, Trb) { - { - // If ERDP EHB bit is set, clear it before sending command - //TODO: find out why this bit is set earlier! - let mut run = self.run.lock().unwrap(); - let mut int = &mut run.ints[0]; - if int.erdp_low.readf(1 << 3) { - int.erdp_low.writef(1 << 3, true); - } + //TODO: find out why this bit is set earlier! + if self.interrupt_is_pending(0) { + warn!("The EHB bit is already set!"); + //self.force_clear_interrupt(0); } let next_event = { let mut command_ring = self.cmd.lock().unwrap(); let (cmd_index, cycle) = (command_ring.next_index(), command_ring.cycle); + info!("Sending command with cycle bit {}", cycle as u8); + { let command_trb = &mut command_ring.trbs[cmd_index]; f(command_trb, cycle); @@ -657,7 +655,7 @@ impl Xhci { handle_transfer_event_trb("CONTROL_TRANSFER", &event_trb, &status_trb)?; - self.event_handler_finished(); + //self.event_handler_finished(); Ok(event_trb) } @@ -824,7 +822,7 @@ impl Xhci { trb.reset_endpoint(slot, endp_num_xhc, tsp, cycle); }) .await; - self.event_handler_finished(); + //self.event_handler_finished(); handle_event_trb("RESET_ENDPOINT", &event_trb, &command_trb) } @@ -913,7 +911,11 @@ impl Xhci { self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) } - async fn configure_endpoints_once(&self, port: usize, req: &ConfigureEndpointsReq) -> Result<()> { + async fn configure_endpoints_once( + &self, + port: usize, + req: &ConfigureEndpointsReq, + ) -> Result<()> { let (endp_desc_count, new_context_entries, configuration_value) = { let mut port_state = self.port_states.get_mut(&port).ok_or(Error::new(EBADFD))?; @@ -1148,7 +1150,7 @@ impl Xhci { }) .await; - self.event_handler_finished(); + //self.event_handler_finished(); handle_event_trb("CONFIGURE_ENDPOINT", &event_trb, &command_trb)?; } @@ -1177,7 +1179,7 @@ impl Xhci { port_state.cfg_idx == Some(req.config_desc) }; - if ! already_configured { + if !already_configured { self.configure_endpoints_once(port, &req).await?; } @@ -1381,7 +1383,7 @@ impl Xhci { }, ) .await?; - self.event_handler_finished(); + //self.event_handler_finished(); let bytes_transferred = dma_buf .as_ref() @@ -1443,6 +1445,7 @@ impl Xhci { let mut config_descs = SmallVec::new(); for index in 0..raw_dd.configurations { + debug!("Fetching the config descriptor at index {}", index); let (desc, data) = self.fetch_config_desc(port_id, slot, index).await?; log::debug!( "port {} slot {} config {} desc {:X?}", @@ -2198,7 +2201,7 @@ impl Scheme for Xhci { EndpointHandleTy::Data => { block_on(self.on_write_endp_data(port_num, endp_num, buf)) } - EndpointHandleTy::Root(_, _) => Err(Error::new(EBADF)), + EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), }, &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); @@ -2395,7 +2398,7 @@ impl Xhci { ) }) .await; - self.event_handler_finished(); + //self.event_handler_finished(); handle_event_trb("SET_TR_DEQUEUE_PTR", &event_trb, &command_trb) } diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 0705468d14..5d175ddbfa 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -1,8 +1,9 @@ -use crate::usb; -use common::io::{Io, Mmio}; -use std::{fmt, mem}; - use super::context::StreamContextType; +use crate::usb; +use crate::xhci::trb::TrbType::PortStatusChange; +use common::io::{Io, Mmio}; +use log::trace; +use std::{fmt, mem}; #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -196,6 +197,17 @@ impl Trb { } } + pub fn port_status_change_port_id(&self) -> Option { + debug_assert_eq!(self.trb_type(), TrbType::PortStatusChange as u8); + + if self.has_completion_trb_pointer() { + let data = self.read_data(); + Some(((data >> 24) & 0xFF) as u8) + } else { + None + } + } + pub fn event_slot(&self) -> u8 { (self.control.read() >> 24) as u8 } @@ -234,6 +246,7 @@ impl Trb { } pub fn enable_slot(&mut self, slot_type: u8, cycle: bool) { + trace!("Enabling slot with type {}", slot_type); self.set( 0, 0, @@ -381,6 +394,10 @@ impl Trb { ); } + pub fn cycle(&self) -> bool { + self.control.readf(0x01) + } + pub fn status( &mut self, interrupter: u16, From 191c7973a9b94e696ed239a25f1ae1e760ecd2d7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 11 Nov 2024 12:10:01 -0700 Subject: [PATCH 1001/1301] Fix deadlock in xhcid detach_device --- xhcid/src/xhci/device_enumerator.rs | 3 ++- xhcid/src/xhci/mod.rs | 18 +++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/xhcid/src/xhci/device_enumerator.rs b/xhcid/src/xhci/device_enumerator.rs index 9109ee4c56..6e07bd3fa0 100644 --- a/xhcid/src/xhci/device_enumerator.rs +++ b/xhcid/src/xhci/device_enumerator.rs @@ -103,13 +103,14 @@ impl DeviceEnumerator { pub fn run(&mut self) { loop { - trace!("Start Device Enumerator Loop"); + info!("Start Device Enumerator Loop"); let request = match self.request_queue.recv() { Ok(req) => req, Err(err) => { panic!("Failed to received an enumeration request! error: {}", err) } }; + info!("Device Enumerator request for port {}", request.port_number); let port_array_index = request.port_number - 1; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 2cc2dcf0ba..4e1e7a9ee4 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -844,31 +844,31 @@ impl Xhci { } pub async fn detach_device(&self, port_number: usize) -> Result<()> { - let port_state = self.port_states.get(&port_number); - let mut driver_process = self.drivers.get(&port_number); - - if let Some(state) = port_state { + if let Some(state) = self.port_states.remove(&port_number) { + info!("disabling port slot {} for port {}", state.slot, port_number); let result = self.disable_port_slot(state.slot).await; - self.port_states.remove(&port_number); + info!("disabled port slot {} for port {} with result: {:?}", state.slot, port_number, result); //TODO handle killing the child process properly. I'm not sure how //to get a mutable reference that I can kill. - if let Some(mutex) = driver_process { + if let Some(mutex) = self.drivers.remove(&port_number) { + info!("locking driver process for port {}", port_number); let mut child = mutex.lock().unwrap(); + info!("Killing {:?}", child); match child.kill() { Ok(_) => { - info!("Killing {:?}", child) + info!("Killed {:?}", child) } Err(_) => { warn!("Failed to kill the child process!"); } } + } else { + info!("no driver process for port {}", port_number); } - self.drivers.remove(&port_number); - result } else { warn!( From 842fc73a341fe0c449b6c26127477274cfd41a0f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 11 Nov 2024 12:51:22 -0700 Subject: [PATCH 1002/1301] Track all drivers launched for a port --- xhcid/src/xhci/mod.rs | 86 ++++++++++++++++++++++++------------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 4e1e7a9ee4..2d26601c6a 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -271,7 +271,7 @@ pub struct Xhci { handles: CHashMap, next_handle: AtomicUsize, port_states: CHashMap, - drivers: CHashMap>, + drivers: CHashMap>, scheme_name: String, interrupt_method: InterruptMethod, @@ -844,31 +844,39 @@ impl Xhci { } pub async fn detach_device(&self, port_number: usize) -> Result<()> { + if let Some(children) = self.drivers.remove(&port_number) { + for mut child in children { + info!("killing driver process {} for port {}", child.id(), port_number); + match child.kill() { + Ok(()) => { + info!("killed driver process {} for port {}", child.id(), port_number); + match child.try_wait() { + Ok(status_opt) => match status_opt { + Some(status) => { + info!("driver process {} for port {} exited with status {}", child.id(), port_number, status); + }, + None => { + //TODO: kill harder + info!("driver process {} for port {} still running", child.id(), port_number); + } + }, + Err(err) => { + info!("failed to wait for the driver process {} for port {}: {}", child.id(), port_number, err); + } + } + } + Err(err) => { + warn!("failed to kill the driver process {} for port {}: {}", child.id(), port_number, err); + } + } + } + } + if let Some(state) = self.port_states.remove(&port_number) { info!("disabling port slot {} for port {}", state.slot, port_number); let result = self.disable_port_slot(state.slot).await; info!("disabled port slot {} for port {} with result: {:?}", state.slot, port_number, result); - //TODO handle killing the child process properly. I'm not sure how - //to get a mutable reference that I can kill. - - if let Some(mutex) = self.drivers.remove(&port_number) { - info!("locking driver process for port {}", port_number); - let mut child = mutex.lock().unwrap(); - - info!("Killing {:?}", child); - match child.kill() { - Ok(_) => { - info!("Killed {:?}", child) - } - Err(_) => { - warn!("Failed to kill the child process!"); - } - } - } else { - info!("no driver process for port {}", port_number); - } - result } else { warn!( @@ -1155,23 +1163,25 @@ impl Xhci { } else { "/usr/lib/drivers/".to_owned() + command }; - let process = Mutex::new( - process::Command::new(command) - .args( - args.into_iter() - .map(|arg| { - arg.replace("$SCHEME", &self.scheme_name) - .replace("$PORT", &format!("{}", port)) - .replace("$IF_NUM", &format!("{}", ifdesc.number)) - .replace("$IF_PROTO", &format!("{}", ifdesc.protocol)) - }) - .collect::>(), - ) - .stdin(process::Stdio::null()) - .spawn() - .or(Err(Error::new(ENOENT)))?, - ); - self.drivers.insert(port, process); + let process = process::Command::new(command) + .args( + args.into_iter() + .map(|arg| { + arg.replace("$SCHEME", &self.scheme_name) + .replace("$PORT", &format!("{}", port)) + .replace("$IF_NUM", &format!("{}", ifdesc.number)) + .replace("$IF_PROTO", &format!("{}", ifdesc.protocol)) + }) + .collect::>(), + ) + .stdin(process::Stdio::null()) + .spawn() + .or(Err(Error::new(ENOENT)))?; + self.drivers.alter(port, |children_opt| { + let mut children = children_opt.unwrap_or_else(|| Vec::new()); + children.push(process); + Some(children) + }); } else { warn!( "No driver for USB class {}.{}", From 5cf8bfda72b526d32eac6d8f094c4f37b1a7e555 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 11 Nov 2024 14:27:32 -0700 Subject: [PATCH 1003/1301] xhcid: remove transfer states on dead rings --- xhcid/src/main.rs | 20 ++------------ xhcid/src/xhci/irq_reactor.rs | 51 ++++++++++++++++++++++------------- xhcid/src/xhci/mod.rs | 3 ++- xhcid/src/xhci/scheme.rs | 6 ++--- 4 files changed, 39 insertions(+), 41 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index ae876f9643..7f76153d7c 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -63,10 +63,6 @@ pub mod driver_interface; mod usb; mod xhci; -async fn handle_packet(hci: Arc, packet: Packet) -> Packet { - todo!() -} - #[cfg(target_arch = "x86_64")] fn get_int_method( pcid_handle: &mut PciFunctionHandle, @@ -224,7 +220,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let socket_fd = libredox::call::open(format!(":{}", scheme_name), flag::O_RDWR | flag::O_CREAT, 0) .expect("xhcid: failed to create usb scheme"); - let socket = Arc::new(Mutex::new(unsafe { File::from_raw_fd(socket_fd as RawFd) })); + let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; daemon.ready().expect("xhcid: failed to notify parent"); @@ -238,20 +234,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { hci.poll(); - //let event_queue = RawEventQueue::new().expect("xhcid: failed to create event queue"); - - let todo = Arc::new(Mutex::new(Vec::::new())); - //let todo_futures = Arc::new(Mutex::new(Vec:: + Send + Sync + 'static>>>::new())); - - //let socket_fd = socket.lock().unwrap().as_raw_fd(); - //event_queue.subscribe(socket_fd as usize, 0, event::EventFlags::READ).unwrap(); - - let socket_packet = socket.clone(); - + let mut todo = Vec::::new(); loop { - let mut socket = socket_packet.lock().unwrap(); - let mut todo = todo.lock().unwrap(); - let mut packet = Packet::default(); match socket.read(&mut packet) { Ok(0) => break, diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 6a1bd86908..3317ee11e7 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -34,6 +34,14 @@ pub struct State { is_isoch_or_vf: bool, } +impl State { + fn finish(self, message: Option) { + *self.message.lock().unwrap() = message; + trace!("Waking up future with waker: {:?}", self.waker); + self.waker.wake(); + } +} + #[derive(Debug)] pub struct NextEventTrb { pub event_trb: Trb, @@ -401,13 +409,10 @@ impl IrqReactor { }; // TODO: Validate the command TRB. - *state.message.lock().unwrap() = Some(NextEventTrb { + state.finish(Some(NextEventTrb { src_trb: Some(command_trb.clone()), event_trb: trb.clone(), - }); - - trace!("Waking up future with waker: {:?}", state.waker); - state.waker.wake(); + })); return; } else if trb.completion_trb_pointer().is_none() { @@ -419,12 +424,9 @@ impl IrqReactor { first_phys_ptr, last_phys_ptr, ring_id, - } if trb.trb_type() == TrbType::Transfer as u8 => { - if let Some(src_trb) = trb - .transfer_event_trb_pointer() - .map(|ptr| self.hci.get_transfer_trb(ptr, ring_id)) - .flatten() - { + } => { + // Check if the TRB matches the transfer + if trb.trb_type() == TrbType::Transfer as u8 { match trb.transfer_event_trb_pointer() { Some(phys_ptr) => { let matches = if first_phys_ptr <= last_phys_ptr { @@ -434,13 +436,13 @@ impl IrqReactor { phys_ptr >= first_phys_ptr || phys_ptr <= last_phys_ptr }; if matches { + let src_trb = self.hci.get_transfer_trb(phys_ptr, ring_id); // Give the source transfer TRB together with the event TRB, to the future. let state = self.states.remove(index); - *state.message.lock().unwrap() = Some(NextEventTrb { - src_trb: Some(src_trb), + state.finish(Some(NextEventTrb { + src_trb: src_trb, event_trb: trb.clone(), - }); - state.waker.wake(); + })); return; } } @@ -461,11 +463,23 @@ impl IrqReactor { } } } + + // Also check if the transfer is on a dead ring + if self.hci.with_ring(ring_id, |_ring| ()).is_none() { + log::debug!("State {} is a dead transfer", index); + let state = self.states.remove(index); + state.finish(Some(NextEventTrb { + src_trb: None, + //TODO: don't send this TRB as it may not be related + event_trb: trb.clone(), + })); + continue; + } } StateKind::Other(trb_type) if trb_type as u8 == trb.trb_type() => { let state = self.states.remove(index); - state.waker.wake(); + state.finish(None); return; } @@ -493,11 +507,10 @@ impl IrqReactor { continue; } let state = self.states.remove(index); - *state.message.lock().unwrap() = Some(NextEventTrb { + state.finish(Some(NextEventTrb { event_trb: trb.clone(), src_trb: None, - }); - state.waker.wake(); + })); } } /// Checks if an event TRB is a Host Controller Event, with the completion code Event Ring diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 2d26601c6a..1c32b122c0 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -162,7 +162,7 @@ impl Xhci { debug!("Waiting for the next transfer event TRB..."); let trbs = future.await; let event_trb = trbs.event_trb; - let status_trb = trbs.src_trb.unwrap(); + let status_trb = trbs.src_trb.ok_or(Error::new(EIO))?; trace!("Handling the transfer event TRB!"); self::scheme::handle_transfer_event_trb("GET_DESC", &event_trb, &status_trb)?; @@ -698,6 +698,7 @@ impl Xhci { Ok(event_trb.event_slot()) } pub async fn disable_port_slot(&self, slot: u8) -> Result<()> { + trace!("Disable slot {}", slot); let (event_trb, command_trb) = self .execute_command(|cmd, cycle| cmd.disable_slot(slot, cycle)) .await; diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index a2f780dce7..1fd3631b90 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -651,7 +651,7 @@ impl Xhci { let trbs = future.await; let event_trb = trbs.event_trb; - let status_trb = trbs.src_trb.unwrap(); + let status_trb = trbs.src_trb.ok_or(Error::new(EIO))?; handle_transfer_event_trb("CONTROL_TRANSFER", &event_trb, &status_trb)?; @@ -748,7 +748,7 @@ impl Xhci { let trbs = future.await; let event_trb = trbs.event_trb; - let transfer_trb = trbs.src_trb.unwrap(); + let transfer_trb = trbs.src_trb.ok_or(Error::new(EIO))?; handle_transfer_event_trb("EXECUTE_TRANSFER", &event_trb, &transfer_trb)?; @@ -1136,7 +1136,7 @@ impl Xhci { .c .write(u32::from(avg_trb_len) | (u32::from(max_esit_payload_lo) << 16)); - log::info!("INITIALIZED ENDPOINT {}", endp_num); + log::info!("initialized endpoint {}", endp_num); } { From 2f9e28e23e550cc4f26f828d818ed65bb8376724 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Wed, 18 Dec 2024 21:16:17 +0300 Subject: [PATCH 1004/1301] Rerun cargo fmt to bring CI back to norm --- acpid/src/aml_physmem.rs | 57 +++++++++++++++++++++++++++++++++++----- amlserde/src/lib.rs | 6 +++-- hwd/src/main.rs | 4 +-- xhcid/src/xhci/mod.rs | 51 ++++++++++++++++++++++++++++------- 4 files changed, 98 insertions(+), 20 deletions(-) diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index f7b969b884..8f38ef6dcd 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -247,7 +247,14 @@ impl aml::Handler for AmlPhysMemHandler { } fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { - log::error!("read pci u8 {:X}, {:X}, {:X}, {:X}, {:X}", _segment, _bus, _device, _function, _offset); + log::error!( + "read pci u8 {:X}, {:X}, {:X}, {:X}, {:X}", + _segment, + _bus, + _device, + _function, + _offset + ); 0 } @@ -259,7 +266,14 @@ impl aml::Handler for AmlPhysMemHandler { _function: u8, _offset: u16, ) -> u16 { - log::error!("read pci u16 {:X}, {:X}, {:X}, {:X}, {:X}", _segment, _bus, _device, _function, _offset); + log::error!( + "read pci u16 {:X}, {:X}, {:X}, {:X}, {:X}", + _segment, + _bus, + _device, + _function, + _offset + ); 0 } @@ -271,7 +285,14 @@ impl aml::Handler for AmlPhysMemHandler { _function: u8, _offset: u16, ) -> u32 { - log::error!("read pci u32 {:X}, {:X}, {:X}, {:X}, {:X}", _segment, _bus, _device, _function, _offset); + log::error!( + "read pci u32 {:X}, {:X}, {:X}, {:X}, {:X}", + _segment, + _bus, + _device, + _function, + _offset + ); 0 } @@ -284,7 +305,15 @@ impl aml::Handler for AmlPhysMemHandler { _offset: u16, _value: u8, ) { - log::error!("write pci u8 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", _segment, _bus, _device, _function, _offset, _value); + log::error!( + "write pci u8 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", + _segment, + _bus, + _device, + _function, + _offset, + _value + ); } fn write_pci_u16( &self, @@ -295,7 +324,15 @@ impl aml::Handler for AmlPhysMemHandler { _offset: u16, _value: u16, ) { - log::error!("write pci u16 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", _segment, _bus, _device, _function, _offset, _value); + log::error!( + "write pci u16 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", + _segment, + _bus, + _device, + _function, + _offset, + _value + ); } fn write_pci_u32( &self, @@ -306,7 +343,15 @@ impl aml::Handler for AmlPhysMemHandler { _offset: u16, _value: u32, ) { - log::error!("write pci u32 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", _segment, _bus, _device, _function, _offset, _value); + log::error!( + "write pci u32 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", + _segment, + _bus, + _device, + _function, + _offset, + _value + ); } } diff --git a/amlserde/src/lib.rs b/amlserde/src/lib.rs index 1336f5778d..a7ea76b9de 100644 --- a/amlserde/src/lib.rs +++ b/amlserde/src/lib.rs @@ -211,7 +211,9 @@ impl AmlSerdeValue { serialize: flags.serialize(), sync_level: flags.sync_level(), }, - AmlValue::Buffer(buffer_data) => AmlSerdeValue::Buffer({ buffer_data.lock().to_owned() }), + AmlValue::Buffer(buffer_data) => { + AmlSerdeValue::Buffer({ buffer_data.lock().to_owned() }) + } AmlValue::BufferField { buffer_data, offset, @@ -219,7 +221,7 @@ impl AmlSerdeValue { } => AmlSerdeValue::BufferField { offset: offset.to_owned(), length: length.to_owned(), - data: { buffer_data.lock().to_owned() } + data: { buffer_data.lock().to_owned() }, }, AmlValue::Processor { id, diff --git a/hwd/src/main.rs b/hwd/src/main.rs index 7b50c43153..45710fb8cc 100644 --- a/hwd/src/main.rs +++ b/hwd/src/main.rs @@ -18,9 +18,7 @@ fn acpi() -> Result<(), Box> { let vendor_3 = (((vendor_rev >> 0) & 0x1f) as u8 + 64) as char; format!("{}{}{}{:04X}", vendor_1, vendor_2, vendor_3, device) } - AmlSerdeValue::String(string) => { - string - }, + AmlSerdeValue::String(string) => string, _ => { log::warn!("{}: unsupported value {:x?}", name, value); continue; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 1c32b122c0..6ba32fc6ea 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -847,36 +847,69 @@ impl Xhci { pub async fn detach_device(&self, port_number: usize) -> Result<()> { if let Some(children) = self.drivers.remove(&port_number) { for mut child in children { - info!("killing driver process {} for port {}", child.id(), port_number); + info!( + "killing driver process {} for port {}", + child.id(), + port_number + ); match child.kill() { Ok(()) => { - info!("killed driver process {} for port {}", child.id(), port_number); + info!( + "killed driver process {} for port {}", + child.id(), + port_number + ); match child.try_wait() { Ok(status_opt) => match status_opt { Some(status) => { - info!("driver process {} for port {} exited with status {}", child.id(), port_number, status); - }, + info!( + "driver process {} for port {} exited with status {}", + child.id(), + port_number, + status + ); + } None => { //TODO: kill harder - info!("driver process {} for port {} still running", child.id(), port_number); + info!( + "driver process {} for port {} still running", + child.id(), + port_number + ); } }, Err(err) => { - info!("failed to wait for the driver process {} for port {}: {}", child.id(), port_number, err); + info!( + "failed to wait for the driver process {} for port {}: {}", + child.id(), + port_number, + err + ); } } } Err(err) => { - warn!("failed to kill the driver process {} for port {}: {}", child.id(), port_number, err); + warn!( + "failed to kill the driver process {} for port {}: {}", + child.id(), + port_number, + err + ); } } } } if let Some(state) = self.port_states.remove(&port_number) { - info!("disabling port slot {} for port {}", state.slot, port_number); + info!( + "disabling port slot {} for port {}", + state.slot, port_number + ); let result = self.disable_port_slot(state.slot).await; - info!("disabled port slot {} for port {} with result: {:?}", state.slot, port_number, result); + info!( + "disabled port slot {} for port {} with result: {:?}", + state.slot, port_number, result + ); result } else { From e5e753a426e9d9df4eb4bb7ca168e0adb7a05330 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Sat, 16 Nov 2024 09:16:00 +0300 Subject: [PATCH 1005/1301] Sync up with changes to kernel's phandle irq scheme --- pcid/src/cfg_access/mod.rs | 8 +++++--- pcid/src/driver_interface/mod.rs | 33 +++++++++++++++++++++++--------- pcid/src/main.rs | 13 +++++++------ 3 files changed, 36 insertions(+), 18 deletions(-) diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index 72c0c6b001..a8ea2b16e8 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -15,6 +15,7 @@ pub struct InterruptMap { pub interrupt: u32, pub parent_phandle: u32, pub parent_interrupt: [u32; 3], + pub parent_interrupt_cells: usize, } // https://elinux.org/Device_Tree_Usage has a lot of useful information @@ -55,11 +56,11 @@ fn locate_ecam_dtb( let mut interrupt_map = Vec::::new(); while let Ok([addr1, addr2, addr3, int1, phandle]) = interrupt_map_data.next_chunk::<5>() { let parent = dt.find_phandle(phandle).unwrap(); - let interrupt_cells = parent.interrupt_cells().unwrap(); - let parent_interrupt = match interrupt_cells { + let parent_interrupt_cells = parent.interrupt_cells().unwrap(); + let parent_interrupt = match parent_interrupt_cells { 1 if let Some(a) = interrupt_map_data.next() => [a, 0, 0], 2 if let Ok([a, b]) = interrupt_map_data.next_chunk::<2>() => [a, b, 0], - 2 if let Ok([a, b, c]) = interrupt_map_data.next_chunk::<3>() => [a, b, c], + 3 if let Ok([a, b, c]) = interrupt_map_data.next_chunk::<3>() => [a, b, c], _ => break, }; interrupt_map.push(InterruptMap { @@ -67,6 +68,7 @@ fn locate_ecam_dtb( interrupt: int1, parent_phandle: phandle, parent_interrupt, + parent_interrupt_cells, }); } diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 2b103353c5..183f5036c3 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -25,18 +25,26 @@ pub mod msi; pub struct LegacyInterruptLine { #[doc(hidden)] pub irq: u8, - pub phandled: Option<(u32, [u32; 3])>, + pub phandled: Option<(u32, [u32; 3], usize)>, } impl LegacyInterruptLine { /// Get an IRQ handle for this interrupt line. pub fn irq_handle(self, driver: &str) -> File { - if let Some((phandle, addr)) = self.phandled { - File::create(format!( - "/scheme/irq/phandle-{}/{},{},{}", - phandle, addr[0], addr[1], addr[2] - )) - .unwrap_or_else(|err| panic!("{driver}: failed to open IRQ file: {err}")) + if let Some((phandle, addr, cells)) = self.phandled { + let path = match cells { + 1 => format!("/scheme/irq/phandle-{}/{}", phandle, addr[0]), + 2 => format!("/scheme/irq/phandle-{}/{},{}", phandle, addr[0], addr[1]), + 3 => format!( + "/scheme/irq/phandle-{}/{},{},{}", + phandle, addr[0], addr[1], addr[2] + ), + _ => panic!( + "unexpected number of IRQ description cells for phandle {phandle}: {cells}" + ), + }; + File::create(path) + .unwrap_or_else(|err| panic!("{driver}: failed to open IRQ file: {err}")) } else { File::open(format!("/scheme/irq/{}", self.irq)) .unwrap_or_else(|err| panic!("{driver}: failed to open IRQ file: {err}")) @@ -46,8 +54,15 @@ impl LegacyInterruptLine { impl fmt::Display for LegacyInterruptLine { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some((phandle, addr)) = self.phandled { - write!(f, "(phandle {}, {:?})", phandle, addr) + if let Some((phandle, addr, cells)) = self.phandled { + match cells { + 1 => write!(f, "(phandle {}, {:?})", phandle, addr[0]), + 2 => write!(f, "(phandle {}, {:?},{:?})", phandle, addr[0], addr[1]), + 3 => write!(f, "(phandle {}, {:?})", phandle, addr), + _ => panic!( + "unexpected number of IRQ description cells for phandle {phandle}: {cells}" + ), + } } else { write!(f, "{}", self.irq) } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 2b7f120b1d..231463df73 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -136,7 +136,7 @@ fn handle_parsed_header( } }; - let mut phandled: Option<(u32, [u32; 3])> = None; + let mut phandled: Option<(u32, [u32; 3], usize)> = None; if legacy_interrupt_enabled { let pci_address = endpoint_header.header().address(); let dt_address = ((pci_address.bus() as u32) << 16) @@ -154,11 +154,12 @@ fn handle_parsed_header( .iter() .find(|x| x.addr == addr[0..3] && x.interrupt == addr[3]); if let Some(mapping) = mapping { - debug!( - "found mapping: addr={:?} => (phandle={} irq={:?})", - addr, mapping.parent_phandle, mapping.parent_interrupt - ); - phandled = Some((mapping.parent_phandle, mapping.parent_interrupt)); + phandled = Some(( + mapping.parent_phandle, + mapping.parent_interrupt, + mapping.parent_interrupt_cells, + )); + debug!("found mapping: addr={:?} => {:?}", addr, phandled); } } From 63b1d2cf8aaacead921e67a6174dfa4bbcf4a608 Mon Sep 17 00:00:00 2001 From: Andrey Turkin Date: Wed, 18 Dec 2024 20:16:59 +0300 Subject: [PATCH 1006/1301] bcm2835-sdhcid: remap mmio range as instructed by DTB --- Cargo.lock | 9 +++++++-- storage/bcm2835-sdhcid/Cargo.toml | 2 +- storage/bcm2835-sdhcid/src/main.rs | 20 +++++++++++++++++--- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 14a3c617fd..6954ea031f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -177,7 +177,7 @@ version = "0.1.0" dependencies = [ "common", "driver-block", - "fdt", + "fdt 0.2.0-alpha1", "libredox", "redox-daemon", "redox-scheme", @@ -433,6 +433,11 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784a4df722dc6267a04af36895398f59d21d07dce47232adf31ec0ff2fa45e67" +[[package]] +name = "fdt" +version = "0.2.0-alpha1" +source = "git+https://github.com/repnop/fdt.git#059bb2383873f8001959456e36ec123228f67642" + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -947,7 +952,7 @@ dependencies = [ "bit_field", "bitflags 1.3.2", "common", - "fdt", + "fdt 0.1.5", "libc", "libredox", "log", diff --git a/storage/bcm2835-sdhcid/Cargo.toml b/storage/bcm2835-sdhcid/Cargo.toml index df313e6a93..ac42319149 100644 --- a/storage/bcm2835-sdhcid/Cargo.toml +++ b/storage/bcm2835-sdhcid/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -fdt = "0.1.5" +fdt = { git = "https://github.com/repnop/fdt.git" } common = { path = "../../common" } driver-block = { path = "../driver-block" } diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index 878604a0a4..c3a5bec63d 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -1,3 +1,5 @@ +#![feature(let_chains)] + use std::{ fs::File, io::{Read, Write}, @@ -50,17 +52,29 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let fdt = Fdt::new(&dtb_data).unwrap(); println!("DTB model = {}", fdt.root().model()); - let with = ["brcm,bcm2835-sdhcid"]; + let with = ["brcm,bcm2835-sdhci"]; let compat_node = fdt.find_compatible(&with).unwrap(); let reg = compat_node.reg().unwrap().next().unwrap(); let reg_size = reg.size.unwrap(); + let mut reg_addr = reg.starting_address as usize; println!( "DeviceMemory start = 0x{:08x}, size = 0x{:08x}", - reg.starting_address as usize, reg_size + reg_addr, reg_size ); + if let Some(mut ranges) = fdt.find_node("/soc").and_then(|f| f.ranges()) { + let range = ranges + .find(|f| f.child_bus_address <= reg_addr && reg_addr - f.child_bus_address < f.size) + .expect("Couldn't find device range in /soc/@ranges"); + reg_addr = range.parent_bus_address + (reg_addr - range.child_bus_address); + println!( + "DeviceMemory remapped onto CPU address space: start = 0x{:08x}, size = 0x{:08x}", + reg_addr, reg_size + ); + } + let addr = unsafe { common::physmap( - reg.starting_address as usize, + reg_addr, reg_size, common::Prot::RW, common::MemoryType::DeviceMemory, From 0b2111b029f90b7045b9a18e5d035c32a049bffd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 14:36:11 +0100 Subject: [PATCH 1007/1301] Port inputd to redox-scheme --- Cargo.lock | 1 + inputd/Cargo.toml | 1 + inputd/src/main.rs | 61 +++++++++++++++++++++++++++++----------------- 3 files changed, 41 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6954ea031f..a9a546933b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -677,6 +677,7 @@ dependencies = [ "log", "orbclient", "redox-daemon", + "redox-scheme", "redox_syscall", "spin", ] diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index 0ba28069f3..fa8ae45fce 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -14,3 +14,4 @@ spin = "0.9.8" libredox = "0.1.3" common = { path = "../common" } +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } diff --git a/inputd/src/main.rs b/inputd/src/main.rs index be8ae15f6b..446a68af7a 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -13,17 +13,17 @@ use std::collections::BTreeMap; use std::fs::File; -use std::io::{Read, Write}; use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use inputd::{Cmd, VtActivate}; +use redox_scheme::{RequestKind, SchemeMut, SignalBehavior, Socket, V2}; use spin::Mutex; use orbclient::{Event, EventOption}; -use syscall::{Error as SysError, EventFlags, Packet, SchemeMut, EINVAL}; +use syscall::{Error as SysError, EventFlags, EINVAL}; enum Handle { Producer, @@ -89,6 +89,8 @@ struct InputScheme { active_vt: Option>, todo: Vec, + + has_new_events: bool, } impl InputScheme { @@ -103,6 +105,8 @@ impl InputScheme { active_vt: None, todo: vec![], + + has_new_events: false, } } } @@ -162,7 +166,13 @@ impl SchemeMut for InputScheme { } } - fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { + fn read( + &mut self, + id: usize, + buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + ) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; match handle { @@ -188,7 +198,15 @@ impl SchemeMut for InputScheme { } } - fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { + fn write( + &mut self, + id: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + ) -> syscall::Result { + self.has_new_events = true; + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; match handle { @@ -351,24 +369,29 @@ impl SchemeMut for InputScheme { fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { // Create the ":input" scheme. - let mut socket_file = File::create(":input")?; + let socket_file: Socket = Socket::create("input")?; let mut scheme = InputScheme::new(); deamon.ready().unwrap(); loop { - let mut should_handle = false; - let mut packet = Packet::default(); - socket_file.read(&mut packet)?; + scheme.has_new_events = false; + let Some(request) = socket_file.next_request(SignalBehavior::Restart)? else { + // Scheme likely got unmounted + return Ok(()); + }; - // The producer has written to the channel; the consumers should be notified. - if packet.a == syscall::SYS_WRITE { - should_handle = true; + match request.kind() { + RequestKind::Call(call_request) => { + socket_file.write_response( + call_request.handle_scheme_mut(&mut scheme), + SignalBehavior::Restart, + )?; + } + RequestKind::Cancellation(_cancellation_request) => {}, + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), } - scheme.handle(&mut packet); - socket_file.write(&packet)?; - while let Some(cmd) = scheme.todo.pop() { let vt = scheme.vts.get_mut(&cmd.vt).unwrap(); let mut vt_inner = vt.inner().lock(); @@ -383,7 +406,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { scheme.active_vt = Some(vt.clone()); } - if !should_handle { + if !scheme.has_new_events { continue; } @@ -408,13 +431,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } // Notify the consumer that we have some events to read. Yum yum. - let mut event_packet = Packet::default(); - event_packet.a = syscall::SYS_FEVENT; - event_packet.b = *id; - event_packet.c = EventFlags::EVENT_READ.bits(); - // Specifies the number of bytes that can be read non-blocking. - event_packet.d = pending.len(); - socket_file.write(&event_packet)?; + socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?; *notified = true; } From f4193c688633bad33a6f9c1a62528de4256a868c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 15:38:13 +0100 Subject: [PATCH 1008/1301] inputd: Avoid panic when client tried to perform invalid operation --- inputd/src/main.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 446a68af7a..69f7c9b7a6 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -194,7 +194,10 @@ impl SchemeMut for InputScheme { Ok(vt) } - _ => unreachable!(), + Handle::Producer => { + log::error!("inputd: producer tried to read"); + return Err(SysError::new(EINVAL)); + } } } @@ -211,7 +214,10 @@ impl SchemeMut for InputScheme { match handle { Handle::Device { device } => { - assert!(buf.len() == core::mem::size_of::()); + if buf.len() != core::mem::size_of::() { + log::error!("inputd: device tried to write incorrectly sized command"); + return Err(SysError::new(EINVAL)); + } // SAFETY: We have verified the size of the buffer above. let cmd = unsafe { &*buf.as_ptr().cast::() }; @@ -222,8 +228,11 @@ impl SchemeMut for InputScheme { return Ok(buf.len()); } - Handle::Consumer { .. } => unreachable!(), - _ => {} + Handle::Consumer { .. } => { + log::error!("inputd: consumer tried to write"); + return Err(SysError::new(EINVAL)); + } + Handle::Producer => {} } if buf.len() == 1 && buf[0] > 0xf4 { @@ -355,11 +364,13 @@ impl SchemeMut for InputScheme { } => { *events = flags; *notified = false; + Ok(EventFlags::empty()) + } + Handle::Producer | Handle::Device { .. } => { + log::error!("inputd: producer or device tried to use an event queue"); + Err(SysError::new(EINVAL)) } - _ => unreachable!(), } - - Ok(EventFlags::empty()) } fn close(&mut self, _id: usize) -> syscall::Result { @@ -388,7 +399,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { SignalBehavior::Restart, )?; } - RequestKind::Cancellation(_cancellation_request) => {}, + RequestKind::Cancellation(_cancellation_request) => {} RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), } From 6a1cb33105253828c25a028710370bc20253ff8d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 15:52:36 +0100 Subject: [PATCH 1009/1301] inputd: Misc changes --- inputd/src/main.rs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 69f7c9b7a6..0062e68b2b 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -59,7 +59,7 @@ struct Vt { } impl Vt { - pub fn new(display: D, index: usize) -> Arc + fn new(display: D, index: usize) -> Arc where D: Into, { @@ -70,7 +70,7 @@ impl Vt { }) } - pub fn inner(&self) -> &Mutex { + fn inner(&self) -> &Mutex { self.inner.call_once(|| { let handle_file = File::open(format!("/scheme/{}/handle", self.display)).unwrap(); Mutex::new(VtInner { handle_file }) @@ -88,13 +88,12 @@ struct InputScheme { super_key: bool, active_vt: Option>, - todo: Vec, - + pending_activate: Option, has_new_events: bool, } impl InputScheme { - pub fn new() -> Self { + fn new() -> Self { Self { next_id: AtomicUsize::new(0), next_vt_id: AtomicUsize::new(1), @@ -104,8 +103,7 @@ impl InputScheme { super_key: false, active_vt: None, - todo: vec![], - + pending_activate: None, has_new_events: false, } } @@ -223,7 +221,7 @@ impl SchemeMut for InputScheme { let cmd = unsafe { &*buf.as_ptr().cast::() }; self.vts.insert(cmd.vt, Vt::new(device.clone(), cmd.vt)); - self.todo.push(cmd.clone()); + self.pending_activate = Some(cmd.clone()); return Ok(buf.len()); } @@ -403,7 +401,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), } - while let Some(cmd) = scheme.todo.pop() { + if let Some(cmd) = scheme.pending_activate.take() { let vt = scheme.vts.get_mut(&cmd.vt).unwrap(); let mut vt_inner = vt.inner().lock(); @@ -455,7 +453,7 @@ fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { unreachable!(); } -pub fn main() { +fn main() { common::setup_logging( "misc", "inputd", From 08f619bc229e954a0bb331121bbf8e9677bf7830 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 15:58:07 +0100 Subject: [PATCH 1010/1301] inputd: Remove usage of Arc for Vt Storing the vt index instead of a direct reference to the vt is just as easy. --- inputd/src/main.rs | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 0062e68b2b..928b8531e8 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -15,7 +15,6 @@ use std::collections::BTreeMap; use std::fs::File; use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Arc; use inputd::{Cmd, VtActivate}; @@ -59,15 +58,12 @@ struct Vt { } impl Vt { - fn new(display: D, index: usize) -> Arc - where - D: Into, - { - Arc::new(Self { + fn new(display: impl Into, index: usize) -> Self { + Self { display: display.into(), inner: spin::Once::new(), index, - }) + } } fn inner(&self) -> &Mutex { @@ -84,9 +80,9 @@ struct InputScheme { next_id: AtomicUsize, next_vt_id: AtomicUsize, - vts: BTreeMap>, + vts: BTreeMap, super_key: bool, - active_vt: Option>, + active_vt: Option, pending_activate: Option, has_new_events: bool, @@ -272,7 +268,7 @@ impl SchemeMut for InputScheme { }, EventOption::Resize(resize_event) => { - let active_vt = self.active_vt.as_ref().unwrap(); + let active_vt = &self.vts[&self.active_vt.unwrap()]; let mut vt_inner = active_vt.inner().lock(); inputd::send_comand( @@ -292,13 +288,13 @@ impl SchemeMut for InputScheme { } if let Some(new_active) = new_active_opt { - if new_active == self.active_vt.as_ref().unwrap().index { + if new_active == self.vts[&self.active_vt.unwrap()].index { continue 'out; } - if let Some(new_active) = self.vts.get(&new_active).cloned() { + if let Some(new_active) = self.vts.get(&new_active) { { - let active_vt = self.active_vt.as_ref().unwrap(); + let active_vt = &self.vts[&self.active_vt.unwrap()]; let mut vt_inner = active_vt.inner().lock(); inputd::send_comand( @@ -315,7 +311,7 @@ impl SchemeMut for InputScheme { vt: new_active.index, }, )?; - self.active_vt = Some(new_active.clone()); + self.active_vt = Some(new_active.index); } else { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); } @@ -324,7 +320,7 @@ impl SchemeMut for InputScheme { assert!(handle.is_producer()); - let active_vt = self.active_vt.as_ref().unwrap(); + let active_vt = self.active_vt.unwrap(); for handle in self.handles.values_mut() { match handle { Handle::Consumer { @@ -333,7 +329,7 @@ impl SchemeMut for InputScheme { vt, .. } => { - if *vt != active_vt.index { + if *vt != active_vt { continue; } @@ -412,7 +408,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { log::error!("inputd: failed to activate VT #{}: {err}", vt.index) } - scheme.active_vt = Some(vt.clone()); + scheme.active_vt = Some(vt.index); } if !scheme.has_new_events { @@ -431,11 +427,11 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { continue; } - let active_vt = scheme.active_vt.as_ref().unwrap(); + let active_vt = scheme.active_vt.unwrap(); // The activate VT is not the same as the VT that the consumer is listening to // for events. - if active_vt.index != *vt { + if active_vt != *vt { continue; } From cf84e712200f1586cb9c30f00c3827530c94a26d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 16:00:34 +0100 Subject: [PATCH 1011/1301] inputd: Use std's concurrency primitives instead of spin --- Cargo.lock | 1 - inputd/Cargo.toml | 1 - inputd/src/main.rs | 17 +++++++++-------- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a9a546933b..27fb0ab0b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -679,7 +679,6 @@ dependencies = [ "redox-daemon", "redox-scheme", "redox_syscall", - "spin", ] [[package]] diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index fa8ae45fce..d45b055cb1 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -10,7 +10,6 @@ log = "0.4.19" redox-daemon = "0.1.2" redox_syscall = "0.5" orbclient = "0.3.27" -spin = "0.9.8" libredox = "0.1.3" common = { path = "../common" } diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 928b8531e8..78b97f7f1a 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -11,15 +11,16 @@ //! Read events from `input:consumer`. Optionally, set the `EVENT_READ` flag to be notified when //! events are available. +use std::cell::OnceCell; use std::collections::BTreeMap; use std::fs::File; use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Mutex; use inputd::{Cmd, VtActivate}; use redox_scheme::{RequestKind, SchemeMut, SignalBehavior, Socket, V2}; -use spin::Mutex; use orbclient::{Event, EventOption}; use syscall::{Error as SysError, EventFlags, EINVAL}; @@ -54,20 +55,20 @@ struct VtInner { struct Vt { display: String, index: usize, - inner: spin::Once>, + inner: OnceCell>, } impl Vt { fn new(display: impl Into, index: usize) -> Self { Self { display: display.into(), - inner: spin::Once::new(), + inner: OnceCell::new(), index, } } fn inner(&self) -> &Mutex { - self.inner.call_once(|| { + self.inner.get_or_init(|| { let handle_file = File::open(format!("/scheme/{}/handle", self.display)).unwrap(); Mutex::new(VtInner { handle_file }) }) @@ -269,7 +270,7 @@ impl SchemeMut for InputScheme { EventOption::Resize(resize_event) => { let active_vt = &self.vts[&self.active_vt.unwrap()]; - let mut vt_inner = active_vt.inner().lock(); + let mut vt_inner = active_vt.inner().lock().unwrap(); inputd::send_comand( &mut vt_inner.handle_file, @@ -295,7 +296,7 @@ impl SchemeMut for InputScheme { if let Some(new_active) = self.vts.get(&new_active) { { let active_vt = &self.vts[&self.active_vt.unwrap()]; - let mut vt_inner = active_vt.inner().lock(); + let mut vt_inner = active_vt.inner().lock().unwrap(); inputd::send_comand( &mut vt_inner.handle_file, @@ -303,7 +304,7 @@ impl SchemeMut for InputScheme { )?; } - let mut vt_inner = new_active.inner().lock(); + let mut vt_inner = new_active.inner().lock().unwrap(); inputd::send_comand( &mut vt_inner.handle_file, @@ -399,7 +400,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { if let Some(cmd) = scheme.pending_activate.take() { let vt = scheme.vts.get_mut(&cmd.vt).unwrap(); - let mut vt_inner = vt.inner().lock(); + let mut vt_inner = vt.inner().lock().unwrap(); // Failing to activate a VT is not a fatal error. if let Err(err) = From 3c00151d49db65fc9f4b70143ff44e3a59197dea Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 16:15:19 +0100 Subject: [PATCH 1012/1301] inputd: Remove the vt handle mutex --- inputd/src/main.rs | 79 ++++++++++++++++------------------------------ 1 file changed, 27 insertions(+), 52 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 78b97f7f1a..8aa562a888 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -11,12 +11,10 @@ //! Read events from `input:consumer`. Optionally, set the `EVENT_READ` flag to be notified when //! events are available. -use std::cell::OnceCell; use std::collections::BTreeMap; use std::fs::File; use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Mutex; use inputd::{Cmd, VtActivate}; @@ -44,34 +42,29 @@ impl Handle { } } -/// VT Inner State -/// -/// This is *required* to be lazily initialized since opening the handle to the display -/// requires the system call to return first. Otherwise, it will block indefinitely. -struct VtInner { - handle_file: File, -} - struct Vt { display: String, index: usize, - inner: OnceCell>, + + /// This is *required* to be lazily initialized since opening the handle to the display + /// requires the system call to return first. Otherwise, it will block indefinitely. + handle_file: Option, } impl Vt { fn new(display: impl Into, index: usize) -> Self { Self { display: display.into(), - inner: OnceCell::new(), + handle_file: None, index, } } - fn inner(&self) -> &Mutex { - self.inner.get_or_init(|| { - let handle_file = File::open(format!("/scheme/{}/handle", self.display)).unwrap(); - Mutex::new(VtInner { handle_file }) - }) + fn send_command(&mut self, cmd: Cmd) -> Result<(), libredox::error::Error> { + let handle_file = self + .handle_file + .get_or_insert_with(|| File::open(format!("/scheme/{}/handle", self.display)).unwrap()); + inputd::send_comand(handle_file, cmd) } } @@ -269,20 +262,15 @@ impl SchemeMut for InputScheme { }, EventOption::Resize(resize_event) => { - let active_vt = &self.vts[&self.active_vt.unwrap()]; - let mut vt_inner = active_vt.inner().lock().unwrap(); + let active_vt = self.vts.get_mut(&self.active_vt.unwrap()).unwrap(); + active_vt.send_command(Cmd::Resize { + vt: active_vt.index, + width: resize_event.width, + height: resize_event.height, - inputd::send_comand( - &mut vt_inner.handle_file, - Cmd::Resize { - vt: active_vt.index, - width: resize_event.width, - height: resize_event.height, - - // TODO(andypython): Figure out how to get the stride. - stride: resize_event.width, - }, - )?; + // TODO(andypython): Figure out how to get the stride. + stride: resize_event.width, + })?; } _ => continue, @@ -293,25 +281,16 @@ impl SchemeMut for InputScheme { continue 'out; } - if let Some(new_active) = self.vts.get(&new_active) { - { - let active_vt = &self.vts[&self.active_vt.unwrap()]; - let mut vt_inner = active_vt.inner().lock().unwrap(); + if self.vts.contains_key(&new_active) { + let active_vt = self.vts.get_mut(&self.active_vt.unwrap()).unwrap(); - inputd::send_comand( - &mut vt_inner.handle_file, - Cmd::Deactivate(active_vt.index), - )?; - } + active_vt.send_command(Cmd::Deactivate(active_vt.index))?; + } - let mut vt_inner = new_active.inner().lock().unwrap(); - - inputd::send_comand( - &mut vt_inner.handle_file, - Cmd::Activate { - vt: new_active.index, - }, - )?; + if let Some(new_active) = self.vts.get_mut(&new_active) { + new_active.send_command(Cmd::Activate { + vt: new_active.index, + })?; self.active_vt = Some(new_active.index); } else { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); @@ -400,12 +379,8 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { if let Some(cmd) = scheme.pending_activate.take() { let vt = scheme.vts.get_mut(&cmd.vt).unwrap(); - let mut vt_inner = vt.inner().lock().unwrap(); - // Failing to activate a VT is not a fatal error. - if let Err(err) = - inputd::send_comand(&mut vt_inner.handle_file, Cmd::Activate { vt: vt.index }) - { + if let Err(err) = vt.send_command(Cmd::Activate { vt: vt.index }) { log::error!("inputd: failed to activate VT #{}: {err}", vt.index) } From 7565720f34a417d6badf241be1ccb9d09d91ebf3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 19:24:29 +0100 Subject: [PATCH 1013/1301] vesad: Migrate to redox-scheme --- Cargo.lock | 1 + graphics/vesad/Cargo.toml | 1 + graphics/vesad/src/main.rs | 90 +++++++++++++------------------ graphics/vesad/src/scheme.rs | 102 ++++++++++++++++++++--------------- graphics/vesad/src/screen.rs | 8 +-- 5 files changed, 100 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 27fb0ab0b9..92d3f8964b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1680,6 +1680,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", + "redox-scheme", "redox_syscall", ] diff --git a/graphics/vesad/Cargo.toml b/graphics/vesad/Cargo.toml index 87f9083af7..0361c8bf7d 100644 --- a/graphics/vesad/Cargo.toml +++ b/graphics/vesad/Cargo.toml @@ -12,6 +12,7 @@ redox-daemon = "0.1" common = { path = "../../common" } inputd = { path = "../../inputd" } libredox = "0.1.3" +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } [features] default = [] diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 8245a5c2b5..9b01e97624 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -2,10 +2,10 @@ extern crate orbclient; extern crate syscall; +use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; use std::env; use std::fs::File; -use std::io::{Read, Write}; -use syscall::{Packet, SchemeMut, EVENT_READ}; +use syscall::EVENT_READ; use crate::{ framebuffer::FrameBuffer, @@ -79,7 +79,8 @@ fn main() { .expect("failed to create daemon"); } fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[()]) -> ! { - let mut socket = File::create(":display.vesa").expect("vesad: failed to create display scheme"); + let socket: Socket = + Socket::create("display.vesa").expect("vesad: failed to create display scheme"); let mut scheme = DisplayScheme::new(framebuffers, &spec); @@ -93,39 +94,37 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( let mut blocked = Vec::new(); loop { - let mut packet = Packet::default(); - if socket - .read(&mut packet) + let Some(request) = socket + .next_request(SignalBehavior::Restart) .expect("vesad: failed to read display scheme") - == 0 - { - //TODO: Handle blocked - break; + else { + // Scheme likely got unmounted + std::process::exit(0); + }; + + match request.kind() { + RequestKind::Call(call_request) => { + if let Some(resp) = call_request.handle_scheme_block_mut(&mut scheme) { + socket + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + } else { + blocked.push(call_request); + } + } + RequestKind::Cancellation(_cancellation_request) => {} + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), } - // If it is a read packet, and there is no data, block it. Otherwise, handle packet - if packet.a == syscall::number::SYS_READ - && packet.d > 0 - && scheme.can_read(packet.b).is_none() - { - blocked.push(packet); - } else { - scheme.handle(&mut packet); - socket - .write(&packet) - .expect("vesad: failed to write display scheme"); - } - - // If there are blocked readers, and data is available, handle them + // If there are blocked readers, try to handle them. { let mut i = 0; while i < blocked.len() { - if scheme.can_read(blocked[i].b).is_some() { - let mut packet = blocked.remove(i); - scheme.handle(&mut packet); + if let Some(resp) = blocked[i].handle_scheme_block_mut(&mut scheme) { socket - .write(&packet) + .write_response(resp, SignalBehavior::Restart) .expect("vesad: failed to write display scheme"); + blocked.remove(i); } else { i += 1; } @@ -133,45 +132,28 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( } for (handle_id, handle) in scheme.handles.iter_mut() { - if !handle.events.contains(EVENT_READ) { + if handle.notified_read || !handle.events.contains(EVENT_READ) { continue; } - // Can't use scheme.can_read() because we borrow handles as mutable. - // (and because it'd treat O_NONBLOCK sockets differently) - let count = if let HandleKind::Screen(vt_i, screen_i) = handle.kind { + let can_read = if let HandleKind::Screen(vt_i, screen_i) = handle.kind { scheme .vts .get(&vt_i) .and_then(|screens| screens.get(&screen_i)) - .and_then(|screen| screen.can_read()) - .unwrap_or(0) + .map_or(false, |screen| screen.can_read()) } else { - 0 + false }; - if count > 0 { - if !handle.notified_read { - handle.notified_read = true; - let event_packet = Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: EVENT_READ.bits(), - d: count, - }; - - socket - .write(&event_packet) - .expect("vesad: failed to write display event"); - } + if can_read { + handle.notified_read = true; + socket + .post_fevent(*handle_id, EVENT_READ.bits()) + .expect("vesad: failed to write display event"); } else { handle.notified_read = false; } } } - std::process::exit(0); } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 1d4f7cb238..65baf8dace 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -1,7 +1,8 @@ use std::collections::BTreeMap; use std::str; -use syscall::{Error, EventFlags, MapFlags, Result, SchemeMut, EBADF, EINVAL, ENOENT, O_NONBLOCK}; +use redox_scheme::SchemeBlockMut; +use syscall::{Error, EventFlags, MapFlags, Result, EBADF, EINVAL, ENOENT, O_NONBLOCK}; use crate::{framebuffer::FrameBuffer, screen::GraphicScreen}; @@ -59,26 +60,6 @@ impl DisplayScheme { } } - pub fn can_read(&self, id: usize) -> Option { - if let Some(handle) = self.handles.get(&id) { - if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - if let Some(screens) = self.vts.get(&vt_i) { - if let Some(screen) = screens.get(&screen_i) { - screen - .can_read() - .or(if handle.flags & O_NONBLOCK == O_NONBLOCK { - Some(0) - } else { - None - }); - } - } - } - } - - Some(0) - } - fn resize(&mut self, width: usize, height: usize, stride: usize) { //TODO: support resizing other outputs? let fb_i = 0; @@ -105,8 +86,14 @@ impl DisplayScheme { } } -impl SchemeMut for DisplayScheme { - fn open(&mut self, path_str: &str, flags: usize, _uid: u32, _gid: u32) -> Result { +impl SchemeBlockMut for DisplayScheme { + fn open( + &mut self, + path_str: &str, + flags: usize, + _uid: u32, + _gid: u32, + ) -> Result> { if path_str == "handle" { let id = self.next_id; self.next_id += 1; @@ -119,7 +106,7 @@ impl SchemeMut for DisplayScheme { notified_read: false, }, ); - return Ok(id); + return Ok(Some(id)); } let mut parts = path_str.split('/'); @@ -141,7 +128,7 @@ impl SchemeMut for DisplayScheme { }, ); - Ok(id) + Ok(Some(id)) } else { Err(Error::new(ENOENT)) } @@ -150,7 +137,7 @@ impl SchemeMut for DisplayScheme { } } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result { + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { if !buf.is_empty() { return Err(Error::new(EINVAL)); } @@ -166,23 +153,27 @@ impl SchemeMut for DisplayScheme { self.handles.insert(new_id, handle.clone()); - Ok(new_id) + Ok(Some(new_id)) } - fn fevent(&mut self, id: usize, flags: syscall::EventFlags) -> Result { + fn fevent( + &mut self, + id: usize, + flags: syscall::EventFlags, + ) -> Result> { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; handle.notified_read = false; if let HandleKind::Screen(_vt_i, _screen_i) = handle.kind { handle.events = flags; - Ok(syscall::EventFlags::empty()) + Ok(Some(syscall::EventFlags::empty())) } else { Err(Error::new(EBADF)) } } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; let path_str = match handle.kind { @@ -217,10 +208,10 @@ impl SchemeMut for DisplayScheme { i += 1; } - Ok(i) + Ok(Some(i)) } - fn fsync(&mut self, id: usize) -> Result { + fn fsync(&mut self, id: usize) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(vt_i, screen_i) = handle.kind { @@ -229,7 +220,7 @@ impl SchemeMut for DisplayScheme { if vt_i == self.active { screen.sync(&mut self.framebuffers[screen_i.0]); } - return Ok(0); + return Ok(Some(0)); } } } @@ -237,13 +228,28 @@ impl SchemeMut for DisplayScheme { Err(Error::new(EBADF)) } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + fn read( + &mut self, + id: usize, + buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(vt_i, screen_i) = handle.kind { if let Some(screens) = self.vts.get_mut(&vt_i) { if let Some(screen) = screens.get_mut(&screen_i) { - return screen.read(buf); + let nread = screen.read(buf)?; + if nread != 0 { + return Ok(Some(nread)); + } else { + if handle.flags & O_NONBLOCK == O_NONBLOCK { + return Ok(Some(0)); + } else { + return Ok(None); + } + } } } } @@ -251,7 +257,13 @@ impl SchemeMut for DisplayScheme { Err(Error::new(EBADF)) } - fn write(&mut self, id: usize, buf: &[u8]) -> Result { + fn write( + &mut self, + id: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; match handle.kind { @@ -286,7 +298,7 @@ impl SchemeMut for DisplayScheme { DisplayCommand::Deactivate(_) => {} } - Ok(buf.len()) + Ok(Some(buf.len())) } HandleKind::Screen(vt_i, screen_i) => { @@ -296,7 +308,7 @@ impl SchemeMut for DisplayScheme { if vt_i == self.active { screen.sync(&mut self.framebuffers[screen_i.0]); } - Ok(count) + Ok(Some(count)) } else { Err(Error::new(EBADF)) } @@ -307,18 +319,24 @@ impl SchemeMut for DisplayScheme { } } - fn close(&mut self, id: usize) -> Result { + fn close(&mut self, id: usize) -> Result> { self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(0) + Ok(Some(0)) } - fn mmap_prep(&mut self, id: usize, off: u64, size: usize, _flags: MapFlags) -> Result { + fn mmap_prep( + &mut self, + id: usize, + off: u64, + size: usize, + _flags: MapFlags, + ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let HandleKind::Screen(vt_i, screen_i) = handle.kind { if let Some(screens) = self.vts.get(&vt_i) { if let Some(screen) = screens.get(&screen_i) { if off as usize + size <= screen.offscreen.len() * 4 { - return Ok(screen.offscreen.as_ptr() as usize + off as usize); + return Ok(Some(screen.offscreen.as_ptr() as usize + off as usize)); } else { return Err(Error::new(EINVAL)); } diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index 50f2f05af2..471340ce86 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -110,12 +110,8 @@ impl GraphicScreen { Ok(i * mem::size_of::()) } - pub fn can_read(&self) -> Option { - if self.input.is_empty() { - None - } else { - Some(self.input.len() * mem::size_of::()) - } + pub fn can_read(&self) -> bool { + !self.input.is_empty() } pub fn write(&mut self, buf: &[u8]) -> Result { From 436a16b06983ea4fd58e75c21ce4203ec7df6fb6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 20:37:21 +0100 Subject: [PATCH 1014/1301] virtio-gpud: Migrate to redox-scheme --- Cargo.lock | 1 + graphics/virtio-gpud/Cargo.toml | 1 + graphics/virtio-gpud/src/main.rs | 29 +++++++++++++++++------------ graphics/virtio-gpud/src/scheme.rs | 23 ++++++++++++++++------- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 92d3f8964b..639bf4af21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1736,6 +1736,7 @@ dependencies = [ "paste", "pcid", "redox-daemon", + "redox-scheme", "redox_syscall", "spin", "static_assertions", diff --git a/graphics/virtio-gpud/Cargo.toml b/graphics/virtio-gpud/Cargo.toml index 75901d433e..4068fc438a 100644 --- a/graphics/virtio-gpud/Cargo.toml +++ b/graphics/virtio-gpud/Cargo.toml @@ -21,3 +21,4 @@ redox_syscall = "0.5" orbclient = "0.3.27" spin = "0.9.8" libredox = "0.1.3" +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 7ad1e13e08..7ba38cb8cf 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -23,13 +23,11 @@ #![feature(int_roundings)] use std::cell::UnsafeCell; -use std::fs::File; -use std::io::{Read, Write}; use std::sync::Arc; use pcid_interface::PciFunctionHandle; -use syscall::{Packet, SchemeMut}; +use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; use virtio_core::transport::{self, Queue}; use virtio_core::utils::VolatileCell; use virtio_core::MSIX_PRIMARY_VECTOR; @@ -438,7 +436,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device.transport.run_device(); deamon.ready().unwrap(); - let mut socket_file = File::create(":display.virtio-gpu")?; + let socket_file: Socket = Socket::create("display.virtio-gpu")?; let mut scheme = futures::executor::block_on(scheme::Scheme::new( config, control_queue.clone(), @@ -449,14 +447,21 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { // scheme.inputd_handle.activate(scheme.main_vt)?; loop { - let mut packet = Packet::default(); - socket_file - .read(&mut packet) - .expect("virtio-gpud: failed to read disk scheme"); - scheme.handle(&mut packet); - socket_file - .write(&packet) - .expect("virtio-gpud: failed to read disk scheme"); + let Some(request) = socket_file.next_request(SignalBehavior::Restart)? else { + // Scheme likely got unmounted + return Ok(()); + }; + + match request.kind() { + RequestKind::Call(call_request) => { + socket_file.write_response( + call_request.handle_scheme_mut(&mut scheme), + SignalBehavior::Restart, + )?; + } + RequestKind::Cancellation(_cancellation_request) => {} + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), + } } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 73bb2aab5f..462a29070c 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -7,7 +7,8 @@ use std::sync::Arc; use common::{dma::Dma, sgl}; use inputd::Damage; -use syscall::{Error as SysError, MapFlags, SchemeMut, EAGAIN, EINVAL, PAGE_SIZE}; +use redox_scheme::SchemeMut; +use syscall::{Error as SysError, MapFlags, EAGAIN, EINVAL, PAGE_SIZE}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::{Error, Queue, Transport}; @@ -384,13 +385,25 @@ impl<'a> SchemeMut for Scheme<'a> { } } - fn read(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result { + fn read( + &mut self, + _id: usize, + _buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + ) -> syscall::Result { // TODO: figure out how to get input lol log::warn!("virtio_gpu::read is a stub!"); Ok(0) } - fn write(&mut self, id: usize, buf: &[u8]) -> syscall::Result { + fn write( + &mut self, + id: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + ) -> syscall::Result { match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { Handle::Vt { display, .. } => { // The VT is not active and the device is reseted. Ask them to try @@ -460,10 +473,6 @@ impl<'a> SchemeMut for Scheme<'a> { } } - fn seek(&mut self, _id: usize, _pos: isize, _whence: usize) -> syscall::Result { - todo!() - } - fn close(&mut self, _id: usize) -> syscall::Result { Ok(0) } From 273cbda8725e0e9594c0f3d66ba89a2fc1ba28bb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 17:08:15 +0100 Subject: [PATCH 1015/1301] inputd: Split ControlHandle and DisplayHandle ControlHandle is used to switch the active vt, while DisplayHandle is used by display drivers to register new vt's. There are entirely unrelated tasks and the fact that they had been merged together has been confusing me for a while. Also changed activating a VT to no longer create a new vt when none existed previously. The target graphics driver may not be able to handle the new VT. inputd -A already didn't allow activating non-existent VT's as it first tried to open a consumer handle for the target VT. --- graphics/fbcond/src/main.rs | 4 +- graphics/fbcond/src/scheme.rs | 4 -- graphics/vesad/src/main.rs | 4 +- graphics/vesad/src/scheme.rs | 8 ++-- inputd/src/lib.rs | 18 +++++++-- inputd/src/main.rs | 71 +++++++++++++++-------------------- 6 files changed, 55 insertions(+), 54 deletions(-) diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 4393c9185c..7449d5a4d7 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -53,11 +53,13 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { let mut scheme = FbconScheme::new(vt_ids, &mut event_queue); + let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); + libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); - scheme.inputd_handle.activate(1).unwrap(); + inputd_control_handle.activate_vt(1).unwrap(); let mut blocked = Vec::new(); diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index bd128f2e5a..9ff10d4dbe 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -36,13 +36,10 @@ pub struct FbconScheme { pub vts: BTreeMap, next_id: usize, pub handles: BTreeMap, - pub inputd_handle: inputd::Handle, } impl FbconScheme { pub fn new(vt_ids: &[usize], event_queue: &mut EventQueue) -> FbconScheme { - let inputd_handle = inputd::Handle::new("vesa").unwrap(); - let mut vts = BTreeMap::new(); for &vt_i in vt_ids { @@ -61,7 +58,6 @@ impl FbconScheme { vts, next_id: 0, handles: BTreeMap::new(), - inputd_handle, } } diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 9b01e97624..6bbab330e1 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -86,11 +86,13 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( let _ = File::open("/scheme/debug/disable-graphical-debug"); + let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); + libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); - scheme.inputd_handle.activate(1).unwrap(); + inputd_control_handle.activate_vt(1).unwrap(); let mut blocked = Vec::new(); loop { diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 65baf8dace..b3218b2834 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -32,12 +32,12 @@ pub struct DisplayScheme { pub vts: BTreeMap>, next_id: usize, pub handles: BTreeMap, - pub inputd_handle: inputd::Handle, + _inputd_handle: inputd::DisplayHandle, } impl DisplayScheme { pub fn new(framebuffers: Vec, spec: &[()]) -> DisplayScheme { - let mut inputd_handle = inputd::Handle::new("vesa").unwrap(); + let mut inputd_handle = inputd::DisplayHandle::new("vesa").unwrap(); let mut vts = BTreeMap::>::new(); @@ -47,7 +47,7 @@ impl DisplayScheme { let fb = &framebuffers[fb_i]; screens.insert(ScreenIndex(fb_i), GraphicScreen::new(fb.width, fb.height)); } - vts.insert(VtIndex(inputd_handle.register().unwrap()), screens); + vts.insert(VtIndex(inputd_handle.register_vt().unwrap()), screens); } DisplayScheme { @@ -56,7 +56,7 @@ impl DisplayScheme { vts, next_id: 0, handles: BTreeMap::new(), - inputd_handle, + _inputd_handle: inputd_handle, } } diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 6c55e96949..1b1dc3a2ff 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -13,9 +13,9 @@ pub struct VtActivate { pub vt: usize, } -pub struct Handle(File); +pub struct DisplayHandle(File); -impl Handle { +impl DisplayHandle { pub fn new>(device_name: S) -> Result { let path = format!("/scheme/input/handle/display/{}", device_name.into()); Ok(Self(File::open(path)?)) @@ -23,11 +23,21 @@ impl Handle { // The return value is the display identifier. It will be used to uniquely // identify the display on activation events. - pub fn register(&mut self) -> Result { + pub fn register_vt(&mut self) -> Result { self.0.read(&mut []) } - pub fn activate(&mut self, vt: usize) -> Result { +} + +pub struct ControlHandle(File); + +impl ControlHandle { + pub fn new() -> Result { + let path = format!("/scheme/input/control"); + Ok(Self(File::open(path)?)) + } + + pub fn activate_vt(&mut self, vt: usize) -> Result { let cmd = VtActivate { vt }; self.0.write(unsafe { any_as_u8_slice(&cmd) }) } diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 8aa562a888..66f204adae 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -13,7 +13,6 @@ use std::collections::BTreeMap; use std::fs::File; -use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicUsize, Ordering}; use inputd::{Cmd, VtActivate}; @@ -31,9 +30,10 @@ enum Handle { notified: bool, vt: usize, }, - Device { + Display { device: String, }, + Control, } impl Handle { @@ -123,8 +123,9 @@ impl SchemeMut for InputScheme { } "handle" => { let display = path_parts.collect::>().join("."); - Handle::Device { device: display } + Handle::Display { device: display } } + "control" => Handle::Control, _ => { log::error!("inputd: invalid path {path}"); @@ -174,7 +175,7 @@ impl SchemeMut for InputScheme { Ok(copy) } - Handle::Device { device } => { + Handle::Display { device } => { assert!(buf.is_empty()); let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); @@ -186,6 +187,10 @@ impl SchemeMut for InputScheme { log::error!("inputd: producer tried to read"); return Err(SysError::new(EINVAL)); } + Handle::Control => { + log::error!("inputd: control tried to read"); + return Err(SysError::new(EINVAL)); + } } } @@ -201,16 +206,15 @@ impl SchemeMut for InputScheme { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; match handle { - Handle::Device { device } => { + Handle::Control => { if buf.len() != core::mem::size_of::() { - log::error!("inputd: device tried to write incorrectly sized command"); + log::error!("inputd: control tried to write incorrectly sized command"); return Err(SysError::new(EINVAL)); } // SAFETY: We have verified the size of the buffer above. let cmd = unsafe { &*buf.as_ptr().cast::() }; - self.vts.insert(cmd.vt, Vt::new(device.clone(), cmd.vt)); self.pending_activate = Some(cmd.clone()); return Ok(buf.len()); @@ -220,6 +224,10 @@ impl SchemeMut for InputScheme { log::error!("inputd: consumer tried to write"); return Err(SysError::new(EINVAL)); } + Handle::Display { .. } => { + log::error!("inputd: display tried to write"); + return Err(SysError::new(EINVAL)); + } Handle::Producer => {} } @@ -340,8 +348,8 @@ impl SchemeMut for InputScheme { *notified = false; Ok(EventFlags::empty()) } - Handle::Producer | Handle::Device { .. } => { - log::error!("inputd: producer or device tried to use an event queue"); + Handle::Producer | Handle::Control | Handle::Display { .. } => { + log::error!("inputd: producer, control or display tried to use an event queue"); Err(SysError::new(EINVAL)) } } @@ -378,13 +386,16 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } if let Some(cmd) = scheme.pending_activate.take() { - let vt = scheme.vts.get_mut(&cmd.vt).unwrap(); - // Failing to activate a VT is not a fatal error. - if let Err(err) = vt.send_command(Cmd::Activate { vt: vt.index }) { - log::error!("inputd: failed to activate VT #{}: {err}", vt.index) - } + if let Some(vt) = scheme.vts.get_mut(&cmd.vt) { + // Failing to activate a VT is not a fatal error. + if let Err(err) = vt.send_command(Cmd::Activate { vt: vt.index }) { + log::error!("inputd: failed to activate VT #{}: {err}", vt.index) + } - scheme.active_vt = Some(vt.index); + scheme.active_vt = Some(vt.index); + } else { + log::error!("inputd: failed to activate non-existent VT #{}", cmd.vt) + } } if !scheme.has_new_events { @@ -442,31 +453,11 @@ fn main() { "-A" => { let vt = args.next().unwrap().parse::().unwrap(); - let handle = File::open(format!("/scheme/input/consumer/{vt}")) - .expect("inputd: failed to open consumer handle"); - let mut display_path = [0; 4096]; - - let written = libredox::call::fpath(handle.as_raw_fd() as usize, &mut display_path) - .expect("inputd: fpath() failed"); - - assert!(written <= display_path.len()); - drop(handle); - - let display_path = std::str::from_utf8(&display_path[..written]) - .expect("inputd: display path UTF-8 validation failed"); - let display_name = display_path - .split('.') - .skip(1) - .next() - .expect("inputd: invalid display path"); - let display_scheme = display_name - .split(':') - .next() - .expect("inputd: invalid display path"); - - let mut handle = inputd::Handle::new(display_scheme) - .expect("inputd: failed to open display handle"); - handle.activate(vt).expect("inputd: failed to activate VT"); + let mut handle = + inputd::ControlHandle::new().expect("inputd: failed to open display handle"); + handle + .activate_vt(vt) + .expect("inputd: failed to activate VT"); } _ => panic!("inputd: invalid argument: {}", val), From 8e92e2c74387663d3fae2499e974b7c1bf6f3ad6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 18:09:15 +0100 Subject: [PATCH 1016/1301] inputd: Let graphics drivers pull vt activation events from inputd Previously inputd would directly push vt activation events to the graphics driver, which required being quite lazy to prevent deadlocks as well as the graphics driver having a location where events can be pushed to. By having graphics drivers pull the vt activation events instead, the effective control flow becomes simpler and it becomes easier to correctly handle multiple graphics drivers on the system. For example it becomes possible for multiple graphics drivers to present displays for a single VT as well as making it easier to provide a handoff from the early framebuffer to a real graphics driver. --- Cargo.lock | 1 + graphics/vesad/Cargo.toml | 3 +- graphics/vesad/src/main.rs | 184 +++++++++++++------- graphics/vesad/src/scheme.rs | 200 +++++++++------------- graphics/virtio-gpud/src/scheme.rs | 177 ++++++++----------- inputd/src/lib.rs | 148 +++++----------- inputd/src/main.rs | 261 +++++++++++++++++++---------- 7 files changed, 484 insertions(+), 490 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 639bf4af21..e19f9fdb99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1681,6 +1681,7 @@ dependencies = [ "ransid", "redox-daemon", "redox-scheme", + "redox_event", "redox_syscall", ] diff --git a/graphics/vesad/Cargo.toml b/graphics/vesad/Cargo.toml index 0361c8bf7d..eeb5bc77ed 100644 --- a/graphics/vesad/Cargo.toml +++ b/graphics/vesad/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "vesad" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] orbclient = "0.3.27" ransid = "0.4" redox_syscall = "0.5" redox-daemon = "0.1" +redox_event = "0.4.1" common = { path = "../../common" } inputd = { path = "../../inputd" } diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 6bbab330e1..b028a9ba84 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -2,15 +2,15 @@ extern crate orbclient; extern crate syscall; -use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; +use event::{user_data, EventQueue}; +use libredox::errno::{EAGAIN, EINTR}; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; use std::env; use std::fs::File; +use std::os::fd::AsRawFd; use syscall::EVENT_READ; -use crate::{ - framebuffer::FrameBuffer, - scheme::{DisplayScheme, HandleKind}, -}; +use crate::{framebuffer::FrameBuffer, scheme::DisplayScheme}; mod display; mod framebuffer; @@ -80,14 +80,38 @@ fn main() { } fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[()]) -> ! { let socket: Socket = - Socket::create("display.vesa").expect("vesad: failed to create display scheme"); + Socket::nonblock("display.vesa").expect("vesad: failed to create display scheme"); let mut scheme = DisplayScheme::new(framebuffers, &spec); - let _ = File::open("/scheme/debug/disable-graphical-debug"); - let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); + user_data! { + enum Source { + Input, + Scheme, + } + } + + let event_queue: EventQueue = + EventQueue::new().expect("vesad: failed to create event queue"); + event_queue + .subscribe( + scheme.inputd_handle.inner().as_raw_fd() as usize, + Source::Input, + event::EventFlags::READ, + ) + .unwrap(); + event_queue + .subscribe( + socket.inner().raw(), + Source::Scheme, + event::EventFlags::READ, + ) + .unwrap(); + + let _ = File::open("/scheme/debug/disable-graphical-debug"); + libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); @@ -95,67 +119,99 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( inputd_control_handle.activate_vt(1).unwrap(); let mut blocked = Vec::new(); - loop { - let Some(request) = socket - .next_request(SignalBehavior::Restart) - .expect("vesad: failed to read display scheme") - else { - // Scheme likely got unmounted - std::process::exit(0); - }; - - match request.kind() { - RequestKind::Call(call_request) => { - if let Some(resp) = call_request.handle_scheme_block_mut(&mut scheme) { - socket - .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); - } else { - blocked.push(call_request); + let all = [Source::Input, Source::Scheme]; + for event in all + .into_iter() + .chain(event_queue.map(|e| e.expect("vesad: failed to get next event").user_data)) + { + match event { + Source::Input => { + while let Some(vt_event) = scheme + .inputd_handle + .read_vt_event() + .expect("vesad: failed to read display handle") + { + scheme.handle_vt_event(vt_event); } } - RequestKind::Cancellation(_cancellation_request) => {} - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), - } + Source::Scheme => { + loop { + let request = match socket.next_request(SignalBehavior::Restart) { + Ok(Some(request)) => request, + Ok(None) => { + // Scheme likely got unmounted + std::process::exit(0); + } + Err(err) if err.errno == EAGAIN => break, + Err(err) => panic!("vesad: failed to read display scheme: {err}"), + }; - // If there are blocked readers, try to handle them. - { - let mut i = 0; - while i < blocked.len() { - if let Some(resp) = blocked[i].handle_scheme_block_mut(&mut scheme) { - socket - .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); - blocked.remove(i); - } else { - i += 1; + match request.kind() { + RequestKind::Call(call_request) => { + if let Some(resp) = call_request.handle_scheme_block_mut(&mut scheme) { + socket + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + } else { + blocked.push(call_request); + } + } + RequestKind::Cancellation(cancellation_request) => { + if let Some(i) = blocked.iter().position(|req| { + req.request().request_id() == cancellation_request.id + }) { + let blocked_req = blocked.remove(i); + let resp = + Response::new(&blocked_req, Err(syscall::Error::new(EINTR))); + socket + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + } + } + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() + } + } + + // If there are blocked readers, try to handle them. + { + let mut i = 0; + while i < blocked.len() { + if let Some(resp) = blocked[i].handle_scheme_block_mut(&mut scheme) { + socket + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + blocked.remove(i); + } else { + i += 1; + } + } + } + + for (handle_id, handle) in scheme.handles.iter_mut() { + if handle.notified_read || !handle.events.contains(EVENT_READ) { + continue; + } + + let can_read = scheme + .vts + .get(&handle.vt) + .and_then(|screens| screens.get(&handle.screen)) + .map_or(false, |screen| screen.can_read()); + + if can_read { + handle.notified_read = true; + socket + .post_fevent(*handle_id, EVENT_READ.bits()) + .expect("vesad: failed to write display event"); + } else { + handle.notified_read = false; + } + } } } } - - for (handle_id, handle) in scheme.handles.iter_mut() { - if handle.notified_read || !handle.events.contains(EVENT_READ) { - continue; - } - - let can_read = if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - scheme - .vts - .get(&vt_i) - .and_then(|screens| screens.get(&screen_i)) - .map_or(false, |screen| screen.can_read()) - } else { - false - }; - - if can_read { - handle.notified_read = true; - socket - .post_fevent(*handle_id, EVENT_READ.bits()) - .expect("vesad: failed to write display event"); - } else { - handle.notified_read = false; - } - } } + + panic!(); } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index b3218b2834..3dd2b3a9ef 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; use std::str; +use inputd::{VtEvent, VtEventKind}; use redox_scheme::SchemeBlockMut; use syscall::{Error, EventFlags, MapFlags, Result, EBADF, EINVAL, ENOENT, O_NONBLOCK}; @@ -12,15 +13,11 @@ pub struct VtIndex(usize); #[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)] pub struct ScreenIndex(usize); -#[derive(Clone)] -pub enum HandleKind { - Input, - Screen(VtIndex, ScreenIndex), -} - #[derive(Clone)] pub struct Handle { - pub kind: HandleKind, + pub vt: VtIndex, + pub screen: ScreenIndex, + pub flags: usize, pub events: EventFlags, pub notified_read: bool, @@ -32,7 +29,7 @@ pub struct DisplayScheme { pub vts: BTreeMap>, next_id: usize, pub handles: BTreeMap, - _inputd_handle: inputd::DisplayHandle, + pub inputd_handle: inputd::DisplayHandle, } impl DisplayScheme { @@ -56,7 +53,7 @@ impl DisplayScheme { vts, next_id: 0, handles: BTreeMap::new(), - _inputd_handle: inputd_handle, + inputd_handle, } } @@ -84,6 +81,32 @@ impl DisplayScheme { } } } + + pub fn handle_vt_event(&mut self, vt_event: VtEvent) { + match vt_event.kind { + VtEventKind::Activate => { + let vt_i = VtIndex(vt_event.vt); + + if let Some(screens) = self.vts.get_mut(&vt_i) { + for (screen_i, screen) in screens.iter_mut() { + screen.redraw(&mut self.framebuffers[screen_i.0]); + } + } + + self.active = vt_i; + } + VtEventKind::Deactivate => { + // Nothing to do for deactivate :) + } + VtEventKind::Resize => { + self.resize( + vt_event.width as usize, + vt_event.height as usize, + vt_event.stride as usize, + ); + } + } + } } impl SchemeBlockMut for DisplayScheme { @@ -94,21 +117,6 @@ impl SchemeBlockMut for DisplayScheme { _uid: u32, _gid: u32, ) -> Result> { - if path_str == "handle" { - let id = self.next_id; - self.next_id += 1; - self.handles.insert( - id, - Handle { - kind: HandleKind::Input, - flags, - events: EventFlags::empty(), - notified_read: false, - }, - ); - return Ok(Some(id)); - } - let mut parts = path_str.split('/'); let mut vt_screen = parts.next().unwrap_or("").split('.'); let vt_i = VtIndex(vt_screen.next().unwrap_or("").parse::().unwrap_or(1)); @@ -121,7 +129,9 @@ impl SchemeBlockMut for DisplayScheme { self.handles.insert( id, Handle { - kind: HandleKind::Screen(vt_i, screen_i), + vt: vt_i, + screen: screen_i, + flags, events: EventFlags::empty(), notified_read: false, @@ -164,39 +174,25 @@ impl SchemeBlockMut for DisplayScheme { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; handle.notified_read = false; - - if let HandleKind::Screen(_vt_i, _screen_i) = handle.kind { - handle.events = flags; - Ok(Some(syscall::EventFlags::empty())) - } else { - Err(Error::new(EBADF)) - } + handle.events = flags; + Ok(Some(syscall::EventFlags::empty())) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - let path_str = match handle.kind { - HandleKind::Input => { - //TODO: allow inputs associated with other framebuffers? - format!( - "display:input/{}/{}", - self.framebuffers[0].width, self.framebuffers[0].height - ) - } - HandleKind::Screen(vt_i, screen_i) => { - if let Some(screens) = self.vts.get(&vt_i) { - if let Some(screen) = screens.get(&screen_i) { - format!( - "display:{}.{}/{}/{}", - vt_i.0, screen_i.0, screen.width, screen.height - ) - } else { - return Err(Error::new(EBADF)); - } + let path_str = { + if let Some(screens) = self.vts.get(&handle.vt) { + if let Some(screen) = screens.get(&handle.screen) { + format!( + "display:{}.{}/{}/{}", + handle.vt.0, handle.screen.0, screen.width, screen.height + ) } else { return Err(Error::new(EBADF)); } + } else { + return Err(Error::new(EBADF)); } }; @@ -214,14 +210,12 @@ impl SchemeBlockMut for DisplayScheme { fn fsync(&mut self, id: usize) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - if let Some(screens) = self.vts.get_mut(&vt_i) { - if let Some(screen) = screens.get_mut(&screen_i) { - if vt_i == self.active { - screen.sync(&mut self.framebuffers[screen_i.0]); - } - return Ok(Some(0)); + if let Some(screens) = self.vts.get_mut(&handle.vt) { + if let Some(screen) = screens.get_mut(&handle.screen) { + if handle.vt == self.active { + screen.sync(&mut self.framebuffers[handle.screen.0]); } + return Ok(Some(0)); } } @@ -237,18 +231,16 @@ impl SchemeBlockMut for DisplayScheme { ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - if let Some(screens) = self.vts.get_mut(&vt_i) { - if let Some(screen) = screens.get_mut(&screen_i) { - let nread = screen.read(buf)?; - if nread != 0 { - return Ok(Some(nread)); + if let Some(screens) = self.vts.get_mut(&handle.vt) { + if let Some(screen) = screens.get_mut(&handle.screen) { + let nread = screen.read(buf)?; + if nread != 0 { + return Ok(Some(nread)); + } else { + if handle.flags & O_NONBLOCK == O_NONBLOCK { + return Ok(Some(0)); } else { - if handle.flags & O_NONBLOCK == O_NONBLOCK { - return Ok(Some(0)); - } else { - return Ok(None); - } + return Ok(None); } } } @@ -266,56 +258,18 @@ impl SchemeBlockMut for DisplayScheme { ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - match handle.kind { - HandleKind::Input => { - use inputd::Cmd as DisplayCommand; - - let command = inputd::parse_command(buf).unwrap(); - - match command { - DisplayCommand::Activate { vt } => { - let vt_i = VtIndex(vt); - - if let Some(screens) = self.vts.get_mut(&vt_i) { - for (screen_i, screen) in screens.iter_mut() { - screen.redraw(&mut self.framebuffers[screen_i.0]); - } - } - - self.active = vt_i; - } - - DisplayCommand::Resize { - width, - height, - stride, - .. - } => { - self.resize(width as usize, height as usize, stride as usize); - } - - // Nothing to do for deactivate :) - DisplayCommand::Deactivate(_) => {} - } - - Ok(Some(buf.len())) - } - - HandleKind::Screen(vt_i, screen_i) => { - if let Some(screens) = self.vts.get_mut(&vt_i) { - if let Some(screen) = screens.get_mut(&screen_i) { - let count = screen.write(buf)?; - if vt_i == self.active { - screen.sync(&mut self.framebuffers[screen_i.0]); - } - Ok(Some(count)) - } else { - Err(Error::new(EBADF)) - } - } else { - Err(Error::new(EBADF)) + if let Some(screens) = self.vts.get_mut(&handle.vt) { + if let Some(screen) = screens.get_mut(&handle.screen) { + let count = screen.write(buf)?; + if handle.vt == self.active { + screen.sync(&mut self.framebuffers[handle.screen.0]); } + Ok(Some(count)) + } else { + Err(Error::new(EBADF)) } + } else { + Err(Error::new(EBADF)) } } @@ -332,14 +286,12 @@ impl SchemeBlockMut for DisplayScheme { ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let HandleKind::Screen(vt_i, screen_i) = handle.kind { - if let Some(screens) = self.vts.get(&vt_i) { - if let Some(screen) = screens.get(&screen_i) { - if off as usize + size <= screen.offscreen.len() * 4 { - return Ok(Some(screen.offscreen.as_ptr() as usize + off as usize)); - } else { - return Err(Error::new(EINVAL)); - } + if let Some(screens) = self.vts.get(&handle.vt) { + if let Some(screen) = screens.get(&handle.screen) { + if off as usize + size <= screen.offscreen.len() * 4 { + return Ok(Some(screen.offscreen.as_ptr() as usize + off as usize)); + } else { + return Err(Error::new(EINVAL)); } } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 462a29070c..84c2da348f 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -5,7 +5,7 @@ use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; use std::sync::Arc; use common::{dma::Dma, sgl}; -use inputd::Damage; +use inputd::{Damage, VtEvent, VtEventKind}; use redox_scheme::SchemeMut; use syscall::{Error as SysError, MapFlags, EAGAIN, EINVAL, PAGE_SIZE}; @@ -246,12 +246,9 @@ impl<'a> Display<'a> { } } -enum Handle<'a> { - Vt { - display: Arc>, - vt: usize, - }, - Input, +struct Handle<'a> { + display: Arc>, + vt: usize, } pub struct Scheme<'a> { @@ -331,17 +328,52 @@ impl<'a> Scheme<'a> { Ok(response) } + + // FIXME wire this up + fn handle_vt_event(&mut self, vt_event: VtEvent) { + match vt_event.kind { + VtEventKind::Activate => { + log::info!("activate {}", vt_event.vt); + + for handle in self.handles.values() { + if handle.vt != vt_event.vt { + continue; + } + + log::warn!("virtio-gpu: activating"); + + futures::executor::block_on(handle.display.init()).unwrap(); + } + } + + VtEventKind::Deactivate => { + log::info!("deactivate {}", vt_event.vt); + + for handle in self.handles.values() { + if handle.vt != vt_event.vt { + continue; + } + + log::warn!("virtio-gpu: deactivating"); + + futures::executor::block_on(handle.display.detach()).unwrap(); + break; + } + + // for display in self.displays.iter() { + // futures::executor::block_on(display.detach()).unwrap(); + // } + } + + VtEventKind::Resize => { + log::warn!("virtio-gpu: resize is not implemented yet") + } + } + } } impl<'a> SchemeMut for Scheme<'a> { fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { - if path == "handle" { - let fd = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.insert(fd, Handle::Input); - - return Ok(fd); - } - let mut parts = path.split('/'); let mut screen = parts.next().unwrap_or("").split('.'); @@ -355,7 +387,7 @@ impl<'a> SchemeMut for Scheme<'a> { let fd = self.next_id.fetch_add(1, Ordering::SeqCst); self.handles.insert( fd, - Handle::Vt { + Handle { display: display.clone(), vt, }, @@ -364,25 +396,15 @@ impl<'a> SchemeMut for Scheme<'a> { } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { - match self.handles.get(&id).unwrap() { - Handle::Vt { display, .. } => { - let bytes_copied = futures::executor::block_on(display.get_fpath(buf)).unwrap(); - Ok(bytes_copied) - } - - Handle::Input => unreachable!(), - } + let handle = self.handles.get(&id).unwrap(); + let bytes_copied = futures::executor::block_on(handle.display.get_fpath(buf)).unwrap(); + Ok(bytes_copied) } fn fsync(&mut self, id: usize) -> syscall::Result { - match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { - Handle::Vt { display, .. } => { - futures::executor::block_on(display.flush(None)).unwrap(); - Ok(0) - } - - _ => unreachable!(), - } + let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; + futures::executor::block_on(handle.display.flush(None)).unwrap(); + Ok(0) } fn read( @@ -404,73 +426,26 @@ impl<'a> SchemeMut for Scheme<'a> { _offset: u64, _fcntl_flags: u32, ) -> syscall::Result { - match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { - Handle::Vt { display, .. } => { - // The VT is not active and the device is reseted. Ask them to try - // again later. - if display.is_reseted.load(Ordering::SeqCst) { - return Err(SysError::new(EAGAIN)); - } + let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; - let damages = unsafe { - core::slice::from_raw_parts( - buf.as_ptr() as *const Damage, - buf.len() / core::mem::size_of::(), - ) - }; - - for damage in damages { - futures::executor::block_on(display.flush(Some(damage))).unwrap(); - } - - Ok(buf.len()) - } - - Handle::Input => { - use inputd::Cmd as DisplayCommand; - - let command = inputd::parse_command(buf).unwrap(); - - match command { - DisplayCommand::Activate { vt } => { - let target_vt = vt; - - for handle in self.handles.values() { - if let Handle::Vt { display, vt } = handle { - if *vt != target_vt { - continue; - } - - futures::executor::block_on(display.init()).unwrap(); - } - } - } - - DisplayCommand::Deactivate(target_vt) => { - for handle in self.handles.values() { - if let Handle::Vt { display, vt } = handle { - if *vt != target_vt { - continue; - } - - futures::executor::block_on(display.detach()).unwrap(); - break; - } - } - - // for display in self.displays.iter() { - // futures::executor::block_on(display.detach()).unwrap(); - // } - } - - DisplayCommand::Resize { .. } => { - log::warn!("virtio-gpu: resize is not implemented yet") - } - } - - Ok(buf.len()) - } + // The VT is not active and the device is reseted. Ask them to try + // again later. + if handle.display.is_reseted.load(Ordering::SeqCst) { + return Err(SysError::new(EAGAIN)); } + + let damages = unsafe { + core::slice::from_raw_parts( + buf.as_ptr() as *const Damage, + buf.len() / core::mem::size_of::(), + ) + }; + + for damage in damages { + futures::executor::block_on(handle.display.flush(Some(damage))).unwrap(); + } + + Ok(buf.len()) } fn close(&mut self, _id: usize) -> syscall::Result { @@ -484,12 +459,8 @@ impl<'a> SchemeMut for Scheme<'a> { flags: MapFlags, ) -> syscall::Result { log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); - match self.handles.get(&id).ok_or(SysError::new(EINVAL))? { - Handle::Vt { display, .. } => Ok(futures::executor::block_on( - display.map_screen(offset as usize), - ) - .unwrap() as usize), - _ => unreachable!(), - } + let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; + let ptr = futures::executor::block_on(handle.display.map_screen(offset as usize)).unwrap(); + Ok(ptr as usize) } } diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 1b1dc3a2ff..e48539f683 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -2,9 +2,15 @@ use std::fs::File; use std::io::{Error, Read, Write}; +use std::mem::size_of; +use std::os::fd::{AsFd, BorrowedFd}; unsafe fn any_as_u8_slice(p: &T) -> &[u8] { - ::core::slice::from_raw_parts((p as *const T) as *const u8, ::core::mem::size_of::()) + std::slice::from_raw_parts((p as *const T) as *const u8, size_of::()) +} + +unsafe fn any_as_u8_slice_mut(p: &mut T) -> &mut [u8] { + std::slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::()) } #[derive(Debug, Clone)] @@ -27,6 +33,28 @@ impl DisplayHandle { self.0.read(&mut []) } + pub fn read_vt_event(&mut self) -> Result, Error> { + let mut event = VtEvent { + kind: VtEventKind::Resize, + vt: usize::MAX, + width: u32::MAX, + height: u32::MAX, + stride: u32::MAX, + }; + + let nread = self.0.read(unsafe { any_as_u8_slice_mut(&mut event) })?; + + if nread == 0 { + Ok(None) + } else { + assert_eq!(nread, size_of::()); + Ok(Some(event)) + } + } + + pub fn inner(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } } pub struct ControlHandle(File); @@ -43,121 +71,23 @@ impl ControlHandle { } } -#[derive(Debug, Copy, Clone, PartialEq)] -#[repr(u8)] -enum CmdTy { - Unknown = 0, - +#[derive(Debug)] +#[repr(usize)] +pub enum VtEventKind { Activate, Deactivate, Resize, } -impl From for CmdTy { - fn from(value: u8) -> Self { - match value { - 1 => CmdTy::Activate, - 2 => CmdTy::Deactivate, - 3 => CmdTy::Resize, - _ => CmdTy::Unknown, - } - } -} - #[derive(Debug)] -pub enum Cmd { - // TODO(andypython): #VT should really need to be a `u8`. - Activate { - vt: usize, - }, +#[repr(C)] +pub struct VtEvent { + pub kind: VtEventKind, + pub vt: usize, - Deactivate(usize /* #VT */), - Resize { - // TODO(andypython): do we really need to pass the VT here? - vt: usize, - - width: u32, - height: u32, - stride: u32, - }, -} - -impl Cmd { - fn ty(&self) -> CmdTy { - match self { - Cmd::Activate { .. } => CmdTy::Activate, - Cmd::Deactivate(_) => CmdTy::Deactivate, - Cmd::Resize { .. } => CmdTy::Resize, - } - } -} - -pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), libredox::error::Error> { - use std::os::fd::AsRawFd; - - let mut result = vec![]; - result.push(command.ty() as u8); - - match command { - Cmd::Activate { vt } => { - let cmd = VtActivate { vt }; - let bytes = unsafe { any_as_u8_slice(&cmd) }; - - result.extend_from_slice(bytes); - } - - Cmd::Deactivate(vt) => result.extend_from_slice(&vt.to_le_bytes()), - Cmd::Resize { - vt, - width, - height, - stride, - } => { - result.extend_from_slice(&vt.to_le_bytes()); - result.extend(width.to_le_bytes()); - result.extend(height.to_le_bytes()); - result.extend(stride.to_le_bytes()); - } - }; - - let written = libredox::call::write(file.as_raw_fd() as usize, &result)?; - - // XXX: Ensure all of the data is written. - assert_eq!(written, result.len()); - Ok(()) -} - -pub fn parse_command(buffer: &[u8]) -> Option { - const U32_SIZE: usize = core::mem::size_of::(); - const USIZE_SIZE: usize = core::mem::size_of::(); - - let mut parser = buffer.iter().cloned(); - - let command = CmdTy::from(parser.next()?); - let vt = usize::from_le_bytes(parser.next_chunk::().ok()?); - - match command { - CmdTy::Activate => { - let cmd = unsafe { &*buffer.as_ptr().offset(1).cast::() }; - Some(Cmd::Activate { vt: cmd.vt }) - } - - CmdTy::Deactivate => Some(Cmd::Deactivate(vt)), - CmdTy::Resize => { - let width = parser.next_chunk::().ok()?; - let height = parser.next_chunk::().ok()?; - let stride = parser.next_chunk::().ok()?; - - Some(Cmd::Resize { - vt, - width: u32::from_le_bytes(width), - height: u32::from_le_bytes(height), - stride: u32::from_le_bytes(stride), - }) - } - - CmdTy::Unknown => None, - } + pub width: u32, + pub height: u32, + pub stride: u32, } #[repr(packed)] diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 66f204adae..569e1d80e4 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -11,11 +11,12 @@ //! Read events from `input:consumer`. Optionally, set the `EVENT_READ` flag to be notified when //! events are available. +use core::mem::size_of; use std::collections::BTreeMap; -use std::fs::File; +use std::mem::transmute; use std::sync::atomic::{AtomicUsize, Ordering}; -use inputd::{Cmd, VtActivate}; +use inputd::{VtActivate, VtEvent, VtEventKind}; use redox_scheme::{RequestKind, SchemeMut, SignalBehavior, Socket, V2}; @@ -31,6 +32,9 @@ enum Handle { vt: usize, }, Display { + events: EventFlags, + pending: Vec, + notified: bool, device: String, }, Control, @@ -44,28 +48,14 @@ impl Handle { struct Vt { display: String, - index: usize, - - /// This is *required* to be lazily initialized since opening the handle to the display - /// requires the system call to return first. Otherwise, it will block indefinitely. - handle_file: Option, } impl Vt { - fn new(display: impl Into, index: usize) -> Self { + fn new(display: impl Into) -> Self { Self { display: display.into(), - handle_file: None, - index, } } - - fn send_command(&mut self, cmd: Cmd) -> Result<(), libredox::error::Error> { - let handle_file = self - .handle_file - .get_or_insert_with(|| File::open(format!("/scheme/{}/handle", self.display)).unwrap()); - inputd::send_comand(handle_file, cmd) - } } struct InputScheme { @@ -78,7 +68,6 @@ struct InputScheme { super_key: bool, active_vt: Option, - pending_activate: Option, has_new_events: bool, } @@ -93,10 +82,67 @@ impl InputScheme { super_key: false, active_vt: None, - pending_activate: None, has_new_events: false, } } + + fn switch_vt(&mut self, new_active: usize) -> syscall::Result<()> { + if let Some(active_vt) = self.active_vt { + if new_active == active_vt { + return Ok(()); + } + } + + if !self.vts.contains_key(&new_active) { + log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); + return Ok(()); + } + + log::info!( + "inputd: switching from VT #{} to VT #{new_active}", + self.active_vt.unwrap_or(0) + ); + + for handle in self.handles.values_mut() { + match handle { + Handle::Display { + pending, + notified, + device, + .. + } => { + if let Some(active_vt) = self.active_vt { + if &self.vts[&active_vt].display == &*device { + pending.push(VtEvent { + kind: VtEventKind::Deactivate, + vt: self.active_vt.unwrap(), + width: 0, + height: 0, + stride: 0, + }); + *notified = false; + } + } + + if &self.vts[&new_active].display == &*device { + pending.push(VtEvent { + kind: VtEventKind::Activate, + vt: new_active, + width: 0, + height: 0, + stride: 0, + }); + *notified = false; + } + } + _ => continue, + } + } + + self.active_vt = Some(new_active); + + Ok(()) + } } impl SchemeMut for InputScheme { @@ -123,7 +169,12 @@ impl SchemeMut for InputScheme { } "handle" => { let display = path_parts.collect::>().join("."); - Handle::Display { device: display } + Handle::Display { + events: EventFlags::empty(), + pending: Vec::new(), + notified: false, + device: display, + } } "control" => Handle::Control, @@ -175,12 +226,32 @@ impl SchemeMut for InputScheme { Ok(copy) } - Handle::Display { device } => { - assert!(buf.is_empty()); + Handle::Display { + pending, device, .. + } => { + // FIXME Create new VT through a write instead and return a NewVt event on read + // This allows also returning events for VT (de)activation from the display handle + // rather than pushing them to the graphics driver. + if buf.is_empty() { + // Trying to do an empty read creates a new VT. + let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); + log::info!("inputd: created VT #{vt} for {device}"); + self.vts.insert(vt, Vt::new(device.clone())); + Ok(vt) + } else if buf.len() % size_of::() == 0 { + let copy = core::cmp::min(pending.len(), buf.len() / size_of::()); - let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); - self.vts.insert(vt, Vt::new(device.clone(), vt)); - Ok(vt) + for (i, event) in pending.drain(..copy).enumerate() { + buf[i * size_of::()..(i + 1) * size_of::()] + .copy_from_slice(&unsafe { + transmute::()]>(event) + }); + } + Ok(copy * size_of::()) + } else { + log::error!("inputd: display tried to read incorrectly sized event"); + return Err(SysError::new(EINVAL)); + } } Handle::Producer => { @@ -207,7 +278,7 @@ impl SchemeMut for InputScheme { match handle { Handle::Control => { - if buf.len() != core::mem::size_of::() { + if buf.len() != size_of::() { log::error!("inputd: control tried to write incorrectly sized command"); return Err(SysError::new(EINVAL)); } @@ -215,7 +286,7 @@ impl SchemeMut for InputScheme { // SAFETY: We have verified the size of the buffer above. let cmd = unsafe { &*buf.as_ptr().cast::() }; - self.pending_activate = Some(cmd.clone()); + self.switch_vt(cmd.vt)?; return Ok(buf.len()); } @@ -238,11 +309,11 @@ impl SchemeMut for InputScheme { let events = unsafe { core::slice::from_raw_parts( buf.as_ptr() as *const Event, - buf.len() / core::mem::size_of::(), + buf.len() / size_of::(), ) }; - 'out: for event in events.iter() { + for event in events.iter() { let mut new_active_opt = None; match event.to_option() { EventOption::Key(key_event) => match key_event.scancode { @@ -270,42 +341,41 @@ impl SchemeMut for InputScheme { }, EventOption::Resize(resize_event) => { - let active_vt = self.vts.get_mut(&self.active_vt.unwrap()).unwrap(); - active_vt.send_command(Cmd::Resize { - vt: active_vt.index, - width: resize_event.width, - height: resize_event.height, + for handle in self.handles.values_mut() { + match handle { + Handle::Display { + pending, + notified, + device, + .. + } => { + if &self.vts[&self.active_vt.unwrap()].display == &*device { + pending.push(VtEvent { + kind: VtEventKind::Resize, + vt: self.active_vt.unwrap(), + width: resize_event.width, + height: resize_event.height, - // TODO(andypython): Figure out how to get the stride. - stride: resize_event.width, - })?; + // TODO(andypython): Figure out how to get the stride. + stride: resize_event.width, + }); + *notified = false; + } + } + _ => continue, + } + } } _ => continue, } if let Some(new_active) = new_active_opt { - if new_active == self.vts[&self.active_vt.unwrap()].index { - continue 'out; - } - - if self.vts.contains_key(&new_active) { - let active_vt = self.vts.get_mut(&self.active_vt.unwrap()).unwrap(); - - active_vt.send_command(Cmd::Deactivate(active_vt.index))?; - } - - if let Some(new_active) = self.vts.get_mut(&new_active) { - new_active.send_command(Cmd::Activate { - vt: new_active.index, - })?; - self.active_vt = Some(new_active.index); - } else { - log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); - } + self.switch_vt(new_active)?; } } + let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; assert!(handle.is_producer()); let active_vt = self.active_vt.unwrap(); @@ -348,8 +418,17 @@ impl SchemeMut for InputScheme { *notified = false; Ok(EventFlags::empty()) } - Handle::Producer | Handle::Control | Handle::Display { .. } => { - log::error!("inputd: producer, control or display tried to use an event queue"); + Handle::Display { + ref mut events, + ref mut notified, + .. + } => { + *events = flags; + *notified = false; + Ok(EventFlags::empty()) + } + Handle::Producer | Handle::Control => { + log::error!("inputd: producer or control tried to use an event queue"); Err(SysError::new(EINVAL)) } } @@ -385,47 +464,51 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), } - if let Some(cmd) = scheme.pending_activate.take() { - if let Some(vt) = scheme.vts.get_mut(&cmd.vt) { - // Failing to activate a VT is not a fatal error. - if let Err(err) = vt.send_command(Cmd::Activate { vt: vt.index }) { - log::error!("inputd: failed to activate VT #{}: {err}", vt.index) - } - - scheme.active_vt = Some(vt.index); - } else { - log::error!("inputd: failed to activate non-existent VT #{}", cmd.vt) - } - } - if !scheme.has_new_events { continue; } for (id, handle) in scheme.handles.iter_mut() { - if let Handle::Consumer { - events, - pending, - ref mut notified, - vt, - } = handle - { - if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) { - continue; + match handle { + Handle::Consumer { + events, + pending, + ref mut notified, + vt, + } => { + if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) { + continue; + } + + let active_vt = scheme.active_vt.unwrap(); + + // The activate VT is not the same as the VT that the consumer is listening to + // for events. + if active_vt != *vt { + continue; + } + + // Notify the consumer that we have some events to read. Yum yum. + socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?; + + *notified = true; } + Handle::Display { + events, + pending, + ref mut notified, + .. + } => { + if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) { + continue; + } - let active_vt = scheme.active_vt.unwrap(); + // Notify the consumer that we have some events to read. Yum yum. + socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?; - // The activate VT is not the same as the VT that the consumer is listening to - // for events. - if active_vt != *vt { - continue; + *notified = true; } - - // Notify the consumer that we have some events to read. Yum yum. - socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?; - - *notified = true; + _ => {} } } } From 99a00abecadb1a1f6fbdfb102b0220c016997cc9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 22 Dec 2024 17:49:17 +0100 Subject: [PATCH 1017/1301] fbcond: Split a couple of helper functions out of open_vt --- graphics/fbcond/src/display.rs | 42 +++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 01f58ed2c8..11a2dce490 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -50,24 +50,42 @@ pub struct Display { impl Display { pub fn open_vt(vt: usize) -> io::Result { - let mut buffer = [0; 1024]; - - let input_handle = OpenOptions::new() + let mut input_handle = OpenOptions::new() .read(true) .custom_flags(O_NONBLOCK as i32) .open(format!("/scheme/input/consumer/{vt}"))?; - let fd = input_handle.as_raw_fd(); + let display_path = Self::display_path(&mut input_handle)?; + + let (display_file, width, height) = Self::open_display(&display_path)?; + + let offscreen_buffer = display_fd_map(width, height, display_file.as_raw_fd() as usize) + .unwrap_or_else(|e| panic!("failed to map display '{display_path}: {e}")); + Ok(Self { + input_handle, + display_file, + offscreen: offscreen_buffer, + width, + height, + }) + } + + fn display_path(input_handle: &mut File) -> io::Result { + let mut buffer = [0; 1024]; + let fd = input_handle.as_raw_fd(); let written = libredox::call::fpath(fd as usize, &mut buffer) .expect("init: failed to get the path to the display device"); assert!(written <= buffer.len()); - let display_path = - std::str::from_utf8(&buffer[..written]).expect("init: display path UTF-8 check failed"); + Ok(std::str::from_utf8(&buffer[..written]) + .expect("init: display path UTF-8 check failed") + .to_owned()) + } + fn open_display(display_path: &str) -> io::Result<(File, usize, usize)> { let display_file = - libredox::call::open(display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) + libredox::call::open(&display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) .unwrap_or_else(|err| { panic!("failed to open display {}: {}", display_path, err); @@ -84,15 +102,7 @@ impl Display { let path = Self::url_parts(&url)?; let (width, height) = Self::parse_display_path(path); - let offscreen_buffer = display_fd_map(width, height, display_file.as_raw_fd() as usize) - .unwrap_or_else(|e| panic!("failed to map display '{display_path}: {e}")); - Ok(Self { - input_handle, - display_file, - offscreen: offscreen_buffer, - width, - height, - }) + Ok((display_file, width, height)) } fn url_parts(url: &str) -> io::Result<&str> { From 15cee6bb4851ae538bc6ba97ea7ac28dfaf33e2e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 22 Dec 2024 18:15:56 +0100 Subject: [PATCH 1018/1301] fbcond: Resize ransid console on every write This is necessary to correctly handle async changes to the framebuffer size in the future. --- graphics/fbcond/src/text.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index 7f75c6fbc5..2adcc5a7dd 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -21,7 +21,8 @@ pub struct TextScreen { impl TextScreen { pub fn new(display: Display) -> TextScreen { TextScreen { - console: ransid::Console::new(display.width / 8, display.height / 16), + // Width and height will be filled in on the next write to the console + console: ransid::Console::new(0, 0), display, changed: BTreeSet::new(), ctrl: false, @@ -121,8 +122,6 @@ impl TextScreen { pub fn resize(&mut self, width: usize, height: usize) { self.display .resize(width.try_into().unwrap(), height.try_into().unwrap()); - self.console.state.w = width / 8; - self.console.state.h = height / 16; } pub fn input(&mut self, event: &Event) { @@ -223,6 +222,10 @@ impl TextScreen { } pub fn write(&mut self, buf: &[u8]) -> Result { + self.console.state.w = self.display.width / 8; + self.console.state.h = self.display.height / 16; + self.console.state.bottom_margin = (self.display.height / 16).saturating_sub(1); + if self.console.state.cursor && self.console.state.x < self.console.state.w && self.console.state.y < self.console.state.h From 5f7ee8f646e7f107b86962e322d49170fae9863e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 22 Dec 2024 19:45:27 +0100 Subject: [PATCH 1019/1301] Use inputd's Damage everywhere instead of separate SyncRect types --- graphics/fbcond/src/display.rs | 17 ++++------------- graphics/fbcond/src/text.rs | 9 +++++---- graphics/vesad/src/screen.rs | 29 ++++++++++------------------- inputd/src/lib.rs | 2 ++ 4 files changed, 21 insertions(+), 36 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 11a2dce490..bc9afc6a38 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,3 +1,4 @@ +use inputd::Damage; use libredox::flag; use std::fs::OpenOptions; use std::mem; @@ -11,16 +12,6 @@ use std::{ }; use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; -// Keep synced with vesad -#[derive(Clone, Copy)] -#[repr(C, packed)] -pub struct SyncRect { - pub x: i32, - pub y: i32, - pub w: i32, - pub h: i32, -} - fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Result<*mut [u32]> { unsafe { let display_ptr = libredox::call::mmap(libredox::call::MmapArgs { @@ -146,13 +137,13 @@ impl Display { } } - pub fn sync_rect(&mut self, sync_rect: SyncRect) -> syscall::Result<()> { + pub fn sync_rect(&mut self, sync_rect: Damage) -> syscall::Result<()> { unsafe { libredox::call::write( self.display_file.as_raw_fd().as_raw_fd() as usize, slice::from_raw_parts( - &sync_rect as *const SyncRect as *const u8, - mem::size_of::(), + &sync_rect as *const Damage as *const u8, + mem::size_of::(), ), )?; Ok(()) diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index 2adcc5a7dd..4f680496c8 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -5,10 +5,11 @@ use std::convert::{TryFrom, TryInto}; use std::os::fd::AsRawFd; use std::{cmp, ptr}; +use inputd::Damage; use orbclient::{Event, EventOption, FONT}; use syscall::error::*; -use crate::display::{Display, SyncRect}; +use crate::display::Display; pub struct TextScreen { console: ransid::Console, @@ -315,11 +316,11 @@ impl TextScreen { let width = self.display.width.try_into().unwrap(); for &change in self.changed.iter() { - self.display.sync_rect(SyncRect { + self.display.sync_rect(Damage { x: 0, y: i32::try_from(change).unwrap() * 16, - w: width, - h: 16, + width, + height: 16, })?; } self.changed.clear(); diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index 471340ce86..2b86e83d28 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -2,28 +2,19 @@ use std::collections::VecDeque; use std::convert::TryInto; use std::{cmp, mem, ptr, slice}; +use inputd::Damage; use orbclient::{Event, ResizeEvent}; use syscall::error::*; use crate::display::OffscreenBuffer; use crate::framebuffer::FrameBuffer; -// Keep synced with orbital -#[derive(Clone, Copy)] -#[repr(C, packed)] -pub struct SyncRect { - pub x: i32, - pub y: i32, - pub w: i32, - pub h: i32, -} - pub struct GraphicScreen { pub width: usize, pub height: usize, pub offscreen: OffscreenBuffer, pub input: VecDeque, - pub sync_rects: Vec, + pub sync_rects: Vec, } impl GraphicScreen { @@ -117,22 +108,22 @@ impl GraphicScreen { pub fn write(&mut self, buf: &[u8]) -> Result { let sync_rects = unsafe { slice::from_raw_parts( - buf.as_ptr() as *const SyncRect, - buf.len() / mem::size_of::(), + buf.as_ptr() as *const Damage, + buf.len() / mem::size_of::(), ) }; self.sync_rects.extend_from_slice(sync_rects); - Ok(sync_rects.len() * mem::size_of::()) + Ok(sync_rects.len() * mem::size_of::()) } pub fn sync(&mut self, framebuffer: &mut FrameBuffer) { for sync_rect in self.sync_rects.drain(..) { let x = sync_rect.x.try_into().unwrap_or(0); let y = sync_rect.y.try_into().unwrap_or(0); - let w = sync_rect.w.try_into().unwrap_or(0); - let h = sync_rect.h.try_into().unwrap_or(0); + let w = sync_rect.width.try_into().unwrap_or(0); + let h = sync_rect.height.try_into().unwrap_or(0); let start_y = cmp::min(self.height, y); let end_y = cmp::min(self.height, y + h); @@ -161,11 +152,11 @@ impl GraphicScreen { pub fn redraw(&mut self, framebuffer: &mut FrameBuffer) { let width = self.width.try_into().unwrap(); let height = self.height.try_into().unwrap(); - self.sync_rects.push(SyncRect { + self.sync_rects.push(Damage { x: 0, y: 0, - w: width, - h: height, + width, + height, }); self.sync(framebuffer); } diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index e48539f683..907ea53a9b 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -90,6 +90,8 @@ pub struct VtEvent { pub stride: u32, } +// Keep synced with orbital's SyncRect +#[derive(Debug, Copy, Clone)] #[repr(packed)] pub struct Damage { pub x: i32, From c97652a50832e6ab88bd27eab5def3172f389479 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 22 Dec 2024 16:33:17 +0100 Subject: [PATCH 1020/1301] fbcond: Make sure we never block on the graphics driver To prevent deadlocks if the graphics driver in turn tries to write to fbcond for log messages. --- graphics/fbcond/src/display.rs | 134 ++++++++++++++++++++++----------- graphics/fbcond/src/text.rs | 83 ++++++++++---------- 2 files changed, 132 insertions(+), 85 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index bc9afc6a38..39b615e5a9 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -3,6 +3,8 @@ use libredox::flag; use std::fs::OpenOptions; use std::mem; use std::os::unix::fs::OpenOptionsExt; +use std::sync::mpsc::{self, Sender}; +use std::sync::{Arc, Mutex}; use std::{ fs::File, io, @@ -12,10 +14,14 @@ use std::{ }; use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; -fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Result<*mut [u32]> { +fn display_fd_map( + width: usize, + height: usize, + display_file: &mut File, +) -> syscall::Result { unsafe { let display_ptr = libredox::call::mmap(libredox::call::MmapArgs { - fd: display_fd, + fd: display_file.as_raw_fd() as usize, offset: 0, length: (width * height * 4), prot: flag::PROT_READ | flag::PROT_WRITE, @@ -23,7 +29,11 @@ fn display_fd_map(width: usize, height: usize, display_fd: usize) -> syscall::Re addr: core::ptr::null_mut(), })?; let display_slice = slice::from_raw_parts_mut(display_ptr as *mut u32, width * height); - Ok(display_slice) + Ok(DisplayMap { + offscreen: display_slice, + width, + height, + }) } } @@ -31,14 +41,34 @@ unsafe fn display_fd_unmap(image: *mut [u32]) { let _ = libredox::call::munmap(image as *mut (), image.len()); } -pub struct Display { - pub input_handle: File, - pub display_file: File, +pub struct DisplayMap { pub offscreen: *mut [u32], pub width: usize, pub height: usize, } +unsafe impl Send for DisplayMap {} +unsafe impl Sync for DisplayMap {} + +impl Drop for DisplayMap { + fn drop(&mut self) { + unsafe { + display_fd_unmap(self.offscreen); + } + } +} + +enum DisplayCommand { + Resize { width: usize, height: usize }, + SyncRects(Vec), +} + +pub struct Display { + pub input_handle: File, + cmd_tx: Sender, + pub map: Arc>, +} + impl Display { pub fn open_vt(vt: usize) -> io::Result { let mut input_handle = OpenOptions::new() @@ -48,16 +78,55 @@ impl Display { let display_path = Self::display_path(&mut input_handle)?; - let (display_file, width, height) = Self::open_display(&display_path)?; + let (mut display_file, width, height) = Self::open_display(&display_path)?; + + let map = Arc::new(Mutex::new( + display_fd_map(width, height, &mut display_file) + .unwrap_or_else(|e| panic!("failed to map display '{display_path}: {e}")), + )); + + let (cmd_tx, cmd_rx) = mpsc::channel(); + + let map_clone = map.clone(); + std::thread::spawn(move || { + while let Ok(cmd) = cmd_rx.recv() { + match cmd { + DisplayCommand::Resize { width, height } => { + match display_fd_map(width, height, &mut display_file) { + Ok(ok) => { + *map_clone.lock().unwrap() = ok; + } + Err(err) => { + eprintln!( + "failed to resize display to {}x{}: {}", + width, height, err + ); + } + } + } + DisplayCommand::SyncRects(sync_rects) => { + for sync_rect in sync_rects { + unsafe { + libredox::call::write( + display_file.as_raw_fd() as usize, + slice::from_raw_parts( + &sync_rect as *const Damage as *const u8, + mem::size_of::(), + ), + ) + .unwrap(); + } + } + libredox::call::fsync(display_file.as_raw_fd() as usize).unwrap(); + } + } + } + }); - let offscreen_buffer = display_fd_map(width, height, display_file.as_raw_fd() as usize) - .unwrap_or_else(|e| panic!("failed to map display '{display_path}: {e}")); Ok(Self { input_handle, - display_file, - offscreen: offscreen_buffer, - width, - height, + cmd_tx, + map, }) } @@ -122,39 +191,14 @@ impl Display { } pub fn resize(&mut self, width: usize, height: usize) { - match display_fd_map(width, height, self.display_file.as_raw_fd() as usize) { - Ok(ok) => { - unsafe { - display_fd_unmap(self.offscreen); - } - self.offscreen = ok; - self.width = width; - self.height = height; - } - Err(err) => { - eprintln!("failed to resize display to {}x{}: {}", width, height, err); - } - } + self.cmd_tx + .send(DisplayCommand::Resize { width, height }) + .unwrap(); } - pub fn sync_rect(&mut self, sync_rect: Damage) -> syscall::Result<()> { - unsafe { - libredox::call::write( - self.display_file.as_raw_fd().as_raw_fd() as usize, - slice::from_raw_parts( - &sync_rect as *const Damage as *const u8, - mem::size_of::(), - ), - )?; - Ok(()) - } - } -} - -impl Drop for Display { - fn drop(&mut self) { - unsafe { - display_fd_unmap(self.offscreen); - } + pub fn sync_rects(&mut self, sync_rects: Vec) { + self.cmd_tx + .send(DisplayCommand::SyncRects(sync_rects)) + .unwrap(); } } diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index 4f680496c8..46afcc738c 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -2,14 +2,13 @@ extern crate ransid; use std::collections::{BTreeSet, VecDeque}; use std::convert::{TryFrom, TryInto}; -use std::os::fd::AsRawFd; use std::{cmp, ptr}; use inputd::Damage; use orbclient::{Event, EventOption, FONT}; use syscall::error::*; -use crate::display::Display; +use crate::display::{Display, DisplayMap}; pub struct TextScreen { console: ransid::Console, @@ -32,16 +31,16 @@ impl TextScreen { } /// Draw a rectangle - fn rect(display: &mut Display, x: usize, y: usize, w: usize, h: usize, color: u32) { - let start_y = cmp::min(display.height, y); - let end_y = cmp::min(display.height, y + h); + fn rect(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize, color: u32) { + let start_y = cmp::min(map.height, y); + let end_y = cmp::min(map.height, y + h); - let start_x = cmp::min(display.width, x); - let len = cmp::min(display.width, x + w) - start_x; + let start_x = cmp::min(map.width, x); + let len = cmp::min(map.width, x + w) - start_x; - let mut offscreen_ptr = display.offscreen as *mut u8 as usize; + let mut offscreen_ptr = map.offscreen as *mut u8 as usize; - let stride = display.width * 4; + let stride = map.width * 4; let offset = y * stride + start_x * 4; offscreen_ptr += offset; @@ -59,16 +58,16 @@ impl TextScreen { } /// Invert a rectangle - fn invert(display: &mut Display, x: usize, y: usize, w: usize, h: usize) { - let start_y = cmp::min(display.height, y); - let end_y = cmp::min(display.height, y + h); + fn invert(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize) { + let start_y = cmp::min(map.height, y); + let end_y = cmp::min(map.height, y + h); - let start_x = cmp::min(display.width, x); - let len = cmp::min(display.width, x + w) - start_x; + let start_x = cmp::min(map.width, x); + let len = cmp::min(map.width, x + w) - start_x; - let mut offscreen_ptr = display.offscreen as *mut u8 as usize; + let mut offscreen_ptr = map.offscreen as *mut u8 as usize; - let stride = display.width * 4; + let stride = map.width * 4; let offset = y * stride + start_x * 4; offscreen_ptr += offset; @@ -92,7 +91,7 @@ impl TextScreen { /// Draw a character fn char( - display: &mut Display, + map: &mut DisplayMap, x: usize, y: usize, character: char, @@ -100,8 +99,8 @@ impl TextScreen { _bold: bool, _italic: bool, ) { - if x + 8 <= display.width && y + 16 <= display.height { - let mut dst = display.offscreen as *mut u8 as usize + (y * display.width + x) * 4; + if x + 8 <= map.width && y + 16 <= map.height { + let mut dst = map.offscreen as *mut u8 as usize + (y * map.width + x) * 4; let font_i = 16 * (character as usize); if font_i + 16 <= FONT.len() { @@ -114,7 +113,7 @@ impl TextScreen { } } } - dst += display.width * 4; + dst += map.width * 4; } } } @@ -223,9 +222,11 @@ impl TextScreen { } pub fn write(&mut self, buf: &[u8]) -> Result { - self.console.state.w = self.display.width / 8; - self.console.state.h = self.display.height / 16; - self.console.state.bottom_margin = (self.display.height / 16).saturating_sub(1); + let mut map = self.display.map.lock().unwrap(); + + self.console.state.w = map.width / 8; + self.console.state.h = map.height / 16; + self.console.state.bottom_margin = (map.height / 16).saturating_sub(1); if self.console.state.cursor && self.console.state.x < self.console.state.w @@ -233,12 +234,11 @@ impl TextScreen { { let x = self.console.state.x; let y = self.console.state.y; - Self::invert(&mut self.display, x * 8, y * 16, 8, 16); + Self::invert(&mut map, x * 8, y * 16, 8, 16); self.changed.insert(y); } { - let display = &mut self.display; let changed = &mut self.changed; let input = &mut self.input; self.console.write(buf, |event| match event { @@ -250,14 +250,14 @@ impl TextScreen { bold, .. } => { - Self::char(display, x * 8, y * 16, c, color.as_rgb(), bold, false); + Self::char(&mut map, x * 8, y * 16, c, color.as_rgb(), bold, false); changed.insert(y); } ransid::Event::Input { data } => { input.extend(data); } ransid::Event::Rect { x, y, w, h, color } => { - Self::rect(display, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); + Self::rect(&mut map, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); for y2 in y..y + h { changed.insert(y2); } @@ -271,8 +271,8 @@ impl TextScreen { w, h, } => { - let width = display.width; - let pixels = unsafe { &mut *display.offscreen }; + let width = map.width; + let pixels = unsafe { &mut *map.offscreen }; for raw_y in 0..h { let y = if from_y > to_y { raw_y } else { h - raw_y - 1 }; @@ -310,21 +310,24 @@ impl TextScreen { { let x = self.console.state.x; let y = self.console.state.y; - Self::invert(&mut self.display, x * 8, y * 16, 8, 16); + Self::invert(&mut map, x * 8, y * 16, 8, 16); self.changed.insert(y); } - let width = self.display.width.try_into().unwrap(); - for &change in self.changed.iter() { - self.display.sync_rect(Damage { - x: 0, - y: i32::try_from(change).unwrap() * 16, - width, - height: 16, - })?; - } + let width = map.width.try_into().unwrap(); + drop(map); + self.display.sync_rects( + self.changed + .iter() + .map(|&change| Damage { + x: 0, + y: i32::try_from(change).unwrap() * 16, + width, + height: 16, + }) + .collect(), + ); self.changed.clear(); - libredox::call::fsync(self.display.display_file.as_raw_fd().as_raw_fd() as usize)?; Ok(buf.len()) } From 31deddd0d5e74a9e2d52047c0a6149107ccbe6f5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 21 Dec 2024 20:57:22 +0100 Subject: [PATCH 1021/1301] virtio-gpud: Claim a new VT Before these changes virtio-gpud effectively didn't do anything and vesad's framebuffer was kept instead. --- Cargo.lock | 1 + graphics/virtio-gpud/Cargo.toml | 1 + graphics/virtio-gpud/src/main.rs | 84 ++++++++++++++++++++++++++++-- graphics/virtio-gpud/src/scheme.rs | 9 +++- 4 files changed, 89 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e19f9fdb99..2d1329e6a3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1738,6 +1738,7 @@ dependencies = [ "pcid", "redox-daemon", "redox-scheme", + "redox_event", "redox_syscall", "spin", "static_assertions", diff --git a/graphics/virtio-gpud/Cargo.toml b/graphics/virtio-gpud/Cargo.toml index 4068fc438a..1362b2d8b3 100644 --- a/graphics/virtio-gpud/Cargo.toml +++ b/graphics/virtio-gpud/Cargo.toml @@ -17,6 +17,7 @@ pcid = { path = "../../pcid" } inputd = { path = "../../inputd" } redox-daemon = "0.1" +redox_event = "0.4.1" redox_syscall = "0.5" orbclient = "0.3.27" spin = "0.9.8" diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 7ba38cb8cf..6ac65e3c1b 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -23,8 +23,11 @@ #![feature(int_roundings)] use std::cell::UnsafeCell; +use std::os::fd::AsRawFd; use std::sync::Arc; +use event::{user_data, EventQueue}; +use libredox::errno::EAGAIN; use pcid_interface::PciFunctionHandle; use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; @@ -436,7 +439,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device.transport.run_device(); deamon.ready().unwrap(); - let socket_file: Socket = Socket::create("display.virtio-gpu")?; + let socket: Socket = Socket::nonblock("display.virtio-gpu")?; let mut scheme = futures::executor::block_on(scheme::Scheme::new( config, control_queue.clone(), @@ -444,17 +447,90 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device.transport.clone(), ))?; - // scheme.inputd_handle.activate(scheme.main_vt)?; + user_data! { + enum Source { + Input, + Scheme, + } + } + + let event_queue: EventQueue = + EventQueue::new().expect("vesad: failed to create event queue"); + event_queue + .subscribe( + scheme.inputd_handle.inner().as_raw_fd() as usize, + Source::Input, + event::EventFlags::READ, + ) + .unwrap(); + event_queue + .subscribe( + socket.inner().raw(), + Source::Scheme, + event::EventFlags::READ, + ) + .unwrap(); + + //let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); + //inputd_control_handle.activate_vt(3).unwrap(); + + let all = [Source::Input, Source::Scheme]; + for event in all + .into_iter() + .chain(event_queue.map(|e| e.expect("vesad: failed to get next event").user_data)) + { + match event { + Source::Input => { + while let Some(vt_event) = scheme + .inputd_handle + .read_vt_event() + .expect("vesad: failed to read display handle") + { + scheme.handle_vt_event(vt_event); + } + } + Source::Scheme => { + loop { + let request = match socket.next_request(SignalBehavior::Restart) { + Ok(Some(request)) => request, + Ok(None) => { + // Scheme likely got unmounted + std::process::exit(0); + } + Err(err) if err.errno == EAGAIN => break, + Err(err) => return Err(err.into()), + }; + + match request.kind() { + RequestKind::Call(call_request) => { + socket + .write_response( + call_request.handle_scheme_mut(&mut scheme), + SignalBehavior::Restart, + ) + .expect("vesad: failed to write display scheme"); + } + RequestKind::Cancellation(_cancellation_request) => { + // FIXME handle this + } + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() + } + } + } + } + } + } loop { - let Some(request) = socket_file.next_request(SignalBehavior::Restart)? else { + let Some(request) = socket.next_request(SignalBehavior::Restart)? else { // Scheme likely got unmounted return Ok(()); }; match request.kind() { RequestKind::Call(call_request) => { - socket_file.write_response( + socket.write_response( call_request.handle_scheme_mut(&mut scheme), SignalBehavior::Restart, )?; diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 84c2da348f..8c8df4de2a 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -256,6 +256,7 @@ pub struct Scheme<'a> { /// Counter used for file descriptor allocation. next_id: AtomicUsize, displays: Vec>>, + pub inputd_handle: inputd::DisplayHandle, } impl<'a> Scheme<'a> { @@ -273,10 +274,15 @@ impl<'a> Scheme<'a> { ) .await?; + let mut inputd_handle = inputd::DisplayHandle::new("virtio-gpu").unwrap(); + // FIXME make vesad handoff control over all it's VT's instead + inputd_handle.register_vt().unwrap(); + Ok(Self { handles: BTreeMap::new(), next_id: AtomicUsize::new(0), displays, + inputd_handle, }) } @@ -329,8 +335,7 @@ impl<'a> Scheme<'a> { Ok(response) } - // FIXME wire this up - fn handle_vt_event(&mut self, vt_event: VtEvent) { + pub fn handle_vt_event(&mut self, vt_event: VtEvent) { match vt_event.kind { VtEventKind::Activate => { log::info!("activate {}", vt_event.vt); From b0f682c95d97a4e093c5f7aed9c05c7827f054e2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 23 Dec 2024 11:09:28 +0100 Subject: [PATCH 1022/1301] virtio-gpud: Handle multiple VT's The code will become simpler once handoff is implemented such that virtio-gpud no longer needs to support reset and reinitialization of the virtio gpu device. --- graphics/virtio-gpud/src/main.rs | 71 +++++++------ graphics/virtio-gpud/src/scheme.rs | 155 ++++++++++++++++------------- 2 files changed, 120 insertions(+), 106 deletions(-) diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 6ac65e3c1b..fa26bbc036 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -24,6 +24,7 @@ use std::cell::UnsafeCell; use std::os::fd::AsRawFd; +use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::Arc; use event::{user_data, EventQueue}; @@ -225,6 +226,18 @@ impl Default for GetDisplayInfo { } } +static RESOURCE_ALLOC: AtomicU32 = AtomicU32::new(1); // XXX: 0 is reserved for whatever that takes `resource_id`. + +#[derive(Debug, Copy, Clone)] +#[repr(C)] +pub struct ResourceId(u32); + +impl ResourceId { + fn alloc() -> Self { + ResourceId(RESOURCE_ALLOC.fetch_add(1, Ordering::SeqCst)) + } +} + #[derive(Debug, Copy, Clone)] #[repr(u32)] pub enum ResourceFormat { @@ -239,14 +252,16 @@ pub enum ResourceFormat { pub struct ResourceCreate2d { pub header: ControlHeader, - resource_id: VolatileCell, + // FIXME we can likely use regular loads and stores as the ring buffer should provide the + // necessary synchronization. + resource_id: VolatileCell, format: VolatileCell, width: VolatileCell, height: VolatileCell, } impl ResourceCreate2d { - make_getter_setter!(resource_id: u32, format: ResourceFormat, width: u32, height: u32); + make_getter_setter!(resource_id: ResourceId, format: ResourceFormat, width: u32, height: u32); } impl Default for ResourceCreate2d { @@ -257,7 +272,7 @@ impl Default for ResourceCreate2d { ..Default::default() }, - resource_id: VolatileCell::new(0), + resource_id: VolatileCell::new(ResourceId(0)), format: VolatileCell::new(ResourceFormat::Unknown), width: VolatileCell::new(0), height: VolatileCell::new(0), @@ -277,12 +292,12 @@ pub struct MemEntry { #[repr(C)] pub struct AttachBacking { pub header: ControlHeader, - pub resource_id: u32, + pub resource_id: ResourceId, pub num_entries: u32, } impl AttachBacking { - pub fn new(resource_id: u32, num_entries: u32) -> Self { + pub fn new(resource_id: ResourceId, num_entries: u32) -> Self { Self { header: ControlHeader::with_ty(CommandTy::ResourceAttachBacking), resource_id, @@ -295,12 +310,12 @@ impl AttachBacking { #[repr(C)] pub struct DetachBacking { pub header: ControlHeader, - pub resource_id: u32, + pub resource_id: ResourceId, pub padding: u32, } impl DetachBacking { - pub fn new(resource_id: u32) -> Self { + pub fn new(resource_id: ResourceId) -> Self { Self { header: ControlHeader::with_ty(CommandTy::ResourceDetachBacking), resource_id, @@ -314,12 +329,12 @@ impl DetachBacking { pub struct ResourceFlush { pub header: ControlHeader, pub rect: GpuRect, - pub resource_id: u32, + pub resource_id: ResourceId, pub padding: u32, } impl ResourceFlush { - pub fn new(resource_id: u32, rect: GpuRect) -> Self { + pub fn new(resource_id: ResourceId, rect: GpuRect) -> Self { Self { header: ControlHeader::with_ty(CommandTy::ResourceFlush), rect, @@ -333,12 +348,12 @@ impl ResourceFlush { #[repr(C)] pub struct ResourceUnref { pub header: ControlHeader, - pub resource_id: u32, + pub resource_id: ResourceId, pub padding: u32, } impl ResourceUnref { - pub fn new(resource_id: u32) -> Self { + pub fn new(resource_id: ResourceId) -> Self { Self { header: ControlHeader::with_ty(CommandTy::ResourceUnref), resource_id, @@ -353,11 +368,11 @@ pub struct SetScanout { pub header: ControlHeader, pub rect: GpuRect, pub scanout_id: u32, - pub resource_id: u32, + pub resource_id: ResourceId, } impl SetScanout { - pub fn new(scanout_id: u32, resource_id: u32, rect: GpuRect) -> Self { + pub fn new(scanout_id: u32, resource_id: ResourceId, rect: GpuRect) -> Self { Self { header: ControlHeader::with_ty(CommandTy::SetScanout), @@ -374,12 +389,12 @@ pub struct XferToHost2d { pub header: ControlHeader, pub rect: GpuRect, pub offset: u64, - pub resource_id: u32, + pub resource_id: ResourceId, pub padding: u32, } impl XferToHost2d { - pub fn new(resource_id: u32, rect: GpuRect) -> Self { + pub fn new(resource_id: ResourceId, rect: GpuRect) -> Self { Self { header: ControlHeader { ty: VolatileCell::new(CommandTy::TransferToHost2d), @@ -455,7 +470,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } let event_queue: EventQueue = - EventQueue::new().expect("vesad: failed to create event queue"); + EventQueue::new().expect("virtio-gpud: failed to create event queue"); event_queue .subscribe( scheme.inputd_handle.inner().as_raw_fd() as usize, @@ -477,14 +492,14 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let all = [Source::Input, Source::Scheme]; for event in all .into_iter() - .chain(event_queue.map(|e| e.expect("vesad: failed to get next event").user_data)) + .chain(event_queue.map(|e| e.expect("virtio-gpud: failed to get next event").user_data)) { match event { Source::Input => { while let Some(vt_event) = scheme .inputd_handle .read_vt_event() - .expect("vesad: failed to read display handle") + .expect("virtio-gpud: failed to read display handle") { scheme.handle_vt_event(vt_event); } @@ -508,7 +523,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { call_request.handle_scheme_mut(&mut scheme), SignalBehavior::Restart, ) - .expect("vesad: failed to write display scheme"); + .expect("virtio-gpud: failed to write display scheme"); } RequestKind::Cancellation(_cancellation_request) => { // FIXME handle this @@ -522,23 +537,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } } - loop { - let Some(request) = socket.next_request(SignalBehavior::Restart)? else { - // Scheme likely got unmounted - return Ok(()); - }; - - match request.kind() { - RequestKind::Call(call_request) => { - socket.write_response( - call_request.handle_scheme_mut(&mut scheme), - SignalBehavior::Restart, - )?; - } - RequestKind::Cancellation(_cancellation_request) => {} - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), - } - } + std::process::exit(0); } fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 8c8df4de2a..ba8c70b938 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -1,14 +1,14 @@ -use std::cell::OnceCell; -use std::collections::BTreeMap; +use std::cell::RefCell; +use std::collections::{BTreeMap, HashMap}; -use std::sync::atomic::{AtomicBool, AtomicU32, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; use common::{dma::Dma, sgl}; use inputd::{Damage, VtEvent, VtEventKind}; use redox_scheme::SchemeMut; -use syscall::{Error as SysError, MapFlags, EAGAIN, EINVAL, PAGE_SIZE}; +use syscall::{Error as SysError, MapFlags, EINVAL, PAGE_SIZE}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::{Error, Queue, Transport}; @@ -16,8 +16,6 @@ use virtio_core::utils::VolatileCell; use crate::*; -static RESOURCE_ALLOC: AtomicU32 = AtomicU32::new(1); // XXX: 0 is reserved for whatever that takes `resource_id`. - impl Into for &Damage { fn into(self) -> GpuRect { GpuRect { @@ -34,12 +32,13 @@ pub struct Display<'a> { cursor_queue: Arc>, transport: Arc, - mapped: OnceCell, + active_vt: RefCell, + vts_map: RefCell>, + vts_res: RefCell>, width: u32, height: u32, - resource_id: u32, id: usize, is_reseted: AtomicBool, @@ -56,22 +55,24 @@ impl<'a> Display<'a> { control_queue, cursor_queue, - mapped: OnceCell::new(), + active_vt: RefCell::new(0), + vts_map: RefCell::new(HashMap::new()), + vts_res: RefCell::new(HashMap::new()), width: 1920, height: 1080, transport, id, - resource_id: RESOURCE_ALLOC.fetch_add(1, Ordering::SeqCst), is_reseted: AtomicBool::new(false), } } - async fn init(&self) -> Result<(), Error> { + async fn init(&self, vt: usize) -> Result<(), Error> { if !self.is_reseted.load(Ordering::SeqCst) { // The device is already initialized. + self.set_scanout(vt).await?; return Ok(()); } @@ -80,7 +81,7 @@ impl<'a> Display<'a> { log::info!("virtio-gpu: initializing GPU after a reset"); crate::reinit(self.control_queue.clone(), self.cursor_queue.clone())?; - self.remap_screen().await?; + self.set_scanout(vt).await?; Ok(()) } @@ -111,20 +112,9 @@ impl<'a> Display<'a> { Ok(()) } - // TODO: Is this a no-op? - async fn remap_screen(&self) -> Result<*mut u8, Error> { - let bpp = 32; - - let fb_size = self.width as usize * self.height as usize * bpp / 8; - - let mapped = self.mapped.get().unwrap(); - self.map_screen_with(0, fb_size, mapped.as_ptr(), mapped.chunks()) - .await - } - - async fn map_screen(&self, offset: usize) -> Result<*mut u8, Error> { - if let Some(mapped) = self.mapped.get() { - return Ok(mapped.as_ptr().wrapping_add(offset)); + async fn mmap_screen(&self, vt: usize, offset: usize) -> Result<*mut u8, Error> { + if let Some(sgl) = self.vts_map.borrow().get(&vt) { + return Ok(sgl.as_ptr().wrapping_add(offset)); } let bpp = 32; @@ -134,35 +124,40 @@ impl<'a> Display<'a> { unsafe { core::ptr::write_bytes(mapped.as_ptr() as *mut u8, 255, fb_size); } - let _ = self.mapped.set(mapped); - let mapped = self.mapped.get().unwrap(); - self.map_screen_with(offset, fb_size, mapped.as_ptr(), mapped.chunks()) - .await + let mut mapped_vts = self.vts_map.borrow_mut(); + let sgl = mapped_vts.entry(vt).or_insert(mapped); + Ok(sgl.as_ptr().wrapping_add(offset)) } - async fn map_screen_with( - &self, - offset: usize, - _size: usize, - virt: *mut u8, - chunks: &[sgl::Chunk], - ) -> Result<*mut u8, Error> { + async fn create_res_for_screen(&self, vt: usize) -> Result { + if let Some(&res_id) = self.vts_res.borrow().get(&vt) { + return Ok(res_id); + } + + self.mmap_screen(vt, 0).await?; + + let vts_map = self.vts_map.borrow(); + let mapped = &vts_map.get(&vt).unwrap(); + + let res_id = ResourceId::alloc(); + // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. let mut request = Dma::new(ResourceCreate2d::default())?; request.set_width(self.width); request.set_height(self.height); request.set_format(ResourceFormat::Bgrx); - request.set_resource_id(self.resource_id); + request.set_resource_id(res_id); - self.send_request(request).await?; + let header = self.send_request(request).await?; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); // Use the allocated framebuffer from tthe guest ram, and attach it as backing // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. - let mut mem_entries = unsafe { Dma::zeroed_slice(chunks.len())?.assume_init() }; - for (entry, chunk) in mem_entries.iter_mut().zip(chunks.iter()) { + let mut mem_entries = unsafe { Dma::zeroed_slice(mapped.chunks().len())?.assume_init() }; + for (entry, chunk) in mem_entries.iter_mut().zip(mapped.chunks().iter()) { *entry = MemEntry { address: chunk.phys as u64, length: chunk.length.next_multiple_of(PAGE_SIZE) as u32, @@ -170,10 +165,7 @@ impl<'a> Display<'a> { }; } - let attach_request = Dma::new(AttachBacking::new( - self.resource_id, - mem_entries.len() as u32, - ))?; + let attach_request = Dma::new(AttachBacking::new(res_id, mem_entries.len() as u32))?; let header = Dma::new(ControlHeader::default())?; let command = ChainBuilder::new() .chain(Buffer::new(&attach_request)) @@ -184,21 +176,33 @@ impl<'a> Display<'a> { self.control_queue.send(command).await; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + let mut mapped_vts = self.vts_res.borrow_mut(); + mapped_vts.insert(vt, res_id); + Ok(res_id) + } + + async fn set_scanout(&self, vt: usize) -> Result<(), Error> { + let res_id = self.create_res_for_screen(vt).await?; + let scanout_request = Dma::new(SetScanout::new( self.id as u32, - self.resource_id, + res_id, GpuRect::new(0, 0, self.width, self.height), ))?; let header = self.send_request(scanout_request).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - self.flush(None).await?; + self.flush(vt, None).await?; - Ok(virt.wrapping_add(offset)) + Ok(()) } /// If `damage` is `None`, the entire screen is flushed. - async fn flush(&self, damage: Option<&Damage>) -> Result<(), Error> { + async fn flush(&self, vt: usize, damage: Option<&Damage>) -> Result<(), Error> { + if vt != *self.active_vt.borrow() { + return Ok(()); + } + let damage = if let Some(damage) = damage { damage.into() } else { @@ -211,7 +215,7 @@ impl<'a> Display<'a> { }; let req = Dma::new(XferToHost2d::new( - self.resource_id, + self.vts_res.borrow()[&vt], GpuRect { x: 0, y: 0, @@ -222,21 +226,26 @@ impl<'a> Display<'a> { let header = self.send_request(req).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - self.flush_resource(ResourceFlush::new(self.resource_id, damage.clone())) - .await?; + self.flush_resource(ResourceFlush::new( + self.vts_res.borrow()[&vt], + damage.clone(), + )) + .await?; Ok(()) } /// This detaches any backing pages from the display and unrefs the resource. Also resets the /// device, which is required to go back to legacy mode. async fn detach(&self) -> Result<(), Error> { - let request = Dma::new(DetachBacking::new(self.resource_id))?; - let header = self.send_request(request).await?; - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + for (_vt, res_id) in self.vts_res.borrow_mut().drain() { + let request = Dma::new(DetachBacking::new(res_id))?; + let header = self.send_request(request).await?; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - let request = Dma::new(ResourceUnref::new(self.resource_id))?; - let header = self.send_request(request).await?; - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + let request = Dma::new(ResourceUnref::new(res_id))?; + let header = self.send_request(request).await?; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + } // Go back to legacy mode. self.transport.reset(); @@ -310,6 +319,11 @@ impl<'a> Scheme<'a> { transport.clone(), id, ); + // FIXME this is a hack to avoid breaking things while we need to co-exist with vesad + // Somehow necessary to ensure that creating a resource on the first reinitialization + // after this detach doesn't fail. + display.init(1).await?; + display.detach().await?; result.push(Arc::new(display)); } @@ -340,14 +354,12 @@ impl<'a> Scheme<'a> { VtEventKind::Activate => { log::info!("activate {}", vt_event.vt); - for handle in self.handles.values() { - if handle.vt != vt_event.vt { - continue; - } - + for display in &self.displays { log::warn!("virtio-gpu: activating"); - futures::executor::block_on(handle.display.init()).unwrap(); + futures::executor::block_on(display.init(vt_event.vt)).unwrap(); + + *display.active_vt.borrow_mut() = vt_event.vt; } } @@ -408,7 +420,7 @@ impl<'a> SchemeMut for Scheme<'a> { fn fsync(&mut self, id: usize) -> syscall::Result { let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; - futures::executor::block_on(handle.display.flush(None)).unwrap(); + futures::executor::block_on(handle.display.flush(handle.vt, None)).unwrap(); Ok(0) } @@ -433,10 +445,11 @@ impl<'a> SchemeMut for Scheme<'a> { ) -> syscall::Result { let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; - // The VT is not active and the device is reseted. Ask them to try - // again later. + // The VT is not active and the device is reseted. Ignore the damage. We will recreate the + // backing storage from scratch next time we initialize, which is equivalent to damaging the + // entire buffer. if handle.display.is_reseted.load(Ordering::SeqCst) { - return Err(SysError::new(EAGAIN)); + return Ok(buf.len()); } let damages = unsafe { @@ -447,7 +460,7 @@ impl<'a> SchemeMut for Scheme<'a> { }; for damage in damages { - futures::executor::block_on(handle.display.flush(Some(damage))).unwrap(); + futures::executor::block_on(handle.display.flush(handle.vt, Some(damage))).unwrap(); } Ok(buf.len()) @@ -465,7 +478,9 @@ impl<'a> SchemeMut for Scheme<'a> { ) -> syscall::Result { log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; - let ptr = futures::executor::block_on(handle.display.map_screen(offset as usize)).unwrap(); + let ptr = + futures::executor::block_on(handle.display.mmap_screen(handle.vt, offset as usize)) + .unwrap(); Ok(ptr as usize) } } From b9189b91cf1bf95b678745c37983770cdcc8b987 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 23 Dec 2024 13:07:00 +0100 Subject: [PATCH 1023/1301] virtio-gpud: Couple minor improvements --- graphics/virtio-gpud/src/main.rs | 4 +--- graphics/virtio-gpud/src/scheme.rs | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index fa26bbc036..8a40452427 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -525,9 +525,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { ) .expect("virtio-gpud: failed to write display scheme"); } - RequestKind::Cancellation(_cancellation_request) => { - // FIXME handle this - } + RequestKind::Cancellation(_cancellation_request) => {} RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { unreachable!() } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index ba8c70b938..0d8dc80414 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -391,6 +391,10 @@ impl<'a> Scheme<'a> { impl<'a> SchemeMut for Scheme<'a> { fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { + if path.is_empty() { + return Err(SysError::new(EINVAL)); + } + let mut parts = path.split('/'); let mut screen = parts.next().unwrap_or("").split('.'); From 4c4ab2de442366ca14d313f52e36b50e0292e989 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 22 Dec 2024 11:04:53 +0100 Subject: [PATCH 1024/1301] graphics: Implement handoff from vesad to virtio-gpud With this virtio-gpud no longer has to support getting deactivated at any time to hand back control to vesad. This makes it much easier to add many new features that a proper graphics driver is supposed to support. Be aware that virtio-gpud waits for the vsync on every flush request. Fbcond and orbital are not really happy about this right now and when something changes multiple times within a single frame, flush requests queue up, causing the ui to hang until all flush requests are finished. It is still possible to switch to another VT though which won't hang. --- graphics/fbcond/src/display.rs | 38 +++++++++++ graphics/fbcond/src/main.rs | 9 ++- graphics/fbcond/src/text.rs | 4 ++ graphics/vesad/src/scheme.rs | 2 +- graphics/virtio-gpud/src/main.rs | 15 ----- graphics/virtio-gpud/src/scheme.rs | 93 ++++---------------------- inputd/src/lib.rs | 5 ++ inputd/src/main.rs | 103 +++++++++++++++++++++++++++-- 8 files changed, 167 insertions(+), 102 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 39b615e5a9..ceaf48da44 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -60,6 +60,7 @@ impl Drop for DisplayMap { enum DisplayCommand { Resize { width: usize, height: usize }, + ReopenForHandoff { display_path: String }, SyncRects(Vec), } @@ -104,6 +105,29 @@ impl Display { } } } + DisplayCommand::ReopenForHandoff { display_path } => { + eprintln!("fbcond: Performing handoff for '{display_path}'"); + + let (mut new_display_file, width, height) = + Self::open_display(&display_path).unwrap(); + + eprintln!("fbcond: Opened new display '{display_path}'"); + + match display_fd_map(width, height, &mut new_display_file) { + Ok(ok) => { + *map_clone.lock().unwrap() = ok; + display_file = new_display_file; + + eprintln!("fbcond: Mapped new display '{display_path}'"); + } + Err(err) => { + eprintln!( + "failed to resize display to {}x{}: {}", + width, height, err + ); + } + } + } DisplayCommand::SyncRects(sync_rects) => { for sync_rect in sync_rects { unsafe { @@ -130,6 +154,20 @@ impl Display { }) } + /// Re-open the display after a handoff. + /// + /// Once re-opening is finished, you must call [`resize`] to map the new framebuffer. + /// + /// Warning: This must be called in a background thread to avoid a deadlock when the + /// graphics driver (indirectly) writes logs to fbcond. + pub fn reopen_for_handoff(&mut self) { + let display_path = Self::display_path(&mut self.input_handle).unwrap(); + + self.cmd_tx + .send(DisplayCommand::ReopenForHandoff { display_path }) + .unwrap(); + } + fn display_path(input_handle: &mut File) -> io::Result { let mut buffer = [0; 1024]; let fd = input_handle.as_raw_fd(); diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 7449d5a4d7..f5d5b8d243 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -1,3 +1,5 @@ +#![feature(io_error_more)] + use event::EventQueue; use orbclient::Event; use std::fs::{File, OpenOptions}; @@ -55,7 +57,9 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); - libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace"); + // This is not possible for now as fbcond needs to open new displays at runtime for graphics + // driver handoff. In the future inputd may directly pass a handle to the display instead. + //libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); @@ -127,6 +131,9 @@ fn handle_event( Err(err) if err.kind() == ErrorKind::WouldBlock => { break; } + Err(err) if err.kind() == ErrorKind::StaleNetworkFileHandle => { + vt.handle_handoff(); + } Ok(count) => { let events = &mut events[..count]; diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index 46afcc738c..d62b15f502 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -119,6 +119,10 @@ impl TextScreen { } } + pub fn handle_handoff(&mut self) { + self.display.reopen_for_handoff(); + } + pub fn resize(&mut self, width: usize, height: usize) { self.display .resize(width.try_into().unwrap(), height.try_into().unwrap()); diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 3dd2b3a9ef..84dcb3ec39 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -34,7 +34,7 @@ pub struct DisplayScheme { impl DisplayScheme { pub fn new(framebuffers: Vec, spec: &[()]) -> DisplayScheme { - let mut inputd_handle = inputd::DisplayHandle::new("vesa").unwrap(); + let mut inputd_handle = inputd::DisplayHandle::new_early("vesa").unwrap(); let mut vts = BTreeMap::>::new(); diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 8a40452427..ab36a1048e 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -25,14 +25,12 @@ use std::cell::UnsafeCell; use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicU32, Ordering}; -use std::sync::Arc; use event::{user_data, EventQueue}; use libredox::errno::EAGAIN; use pcid_interface::PciFunctionHandle; use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; -use virtio_core::transport::{self, Queue}; use virtio_core::utils::VolatileCell; use virtio_core::MSIX_PRIMARY_VECTOR; @@ -411,19 +409,6 @@ impl XferToHost2d { static DEVICE: spin::Once = spin::Once::new(); -fn reinit(control_queue: Arc, cursor_queue: Arc) -> Result<(), transport::Error> { - let device = DEVICE.get().unwrap(); - - virtio_core::reinit(device)?; - device.transport.finalize_features(); - - device.transport.reinit_queue(control_queue.clone()); - device.transport.reinit_queue(cursor_queue.clone()); - - device.transport.run_device(); - Ok(()) -} - fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut pcid_handle = PciFunctionHandle::connect_default()?; diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 0d8dc80414..97c4a0f031 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; use std::collections::{BTreeMap, HashMap}; -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use common::{dma::Dma, sgl}; @@ -40,8 +40,6 @@ pub struct Display<'a> { height: u32, id: usize, - - is_reseted: AtomicBool, } impl<'a> Display<'a> { @@ -64,28 +62,9 @@ impl<'a> Display<'a> { transport, id, - - is_reseted: AtomicBool::new(false), } } - async fn init(&self, vt: usize) -> Result<(), Error> { - if !self.is_reseted.load(Ordering::SeqCst) { - // The device is already initialized. - self.set_scanout(vt).await?; - return Ok(()); - } - - self.is_reseted.store(false, Ordering::SeqCst); - - log::info!("virtio-gpu: initializing GPU after a reset"); - - crate::reinit(self.control_queue.clone(), self.cursor_queue.clone())?; - self.set_scanout(vt).await?; - - Ok(()) - } - async fn get_fpath(&self, buffer: &mut [u8]) -> Result { let path = format!("display.virtio-gpu:3.0/{}/{}", self.width, self.height); @@ -199,9 +178,12 @@ impl<'a> Display<'a> { /// If `damage` is `None`, the entire screen is flushed. async fn flush(&self, vt: usize, damage: Option<&Damage>) -> Result<(), Error> { - if vt != *self.active_vt.borrow() { + let Some(&res_id) = self.vts_res.borrow().get(&vt) else { + // The resource is not yet created. Ignore the damage. We will write the entire backing + // storage to the resource once we create the resource, which is equivalent to damaging + // the entire resource. return Ok(()); - } + }; let damage = if let Some(damage) = damage { damage.into() @@ -215,7 +197,7 @@ impl<'a> Display<'a> { }; let req = Dma::new(XferToHost2d::new( - self.vts_res.borrow()[&vt], + res_id, GpuRect { x: 0, y: 0, @@ -226,31 +208,8 @@ impl<'a> Display<'a> { let header = self.send_request(req).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - self.flush_resource(ResourceFlush::new( - self.vts_res.borrow()[&vt], - damage.clone(), - )) - .await?; - Ok(()) - } - - /// This detaches any backing pages from the display and unrefs the resource. Also resets the - /// device, which is required to go back to legacy mode. - async fn detach(&self) -> Result<(), Error> { - for (_vt, res_id) in self.vts_res.borrow_mut().drain() { - let request = Dma::new(DetachBacking::new(res_id))?; - let header = self.send_request(request).await?; - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - - let request = Dma::new(ResourceUnref::new(res_id))?; - let header = self.send_request(request).await?; - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - } - - // Go back to legacy mode. - self.transport.reset(); - self.is_reseted.store(true, Ordering::SeqCst); - + self.flush_resource(ResourceFlush::new(res_id, damage.clone())) + .await?; Ok(()) } } @@ -283,9 +242,7 @@ impl<'a> Scheme<'a> { ) .await?; - let mut inputd_handle = inputd::DisplayHandle::new("virtio-gpu").unwrap(); - // FIXME make vesad handoff control over all it's VT's instead - inputd_handle.register_vt().unwrap(); + let inputd_handle = inputd::DisplayHandle::new("virtio-gpu").unwrap(); Ok(Self { handles: BTreeMap::new(), @@ -319,11 +276,6 @@ impl<'a> Scheme<'a> { transport.clone(), id, ); - // FIXME this is a hack to avoid breaking things while we need to co-exist with vesad - // Somehow necessary to ensure that creating a resource on the first reinitialization - // after this detach doesn't fail. - display.init(1).await?; - display.detach().await?; result.push(Arc::new(display)); } @@ -357,7 +309,7 @@ impl<'a> Scheme<'a> { for display in &self.displays { log::warn!("virtio-gpu: activating"); - futures::executor::block_on(display.init(vt_event.vt)).unwrap(); + futures::executor::block_on(display.set_scanout(vt_event.vt)).unwrap(); *display.active_vt.borrow_mut() = vt_event.vt; } @@ -365,21 +317,7 @@ impl<'a> Scheme<'a> { VtEventKind::Deactivate => { log::info!("deactivate {}", vt_event.vt); - - for handle in self.handles.values() { - if handle.vt != vt_event.vt { - continue; - } - - log::warn!("virtio-gpu: deactivating"); - - futures::executor::block_on(handle.display.detach()).unwrap(); - break; - } - - // for display in self.displays.iter() { - // futures::executor::block_on(display.detach()).unwrap(); - // } + // nothing to do :) } VtEventKind::Resize => { @@ -449,13 +387,6 @@ impl<'a> SchemeMut for Scheme<'a> { ) -> syscall::Result { let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; - // The VT is not active and the device is reseted. Ignore the damage. We will recreate the - // backing storage from scratch next time we initialize, which is equivalent to damaging the - // entire buffer. - if handle.display.is_reseted.load(Ordering::SeqCst) { - return Ok(buf.len()); - } - let damages = unsafe { core::slice::from_raw_parts( buf.as_ptr() as *const Damage, diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 907ea53a9b..ca8b25750f 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -27,6 +27,11 @@ impl DisplayHandle { Ok(Self(File::open(path)?)) } + pub fn new_early>(device_name: S) -> Result { + let path = format!("/scheme/input/handle_early/display/{}", device_name.into()); + Ok(Self(File::open(path)?)) + } + // The return value is the display identifier. It will be used to uniquely // identify the display on activation events. pub fn register_vt(&mut self) -> Result { diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 569e1d80e4..a79ba703df 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -18,6 +18,7 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use inputd::{VtActivate, VtEvent, VtEventKind}; +use libredox::errno::ESTALE; use redox_scheme::{RequestKind, SchemeMut, SignalBehavior, Socket, V2}; use orbclient::{Event, EventOption}; @@ -28,6 +29,9 @@ enum Handle { Consumer { events: EventFlags, pending: Vec, + /// We return an ESTALE error once to indicate that a handoff to a different graphics driver + /// is necessary. + needs_handoff: bool, notified: bool, vt: usize, }, @@ -36,6 +40,8 @@ enum Handle { pending: Vec, notified: bool, device: String, + /// Control of all VT's gets handed over from earlyfb devices to the first non-earlyfb device. + is_earlyfb: bool, }, Control, } @@ -46,6 +52,7 @@ impl Handle { } } +#[derive(Debug)] struct Vt { display: String, } @@ -69,6 +76,7 @@ struct InputScheme { active_vt: Option, has_new_events: bool, + maybe_perform_handoff_to: Option, } impl InputScheme { @@ -83,6 +91,7 @@ impl InputScheme { active_vt: None, has_new_events: false, + maybe_perform_handoff_to: None, } } @@ -163,17 +172,40 @@ impl SchemeMut for InputScheme { Handle::Consumer { events: EventFlags::empty(), pending: Vec::new(), + needs_handoff: false, notified: false, vt: target, } } - "handle" => { + "handle_early" => { let display = path_parts.collect::>().join("."); Handle::Display { events: EventFlags::empty(), pending: Vec::new(), notified: false, device: display, + is_earlyfb: true, + } + } + "handle" => { + let display = path_parts.collect::>().join("."); + self.maybe_perform_handoff_to = Some(display.clone()); + Handle::Display { + events: EventFlags::empty(), + pending: if let Some(active_vt) = self.active_vt { + vec![VtEvent { + kind: VtEventKind::Activate, + vt: active_vt, + width: 0, + height: 0, + stride: 0, + }] + } else { + vec![] + }, + notified: false, + device: display, + is_earlyfb: false, } } "control" => Handle::Control, @@ -216,7 +248,17 @@ impl SchemeMut for InputScheme { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; match handle { - Handle::Consumer { pending, .. } => { + Handle::Consumer { + pending, + needs_handoff, + .. + } => { + if *needs_handoff { + *needs_handoff = false; + // Indicates that handoff to a new graphics driver is necessary. + return Err(SysError::new(ESTALE)); + } + let copy = core::cmp::min(pending.len(), buf.len()); for (i, byte) in pending.drain(..copy).enumerate() { @@ -464,6 +506,55 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), } + if let Some(display) = scheme.maybe_perform_handoff_to.take() { + let early_displays = scheme + .handles + .values() + .filter_map(|handle| match handle { + Handle::Display { + device, + is_earlyfb: true, + .. + } => Some(&**device), + _ => None, + }) + .collect::>(); + let vts = scheme + .vts + .iter_mut() + .filter_map(|(&i, vt)| { + if early_displays.contains(&&*vt.display) { + vt.display = display.clone(); + + scheme.has_new_events = true; + + Some(i) + } else { + None + } + }) + .collect::>(); + + for handle in scheme.handles.values_mut() { + match handle { + Handle::Consumer { + needs_handoff, + notified, + vt, + .. + } => { + if !vts.contains(vt) { + continue; + } + + *needs_handoff = true; + *notified = false; + } + _ => continue, + } + } + } + if !scheme.has_new_events { continue; } @@ -473,10 +564,14 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { Handle::Consumer { events, pending, + needs_handoff, ref mut notified, vt, } => { - if pending.is_empty() || *notified || !events.contains(EventFlags::EVENT_READ) { + if (!*needs_handoff && pending.is_empty()) + || *notified + || !events.contains(EventFlags::EVENT_READ) + { continue; } @@ -484,7 +579,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { // The activate VT is not the same as the VT that the consumer is listening to // for events. - if active_vt != *vt { + if !*needs_handoff && active_vt != *vt { continue; } From f2156d4654b9c598c331f7d641e2647bbeb6fb18 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 23 Dec 2024 16:22:41 +0100 Subject: [PATCH 1025/1301] graphics: Optimize the damage buffer api It is now possible to write multiple damage locations in a single write call. Vesad also no longer processes damage for background vt's. The entire framebuffer will be redrawn once the vt switches to the foreground anyway. And finally fsync now consistently redraws the entire screen rather than having different behavior between vesad and virtio-gpud. --- graphics/fbcond/src/display.rs | 21 ++++++++--------- graphics/vesad/src/scheme.rs | 10 +++++---- graphics/vesad/src/screen.rs | 28 ++++++++++++----------- graphics/virtio-gpud/src/scheme.rs | 36 ++++++++++++++++-------------- 4 files changed, 49 insertions(+), 46 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index ceaf48da44..bf6c435182 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -129,19 +129,16 @@ impl Display { } } DisplayCommand::SyncRects(sync_rects) => { - for sync_rect in sync_rects { - unsafe { - libredox::call::write( - display_file.as_raw_fd() as usize, - slice::from_raw_parts( - &sync_rect as *const Damage as *const u8, - mem::size_of::(), - ), - ) - .unwrap(); - } + unsafe { + libredox::call::write( + display_file.as_raw_fd() as usize, + slice::from_raw_parts( + sync_rects.as_ptr() as *const u8, + sync_rects.len() * mem::size_of::(), + ), + ) + .unwrap(); } - libredox::call::fsync(display_file.as_raw_fd() as usize).unwrap(); } } } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 84dcb3ec39..d2127e3a68 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -213,7 +213,7 @@ impl SchemeBlockMut for DisplayScheme { if let Some(screens) = self.vts.get_mut(&handle.vt) { if let Some(screen) = screens.get_mut(&handle.screen) { if handle.vt == self.active { - screen.sync(&mut self.framebuffers[handle.screen.0]); + screen.redraw(&mut self.framebuffers[handle.screen.0]); } return Ok(Some(0)); } @@ -260,11 +260,13 @@ impl SchemeBlockMut for DisplayScheme { if let Some(screens) = self.vts.get_mut(&handle.vt) { if let Some(screen) = screens.get_mut(&handle.screen) { - let count = screen.write(buf)?; if handle.vt == self.active { - screen.sync(&mut self.framebuffers[handle.screen.0]); + screen + .write(buf, Some(&mut self.framebuffers[handle.screen.0])) + .map(|count| Some(count)) + } else { + screen.write(buf, None).map(|count| Some(count)) } - Ok(Some(count)) } else { Err(Error::new(EBADF)) } diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index 2b86e83d28..d4a26c07c2 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -14,7 +14,6 @@ pub struct GraphicScreen { pub height: usize, pub offscreen: OffscreenBuffer, pub input: VecDeque, - pub sync_rects: Vec, } impl GraphicScreen { @@ -24,7 +23,6 @@ impl GraphicScreen { height, offscreen: OffscreenBuffer::new(width * height), input: VecDeque::new(), - sync_rects: Vec::new(), } } } @@ -105,7 +103,7 @@ impl GraphicScreen { !self.input.is_empty() } - pub fn write(&mut self, buf: &[u8]) -> Result { + pub fn write(&mut self, buf: &[u8], framebuffer: Option<&mut FrameBuffer>) -> Result { let sync_rects = unsafe { slice::from_raw_parts( buf.as_ptr() as *const Damage, @@ -113,13 +111,15 @@ impl GraphicScreen { ) }; - self.sync_rects.extend_from_slice(sync_rects); + if let Some(framebuffer) = framebuffer { + self.sync(framebuffer, sync_rects); + } Ok(sync_rects.len() * mem::size_of::()) } - pub fn sync(&mut self, framebuffer: &mut FrameBuffer) { - for sync_rect in self.sync_rects.drain(..) { + pub fn sync(&mut self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) { + for sync_rect in sync_rects { let x = sync_rect.x.try_into().unwrap_or(0); let y = sync_rect.y.try_into().unwrap_or(0); let w = sync_rect.width.try_into().unwrap_or(0); @@ -152,12 +152,14 @@ impl GraphicScreen { pub fn redraw(&mut self, framebuffer: &mut FrameBuffer) { let width = self.width.try_into().unwrap(); let height = self.height.try_into().unwrap(); - self.sync_rects.push(Damage { - x: 0, - y: 0, - width, - height, - }); - self.sync(framebuffer); + self.sync( + framebuffer, + &[Damage { + x: 0, + y: 0, + width, + height, + }], + ); } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 97c4a0f031..d34c20cda1 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -177,7 +177,7 @@ impl<'a> Display<'a> { } /// If `damage` is `None`, the entire screen is flushed. - async fn flush(&self, vt: usize, damage: Option<&Damage>) -> Result<(), Error> { + async fn flush(&self, vt: usize, damage: Option<&[Damage]>) -> Result<(), Error> { let Some(&res_id) = self.vts_res.borrow().get(&vt) else { // The resource is not yet created. Ignore the damage. We will write the entire backing // storage to the resource once we create the resource, which is equivalent to damaging @@ -185,17 +185,6 @@ impl<'a> Display<'a> { return Ok(()); }; - let damage = if let Some(damage) = damage { - damage.into() - } else { - GpuRect { - x: 0, - y: 0, - width: self.width, - height: self.height, - } - }; - let req = Dma::new(XferToHost2d::new( res_id, GpuRect { @@ -208,8 +197,23 @@ impl<'a> Display<'a> { let header = self.send_request(req).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - self.flush_resource(ResourceFlush::new(res_id, damage.clone())) + if let Some(damage) = damage { + for damage in damage { + self.flush_resource(ResourceFlush::new(res_id, damage.into())) + .await?; + } + } else { + self.flush_resource(ResourceFlush::new( + res_id, + GpuRect { + x: 0, + y: 0, + width: self.width, + height: self.height, + }, + )) .await?; + } Ok(()) } } @@ -387,16 +391,14 @@ impl<'a> SchemeMut for Scheme<'a> { ) -> syscall::Result { let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; - let damages = unsafe { + let damage = unsafe { core::slice::from_raw_parts( buf.as_ptr() as *const Damage, buf.len() / core::mem::size_of::(), ) }; - for damage in damages { - futures::executor::block_on(handle.display.flush(handle.vt, Some(damage))).unwrap(); - } + futures::executor::block_on(handle.display.flush(handle.vt, Some(damage))).unwrap(); Ok(buf.len()) } From f6cc7d25dfc9afd7021ac2b94bcd9ca396aabd01 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 23 Dec 2024 16:27:57 +0100 Subject: [PATCH 1026/1301] graphics: Unify damage clipping --- graphics/vesad/src/screen.rs | 23 +++++++++++++---------- graphics/virtio-gpud/src/main.rs | 2 +- graphics/virtio-gpud/src/scheme.rs | 9 ++++++--- inputd/src/lib.rs | 17 +++++++++++++++++ 4 files changed, 37 insertions(+), 14 deletions(-) diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index d4a26c07c2..765de4ff3d 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -120,23 +120,26 @@ impl GraphicScreen { pub fn sync(&mut self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) { for sync_rect in sync_rects { - let x = sync_rect.x.try_into().unwrap_or(0); - let y = sync_rect.y.try_into().unwrap_or(0); - let w = sync_rect.width.try_into().unwrap_or(0); - let h = sync_rect.height.try_into().unwrap_or(0); + let sync_rect = sync_rect.clip( + self.height.try_into().unwrap(), + self.width.try_into().unwrap(), + ); - let start_y = cmp::min(self.height, y); - let end_y = cmp::min(self.height, y + h); + let start_x: usize = sync_rect.x.try_into().unwrap_or(0); + let start_y: usize = sync_rect.y.try_into().unwrap_or(0); + let w: usize = sync_rect.width.try_into().unwrap_or(0); + let h: usize = sync_rect.height.try_into().unwrap_or(0); - let start_x = cmp::min(self.width, x); - let row_pixel_count = cmp::min(self.width, x + w) - start_x; + let end_y = start_y + h; + + let row_pixel_count = w; let mut offscreen_ptr = self.offscreen.as_mut_ptr(); let mut onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable unsafe { - offscreen_ptr = offscreen_ptr.add(y * self.width + start_x); - onscreen_ptr = onscreen_ptr.add(y * framebuffer.stride + start_x); + offscreen_ptr = offscreen_ptr.add(start_y * self.width + start_x); + onscreen_ptr = onscreen_ptr.add(start_y * framebuffer.stride + start_x); let mut rows = end_y - start_y; while rows > 0 { diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index ab36a1048e..dcb33958f1 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -169,7 +169,7 @@ impl Default for ControlHeader { } } -#[derive(Debug, Clone)] +#[derive(Debug, Copy, Clone)] #[repr(C)] pub struct GpuRect { pub x: u32, diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index d34c20cda1..7654291251 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -16,7 +16,7 @@ use virtio_core::utils::VolatileCell; use crate::*; -impl Into for &Damage { +impl Into for Damage { fn into(self) -> GpuRect { GpuRect { x: self.x as u32, @@ -199,8 +199,11 @@ impl<'a> Display<'a> { if let Some(damage) = damage { for damage in damage { - self.flush_resource(ResourceFlush::new(res_id, damage.into())) - .await?; + self.flush_resource(ResourceFlush::new( + res_id, + damage.clip(self.width as i32, self.height as i32).into(), + )) + .await?; } } else { self.flush_resource(ResourceFlush::new( diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index ca8b25750f..d73cc62d28 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -1,5 +1,6 @@ #![feature(iter_next_chunk)] +use std::cmp; use std::fs::File; use std::io::{Error, Read, Write}; use std::mem::size_of; @@ -104,3 +105,19 @@ pub struct Damage { pub width: i32, pub height: i32, } + +impl Damage { + #[must_use] + pub fn clip(mut self, width: i32, height: i32) -> Self { + // Clip damage + self.x = cmp::min(self.x, width); + if self.x + self.width > width { + self.width -= cmp::min(self.width, width - self.x); + } + self.y = cmp::min(self.y, height); + if self.y + self.height > height { + self.height = cmp::min(self.height, height - self.y); + } + self + } +} From 025086acd10d533e9d6e12c96e991aba7e14859e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 23 Dec 2024 18:10:32 +0100 Subject: [PATCH 1027/1301] virtio-gpud: Add offset method to XferToHost2d This will hopefully avoid confusion if someone in the future changes the XferToHost2d in flush to pass a smaller GpuRect. Without adjusting offset this would cause glitches. --- graphics/virtio-gpud/src/main.rs | 4 ++-- graphics/virtio-gpud/src/scheme.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index dcb33958f1..66f41b64dd 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -392,7 +392,7 @@ pub struct XferToHost2d { } impl XferToHost2d { - pub fn new(resource_id: ResourceId, rect: GpuRect) -> Self { + pub fn new(resource_id: ResourceId, rect: GpuRect, offset: u64) -> Self { Self { header: ControlHeader { ty: VolatileCell::new(CommandTy::TransferToHost2d), @@ -400,8 +400,8 @@ impl XferToHost2d { }, rect, + offset, resource_id, - offset: 0, padding: 0, } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 7654291251..a874d782cd 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -193,6 +193,7 @@ impl<'a> Display<'a> { width: self.width, height: self.height, }, + 0, ))?; let header = self.send_request(req).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); From 0019eecadde1b6e0a1fd51eeb0da86576e496dab Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 23 Dec 2024 18:39:23 +0100 Subject: [PATCH 1028/1301] virtio-gpud: Don't process flush requests for background VT's This ensures that the foreground VT doesn't lockup if a background VT spams us with flush requests. In the future we may want to add a scheduler or collapse redundant flush requests. --- graphics/virtio-gpud/src/scheme.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index a874d782cd..c7b3bed07a 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -370,6 +370,11 @@ impl<'a> SchemeMut for Scheme<'a> { fn fsync(&mut self, id: usize) -> syscall::Result { let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; + if handle.vt != *handle.display.active_vt.borrow() { + // This is a protection against background VT's spamming us with flush requests. We will + // flush the resource on the next scanout anyway + return Ok(0); + } futures::executor::block_on(handle.display.flush(handle.vt, None)).unwrap(); Ok(0) } @@ -395,6 +400,12 @@ impl<'a> SchemeMut for Scheme<'a> { ) -> syscall::Result { let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; + if handle.vt != *handle.display.active_vt.borrow() { + // This is a protection against background VT's spamming us with flush requests. We will + // flush the resource on the next scanout anyway + return Ok(buf.len()); + } + let damage = unsafe { core::slice::from_raw_parts( buf.as_ptr() as *const Damage, From 05a6058131ebe0268594d5965228b2828300ea33 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 23 Dec 2024 19:05:00 +0100 Subject: [PATCH 1029/1301] Rustfmt --- graphics/fbcond/src/display.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index bf6c435182..d7af9f1ab6 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -128,18 +128,16 @@ impl Display { } } } - DisplayCommand::SyncRects(sync_rects) => { - unsafe { - libredox::call::write( - display_file.as_raw_fd() as usize, - slice::from_raw_parts( - sync_rects.as_ptr() as *const u8, - sync_rects.len() * mem::size_of::(), - ), - ) - .unwrap(); - } - } + DisplayCommand::SyncRects(sync_rects) => unsafe { + libredox::call::write( + display_file.as_raw_fd() as usize, + slice::from_raw_parts( + sync_rects.as_ptr() as *const u8, + sync_rects.len() * mem::size_of::(), + ), + ) + .unwrap(); + }, } } }); From db9ee0a495f8a78f1c70f8d73dbad14e4efa13e8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 23 Dec 2024 21:29:42 +0100 Subject: [PATCH 1030/1301] vesad: Fix damage clipping oops --- graphics/vesad/src/screen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index 765de4ff3d..3f6612b20a 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -121,8 +121,8 @@ impl GraphicScreen { pub fn sync(&mut self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) { for sync_rect in sync_rects { let sync_rect = sync_rect.clip( - self.height.try_into().unwrap(), self.width.try_into().unwrap(), + self.height.try_into().unwrap(), ); let start_x: usize = sync_rect.x.try_into().unwrap_or(0); From a88f2c4b538cc29040febd22480078fb93164a63 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 22 Dec 2024 17:07:24 +0100 Subject: [PATCH 1031/1301] graphics/vesad: Remove support for reading resize events Nobody actually listens for them from vesad itself anyway. Instead they listen for them from inputd. --- graphics/vesad/src/main.rs | 68 ++++--------------------- graphics/vesad/src/scheme.rs | 99 ++++++++---------------------------- graphics/vesad/src/screen.rs | 35 ------------- 3 files changed, 31 insertions(+), 171 deletions(-) diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index b028a9ba84..20bd314650 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -3,12 +3,11 @@ extern crate orbclient; extern crate syscall; use event::{user_data, EventQueue}; -use libredox::errno::{EAGAIN, EINTR}; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; +use libredox::errno::EAGAIN; +use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; use std::env; use std::fs::File; use std::os::fd::AsRawFd; -use syscall::EVENT_READ; use crate::{framebuffer::FrameBuffer, scheme::DisplayScheme}; @@ -118,7 +117,6 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( inputd_control_handle.activate_vt(1).unwrap(); - let mut blocked = Vec::new(); let all = [Source::Input, Source::Scheme]; for event in all .into_iter() @@ -148,66 +146,18 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( match request.kind() { RequestKind::Call(call_request) => { - if let Some(resp) = call_request.handle_scheme_block_mut(&mut scheme) { - socket - .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); - } else { - blocked.push(call_request); - } - } - RequestKind::Cancellation(cancellation_request) => { - if let Some(i) = blocked.iter().position(|req| { - req.request().request_id() == cancellation_request.id - }) { - let blocked_req = blocked.remove(i); - let resp = - Response::new(&blocked_req, Err(syscall::Error::new(EINTR))); - socket - .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); - } + socket + .write_response( + call_request.handle_scheme_mut(&mut scheme), + SignalBehavior::Restart, + ) + .expect("vesad: failed to write display scheme"); } + RequestKind::Cancellation(_cancellation_request) => {} RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { unreachable!() } } - - // If there are blocked readers, try to handle them. - { - let mut i = 0; - while i < blocked.len() { - if let Some(resp) = blocked[i].handle_scheme_block_mut(&mut scheme) { - socket - .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); - blocked.remove(i); - } else { - i += 1; - } - } - } - - for (handle_id, handle) in scheme.handles.iter_mut() { - if handle.notified_read || !handle.events.contains(EVENT_READ) { - continue; - } - - let can_read = scheme - .vts - .get(&handle.vt) - .and_then(|screens| screens.get(&handle.screen)) - .map_or(false, |screen| screen.can_read()); - - if can_read { - handle.notified_read = true; - socket - .post_fevent(*handle_id, EVENT_READ.bits()) - .expect("vesad: failed to write display event"); - } else { - handle.notified_read = false; - } - } } } } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index d2127e3a68..19ac71782d 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -2,8 +2,8 @@ use std::collections::BTreeMap; use std::str; use inputd::{VtEvent, VtEventKind}; -use redox_scheme::SchemeBlockMut; -use syscall::{Error, EventFlags, MapFlags, Result, EBADF, EINVAL, ENOENT, O_NONBLOCK}; +use redox_scheme::SchemeMut; +use syscall::{Error, MapFlags, Result, EBADF, EINVAL, ENOENT}; use crate::{framebuffer::FrameBuffer, screen::GraphicScreen}; @@ -17,10 +17,6 @@ pub struct ScreenIndex(usize); pub struct Handle { pub vt: VtIndex, pub screen: ScreenIndex, - - pub flags: usize, - pub events: EventFlags, - pub notified_read: bool, } pub struct DisplayScheme { @@ -109,14 +105,8 @@ impl DisplayScheme { } } -impl SchemeBlockMut for DisplayScheme { - fn open( - &mut self, - path_str: &str, - flags: usize, - _uid: u32, - _gid: u32, - ) -> Result> { +impl SchemeMut for DisplayScheme { + fn open(&mut self, path_str: &str, _flags: usize, _uid: u32, _gid: u32) -> Result { let mut parts = path_str.split('/'); let mut vt_screen = parts.next().unwrap_or("").split('.'); let vt_i = VtIndex(vt_screen.next().unwrap_or("").parse::().unwrap_or(1)); @@ -131,14 +121,10 @@ impl SchemeBlockMut for DisplayScheme { Handle { vt: vt_i, screen: screen_i, - - flags, - events: EventFlags::empty(), - notified_read: false, }, ); - Ok(Some(id)) + Ok(id) } else { Err(Error::new(ENOENT)) } @@ -147,7 +133,7 @@ impl SchemeBlockMut for DisplayScheme { } } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { + fn dup(&mut self, id: usize, buf: &[u8]) -> Result { if !buf.is_empty() { return Err(Error::new(EINVAL)); } @@ -163,22 +149,10 @@ impl SchemeBlockMut for DisplayScheme { self.handles.insert(new_id, handle.clone()); - Ok(Some(new_id)) + Ok(new_id) } - fn fevent( - &mut self, - id: usize, - flags: syscall::EventFlags, - ) -> Result> { - let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - handle.notified_read = false; - handle.events = flags; - Ok(Some(syscall::EventFlags::empty())) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; let path_str = { @@ -204,10 +178,10 @@ impl SchemeBlockMut for DisplayScheme { i += 1; } - Ok(Some(i)) + Ok(i) } - fn fsync(&mut self, id: usize) -> Result> { + fn fsync(&mut self, id: usize) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let Some(screens) = self.vts.get_mut(&handle.vt) { @@ -215,7 +189,7 @@ impl SchemeBlockMut for DisplayScheme { if handle.vt == self.active { screen.redraw(&mut self.framebuffers[handle.screen.0]); } - return Ok(Some(0)); + return Ok(0); } } @@ -225,47 +199,24 @@ impl SchemeBlockMut for DisplayScheme { fn read( &mut self, id: usize, - buf: &mut [u8], + _buf: &mut [u8], _offset: u64, _fcntl_flags: u32, - ) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + ) -> Result { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if let Some(screens) = self.vts.get_mut(&handle.vt) { - if let Some(screen) = screens.get_mut(&handle.screen) { - let nread = screen.read(buf)?; - if nread != 0 { - return Ok(Some(nread)); - } else { - if handle.flags & O_NONBLOCK == O_NONBLOCK { - return Ok(Some(0)); - } else { - return Ok(None); - } - } - } - } - - Err(Error::new(EBADF)) + Err(Error::new(EINVAL)) } - fn write( - &mut self, - id: usize, - buf: &[u8], - _offset: u64, - _fcntl_flags: u32, - ) -> Result> { + fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let Some(screens) = self.vts.get_mut(&handle.vt) { if let Some(screen) = screens.get_mut(&handle.screen) { if handle.vt == self.active { - screen - .write(buf, Some(&mut self.framebuffers[handle.screen.0])) - .map(|count| Some(count)) + screen.write(buf, Some(&mut self.framebuffers[handle.screen.0])) } else { - screen.write(buf, None).map(|count| Some(count)) + screen.write(buf, None) } } else { Err(Error::new(EBADF)) @@ -275,23 +226,17 @@ impl SchemeBlockMut for DisplayScheme { } } - fn close(&mut self, id: usize) -> Result> { + fn close(&mut self, id: usize) -> Result { self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) + Ok(0) } - fn mmap_prep( - &mut self, - id: usize, - off: u64, - size: usize, - _flags: MapFlags, - ) -> Result> { + fn mmap_prep(&mut self, id: usize, off: u64, size: usize, _flags: MapFlags) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let Some(screens) = self.vts.get(&handle.vt) { if let Some(screen) = screens.get(&handle.screen) { if off as usize + size <= screen.offscreen.len() * 4 { - return Ok(Some(screen.offscreen.as_ptr() as usize + off as usize)); + return Ok(screen.offscreen.as_ptr() as usize + off as usize); } else { return Err(Error::new(EINVAL)); } diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index 3f6612b20a..a50518ae4c 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -1,9 +1,7 @@ -use std::collections::VecDeque; use std::convert::TryInto; use std::{cmp, mem, ptr, slice}; use inputd::Damage; -use orbclient::{Event, ResizeEvent}; use syscall::error::*; use crate::display::OffscreenBuffer; @@ -13,7 +11,6 @@ pub struct GraphicScreen { pub width: usize, pub height: usize, pub offscreen: OffscreenBuffer, - pub input: VecDeque, } impl GraphicScreen { @@ -22,7 +19,6 @@ impl GraphicScreen { width, height, offscreen: OffscreenBuffer::new(width * height), - input: VecDeque::new(), } } } @@ -71,36 +67,6 @@ impl GraphicScreen { } else { println!("Display is already {}, {}", width, height); }; - - self.input.push_back( - ResizeEvent { - width: width as u32, - height: height as u32, - } - .to_event(), - ); - } - - pub fn read(&mut self, buf: &mut [u8]) -> Result { - let mut i = 0; - - let event_buf = unsafe { - slice::from_raw_parts_mut( - buf.as_mut_ptr() as *mut Event, - buf.len() / mem::size_of::(), - ) - }; - - while i < event_buf.len() && !self.input.is_empty() { - event_buf[i] = self.input.pop_front().unwrap(); - i += 1; - } - - Ok(i * mem::size_of::()) - } - - pub fn can_read(&self) -> bool { - !self.input.is_empty() } pub fn write(&mut self, buf: &[u8], framebuffer: Option<&mut FrameBuffer>) -> Result { @@ -117,7 +83,6 @@ impl GraphicScreen { Ok(sync_rects.len() * mem::size_of::()) } - pub fn sync(&mut self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) { for sync_rect in sync_rects { let sync_rect = sync_rect.clip( From a82fa314377368d4bbf8b87b573e4114368dcd20 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 24 Dec 2024 14:37:15 +0100 Subject: [PATCH 1032/1301] graphics/fbcond: Get display path in the background thread --- graphics/fbcond/src/display.rs | 43 +++++++++++++++------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index d7af9f1ab6..0a36c34d0a 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -60,26 +60,26 @@ impl Drop for DisplayMap { enum DisplayCommand { Resize { width: usize, height: usize }, - ReopenForHandoff { display_path: String }, + ReopenForHandoff, SyncRects(Vec), } pub struct Display { - pub input_handle: File, + pub input_handle: Arc, cmd_tx: Sender, pub map: Arc>, } impl Display { pub fn open_vt(vt: usize) -> io::Result { - let mut input_handle = OpenOptions::new() - .read(true) - .custom_flags(O_NONBLOCK as i32) - .open(format!("/scheme/input/consumer/{vt}"))?; + let input_handle = Arc::new( + OpenOptions::new() + .read(true) + .custom_flags(O_NONBLOCK as i32) + .open(format!("/scheme/input/consumer/{vt}"))?, + ); - let display_path = Self::display_path(&mut input_handle)?; - - let (mut display_file, width, height) = Self::open_display(&display_path)?; + let (display_path, mut display_file, width, height) = Self::open_display(&input_handle)?; let map = Arc::new(Mutex::new( display_fd_map(width, height, &mut display_file) @@ -88,6 +88,7 @@ impl Display { let (cmd_tx, cmd_rx) = mpsc::channel(); + let input_handle_clone = input_handle.clone(); let map_clone = map.clone(); std::thread::spawn(move || { while let Ok(cmd) = cmd_rx.recv() { @@ -105,11 +106,11 @@ impl Display { } } } - DisplayCommand::ReopenForHandoff { display_path } => { - eprintln!("fbcond: Performing handoff for '{display_path}'"); + DisplayCommand::ReopenForHandoff => { + eprintln!("fbcond: Performing handoff"); - let (mut new_display_file, width, height) = - Self::open_display(&display_path).unwrap(); + let (display_path, mut new_display_file, width, height) = + Self::open_display(&input_handle_clone).unwrap(); eprintln!("fbcond: Opened new display '{display_path}'"); @@ -156,14 +157,10 @@ impl Display { /// Warning: This must be called in a background thread to avoid a deadlock when the /// graphics driver (indirectly) writes logs to fbcond. pub fn reopen_for_handoff(&mut self) { - let display_path = Self::display_path(&mut self.input_handle).unwrap(); - - self.cmd_tx - .send(DisplayCommand::ReopenForHandoff { display_path }) - .unwrap(); + self.cmd_tx.send(DisplayCommand::ReopenForHandoff).unwrap(); } - fn display_path(input_handle: &mut File) -> io::Result { + fn open_display(input_handle: &File) -> io::Result<(String, File, usize, usize)> { let mut buffer = [0; 1024]; let fd = input_handle.as_raw_fd(); let written = libredox::call::fpath(fd as usize, &mut buffer) @@ -171,12 +168,10 @@ impl Display { assert!(written <= buffer.len()); - Ok(std::str::from_utf8(&buffer[..written]) + let display_path = std::str::from_utf8(&buffer[..written]) .expect("init: display path UTF-8 check failed") - .to_owned()) - } + .to_owned(); - fn open_display(display_path: &str) -> io::Result<(File, usize, usize)> { let display_file = libredox::call::open(&display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) @@ -195,7 +190,7 @@ impl Display { let path = Self::url_parts(&url)?; let (width, height) = Self::parse_display_path(path); - Ok((display_file, width, height)) + Ok((display_path, display_file, width, height)) } fn url_parts(url: &str) -> io::Result<&str> { From 84eed1ad0e8824febb2285c983988eb19728e1fc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 24 Dec 2024 14:43:48 +0100 Subject: [PATCH 1033/1301] graphics: Introduce new ConsumerHandle type This type has a method to open the current display. --- graphics/fbcond/src/display.rs | 54 ++++++++-------------------------- graphics/fbcond/src/main.rs | 25 ++++++++-------- graphics/fbcond/src/scheme.rs | 2 +- inputd/src/lib.rs | 45 ++++++++++++++++++++++++++-- 4 files changed, 69 insertions(+), 57 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 0a36c34d0a..2cd4d897dd 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,18 +1,9 @@ -use inputd::Damage; +use inputd::{ConsumerHandle, Damage}; use libredox::flag; -use std::fs::OpenOptions; use std::mem; -use std::os::unix::fs::OpenOptionsExt; use std::sync::mpsc::{self, Sender}; use std::sync::{Arc, Mutex}; -use std::{ - fs::File, - io, - os::fd::RawFd, - os::unix::io::{AsRawFd, FromRawFd}, - slice, -}; -use syscall::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; +use std::{fs::File, io, os::unix::io::AsRawFd, slice}; fn display_fd_map( width: usize, @@ -65,25 +56,20 @@ enum DisplayCommand { } pub struct Display { - pub input_handle: Arc, + pub input_handle: Arc, cmd_tx: Sender, pub map: Arc>, } impl Display { pub fn open_vt(vt: usize) -> io::Result { - let input_handle = Arc::new( - OpenOptions::new() - .read(true) - .custom_flags(O_NONBLOCK as i32) - .open(format!("/scheme/input/consumer/{vt}"))?, - ); + let input_handle = Arc::new(ConsumerHandle::for_vt(vt)?); - let (display_path, mut display_file, width, height) = Self::open_display(&input_handle)?; + let (mut display_file, width, height) = Self::open_display(&input_handle)?; let map = Arc::new(Mutex::new( display_fd_map(width, height, &mut display_file) - .unwrap_or_else(|e| panic!("failed to map display '{display_path}: {e}")), + .unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")), )); let (cmd_tx, cmd_rx) = mpsc::channel(); @@ -109,17 +95,17 @@ impl Display { DisplayCommand::ReopenForHandoff => { eprintln!("fbcond: Performing handoff"); - let (display_path, mut new_display_file, width, height) = + let (mut new_display_file, width, height) = Self::open_display(&input_handle_clone).unwrap(); - eprintln!("fbcond: Opened new display '{display_path}'"); + eprintln!("fbcond: Opened new display for VT #{vt}"); match display_fd_map(width, height, &mut new_display_file) { Ok(ok) => { *map_clone.lock().unwrap() = ok; display_file = new_display_file; - eprintln!("fbcond: Mapped new display '{display_path}'"); + eprintln!("fbcond: Mapped new display for VT #{vt}"); } Err(err) => { eprintln!( @@ -160,24 +146,8 @@ impl Display { self.cmd_tx.send(DisplayCommand::ReopenForHandoff).unwrap(); } - fn open_display(input_handle: &File) -> io::Result<(String, File, usize, usize)> { - let mut buffer = [0; 1024]; - let fd = input_handle.as_raw_fd(); - let written = libredox::call::fpath(fd as usize, &mut buffer) - .expect("init: failed to get the path to the display device"); - - assert!(written <= buffer.len()); - - let display_path = std::str::from_utf8(&buffer[..written]) - .expect("init: display path UTF-8 check failed") - .to_owned(); - - let display_file = - libredox::call::open(&display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) - .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) - .unwrap_or_else(|err| { - panic!("failed to open display {}: {}", display_path, err); - }); + fn open_display(input_handle: &ConsumerHandle) -> io::Result<(File, usize, usize)> { + let display_file = input_handle.open_display()?; let mut buf: [u8; 4096] = [0; 4096]; let count = libredox::call::fpath(display_file.as_raw_fd() as usize, &mut buf) @@ -190,7 +160,7 @@ impl Display { let path = Self::url_parts(&url)?; let (width, height) = Self::parse_display_path(path); - Ok((display_path, display_file, width, height)) + Ok((display_file, width, height)) } fn url_parts(url: &str) -> io::Result<&str> { diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index f5d5b8d243..09c9a44478 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -1,12 +1,13 @@ #![feature(io_error_more)] use event::EventQueue; +use libredox::errno::ESTALE; use orbclient::Event; use std::fs::{File, OpenOptions}; use std::io::{ErrorKind, Read, Write}; -use std::os::fd::AsRawFd; +use std::os::fd::{AsRawFd, BorrowedFd}; use std::os::unix::fs::OpenOptionsExt; -use std::{env, io, mem, slice}; +use std::{env, mem, slice}; use syscall::{Packet, SchemeMut, EVENT_READ, O_NONBLOCK}; use crate::scheme::{FbconScheme, VtIndex}; @@ -15,12 +16,15 @@ mod display; mod scheme; mod text; -fn read_to_slice(mut r: R, buf: &mut [T]) -> io::Result { +fn read_to_slice( + file: BorrowedFd, + buf: &mut [T], +) -> Result { unsafe { - r.read(slice::from_raw_parts_mut( - buf.as_mut_ptr() as *mut u8, - buf.len() * mem::size_of::(), - )) + libredox::call::read( + file.as_raw_fd() as usize, + slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * mem::size_of::()), + ) .map(|count| count / mem::size_of::()) } } @@ -126,12 +130,9 @@ fn handle_event( let mut events = [Event::new(); 16]; loop { - match read_to_slice(&mut vt.display.input_handle, &mut events) { + match read_to_slice(vt.display.input_handle.inner(), &mut events) { Ok(0) => break, - Err(err) if err.kind() == ErrorKind::WouldBlock => { - break; - } - Err(err) if err.kind() == ErrorKind::StaleNetworkFileHandle => { + Err(err) if err.errno() == ESTALE => { vt.handle_handoff(); } diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index 9ff10d4dbe..4b8afe212e 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -46,7 +46,7 @@ impl FbconScheme { let display = Display::open_vt(vt_i).expect("Failed to open display for vt"); event_queue .subscribe( - display.input_handle.as_raw_fd().as_raw_fd() as usize, + display.input_handle.inner().as_raw_fd() as usize, VtIndex(vt_i), event::EventFlags::READ, ) diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index d73cc62d28..8956964ed6 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -1,10 +1,13 @@ #![feature(iter_next_chunk)] use std::cmp; -use std::fs::File; +use std::fs::{File, OpenOptions}; use std::io::{Error, Read, Write}; use std::mem::size_of; -use std::os::fd::{AsFd, BorrowedFd}; +use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd}; +use std::os::unix::fs::OpenOptionsExt; + +use libredox::flag::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; unsafe fn any_as_u8_slice(p: &T) -> &[u8] { std::slice::from_raw_parts((p as *const T) as *const u8, size_of::()) @@ -14,6 +17,44 @@ unsafe fn any_as_u8_slice_mut(p: &mut T) -> &mut [u8] { std::slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::()) } +pub struct ConsumerHandle(File); + +impl ConsumerHandle { + pub fn for_vt(vt: usize) -> Result { + let file = OpenOptions::new() + .read(true) + .custom_flags(O_NONBLOCK as i32) + .open(format!("/scheme/input/consumer/{vt}"))?; + Ok(Self(file)) + } + + pub fn inner(&self) -> BorrowedFd<'_> { + self.0.as_fd() + } + + pub fn open_display(&self) -> Result { + let mut buffer = [0; 1024]; + let fd = self.0.as_raw_fd(); + let written = libredox::call::fpath(fd as usize, &mut buffer) + .expect("init: failed to get the path to the display device"); + + assert!(written <= buffer.len()); + + let display_path = std::str::from_utf8(&buffer[..written]) + .expect("init: display path UTF-8 check failed") + .to_owned(); + + let display_file = + libredox::call::open(&display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) + .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) + .unwrap_or_else(|err| { + panic!("failed to open display {}: {}", display_path, err); + }); + + Ok(display_file) + } +} + #[derive(Debug, Clone)] #[repr(C)] pub struct VtActivate { From 0789069afc5b8ca6b6e9ba7d6077c1ad8ac602fc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 24 Dec 2024 14:58:39 +0100 Subject: [PATCH 1034/1301] input: Move all input drivers to a subdirectory --- Cargo.toml | 5 +++-- {ps2d => input/ps2d}/.gitignore | 0 {ps2d => input/ps2d}/Cargo.toml | 2 +- {ps2d => input/ps2d}/src/controller.rs | 0 {ps2d => input/ps2d}/src/keymap.rs | 0 {ps2d => input/ps2d}/src/main.rs | 0 {ps2d => input/ps2d}/src/state.rs | 0 {ps2d => input/ps2d}/src/vm.rs | 0 {usbhidd => input/usbhidd}/.gitignore | 0 {usbhidd => input/usbhidd}/Cargo.toml | 4 ++-- {usbhidd => input/usbhidd}/src/keymap.rs | 0 {usbhidd => input/usbhidd}/src/main.rs | 0 {usbhidd => input/usbhidd}/src/reqs.rs | 0 13 files changed, 6 insertions(+), 5 deletions(-) rename {ps2d => input/ps2d}/.gitignore (100%) rename {ps2d => input/ps2d}/Cargo.toml (84%) rename {ps2d => input/ps2d}/src/controller.rs (100%) rename {ps2d => input/ps2d}/src/keymap.rs (100%) rename {ps2d => input/ps2d}/src/main.rs (100%) rename {ps2d => input/ps2d}/src/state.rs (100%) rename {ps2d => input/ps2d}/src/vm.rs (100%) rename {usbhidd => input/usbhidd}/.gitignore (100%) rename {usbhidd => input/usbhidd}/Cargo.toml (84%) rename {usbhidd => input/usbhidd}/src/keymap.rs (100%) rename {usbhidd => input/usbhidd}/src/main.rs (100%) rename {usbhidd => input/usbhidd}/src/reqs.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index ed8c1bd82f..a8d2519edb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,12 +4,10 @@ members = [ "common", "hwd", "pcid", - "ps2d", "vboxd", "xhcid", "usbctl", "usbhubd", - "usbhidd", "inputd", "virtio-core", @@ -23,6 +21,9 @@ members = [ "graphics/vesad", "graphics/virtio-gpud", + "input/ps2d", + "input/usbhidd", + "net/alxd", "net/driver-network", "net/e1000d", diff --git a/ps2d/.gitignore b/input/ps2d/.gitignore similarity index 100% rename from ps2d/.gitignore rename to input/ps2d/.gitignore diff --git a/ps2d/Cargo.toml b/input/ps2d/Cargo.toml similarity index 84% rename from ps2d/Cargo.toml rename to input/ps2d/Cargo.toml index 78f9dbe207..233e027e6f 100644 --- a/ps2d/Cargo.toml +++ b/input/ps2d/Cargo.toml @@ -11,4 +11,4 @@ redox_syscall = "0.5" redox-daemon = "0.1" libredox = "0.1.3" -common = { path = "../common" } +common = { path = "../../common" } diff --git a/ps2d/src/controller.rs b/input/ps2d/src/controller.rs similarity index 100% rename from ps2d/src/controller.rs rename to input/ps2d/src/controller.rs diff --git a/ps2d/src/keymap.rs b/input/ps2d/src/keymap.rs similarity index 100% rename from ps2d/src/keymap.rs rename to input/ps2d/src/keymap.rs diff --git a/ps2d/src/main.rs b/input/ps2d/src/main.rs similarity index 100% rename from ps2d/src/main.rs rename to input/ps2d/src/main.rs diff --git a/ps2d/src/state.rs b/input/ps2d/src/state.rs similarity index 100% rename from ps2d/src/state.rs rename to input/ps2d/src/state.rs diff --git a/ps2d/src/vm.rs b/input/ps2d/src/vm.rs similarity index 100% rename from ps2d/src/vm.rs rename to input/ps2d/src/vm.rs diff --git a/usbhidd/.gitignore b/input/usbhidd/.gitignore similarity index 100% rename from usbhidd/.gitignore rename to input/usbhidd/.gitignore diff --git a/usbhidd/Cargo.toml b/input/usbhidd/Cargo.toml similarity index 84% rename from usbhidd/Cargo.toml rename to input/usbhidd/Cargo.toml index 52a7b01ce9..0d5929a857 100644 --- a/usbhidd/Cargo.toml +++ b/input/usbhidd/Cargo.toml @@ -13,6 +13,6 @@ log = "0.4" orbclient = "0.3.47" redox_syscall = "0.5" rehid = { git = "https://gitlab.redox-os.org/redox-os/rehid.git" } -xhcid = { path = "../xhcid" } +xhcid = { path = "../../xhcid" } -common = { path = "../common" } +common = { path = "../../common" } diff --git a/usbhidd/src/keymap.rs b/input/usbhidd/src/keymap.rs similarity index 100% rename from usbhidd/src/keymap.rs rename to input/usbhidd/src/keymap.rs diff --git a/usbhidd/src/main.rs b/input/usbhidd/src/main.rs similarity index 100% rename from usbhidd/src/main.rs rename to input/usbhidd/src/main.rs diff --git a/usbhidd/src/reqs.rs b/input/usbhidd/src/reqs.rs similarity index 100% rename from usbhidd/src/reqs.rs rename to input/usbhidd/src/reqs.rs From e3eb5fbb5dda8c5c8880e42169f0af9f4c95f868 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 24 Dec 2024 15:07:27 +0100 Subject: [PATCH 1035/1301] input/ps2d: Use redox_event --- Cargo.lock | 1 + input/ps2d/Cargo.toml | 1 + input/ps2d/src/main.rs | 63 +++++++++++++++++++----------------------- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2d1329e6a3..cdb562c6cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1039,6 +1039,7 @@ dependencies = [ "log", "orbclient", "redox-daemon", + "redox_event", "redox_syscall", ] diff --git a/input/ps2d/Cargo.toml b/input/ps2d/Cargo.toml index 233e027e6f..212a3e078a 100644 --- a/input/ps2d/Cargo.toml +++ b/input/ps2d/Cargo.toml @@ -7,6 +7,7 @@ edition = "2018" bitflags = "1" log = "0.4" orbclient = "0.3.27" +redox_event = "0.4.1" redox_syscall = "0.5" redox-daemon = "0.1" libredox = "0.1.3" diff --git a/input/ps2d/src/main.rs b/input/ps2d/src/main.rs index 5455aaa161..7399bbd0a2 100644 --- a/input/ps2d/src/main.rs +++ b/input/ps2d/src/main.rs @@ -6,11 +6,12 @@ extern crate orbclient; extern crate syscall; use std::fs::OpenOptions; -use std::io::{Read, Write}; +use std::io::Read; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; use std::{env, process}; +use event::{user_data, EventQueue}; use log::info; use syscall::call::iopl; @@ -54,11 +55,15 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .open("/scheme/input/producer") .expect("ps2d: failed to open /scheme/input/producer"); - let mut event_file = OpenOptions::new() - .read(true) - .write(true) - .open("/scheme/event") - .expect("ps2d: failed to open /scheme/event"); + user_data! { + enum Source { + Keyboard, + Mouse, + } + } + + let event_queue: EventQueue = + EventQueue::new().expect("ps2d: failed to create event queue"); let mut key_file = OpenOptions::new() .read(true) @@ -67,13 +72,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .open("/scheme/serio/0") .expect("ps2d: failed to open /scheme/serio/0"); - event_file - .write(&syscall::Event { - id: key_file.as_raw_fd() as usize, - flags: syscall::EVENT_READ, - data: 0, - }) - .expect("ps2d: failed to event /scheme/serio/0"); + event_queue + .subscribe( + key_file.as_raw_fd() as usize, + Source::Keyboard, + event::EventFlags::READ, + ) + .unwrap(); let mut mouse_file = OpenOptions::new() .read(true) @@ -82,13 +87,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .open("/scheme/serio/1") .expect("ps2d: failed to open /scheme/serio/1"); - event_file - .write(&syscall::Event { - id: mouse_file.as_raw_fd() as usize, - flags: syscall::EVENT_READ, - data: 1, - }) - .expect("ps2d: failed to event /scheme/serio/1"); + event_queue + .subscribe( + mouse_file.as_raw_fd() as usize, + Source::Mouse, + event::EventFlags::READ, + ) + .unwrap(); libredox::call::setrens(0, 0).expect("ps2d: failed to enter null namespace"); @@ -99,7 +104,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut ps2d = Ps2d::new(input, keymap); let mut data = [0; 256]; - loop { + for event in event_queue.map(|e| e.expect("ps2d: failed to get next event").user_data) { // There are some gotchas with ps/2 controllers that require this weird // way of doing things. You read key and mouse data from the same // place. There is a status register that may show you which the data @@ -109,19 +114,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // Due to this, we have a kernel driver doing a small amount of work // to grab bytes and sort them based on the source - let mut event = syscall::Event::default(); - if event_file - .read(&mut event) - .expect("ps2d: failed to read event file") - == 0 - { - break; - } - - let (file, keyboard) = match event.data { - 0 => (&mut key_file, true), - 1 => (&mut mouse_file, false), - _ => continue, + let (file, keyboard) = match event { + Source::Keyboard => (&mut key_file, true), + Source::Mouse => (&mut mouse_file, false), }; loop { From aa35e573cf94157065b100225930caf5bc31c6d1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 24 Dec 2024 15:28:34 +0100 Subject: [PATCH 1036/1301] input: Introduce ProducerHandle type --- Cargo.lock | 3 +++ graphics/bgad/Cargo.toml | 1 + graphics/bgad/src/main.rs | 3 ++- graphics/bgad/src/scheme.rs | 9 ++++--- input/ps2d/Cargo.toml | 1 + input/ps2d/src/main.rs | 6 ++--- input/ps2d/src/state.rs | 48 +++++++++++++++++-------------------- input/usbhidd/Cargo.toml | 1 + input/usbhidd/src/main.rs | 18 +++++++------- inputd/src/lib.rs | 13 ++++++++++ 10 files changed, 57 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cdb562c6cc..a56be31c9d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -190,6 +190,7 @@ name = "bgad" version = "0.1.0" dependencies = [ "common", + "inputd", "libredox", "orbclient", "pcid", @@ -1035,6 +1036,7 @@ version = "0.1.0" dependencies = [ "bitflags 1.3.2", "common", + "inputd", "libredox", "log", "orbclient", @@ -1594,6 +1596,7 @@ version = "0.1.0" dependencies = [ "bitflags 2.6.0", "common", + "inputd", "log", "orbclient", "redox_syscall", diff --git a/graphics/bgad/Cargo.toml b/graphics/bgad/Cargo.toml index 4e9fe1ae5f..eadf2c22f9 100644 --- a/graphics/bgad/Cargo.toml +++ b/graphics/bgad/Cargo.toml @@ -9,5 +9,6 @@ redox-daemon = "0.1" redox_syscall = "0.5" common = { path = "../../common" } +inputd = { path = "../../inputd" } pcid = { path = "../../pcid" } libredox = "0.1.3" diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index ad3a4fe393..a208db2b27 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -4,6 +4,7 @@ extern crate syscall; use std::fs::File; use std::io::{Read, Write}; +use inputd::ProducerHandle; use pcid_interface::PciFunctionHandle; use syscall::call::iopl; use syscall::data::Packet; @@ -35,7 +36,7 @@ fn main() { let mut scheme = BgaScheme { bga, - display: File::open("/scheme/input/producer").ok(), + display: ProducerHandle::new().ok(), }; scheme.update_size(); diff --git a/graphics/bgad/src/scheme.rs b/graphics/bgad/src/scheme.rs index 1a1315df0e..197f0ec01d 100644 --- a/graphics/bgad/src/scheme.rs +++ b/graphics/bgad/src/scheme.rs @@ -1,6 +1,5 @@ -use std::fs::File; -use std::io::Write; use std::str; +use inputd::ProducerHandle; use syscall::data::Stat; use syscall::{Error, Result, SchemeMut, EACCES, EINVAL, MODE_CHR}; @@ -8,14 +7,14 @@ use crate::bga::Bga; pub struct BgaScheme { pub bga: Bga, - pub display: Option, + pub display: Option, } impl BgaScheme { pub fn update_size(&mut self) { if let Some(ref mut display) = self.display { - let _ = display.write( - &orbclient::ResizeEvent { + let _ = display.write_event( + orbclient::ResizeEvent { width: self.bga.width() as u32, height: self.bga.height() as u32, } diff --git a/input/ps2d/Cargo.toml b/input/ps2d/Cargo.toml index 212a3e078a..9e3298eb17 100644 --- a/input/ps2d/Cargo.toml +++ b/input/ps2d/Cargo.toml @@ -13,3 +13,4 @@ redox-daemon = "0.1" libredox = "0.1.3" common = { path = "../../common" } +inputd = { path = "../../inputd" } diff --git a/input/ps2d/src/main.rs b/input/ps2d/src/main.rs index 7399bbd0a2..186904cf9a 100644 --- a/input/ps2d/src/main.rs +++ b/input/ps2d/src/main.rs @@ -12,6 +12,7 @@ use std::os::unix::io::AsRawFd; use std::{env, process}; use event::{user_data, EventQueue}; +use inputd::ProducerHandle; use log::info; use syscall::call::iopl; @@ -50,10 +51,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { info!("ps2d: using keymap '{}'", keymap_name); - let input = OpenOptions::new() - .write(true) - .open("/scheme/input/producer") - .expect("ps2d: failed to open /scheme/input/producer"); + let input = ProducerHandle::new().expect("ps2d: failed to open input producer"); user_data! { enum Source { diff --git a/input/ps2d/src/state.rs b/input/ps2d/src/state.rs index b25cec9455..711c7bfbbf 100644 --- a/input/ps2d/src/state.rs +++ b/input/ps2d/src/state.rs @@ -1,8 +1,4 @@ -use std::fs::File; -use std::io::Write; -use std::os::unix::io::AsRawFd; -use std::str; - +use inputd::ProducerHandle; use log::{error, warn}; use orbclient::{ButtonEvent, KeyEvent, MouseEvent, MouseRelativeEvent, ScrollEvent}; @@ -26,7 +22,7 @@ pub struct Ps2d char> { ps2: Ps2, vmmouse: bool, vmmouse_relative: bool, - input: File, + input: ProducerHandle, extended: bool, lshift: bool, rshift: bool, @@ -43,7 +39,7 @@ pub struct Ps2d char> { } impl char> Ps2d { - pub fn new(input: File, keymap: F) -> Self { + pub fn new(input: ProducerHandle, keymap: F) -> Self { let mut ps2 = Ps2::new(); let extra_packet = ps2.init().expect("ps2d: failed to initialize"); @@ -229,8 +225,8 @@ impl char> Ps2d { if scancode != 0 { self.input - .write( - &KeyEvent { + .write_event( + KeyEvent { character: (self.get_char)( ps2_scancode, self.lshift || self.rshift, @@ -263,8 +259,8 @@ impl char> Ps2d { if self.vmmouse_relative { if dx != 0 || dy != 0 { self.input - .write( - &MouseRelativeEvent { + .write_event( + MouseRelativeEvent { dx: dx as i32, dy: dy as i32, } @@ -279,15 +275,15 @@ impl char> Ps2d { self.mouse_x = x; self.mouse_y = y; self.input - .write(&MouseEvent { x, y }.to_event()) + .write_event(MouseEvent { x, y }.to_event()) .expect("ps2d: failed to write mouse event"); } }; if dz != 0 { self.input - .write( - &ScrollEvent { + .write_event( + ScrollEvent { x: 0, y: -(dz as i32), } @@ -307,11 +303,11 @@ impl char> Ps2d { self.mouse_middle = middle; self.mouse_right = right; self.input - .write( - &ButtonEvent { - left: left, - middle: middle, - right: right, + .write_event( + ButtonEvent { + left, + middle, + right, } .to_event(), ) @@ -355,13 +351,13 @@ impl char> Ps2d { if dx != 0 || dy != 0 { self.input - .write(&MouseRelativeEvent { dx: dx, dy: dy }.to_event()) + .write_event(MouseRelativeEvent { dx, dy }.to_event()) .expect("ps2d: failed to write mouse event"); } if dz != 0 { self.input - .write(&ScrollEvent { x: 0, y: dz }.to_event()) + .write_event(ScrollEvent { x: 0, y: dz }.to_event()) .expect("ps2d: failed to write scroll event"); } @@ -376,11 +372,11 @@ impl char> Ps2d { self.mouse_middle = middle; self.mouse_right = right; self.input - .write( - &ButtonEvent { - left: left, - middle: middle, - right: right, + .write_event( + ButtonEvent { + left, + middle, + right, } .to_event(), ) diff --git a/input/usbhidd/Cargo.toml b/input/usbhidd/Cargo.toml index 0d5929a857..0a3df4d43c 100644 --- a/input/usbhidd/Cargo.toml +++ b/input/usbhidd/Cargo.toml @@ -16,3 +16,4 @@ rehid = { git = "https://gitlab.redox-os.org/redox-os/rehid.git" } xhcid = { path = "../../xhcid" } common = { path = "../../common" } +inputd = { path = "../../inputd" } diff --git a/input/usbhidd/src/main.rs b/input/usbhidd/src/main.rs index ca19f1905d..ed79994e1a 100644 --- a/input/usbhidd/src/main.rs +++ b/input/usbhidd/src/main.rs @@ -1,8 +1,7 @@ use std::collections::VecDeque; use std::env; -use std::fs::File; -use std::io::{Read, Write}; +use inputd::ProducerHandle; use orbclient::KeyEvent as OrbKeyEvent; use rehid::{ report_desc::{self, ReportTy, REPORT_DESC_TY}, @@ -17,7 +16,7 @@ mod keymap; mod reqs; fn send_key_event( - display: &mut File, + display: &mut ProducerHandle, usage_page: u16, usage: u16, pressed: bool, @@ -159,7 +158,7 @@ fn send_key_event( pressed, }; - match display.write(&key_event.to_event()) { + match display.write_event(key_event.to_event()) { Ok(_) => (), Err(err) => { log::warn!("failed to send key event to orbital: {}", err); @@ -277,8 +276,7 @@ fn main() { let report_ty = ReportTy::Input; let report_id = 0; - let mut display = - File::open("/scheme/input/producer").expect("Failed to open orbital input socket"); + let mut display = ProducerHandle::new().expect("Failed to open input socket"); let mut endpoint_opt = match endp_desc_opt { Some((endp_num, _endp_desc)) => match handle.open_endpoint(endp_num as u8) { Ok(ok) => Some(ok), @@ -405,7 +403,7 @@ fn main() { y: mouse_pos.1 * 2, }; - match display.write(&mouse_event.to_event()) { + match display.write_event(mouse_event.to_event()) { Ok(_) => (), Err(err) => { log::warn!("failed to send mouse event to orbital: {}", err); @@ -419,7 +417,7 @@ fn main() { dy: mouse_dy, }; - match display.write(&mouse_event.to_event()) { + match display.write_event(mouse_event.to_event()) { Ok(_) => (), Err(err) => { log::warn!("failed to send mouse event to orbital: {}", err); @@ -430,7 +428,7 @@ fn main() { if scroll_y != 0 { let scroll_event = orbclient::event::ScrollEvent { x: 0, y: scroll_y }; - match display.write(&scroll_event.to_event()) { + match display.write_event(scroll_event.to_event()) { Ok(_) => (), Err(err) => { log::warn!("failed to send scroll event to orbital: {}", err); @@ -447,7 +445,7 @@ fn main() { middle: buttons[2], }; - match display.write(&button_event.to_event()) { + match display.write_event(button_event.to_event()) { Ok(_) => (), Err(err) => { log::warn!("failed to send button event to orbital: {}", err); diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 8956964ed6..4bc019d4ad 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -162,3 +162,16 @@ impl Damage { self } } + +pub struct ProducerHandle(File); + +impl ProducerHandle { + pub fn new() -> Result { + File::open("/scheme/input/producer").map(ProducerHandle) + } + + pub fn write_event(&mut self, event: orbclient::Event) -> Result<(), Error> { + self.0.write(&event)?; + Ok(()) + } +} From f4897c59b46437d8fc0b5d55dcd3919d85f58e5c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 24 Dec 2024 16:34:25 +0100 Subject: [PATCH 1037/1301] graphics/fbcond: Inline some helpers --- graphics/fbcond/src/display.rs | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 2cd4d897dd..d38d99981e 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -157,22 +157,8 @@ impl Display { let url = String::from_utf8(Vec::from(&buf[..count])).expect("Could not create Utf8 Url String"); - let path = Self::url_parts(&url)?; - let (width, height) = Self::parse_display_path(path); + let path = url.split(':').nth(1).expect("Could not get path from url"); - Ok((display_file, width, height)) - } - - fn url_parts(url: &str) -> io::Result<&str> { - let mut url_parts = url.split(':'); - url_parts - .next() - .expect("Could not get scheme name from url"); - let path = url_parts.next().expect("Could not get path from url"); - Ok(path) - } - - fn parse_display_path(path: &str) -> (usize, usize) { let mut path_parts = path.split('/').skip(1); let width = path_parts .next() @@ -185,7 +171,7 @@ impl Display { .parse::() .unwrap_or(0); - (width, height) + Ok((display_file, width, height)) } pub fn resize(&mut self, width: usize, height: usize) { From 5a1648fdca13d5f7fa656fee98d01a55d1daa31e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 24 Dec 2024 16:56:11 +0100 Subject: [PATCH 1038/1301] graphics/fbcond: Migrate to redox-scheme --- Cargo.lock | 1 + graphics/fbcond/Cargo.toml | 1 + graphics/fbcond/src/main.rs | 109 +++++++++++++++------------------- graphics/fbcond/src/scheme.rs | 79 +++++++++++++----------- graphics/fbcond/src/text.rs | 8 +-- 5 files changed, 98 insertions(+), 100 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a56be31c9d..fc46dcb053 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -424,6 +424,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", + "redox-scheme", "redox_event", "redox_syscall", ] diff --git a/graphics/fbcond/Cargo.toml b/graphics/fbcond/Cargo.toml index 42e155eaac..a22c102f40 100644 --- a/graphics/fbcond/Cargo.toml +++ b/graphics/fbcond/Cargo.toml @@ -9,6 +9,7 @@ ransid = "0.4" redox_event = "0.4" redox_syscall = "0.5" redox-daemon = "0.1" +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } inputd = { path = "../../inputd" } libredox = "0.1.3" diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 09c9a44478..11ac25cec2 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -1,14 +1,12 @@ #![feature(io_error_more)] use event::EventQueue; -use libredox::errno::ESTALE; +use libredox::errno::{EAGAIN, EINTR, ESTALE}; use orbclient::Event; -use std::fs::{File, OpenOptions}; -use std::io::{ErrorKind, Read, Write}; +use redox_scheme::{CallRequest, RequestKind, Response, SignalBehavior, Socket}; use std::os::fd::{AsRawFd, BorrowedFd}; -use std::os::unix::fs::OpenOptionsExt; use std::{env, mem, slice}; -use syscall::{Packet, SchemeMut, EVENT_READ, O_NONBLOCK}; +use syscall::EVENT_READ; use crate::scheme::{FbconScheme, VtIndex}; @@ -42,16 +40,10 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { // FIXME listen for resize events from inputd and handle them - let mut socket = OpenOptions::new() - .write(true) - .create(true) - .truncate(true) - .custom_flags(O_NONBLOCK as i32) - .open(":fbcon") - .expect("fbcond: failed to create fbcon scheme"); + let mut socket = Socket::nonblock("fbcon").expect("fbcond: failed to create fbcon scheme"); event_queue .subscribe( - socket.as_raw_fd().as_raw_fd() as usize, + socket.inner().raw(), VtIndex::SCHEMA_SENTINEL, event::EventFlags::READ, ) @@ -91,37 +83,49 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { } fn handle_event( - socket: &mut File, + socket: &mut Socket, scheme: &mut FbconScheme, - blocked: &mut Vec, + blocked: &mut Vec, event: VtIndex, ) { match event { VtIndex::SCHEMA_SENTINEL => { loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => break, - Err(err) if err.kind() == ErrorKind::WouldBlock => { - break; + let request = match socket.next_request(SignalBehavior::Restart) { + Ok(Some(request)) => request, + Ok(None) => { + // Scheme likely got unmounted + std::process::exit(0); } - Ok(_) => {} - Err(err) => { - panic!("fbcond: failed to read display scheme: {err}"); - } - } + Err(err) if err.errno == EAGAIN => break, + Err(err) => panic!("vesad: failed to read display scheme: {err}"), + }; - // If it is a read packet, and there is no data, block it. Otherwise, handle packet - if packet.a == syscall::number::SYS_READ - && packet.d > 0 - && scheme.can_read(packet.b).is_none() - { - blocked.push(packet); - } else { - scheme.handle(&mut packet); - socket - .write(&packet) - .expect("fbcond: failed to write display scheme"); + match request.kind() { + RequestKind::Call(call_request) => { + if let Some(resp) = call_request.handle_scheme_block_mut(scheme) { + socket + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + } else { + blocked.push(call_request); + } + } + RequestKind::Cancellation(cancellation_request) => { + if let Some(i) = blocked + .iter() + .position(|req| req.request().request_id() == cancellation_request.id) + { + let blocked_req = blocked.remove(i); + let resp = Response::new(&blocked_req, Err(syscall::Error::new(EINTR))); + socket + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + } + } + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() + } } } } @@ -150,16 +154,15 @@ fn handle_event( } } - // If there are blocked readers, and data is available, handle them + // If there are blocked readers, try to handle them. { let mut i = 0; while i < blocked.len() { - if scheme.can_read(blocked[i].b).is_some() { - let mut packet = blocked.remove(i); - scheme.handle(&mut packet); + if let Some(resp) = blocked[i].handle_scheme_block_mut(scheme) { socket - .write(&packet) - .expect("fbcond: failed to write display scheme"); + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + blocked.remove(i); } else { i += 1; } @@ -171,30 +174,16 @@ fn handle_event( continue; } - // Can't use scheme.can_read() because we borrow handles as mutable. - // (and because it'd treat O_NONBLOCK sockets differently) - let count = scheme + let can_read = scheme .vts .get(&handle.vt_i) - .and_then(|console| console.can_read()) - .unwrap_or(0); + .map_or(false, |console| console.can_read()); - if count > 0 { + if can_read { if !handle.notified_read { handle.notified_read = true; - let event_packet = Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: *handle_id, - c: EVENT_READ.bits(), - d: count, - }; - socket - .write(&event_packet) + .post_fevent(*handle_id, EVENT_READ.bits()) .expect("fbcond: failed to write display event"); } } else { diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index 4b8afe212e..1b37b6674c 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -2,7 +2,8 @@ use std::collections::BTreeMap; use std::os::fd::AsRawFd; use event::{EventQueue, UserData}; -use syscall::{Error, EventFlags, Result, SchemeMut, EBADF, EINVAL, ENOENT, O_NONBLOCK}; +use redox_scheme::SchemeBlockMut; +use syscall::{Error, EventFlags, Result, EBADF, EINVAL, ENOENT, O_NONBLOCK}; use crate::display::Display; use crate::text::TextScreen; @@ -61,22 +62,6 @@ impl FbconScheme { } } - pub fn can_read(&self, id: usize) -> Option { - if let Some(handle) = self.handles.get(&id) { - if let Some(console) = self.vts.get(&handle.vt_i) { - console - .can_read() - .or(if handle.flags & O_NONBLOCK == O_NONBLOCK { - Some(0) - } else { - None - }); - } - } - - Some(0) - } - fn resize(&mut self, width: usize, height: usize, stride: usize) { for console in self.vts.values_mut() { console.resize(width, height); @@ -84,8 +69,14 @@ impl FbconScheme { } } -impl SchemeMut for FbconScheme { - fn open(&mut self, path_str: &str, flags: usize, _uid: u32, _gid: u32) -> Result { +impl SchemeBlockMut for FbconScheme { + fn open( + &mut self, + path_str: &str, + flags: usize, + _uid: u32, + _gid: u32, + ) -> Result> { let vt_i = VtIndex(path_str.parse::().map_err(|_| Error::new(ENOENT))?); if let Some(_console) = self.vts.get_mut(&vt_i) { let id = self.next_id; @@ -101,13 +92,13 @@ impl SchemeMut for FbconScheme { }, ); - Ok(id) + Ok(Some(id)) } else { Err(Error::new(ENOENT)) } } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result { + fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { if !buf.is_empty() { return Err(Error::new(EINVAL)); } @@ -123,19 +114,23 @@ impl SchemeMut for FbconScheme { self.handles.insert(new_id, handle); - Ok(new_id) + Ok(Some(new_id)) } - fn fevent(&mut self, id: usize, flags: syscall::EventFlags) -> Result { + fn fevent( + &mut self, + id: usize, + flags: syscall::EventFlags, + ) -> Result> { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; handle.notified_read = false; handle.events = flags; - Ok(syscall::EventFlags::empty()) + Ok(Some(syscall::EventFlags::empty())) } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; let path_str = format!("fbcon:{}", handle.vt_i.0); @@ -148,37 +143,53 @@ impl SchemeMut for FbconScheme { i += 1; } - Ok(i) + Ok(Some(i)) } - fn fsync(&mut self, id: usize) -> Result { + fn fsync(&mut self, id: usize) -> Result> { let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - return Ok(0); + return Ok(Some(0)); } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result { + fn read( + &mut self, + id: usize, + buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let Some(screen) = self.vts.get_mut(&handle.vt_i) { - return screen.read(buf); + if !screen.can_read() && handle.flags & O_NONBLOCK != O_NONBLOCK { + return Ok(None); + } else { + return screen.read(buf).map(Some); + } } Err(Error::new(EBADF)) } - fn write(&mut self, id: usize, buf: &[u8]) -> Result { + fn write( + &mut self, + id: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; if let Some(console) = self.vts.get_mut(&handle.vt_i) { - console.write(buf) + console.write(buf).map(Some) } else { Err(Error::new(EBADF)) } } - fn close(&mut self, id: usize) -> Result { + fn close(&mut self, id: usize) -> Result> { self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(0) + Ok(Some(0)) } } diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index d62b15f502..bbe519b117 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -204,12 +204,8 @@ impl TextScreen { } } - pub fn can_read(&self) -> Option { - if self.input.is_empty() { - None - } else { - Some(self.input.len()) - } + pub fn can_read(&self) -> bool { + !self.input.is_empty() } } From 4e2f1a730caefd67e3f2dbaacb5ad6782132d14f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 24 Dec 2024 21:05:26 +0100 Subject: [PATCH 1039/1301] graphics: Introduce a separate daemon for the boot log The daemon responsible for the boot log must never ever block to avoid deadlocks, but doing so while still accepting keyboard input is non-trivial. This commit splits the boot log out from fbcond into a separate daemon to make this a lot easier to implement. This will also allow making fbcond blocking again, which will simplify some things. --- Cargo.lock | 25 ++++ Cargo.toml | 2 + graphics/bgad/src/scheme.rs | 2 +- graphics/console-draw/Cargo.toml | 13 ++ graphics/console-draw/src/lib.rs | 230 +++++++++++++++++++++++++++++ graphics/fbbootlogd/Cargo.toml | 19 +++ graphics/fbbootlogd/src/display.rs | 202 +++++++++++++++++++++++++ graphics/fbbootlogd/src/main.rs | 68 +++++++++ graphics/fbbootlogd/src/scheme.rs | 124 ++++++++++++++++ graphics/fbbootlogd/src/text.rs | 41 +++++ graphics/fbcond/Cargo.toml | 1 + graphics/fbcond/src/main.rs | 4 - graphics/fbcond/src/text.rs | 223 +++------------------------- 13 files changed, 744 insertions(+), 210 deletions(-) create mode 100644 graphics/console-draw/Cargo.toml create mode 100644 graphics/console-draw/src/lib.rs create mode 100644 graphics/fbbootlogd/Cargo.toml create mode 100644 graphics/fbbootlogd/src/display.rs create mode 100644 graphics/fbbootlogd/src/main.rs create mode 100644 graphics/fbbootlogd/src/scheme.rs create mode 100644 graphics/fbbootlogd/src/text.rs diff --git a/Cargo.lock b/Cargo.lock index fc46dcb053..3bd00c9a93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,6 +322,15 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "console-draw" +version = "0.1.0" +dependencies = [ + "inputd", + "orbclient", + "ransid", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -415,10 +424,26 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "fbbootlogd" +version = "0.1.0" +dependencies = [ + "console-draw", + "inputd", + "libredox", + "orbclient", + "ransid", + "redox-daemon", + "redox-scheme", + "redox_event", + "redox_syscall", +] + [[package]] name = "fbcond" version = "0.1.0" dependencies = [ + "console-draw", "inputd", "libredox", "orbclient", diff --git a/Cargo.toml b/Cargo.toml index a8d2519edb..2181fb2841 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,8 @@ members = [ "audio/sb16d", "graphics/bgad", + "graphics/console-draw", + "graphics/fbbootlogd", "graphics/fbcond", "graphics/vesad", "graphics/virtio-gpud", diff --git a/graphics/bgad/src/scheme.rs b/graphics/bgad/src/scheme.rs index 197f0ec01d..0d536e4e9d 100644 --- a/graphics/bgad/src/scheme.rs +++ b/graphics/bgad/src/scheme.rs @@ -1,5 +1,5 @@ -use std::str; use inputd::ProducerHandle; +use std::str; use syscall::data::Stat; use syscall::{Error, Result, SchemeMut, EACCES, EINVAL, MODE_CHR}; diff --git a/graphics/console-draw/Cargo.toml b/graphics/console-draw/Cargo.toml new file mode 100644 index 0000000000..56d8d98562 --- /dev/null +++ b/graphics/console-draw/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "console-draw" +version = "0.1.0" +edition = "2021" + +[dependencies] +orbclient = "0.3.27" +ransid = "0.4" + +inputd = { path = "../../inputd" } + +[features] +default = [] diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs new file mode 100644 index 0000000000..d52e46c57f --- /dev/null +++ b/graphics/console-draw/src/lib.rs @@ -0,0 +1,230 @@ +extern crate ransid; + +use std::collections::{BTreeSet, VecDeque}; +use std::convert::{TryFrom, TryInto}; +use std::{cmp, ptr}; + +use inputd::Damage; +use orbclient::FONT; + +pub struct DisplayMap { + pub offscreen: *mut [u32], + pub width: usize, + pub height: usize, +} + +pub struct TextScreen { + console: ransid::Console, + changed: BTreeSet, +} + +impl TextScreen { + pub fn new() -> TextScreen { + TextScreen { + // Width and height will be filled in on the next write to the console + console: ransid::Console::new(0, 0), + changed: BTreeSet::new(), + } + } + + /// Draw a rectangle + fn rect(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize, color: u32) { + let start_y = cmp::min(map.height, y); + let end_y = cmp::min(map.height, y + h); + + let start_x = cmp::min(map.width, x); + let len = cmp::min(map.width, x + w) - start_x; + + let mut offscreen_ptr = map.offscreen as *mut u8 as usize; + + let stride = map.width * 4; + + let offset = y * stride + start_x * 4; + offscreen_ptr += offset; + + let mut rows = end_y - start_y; + while rows > 0 { + for i in 0..len { + unsafe { + *(offscreen_ptr as *mut u32).add(i) = color; + } + } + offscreen_ptr += stride; + rows -= 1; + } + } + + /// Invert a rectangle + fn invert(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize) { + let start_y = cmp::min(map.height, y); + let end_y = cmp::min(map.height, y + h); + + let start_x = cmp::min(map.width, x); + let len = cmp::min(map.width, x + w) - start_x; + + let mut offscreen_ptr = map.offscreen as *mut u8 as usize; + + let stride = map.width * 4; + + let offset = y * stride + start_x * 4; + offscreen_ptr += offset; + + let mut rows = end_y - start_y; + while rows > 0 { + let mut row_ptr = offscreen_ptr; + let mut cols = len; + while cols > 0 { + unsafe { + let color = *(row_ptr as *mut u32); + *(row_ptr as *mut u32) = !color; + } + row_ptr += 4; + cols -= 1; + } + offscreen_ptr += stride; + rows -= 1; + } + } + + /// Draw a character + fn char( + map: &mut DisplayMap, + x: usize, + y: usize, + character: char, + color: u32, + _bold: bool, + _italic: bool, + ) { + if x + 8 <= map.width && y + 16 <= map.height { + let mut dst = map.offscreen as *mut u8 as usize + (y * map.width + x) * 4; + + let font_i = 16 * (character as usize); + if font_i + 16 <= FONT.len() { + for row in 0..16 { + let row_data = FONT[font_i + row]; + for col in 0..8 { + if (row_data >> (7 - col)) & 1 == 1 { + unsafe { + *((dst + col * 4) as *mut u32) = color; + } + } + } + dst += map.width * 4; + } + } + } + } +} + +impl TextScreen { + pub fn write( + &mut self, + map: &mut DisplayMap, + buf: &[u8], + input: &mut VecDeque, + ) -> Vec { + self.console.state.w = map.width / 8; + self.console.state.h = map.height / 16; + self.console.state.bottom_margin = (map.height / 16).saturating_sub(1); + + if self.console.state.cursor + && self.console.state.x < self.console.state.w + && self.console.state.y < self.console.state.h + { + let x = self.console.state.x; + let y = self.console.state.y; + Self::invert(map, x * 8, y * 16, 8, 16); + self.changed.insert(y); + } + + { + let changed = &mut self.changed; + self.console.write(buf, |event| match event { + ransid::Event::Char { + x, + y, + c, + color, + bold, + .. + } => { + Self::char(map, x * 8, y * 16, c, color.as_rgb(), bold, false); + changed.insert(y); + } + ransid::Event::Input { data } => input.extend(data), + ransid::Event::Rect { x, y, w, h, color } => { + Self::rect(map, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); + for y2 in y..y + h { + changed.insert(y2); + } + } + ransid::Event::ScreenBuffer { .. } => (), + ransid::Event::Move { + from_x, + from_y, + to_x, + to_y, + w, + h, + } => { + let width = map.width; + let pixels = unsafe { &mut *map.offscreen }; + + for raw_y in 0..h { + let y = if from_y > to_y { raw_y } else { h - raw_y - 1 }; + + for pixel_y in 0..16 { + { + let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8; + let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8; + let len = w * 8; + + if off_from + len <= pixels.len() && off_to + len <= pixels.len() { + unsafe { + let data_ptr = pixels.as_mut_ptr() as *mut u32; + ptr::copy( + data_ptr.offset(off_from as isize), + data_ptr.offset(off_to as isize), + len, + ); + } + } + } + } + + changed.insert(to_y + y); + } + } + ransid::Event::Resize { .. } => (), + ransid::Event::Title { .. } => (), + }); + } + + if self.console.state.cursor + && self.console.state.x < self.console.state.w + && self.console.state.y < self.console.state.h + { + let x = self.console.state.x; + let y = self.console.state.y; + Self::invert(map, x * 8, y * 16, 8, 16); + self.changed.insert(y); + } + + let width = map.width.try_into().unwrap(); + let damage = self + .changed + .iter() + .map(|&change| Damage { + x: 0, + y: i32::try_from(change).unwrap() * 16, + width, + height: 16, + }) + .collect(); + + self.changed.clear(); + + damage + } +} diff --git a/graphics/fbbootlogd/Cargo.toml b/graphics/fbbootlogd/Cargo.toml new file mode 100644 index 0000000000..90862d2780 --- /dev/null +++ b/graphics/fbbootlogd/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "fbbootlogd" +version = "0.1.0" +edition = "2021" + +[dependencies] +orbclient = "0.3.27" +ransid = "0.4" +redox_event = "0.4" +redox_syscall = "0.5" +redox-daemon = "0.1" +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } + +console-draw = { path = "../console-draw" } +inputd = { path = "../../inputd" } +libredox = "0.1.3" + +[features] +default = [] diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs new file mode 100644 index 0000000000..ad3b39d4cb --- /dev/null +++ b/graphics/fbbootlogd/src/display.rs @@ -0,0 +1,202 @@ +use event::{user_data, EventQueue}; +use inputd::{ConsumerHandle, Damage}; +use libredox::errno::ESTALE; +use libredox::flag; +use orbclient::Event; +use std::mem; +use std::os::fd::BorrowedFd; +use std::sync::mpsc::{self, Receiver, Sender}; +use std::sync::{Arc, Mutex}; +use std::{fs::File, io, os::unix::io::AsRawFd, slice}; + +fn read_to_slice( + file: BorrowedFd, + buf: &mut [T], +) -> Result { + unsafe { + libredox::call::read( + file.as_raw_fd() as usize, + slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * mem::size_of::()), + ) + .map(|count| count / mem::size_of::()) + } +} + +fn display_fd_map(width: usize, height: usize, display_file: File) -> syscall::Result { + unsafe { + let display_ptr = libredox::call::mmap(libredox::call::MmapArgs { + fd: display_file.as_raw_fd() as usize, + offset: 0, + length: (width * height * 4), + prot: flag::PROT_READ | flag::PROT_WRITE, + flags: flag::MAP_SHARED, + addr: core::ptr::null_mut(), + })?; + let display_slice = slice::from_raw_parts_mut(display_ptr as *mut u32, width * height); + Ok(DisplayMap { + display_file: Arc::new(display_file), + offscreen: display_slice, + width, + height, + }) + } +} + +unsafe fn display_fd_unmap(image: *mut [u32]) { + let _ = libredox::call::munmap(image as *mut (), image.len()); +} + +pub struct DisplayMap { + display_file: Arc, + pub offscreen: *mut [u32], + pub width: usize, + pub height: usize, +} + +unsafe impl Send for DisplayMap {} +unsafe impl Sync for DisplayMap {} + +impl Drop for DisplayMap { + fn drop(&mut self) { + unsafe { + display_fd_unmap(self.offscreen); + } + } +} + +enum DisplayCommand { + SyncRects(Vec), +} + +pub struct Display { + cmd_tx: Sender, + pub map: Arc>, +} + +impl Display { + pub fn open_first_vt() -> io::Result { + let input_handle = ConsumerHandle::for_vt(1)?; + + let (display_file, width, height) = Self::open_display(&input_handle)?; + + let map = Arc::new(Mutex::new( + display_fd_map(width, height, display_file) + .unwrap_or_else(|e| panic!("failed to map display: {e}")), + )); + + let map_clone = map.clone(); + std::thread::spawn(move || { + Self::handle_input_events(map_clone, input_handle); + }); + + let (cmd_tx, cmd_rx) = mpsc::channel(); + let map_clone = map.clone(); + std::thread::spawn(move || { + Self::handle_sync_rect(map_clone, cmd_rx); + }); + + Ok(Self { cmd_tx, map }) + } + + fn open_display(input_handle: &ConsumerHandle) -> io::Result<(File, usize, usize)> { + let display_file = input_handle.open_display()?; + + let mut buf: [u8; 4096] = [0; 4096]; + let count = libredox::call::fpath(display_file.as_raw_fd() as usize, &mut buf) + .unwrap_or_else(|e| { + panic!("Could not read display path with fpath(): {e}"); + }); + + let url = + String::from_utf8(Vec::from(&buf[..count])).expect("Could not create Utf8 Url String"); + let path = url.split(':').nth(1).expect("Could not get path from url"); + + let mut path_parts = path.split('/').skip(1); + let width = path_parts + .next() + .unwrap_or("") + .parse::() + .unwrap_or(0); + let height = path_parts + .next() + .unwrap_or("") + .parse::() + .unwrap_or(0); + + Ok((display_file, width, height)) + } + + fn handle_input_events(map: Arc>, input_handle: ConsumerHandle) { + let event_queue = EventQueue::new().expect("fbbootlogd: failed to create event queue"); + + user_data! { + enum Source { + Input, + } + } + + // FIXME listen for resize events from inputd and handle them + + event_queue + .subscribe( + input_handle.inner().as_raw_fd() as usize, + Source::Input, + event::EventFlags::READ, + ) + .expect("fbbootlogd: failed to subscribe to scheme events"); + + let mut events = [Event::new(); 16]; + for Source::Input in event_queue.map(|event| event.unwrap().user_data) { + match read_to_slice(input_handle.inner(), &mut events) { + Err(err) if err.errno() == ESTALE => { + eprintln!("fbbootlogd: handoff requested"); + + let (new_display_file, width, height) = + Self::open_display(&input_handle).unwrap(); + + match display_fd_map(width, height, new_display_file) { + Ok(ok) => { + *map.lock().unwrap() = ok; + + eprintln!("fbbootlogd: handoff finished"); + } + Err(err) => { + eprintln!("fbbootlogd: failed to open display: {}", err); + } + } + } + + Ok(_count) => {} + Err(err) => { + panic!("fbbootlogd: error while reading events: {err}"); + } + } + } + } + + fn handle_sync_rect(map: Arc>, cmd_rx: Receiver) { + while let Ok(cmd) = cmd_rx.recv() { + match cmd { + DisplayCommand::SyncRects(sync_rects) => unsafe { + // We may not hold this lock across the write call to avoid deadlocking if the + // graphics driver tries to write to the bootlog. + let display_file = map.lock().unwrap().display_file.clone(); + libredox::call::write( + display_file.as_raw_fd() as usize, + slice::from_raw_parts( + sync_rects.as_ptr() as *const u8, + sync_rects.len() * mem::size_of::(), + ), + ) + .unwrap(); + }, + } + } + } + + pub fn sync_rects(&mut self, sync_rects: Vec) { + self.cmd_tx + .send(DisplayCommand::SyncRects(sync_rects)) + .unwrap(); + } +} diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs new file mode 100644 index 0000000000..a45601820d --- /dev/null +++ b/graphics/fbbootlogd/src/main.rs @@ -0,0 +1,68 @@ +//! Fbbootlogd renders the boot log and presents it on VT1. +//! +//! While fbbootlogd is superficially similar to fbcond, there are two major differences: +//! +//! * Fbbootlogd doesn't accept input coming from the keyboard. It only allows getting written to. +//! * Writing to fbbootlogd will never block. Not even on the graphics driver or inputd. This makes +//! it safe for graphics drivers and inputd to write to the boot log without risking deadlocks. +//! Fbcond will block on the graphics driver during handoff and will continously block on inputd +//! to get new input. Fbbootlogd does all blocking operations in background threads such that the +//! main thread will always keep accepting new input and writing it to the framebuffer. + +#![feature(io_error_more)] + +use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; + +use crate::scheme::FbbootlogScheme; + +mod display; +mod scheme; +mod text; + +fn main() { + redox_daemon::Daemon::new(|daemon| inner(daemon)).expect("failed to create daemon"); +} +fn inner(daemon: redox_daemon::Daemon) -> ! { + let socket: Socket = + Socket::create("fbbootlog").expect("fbbootlogd: failed to create fbbootlog scheme"); + + let mut scheme = FbbootlogScheme::new(); + + let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); + + // This is not possible for now as fbbootlogd needs to open new displays at runtime for graphics + // driver handoff. In the future inputd may directly pass a handle to the display instead. + //libredox::call::setrens(0, 0).expect("fbbootlogd: failed to enter null namespace"); + + daemon.ready().expect("failed to notify parent"); + + inputd_control_handle.activate_vt(1).unwrap(); + + loop { + let request = match socket + .next_request(SignalBehavior::Restart) + .expect("fbbootlogd: failed to read display scheme") + { + Some(request) => request, + None => { + // Scheme likely got unmounted + std::process::exit(0); + } + }; + + match request.kind() { + RequestKind::Call(call_request) => { + socket + .write_response( + call_request.handle_scheme_mut(&mut scheme), + SignalBehavior::Restart, + ) + .expect("fbbootlogd: failed to write display scheme"); + } + RequestKind::Cancellation(_cancellation_request) => {} + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() + } + } + } +} diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs new file mode 100644 index 0000000000..fa258d6c53 --- /dev/null +++ b/graphics/fbbootlogd/src/scheme.rs @@ -0,0 +1,124 @@ +use std::collections::BTreeMap; + +use redox_scheme::SchemeMut; +use syscall::{Error, EventFlags, Result, EBADF, EINVAL, ENOENT}; + +use crate::display::Display; +use crate::text::TextScreen; + +#[derive(Clone)] +pub struct Handle { + pub events: EventFlags, + pub notified_read: bool, +} + +pub struct FbbootlogScheme { + pub screen: TextScreen, + next_id: usize, + pub handles: BTreeMap, +} + +impl FbbootlogScheme { + pub fn new() -> FbbootlogScheme { + let display = Display::open_first_vt().expect("Failed to open display for vt"); + let screen = TextScreen::new(display); + + FbbootlogScheme { + screen, + next_id: 0, + handles: BTreeMap::new(), + } + } +} + +impl SchemeMut for FbbootlogScheme { + fn open(&mut self, path_str: &str, _flags: usize, _uid: u32, _gid: u32) -> Result { + if !path_str.is_empty() { + return Err(Error::new(ENOENT)); + } + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert( + id, + Handle { + events: EventFlags::empty(), + notified_read: false, + }, + ); + + Ok(id) + } + + fn dup(&mut self, id: usize, buf: &[u8]) -> Result { + if !buf.is_empty() { + return Err(Error::new(EINVAL)); + } + + let handle = self + .handles + .get(&id) + .map(|handle| handle.clone()) + .ok_or(Error::new(EBADF))?; + + let new_id = self.next_id; + self.next_id += 1; + + self.handles.insert(new_id, handle); + + Ok(new_id) + } + + fn fevent(&mut self, id: usize, flags: syscall::EventFlags) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + handle.notified_read = false; + + handle.events = flags; + Ok(syscall::EventFlags::empty()) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let path = b"fbbootlog:"; + + let mut i = 0; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; + i += 1; + } + + Ok(i) + } + + fn fsync(&mut self, id: usize) -> Result { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + return Ok(0); + } + + fn read( + &mut self, + id: usize, + _buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + ) -> Result { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + Err(Error::new(EINVAL)) + } + + fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + self.screen.write(buf) + } + + fn close(&mut self, id: usize) -> Result { + self.handles.remove(&id).ok_or(Error::new(EBADF))?; + Ok(0) + } +} diff --git a/graphics/fbbootlogd/src/text.rs b/graphics/fbbootlogd/src/text.rs new file mode 100644 index 0000000000..5dff07d565 --- /dev/null +++ b/graphics/fbbootlogd/src/text.rs @@ -0,0 +1,41 @@ +extern crate ransid; + +use std::collections::VecDeque; + +use syscall::error::*; + +use crate::display::Display; + +pub struct TextScreen { + pub display: Display, + inner: console_draw::TextScreen, +} + +impl TextScreen { + pub fn new(display: Display) -> TextScreen { + TextScreen { + display, + inner: console_draw::TextScreen::new(), + } + } +} + +impl TextScreen { + pub fn write(&mut self, buf: &[u8]) -> Result { + let map = self.display.map.lock().unwrap(); + let damage = self.inner.write( + &mut console_draw::DisplayMap { + offscreen: map.offscreen, + width: map.width, + height: map.height, + }, + buf, + &mut VecDeque::new(), + ); + drop(map); + + self.display.sync_rects(damage); + + Ok(buf.len()) + } +} diff --git a/graphics/fbcond/Cargo.toml b/graphics/fbcond/Cargo.toml index a22c102f40..fffb1a0729 100644 --- a/graphics/fbcond/Cargo.toml +++ b/graphics/fbcond/Cargo.toml @@ -11,6 +11,7 @@ redox_syscall = "0.5" redox-daemon = "0.1" redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +console-draw = { path = "../console-draw" } inputd = { path = "../../inputd" } libredox = "0.1.3" diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 11ac25cec2..7d270eb0d0 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -51,16 +51,12 @@ fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { let mut scheme = FbconScheme::new(vt_ids, &mut event_queue); - let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); - // This is not possible for now as fbcond needs to open new displays at runtime for graphics // driver handoff. In the future inputd may directly pass a handle to the display instead. //libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); - inputd_control_handle.activate_vt(1).unwrap(); - let mut blocked = Vec::new(); // Handle all events that could have happened before registering with the event queue. diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index bbe519b117..696adf0ba2 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -1,19 +1,16 @@ extern crate ransid; -use std::collections::{BTreeSet, VecDeque}; -use std::convert::{TryFrom, TryInto}; -use std::{cmp, ptr}; +use std::collections::VecDeque; +use std::convert::TryInto; -use inputd::Damage; -use orbclient::{Event, EventOption, FONT}; +use orbclient::{Event, EventOption}; use syscall::error::*; -use crate::display::{Display, DisplayMap}; +use crate::display::Display; pub struct TextScreen { - console: ransid::Console, pub display: Display, - changed: BTreeSet, + inner: console_draw::TextScreen, ctrl: bool, input: VecDeque, } @@ -21,104 +18,13 @@ pub struct TextScreen { impl TextScreen { pub fn new(display: Display) -> TextScreen { TextScreen { - // Width and height will be filled in on the next write to the console - console: ransid::Console::new(0, 0), display, - changed: BTreeSet::new(), + inner: console_draw::TextScreen::new(), ctrl: false, input: VecDeque::new(), } } - /// Draw a rectangle - fn rect(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize, color: u32) { - let start_y = cmp::min(map.height, y); - let end_y = cmp::min(map.height, y + h); - - let start_x = cmp::min(map.width, x); - let len = cmp::min(map.width, x + w) - start_x; - - let mut offscreen_ptr = map.offscreen as *mut u8 as usize; - - let stride = map.width * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - - let mut rows = end_y - start_y; - while rows > 0 { - for i in 0..len { - unsafe { - *(offscreen_ptr as *mut u32).add(i) = color; - } - } - offscreen_ptr += stride; - rows -= 1; - } - } - - /// Invert a rectangle - fn invert(map: &mut DisplayMap, x: usize, y: usize, w: usize, h: usize) { - let start_y = cmp::min(map.height, y); - let end_y = cmp::min(map.height, y + h); - - let start_x = cmp::min(map.width, x); - let len = cmp::min(map.width, x + w) - start_x; - - let mut offscreen_ptr = map.offscreen as *mut u8 as usize; - - let stride = map.width * 4; - - let offset = y * stride + start_x * 4; - offscreen_ptr += offset; - - let mut rows = end_y - start_y; - while rows > 0 { - let mut row_ptr = offscreen_ptr; - let mut cols = len; - while cols > 0 { - unsafe { - let color = *(row_ptr as *mut u32); - *(row_ptr as *mut u32) = !color; - } - row_ptr += 4; - cols -= 1; - } - offscreen_ptr += stride; - rows -= 1; - } - } - - /// Draw a character - fn char( - map: &mut DisplayMap, - x: usize, - y: usize, - character: char, - color: u32, - _bold: bool, - _italic: bool, - ) { - if x + 8 <= map.width && y + 16 <= map.height { - let mut dst = map.offscreen as *mut u8 as usize + (y * map.width + x) * 4; - - let font_i = 16 * (character as usize); - if font_i + 16 <= FONT.len() { - for row in 0..16 { - let row_data = FONT[font_i + row]; - for col in 0..8 { - if (row_data >> (7 - col)) & 1 == 1 { - unsafe { - *((dst + col * 4) as *mut u32) = color; - } - } - } - dst += map.width * 4; - } - } - } - } - pub fn handle_handoff(&mut self) { self.display.reopen_for_handoff(); } @@ -222,112 +128,19 @@ impl TextScreen { } pub fn write(&mut self, buf: &[u8]) -> Result { - let mut map = self.display.map.lock().unwrap(); - - self.console.state.w = map.width / 8; - self.console.state.h = map.height / 16; - self.console.state.bottom_margin = (map.height / 16).saturating_sub(1); - - if self.console.state.cursor - && self.console.state.x < self.console.state.w - && self.console.state.y < self.console.state.h - { - let x = self.console.state.x; - let y = self.console.state.y; - Self::invert(&mut map, x * 8, y * 16, 8, 16); - self.changed.insert(y); - } - - { - let changed = &mut self.changed; - let input = &mut self.input; - self.console.write(buf, |event| match event { - ransid::Event::Char { - x, - y, - c, - color, - bold, - .. - } => { - Self::char(&mut map, x * 8, y * 16, c, color.as_rgb(), bold, false); - changed.insert(y); - } - ransid::Event::Input { data } => { - input.extend(data); - } - ransid::Event::Rect { x, y, w, h, color } => { - Self::rect(&mut map, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); - for y2 in y..y + h { - changed.insert(y2); - } - } - ransid::Event::ScreenBuffer { .. } => (), - ransid::Event::Move { - from_x, - from_y, - to_x, - to_y, - w, - h, - } => { - let width = map.width; - let pixels = unsafe { &mut *map.offscreen }; - - for raw_y in 0..h { - let y = if from_y > to_y { raw_y } else { h - raw_y - 1 }; - - for pixel_y in 0..16 { - { - let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8; - let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8; - let len = w * 8; - - if off_from + len <= pixels.len() && off_to + len <= pixels.len() { - unsafe { - let data_ptr = pixels.as_mut_ptr() as *mut u32; - ptr::copy( - data_ptr.offset(off_from as isize), - data_ptr.offset(off_to as isize), - len, - ); - } - } - } - } - - changed.insert(to_y + y); - } - } - ransid::Event::Resize { .. } => (), - ransid::Event::Title { .. } => (), - }); - } - - if self.console.state.cursor - && self.console.state.x < self.console.state.w - && self.console.state.y < self.console.state.h - { - let x = self.console.state.x; - let y = self.console.state.y; - Self::invert(&mut map, x * 8, y * 16, 8, 16); - self.changed.insert(y); - } - - let width = map.width.try_into().unwrap(); - drop(map); - self.display.sync_rects( - self.changed - .iter() - .map(|&change| Damage { - x: 0, - y: i32::try_from(change).unwrap() * 16, - width, - height: 16, - }) - .collect(), + let map = self.display.map.lock().unwrap(); + let damage = self.inner.write( + &mut console_draw::DisplayMap { + offscreen: map.offscreen, + width: map.width, + height: map.height, + }, + buf, + &mut self.input, ); - self.changed.clear(); + drop(map); + + self.display.sync_rects(damage); Ok(buf.len()) } From 12fc9597375f95a45198678c97e2c22b8fc44e31 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 24 Dec 2024 21:39:31 +0100 Subject: [PATCH 1040/1301] graphics/fbcond: Move blocking operations back to the main thread With fbbootlogd split out it is no longer essential to avoid blocking operations on the main thread of fbcond. Moving them back to the main thread simplifies things a fair bit. --- graphics/fbcond/src/display.rs | 170 ++++++++++++--------------------- graphics/fbcond/src/text.rs | 8 +- 2 files changed, 63 insertions(+), 115 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index d38d99981e..46785796df 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,15 +1,14 @@ use inputd::{ConsumerHandle, Damage}; use libredox::flag; -use std::mem; -use std::sync::mpsc::{self, Sender}; -use std::sync::{Arc, Mutex}; -use std::{fs::File, io, os::unix::io::AsRawFd, slice}; +use std::fs::File; +use std::os::unix::io::AsRawFd; +use std::{io, mem, ptr, slice}; fn display_fd_map( width: usize, height: usize, display_file: &mut File, -) -> syscall::Result { +) -> syscall::Result<*mut [u32]> { unsafe { let display_ptr = libredox::call::mmap(libredox::call::MmapArgs { fd: display_file.as_raw_fd() as usize, @@ -19,12 +18,10 @@ fn display_fd_map( flags: flag::MAP_SHARED, addr: core::ptr::null_mut(), })?; - let display_slice = slice::from_raw_parts_mut(display_ptr as *mut u32, width * height); - Ok(DisplayMap { - offscreen: display_slice, - width, - height, - }) + Ok(ptr::slice_from_raw_parts_mut( + display_ptr as *mut u32, + width * height, + )) } } @@ -32,118 +29,51 @@ unsafe fn display_fd_unmap(image: *mut [u32]) { let _ = libredox::call::munmap(image as *mut (), image.len()); } -pub struct DisplayMap { +pub struct Display { + pub input_handle: ConsumerHandle, + pub display_file: File, pub offscreen: *mut [u32], pub width: usize, pub height: usize, } -unsafe impl Send for DisplayMap {} -unsafe impl Sync for DisplayMap {} - -impl Drop for DisplayMap { - fn drop(&mut self) { - unsafe { - display_fd_unmap(self.offscreen); - } - } -} - -enum DisplayCommand { - Resize { width: usize, height: usize }, - ReopenForHandoff, - SyncRects(Vec), -} - -pub struct Display { - pub input_handle: Arc, - cmd_tx: Sender, - pub map: Arc>, -} - impl Display { pub fn open_vt(vt: usize) -> io::Result { - let input_handle = Arc::new(ConsumerHandle::for_vt(vt)?); + let input_handle = ConsumerHandle::for_vt(vt)?; let (mut display_file, width, height) = Self::open_display(&input_handle)?; - let map = Arc::new(Mutex::new( - display_fd_map(width, height, &mut display_file) - .unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")), - )); - - let (cmd_tx, cmd_rx) = mpsc::channel(); - - let input_handle_clone = input_handle.clone(); - let map_clone = map.clone(); - std::thread::spawn(move || { - while let Ok(cmd) = cmd_rx.recv() { - match cmd { - DisplayCommand::Resize { width, height } => { - match display_fd_map(width, height, &mut display_file) { - Ok(ok) => { - *map_clone.lock().unwrap() = ok; - } - Err(err) => { - eprintln!( - "failed to resize display to {}x{}: {}", - width, height, err - ); - } - } - } - DisplayCommand::ReopenForHandoff => { - eprintln!("fbcond: Performing handoff"); - - let (mut new_display_file, width, height) = - Self::open_display(&input_handle_clone).unwrap(); - - eprintln!("fbcond: Opened new display for VT #{vt}"); - - match display_fd_map(width, height, &mut new_display_file) { - Ok(ok) => { - *map_clone.lock().unwrap() = ok; - display_file = new_display_file; - - eprintln!("fbcond: Mapped new display for VT #{vt}"); - } - Err(err) => { - eprintln!( - "failed to resize display to {}x{}: {}", - width, height, err - ); - } - } - } - DisplayCommand::SyncRects(sync_rects) => unsafe { - libredox::call::write( - display_file.as_raw_fd() as usize, - slice::from_raw_parts( - sync_rects.as_ptr() as *const u8, - sync_rects.len() * mem::size_of::(), - ), - ) - .unwrap(); - }, - } - } - }); + let offscreen = display_fd_map(width, height, &mut display_file) + .unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")); Ok(Self { input_handle, - cmd_tx, - map, + display_file, + offscreen, + width, + height, }) } /// Re-open the display after a handoff. - /// - /// Once re-opening is finished, you must call [`resize`] to map the new framebuffer. - /// - /// Warning: This must be called in a background thread to avoid a deadlock when the - /// graphics driver (indirectly) writes logs to fbcond. pub fn reopen_for_handoff(&mut self) { - self.cmd_tx.send(DisplayCommand::ReopenForHandoff).unwrap(); + eprintln!("fbcond: Performing handoff"); + + let (mut new_display_file, width, height) = Self::open_display(&self.input_handle).unwrap(); + + eprintln!("fbcond: Opened new display"); + + match display_fd_map(width, height, &mut new_display_file) { + Ok(offscreen) => { + self.offscreen = offscreen; + self.display_file = new_display_file; + + eprintln!("fbcond: Mapped new display"); + } + Err(err) => { + eprintln!("failed to resize display to {}x{}: {}", width, height, err); + } + } } fn open_display(input_handle: &ConsumerHandle) -> io::Result<(File, usize, usize)> { @@ -175,14 +105,34 @@ impl Display { } pub fn resize(&mut self, width: usize, height: usize) { - self.cmd_tx - .send(DisplayCommand::Resize { width, height }) - .unwrap(); + match display_fd_map(width, height, &mut self.display_file) { + Ok(offscreen) => { + self.offscreen = offscreen; + } + Err(err) => { + eprintln!("failed to resize display to {}x{}: {}", width, height, err); + } + } } pub fn sync_rects(&mut self, sync_rects: Vec) { - self.cmd_tx - .send(DisplayCommand::SyncRects(sync_rects)) + unsafe { + libredox::call::write( + self.display_file.as_raw_fd() as usize, + slice::from_raw_parts( + sync_rects.as_ptr() as *const u8, + sync_rects.len() * mem::size_of::(), + ), + ) .unwrap(); + } + } +} + +impl Drop for Display { + fn drop(&mut self) { + unsafe { + display_fd_unmap(self.offscreen); + } } } diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index 696adf0ba2..e01dab8ae6 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -128,17 +128,15 @@ impl TextScreen { } pub fn write(&mut self, buf: &[u8]) -> Result { - let map = self.display.map.lock().unwrap(); let damage = self.inner.write( &mut console_draw::DisplayMap { - offscreen: map.offscreen, - width: map.width, - height: map.height, + offscreen: self.display.offscreen, + width: self.display.width, + height: self.display.height, }, buf, &mut self.input, ); - drop(map); self.display.sync_rects(damage); From c4dbcbecf286b26c2a53ebc988052250cd52bdd6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:17:47 +0100 Subject: [PATCH 1041/1301] Use redox-scheme in driver-network --- Cargo.lock | 1 + net/driver-network/Cargo.toml | 1 + net/driver-network/src/lib.rs | 122 ++++++++++++++++++---------------- net/e1000d/src/main.rs | 10 +-- net/ixgbed/src/main.rs | 10 +-- net/rtl8139d/src/main.rs | 11 ++- net/rtl8168d/src/main.rs | 12 ++-- net/virtio-netd/src/main.rs | 2 +- 8 files changed, 82 insertions(+), 87 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3bd00c9a93..98e288a0d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -401,6 +401,7 @@ name = "driver-network" version = "0.1.0" dependencies = [ "libredox", + "redox-scheme", "redox_syscall", ] diff --git a/net/driver-network/Cargo.toml b/net/driver-network/Cargo.toml index bfec9b86d1..26535c8627 100644 --- a/net/driver-network/Cargo.toml +++ b/net/driver-network/Cargo.toml @@ -5,4 +5,5 @@ edition = "2021" [dependencies] libredox = "0.1.3" +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_syscall = "0.5" diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index ce108dcd70..33b33172c2 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -1,13 +1,11 @@ use std::collections::BTreeMap; -use std::fs::File; -use std::io::{ErrorKind, Read, Write}; -use std::os::fd::{AsRawFd, FromRawFd, RawFd}; use std::{cmp, io}; -use libredox::flag; +use libredox::Fd; +use redox_scheme::{CallRequest, RequestKind, Response, SchemeBlockMut, SignalBehavior, Socket}; use syscall::{ - Error, EventFlags, Packet, Result, SchemeBlockMut, Stat, EACCES, EBADF, EINVAL, EWOULDBLOCK, - MODE_FILE, O_NONBLOCK, + Error, EventFlags, Result, Stat, EACCES, EAGAIN, EBADF, EINTR, EINVAL, EWOULDBLOCK, MODE_FILE, + O_NONBLOCK, }; pub trait NetworkAdapter { @@ -32,10 +30,10 @@ pub trait NetworkAdapter { pub struct NetworkScheme { adapter: T, scheme_name: String, - scheme: File, + socket: Socket, next_id: usize, handles: BTreeMap, - todo_packets: Vec, + blocked: Vec, } #[derive(Copy, Clone)] @@ -47,26 +45,20 @@ enum Handle { impl NetworkScheme { pub fn new(adapter: T, scheme_name: String) -> Self { assert!(scheme_name.starts_with("network")); - let scheme_fd = libredox::call::open( - format!(":{scheme_name}"), - flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, - 0, - ) - .expect("failed to create network scheme"); - let scheme = unsafe { File::from_raw_fd(scheme_fd as RawFd) }; + let socket = Socket::nonblock(&scheme_name).expect("failed to create network scheme"); NetworkScheme { adapter, scheme_name, - scheme, + socket, next_id: 0, handles: BTreeMap::new(), - todo_packets: vec![], + blocked: vec![], } } - pub fn event_handle(&self) -> RawFd { - self.scheme.as_raw_fd() + pub fn event_handle(&self) -> &Fd { + self.socket.inner() } pub fn adapter(&self) -> &T { @@ -86,41 +78,53 @@ impl NetworkScheme { // to call when an irq is received to indicate that blocked packets can // be processed. pub fn tick(&mut self) -> io::Result<()> { - // Handle any blocked packets + // Handle any blocked requests let mut i = 0; - while i < self.todo_packets.len() { - let mut packet = self.todo_packets[i].clone(); - if let Some(a) = self.handle(&packet) { - self.todo_packets.remove(i); - packet.a = a; - self.scheme.write(&packet)?; + while i < self.blocked.len() { + if let Some(resp) = self.blocked[i].handle_scheme_block_mut(self) { + self.socket + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + self.blocked.remove(i); } else { i += 1; } } - // Handle new scheme packets + // Handle new scheme requests loop { - let mut packet = Packet::default(); - match self.scheme.read(&mut packet) { - Ok(0) => { - return Err(io::Error::new( - ErrorKind::BrokenPipe, - "scheme has been closed by the kernel", - )); + let request = match self.socket.next_request(SignalBehavior::Restart) { + Ok(Some(request)) => request, + Ok(None) => { + // Scheme likely got unmounted + std::process::exit(0); } - Ok(_) => {} - Err(err) if err.kind() == ErrorKind::WouldBlock => break, - Err(err) => { - return Err(err); - } - } + Err(err) if err.errno == EAGAIN => break, + Err(err) => return Err(err.into()), + }; - if let Some(a) = self.handle(&packet) { - packet.a = a; - self.scheme.write(&packet)?; - } else { - self.todo_packets.push(packet); + match request.kind() { + RequestKind::Call(call_request) => { + if let Some(resp) = call_request.handle_scheme_block_mut(self) { + self.socket.write_response(resp, SignalBehavior::Restart)?; + } else { + self.blocked.push(call_request); + } + } + RequestKind::Cancellation(cancellation_request) => { + if let Some(i) = self + .blocked + .iter() + .position(|req| req.request().request_id() == cancellation_request.id) + { + let blocked_req = self.blocked.remove(i); + let resp = Response::new(&blocked_req, Err(syscall::Error::new(EINTR))); + self.socket.write_response(resp, SignalBehavior::Restart)?; + } + } + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() + } } } @@ -128,16 +132,8 @@ impl NetworkScheme { let available_for_read = self.adapter.available_for_read(); if available_for_read > 0 { for &handle_id in self.handles.keys() { - self.scheme.write(&Packet { - id: 0, - pid: 0, - uid: 0, - gid: 0, - a: syscall::number::SYS_FEVENT, - b: handle_id, - c: syscall::flag::EVENT_READ.bits(), - d: available_for_read, - })?; + self.socket + .post_fevent(handle_id, syscall::flag::EVENT_READ.bits())?; } return Ok(()); } @@ -174,7 +170,13 @@ impl SchemeBlockMut for NetworkScheme { Ok(Some(self.next_id)) } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { + fn read( + &mut self, + id: usize, + buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + ) -> Result> { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; let flags = match *handle { @@ -200,7 +202,13 @@ impl SchemeBlockMut for NetworkScheme { } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + fn write( + &mut self, + id: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + ) -> Result> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; match handle { diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index ca506185c3..4d2299d89e 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -1,13 +1,9 @@ -use std::cell::RefCell; -use std::convert::Infallible; -use std::io::{Read, Result, Write}; +use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; -use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; use pcid_interface::PciFunctionHandle; -use syscall::EventFlags; pub mod device; @@ -46,7 +42,7 @@ fn main() { } } - let mut event_queue = + let event_queue = EventQueue::::new().expect("e1000d: failed to create event queue"); event_queue @@ -58,7 +54,7 @@ fn main() { .expect("e1000d: failed to subscribe to IRQ fd"); event_queue .subscribe( - scheme.event_handle() as usize, + scheme.event_handle().raw(), Source::Scheme, event::EventFlags::READ, ) diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index cd4090c319..a066c3db0a 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -1,13 +1,9 @@ -use std::cell::RefCell; -use std::convert::Infallible; -use std::io::{Read, Result, Write}; +use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; -use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; use pcid_interface::PciFunctionHandle; -use syscall::EventFlags; pub mod device; #[rustfmt::skip] @@ -47,7 +43,7 @@ fn main() { } } - let mut event_queue = + let event_queue = EventQueue::::new().expect("ixgbed: Could not create event queue."); event_queue .subscribe( @@ -58,7 +54,7 @@ fn main() { .unwrap(); event_queue .subscribe( - scheme.event_handle() as usize, + scheme.event_handle().raw(), Source::Scheme, event::EventFlags::READ, ) diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index c6db719c9d..70e56cd655 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -1,12 +1,10 @@ #![feature(int_roundings)] -use std::cell::RefCell; -use std::convert::{Infallible, TryInto}; +use std::convert::TryInto; use std::fs::File; -use std::io::{Read, Result, Write}; +use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; use std::ptr::NonNull; -use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; @@ -18,7 +16,6 @@ use pcid_interface::{ MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, SubdriverArguments, }; -use syscall::EventFlags; pub mod device; @@ -221,7 +218,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - let mut event_queue = + let event_queue = EventQueue::::new().expect("rtl8139d: Could not create event queue."); event_queue .subscribe( @@ -232,7 +229,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .unwrap(); event_queue .subscribe( - scheme.event_handle() as usize, + scheme.event_handle().raw(), Source::Scheme, event::EventFlags::READ, ) diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 49ebc8491c..49dfef09c3 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -1,10 +1,8 @@ -use std::cell::RefCell; -use std::convert::{Infallible, TryInto}; +use std::convert::TryInto; use std::fs::File; -use std::io::{Read, Result, Write}; +use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; use std::ptr::NonNull; -use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; @@ -16,7 +14,6 @@ use pcid_interface::{ MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, SubdriverArguments, }; -use syscall::EventFlags; pub mod device; @@ -219,8 +216,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - let mut event_queue = - EventQueue::::new().expect("rtl8168d: Could not create event queue."); + let event_queue = EventQueue::::new().expect("rtl8168d: Could not create event queue."); event_queue .subscribe( irq_file.as_raw_fd() as usize, @@ -230,7 +226,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .unwrap(); event_queue .subscribe( - scheme.event_handle() as usize, + scheme.event_handle().raw(), Source::Scheme, event::EventFlags::READ, ) diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index b054534a7a..c2c4a798dc 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -97,7 +97,7 @@ fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box let mut event_queue = File::open("/scheme/event")?; event_queue.write(&syscall::Event { - id: scheme.event_handle() as usize, + id: scheme.event_handle().raw(), flags: syscall::EVENT_READ, data: 0, })?; From 20cd7b6dcd95a8b08c497317f873949777239602 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 15:06:11 +0100 Subject: [PATCH 1042/1301] driver-network: Use handle flags and offset stored by the kernel --- net/driver-network/src/lib.rs | 49 +++++++++++++++++++++-------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index 33b33172c2..7f78a52695 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -1,11 +1,15 @@ use std::collections::BTreeMap; use std::{cmp, io}; +use libredox::flag::O_NONBLOCK; use libredox::Fd; -use redox_scheme::{CallRequest, RequestKind, Response, SchemeBlockMut, SignalBehavior, Socket}; +use redox_scheme::{ + CallRequest, CallerCtx, OpenResult, RequestKind, Response, SchemeBlockMut, SignalBehavior, + Socket, +}; +use syscall::schemev2::NewFdFlags; use syscall::{ Error, EventFlags, Result, Stat, EACCES, EAGAIN, EBADF, EINTR, EINVAL, EWOULDBLOCK, MODE_FILE, - O_NONBLOCK, }; pub trait NetworkAdapter { @@ -38,8 +42,8 @@ pub struct NetworkScheme { #[derive(Copy, Clone)] enum Handle { - Data { flags: usize }, - Mac { offset: usize }, + Data, + Mac, } impl NetworkScheme { @@ -143,20 +147,28 @@ impl NetworkScheme { } impl SchemeBlockMut for NetworkScheme { - fn open(&mut self, path: &str, flags: usize, uid: u32, _gid: u32) -> Result> { - if uid != 0 { + fn xopen( + &mut self, + path: &str, + _flags: usize, + caller_ctx: &CallerCtx, + ) -> Result> { + if caller_ctx.uid != 0 { return Err(Error::new(EACCES)); } - let handle = match path { - "" => Handle::Data { flags }, - "mac" => Handle::Mac { offset: 0 }, + let (handle, flags) = match path { + "" => (Handle::Data, NewFdFlags::empty()), + "mac" => (Handle::Mac, NewFdFlags::POSITIONED), _ => return Err(Error::new(EINVAL)), }; self.next_id += 1; self.handles.insert(self.next_id, handle); - Ok(Some(self.next_id)) + Ok(Some(OpenResult::ThisScheme { + number: self.next_id, + flags, + })) } fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { @@ -174,18 +186,17 @@ impl SchemeBlockMut for NetworkScheme { &mut self, id: usize, buf: &mut [u8], - _offset: u64, - _fcntl_flags: u32, + offset: u64, + fcntl_flags: u32, ) -> Result> { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; - let flags = match *handle { - Handle::Data { flags } => flags, - Handle::Mac { ref mut offset } => { - let data = &self.adapter.mac_address()[*offset..]; + match *handle { + Handle::Data => {} + Handle::Mac => { + let data = &self.adapter.mac_address()[offset as usize..]; let i = cmp::min(buf.len(), data.len()); buf[..i].copy_from_slice(&data[..i]); - *offset += i; return Ok(Some(i)); } }; @@ -193,7 +204,7 @@ impl SchemeBlockMut for NetworkScheme { match self.adapter.read_packet(buf)? { Some(count) => Ok(Some(count)), None => { - if flags & O_NONBLOCK == O_NONBLOCK { + if fcntl_flags & O_NONBLOCK as u32 != 0 { Err(Error::new(EWOULDBLOCK)) } else { Ok(None) @@ -212,7 +223,7 @@ impl SchemeBlockMut for NetworkScheme { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; match handle { - Handle::Data { .. } => {} + Handle::Data => {} Handle::Mac { .. } => return Err(Error::new(EINVAL)), } From 8eabb75524125468375a0bd4af1f020ff457f797 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 15:45:10 +0100 Subject: [PATCH 1043/1301] Update redox-scheme to 0.3.0 --- Cargo.lock | 4 ++-- acpid/src/main.rs | 6 +++--- acpid/src/scheme.rs | 4 ++-- graphics/fbbootlogd/src/main.rs | 15 ++++++++++++--- graphics/fbbootlogd/src/scheme.rs | 4 ++-- graphics/fbcond/src/main.rs | 19 +++++++++++++++---- graphics/fbcond/src/scheme.rs | 4 ++-- graphics/vesad/src/main.rs | 20 +++++++++++++++----- graphics/vesad/src/scheme.rs | 4 ++-- graphics/virtio-gpud/src/main.rs | 21 ++++++++++++++++----- graphics/virtio-gpud/src/scheme.rs | 10 +++++----- inputd/src/main.rs | 16 +++++++++++----- net/driver-network/src/lib.rs | 18 ++++++++++++------ net/rtl8139d/src/main.rs | 5 ++--- storage/ahcid/src/main.rs | 11 +++++------ storage/ahcid/src/scheme.rs | 4 ++-- storage/bcm2835-sdhcid/src/main.rs | 8 ++++---- storage/bcm2835-sdhcid/src/scheme.rs | 4 ++-- storage/ided/src/main.rs | 13 ++++++------- storage/ided/src/scheme.rs | 4 ++-- storage/lived/src/main.rs | 8 ++++---- storage/nvmed/src/main.rs | 6 +++--- storage/nvmed/src/scheme.rs | 4 ++-- storage/usbscsid/src/main.rs | 6 +++--- storage/usbscsid/src/scheme.rs | 4 ++-- storage/virtio-blkd/src/main.rs | 8 +++----- storage/virtio-blkd/src/scheme.rs | 4 ++-- 27 files changed, 141 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 98e288a0d1..0e99da0d5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1157,8 +1157,8 @@ dependencies = [ [[package]] name = "redox-scheme" -version = "0.2.4" -source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#efe7addc3d6c54149694f875ed51467f8c4aa8b9" +version = "0.3.0" +source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#d2bfa80a1072facb2662d0bc73656247f0b254b4" dependencies = [ "libredox", "redox_syscall", diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 9ddd3ca01d..c9276d6662 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -7,7 +7,7 @@ use std::os::unix::io::AsRawFd; use std::sync::Arc; use event::{EventFlags, RawEventQueue}; -use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; +use redox_scheme::{RequestKind, SignalBehavior, Socket}; use syscall::{EAGAIN, EWOULDBLOCK}; mod acpi; @@ -66,7 +66,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("acpid: failed to open `/scheme/kernel.acpi/kstop`"); let mut event_queue = RawEventQueue::new().expect("acpid: failed to create event queue"); - let socket = Socket::::nonblock("acpi").expect("acpid: failed to create disk scheme"); + let socket = Socket::nonblock("acpi").expect("acpid: failed to create disk scheme"); daemon.ready().expect("acpid: failed to notify parent"); @@ -114,7 +114,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } }; - let response = sqe.handle_scheme_mut(&mut scheme); + let response = sqe.handle_scheme(&mut scheme); socket .write_response(response, SignalBehavior::Restart) .expect("acpid: failed to write response"); diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index fec64bacee..19ab3d7454 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -1,6 +1,6 @@ use core::str; use parking_lot::RwLockReadGuard; -use redox_scheme::{CallerCtx, OpenResult, SchemeMut}; +use redox_scheme::{CallerCtx, OpenResult, Scheme}; use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; @@ -141,7 +141,7 @@ fn parse_table(table: &[u8]) -> Option { }) } -impl SchemeMut for AcpiScheme<'_> { +impl Scheme for AcpiScheme<'_> { fn xopen(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result { let path = path.trim_start_matches('/'); diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index a45601820d..2168f2ed63 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -11,7 +11,8 @@ #![feature(io_error_more)] -use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; +use libredox::errno::EOPNOTSUPP; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; use crate::scheme::FbbootlogScheme; @@ -23,7 +24,7 @@ fn main() { redox_daemon::Daemon::new(|daemon| inner(daemon)).expect("failed to create daemon"); } fn inner(daemon: redox_daemon::Daemon) -> ! { - let socket: Socket = + let socket = Socket::create("fbbootlog").expect("fbbootlogd: failed to create fbbootlog scheme"); let mut scheme = FbbootlogScheme::new(); @@ -54,11 +55,19 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { RequestKind::Call(call_request) => { socket .write_response( - call_request.handle_scheme_mut(&mut scheme), + call_request.handle_scheme(&mut scheme), SignalBehavior::Restart, ) .expect("fbbootlogd: failed to write display scheme"); } + RequestKind::SendFd(sendfd_request) => { + socket + .write_response( + Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), + SignalBehavior::Restart, + ) + .expect("fbbootlogd: failed to write scheme"); + } RequestKind::Cancellation(_cancellation_request) => {} RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { unreachable!() diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index fa258d6c53..ca848b90da 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use redox_scheme::SchemeMut; +use redox_scheme::Scheme; use syscall::{Error, EventFlags, Result, EBADF, EINVAL, ENOENT}; use crate::display::Display; @@ -31,7 +31,7 @@ impl FbbootlogScheme { } } -impl SchemeMut for FbbootlogScheme { +impl Scheme for FbbootlogScheme { fn open(&mut self, path_str: &str, _flags: usize, _uid: u32, _gid: u32) -> Result { if !path_str.is_empty() { return Err(Error::new(ENOENT)); diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 7d270eb0d0..bdaac9f33a 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -1,7 +1,7 @@ #![feature(io_error_more)] use event::EventQueue; -use libredox::errno::{EAGAIN, EINTR, ESTALE}; +use libredox::errno::{EAGAIN, EINTR, EOPNOTSUPP, ESTALE}; use orbclient::Event; use redox_scheme::{CallRequest, RequestKind, Response, SignalBehavior, Socket}; use std::os::fd::{AsRawFd, BorrowedFd}; @@ -99,14 +99,25 @@ fn handle_event( match request.kind() { RequestKind::Call(call_request) => { - if let Some(resp) = call_request.handle_scheme_block_mut(scheme) { + if let Some(resp) = call_request.handle_scheme_block(scheme) { socket .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); + .expect("fbcond: failed to write display scheme"); } else { blocked.push(call_request); } } + RequestKind::SendFd(sendfd_request) => { + socket + .write_response( + Response::for_sendfd( + &sendfd_request, + Err(syscall::Error::new(EOPNOTSUPP)), + ), + SignalBehavior::Restart, + ) + .expect("fbcond: failed to write scheme"); + } RequestKind::Cancellation(cancellation_request) => { if let Some(i) = blocked .iter() @@ -154,7 +165,7 @@ fn handle_event( { let mut i = 0; while i < blocked.len() { - if let Some(resp) = blocked[i].handle_scheme_block_mut(scheme) { + if let Some(resp) = blocked[i].handle_scheme_block(scheme) { socket .write_response(resp, SignalBehavior::Restart) .expect("vesad: failed to write display scheme"); diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index 1b37b6674c..7e1d46d18e 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::os::fd::AsRawFd; use event::{EventQueue, UserData}; -use redox_scheme::SchemeBlockMut; +use redox_scheme::SchemeBlock; use syscall::{Error, EventFlags, Result, EBADF, EINVAL, ENOENT, O_NONBLOCK}; use crate::display::Display; @@ -69,7 +69,7 @@ impl FbconScheme { } } -impl SchemeBlockMut for FbconScheme { +impl SchemeBlock for FbconScheme { fn open( &mut self, path_str: &str, diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 20bd314650..4880e1a67b 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -3,8 +3,8 @@ extern crate orbclient; extern crate syscall; use event::{user_data, EventQueue}; -use libredox::errno::EAGAIN; -use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; +use libredox::errno::{EAGAIN, EOPNOTSUPP}; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; use std::env; use std::fs::File; use std::os::fd::AsRawFd; @@ -78,8 +78,7 @@ fn main() { .expect("failed to create daemon"); } fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[()]) -> ! { - let socket: Socket = - Socket::nonblock("display.vesa").expect("vesad: failed to create display scheme"); + let socket = Socket::nonblock("display.vesa").expect("vesad: failed to create display scheme"); let mut scheme = DisplayScheme::new(framebuffers, &spec); @@ -148,11 +147,22 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( RequestKind::Call(call_request) => { socket .write_response( - call_request.handle_scheme_mut(&mut scheme), + call_request.handle_scheme(&mut scheme), SignalBehavior::Restart, ) .expect("vesad: failed to write display scheme"); } + RequestKind::SendFd(sendfd_request) => { + socket + .write_response( + Response::for_sendfd( + &sendfd_request, + Err(syscall::Error::new(EOPNOTSUPP)), + ), + SignalBehavior::Restart, + ) + .expect("vesad: failed to write scheme"); + } RequestKind::Cancellation(_cancellation_request) => {} RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { unreachable!() diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 19ac71782d..a2cf93a011 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::str; use inputd::{VtEvent, VtEventKind}; -use redox_scheme::SchemeMut; +use redox_scheme::Scheme; use syscall::{Error, MapFlags, Result, EBADF, EINVAL, ENOENT}; use crate::{framebuffer::FrameBuffer, screen::GraphicScreen}; @@ -105,7 +105,7 @@ impl DisplayScheme { } } -impl SchemeMut for DisplayScheme { +impl Scheme for DisplayScheme { fn open(&mut self, path_str: &str, _flags: usize, _uid: u32, _gid: u32) -> Result { let mut parts = path_str.split('/'); let mut vt_screen = parts.next().unwrap_or("").split('.'); diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 66f41b64dd..6543d97ddc 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -27,10 +27,10 @@ use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicU32, Ordering}; use event::{user_data, EventQueue}; -use libredox::errno::EAGAIN; +use libredox::errno::{EAGAIN, EOPNOTSUPP}; use pcid_interface::PciFunctionHandle; -use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; use virtio_core::utils::VolatileCell; use virtio_core::MSIX_PRIMARY_VECTOR; @@ -439,8 +439,8 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device.transport.run_device(); deamon.ready().unwrap(); - let socket: Socket = Socket::nonblock("display.virtio-gpu")?; - let mut scheme = futures::executor::block_on(scheme::Scheme::new( + let socket = Socket::nonblock("display.virtio-gpu")?; + let mut scheme = futures::executor::block_on(scheme::GpuScheme::new( config, control_queue.clone(), cursor_queue.clone(), @@ -505,11 +505,22 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { RequestKind::Call(call_request) => { socket .write_response( - call_request.handle_scheme_mut(&mut scheme), + call_request.handle_scheme(&mut scheme), SignalBehavior::Restart, ) .expect("virtio-gpud: failed to write display scheme"); } + RequestKind::SendFd(sendfd_request) => { + socket + .write_response( + Response::for_sendfd( + &sendfd_request, + Err(syscall::Error::new(EOPNOTSUPP)), + ), + SignalBehavior::Restart, + ) + .expect("virtio-gpud: failed to write scheme"); + } RequestKind::Cancellation(_cancellation_request) => {} RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { unreachable!() diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index c7b3bed07a..deb7439843 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use common::{dma::Dma, sgl}; use inputd::{Damage, VtEvent, VtEventKind}; -use redox_scheme::SchemeMut; +use redox_scheme::Scheme; use syscall::{Error as SysError, MapFlags, EINVAL, PAGE_SIZE}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; @@ -227,7 +227,7 @@ struct Handle<'a> { vt: usize, } -pub struct Scheme<'a> { +pub struct GpuScheme<'a> { handles: BTreeMap>, /// Counter used for file descriptor allocation. next_id: AtomicUsize, @@ -235,13 +235,13 @@ pub struct Scheme<'a> { pub inputd_handle: inputd::DisplayHandle, } -impl<'a> Scheme<'a> { +impl<'a> GpuScheme<'a> { pub async fn new( config: &'a mut GpuConfig, control_queue: Arc>, cursor_queue: Arc>, transport: Arc, - ) -> Result, Error> { + ) -> Result, Error> { let displays = Self::probe( control_queue.clone(), cursor_queue.clone(), @@ -335,7 +335,7 @@ impl<'a> Scheme<'a> { } } -impl<'a> SchemeMut for Scheme<'a> { +impl<'a> Scheme for GpuScheme<'a> { fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { if path.is_empty() { return Err(SysError::new(EINVAL)); diff --git a/inputd/src/main.rs b/inputd/src/main.rs index a79ba703df..edd0be1a33 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -18,8 +18,8 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use inputd::{VtActivate, VtEvent, VtEventKind}; -use libredox::errno::ESTALE; -use redox_scheme::{RequestKind, SchemeMut, SignalBehavior, Socket, V2}; +use libredox::errno::{EOPNOTSUPP, ESTALE}; +use redox_scheme::{RequestKind, Response, Scheme, SignalBehavior, Socket}; use orbclient::{Event, EventOption}; use syscall::{Error as SysError, EventFlags, EINVAL}; @@ -154,7 +154,7 @@ impl InputScheme { } } -impl SchemeMut for InputScheme { +impl Scheme for InputScheme { fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { let mut path_parts = path.split('/'); @@ -483,7 +483,7 @@ impl SchemeMut for InputScheme { fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { // Create the ":input" scheme. - let socket_file: Socket = Socket::create("input")?; + let socket_file = Socket::create("input")?; let mut scheme = InputScheme::new(); deamon.ready().unwrap(); @@ -498,7 +498,13 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { match request.kind() { RequestKind::Call(call_request) => { socket_file.write_response( - call_request.handle_scheme_mut(&mut scheme), + call_request.handle_scheme(&mut scheme), + SignalBehavior::Restart, + )?; + } + RequestKind::SendFd(sendfd_request) => { + socket_file.write_response( + Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), SignalBehavior::Restart, )?; } diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index 7f78a52695..c52d0d7481 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -1,11 +1,11 @@ use std::collections::BTreeMap; use std::{cmp, io}; +use libredox::errno::EOPNOTSUPP; use libredox::flag::O_NONBLOCK; use libredox::Fd; use redox_scheme::{ - CallRequest, CallerCtx, OpenResult, RequestKind, Response, SchemeBlockMut, SignalBehavior, - Socket, + CallRequest, CallerCtx, OpenResult, RequestKind, Response, SchemeBlock, SignalBehavior, Socket, }; use syscall::schemev2::NewFdFlags; use syscall::{ @@ -85,10 +85,10 @@ impl NetworkScheme { // Handle any blocked requests let mut i = 0; while i < self.blocked.len() { - if let Some(resp) = self.blocked[i].handle_scheme_block_mut(self) { + if let Some(resp) = self.blocked[i].handle_scheme_block(self) { self.socket .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); + .expect("driver-network: failed to write scheme"); self.blocked.remove(i); } else { i += 1; @@ -109,12 +109,18 @@ impl NetworkScheme { match request.kind() { RequestKind::Call(call_request) => { - if let Some(resp) = call_request.handle_scheme_block_mut(self) { + if let Some(resp) = call_request.handle_scheme_block(self) { self.socket.write_response(resp, SignalBehavior::Restart)?; } else { self.blocked.push(call_request); } } + RequestKind::SendFd(sendfd_request) => { + self.socket.write_response( + Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), + SignalBehavior::Restart, + )?; + } RequestKind::Cancellation(cancellation_request) => { if let Some(i) = self .blocked @@ -146,7 +152,7 @@ impl NetworkScheme { } } -impl SchemeBlockMut for NetworkScheme { +impl SchemeBlock for NetworkScheme { fn xopen( &mut self, path: &str, diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 70e56cd655..774341b83d 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -2,7 +2,7 @@ use std::convert::TryInto; use std::fs::File; -use std::io::{Read, Write}; +use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; use std::ptr::NonNull; @@ -218,8 +218,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - let event_queue = - EventQueue::::new().expect("rtl8139d: Could not create event queue."); + let event_queue = EventQueue::::new().expect("rtl8139d: Could not create event queue."); event_queue .subscribe( irq_file.as_raw_fd() as usize, diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 3cfb63a435..0af3d33e7e 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -10,7 +10,7 @@ use std::usize; use event::{EventFlags, RawEventQueue}; use pcid_interface::PciFunctionHandle; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; use syscall::error::{Error, ENODEV}; use log::{error, info}; @@ -53,8 +53,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .as_ptr() as usize; { let scheme_name = format!("disk.{}", name); - let socket = - Socket::::nonblock(&scheme_name).expect("ahcid: failed to create disk scheme"); + let socket = Socket::nonblock(&scheme_name).expect("ahcid: failed to create disk scheme"); let mut irq_file = irq.irq_handle("ahcid"); let irq_fd = irq_file.as_raw_fd() as usize; @@ -109,7 +108,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } }; - if let Some(response) = sqe.handle_scheme_block_mut(&mut scheme) { + if let Some(response) = sqe.handle_scheme_block(&mut scheme) { // TODO: handle full CQE? socket .write_response(response, SignalBehavior::Restart) @@ -133,7 +132,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // Handle todos in order to finish previous packets if possible let mut i = 0; while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { let _sqe = todo.remove(i); socket .write_response(resp, SignalBehavior::Restart) @@ -151,7 +150,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // Handle todos to start new packets if possible let mut i = 0; while i < todo.len() { - if let Some(response) = todo[i].handle_scheme_block_mut(&mut scheme) { + if let Some(response) = todo[i].handle_scheme_block(&mut scheme) { let _sqe = todo.remove(i); socket .write_response(response, SignalBehavior::Restart) diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index 67ea31262e..ce153ffb1e 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -4,7 +4,7 @@ use std::str; use common::io::Io as _; use driver_block::{Disk, DiskWrapper}; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; +use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; use syscall::schemev2::NewFdFlags; use syscall::{ Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, @@ -96,7 +96,7 @@ impl DiskScheme { } } -impl SchemeBlockMut for DiskScheme { +impl SchemeBlock for DiskScheme { fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { if ctx.uid != 0 { return Err(Error::new(EACCES)); diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index c3a5bec63d..fded57eb4b 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -9,7 +9,7 @@ use std::{ use driver_block::Disk; use event::{EventFlags, RawEventQueue}; use fdt::{node::FdtNode, Fdt}; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; use syscall::{ data::{Event, Packet}, error::{Error, ENODEV}, @@ -115,7 +115,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } let scheme_name = "disk.mmc"; - let socket_fd = Socket::::create(&scheme_name).expect("mmcd: failed to create disk scheme"); + let socket_fd = Socket::create(&scheme_name).expect("mmcd: failed to create disk scheme"); let mut event_queue = RawEventQueue::new().expect("mmcd: failed to open event file"); event_queue @@ -158,7 +158,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } }; - if let Some(resp) = req.handle_scheme_block_mut(&mut scheme) { + if let Some(resp) = req.handle_scheme_block(&mut scheme) { socket_fd .write_response(resp, SignalBehavior::Restart) .expect("mmcd: failed to write disk scheme"); @@ -173,7 +173,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // Handle todos to start new packets if possible let mut i = 0; while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { socket_fd .write_response(resp, SignalBehavior::Restart) .expect("mmcd: failed to write disk scheme"); diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs index 18e8d28a3f..27777290bb 100644 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ b/storage/bcm2835-sdhcid/src/scheme.rs @@ -10,7 +10,7 @@ use syscall::{ MODE_FILE, O_DIRECTORY, O_STAT, }; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; +use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; #[derive(Clone)] enum Handle { @@ -70,7 +70,7 @@ impl DiskScheme { } } -impl SchemeBlockMut for DiskScheme { +impl SchemeBlock for DiskScheme { fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { if ctx.uid == 0 { let path_str = path.trim_matches('/'); diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index cc8abb79f2..178daba6b9 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -4,7 +4,7 @@ use event::{EventFlags, RawEventQueue}; use libredox::flag; use log::{error, info}; use pcid_interface::{PciBar, PciFunctionHandle}; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket, V2}; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; use std::{ fs::File, io::{ErrorKind, Read, Write}, @@ -200,8 +200,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } let scheme_name = format!("disk.{}", name); - let socket_fd = - Socket::::nonblock(&scheme_name).expect("ided: failed to create disk scheme"); + let socket_fd = Socket::nonblock(&scheme_name).expect("ided: failed to create disk scheme"); let primary_irq_fd = libredox::call::open( &format!("/scheme/irq/{}", primary_irq), @@ -267,7 +266,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } }; - if let Some(resp) = req.handle_scheme_block_mut(&mut scheme) { + if let Some(resp) = req.handle_scheme_block(&mut scheme) { socket_fd .write_response(resp, SignalBehavior::Restart) .expect("ided: failed to write disk scheme"); @@ -290,7 +289,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // Handle todos in order to finish previous packets if possible let mut i = 0; while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { socket_fd .write_response(resp, SignalBehavior::Restart) .expect("ided: failed to write disk scheme"); @@ -315,7 +314,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // Handle todos in order to finish previous packets if possible let mut i = 0; while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { socket_fd .write_response(resp, SignalBehavior::Restart) .expect("ided: failed to write disk scheme"); @@ -332,7 +331,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { // Handle todos to start new packets if possible let mut i = 0; while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { socket_fd .write_response(resp, SignalBehavior::Restart) .expect("ided: failed to write disk scheme"); diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs index 0248cae6c5..d2ceaa4ad6 100644 --- a/storage/ided/src/scheme.rs +++ b/storage/ided/src/scheme.rs @@ -11,7 +11,7 @@ use syscall::{ }; use crate::ide::Channel; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; +use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; #[derive(Clone)] enum Handle { @@ -83,7 +83,7 @@ impl DiskScheme { } } -impl SchemeBlockMut for DiskScheme { +impl SchemeBlock for DiskScheme { fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { if ctx.uid == 0 { let path_str = path.trim_matches('/'); diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index 2a611690f6..b2f9096600 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -9,7 +9,7 @@ use std::str; use libredox::call::MmapArgs; use libredox::flag; -use redox_scheme::{CallerCtx, OpenResult, RequestKind, SchemeMut, SignalBehavior, Socket, V2}; +use redox_scheme::{CallerCtx, OpenResult, RequestKind, Scheme, SignalBehavior, Socket}; use syscall::data::Stat; use syscall::error::*; @@ -97,7 +97,7 @@ impl DiskScheme { } } -impl SchemeMut for DiskScheme { +impl Scheme for DiskScheme { fn fsize(&mut self, id: usize) -> Result { Ok( match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { @@ -195,7 +195,7 @@ impl SchemeMut for DiskScheme { } fn main() -> anyhow::Result<()> { redox_daemon::Daemon::new(move |daemon| { - let socket_fd = Socket::::create("disk.live").expect("failed to open scheme"); + let socket_fd = Socket::create("disk.live").expect("failed to open scheme"); let mut scheme = DiskScheme::new().unwrap_or_else(|err| { eprintln!("failed to initialize livedisk scheme: {}", err); std::process::exit(1) @@ -216,7 +216,7 @@ fn main() -> anyhow::Result<()> { } None => break, }; - let resp = req.handle_scheme_mut(&mut scheme); + let resp = req.handle_scheme(&mut scheme); socket_fd .write_response(resp, SignalBehavior::Restart) .expect("failed to write packet"); diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 2a1040192c..618fdfaf12 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -12,7 +12,7 @@ use std::{slice, usize}; use libredox::flag; use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PciFunctionHandle}; -use redox_scheme::{CallRequest, RequestKind, SignalBehavior, Socket, V2}; +use redox_scheme::{CallRequest, RequestKind, SignalBehavior, Socket}; use syscall::{Event, Packet, Result, SchemeBlockMut, PAGE_SIZE}; use self::nvme::{InterruptMethod, InterruptSources, Nvme}; @@ -170,7 +170,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { pcid_handle.map_bar(0).expect("nvmed").ptr }; - let socket = Socket::::create(&scheme_name).expect("nvmed: failed to create disk scheme"); + let socket = Socket::create(&scheme_name).expect("nvmed: failed to create disk scheme"); daemon.ready().expect("nvmed: failed to signal readiness"); @@ -220,7 +220,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut i = 0; while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block_mut(&mut scheme) { + if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { let _req = todo.remove(i); socket .write_response(resp, SignalBehavior::Restart) diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 4c63169ce0..25b77e5578 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -6,7 +6,7 @@ use std::io::prelude::*; use std::sync::Arc; use std::{cmp, str}; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlockMut}; +use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; use syscall::schemev2::NewFdFlags; use syscall::{ Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, @@ -192,7 +192,7 @@ impl DiskScheme { } } -impl SchemeBlockMut for DiskScheme { +impl SchemeBlock for DiskScheme { fn xopen( &mut self, path_str: &str, diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index 4f15115c55..a4cb53992a 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -1,6 +1,6 @@ use std::env; -use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; +use redox_scheme::{RequestKind, SignalBehavior, Socket}; use xhcid_interface::{ConfigureEndpointsReq, XhciClientHandle}; pub mod protocol; @@ -83,7 +83,7 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u // TODO: Let all of the USB drivers fork or be managed externally, and xhcid won't have to keep // track of all the drivers. let socket_fd = - Socket::::create(&disk_scheme_name).expect("usbscsid: failed to create disk scheme"); + Socket::create(&disk_scheme_name).expect("usbscsid: failed to create disk scheme"); //libredox::call::setrens(0, 0).expect("scsid: failed to enter null namespace"); let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI"); @@ -109,7 +109,7 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u } None => break, }; - let resp = req.handle_scheme_mut(&mut scsi_scheme); + let resp = req.handle_scheme(&mut scsi_scheme); socket_fd .write_response(resp, SignalBehavior::Restart) .expect("scsid: failed to write cqe"); diff --git a/storage/usbscsid/src/scheme.rs b/storage/usbscsid/src/scheme.rs index ed89dd2254..4462e3296a 100644 --- a/storage/usbscsid/src/scheme.rs +++ b/storage/usbscsid/src/scheme.rs @@ -4,7 +4,7 @@ use std::{cmp, str}; use crate::protocol::Protocol; use crate::scsi::Scsi; -use redox_scheme::{CallerCtx, OpenResult, SchemeMut}; +use redox_scheme::{CallerCtx, OpenResult, Scheme}; use syscall::error::{Error, Result}; use syscall::error::{EACCES, EBADF, EINVAL, EIO, ENOENT, ENOSYS}; use syscall::flag::{MODE_CHR, MODE_DIR}; @@ -39,7 +39,7 @@ impl<'a> ScsiScheme<'a> { } } -impl SchemeMut for ScsiScheme<'_> { +impl Scheme for ScsiScheme<'_> { fn xopen(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result { if ctx.uid != 0 { return Err(Error::new(EACCES)); diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index df5cda91a5..a7ef29308e 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -7,7 +7,7 @@ use std::os::fd::{FromRawFd, RawFd}; use std::sync::{Arc, Weak}; use libredox::flag; -use redox_scheme::{RequestKind, SignalBehavior, Socket, V2}; +use redox_scheme::{RequestKind, SignalBehavior, Socket}; use static_assertions::const_assert_eq; use pcid_interface::*; @@ -147,7 +147,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let scheme_name = format!("disk.{}", name); - let socket_fd = Socket::::create(&scheme_name).map_err(Error::SyscallError)?; + let socket_fd = Socket::create(&scheme_name).map_err(Error::SyscallError)?; let mut scheme = scheme::DiskScheme::new(queue, device_space); @@ -167,9 +167,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } None => break, }; - let resp = req - .handle_scheme_block_mut(&mut scheme) - .expect("TODO: block?"); + let resp = req.handle_scheme_block(&mut scheme).expect("TODO: block?"); socket_fd .write_response(resp, SignalBehavior::Restart) .expect("virtio-blkd: failed to write to disk scheme"); diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 79d116db03..2b1c86d3ca 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -13,7 +13,7 @@ use partitionlib::PartitionTable; use redox_scheme::CallerCtx; use redox_scheme::OpenResult; -use redox_scheme::SchemeBlockMut; +use redox_scheme::SchemeBlock; use syscall::error::*; use syscall::flag::*; use syscall::schemev2::NewFdFlags; @@ -201,7 +201,7 @@ impl<'a> DiskScheme<'a> { } } -impl<'a> SchemeBlockMut for DiskScheme<'a> { +impl<'a> SchemeBlock for DiskScheme<'a> { fn xopen( &mut self, path: &str, From 2c042f8c98e8ae844e1adf565733550a371fe2e9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:33:32 +0100 Subject: [PATCH 1044/1301] Fix a ton of unused import warnings --- acpid/src/acpi.rs | 1 - audio/ac97d/src/device.rs | 1 - audio/ac97d/src/main.rs | 10 ++++------ audio/ihdad/src/hda/stream.rs | 1 - audio/ihdad/src/main.rs | 8 +++----- input/usbhidd/src/main.rs | 3 +-- pcid/src/cfg_access/mod.rs | 1 - pcid/src/driver_interface/mod.rs | 1 - storage/ided/src/main.rs | 12 +++--------- storage/nvmed/src/main.rs | 11 +++-------- storage/nvmed/src/nvme/mod.rs | 8 +++----- storage/nvmed/src/scheme.rs | 2 +- storage/usbscsid/src/scheme.rs | 5 ++--- storage/usbscsid/src/scsi/mod.rs | 5 ++--- storage/virtio-blkd/src/main.rs | 6 ------ storage/virtio-blkd/src/scheme.rs | 1 - usbhubd/src/main.rs | 6 +----- vboxd/src/main.rs | 5 ++--- virtio-core/src/transport.rs | 2 +- xhcid/src/main.rs | 14 +++----------- xhcid/src/xhci/device_enumerator.rs | 6 ++---- xhcid/src/xhci/irq_reactor.rs | 10 +++------- xhcid/src/xhci/mod.rs | 16 ++++++---------- xhcid/src/xhci/operational.rs | 4 ---- xhcid/src/xhci/scheme.rs | 23 +++++++---------------- xhcid/src/xhci/trb.rs | 1 - 26 files changed, 47 insertions(+), 116 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index de268e6043..f7aa3ed6f4 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,6 +1,5 @@ use rustc_hash::FxHashMap; use std::convert::{TryFrom, TryInto}; -use std::fmt::Write; use std::ops::Deref; use std::sync::{Arc, Mutex}; use std::{fmt, mem}; diff --git a/audio/ac97d/src/device.rs b/audio/ac97d/src/device.rs index de182de2ba..0eef06a71f 100644 --- a/audio/ac97d/src/device.rs +++ b/audio/ac97d/src/device.rs @@ -1,7 +1,6 @@ #![allow(dead_code)] use std::collections::BTreeMap; -use std::mem; use std::sync::atomic::{AtomicUsize, Ordering}; use common::io::Pio; diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index 3b848481fe..a7a8c0327f 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -5,17 +5,15 @@ extern crate event; extern crate spin; extern crate syscall; -use std::cell::RefCell; use std::fs::File; -use std::io::{ErrorKind, Read, Result, Write}; +use std::io::{ErrorKind, Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::sync::Arc; use std::usize; use event::{user_data, EventQueue}; use libredox::flag; -use pcid_interface::{PciBar, PciFunctionHandle}; -use syscall::{EventFlags, Packet, SchemeBlockMut}; +use pcid_interface::PciFunctionHandle; +use syscall::{Packet, SchemeBlockMut}; pub mod device; @@ -69,7 +67,7 @@ fn main() { } } - let mut event_queue = + let event_queue = EventQueue::::new().expect("ac97d: Could not create event queue."); event_queue .subscribe( diff --git a/audio/ihdad/src/hda/stream.rs b/audio/ihdad/src/hda/stream.rs index dfc72abc8d..cb02b72630 100644 --- a/audio/ihdad/src/hda/stream.rs +++ b/audio/ihdad/src/hda/stream.rs @@ -1,7 +1,6 @@ use common::dma::Dma; use common::io::{Io, Mmio}; use std::cmp::min; -use std::ptr; use std::ptr::copy_nonoverlapping; use std::result; use syscall::error::{Error, Result, EIO}; diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index b467e33699..503cf23848 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -7,13 +7,11 @@ extern crate spin; extern crate syscall; use libredox::flag; -use std::cell::RefCell; use std::fs::File; -use std::io::{ErrorKind, Read, Result, Write}; +use std::io::{ErrorKind, Read, Write}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::sync::Arc; use std::usize; -use syscall::{EventFlags, Packet, SchemeBlockMut}; +use syscall::{Packet, SchemeBlockMut}; use event::{user_data, EventQueue}; #[cfg(target_arch = "x86_64")] @@ -136,7 +134,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - let mut event_queue = + let event_queue = EventQueue::::new().expect("ihdad: Could not create event queue."); let mut device = unsafe { hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") diff --git a/input/usbhidd/src/main.rs b/input/usbhidd/src/main.rs index ed79994e1a..dfda4cd472 100644 --- a/input/usbhidd/src/main.rs +++ b/input/usbhidd/src/main.rs @@ -1,10 +1,9 @@ -use std::collections::VecDeque; use std::env; use inputd::ProducerHandle; use orbclient::KeyEvent as OrbKeyEvent; use rehid::{ - report_desc::{self, ReportTy, REPORT_DESC_TY}, + report_desc::{ReportTy, REPORT_DESC_TY}, report_handler::ReportHandler, usage_tables::{GenericDesktopUsage, UsagePage}, }; diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index a8ea2b16e8..20eb0750a4 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -2,7 +2,6 @@ use std::sync::Mutex; use std::{fs, io, mem}; use common::{MemoryType, PhysBorrowed, Prot}; -use fdt::node::CellSizes; use fdt::Fdt; use pci_types::{ConfigRegionAccess, PciAddress}; diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 183f5036c3..5d1054a23f 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -4,7 +4,6 @@ use std::io::prelude::*; use std::ptr::NonNull; use std::{env, io}; -use log::info; use std::os::unix::io::{FromRawFd, RawFd}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 178daba6b9..068477cbd7 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -3,23 +3,17 @@ use driver_block::Disk; use event::{EventFlags, RawEventQueue}; use libredox::flag; use log::{error, info}; -use pcid_interface::{PciBar, PciFunctionHandle}; +use pcid_interface::PciFunctionHandle; use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; use std::{ fs::File, - io::{ErrorKind, Read, Write}, + io::{Read, Write}, os::unix::io::{FromRawFd, RawFd}, sync::{Arc, Mutex}, thread::{self, sleep}, time::Duration, }; -use syscall::{ - data::{Event, Packet}, - error::{Error, ENODEV}, - flag::EVENT_READ, - scheme::SchemeBlockMut, - EAGAIN, EINTR, EWOULDBLOCK, -}; +use syscall::error::{Error, EAGAIN, EINTR, ENODEV, EWOULDBLOCK}; use crate::{ ide::{AtaCommand, AtaDisk, Channel}, diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 618fdfaf12..91b289a987 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -2,18 +2,13 @@ #![cfg_attr(target_arch = "riscv64", feature(riscv_ext_intrinsics))] // Required for pause instruction #![feature(int_roundings)] -use std::convert::TryInto; -use std::fs::File; -use std::io::{ErrorKind, Read, Write}; -use std::os::unix::io::{FromRawFd, RawFd}; use std::ptr::NonNull; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use std::{slice, usize}; -use libredox::flag; use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PciFunctionHandle}; -use redox_scheme::{CallRequest, RequestKind, SignalBehavior, Socket}; -use syscall::{Event, Packet, Result, SchemeBlockMut, PAGE_SIZE}; +use redox_scheme::{RequestKind, SignalBehavior, Socket}; +use syscall::Result; use self::nvme::{InterruptMethod, InterruptSources, Nvme}; use self::scheme::DiskScheme; diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index afb1bebcd9..17d8cd039c 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -1,16 +1,14 @@ use std::collections::BTreeMap; use std::convert::TryFrom; use std::fs::File; -use std::ptr; -use std::sync::atomic::{AtomicU16, AtomicU64, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicU16, AtomicU64}; use std::sync::{Mutex, RwLock}; -use std::thread; use crossbeam_channel::Sender; use smallvec::{smallvec, SmallVec}; use common::io::{Io, Mmio}; -use syscall::error::{Error, Result, EINVAL, EIO}; +use syscall::error::{Error, Result, EIO}; use common::dma::Dma; @@ -526,7 +524,7 @@ impl Nvme { return entry; } } - thread::yield_now(); + std::thread::yield_now(); } } diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 25b77e5578..772b72e8b6 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -10,7 +10,7 @@ use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; use syscall::schemev2::NewFdFlags; use syscall::{ Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, - MODE_FILE, O_DIRECTORY, O_STAT, SEEK_CUR, SEEK_END, SEEK_SET, + MODE_FILE, O_DIRECTORY, O_STAT, }; use crate::nvme::{Nvme, NvmeNamespace}; diff --git a/storage/usbscsid/src/scheme.rs b/storage/usbscsid/src/scheme.rs index 4462e3296a..4680fb937e 100644 --- a/storage/usbscsid/src/scheme.rs +++ b/storage/usbscsid/src/scheme.rs @@ -1,15 +1,14 @@ use std::collections::BTreeMap; -use std::{cmp, str}; +use std::str; use crate::protocol::Protocol; use crate::scsi::Scsi; use redox_scheme::{CallerCtx, OpenResult, Scheme}; use syscall::error::{Error, Result}; -use syscall::error::{EACCES, EBADF, EINVAL, EIO, ENOENT, ENOSYS}; +use syscall::error::{EACCES, EBADF, EINVAL, EIO, ENOSYS}; use syscall::flag::{MODE_CHR, MODE_DIR}; use syscall::flag::{O_DIRECTORY, O_STAT}; -use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET}; use syscall::schemev2::NewFdFlags; // TODO: Only one disk, right? diff --git a/storage/usbscsid/src/scsi/mod.rs b/storage/usbscsid/src/scsi/mod.rs index b5741fbd81..e6364e9c2f 100644 --- a/storage/usbscsid/src/scsi/mod.rs +++ b/storage/usbscsid/src/scsi/mod.rs @@ -1,5 +1,5 @@ use std::convert::TryFrom; -use std::{mem, ops}; +use std::mem; pub mod cmds; pub mod opcodes; @@ -8,8 +8,7 @@ use thiserror::Error; use xhcid_interface::DeviceReqData; use crate::protocol::{Protocol, ProtocolError, SendCommandStatus, SendCommandStatusKind}; -use cmds::{SenseKey, StandardInquiryData}; -use opcodes::Opcode; +use cmds::StandardInquiryData; pub struct Scsi { command_buffer: [u8; 16], diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index a7ef29308e..14cec55197 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -1,20 +1,14 @@ #![deny(trivial_numeric_casts, unused_allocation)] #![feature(int_roundings)] -use std::fs::File; -use std::io::{Read, Write}; -use std::os::fd::{FromRawFd, RawFd}; use std::sync::{Arc, Weak}; -use libredox::flag; use redox_scheme::{RequestKind, SignalBehavior, Socket}; use static_assertions::const_assert_eq; use pcid_interface::*; use virtio_core::spec::*; -use syscall::{Packet, SchemeBlockMut}; - use virtio_core::transport::Transport; use virtio_core::utils::VolatileCell; diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 2b1c86d3ca..b3288516d4 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -1,4 +1,3 @@ -use std::cmp; use std::collections::BTreeMap; use std::io::Read; use std::io::Result as IoResult; diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index 2f32ba8c70..f95b8a7a92 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -1,11 +1,7 @@ -use std::collections::VecDeque; use std::env; -use std::fs::File; -use std::io::{Read, Write}; use xhcid_interface::{ - plain, usb, ConfigureEndpointsReq, DevDesc, DeviceReqData, EndpDirection, EndpointTy, - PortReqRecipient, PortReqTy, XhciClientHandle, + plain, usb, DevDesc, DeviceReqData, PortReqRecipient, PortReqTy, XhciClientHandle, }; fn main() { diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 4c29c5260a..f944ec3ece 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -2,13 +2,12 @@ use event::{user_data, EventQueue}; use std::fs::File; -use std::io::{Read, Result, Write}; +use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; use std::{iter, mem}; use common::io::{Io, Mmio, Pio}; -use pcid_interface::{PciBar, PciFunctionHandle}; -use syscall::flag::EventFlags; +use pcid_interface::PciFunctionHandle; use common::dma::Dma; diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index f7379abe43..8f12e17524 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -2,7 +2,7 @@ use crate::spec::*; use crate::utils::align; use common::dma::Dma; -use event::{EventQueue, RawEventQueue}; +use event::RawEventQueue; use core::mem::size_of; use core::sync::atomic::{AtomicU16, Ordering}; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 7f76153d7c..7f9dc09b39 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -26,13 +26,9 @@ #[macro_use] extern crate bitflags; -use std::convert::{TryFrom, TryInto}; -use std::env; -use std::fs::{self, File}; -use std::future::Future; -use std::io::{self, Read, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::pin::Pin; +use std::fs::File; +use std::io::{Read, Write}; +use std::os::unix::io::{FromRawFd, RawFd}; use std::ptr::NonNull; use std::sync::{Arc, Mutex}; @@ -45,12 +41,8 @@ use pcid_interface::{ MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, }; -use common::io::Io; -use event::{Event, RawEventQueue}; -use log::info; use syscall::data::Packet; use syscall::error::EWOULDBLOCK; -use syscall::flag::EventFlags; use syscall::scheme::Scheme; use crate::xhci::{InterruptMethod, Xhci}; diff --git a/xhcid/src/xhci/device_enumerator.rs b/xhcid/src/xhci/device_enumerator.rs index 6e07bd3fa0..207211133b 100644 --- a/xhcid/src/xhci/device_enumerator.rs +++ b/xhcid/src/xhci/device_enumerator.rs @@ -1,11 +1,9 @@ use crate::xhci::port::PortFlags; -use crate::xhci::scheme::Handle::Port; use crate::xhci::Xhci; use common::io::Io; use crossbeam_channel; -use crossbeam_channel::RecvError; -use log::{debug, error, info, trace, warn}; -use std::sync::{Arc, Mutex}; +use log::{debug, info, warn}; +use std::sync::Arc; use std::time::Duration; use syscall::EAGAIN; diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 3317ee11e7..298e52ddcc 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -1,28 +1,24 @@ -use std::collections::BTreeMap; use std::fs::File; use std::future::Future; use std::io::prelude::*; use std::pin::Pin; -use std::sync::atomic::{self, AtomicUsize}; use std::sync::{Arc, Mutex}; -use std::{io, mem, task, thread}; +use std::task; use std::os::unix::io::AsRawFd; use crossbeam_channel::{Receiver, Sender}; -use futures::Stream; use log::{debug, error, info, trace, warn}; use super::doorbell::Doorbell; use super::event::EventRing; use super::ring::Ring; use super::trb::{Trb, TrbCompletionCode, TrbType}; -use super::{port, Xhci}; +use super::Xhci; use crate::xhci::device_enumerator::DeviceEnumerationRequest; use crate::xhci::port::PortFlags; -use crate::xhci::scheme::AnyDescriptor::Device; use common::io::Io as _; -use event::{Event, EventQueue, RawEventQueue}; +use event::RawEventQueue; /// Short-term states (as in, they are removed when the waker is consumed, but probably pushed back /// by the future unless it completed). diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 6ba32fc6ea..d64a03a0da 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -12,28 +12,24 @@ use std::collections::BTreeMap; use std::convert::TryFrom; use std::fs::File; -use std::future::Future; -use std::pin::Pin; use std::ptr::NonNull; -use std::sync::atomic::{AtomicBool, AtomicUsize}; -use std::sync::{Arc, Mutex, MutexGuard, Weak}; +use std::sync::atomic::AtomicUsize; +use std::sync::{Arc, Mutex, MutexGuard}; -use std::time::Duration; -use std::{mem, process, slice, sync::atomic, task, thread}; +use std::{mem, process, slice, thread}; use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT}; use syscall::{EAGAIN, PAGE_SIZE}; use chashmap::CHashMap; use common::{dma::Dma, io::Io}; use crossbeam_channel::{Receiver, Sender}; -use futures::AsyncReadExt; use log::{debug, error, info, trace, warn}; use serde::Deserialize; use crate::usb; use pcid_interface::msi::{MsixInfo, MsixTableEntry}; -use pcid_interface::{PciFeature, PciFunctionHandle}; +use pcid_interface::PciFunctionHandle; mod capability; mod context; @@ -58,8 +54,8 @@ use self::irq_reactor::{EventDoorbell, IrqReactor, NewPendingTrb, RingId}; use self::operational::OperationalRegs; use self::port::Port; use self::ring::Ring; -use self::runtime::{Interrupter, RuntimeRegs}; -use self::trb::{TransferKind, Trb, TrbCompletionCode, TrbType}; +use self::runtime::RuntimeRegs; +use self::trb::{TransferKind, Trb, TrbCompletionCode}; use self::scheme::EndpIfState; diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index cfe1dc5878..60dde7f7ae 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -1,8 +1,4 @@ use common::io::{Io, Mmio}; -use std::num::NonZeroU8; -use std::slice; - -use super::CapabilityRegs; /// The XHCI Operational Registers /// diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 1fd3631b90..bf4d948ef1 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -20,38 +20,30 @@ use std::convert::TryFrom; use std::io::prelude::*; use std::ops::Deref; use std::sync::atomic; -use std::{cmp, fmt, io, mem, path, str}; +use std::{cmp, fmt, io, mem, str}; use common::dma::Dma; use futures::executor::block_on; use log::{debug, error, info, trace, warn}; -use serde::{Deserialize, Serialize}; -use smallvec::{smallvec, SmallVec}; +use smallvec::SmallVec; use common::io::Io; use syscall::scheme::Scheme; use syscall::{ - Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EEXIST, EINVAL, EIO, EISDIR, ENOENT, - ENOSYS, ENOTDIR, ENXIO, EOPNOTSUPP, EOVERFLOW, EPERM, EPROTO, ESPIPE, MODE_CHR, MODE_DIR, - MODE_FILE, O_CREAT, O_DIRECTORY, O_RDONLY, O_RDWR, O_STAT, O_WRONLY, SEEK_CUR, SEEK_END, - SEEK_SET, + Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, + ENOTDIR, EPROTO, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_DIRECTORY, O_RDWR, O_STAT, O_WRONLY, + SEEK_CUR, SEEK_END, SEEK_SET, }; use super::{port, usb}; use super::{EndpointState, Xhci}; -use super::context::{ - InputContext, SlotState, StreamContext, StreamContextArray, StreamContextType, - ENDPOINT_CONTEXT_STATUS_MASK, -}; -use super::doorbell::Doorbell; +use super::context::{SlotState, StreamContextArray, StreamContextType}; use super::extended::ProtocolSpeed; use super::irq_reactor::{EventDoorbell, RingId}; -use super::operational::OperationalRegs; use super::ring::Ring; -use super::runtime::RuntimeRegs; use super::trb::{TransferKind, Trb, TrbCompletionCode, TrbType}; -use super::usb::endpoint::{EndpointTy, ENDP_ATTR_TY_MASK}; +use super::usb::endpoint::EndpointTy; use crate::driver_interface::*; use regex::Regex; @@ -2696,7 +2688,6 @@ pub fn handle_transfer_event_trb(name: &str, event_trb: &Trb, transfer_trb: &Trb } use lazy_static::lazy_static; use std::ops::{Add, Div, Rem}; -use std::path::Path; pub fn div_round_up(a: T, b: T) -> T where diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index 5d175ddbfa..d8e58417c0 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -1,6 +1,5 @@ use super::context::StreamContextType; use crate::usb; -use crate::xhci::trb::TrbType::PortStatusChange; use common::io::{Io, Mmio}; use log::trace; use std::{fmt, mem}; From 2344206c21d2e730e9dc239d01c44ceb5c780a2a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 17:36:40 +0100 Subject: [PATCH 1045/1301] graphics/virtio-gpud: Bundle resource id and resource mapping --- graphics/virtio-gpud/src/scheme.rs | 64 +++++++++++------------------- 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index deb7439843..60c49b0f19 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -27,14 +27,18 @@ impl Into for Damage { } } +struct GpuResource { + id: ResourceId, + sgl: sgl::Sgl, +} + pub struct Display<'a> { control_queue: Arc>, cursor_queue: Arc>, transport: Arc, active_vt: RefCell, - vts_map: RefCell>, - vts_res: RefCell>, + vts: RefCell>, width: u32, height: u32, @@ -54,8 +58,7 @@ impl<'a> Display<'a> { cursor_queue, active_vt: RefCell::new(0), - vts_map: RefCell::new(HashMap::new()), - vts_res: RefCell::new(HashMap::new()), + vts: RefCell::new(HashMap::new()), width: 1920, height: 1080, @@ -91,34 +94,19 @@ impl<'a> Display<'a> { Ok(()) } - async fn mmap_screen(&self, vt: usize, offset: usize) -> Result<*mut u8, Error> { - if let Some(sgl) = self.vts_map.borrow().get(&vt) { - return Ok(sgl.as_ptr().wrapping_add(offset)); + async fn res_for_screen(&self, vt: usize) -> Result<(ResourceId, *mut u8), Error> { + if let Some(res) = self.vts.borrow().get(&vt) { + return Ok((res.id, res.sgl.as_ptr())); } let bpp = 32; let fb_size = self.width as usize * self.height as usize * bpp / 8; - let mapped = sgl::Sgl::new(fb_size)?; + let sgl = sgl::Sgl::new(fb_size)?; unsafe { - core::ptr::write_bytes(mapped.as_ptr() as *mut u8, 255, fb_size); + core::ptr::write_bytes(sgl.as_ptr() as *mut u8, 255, fb_size); } - let mut mapped_vts = self.vts_map.borrow_mut(); - let sgl = mapped_vts.entry(vt).or_insert(mapped); - Ok(sgl.as_ptr().wrapping_add(offset)) - } - - async fn create_res_for_screen(&self, vt: usize) -> Result { - if let Some(&res_id) = self.vts_res.borrow().get(&vt) { - return Ok(res_id); - } - - self.mmap_screen(vt, 0).await?; - - let vts_map = self.vts_map.borrow(); - let mapped = &vts_map.get(&vt).unwrap(); - let res_id = ResourceId::alloc(); // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. @@ -135,8 +123,8 @@ impl<'a> Display<'a> { // Use the allocated framebuffer from tthe guest ram, and attach it as backing // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. - let mut mem_entries = unsafe { Dma::zeroed_slice(mapped.chunks().len())?.assume_init() }; - for (entry, chunk) in mem_entries.iter_mut().zip(mapped.chunks().iter()) { + let mut mem_entries = unsafe { Dma::zeroed_slice(sgl.chunks().len())?.assume_init() }; + for (entry, chunk) in mem_entries.iter_mut().zip(sgl.chunks().iter()) { *entry = MemEntry { address: chunk.phys as u64, length: chunk.length.next_multiple_of(PAGE_SIZE) as u32, @@ -155,13 +143,15 @@ impl<'a> Display<'a> { self.control_queue.send(command).await; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - let mut mapped_vts = self.vts_res.borrow_mut(); - mapped_vts.insert(vt, res_id); - Ok(res_id) + let mut mapped_vts = self.vts.borrow_mut(); + let res = mapped_vts + .entry(vt) + .or_insert(GpuResource { id: res_id, sgl }); + Ok((res.id, res.sgl.as_ptr())) } async fn set_scanout(&self, vt: usize) -> Result<(), Error> { - let res_id = self.create_res_for_screen(vt).await?; + let (res_id, _) = self.res_for_screen(vt).await?; let scanout_request = Dma::new(SetScanout::new( self.id as u32, @@ -178,12 +168,7 @@ impl<'a> Display<'a> { /// If `damage` is `None`, the entire screen is flushed. async fn flush(&self, vt: usize, damage: Option<&[Damage]>) -> Result<(), Error> { - let Some(&res_id) = self.vts_res.borrow().get(&vt) else { - // The resource is not yet created. Ignore the damage. We will write the entire backing - // storage to the resource once we create the resource, which is equivalent to damaging - // the entire resource. - return Ok(()); - }; + let (res_id, _) = self.res_for_screen(vt).await?; let req = Dma::new(XferToHost2d::new( res_id, @@ -430,9 +415,8 @@ impl<'a> Scheme for GpuScheme<'a> { ) -> syscall::Result { log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; - let ptr = - futures::executor::block_on(handle.display.mmap_screen(handle.vt, offset as usize)) - .unwrap(); - Ok(ptr as usize) + let (_, ptr) = + futures::executor::block_on(handle.display.res_for_screen(handle.vt)).unwrap(); + Ok(unsafe { ptr.offset(offset as isize) } as usize) } } From 62f1a80c3ee2a76ed3e75d691338ac3f79dc94d9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 17:53:45 +0100 Subject: [PATCH 1046/1301] graphics/virtio-gpud: Move resources from Display to GpuScheme Resources are global for the entire virtio-gpud device, not local to a single display. In the future resource creation will become entirely detached from specific displays. --- graphics/virtio-gpud/src/scheme.rs | 176 ++++++++++++++--------------- 1 file changed, 87 insertions(+), 89 deletions(-) diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 60c49b0f19..b72f1aa5f6 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -1,4 +1,3 @@ -use std::cell::RefCell; use std::collections::{BTreeMap, HashMap}; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -32,39 +31,18 @@ struct GpuResource { sgl: sgl::Sgl, } -pub struct Display<'a> { - control_queue: Arc>, - cursor_queue: Arc>, - transport: Arc, - - active_vt: RefCell, - vts: RefCell>, - +#[derive(Debug, Copy, Clone)] +pub struct Display { width: u32, height: u32, - - id: usize, } -impl<'a> Display<'a> { - pub fn new( - control_queue: Arc>, - cursor_queue: Arc>, - transport: Arc, - id: usize, - ) -> Self { +impl Display { + pub fn new() -> Self { Self { - control_queue, - cursor_queue, - - active_vt: RefCell::new(0), - vts: RefCell::new(HashMap::new()), - + // FIXME use the actual screen size width: 1920, height: 1080, - transport, - - id, } } @@ -75,7 +53,9 @@ impl<'a> Display<'a> { buffer[..path.len()].copy_from_slice(path.as_bytes()); Ok(path.len()) } +} +impl GpuScheme<'_> { async fn send_request(&self, request: Dma) -> Result, Error> { let header = Dma::new(ControlHeader::default())?; let command = ChainBuilder::new() @@ -94,13 +74,18 @@ impl<'a> Display<'a> { Ok(()) } - async fn res_for_screen(&self, vt: usize) -> Result<(ResourceId, *mut u8), Error> { - if let Some(res) = self.vts.borrow().get(&vt) { + async fn res_for_screen( + &mut self, + vt: usize, + screen: usize, + ) -> Result<(ResourceId, *mut u8), Error> { + if let Some(res) = self.vts.entry(vt).or_default().get(&screen) { return Ok((res.id, res.sgl.as_ptr())); } let bpp = 32; - let fb_size = self.width as usize * self.height as usize * bpp / 8; + let fb_size = + self.displays[screen].width as usize * self.displays[screen].height as usize * bpp / 8; let sgl = sgl::Sgl::new(fb_size)?; unsafe { @@ -112,8 +97,8 @@ impl<'a> Display<'a> { // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. let mut request = Dma::new(ResourceCreate2d::default())?; - request.set_width(self.width); - request.set_height(self.height); + request.set_width(self.displays[screen].width); + request.set_height(self.displays[screen].height); request.set_format(ResourceFormat::Bgrx); request.set_resource_id(res_id); @@ -143,40 +128,52 @@ impl<'a> Display<'a> { self.control_queue.send(command).await; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - let mut mapped_vts = self.vts.borrow_mut(); - let res = mapped_vts + let res = self + .vts .entry(vt) + .or_default() + .entry(screen) .or_insert(GpuResource { id: res_id, sgl }); Ok((res.id, res.sgl.as_ptr())) } - async fn set_scanout(&self, vt: usize) -> Result<(), Error> { - let (res_id, _) = self.res_for_screen(vt).await?; + async fn set_scanout(&mut self, vt: usize, screen: usize) -> Result<(), Error> { + let (res_id, _) = self.res_for_screen(vt, screen).await?; let scanout_request = Dma::new(SetScanout::new( - self.id as u32, + screen as u32, res_id, - GpuRect::new(0, 0, self.width, self.height), + GpuRect::new( + 0, + 0, + self.displays[screen].width, + self.displays[screen].height, + ), ))?; let header = self.send_request(scanout_request).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - self.flush(vt, None).await?; + self.flush(vt, screen, None).await?; Ok(()) } /// If `damage` is `None`, the entire screen is flushed. - async fn flush(&self, vt: usize, damage: Option<&[Damage]>) -> Result<(), Error> { - let (res_id, _) = self.res_for_screen(vt).await?; + async fn flush( + &mut self, + vt: usize, + screen: usize, + damage: Option<&[Damage]>, + ) -> Result<(), Error> { + let (res_id, _) = self.res_for_screen(vt, screen).await?; let req = Dma::new(XferToHost2d::new( res_id, GpuRect { x: 0, y: 0, - width: self.width, - height: self.height, + width: self.displays[screen].width, + height: self.displays[screen].height, }, 0, ))?; @@ -187,7 +184,12 @@ impl<'a> Display<'a> { for damage in damage { self.flush_resource(ResourceFlush::new( res_id, - damage.clip(self.width as i32, self.height as i32).into(), + damage + .clip( + self.displays[screen].width as i32, + self.displays[screen].height as i32, + ) + .into(), )) .await?; } @@ -197,8 +199,8 @@ impl<'a> Display<'a> { GpuRect { x: 0, y: 0, - width: self.width, - height: self.height, + width: self.displays[screen].width, + height: self.displays[screen].height, }, )) .await?; @@ -207,17 +209,24 @@ impl<'a> Display<'a> { } } -struct Handle<'a> { - display: Arc>, +struct Handle { + screen: usize, vt: usize, } pub struct GpuScheme<'a> { - handles: BTreeMap>, + control_queue: Arc>, + cursor_queue: Arc>, + transport: Arc, + pub inputd_handle: inputd::DisplayHandle, + + handles: BTreeMap, /// Counter used for file descriptor allocation. next_id: AtomicUsize, - displays: Vec>>, - pub inputd_handle: inputd::DisplayHandle, + + active_vt: usize, + vts: HashMap>, + displays: Vec, } impl<'a> GpuScheme<'a> { @@ -227,50 +236,42 @@ impl<'a> GpuScheme<'a> { cursor_queue: Arc>, transport: Arc, ) -> Result, Error> { - let displays = Self::probe( - control_queue.clone(), - cursor_queue.clone(), - transport.clone(), - config, - ) - .await?; + let displays = Self::probe(control_queue.clone(), config).await?; let inputd_handle = inputd::DisplayHandle::new("virtio-gpu").unwrap(); Ok(Self { + control_queue, + cursor_queue, + transport, + inputd_handle, + handles: BTreeMap::new(), next_id: AtomicUsize::new(0), + + active_vt: 0, + vts: HashMap::new(), displays, - inputd_handle, }) } async fn probe( control_queue: Arc>, - cursor_queue: Arc>, - transport: Arc, config: &GpuConfig, - ) -> Result>>, Error> { + ) -> Result, Error> { let mut display_info = Self::get_display_info(control_queue.clone()).await?; let displays = &mut display_info.display_info[..config.num_scanouts() as usize]; let mut result = vec![]; - for (id, info) in displays.iter().enumerate() { + for info in displays.iter() { log::info!( "virtio-gpu: opening display ({}x{}px)", info.rect().width, info.rect().height ); - let display = Display::new( - control_queue.clone(), - cursor_queue.clone(), - transport.clone(), - id, - ); - - result.push(Arc::new(display)); + result.push(Display::new()); } Ok(result) @@ -299,13 +300,13 @@ impl<'a> GpuScheme<'a> { VtEventKind::Activate => { log::info!("activate {}", vt_event.vt); - for display in &self.displays { + for id in 0..self.displays.len() { log::warn!("virtio-gpu: activating"); - futures::executor::block_on(display.set_scanout(vt_event.vt)).unwrap(); - - *display.active_vt.borrow_mut() = vt_event.vt; + futures::executor::block_on(self.set_scanout(vt_event.vt, id)).unwrap(); } + + self.active_vt = vt_event.vt; } VtEventKind::Deactivate => { @@ -334,33 +335,30 @@ impl<'a> Scheme for GpuScheme<'a> { dbg!(vt, id); - let display = self.displays.get(id).ok_or(SysError::new(EINVAL))?; + if id >= self.displays.len() { + return Err(SysError::new(EINVAL)); + }; let fd = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.insert( - fd, - Handle { - display: display.clone(), - vt, - }, - ); + self.handles.insert(fd, Handle { screen: id, vt }); Ok(fd) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { let handle = self.handles.get(&id).unwrap(); - let bytes_copied = futures::executor::block_on(handle.display.get_fpath(buf)).unwrap(); + let bytes_copied = + futures::executor::block_on(self.displays[handle.screen].get_fpath(buf)).unwrap(); Ok(bytes_copied) } fn fsync(&mut self, id: usize) -> syscall::Result { let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; - if handle.vt != *handle.display.active_vt.borrow() { + if handle.vt != self.active_vt { // This is a protection against background VT's spamming us with flush requests. We will // flush the resource on the next scanout anyway return Ok(0); } - futures::executor::block_on(handle.display.flush(handle.vt, None)).unwrap(); + futures::executor::block_on(self.flush(handle.vt, handle.screen, None)).unwrap(); Ok(0) } @@ -385,7 +383,7 @@ impl<'a> Scheme for GpuScheme<'a> { ) -> syscall::Result { let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; - if handle.vt != *handle.display.active_vt.borrow() { + if handle.vt != self.active_vt { // This is a protection against background VT's spamming us with flush requests. We will // flush the resource on the next scanout anyway return Ok(buf.len()); @@ -398,7 +396,7 @@ impl<'a> Scheme for GpuScheme<'a> { ) }; - futures::executor::block_on(handle.display.flush(handle.vt, Some(damage))).unwrap(); + futures::executor::block_on(self.flush(handle.vt, handle.screen, Some(damage))).unwrap(); Ok(buf.len()) } @@ -416,7 +414,7 @@ impl<'a> Scheme for GpuScheme<'a> { log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; let (_, ptr) = - futures::executor::block_on(handle.display.res_for_screen(handle.vt)).unwrap(); + futures::executor::block_on(self.res_for_screen(handle.vt, handle.screen)).unwrap(); Ok(unsafe { ptr.offset(offset as isize) } as usize) } } From 09de72e9a850a8664204f5ea0697d0c8e6449f87 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 20:50:44 +0100 Subject: [PATCH 1047/1301] common: Fix mmap overwriting unintended memory in Sgl If unaligned_length is for example 8193, the initial reservation would be rounded up to the next page resulting in 12288. However the physmap would previously round up to the next power of two forming 16384, potentially overwriting one page of data directly after the reservation. In case of bigger allocations, more pages could be overwritten. --- common/src/sgl.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/common/src/sgl.rs b/common/src/sgl.rs index ba26d3f00b..9bab7ad7c4 100644 --- a/common/src/sgl.rs +++ b/common/src/sgl.rs @@ -15,6 +15,8 @@ use crate::dma::phys_contiguous_fd; pub struct Sgl { /// A raw pointer to the SGL in virtual memory virt: *mut u8, + /// The length of the allocated memory, guaranteed to be a multiple of [PAGE_SIZE]. + aligned_length: usize, /// The length of the allocated memory. This value is NOT guaranteed to be a multiple of [PAGE_SIZE] unaligned_length: NonZeroUsize, /// The vector of chunks tracked by this [Sgl] object. This is the sparsely-populated vector in the SGL algorithm. @@ -39,15 +41,20 @@ impl Sgl { /// /// # Arguments /// - /// 'unaligned_length: [usize]' - The length of the SGL, not aligned to the nearest page. + /// 'unaligned_length: [usize]' - The length of the SGL, not necessarily aligned to the nearest + /// page. pub fn new(unaligned_length: usize) -> Result { let unaligned_length = NonZeroUsize::new(unaligned_length).ok_or(Error::new(EINVAL))?; + // TODO: Both PAGE_SIZE and MAX_ALLOC_SIZE should be dynamic. + let aligned_length = unaligned_length.get().next_multiple_of(PAGE_SIZE); + const MAX_ALLOC_SIZE: usize = 1 << 22; + unsafe { let virt = libredox::call::mmap(MmapArgs { flags: MAP_PRIVATE, prot: PROT_READ | PROT_WRITE, - length: unaligned_length.get(), + length: aligned_length, offset: 0, fd: !0, @@ -57,21 +64,23 @@ impl Sgl { let mut this = Self { virt, + aligned_length, unaligned_length, chunks: Vec::new(), }; let phys_contiguous_fd = phys_contiguous_fd()?; - // TODO: Both PAGE_SIZE and MAX_ALLOC_SIZE should be dynamic. - let aligned_length = unaligned_length.get().next_multiple_of(PAGE_SIZE); - const MAX_ALLOC_SIZE: usize = 1 << 22; - let mut offset = 0; - while offset < unaligned_length.get() { - let chunk_length = (aligned_length - offset) + while offset < aligned_length { + let preferred_chunk_length = (aligned_length - offset) .min(MAX_ALLOC_SIZE) .next_power_of_two(); + let chunk_length = if preferred_chunk_length > aligned_length - offset { + preferred_chunk_length / 2 + } else { + preferred_chunk_length + }; libredox::call::mmap(MmapArgs { addr: virt.add(offset).cast(), flags: MAP_PRIVATE | (MAP_FIXED.bits() as u32), @@ -112,7 +121,7 @@ impl Sgl { impl Drop for Sgl { fn drop(&mut self) { unsafe { - let _ = libredox::call::munmap(self.virt.cast(), self.unaligned_length.get()); + let _ = libredox::call::munmap(self.virt.cast(), self.aligned_length); } } } From 3ed3ff2edbbbe385bbd98b2633fdae7cb837b9ff Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 20:57:53 +0100 Subject: [PATCH 1048/1301] graphics/fbcond: Handle framebuffer resize during handoff --- graphics/fbcond/src/display.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 46785796df..053b585563 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -61,11 +61,13 @@ impl Display { let (mut new_display_file, width, height) = Self::open_display(&self.input_handle).unwrap(); - eprintln!("fbcond: Opened new display"); + eprintln!("fbcond: Opened new display with size {width}x{height}"); match display_fd_map(width, height, &mut new_display_file) { Ok(offscreen) => { self.offscreen = offscreen; + self.width = width; + self.height = height; self.display_file = new_display_file; eprintln!("fbcond: Mapped new display"); @@ -108,6 +110,8 @@ impl Display { match display_fd_map(width, height, &mut self.display_file) { Ok(offscreen) => { self.offscreen = offscreen; + self.width = width; + self.height = height; } Err(err) => { eprintln!("failed to resize display to {}x{}: {}", width, height, err); From 1b6feeb7c7f0da84ea22c7fa3168efa8653a9006 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 20:59:08 +0100 Subject: [PATCH 1049/1301] graphics/virtio-gpud: Use VM window size as display size Rather than hard coding 1920x1080. This doesn't yet handle resizing the VM window at runtime though. --- graphics/virtio-gpud/src/scheme.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index b72f1aa5f6..e9c1bef067 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -38,14 +38,6 @@ pub struct Display { } impl Display { - pub fn new() -> Self { - Self { - // FIXME use the actual screen size - width: 1920, - height: 1080, - } - } - async fn get_fpath(&self, buffer: &mut [u8]) -> Result { let path = format!("display.virtio-gpu:3.0/{}/{}", self.width, self.height); @@ -271,7 +263,10 @@ impl<'a> GpuScheme<'a> { info.rect().height ); - result.push(Display::new()); + result.push(Display { + width: info.rect().width, + height: info.rect().height, + }); } Ok(result) From 3fbf0fecbb4daa3f31b06de5b361a83f1d5e1c9c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 21:57:41 +0100 Subject: [PATCH 1050/1301] graphics/console-draw: Fix resizing to a smaller display Without this commit ransid would generate move events with an underflowed height which take forever to process. --- graphics/console-draw/src/lib.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index d52e46c57f..9c94ee934c 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -124,9 +124,13 @@ impl TextScreen { buf: &[u8], input: &mut VecDeque, ) -> Vec { - self.console.state.w = map.width / 8; - self.console.state.h = map.height / 16; - self.console.state.bottom_margin = (map.height / 16).saturating_sub(1); + self.console.resize(map.width / 8, map.height / 16); + if self.console.state.x > self.console.state.w { + self.console.state.x = self.console.state.w; + } + if self.console.state.y > self.console.state.h { + self.console.state.y = self.console.state.h; + } if self.console.state.cursor && self.console.state.x < self.console.state.w From bf6e16c8c9f14adbe25f112ec20b6af752cbb0b9 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 21:58:07 +0100 Subject: [PATCH 1051/1301] graphics/console-draw: Slightly simplify TextScreen::write --- graphics/console-draw/src/lib.rs | 103 +++++++++++++++---------------- 1 file changed, 50 insertions(+), 53 deletions(-) diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index 9c94ee934c..1b4c386cf1 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -142,68 +142,65 @@ impl TextScreen { self.changed.insert(y); } - { - let changed = &mut self.changed; - self.console.write(buf, |event| match event { - ransid::Event::Char { - x, - y, - c, - color, - bold, - .. - } => { - Self::char(map, x * 8, y * 16, c, color.as_rgb(), bold, false); - changed.insert(y); + self.console.write(buf, |event| match event { + ransid::Event::Char { + x, + y, + c, + color, + bold, + .. + } => { + Self::char(map, x * 8, y * 16, c, color.as_rgb(), bold, false); + self.changed.insert(y); + } + ransid::Event::Input { data } => input.extend(data), + ransid::Event::Rect { x, y, w, h, color } => { + Self::rect(map, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); + for y2 in y..y + h { + self.changed.insert(y2); } - ransid::Event::Input { data } => input.extend(data), - ransid::Event::Rect { x, y, w, h, color } => { - Self::rect(map, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); - for y2 in y..y + h { - changed.insert(y2); - } - } - ransid::Event::ScreenBuffer { .. } => (), - ransid::Event::Move { - from_x, - from_y, - to_x, - to_y, - w, - h, - } => { - let width = map.width; - let pixels = unsafe { &mut *map.offscreen }; + } + ransid::Event::ScreenBuffer { .. } => (), + ransid::Event::Move { + from_x, + from_y, + to_x, + to_y, + w, + h, + } => { + let width = map.width; + let pixels = unsafe { &mut *map.offscreen }; - for raw_y in 0..h { - let y = if from_y > to_y { raw_y } else { h - raw_y - 1 }; + for raw_y in 0..h { + let y = if from_y > to_y { raw_y } else { h - raw_y - 1 }; - for pixel_y in 0..16 { - { - let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8; - let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8; - let len = w * 8; + for pixel_y in 0..16 { + { + let off_from = ((from_y + y) * 16 + pixel_y) * width + from_x * 8; + let off_to = ((to_y + y) * 16 + pixel_y) * width + to_x * 8; + let len = w * 8; - if off_from + len <= pixels.len() && off_to + len <= pixels.len() { - unsafe { - let data_ptr = pixels.as_mut_ptr() as *mut u32; - ptr::copy( - data_ptr.offset(off_from as isize), - data_ptr.offset(off_to as isize), - len, - ); - } + if off_from + len <= pixels.len() && off_to + len <= pixels.len() { + unsafe { + let data_ptr = pixels.as_mut_ptr() as *mut u32; + ptr::copy( + data_ptr.offset(off_from as isize), + data_ptr.offset(off_to as isize), + len, + ); } } } - - changed.insert(to_y + y); } + + self.changed.insert(to_y + y); } - ransid::Event::Resize { .. } => (), - ransid::Event::Title { .. } => (), - }); - } + } + ransid::Event::Resize { .. } => (), + ransid::Event::Title { .. } => (), + }); if self.console.state.cursor && self.console.state.x < self.console.state.w From 6f188cf7efa3a6460a7ad234002e2c23d8678dec Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 21:58:41 +0100 Subject: [PATCH 1052/1301] graphics/fbcond: Unmap old offscreen buffer on handoff and resize --- graphics/fbcond/src/display.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 053b585563..cf2dbc528a 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -65,6 +65,10 @@ impl Display { match display_fd_map(width, height, &mut new_display_file) { Ok(offscreen) => { + unsafe { + display_fd_unmap(self.offscreen); + } + self.offscreen = offscreen; self.width = width; self.height = height; @@ -109,6 +113,10 @@ impl Display { pub fn resize(&mut self, width: usize, height: usize) { match display_fd_map(width, height, &mut self.display_file) { Ok(offscreen) => { + unsafe { + display_fd_unmap(self.offscreen); + } + self.offscreen = offscreen; self.width = width; self.height = height; From b7f4af9bd2bf958caaf9c66a327564d6832676a8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 26 Dec 2024 16:11:48 +0100 Subject: [PATCH 1053/1301] graphics/virtio-gpud: Bring scheme impl closer in line with vesad --- graphics/virtio-gpud/src/scheme.rs | 35 ++++++++++++------------------ 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index e9c1bef067..35933fad9d 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -7,7 +7,7 @@ use common::{dma::Dma, sgl}; use inputd::{Damage, VtEvent, VtEventKind}; use redox_scheme::Scheme; -use syscall::{Error as SysError, MapFlags, EINVAL, PAGE_SIZE}; +use syscall::{Error as SysError, MapFlags, EBADF, EINVAL, PAGE_SIZE}; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::{Error, Queue, Transport}; @@ -37,16 +37,6 @@ pub struct Display { height: u32, } -impl Display { - async fn get_fpath(&self, buffer: &mut [u8]) -> Result { - let path = format!("display.virtio-gpu:3.0/{}/{}", self.width, self.height); - - // Copy the path into the target buffer. - buffer[..path.len()].copy_from_slice(path.as_bytes()); - Ok(path.len()) - } -} - impl GpuScheme<'_> { async fn send_request(&self, request: Dma) -> Result, Error> { let header = Dma::new(ControlHeader::default())?; @@ -341,13 +331,16 @@ impl<'a> Scheme for GpuScheme<'a> { fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { let handle = self.handles.get(&id).unwrap(); - let bytes_copied = - futures::executor::block_on(self.displays[handle.screen].get_fpath(buf)).unwrap(); - Ok(bytes_copied) + let path = format!( + "display.virtio-gpu:3.0/{}/{}", + self.displays[handle.screen].width, self.displays[handle.screen].height + ); + buf[..path.len()].copy_from_slice(path.as_bytes()); + Ok(path.len()) } fn fsync(&mut self, id: usize) -> syscall::Result { - let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; + let handle = self.handles.get(&id).ok_or(SysError::new(EBADF))?; if handle.vt != self.active_vt { // This is a protection against background VT's spamming us with flush requests. We will // flush the resource on the next scanout anyway @@ -359,14 +352,13 @@ impl<'a> Scheme for GpuScheme<'a> { fn read( &mut self, - _id: usize, + id: usize, _buf: &mut [u8], _offset: u64, _fcntl_flags: u32, ) -> syscall::Result { - // TODO: figure out how to get input lol - log::warn!("virtio_gpu::read is a stub!"); - Ok(0) + let _handle = self.handles.get(&id).ok_or(SysError::new(EBADF))?; + Err(SysError::new(EINVAL)) } fn write( @@ -376,7 +368,7 @@ impl<'a> Scheme for GpuScheme<'a> { _offset: u64, _fcntl_flags: u32, ) -> syscall::Result { - let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; + let handle = self.handles.get(&id).ok_or(SysError::new(EBADF))?; if handle.vt != self.active_vt { // This is a protection against background VT's spamming us with flush requests. We will @@ -396,7 +388,8 @@ impl<'a> Scheme for GpuScheme<'a> { Ok(buf.len()) } - fn close(&mut self, _id: usize) -> syscall::Result { + fn close(&mut self, id: usize) -> syscall::Result { + self.handles.remove(&id).ok_or(SysError::new(EBADF))?; Ok(0) } fn mmap_prep( From d2f1af9ca7e2f99eb504bcc161221d62b0e5b4fc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 24 Dec 2024 13:22:32 +0100 Subject: [PATCH 1054/1301] Add driver-graphics crate This unifies the driver interface handling between graphics drivers and makes it easier to change all graphics drivers in lockstep when adding new features. --- Cargo.lock | 16 +- Cargo.toml | 1 + graphics/driver-graphics/Cargo.toml | 13 + graphics/driver-graphics/src/lib.rs | 259 ++++++++++++++++ graphics/vesad/Cargo.toml | 2 +- graphics/vesad/src/display.rs | 4 + graphics/vesad/src/main.rs | 67 ++--- graphics/vesad/src/scheme.rs | 253 ++-------------- graphics/vesad/src/screen.rs | 34 +-- graphics/virtio-gpud/Cargo.toml | 2 +- graphics/virtio-gpud/src/main.rs | 51 +--- graphics/virtio-gpud/src/scheme.rs | 446 ++++++++++------------------ 12 files changed, 523 insertions(+), 625 deletions(-) create mode 100644 graphics/driver-graphics/Cargo.toml create mode 100644 graphics/driver-graphics/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 0e99da0d5d..28de7e560d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -396,6 +396,18 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "driver-graphics" +version = "0.1.0" +dependencies = [ + "common", + "inputd", + "libredox", + "log", + "redox-scheme", + "redox_syscall", +] + [[package]] name = "driver-network" version = "0.1.0" @@ -1706,12 +1718,12 @@ name = "vesad" version = "0.1.0" dependencies = [ "common", + "driver-graphics", "inputd", "libredox", "orbclient", "ransid", "redox-daemon", - "redox-scheme", "redox_event", "redox_syscall", ] @@ -1760,6 +1772,7 @@ version = "0.1.0" dependencies = [ "anyhow", "common", + "driver-graphics", "futures", "inputd", "libredox", @@ -1768,7 +1781,6 @@ dependencies = [ "paste", "pcid", "redox-daemon", - "redox-scheme", "redox_event", "redox_syscall", "spin", diff --git a/Cargo.toml b/Cargo.toml index 2181fb2841..9fe3ecd2be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "graphics/bgad", "graphics/console-draw", "graphics/fbbootlogd", + "graphics/driver-graphics", "graphics/fbcond", "graphics/vesad", "graphics/virtio-gpud", diff --git a/graphics/driver-graphics/Cargo.toml b/graphics/driver-graphics/Cargo.toml new file mode 100644 index 0000000000..c7cd6f9de5 --- /dev/null +++ b/graphics/driver-graphics/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "driver-graphics" +version = "0.1.0" +edition = "2021" + +[dependencies] +log = "0.4" +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox_syscall = "0.5" +libredox = "0.1.3" + +common = { path = "../../common" } +inputd = { path = "../../inputd" } diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs new file mode 100644 index 0000000000..33c925206c --- /dev/null +++ b/graphics/driver-graphics/src/lib.rs @@ -0,0 +1,259 @@ +use std::collections::{BTreeMap, HashMap}; +use std::io; + +use inputd::{Damage, VtEvent, VtEventKind}; +use libredox::errno::EOPNOTSUPP; +use libredox::Fd; +use redox_scheme::{RequestKind, Response, Scheme, SignalBehavior, Socket}; +use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL}; + +pub trait GraphicsAdapter { + type Resource: Resource; + + fn displays(&self) -> Vec; + fn display_size(&self, display_id: usize) -> (u32, u32); + + fn create_resource(&mut self, width: u32, height: u32) -> Self::Resource; + fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8; + + fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource); + fn flush_resource( + &mut self, + display_id: usize, + resource: &Self::Resource, + damage: Option<&[Damage]>, + ); +} + +pub trait Resource { + fn width(&self) -> u32; + fn height(&self) -> u32; +} + +pub struct GraphicsScheme { + adapter: T, + + scheme_name: String, + socket: Socket, + next_id: usize, + handles: BTreeMap, + + active_vt: usize, + vts_res: HashMap>, +} + +enum Handle { + Screen { vt: usize, screen: usize }, +} + +impl GraphicsScheme { + pub fn new(adapter: T, scheme_name: String) -> Self { + assert!(scheme_name.starts_with("display")); + let socket = Socket::nonblock(&scheme_name).expect("failed to create graphics scheme"); + + GraphicsScheme { + adapter, + scheme_name, + socket, + next_id: 0, + handles: BTreeMap::new(), + active_vt: 0, + vts_res: HashMap::new(), + } + } + + pub fn event_handle(&self) -> &Fd { + self.socket.inner() + } + + pub fn adapter(&self) -> &T { + &self.adapter + } + + pub fn adapter_mut(&mut self) -> &mut T { + &mut self.adapter + } + + pub fn handle_vt_event(&mut self, vt_event: VtEvent) { + match vt_event.kind { + VtEventKind::Activate => { + log::info!("activate {}", vt_event.vt); + + for display_id in self.adapter.displays() { + let resource = self + .vts_res + .entry(vt_event.vt) + .or_default() + .entry(display_id) + .or_insert_with(|| { + let (width, height) = self.adapter.display_size(display_id); + self.adapter.create_resource(width, height) + }); + self.adapter.set_scanout(display_id, resource); + + self.active_vt = vt_event.vt; + } + } + + VtEventKind::Deactivate => { + log::info!("deactivate {}", vt_event.vt); + // nothing to do :) + } + + VtEventKind::Resize => { + log::warn!("driver-graphics: resize is not implemented yet") + } + } + } + + /// Process new scheme requests. + /// + /// This needs to be called each time there is a new event on the scheme + /// file. + pub fn tick(&mut self) -> io::Result<()> { + loop { + let request = match self.socket.next_request(SignalBehavior::Restart) { + Ok(Some(request)) => request, + Ok(None) => { + // Scheme likely got unmounted + std::process::exit(0); + } + Err(err) if err.errno == EAGAIN => break, + Err(err) => panic!("vesad: failed to read display scheme: {err}"), + }; + + match request.kind() { + RequestKind::Call(call_request) => { + let resp = call_request.handle_scheme(self); + self.socket + .write_response(resp, SignalBehavior::Restart) + .expect("vesad: failed to write display scheme"); + } + RequestKind::SendFd(sendfd_request) => { + self.socket.write_response( + Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), + SignalBehavior::Restart, + )?; + } + RequestKind::Cancellation(_cancellation_request) => {} + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() + } + } + } + + Ok(()) + } +} + +impl Scheme for GraphicsScheme { + fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> Result { + if path.is_empty() { + return Err(Error::new(EINVAL)); + } + + let mut parts = path.split('/'); + let mut screen = parts.next().unwrap_or("").split('.'); + + let vt = screen.next().unwrap_or("").parse::().unwrap(); + let id = screen.next().unwrap_or("").parse::().unwrap_or(0); + + dbg!(vt, id); + + if id >= self.adapter.displays().len() { + return Err(Error::new(EINVAL)); + } + + self.vts_res + .entry(vt) + .or_default() + .entry(id) + .or_insert_with(|| { + let (width, height) = self.adapter.display_size(id); + self.adapter.create_resource(width, height) + }); + + self.next_id += 1; + self.handles + .insert(self.next_id, Handle::Screen { vt, screen: id }); + Ok(self.next_id) + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { + let Handle::Screen { vt, screen } = self.handles.get(&id).ok_or(Error::new(EBADF))?; + let resource = &self.vts_res[vt][screen]; + let path = format!( + "{}:{vt}.{screen}/{}/{}", + self.scheme_name, + resource.width(), + resource.height() + ); + buf[..path.len()].copy_from_slice(path.as_bytes()); + Ok(path.len()) + } + + fn fsync(&mut self, id: usize) -> syscall::Result { + let Handle::Screen { vt, screen } = self.handles.get(&id).ok_or(Error::new(EBADF))?; + if *vt != self.active_vt { + // This is a protection against background VT's spamming us with flush requests. We will + // flush the resource on the next VT switch anyway + return Ok(0); + } + let resource = &self.vts_res[vt][screen]; + self.adapter.flush_resource(*screen, resource, None); + Ok(0) + } + + fn read( + &mut self, + id: usize, + _buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + ) -> Result { + let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + Err(Error::new(EINVAL)) + } + + fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { + let Handle::Screen { vt, screen } = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + if *vt != self.active_vt { + // This is a protection against background VT's spamming us with flush requests. We will + // flush the resource on the next VT switch anyway + return Ok(buf.len()); + } + + let resource = &self.vts_res[vt][screen]; + + let damage = unsafe { + core::slice::from_raw_parts( + buf.as_ptr() as *const Damage, + buf.len() / core::mem::size_of::(), + ) + }; + + self.adapter.flush_resource(*screen, resource, Some(damage)); + + Ok(buf.len()) + } + + fn close(&mut self, id: usize) -> syscall::Result { + self.handles.remove(&id).ok_or(Error::new(EBADF))?; + Ok(0) + } + fn mmap_prep( + &mut self, + id: usize, + offset: u64, + size: usize, + flags: MapFlags, + ) -> syscall::Result { + log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); + let handle = self.handles.get(&id).ok_or(Error::new(EINVAL))?; + let Handle::Screen { vt, screen } = handle; + let resource = &self.vts_res[vt][screen]; + let ptr = T::map_resource(&mut self.adapter, resource); + Ok(ptr as usize) + } +} diff --git a/graphics/vesad/Cargo.toml b/graphics/vesad/Cargo.toml index eeb5bc77ed..8106dbca03 100644 --- a/graphics/vesad/Cargo.toml +++ b/graphics/vesad/Cargo.toml @@ -11,9 +11,9 @@ redox-daemon = "0.1" redox_event = "0.4.1" common = { path = "../../common" } +driver-graphics = { path = "../driver-graphics" } inputd = { path = "../../inputd" } libredox = "0.1.3" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } [features] default = [] diff --git a/graphics/vesad/src/display.rs b/graphics/vesad/src/display.rs index f746c5ac14..8aad04d62c 100644 --- a/graphics/vesad/src/display.rs +++ b/graphics/vesad/src/display.rs @@ -21,6 +21,10 @@ impl OffscreenBuffer { let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout)); OffscreenBuffer { ptr } } + + pub fn ptr(&self) -> *mut u8 { + self.ptr.as_mut_ptr().cast::() + } } impl Drop for OffscreenBuffer { fn drop(&mut self) { diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 4880e1a67b..457870ba64 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -1,15 +1,16 @@ -#![feature(int_roundings)] +#![feature(int_roundings, slice_ptr_get)] extern crate orbclient; extern crate syscall; +use driver_graphics::GraphicsScheme; use event::{user_data, EventQueue}; -use libredox::errno::{EAGAIN, EOPNOTSUPP}; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; +use inputd::DisplayHandle; use std::env; use std::fs::File; use std::os::fd::AsRawFd; -use crate::{framebuffer::FrameBuffer, scheme::DisplayScheme}; +use crate::framebuffer::FrameBuffer; +use crate::scheme::FbAdapter; mod display; mod framebuffer; @@ -78,12 +79,15 @@ fn main() { .expect("failed to create daemon"); } fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[()]) -> ! { - let socket = Socket::nonblock("display.vesa").expect("vesad: failed to create display scheme"); - - let mut scheme = DisplayScheme::new(framebuffers, &spec); - + let mut inputd_display_handle = DisplayHandle::new_early("vesa").unwrap(); let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); + for &() in spec.iter() { + inputd_display_handle.register_vt().unwrap(); + } + + let mut scheme = GraphicsScheme::new(FbAdapter { framebuffers }, "display.vesa".to_owned()); + user_data! { enum Source { Input, @@ -95,14 +99,14 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( EventQueue::new().expect("vesad: failed to create event queue"); event_queue .subscribe( - scheme.inputd_handle.inner().as_raw_fd() as usize, + inputd_display_handle.inner().as_raw_fd() as usize, Source::Input, event::EventFlags::READ, ) .unwrap(); event_queue .subscribe( - socket.inner().raw(), + scheme.event_handle().raw(), Source::Scheme, event::EventFlags::READ, ) @@ -123,8 +127,7 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( { match event { Source::Input => { - while let Some(vt_event) = scheme - .inputd_handle + while let Some(vt_event) = inputd_display_handle .read_vt_event() .expect("vesad: failed to read display handle") { @@ -132,43 +135,9 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( } } Source::Scheme => { - loop { - let request = match socket.next_request(SignalBehavior::Restart) { - Ok(Some(request)) => request, - Ok(None) => { - // Scheme likely got unmounted - std::process::exit(0); - } - Err(err) if err.errno == EAGAIN => break, - Err(err) => panic!("vesad: failed to read display scheme: {err}"), - }; - - match request.kind() { - RequestKind::Call(call_request) => { - socket - .write_response( - call_request.handle_scheme(&mut scheme), - SignalBehavior::Restart, - ) - .expect("vesad: failed to write display scheme"); - } - RequestKind::SendFd(sendfd_request) => { - socket - .write_response( - Response::for_sendfd( - &sendfd_request, - Err(syscall::Error::new(EOPNOTSUPP)), - ), - SignalBehavior::Restart, - ) - .expect("vesad: failed to write scheme"); - } - RequestKind::Cancellation(_cancellation_request) => {} - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { - unreachable!() - } - } - } + scheme + .tick() + .expect("vesad: failed to handle scheme events"); } } } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index a2cf93a011..495a5a48cf 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -1,248 +1,47 @@ -use std::collections::BTreeMap; -use std::str; - -use inputd::{VtEvent, VtEventKind}; -use redox_scheme::Scheme; -use syscall::{Error, MapFlags, Result, EBADF, EINVAL, ENOENT}; +use driver_graphics::GraphicsAdapter; use crate::{framebuffer::FrameBuffer, screen::GraphicScreen}; -#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)] -pub struct VtIndex(usize); - -#[derive(Clone, Copy, Eq, Ord, PartialEq, PartialOrd, Debug)] -pub struct ScreenIndex(usize); - -#[derive(Clone)] -pub struct Handle { - pub vt: VtIndex, - pub screen: ScreenIndex, +pub struct FbAdapter { + pub framebuffers: Vec, } -pub struct DisplayScheme { - framebuffers: Vec, - active: VtIndex, - pub vts: BTreeMap>, - next_id: usize, - pub handles: BTreeMap, - pub inputd_handle: inputd::DisplayHandle, -} +impl GraphicsAdapter for FbAdapter { + type Resource = GraphicScreen; -impl DisplayScheme { - pub fn new(framebuffers: Vec, spec: &[()]) -> DisplayScheme { - let mut inputd_handle = inputd::DisplayHandle::new_early("vesa").unwrap(); - - let mut vts = BTreeMap::>::new(); - - for &() in spec.iter() { - let mut screens = BTreeMap::::new(); - for fb_i in 0..framebuffers.len() { - let fb = &framebuffers[fb_i]; - screens.insert(ScreenIndex(fb_i), GraphicScreen::new(fb.width, fb.height)); - } - vts.insert(VtIndex(inputd_handle.register_vt().unwrap()), screens); - } - - DisplayScheme { - framebuffers, - active: VtIndex(1), - vts, - next_id: 0, - handles: BTreeMap::new(), - inputd_handle, - } + fn displays(&self) -> Vec { + (0..self.framebuffers.len()).collect() } - fn resize(&mut self, width: usize, height: usize, stride: usize) { - //TODO: support resizing other outputs? - let fb_i = 0; - println!( - "Resizing framebuffer {} to {}, {} stride {}", - fb_i, width, height, stride - ); - - unsafe { - self.framebuffers[fb_i].resize(width, height, stride); - } - - // Resize screens - for (vt_i, screens) in self.vts.iter_mut() { - for (screen_i, screen) in screens.iter_mut() { - if screen_i.0 == fb_i { - screen.resize(width, height); - if *vt_i == self.active { - screen.redraw(&mut self.framebuffers[screen_i.0]); - } - } - } - } + fn display_size(&self, display_id: usize) -> (u32, u32) { + ( + self.framebuffers[display_id].width as u32, + self.framebuffers[display_id].height as u32, + ) } - pub fn handle_vt_event(&mut self, vt_event: VtEvent) { - match vt_event.kind { - VtEventKind::Activate => { - let vt_i = VtIndex(vt_event.vt); - - if let Some(screens) = self.vts.get_mut(&vt_i) { - for (screen_i, screen) in screens.iter_mut() { - screen.redraw(&mut self.framebuffers[screen_i.0]); - } - } - - self.active = vt_i; - } - VtEventKind::Deactivate => { - // Nothing to do for deactivate :) - } - VtEventKind::Resize => { - self.resize( - vt_event.width as usize, - vt_event.height as usize, - vt_event.stride as usize, - ); - } - } - } -} - -impl Scheme for DisplayScheme { - fn open(&mut self, path_str: &str, _flags: usize, _uid: u32, _gid: u32) -> Result { - let mut parts = path_str.split('/'); - let mut vt_screen = parts.next().unwrap_or("").split('.'); - let vt_i = VtIndex(vt_screen.next().unwrap_or("").parse::().unwrap_or(1)); - let screen_i = ScreenIndex(vt_screen.next().unwrap_or("").parse::().unwrap_or(0)); - if let Some(screens) = self.vts.get_mut(&vt_i) { - if screens.get_mut(&screen_i).is_some() { - let id = self.next_id; - self.next_id += 1; - - self.handles.insert( - id, - Handle { - vt: vt_i, - screen: screen_i, - }, - ); - - Ok(id) - } else { - Err(Error::new(ENOENT)) - } - } else { - Err(Error::new(ENOENT)) - } + fn create_resource(&mut self, width: u32, height: u32) -> Self::Resource { + GraphicScreen::new(width as usize, height as usize) } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let handle = self - .handles - .get(&id) - .map(|handle| handle.clone()) - .ok_or(Error::new(EBADF))?; - - let new_id = self.next_id; - self.next_id += 1; - - self.handles.insert(new_id, handle.clone()); - - Ok(new_id) + fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8 { + resource.offscreen.ptr() } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let path_str = { - if let Some(screens) = self.vts.get(&handle.vt) { - if let Some(screen) = screens.get(&handle.screen) { - format!( - "display:{}.{}/{}/{}", - handle.vt.0, handle.screen.0, screen.width, screen.height - ) - } else { - return Err(Error::new(EBADF)); - } - } else { - return Err(Error::new(EBADF)); - } - }; - - let path = path_str.as_bytes(); - - let mut i = 0; - while i < buf.len() && i < path.len() { - buf[i] = path[i]; - i += 1; - } - - Ok(i) + fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource) { + resource.redraw(&mut self.framebuffers[display_id]); } - fn fsync(&mut self, id: usize) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - if let Some(screens) = self.vts.get_mut(&handle.vt) { - if let Some(screen) = screens.get_mut(&handle.screen) { - if handle.vt == self.active { - screen.redraw(&mut self.framebuffers[handle.screen.0]); - } - return Ok(0); - } - } - - Err(Error::new(EBADF)) - } - - fn read( + fn flush_resource( &mut self, - id: usize, - _buf: &mut [u8], - _offset: u64, - _fcntl_flags: u32, - ) -> Result { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - Err(Error::new(EINVAL)) - } - - fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - if let Some(screens) = self.vts.get_mut(&handle.vt) { - if let Some(screen) = screens.get_mut(&handle.screen) { - if handle.vt == self.active { - screen.write(buf, Some(&mut self.framebuffers[handle.screen.0])) - } else { - screen.write(buf, None) - } - } else { - Err(Error::new(EBADF)) - } + display_id: usize, + resource: &Self::Resource, + damage: Option<&[inputd::Damage]>, + ) { + if let Some(damage) = damage { + resource.sync(&mut self.framebuffers[display_id], damage) } else { - Err(Error::new(EBADF)) + resource.redraw(&mut self.framebuffers[display_id]) } } - - fn close(&mut self, id: usize) -> Result { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(0) - } - fn mmap_prep(&mut self, id: usize, off: u64, size: usize, _flags: MapFlags) -> Result { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - if let Some(screens) = self.vts.get(&handle.vt) { - if let Some(screen) = screens.get(&handle.screen) { - if off as usize + size <= screen.offscreen.len() * 4 { - return Ok(screen.offscreen.as_ptr() as usize + off as usize); - } else { - return Err(Error::new(EINVAL)); - } - } - } - - Err(Error::new(EBADF)) - } } diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index a50518ae4c..71b99f7b51 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -1,8 +1,8 @@ use std::convert::TryInto; -use std::{cmp, mem, ptr, slice}; +use std::{cmp, ptr}; +use driver_graphics::Resource; use inputd::Damage; -use syscall::error::*; use crate::display::OffscreenBuffer; use crate::framebuffer::FrameBuffer; @@ -23,6 +23,16 @@ impl GraphicScreen { } } +impl Resource for GraphicScreen { + fn width(&self) -> u32 { + self.width as u32 + } + + fn height(&self) -> u32 { + self.height as u32 + } +} + impl GraphicScreen { pub fn resize(&mut self, width: usize, height: usize) { //TODO: Fix issue with mapped screens @@ -69,21 +79,7 @@ impl GraphicScreen { }; } - pub fn write(&mut self, buf: &[u8], framebuffer: Option<&mut FrameBuffer>) -> Result { - let sync_rects = unsafe { - slice::from_raw_parts( - buf.as_ptr() as *const Damage, - buf.len() / mem::size_of::(), - ) - }; - - if let Some(framebuffer) = framebuffer { - self.sync(framebuffer, sync_rects); - } - - Ok(sync_rects.len() * mem::size_of::()) - } - pub fn sync(&mut self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) { + pub fn sync(&self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) { for sync_rect in sync_rects { let sync_rect = sync_rect.clip( self.width.try_into().unwrap(), @@ -99,7 +95,7 @@ impl GraphicScreen { let row_pixel_count = w; - let mut offscreen_ptr = self.offscreen.as_mut_ptr(); + let mut offscreen_ptr = self.offscreen.as_ptr(); let mut onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable unsafe { @@ -117,7 +113,7 @@ impl GraphicScreen { } } - pub fn redraw(&mut self, framebuffer: &mut FrameBuffer) { + pub fn redraw(&self, framebuffer: &mut FrameBuffer) { let width = self.width.try_into().unwrap(); let height = self.height.try_into().unwrap(); self.sync( diff --git a/graphics/virtio-gpud/Cargo.toml b/graphics/virtio-gpud/Cargo.toml index 1362b2d8b3..42da6e798f 100644 --- a/graphics/virtio-gpud/Cargo.toml +++ b/graphics/virtio-gpud/Cargo.toml @@ -12,6 +12,7 @@ anyhow = "1.0.71" paste = "1.0.13" common = { path = "../../common" } +driver-graphics = { path = "../driver-graphics" } virtio-core = { path = "../../virtio-core" } pcid = { path = "../../pcid" } inputd = { path = "../../inputd" } @@ -22,4 +23,3 @@ redox_syscall = "0.5" orbclient = "0.3.27" spin = "0.9.8" libredox = "0.1.3" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 6543d97ddc..985d03b7c1 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -27,10 +27,8 @@ use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicU32, Ordering}; use event::{user_data, EventQueue}; -use libredox::errno::{EAGAIN, EOPNOTSUPP}; use pcid_interface::PciFunctionHandle; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; use virtio_core::utils::VolatileCell; use virtio_core::MSIX_PRIMARY_VECTOR; @@ -439,7 +437,6 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device.transport.run_device(); deamon.ready().unwrap(); - let socket = Socket::nonblock("display.virtio-gpu")?; let mut scheme = futures::executor::block_on(scheme::GpuScheme::new( config, control_queue.clone(), @@ -465,15 +462,12 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { .unwrap(); event_queue .subscribe( - socket.inner().raw(), + scheme.inner.event_handle().raw(), Source::Scheme, event::EventFlags::READ, ) .unwrap(); - //let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); - //inputd_control_handle.activate_vt(3).unwrap(); - let all = [Source::Input, Source::Scheme]; for event in all .into_iter() @@ -486,47 +480,14 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { .read_vt_event() .expect("virtio-gpud: failed to read display handle") { - scheme.handle_vt_event(vt_event); + scheme.inner.handle_vt_event(vt_event); } } Source::Scheme => { - loop { - let request = match socket.next_request(SignalBehavior::Restart) { - Ok(Some(request)) => request, - Ok(None) => { - // Scheme likely got unmounted - std::process::exit(0); - } - Err(err) if err.errno == EAGAIN => break, - Err(err) => return Err(err.into()), - }; - - match request.kind() { - RequestKind::Call(call_request) => { - socket - .write_response( - call_request.handle_scheme(&mut scheme), - SignalBehavior::Restart, - ) - .expect("virtio-gpud: failed to write display scheme"); - } - RequestKind::SendFd(sendfd_request) => { - socket - .write_response( - Response::for_sendfd( - &sendfd_request, - Err(syscall::Error::new(EOPNOTSUPP)), - ), - SignalBehavior::Restart, - ) - .expect("virtio-gpud: failed to write scheme"); - } - RequestKind::Cancellation(_cancellation_request) => {} - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { - unreachable!() - } - } - } + scheme + .inner + .tick() + .expect("virtio-gpud: failed to process scheme events"); } } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 35933fad9d..69d41ab868 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -1,13 +1,10 @@ -use std::collections::{BTreeMap, HashMap}; - -use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; use common::{dma::Dma, sgl}; -use inputd::{Damage, VtEvent, VtEventKind}; +use driver_graphics::{GraphicsAdapter, GraphicsScheme, Resource}; +use inputd::Damage; -use redox_scheme::Scheme; -use syscall::{Error as SysError, MapFlags, EBADF, EINVAL, PAGE_SIZE}; +use syscall::PAGE_SIZE; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::{Error, Queue, Transport}; @@ -26,9 +23,21 @@ impl Into for Damage { } } -struct GpuResource { +pub struct VirtGpuResource { id: ResourceId, sgl: sgl::Sgl, + width: u32, + height: u32, +} + +impl Resource for VirtGpuResource { + fn width(&self) -> u32 { + self.width + } + + fn height(&self) -> u32 { + self.height + } } #[derive(Debug, Copy, Clone)] @@ -37,7 +46,14 @@ pub struct Display { height: u32, } -impl GpuScheme<'_> { +pub struct VirtGpuAdapter<'a> { + control_queue: Arc>, + cursor_queue: Arc>, + transport: Arc, + displays: Vec, +} + +impl VirtGpuAdapter<'_> { async fn send_request(&self, request: Dma) -> Result, Error> { let header = Dma::new(ControlHeader::default())?; let command = ChainBuilder::new() @@ -49,166 +65,161 @@ impl GpuScheme<'_> { Ok(header) } - async fn flush_resource(&self, flush: ResourceFlush) -> Result<(), Error> { + async fn flush_resource_inner(&self, flush: ResourceFlush) -> Result<(), Error> { let header = self.send_request(Dma::new(flush)?).await?; assert_eq!(header.ty.get(), CommandTy::RespOkNodata); Ok(()) } +} - async fn res_for_screen( - &mut self, - vt: usize, - screen: usize, - ) -> Result<(ResourceId, *mut u8), Error> { - if let Some(res) = self.vts.entry(vt).or_default().get(&screen) { - return Ok((res.id, res.sgl.as_ptr())); - } +impl GraphicsAdapter for VirtGpuAdapter<'_> { + type Resource = VirtGpuResource; - let bpp = 32; - let fb_size = - self.displays[screen].width as usize * self.displays[screen].height as usize * bpp / 8; - let sgl = sgl::Sgl::new(fb_size)?; - - unsafe { - core::ptr::write_bytes(sgl.as_ptr() as *mut u8, 255, fb_size); - } - - let res_id = ResourceId::alloc(); - - // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. - let mut request = Dma::new(ResourceCreate2d::default())?; - - request.set_width(self.displays[screen].width); - request.set_height(self.displays[screen].height); - request.set_format(ResourceFormat::Bgrx); - request.set_resource_id(res_id); - - let header = self.send_request(request).await?; - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - - // Use the allocated framebuffer from tthe guest ram, and attach it as backing - // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. - - let mut mem_entries = unsafe { Dma::zeroed_slice(sgl.chunks().len())?.assume_init() }; - for (entry, chunk) in mem_entries.iter_mut().zip(sgl.chunks().iter()) { - *entry = MemEntry { - address: chunk.phys as u64, - length: chunk.length.next_multiple_of(PAGE_SIZE) as u32, - padding: 0, - }; - } - - let attach_request = Dma::new(AttachBacking::new(res_id, mem_entries.len() as u32))?; - let header = Dma::new(ControlHeader::default())?; - let command = ChainBuilder::new() - .chain(Buffer::new(&attach_request)) - .chain(Buffer::new_unsized(&mem_entries)) - .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - self.control_queue.send(command).await; - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - - let res = self - .vts - .entry(vt) - .or_default() - .entry(screen) - .or_insert(GpuResource { id: res_id, sgl }); - Ok((res.id, res.sgl.as_ptr())) + fn displays(&self) -> Vec { + self.displays.iter().enumerate().map(|(i, _)| i).collect() } - async fn set_scanout(&mut self, vt: usize, screen: usize) -> Result<(), Error> { - let (res_id, _) = self.res_for_screen(vt, screen).await?; - - let scanout_request = Dma::new(SetScanout::new( - screen as u32, - res_id, - GpuRect::new( - 0, - 0, - self.displays[screen].width, - self.displays[screen].height, - ), - ))?; - let header = self.send_request(scanout_request).await?; - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - - self.flush(vt, screen, None).await?; - - Ok(()) + fn display_size(&self, display_id: usize) -> (u32, u32) { + ( + self.displays[display_id].width, + self.displays[display_id].height, + ) } - /// If `damage` is `None`, the entire screen is flushed. - async fn flush( - &mut self, - vt: usize, - screen: usize, - damage: Option<&[Damage]>, - ) -> Result<(), Error> { - let (res_id, _) = self.res_for_screen(vt, screen).await?; + fn create_resource(&mut self, width: u32, height: u32) -> Self::Resource { + futures::executor::block_on(async { + let bpp = 32; + let fb_size = width as usize * height as usize * bpp / 8; + let sgl = sgl::Sgl::new(fb_size).unwrap(); - let req = Dma::new(XferToHost2d::new( - res_id, - GpuRect { - x: 0, - y: 0, - width: self.displays[screen].width, - height: self.displays[screen].height, - }, - 0, - ))?; - let header = self.send_request(req).await?; - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); - - if let Some(damage) = damage { - for damage in damage { - self.flush_resource(ResourceFlush::new( - res_id, - damage - .clip( - self.displays[screen].width as i32, - self.displays[screen].height as i32, - ) - .into(), - )) - .await?; + unsafe { + core::ptr::write_bytes(sgl.as_ptr() as *mut u8, 255, fb_size); } - } else { - self.flush_resource(ResourceFlush::new( - res_id, + + let res_id = ResourceId::alloc(); + + // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. + let mut request = Dma::new(ResourceCreate2d::default()).unwrap(); + + request.set_width(width); + request.set_height(height); + request.set_format(ResourceFormat::Bgrx); + request.set_resource_id(res_id); + + let header = self.send_request(request).await.unwrap(); + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + + // Use the allocated framebuffer from tthe guest ram, and attach it as backing + // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. + + let mut mem_entries = + unsafe { Dma::zeroed_slice(sgl.chunks().len()).unwrap().assume_init() }; + for (entry, chunk) in mem_entries.iter_mut().zip(sgl.chunks().iter()) { + *entry = MemEntry { + address: chunk.phys as u64, + length: chunk.length.next_multiple_of(PAGE_SIZE) as u32, + padding: 0, + }; + } + + let attach_request = + Dma::new(AttachBacking::new(res_id, mem_entries.len() as u32)).unwrap(); + let header = Dma::new(ControlHeader::default()).unwrap(); + let command = ChainBuilder::new() + .chain(Buffer::new(&attach_request)) + .chain(Buffer::new_unsized(&mem_entries)) + .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.control_queue.send(command).await; + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + + VirtGpuResource { + id: res_id, + sgl, + width, + height, + } + }) + } + + fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8 { + resource.sgl.as_ptr() + } + + fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource) { + futures::executor::block_on(async { + let scanout_request = Dma::new(SetScanout::new( + display_id as u32, + resource.id, + GpuRect::new( + 0, + 0, + self.displays[display_id].width, + self.displays[display_id].height, + ), + )) + .unwrap(); + let header = self.send_request(scanout_request).await.unwrap(); + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + }); + + self.flush_resource(display_id, resource, None); + } + + fn flush_resource( + &mut self, + _display_id: usize, + resource: &Self::Resource, + damage: Option<&[Damage]>, + ) { + futures::executor::block_on(async { + let req = Dma::new(XferToHost2d::new( + resource.id, GpuRect { x: 0, y: 0, - width: self.displays[screen].width, - height: self.displays[screen].height, + width: resource.width, + height: resource.height, }, + 0, )) - .await?; - } - Ok(()) + .unwrap(); + let header = self.send_request(req).await.unwrap(); + assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + + if let Some(damage) = damage { + for damage in damage { + self.flush_resource_inner(ResourceFlush::new( + resource.id, + damage + .clip(resource.width as i32, resource.height as i32) + .into(), + )) + .await + .unwrap(); + } + } else { + self.flush_resource_inner(ResourceFlush::new( + resource.id, + GpuRect { + x: 0, + y: 0, + width: resource.width, + height: resource.height, + }, + )) + .await + .unwrap(); + } + }); } } -struct Handle { - screen: usize, - vt: usize, -} - pub struct GpuScheme<'a> { - control_queue: Arc>, - cursor_queue: Arc>, - transport: Arc, + pub inner: GraphicsScheme>, pub inputd_handle: inputd::DisplayHandle, - - handles: BTreeMap, - /// Counter used for file descriptor allocation. - next_id: AtomicUsize, - - active_vt: usize, - vts: HashMap>, - displays: Vec, } impl<'a> GpuScheme<'a> { @@ -223,17 +234,16 @@ impl<'a> GpuScheme<'a> { let inputd_handle = inputd::DisplayHandle::new("virtio-gpu").unwrap(); Ok(Self { - control_queue, - cursor_queue, - transport, + inner: GraphicsScheme::new( + VirtGpuAdapter { + control_queue, + cursor_queue, + transport, + displays, + }, + "display.virtio-gpu".to_owned(), + ), inputd_handle, - - handles: BTreeMap::new(), - next_id: AtomicUsize::new(0), - - active_vt: 0, - vts: HashMap::new(), - displays, }) } @@ -279,130 +289,4 @@ impl<'a> GpuScheme<'a> { Ok(response) } - - pub fn handle_vt_event(&mut self, vt_event: VtEvent) { - match vt_event.kind { - VtEventKind::Activate => { - log::info!("activate {}", vt_event.vt); - - for id in 0..self.displays.len() { - log::warn!("virtio-gpu: activating"); - - futures::executor::block_on(self.set_scanout(vt_event.vt, id)).unwrap(); - } - - self.active_vt = vt_event.vt; - } - - VtEventKind::Deactivate => { - log::info!("deactivate {}", vt_event.vt); - // nothing to do :) - } - - VtEventKind::Resize => { - log::warn!("virtio-gpu: resize is not implemented yet") - } - } - } -} - -impl<'a> Scheme for GpuScheme<'a> { - fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { - if path.is_empty() { - return Err(SysError::new(EINVAL)); - } - - let mut parts = path.split('/'); - let mut screen = parts.next().unwrap_or("").split('.'); - - let vt = screen.next().unwrap_or("").parse::().unwrap(); - let id = screen.next().unwrap_or("").parse::().unwrap_or(0); - - dbg!(vt, id); - - if id >= self.displays.len() { - return Err(SysError::new(EINVAL)); - }; - - let fd = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.insert(fd, Handle { screen: id, vt }); - Ok(fd) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { - let handle = self.handles.get(&id).unwrap(); - let path = format!( - "display.virtio-gpu:3.0/{}/{}", - self.displays[handle.screen].width, self.displays[handle.screen].height - ); - buf[..path.len()].copy_from_slice(path.as_bytes()); - Ok(path.len()) - } - - fn fsync(&mut self, id: usize) -> syscall::Result { - let handle = self.handles.get(&id).ok_or(SysError::new(EBADF))?; - if handle.vt != self.active_vt { - // This is a protection against background VT's spamming us with flush requests. We will - // flush the resource on the next scanout anyway - return Ok(0); - } - futures::executor::block_on(self.flush(handle.vt, handle.screen, None)).unwrap(); - Ok(0) - } - - fn read( - &mut self, - id: usize, - _buf: &mut [u8], - _offset: u64, - _fcntl_flags: u32, - ) -> syscall::Result { - let _handle = self.handles.get(&id).ok_or(SysError::new(EBADF))?; - Err(SysError::new(EINVAL)) - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - _offset: u64, - _fcntl_flags: u32, - ) -> syscall::Result { - let handle = self.handles.get(&id).ok_or(SysError::new(EBADF))?; - - if handle.vt != self.active_vt { - // This is a protection against background VT's spamming us with flush requests. We will - // flush the resource on the next scanout anyway - return Ok(buf.len()); - } - - let damage = unsafe { - core::slice::from_raw_parts( - buf.as_ptr() as *const Damage, - buf.len() / core::mem::size_of::(), - ) - }; - - futures::executor::block_on(self.flush(handle.vt, handle.screen, Some(damage))).unwrap(); - - Ok(buf.len()) - } - - fn close(&mut self, id: usize) -> syscall::Result { - self.handles.remove(&id).ok_or(SysError::new(EBADF))?; - Ok(0) - } - fn mmap_prep( - &mut self, - id: usize, - offset: u64, - size: usize, - flags: MapFlags, - ) -> syscall::Result { - log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); - let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; - let (_, ptr) = - futures::executor::block_on(self.res_for_screen(handle.vt, handle.screen)).unwrap(); - Ok(unsafe { ptr.offset(offset as isize) } as usize) - } } From d7becba02393ddb2a7913d339e56131e7ba70c5a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 27 Dec 2024 11:40:29 +0100 Subject: [PATCH 1055/1301] graphics/virtio-gpud: Don't crash when multiple displays are attached --- graphics/virtio-gpud/src/scheme.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 69d41ab868..db89ee0f02 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -263,10 +263,20 @@ impl<'a> GpuScheme<'a> { info.rect().height ); - result.push(Display { - width: info.rect().width, - height: info.rect().height, - }); + if info.rect().width == 0 || info.rect().height == 0 { + // QEMU gives all displays other than the first a zero width and height, but trying + // to attach a zero sized framebuffer to the display will result an error, so + // default to 640x480px. + result.push(Display { + width: 640, + height: 480, + }); + } else { + result.push(Display { + width: info.rect().width, + height: info.rect().height, + }); + } } Ok(result) From b1743d800c9b675b382e0120854127632cbcb98e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 25 Dec 2024 10:41:21 +0100 Subject: [PATCH 1056/1301] Remove all dup impls that only accept empty paths Those dups are handled by the kernel already by creating a new reference to the underlying file descriptor. --- audio/pcspkrd/src/scheme.rs | 4 ---- graphics/bgad/src/scheme.rs | 8 -------- graphics/fbbootlogd/src/scheme.rs | 20 -------------------- graphics/fbcond/src/scheme.rs | 22 +--------------------- net/alxd/src/device/mod.rs | 8 -------- net/driver-network/src/lib.rs | 12 ------------ storage/ahcid/src/scheme.rs | 24 ++---------------------- storage/bcm2835-sdhcid/src/scheme.rs | 22 ++-------------------- storage/ided/src/scheme.rs | 21 ++------------------- storage/nvmed/src/scheme.rs | 21 ++------------------- storage/virtio-blkd/src/scheme.rs | 4 ---- 11 files changed, 9 insertions(+), 157 deletions(-) diff --git a/audio/pcspkrd/src/scheme.rs b/audio/pcspkrd/src/scheme.rs index 4a24228f22..2cb21fc51a 100644 --- a/audio/pcspkrd/src/scheme.rs +++ b/audio/pcspkrd/src/scheme.rs @@ -28,10 +28,6 @@ impl SchemeMut for PcspkrScheme { } } - fn dup(&mut self, _id: usize, _buf: &[u8]) -> Result { - Err(Error::new(EPERM)) - } - fn read(&mut self, _id: usize, _buf: &mut [u8]) -> Result { Err(Error::new(EPERM)) } diff --git a/graphics/bgad/src/scheme.rs b/graphics/bgad/src/scheme.rs index 0d536e4e9d..3d2c89996e 100644 --- a/graphics/bgad/src/scheme.rs +++ b/graphics/bgad/src/scheme.rs @@ -33,14 +33,6 @@ impl SchemeMut for BgaScheme { } } - fn dup(&mut self, file: usize, buf: &[u8]) -> Result { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - Ok(file) - } - fn read(&mut self, _file: usize, buf: &mut [u8]) -> Result { let mut i = 0; let data = format!("{},{}\n", self.bga.width(), self.bga.height()).into_bytes(); diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index ca848b90da..7e37aa8cb6 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -6,7 +6,6 @@ use syscall::{Error, EventFlags, Result, EBADF, EINVAL, ENOENT}; use crate::display::Display; use crate::text::TextScreen; -#[derive(Clone)] pub struct Handle { pub events: EventFlags, pub notified_read: bool, @@ -51,25 +50,6 @@ impl Scheme for FbbootlogScheme { Ok(id) } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let handle = self - .handles - .get(&id) - .map(|handle| handle.clone()) - .ok_or(Error::new(EBADF))?; - - let new_id = self.next_id; - self.next_id += 1; - - self.handles.insert(new_id, handle); - - Ok(new_id) - } - fn fevent(&mut self, id: usize, flags: syscall::EventFlags) -> Result { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index 7e1d46d18e..dd667cbf47 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -3,7 +3,7 @@ use std::os::fd::AsRawFd; use event::{EventQueue, UserData}; use redox_scheme::SchemeBlock; -use syscall::{Error, EventFlags, Result, EBADF, EINVAL, ENOENT, O_NONBLOCK}; +use syscall::{Error, EventFlags, Result, EBADF, ENOENT, O_NONBLOCK}; use crate::display::Display; use crate::text::TextScreen; @@ -25,7 +25,6 @@ impl UserData for VtIndex { } } -#[derive(Clone)] pub struct Handle { pub vt_i: VtIndex, pub flags: usize, @@ -98,25 +97,6 @@ impl SchemeBlock for FbconScheme { } } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let handle = self - .handles - .get(&id) - .map(|handle| handle.clone()) - .ok_or(Error::new(EBADF))?; - - let new_id = self.next_id; - self.next_id += 1; - - self.handles.insert(new_id, handle); - - Ok(Some(new_id)) - } - fn fevent( &mut self, id: usize, diff --git a/net/alxd/src/device/mod.rs b/net/alxd/src/device/mod.rs index 64415b1887..e461f04003 100644 --- a/net/alxd/src/device/mod.rs +++ b/net/alxd/src/device/mod.rs @@ -1802,14 +1802,6 @@ impl scheme::SchemeMut for Alx { } } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - Ok(id) - } - fn read(&mut self, id: usize, _buf: &mut [u8]) -> Result { /* let head = unsafe { self.read(RDH) }; diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index c52d0d7481..0f5a8663a9 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -40,7 +40,6 @@ pub struct NetworkScheme { blocked: Vec, } -#[derive(Copy, Clone)] enum Handle { Data, Mac, @@ -177,17 +176,6 @@ impl SchemeBlock for NetworkScheme { })) } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let handle = *self.handles.get(&id).ok_or(Error::new(EBADF))?; - self.next_id += 1; - self.handles.insert(self.next_id, handle); - Ok(Some(self.next_id)) - } - fn read( &mut self, id: usize, diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index ce153ffb1e..7ed30f2de1 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -7,13 +7,12 @@ use driver_block::{Disk, DiskWrapper}; use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, - MODE_FILE, O_DIRECTORY, O_STAT, + Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, + O_DIRECTORY, O_STAT, }; use crate::ahci::hba::HbaMem; -#[derive(Clone)] enum Handle { List(Vec), // Dir contents buffer Disk(usize), // Disk index @@ -165,25 +164,6 @@ impl SchemeBlock for DiskScheme { })) } - fn xdup(&mut self, id: usize, buf: &[u8], _: &CallerCtx) -> Result> { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let new_handle = { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - handle.clone() - }; - - let new_id = self.next_id; - self.next_id += 1; - self.handles.insert(new_id, new_handle); - Ok(Some(OpenResult::ThisScheme { - number: new_id, - flags: NewFdFlags::POSITIONED, - })) - } - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { match *self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::List(ref data) => { diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs index 27777290bb..70bf4772e0 100644 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ b/storage/bcm2835-sdhcid/src/scheme.rs @@ -1,18 +1,16 @@ use std::collections::BTreeMap; use std::fmt::Write; use std::str; -use std::sync::{Arc, Mutex}; use driver_block::{Disk, DiskWrapper}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, - MODE_FILE, O_DIRECTORY, O_STAT, + Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, + O_DIRECTORY, O_STAT, }; use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; -#[derive(Clone)] enum Handle { List(Vec), // Dir contents buffer Disk(usize), // Disk index @@ -155,22 +153,6 @@ impl SchemeBlock for DiskScheme { } } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let new_handle = { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - handle.clone() - }; - - let new_id = self.next_id; - self.next_id += 1; - self.handles.insert(new_id, new_handle); - Ok(Some(new_id)) - } - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { match *self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::List(ref data) => { diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs index d2ceaa4ad6..ff0a63e58a 100644 --- a/storage/ided/src/scheme.rs +++ b/storage/ided/src/scheme.rs @@ -6,14 +6,13 @@ use std::sync::{Arc, Mutex}; use driver_block::{Disk, DiskWrapper}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, - MODE_FILE, O_DIRECTORY, O_STAT, + Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, + O_DIRECTORY, O_STAT, }; use crate::ide::Channel; use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; -#[derive(Clone)] enum Handle { List(Vec), // Dir contents buffer Disk(usize), // Disk index @@ -168,22 +167,6 @@ impl SchemeBlock for DiskScheme { } } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let new_handle = { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - handle.clone() - }; - - let new_id = self.next_id; - self.next_id += 1; - self.handles.insert(new_id, new_handle); - Ok(Some(new_id)) - } - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { match *self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::List(ref data) => { diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 772b72e8b6..493a08293b 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -9,15 +9,14 @@ use std::{cmp, str}; use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, - MODE_FILE, O_DIRECTORY, O_STAT, + Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, + O_DIRECTORY, O_STAT, }; use crate::nvme::{Nvme, NvmeNamespace}; use partitionlib::{LogicalBlockSize, PartitionTable}; -#[derive(Clone)] enum Handle { List(Vec), // entries Disk(u32), // disk num @@ -271,22 +270,6 @@ impl SchemeBlock for DiskScheme { })) } - fn dup(&mut self, id: usize, buf: &[u8]) -> Result> { - if !buf.is_empty() { - return Err(Error::new(EINVAL)); - } - - let new_handle = { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - handle.clone() - }; - - let new_id = self.next_id; - self.next_id += 1; - self.handles.insert(new_id, new_handle); - Ok(Some(new_id)) - } - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { match *self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::List(ref data) => { diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index b3288516d4..217bf68f94 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -384,10 +384,6 @@ impl<'a> SchemeBlock for DiskScheme<'a> { } } - fn dup(&mut self, _old_id: usize, _buf: &[u8]) -> Result> { - todo!() - } - fn close(&mut self, id: usize) -> syscall::Result> { self.handles .remove(&id) From ed9ad1aaf167d192d1e5d9f8409a202a18014a73 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 27 Dec 2024 15:57:18 +0100 Subject: [PATCH 1057/1301] graphics/vesad: Remove old resizing code Graphics clients will need to handle resizing themself anyway for handoff between graphics drivers and as such don't need the graphics to modify the framebuffer during resize. --- graphics/vesad/src/framebuffer.rs | 34 ---------------------- graphics/vesad/src/screen.rs | 47 +------------------------------ 2 files changed, 1 insertion(+), 80 deletions(-) diff --git a/graphics/vesad/src/framebuffer.rs b/graphics/vesad/src/framebuffer.rs index 74d5b1be89..7eeab2fe4d 100644 --- a/graphics/vesad/src/framebuffer.rs +++ b/graphics/vesad/src/framebuffer.rs @@ -1,7 +1,5 @@ use std::ptr; -use syscall::PAGE_SIZE; - pub struct FrameBuffer { pub onscreen: *mut [u32], pub phys: usize, @@ -58,36 +56,4 @@ impl FrameBuffer { let stride = parse_number(parts.next()?)?; Some(Self::new(phys, width, height, stride)) } - - pub unsafe fn resize(&mut self, width: usize, height: usize, stride: usize) { - // Unmap old onscreen - unsafe { - let slice = self.onscreen; - libredox::call::munmap(slice.cast(), (slice.len() * 4).next_multiple_of(PAGE_SIZE)) - .expect("vesad: failed to unmap framebuffer"); - } - - // Map new onscreen - self.onscreen = unsafe { - let size = stride * height; - let onscreen_ptr = common::physmap( - self.phys, - size * 4, - common::Prot { - read: true, - write: true, - }, - common::MemoryType::WriteCombining, - ) - .expect("vesad: failed to map framebuffer") as *mut u32; - ptr::write_bytes(onscreen_ptr, 0, size); - - ptr::slice_from_raw_parts_mut(onscreen_ptr, size) - }; - - // Update size - self.width = width; - self.height = height; - self.stride = stride; - } } diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index 71b99f7b51..3523f24a83 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -1,5 +1,5 @@ use std::convert::TryInto; -use std::{cmp, ptr}; +use std::ptr; use driver_graphics::Resource; use inputd::Damage; @@ -34,51 +34,6 @@ impl Resource for GraphicScreen { } impl GraphicScreen { - pub fn resize(&mut self, width: usize, height: usize) { - //TODO: Fix issue with mapped screens - - if width != self.width || height != self.height { - println!("Resize display to {}, {}", width, height); - - let size = width * height; - let mut offscreen = OffscreenBuffer::new(size); - - let mut old_ptr = self.offscreen.as_ptr(); - let mut new_ptr = offscreen.as_mut_ptr(); - - for _y in 0..cmp::min(height, self.height) { - unsafe { - ptr::copy(old_ptr, new_ptr, cmp::min(width, self.width)); - if width > self.width { - ptr::write_bytes( - new_ptr.offset(self.width as isize), - 0, - width - self.width, - ); - } - old_ptr = old_ptr.offset(self.width as isize); - new_ptr = new_ptr.offset(width as isize); - } - } - - if height > self.height { - for _y in self.height..height { - unsafe { - ptr::write_bytes(new_ptr, 0, width); - new_ptr = new_ptr.offset(width as isize); - } - } - } - - self.width = width; - self.height = height; - - self.offscreen = offscreen; - } else { - println!("Display is already {}, {}", width, height); - }; - } - pub fn sync(&self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) { for sync_rect in sync_rects { let sync_rect = sync_rect.clip( From 9afe3b390baf25d88d5adbebfe7552457e717f67 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 27 Dec 2024 15:57:43 +0100 Subject: [PATCH 1058/1301] graphics/vesad: Remove all usage of unstable features --- graphics/vesad/src/display.rs | 2 +- graphics/vesad/src/main.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/graphics/vesad/src/display.rs b/graphics/vesad/src/display.rs index 8aad04d62c..f1276bcdd4 100644 --- a/graphics/vesad/src/display.rs +++ b/graphics/vesad/src/display.rs @@ -23,7 +23,7 @@ impl OffscreenBuffer { } pub fn ptr(&self) -> *mut u8 { - self.ptr.as_mut_ptr().cast::() + self.ptr.as_ptr().cast::() } } impl Drop for OffscreenBuffer { diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 457870ba64..e92f92b642 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -1,4 +1,3 @@ -#![feature(int_roundings, slice_ptr_get)] extern crate orbclient; extern crate syscall; From 1d89ca7bd2ed3287bc1ea935cde908ee98a8a105 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 28 Dec 2024 14:01:09 +0100 Subject: [PATCH 1059/1301] graphics/virtio-gpud: Remove unnecessary VolatileCell The virtio queue abstraction already provides the necessary synchronization to make everything data-race free without volatile accesses. --- graphics/virtio-gpud/src/main.rs | 79 ++++++++++-------------------- graphics/virtio-gpud/src/scheme.rs | 28 +++++------ 2 files changed, 39 insertions(+), 68 deletions(-) diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 985d03b7c1..f6084b876c 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -22,7 +22,6 @@ #![feature(int_roundings)] -use std::cell::UnsafeCell; use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicU32, Ordering}; @@ -41,22 +40,16 @@ macro_rules! make_getter_setter { ($($field:ident: $return_ty:ty),*) => { $( pub fn $field(&self) -> $return_ty { - self.$field.get() + self.$field } paste::item! { pub fn [](&mut self, value: $return_ty) { - self.$field.set(value) + self.$field = value; } } )* }; - - (@$field:ident: $return_ty:ty) => { - pub fn $field(&mut self, value: $return_ty) { - self.$field.set(value) - } - }; } #[repr(C)] @@ -137,18 +130,18 @@ static_assertions::const_assert_eq!(core::mem::size_of::(), 4); #[derive(Debug)] #[repr(C)] pub struct ControlHeader { - pub ty: VolatileCell, - pub flags: VolatileCell, - pub fence_id: VolatileCell, - pub ctx_id: VolatileCell, - pub ring_index: VolatileCell, + pub ty: CommandTy, + pub flags: u32, + pub fence_id: u64, + pub ctx_id: u32, + pub ring_index: u8, padding: [u8; 3], } impl ControlHeader { pub fn with_ty(ty: CommandTy) -> Self { Self { - ty: VolatileCell::new(ty), + ty, ..Default::default() } } @@ -157,11 +150,11 @@ impl ControlHeader { impl Default for ControlHeader { fn default() -> Self { Self { - ty: VolatileCell::new(CommandTy::Undefined), - flags: VolatileCell::new(0), - fence_id: VolatileCell::new(0), - ctx_id: VolatileCell::new(0), - ring_index: VolatileCell::new(0), + ty: CommandTy::Undefined, + flags: 0, + fence_id: 0, + ctx_id: 0, + ring_index: 0, padding: [0; 3], } } @@ -190,16 +183,9 @@ impl GpuRect { #[derive(Debug)] #[repr(C)] pub struct DisplayInfo { - rect: UnsafeCell, - pub enabled: VolatileCell, - pub flags: VolatileCell, -} - -impl DisplayInfo { - pub fn rect(&self) -> &GpuRect { - // SAFETY: We never give out mutable references to `self.rect`. - unsafe { &*self.rect.get() } - } + rect: GpuRect, + pub enabled: u32, + pub flags: u32, } #[derive(Debug)] @@ -213,7 +199,7 @@ impl Default for GetDisplayInfo { fn default() -> Self { Self { header: ControlHeader { - ty: VolatileCell::new(CommandTy::GetDisplayInfo), + ty: CommandTy::GetDisplayInfo, ..Default::default() }, @@ -247,13 +233,10 @@ pub enum ResourceFormat { #[repr(C)] pub struct ResourceCreate2d { pub header: ControlHeader, - - // FIXME we can likely use regular loads and stores as the ring buffer should provide the - // necessary synchronization. - resource_id: VolatileCell, - format: VolatileCell, - width: VolatileCell, - height: VolatileCell, + resource_id: ResourceId, + format: ResourceFormat, + width: u32, + height: u32, } impl ResourceCreate2d { @@ -263,15 +246,11 @@ impl ResourceCreate2d { impl Default for ResourceCreate2d { fn default() -> Self { Self { - header: ControlHeader { - ty: VolatileCell::new(CommandTy::ResourceCreate2d), - ..Default::default() - }, - - resource_id: VolatileCell::new(ResourceId(0)), - format: VolatileCell::new(ResourceFormat::Unknown), - width: VolatileCell::new(0), - height: VolatileCell::new(0), + header: ControlHeader::with_ty(CommandTy::ResourceCreate2d), + resource_id: ResourceId(0), + format: ResourceFormat::Unknown, + width: 0, + height: 0, } } } @@ -392,11 +371,7 @@ pub struct XferToHost2d { impl XferToHost2d { pub fn new(resource_id: ResourceId, rect: GpuRect, offset: u64) -> Self { Self { - header: ControlHeader { - ty: VolatileCell::new(CommandTy::TransferToHost2d), - ..Default::default() - }, - + header: ControlHeader::with_ty(CommandTy::TransferToHost2d), rect, offset, resource_id, diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index db89ee0f02..cc9c9a86bd 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -8,7 +8,6 @@ use syscall::PAGE_SIZE; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::{Error, Queue, Transport}; -use virtio_core::utils::VolatileCell; use crate::*; @@ -67,7 +66,7 @@ impl VirtGpuAdapter<'_> { async fn flush_resource_inner(&self, flush: ResourceFlush) -> Result<(), Error> { let header = self.send_request(Dma::new(flush)?).await?; - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + assert_eq!(header.ty, CommandTy::RespOkNodata); Ok(()) } @@ -108,7 +107,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { request.set_resource_id(res_id); let header = self.send_request(request).await.unwrap(); - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + assert_eq!(header.ty, CommandTy::RespOkNodata); // Use the allocated framebuffer from tthe guest ram, and attach it as backing // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. @@ -133,7 +132,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { .build(); self.control_queue.send(command).await; - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + assert_eq!(header.ty, CommandTy::RespOkNodata); VirtGpuResource { id: res_id, @@ -162,7 +161,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { )) .unwrap(); let header = self.send_request(scanout_request).await.unwrap(); - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + assert_eq!(header.ty, CommandTy::RespOkNodata); }); self.flush_resource(display_id, resource, None); @@ -187,7 +186,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { )) .unwrap(); let header = self.send_request(req).await.unwrap(); - assert_eq!(header.ty.get(), CommandTy::RespOkNodata); + assert_eq!(header.ty, CommandTy::RespOkNodata); if let Some(damage) = damage { for damage in damage { @@ -259,11 +258,11 @@ impl<'a> GpuScheme<'a> { for info in displays.iter() { log::info!( "virtio-gpu: opening display ({}x{}px)", - info.rect().width, - info.rect().height + info.rect.width, + info.rect.height ); - if info.rect().width == 0 || info.rect().height == 0 { + if info.rect.width == 0 || info.rect.height == 0 { // QEMU gives all displays other than the first a zero width and height, but trying // to attach a zero sized framebuffer to the display will result an error, so // default to 640x480px. @@ -273,8 +272,8 @@ impl<'a> GpuScheme<'a> { }); } else { result.push(Display { - width: info.rect().width, - height: info.rect().height, + width: info.rect.width, + height: info.rect.height, }); } } @@ -283,10 +282,7 @@ impl<'a> GpuScheme<'a> { } async fn get_display_info(control_queue: Arc>) -> Result, Error> { - let header = Dma::new(ControlHeader { - ty: VolatileCell::new(CommandTy::GetDisplayInfo), - ..Default::default() - })?; + let header = Dma::new(ControlHeader::with_ty(CommandTy::GetDisplayInfo))?; let response = Dma::new(GetDisplayInfo::default())?; let command = ChainBuilder::new() @@ -295,7 +291,7 @@ impl<'a> GpuScheme<'a> { .build(); control_queue.send(command).await; - assert!(response.header.ty.get() == CommandTy::RespOkDisplayInfo); + assert!(response.header.ty == CommandTy::RespOkDisplayInfo); Ok(response) } From 1ef298e5767efbe5045b37820099a92e07e54b51 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 28 Dec 2024 14:04:10 +0100 Subject: [PATCH 1060/1301] graphics/virtio-gpud: Remove getters and setters for ResourceCreate2d --- Cargo.lock | 7 ------- graphics/virtio-gpud/Cargo.toml | 1 - graphics/virtio-gpud/src/main.rs | 30 +++++------------------------- graphics/virtio-gpud/src/scheme.rs | 13 +++++++------ 4 files changed, 12 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28de7e560d..374df5ce0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -941,12 +941,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "paw" version = "1.0.0" @@ -1778,7 +1772,6 @@ dependencies = [ "libredox", "log", "orbclient", - "paste", "pcid", "redox-daemon", "redox_event", diff --git a/graphics/virtio-gpud/Cargo.toml b/graphics/virtio-gpud/Cargo.toml index 42da6e798f..a8cf34ed40 100644 --- a/graphics/virtio-gpud/Cargo.toml +++ b/graphics/virtio-gpud/Cargo.toml @@ -9,7 +9,6 @@ log = "0.4" static_assertions = "1.1.0" futures = { version = "0.3.28", features = ["executor"] } anyhow = "1.0.71" -paste = "1.0.13" common = { path = "../../common" } driver-graphics = { path = "../driver-graphics" } diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index f6084b876c..9ce2447ba0 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -36,22 +36,6 @@ mod scheme; // const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0; const VIRTIO_GPU_MAX_SCANOUTS: usize = 16; -macro_rules! make_getter_setter { - ($($field:ident: $return_ty:ty),*) => { - $( - pub fn $field(&self) -> $return_ty { - self.$field - } - - paste::item! { - pub fn [](&mut self, value: $return_ty) { - self.$field = value; - } - } - )* - }; -} - #[repr(C)] pub struct GpuConfig { /// Signals pending events to the driver. @@ -240,17 +224,13 @@ pub struct ResourceCreate2d { } impl ResourceCreate2d { - make_getter_setter!(resource_id: ResourceId, format: ResourceFormat, width: u32, height: u32); -} - -impl Default for ResourceCreate2d { - fn default() -> Self { + fn new(resource_id: ResourceId, format: ResourceFormat, width: u32, height: u32) -> Self { Self { header: ControlHeader::with_ty(CommandTy::ResourceCreate2d), - resource_id: ResourceId(0), - format: ResourceFormat::Unknown, - width: 0, - height: 0, + resource_id, + format, + width, + height, } } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index cc9c9a86bd..7a548407d1 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -99,12 +99,13 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { let res_id = ResourceId::alloc(); // Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`. - let mut request = Dma::new(ResourceCreate2d::default()).unwrap(); - - request.set_width(width); - request.set_height(height); - request.set_format(ResourceFormat::Bgrx); - request.set_resource_id(res_id); + let request = Dma::new(ResourceCreate2d::new( + res_id, + ResourceFormat::Bgrx, + width, + height, + )) + .unwrap(); let header = self.send_request(request).await.unwrap(); assert_eq!(header.ty, CommandTy::RespOkNodata); From 0b8648ff5ba3eb90da1b1e4b606b2daf16c04733 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 28 Dec 2024 14:16:56 +0100 Subject: [PATCH 1061/1301] graphics/virtio-gpud: Move some initialization code around --- graphics/virtio-gpud/src/main.rs | 12 ++--- graphics/virtio-gpud/src/scheme.rs | 85 ++++++++++++------------------ 2 files changed, 40 insertions(+), 57 deletions(-) diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 9ce2447ba0..880e80b9ab 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -392,7 +392,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { device.transport.run_device(); deamon.ready().unwrap(); - let mut scheme = futures::executor::block_on(scheme::GpuScheme::new( + let (mut scheme, mut inputd_handle) = futures::executor::block_on(scheme::GpuScheme::new( config, control_queue.clone(), cursor_queue.clone(), @@ -410,14 +410,14 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { EventQueue::new().expect("virtio-gpud: failed to create event queue"); event_queue .subscribe( - scheme.inputd_handle.inner().as_raw_fd() as usize, + inputd_handle.inner().as_raw_fd() as usize, Source::Input, event::EventFlags::READ, ) .unwrap(); event_queue .subscribe( - scheme.inner.event_handle().raw(), + scheme.event_handle().raw(), Source::Scheme, event::EventFlags::READ, ) @@ -430,17 +430,15 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { { match event { Source::Input => { - while let Some(vt_event) = scheme - .inputd_handle + while let Some(vt_event) = inputd_handle .read_vt_event() .expect("virtio-gpud: failed to read display handle") { - scheme.inner.handle_vt_event(vt_event); + scheme.handle_vt_event(vt_event); } } Source::Scheme => { scheme - .inner .tick() .expect("virtio-gpud: failed to process scheme events"); } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 7a548407d1..82809cad41 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use common::{dma::Dma, sgl}; use driver_graphics::{GraphicsAdapter, GraphicsScheme, Resource}; -use inputd::Damage; +use inputd::{Damage, DisplayHandle}; use syscall::PAGE_SIZE; @@ -70,6 +70,21 @@ impl VirtGpuAdapter<'_> { Ok(()) } + + async fn get_display_info(&self) -> Result, Error> { + let header = Dma::new(ControlHeader::with_ty(CommandTy::GetDisplayInfo))?; + + let response = Dma::new(GetDisplayInfo::default())?; + let command = ChainBuilder::new() + .chain(Buffer::new(&header)) + .chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.control_queue.send(command).await; + assert!(response.header.ty == CommandTy::RespOkDisplayInfo); + + Ok(response) + } } impl GraphicsAdapter for VirtGpuAdapter<'_> { @@ -217,46 +232,26 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { } } -pub struct GpuScheme<'a> { - pub inner: GraphicsScheme>, - pub inputd_handle: inputd::DisplayHandle, -} +pub struct GpuScheme {} -impl<'a> GpuScheme<'a> { +impl<'a> GpuScheme { pub async fn new( config: &'a mut GpuConfig, control_queue: Arc>, cursor_queue: Arc>, transport: Arc, - ) -> Result, Error> { - let displays = Self::probe(control_queue.clone(), config).await?; + ) -> Result<(GraphicsScheme>, DisplayHandle), Error> { + let mut adapter = VirtGpuAdapter { + control_queue, + cursor_queue, + transport, + displays: vec![], + }; - let inputd_handle = inputd::DisplayHandle::new("virtio-gpu").unwrap(); + let mut display_info = adapter.get_display_info().await?; + let raw_displays = &mut display_info.display_info[..config.num_scanouts() as usize]; - Ok(Self { - inner: GraphicsScheme::new( - VirtGpuAdapter { - control_queue, - cursor_queue, - transport, - displays, - }, - "display.virtio-gpu".to_owned(), - ), - inputd_handle, - }) - } - - async fn probe( - control_queue: Arc>, - config: &GpuConfig, - ) -> Result, Error> { - let mut display_info = Self::get_display_info(control_queue.clone()).await?; - let displays = &mut display_info.display_info[..config.num_scanouts() as usize]; - - let mut result = vec![]; - - for info in displays.iter() { + for info in raw_displays.iter() { log::info!( "virtio-gpu: opening display ({}x{}px)", info.rect.width, @@ -267,33 +262,23 @@ impl<'a> GpuScheme<'a> { // QEMU gives all displays other than the first a zero width and height, but trying // to attach a zero sized framebuffer to the display will result an error, so // default to 640x480px. - result.push(Display { + adapter.displays.push(Display { width: 640, height: 480, }); } else { - result.push(Display { + adapter.displays.push(Display { width: info.rect.width, height: info.rect.height, }); } } - Ok(result) - } + let inputd_handle = DisplayHandle::new("virtio-gpu").unwrap(); - async fn get_display_info(control_queue: Arc>) -> Result, Error> { - let header = Dma::new(ControlHeader::with_ty(CommandTy::GetDisplayInfo))?; - - let response = Dma::new(GetDisplayInfo::default())?; - let command = ChainBuilder::new() - .chain(Buffer::new(&header)) - .chain(Buffer::new(&response).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - control_queue.send(command).await; - assert!(response.header.ty == CommandTy::RespOkDisplayInfo); - - Ok(response) + Ok(( + GraphicsScheme::new(adapter, "display.virtio-gpu".to_owned()), + inputd_handle, + )) } } From b5eeaed9e17ce2acaf4a50f01c4e90718d62516f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 28 Dec 2024 14:31:03 +0100 Subject: [PATCH 1062/1301] graphics/virtio-gpud: Use resource size rather than display size in set_scanout This ensures we use the right size if the display got resized but the resource hasn't been resized yet. --- graphics/virtio-gpud/src/scheme.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 82809cad41..3f140fb8f3 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -125,7 +125,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { let header = self.send_request(request).await.unwrap(); assert_eq!(header.ty, CommandTy::RespOkNodata); - // Use the allocated framebuffer from tthe guest ram, and attach it as backing + // Use the allocated framebuffer from the guest ram, and attach it as backing // storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`. let mut mem_entries = @@ -168,12 +168,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { let scanout_request = Dma::new(SetScanout::new( display_id as u32, resource.id, - GpuRect::new( - 0, - 0, - self.displays[display_id].width, - self.displays[display_id].height, - ), + GpuRect::new(0, 0, resource.width, resource.height), )) .unwrap(); let header = self.send_request(scanout_request).await.unwrap(); From 5af43fcaa2c2ecaece4d029f42bc4c12bc0a95aa Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 28 Dec 2024 14:51:02 +0100 Subject: [PATCH 1063/1301] graphics/vesad: Merge OffscreenBuffer into GraphicScreen --- graphics/vesad/src/display.rs | 45 ----------------------------------- graphics/vesad/src/main.rs | 1 - graphics/vesad/src/scheme.rs | 2 +- graphics/vesad/src/screen.rs | 41 ++++++++++++++++++++++++------- 4 files changed, 33 insertions(+), 56 deletions(-) delete mode 100644 graphics/vesad/src/display.rs diff --git a/graphics/vesad/src/display.rs b/graphics/vesad/src/display.rs deleted file mode 100644 index f1276bcdd4..0000000000 --- a/graphics/vesad/src/display.rs +++ /dev/null @@ -1,45 +0,0 @@ -use std::alloc::{self, Layout}; -use std::ptr; -use std::ptr::NonNull; - -pub struct OffscreenBuffer { - ptr: NonNull<[u32]>, -} - -impl OffscreenBuffer { - #[inline] - fn layout(len: usize) -> Layout { - // optimizes to an integer mul - Layout::array::(len).unwrap().align_to(4096).unwrap() - } - - #[inline] - pub fn new(len: usize) -> Self { - let layout = Self::layout(len); - let ptr = unsafe { alloc::alloc_zeroed(layout) }; - let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len); - let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout)); - OffscreenBuffer { ptr } - } - - pub fn ptr(&self) -> *mut u8 { - self.ptr.as_ptr().cast::() - } -} -impl Drop for OffscreenBuffer { - fn drop(&mut self) { - let layout = Self::layout(self.ptr.len()); - unsafe { alloc::dealloc(self.ptr.as_ptr().cast(), layout) }; - } -} -impl std::ops::Deref for OffscreenBuffer { - type Target = [u32]; - fn deref(&self) -> &[u32] { - unsafe { self.ptr.as_ref() } - } -} -impl std::ops::DerefMut for OffscreenBuffer { - fn deref_mut(&mut self) -> &mut [u32] { - unsafe { self.ptr.as_mut() } - } -} diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index e92f92b642..8cafa6b2ee 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -11,7 +11,6 @@ use std::os::fd::AsRawFd; use crate::framebuffer::FrameBuffer; use crate::scheme::FbAdapter; -mod display; mod framebuffer; mod scheme; mod screen; diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 495a5a48cf..15d7f2867a 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -25,7 +25,7 @@ impl GraphicsAdapter for FbAdapter { } fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8 { - resource.offscreen.ptr() + resource.ptr() } fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource) { diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index 3523f24a83..e90a4b39c2 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -1,25 +1,44 @@ +use std::alloc::{self, Layout}; use std::convert::TryInto; -use std::ptr; +use std::ptr::{self, NonNull}; use driver_graphics::Resource; use inputd::Damage; +use syscall::PAGE_SIZE; -use crate::display::OffscreenBuffer; use crate::framebuffer::FrameBuffer; pub struct GraphicScreen { pub width: usize, pub height: usize, - pub offscreen: OffscreenBuffer, + ptr: NonNull<[u32]>, } impl GraphicScreen { pub fn new(width: usize, height: usize) -> GraphicScreen { - GraphicScreen { - width, - height, - offscreen: OffscreenBuffer::new(width * height), - } + let len = width * height; + let layout = Self::layout(len); + let ptr = unsafe { alloc::alloc_zeroed(layout) }; + let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len); + let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout)); + + GraphicScreen { width, height, ptr } + } + + #[inline] + fn layout(len: usize) -> Layout { + // optimizes to an integer mul + Layout::array::(len) + .unwrap() + .align_to(PAGE_SIZE) + .unwrap() + } +} + +impl Drop for GraphicScreen { + fn drop(&mut self) { + let layout = Self::layout(self.ptr.len()); + unsafe { alloc::dealloc(self.ptr.as_ptr().cast(), layout) }; } } @@ -34,6 +53,10 @@ impl Resource for GraphicScreen { } impl GraphicScreen { + pub fn ptr(&self) -> *mut u8 { + self.ptr.as_ptr().cast::() + } + pub fn sync(&self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) { for sync_rect in sync_rects { let sync_rect = sync_rect.clip( @@ -50,7 +73,7 @@ impl GraphicScreen { let row_pixel_count = w; - let mut offscreen_ptr = self.offscreen.as_ptr(); + let mut offscreen_ptr = self.ptr.as_ptr() as *mut u32; let mut onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable unsafe { From 5bfce514be01d239664e29788c96cfdb564813ba Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 28 Dec 2024 15:15:10 +0100 Subject: [PATCH 1064/1301] graphics/console-draw: Collapse consecutive damage entries --- graphics/console-draw/src/lib.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index 1b4c386cf1..729cbd744a 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -213,16 +213,21 @@ impl TextScreen { } let width = map.width.try_into().unwrap(); - let damage = self - .changed - .iter() - .map(|&change| Damage { - x: 0, - y: i32::try_from(change).unwrap() * 16, - width, - height: 16, - }) - .collect(); + let mut damage: Vec = vec![]; + let mut last_change = usize::MAX - 1; + for &change in &self.changed { + if change == last_change + 1 { + damage.last_mut().unwrap().height += 16; + } else { + damage.push(Damage { + x: 0, + y: i32::try_from(change).unwrap() * 16, + width, + height: 16, + }); + } + last_change = change; + } self.changed.clear(); From 7b11acbc46b8d96a521881ccea9b57878210214e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 28 Dec 2024 16:21:36 +0100 Subject: [PATCH 1065/1301] graphics: Introduce graphics-ipc crate While for now this for now only includes helpers for the current limited display interface which is relatively simple to implement manually, in the future we will likely need a more complex interface with gpu drivers that would be hard to get right without a common crate proving the interface. --- Cargo.lock | 12 +++ Cargo.toml | 1 + graphics/fbbootlogd/Cargo.toml | 1 + graphics/fbbootlogd/src/display.rs | 104 ++++----------------- graphics/fbbootlogd/src/text.rs | 8 +- graphics/fbcond/Cargo.toml | 1 + graphics/fbcond/src/display.rs | 136 +++++----------------------- graphics/fbcond/src/scheme.rs | 6 -- graphics/fbcond/src/text.rs | 14 +-- graphics/graphics-ipc/Cargo.toml | 11 +++ graphics/graphics-ipc/src/legacy.rs | 112 +++++++++++++++++++++++ graphics/graphics-ipc/src/lib.rs | 1 + 12 files changed, 190 insertions(+), 217 deletions(-) create mode 100644 graphics/graphics-ipc/Cargo.toml create mode 100644 graphics/graphics-ipc/src/legacy.rs create mode 100644 graphics/graphics-ipc/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 374df5ce0a..602e66313e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -442,6 +442,7 @@ name = "fbbootlogd" version = "0.1.0" dependencies = [ "console-draw", + "graphics-ipc", "inputd", "libredox", "orbclient", @@ -457,6 +458,7 @@ name = "fbcond" version = "0.1.0" dependencies = [ "console-draw", + "graphics-ipc", "inputd", "libredox", "orbclient", @@ -602,6 +604,16 @@ dependencies = [ "uuid", ] +[[package]] +name = "graphics-ipc" +version = "0.1.0" +dependencies = [ + "common", + "inputd", + "libredox", + "log", +] + [[package]] name = "hashbrown" version = "0.15.1" diff --git a/Cargo.toml b/Cargo.toml index 9fe3ecd2be..be9ace45b5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ members = [ "graphics/fbbootlogd", "graphics/driver-graphics", "graphics/fbcond", + "graphics/graphics-ipc", "graphics/vesad", "graphics/virtio-gpud", diff --git a/graphics/fbbootlogd/Cargo.toml b/graphics/fbbootlogd/Cargo.toml index 90862d2780..b05978513e 100644 --- a/graphics/fbbootlogd/Cargo.toml +++ b/graphics/fbbootlogd/Cargo.toml @@ -12,6 +12,7 @@ redox-daemon = "0.1" redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } console-draw = { path = "../console-draw" } +graphics-ipc = { path = "../graphics-ipc" } inputd = { path = "../../inputd" } libredox = "0.1.3" diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index ad3b39d4cb..646d3e4d6a 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -1,13 +1,13 @@ use event::{user_data, EventQueue}; +use graphics_ipc::legacy::LegacyGraphicsHandle; use inputd::{ConsumerHandle, Damage}; use libredox::errno::ESTALE; -use libredox::flag; use orbclient::Event; use std::mem; use std::os::fd::BorrowedFd; use std::sync::mpsc::{self, Receiver, Sender}; use std::sync::{Arc, Mutex}; -use std::{fs::File, io, os::unix::io::AsRawFd, slice}; +use std::{io, os::unix::io::AsRawFd, slice}; fn read_to_slice( file: BorrowedFd, @@ -22,46 +22,17 @@ fn read_to_slice( } } -fn display_fd_map(width: usize, height: usize, display_file: File) -> syscall::Result { - unsafe { - let display_ptr = libredox::call::mmap(libredox::call::MmapArgs { - fd: display_file.as_raw_fd() as usize, - offset: 0, - length: (width * height * 4), - prot: flag::PROT_READ | flag::PROT_WRITE, - flags: flag::MAP_SHARED, - addr: core::ptr::null_mut(), - })?; - let display_slice = slice::from_raw_parts_mut(display_ptr as *mut u32, width * height); - Ok(DisplayMap { - display_file: Arc::new(display_file), - offscreen: display_slice, - width, - height, - }) - } -} - -unsafe fn display_fd_unmap(image: *mut [u32]) { - let _ = libredox::call::munmap(image as *mut (), image.len()); +fn display_fd_map(display_handle: LegacyGraphicsHandle) -> io::Result { + let display_map = display_handle.map_display()?; + Ok(DisplayMap { + display_handle: Arc::new(display_handle), + inner: display_map, + }) } pub struct DisplayMap { - display_file: Arc, - pub offscreen: *mut [u32], - pub width: usize, - pub height: usize, -} - -unsafe impl Send for DisplayMap {} -unsafe impl Sync for DisplayMap {} - -impl Drop for DisplayMap { - fn drop(&mut self) { - unsafe { - display_fd_unmap(self.offscreen); - } - } + display_handle: Arc, + pub inner: graphics_ipc::legacy::DisplayMap, } enum DisplayCommand { @@ -77,11 +48,10 @@ impl Display { pub fn open_first_vt() -> io::Result { let input_handle = ConsumerHandle::for_vt(1)?; - let (display_file, width, height) = Self::open_display(&input_handle)?; + let display_handle = LegacyGraphicsHandle::from_file(input_handle.open_display()?)?; let map = Arc::new(Mutex::new( - display_fd_map(width, height, display_file) - .unwrap_or_else(|e| panic!("failed to map display: {e}")), + display_fd_map(display_handle).unwrap_or_else(|e| panic!("failed to map display: {e}")), )); let map_clone = map.clone(); @@ -98,34 +68,6 @@ impl Display { Ok(Self { cmd_tx, map }) } - fn open_display(input_handle: &ConsumerHandle) -> io::Result<(File, usize, usize)> { - let display_file = input_handle.open_display()?; - - let mut buf: [u8; 4096] = [0; 4096]; - let count = libredox::call::fpath(display_file.as_raw_fd() as usize, &mut buf) - .unwrap_or_else(|e| { - panic!("Could not read display path with fpath(): {e}"); - }); - - let url = - String::from_utf8(Vec::from(&buf[..count])).expect("Could not create Utf8 Url String"); - let path = url.split(':').nth(1).expect("Could not get path from url"); - - let mut path_parts = path.split('/').skip(1); - let width = path_parts - .next() - .unwrap_or("") - .parse::() - .unwrap_or(0); - let height = path_parts - .next() - .unwrap_or("") - .parse::() - .unwrap_or(0); - - Ok((display_file, width, height)) - } - fn handle_input_events(map: Arc>, input_handle: ConsumerHandle) { let event_queue = EventQueue::new().expect("fbbootlogd: failed to create event queue"); @@ -151,10 +93,11 @@ impl Display { Err(err) if err.errno() == ESTALE => { eprintln!("fbbootlogd: handoff requested"); - let (new_display_file, width, height) = - Self::open_display(&input_handle).unwrap(); + let new_display_handle = + LegacyGraphicsHandle::from_file(input_handle.open_display().unwrap()) + .unwrap(); - match display_fd_map(width, height, new_display_file) { + match display_fd_map(new_display_handle) { Ok(ok) => { *map.lock().unwrap() = ok; @@ -177,19 +120,12 @@ impl Display { fn handle_sync_rect(map: Arc>, cmd_rx: Receiver) { while let Ok(cmd) = cmd_rx.recv() { match cmd { - DisplayCommand::SyncRects(sync_rects) => unsafe { + DisplayCommand::SyncRects(sync_rects) => { // We may not hold this lock across the write call to avoid deadlocking if the // graphics driver tries to write to the bootlog. - let display_file = map.lock().unwrap().display_file.clone(); - libredox::call::write( - display_file.as_raw_fd() as usize, - slice::from_raw_parts( - sync_rects.as_ptr() as *const u8, - sync_rects.len() * mem::size_of::(), - ), - ) - .unwrap(); - }, + let display_handle = map.lock().unwrap().display_handle.clone(); + display_handle.sync_rects(&sync_rects).unwrap(); + } } } } diff --git a/graphics/fbbootlogd/src/text.rs b/graphics/fbbootlogd/src/text.rs index 5dff07d565..15e34e0584 100644 --- a/graphics/fbbootlogd/src/text.rs +++ b/graphics/fbbootlogd/src/text.rs @@ -22,12 +22,12 @@ impl TextScreen { impl TextScreen { pub fn write(&mut self, buf: &[u8]) -> Result { - let map = self.display.map.lock().unwrap(); + let mut map = self.display.map.lock().unwrap(); let damage = self.inner.write( &mut console_draw::DisplayMap { - offscreen: map.offscreen, - width: map.width, - height: map.height, + offscreen: map.inner.ptr_mut(), + width: map.inner.width(), + height: map.inner.height(), }, buf, &mut VecDeque::new(), diff --git a/graphics/fbcond/Cargo.toml b/graphics/fbcond/Cargo.toml index fffb1a0729..10fc0ebf37 100644 --- a/graphics/fbcond/Cargo.toml +++ b/graphics/fbcond/Cargo.toml @@ -12,6 +12,7 @@ redox-daemon = "0.1" redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } console-draw = { path = "../console-draw" } +graphics-ipc = { path = "../graphics-ipc" } inputd = { path = "../../inputd" } libredox = "0.1.3" diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index cf2dbc528a..d50ac26217 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,57 +1,27 @@ +use graphics_ipc::legacy::{DisplayMap, LegacyGraphicsHandle}; use inputd::{ConsumerHandle, Damage}; -use libredox::flag; -use std::fs::File; -use std::os::unix::io::AsRawFd; -use std::{io, mem, ptr, slice}; - -fn display_fd_map( - width: usize, - height: usize, - display_file: &mut File, -) -> syscall::Result<*mut [u32]> { - unsafe { - let display_ptr = libredox::call::mmap(libredox::call::MmapArgs { - fd: display_file.as_raw_fd() as usize, - offset: 0, - length: (width * height * 4), - prot: flag::PROT_READ | flag::PROT_WRITE, - flags: flag::MAP_SHARED, - addr: core::ptr::null_mut(), - })?; - Ok(ptr::slice_from_raw_parts_mut( - display_ptr as *mut u32, - width * height, - )) - } -} - -unsafe fn display_fd_unmap(image: *mut [u32]) { - let _ = libredox::call::munmap(image as *mut (), image.len()); -} +use std::io; pub struct Display { pub input_handle: ConsumerHandle, - pub display_file: File, - pub offscreen: *mut [u32], - pub width: usize, - pub height: usize, + pub display_handle: LegacyGraphicsHandle, + pub map: DisplayMap, } impl Display { pub fn open_vt(vt: usize) -> io::Result { let input_handle = ConsumerHandle::for_vt(vt)?; - let (mut display_file, width, height) = Self::open_display(&input_handle)?; + let display_handle = Self::open_display(&input_handle)?; - let offscreen = display_fd_map(width, height, &mut display_file) + let map = display_handle + .map_display() .unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")); Ok(Self { input_handle, - display_file, - offscreen, - width, - height, + display_handle, + map, }) } @@ -59,92 +29,34 @@ impl Display { pub fn reopen_for_handoff(&mut self) { eprintln!("fbcond: Performing handoff"); - let (mut new_display_file, width, height) = Self::open_display(&self.input_handle).unwrap(); + let new_display_handle = Self::open_display(&self.input_handle).unwrap(); - eprintln!("fbcond: Opened new display with size {width}x{height}"); + eprintln!("fbcond: Opened new display"); - match display_fd_map(width, height, &mut new_display_file) { - Ok(offscreen) => { - unsafe { - display_fd_unmap(self.offscreen); - } + match new_display_handle.map_display() { + Ok(map) => { + self.map = map; + self.display_handle = new_display_handle; - self.offscreen = offscreen; - self.width = width; - self.height = height; - self.display_file = new_display_file; - - eprintln!("fbcond: Mapped new display"); + eprintln!( + "fbcond: Mapped new display with size {}x{}", + self.map.width(), + self.map.height() + ); } Err(err) => { - eprintln!("failed to resize display to {}x{}: {}", width, height, err); + eprintln!("failed to resize display: {}", err); } } } - fn open_display(input_handle: &ConsumerHandle) -> io::Result<(File, usize, usize)> { + fn open_display(input_handle: &ConsumerHandle) -> io::Result { let display_file = input_handle.open_display()?; - let mut buf: [u8; 4096] = [0; 4096]; - let count = libredox::call::fpath(display_file.as_raw_fd() as usize, &mut buf) - .unwrap_or_else(|e| { - panic!("Could not read display path with fpath(): {e}"); - }); - - let url = - String::from_utf8(Vec::from(&buf[..count])).expect("Could not create Utf8 Url String"); - let path = url.split(':').nth(1).expect("Could not get path from url"); - - let mut path_parts = path.split('/').skip(1); - let width = path_parts - .next() - .unwrap_or("") - .parse::() - .unwrap_or(0); - let height = path_parts - .next() - .unwrap_or("") - .parse::() - .unwrap_or(0); - - Ok((display_file, width, height)) - } - - pub fn resize(&mut self, width: usize, height: usize) { - match display_fd_map(width, height, &mut self.display_file) { - Ok(offscreen) => { - unsafe { - display_fd_unmap(self.offscreen); - } - - self.offscreen = offscreen; - self.width = width; - self.height = height; - } - Err(err) => { - eprintln!("failed to resize display to {}x{}: {}", width, height, err); - } - } + LegacyGraphicsHandle::from_file(display_file) } pub fn sync_rects(&mut self, sync_rects: Vec) { - unsafe { - libredox::call::write( - self.display_file.as_raw_fd() as usize, - slice::from_raw_parts( - sync_rects.as_ptr() as *const u8, - sync_rects.len() * mem::size_of::(), - ), - ) - .unwrap(); - } - } -} - -impl Drop for Display { - fn drop(&mut self) { - unsafe { - display_fd_unmap(self.offscreen); - } + self.display_handle.sync_rects(&sync_rects).unwrap(); } } diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index dd667cbf47..0643b11223 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -60,12 +60,6 @@ impl FbconScheme { handles: BTreeMap::new(), } } - - fn resize(&mut self, width: usize, height: usize, stride: usize) { - for console in self.vts.values_mut() { - console.resize(width, height); - } - } } impl SchemeBlock for FbconScheme { diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index e01dab8ae6..02f36377cc 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -1,7 +1,4 @@ -extern crate ransid; - use std::collections::VecDeque; -use std::convert::TryInto; use orbclient::{Event, EventOption}; use syscall::error::*; @@ -29,11 +26,6 @@ impl TextScreen { self.display.reopen_for_handoff(); } - pub fn resize(&mut self, width: usize, height: usize) { - self.display - .resize(width.try_into().unwrap(), height.try_into().unwrap()); - } - pub fn input(&mut self, event: &Event) { let mut buf = vec![]; @@ -130,9 +122,9 @@ impl TextScreen { pub fn write(&mut self, buf: &[u8]) -> Result { let damage = self.inner.write( &mut console_draw::DisplayMap { - offscreen: self.display.offscreen, - width: self.display.width, - height: self.display.height, + offscreen: self.display.map.ptr_mut(), + width: self.display.map.width(), + height: self.display.map.height(), }, buf, &mut self.input, diff --git a/graphics/graphics-ipc/Cargo.toml b/graphics/graphics-ipc/Cargo.toml new file mode 100644 index 0000000000..61298ced0e --- /dev/null +++ b/graphics/graphics-ipc/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "graphics-ipc" +version = "0.1.0" +edition = "2021" + +[dependencies] +log = "0.4" +libredox = "0.1.3" + +common = { path = "../../common" } +inputd = { path = "../../inputd" } diff --git a/graphics/graphics-ipc/src/legacy.rs b/graphics/graphics-ipc/src/legacy.rs new file mode 100644 index 0000000000..6d039f8f6b --- /dev/null +++ b/graphics/graphics-ipc/src/legacy.rs @@ -0,0 +1,112 @@ +use std::fs::File; +use std::os::unix::io::AsRawFd; +use std::{io, mem, ptr, slice}; + +use inputd::Damage; +use libredox::flag; + +/// A graphics handle using the legacy graphics API. +/// +/// The legacy graphics API only allows a single framebuffer for each VT and supports neither page +/// flipping nor cursor planes. +pub struct LegacyGraphicsHandle { + file: File, +} + +impl LegacyGraphicsHandle { + pub fn from_file(file: File) -> io::Result { + Ok(LegacyGraphicsHandle { file }) + } + + pub fn map_display(&self) -> io::Result { + let mut buf: [u8; 4096] = [0; 4096]; + let count = + libredox::call::fpath(self.file.as_raw_fd() as usize, &mut buf).unwrap_or_else(|e| { + panic!("Could not read display path with fpath(): {e}"); + }); + + let url = + String::from_utf8(Vec::from(&buf[..count])).expect("Could not create Utf8 Url String"); + let path = url.split(':').nth(1).expect("Could not get path from url"); + + let mut path_parts = path.split('/').skip(1); + let width = path_parts + .next() + .unwrap_or("") + .parse::() + .unwrap_or(0); + let height = path_parts + .next() + .unwrap_or("") + .parse::() + .unwrap_or(0); + + let display_ptr = unsafe { + libredox::call::mmap(libredox::call::MmapArgs { + fd: self.file.as_raw_fd() as usize, + offset: 0, + length: (width * height * 4), + prot: flag::PROT_READ | flag::PROT_WRITE, + flags: flag::MAP_SHARED, + addr: core::ptr::null_mut(), + })? + }; + let offscreen = ptr::slice_from_raw_parts_mut(display_ptr as *mut u32, width * height); + + Ok(DisplayMap { + offscreen, + width, + height, + }) + } + + pub fn sync_full_screen(&self) -> io::Result<()> { + libredox::call::fsync(self.file.as_raw_fd() as usize)?; + Ok(()) + } + + pub fn sync_rects(&self, sync_rects: &[Damage]) -> io::Result<()> { + libredox::call::write(self.file.as_raw_fd() as usize, unsafe { + slice::from_raw_parts( + sync_rects.as_ptr() as *const u8, + sync_rects.len() * mem::size_of::(), + ) + })?; + Ok(()) + } +} + +pub struct DisplayMap { + offscreen: *mut [u32], + width: usize, + height: usize, +} + +impl DisplayMap { + pub fn ptr(&self) -> *const [u32] { + self.offscreen + } + + pub fn ptr_mut(&mut self) -> *mut [u32] { + self.offscreen + } + + pub fn width(&self) -> usize { + self.width + } + + pub fn height(&self) -> usize { + self.height + } +} + +unsafe impl Send for DisplayMap {} +unsafe impl Sync for DisplayMap {} + +impl Drop for DisplayMap { + fn drop(&mut self) { + unsafe { + let _ = libredox::call::munmap(self.offscreen as *mut (), self.offscreen.len()); + } + } +} diff --git a/graphics/graphics-ipc/src/lib.rs b/graphics/graphics-ipc/src/lib.rs new file mode 100644 index 0000000000..d0b036677b --- /dev/null +++ b/graphics/graphics-ipc/src/lib.rs @@ -0,0 +1 @@ +pub mod legacy; From 5fc04c332d5e889d3cc94f557b5309dcdd6fdb17 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 28 Dec 2024 16:26:18 +0100 Subject: [PATCH 1066/1301] graphics: Move Damage from inputd to graphics-ipc --- Cargo.lock | 6 ++++-- graphics/console-draw/Cargo.toml | 2 +- graphics/console-draw/src/lib.rs | 2 +- graphics/driver-graphics/Cargo.toml | 1 + graphics/driver-graphics/src/lib.rs | 3 ++- graphics/fbbootlogd/src/display.rs | 4 ++-- graphics/fbcond/src/display.rs | 4 ++-- graphics/graphics-ipc/Cargo.toml | 1 - graphics/graphics-ipc/src/legacy.rs | 29 +++++++++++++++++++++++++++-- graphics/vesad/Cargo.toml | 1 + graphics/vesad/src/scheme.rs | 3 ++- graphics/vesad/src/screen.rs | 2 +- graphics/virtio-gpud/Cargo.toml | 1 + graphics/virtio-gpud/src/scheme.rs | 3 ++- inputd/src/lib.rs | 29 ----------------------------- 15 files changed, 47 insertions(+), 44 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 602e66313e..145efadb1d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -326,7 +326,7 @@ dependencies = [ name = "console-draw" version = "0.1.0" dependencies = [ - "inputd", + "graphics-ipc", "orbclient", "ransid", ] @@ -401,6 +401,7 @@ name = "driver-graphics" version = "0.1.0" dependencies = [ "common", + "graphics-ipc", "inputd", "libredox", "log", @@ -609,7 +610,6 @@ name = "graphics-ipc" version = "0.1.0" dependencies = [ "common", - "inputd", "libredox", "log", ] @@ -1725,6 +1725,7 @@ version = "0.1.0" dependencies = [ "common", "driver-graphics", + "graphics-ipc", "inputd", "libredox", "orbclient", @@ -1780,6 +1781,7 @@ dependencies = [ "common", "driver-graphics", "futures", + "graphics-ipc", "inputd", "libredox", "log", diff --git a/graphics/console-draw/Cargo.toml b/graphics/console-draw/Cargo.toml index 56d8d98562..6153d6143d 100644 --- a/graphics/console-draw/Cargo.toml +++ b/graphics/console-draw/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" orbclient = "0.3.27" ransid = "0.4" -inputd = { path = "../../inputd" } +graphics-ipc = { path = "../graphics-ipc" } [features] default = [] diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index 729cbd744a..bbd2d4fdeb 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -4,7 +4,7 @@ use std::collections::{BTreeSet, VecDeque}; use std::convert::{TryFrom, TryInto}; use std::{cmp, ptr}; -use inputd::Damage; +use graphics_ipc::legacy::Damage; use orbclient::FONT; pub struct DisplayMap { diff --git a/graphics/driver-graphics/Cargo.toml b/graphics/driver-graphics/Cargo.toml index c7cd6f9de5..6ad15add9d 100644 --- a/graphics/driver-graphics/Cargo.toml +++ b/graphics/driver-graphics/Cargo.toml @@ -10,4 +10,5 @@ redox_syscall = "0.5" libredox = "0.1.3" common = { path = "../../common" } +graphics-ipc = { path = "../graphics-ipc" } inputd = { path = "../../inputd" } diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 33c925206c..147802dc60 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -1,7 +1,8 @@ use std::collections::{BTreeMap, HashMap}; use std::io; -use inputd::{Damage, VtEvent, VtEventKind}; +use graphics_ipc::legacy::Damage; +use inputd::{VtEvent, VtEventKind}; use libredox::errno::EOPNOTSUPP; use libredox::Fd; use redox_scheme::{RequestKind, Response, Scheme, SignalBehavior, Socket}; diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index 646d3e4d6a..4fa9d53213 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -1,6 +1,6 @@ use event::{user_data, EventQueue}; -use graphics_ipc::legacy::LegacyGraphicsHandle; -use inputd::{ConsumerHandle, Damage}; +use graphics_ipc::legacy::{Damage, LegacyGraphicsHandle}; +use inputd::ConsumerHandle; use libredox::errno::ESTALE; use orbclient::Event; use std::mem; diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index d50ac26217..8595ec6e9c 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,5 +1,5 @@ -use graphics_ipc::legacy::{DisplayMap, LegacyGraphicsHandle}; -use inputd::{ConsumerHandle, Damage}; +use graphics_ipc::legacy::{Damage, DisplayMap, LegacyGraphicsHandle}; +use inputd::ConsumerHandle; use std::io; pub struct Display { diff --git a/graphics/graphics-ipc/Cargo.toml b/graphics/graphics-ipc/Cargo.toml index 61298ced0e..7491222b9c 100644 --- a/graphics/graphics-ipc/Cargo.toml +++ b/graphics/graphics-ipc/Cargo.toml @@ -8,4 +8,3 @@ log = "0.4" libredox = "0.1.3" common = { path = "../../common" } -inputd = { path = "../../inputd" } diff --git a/graphics/graphics-ipc/src/legacy.rs b/graphics/graphics-ipc/src/legacy.rs index 6d039f8f6b..2bfb4f2ce3 100644 --- a/graphics/graphics-ipc/src/legacy.rs +++ b/graphics/graphics-ipc/src/legacy.rs @@ -1,8 +1,7 @@ use std::fs::File; use std::os::unix::io::AsRawFd; -use std::{io, mem, ptr, slice}; +use std::{cmp, io, mem, ptr, slice}; -use inputd::Damage; use libredox::flag; /// A graphics handle using the legacy graphics API. @@ -110,3 +109,29 @@ impl Drop for DisplayMap { } } } + +// Keep synced with orbital's SyncRect +#[derive(Debug, Copy, Clone)] +#[repr(packed)] +pub struct Damage { + pub x: i32, + pub y: i32, + pub width: i32, + pub height: i32, +} + +impl Damage { + #[must_use] + pub fn clip(mut self, width: i32, height: i32) -> Self { + // Clip damage + self.x = cmp::min(self.x, width); + if self.x + self.width > width { + self.width -= cmp::min(self.width, width - self.x); + } + self.y = cmp::min(self.y, height); + if self.y + self.height > height { + self.height = cmp::min(self.height, height - self.y); + } + self + } +} diff --git a/graphics/vesad/Cargo.toml b/graphics/vesad/Cargo.toml index 8106dbca03..fd983213a7 100644 --- a/graphics/vesad/Cargo.toml +++ b/graphics/vesad/Cargo.toml @@ -12,6 +12,7 @@ redox_event = "0.4.1" common = { path = "../../common" } driver-graphics = { path = "../driver-graphics" } +graphics-ipc = { path = "../graphics-ipc" } inputd = { path = "../../inputd" } libredox = "0.1.3" diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 15d7f2867a..51a3712e02 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -1,4 +1,5 @@ use driver_graphics::GraphicsAdapter; +use graphics_ipc::legacy::Damage; use crate::{framebuffer::FrameBuffer, screen::GraphicScreen}; @@ -36,7 +37,7 @@ impl GraphicsAdapter for FbAdapter { &mut self, display_id: usize, resource: &Self::Resource, - damage: Option<&[inputd::Damage]>, + damage: Option<&[Damage]>, ) { if let Some(damage) = damage { resource.sync(&mut self.framebuffers[display_id], damage) diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs index e90a4b39c2..8460ffbbf7 100644 --- a/graphics/vesad/src/screen.rs +++ b/graphics/vesad/src/screen.rs @@ -3,7 +3,7 @@ use std::convert::TryInto; use std::ptr::{self, NonNull}; use driver_graphics::Resource; -use inputd::Damage; +use graphics_ipc::legacy::Damage; use syscall::PAGE_SIZE; use crate::framebuffer::FrameBuffer; diff --git a/graphics/virtio-gpud/Cargo.toml b/graphics/virtio-gpud/Cargo.toml index a8cf34ed40..ae340bc391 100644 --- a/graphics/virtio-gpud/Cargo.toml +++ b/graphics/virtio-gpud/Cargo.toml @@ -12,6 +12,7 @@ anyhow = "1.0.71" common = { path = "../../common" } driver-graphics = { path = "../driver-graphics" } +graphics-ipc = { path = "../graphics-ipc" } virtio-core = { path = "../../virtio-core" } pcid = { path = "../../pcid" } inputd = { path = "../../inputd" } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 3f140fb8f3..d80f45bbb6 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -2,7 +2,8 @@ use std::sync::Arc; use common::{dma::Dma, sgl}; use driver_graphics::{GraphicsAdapter, GraphicsScheme, Resource}; -use inputd::{Damage, DisplayHandle}; +use graphics_ipc::legacy::Damage; +use inputd::DisplayHandle; use syscall::PAGE_SIZE; diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 4bc019d4ad..877e3f3145 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -1,6 +1,3 @@ -#![feature(iter_next_chunk)] - -use std::cmp; use std::fs::{File, OpenOptions}; use std::io::{Error, Read, Write}; use std::mem::size_of; @@ -137,32 +134,6 @@ pub struct VtEvent { pub stride: u32, } -// Keep synced with orbital's SyncRect -#[derive(Debug, Copy, Clone)] -#[repr(packed)] -pub struct Damage { - pub x: i32, - pub y: i32, - pub width: i32, - pub height: i32, -} - -impl Damage { - #[must_use] - pub fn clip(mut self, width: i32, height: i32) -> Self { - // Clip damage - self.x = cmp::min(self.x, width); - if self.x + self.width > width { - self.width -= cmp::min(self.width, width - self.x); - } - self.y = cmp::min(self.y, height); - if self.y + self.height > height { - self.height = cmp::min(self.height, height - self.y); - } - self - } -} - pub struct ProducerHandle(File); impl ProducerHandle { From e6139319e8a6bbfcdf0fc3b4d71bbcd56c6421d2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 30 Dec 2024 11:40:02 +0100 Subject: [PATCH 1067/1301] pcid: Remove a couple of unused dependencies --- Cargo.lock | 4 ---- pcid/Cargo.toml | 4 ---- 2 files changed, 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 145efadb1d..03a983b183 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -995,8 +995,6 @@ name = "pcid" version = "0.1.0" dependencies = [ "bincode", - "bit_field", - "bitflags 1.3.2", "common", "fdt 0.1.5", "libc", @@ -1006,9 +1004,7 @@ dependencies = [ "pci_types", "plain", "redox-daemon", - "redox_syscall", "serde", - "serde_json", "structopt", "thiserror", "toml 0.5.11", diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 1bf295f8d4..0108db9c69 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -13,8 +13,6 @@ path = "src/lib.rs" [dependencies] bincode = "1.2" -bitflags = "1" -bit_field = "0.10" fdt = "0.1.5" libc = "0.2" log = "0.4" @@ -22,9 +20,7 @@ paw = "1.0" pci_types = "0.10" plain = "0.2" redox-daemon = "0.1" -redox_syscall = "0.5" serde = { version = "1", features = ["derive"] } -serde_json = "1" structopt = { version = "0.3", default-features = false, features = [ "paw" ] } thiserror = "1" toml = "0.5" From 898f8dc72befa770e666f2f7b6379bfa4cb71975 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 30 Dec 2024 11:41:34 +0100 Subject: [PATCH 1068/1301] pcid: Remove usage of paw --- Cargo.lock | 29 ----------------------------- pcid/Cargo.toml | 3 +-- pcid/src/main.rs | 5 +++-- 3 files changed, 4 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 03a983b183..57abb4719d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -953,33 +953,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "paw" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09c0fc9b564dbc3dc2ed7c92c0c144f4de340aa94514ce2b446065417c4084e9" -dependencies = [ - "paw-attributes", - "paw-raw", -] - -[[package]] -name = "paw-attributes" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f35583365be5d148e959284f42526841917b7bfa09e2d1a7ad5dde2cf0eaa39" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "paw-raw" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f0b59668fe80c5afe998f0c0bf93322bf2cd66cafeeb80581f291716f3467f2" - [[package]] name = "pci_types" version = "0.10.0" @@ -1000,7 +973,6 @@ dependencies = [ "libc", "libredox", "log", - "paw", "pci_types", "plain", "redox-daemon", @@ -1476,7 +1448,6 @@ checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" dependencies = [ "clap", "lazy_static", - "paw", "structopt-derive", ] diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 0108db9c69..6acfa7774a 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -16,12 +16,11 @@ bincode = "1.2" fdt = "0.1.5" libc = "0.2" log = "0.4" -paw = "1.0" pci_types = "0.10" plain = "0.2" redox-daemon = "0.1" serde = { version = "1", features = ["derive"] } -structopt = { version = "0.3", default-features = false, features = [ "paw" ] } +structopt = { version = "0.3", default-features = false } thiserror = "1" toml = "0.5" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 231463df73..49fc2119dd 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -194,8 +194,9 @@ fn handle_parsed_header( } } -#[paw::main] -fn main(args: Args) { +fn main() { + let args = Args::from_args(); + let mut config = Config::default(); if let Some(config_path) = args.config_path { From b26aa9b32be53e2d41f807d674c067969e3dd2d3 Mon Sep 17 00:00:00 2001 From: Ribbon Date: Thu, 9 Jan 2025 11:54:44 +0000 Subject: [PATCH 1069/1301] Document how to contribute and do development in the README --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 93a21c3cf1..0fa66e76dc 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ This section cover the interfaces used by Redox drivers. - `/scheme/memory/physical@wc`: write-combining memory - `/scheme/irq` - allows getting events from interrupts. It is used primarily by listening for its file descriptors using the `/scheme/event` scheme. -## Contributing +## Contribution Details ### Driver Design @@ -80,3 +80,19 @@ If you want to reverse enginner the existing drivers, you can access the BSD cod - [FreeBSD drivers](https://github.com/freebsd/freebsd-src/tree/main/sys/dev) - [NetBSD drivers](https://github.com/NetBSD/src/tree/trunk/sys/dev) - [OpenBSD drivers](https://github.com/openbsd/src/tree/master/sys/dev) + +## How To Contribute + +To learn how to contribute to this system component you need to read the following document: + +- [CONTRIBUTING.md](https://gitlab.redox-os.org/redox-os/redox/-/blob/master/CONTRIBUTING.md) + +## Development + +To learn how to do development with this system component inside the Redox build system you need to read the [Build System](https://doc.redox-os.org/book/build-system-reference.html) and [Coding and Building](https://doc.redox-os.org/book/coding-and-building.html) pages. + +### How To Build + +To build this system component you need to download the Redox build system, you can learn how to do it on the [Building Redox](https://doc.redox-os.org/book/podman-build.html) page. + +This is necessary because they only work with cross-compilation to a Redox virtual machine, but you can do some testing from Linux. From 3f67a82d1f168372384c3a72814af6cc66d378b1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 13 Jan 2025 14:33:28 -0700 Subject: [PATCH 1070/1301] Update rust-toolchain --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 46893dd3f4..e34f9fb808 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-05-11" +channel = "nightly-2025-01-12" components = ["rust-src"] From aa3887d4e7aba055f92ea2ec40a551242822cad8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jesper=20M=C3=B8ller?= Date: Tue, 4 Feb 2025 20:54:40 +0000 Subject: [PATCH 1071/1301] Fix link to "a-note-about-drivers" --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0fa66e76dc..41a8b5fff7 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ If you don't have datasheets, we recommend you to do reverse-engineering of avai You can use the [example](https://gitlab.redox-os.org/redox-os/exampled) driver or read the code of other drivers with the same type of your device. -Before testing your changes, be aware of [this](https://doc.redox-os.org/book/ch09-02-coding-and-building.html#a-note-about-drivers). +Before testing your changes, be aware of [this](https://doc.redox-os.org/book/coding-and-building.html#a-note-about-drivers). ### Driver References From 7f12a14505f3c138b7dfed03c7fd487d382088f7 Mon Sep 17 00:00:00 2001 From: Alice Shelton Date: Sat, 8 Feb 2025 01:47:52 -0600 Subject: [PATCH 1072/1301] ihdad: Follow spec more closely for state changes --- audio/ihdad/src/hda/cmdbuff.rs | 65 +++++++++++++++++----------------- audio/ihdad/src/hda/device.rs | 11 +++++- 2 files changed, 42 insertions(+), 34 deletions(-) diff --git a/audio/ihdad/src/hda/cmdbuff.rs b/audio/ihdad/src/hda/cmdbuff.rs index aec6c2dde7..88c08b5eea 100644 --- a/audio/ihdad/src/hda/cmdbuff.rs +++ b/audio/ihdad/src/hda/cmdbuff.rs @@ -118,8 +118,11 @@ impl Corb { assert!(self.corb_count != 0); let addr = self.corb_base_phys; self.set_address(addr); - self.regs.corbwp.write(0); + self.regs.corbsize.write((corbsize_reg & 0xFC) | corbsize); + self.reset_read_pointer(); + let old_wp = self.regs.corbwp.read(); + self.regs.corbwp.write(old_wp & 0xFF00); } pub fn start(&mut self) { @@ -129,7 +132,7 @@ impl Corb { #[inline(never)] pub fn stop(&mut self) { while self.regs.corbctl.readf(CORBRUN) { - self.regs.corbctl.write(0); + self.regs.corbctl.writef(CORBRUN, false); } } @@ -139,38 +142,29 @@ impl Corb { } pub fn reset_read_pointer(&mut self) { - /* - * FIRST ISSUE/PATCH - * This will loop forever in virtualbox - * So maybe just resetting the read pointer - * and leaving for the specific model? - */ - if true { + // 3.3.21 + + self.stop(); + + // Set CORBRPRST to 1 + log::trace!("CORBRP {:X}", self.regs.corbrp.read()); + self.regs.corbrp.writef(CORBRPRST, true); + log::trace!("CORBRP {:X}", self.regs.corbrp.read()); + + // Wait for it to become 1 + while !self.regs.corbrp.readf(CORBRPRST) { self.regs.corbrp.writef(CORBRPRST, true); - } else { - // 3.3.21 + } - self.stop(); - // Set CORBRPRST to 1 - log::trace!("CORBRP {:X}", self.regs.corbrp.read()); - self.regs.corbrp.writef(CORBRPRST, true); - log::trace!("CORBRP {:X}", self.regs.corbrp.read()); + // Clear the bit again + self.regs.corbrp.writef(CORBRPRST, false); - // Wait for it to become 1 - while !self.regs.corbrp.readf(CORBRPRST) { - self.regs.corbrp.writef(CORBRPRST, true); - } - // Clear the bit again - self.regs.corbrp.write(0); - - // Read back the bit until zero to verify that it is cleared. - - loop { - if !self.regs.corbrp.readf(CORBRPRST) { - break; - } - self.regs.corbrp.write(0); + // Read back the bit until zero to verify that it is cleared. + loop { + if !self.regs.corbrp.readf(CORBRPRST) { + break; } + self.regs.corbrp.writef(CORBRPRST, false); } } @@ -262,9 +256,9 @@ impl Rirb { } pub fn stop(&mut self) { - let mut val = self.regs.rirbctl.read(); - val &= !(RIRBDMAEN); - self.regs.rirbctl.write(val); + while self.regs.rirbctl.readf(RIRBDMAEN) { + self.regs.rirbctl.writef(RIRBDMAEN, false); + } } pub fn set_address(&mut self, addr: usize) { @@ -384,6 +378,11 @@ impl CommandBuffer { self.set_use_imm_cmds(use_imm_cmds); } + pub fn stop(&mut self) { + self.corb.stop(); + self.rirb.stop(); + } + pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> u64 { let mut ncmd: u32 = 0; diff --git a/audio/ihdad/src/hda/device.rs b/audio/ihdad/src/hda/device.rs index 13b1bb7e73..a3cd57b62a 100755 --- a/audio/ihdad/src/hda/device.rs +++ b/audio/ihdad/src/hda/device.rs @@ -6,6 +6,8 @@ use std::collections::HashMap; use std::fmt::Write; use std::str; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread; +use std::time::Duration; use common::dma::Dma; use common::io::{Io, Mmio}; @@ -651,7 +653,9 @@ impl IntelHDA { } pub fn reset_controller(&mut self) -> bool { - self.regs.statests.write(0xFFFF); + self.cmd.stop(); + + self.regs.statests.write(0x7FFF); // 3.3.7 self.regs.gctl.writef(CRST, false); @@ -660,6 +664,9 @@ impl IntelHDA { break; } } + + thread::sleep(Duration::from_millis(1)); + self.regs.gctl.writef(CRST, true); loop { if self.regs.gctl.readf(CRST) { @@ -667,6 +674,8 @@ impl IntelHDA { } } + thread::sleep(Duration::from_millis(2)); + let mut ticks: u32 = 0; while self.regs.statests.read() == 0 { ticks += 1; From 4898261594af3bde107ed1619b096d84628cac15 Mon Sep 17 00:00:00 2001 From: toadster172 Date: Mon, 17 Feb 2025 17:42:51 -0600 Subject: [PATCH 1073/1301] ps2: Use sleep functions for read and write waits --- input/ps2d/src/controller.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/input/ps2d/src/controller.rs b/input/ps2d/src/controller.rs index 9172fa5ee3..f1560faaef 100644 --- a/input/ps2d/src/controller.rs +++ b/input/ps2d/src/controller.rs @@ -1,7 +1,7 @@ use common::io::{Io, Pio, ReadOnly, WriteOnly}; use log::{debug, error, info, trace}; -use std::fmt; +use std::{fmt, thread, time::Duration}; #[cfg(target_arch = "aarch64")] #[inline(always)] @@ -133,29 +133,25 @@ impl Ps2 { } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 100_000; + let mut timeout = 500; while timeout > 0 { if self.status().contains(StatusFlags::OUTPUT_FULL) { return Ok(()); } - unsafe { - pause(); - } timeout -= 1; + thread::sleep(Duration::from_millis(1)); } Err(Error::ReadTimeout) } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 100_000; + let mut timeout = 500; while timeout > 0 { if !self.status().contains(StatusFlags::INPUT_FULL) { return Ok(()); } - unsafe { - pause(); - } timeout -= 1; + thread::sleep(Duration::from_millis(1)); } Err(Error::WriteTimeout) } From 1cae6512fa5d6b54230fa8809a01af8d7c2f63dd Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 13:57:15 +0100 Subject: [PATCH 1074/1301] Don't scan through all 8 functions of a single function PCI device --- pcid/src/main.rs | 105 +++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 45 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 49fc2119dd..c9e3d7f423 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -252,51 +252,8 @@ fn main_inner(config: Config, daemon: redox_daemon::Daemon) -> ! { let bus_num = bus_nums[bus_i]; bus_i += 1; - 'dev: for dev_num in 0..32 { - for func_num in 0..8 { - let header = TyPciHeader::new(PciAddress::new(0, bus_num, dev_num, func_num)); - - let (vendor_id, device_id) = header.id(&state.pcie); - if vendor_id == 0xffff && device_id == 0xffff { - if func_num == 0 { - trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); - continue 'dev; - } - - continue; - } - - let (revision, class, subclass, interface) = header.revision_and_class(&state.pcie); - let full_device_id = FullDeviceId { - vendor_id, - device_id, - class, - subclass, - interface, - revision, - }; - - info!("PCI {} {}", header.address(), full_device_id.display()); - - match header.header_type(&state.pcie) { - HeaderType::Endpoint => { - handle_parsed_header( - Arc::clone(&state), - &config, - EndpointHeader::from_header(header, &state.pcie).unwrap(), - full_device_id, - ); - } - HeaderType::PciPciBridge => { - let bridge_header = - PciPciBridgeHeader::from_header(header, &state.pcie).unwrap(); - bus_nums.push(bridge_header.secondary_bus_number(&state.pcie)); - } - ty => { - warn!("pcid: unknown header type: {ty:?}"); - } - } - } + for dev_num in 0..32 { + scan_device(&config, &state, &mut bus_nums, bus_num, dev_num); } } @@ -308,3 +265,61 @@ fn main_inner(config: Config, daemon: redox_daemon::Daemon) -> ! { std::process::exit(0); } + +fn scan_device( + config: &Config, + state: &Arc, + bus_nums: &mut Vec, + bus_num: u8, + dev_num: u8, +) { + for func_num in 0..8 { + let header = TyPciHeader::new(PciAddress::new(0, bus_num, dev_num, func_num)); + + let (vendor_id, device_id) = header.id(&state.pcie); + if vendor_id == 0xffff && device_id == 0xffff { + if func_num == 0 { + trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); + return; + } + + continue; + } + + let (revision, class, subclass, interface) = header.revision_and_class(&state.pcie); + let full_device_id = FullDeviceId { + vendor_id, + device_id, + class, + subclass, + interface, + revision, + }; + + info!("PCI {} {}", header.address(), full_device_id.display()); + + let has_multiple_functions = header.has_multiple_functions(&state.pcie); + + match header.header_type(&state.pcie) { + HeaderType::Endpoint => { + handle_parsed_header( + Arc::clone(state), + config, + EndpointHeader::from_header(header, &state.pcie).unwrap(), + full_device_id, + ); + } + HeaderType::PciPciBridge => { + let bridge_header = PciPciBridgeHeader::from_header(header, &state.pcie).unwrap(); + bus_nums.push(bridge_header.secondary_bus_number(&state.pcie)); + } + ty => { + warn!("pcid: unknown header type: {ty:?}"); + } + } + + if func_num == 0 && !has_multiple_functions { + return; + } + } +} From 6828b744fdde0944978cdc6de4de85f18560e8ec Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 14:05:33 +0100 Subject: [PATCH 1075/1301] Make Mcfg repr(C, packed) rather than repr(packed) repr(packed) officially still allows reordering the fields. --- pcid/src/cfg_access/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index 20eb0750a4..d2dccf0b8f 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -97,7 +97,7 @@ fn locate_ecam_dtb( pub const MCFG_NAME: [u8; 4] = *b"MCFG"; -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct Mcfg { // base sdt fields From e973f8913988256d11864b3166187ab995c25574 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 14:35:52 +0100 Subject: [PATCH 1076/1301] Remove unnecessary feature gates Some of these have been stabilized while others were likely no longer used at all. --- acpid/src/main.rs | 2 -- audio/ihdad/src/main.rs | 3 --- common/src/lib.rs | 1 - graphics/fbbootlogd/src/main.rs | 2 -- graphics/fbcond/src/main.rs | 2 -- graphics/virtio-gpud/src/main.rs | 2 -- input/ps2d/src/main.rs | 2 -- net/rtl8139d/src/main.rs | 2 -- storage/ahcid/src/main.rs | 1 - storage/nvmed/src/main.rs | 1 - storage/virtio-blkd/src/main.rs | 1 - virtio-core/src/lib.rs | 2 -- 12 files changed, 21 deletions(-) diff --git a/acpid/src/main.rs b/acpid/src/main.rs index c9276d6662..0b846b54b7 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -1,5 +1,3 @@ -#![feature(if_let_guard, int_roundings)] - use std::convert::TryFrom; use std::fs::File; use std::mem; diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 503cf23848..231b32e926 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -1,6 +1,3 @@ -//#![deny(warnings)] -#![feature(int_roundings)] - extern crate bitflags; extern crate event; extern crate spin; diff --git a/common/src/lib.rs b/common/src/lib.rs index 61fa6ced99..73ab361c37 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -2,7 +2,6 @@ //! //! This includes direct memory access via [dma], and Scatter-Gather List support via [sgl]. It also //! provides various memory management structures for use with drivers, and some logging support. -#![feature(int_roundings)] #![warn(missing_docs)] use libredox::call::MmapArgs; diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index 2168f2ed63..cd4d44ff07 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -9,8 +9,6 @@ //! to get new input. Fbbootlogd does all blocking operations in background threads such that the //! main thread will always keep accepting new input and writing it to the framebuffer. -#![feature(io_error_more)] - use libredox::errno::EOPNOTSUPP; use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index bdaac9f33a..2b70ddc0ce 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -1,5 +1,3 @@ -#![feature(io_error_more)] - use event::EventQueue; use libredox::errno::{EAGAIN, EINTR, EOPNOTSUPP, ESTALE}; use orbclient::Event; diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 880e80b9ab..8170c6f33b 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -20,8 +20,6 @@ // cc https://docs.mesa3d.org/drivers/venus.html // cc https://docs.mesa3d.org/drivers/virgl.html -#![feature(int_roundings)] - use std::os::fd::AsRawFd; use std::sync::atomic::{AtomicU32, Ordering}; diff --git a/input/ps2d/src/main.rs b/input/ps2d/src/main.rs index 186904cf9a..20f6b2d5f9 100644 --- a/input/ps2d/src/main.rs +++ b/input/ps2d/src/main.rs @@ -1,5 +1,3 @@ -#![feature(asm_const)] - #[macro_use] extern crate bitflags; extern crate orbclient; diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 774341b83d..37930b6187 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -1,5 +1,3 @@ -#![feature(int_roundings)] - use std::convert::TryInto; use std::fs::File; use std::io::{Read, Write}; diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 0af3d33e7e..89467e04ce 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -1,5 +1,4 @@ #![cfg_attr(target_arch = "aarch64", feature(stdsimd))] // Required for yield instruction -#![feature(int_roundings)] extern crate byteorder; extern crate syscall; diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 91b289a987..420f1e17e7 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -1,6 +1,5 @@ #![cfg_attr(target_arch = "aarch64", feature(stdarch_arm_hints))] // Required for yield instruction #![cfg_attr(target_arch = "riscv64", feature(riscv_ext_intrinsics))] // Required for pause instruction -#![feature(int_roundings)] use std::ptr::NonNull; use std::sync::Arc; diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 14cec55197..2db8ab4779 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -1,5 +1,4 @@ #![deny(trivial_numeric_casts, unused_allocation)] -#![feature(int_roundings)] use std::sync::{Arc, Weak}; diff --git a/virtio-core/src/lib.rs b/virtio-core/src/lib.rs index cc46d36ff8..2557d0b78e 100644 --- a/virtio-core/src/lib.rs +++ b/virtio-core/src/lib.rs @@ -1,5 +1,3 @@ -#![feature(int_roundings)] - pub mod spec; pub mod transport; pub mod utils; From 23c20b0fa2d1e6ef81529e4516ecf2a7d482fbae Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 16:07:10 +0100 Subject: [PATCH 1077/1301] Replace a couple direct uses of physmap with map_bar --- net/rtl8139d/src/main.rs | 39 ++++++++++++++++----------------------- net/rtl8168d/src/main.rs | 39 ++++++++++++++++----------------------- 2 files changed, 32 insertions(+), 46 deletions(-) diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 37930b6187..a8ff4dab49 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -1,8 +1,8 @@ -use std::convert::TryInto; use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; use std::ptr::NonNull; +use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; @@ -11,8 +11,7 @@ use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixInfo, MsixTableEntry}; use pcid_interface::{ - MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, - SubdriverArguments, + MappedBar, MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, }; pub mod device; @@ -155,20 +154,23 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { } } -fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { +fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { + let config = pcid_handle.config(); + // RTL8139 uses BAR2, RTL8169 uses BAR1, search in that order for &barnum in &[2, 1] { - match pci_config.func.bars[barnum] { - pcid_interface::PciBar::Memory32 { addr, size } => { - return Some((addr.try_into().unwrap(), size.try_into().unwrap())) - } - pcid_interface::PciBar::Memory64 { addr, size } => { - return Some((addr.try_into().unwrap(), size.try_into().unwrap())) - } + match config.func.bars[usize::from(barnum)] { + pcid_interface::PciBar::Memory32 { .. } | pcid_interface::PciBar::Memory64 { .. } => unsafe { + return pcid_handle + .map_bar(barnum) + .expect("rtl8139d: failed to map address") + .ptr + .as_ptr(); + }, other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), } } - None + panic!("rtl8139d: failed to find BAR"); } fn daemon(daemon: redox_daemon::Daemon) -> ! { @@ -188,24 +190,15 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_rtl8139"); - let (bar_ptr, bar_size) = find_bar(&pci_config).expect("rtl8139d: failed to find BAR"); log::info!(" + RTL8139 {}", pci_config.func.display()); - let address = unsafe { - common::physmap( - bar_ptr, - bar_size, - common::Prot::RW, - common::MemoryType::Uncacheable, - ) - .expect("rtl8139d: failed to map address") as usize - }; + let bar = map_bar(&mut pcid_handle); //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); let device = - unsafe { device::Rtl8139::new(address).expect("rtl8139d: failed to allocate device") }; + unsafe { device::Rtl8139::new(bar as usize).expect("rtl8139d: failed to allocate device") }; let mut scheme = NetworkScheme::new(device, format!("network.{name}")); diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 49dfef09c3..50fefba7aa 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -1,8 +1,8 @@ -use std::convert::TryInto; use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; use std::ptr::NonNull; +use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; @@ -11,8 +11,7 @@ use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; use pcid_interface::msi::{MsixInfo, MsixTableEntry}; use pcid_interface::{ - MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, - SubdriverArguments, + MappedBar, MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, }; pub mod device; @@ -155,20 +154,23 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { } } -fn find_bar(pci_config: &SubdriverArguments) -> Option<(usize, usize)> { +fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { + let config = pcid_handle.config(); + // RTL8168 uses BAR2, RTL8169 uses BAR1, search in that order for &barnum in &[2, 1] { - match pci_config.func.bars[barnum] { - pcid_interface::PciBar::Memory32 { addr, size } => { - return Some((addr.try_into().unwrap(), size.try_into().unwrap())) - } - pcid_interface::PciBar::Memory64 { addr, size } => { - return Some((addr.try_into().unwrap(), size.try_into().unwrap())) - } + match config.func.bars[usize::from(barnum)] { + pcid_interface::PciBar::Memory32 { .. } | pcid_interface::PciBar::Memory64 { .. } => unsafe { + return pcid_handle + .map_bar(barnum) + .expect("rtl8168d: failed to map address") + .ptr + .as_ptr(); + }, other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), } } - None + panic!("rtl8168d: failed to find BAR"); } fn daemon(daemon: redox_daemon::Daemon) -> ! { @@ -188,24 +190,15 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_rtl8168"); - let (bar_ptr, bar_size) = find_bar(&pci_config).expect("rtl8168d: failed to find BAR"); log::info!(" + RTL8168 {}", pci_config.func.display()); - let address = unsafe { - common::physmap( - bar_ptr, - bar_size, - common::Prot::RW, - common::MemoryType::Uncacheable, - ) - .expect("rtl8168d: failed to map address") as usize - }; + let bar = map_bar(&mut pcid_handle); //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); let device = - unsafe { device::Rtl8168::new(address).expect("rtl8168d: failed to allocate device") }; + unsafe { device::Rtl8168::new(bar as usize).expect("rtl8168d: failed to allocate device") }; let mut scheme = NetworkScheme::new(device, format!("network.{name}")); From 23497b1148af8d93356ec6d814ce49fa34b63343 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 16:12:39 +0100 Subject: [PATCH 1078/1301] Fix standalone compilation of driver-network driver-network does conversions from syscall::Error to std::io::Error which needs the std feature enabled. Without this change rust-analyzer would report errors when trying to compile driver-network without any other crate in the same build to enable the std feature. --- net/driver-network/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/driver-network/Cargo.toml b/net/driver-network/Cargo.toml index 26535c8627..524abbffe3 100644 --- a/net/driver-network/Cargo.toml +++ b/net/driver-network/Cargo.toml @@ -6,4 +6,4 @@ edition = "2021" [dependencies] libredox = "0.1.3" redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } -redox_syscall = "0.5" +redox_syscall = { version = "0.5", features = ["std"] } From 581d9eea33b884a335854887a3b6b7013428e121 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 16:19:08 +0100 Subject: [PATCH 1079/1301] Replace a whole bunch more repr(packed) with repr(C, packed) --- acpid/src/acpi.rs | 8 +++---- acpid/src/acpi/dmar/drhd.rs | 14 ++++++------ acpid/src/acpi/dmar/mod.rs | 16 ++++++------- audio/ac97d/src/device.rs | 2 +- audio/ihdad/src/hda/device.rs | 2 +- audio/ihdad/src/hda/stream.rs | 4 ++-- common/src/io/mmio.rs | 2 +- net/alxd/src/device/mod.rs | 6 ++--- net/e1000d/src/device.rs | 4 ++-- net/ixgbed/src/ixgbe.rs | 24 ++++++++++---------- net/rtl8139d/src/device.rs | 2 +- net/rtl8168d/src/device.rs | 6 ++--- pcid/src/cfg_access/mod.rs | 2 +- pcid/src/driver_interface/msi.rs | 2 +- storage/ahcid/src/ahci/fis.rs | 10 ++++---- storage/ahcid/src/ahci/hba.rs | 10 ++++---- storage/bcm2835-sdhcid/src/sd/mod.rs | 2 +- storage/ided/src/ide.rs | 2 +- storage/nvmed/src/nvme/identify.rs | 6 ++--- storage/nvmed/src/nvme/mod.rs | 2 +- storage/nvmed/src/nvme/queues.rs | 4 ++-- storage/usbscsid/src/protocol/bot.rs | 4 ++-- storage/usbscsid/src/scsi/cmds.rs | 34 ++++++++++++++-------------- vboxd/src/main.rs | 14 ++++++------ xhcid/src/usb/bos.rs | 10 ++++---- xhcid/src/usb/config.rs | 4 ++-- xhcid/src/usb/device.rs | 6 ++--- xhcid/src/usb/endpoint.rs | 8 +++---- xhcid/src/usb/hub.rs | 2 +- xhcid/src/usb/interface.rs | 2 +- xhcid/src/usb/setup.rs | 2 +- xhcid/src/xhci/capability.rs | 2 +- xhcid/src/xhci/context.rs | 12 +++++----- xhcid/src/xhci/doorbell.rs | 2 +- xhcid/src/xhci/event.rs | 2 +- xhcid/src/xhci/extended.rs | 4 ++-- xhcid/src/xhci/operational.rs | 2 +- xhcid/src/xhci/port.rs | 2 +- xhcid/src/xhci/runtime.rs | 4 ++-- xhcid/src/xhci/trb.rs | 2 +- 40 files changed, 124 insertions(+), 124 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index f7aa3ed6f4..48a1f559b8 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -21,7 +21,7 @@ use crate::aml_physmem::{AmlPageCache, AmlPhysMemHandler}; /// The raw SDT header struct, as defined by the ACPI specification. #[derive(Copy, Clone, Debug)] -#[repr(packed)] +#[repr(C, packed)] pub struct SdtHeader { pub signature: [u8; 4], pub length: u32, @@ -601,7 +601,7 @@ impl AcpiContext { } } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct FadtStruct { pub header: SdtHeader, @@ -652,7 +652,7 @@ pub struct FadtStruct { } unsafe impl plain::Plain for FadtStruct {} -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct GenericAddressStructure { address_space: u8, @@ -662,7 +662,7 @@ pub struct GenericAddressStructure { address: u64, } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct FadtAcpi2Struct { // 12 byte structure; see below for details diff --git a/acpid/src/acpi/dmar/drhd.rs b/acpid/src/acpi/dmar/drhd.rs index cce735d0dd..f33f3bf6e2 100644 --- a/acpid/src/acpi/dmar/drhd.rs +++ b/acpid/src/acpi/dmar/drhd.rs @@ -49,7 +49,7 @@ impl Drop for DrhdPage { } } -#[repr(packed)] +#[repr(C, packed)] pub struct DrhdFault { pub sts: Mmio, pub ctrl: Mmio, @@ -59,7 +59,7 @@ pub struct DrhdFault { pub log: Mmio, } -#[repr(packed)] +#[repr(C, packed)] pub struct DrhdProtectedMemory { pub en: Mmio, pub low_base: Mmio, @@ -68,7 +68,7 @@ pub struct DrhdProtectedMemory { pub high_limit: Mmio, } -#[repr(packed)] +#[repr(C, packed)] pub struct DrhdInvalidation { pub queue_head: Mmio, pub queue_tail: Mmio, @@ -80,7 +80,7 @@ pub struct DrhdInvalidation { pub cmpl_addr: [Mmio; 2], } -#[repr(packed)] +#[repr(C, packed)] pub struct DrhdPageRequest { pub queue_head: Mmio, pub queue_tail: Mmio, @@ -92,13 +92,13 @@ pub struct DrhdPageRequest { pub addr: [Mmio; 2], } -#[repr(packed)] +#[repr(C, packed)] pub struct DrhdMtrrVariable { pub base: Mmio, pub mask: Mmio, } -#[repr(packed)] +#[repr(C, packed)] pub struct DrhdMtrr { pub cap: Mmio, pub def_type: Mmio, @@ -106,7 +106,7 @@ pub struct DrhdMtrr { pub variable: [DrhdMtrrVariable; 10], } -#[repr(packed)] +#[repr(C, packed)] pub struct Drhd { pub version: Mmio, _rsv: Mmio, diff --git a/acpid/src/acpi/dmar/mod.rs b/acpid/src/acpi/dmar/mod.rs index b6a350d44f..c42b379a10 100644 --- a/acpid/src/acpi/dmar/mod.rs +++ b/acpid/src/acpi/dmar/mod.rs @@ -20,7 +20,7 @@ use crate::acpi::{AcpiContext, Sdt, SdtHeader}; pub mod drhd; -#[repr(packed)] +#[repr(C, packed)] pub struct DmarStruct { pub sdt_header: SdtHeader, pub host_addr_width: u8, @@ -116,7 +116,7 @@ impl Dmar { /// DMAR DMA Remapping Hardware Unit Definition #[derive(Clone, Copy, Debug)] -#[repr(packed)] +#[repr(C, packed)] pub struct DmarDrhdHeader { pub kind: u16, pub length: u16, @@ -129,7 +129,7 @@ pub struct DmarDrhdHeader { unsafe impl plain::Plain for DmarDrhdHeader {} #[derive(Clone, Copy, Debug)] -#[repr(packed)] +#[repr(C, packed)] pub struct DeviceScopeHeader { pub ty: u8, pub len: u8, @@ -225,7 +225,7 @@ impl fmt::Debug for DmarDrhd { /// DMAR Reserved Memory Region Reporting #[derive(Clone, Copy, Debug)] -#[repr(packed)] +#[repr(C, packed)] pub struct DmarRmrrHeader { pub kind: u16, pub length: u16, @@ -267,7 +267,7 @@ impl fmt::Debug for DmarRmrr { /// DMAR Root Port ATS Capability Reporting #[derive(Clone, Copy, Debug)] -#[repr(packed)] +#[repr(C, packed)] pub struct DmarAtsrHeader { kind: u16, length: u16, @@ -308,7 +308,7 @@ impl fmt::Debug for DmarAtsr { /// DMAR Remapping Hardware Static Affinity #[derive(Clone, Copy, Debug)] -#[repr(packed)] +#[repr(C, packed)] pub struct DmarRhsa { pub kind: u16, pub length: u16, @@ -331,7 +331,7 @@ impl DmarRhsa { /// DMAR ACPI Name-space Device Declaration #[derive(Clone, Copy, Debug)] -#[repr(packed)] +#[repr(C, packed)] pub struct DmarAnddHeader { pub kind: u16, pub length: u16, @@ -372,7 +372,7 @@ impl fmt::Debug for DmarAndd { /// DMAR ACPI Name-space Device Declaration #[derive(Clone, Copy, Debug)] -#[repr(packed)] +#[repr(C, packed)] pub struct DmarSatcHeader { pub kind: u16, pub length: u16, diff --git a/audio/ac97d/src/device.rs b/audio/ac97d/src/device.rs index 0eef06a71f..5785f67c0f 100644 --- a/audio/ac97d/src/device.rs +++ b/audio/ac97d/src/device.rs @@ -139,7 +139,7 @@ impl BusRegs { } } -#[repr(packed)] +#[repr(C, packed)] pub struct BufferDescriptor { /* 0x00 */ addr: Mmio, /* 0x04 */ samples: Mmio, diff --git a/audio/ihdad/src/hda/device.rs b/audio/ihdad/src/hda/device.rs index a3cd57b62a..5a885ce056 100755 --- a/audio/ihdad/src/hda/device.rs +++ b/audio/ihdad/src/hda/device.rs @@ -67,7 +67,7 @@ enum Handle { StrBuf(Vec, usize), } -#[repr(packed)] +#[repr(C, packed)] #[allow(dead_code)] struct Regs { gcap: Mmio, diff --git a/audio/ihdad/src/hda/stream.rs b/audio/ihdad/src/hda/stream.rs index cb02b72630..caa3c36445 100644 --- a/audio/ihdad/src/hda/stream.rs +++ b/audio/ihdad/src/hda/stream.rs @@ -108,7 +108,7 @@ pub fn format_to_u16(sr: &SampleRate, bps: BitsPerSample, channels: u8) -> u16 { val } -#[repr(packed)] +#[repr(C, packed)] pub struct StreamDescriptorRegs { ctrl_lo: Mmio, ctrl_hi: Mmio, @@ -271,7 +271,7 @@ impl OutputStream { } } -#[repr(packed)] +#[repr(C, packed)] pub struct BufferDescriptorListEntry { addr_low: Mmio, addr_high: Mmio, diff --git a/common/src/io/mmio.rs b/common/src/io/mmio.rs index 6b21b66ed5..1edb71014c 100644 --- a/common/src/io/mmio.rs +++ b/common/src/io/mmio.rs @@ -3,7 +3,7 @@ use core::{mem::MaybeUninit, ptr}; use super::Io; /// MMIO abstraction -#[repr(packed)] +#[repr(C, packed)] pub struct Mmio { value: MaybeUninit, } diff --git a/net/alxd/src/device/mod.rs b/net/alxd/src/device/mod.rs index e461f04003..8dcfc3192d 100644 --- a/net/alxd/src/device/mod.rs +++ b/net/alxd/src/device/mod.rs @@ -194,7 +194,7 @@ fn ethtool_adv_to_mii_ctrl1000_t(ethadv: u32) -> u32 { } /// Transmit packet descriptor -#[repr(packed)] +#[repr(C, packed)] struct Tpd { blen: Mmio, vlan: Mmio, @@ -204,14 +204,14 @@ struct Tpd { } /// Receive free descriptor -#[repr(packed)] +#[repr(C, packed)] struct Rfd { addr_low: Mmio, addr_high: Mmio, } /// Receive return descriptor -#[repr(packed)] +#[repr(C, packed)] struct Rrd { checksum: Mmio, rfd: Mmio, diff --git a/net/e1000d/src/device.rs b/net/e1000d/src/device.rs index 721e7cf913..30213fd829 100644 --- a/net/e1000d/src/device.rs +++ b/net/e1000d/src/device.rs @@ -56,7 +56,7 @@ const RAL0: u32 = 0x5400; const RAH0: u32 = 0x5404; #[derive(Debug, Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] struct Rd { buffer: u64, length: u16, @@ -79,7 +79,7 @@ const TDH: u32 = 0x3810; const TDT: u32 = 0x3818; #[derive(Debug, Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] struct Td { buffer: u64, length: u16, diff --git a/net/ixgbed/src/ixgbe.rs b/net/ixgbed/src/ixgbe.rs index abfd5ddda1..a4b941f8c9 100644 --- a/net/ixgbed/src/ixgbe.rs +++ b/net/ixgbed/src/ixgbe.rs @@ -212,7 +212,7 @@ pub fn IXGBE_IVAR(i: u32) -> u32 { } /* 24 at 0x900-0x960 */ #[derive(Debug, Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub struct ixgbe_adv_rx_desc_read { pub pkt_addr: u64, /* Packet buffer address */ @@ -222,7 +222,7 @@ pub struct ixgbe_adv_rx_desc_read { /* Receive Descriptor - Advanced */ #[derive(Debug, Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub struct ixgbe_adv_rx_desc_wb_lower_lo_dword_hs_rss { pub pkt_info: u16, /* RSS, Pkt type */ @@ -231,14 +231,14 @@ pub struct ixgbe_adv_rx_desc_wb_lower_lo_dword_hs_rss { } #[derive(Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub union ixgbe_adv_rx_desc_wb_lower_lo_dword { pub data: u32, pub hs_rss: ixgbe_adv_rx_desc_wb_lower_lo_dword_hs_rss, } #[derive(Debug, Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub struct ixgbe_adv_rx_desc_wb_lower_hi_dword_csum_ip { pub ip_id: u16, /* IP id */ @@ -247,7 +247,7 @@ pub struct ixgbe_adv_rx_desc_wb_lower_hi_dword_csum_ip { } #[derive(Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub union ixgbe_adv_rx_desc_wb_lower_hi_dword { pub rss: u32, /* RSS Hash */ @@ -255,14 +255,14 @@ pub union ixgbe_adv_rx_desc_wb_lower_hi_dword { } #[derive(Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub struct ixgbe_adv_rx_desc_wb_lower { pub lo_dword: ixgbe_adv_rx_desc_wb_lower_lo_dword, pub hi_dword: ixgbe_adv_rx_desc_wb_lower_hi_dword, } #[derive(Debug, Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub struct ixgbe_adv_rx_desc_wb_upper { pub status_error: u32, /* ext status/error */ @@ -273,14 +273,14 @@ pub struct ixgbe_adv_rx_desc_wb_upper { } #[derive(Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub struct ixgbe_adv_rx_desc_wb { pub lower: ixgbe_adv_rx_desc_wb_lower, pub upper: ixgbe_adv_rx_desc_wb_upper, } #[derive(Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub union ixgbe_adv_rx_desc { pub read: ixgbe_adv_rx_desc_read, pub wb: ixgbe_adv_rx_desc_wb, /* writeback */ @@ -289,7 +289,7 @@ pub union ixgbe_adv_rx_desc { /* Transmit Descriptor - Advanced */ #[derive(Debug, Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub struct ixgbe_adv_tx_desc_read { pub buffer_addr: u64, /* Address of descriptor's data buf */ @@ -298,7 +298,7 @@ pub struct ixgbe_adv_tx_desc_read { } #[derive(Debug, Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub struct ixgbe_adv_tx_desc_wb { pub rsvd: u64, /* Reserved */ @@ -307,7 +307,7 @@ pub struct ixgbe_adv_tx_desc_wb { } #[derive(Copy, Clone)] -#[repr(packed)] +#[repr(C, packed)] pub union ixgbe_adv_tx_desc { pub read: ixgbe_adv_tx_desc_read, pub wb: ixgbe_adv_tx_desc_wb, diff --git a/net/rtl8139d/src/device.rs b/net/rtl8139d/src/device.rs index 43ce16d26c..cf98266feb 100644 --- a/net/rtl8139d/src/device.rs +++ b/net/rtl8139d/src/device.rs @@ -35,7 +35,7 @@ const RCR_AM: u32 = 1 << 2; const RCR_APM: u32 = 1 << 1; const RCR_AAP: u32 = 1 << 0; -#[repr(packed)] +#[repr(C, packed)] struct Regs { mac: [Mmio; 2], mar: [Mmio; 2], diff --git a/net/rtl8168d/src/device.rs b/net/rtl8168d/src/device.rs index c813f06b80..32288cf8d1 100644 --- a/net/rtl8168d/src/device.rs +++ b/net/rtl8168d/src/device.rs @@ -7,7 +7,7 @@ use syscall::error::{Error, Result, EMSGSIZE}; use common::dma::Dma; -#[repr(packed)] +#[repr(C, packed)] struct Regs { mac: [Mmio; 2], _mar: [Mmio; 2], @@ -51,7 +51,7 @@ const EOR: u32 = 1 << 30; const FS: u32 = 1 << 29; const LS: u32 = 1 << 28; -#[repr(packed)] +#[repr(C, packed)] struct Rd { ctrl: Mmio, _vlan: Mmio, @@ -59,7 +59,7 @@ struct Rd { buffer_high: Mmio, } -#[repr(packed)] +#[repr(C, packed)] struct Td { ctrl: Mmio, _vlan: Mmio, diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index d2dccf0b8f..476592dd66 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -116,7 +116,7 @@ unsafe impl plain::Plain for Mcfg {} /// The "Memory Mapped Enhanced Configuration Space Base Address Allocation Structure" (yes, it's /// called that). -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct PcieAlloc { pub base_addr: u64, diff --git a/pcid/src/driver_interface/msi.rs b/pcid/src/driver_interface/msi.rs index 3168c61cda..822ac0976c 100644 --- a/pcid/src/driver_interface/msi.rs +++ b/pcid/src/driver_interface/msi.rs @@ -78,7 +78,7 @@ impl MsixInfo { } } -#[repr(packed)] +#[repr(C, packed)] pub struct MsixTableEntry { pub addr_lo: Mmio, pub addr_hi: Mmio, diff --git a/storage/ahcid/src/ahci/fis.rs b/storage/ahcid/src/ahci/fis.rs index 5c1f69b78d..56dd45b814 100644 --- a/storage/ahcid/src/ahci/fis.rs +++ b/storage/ahcid/src/ahci/fis.rs @@ -20,7 +20,7 @@ pub enum FisType { DevBits = 0xA1, } -#[repr(packed)] +#[repr(C, packed)] pub struct FisRegH2D { // DWORD 0 pub fis_type: Mmio, // FIS_TYPE_REG_H2D @@ -52,7 +52,7 @@ pub struct FisRegH2D { pub rsv1: [Mmio; 4], // Reserved } -#[repr(packed)] +#[repr(C, packed)] pub struct FisRegD2H { // DWORD 0 pub fis_type: Mmio, // FIS_TYPE_REG_D2H @@ -83,7 +83,7 @@ pub struct FisRegD2H { pub rsv4: [Mmio; 4], // Reserved } -#[repr(packed)] +#[repr(C, packed)] pub struct FisData { // DWORD 0 pub fis_type: Mmio, // FIS_TYPE_DATA @@ -96,7 +96,7 @@ pub struct FisData { pub data: [Mmio; 252], // Payload } -#[repr(packed)] +#[repr(C, packed)] pub struct FisPioSetup { // DWORD 0 pub fis_type: Mmio, // FIS_TYPE_PIO_SETUP @@ -129,7 +129,7 @@ pub struct FisPioSetup { pub rsv4: [Mmio; 2], // Reserved } -#[repr(packed)] +#[repr(C, packed)] pub struct FisDmaSetup { // DWORD 0 pub fis_type: Mmio, // FIS_TYPE_DMA_SETUP diff --git a/storage/ahcid/src/ahci/hba.rs b/storage/ahcid/src/ahci/hba.rs index 00e80f37e4..0a4c71757e 100644 --- a/storage/ahcid/src/ahci/hba.rs +++ b/storage/ahcid/src/ahci/hba.rs @@ -39,7 +39,7 @@ pub enum HbaPortType { SEMB, } -#[repr(packed)] +#[repr(C, packed)] pub struct HbaPort { pub clb: [Mmio; 2], // 0x00, command list base address, 1K-byte aligned pub fb: [Mmio; 2], // 0x08, FIS base address, 256-byte aligned @@ -441,7 +441,7 @@ impl HbaPort { } } -#[repr(packed)] +#[repr(C, packed)] pub struct HbaMem { pub cap: Mmio, // 0x00, Host capability pub ghc: Mmio, // 0x04, Global host control @@ -482,7 +482,7 @@ impl HbaMem { } } -#[repr(packed)] +#[repr(C, packed)] pub struct HbaPrdtEntry { dba_low: Mmio, // Data base address (low dba_high: Mmio, // Data base address (high) @@ -490,7 +490,7 @@ pub struct HbaPrdtEntry { dbc: Mmio, // Byte count, 4M max, interrupt = 1 } -#[repr(packed)] +#[repr(C, packed)] pub struct HbaCmdTable { // 0x00 cfis: [Mmio; 64], // Command FIS @@ -507,7 +507,7 @@ pub struct HbaCmdTable { const CMD_TBL_SIZE: usize = 256 * 4096; const PRDT_ENTRIES: usize = (CMD_TBL_SIZE - 128) / size_of::(); -#[repr(packed)] +#[repr(C, packed)] pub struct HbaCmdHeader { // DW0 cfl: Mmio, /* Command FIS length in DWORDS, 2 ~ 16, atapi: 4, write - host to device: 2, prefetchable: 1 */ diff --git a/storage/bcm2835-sdhcid/src/sd/mod.rs b/storage/bcm2835-sdhcid/src/sd/mod.rs index 00d967725c..8c718ba105 100644 --- a/storage/bcm2835-sdhcid/src/sd/mod.rs +++ b/storage/bcm2835-sdhcid/src/sd/mod.rs @@ -115,7 +115,7 @@ const SCR_SUPP_SET_BLKCNT: u32 = 0x0200_0000; //added by bztsrc driver const SCR_SUPP_CCS: u32 = 0x0000_0001; -#[repr(packed)] +#[repr(C, packed)] pub struct SdHostCtrlRegs { //LSB diff --git a/storage/ided/src/ide.rs b/storage/ided/src/ide.rs index c63cedfc38..ad2b771446 100644 --- a/storage/ided/src/ide.rs +++ b/storage/ided/src/ide.rs @@ -30,7 +30,7 @@ pub enum AtaCommand { Identify = 0xEC, } -#[repr(packed)] +#[repr(C, packed)] struct PrdtEntry { phys: u32, size: u16, diff --git a/storage/nvmed/src/nvme/identify.rs b/storage/nvmed/src/nvme/identify.rs index af82008f17..93f221039d 100644 --- a/storage/nvmed/src/nvme/identify.rs +++ b/storage/nvmed/src/nvme/identify.rs @@ -4,7 +4,7 @@ use common::dma::Dma; /// See NVME spec section 5.15.2.2. #[derive(Clone, Copy)] -#[repr(packed)] +#[repr(C, packed)] pub struct IdentifyControllerData { /// PCI vendor ID, always the same as in the PCI function header. pub vid: u16, @@ -22,7 +22,7 @@ pub struct IdentifyControllerData { /// See NVME spec section 5.15.2.1. #[derive(Clone, Copy)] -#[repr(packed)] +#[repr(C, packed)] pub struct IdentifyNamespaceData { pub nsze: u64, pub ncap: u64, @@ -96,7 +96,7 @@ impl IdentifyNamespaceData { } #[derive(Clone, Copy)] -#[repr(packed)] +#[repr(C, packed)] pub struct LbaFormat(pub u32); #[repr(u8)] diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 17d8cd039c..127dd5ae9f 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -137,7 +137,7 @@ pub struct MappedMsixRegs { pub table: &'static mut [MsixTableEntry], } -#[repr(packed)] +#[repr(C, packed)] pub struct NvmeRegs { /// Controller Capabilities cap_low: Mmio, diff --git a/storage/nvmed/src/nvme/queues.rs b/storage/nvmed/src/nvme/queues.rs index 836ec89a6a..133c42effe 100644 --- a/storage/nvmed/src/nvme/queues.rs +++ b/storage/nvmed/src/nvme/queues.rs @@ -5,7 +5,7 @@ use common::dma::Dma; /// A submission queue entry. #[derive(Clone, Copy, Debug, Default)] -#[repr(packed)] +#[repr(C, packed)] pub struct NvmeCmd { /// Opcode pub opcode: u8, @@ -37,7 +37,7 @@ pub struct NvmeCmd { /// A completion queue entry. #[derive(Clone, Copy, Debug)] -#[repr(packed)] +#[repr(C, packed)] pub struct NvmeComp { pub command_specific: u32, pub _rsvd: u32, diff --git a/storage/usbscsid/src/protocol/bot.rs b/storage/usbscsid/src/protocol/bot.rs index 6f1f847db2..b751d51ad6 100644 --- a/storage/usbscsid/src/protocol/bot.rs +++ b/storage/usbscsid/src/protocol/bot.rs @@ -15,7 +15,7 @@ pub const CBW_SIGNATURE: u32 = 0x43425355; pub const CBW_FLAGS_DIRECTION_BIT: u8 = 1 << CBW_FLAGS_DIRECTION_SHIFT; pub const CBW_FLAGS_DIRECTION_SHIFT: u8 = 7; -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct CommandBlockWrapper { pub signature: u32, @@ -66,7 +66,7 @@ pub enum CswStatus { // the rest are reserved } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct CommandStatusWrapper { pub signature: u32, diff --git a/storage/usbscsid/src/scsi/cmds.rs b/storage/usbscsid/src/scsi/cmds.rs index 3868f57eae..a9141e8c0e 100644 --- a/storage/usbscsid/src/scsi/cmds.rs +++ b/storage/usbscsid/src/scsi/cmds.rs @@ -2,7 +2,7 @@ use super::opcodes::Opcode; use std::convert::TryInto; use std::{fmt, mem, slice}; -#[repr(packed)] +#[repr(C, packed)] pub struct Inquiry { pub opcode: u8, /// bits 7:2 are reserved, bit 1 (CMDDT) is obsolete, bit 0 is EVPD @@ -26,7 +26,7 @@ impl Inquiry { } } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct StandardInquiryData { /// Peripheral device type (bits 4:0), and peripheral device qualifier (bits 7:5). @@ -78,7 +78,7 @@ pub enum InquiryVersion { Spc5, } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct RequestSense { pub opcode: u8, @@ -103,7 +103,7 @@ impl RequestSense { } } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct FixedFormatSenseData { pub a: u8, @@ -165,7 +165,7 @@ impl Default for SenseKey { pub const ADD_SENSE_CODE05_INVAL_CDB_FIELD: u8 = 0x24; -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct Read16 { pub opcode: u8, @@ -193,7 +193,7 @@ impl Read16 { } } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct Write16 { pub opcode: u8, @@ -219,7 +219,7 @@ impl Write16 { } } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct ModeSense6 { pub opcode: u8, @@ -251,7 +251,7 @@ impl ModeSense6 { } } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct ModeSense10 { pub opcode: u8, @@ -305,7 +305,7 @@ pub enum ModePageControl { SavedValue, } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy)] pub struct ShortLbaModeParamBlkDesc { pub block_count: u32, @@ -336,7 +336,7 @@ const fn u24_be_to_u32(u24: [u8; 3]) -> u32 { } /// From SPC-3, when LONGLBA is not set, and the peripheral device type of the INQUIRY data indicates that the device is not a direct access device. Otherwise, `ShortLbaModeParamBlkDesc` is used instead. -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy)] pub struct GeneralModeParamBlkDesc { pub density_code: u8, @@ -365,7 +365,7 @@ impl fmt::Debug for GeneralModeParamBlkDesc { } } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct LongLbaModeParamBlkDesc { pub block_count: u64, @@ -383,7 +383,7 @@ impl LongLbaModeParamBlkDesc { } } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct ModeParamHeader6 { pub mode_data_len: u8, @@ -393,7 +393,7 @@ pub struct ModeParamHeader6 { } unsafe impl plain::Plain for ModeParamHeader6 {} -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct ModeParamHeader10 { pub mode_data_len: u16, @@ -416,7 +416,7 @@ impl ModeParamHeader10 { } } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct ReadCapacity10 { pub opcode: u8, @@ -440,7 +440,7 @@ impl ReadCapacity10 { } // TODO: ReadCapacity16 -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct ReadCapacity10ParamData { pub max_lba: u32, @@ -457,7 +457,7 @@ impl ReadCapacity10ParamData { } } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct RwErrorRecoveryPage { pub a: u8, @@ -470,7 +470,7 @@ pub struct RwErrorRecoveryPage { } unsafe impl plain::Plain for RwErrorRecoveryPage {} -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct CachingModePage { pub a: u8, diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index f944ec3ece..63935cf0a8 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -22,7 +22,7 @@ const VBOX_EVENT_DISPLAY: u32 = 1 << 2; const VBOX_EVENT_MOUSE: u32 = 1 << 9; /// VBox VMMDevMemory -#[repr(packed)] +#[repr(C, packed)] struct VboxVmmDev { size: Mmio, version: Mmio, @@ -31,7 +31,7 @@ struct VboxVmmDev { } /// VBox Guest packet header -#[repr(packed)] +#[repr(C, packed)] struct VboxHeader { /// Size of the entire packet (including this header) size: Mmio, @@ -46,7 +46,7 @@ struct VboxHeader { } /// VBox Get Mouse -#[repr(packed)] +#[repr(C, packed)] struct VboxGetMouse { header: VboxHeader, features: Mmio, @@ -71,7 +71,7 @@ impl VboxGetMouse { } /// VBox Set Mouse -#[repr(packed)] +#[repr(C, packed)] struct VboxSetMouse { header: VboxHeader, features: Mmio, @@ -96,7 +96,7 @@ impl VboxSetMouse { } /// VBox Acknowledge Events packet -#[repr(packed)] +#[repr(C, packed)] struct VboxAckEvents { header: VboxHeader, events: Mmio, @@ -119,7 +119,7 @@ impl VboxAckEvents { } /// VBox Guest Capabilities packet -#[repr(packed)] +#[repr(C, packed)] struct VboxGuestCaps { header: VboxHeader, caps: Mmio, @@ -167,7 +167,7 @@ impl VboxDisplayChange { } /// VBox Guest Info packet (legacy) -#[repr(packed)] +#[repr(C, packed)] struct VboxGuestInfo { header: VboxHeader, version: Mmio, diff --git a/xhcid/src/usb/bos.rs b/xhcid/src/usb/bos.rs index 7e843b485a..f6a095712d 100644 --- a/xhcid/src/usb/bos.rs +++ b/xhcid/src/usb/bos.rs @@ -1,6 +1,6 @@ use std::slice; -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct BosDescriptor { pub len: u8, @@ -11,7 +11,7 @@ pub struct BosDescriptor { unsafe impl plain::Plain for BosDescriptor {} -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct BosDevDescriptorBase { pub len: u8, @@ -21,7 +21,7 @@ pub struct BosDevDescriptorBase { unsafe impl plain::Plain for BosDevDescriptorBase {} -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct BosSuperSpeedDesc { pub len: u8, @@ -34,7 +34,7 @@ pub struct BosSuperSpeedDesc { pub u1_dev_exit_lat: u8, pub u2_dev_exit_lat: u16, } -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct BosSuperSpeedPlusDesc { pub len: u8, @@ -48,7 +48,7 @@ pub struct BosSuperSpeedPlusDesc { unsafe impl plain::Plain for BosSuperSpeedPlusDesc {} -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct BosUsb2ExtDesc { pub len: u8, diff --git a/xhcid/src/usb/config.rs b/xhcid/src/usb/config.rs index 11f5e4cbbd..5d4a23bca7 100644 --- a/xhcid/src/usb/config.rs +++ b/xhcid/src/usb/config.rs @@ -1,4 +1,4 @@ -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct ConfigDescriptor { pub length: u8, @@ -13,7 +13,7 @@ pub struct ConfigDescriptor { unsafe impl plain::Plain for ConfigDescriptor {} -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct OtherSpeedConfig { pub length: u8, diff --git a/xhcid/src/usb/device.rs b/xhcid/src/usb/device.rs index 59a09f1f98..accac1c316 100644 --- a/xhcid/src/usb/device.rs +++ b/xhcid/src/usb/device.rs @@ -10,7 +10,7 @@ /// A given device will only have one device descriptor. /// /// USB32 Table 9-11 describes the USB packet offsets of the fields described by this structure. -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct DeviceDescriptor { /// The length of this descriptor in bytes. @@ -101,7 +101,7 @@ impl DeviceDescriptor { /// at a later point. /// /// See [DeviceDescriptor] -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct DeviceDescriptor8Byte { /// See [DeviceDescriptor] @@ -147,7 +147,7 @@ impl DeviceDescriptor8Byte { /// See USB2 section 9.6.2 /// /// The packet offsets are described in USB2 Table 9-9 -#[repr(packed)] +#[repr(C, packed)] pub struct DeviceQualifier { /// The size of the descriptor. /// diff --git a/xhcid/src/usb/endpoint.rs b/xhcid/src/usb/endpoint.rs index c8f8163c62..e0f3510a7d 100644 --- a/xhcid/src/usb/endpoint.rs +++ b/xhcid/src/usb/endpoint.rs @@ -11,7 +11,7 @@ use plain::Plain; /// See USB32 9.6.6 /// /// The offsets for the fields in the packet are described in USB32 Table 9-26 -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct EndpointDescriptor { pub length: u8, @@ -48,7 +48,7 @@ impl EndpointDescriptor { unsafe impl Plain for EndpointDescriptor {} -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct SuperSpeedCompanionDescriptor { pub length: u8, @@ -59,7 +59,7 @@ pub struct SuperSpeedCompanionDescriptor { } unsafe impl Plain for SuperSpeedCompanionDescriptor {} -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct SuperSpeedPlusIsochCmpDescriptor { pub length: u8, @@ -69,7 +69,7 @@ pub struct SuperSpeedPlusIsochCmpDescriptor { } unsafe impl Plain for SuperSpeedPlusIsochCmpDescriptor {} -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct HidDescriptor { pub length: u8, diff --git a/xhcid/src/usb/hub.rs b/xhcid/src/usb/hub.rs index 99022ec7a7..f83d734fe6 100644 --- a/xhcid/src/usb/hub.rs +++ b/xhcid/src/usb/hub.rs @@ -1,4 +1,4 @@ -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug)] pub struct HubDescriptor { pub length: u8, diff --git a/xhcid/src/usb/interface.rs b/xhcid/src/usb/interface.rs index 1030993bb8..4b60e06cf0 100644 --- a/xhcid/src/usb/interface.rs +++ b/xhcid/src/usb/interface.rs @@ -1,7 +1,7 @@ use plain::Plain; /// -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct InterfaceDescriptor { pub length: u8, diff --git a/xhcid/src/usb/setup.rs b/xhcid/src/usb/setup.rs index aa430e2363..dc315ac502 100644 --- a/xhcid/src/usb/setup.rs +++ b/xhcid/src/usb/setup.rs @@ -1,7 +1,7 @@ use super::DescriptorKind; use crate::driver_interface::*; -#[repr(packed)] +#[repr(C, packed)] #[derive(Clone, Copy, Debug, Default)] pub struct Setup { pub kind: u8, diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index 7dfd670448..cc45611c7d 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -10,7 +10,7 @@ use common::io::{Io, Mmio}; /// /// See XHCI Section 5.3. Table 5-9 describes the offsets of the registers /// in memory. -#[repr(packed)] +#[repr(C, packed)] pub struct CapabilityRegs { /// The length of the Capability Registers data structure in XHCI memory. /// diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index a866886800..497a39dafe 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -10,7 +10,7 @@ use common::dma::Dma; use super::ring::Ring; use super::Xhci; -#[repr(packed)] +#[repr(C, packed)] pub struct SlotContext { pub a: Mmio, pub b: Mmio, @@ -36,7 +36,7 @@ pub enum SlotState { Configured = 3, } -#[repr(packed)] +#[repr(C, packed)] pub struct EndpointContext { pub a: Mmio, pub b: Mmio, @@ -48,13 +48,13 @@ pub struct EndpointContext { pub const ENDPOINT_CONTEXT_STATUS_MASK: u32 = 0x7; -#[repr(packed)] +#[repr(C, packed)] pub struct DeviceContext { pub slot: SlotContext, pub endpoints: [EndpointContext; 31], } -#[repr(packed)] +#[repr(C, packed)] pub struct InputContext { pub drop_context: Mmio, pub add_context: Mmio, @@ -106,7 +106,7 @@ impl DeviceContextList { } } -#[repr(packed)] +#[repr(C, packed)] pub struct StreamContext { trl: Mmio, trh: Mmio, @@ -165,7 +165,7 @@ impl StreamContextArray { } } -#[repr(packed)] +#[repr(C, packed)] pub struct ScratchpadBufferEntry { pub value_low: Mmio, pub value_high: Mmio, diff --git a/xhcid/src/xhci/doorbell.rs b/xhcid/src/xhci/doorbell.rs index 58c6cba36f..f65db206aa 100644 --- a/xhcid/src/xhci/doorbell.rs +++ b/xhcid/src/xhci/doorbell.rs @@ -1,6 +1,6 @@ use common::io::{Io, Mmio}; -#[repr(packed)] +#[repr(C, packed)] pub struct Doorbell(Mmio); impl Doorbell { diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index 13bdeff7d1..47c370ccff 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -7,7 +7,7 @@ use super::ring::Ring; use super::trb::Trb; use super::Xhci; -#[repr(packed)] +#[repr(C, packed)] pub struct EventRingSte { pub address_low: Mmio, pub address_high: Mmio, diff --git a/xhcid/src/xhci/extended.rs b/xhcid/src/xhci/extended.rs index 2ef900cf41..00ab6f2f1b 100644 --- a/xhcid/src/xhci/extended.rs +++ b/xhcid/src/xhci/extended.rs @@ -52,7 +52,7 @@ pub enum CapabilityId { // bits 192-255 are vendor-defined } -#[repr(packed)] +#[repr(C, packed)] pub struct SupportedProtoCap { a: Mmio, b: Mmio, @@ -61,7 +61,7 @@ pub struct SupportedProtoCap { protocol_speeds: [u8; 0], } -#[repr(packed)] +#[repr(C, packed)] pub struct ProtocolSpeed { a: Mmio, } diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index 60dde7f7ae..6562a48760 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -7,7 +7,7 @@ use common::io::{Io, Mmio}; /// "length" field of the [CapabilityRegs] /// /// See XHCI section 5.4. Table 5-18 describes the offset of these registers in memory. -#[repr(packed)] +#[repr(C, packed)] pub struct OperationalRegs { /// The USB Command Register (USBCMD) /// diff --git a/xhcid/src/xhci/port.rs b/xhcid/src/xhci/port.rs index 64840c438a..cf1066f955 100644 --- a/xhcid/src/xhci/port.rs +++ b/xhcid/src/xhci/port.rs @@ -27,7 +27,7 @@ bitflags! { } } -#[repr(packed)] +#[repr(C, packed)] pub struct Port { pub portsc: Mmio, pub portpmsc: Mmio, diff --git a/xhcid/src/xhci/runtime.rs b/xhcid/src/xhci/runtime.rs index deeb96f401..55d54d4472 100644 --- a/xhcid/src/xhci/runtime.rs +++ b/xhcid/src/xhci/runtime.rs @@ -1,6 +1,6 @@ use common::io::Mmio; -#[repr(packed)] +#[repr(C, packed)] pub struct Interrupter { pub iman: Mmio, pub imod: Mmio, @@ -12,7 +12,7 @@ pub struct Interrupter { pub erdp_high: Mmio, } -#[repr(packed)] +#[repr(C, packed)] pub struct RuntimeRegs { pub mfindex: Mmio, _rsvd: [Mmio; 7], diff --git a/xhcid/src/xhci/trb.rs b/xhcid/src/xhci/trb.rs index d8e58417c0..e0e5dc79fe 100644 --- a/xhcid/src/xhci/trb.rs +++ b/xhcid/src/xhci/trb.rs @@ -108,7 +108,7 @@ pub enum TransferKind { In, } -#[repr(packed)] +#[repr(C, packed)] pub struct Trb { pub data_low: Mmio, pub data_high: Mmio, From 4b61e7bc866223e9da942d052682aeb69d9500d8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 16:27:27 +0100 Subject: [PATCH 1080/1301] graphics/fbbootlogd: Inline TextScreen into FbbootlogScheme --- graphics/fbbootlogd/src/main.rs | 1 - graphics/fbbootlogd/src/scheme.rs | 28 +++++++++++++++------ graphics/fbbootlogd/src/text.rs | 41 ------------------------------- 3 files changed, 20 insertions(+), 50 deletions(-) delete mode 100644 graphics/fbbootlogd/src/text.rs diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index cd4d44ff07..ca1c3863df 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -16,7 +16,6 @@ use crate::scheme::FbbootlogScheme; mod display; mod scheme; -mod text; fn main() { redox_daemon::Daemon::new(|daemon| inner(daemon)).expect("failed to create daemon"); diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 7e37aa8cb6..1e9f408ef8 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -1,10 +1,9 @@ -use std::collections::BTreeMap; +use std::collections::{BTreeMap, VecDeque}; use redox_scheme::Scheme; use syscall::{Error, EventFlags, Result, EBADF, EINVAL, ENOENT}; use crate::display::Display; -use crate::text::TextScreen; pub struct Handle { pub events: EventFlags, @@ -12,18 +11,17 @@ pub struct Handle { } pub struct FbbootlogScheme { - pub screen: TextScreen, + display: Display, + text_screen: console_draw::TextScreen, next_id: usize, pub handles: BTreeMap, } impl FbbootlogScheme { pub fn new() -> FbbootlogScheme { - let display = Display::open_first_vt().expect("Failed to open display for vt"); - let screen = TextScreen::new(display); - FbbootlogScheme { - screen, + display: Display::open_first_vt().expect("Failed to open display for vt"), + text_screen: console_draw::TextScreen::new(), next_id: 0, handles: BTreeMap::new(), } @@ -94,7 +92,21 @@ impl Scheme for FbbootlogScheme { fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - self.screen.write(buf) + let mut map = self.display.map.lock().unwrap(); + let damage = self.text_screen.write( + &mut console_draw::DisplayMap { + offscreen: map.inner.ptr_mut(), + width: map.inner.width(), + height: map.inner.height(), + }, + buf, + &mut VecDeque::new(), + ); + drop(map); + + self.display.sync_rects(damage); + + Ok(buf.len()) } fn close(&mut self, id: usize) -> Result { diff --git a/graphics/fbbootlogd/src/text.rs b/graphics/fbbootlogd/src/text.rs deleted file mode 100644 index 15e34e0584..0000000000 --- a/graphics/fbbootlogd/src/text.rs +++ /dev/null @@ -1,41 +0,0 @@ -extern crate ransid; - -use std::collections::VecDeque; - -use syscall::error::*; - -use crate::display::Display; - -pub struct TextScreen { - pub display: Display, - inner: console_draw::TextScreen, -} - -impl TextScreen { - pub fn new(display: Display) -> TextScreen { - TextScreen { - display, - inner: console_draw::TextScreen::new(), - } - } -} - -impl TextScreen { - pub fn write(&mut self, buf: &[u8]) -> Result { - let mut map = self.display.map.lock().unwrap(); - let damage = self.inner.write( - &mut console_draw::DisplayMap { - offscreen: map.inner.ptr_mut(), - width: map.inner.width(), - height: map.inner.height(), - }, - buf, - &mut VecDeque::new(), - ); - drop(map); - - self.display.sync_rects(damage); - - Ok(buf.len()) - } -} From 31450e577047d93fee6eca6c7160b00fccf1b09d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 16:32:56 +0100 Subject: [PATCH 1081/1301] graphics/fbbootlogd: Get rid of fevent and tracking handles Fbbootlogd doesn't do non-blocking operations, so fevent isn't needed. And the kernel shouldn't pass closed handles to us and even if it does due to a bug, it is harmless to silently ignore the fact that the handle was closed. --- graphics/fbbootlogd/src/scheme.rs | 56 +++++-------------------------- 1 file changed, 9 insertions(+), 47 deletions(-) diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 1e9f408ef8..3447a91466 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -1,20 +1,13 @@ -use std::collections::{BTreeMap, VecDeque}; +use std::collections::VecDeque; use redox_scheme::Scheme; -use syscall::{Error, EventFlags, Result, EBADF, EINVAL, ENOENT}; +use syscall::{Error, Result, EINVAL, ENOENT}; use crate::display::Display; -pub struct Handle { - pub events: EventFlags, - pub notified_read: bool, -} - pub struct FbbootlogScheme { display: Display, text_screen: console_draw::TextScreen, - next_id: usize, - pub handles: BTreeMap, } impl FbbootlogScheme { @@ -22,8 +15,6 @@ impl FbbootlogScheme { FbbootlogScheme { display: Display::open_first_vt().expect("Failed to open display for vt"), text_screen: console_draw::TextScreen::new(), - next_id: 0, - handles: BTreeMap::new(), } } } @@ -34,32 +25,10 @@ impl Scheme for FbbootlogScheme { return Err(Error::new(ENOENT)); } - let id = self.next_id; - self.next_id += 1; - - self.handles.insert( - id, - Handle { - events: EventFlags::empty(), - notified_read: false, - }, - ); - - Ok(id) + Ok(0) } - fn fevent(&mut self, id: usize, flags: syscall::EventFlags) -> Result { - let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; - - handle.notified_read = false; - - handle.events = flags; - Ok(syscall::EventFlags::empty()) - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - + fn fpath(&mut self, _id: usize, buf: &mut [u8]) -> Result { let path = b"fbbootlog:"; let mut i = 0; @@ -71,27 +40,21 @@ impl Scheme for FbbootlogScheme { Ok(i) } - fn fsync(&mut self, id: usize) -> Result { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - return Ok(0); + fn fsync(&mut self, _id: usize) -> Result { + Ok(0) } fn read( &mut self, - id: usize, + _id: usize, _buf: &mut [u8], _offset: u64, _fcntl_flags: u32, ) -> Result { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Err(Error::new(EINVAL)) } - fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - + fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { let mut map = self.display.map.lock().unwrap(); let damage = self.text_screen.write( &mut console_draw::DisplayMap { @@ -109,8 +72,7 @@ impl Scheme for FbbootlogScheme { Ok(buf.len()) } - fn close(&mut self, id: usize) -> Result { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; + fn close(&mut self, _id: usize) -> Result { Ok(0) } } From 5b45f06cf366c822e6eb2fb2dd3ebb04cb5b3685 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 17:58:20 +0100 Subject: [PATCH 1082/1301] Extract enable_function out of handle_parsed_header This is the only part that actually modifies the PCI configuration. In the future we will want to delay enabling a PCI device until it is actually going to be used while still reading metadata about the PCI device before that point. --- pcid/src/main.rs | 132 +++++++++++++++++++++++++---------------------- 1 file changed, 71 insertions(+), 61 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index c9e3d7f423..6f08c4ff1d 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -106,62 +106,7 @@ fn handle_parsed_header( info!(" BAR{}", string); } - // Enable bus mastering, memory space, and I/O space - endpoint_header.update_command(&state.pcie, |cmd| { - cmd | CommandRegister::BUS_MASTER_ENABLE - | CommandRegister::MEMORY_ENABLE - | CommandRegister::IO_ENABLE - }); - - // Set IRQ line to 9 if not set - let mut irq = 0xFF; - let mut interrupt_pin = 0xFF; - - endpoint_header.update_interrupt(&state.pcie, |(pin, mut line)| { - if line == 0xFF { - line = 9; - } - irq = line; - interrupt_pin = pin; - (pin, line) - }); - - let legacy_interrupt_enabled = match interrupt_pin { - 0 => false, - 1 | 2 | 3 | 4 => true, - - other => { - warn!("pcid: invalid interrupt pin: {}", other); - false - } - }; - - let mut phandled: Option<(u32, [u32; 3], usize)> = None; - if legacy_interrupt_enabled { - let pci_address = endpoint_header.header().address(); - let dt_address = ((pci_address.bus() as u32) << 16) - | ((pci_address.device() as u32) << 11) - | ((pci_address.function() as u32) << 8); - let addr = [ - dt_address & state.pcie.interrupt_map_mask[0], - 0u32, - 0u32, - interrupt_pin as u32 & state.pcie.interrupt_map_mask[3], - ]; - let mapping = state - .pcie - .interrupt_map - .iter() - .find(|x| x.addr == addr[0..3] && x.interrupt == addr[3]); - if let Some(mapping) = mapping { - phandled = Some(( - mapping.parent_phandle, - mapping.parent_interrupt, - mapping.parent_interrupt_cells, - )); - debug!("found mapping: addr={:?} => {:?}", addr, phandled); - } - } + let legacy_interrupt_line = enable_function(&state, &mut endpoint_header); let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { endpoint_header @@ -182,11 +127,7 @@ fn handle_parsed_header( let func = pcid_interface::PciFunction { bars, addr: endpoint_header.header().address(), - legacy_interrupt_line: if legacy_interrupt_enabled { - Some(LegacyInterruptLine { irq, phandled }) - } else { - None - }, + legacy_interrupt_line, full_device_id: full_device_id.clone(), }; @@ -194,6 +135,75 @@ fn handle_parsed_header( } } +fn enable_function( + state: &Arc, + endpoint_header: &mut EndpointHeader, +) -> Option { + // Enable bus mastering, memory space, and I/O space + endpoint_header.update_command(&state.pcie, |cmd| { + cmd | CommandRegister::BUS_MASTER_ENABLE + | CommandRegister::MEMORY_ENABLE + | CommandRegister::IO_ENABLE + }); + + // Set IRQ line to 9 if not set + let mut irq = 0xFF; + let mut interrupt_pin = 0xFF; + + endpoint_header.update_interrupt(&state.pcie, |(pin, mut line)| { + if line == 0xFF { + line = 9; + } + irq = line; + interrupt_pin = pin; + (pin, line) + }); + + let legacy_interrupt_enabled = match interrupt_pin { + 0 => false, + 1 | 2 | 3 | 4 => true, + + other => { + warn!("pcid: invalid interrupt pin: {}", other); + false + } + }; + + if legacy_interrupt_enabled { + let pci_address = endpoint_header.header().address(); + let dt_address = ((pci_address.bus() as u32) << 16) + | ((pci_address.device() as u32) << 11) + | ((pci_address.function() as u32) << 8); + let addr = [ + dt_address & state.pcie.interrupt_map_mask[0], + 0u32, + 0u32, + interrupt_pin as u32 & state.pcie.interrupt_map_mask[3], + ]; + let mapping = state + .pcie + .interrupt_map + .iter() + .find(|x| x.addr == addr[0..3] && x.interrupt == addr[3]); + let phandled = if let Some(mapping) = mapping { + Some(( + mapping.parent_phandle, + mapping.parent_interrupt, + mapping.parent_interrupt_cells, + )) + } else { + None + }; + if mapping.is_some() { + debug!("found mapping: addr={:?} => {:?}", addr, phandled); + } + + Some(LegacyInterruptLine { irq, phandled }) + } else { + None + } +} + fn main() { let args = Args::from_args(); From cd5604a0543581395027d800980d1b43542e6173 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 18:56:14 +0100 Subject: [PATCH 1083/1301] Move config from pcid to pcid_interface This will allow serializing/deserializing to be shared across programs. For pcid-spawner will need to parse the config files and if we want to embed config files into the driver executables at some point it may also be useful. --- pcid/src/{ => driver_interface}/config.rs | 2 +- pcid/src/driver_interface/mod.rs | 1 + pcid/src/main.rs | 4 +--- 3 files changed, 3 insertions(+), 4 deletions(-) rename pcid/src/{ => driver_interface}/config.rs (98%) diff --git a/pcid/src/config.rs b/pcid/src/driver_interface/config.rs similarity index 98% rename from pcid/src/config.rs rename to pcid/src/driver_interface/config.rs index c9610f667c..8278f33c3c 100644 --- a/pcid/src/config.rs +++ b/pcid/src/driver_interface/config.rs @@ -3,7 +3,7 @@ use std::ops::Range; use serde::Deserialize; -use pcid_interface::FullDeviceId; +use crate::driver_interface::FullDeviceId; #[derive(Clone, Debug, Default, Deserialize)] pub struct Config { diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 5d1054a23f..2cf16e8bba 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -16,6 +16,7 @@ pub use pci_types::PciAddress; mod bar; pub mod cap; +pub mod config; mod id; pub mod irq_helpers; pub mod msi; diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 6f08c4ff1d..edc48df6a9 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -15,11 +15,9 @@ use pci_types::{ use structopt::StructOpt; use crate::cfg_access::Pcie; -use crate::config::Config; -use pcid_interface::{FullDeviceId, LegacyInterruptLine, PciBar}; +use pcid_interface::{config::Config, FullDeviceId, LegacyInterruptLine, PciBar}; mod cfg_access; -mod config; mod driver_handler; #[derive(StructOpt)] From cffa5308a175c70fa117091db789b56bb201fc53 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 19:10:09 +0100 Subject: [PATCH 1084/1301] Use pico-args instead of structopt for pcid It is much lighter weight. Co-Authored-By: 4lDO2 <4lDO2@protonmail.com> --- Cargo.lock | 79 +++++------------------------------------------- pcid/Cargo.toml | 2 +- pcid/src/main.rs | 26 +++------------- 3 files changed, 14 insertions(+), 93 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 57abb4719d..4c1f1c7833 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "ac97d" @@ -620,15 +620,6 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "hermit-abi" version = "0.1.19" @@ -974,10 +965,10 @@ dependencies = [ "libredox", "log", "pci_types", + "pico-args", "plain", "redox-daemon", "serde", - "structopt", "thiserror", "toml 0.5.11", ] @@ -992,6 +983,12 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + [[package]] name = "pin-project-lite" version = "0.2.15" @@ -1010,30 +1007,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" version = "1.0.89" @@ -1440,30 +1413,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -[[package]] -name = "structopt" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c6b5c64445ba8094a6ab0c3cd2ad323e07171012d9c98b0b15651daf1787a10" -dependencies = [ - "clap", - "lazy_static", - "structopt-derive", -] - -[[package]] -name = "structopt-derive" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0" -dependencies = [ - "heck", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "syn" version = "1.0.109" @@ -1582,12 +1531,6 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - [[package]] name = "unicode-width" version = "0.1.14" @@ -1680,12 +1623,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - [[package]] name = "vesad" version = "0.1.0" diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 6acfa7774a..b78a994584 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -17,10 +17,10 @@ fdt = "0.1.5" libc = "0.2" log = "0.4" pci_types = "0.10" +pico-args = { version = "0.5", features = ["combined-flags"] } plain = "0.2" redox-daemon = "0.1" serde = { version = "1", features = ["derive"] } -structopt = { version = "0.3", default-features = false } thiserror = "1" toml = "0.5" diff --git a/pcid/src/main.rs b/pcid/src/main.rs index edc48df6a9..c432539fda 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -4,6 +4,7 @@ use std::fs::{metadata, read_dir, File}; use std::io::prelude::*; +use std::path::PathBuf; use std::sync::{Arc, Mutex}; use std::thread; @@ -12,7 +13,6 @@ use pci_types::{ Bar as TyBar, CommandRegister, EndpointHeader, HeaderType, PciAddress, PciHeader as TyPciHeader, PciPciBridgeHeader, }; -use structopt::StructOpt; use crate::cfg_access::Pcie; use pcid_interface::{config::Config, FullDeviceId, LegacyInterruptLine, PciBar}; @@ -20,23 +20,6 @@ use pcid_interface::{config::Config, FullDeviceId, LegacyInterruptLine, PciBar}; mod cfg_access; mod driver_handler; -#[derive(StructOpt)] -#[structopt(about)] -struct Args { - #[structopt( - short, - long, - help = "Increase logging level once for each arg.", - parse(from_occurrences) - )] - verbose: u8, - - #[structopt( - help = "A path to a pcid config file or a directory that contains pcid config files." - )] - config_path: Option, -} - pub struct State { threads: Mutex>>, pcie: Pcie, @@ -203,11 +186,11 @@ fn enable_function( } fn main() { - let args = Args::from_args(); + let mut args = pico_args::Arguments::from_env(); let mut config = Config::default(); - if let Some(config_path) = args.config_path { + if let Ok(config_path) = args.free_from_str::() { if metadata(&config_path).unwrap().is_file() { if let Ok(mut config_file) = File::open(&config_path) { let mut config_data = String::new(); @@ -232,7 +215,8 @@ fn main() { } } - let log_level = match args.verbose { + let verbosity = (0..).find(|_| !args.contains("-v")).unwrap_or(0); + let log_level = match verbosity { 0 => log::LevelFilter::Info, 1 => log::LevelFilter::Debug, _ => log::LevelFilter::Trace, From 8f1549e28412a7b26984c7f17d27fa021f0db711 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 22 Feb 2025 19:47:52 +0100 Subject: [PATCH 1085/1301] Introduce a pci scheme and move driver spawning to pcid-spawner This allows a single PCI daemon to run on the whole system, prevents multiple drivers from claiming the same PCI device and makes it possible for userspace to enumerate all available PCI devices. In the future this will enable an lspci tool, possibly PCIe hot plugging and more. Co-Authored-By: 4lDO2 <4lDO2@protonmail.com> --- Cargo.lock | 55 +++-- Cargo.toml | 1 + pcid-spawner/Cargo.toml | 17 ++ pcid-spawner/src/main.rs | 102 +++++++++ pcid/Cargo.toml | 3 +- pcid/src/driver_handler.rs | 131 +++--------- pcid/src/driver_interface/config.rs | 2 +- pcid/src/driver_interface/mod.rs | 70 ++++--- pcid/src/main.rs | 236 ++++++++++----------- pcid/src/scheme.rs | 313 ++++++++++++++++++++++++++++ 10 files changed, 663 insertions(+), 267 deletions(-) create mode 100644 pcid-spawner/Cargo.toml create mode 100644 pcid-spawner/src/main.rs create mode 100644 pcid/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index 4c1f1c7833..484b372504 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,7 +32,7 @@ dependencies = [ "parking_lot 0.12.3", "plain", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", "ron", @@ -52,7 +52,7 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -180,7 +180,7 @@ dependencies = [ "fdt 0.2.0-alpha1", "libredox", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -405,7 +405,7 @@ dependencies = [ "inputd", "libredox", "log", - "redox-scheme", + "redox-scheme 0.3.0", "redox_syscall", ] @@ -414,7 +414,7 @@ name = "driver-network" version = "0.1.0" dependencies = [ "libredox", - "redox-scheme", + "redox-scheme 0.3.0", "redox_syscall", ] @@ -449,7 +449,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -465,7 +465,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -680,7 +680,7 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -720,7 +720,7 @@ dependencies = [ "log", "orbclient", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_syscall", ] @@ -783,7 +783,7 @@ dependencies = [ "anyhow", "libredox", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -857,7 +857,7 @@ dependencies = [ "partitionlib", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", "smallvec 1.13.2", @@ -968,8 +968,23 @@ dependencies = [ "pico-args", "plain", "redox-daemon", + "redox-scheme 0.4.0", + "redox_syscall", "serde", "thiserror", +] + +[[package]] +name = "pcid-spawner" +version = "0.1.0" +dependencies = [ + "anyhow", + "common", + "log", + "pcid", + "pico-args", + "redox_syscall", + "serde", "toml 0.5.11", ] @@ -1123,6 +1138,16 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "redox-scheme" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28d292981c8f3338cb772b6024b08bcc597d0dd81020de17080a9a7b470ebb2" +dependencies = [ + "libredox", + "redox_syscall", +] + [[package]] name = "redox_event" version = "0.4.1" @@ -1135,9 +1160,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f" dependencies = [ "bitflags 2.6.0", ] @@ -1577,7 +1602,7 @@ dependencies = [ "libredox", "plain", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_syscall", "thiserror", "xhcid", @@ -1652,7 +1677,7 @@ dependencies = [ "partitionlib", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.3.0", "redox_syscall", "spin", "static_assertions", diff --git a/Cargo.toml b/Cargo.toml index be9ace45b5..62d4865e02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "common", "hwd", "pcid", + "pcid-spawner", "vboxd", "xhcid", "usbctl", diff --git a/pcid-spawner/Cargo.toml b/pcid-spawner/Cargo.toml new file mode 100644 index 0000000000..77dd21063f --- /dev/null +++ b/pcid-spawner/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "pcid-spawner" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2021" +license = "MIT" + +[dependencies] +anyhow = "1" +log = "0.4" +pico-args = "0.5" +redox_syscall = "0.5.9" +serde = { version = "1", features = ["derive"] } +toml = "0.5" + +common = { path = "../common" } +pcid = { path = "../pcid" } diff --git a/pcid-spawner/src/main.rs b/pcid-spawner/src/main.rs new file mode 100644 index 0000000000..a8ac5d5e13 --- /dev/null +++ b/pcid-spawner/src/main.rs @@ -0,0 +1,102 @@ +use std::fs; +use std::process::Command; + +use anyhow::{anyhow, Context, Result}; + +use pcid_interface::config::Config; +use pcid_interface::PciFunctionHandle; + +fn main() -> Result<()> { + let mut args = pico_args::Arguments::from_env(); + let config_path = args + .free_from_str::() + .expect("failed to parse --config argument"); + + common::setup_logging( + "bus", + "pci", + "pci-spawner.log", + log::LevelFilter::Info, + log::LevelFilter::Trace, + ); + + let config_data = if fs::metadata(&config_path)?.is_file() { + fs::read_to_string(&config_path)? + } else { + let mut config_data = String::new(); + for path in fs::read_dir(&config_path)? { + if let Ok(tmp) = fs::read_to_string(path.unwrap().path()) { + config_data.push_str(&tmp); + } + } + config_data + }; + let config: Config = toml::from_str(&config_data)?; + + for entry in fs::read_dir("/scheme/pci")? { + let entry = entry.context("failed to get entry")?; + let device_path = entry.path(); + log::trace!("ENTRY: {}", device_path.to_string_lossy()); + + let mut handle = match PciFunctionHandle::connect_by_path(&device_path) { + Ok(handle) => handle, + Err(err) => { + // Either the device is gone or it is already in-use by a driver. + log::debug!( + "pcid-spawner: {} already in use: {err}", + device_path.display(), + ); + continue; + } + }; + + let full_device_id = handle.config().func.full_device_id; + + log::debug!( + "pcid-spawner enumerated: PCI {} {}", + handle.config().func.addr, + full_device_id.display() + ); + + let Some(driver) = config + .drivers + .iter() + .find(|driver| driver.match_function(&full_device_id)) + else { + log::debug!("no driver for {}, continuing", handle.config().func.addr); + continue; + }; + + let mut args = driver.command.iter(); + + let program = args + .next() + .ok_or_else(|| anyhow!("driver configuration entry did not have any command!"))?; + let program = if program.starts_with('/') { + program.to_owned() + } else { + "/usr/lib/drivers/".to_owned() + program + }; + + let mut command = Command::new(program); + command.args(args); + + log::info!("pcid-spawner: spawn {:?}", command); + + handle.enable_device()?; + + let channel_fd = handle.into_inner_fd(); + command.env("PCID_CLIENT_CHANNEL", channel_fd.to_string()); + + match command.status() { + Ok(status) if !status.success() => { + log::error!("pcid-spawner: driver {command:?} failed with {status}"); + } + Ok(_) => {} + Err(err) => log::error!("pcid-spawner: failed to execute {command:?}: {err}"), + } + syscall::close(channel_fd as usize).unwrap(); + } + + Ok(()) +} diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index b78a994584..b2d6b51317 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -20,9 +20,10 @@ pci_types = "0.10" pico-args = { version = "0.5", features = ["combined-flags"] } plain = "0.2" redox-daemon = "0.1" +redox-scheme = "0.4" +redox_syscall = "0.5.9" serde = { version = "1", features = ["derive"] } thiserror = "1" -toml = "0.5" common = { path = "../common" } libredox = "0.1.3" diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index cbaf221e54..8537be5c65 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -1,109 +1,48 @@ -use std::fs::File; -use std::os::unix::io::{FromRawFd, RawFd}; -use std::process::Command; use std::sync::Arc; -use std::thread; -use log::{error, info}; use pci_types::capability::{MultipleMessageSupport, PciCapability}; -use pci_types::{ConfigRegionAccess, PciAddress}; +use pci_types::{ConfigRegionAccess, EndpointHeader}; +use pcid_interface::PciFunction; use crate::State; -pub struct DriverHandler { - addr: PciAddress, +pub struct DriverHandler<'a> { + func: PciFunction, + endpoint_header: &'a mut EndpointHeader, capabilities: Vec, state: Arc, } -impl DriverHandler { - pub fn spawn( - state: Arc, - func: pcid_interface::PciFunction, +impl<'a> DriverHandler<'a> { + pub fn new( + func: PciFunction, + endpoint_header: &'a mut EndpointHeader, capabilities: Vec, - args: &[String], - ) { - let subdriver_args = pcid_interface::SubdriverArguments { func }; - - let mut args = args.iter(); - if let Some(program) = args.next() { - let program = if program.starts_with('/') { - program.to_owned() - } else { - "/usr/lib/drivers/".to_owned() + program - }; - let mut command = Command::new(program); - for arg in args { - if arg.starts_with("$") { - panic!("support for $VARIABLE has been removed. use pcid_interface instead"); - } - command.arg(arg); - } - - info!("PCID SPAWN {:?}", command); - - // TODO: libc wrapper? - let [fds1, fds2] = unsafe { - let mut fds1 = [0 as libc::c_int; 2]; - let mut fds2 = [0 as libc::c_int; 2]; - - assert_eq!( - libc::pipe(fds1.as_mut_ptr()), - 0, - "pcid: failed to create pcid->client pipe" - ); - assert_eq!( - libc::pipe(fds2.as_mut_ptr()), - 0, - "pcid: failed to create client->pcid pipe" - ); - - [fds1.map(|c| c as usize), fds2.map(|c| c as usize)] - }; - - let [pcid_to_client_read, pcid_to_client_write] = fds1; - let [pcid_from_client_read, pcid_from_client_write] = fds2; - - let envs = vec![ - ("PCID_TO_CLIENT_FD", format!("{}", pcid_to_client_read)), - ("PCID_FROM_CLIENT_FD", format!("{}", pcid_from_client_write)), - ]; - - match command.envs(envs).spawn() { - Ok(mut child) => { - let driver_handler = DriverHandler { - addr: func.addr, - state: state.clone(), - capabilities, - }; - let handle = thread::spawn(move || { - driver_handler.handle_spawn( - pcid_to_client_write, - pcid_from_client_read, - subdriver_args, - ); - }); - state.threads.lock().unwrap().push(handle); - match child.wait() { - Ok(_status) => (), - Err(err) => error!("pcid: failed to wait for {:?}: {}", command, err), - } - } - Err(err) => error!("pcid: failed to execute {:?}: {}", command, err), - } + state: Arc, + ) -> Self { + DriverHandler { + func, + endpoint_header, + capabilities, + state, } } - fn respond( + pub fn respond( &mut self, request: pcid_interface::PcidClientRequest, - args: &pcid_interface::SubdriverArguments, ) -> pcid_interface::PcidClientResponse { use pcid_interface::*; #[forbid(non_exhaustive_omitted_patterns)] match request { + PcidClientRequest::EnableDevice => { + self.func.legacy_interrupt_line = + crate::enable_function(&self.state, &mut self.endpoint_header); + + PcidClientResponse::EnabledDevice + } PcidClientRequest::RequestVendorCapabilities => PcidClientResponse::VendorCapabilities( self.capabilities .iter() @@ -115,7 +54,9 @@ impl DriverHandler { }) .collect::>(), ), - PcidClientRequest::RequestConfig => PcidClientResponse::Config(args.clone()), + PcidClientRequest::RequestConfig => { + PcidClientResponse::Config(SubdriverArguments { func: self.func }) + } PcidClientRequest::RequestFeatures => PcidClientResponse::AllFeatures( self.capabilities .iter() @@ -327,32 +268,16 @@ impl DriverHandler { _ => unreachable!(), }, PcidClientRequest::ReadConfig(offset) => { - let value = unsafe { self.state.pcie.read(self.addr, offset) }; + let value = unsafe { self.state.pcie.read(self.func.addr, offset) }; return PcidClientResponse::ReadConfig(value); } PcidClientRequest::WriteConfig(offset, value) => { unsafe { - self.state.pcie.write(self.addr, offset, value); + self.state.pcie.write(self.func.addr, offset, value); } return PcidClientResponse::WriteConfig; } _ => unreachable!(), } } - fn handle_spawn( - mut self, - pcid_to_client_write: usize, - pcid_from_client_read: usize, - args: pcid_interface::SubdriverArguments, - ) { - use pcid_interface::*; - - let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_write as RawFd) }; - let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_read as RawFd) }; - - while let Ok(msg) = recv(&mut pcid_from_client) { - let response = self.respond(msg, &args); - send(&mut pcid_to_client, &response).unwrap(); - } - } } diff --git a/pcid/src/driver_interface/config.rs b/pcid/src/driver_interface/config.rs index 8278f33c3c..e148b26ce6 100644 --- a/pcid/src/driver_interface/config.rs +++ b/pcid/src/driver_interface/config.rs @@ -20,7 +20,7 @@ pub struct DriverConfig { pub vendor: Option, pub device: Option, pub device_id_range: Option>, - pub command: Option>, + pub command: Vec, } impl DriverConfig { diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 2cf16e8bba..7365276dc9 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -1,11 +1,11 @@ use std::fmt; use std::fs::File; use std::io::prelude::*; +use std::os::fd::{FromRawFd, IntoRawFd, RawFd}; +use std::path::Path; use std::ptr::NonNull; use std::{env, io}; -use std::os::unix::io::{FromRawFd, RawFd}; - use serde::{de::DeserializeOwned, Deserialize, Serialize}; use thiserror::Error; @@ -240,6 +240,7 @@ pub enum SetFeatureInfo { #[derive(Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum PcidClientRequest { + EnableDevice, RequestConfig, RequestFeatures, RequestVendorCapabilities, @@ -260,6 +261,7 @@ pub enum PcidServerResponseError { #[derive(Debug, Serialize, Deserialize)] #[non_exhaustive] pub enum PcidClientResponse { + EnabledDevice, Config(SubdriverArguments), AllFeatures(Vec), VendorCapabilities(Vec), @@ -277,14 +279,9 @@ pub struct MappedBar { pub bar_size: usize, } -// TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over -// a channel, the communication could potentially be done via mmap, using a channel -// very similar to crossbeam-channel or libstd's mpsc (except the cycle, enqueue and dequeue fields -// are stored in the same buffer as the actual data). /// A handle from a `pcid` client (e.g. `ahcid`) to `pcid`. pub struct PciFunctionHandle { - pcid_to_client: File, - pcid_from_client: File, + channel: File, config: SubdriverArguments, mapped_bars: [Option; 6], } @@ -293,9 +290,7 @@ pub struct PciFunctionHandle { pub fn send(w: &mut W, message: &T) -> Result<()> { let mut data = Vec::new(); bincode::serialize_into(&mut data, message)?; - let length_bytes = u64::to_le_bytes(data.len() as u64); - w.write_all(&length_bytes)?; - w.write_all(&data)?; + assert_eq!(w.write(&data)?, data.len()); Ok(()) } #[doc(hidden)] @@ -314,42 +309,69 @@ pub fn recv(r: &mut R) -> Result { impl PciFunctionHandle { pub fn connect_default() -> Result { - let pcid_to_client_fd = env::var("PCID_TO_CLIENT_FD")? - .parse::() - .map_err(PcidClientHandleError::EnvValidityError)?; - let pcid_from_client_fd = env::var("PCID_FROM_CLIENT_FD")? + let channel_fd = env::var("PCID_CLIENT_CHANNEL")? .parse::() .map_err(PcidClientHandleError::EnvValidityError)?; + Self::connect_common(channel_fd) + } - let mut pcid_to_client = unsafe { File::from_raw_fd(pcid_to_client_fd) }; - let mut pcid_from_client = unsafe { File::from_raw_fd(pcid_from_client_fd) }; + pub fn connect_by_path(device_path: &Path) -> Result { + let channel_fd = syscall::open( + device_path.join("channel").to_str().unwrap(), + syscall::O_RDWR, + ) + .map_err(|err| { + PcidClientHandleError::IoError(io::Error::other(format!( + "failed to open pcid channel: {}", + err + ))) + })?; + Self::connect_common(channel_fd as RawFd) + } - send(&mut pcid_from_client, &PcidClientRequest::RequestConfig)?; - let config = match recv(&mut pcid_to_client)? { + fn connect_common( + channel_fd: i32, + ) -> std::result::Result { + let mut channel = unsafe { File::from_raw_fd(channel_fd) }; + + send(&mut channel, &PcidClientRequest::RequestConfig)?; + let config = match recv(&mut channel)? { PcidClientResponse::Config(a) => a, other => return Err(PcidClientHandleError::InvalidResponse(other)), }; Ok(Self { - pcid_to_client, - pcid_from_client, + channel, config, mapped_bars: [const { None }; 6], }) } + + pub fn into_inner_fd(self) -> RawFd { + self.channel.into_raw_fd() + } + fn send(&mut self, req: &PcidClientRequest) -> Result<()> { - send(&mut self.pcid_from_client, req) + send(&mut self.channel, req) } fn recv(&mut self) -> Result { - recv(&mut self.pcid_to_client) + recv(&mut self.channel) } + pub fn config(&self) -> SubdriverArguments { self.config.clone() } + pub fn enable_device(&mut self) -> Result<()> { + self.send(&PcidClientRequest::EnableDevice)?; + match self.recv()? { + PcidClientResponse::EnabledDevice => Ok(()), + other => Err(PcidClientHandleError::InvalidResponse(other)), + } + } + pub fn get_vendor_capabilities(&mut self) -> Result> { self.send(&PcidClientRequest::RequestVendorCapabilities)?; - match self.recv()? { PcidClientResponse::VendorCapabilities(a) => Ok(a), other => Err(PcidClientHandleError::InvalidResponse(other)), diff --git a/pcid/src/main.rs b/pcid/src/main.rs index c432539fda..8723cac4b5 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,123 +1,120 @@ +#![feature(array_chunks)] #![feature(non_exhaustive_omitted_patterns_lint)] #![feature(iter_next_chunk)] #![feature(if_let_guard)] -use std::fs::{metadata, read_dir, File}; -use std::io::prelude::*; -use std::path::PathBuf; -use std::sync::{Arc, Mutex}; -use std::thread; +use std::collections::BTreeMap; +use std::sync::Arc; use log::{debug, info, trace, warn}; +use pci_types::capability::PciCapability; use pci_types::{ Bar as TyBar, CommandRegister, EndpointHeader, HeaderType, PciAddress, PciHeader as TyPciHeader, PciPciBridgeHeader, }; +use redox_scheme::{RequestKind, SignalBehavior}; use crate::cfg_access::Pcie; -use pcid_interface::{config::Config, FullDeviceId, LegacyInterruptLine, PciBar}; +use pcid_interface::{FullDeviceId, LegacyInterruptLine, PciBar, PciFunction}; mod cfg_access; mod driver_handler; +mod scheme; pub struct State { - threads: Mutex>>, pcie: Pcie, } +pub struct Func { + inner: PciFunction, + + capabilities: Vec, + endpoint_header: EndpointHeader, + enabled: bool, +} + fn handle_parsed_header( - state: Arc, - config: &Config, - mut endpoint_header: EndpointHeader, + state: &State, + tree: &mut BTreeMap, + endpoint_header: EndpointHeader, full_device_id: FullDeviceId, ) { - for driver in config.drivers.iter() { - if !driver.match_function(&full_device_id) { + let mut bars = [PciBar::None; 6]; + let mut skip = false; + for i in 0..6 { + if skip { + skip = false; continue; } - - let Some(ref args) = driver.command else { - continue; - }; - - let mut bars = [PciBar::None; 6]; - let mut skip = false; - for i in 0..6 { - if skip { - skip = false; - continue; - } - match endpoint_header.bar(i, &state.pcie) { - Some(TyBar::Io { port }) => { - bars[i as usize] = PciBar::Port(port.try_into().unwrap()) - } - Some(TyBar::Memory32 { - address, + match endpoint_header.bar(i, &state.pcie) { + Some(TyBar::Io { port }) => bars[i as usize] = PciBar::Port(port.try_into().unwrap()), + Some(TyBar::Memory32 { + address, + size, + prefetchable: _, + }) => { + bars[i as usize] = PciBar::Memory32 { + addr: address, size, - prefetchable: _, - }) => { - bars[i as usize] = PciBar::Memory32 { - addr: address, - size, - } } - Some(TyBar::Memory64 { - address, + } + Some(TyBar::Memory64 { + address, + size, + prefetchable: _, + }) => { + bars[i as usize] = PciBar::Memory64 { + addr: address, size, - prefetchable: _, - }) => { - bars[i as usize] = PciBar::Memory64 { - addr: address, - size, - }; - skip = true; // Each 64bit memory BAR occupies two slots - } - None => bars[i as usize] = PciBar::None, + }; + skip = true; // Each 64bit memory BAR occupies two slots } + None => bars[i as usize] = PciBar::None, } + } - let mut string = String::new(); - for (i, bar) in bars.iter().enumerate() { - if !bar.is_none() { - string.push_str(&format!(" {i}={}", bar.display())); - } + let mut string = String::new(); + for (i, bar) in bars.iter().enumerate() { + if !bar.is_none() { + string.push_str(&format!(" {i}={}", bar.display())); } + } - if !string.is_empty() { - info!(" BAR{}", string); - } + if !string.is_empty() { + info!(" BAR{}", string); + } - let legacy_interrupt_line = enable_function(&state, &mut endpoint_header); + let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { + endpoint_header + .capabilities(&state.pcie) + .collect::>() + } else { + Vec::new() + }; + debug!( + "PCI DEVICE CAPABILITIES for {}: {:?}", + endpoint_header.header().address(), + capabilities + ); - let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { - endpoint_header - .capabilities(&state.pcie) - .collect::>() - } else { - Vec::new() - }; - debug!( - "PCI DEVICE CAPABILITIES for {}: {:?}", - args.iter() - .map(|string| string.as_ref()) - .nth(0) - .unwrap_or("[unknown]"), - capabilities - ); - - let func = pcid_interface::PciFunction { + let func = Func { + inner: pcid_interface::PciFunction { bars, addr: endpoint_header.header().address(), - legacy_interrupt_line, + legacy_interrupt_line: None, // Will be filled in when enabling the device full_device_id: full_device_id.clone(), - }; + }, - driver_handler::DriverHandler::spawn(Arc::clone(&state), func, capabilities, args); - } + capabilities, + endpoint_header, + enabled: false, + }; + + tree.insert(func.inner.addr, func); } fn enable_function( - state: &Arc, + state: &State, endpoint_header: &mut EndpointHeader, ) -> Option { // Enable bus mastering, memory space, and I/O space @@ -187,34 +184,6 @@ fn enable_function( fn main() { let mut args = pico_args::Arguments::from_env(); - - let mut config = Config::default(); - - if let Ok(config_path) = args.free_from_str::() { - if metadata(&config_path).unwrap().is_file() { - if let Ok(mut config_file) = File::open(&config_path) { - let mut config_data = String::new(); - if let Ok(_) = config_file.read_to_string(&mut config_data) { - config = toml::from_str(&config_data).unwrap_or(Config::default()); - } - } - } else { - let paths = read_dir(&config_path).unwrap(); - - let mut config_data = String::new(); - - for path in paths { - if let Ok(mut config_file) = File::open(&path.unwrap().path()) { - let mut tmp = String::new(); - if let Ok(_) = config_file.read_to_string(&mut tmp) { - config_data.push_str(&tmp); - } - } - } - config = toml::from_str(&config_data).unwrap_or(Config::default()); - } - } - let verbosity = (0..).find(|_| !args.contains("-v")).unwrap_or(0); let log_level = match verbosity { 0 => log::LevelFilter::Info, @@ -224,14 +193,12 @@ fn main() { common::setup_logging("bus", "pci", "pcid", log_level, log::LevelFilter::Trace); - redox_daemon::Daemon::new(move |daemon| main_inner(config, daemon)).unwrap(); + redox_daemon::Daemon::new(move |daemon| main_inner(daemon)).unwrap(); } -fn main_inner(config: Config, daemon: redox_daemon::Daemon) -> ! { - let state = Arc::new(State { - pcie: Pcie::new(), - threads: Mutex::new(Vec::new()), - }); +fn main_inner(daemon: redox_daemon::Daemon) -> ! { + let state = Arc::new(State { pcie: Pcie::new() }); + let mut tree = BTreeMap::new(); info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV"); @@ -245,22 +212,45 @@ fn main_inner(config: Config, daemon: redox_daemon::Daemon) -> ! { bus_i += 1; for dev_num in 0..32 { - scan_device(&config, &state, &mut bus_nums, bus_num, dev_num); + scan_device(&mut tree, &state, &mut bus_nums, bus_num, dev_num); + } + } + info!("Enumeration complete, now starting pci scheme"); + + let mut scheme = scheme::PciScheme::new(state, tree); + let socket = redox_scheme::Socket::create("pci").expect("failed to open pci scheme socket"); + + let _ = daemon.ready(); + + loop { + let Some(request) = socket + .next_request(SignalBehavior::Restart) + .expect("pcid: failed to get next scheme request") + else { + break; + }; + match request.kind() { + RequestKind::Call(call) => { + let response = call.handle_scheme(&mut scheme); + + socket + .write_responses(&[response], SignalBehavior::Restart) + .expect("pcid: failed to write next scheme response"); + } + RequestKind::OnClose { id } => { + scheme.on_close(id); + } + _ => (), } } - daemon.ready().unwrap(); - - for thread in state.threads.lock().unwrap().drain(..) { - thread.join().unwrap(); - } - + println!("pcid: exit"); std::process::exit(0); } fn scan_device( - config: &Config, - state: &Arc, + tree: &mut BTreeMap, + state: &State, bus_nums: &mut Vec, bus_num: u8, dev_num: u8, @@ -295,8 +285,8 @@ fn scan_device( match header.header_type(&state.pcie) { HeaderType::Endpoint => { handle_parsed_header( - Arc::clone(state), - config, + state, + tree, EndpointHeader::from_header(header, &state.pcie).unwrap(), full_device_id, ); diff --git a/pcid/src/scheme.rs b/pcid/src/scheme.rs new file mode 100644 index 0000000000..d1c35166d7 --- /dev/null +++ b/pcid/src/scheme.rs @@ -0,0 +1,313 @@ +use std::collections::{BTreeMap, VecDeque}; +use std::sync::Arc; + +use pci_types::PciAddress; +use redox_scheme::{CallerCtx, OpenResult, Scheme}; +use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; +use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR}; +use syscall::flag::{MODE_CHR, MODE_DIR, O_DIRECTORY, O_STAT}; +use syscall::schemev2::NewFdFlags; +use syscall::ENOLCK; + +use crate::State; + +pub struct PciScheme { + handles: BTreeMap, + next_id: usize, + state: Arc, + tree: BTreeMap, +} +enum Handle { + TopLevel { entries: Vec }, + Device, + Channel { addr: PciAddress, st: ChannelState }, +} +struct HandleWrapper { + inner: Handle, + stat: bool, +} +impl Handle { + fn is_file(&self) -> bool { + matches!(self, Self::Channel { .. }) + } + fn is_dir(&self) -> bool { + !self.is_file() + } + // TODO: capability rather than root + fn requires_root(&self) -> bool { + matches!(self, Self::Channel { .. }) + } +} + +enum ChannelState { + AwaitingData, + AwaitingResponseRead(VecDeque), +} + +const DEVICE_CONTENTS: &[&str] = &["channel"]; + +impl Scheme for PciScheme { + fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result { + log::trace!("OPEN `{}` flags {}", path, flags); + + // TODO: Check flags are correct + let expects_dir = path.ends_with('/') || flags & O_DIRECTORY != 0; + + let path = path.trim_matches('/'); + + let handle = if path.is_empty() { + Handle::TopLevel { + entries: self + .tree + .iter() + // FIXME remove replacement of : once the old scheme format is no longer supported. + .map(|(addr, _)| format!("{}", addr).replace(':', "--")) + .collect::>(), + } + } else { + let idx = path.find('/').unwrap_or(path.len()); + let (addr_str, after) = path.split_at(idx); + let addr = parse_pci_addr(addr_str).ok_or(Error::new(ENOENT))?; + + self.parse_after_pci_addr(addr, after)? + }; + + let stat = flags & O_STAT != 0; + if expects_dir && handle.is_file() && !stat { + return Err(Error::new(ENOTDIR)); + } + if !expects_dir && handle.is_dir() && !stat { + return Err(Error::new(EISDIR)); + } + if ctx.uid != 0 && handle.requires_root() && !stat { + return Err(Error::new(EACCES)); + } + + let id = self.next_id; + self.next_id += 1; + + self.handles.insert( + id, + HandleWrapper { + inner: handle, + stat, + }, + ); + Ok(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + }) + } + fn fstat(&mut self, id: usize, stat: &mut syscall::Stat) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + let (len, mode) = match handle.inner { + Handle::TopLevel { ref entries } => (entries.len(), MODE_DIR | 0o755), + Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755), + Handle::Channel { .. } => (0, MODE_CHR | 0o600), + }; + stat.st_size = len as u64; + stat.st_mode = mode; + Ok(0) + } + fn read( + &mut self, + id: usize, + buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + ) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + if handle.stat { + return Err(Error::new(EBADF)); + } + + match handle.inner { + Handle::TopLevel { .. } => Err(Error::new(EISDIR)), + Handle::Device => Err(Error::new(EISDIR)), + Handle::Channel { + addr: _, + ref mut st, + } => Self::read_channel(st, buf), + } + } + fn getdents<'buf>( + &mut self, + id: usize, + mut buf: DirentBuf<&'buf mut [u8]>, + opaque_offset: u64, + ) -> Result> { + let Ok(offset) = usize::try_from(opaque_offset) else { + return Ok(buf); + }; + + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + if handle.stat { + return Err(Error::new(EBADF)); + } + + let entries = match handle.inner { + Handle::TopLevel { ref entries } => { + for (i, dent_name) in entries.iter().enumerate().skip(offset) { + buf.entry(DirEntry { + inode: 0, + name: dent_name, + kind: DirentKind::Unspecified, + next_opaque_id: i as u64 + 1, + })?; + } + return Ok(buf); + } + Handle::Device => DEVICE_CONTENTS, + Handle::Channel { .. } => return Err(Error::new(ENOTDIR)), + }; + + for (i, dent_name) in entries.iter().enumerate().skip(offset) { + buf.entry(DirEntry { + inode: 0, + name: dent_name, + kind: DirentKind::Unspecified, + next_opaque_id: i as u64 + 1, + })?; + } + Ok(buf) + } + + fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + if handle.stat { + return Err(Error::new(EBADF)); + } + + match handle.inner { + Handle::Channel { addr, ref mut st } => { + Self::write_channel(&self.state, &mut self.tree, addr, st, buf) + } + + _ => Err(Error::new(EBADF)), + } + } +} + +impl PciScheme { + pub fn on_close(&mut self, id: usize) { + match self.handles.remove(&id) { + Some(HandleWrapper { + inner: Handle::Channel { addr, .. }, + .. + }) => { + log::trace!("TODO: Support disabling device (called on {})", addr); + if let Some(func) = self.tree.get_mut(&addr) { + func.enabled = false; + } + } + _ => {} + } + } +} + +impl PciScheme { + pub fn new(state: Arc, tree: BTreeMap) -> Self { + Self { + handles: BTreeMap::new(), + next_id: 0, + state, + tree, + } + } + fn parse_after_pci_addr(&mut self, addr: PciAddress, after: &str) -> Result { + if after.chars().next().map_or(false, |c| c != '/') { + return Err(Error::new(ENOENT)); + } + let func = self.tree.get_mut(&addr).ok_or(Error::new(ENOENT))?; + + Ok(if after.is_empty() { + Handle::Device + } else { + let path = &after[1..]; + + match path { + "channel" => { + if func.enabled { + return Err(Error::new(ENOLCK)); + } + func.inner.legacy_interrupt_line = + crate::enable_function(&self.state, &mut func.endpoint_header); + func.enabled = true; + Handle::Channel { + addr, + st: ChannelState::AwaitingData, + } + } + _ => return Err(Error::new(ENOENT)), + } + }) + } + + fn read_channel(state: &mut ChannelState, buf: &mut [u8]) -> Result { + match *state { + ChannelState::AwaitingResponseRead(ref mut queue) => { + let byte_count = std::cmp::min(queue.len(), buf.len()); + // XXX: Why can't VecDeque support dequeueing into slices? + for (idx, byte) in queue.drain(..byte_count).enumerate() { + buf[idx] = byte; + } + if queue.is_empty() { + *state = ChannelState::AwaitingData; + } + Ok(byte_count) + } + ChannelState::AwaitingData => Err(Error::new(EINVAL)), + } + } + fn write_channel( + pci_state: &Arc, + tree: &mut BTreeMap, + addr: PciAddress, + state: &mut ChannelState, + buf: &[u8], + ) -> Result { + match *state { + ChannelState::AwaitingResponseRead(_) => return Err(Error::new(EINVAL)), + ChannelState::AwaitingData => { + let func = tree.get_mut(&addr).unwrap(); + + let request = bincode::deserialize_from(buf).map_err(|_| Error::new(EINVAL))?; + let response = crate::driver_handler::DriverHandler::new( + func.inner.clone(), + &mut func.endpoint_header, + func.capabilities.clone(), + Arc::clone(pci_state), + ) + .respond(request); + + let mut output_bytes = vec![0_u8; 8]; + bincode::serialize_into(&mut output_bytes, &response) + .map_err(|_| Error::new(EIO))?; + let len = output_bytes.len() - 8; + output_bytes[..8].copy_from_slice(&u64::to_le_bytes(len as u64)); + *state = ChannelState::AwaitingResponseRead(output_bytes.into()); + + Ok(buf.len()) + } + } + } +} + +fn parse_pci_addr(addr: &str) -> Option { + let (segment, rest) = addr.split_once('-')?; + let segment = u16::from_str_radix(segment, 16).ok()?; + + // FIXME use : instead of -- as separator once the old scheme format is no longer supported. + let (bus, rest) = rest.split_once("--")?; + let bus = u8::from_str_radix(bus, 16).ok()?; + + let (device, function) = rest.split_once('.')?; + let device = u8::from_str_radix(device, 16).ok()?; + let function = u8::from_str_radix(function, 16).ok()?; + + Some(PciAddress::new(segment, bus, device, function)) +} From 7dbce70d9551ace0fc74f1e6f31c14fb48412048 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Mar 2025 17:09:52 +0100 Subject: [PATCH 1086/1301] Get rid of the State struct and the Arc wrapper around Pcie --- pcid/src/driver_handler.rs | 36 +++++++++++++------------- pcid/src/main.rs | 52 ++++++++++++++++---------------------- pcid/src/scheme.rs | 17 ++++++------- 3 files changed, 47 insertions(+), 58 deletions(-) diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 8537be5c65..435c225937 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -1,17 +1,15 @@ -use std::sync::Arc; - use pci_types::capability::{MultipleMessageSupport, PciCapability}; use pci_types::{ConfigRegionAccess, EndpointHeader}; use pcid_interface::PciFunction; -use crate::State; +use crate::cfg_access::Pcie; pub struct DriverHandler<'a> { func: PciFunction, endpoint_header: &'a mut EndpointHeader, capabilities: Vec, - state: Arc, + pcie: &'a Pcie, } impl<'a> DriverHandler<'a> { @@ -19,13 +17,13 @@ impl<'a> DriverHandler<'a> { func: PciFunction, endpoint_header: &'a mut EndpointHeader, capabilities: Vec, - state: Arc, + pcie: &'a Pcie, ) -> Self { DriverHandler { func, endpoint_header, capabilities, - state, + pcie, } } @@ -39,7 +37,7 @@ impl<'a> DriverHandler<'a> { match request { PcidClientRequest::EnableDevice => { self.func.legacy_interrupt_line = - crate::enable_function(&self.state, &mut self.endpoint_header); + crate::enable_function(&self.pcie, &mut self.endpoint_header); PcidClientResponse::EnabledDevice } @@ -48,7 +46,7 @@ impl<'a> DriverHandler<'a> { .iter() .filter_map(|capability| match capability { PciCapability::Vendor(addr) => unsafe { - Some(VendorSpecificCapability::parse(*addr, &self.state.pcie)) + Some(VendorSpecificCapability::parse(*addr, self.pcie)) }, _ => None, }) @@ -80,7 +78,7 @@ impl<'a> DriverHandler<'a> { { // If MSI-X is supported disable it before enabling MSI as they can't be // active at the same time. - msix_capability.set_enabled(false, &self.state.pcie); + msix_capability.set_enabled(false, self.pcie); } let capability = match self.capabilities.iter_mut().find_map(|capability| { @@ -96,7 +94,7 @@ impl<'a> DriverHandler<'a> { ) } }; - capability.set_enabled(true, &self.state.pcie); + capability.set_enabled(true, self.pcie); PcidClientResponse::FeatureEnabled(feature) } PciFeature::MsiX => { @@ -110,7 +108,7 @@ impl<'a> DriverHandler<'a> { { // If MSI is supported disable it before enabling MSI-X as they can't be // active at the same time. - msi_capability.set_enabled(false, &self.state.pcie); + msi_capability.set_enabled(false, self.pcie); } let capability = match self.capabilities.iter_mut().find_map(|capability| { @@ -126,7 +124,7 @@ impl<'a> DriverHandler<'a> { ) } }; - capability.set_enabled(true, &self.state.pcie); + capability.set_enabled(true, self.pcie); PcidClientResponse::FeatureEnabled(feature) } } @@ -209,7 +207,7 @@ impl<'a> DriverHandler<'a> { ) } }, - &self.state.pcie, + self.pcie, ); } if let Some(message_addr_and_data) = info_to_set.message_address_and_data { @@ -220,7 +218,7 @@ impl<'a> DriverHandler<'a> { ); } if message_addr_and_data.data - & ((1 << info.multiple_message_enable(&self.state.pcie) as u8) - 1) + & ((1 << info.multiple_message_enable(self.pcie) as u8) - 1) != 0 { return PcidClientResponse::Error( @@ -233,11 +231,11 @@ impl<'a> DriverHandler<'a> { .data .try_into() .expect("pcid: MSI message data too big"), - &self.state.pcie, + self.pcie, ); } if let Some(mask_bits) = info_to_set.mask_bits { - info.set_message_mask(mask_bits, &self.state.pcie); + info.set_message_mask(mask_bits, self.pcie); } PcidClientResponse::SetFeatureInfo(PciFeature::Msi) } else { @@ -256,7 +254,7 @@ impl<'a> DriverHandler<'a> { }) { if let Some(mask) = function_mask { - info.set_function_mask(mask, &self.state.pcie); + info.set_function_mask(mask, self.pcie); } PcidClientResponse::SetFeatureInfo(PciFeature::MsiX) } else { @@ -268,12 +266,12 @@ impl<'a> DriverHandler<'a> { _ => unreachable!(), }, PcidClientRequest::ReadConfig(offset) => { - let value = unsafe { self.state.pcie.read(self.func.addr, offset) }; + let value = unsafe { self.pcie.read(self.func.addr, offset) }; return PcidClientResponse::ReadConfig(value); } PcidClientRequest::WriteConfig(offset, value) => { unsafe { - self.state.pcie.write(self.func.addr, offset, value); + self.pcie.write(self.func.addr, offset, value); } return PcidClientResponse::WriteConfig; } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 8723cac4b5..3545c800f9 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -4,7 +4,6 @@ #![feature(if_let_guard)] use std::collections::BTreeMap; -use std::sync::Arc; use log::{debug, info, trace, warn}; use pci_types::capability::PciCapability; @@ -21,10 +20,6 @@ mod cfg_access; mod driver_handler; mod scheme; -pub struct State { - pcie: Pcie, -} - pub struct Func { inner: PciFunction, @@ -34,7 +29,7 @@ pub struct Func { } fn handle_parsed_header( - state: &State, + pcie: &Pcie, tree: &mut BTreeMap, endpoint_header: EndpointHeader, full_device_id: FullDeviceId, @@ -46,7 +41,7 @@ fn handle_parsed_header( skip = false; continue; } - match endpoint_header.bar(i, &state.pcie) { + match endpoint_header.bar(i, pcie) { Some(TyBar::Io { port }) => bars[i as usize] = PciBar::Port(port.try_into().unwrap()), Some(TyBar::Memory32 { address, @@ -84,10 +79,8 @@ fn handle_parsed_header( info!(" BAR{}", string); } - let capabilities = if endpoint_header.status(&state.pcie).has_capability_list() { - endpoint_header - .capabilities(&state.pcie) - .collect::>() + let capabilities = if endpoint_header.status(pcie).has_capability_list() { + endpoint_header.capabilities(pcie).collect::>() } else { Vec::new() }; @@ -114,11 +107,11 @@ fn handle_parsed_header( } fn enable_function( - state: &State, + pcie: &Pcie, endpoint_header: &mut EndpointHeader, ) -> Option { // Enable bus mastering, memory space, and I/O space - endpoint_header.update_command(&state.pcie, |cmd| { + endpoint_header.update_command(pcie, |cmd| { cmd | CommandRegister::BUS_MASTER_ENABLE | CommandRegister::MEMORY_ENABLE | CommandRegister::IO_ENABLE @@ -128,7 +121,7 @@ fn enable_function( let mut irq = 0xFF; let mut interrupt_pin = 0xFF; - endpoint_header.update_interrupt(&state.pcie, |(pin, mut line)| { + endpoint_header.update_interrupt(pcie, |(pin, mut line)| { if line == 0xFF { line = 9; } @@ -153,13 +146,12 @@ fn enable_function( | ((pci_address.device() as u32) << 11) | ((pci_address.function() as u32) << 8); let addr = [ - dt_address & state.pcie.interrupt_map_mask[0], + dt_address & pcie.interrupt_map_mask[0], 0u32, 0u32, - interrupt_pin as u32 & state.pcie.interrupt_map_mask[3], + interrupt_pin as u32 & pcie.interrupt_map_mask[3], ]; - let mapping = state - .pcie + let mapping = pcie .interrupt_map .iter() .find(|x| x.addr == addr[0..3] && x.interrupt == addr[3]); @@ -197,7 +189,7 @@ fn main() { } fn main_inner(daemon: redox_daemon::Daemon) -> ! { - let state = Arc::new(State { pcie: Pcie::new() }); + let pcie = Pcie::new(); let mut tree = BTreeMap::new(); info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV"); @@ -212,12 +204,12 @@ fn main_inner(daemon: redox_daemon::Daemon) -> ! { bus_i += 1; for dev_num in 0..32 { - scan_device(&mut tree, &state, &mut bus_nums, bus_num, dev_num); + scan_device(&mut tree, &pcie, &mut bus_nums, bus_num, dev_num); } } info!("Enumeration complete, now starting pci scheme"); - let mut scheme = scheme::PciScheme::new(state, tree); + let mut scheme = scheme::PciScheme::new(pcie, tree); let socket = redox_scheme::Socket::create("pci").expect("failed to open pci scheme socket"); let _ = daemon.ready(); @@ -250,7 +242,7 @@ fn main_inner(daemon: redox_daemon::Daemon) -> ! { fn scan_device( tree: &mut BTreeMap, - state: &State, + pcie: &Pcie, bus_nums: &mut Vec, bus_num: u8, dev_num: u8, @@ -258,7 +250,7 @@ fn scan_device( for func_num in 0..8 { let header = TyPciHeader::new(PciAddress::new(0, bus_num, dev_num, func_num)); - let (vendor_id, device_id) = header.id(&state.pcie); + let (vendor_id, device_id) = header.id(pcie); if vendor_id == 0xffff && device_id == 0xffff { if func_num == 0 { trace!("PCI {:>02X}:{:>02X}: no dev", bus_num, dev_num); @@ -268,7 +260,7 @@ fn scan_device( continue; } - let (revision, class, subclass, interface) = header.revision_and_class(&state.pcie); + let (revision, class, subclass, interface) = header.revision_and_class(pcie); let full_device_id = FullDeviceId { vendor_id, device_id, @@ -280,20 +272,20 @@ fn scan_device( info!("PCI {} {}", header.address(), full_device_id.display()); - let has_multiple_functions = header.has_multiple_functions(&state.pcie); + let has_multiple_functions = header.has_multiple_functions(pcie); - match header.header_type(&state.pcie) { + match header.header_type(pcie) { HeaderType::Endpoint => { handle_parsed_header( - state, + pcie, tree, - EndpointHeader::from_header(header, &state.pcie).unwrap(), + EndpointHeader::from_header(header, pcie).unwrap(), full_device_id, ); } HeaderType::PciPciBridge => { - let bridge_header = PciPciBridgeHeader::from_header(header, &state.pcie).unwrap(); - bus_nums.push(bridge_header.secondary_bus_number(&state.pcie)); + let bridge_header = PciPciBridgeHeader::from_header(header, pcie).unwrap(); + bus_nums.push(bridge_header.secondary_bus_number(pcie)); } ty => { warn!("pcid: unknown header type: {ty:?}"); diff --git a/pcid/src/scheme.rs b/pcid/src/scheme.rs index d1c35166d7..cee1fc7a11 100644 --- a/pcid/src/scheme.rs +++ b/pcid/src/scheme.rs @@ -1,5 +1,4 @@ use std::collections::{BTreeMap, VecDeque}; -use std::sync::Arc; use pci_types::PciAddress; use redox_scheme::{CallerCtx, OpenResult, Scheme}; @@ -9,12 +8,12 @@ use syscall::flag::{MODE_CHR, MODE_DIR, O_DIRECTORY, O_STAT}; use syscall::schemev2::NewFdFlags; use syscall::ENOLCK; -use crate::State; +use crate::cfg_access::Pcie; pub struct PciScheme { handles: BTreeMap, next_id: usize, - state: Arc, + pcie: Pcie, tree: BTreeMap, } enum Handle { @@ -184,7 +183,7 @@ impl Scheme for PciScheme { match handle.inner { Handle::Channel { addr, ref mut st } => { - Self::write_channel(&self.state, &mut self.tree, addr, st, buf) + Self::write_channel(&self.pcie, &mut self.tree, addr, st, buf) } _ => Err(Error::new(EBADF)), @@ -210,11 +209,11 @@ impl PciScheme { } impl PciScheme { - pub fn new(state: Arc, tree: BTreeMap) -> Self { + pub fn new(pcie: Pcie, tree: BTreeMap) -> Self { Self { handles: BTreeMap::new(), next_id: 0, - state, + pcie, tree, } } @@ -235,7 +234,7 @@ impl PciScheme { return Err(Error::new(ENOLCK)); } func.inner.legacy_interrupt_line = - crate::enable_function(&self.state, &mut func.endpoint_header); + crate::enable_function(&self.pcie, &mut func.endpoint_header); func.enabled = true; Handle::Channel { addr, @@ -264,7 +263,7 @@ impl PciScheme { } } fn write_channel( - pci_state: &Arc, + pci_state: &Pcie, tree: &mut BTreeMap, addr: PciAddress, state: &mut ChannelState, @@ -280,7 +279,7 @@ impl PciScheme { func.inner.clone(), &mut func.endpoint_header, func.capabilities.clone(), - Arc::clone(pci_state), + &*pci_state, ) .respond(request); From 0c42f431bd343397b90d33f35a8110f43f0d3c16 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Mar 2025 18:09:23 +0100 Subject: [PATCH 1087/1301] graphics/vesad: Merge screen.rs into scheme.rs --- graphics/driver-graphics/Cargo.toml | 2 +- graphics/vesad/src/main.rs | 1 - graphics/vesad/src/scheme.rs | 108 ++++++++++++++++++++++++++-- graphics/vesad/src/screen.rs | 107 --------------------------- 4 files changed, 103 insertions(+), 115 deletions(-) delete mode 100644 graphics/vesad/src/screen.rs diff --git a/graphics/driver-graphics/Cargo.toml b/graphics/driver-graphics/Cargo.toml index 6ad15add9d..a592861035 100644 --- a/graphics/driver-graphics/Cargo.toml +++ b/graphics/driver-graphics/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] log = "0.4" redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } -redox_syscall = "0.5" +redox_syscall = { version = "0.5", features = ["std"] } libredox = "0.1.3" common = { path = "../../common" } diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 8cafa6b2ee..fa1b8bd53e 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -13,7 +13,6 @@ use crate::scheme::FbAdapter; mod framebuffer; mod scheme; -mod screen; fn main() { let mut spec = Vec::new(); diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 51a3712e02..a83bef14dd 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -1,7 +1,12 @@ -use driver_graphics::GraphicsAdapter; -use graphics_ipc::legacy::Damage; +use std::alloc::{self, Layout}; +use std::convert::TryInto; +use std::ptr::{self, NonNull}; -use crate::{framebuffer::FrameBuffer, screen::GraphicScreen}; +use driver_graphics::{GraphicsAdapter, Resource}; +use graphics_ipc::legacy::Damage; +use syscall::PAGE_SIZE; + +use crate::framebuffer::FrameBuffer; pub struct FbAdapter { pub framebuffers: Vec, @@ -26,11 +31,11 @@ impl GraphicsAdapter for FbAdapter { } fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8 { - resource.ptr() + resource.ptr.as_ptr().cast::() } fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource) { - resource.redraw(&mut self.framebuffers[display_id]); + self.flush_resource(display_id, resource, None); } fn flush_resource( @@ -42,7 +47,98 @@ impl GraphicsAdapter for FbAdapter { if let Some(damage) = damage { resource.sync(&mut self.framebuffers[display_id], damage) } else { - resource.redraw(&mut self.framebuffers[display_id]) + let framebuffer: &mut FrameBuffer = &mut self.framebuffers[display_id]; + let width = resource.width.try_into().unwrap(); + let height = resource.height.try_into().unwrap(); + resource.sync( + framebuffer, + &[Damage { + x: 0, + y: 0, + width, + height, + }], + ); + } + } +} + +pub struct GraphicScreen { + pub width: usize, + pub height: usize, + ptr: NonNull<[u32]>, +} + +impl GraphicScreen { + pub fn new(width: usize, height: usize) -> GraphicScreen { + let len = width * height; + let layout = Self::layout(len); + let ptr = unsafe { alloc::alloc_zeroed(layout) }; + let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len); + let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout)); + + GraphicScreen { width, height, ptr } + } + + #[inline] + fn layout(len: usize) -> Layout { + // optimizes to an integer mul + Layout::array::(len) + .unwrap() + .align_to(PAGE_SIZE) + .unwrap() + } +} + +impl Drop for GraphicScreen { + fn drop(&mut self) { + let layout = Self::layout(self.ptr.len()); + unsafe { alloc::dealloc(self.ptr.as_ptr().cast(), layout) }; + } +} + +impl Resource for GraphicScreen { + fn width(&self) -> u32 { + self.width as u32 + } + + fn height(&self) -> u32 { + self.height as u32 + } +} + +impl GraphicScreen { + fn sync(&self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) { + for sync_rect in sync_rects { + let sync_rect = sync_rect.clip( + self.width.try_into().unwrap(), + self.height.try_into().unwrap(), + ); + + let start_x: usize = sync_rect.x.try_into().unwrap_or(0); + let start_y: usize = sync_rect.y.try_into().unwrap_or(0); + let w: usize = sync_rect.width.try_into().unwrap_or(0); + let h: usize = sync_rect.height.try_into().unwrap_or(0); + + let end_y = start_y + h; + + let row_pixel_count = w; + + let mut offscreen_ptr = self.ptr.as_ptr() as *mut u32; + let mut onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable + + unsafe { + offscreen_ptr = offscreen_ptr.add(start_y * self.width + start_x); + onscreen_ptr = onscreen_ptr.add(start_y * framebuffer.stride + start_x); + + let mut rows = end_y - start_y; + while rows > 0 { + ptr::copy(offscreen_ptr, onscreen_ptr, row_pixel_count); + offscreen_ptr = offscreen_ptr.add(self.width); + onscreen_ptr = onscreen_ptr.add(framebuffer.stride); + rows -= 1; + } + } } } } diff --git a/graphics/vesad/src/screen.rs b/graphics/vesad/src/screen.rs deleted file mode 100644 index 8460ffbbf7..0000000000 --- a/graphics/vesad/src/screen.rs +++ /dev/null @@ -1,107 +0,0 @@ -use std::alloc::{self, Layout}; -use std::convert::TryInto; -use std::ptr::{self, NonNull}; - -use driver_graphics::Resource; -use graphics_ipc::legacy::Damage; -use syscall::PAGE_SIZE; - -use crate::framebuffer::FrameBuffer; - -pub struct GraphicScreen { - pub width: usize, - pub height: usize, - ptr: NonNull<[u32]>, -} - -impl GraphicScreen { - pub fn new(width: usize, height: usize) -> GraphicScreen { - let len = width * height; - let layout = Self::layout(len); - let ptr = unsafe { alloc::alloc_zeroed(layout) }; - let ptr = ptr::slice_from_raw_parts_mut(ptr.cast(), len); - let ptr = NonNull::new(ptr).unwrap_or_else(|| alloc::handle_alloc_error(layout)); - - GraphicScreen { width, height, ptr } - } - - #[inline] - fn layout(len: usize) -> Layout { - // optimizes to an integer mul - Layout::array::(len) - .unwrap() - .align_to(PAGE_SIZE) - .unwrap() - } -} - -impl Drop for GraphicScreen { - fn drop(&mut self) { - let layout = Self::layout(self.ptr.len()); - unsafe { alloc::dealloc(self.ptr.as_ptr().cast(), layout) }; - } -} - -impl Resource for GraphicScreen { - fn width(&self) -> u32 { - self.width as u32 - } - - fn height(&self) -> u32 { - self.height as u32 - } -} - -impl GraphicScreen { - pub fn ptr(&self) -> *mut u8 { - self.ptr.as_ptr().cast::() - } - - pub fn sync(&self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) { - for sync_rect in sync_rects { - let sync_rect = sync_rect.clip( - self.width.try_into().unwrap(), - self.height.try_into().unwrap(), - ); - - let start_x: usize = sync_rect.x.try_into().unwrap_or(0); - let start_y: usize = sync_rect.y.try_into().unwrap_or(0); - let w: usize = sync_rect.width.try_into().unwrap_or(0); - let h: usize = sync_rect.height.try_into().unwrap_or(0); - - let end_y = start_y + h; - - let row_pixel_count = w; - - let mut offscreen_ptr = self.ptr.as_ptr() as *mut u32; - let mut onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable - - unsafe { - offscreen_ptr = offscreen_ptr.add(start_y * self.width + start_x); - onscreen_ptr = onscreen_ptr.add(start_y * framebuffer.stride + start_x); - - let mut rows = end_y - start_y; - while rows > 0 { - ptr::copy(offscreen_ptr, onscreen_ptr, row_pixel_count); - offscreen_ptr = offscreen_ptr.add(self.width); - onscreen_ptr = onscreen_ptr.add(framebuffer.stride); - rows -= 1; - } - } - } - } - - pub fn redraw(&self, framebuffer: &mut FrameBuffer) { - let width = self.width.try_into().unwrap(); - let height = self.height.try_into().unwrap(); - self.sync( - framebuffer, - &[Damage { - x: 0, - y: 0, - width, - height, - }], - ); - } -} From 91f814a42c208d947c3306d5b0c434b95826560e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Mar 2025 18:22:18 +0100 Subject: [PATCH 1088/1301] graphics/vesad: Simplify sync loop LLVM should optimize it to pretty much the same code, but using a regular for loop makes it's behavior clearer. --- graphics/vesad/src/scheme.rs | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index a83bef14dd..88cf385ba2 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -120,23 +120,16 @@ impl GraphicScreen { let w: usize = sync_rect.width.try_into().unwrap_or(0); let h: usize = sync_rect.height.try_into().unwrap_or(0); - let end_y = start_y + h; + let offscreen_ptr = self.ptr.as_ptr() as *mut u32; + let onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable - let row_pixel_count = w; - - let mut offscreen_ptr = self.ptr.as_ptr() as *mut u32; - let mut onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable - - unsafe { - offscreen_ptr = offscreen_ptr.add(start_y * self.width + start_x); - onscreen_ptr = onscreen_ptr.add(start_y * framebuffer.stride + start_x); - - let mut rows = end_y - start_y; - while rows > 0 { - ptr::copy(offscreen_ptr, onscreen_ptr, row_pixel_count); - offscreen_ptr = offscreen_ptr.add(self.width); - onscreen_ptr = onscreen_ptr.add(framebuffer.stride); - rows -= 1; + for row in start_y..start_y + h { + unsafe { + ptr::copy( + offscreen_ptr.add(row * self.width + start_x), + onscreen_ptr.add(row * framebuffer.stride + start_x), + w, + ); } } } From 68af18aead658f65a27a32ef93df2ce3aef0797b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Mar 2025 18:23:16 +0100 Subject: [PATCH 1089/1301] graphics/vesad: Make some fields and methods private --- graphics/vesad/src/scheme.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 88cf385ba2..48c3b0940a 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -64,13 +64,13 @@ impl GraphicsAdapter for FbAdapter { } pub struct GraphicScreen { - pub width: usize, - pub height: usize, + width: usize, + height: usize, ptr: NonNull<[u32]>, } impl GraphicScreen { - pub fn new(width: usize, height: usize) -> GraphicScreen { + fn new(width: usize, height: usize) -> GraphicScreen { let len = width * height; let layout = Self::layout(len); let ptr = unsafe { alloc::alloc_zeroed(layout) }; From d26ee5a58d88c61a13ae991aa428974f69f53308 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Mar 2025 19:23:56 +0100 Subject: [PATCH 1090/1301] graphics/fbbootlogd: Handle non-existent graphics adapter This ensures a serial console shows up with all non-graphics related daemons started when there is no framebuffer passed by the bootloader. --- graphics/fbbootlogd/src/display.rs | 42 +++++++++++++++++++++--------- graphics/fbbootlogd/src/scheme.rs | 26 +++++++++--------- inputd/Cargo.toml | 2 +- inputd/src/lib.rs | 3 +-- 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index 4fa9d53213..4f736f8643 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -41,18 +41,26 @@ enum DisplayCommand { pub struct Display { cmd_tx: Sender, - pub map: Arc>, + pub map: Arc>>, } impl Display { pub fn open_first_vt() -> io::Result { let input_handle = ConsumerHandle::for_vt(1)?; - let display_handle = LegacyGraphicsHandle::from_file(input_handle.open_display()?)?; - - let map = Arc::new(Mutex::new( - display_fd_map(display_handle).unwrap_or_else(|e| panic!("failed to map display: {e}")), - )); + let map = match input_handle.open_display() { + Ok(display) => { + let display_handle = LegacyGraphicsHandle::from_file(display)?; + Arc::new(Mutex::new(Some( + display_fd_map(display_handle) + .unwrap_or_else(|e| panic!("failed to map display: {e}")), + ))) + } + Err(err) => { + println!("fbbootlogd: No display present yet: {err}"); + Arc::new(Mutex::new(None)) + } + }; let map_clone = map.clone(); std::thread::spawn(move || { @@ -68,7 +76,7 @@ impl Display { Ok(Self { cmd_tx, map }) } - fn handle_input_events(map: Arc>, input_handle: ConsumerHandle) { + fn handle_input_events(map: Arc>>, input_handle: ConsumerHandle) { let event_queue = EventQueue::new().expect("fbbootlogd: failed to create event queue"); user_data! { @@ -93,13 +101,17 @@ impl Display { Err(err) if err.errno() == ESTALE => { eprintln!("fbbootlogd: handoff requested"); - let new_display_handle = - LegacyGraphicsHandle::from_file(input_handle.open_display().unwrap()) - .unwrap(); + let new_display_handle = match input_handle.open_display() { + Ok(display) => LegacyGraphicsHandle::from_file(display).unwrap(), + Err(err) => { + println!("fbbootlogd: No display present yet: {err}"); + continue; + } + }; match display_fd_map(new_display_handle) { Ok(ok) => { - *map.lock().unwrap() = ok; + *map.lock().unwrap() = Some(ok); eprintln!("fbbootlogd: handoff finished"); } @@ -117,13 +129,17 @@ impl Display { } } - fn handle_sync_rect(map: Arc>, cmd_rx: Receiver) { + fn handle_sync_rect(map: Arc>>, cmd_rx: Receiver) { while let Ok(cmd) = cmd_rx.recv() { match cmd { DisplayCommand::SyncRects(sync_rects) => { // We may not hold this lock across the write call to avoid deadlocking if the // graphics driver tries to write to the bootlog. - let display_handle = map.lock().unwrap().display_handle.clone(); + let display_handle = if let Some(map) = &*map.lock().unwrap() { + map.display_handle.clone() + } else { + continue; + }; display_handle.sync_rects(&sync_rects).unwrap(); } } diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 3447a91466..1cf0adb5c3 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -55,19 +55,21 @@ impl Scheme for FbbootlogScheme { } fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { - let mut map = self.display.map.lock().unwrap(); - let damage = self.text_screen.write( - &mut console_draw::DisplayMap { - offscreen: map.inner.ptr_mut(), - width: map.inner.width(), - height: map.inner.height(), - }, - buf, - &mut VecDeque::new(), - ); - drop(map); + let mut map_guard = self.display.map.lock().unwrap(); + if let Some(map) = &mut *map_guard { + let damage = self.text_screen.write( + &mut console_draw::DisplayMap { + offscreen: map.inner.ptr_mut(), + width: map.inner.width(), + height: map.inner.height(), + }, + buf, + &mut VecDeque::new(), + ); + drop(map_guard); - self.display.sync_rects(damage); + self.display.sync_rects(damage); + } Ok(buf.len()) } diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index d45b055cb1..c3cb227a08 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -8,7 +8,7 @@ authors = ["Anhad Singh "] anyhow = "1.0.71" log = "0.4.19" redox-daemon = "0.1.2" -redox_syscall = "0.5" +redox_syscall = { version = "0.5", features = ["std"] } orbclient = "0.3.27" libredox = "0.1.3" diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 877e3f3145..a2482cef23 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -32,8 +32,7 @@ impl ConsumerHandle { pub fn open_display(&self) -> Result { let mut buffer = [0; 1024]; let fd = self.0.as_raw_fd(); - let written = libredox::call::fpath(fd as usize, &mut buffer) - .expect("init: failed to get the path to the display device"); + let written = libredox::call::fpath(fd as usize, &mut buffer)?; assert!(written <= buffer.len()); From 2a71d48a767c86de9d6480585e6e0570eb879699 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Mar 2025 19:24:30 +0100 Subject: [PATCH 1091/1301] inputd: Don't crash when receiving input while there is no active vt --- inputd/src/main.rs | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index edd0be1a33..93e6b83fdb 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -420,23 +420,24 @@ impl Scheme for InputScheme { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; assert!(handle.is_producer()); - let active_vt = self.active_vt.unwrap(); - for handle in self.handles.values_mut() { - match handle { - Handle::Consumer { - pending, - notified, - vt, - .. - } => { - if *vt != active_vt { - continue; - } + if let Some(active_vt) = self.active_vt { + for handle in self.handles.values_mut() { + match handle { + Handle::Consumer { + pending, + notified, + vt, + .. + } => { + if *vt != active_vt { + continue; + } - pending.extend_from_slice(buf); - *notified = false; + pending.extend_from_slice(buf); + *notified = false; + } + _ => continue, } - _ => continue, } } From 4f2268bbfe3d95639474a35d91cec6ba3fa2e868 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Mar 2025 19:24:56 +0100 Subject: [PATCH 1092/1301] graphics/vesad: Exit gracefully when there is no boot framebuffer --- graphics/vesad/src/main.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index fa1b8bd53e..541ce13d79 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -21,6 +21,11 @@ fn main() { spec.push(()); } + if env::var("FRAMEBUFFER_WIDTH").is_err() { + println!("vesad: No boot framebuffer"); + return; + } + let width = usize::from_str_radix( &env::var("FRAMEBUFFER_WIDTH").expect("FRAMEBUFFER_WIDTH not set"), 16, @@ -48,6 +53,7 @@ fn main() { ); if phys == 0 { + println!("vesad: Boot framebuffer at address 0"); return; } From fe31bd0578acc67281aca0829eaae9b3df42ca61 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Mar 2025 20:00:29 +0100 Subject: [PATCH 1093/1301] inputd: Remove deactivate event It is no longer useful now that virtio-gpud permanently takes over control of the display when it starts. --- graphics/driver-graphics/src/lib.rs | 5 ----- inputd/src/lib.rs | 1 - inputd/src/main.rs | 13 ------------- 3 files changed, 19 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 147802dc60..c35b88bcd8 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -96,11 +96,6 @@ impl GraphicsScheme { } } - VtEventKind::Deactivate => { - log::info!("deactivate {}", vt_event.vt); - // nothing to do :) - } - VtEventKind::Resize => { log::warn!("driver-graphics: resize is not implemented yet") } diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index a2482cef23..239c5f1b52 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -118,7 +118,6 @@ impl ControlHandle { #[repr(usize)] pub enum VtEventKind { Activate, - Deactivate, Resize, } diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 93e6b83fdb..218da3c62f 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -120,19 +120,6 @@ impl InputScheme { device, .. } => { - if let Some(active_vt) = self.active_vt { - if &self.vts[&active_vt].display == &*device { - pending.push(VtEvent { - kind: VtEventKind::Deactivate, - vt: self.active_vt.unwrap(), - width: 0, - height: 0, - stride: 0, - }); - *notified = false; - } - } - if &self.vts[&new_active].display == &*device { pending.push(VtEvent { kind: VtEventKind::Activate, From e7fe3183b0c3aa4c41cc55ac548ace4924bbf29d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 12:36:35 +0100 Subject: [PATCH 1094/1301] Make all pcid_interface methods abort the process on errors Effectively the only way to recover from errors in the communication with pcid is by restarting the driver from scratch possibly after restarting pcid. As such moving the aborts from individual drivers to pcid_interface simplifies drivers while at the same time allowing nicer error messages. --- Cargo.lock | 1 - audio/ac97d/src/main.rs | 3 +- audio/ihdad/src/main.rs | 24 +--- common/Cargo.toml | 2 +- graphics/bgad/src/main.rs | 3 +- graphics/virtio-gpud/src/main.rs | 2 +- net/e1000d/src/main.rs | 8 +- net/ixgbed/src/main.rs | 5 +- net/rtl8139d/src/main.rs | 37 ++--- net/rtl8168d/src/main.rs | 37 ++--- net/virtio-netd/src/main.rs | 2 +- pcid-spawner/src/main.rs | 2 +- pcid/Cargo.toml | 1 - pcid/src/driver_interface/mod.rs | 225 +++++++++++++++++-------------- storage/ahcid/src/main.rs | 7 +- storage/ided/src/main.rs | 3 +- storage/nvmed/src/main.rs | 29 ++-- storage/virtio-blkd/src/main.rs | 2 +- vboxd/src/main.rs | 8 +- virtio-core/src/arch/x86.rs | 6 +- virtio-core/src/probe.rs | 4 +- virtio-core/src/transport.rs | 8 -- xhcid/src/main.rs | 34 ++--- 23 files changed, 191 insertions(+), 262 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 484b372504..e101de9edb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -971,7 +971,6 @@ dependencies = [ "redox-scheme 0.4.0", "redox_syscall", "serde", - "thiserror", ] [[package]] diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index a7a8c0327f..92bd69db41 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -18,8 +18,7 @@ use syscall::{Packet, SchemeBlockMut}; pub mod device; fn main() { - let pcid_handle = - PciFunctionHandle::connect_default().expect("ac97d: failed to setup channel to pcid"); + let pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 231b32e926..e9a91590ec 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -31,19 +31,14 @@ QEMU ICH9 8086:293E fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.config(); - let all_pci_features = pcid_handle - .fetch_all_features() - .expect("ihdad: failed to fetch pci features"); + let all_pci_features = pcid_handle.fetch_all_features(); log::debug!("PCI FEATURES: {:?}", all_pci_features); let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); if has_msi && !has_msix { - let capability = match pcid_handle - .feature_info(PciFeature::Msi) - .expect("ihdad: failed to retrieve the MSI capability structure from pcid") - { + let capability = match pcid_handle.feature_info(PciFeature::Msi) { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), }; @@ -61,13 +56,9 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; - pcid_handle - .set_feature_info(SetFeatureInfo::Msi(set_feature_info)) - .expect("ihdad: failed to set feature info"); + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - pcid_handle - .enable_feature(PciFeature::Msi) - .expect("ihdad: failed to enable MSI"); + pcid_handle.enable_feature(PciFeature::Msi); log::debug!("Enabled MSI"); interrupt_handle @@ -103,8 +94,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::LevelFilter::Info, ); - let mut pcid_handle = - PciFunctionHandle::connect_default().expect("ihdad: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); @@ -113,9 +103,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::info!(" + IHDA {}", pci_config.func.display()); - let address = unsafe { pcid_handle.map_bar(0).expect("ihdad") } - .ptr - .as_ptr() as usize; + let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); diff --git a/common/Cargo.toml b/common/Cargo.toml index 50437c7d4b..278e00c9c3 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -10,5 +10,5 @@ license = "MIT" [dependencies] libredox = "0.1.3" log = "0.4" -redox_syscall = "0.5" +redox_syscall = { version = "0.5", features = ["std"] } redox-log = "0.1.2" diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index a208db2b27..72824703ed 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -17,8 +17,7 @@ mod bga; mod scheme; fn main() { - let pcid_handle = - PciFunctionHandle::connect_default().expect("bgad: failed to setup channel to pcid"); + let pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 8170c6f33b..6b0b62f3fe 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -361,7 +361,7 @@ impl XferToHost2d { static DEVICE: spin::Once = spin::Once::new(); fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { - let mut pcid_handle = PciFunctionHandle::connect_default()?; + let mut pcid_handle = PciFunctionHandle::connect_default(); // Double check that we have the right device. // diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index 4d2299d89e..412986739a 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -8,8 +8,7 @@ use pcid_interface::PciFunctionHandle; pub mod device; fn main() { - let mut pcid_handle = - PciFunctionHandle::connect_default().expect("e1000d: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); @@ -25,10 +24,7 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let mut irq_file = irq.irq_handle("e1000d"); - let address = unsafe { pcid_handle.map_bar(0) } - .expect("e1000d") - .ptr - .as_ptr() as usize; + let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; let device = unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }; diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index a066c3db0a..c6ea98600f 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -10,8 +10,7 @@ pub mod device; mod ixgbe; fn main() { - let mut pcid_handle = - PciFunctionHandle::connect_default().expect("ixgbed: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); @@ -27,7 +26,7 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { let mut irq_file = irq.irq_handle("ixgbed"); - let mapped_bar = unsafe { pcid_handle.map_bar(0) }.expect("ixgbed"); + let mapped_bar = unsafe { pcid_handle.map_bar(0) }; let address = mapped_bar.ptr.as_ptr(); let size = mapped_bar.bar_size; diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index a8ff4dab49..c0272136c7 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -47,19 +47,14 @@ impl MappedMsixRegs { fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.config(); - let all_pci_features = pcid_handle - .fetch_all_features() - .expect("rtl8139d: failed to fetch pci features"); + let all_pci_features = pcid_handle.fetch_all_features(); log::info!("PCI FEATURES: {:?}", all_pci_features); let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); if has_msi && !has_msix { - let capability = match pcid_handle - .feature_info(PciFeature::Msi) - .expect("rtl8139d: failed to retrieve the MSI capability structure from pcid") - { + let capability = match pcid_handle.feature_info(PciFeature::Msi) { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), }; @@ -77,27 +72,20 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; - pcid_handle - .set_feature_info(SetFeatureInfo::Msi(set_feature_info)) - .expect("rtl8139d: failed to set feature info"); + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - pcid_handle - .enable_feature(PciFeature::Msi) - .expect("rtl8139d: failed to enable MSI"); + pcid_handle.enable_feature(PciFeature::Msi); log::info!("Enabled MSI"); interrupt_handle } else if has_msix { - let msix_info = match pcid_handle - .feature_info(PciFeature::MsiX) - .expect("rtl8139d: failed to retrieve the MSI-X capability structure from pcid") - { + let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; msix_info.validate(pci_config.func.bars); - let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar).expect("rtl8139d") } + let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar) } .ptr .as_ptr() as usize; @@ -127,9 +115,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { interrupt_handle }; - pcid_handle - .enable_feature(PciFeature::MsiX) - .expect("rtl8139d: failed to enable MSI-X"); + pcid_handle.enable_feature(PciFeature::MsiX); log::info!("Enabled MSI-X"); method @@ -161,11 +147,7 @@ fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { for &barnum in &[2, 1] { match config.func.bars[usize::from(barnum)] { pcid_interface::PciBar::Memory32 { .. } | pcid_interface::PciBar::Memory64 { .. } => unsafe { - return pcid_handle - .map_bar(barnum) - .expect("rtl8139d: failed to map address") - .ptr - .as_ptr(); + return pcid_handle.map_bar(barnum).ptr.as_ptr(); }, other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), } @@ -182,8 +164,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::LevelFilter::Info, ); - let mut pcid_handle = - PciFunctionHandle::connect_default().expect("rtl8139d: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 50fefba7aa..44150572f7 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -47,19 +47,14 @@ impl MappedMsixRegs { fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.config(); - let all_pci_features = pcid_handle - .fetch_all_features() - .expect("rtl8168d: failed to fetch pci features"); + let all_pci_features = pcid_handle.fetch_all_features(); log::info!("PCI FEATURES: {:?}", all_pci_features); let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); if has_msi && !has_msix { - let capability = match pcid_handle - .feature_info(PciFeature::Msi) - .expect("rtl8168d: failed to retrieve the MSI capability structure from pcid") - { + let capability = match pcid_handle.feature_info(PciFeature::Msi) { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), }; @@ -77,27 +72,20 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; - pcid_handle - .set_feature_info(SetFeatureInfo::Msi(set_feature_info)) - .expect("rtl8168d: failed to set feature info"); + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - pcid_handle - .enable_feature(PciFeature::Msi) - .expect("rtl8168d: failed to enable MSI"); + pcid_handle.enable_feature(PciFeature::Msi); log::info!("Enabled MSI"); interrupt_handle } else if has_msix { - let msix_info = match pcid_handle - .feature_info(PciFeature::MsiX) - .expect("rtl8168d: failed to retrieve the MSI-X capability structure from pcid") - { + let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; msix_info.validate(pci_config.func.bars); - let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar).expect("rtl8168d") } + let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar) } .ptr .as_ptr() as usize; @@ -127,9 +115,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { interrupt_handle }; - pcid_handle - .enable_feature(PciFeature::MsiX) - .expect("rtl8168d: failed to enable MSI-X"); + pcid_handle.enable_feature(PciFeature::MsiX); log::info!("Enabled MSI-X"); method @@ -161,11 +147,7 @@ fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { for &barnum in &[2, 1] { match config.func.bars[usize::from(barnum)] { pcid_interface::PciBar::Memory32 { .. } | pcid_interface::PciBar::Memory64 { .. } => unsafe { - return pcid_handle - .map_bar(barnum) - .expect("rtl8168d: failed to map address") - .ptr - .as_ptr(); + return pcid_handle.map_bar(barnum).ptr.as_ptr(); }, other => log::warn!("BAR {} is {:?} instead of memory BAR", barnum, other), } @@ -182,8 +164,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::LevelFilter::Info, ); - let mut pcid_handle = - PciFunctionHandle::connect_default().expect("rtl8168d: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index c2c4a798dc..ac4c2fa92b 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -28,7 +28,7 @@ static_assertions::const_assert_eq!(core::mem::size_of::(), 12); const MAX_BUFFER_LEN: usize = 65535; fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box> { - let mut pcid_handle = PciFunctionHandle::connect_default()?; + let mut pcid_handle = PciFunctionHandle::connect_default(); // Double check that we have the right device. // diff --git a/pcid-spawner/src/main.rs b/pcid-spawner/src/main.rs index a8ac5d5e13..e99ce2e320 100644 --- a/pcid-spawner/src/main.rs +++ b/pcid-spawner/src/main.rs @@ -83,7 +83,7 @@ fn main() -> Result<()> { log::info!("pcid-spawner: spawn {:?}", command); - handle.enable_device()?; + handle.enable_device(); let channel_fd = handle.into_inner_fd(); command.env("PCID_CLIENT_CHANNEL", channel_fd.to_string()); diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index b2d6b51317..78f0192346 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -23,7 +23,6 @@ redox-daemon = "0.1" redox-scheme = "0.4" redox_syscall = "0.5.9" serde = { version = "1", features = ["derive"] } -thiserror = "1" common = { path = "../common" } libredox = "0.1.3" diff --git a/pcid/src/driver_interface/mod.rs b/pcid/src/driver_interface/mod.rs index 7365276dc9..d1fa8d733d 100644 --- a/pcid/src/driver_interface/mod.rs +++ b/pcid/src/driver_interface/mod.rs @@ -1,13 +1,12 @@ -use std::fmt; use std::fs::File; use std::io::prelude::*; use std::os::fd::{FromRawFd, IntoRawFd, RawFd}; use std::path::Path; use std::ptr::NonNull; use std::{env, io}; +use std::{fmt, process}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; -use thiserror::Error; pub use bar::PciBar; pub use cap::VendorSpecificCapability; @@ -186,25 +185,6 @@ pub enum PciFeatureInfo { MsiX(msi::MsixInfo), } -#[derive(Debug, Error)] -pub enum PcidClientHandleError { - #[error("i/o error: {0}")] - IoError(#[from] io::Error), - - #[error("JSON ser/de error: {0}")] - SerializationError(#[from] bincode::Error), - - #[error("environment variable error: {0}")] - EnvError(#[from] env::VarError), - - #[error("malformed fd: {0}")] - EnvValidityError(std::num::ParseIntError), - - #[error("invalid response: {0:?}")] - InvalidResponse(PcidClientResponse), -} -pub type Result = std::result::Result; - // TODO: Remove these "features" and just go strait to the actual thing. #[derive(Debug, Default, Serialize, Deserialize)] @@ -286,75 +266,91 @@ pub struct PciFunctionHandle { mapped_bars: [Option; 6], } -#[doc(hidden)] -pub fn send(w: &mut W, message: &T) -> Result<()> { +fn send(w: &mut File, message: &T) { let mut data = Vec::new(); - bincode::serialize_into(&mut data, message)?; - assert_eq!(w.write(&data)?, data.len()); - Ok(()) + bincode::serialize_into(&mut data, message).expect("couldn't serialize pcid message"); + match w.write(&data) { + Ok(len) => assert_eq!(len, data.len()), + Err(err) => { + log::error!("writing pcid request failed: {err}"); + process::exit(1); + } + } } -#[doc(hidden)] -pub fn recv(r: &mut R) -> Result { +fn recv(r: &mut File) -> T { let mut length_bytes = [0u8; 8]; - r.read_exact(&mut length_bytes)?; + if let Err(err) = r.read_exact(&mut length_bytes) { + log::error!("reading pcid response length failed: {err}"); + process::exit(1); + } let length = u64::from_le_bytes(length_bytes); if length > 0x100_000 { panic!("pcid_interface: buffer too large"); } let mut data = vec![0u8; length as usize]; - r.read_exact(&mut data)?; + if let Err(err) = r.read_exact(&mut data) { + log::error!("reading pcid response failed: {err}"); + process::exit(1); + } - Ok(bincode::deserialize_from(&data[..])?) + bincode::deserialize_from(&data[..]).expect("couldn't deserialize pcid message") } impl PciFunctionHandle { - pub fn connect_default() -> Result { - let channel_fd = env::var("PCID_CLIENT_CHANNEL")? - .parse::() - .map_err(PcidClientHandleError::EnvValidityError)?; + pub fn connect_default() -> Self { + let channel_fd = match env::var("PCID_CLIENT_CHANNEL") { + Ok(channel_fd) => channel_fd, + Err(err) => { + log::error!("PCID_CLIENT_CHANNEL invalid: {err}"); + process::exit(1); + } + }; + let channel_fd = match channel_fd.parse::() { + Ok(channel_fd) => channel_fd, + Err(err) => { + log::error!("PCID_CLIENT_CHANNEL invalid: {err}"); + process::exit(1); + } + }; Self::connect_common(channel_fd) } - pub fn connect_by_path(device_path: &Path) -> Result { + pub fn connect_by_path(device_path: &Path) -> io::Result { let channel_fd = syscall::open( device_path.join("channel").to_str().unwrap(), syscall::O_RDWR, ) - .map_err(|err| { - PcidClientHandleError::IoError(io::Error::other(format!( - "failed to open pcid channel: {}", - err - ))) - })?; - Self::connect_common(channel_fd as RawFd) + .map_err(|err| io::Error::other(format!("failed to open pcid channel: {}", err)))?; + Ok(Self::connect_common(channel_fd as RawFd)) } - fn connect_common( - channel_fd: i32, - ) -> std::result::Result { + fn connect_common(channel_fd: i32) -> PciFunctionHandle { let mut channel = unsafe { File::from_raw_fd(channel_fd) }; - send(&mut channel, &PcidClientRequest::RequestConfig)?; - let config = match recv(&mut channel)? { + send(&mut channel, &PcidClientRequest::RequestConfig); + let config = match recv(&mut channel) { PcidClientResponse::Config(a) => a, - other => return Err(PcidClientHandleError::InvalidResponse(other)), + other => { + log::error!("received wrong pcid response: {other:?}"); + process::exit(1); + } }; - Ok(Self { + Self { channel, config, mapped_bars: [const { None }; 6], - }) + } } pub fn into_inner_fd(self) -> RawFd { self.channel.into_raw_fd() } - fn send(&mut self, req: &PcidClientRequest) -> Result<()> { + fn send(&mut self, req: &PcidClientRequest) { send(&mut self.channel, req) } - fn recv(&mut self) -> Result { + fn recv(&mut self) -> PcidClientResponse { recv(&mut self.channel) } @@ -362,73 +358,97 @@ impl PciFunctionHandle { self.config.clone() } - pub fn enable_device(&mut self) -> Result<()> { - self.send(&PcidClientRequest::EnableDevice)?; - match self.recv()? { - PcidClientResponse::EnabledDevice => Ok(()), - other => Err(PcidClientHandleError::InvalidResponse(other)), + pub fn enable_device(&mut self) { + self.send(&PcidClientRequest::EnableDevice); + match self.recv() { + PcidClientResponse::EnabledDevice => {} + other => { + log::error!("received wrong pcid response: {other:?}"); + process::exit(1); + } } } - pub fn get_vendor_capabilities(&mut self) -> Result> { - self.send(&PcidClientRequest::RequestVendorCapabilities)?; - match self.recv()? { - PcidClientResponse::VendorCapabilities(a) => Ok(a), - other => Err(PcidClientHandleError::InvalidResponse(other)), + pub fn get_vendor_capabilities(&mut self) -> Vec { + self.send(&PcidClientRequest::RequestVendorCapabilities); + match self.recv() { + PcidClientResponse::VendorCapabilities(a) => a, + other => { + log::error!("received wrong pcid response: {other:?}"); + process::exit(1); + } } } // FIXME turn into struct with bool fields - pub fn fetch_all_features(&mut self) -> Result> { - self.send(&PcidClientRequest::RequestFeatures)?; - match self.recv()? { - PcidClientResponse::AllFeatures(a) => Ok(a), - other => Err(PcidClientHandleError::InvalidResponse(other)), + pub fn fetch_all_features(&mut self) -> Vec { + self.send(&PcidClientRequest::RequestFeatures); + match self.recv() { + PcidClientResponse::AllFeatures(a) => a, + other => { + log::error!("received wrong pcid response: {other:?}"); + process::exit(1); + } } } - pub fn enable_feature(&mut self, feature: PciFeature) -> Result<()> { - self.send(&PcidClientRequest::EnableFeature(feature))?; - match self.recv()? { - PcidClientResponse::FeatureEnabled(feat) if feat == feature => Ok(()), - other => Err(PcidClientHandleError::InvalidResponse(other)), + pub fn enable_feature(&mut self, feature: PciFeature) { + self.send(&PcidClientRequest::EnableFeature(feature)); + match self.recv() { + PcidClientResponse::FeatureEnabled(feat) if feat == feature => {} + other => { + log::error!("received wrong pcid response: {other:?}"); + process::exit(1); + } } } - pub fn feature_info(&mut self, feature: PciFeature) -> Result { - self.send(&PcidClientRequest::FeatureInfo(feature))?; - match self.recv()? { - PcidClientResponse::FeatureInfo(feat, info) if feat == feature => Ok(info), - other => Err(PcidClientHandleError::InvalidResponse(other)), + pub fn feature_info(&mut self, feature: PciFeature) -> PciFeatureInfo { + self.send(&PcidClientRequest::FeatureInfo(feature)); + match self.recv() { + PcidClientResponse::FeatureInfo(feat, info) if feat == feature => info, + other => { + log::error!("received wrong pcid response: {other:?}"); + process::exit(1); + } } } - pub fn set_feature_info(&mut self, info: SetFeatureInfo) -> Result<()> { - self.send(&PcidClientRequest::SetFeatureInfo(info))?; - match self.recv()? { - PcidClientResponse::SetFeatureInfo(_) => Ok(()), - other => Err(PcidClientHandleError::InvalidResponse(other)), + pub fn set_feature_info(&mut self, info: SetFeatureInfo) { + self.send(&PcidClientRequest::SetFeatureInfo(info)); + match self.recv() { + PcidClientResponse::SetFeatureInfo(_) => {} + other => { + log::error!("received wrong pcid response: {other:?}"); + process::exit(1); + } } } - pub unsafe fn read_config(&mut self, offset: u16) -> Result { - self.send(&PcidClientRequest::ReadConfig(offset))?; - match self.recv()? { - PcidClientResponse::ReadConfig(value) => Ok(value), - other => Err(PcidClientHandleError::InvalidResponse(other)), + pub unsafe fn read_config(&mut self, offset: u16) -> u32 { + self.send(&PcidClientRequest::ReadConfig(offset)); + match self.recv() { + PcidClientResponse::ReadConfig(value) => value, + other => { + log::error!("received wrong pcid response: {other:?}"); + process::exit(1); + } } } - pub unsafe fn write_config(&mut self, offset: u16, value: u32) -> Result<()> { - self.send(&PcidClientRequest::WriteConfig(offset, value))?; - match self.recv()? { - PcidClientResponse::WriteConfig => Ok(()), - other => Err(PcidClientHandleError::InvalidResponse(other)), + pub unsafe fn write_config(&mut self, offset: u16, value: u32) { + self.send(&PcidClientRequest::WriteConfig(offset, value)); + match self.recv() { + PcidClientResponse::WriteConfig => {} + other => { + log::error!("received wrong pcid response: {other:?}"); + process::exit(1); + } } } - pub unsafe fn map_bar(&mut self, bir: u8) -> Result<&MappedBar> { + pub unsafe fn map_bar(&mut self, bir: u8) -> &MappedBar { let mapped_bar = &mut self.mapped_bars[bir as usize]; if let Some(mapped_bar) = mapped_bar { - Ok(mapped_bar) + mapped_bar } else { let (bar, bar_size) = self.config.func.bars[bir as usize].expect_mem(); - let ptr = unsafe { + let ptr = match unsafe { common::physmap( bar, bar_size, @@ -436,13 +456,18 @@ impl PciFunctionHandle { // FIXME once the kernel supports this use write-through for prefetchable BAR common::MemoryType::Uncacheable, ) - } - .map_err(|err| io::Error::other(format!("failed to map BAR at {bar:016X}: {err}")))?; + } { + Ok(ptr) => ptr, + Err(err) => { + log::error!("failed to map BAR at {bar:016X}: {err}"); + process::exit(1); + } + }; - Ok(mapped_bar.insert(MappedBar { + mapped_bar.insert(MappedBar { ptr: NonNull::new(ptr.cast::()).expect("Mapping a BAR resulted in a nullptr"), bar_size, - })) + }) } } } diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 89467e04ce..1c5239c1b5 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -25,8 +25,7 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let mut pcid_handle = - PciFunctionHandle::connect_default().expect("ahcid: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); @@ -47,9 +46,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { info!(" + AHCI {}", pci_config.func.display()); - let address = unsafe { pcid_handle.map_bar(5).expect("ahcid") } - .ptr - .as_ptr() as usize; + let address = unsafe { pcid_handle.map_bar(5) }.ptr.as_ptr() as usize; { let scheme_name = format!("disk.{}", name); let socket = Socket::nonblock(&scheme_name).expect("ahcid: failed to create disk scheme"); diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 068477cbd7..2bf9c7c3e9 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -28,8 +28,7 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let pcid_handle = - PciFunctionHandle::connect_default().expect("ided: failed to setup channel to pcid"); + let pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 420f1e17e7..93bd7e47c9 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -26,7 +26,7 @@ fn get_int_method( log::trace!("Begin get_int_method"); use pcid_interface::irq_helpers; - let features = pcid_handle.fetch_all_features().unwrap(); + let features = pcid_handle.fetch_all_features(); let has_msi = features.iter().any(|feature| feature.is_msi()); let has_msix = features.iter().any(|feature| feature.is_msix()); @@ -37,13 +37,13 @@ fn get_int_method( use self::nvme::MappedMsixRegs; use pcid_interface::msi::MsixTableEntry; - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX).unwrap() { + let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { PciFeatureInfo::MsiX(msix) => msix, _ => unreachable!(), }; msix_info.validate(function.bars); fn bar_base(pcid_handle: &mut PciFunctionHandle, bir: u8) -> Result> { - Ok(unsafe { pcid_handle.map_bar(bir) }.expect("nvmed").ptr) + Ok(unsafe { pcid_handle.map_bar(bir) }.ptr) } let table_bar_base: *mut u8 = bar_base(pcid_handle, msix_info.table_bar)?.as_ptr(); let table_base = unsafe { table_bar_base.offset(msix_info.table_offset as isize) }; @@ -59,7 +59,7 @@ fn get_int_method( table_entry.mask(); } - pcid_handle.enable_feature(PciFeature::MsiX).unwrap(); + pcid_handle.enable_feature(PciFeature::MsiX); let (msix_vector_number, irq_handle) = { let entry: &mut MsixTableEntry = &mut table_entries[0]; @@ -84,7 +84,7 @@ fn get_int_method( Ok((interrupt_method, interrupt_sources)) } else if has_msi { // Message signaled interrupts. - let msi_info = match pcid_handle.feature_info(PciFeature::Msi).unwrap() { + let msi_info = match pcid_handle.feature_info(PciFeature::Msi) { PciFeatureInfo::Msi(msi) => msi, _ => unreachable!(), }; @@ -97,13 +97,11 @@ fn get_int_method( let (msg_addr_and_data, irq_handle) = irq_helpers::allocate_single_interrupt_vector_for_msi(bsp_cpu_id); - pcid_handle - .set_feature_info(SetFeatureInfo::Msi(MsiSetFeatureInfo { - message_address_and_data: Some(msg_addr_and_data), - multi_message_enable: Some(0), // enable 2^0=1 vectors - mask_bits: None, - })) - .unwrap(); + pcid_handle.set_feature_info(SetFeatureInfo::Msi(MsiSetFeatureInfo { + message_address_and_data: Some(msg_addr_and_data), + multi_message_enable: Some(0), // enable 2^0=1 vectors + mask_bits: None, + })); (0, irq_handle) }; @@ -115,7 +113,7 @@ fn get_int_method( let interrupt_sources = InterruptSources::Msi(std::iter::once((msi_vector_number, irq_handle)).collect()); - pcid_handle.enable_feature(PciFeature::Msi).unwrap(); + pcid_handle.enable_feature(PciFeature::Msi); Ok((interrupt_method, interrupt_sources)) } else if let Some(irq) = function.legacy_interrupt_line { @@ -146,8 +144,7 @@ fn main() { redox_daemon::Daemon::new(daemon).expect("nvmed: failed to daemonize"); } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let mut pcid_handle = - PciFunctionHandle::connect_default().expect("nvmed: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); let scheme_name = format!("disk.{}-nvme", pci_config.func.name()); @@ -162,7 +159,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::debug!("NVME PCI CONFIG: {:?}", pci_config); - let address = unsafe { pcid_handle.map_bar(0).expect("nvmed").ptr }; + let address = unsafe { pcid_handle.map_bar(0).ptr }; let socket = Socket::create(&scheme_name).expect("nvmed: failed to create disk scheme"); diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 2db8ab4779..ac94312eef 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -107,7 +107,7 @@ pub struct BlockVirtRequest { const_assert_eq!(core::mem::size_of::(), 16); fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { - let mut pcid_handle = PciFunctionHandle::connect_default()?; + let mut pcid_handle = PciFunctionHandle::connect_default(); // Double check that we have the right device. // diff --git a/vboxd/src/main.rs b/vboxd/src/main.rs index 63935cf0a8..cac69b6d0d 100644 --- a/vboxd/src/main.rs +++ b/vboxd/src/main.rs @@ -191,8 +191,7 @@ impl VboxGuestInfo { } fn main() { - let mut pcid_handle = - PciFunctionHandle::connect_default().expect("vboxd: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); @@ -237,10 +236,7 @@ fn main() { let mut irq_file = irq.irq_handle("vboxd"); let mut port = Pio::::new(bar0 as u16); - let address = unsafe { pcid_handle.map_bar(1) } - .expect("vboxd") - .ptr - .as_ptr(); + let address = unsafe { pcid_handle.map_bar(1) }.ptr.as_ptr(); { let vmmdev = unsafe { &mut *(address as *mut VboxVmmDev) }; diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index ebea0f9aa7..7275c63e41 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -12,13 +12,13 @@ pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { let pci_config = pcid_handle.config(); // Extended message signaled interrupts. - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX)? { + let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { PciFeatureInfo::MsiX(capability) => capability, _ => unreachable!(), }; msix_info.validate(pci_config.func.bars); - let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar)? } + let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar) } .ptr .as_ptr() as usize; let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; @@ -43,7 +43,7 @@ pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { interrupt_handle }; - pcid_handle.enable_feature(PciFeature::MsiX)?; + pcid_handle.enable_feature(PciFeature::MsiX); log::info!("virtio: using MSI-X (interrupt_handle={interrupt_handle:?})"); Ok(interrupt_handle) diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index aa67b2e71c..25cf1efb92 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -66,7 +66,7 @@ pub fn probe_device(pcid_handle: &mut PciFunctionHandle) -> Result Result for Error { - fn from(value: pcid_interface::PcidClientHandleError) -> Self { - Self::PcidClientHandle(value) - } -} - /// Returns the queue part sizes in bytes. /// /// ## Reference diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 7f9dc09b39..67bec0174c 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -62,19 +62,14 @@ fn get_int_method( ) -> (Option, InterruptMethod) { let pci_config = pcid_handle.config(); - let all_pci_features = pcid_handle - .fetch_all_features() - .expect("xhcid: failed to fetch pci features"); + let all_pci_features = pcid_handle.fetch_all_features(); log::debug!("XHCI PCI FEATURES: {:?}", all_pci_features); let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); if has_msi && !has_msix { - let mut capability = match pcid_handle - .feature_info(PciFeature::Msi) - .expect("xhcid: failed to retrieve the MSI capability structure from pcid") - { + let mut capability = match pcid_handle.feature_info(PciFeature::Msi) { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), }; @@ -92,21 +87,14 @@ fn get_int_method( message_address_and_data: Some(msg_addr_and_data), mask_bits: None, }; - pcid_handle - .set_feature_info(SetFeatureInfo::Msi(set_feature_info)) - .expect("xhcid: failed to set feature info"); + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - pcid_handle - .enable_feature(PciFeature::Msi) - .expect("xhcid: failed to enable MSI"); + pcid_handle.enable_feature(PciFeature::Msi); log::debug!("Enabled MSI"); (Some(interrupt_handle), InterruptMethod::Msi) } else if has_msix { - let msix_info = match pcid_handle - .feature_info(PciFeature::MsiX) - .expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") - { + let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; @@ -142,9 +130,7 @@ fn get_int_method( ) }; - pcid_handle - .enable_feature(PciFeature::MsiX) - .expect("xhcid: failed to enable MSI-X"); + pcid_handle.enable_feature(PciFeature::MsiX); log::debug!("Enabled MSI-X"); method @@ -181,8 +167,7 @@ fn main() { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - let mut pcid_handle = - PciFunctionHandle::connect_default().expect("xhcid: failed to setup channel to pcid"); + let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); @@ -198,10 +183,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::debug!("XHCI PCI CONFIG: {:?}", pci_config); - let address = unsafe { pcid_handle.map_bar(0) } - .expect("xhcid") - .ptr - .as_ptr() as usize; + let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle, address); //TODO: Fix interrupts. From 9779d1884eb8e3390763f9faad4dfc6b84c0899a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 14:07:39 +0100 Subject: [PATCH 1095/1301] inputd: Remove the active vt check before post_fevent No input is added to pending anyway when the vt for the consumer isn't the active vt anyway. --- inputd/src/main.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 218da3c62f..0667fca53e 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -560,7 +560,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { pending, needs_handoff, ref mut notified, - vt, + .. } => { if (!*needs_handoff && pending.is_empty()) || *notified @@ -569,14 +569,6 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { continue; } - let active_vt = scheme.active_vt.unwrap(); - - // The activate VT is not the same as the VT that the consumer is listening to - // for events. - if !*needs_handoff && active_vt != *vt { - continue; - } - // Notify the consumer that we have some events to read. Yum yum. socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?; From de0239d3edd558b845dfe3fcd7f19b2ae702c9e8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 15:51:32 +0100 Subject: [PATCH 1096/1301] inputd: Automatically switch to first vt once created --- graphics/fbbootlogd/src/main.rs | 4 ---- graphics/vesad/src/main.rs | 3 --- inputd/src/main.rs | 5 +++++ 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index ca1c3863df..8584718c5d 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -26,16 +26,12 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { let mut scheme = FbbootlogScheme::new(); - let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); - // This is not possible for now as fbbootlogd needs to open new displays at runtime for graphics // driver handoff. In the future inputd may directly pass a handle to the display instead. //libredox::call::setrens(0, 0).expect("fbbootlogd: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); - inputd_control_handle.activate_vt(1).unwrap(); - loop { let request = match socket .next_request(SignalBehavior::Restart) diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 541ce13d79..3a74ee42e9 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -83,7 +83,6 @@ fn main() { } fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[()]) -> ! { let mut inputd_display_handle = DisplayHandle::new_early("vesa").unwrap(); - let mut inputd_control_handle = inputd::ControlHandle::new().unwrap(); for &() in spec.iter() { inputd_display_handle.register_vt().unwrap(); @@ -121,8 +120,6 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[( daemon.ready().expect("failed to notify parent"); - inputd_control_handle.activate_vt(1).unwrap(); - let all = [Source::Input, Source::Scheme]; for event in all .into_iter() diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 0667fca53e..97790238d7 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -266,6 +266,11 @@ impl Scheme for InputScheme { let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); log::info!("inputd: created VT #{vt} for {device}"); self.vts.insert(vt, Vt::new(device.clone())); + + if self.active_vt.is_none() { + self.switch_vt(vt)?; + } + Ok(vt) } else if buf.len() % size_of::() == 0 { let copy = core::cmp::min(pending.len(), buf.len() / size_of::()); From a0a8401e8d6a4acf5d3be031d8a5b20e1c8fbc4e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 16:03:24 +0100 Subject: [PATCH 1097/1301] inputd: Inline a couple of functions --- inputd/src/main.rs | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 97790238d7..ce902a44ed 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -46,25 +46,11 @@ enum Handle { Control, } -impl Handle { - pub fn is_producer(&self) -> bool { - matches!(self, Handle::Producer) - } -} - #[derive(Debug)] struct Vt { display: String, } -impl Vt { - fn new(display: impl Into) -> Self { - Self { - display: display.into(), - } - } -} - struct InputScheme { handles: BTreeMap, @@ -265,7 +251,12 @@ impl Scheme for InputScheme { // Trying to do an empty read creates a new VT. let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); log::info!("inputd: created VT #{vt} for {device}"); - self.vts.insert(vt, Vt::new(device.clone())); + self.vts.insert( + vt, + Vt { + display: device.clone(), + }, + ); if self.active_vt.is_none() { self.switch_vt(vt)?; @@ -410,7 +401,7 @@ impl Scheme for InputScheme { } let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; - assert!(handle.is_producer()); + assert!(matches!(handle, Handle::Producer)); if let Some(active_vt) = self.active_vt { for handle in self.handles.values_mut() { @@ -632,6 +623,6 @@ fn main() { _ => panic!("inputd: invalid argument: {}", val), } } else { - redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); + redox_daemon::Daemon::new(daemon_runner).expect("inputd: failed to daemonize"); } } From cd193f2aedea062a5fda195ce02260b8348ec55e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:03:23 +0100 Subject: [PATCH 1098/1301] inputd: Unconditionally perform handoff for all vts together In preparation for having a single set of graphics drivers for all vts. --- inputd/src/main.rs | 48 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index ce902a44ed..eb6caaadfd 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -162,7 +162,18 @@ impl Scheme for InputScheme { } "handle" => { let display = path_parts.collect::>().join("."); - self.maybe_perform_handoff_to = Some(display.clone()); + let needs_handoff = self.handles.values().all(|handle| { + !matches!( + handle, + Handle::Display { + is_earlyfb: false, + .. + } + ) + }); + if needs_handoff { + self.maybe_perform_handoff_to = Some(display.clone()); + } Handle::Display { events: EventFlags::empty(), pending: if let Some(active_vt) = self.active_vt { @@ -497,46 +508,19 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } if let Some(display) = scheme.maybe_perform_handoff_to.take() { - let early_displays = scheme - .handles - .values() - .filter_map(|handle| match handle { - Handle::Display { - device, - is_earlyfb: true, - .. - } => Some(&**device), - _ => None, - }) - .collect::>(); - let vts = scheme - .vts - .iter_mut() - .filter_map(|(&i, vt)| { - if early_displays.contains(&&*vt.display) { - vt.display = display.clone(); + scheme.has_new_events = true; - scheme.has_new_events = true; - - Some(i) - } else { - None - } - }) - .collect::>(); + for vt in scheme.vts.values_mut() { + vt.display = display.clone(); + } for handle in scheme.handles.values_mut() { match handle { Handle::Consumer { needs_handoff, notified, - vt, .. } => { - if !vts.contains(vt) { - continue; - } - *needs_handoff = true; *notified = false; } From ec442b87a3f109745cc25c76d152dc08fec82f3e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:23:27 +0100 Subject: [PATCH 1099/1301] inputd: Use a single global display rather than have a per-vt display selection --- inputd/src/main.rs | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index eb6caaadfd..b642d5f8aa 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -12,7 +12,7 @@ //! events are available. use core::mem::size_of; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; use std::mem::transmute; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -46,18 +46,14 @@ enum Handle { Control, } -#[derive(Debug)] -struct Vt { - display: String, -} - struct InputScheme { handles: BTreeMap, next_id: AtomicUsize, next_vt_id: AtomicUsize, - vts: BTreeMap, + display: Option, + vts: BTreeSet, super_key: bool, active_vt: Option, @@ -68,11 +64,13 @@ struct InputScheme { impl InputScheme { fn new() -> Self { Self { + handles: BTreeMap::new(), + next_id: AtomicUsize::new(0), next_vt_id: AtomicUsize::new(1), - handles: BTreeMap::new(), - vts: BTreeMap::new(), + display: None, + vts: BTreeSet::new(), super_key: false, active_vt: None, @@ -88,7 +86,7 @@ impl InputScheme { } } - if !self.vts.contains_key(&new_active) { + if !self.vts.contains(&new_active) { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); return Ok(()); } @@ -106,7 +104,7 @@ impl InputScheme { device, .. } => { - if &self.vts[&new_active].display == &*device { + if self.display.as_deref() == Some(&*device) { pending.push(VtEvent { kind: VtEventKind::Activate, vt: new_active, @@ -152,6 +150,9 @@ impl Scheme for InputScheme { } "handle_early" => { let display = path_parts.collect::>().join("."); + if self.display.is_none() { + self.maybe_perform_handoff_to = Some(display.clone()); + } Handle::Display { events: EventFlags::empty(), pending: Vec::new(), @@ -210,8 +211,8 @@ impl Scheme for InputScheme { let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; if let Handle::Consumer { vt, .. } = handle { - let display = self.vts.get(vt).ok_or(SysError::new(EINVAL))?; - let vt = format!("{}:{vt}", display.display); + let display = self.display.as_ref().ok_or(SysError::new(EINVAL))?; + let vt = format!("{}:{vt}", display); let size = core::cmp::min(vt.len(), buf.len()); buf[..size].copy_from_slice(&vt.as_bytes()[..size]); @@ -262,12 +263,7 @@ impl Scheme for InputScheme { // Trying to do an empty read creates a new VT. let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); log::info!("inputd: created VT #{vt} for {device}"); - self.vts.insert( - vt, - Vt { - display: device.clone(), - }, - ); + self.vts.insert(vt); if self.active_vt.is_none() { self.switch_vt(vt)?; @@ -385,7 +381,7 @@ impl Scheme for InputScheme { device, .. } => { - if &self.vts[&self.active_vt.unwrap()].display == &*device { + if self.display.as_ref() == Some(device) { pending.push(VtEvent { kind: VtEventKind::Resize, vt: self.active_vt.unwrap(), @@ -510,9 +506,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { if let Some(display) = scheme.maybe_perform_handoff_to.take() { scheme.has_new_events = true; - for vt in scheme.vts.values_mut() { - vt.display = display.clone(); - } + scheme.display = Some(display.clone()); for handle in scheme.handles.values_mut() { match handle { From f8972400ee7c7a57400eb72e9250ab9d12bbca41 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:36:41 +0100 Subject: [PATCH 1100/1301] inputd: Move handoff logic to fn open --- inputd/src/main.rs | 56 ++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index b642d5f8aa..44fb836074 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -58,7 +58,6 @@ struct InputScheme { active_vt: Option, has_new_events: bool, - maybe_perform_handoff_to: Option, } impl InputScheme { @@ -75,7 +74,6 @@ impl InputScheme { active_vt: None, has_new_events: false, - maybe_perform_handoff_to: None, } } @@ -151,7 +149,22 @@ impl Scheme for InputScheme { "handle_early" => { let display = path_parts.collect::>().join("."); if self.display.is_none() { - self.maybe_perform_handoff_to = Some(display.clone()); + self.has_new_events = true; + self.display = Some(display.clone()); + + for handle in self.handles.values_mut() { + match handle { + Handle::Consumer { + needs_handoff, + notified, + .. + } => { + *needs_handoff = true; + *notified = false; + } + _ => continue, + } + } } Handle::Display { events: EventFlags::empty(), @@ -173,7 +186,22 @@ impl Scheme for InputScheme { ) }); if needs_handoff { - self.maybe_perform_handoff_to = Some(display.clone()); + self.has_new_events = true; + self.display = Some(display.clone()); + + for handle in self.handles.values_mut() { + match handle { + Handle::Consumer { + needs_handoff, + notified, + .. + } => { + *needs_handoff = true; + *notified = false; + } + _ => continue, + } + } } Handle::Display { events: EventFlags::empty(), @@ -503,26 +531,6 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), } - if let Some(display) = scheme.maybe_perform_handoff_to.take() { - scheme.has_new_events = true; - - scheme.display = Some(display.clone()); - - for handle in scheme.handles.values_mut() { - match handle { - Handle::Consumer { - needs_handoff, - notified, - .. - } => { - *needs_handoff = true; - *notified = false; - } - _ => continue, - } - } - } - if !scheme.has_new_events { continue; } From 085a6e32c60f2e0094e50020b306f88de071a243 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 17:37:14 +0100 Subject: [PATCH 1101/1301] inputd: Unify early and non-early handle opening --- inputd/src/main.rs | 51 ++++++++++++++-------------------------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 44fb836074..adbfe671c4 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -146,45 +146,23 @@ impl Scheme for InputScheme { vt: target, } } - "handle_early" => { + "handle" | "handle_early" => { let display = path_parts.collect::>().join("."); - if self.display.is_none() { - self.has_new_events = true; - self.display = Some(display.clone()); - for handle in self.handles.values_mut() { - match handle { - Handle::Consumer { - needs_handoff, - notified, + let needs_handoff = match command { + "handle_early" => self.display.is_none(), + "handle" => self.handles.values().all(|handle| { + !matches!( + handle, + Handle::Display { + is_earlyfb: false, .. - } => { - *needs_handoff = true; - *notified = false; } - _ => continue, - } - } - } - Handle::Display { - events: EventFlags::empty(), - pending: Vec::new(), - notified: false, - device: display, - is_earlyfb: true, - } - } - "handle" => { - let display = path_parts.collect::>().join("."); - let needs_handoff = self.handles.values().all(|handle| { - !matches!( - handle, - Handle::Display { - is_earlyfb: false, - .. - } - ) - }); + ) + }), + _ => unreachable!(), + }; + if needs_handoff { self.has_new_events = true; self.display = Some(display.clone()); @@ -203,6 +181,7 @@ impl Scheme for InputScheme { } } } + Handle::Display { events: EventFlags::empty(), pending: if let Some(active_vt) = self.active_vt { @@ -218,7 +197,7 @@ impl Scheme for InputScheme { }, notified: false, device: display, - is_earlyfb: false, + is_earlyfb: command == "handle_early", } } "control" => Handle::Control, From 67e9f298043814781117d9be75e9dfdf846af0c0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 18:57:10 +0100 Subject: [PATCH 1102/1301] inputd: switch_vt is infallible --- inputd/src/main.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index adbfe671c4..83bf152367 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -77,16 +77,16 @@ impl InputScheme { } } - fn switch_vt(&mut self, new_active: usize) -> syscall::Result<()> { + fn switch_vt(&mut self, new_active: usize) { if let Some(active_vt) = self.active_vt { if new_active == active_vt { - return Ok(()); + return; } } if !self.vts.contains(&new_active) { log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); - return Ok(()); + return; } log::info!( @@ -118,8 +118,6 @@ impl InputScheme { } self.active_vt = Some(new_active); - - Ok(()) } } @@ -273,7 +271,7 @@ impl Scheme for InputScheme { self.vts.insert(vt); if self.active_vt.is_none() { - self.switch_vt(vt)?; + self.switch_vt(vt); } Ok(vt) @@ -325,7 +323,7 @@ impl Scheme for InputScheme { // SAFETY: We have verified the size of the buffer above. let cmd = unsafe { &*buf.as_ptr().cast::() }; - self.switch_vt(cmd.vt)?; + self.switch_vt(cmd.vt); return Ok(buf.len()); } @@ -410,7 +408,7 @@ impl Scheme for InputScheme { } if let Some(new_active) = new_active_opt { - self.switch_vt(new_active)?; + self.switch_vt(new_active); } } From 39dd9118c07c09544ce584b8757d9676d49166c8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 19:18:52 +0100 Subject: [PATCH 1103/1301] graphics/fbcond: Handle missing graphics driver at startup --- graphics/fbcond/src/display.rs | 53 ++++++++++++++++++++++------------ graphics/fbcond/src/text.rs | 22 +++++++------- 2 files changed, 46 insertions(+), 29 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 8595ec6e9c..5e613c76b0 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,28 +1,39 @@ -use graphics_ipc::legacy::{Damage, DisplayMap, LegacyGraphicsHandle}; +use graphics_ipc::legacy::{Damage, LegacyGraphicsHandle}; use inputd::ConsumerHandle; use std::io; pub struct Display { pub input_handle: ConsumerHandle, - pub display_handle: LegacyGraphicsHandle, - pub map: DisplayMap, + pub map: Option, +} + +pub struct DisplayMap { + display_handle: LegacyGraphicsHandle, + pub inner: graphics_ipc::legacy::DisplayMap, } impl Display { pub fn open_vt(vt: usize) -> io::Result { let input_handle = ConsumerHandle::for_vt(vt)?; - let display_handle = Self::open_display(&input_handle)?; + if let Ok(display_handle) = Self::open_display(&input_handle) { + let map = display_handle + .map_display() + .unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")); - let map = display_handle - .map_display() - .unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")); - - Ok(Self { - input_handle, - display_handle, - map, - }) + Ok(Self { + input_handle, + map: Some(DisplayMap { + display_handle, + inner: map, + }), + }) + } else { + Ok(Self { + input_handle, + map: None, + }) + } } /// Re-open the display after a handoff. @@ -35,14 +46,16 @@ impl Display { match new_display_handle.map_display() { Ok(map) => { - self.map = map; - self.display_handle = new_display_handle; - eprintln!( "fbcond: Mapped new display with size {}x{}", - self.map.width(), - self.map.height() + map.width(), + map.height() ); + + self.map = Some(DisplayMap { + display_handle: new_display_handle, + inner: map, + }); } Err(err) => { eprintln!("failed to resize display: {}", err); @@ -57,6 +70,8 @@ impl Display { } pub fn sync_rects(&mut self, sync_rects: Vec) { - self.display_handle.sync_rects(&sync_rects).unwrap(); + if let Some(map) = &self.map { + map.display_handle.sync_rects(&sync_rects).unwrap(); + } } } diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index 02f36377cc..3499316da2 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -120,17 +120,19 @@ impl TextScreen { } pub fn write(&mut self, buf: &[u8]) -> Result { - let damage = self.inner.write( - &mut console_draw::DisplayMap { - offscreen: self.display.map.ptr_mut(), - width: self.display.map.width(), - height: self.display.map.height(), - }, - buf, - &mut self.input, - ); + if let Some(map) = &mut self.display.map { + let damage = self.inner.write( + &mut console_draw::DisplayMap { + offscreen: map.inner.ptr_mut(), + width: map.inner.width(), + height: map.inner.height(), + }, + buf, + &mut self.input, + ); - self.display.sync_rects(damage); + self.display.sync_rects(damage); + } Ok(buf.len()) } From e9d8d7ceafad73278d6441acc5e931999a12266f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 1 Mar 2025 20:39:03 +0100 Subject: [PATCH 1104/1301] Implicitly create a new VT for each consumer Instead of requiring the graphics driver to create a fixed set of VTs in advance. This fixes the graphical interface when there is a graphics driver but no boot framebuffer. Previously in that case vesad would exit before it creates any VT and thus no consumer could show anything as their VT was missing. In the future creating new VTs on the fly could also allow a display manager to use a separate VT for each user session. --- graphics/fbbootlogd/src/display.rs | 2 +- graphics/fbcond/src/display.rs | 2 +- graphics/vesad/src/main.rs | 14 ++------- inputd/src/lib.rs | 10 ++---- inputd/src/main.rs | 49 +++++++++++++++--------------- 5 files changed, 31 insertions(+), 46 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index 4f736f8643..bd4d0c2e93 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -46,7 +46,7 @@ pub struct Display { impl Display { pub fn open_first_vt() -> io::Result { - let input_handle = ConsumerHandle::for_vt(1)?; + let input_handle = ConsumerHandle::new_vt()?; let map = match input_handle.open_display() { Ok(display) => { diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 5e613c76b0..b60b8e6674 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -14,7 +14,7 @@ pub struct DisplayMap { impl Display { pub fn open_vt(vt: usize) -> io::Result { - let input_handle = ConsumerHandle::for_vt(vt)?; + let input_handle = ConsumerHandle::new_vt()?; if let Ok(display_handle) = Self::open_display(&input_handle) { let map = display_handle diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 3a74ee42e9..dee3318404 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -15,12 +15,6 @@ mod framebuffer; mod scheme; fn main() { - let mut spec = Vec::new(); - - for _ in env::args().skip(1) { - spec.push(()); - } - if env::var("FRAMEBUFFER_WIDTH").is_err() { println!("vesad: No boot framebuffer"); return; @@ -78,16 +72,12 @@ fn main() { }; } - redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers, &spec)) + redox_daemon::Daemon::new(|daemon| inner(daemon, framebuffers)) .expect("failed to create daemon"); } -fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec, spec: &[()]) -> ! { +fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec) -> ! { let mut inputd_display_handle = DisplayHandle::new_early("vesa").unwrap(); - for &() in spec.iter() { - inputd_display_handle.register_vt().unwrap(); - } - let mut scheme = GraphicsScheme::new(FbAdapter { framebuffers }, "display.vesa".to_owned()); user_data! { diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 239c5f1b52..b7ca196db6 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -17,11 +17,11 @@ unsafe fn any_as_u8_slice_mut(p: &mut T) -> &mut [u8] { pub struct ConsumerHandle(File); impl ConsumerHandle { - pub fn for_vt(vt: usize) -> Result { + pub fn new_vt() -> Result { let file = OpenOptions::new() .read(true) .custom_flags(O_NONBLOCK as i32) - .open(format!("/scheme/input/consumer/{vt}"))?; + .open(format!("/scheme/input/consumer"))?; Ok(Self(file)) } @@ -70,12 +70,6 @@ impl DisplayHandle { Ok(Self(File::open(path)?)) } - // The return value is the display identifier. It will be used to uniquely - // identify the display on activation events. - pub fn register_vt(&mut self) -> Result { - self.0.read(&mut []) - } - pub fn read_vt_event(&mut self) -> Result, Error> { let mut event = VtEvent { kind: VtEventKind::Resize, diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 83bf152367..d98fe35dd5 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -131,17 +131,19 @@ impl Scheme for InputScheme { let handle_ty = match command { "producer" => Handle::Producer, "consumer" => { - let target = path_parts - .next() - .and_then(|x| x.parse::().ok()) - .ok_or(SysError::new(EINVAL))?; + let vt = self.next_vt_id.fetch_add(1, Ordering::Relaxed); + self.vts.insert(vt); + + if self.active_vt.is_none() { + self.switch_vt(vt); + } Handle::Consumer { events: EventFlags::empty(), pending: Vec::new(), needs_handoff: false, notified: false, - vt: target, + vt, } } "handle" | "handle_early" => { @@ -258,24 +260,8 @@ impl Scheme for InputScheme { Ok(copy) } - Handle::Display { - pending, device, .. - } => { - // FIXME Create new VT through a write instead and return a NewVt event on read - // This allows also returning events for VT (de)activation from the display handle - // rather than pushing them to the graphics driver. - if buf.is_empty() { - // Trying to do an empty read creates a new VT. - let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst); - log::info!("inputd: created VT #{vt} for {device}"); - self.vts.insert(vt); - - if self.active_vt.is_none() { - self.switch_vt(vt); - } - - Ok(vt) - } else if buf.len() % size_of::() == 0 { + Handle::Display { pending, .. } => { + if buf.len() % size_of::() == 0 { let copy = core::cmp::min(pending.len(), buf.len() / size_of::()); for (i, event) in pending.drain(..copy).enumerate() { @@ -472,7 +458,22 @@ impl Scheme for InputScheme { } } - fn close(&mut self, _id: usize) -> syscall::Result { + fn close(&mut self, id: usize) -> syscall::Result { + let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; + + match *handle { + Handle::Consumer { vt, .. } => { + self.vts.remove(&vt); + if self.active_vt == Some(vt) { + if let Some(&new_vt) = self.vts.last() { + self.switch_vt(new_vt); + } else { + self.active_vt = None; + } + } + } + _ => {} + } Ok(0) } } From f26fdd7592849754a638f80beb153a0f36a8c39a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 2 Mar 2025 22:00:36 +0100 Subject: [PATCH 1105/1301] Format all packages in fmt.sh --- fmt.sh | 31 ++++++------------------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/fmt.sh b/fmt.sh index 78c3bebd52..007766e270 100755 --- a/fmt.sh +++ b/fmt.sh @@ -2,28 +2,9 @@ set -eo pipefail -function fmt() { - for dir in "$@" - do - pushd $dir - printf "\e[1;32mFormatting\e[0m $dir\n" - if [[ "$CHECK_ONLY" -eq "1" ]]; then - cargo fmt --check - else - cargo fmt - fi - popd - done -} - -fmt common \ - graphics/bgad \ - graphics/fbcond \ - graphics/vesad \ - graphics/virtio-gpud \ - inputd \ - net/driver-network \ - net/virtio-netd \ - pcid \ - storage/driver-block \ - virtio-core +printf "\e[1;32mFormatting\e[0m $dir\n" +if [[ "$CHECK_ONLY" -eq "1" ]]; then + cargo fmt --all --check +else + cargo fmt --all +fi From 88cfa76e2c7ffddbbe7d8173893a3529ff065570 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 18:53:56 +0100 Subject: [PATCH 1106/1301] graphics: Merge set_scanout and flush_resource into update_plane The old api was pretty virtio-gpu specific. The new api is closed to how atomic mode setting on Linux works. --- graphics/driver-graphics/src/lib.rs | 9 ++++---- graphics/vesad/src/scheme.rs | 6 +---- graphics/virtio-gpud/src/main.rs | 2 +- graphics/virtio-gpud/src/scheme.rs | 35 +++++++++++++++-------------- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index c35b88bcd8..3a9b503f54 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -17,8 +17,7 @@ pub trait GraphicsAdapter { fn create_resource(&mut self, width: u32, height: u32) -> Self::Resource; fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8; - fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource); - fn flush_resource( + fn update_plane( &mut self, display_id: usize, resource: &Self::Resource, @@ -90,7 +89,7 @@ impl GraphicsScheme { let (width, height) = self.adapter.display_size(display_id); self.adapter.create_resource(width, height) }); - self.adapter.set_scanout(display_id, resource); + self.adapter.update_plane(display_id, resource, None); self.active_vt = vt_event.vt; } @@ -196,7 +195,7 @@ impl Scheme for GraphicsScheme { return Ok(0); } let resource = &self.vts_res[vt][screen]; - self.adapter.flush_resource(*screen, resource, None); + self.adapter.update_plane(*screen, resource, None); Ok(0) } @@ -229,7 +228,7 @@ impl Scheme for GraphicsScheme { ) }; - self.adapter.flush_resource(*screen, resource, Some(damage)); + self.adapter.update_plane(*screen, resource, Some(damage)); Ok(buf.len()) } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 48c3b0940a..47fde67e88 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -34,11 +34,7 @@ impl GraphicsAdapter for FbAdapter { resource.ptr.as_ptr().cast::() } - fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource) { - self.flush_resource(display_id, resource, None); - } - - fn flush_resource( + fn update_plane( &mut self, display_id: usize, resource: &Self::Resource, diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 6b0b62f3fe..2313808470 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -192,7 +192,7 @@ impl Default for GetDisplayInfo { static RESOURCE_ALLOC: AtomicU32 = AtomicU32::new(1); // XXX: 0 is reserved for whatever that takes `resource_id`. -#[derive(Debug, Copy, Clone)] +#[derive(PartialEq, Eq, Debug, Copy, Clone)] #[repr(C)] pub struct ResourceId(u32); diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index d80f45bbb6..bc0c1c4f98 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -44,6 +44,7 @@ impl Resource for VirtGpuResource { pub struct Display { width: u32, height: u32, + active_resource: Option, } pub struct VirtGpuAdapter<'a> { @@ -164,24 +165,9 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { resource.sgl.as_ptr() } - fn set_scanout(&mut self, display_id: usize, resource: &Self::Resource) { - futures::executor::block_on(async { - let scanout_request = Dma::new(SetScanout::new( - display_id as u32, - resource.id, - GpuRect::new(0, 0, resource.width, resource.height), - )) - .unwrap(); - let header = self.send_request(scanout_request).await.unwrap(); - assert_eq!(header.ty, CommandTy::RespOkNodata); - }); - - self.flush_resource(display_id, resource, None); - } - - fn flush_resource( + fn update_plane( &mut self, - _display_id: usize, + display_id: usize, resource: &Self::Resource, damage: Option<&[Damage]>, ) { @@ -200,6 +186,19 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { let header = self.send_request(req).await.unwrap(); assert_eq!(header.ty, CommandTy::RespOkNodata); + // FIXME once we support resizing we also need to check that the current and target size match + if self.displays[display_id].active_resource != Some(resource.id) { + let scanout_request = Dma::new(SetScanout::new( + display_id as u32, + resource.id, + GpuRect::new(0, 0, resource.width, resource.height), + )) + .unwrap(); + let header = self.send_request(scanout_request).await.unwrap(); + assert_eq!(header.ty, CommandTy::RespOkNodata); + self.displays[display_id].active_resource = Some(resource.id); + } + if let Some(damage) = damage { for damage in damage { self.flush_resource_inner(ResourceFlush::new( @@ -261,11 +260,13 @@ impl<'a> GpuScheme { adapter.displays.push(Display { width: 640, height: 480, + active_resource: None, }); } else { adapter.displays.push(Display { width: info.rect.width, height: info.rect.height, + active_resource: None, }); } } From 972e19e90018a86a1a3e8af895120e2f6a462926 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 19:13:16 +0100 Subject: [PATCH 1107/1301] graphics: Always pass damage to graphics drivers This way the drivers don't have to special case switching between VTs. --- graphics/driver-graphics/src/lib.rs | 26 +++++++++++------ graphics/vesad/src/scheme.rs | 24 ++-------------- graphics/virtio-gpud/src/scheme.rs | 44 ++++++----------------------- 3 files changed, 28 insertions(+), 66 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 3a9b503f54..9be69aa665 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -17,12 +17,7 @@ pub trait GraphicsAdapter { fn create_resource(&mut self, width: u32, height: u32) -> Self::Resource; fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8; - fn update_plane( - &mut self, - display_id: usize, - resource: &Self::Resource, - damage: Option<&[Damage]>, - ); + fn update_plane(&mut self, display_id: usize, resource: &Self::Resource, damage: &[Damage]); } pub trait Resource { @@ -89,7 +84,7 @@ impl GraphicsScheme { let (width, height) = self.adapter.display_size(display_id); self.adapter.create_resource(width, height) }); - self.adapter.update_plane(display_id, resource, None); + Self::update_whole_screen(&mut self.adapter, display_id, resource); self.active_vt = vt_event.vt; } @@ -139,6 +134,19 @@ impl GraphicsScheme { Ok(()) } + + fn update_whole_screen(adapter: &mut T, screen: usize, resource: &T::Resource) { + adapter.update_plane( + screen, + resource, + &[Damage { + x: 0, + y: 0, + width: resource.width() as i32, + height: resource.height() as i32, + }], + ); + } } impl Scheme for GraphicsScheme { @@ -195,7 +203,7 @@ impl Scheme for GraphicsScheme { return Ok(0); } let resource = &self.vts_res[vt][screen]; - self.adapter.update_plane(*screen, resource, None); + Self::update_whole_screen(&mut self.adapter, *screen, resource); Ok(0) } @@ -228,7 +236,7 @@ impl Scheme for GraphicsScheme { ) }; - self.adapter.update_plane(*screen, resource, Some(damage)); + self.adapter.update_plane(*screen, resource, damage); Ok(buf.len()) } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 47fde67e88..f4e8647b98 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -34,28 +34,8 @@ impl GraphicsAdapter for FbAdapter { resource.ptr.as_ptr().cast::() } - fn update_plane( - &mut self, - display_id: usize, - resource: &Self::Resource, - damage: Option<&[Damage]>, - ) { - if let Some(damage) = damage { - resource.sync(&mut self.framebuffers[display_id], damage) - } else { - let framebuffer: &mut FrameBuffer = &mut self.framebuffers[display_id]; - let width = resource.width.try_into().unwrap(); - let height = resource.height.try_into().unwrap(); - resource.sync( - framebuffer, - &[Damage { - x: 0, - y: 0, - width, - height, - }], - ); - } + fn update_plane(&mut self, display_id: usize, resource: &Self::Resource, damage: &[Damage]) { + resource.sync(&mut self.framebuffers[display_id], damage) } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index bc0c1c4f98..95211bc9de 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -66,13 +66,6 @@ impl VirtGpuAdapter<'_> { Ok(header) } - async fn flush_resource_inner(&self, flush: ResourceFlush) -> Result<(), Error> { - let header = self.send_request(Dma::new(flush)?).await?; - assert_eq!(header.ty, CommandTy::RespOkNodata); - - Ok(()) - } - async fn get_display_info(&self) -> Result, Error> { let header = Dma::new(ControlHeader::with_ty(CommandTy::GetDisplayInfo))?; @@ -165,12 +158,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { resource.sgl.as_ptr() } - fn update_plane( - &mut self, - display_id: usize, - resource: &Self::Resource, - damage: Option<&[Damage]>, - ) { + fn update_plane(&mut self, display_id: usize, resource: &Self::Resource, damage: &[Damage]) { futures::executor::block_on(async { let req = Dma::new(XferToHost2d::new( resource.id, @@ -199,29 +187,15 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { self.displays[display_id].active_resource = Some(resource.id); } - if let Some(damage) = damage { - for damage in damage { - self.flush_resource_inner(ResourceFlush::new( - resource.id, - damage - .clip(resource.width as i32, resource.height as i32) - .into(), - )) - .await - .unwrap(); - } - } else { - self.flush_resource_inner(ResourceFlush::new( + for damage in damage { + let flush = ResourceFlush::new( resource.id, - GpuRect { - x: 0, - y: 0, - width: resource.width, - height: resource.height, - }, - )) - .await - .unwrap(); + damage + .clip(resource.width as i32, resource.height as i32) + .into(), + ); + let header = self.send_request(Dma::new(flush).unwrap()).await.unwrap(); + assert_eq!(header.ty, CommandTy::RespOkNodata); } }); } From fc92f0b0cef2dac1697da1da818c70a6bea65888 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 19:17:54 +0100 Subject: [PATCH 1108/1301] graphics: Rename the legacy graphics API to the v1 graphics API It is quite likely that the next graphics API won't be the last one and as such would become a legacy API too. Consistently using version numbers makes it easier to refer to the exact version you mean. --- graphics/console-draw/src/lib.rs | 2 +- graphics/driver-graphics/src/lib.rs | 2 +- graphics/fbbootlogd/src/display.rs | 12 ++++++------ graphics/fbcond/src/display.rs | 10 +++++----- graphics/graphics-ipc/src/lib.rs | 2 +- graphics/graphics-ipc/src/{legacy.rs => v1.rs} | 10 +++++----- graphics/vesad/src/scheme.rs | 2 +- graphics/virtio-gpud/src/scheme.rs | 2 +- 8 files changed, 21 insertions(+), 21 deletions(-) rename graphics/graphics-ipc/src/{legacy.rs => v1.rs} (93%) diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index bbd2d4fdeb..57820c3c09 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -4,7 +4,7 @@ use std::collections::{BTreeSet, VecDeque}; use std::convert::{TryFrom, TryInto}; use std::{cmp, ptr}; -use graphics_ipc::legacy::Damage; +use graphics_ipc::v1::Damage; use orbclient::FONT; pub struct DisplayMap { diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 9be69aa665..0b276ff23f 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use std::io; -use graphics_ipc::legacy::Damage; +use graphics_ipc::v1::Damage; use inputd::{VtEvent, VtEventKind}; use libredox::errno::EOPNOTSUPP; use libredox::Fd; diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index bd4d0c2e93..d276a24038 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -1,5 +1,5 @@ use event::{user_data, EventQueue}; -use graphics_ipc::legacy::{Damage, LegacyGraphicsHandle}; +use graphics_ipc::v1::{Damage, V1GraphicsHandle}; use inputd::ConsumerHandle; use libredox::errno::ESTALE; use orbclient::Event; @@ -22,7 +22,7 @@ fn read_to_slice( } } -fn display_fd_map(display_handle: LegacyGraphicsHandle) -> io::Result { +fn display_fd_map(display_handle: V1GraphicsHandle) -> io::Result { let display_map = display_handle.map_display()?; Ok(DisplayMap { display_handle: Arc::new(display_handle), @@ -31,8 +31,8 @@ fn display_fd_map(display_handle: LegacyGraphicsHandle) -> io::Result, - pub inner: graphics_ipc::legacy::DisplayMap, + display_handle: Arc, + pub inner: graphics_ipc::v1::DisplayMap, } enum DisplayCommand { @@ -50,7 +50,7 @@ impl Display { let map = match input_handle.open_display() { Ok(display) => { - let display_handle = LegacyGraphicsHandle::from_file(display)?; + let display_handle = V1GraphicsHandle::from_file(display)?; Arc::new(Mutex::new(Some( display_fd_map(display_handle) .unwrap_or_else(|e| panic!("failed to map display: {e}")), @@ -102,7 +102,7 @@ impl Display { eprintln!("fbbootlogd: handoff requested"); let new_display_handle = match input_handle.open_display() { - Ok(display) => LegacyGraphicsHandle::from_file(display).unwrap(), + Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), Err(err) => { println!("fbbootlogd: No display present yet: {err}"); continue; diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index b60b8e6674..45ee86d2ca 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,4 +1,4 @@ -use graphics_ipc::legacy::{Damage, LegacyGraphicsHandle}; +use graphics_ipc::v1::{Damage, V1GraphicsHandle}; use inputd::ConsumerHandle; use std::io; @@ -8,8 +8,8 @@ pub struct Display { } pub struct DisplayMap { - display_handle: LegacyGraphicsHandle, - pub inner: graphics_ipc::legacy::DisplayMap, + display_handle: V1GraphicsHandle, + pub inner: graphics_ipc::v1::DisplayMap, } impl Display { @@ -63,10 +63,10 @@ impl Display { } } - fn open_display(input_handle: &ConsumerHandle) -> io::Result { + fn open_display(input_handle: &ConsumerHandle) -> io::Result { let display_file = input_handle.open_display()?; - LegacyGraphicsHandle::from_file(display_file) + V1GraphicsHandle::from_file(display_file) } pub fn sync_rects(&mut self, sync_rects: Vec) { diff --git a/graphics/graphics-ipc/src/lib.rs b/graphics/graphics-ipc/src/lib.rs index d0b036677b..a3a6d96c3f 100644 --- a/graphics/graphics-ipc/src/lib.rs +++ b/graphics/graphics-ipc/src/lib.rs @@ -1 +1 @@ -pub mod legacy; +pub mod v1; diff --git a/graphics/graphics-ipc/src/legacy.rs b/graphics/graphics-ipc/src/v1.rs similarity index 93% rename from graphics/graphics-ipc/src/legacy.rs rename to graphics/graphics-ipc/src/v1.rs index 2bfb4f2ce3..7c165f5b00 100644 --- a/graphics/graphics-ipc/src/legacy.rs +++ b/graphics/graphics-ipc/src/v1.rs @@ -4,17 +4,17 @@ use std::{cmp, io, mem, ptr, slice}; use libredox::flag; -/// A graphics handle using the legacy graphics API. +/// A graphics handle using the v1 graphics API. /// -/// The legacy graphics API only allows a single framebuffer for each VT and supports neither page +/// The v1 graphics API only allows a single framebuffer for each VT and supports neither page /// flipping nor cursor planes. -pub struct LegacyGraphicsHandle { +pub struct V1GraphicsHandle { file: File, } -impl LegacyGraphicsHandle { +impl V1GraphicsHandle { pub fn from_file(file: File) -> io::Result { - Ok(LegacyGraphicsHandle { file }) + Ok(V1GraphicsHandle { file }) } pub fn map_display(&self) -> io::Result { diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index f4e8647b98..229c3cfa8a 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -3,7 +3,7 @@ use std::convert::TryInto; use std::ptr::{self, NonNull}; use driver_graphics::{GraphicsAdapter, Resource}; -use graphics_ipc::legacy::Damage; +use graphics_ipc::v1::Damage; use syscall::PAGE_SIZE; use crate::framebuffer::FrameBuffer; diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 95211bc9de..3241294db3 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use common::{dma::Dma, sgl}; use driver_graphics::{GraphicsAdapter, GraphicsScheme, Resource}; -use graphics_ipc::legacy::Damage; +use graphics_ipc::v1::Damage; use inputd::DisplayHandle; use syscall::PAGE_SIZE; From ee3382aed0789811c4f48bc724ebb5050a7bdcd4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 19:23:45 +0100 Subject: [PATCH 1109/1301] graphics/virtio-gpud: Add helper to submit a fenced request This is necessary for implementing hardware cursor support. --- graphics/virtio-gpud/src/main.rs | 3 +++ graphics/virtio-gpud/src/scheme.rs | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 2313808470..fa2a5da6f5 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -109,6 +109,9 @@ pub enum CommandTy { static_assertions::const_assert_eq!(core::mem::size_of::(), 4); +const VIRTIO_GPU_FLAG_FENCE: u32 = 1 << 0; +//const VIRTIO_GPU_FLAG_INFO_RING_IDX: u32 = 1 << 1; + #[derive(Debug)] #[repr(C)] pub struct ControlHeader { diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 3241294db3..95714e9a77 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -66,6 +66,18 @@ impl VirtGpuAdapter<'_> { Ok(header) } + async fn send_request_fenced(&self, request: Dma) -> Result, Error> { + let mut header = Dma::new(ControlHeader::default())?; + header.flags |= VIRTIO_GPU_FLAG_FENCE; + let command = ChainBuilder::new() + .chain(Buffer::new(&request)) + .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.control_queue.send(command).await; + Ok(header) + } + async fn get_display_info(&self) -> Result, Error> { let header = Dma::new(ControlHeader::with_ty(CommandTy::GetDisplayInfo))?; From 92295f2ea47475bfdca4486ca05b32e9f32e37f2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 19:41:05 +0100 Subject: [PATCH 1110/1301] graphics/graphics-ipc: Use u32 fields in Damage The fields should never be negative and this saves a couple of casts. --- graphics/console-draw/src/lib.rs | 2 +- graphics/driver-graphics/src/lib.rs | 4 ++-- graphics/graphics-ipc/src/v1.rs | 12 +++++++----- graphics/vesad/src/scheme.rs | 8 ++++---- graphics/virtio-gpud/src/scheme.rs | 12 +++++------- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index 57820c3c09..59aea00469 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -221,7 +221,7 @@ impl TextScreen { } else { damage.push(Damage { x: 0, - y: i32::try_from(change).unwrap() * 16, + y: u32::try_from(change).unwrap() * 16, width, height: 16, }); diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 0b276ff23f..035ceb6a91 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -142,8 +142,8 @@ impl GraphicsScheme { &[Damage { x: 0, y: 0, - width: resource.width() as i32, - height: resource.height() as i32, + width: resource.width(), + height: resource.height(), }], ); } diff --git a/graphics/graphics-ipc/src/v1.rs b/graphics/graphics-ipc/src/v1.rs index 7c165f5b00..39226f2b31 100644 --- a/graphics/graphics-ipc/src/v1.rs +++ b/graphics/graphics-ipc/src/v1.rs @@ -111,18 +111,20 @@ impl Drop for DisplayMap { } // Keep synced with orbital's SyncRect +// Technically orbital uses i32 rather than u32, but values larger than i32::MAX +// would be a bug anyway. #[derive(Debug, Copy, Clone)] #[repr(packed)] pub struct Damage { - pub x: i32, - pub y: i32, - pub width: i32, - pub height: i32, + pub x: u32, + pub y: u32, + pub width: u32, + pub height: u32, } impl Damage { #[must_use] - pub fn clip(mut self, width: i32, height: i32) -> Self { + pub fn clip(mut self, width: u32, height: u32) -> Self { // Clip damage self.x = cmp::min(self.x, width); if self.x + self.width > width { diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 229c3cfa8a..938b8a6678 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -91,10 +91,10 @@ impl GraphicScreen { self.height.try_into().unwrap(), ); - let start_x: usize = sync_rect.x.try_into().unwrap_or(0); - let start_y: usize = sync_rect.y.try_into().unwrap_or(0); - let w: usize = sync_rect.width.try_into().unwrap_or(0); - let h: usize = sync_rect.height.try_into().unwrap_or(0); + let start_x: usize = sync_rect.x.try_into().unwrap(); + let start_y: usize = sync_rect.y.try_into().unwrap(); + let w: usize = sync_rect.width.try_into().unwrap(); + let h: usize = sync_rect.height.try_into().unwrap(); let offscreen_ptr = self.ptr.as_ptr() as *mut u32; let onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 95714e9a77..6bd41c91a7 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -15,10 +15,10 @@ use crate::*; impl Into for Damage { fn into(self) -> GpuRect { GpuRect { - x: self.x as u32, - y: self.y as u32, - width: self.width as u32, - height: self.height as u32, + x: self.x, + y: self.y, + width: self.width, + height: self.height, } } } @@ -202,9 +202,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { for damage in damage { let flush = ResourceFlush::new( resource.id, - damage - .clip(resource.width as i32, resource.height as i32) - .into(), + damage.clip(resource.width, resource.height).into(), ); let header = self.send_request(Dma::new(flush).unwrap()).await.unwrap(); assert_eq!(header.ty, CommandTy::RespOkNodata); From be5b8650589dc0849967db0c11eb4b4a1925977e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 21:41:26 +0100 Subject: [PATCH 1111/1301] graphics: Rename resource to framebuffer This matches the Linux DRM name. --- graphics/driver-graphics/src/lib.rs | 61 ++++++++++++++++------------- graphics/vesad/src/scheme.rs | 21 ++++++---- graphics/virtio-gpud/src/scheme.rs | 41 ++++++++++--------- 3 files changed, 69 insertions(+), 54 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 035ceb6a91..d3b8fe3777 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -9,18 +9,23 @@ use redox_scheme::{RequestKind, Response, Scheme, SignalBehavior, Socket}; use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL}; pub trait GraphicsAdapter { - type Resource: Resource; + type Framebuffer: Framebuffer; fn displays(&self) -> Vec; fn display_size(&self, display_id: usize) -> (u32, u32); - fn create_resource(&mut self, width: u32, height: u32) -> Self::Resource; - fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8; + fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer; + fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8; - fn update_plane(&mut self, display_id: usize, resource: &Self::Resource, damage: &[Damage]); + fn update_plane( + &mut self, + display_id: usize, + framebuffer: &Self::Framebuffer, + damage: &[Damage], + ); } -pub trait Resource { +pub trait Framebuffer { fn width(&self) -> u32; fn height(&self) -> u32; } @@ -34,7 +39,7 @@ pub struct GraphicsScheme { handles: BTreeMap, active_vt: usize, - vts_res: HashMap>, + vts_fb: HashMap>, } enum Handle { @@ -53,7 +58,7 @@ impl GraphicsScheme { next_id: 0, handles: BTreeMap::new(), active_vt: 0, - vts_res: HashMap::new(), + vts_fb: HashMap::new(), } } @@ -75,16 +80,16 @@ impl GraphicsScheme { log::info!("activate {}", vt_event.vt); for display_id in self.adapter.displays() { - let resource = self - .vts_res + let framebuffer = self + .vts_fb .entry(vt_event.vt) .or_default() .entry(display_id) .or_insert_with(|| { let (width, height) = self.adapter.display_size(display_id); - self.adapter.create_resource(width, height) + self.adapter.create_dumb_framebuffer(width, height) }); - Self::update_whole_screen(&mut self.adapter, display_id, resource); + Self::update_whole_screen(&mut self.adapter, display_id, framebuffer); self.active_vt = vt_event.vt; } @@ -135,15 +140,15 @@ impl GraphicsScheme { Ok(()) } - fn update_whole_screen(adapter: &mut T, screen: usize, resource: &T::Resource) { + fn update_whole_screen(adapter: &mut T, screen: usize, framebuffer: &T::Framebuffer) { adapter.update_plane( screen, - resource, + framebuffer, &[Damage { x: 0, y: 0, - width: resource.width(), - height: resource.height(), + width: framebuffer.width(), + height: framebuffer.height(), }], ); } @@ -167,13 +172,13 @@ impl Scheme for GraphicsScheme { return Err(Error::new(EINVAL)); } - self.vts_res + self.vts_fb .entry(vt) .or_default() .entry(id) .or_insert_with(|| { let (width, height) = self.adapter.display_size(id); - self.adapter.create_resource(width, height) + self.adapter.create_dumb_framebuffer(width, height) }); self.next_id += 1; @@ -184,12 +189,12 @@ impl Scheme for GraphicsScheme { fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { let Handle::Screen { vt, screen } = self.handles.get(&id).ok_or(Error::new(EBADF))?; - let resource = &self.vts_res[vt][screen]; + let framebuffer = &self.vts_fb[vt][screen]; let path = format!( "{}:{vt}.{screen}/{}/{}", self.scheme_name, - resource.width(), - resource.height() + framebuffer.width(), + framebuffer.height() ); buf[..path.len()].copy_from_slice(path.as_bytes()); Ok(path.len()) @@ -199,11 +204,11 @@ impl Scheme for GraphicsScheme { let Handle::Screen { vt, screen } = self.handles.get(&id).ok_or(Error::new(EBADF))?; if *vt != self.active_vt { // This is a protection against background VT's spamming us with flush requests. We will - // flush the resource on the next VT switch anyway + // flush the framebuffer on the next VT switch anyway return Ok(0); } - let resource = &self.vts_res[vt][screen]; - Self::update_whole_screen(&mut self.adapter, *screen, resource); + let framebuffer = &self.vts_fb[vt][screen]; + Self::update_whole_screen(&mut self.adapter, *screen, framebuffer); Ok(0) } @@ -223,11 +228,11 @@ impl Scheme for GraphicsScheme { if *vt != self.active_vt { // This is a protection against background VT's spamming us with flush requests. We will - // flush the resource on the next VT switch anyway + // flush the framebuffer on the next VT switch anyway return Ok(buf.len()); } - let resource = &self.vts_res[vt][screen]; + let framebuffer = &self.vts_fb[vt][screen]; let damage = unsafe { core::slice::from_raw_parts( @@ -236,7 +241,7 @@ impl Scheme for GraphicsScheme { ) }; - self.adapter.update_plane(*screen, resource, damage); + self.adapter.update_plane(*screen, framebuffer, damage); Ok(buf.len()) } @@ -255,8 +260,8 @@ impl Scheme for GraphicsScheme { log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); let handle = self.handles.get(&id).ok_or(Error::new(EINVAL))?; let Handle::Screen { vt, screen } = handle; - let resource = &self.vts_res[vt][screen]; - let ptr = T::map_resource(&mut self.adapter, resource); + let framebuffer = &self.vts_fb[vt][screen]; + let ptr = T::map_dumb_framebuffer(&mut self.adapter, framebuffer); Ok(ptr as usize) } } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 938b8a6678..32e3a22436 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -2,7 +2,7 @@ use std::alloc::{self, Layout}; use std::convert::TryInto; use std::ptr::{self, NonNull}; -use driver_graphics::{GraphicsAdapter, Resource}; +use driver_graphics::{Framebuffer, GraphicsAdapter}; use graphics_ipc::v1::Damage; use syscall::PAGE_SIZE; @@ -13,7 +13,7 @@ pub struct FbAdapter { } impl GraphicsAdapter for FbAdapter { - type Resource = GraphicScreen; + type Framebuffer = GraphicScreen; fn displays(&self) -> Vec { (0..self.framebuffers.len()).collect() @@ -26,16 +26,21 @@ impl GraphicsAdapter for FbAdapter { ) } - fn create_resource(&mut self, width: u32, height: u32) -> Self::Resource { + fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer { GraphicScreen::new(width as usize, height as usize) } - fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8 { - resource.ptr.as_ptr().cast::() + fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8 { + framebuffer.ptr.as_ptr().cast::() } - fn update_plane(&mut self, display_id: usize, resource: &Self::Resource, damage: &[Damage]) { - resource.sync(&mut self.framebuffers[display_id], damage) + fn update_plane( + &mut self, + display_id: usize, + framebuffer: &Self::Framebuffer, + damage: &[Damage], + ) { + framebuffer.sync(&mut self.framebuffers[display_id], damage) } } @@ -73,7 +78,7 @@ impl Drop for GraphicScreen { } } -impl Resource for GraphicScreen { +impl Framebuffer for GraphicScreen { fn width(&self) -> u32 { self.width as u32 } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 6bd41c91a7..b6eda2e2b0 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -1,7 +1,7 @@ use std::sync::Arc; use common::{dma::Dma, sgl}; -use driver_graphics::{GraphicsAdapter, GraphicsScheme, Resource}; +use driver_graphics::{Framebuffer, GraphicsAdapter, GraphicsScheme}; use graphics_ipc::v1::Damage; use inputd::DisplayHandle; @@ -23,14 +23,14 @@ impl Into for Damage { } } -pub struct VirtGpuResource { +pub struct VirtGpuFramebuffer { id: ResourceId, sgl: sgl::Sgl, width: u32, height: u32, } -impl Resource for VirtGpuResource { +impl Framebuffer for VirtGpuFramebuffer { fn width(&self) -> u32 { self.width } @@ -95,7 +95,7 @@ impl VirtGpuAdapter<'_> { } impl GraphicsAdapter for VirtGpuAdapter<'_> { - type Resource = VirtGpuResource; + type Framebuffer = VirtGpuFramebuffer; fn displays(&self) -> Vec { self.displays.iter().enumerate().map(|(i, _)| i).collect() @@ -108,7 +108,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { ) } - fn create_resource(&mut self, width: u32, height: u32) -> Self::Resource { + fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer { futures::executor::block_on(async { let bpp = 32; let fb_size = width as usize * height as usize * bpp / 8; @@ -157,7 +157,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { self.control_queue.send(command).await; assert_eq!(header.ty, CommandTy::RespOkNodata); - VirtGpuResource { + VirtGpuFramebuffer { id: res_id, sgl, width, @@ -166,19 +166,24 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { }) } - fn map_resource(&mut self, resource: &Self::Resource) -> *mut u8 { - resource.sgl.as_ptr() + fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8 { + framebuffer.sgl.as_ptr() } - fn update_plane(&mut self, display_id: usize, resource: &Self::Resource, damage: &[Damage]) { + fn update_plane( + &mut self, + display_id: usize, + framebuffer: &Self::Framebuffer, + damage: &[Damage], + ) { futures::executor::block_on(async { let req = Dma::new(XferToHost2d::new( - resource.id, + framebuffer.id, GpuRect { x: 0, y: 0, - width: resource.width, - height: resource.height, + width: framebuffer.width, + height: framebuffer.height, }, 0, )) @@ -187,22 +192,22 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { assert_eq!(header.ty, CommandTy::RespOkNodata); // FIXME once we support resizing we also need to check that the current and target size match - if self.displays[display_id].active_resource != Some(resource.id) { + if self.displays[display_id].active_resource != Some(framebuffer.id) { let scanout_request = Dma::new(SetScanout::new( display_id as u32, - resource.id, - GpuRect::new(0, 0, resource.width, resource.height), + framebuffer.id, + GpuRect::new(0, 0, framebuffer.width, framebuffer.height), )) .unwrap(); let header = self.send_request(scanout_request).await.unwrap(); assert_eq!(header.ty, CommandTy::RespOkNodata); - self.displays[display_id].active_resource = Some(resource.id); + self.displays[display_id].active_resource = Some(framebuffer.id); } for damage in damage { let flush = ResourceFlush::new( - resource.id, - damage.clip(resource.width, resource.height).into(), + framebuffer.id, + damage.clip(framebuffer.width, framebuffer.height).into(), ); let header = self.send_request(Dma::new(flush).unwrap()).await.unwrap(); assert_eq!(header.ty, CommandTy::RespOkNodata); From f6c3be42e79bd9abf49db6b37c08b54bcaf6b2e7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 22:17:58 +0100 Subject: [PATCH 1112/1301] storage: Vendor partitionlib to make it easier to change --- Cargo.lock | 1 - storage/driver-block/Cargo.toml | 2 +- storage/nvmed/Cargo.toml | 2 +- storage/partitionlib/Cargo.toml | 11 ++ storage/partitionlib/resources/disk.img | Bin 0 -> 524288 bytes storage/partitionlib/resources/disk_mbr.img | Bin 0 -> 2048 bytes storage/partitionlib/src/lib.rs | 7 ++ storage/partitionlib/src/mbr.rs | 77 +++++++++++++ storage/partitionlib/src/partition.rs | 115 ++++++++++++++++++++ storage/partitionlib/tests/test.rs | 54 +++++++++ storage/virtio-blkd/Cargo.toml | 2 +- storage/virtio-blkd/src/scheme.rs | 3 + 12 files changed, 270 insertions(+), 4 deletions(-) create mode 100644 storage/partitionlib/Cargo.toml create mode 100644 storage/partitionlib/resources/disk.img create mode 100644 storage/partitionlib/resources/disk_mbr.img create mode 100644 storage/partitionlib/src/lib.rs create mode 100644 storage/partitionlib/src/mbr.rs create mode 100644 storage/partitionlib/src/partition.rs create mode 100644 storage/partitionlib/tests/test.rs diff --git a/Cargo.lock b/Cargo.lock index e101de9edb..0bc2322768 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -937,7 +937,6 @@ dependencies = [ [[package]] name = "partitionlib" version = "0.1.0" -source = "git+https://gitlab.redox-os.org/redox-os/partitionlib.git#9e48718a0553a4d0d4070994053e1c402bb33b91" dependencies = [ "gpt", "scroll", diff --git a/storage/driver-block/Cargo.toml b/storage/driver-block/Cargo.toml index f876f19832..278520adca 100644 --- a/storage/driver-block/Cargo.toml +++ b/storage/driver-block/Cargo.toml @@ -4,6 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] -partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +partitionlib = { path = "../partitionlib" } redox_syscall = "0.5" diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 1a00ca727a..04cf4bb27c 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -13,7 +13,7 @@ redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" -partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +partitionlib = { path = "../partitionlib" } smallvec = "1" common = { path = "../../common" } diff --git a/storage/partitionlib/Cargo.toml b/storage/partitionlib/Cargo.toml new file mode 100644 index 0000000000..27df61ce16 --- /dev/null +++ b/storage/partitionlib/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "partitionlib" +version = "0.1.0" +authors = ["Deepak Sirone "] +edition = "2018" +license = "MIT" + +[dependencies] +gpt = { version = "3.0.1" } +scroll = { version = "0.10", features = ["derive"] } +uuid = { version = "1.0", features = ["v4"] } diff --git a/storage/partitionlib/resources/disk.img b/storage/partitionlib/resources/disk.img new file mode 100644 index 0000000000000000000000000000000000000000..76913628c28ec5cbf5beaad39c4f62c41d87ca4a GIT binary patch literal 524288 zcmeI)F-yZh7zW_0{t*%BAE>wqRjS}7QWq-}#8Snt*kTMLR#PL)o&xw`16 zgE$qOgbu;h1k=H8I*7va!SQj)@#gNyoP?nMv%pAr?e+Va_z3;c@1JA&Vs3t6Y;k6( z7(ynj#sQPZ6AwvFl9<#Wb^LQ09@D23uiv^`E9Kd<+~MVOX?J@hy}uXtWOS#agSe?b zE^t!6>%6pch5eh2)>ZcC_B^Vz?rWR*({`!ZSby&gzxTm$*1}Gx4kkJQ0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7 z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+ z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7csfnO3hso!;8+PT91%|`1gdvtpqRa*D8&HQP*)NHK3_r}wGJdS?d z&|26D)vuS#2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+0D&J0%*`*1EzT?zL&${HI3t?sTqIHb^n3qI onmha-fa3LAcWb3QdzL%Ad@k*7Kc(yU;`PbsPDclEQ-56G1ClsdMgRZ+ literal 0 HcmV?d00001 diff --git a/storage/partitionlib/resources/disk_mbr.img b/storage/partitionlib/resources/disk_mbr.img new file mode 100644 index 0000000000000000000000000000000000000000..429d41ca6b83c1e05578b40e84ac25758659273b GIT binary patch literal 2048 zcmeyhgF&G0!XAbVI~W-HZuA}ay^o=0KLguN2ByzTUMaFMFznmMZoyK@-F!@-@!vo8 z($BBOwlHmA+|5w4siCWcvD=5~tne#_8U}{f{}@IA{X#&#!TUSNHYSE<1{MZJAd8s{ Z%R^U@p=nghXb6mkz-S1JhQKfg0RT6oBp(0( literal 0 HcmV?d00001 diff --git a/storage/partitionlib/src/lib.rs b/storage/partitionlib/src/lib.rs new file mode 100644 index 0000000000..1b0b71b4e5 --- /dev/null +++ b/storage/partitionlib/src/lib.rs @@ -0,0 +1,7 @@ +extern crate gpt; +extern crate uuid; + +pub type Result = std::io::Result; +mod mbr; +pub mod partition; +pub use self::partition::*; diff --git a/storage/partitionlib/src/mbr.rs b/storage/partitionlib/src/mbr.rs new file mode 100644 index 0000000000..cf129ce356 --- /dev/null +++ b/storage/partitionlib/src/mbr.rs @@ -0,0 +1,77 @@ +use scroll::{Pread, Pwrite}; +use std::io; +use std::io::prelude::*; + +#[derive(Clone, Copy, Debug, Pread, Pwrite)] +pub struct Entry { + pub drive_attrs: u8, + pub start_head: u8, + pub start_cs: u16, + pub sys_id: u8, + pub end_head: u8, + pub end_cs: u16, + pub rel_sector: u32, + pub len: u32, +} + +#[derive(Pread, Pwrite)] +pub struct Header { + pub bootstrap: [u8; 446], + pub first_entry: Entry, + pub second_entry: Entry, + pub third_entry: Entry, + pub fourth_entry: Entry, + pub last_signature: u16, // 0xAA55 +} + +#[derive(Debug)] +pub enum Error { + IoError(io::Error), + ParsingError(scroll::Error), +} + +impl From for Error { + fn from(err: io::Error) -> Self { + Self::IoError(err) + } +} +impl From for Error { + fn from(err: scroll::Error) -> Self { + Self::ParsingError(err) + } +} + +pub fn read_header(device: &mut D) -> Result { + device.seek(io::SeekFrom::Start(0))?; + + let mut bytes = [0u8; 512]; + device.read_exact(&mut bytes)?; + + let header: Header = bytes.pread_with(0, scroll::LE)?; + + if header.last_signature != 0xAA55 { + return Err(scroll::Error::BadInput { + size: 2, + msg: "no 0xAA55 signature", + } + .into()); + } + + Ok(header) +} + +impl Header { + pub fn partitions(&self) -> [Entry; 4] { + [ + self.first_entry, + self.second_entry, + self.third_entry, + self.fourth_entry, + ] + } +} +impl Entry { + pub fn is_valid(&self) -> bool { + (self.drive_attrs == 0 || self.drive_attrs == 0x80) && self.len != 0 + } +} diff --git a/storage/partitionlib/src/partition.rs b/storage/partitionlib/src/partition.rs new file mode 100644 index 0000000000..030f292852 --- /dev/null +++ b/storage/partitionlib/src/partition.rs @@ -0,0 +1,115 @@ +use super::Result; +pub use gpt::disk::LogicalBlockSize; +use std::fs::File; +use std::io::prelude::*; +use std::path::Path; +use uuid::Uuid; + +/// A union of the MBR and GPT partition entry +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct Partition { + /// The starting logical block number + pub start_lba: u64, + /// The size of the partition in sectors + pub size: u64, + pub flags: Option, + pub name: Option, + pub uuid: Option, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub enum PartitionTableKind { + Mbr, + Gpt, +} +impl Default for PartitionTableKind { + fn default() -> Self { + Self::Gpt + } +} +impl PartitionTableKind { + pub fn is_mbr(self) -> bool { + self == Self::Mbr + } + pub fn is_gpt(self) -> bool { + self == Self::Gpt + } +} + +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct PartitionTable { + pub partitions: Vec, + pub kind: PartitionTableKind, +} + +pub fn get_partitions_from_file>( + path: P, + sector_size: LogicalBlockSize, +) -> Result> { + let mut file = File::open(path)?; + get_partitions(&mut file, sector_size) +} +fn get_gpt_partitions( + device: &mut D, + sector_size: LogicalBlockSize, +) -> Result { + let header = match gpt::header::read_header_from_arbitrary_device(device, sector_size) { + Ok(res) => res, + Err(err) => return Err(err), + }; + Ok(PartitionTable { + partitions: gpt::partition::file_read_partitions(device, &header, sector_size).map( + |btree| { + btree + .into_iter() + .map(|(_, part)| Partition { + flags: Some(part.flags), + size: part.last_lba - part.first_lba + 1, + name: Some(part.name.clone()), + uuid: Some(part.part_guid), + start_lba: part.first_lba, + }) + .collect() + }, + )?, + kind: PartitionTableKind::Gpt, + }) +} +fn get_mbr_partitions(device: &mut D) -> Result> { + let header = match crate::mbr::read_header(device) { + Ok(h) => h, + Err(crate::mbr::Error::ParsingError(_)) => return Ok(None), + Err(crate::mbr::Error::IoError(ioerr)) => return Err(ioerr), + }; + Ok(Some(PartitionTable { + kind: PartitionTableKind::Mbr, + partitions: header + .partitions() + .iter() + .copied() + .filter(crate::mbr::Entry::is_valid) + .map(|partition: crate::mbr::Entry| Partition { + name: None, + uuid: None, // TODO: Some kind of one-way conversion should be possible + flags: None, // TODO + size: partition.len.into(), + start_lba: partition.rel_sector.into(), + }) + .collect(), + })) +} +pub fn get_partitions( + device: &mut D, + sector_size: LogicalBlockSize, +) -> Result> { + get_gpt_partitions(device, sector_size) + .map(Some) + .or_else(|_| get_mbr_partitions(device)) +} + +impl Partition { + pub fn to_offset(&self, sector_size: LogicalBlockSize) -> u64 { + let blksize: u64 = sector_size.into(); + self.start_lba * blksize + } +} diff --git a/storage/partitionlib/tests/test.rs b/storage/partitionlib/tests/test.rs new file mode 100644 index 0000000000..a9254c859b --- /dev/null +++ b/storage/partitionlib/tests/test.rs @@ -0,0 +1,54 @@ +extern crate partitionlib; + +use partitionlib::{get_partitions_from_file, LogicalBlockSize, Partition}; + +#[test] +fn part_is_gpt() { + assert!(dbg!( + get_partitions_from_file("./resources/disk.img", LogicalBlockSize::Lb512) + .unwrap() + .unwrap() + ) + .kind + .is_gpt()); +} + +#[test] +fn part_is_mbr() { + assert!( + get_partitions_from_file("./resources/disk_mbr.img", LogicalBlockSize::Lb512) + .unwrap() + .unwrap() + .kind + .is_mbr() + ); +} + +// NOTE: The following tests rely on outside resource files being correct. +#[test] +fn gpt() { + let table = get_partitions_from_file("./resources/disk.img", LogicalBlockSize::Lb512).unwrap().unwrap(); + assert_eq!(&table.partitions, &[ + Partition { + flags: Some(0), + name: Some("bug".to_owned()), + uuid: Some(uuid::Uuid::parse_str("b665fba9-74d5-4069-a6b9-5ba3a164fdfe").unwrap()), // Microsoft basic data + size: 957, + start_lba: 34, + } + ]); +} + +#[test] +fn mbr() { + let table = get_partitions_from_file("./resources/disk_mbr.img", LogicalBlockSize::Lb512).unwrap().unwrap(); + assert_eq!(&table.partitions, &[ + Partition { + flags: None, + name: None, + uuid: None, + size: 3, + start_lba: 1, + } + ]); +} diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index c9d09ad78d..de7aba04a1 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -15,7 +15,7 @@ spin = "*" redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } -partitionlib = { git = "https://gitlab.redox-os.org/redox-os/partitionlib.git" } +partitionlib = { path = "../partitionlib" } common = { path = "../../common" } driver-block = { path = "../driver-block" } diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 217bf68f94..609f5f5059 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -191,6 +191,9 @@ impl<'a> DiskScheme<'a> { block_bytes: &mut [0u8; 4096], }; + //driver_block::DiskWrapper::new(disk) + + // FIXME use DiskWrapper instead let part_table = partitionlib::get_partitions(&mut shim, LogicalBlockSize::Lb512) .ok() .flatten(); From 398103e7103e732437764904106fc104e375b105 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 22:18:21 +0100 Subject: [PATCH 1113/1301] storage/partitionlib: Rustfmt --- storage/partitionlib/tests/test.rs | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/storage/partitionlib/tests/test.rs b/storage/partitionlib/tests/test.rs index a9254c859b..c2a542a1c7 100644 --- a/storage/partitionlib/tests/test.rs +++ b/storage/partitionlib/tests/test.rs @@ -27,28 +27,34 @@ fn part_is_mbr() { // NOTE: The following tests rely on outside resource files being correct. #[test] fn gpt() { - let table = get_partitions_from_file("./resources/disk.img", LogicalBlockSize::Lb512).unwrap().unwrap(); - assert_eq!(&table.partitions, &[ - Partition { + let table = get_partitions_from_file("./resources/disk.img", LogicalBlockSize::Lb512) + .unwrap() + .unwrap(); + assert_eq!( + &table.partitions, + &[Partition { flags: Some(0), name: Some("bug".to_owned()), uuid: Some(uuid::Uuid::parse_str("b665fba9-74d5-4069-a6b9-5ba3a164fdfe").unwrap()), // Microsoft basic data size: 957, start_lba: 34, - } - ]); + }] + ); } #[test] fn mbr() { - let table = get_partitions_from_file("./resources/disk_mbr.img", LogicalBlockSize::Lb512).unwrap().unwrap(); - assert_eq!(&table.partitions, &[ - Partition { + let table = get_partitions_from_file("./resources/disk_mbr.img", LogicalBlockSize::Lb512) + .unwrap() + .unwrap(); + assert_eq!( + &table.partitions, + &[Partition { flags: None, name: None, uuid: None, size: 3, start_lba: 1, - } - ]); + }] + ); } From 9257cbbfa26a96e5ba22437eeb0c714c4bff10be Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 22:25:24 +0100 Subject: [PATCH 1114/1301] storage/partitionlib: Couple of cleanups --- storage/partitionlib/Cargo.toml | 2 +- storage/partitionlib/src/lib.rs | 6 +-- storage/partitionlib/src/mbr.rs | 70 ++++++++++----------------- storage/partitionlib/src/partition.rs | 49 ++++--------------- storage/partitionlib/tests/test.rs | 41 +++++----------- 5 files changed, 49 insertions(+), 119 deletions(-) diff --git a/storage/partitionlib/Cargo.toml b/storage/partitionlib/Cargo.toml index 27df61ce16..8e5e3fad44 100644 --- a/storage/partitionlib/Cargo.toml +++ b/storage/partitionlib/Cargo.toml @@ -2,7 +2,7 @@ name = "partitionlib" version = "0.1.0" authors = ["Deepak Sirone "] -edition = "2018" +edition = "2021" license = "MIT" [dependencies] diff --git a/storage/partitionlib/src/lib.rs b/storage/partitionlib/src/lib.rs index 1b0b71b4e5..be369ce64e 100644 --- a/storage/partitionlib/src/lib.rs +++ b/storage/partitionlib/src/lib.rs @@ -1,7 +1,3 @@ -extern crate gpt; -extern crate uuid; - -pub type Result = std::io::Result; mod mbr; -pub mod partition; +mod partition; pub use self::partition::*; diff --git a/storage/partitionlib/src/mbr.rs b/storage/partitionlib/src/mbr.rs index cf129ce356..67ae5a6dad 100644 --- a/storage/partitionlib/src/mbr.rs +++ b/storage/partitionlib/src/mbr.rs @@ -1,77 +1,57 @@ use scroll::{Pread, Pwrite}; -use std::io; -use std::io::prelude::*; +use std::io::{self, Read, Seek}; #[derive(Clone, Copy, Debug, Pread, Pwrite)] -pub struct Entry { - pub drive_attrs: u8, - pub start_head: u8, - pub start_cs: u16, - pub sys_id: u8, - pub end_head: u8, - pub end_cs: u16, - pub rel_sector: u32, - pub len: u32, +pub(crate) struct Entry { + pub(crate) drive_attrs: u8, + pub(crate) start_head: u8, + pub(crate) start_cs: u16, + pub(crate) sys_id: u8, + pub(crate) end_head: u8, + pub(crate) end_cs: u16, + pub(crate) rel_sector: u32, + pub(crate) len: u32, } #[derive(Pread, Pwrite)] -pub struct Header { - pub bootstrap: [u8; 446], - pub first_entry: Entry, - pub second_entry: Entry, - pub third_entry: Entry, - pub fourth_entry: Entry, - pub last_signature: u16, // 0xAA55 +pub(crate) struct Header { + pub(crate) bootstrap: [u8; 446], + pub(crate) first_entry: Entry, + pub(crate) second_entry: Entry, + pub(crate) third_entry: Entry, + pub(crate) fourth_entry: Entry, + pub(crate) last_signature: u16, // 0xAA55 } -#[derive(Debug)] -pub enum Error { - IoError(io::Error), - ParsingError(scroll::Error), -} - -impl From for Error { - fn from(err: io::Error) -> Self { - Self::IoError(err) - } -} -impl From for Error { - fn from(err: scroll::Error) -> Self { - Self::ParsingError(err) - } -} - -pub fn read_header(device: &mut D) -> Result { +pub(crate) fn read_header(device: &mut D) -> io::Result> { device.seek(io::SeekFrom::Start(0))?; let mut bytes = [0u8; 512]; device.read_exact(&mut bytes)?; - let header: Header = bytes.pread_with(0, scroll::LE)?; + let header: Header = bytes.pread_with(0, scroll::LE).unwrap(); if header.last_signature != 0xAA55 { - return Err(scroll::Error::BadInput { - size: 2, - msg: "no 0xAA55 signature", - } - .into()); + return Ok(None); } - Ok(header) + Ok(Some(header)) } impl Header { - pub fn partitions(&self) -> [Entry; 4] { + pub(crate) fn partitions(&self) -> impl Iterator { [ self.first_entry, self.second_entry, self.third_entry, self.fourth_entry, ] + .into_iter() + .filter(Entry::is_valid) } } impl Entry { - pub fn is_valid(&self) -> bool { + fn is_valid(&self) -> bool { (self.drive_attrs == 0 || self.drive_attrs == 0x80) && self.len != 0 } } diff --git a/storage/partitionlib/src/partition.rs b/storage/partitionlib/src/partition.rs index 030f292852..949171511b 100644 --- a/storage/partitionlib/src/partition.rs +++ b/storage/partitionlib/src/partition.rs @@ -1,8 +1,5 @@ -use super::Result; pub use gpt::disk::LogicalBlockSize; -use std::fs::File; -use std::io::prelude::*; -use std::path::Path; +use std::io::{self, Read, Seek}; use uuid::Uuid; /// A union of the MBR and GPT partition entry @@ -17,46 +14,23 @@ pub struct Partition { pub uuid: Option, } -#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum PartitionTableKind { Mbr, Gpt, } -impl Default for PartitionTableKind { - fn default() -> Self { - Self::Gpt - } -} -impl PartitionTableKind { - pub fn is_mbr(self) -> bool { - self == Self::Mbr - } - pub fn is_gpt(self) -> bool { - self == Self::Gpt - } -} -#[derive(Clone, Debug, Eq, PartialEq, Hash)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct PartitionTable { pub partitions: Vec, pub kind: PartitionTableKind, } -pub fn get_partitions_from_file>( - path: P, - sector_size: LogicalBlockSize, -) -> Result> { - let mut file = File::open(path)?; - get_partitions(&mut file, sector_size) -} fn get_gpt_partitions( device: &mut D, sector_size: LogicalBlockSize, -) -> Result { - let header = match gpt::header::read_header_from_arbitrary_device(device, sector_size) { - Ok(res) => res, - Err(err) => return Err(err), - }; +) -> io::Result { + let header = gpt::header::read_header_from_arbitrary_device(device, sector_size)?; Ok(PartitionTable { partitions: gpt::partition::file_read_partitions(device, &header, sector_size).map( |btree| { @@ -75,19 +49,14 @@ fn get_gpt_partitions( kind: PartitionTableKind::Gpt, }) } -fn get_mbr_partitions(device: &mut D) -> Result> { - let header = match crate::mbr::read_header(device) { - Ok(h) => h, - Err(crate::mbr::Error::ParsingError(_)) => return Ok(None), - Err(crate::mbr::Error::IoError(ioerr)) => return Err(ioerr), +fn get_mbr_partitions(device: &mut D) -> io::Result> { + let Some(header) = crate::mbr::read_header(device)? else { + return Ok(None); }; Ok(Some(PartitionTable { kind: PartitionTableKind::Mbr, partitions: header .partitions() - .iter() - .copied() - .filter(crate::mbr::Entry::is_valid) .map(|partition: crate::mbr::Entry| Partition { name: None, uuid: None, // TODO: Some kind of one-way conversion should be possible @@ -101,7 +70,7 @@ fn get_mbr_partitions(device: &mut D) -> Result( device: &mut D, sector_size: LogicalBlockSize, -) -> Result> { +) -> io::Result> { get_gpt_partitions(device, sector_size) .map(Some) .or_else(|_| get_mbr_partitions(device)) diff --git a/storage/partitionlib/tests/test.rs b/storage/partitionlib/tests/test.rs index c2a542a1c7..c4ef93220e 100644 --- a/storage/partitionlib/tests/test.rs +++ b/storage/partitionlib/tests/test.rs @@ -1,35 +1,21 @@ -extern crate partitionlib; +use std::fs::File; -use partitionlib::{get_partitions_from_file, LogicalBlockSize, Partition}; +use partitionlib::{ + get_partitions, LogicalBlockSize, Partition, PartitionTable, PartitionTableKind, +}; -#[test] -fn part_is_gpt() { - assert!(dbg!( - get_partitions_from_file("./resources/disk.img", LogicalBlockSize::Lb512) - .unwrap() - .unwrap() - ) - .kind - .is_gpt()); -} - -#[test] -fn part_is_mbr() { - assert!( - get_partitions_from_file("./resources/disk_mbr.img", LogicalBlockSize::Lb512) - .unwrap() - .unwrap() - .kind - .is_mbr() - ); +fn get_partitions_from_file(path: &str) -> PartitionTable { + let mut file = File::open(path).unwrap(); + get_partitions(&mut file, LogicalBlockSize::Lb512) + .unwrap() + .unwrap() } // NOTE: The following tests rely on outside resource files being correct. #[test] fn gpt() { - let table = get_partitions_from_file("./resources/disk.img", LogicalBlockSize::Lb512) - .unwrap() - .unwrap(); + let table = get_partitions_from_file("./resources/disk.img"); + assert_eq!(table.kind, PartitionTableKind::Gpt); assert_eq!( &table.partitions, &[Partition { @@ -44,9 +30,8 @@ fn gpt() { #[test] fn mbr() { - let table = get_partitions_from_file("./resources/disk_mbr.img", LogicalBlockSize::Lb512) - .unwrap() - .unwrap(); + let table = get_partitions_from_file("./resources/disk_mbr.img"); + assert_eq!(table.kind, PartitionTableKind::Mbr); assert_eq!( &table.partitions, &[Partition { From 03329430b457b4e631ee5d3f51a66ce9affc96ab Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Mar 2025 20:34:33 +0100 Subject: [PATCH 1115/1301] storage/driver-block: Handle block_read read buffer internally --- storage/driver-block/src/lib.rs | 31 ++++++++++--------------------- storage/nvmed/src/scheme.rs | 11 +++-------- storage/virtio-blkd/src/scheme.rs | 5 +---- 3 files changed, 14 insertions(+), 33 deletions(-) diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 2d40c69d57..316478f61a 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -6,7 +6,6 @@ use partitionlib::{LogicalBlockSize, PartitionTable}; /// Split the read operation into a series of block reads. /// `read_fn` will be called with a block number to be read, and a buffer to be filled. -/// The buffer must be large enough to hold `blksize` of data. /// `read_fn` must return a full block of data. /// Result will be the number of bytes read. // FIXME make private once nvmed uses the DiskWrapper defined in this crate @@ -14,7 +13,6 @@ pub fn block_read( offset: u64, blksize: u32, buf: &mut [u8], - block_bytes: &mut [u8], mut read_fn: impl FnMut(u64, &mut [u8]) -> Result<(), Error>, ) -> Result { // TODO: Yield sometimes, perhaps after a few blocks or something. @@ -32,6 +30,9 @@ pub fn block_read( let blk_size = usize::try_from(blksize).expect("blksize larger than usize"); let mut total_read = 0; + let mut block_bytes = [0u8; 4096]; + let block_bytes = &mut block_bytes[..blk_size]; + while curr_buf.len() > 0 { // TODO: Async/await? I mean, shouldn't AHCI be async? @@ -72,13 +73,12 @@ impl DiskWrapper { Ok(512) => LogicalBlockSize::Lb512, _ => return None, }; - struct Device<'a, 'b> { + struct Device<'a> { disk: &'a mut dyn Disk, offset: u64, - block_bytes: &'b mut [u8], } - impl<'a, 'b> Seek for Device<'a, 'b> { + impl<'a> Seek for Device<'a> { fn seek(&mut self, from: SeekFrom) -> io::Result { let size = i64::try_from(self.disk.size()).or(Err(io::Error::new( io::ErrorKind::Other, @@ -97,7 +97,7 @@ impl DiskWrapper { } } // TODO: Perhaps this impl should be used in the rest of the scheme. - impl<'a, 'b> Read for Device<'a, 'b> { + impl<'a> Read for Device<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result { let blksize = self .disk @@ -115,7 +115,6 @@ impl DiskWrapper { match disk.read(block, block_bytes) { Ok(Some(bytes)) => { assert_eq!(bytes, block_bytes.len()); - assert_eq!(bytes, blksize as usize); return Ok(()); } Ok(None) => { @@ -126,26 +125,16 @@ impl DiskWrapper { } } }; - let bytes_read = - block_read(self.offset, blksize, buf, self.block_bytes, read_block)?; + let bytes_read = block_read(self.offset, blksize, buf, read_block)?; self.offset += bytes_read as u64; Ok(bytes_read) } } - let mut block_bytes = [0u8; 4096]; - - partitionlib::get_partitions( - &mut Device { - disk, - offset: 0, - block_bytes: &mut block_bytes[..bs.into()], - }, - bs, - ) - .ok() - .flatten() + partitionlib::get_partitions(&mut Device { disk, offset: 0 }, bs) + .ok() + .flatten() } pub fn new(mut disk: Box) -> Self { diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 493a08293b..977d03328b 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -41,14 +41,13 @@ impl DiskWrapper { 4096 => LogicalBlockSize::Lb4096, _ => return None, }; - struct Device<'a, 'b> { + struct Device<'a> { disk: &'a mut NvmeNamespace, nvme: &'a Nvme, offset: u64, - block_bytes: &'b mut [u8], } - impl<'a, 'b> Seek for Device<'a, 'b> { + impl<'a> Seek for Device<'a> { fn seek(&mut self, from: io::SeekFrom) -> io::Result { let size_u = self.disk.blocks * self.disk.block_size; let size = i64::try_from(size_u).or(Err(io::Error::new( @@ -70,7 +69,7 @@ impl DiskWrapper { } } - impl<'a, 'b> Read for Device<'a, 'b> { + impl<'a> Read for Device<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result { let blksize = self.disk.block_size; let size_in_blocks = self.disk.blocks; @@ -105,7 +104,6 @@ impl DiskWrapper { .try_into() .expect("Unreasonable block size above 2^32 bytes"), buf, - self.block_bytes, read_block, )?; self.offset += bytes_read as u64; @@ -113,14 +111,11 @@ impl DiskWrapper { } } - let mut block_bytes = [0u8; 4096]; - partitionlib::get_partitions( &mut Device { disk, nvme, offset: 0, - block_bytes: &mut block_bytes[..bs.into()], }, bs, ) diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 609f5f5059..8880779c59 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -124,7 +124,6 @@ impl<'a> DiskScheme<'a> { struct VirtioShim<'a, 'b> { scheme: &'b DiskScheme<'a>, offset: u64, - block_bytes: &'b mut [u8], } impl<'a, 'b> Read for VirtioShim<'a, 'b> { @@ -156,8 +155,7 @@ impl<'a> DiskScheme<'a> { }; let bytes_read = - driver_block::block_read(self.offset, 512, buf, self.block_bytes, read_block) - .unwrap(); + driver_block::block_read(self.offset, 512, buf, read_block).unwrap(); self.offset += bytes_read as u64; Ok(bytes_read) } @@ -188,7 +186,6 @@ impl<'a> DiskScheme<'a> { let mut shim = VirtioShim { scheme: &this, offset: 0, - block_bytes: &mut [0u8; 4096], }; //driver_block::DiskWrapper::new(disk) From aacf09cef4f630d06e2e4e1d206eaad90e0d22e2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Mar 2025 20:42:41 +0100 Subject: [PATCH 1116/1301] storage/driver-block: Remove id method from Disk trait --- storage/ahcid/src/ahci/disk_ata.rs | 4 ---- storage/ahcid/src/ahci/disk_atapi.rs | 4 ---- storage/bcm2835-sdhcid/src/sd/mod.rs | 4 ---- storage/driver-block/src/lib.rs | 1 - storage/ided/src/ide.rs | 4 ---- 5 files changed, 17 deletions(-) diff --git a/storage/ahcid/src/ahci/disk_ata.rs b/storage/ahcid/src/ahci/disk_ata.rs index 2dc2a1f190..d5173e2f9e 100644 --- a/storage/ahcid/src/ahci/disk_ata.rs +++ b/storage/ahcid/src/ahci/disk_ata.rs @@ -154,10 +154,6 @@ impl DiskATA { } impl Disk for DiskATA { - fn id(&self) -> usize { - self.id - } - fn size(&mut self) -> u64 { self.size } diff --git a/storage/ahcid/src/ahci/disk_atapi.rs b/storage/ahcid/src/ahci/disk_atapi.rs index 29ae47996c..33b35f92b1 100644 --- a/storage/ahcid/src/ahci/disk_atapi.rs +++ b/storage/ahcid/src/ahci/disk_atapi.rs @@ -72,10 +72,6 @@ impl DiskATAPI { } impl Disk for DiskATAPI { - fn id(&self) -> usize { - self.id - } - fn size(&mut self) -> u64 { match self.read_capacity() { Ok((blk_count, blk_size)) => (blk_count as u64) * (blk_size as u64), diff --git a/storage/bcm2835-sdhcid/src/sd/mod.rs b/storage/bcm2835-sdhcid/src/sd/mod.rs index 8c718ba105..b371833773 100644 --- a/storage/bcm2835-sdhcid/src/sd/mod.rs +++ b/storage/bcm2835-sdhcid/src/sd/mod.rs @@ -733,10 +733,6 @@ impl SdHostCtrl { } impl Disk for SdHostCtrl { - fn id(&self) -> usize { - 0xdead_dead - } - fn size(&mut self) -> u64 { //assert 512MiB self.size diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 316478f61a..6b10c14b26 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -54,7 +54,6 @@ pub fn block_read( } pub trait Disk { - fn id(&self) -> usize; fn block_length(&mut self) -> syscall::error::Result; fn size(&mut self) -> u64; diff --git a/storage/ided/src/ide.rs b/storage/ided/src/ide.rs index ad2b771446..b03213a464 100644 --- a/storage/ided/src/ide.rs +++ b/storage/ided/src/ide.rs @@ -169,10 +169,6 @@ pub struct AtaDisk { } impl Disk for AtaDisk { - fn id(&self) -> usize { - self.chan_i << 1 | self.dev as usize - } - fn size(&mut self) -> u64 { self.size } From ebdfc89e7a56baac86cefc26604827cdce80a531 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Mar 2025 20:46:33 +0100 Subject: [PATCH 1117/1301] storage/nvmed: Pass NvmeNamespace by value and remove the separate nsid arguments --- storage/nvmed/src/nvme/mod.rs | 19 ++++++++----------- storage/nvmed/src/scheme.rs | 22 ++++++++++------------ 2 files changed, 18 insertions(+), 23 deletions(-) diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 127dd5ae9f..93a1c03b9b 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -170,7 +170,7 @@ pub struct NvmeRegs { cmbsz: Mmio, } -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub struct NvmeNamespace { pub id: u32, pub blocks: u64, @@ -641,8 +641,7 @@ impl Nvme { fn namespace_rw( &self, - namespace: &NvmeNamespace, - nsid: u32, + namespace: NvmeNamespace, lba: u64, blocks_1: u16, write: bool, @@ -666,9 +665,9 @@ impl Nvme { let mut cmd = NvmeCmd::default(); let comp = self.submit_and_complete_command(1, |cid| { cmd = if write { - NvmeCmd::io_write(cid, nsid, lba, blocks_1, ptr0, ptr1) + NvmeCmd::io_write(cid, namespace.id, lba, blocks_1, ptr0, ptr1) } else { - NvmeCmd::io_read(cid, nsid, lba, blocks_1, ptr0, ptr1) + NvmeCmd::io_read(cid, namespace.id, lba, blocks_1, ptr0, ptr1) }; cmd.clone() }); @@ -683,8 +682,7 @@ impl Nvme { pub fn namespace_read( &self, - namespace: &NvmeNamespace, - nsid: u32, + namespace: NvmeNamespace, mut lba: u64, buf: &mut [u8], ) -> Result> { @@ -698,7 +696,7 @@ impl Nvme { assert!(blocks > 0); assert!(blocks <= 0x1_0000); - self.namespace_rw(namespace, nsid, lba, (blocks - 1) as u16, false)?; + self.namespace_rw(namespace, lba, (blocks - 1) as u16, false)?; chunk.copy_from_slice(&buffer_guard[..chunk.len()]); @@ -710,8 +708,7 @@ impl Nvme { pub fn namespace_write( &self, - namespace: &NvmeNamespace, - nsid: u32, + namespace: NvmeNamespace, mut lba: u64, buf: &[u8], ) -> Result> { @@ -727,7 +724,7 @@ impl Nvme { buffer_guard[..chunk.len()].copy_from_slice(chunk); - self.namespace_rw(namespace, nsid, lba, (blocks - 1) as u16, true)?; + self.namespace_rw(namespace, lba, (blocks - 1) as u16, true)?; lba += blocks as u64; } diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 977d03328b..30dd5d82d5 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -35,14 +35,14 @@ impl AsRef for DiskWrapper { } impl DiskWrapper { - fn pt(disk: &mut NvmeNamespace, nvme: &Nvme) -> Option { + fn pt(disk: NvmeNamespace, nvme: &Nvme) -> Option { let bs = match disk.block_size { 512 => LogicalBlockSize::Lb512, 4096 => LogicalBlockSize::Lb4096, _ => return None, }; struct Device<'a> { - disk: &'a mut NvmeNamespace, + disk: NvmeNamespace, nvme: &'a Nvme, offset: u64, } @@ -74,7 +74,7 @@ impl DiskWrapper { let blksize = self.disk.block_size; let size_in_blocks = self.disk.blocks; - let disk = &mut self.disk; + let disk = self.disk; let nvme = &mut self.nvme; let read_block = |block: u64, block_bytes: &mut [u8]| { @@ -83,7 +83,7 @@ impl DiskWrapper { } loop { match nvme - .namespace_read(disk, disk.id, block, block_bytes) + .namespace_read(disk, block, block_bytes) .map_err(|err| io::Error::from_raw_os_error(err.errno))? { Some(bytes) => { @@ -122,9 +122,9 @@ impl DiskWrapper { .ok() .flatten() } - fn new(mut inner: NvmeNamespace, nvme: &Nvme) -> Self { + fn new(inner: NvmeNamespace, nvme: &Nvme) -> Self { Self { - pt: Self::pt(&mut inner, nvme), + pt: Self::pt(inner, nvme), inner, } } @@ -372,7 +372,7 @@ impl SchemeBlock for DiskScheme { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; self.nvme - .namespace_read(disk.as_ref(), disk.as_ref().id, offset / block_size, buf) + .namespace_read(*disk.as_ref(), offset / block_size, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; @@ -392,8 +392,7 @@ impl SchemeBlock for DiskScheme { let abs_block = part.start_lba + rel_block; - self.nvme - .namespace_read(disk.as_ref(), disk.as_ref().id, abs_block, buf) + self.nvme.namespace_read(*disk.as_ref(), abs_block, buf) } } } @@ -411,7 +410,7 @@ impl SchemeBlock for DiskScheme { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block_size = disk.as_ref().block_size; self.nvme - .namespace_write(disk.as_ref(), disk.as_ref().id, offset / block_size, buf) + .namespace_write(*disk.as_ref(), offset / block_size, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; @@ -431,8 +430,7 @@ impl SchemeBlock for DiskScheme { let abs_block = part.start_lba + rel_block; - self.nvme - .namespace_write(disk.as_ref(), disk.as_ref().id, abs_block, buf) + self.nvme.namespace_write(*disk.as_ref(), abs_block, buf) } } } From f01a8c8d3e20ae90b79742c76d725a7af44dab25 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Mar 2025 20:58:01 +0100 Subject: [PATCH 1118/1301] storage: Use DiskWrapper::pt in nvmed and virtio-blkd --- storage/driver-block/src/lib.rs | 6 +- storage/nvmed/src/scheme.rs | 114 +++++++----------------------- storage/virtio-blkd/src/scheme.rs | 101 ++++++-------------------- 3 files changed, 49 insertions(+), 172 deletions(-) diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 6b10c14b26..02f771e475 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -8,8 +8,7 @@ use partitionlib::{LogicalBlockSize, PartitionTable}; /// `read_fn` will be called with a block number to be read, and a buffer to be filled. /// `read_fn` must return a full block of data. /// Result will be the number of bytes read. -// FIXME make private once nvmed uses the DiskWrapper defined in this crate -pub fn block_read( +fn block_read( offset: u64, blksize: u32, buf: &mut [u8], @@ -67,9 +66,10 @@ pub struct DiskWrapper { } impl DiskWrapper { - fn pt(disk: &mut dyn Disk) -> Option { + pub fn pt(disk: &mut dyn Disk) -> Option { let bs = match disk.block_length() { Ok(512) => LogicalBlockSize::Lb512, + Ok(4096) => LogicalBlockSize::Lb4096, _ => return None, }; struct Device<'a> { diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 30dd5d82d5..ee27527d9e 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -1,11 +1,11 @@ use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::fmt::Write; -use std::io; -use std::io::prelude::*; +use std::str; use std::sync::Arc; -use std::{cmp, str}; +use driver_block::Disk; +use partitionlib::PartitionTable; use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; use syscall::schemev2::NewFdFlags; use syscall::{ @@ -15,14 +15,32 @@ use syscall::{ use crate::nvme::{Nvme, NvmeNamespace}; -use partitionlib::{LogicalBlockSize, PartitionTable}; - enum Handle { List(Vec), // entries Disk(u32), // disk num Partition(u32, u32), // disk num, part num } +struct NamespaceAndNvme<'a>(&'a Nvme, NvmeNamespace); + +impl Disk for NamespaceAndNvme<'_> { + fn block_length(&mut self) -> syscall::error::Result { + Ok(self.1.block_size.try_into().unwrap()) + } + + fn size(&mut self) -> u64 { + self.1.blocks * self.1.block_size + } + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + self.0.namespace_read(self.1, block, buffer) + } + + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + self.0.namespace_write(self.1, block, buffer) + } +} + pub struct DiskWrapper { inner: NvmeNamespace, pt: Option, @@ -36,91 +54,7 @@ impl AsRef for DiskWrapper { impl DiskWrapper { fn pt(disk: NvmeNamespace, nvme: &Nvme) -> Option { - let bs = match disk.block_size { - 512 => LogicalBlockSize::Lb512, - 4096 => LogicalBlockSize::Lb4096, - _ => return None, - }; - struct Device<'a> { - disk: NvmeNamespace, - nvme: &'a Nvme, - offset: u64, - } - - impl<'a> Seek for Device<'a> { - fn seek(&mut self, from: io::SeekFrom) -> io::Result { - let size_u = self.disk.blocks * self.disk.block_size; - let size = i64::try_from(size_u).or(Err(io::Error::new( - io::ErrorKind::Other, - "Disk larger than 2^63 - 1 bytes", - )))?; - - self.offset = match from { - io::SeekFrom::Start(new_pos) => cmp::min(size_u, new_pos), - io::SeekFrom::Current(new_pos) => { - cmp::max(0, cmp::min(size, self.offset as i64 + new_pos)) as u64 - } - io::SeekFrom::End(new_pos) => { - cmp::max(0, cmp::min(size + new_pos, size)) as u64 - } - }; - - Ok(self.offset) - } - } - - impl<'a> Read for Device<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let blksize = self.disk.block_size; - let size_in_blocks = self.disk.blocks; - - let disk = self.disk; - let nvme = &mut self.nvme; - - let read_block = |block: u64, block_bytes: &mut [u8]| { - if block >= size_in_blocks { - return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); - } - loop { - match nvme - .namespace_read(disk, block, block_bytes) - .map_err(|err| io::Error::from_raw_os_error(err.errno))? - { - Some(bytes) => { - assert_eq!(bytes, block_bytes.len()); - assert_eq!(bytes, blksize as usize); - return Ok(()); - } - None => { - std::thread::yield_now(); - continue; - } // TODO: Does this driver have (internal) error handling at all? - } - } - }; - let bytes_read = driver_block::block_read( - self.offset, - blksize - .try_into() - .expect("Unreasonable block size above 2^32 bytes"), - buf, - read_block, - )?; - self.offset += bytes_read as u64; - Ok(bytes_read) - } - } - - partitionlib::get_partitions( - &mut Device { - disk, - nvme, - offset: 0, - }, - bs, - ) - .ok() - .flatten() + driver_block::DiskWrapper::pt(&mut NamespaceAndNvme(nvme, disk)) } fn new(inner: NvmeNamespace, nvme: &Nvme) -> Self { Self { diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 8880779c59..d4727b9278 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -1,13 +1,10 @@ use std::collections::BTreeMap; -use std::io::Read; -use std::io::Result as IoResult; -use std::io::Seek; use std::fmt::Write; use std::sync::Arc; use common::dma::Dma; -use partitionlib::LogicalBlockSize; +use driver_block::DiskWrapper; use partitionlib::PartitionTable; use redox_scheme::CallerCtx; @@ -121,85 +118,31 @@ impl<'a> DiskScheme<'a> { part_table: None, }; - struct VirtioShim<'a, 'b> { - scheme: &'b DiskScheme<'a>, - offset: u64, - } - - impl<'a, 'b> Read for VirtioShim<'a, 'b> { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - let read_block = - |block: u64, block_bytes: &mut [u8]| -> Result<(), std::io::Error> { - let req = Dma::new(BlockVirtRequest { - ty: BlockRequestTy::In, - reserved: 0, - sector: block, - }) - .unwrap(); - - let result = Dma::new([0u8; 512]).unwrap(); - let status = Dma::new(u8::MAX).unwrap(); - - let chain = ChainBuilder::new() - .chain(Buffer::new(&req)) - .chain(Buffer::new(&result).flags(DescriptorFlags::WRITE_ONLY)) - .chain(Buffer::new(&status).flags(DescriptorFlags::WRITE_ONLY)) - .build(); - - futures::executor::block_on(self.scheme.queue.send(chain)); - assert_eq!(*status, 0); - - let size = core::cmp::min(block_bytes.len(), result.len()); - block_bytes[..size].copy_from_slice(&result.as_slice()[..size]); - Ok(()) - }; - - let bytes_read = - driver_block::block_read(self.offset, 512, buf, read_block).unwrap(); - self.offset += bytes_read as u64; - Ok(bytes_read) - } - } - - impl<'a, 'b> Seek for VirtioShim<'a, 'b> { - fn seek(&mut self, from: std::io::SeekFrom) -> IoResult { - let size_u = self.scheme.cfg.capacity() * self.scheme.cfg.block_size() as u64; - let size = i64::try_from(size_u).or(Err(std::io::Error::new( - std::io::ErrorKind::Other, - "Disk larger than 2^63 - 1 bytes", - )))?; - - self.offset = match from { - std::io::SeekFrom::Start(new_pos) => std::cmp::min(size_u, new_pos), - std::io::SeekFrom::Current(new_pos) => { - std::cmp::max(0, std::cmp::min(size, self.offset as i64 + new_pos)) as u64 - } - std::io::SeekFrom::End(new_pos) => { - std::cmp::max(0, std::cmp::min(size + new_pos, size)) as u64 - } - }; - - Ok(self.offset) - } - } - - let mut shim = VirtioShim { - scheme: &this, - offset: 0, - }; - - //driver_block::DiskWrapper::new(disk) - - // FIXME use DiskWrapper instead - let part_table = partitionlib::get_partitions(&mut shim, LogicalBlockSize::Lb512) - .ok() - .flatten(); - - this.part_table = part_table; + this.part_table = DiskWrapper::pt(&mut this); this } } +impl driver_block::Disk for DiskScheme<'_> { + fn block_length(&mut self) -> syscall::error::Result { + Ok(self.cfg.block_size()) + } + + fn size(&mut self) -> u64 { + self.cfg.capacity() * self.cfg.block_size() as u64 + } + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + Ok(Some(futures::executor::block_on( + self.queue.read(block, buffer), + ))) + } + + fn write(&mut self, _block: u64, _buffer: &[u8]) -> syscall::Result> { + todo!() + } +} + impl<'a> SchemeBlock for DiskScheme<'a> { fn xopen( &mut self, From dfe23b06834700847891c69f4831fda3fb8a9a03 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Mar 2025 21:35:49 +0100 Subject: [PATCH 1119/1301] storage/driver-block: Make Disk::block_length infallible It should be read when creating the struct implementing Disk and every disk needs to have some block length. --- storage/ahcid/src/ahci/disk_ata.rs | 4 +-- storage/ahcid/src/ahci/disk_atapi.rs | 44 ++++++++++++---------------- storage/ahcid/src/scheme.rs | 16 +++++----- storage/bcm2835-sdhcid/src/scheme.rs | 16 +++++----- storage/bcm2835-sdhcid/src/sd/mod.rs | 4 +-- storage/driver-block/src/lib.rs | 11 +++---- storage/ided/src/ide.rs | 4 +-- storage/ided/src/scheme.rs | 16 +++++----- storage/nvmed/src/scheme.rs | 4 +-- storage/virtio-blkd/src/scheme.rs | 4 +-- 10 files changed, 57 insertions(+), 66 deletions(-) diff --git a/storage/ahcid/src/ahci/disk_ata.rs b/storage/ahcid/src/ahci/disk_ata.rs index d5173e2f9e..ee3b32a8b6 100644 --- a/storage/ahcid/src/ahci/disk_ata.rs +++ b/storage/ahcid/src/ahci/disk_ata.rs @@ -178,7 +178,7 @@ impl Disk for DiskATA { } } - fn block_length(&mut self) -> Result { - Ok(512) + fn block_length(&mut self) -> u32 { + 512 } } diff --git a/storage/ahcid/src/ahci/disk_atapi.rs b/storage/ahcid/src/ahci/disk_atapi.rs index 33b35f92b1..ce3ce0b962 100644 --- a/storage/ahcid/src/ahci/disk_atapi.rs +++ b/storage/ahcid/src/ahci/disk_atapi.rs @@ -25,6 +25,8 @@ pub struct DiskATAPI { // Just using the same buffer size as DiskATA // Although the sector size is different (and varies) buf: Dma<[u8; 256 * 512]>, + blk_count: u32, + blk_size: u32, } impl DiskATAPI { @@ -38,12 +40,20 @@ impl DiskATAPI { .unwrap_or_else(|_| unreachable!()); let mut fb = unsafe { Dma::zeroed()?.assume_init() }; - let buf = unsafe { Dma::zeroed()?.assume_init() }; + let mut buf = unsafe { Dma::zeroed()?.assume_init() }; port.init(&mut clb, &mut ctbas, &mut fb); let size = unsafe { port.identify_packet(&mut clb, &mut ctbas).unwrap_or(0) }; + let mut cmd = [0; 16]; + cmd[0] = SCSI_READ_CAPACITY; + port.atapi_dma(&cmd, 8, &mut clb, &mut ctbas, &mut buf)?; + + // Instead of a count, contains number of last LBA, so add 1 + let blk_count = BigEndian::read_u32(&buf[0..4]) + 1; + let blk_size = BigEndian::read_u32(&buf[4..8]); + Ok(DiskATAPI { id, port, @@ -52,37 +62,25 @@ impl DiskATAPI { ctbas, _fb: fb, buf, + blk_count, + blk_size, }) } - - fn read_capacity(&mut self) -> Result<(u32, u32)> { - // TODO: only query when needed (disk changed) - - let mut cmd = [0; 16]; - cmd[0] = SCSI_READ_CAPACITY; - self.port - .atapi_dma(&cmd, 8, &mut self.clb, &mut self.ctbas, &mut self.buf)?; - - // Instead of a count, contains number of last LBA, so add 1 - let blk_count = BigEndian::read_u32(&self.buf[0..4]) + 1; - let blk_size = BigEndian::read_u32(&self.buf[4..8]); - - Ok((blk_count, blk_size)) - } } impl Disk for DiskATAPI { + fn block_length(&mut self) -> u32 { + self.blk_size + } + fn size(&mut self) -> u64 { - match self.read_capacity() { - Ok((blk_count, blk_size)) => (blk_count as u64) * (blk_size as u64), - Err(_) => 0, // XXX - } + u64::from(self.blk_count) * u64::from(self.blk_size) } fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result> { // TODO: Handle audio CDs, which use special READ CD command - let blk_len = self.block_length()?; + let blk_len = self.blk_size; let sectors = buffer.len() as u32 / blk_len; fn read10_cmd(block: u32, count: u16) -> [u8; 16] { @@ -147,8 +145,4 @@ impl Disk for DiskATAPI { fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result> { Err(Error::new(EBADF)) // TODO: Implement writing } - - fn block_length(&mut self) -> Result { - Ok(self.read_capacity()?.1) - } } diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index 7ed30f2de1..4655529a6b 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -175,7 +175,7 @@ impl SchemeBlock for DiskScheme { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = disk.size(); - stat.st_blksize = disk.block_length()?; + stat.st_blksize = disk.block_length(); Ok(Some(0)) } Handle::Partition(disk_id, part_num) => { @@ -190,8 +190,8 @@ impl SchemeBlock for DiskScheme { }; stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_length()?); - stat.st_blksize = disk.block_length()?; + stat.st_size = size * u64::from(disk.block_length()); + stat.st_blksize = disk.block_length(); stat.st_blocks = size; Ok(Some(0)) } @@ -263,12 +263,12 @@ impl SchemeBlock for DiskScheme { } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length()?; + let blk_len = disk.block_length(); disk.read(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length()?; + let blksize = disk.block_length(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize); @@ -304,12 +304,12 @@ impl SchemeBlock for DiskScheme { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length()?; + let blk_len = disk.block_length(); disk.write(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length()?; + let blksize = disk.block_length(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize); @@ -351,7 +351,7 @@ impl SchemeBlock for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))? .size; - u64::from(disk.block_length()?) * block_count + u64::from(disk.block_length()) * block_count } }, )) diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs index 70bf4772e0..7b5b195c61 100644 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ b/storage/bcm2835-sdhcid/src/scheme.rs @@ -164,7 +164,7 @@ impl SchemeBlock for DiskScheme { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = disk.size(); - stat.st_blksize = disk.block_length()?; + stat.st_blksize = disk.block_length(); Ok(Some(0)) } Handle::Partition(disk_id, part_num) => { @@ -179,8 +179,8 @@ impl SchemeBlock for DiskScheme { }; stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_length()?); - stat.st_blksize = disk.block_length()?; + stat.st_size = size * u64::from(disk.block_length()); + stat.st_blksize = disk.block_length(); stat.st_blocks = size; Ok(Some(0)) } @@ -251,12 +251,12 @@ impl SchemeBlock for DiskScheme { } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length()?; + let blk_len = disk.block_length(); disk.read(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length()?; + let blksize = disk.block_length(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize); @@ -285,12 +285,12 @@ impl SchemeBlock for DiskScheme { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length()?; + let blk_len = disk.block_length(); disk.write(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length()?; + let blksize = disk.block_length(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize as u64); @@ -331,7 +331,7 @@ impl SchemeBlock for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))? .size; - Ok(Some(u64::from(disk.block_length()?) * block_count)) + Ok(Some(u64::from(disk.block_length()) * block_count)) } } } diff --git a/storage/bcm2835-sdhcid/src/sd/mod.rs b/storage/bcm2835-sdhcid/src/sd/mod.rs index b371833773..deb3839f81 100644 --- a/storage/bcm2835-sdhcid/src/sd/mod.rs +++ b/storage/bcm2835-sdhcid/src/sd/mod.rs @@ -774,7 +774,7 @@ impl Disk for SdHostCtrl { } } - fn block_length(&mut self) -> Result { - Ok(512) + fn block_length(&mut self) -> u32 { + 512 } } diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 02f771e475..24e45b8a1b 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -53,7 +53,7 @@ fn block_read( } pub trait Disk { - fn block_length(&mut self) -> syscall::error::Result; + fn block_length(&mut self) -> u32; fn size(&mut self) -> u64; fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result>; @@ -68,8 +68,8 @@ pub struct DiskWrapper { impl DiskWrapper { pub fn pt(disk: &mut dyn Disk) -> Option { let bs = match disk.block_length() { - Ok(512) => LogicalBlockSize::Lb512, - Ok(4096) => LogicalBlockSize::Lb4096, + 512 => LogicalBlockSize::Lb512, + 4096 => LogicalBlockSize::Lb4096, _ => return None, }; struct Device<'a> { @@ -98,10 +98,7 @@ impl DiskWrapper { // TODO: Perhaps this impl should be used in the rest of the scheme. impl<'a> Read for Device<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result { - let blksize = self - .disk - .block_length() - .map_err(|err| io::Error::from_raw_os_error(err.errno))?; + let blksize = self.disk.block_length(); let size_in_blocks = self.disk.size() / u64::from(blksize); let disk = &mut self.disk; diff --git a/storage/ided/src/ide.rs b/storage/ided/src/ide.rs index b03213a464..94584a9dfb 100644 --- a/storage/ided/src/ide.rs +++ b/storage/ided/src/ide.rs @@ -461,7 +461,7 @@ impl Disk for AtaDisk { Ok(Some(count)) } - fn block_length(&mut self) -> Result { - Ok(512) + fn block_length(&mut self) -> u32 { + 512 } } diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs index ff0a63e58a..aca709013e 100644 --- a/storage/ided/src/scheme.rs +++ b/storage/ided/src/scheme.rs @@ -178,7 +178,7 @@ impl SchemeBlock for DiskScheme { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = disk.size(); - stat.st_blksize = disk.block_length()?; + stat.st_blksize = disk.block_length(); Ok(Some(0)) } Handle::Partition(disk_id, part_num) => { @@ -193,8 +193,8 @@ impl SchemeBlock for DiskScheme { }; stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_length()?); - stat.st_blksize = disk.block_length()?; + stat.st_size = size * u64::from(disk.block_length()); + stat.st_blksize = disk.block_length(); stat.st_blocks = size; Ok(Some(0)) } @@ -265,12 +265,12 @@ impl SchemeBlock for DiskScheme { } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length()?; + let blk_len = disk.block_length(); disk.read(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length()?; + let blksize = disk.block_length(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize); @@ -299,12 +299,12 @@ impl SchemeBlock for DiskScheme { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length()?; + let blk_len = disk.block_length(); disk.write(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length()?; + let blksize = disk.block_length(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize as u64); @@ -345,7 +345,7 @@ impl SchemeBlock for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))? .size; - Ok(Some(u64::from(disk.block_length()?) * block_count)) + Ok(Some(u64::from(disk.block_length()) * block_count)) } } } diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index ee27527d9e..1a730920c9 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -24,8 +24,8 @@ enum Handle { struct NamespaceAndNvme<'a>(&'a Nvme, NvmeNamespace); impl Disk for NamespaceAndNvme<'_> { - fn block_length(&mut self) -> syscall::error::Result { - Ok(self.1.block_size.try_into().unwrap()) + fn block_length(&mut self) -> u32 { + self.1.block_size.try_into().unwrap() } fn size(&mut self) -> u64 { diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index d4727b9278..17d7ae62b5 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -124,8 +124,8 @@ impl<'a> DiskScheme<'a> { } impl driver_block::Disk for DiskScheme<'_> { - fn block_length(&mut self) -> syscall::error::Result { - Ok(self.cfg.block_size()) + fn block_length(&mut self) -> u32 { + self.cfg.block_size() } fn size(&mut self) -> u64 { From d0a7aed2fde4c5ab12e9406f2998652213d93669 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Mar 2025 21:52:19 +0100 Subject: [PATCH 1120/1301] storage/virtio-blk: Introduce VirtioDisk type --- storage/virtio-blkd/src/scheme.rs | 155 +++++++++++++++--------------- 1 file changed, 78 insertions(+), 77 deletions(-) diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 17d7ae62b5..710a43ba4d 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -4,7 +4,7 @@ use std::fmt::Write; use std::sync::Arc; use common::dma::Dma; -use driver_block::DiskWrapper; +use driver_block::{Disk, DiskWrapper}; use partitionlib::PartitionTable; use redox_scheme::CallerCtx; @@ -87,6 +87,39 @@ impl BlkExtension for Queue<'_> { } } +struct VirtioDisk<'a> { + queue: Arc>, + cfg: BlockDeviceConfig, +} + +impl<'a> VirtioDisk<'a> { + pub fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { + Self { queue, cfg } + } +} + +impl driver_block::Disk for VirtioDisk<'_> { + fn block_length(&mut self) -> u32 { + self.cfg.block_size() + } + + fn size(&mut self) -> u64 { + self.cfg.capacity() * u64::from(self.cfg.block_size()) + } + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + Ok(Some(futures::executor::block_on( + self.queue.read(block, buffer), + ))) + } + + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + Ok(Some(futures::executor::block_on( + self.queue.write(block, buffer), + ))) + } +} + pub enum Handle { Partition { /// Partition Number @@ -101,45 +134,22 @@ pub enum Handle { } pub struct DiskScheme<'a> { - queue: Arc>, + disk: VirtioDisk<'a>, next_id: usize, - cfg: BlockDeviceConfig, handles: BTreeMap, part_table: Option, } impl<'a> DiskScheme<'a> { pub fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { - let mut this = Self { - queue, + let mut disk = VirtioDisk::new(queue, cfg); + + Self { + part_table: DiskWrapper::pt(&mut disk), + disk, next_id: 0, - cfg, handles: BTreeMap::new(), - part_table: None, - }; - - this.part_table = DiskWrapper::pt(&mut this); - this - } -} - -impl driver_block::Disk for DiskScheme<'_> { - fn block_length(&mut self) -> u32 { - self.cfg.block_size() - } - - fn size(&mut self) -> u64 { - self.cfg.capacity() * self.cfg.block_size() as u64 - } - - fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { - Ok(Some(futures::executor::block_on( - self.queue.read(block, buffer), - ))) - } - - fn write(&mut self, _block: u64, _buffer: &[u8]) -> syscall::Result> { - todo!() + } } } @@ -224,45 +234,40 @@ impl<'a> SchemeBlock for DiskScheme<'a> { offset: u64, _fcntl_flags: u32, ) -> syscall::Result> { - Ok(Some( - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List { ref mut entries } => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| entries.get(o..)) - .unwrap_or(&[]); - let count = core::cmp::min(src.len(), buf.len()); - buf[..count].copy_from_slice(&src[..count]); - count - } + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List { ref mut entries } => { + let src = usize::try_from(offset) + .ok() + .and_then(|o| entries.get(o..)) + .unwrap_or(&[]); + let count = core::cmp::min(src.len(), buf.len()); + buf[..count].copy_from_slice(&src[..count]); + Ok(Some(count)) + } - Handle::Partition { number } => { - let part_table = self.part_table.as_ref().unwrap(); - let part = part_table - .partitions - .get(number as usize) - .ok_or(Error::new(EBADF))?; + Handle::Partition { number } => { + let part_table = self.part_table.as_ref().unwrap(); + let part = part_table + .partitions + .get(number as usize) + .ok_or(Error::new(EBADF))?; - // Get the offset in sectors. - let rel_block = offset / BLK_SIZE; - // if rel_block >= part.size { - // return Err(Error::new(EOVERFLOW)); - // } + // Get the offset in sectors. + let rel_block = offset / BLK_SIZE; + // if rel_block >= part.size { + // return Err(Error::new(EOVERFLOW)); + // } - let abs_block = part.start_lba + rel_block; + let abs_block = part.start_lba + rel_block; - futures::executor::block_on(self.queue.read(abs_block, buf)) - } + self.disk.read(abs_block, buf) + } - Handle::Disk => { - let block_size = self.cfg.block_size(); - - futures::executor::block_on( - self.queue.read(offset / u64::from(block_size), buf), - ) - } - }, - )) + Handle::Disk => { + let block = offset / u64::from(self.disk.block_length()); + self.disk.read(block, buf) + } + } } fn write( @@ -272,18 +277,14 @@ impl<'a> SchemeBlock for DiskScheme<'a> { offset: u64, _fcntl_flags: u32, ) -> syscall::Result> { - Ok(Some( - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::Disk => { - let block_size = self.cfg.block_size(); - futures::executor::block_on( - self.queue.write(offset / u64::from(block_size), buf), - ) - } + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::Disk => { + let block = offset / u64::from(self.disk.block_length()); + self.disk.write(block, buf) + } - _ => todo!(), - }, - )) + _ => todo!(), + } } fn fsize(&mut self, id: usize) -> syscall::Result> { @@ -311,7 +312,7 @@ impl<'a> SchemeBlock for DiskScheme<'a> { len } - Handle::Disk => self.cfg.capacity() * u64::from(self.cfg.block_size()), + Handle::Disk => self.disk.size(), }, )) } From 9d27fad3d56e7ea6a3b2a2158c1e064332e3b9f5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Mar 2025 22:15:28 +0100 Subject: [PATCH 1121/1301] storage/driver-block: Make DiskWrapper generic over the disk type This allows it to contain non-'static disks. --- storage/ahcid/src/scheme.rs | 2 +- storage/bcm2835-sdhcid/src/scheme.rs | 2 +- storage/driver-block/src/lib.rs | 42 ++++++++++++++++++++-------- storage/ided/src/scheme.rs | 2 +- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index 4655529a6b..437f70bd2c 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -22,7 +22,7 @@ enum Handle { pub struct DiskScheme { scheme_name: String, hba_mem: &'static mut HbaMem, - disks: Box<[DiskWrapper]>, + disks: Box<[DiskWrapper>]>, handles: BTreeMap, next_id: usize, } diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs index 7b5b195c61..66f469a943 100644 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ b/storage/bcm2835-sdhcid/src/scheme.rs @@ -19,7 +19,7 @@ enum Handle { pub struct DiskScheme { scheme_name: String, - disks: Box<[DiskWrapper]>, + disks: Box<[DiskWrapper>]>, handles: BTreeMap, next_id: usize, } diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 24e45b8a1b..12d0926204 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -60,13 +60,31 @@ pub trait Disk { fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result>; } -pub struct DiskWrapper { - pub disk: Box, +impl Disk for Box { + fn block_length(&mut self) -> u32 { + (**self).block_length() + } + + fn size(&mut self) -> u64 { + (**self).size() + } + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + (**self).read(block, buffer) + } + + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + (**self).write(block, buffer) + } +} + +pub struct DiskWrapper { + pub disk: T, pub pt: Option, } -impl DiskWrapper { - pub fn pt(disk: &mut dyn Disk) -> Option { +impl DiskWrapper { + pub fn pt(disk: &mut T) -> Option { let bs = match disk.block_length() { 512 => LogicalBlockSize::Lb512, 4096 => LogicalBlockSize::Lb4096, @@ -133,23 +151,23 @@ impl DiskWrapper { .flatten() } - pub fn new(mut disk: Box) -> Self { + pub fn new(mut disk: T) -> Self { Self { - pt: Self::pt(&mut *disk), + pt: Self::pt(&mut disk), disk, } } } -impl std::ops::Deref for DiskWrapper { - type Target = dyn Disk; +impl std::ops::Deref for DiskWrapper { + type Target = T; fn deref(&self) -> &Self::Target { - &*self.disk + &self.disk } } -impl std::ops::DerefMut for DiskWrapper { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut *self.disk +impl std::ops::DerefMut for DiskWrapper { + fn deref_mut(&mut self) -> &mut T { + &mut self.disk } } diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs index aca709013e..fb0fa26169 100644 --- a/storage/ided/src/scheme.rs +++ b/storage/ided/src/scheme.rs @@ -22,7 +22,7 @@ enum Handle { pub struct DiskScheme { scheme_name: String, chans: Box<[Arc>]>, - disks: Box<[DiskWrapper]>, + disks: Box<[DiskWrapper>]>, handles: BTreeMap, next_id: usize, } From 371e8c0326bdfb918726bb22791f7fa640bcb4a0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Mar 2025 22:15:56 +0100 Subject: [PATCH 1122/1301] storage/virtio-blkd: Use DiskWrapper --- Cargo.lock | 1 - storage/virtio-blkd/Cargo.toml | 1 - storage/virtio-blkd/src/scheme.rs | 17 ++++++----------- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0bc2322768..537432f9cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1672,7 +1672,6 @@ dependencies = [ "futures", "libredox", "log", - "partitionlib", "pcid", "redox-daemon", "redox-scheme 0.3.0", diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index de7aba04a1..2b2a663565 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -15,7 +15,6 @@ spin = "*" redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } -partitionlib = { path = "../partitionlib" } common = { path = "../../common" } driver-block = { path = "../driver-block" } diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 710a43ba4d..e498798556 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -5,7 +5,6 @@ use std::sync::Arc; use common::dma::Dma; use driver_block::{Disk, DiskWrapper}; -use partitionlib::PartitionTable; use redox_scheme::CallerCtx; use redox_scheme::OpenResult; @@ -134,19 +133,15 @@ pub enum Handle { } pub struct DiskScheme<'a> { - disk: VirtioDisk<'a>, + disk: DiskWrapper>, next_id: usize, handles: BTreeMap, - part_table: Option, } impl<'a> DiskScheme<'a> { pub fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { - let mut disk = VirtioDisk::new(queue, cfg); - Self { - part_table: DiskWrapper::pt(&mut disk), - disk, + disk: DiskWrapper::new(VirtioDisk::new(queue, cfg)), next_id: 0, handles: BTreeMap::new(), } @@ -170,7 +165,7 @@ impl<'a> SchemeBlock for DiskScheme<'a> { // to the namespace id). write!(list, "{}\n", 0).unwrap(); - if let Some(part_table) = &self.part_table { + if let Some(part_table) = &self.disk.pt { for part_num in 0..part_table.partitions.len() { write!(list, "{}p{}\n", 0, part_num).unwrap(); } @@ -201,7 +196,7 @@ impl<'a> SchemeBlock for DiskScheme<'a> { let part_num_str = &path_str[p_pos + 1..]; let part_num = part_num_str.parse::().unwrap(); - let part_table = self.part_table.as_ref().unwrap(); + let part_table = self.disk.pt.as_ref().unwrap(); let _part = part_table.partitions.get(part_num as usize).unwrap(); let id = self.next_id; @@ -246,7 +241,7 @@ impl<'a> SchemeBlock for DiskScheme<'a> { } Handle::Partition { number } => { - let part_table = self.part_table.as_ref().unwrap(); + let part_table = self.disk.pt.as_ref().unwrap(); let part = part_table .partitions .get(number as usize) @@ -298,7 +293,7 @@ impl<'a> SchemeBlock for DiskScheme<'a> { } Handle::Partition { number } => { - let part_table = self.part_table.as_ref().unwrap(); + let part_table = self.disk.pt.as_ref().unwrap(); let part = part_table .partitions .get(number as usize) From b1dcda4cf770110b30b9af2591bdfef3a4239188 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Mar 2025 22:35:01 +0100 Subject: [PATCH 1123/1301] storage/nvmed: Use DiskWrapper --- Cargo.lock | 1 - storage/ahcid/src/ahci/disk_ata.rs | 10 ++-- storage/ahcid/src/ahci/disk_atapi.rs | 4 +- storage/ahcid/src/scheme.rs | 16 +++--- storage/bcm2835-sdhcid/src/scheme.rs | 16 +++--- storage/bcm2835-sdhcid/src/sd/mod.rs | 10 ++-- storage/driver-block/src/lib.rs | 14 ++--- storage/ided/src/ide.rs | 10 ++-- storage/ided/src/scheme.rs | 16 +++--- storage/nvmed/Cargo.toml | 1 - storage/nvmed/src/scheme.rs | 80 ++++++++-------------------- storage/virtio-blkd/src/scheme.rs | 8 +-- 12 files changed, 74 insertions(+), 112 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 537432f9cd..7f304690ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -854,7 +854,6 @@ dependencies = [ "futures", "libredox", "log", - "partitionlib", "pcid", "redox-daemon", "redox-scheme 0.3.0", diff --git a/storage/ahcid/src/ahci/disk_ata.rs b/storage/ahcid/src/ahci/disk_ata.rs index ee3b32a8b6..bb52a4571d 100644 --- a/storage/ahcid/src/ahci/disk_ata.rs +++ b/storage/ahcid/src/ahci/disk_ata.rs @@ -154,7 +154,11 @@ impl DiskATA { } impl Disk for DiskATA { - fn size(&mut self) -> u64 { + fn block_size(&self) -> u32 { + 512 + } + + fn size(&self) -> u64 { self.size } @@ -177,8 +181,4 @@ impl Disk for DiskATA { } } } - - fn block_length(&mut self) -> u32 { - 512 - } } diff --git a/storage/ahcid/src/ahci/disk_atapi.rs b/storage/ahcid/src/ahci/disk_atapi.rs index ce3ce0b962..b92112c36e 100644 --- a/storage/ahcid/src/ahci/disk_atapi.rs +++ b/storage/ahcid/src/ahci/disk_atapi.rs @@ -69,11 +69,11 @@ impl DiskATAPI { } impl Disk for DiskATAPI { - fn block_length(&mut self) -> u32 { + fn block_size(&self) -> u32 { self.blk_size } - fn size(&mut self) -> u64 { + fn size(&self) -> u64 { u64::from(self.blk_count) * u64::from(self.blk_size) } diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index 437f70bd2c..63d432e9a8 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -175,7 +175,7 @@ impl SchemeBlock for DiskScheme { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = disk.size(); - stat.st_blksize = disk.block_length(); + stat.st_blksize = disk.block_size(); Ok(Some(0)) } Handle::Partition(disk_id, part_num) => { @@ -190,8 +190,8 @@ impl SchemeBlock for DiskScheme { }; stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_length()); - stat.st_blksize = disk.block_length(); + stat.st_size = size * u64::from(disk.block_size()); + stat.st_blksize = disk.block_size(); stat.st_blocks = size; Ok(Some(0)) } @@ -263,12 +263,12 @@ impl SchemeBlock for DiskScheme { } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length(); + let blk_len = disk.block_size(); disk.read(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length(); + let blksize = disk.block_size(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize); @@ -304,12 +304,12 @@ impl SchemeBlock for DiskScheme { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length(); + let blk_len = disk.block_size(); disk.write(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length(); + let blksize = disk.block_size(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize); @@ -351,7 +351,7 @@ impl SchemeBlock for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))? .size; - u64::from(disk.block_length()) * block_count + u64::from(disk.block_size()) * block_count } }, )) diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs index 66f469a943..ebe0612346 100644 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ b/storage/bcm2835-sdhcid/src/scheme.rs @@ -164,7 +164,7 @@ impl SchemeBlock for DiskScheme { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = disk.size(); - stat.st_blksize = disk.block_length(); + stat.st_blksize = disk.block_size(); Ok(Some(0)) } Handle::Partition(disk_id, part_num) => { @@ -179,8 +179,8 @@ impl SchemeBlock for DiskScheme { }; stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_length()); - stat.st_blksize = disk.block_length(); + stat.st_size = size * u64::from(disk.block_size()); + stat.st_blksize = disk.block_size(); stat.st_blocks = size; Ok(Some(0)) } @@ -251,12 +251,12 @@ impl SchemeBlock for DiskScheme { } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length(); + let blk_len = disk.block_size(); disk.read(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length(); + let blksize = disk.block_size(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize); @@ -285,12 +285,12 @@ impl SchemeBlock for DiskScheme { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length(); + let blk_len = disk.block_size(); disk.write(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length(); + let blksize = disk.block_size(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize as u64); @@ -331,7 +331,7 @@ impl SchemeBlock for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))? .size; - Ok(Some(u64::from(disk.block_length()) * block_count)) + Ok(Some(u64::from(disk.block_size()) * block_count)) } } } diff --git a/storage/bcm2835-sdhcid/src/sd/mod.rs b/storage/bcm2835-sdhcid/src/sd/mod.rs index deb3839f81..f8e9ab351b 100644 --- a/storage/bcm2835-sdhcid/src/sd/mod.rs +++ b/storage/bcm2835-sdhcid/src/sd/mod.rs @@ -733,7 +733,11 @@ impl SdHostCtrl { } impl Disk for SdHostCtrl { - fn size(&mut self) -> u64 { + fn block_size(&self) -> u32 { + 512 + } + + fn size(&self) -> u64 { //assert 512MiB self.size } @@ -773,8 +777,4 @@ impl Disk for SdHostCtrl { Err(err) => Err(err), } } - - fn block_length(&mut self) -> u32 { - 512 - } } diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 12d0926204..1eb165d185 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -53,19 +53,19 @@ fn block_read( } pub trait Disk { - fn block_length(&mut self) -> u32; - fn size(&mut self) -> u64; + fn block_size(&self) -> u32; + fn size(&self) -> u64; fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result>; fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result>; } impl Disk for Box { - fn block_length(&mut self) -> u32 { - (**self).block_length() + fn block_size(&self) -> u32 { + (**self).block_size() } - fn size(&mut self) -> u64 { + fn size(&self) -> u64 { (**self).size() } @@ -85,7 +85,7 @@ pub struct DiskWrapper { impl DiskWrapper { pub fn pt(disk: &mut T) -> Option { - let bs = match disk.block_length() { + let bs = match disk.block_size() { 512 => LogicalBlockSize::Lb512, 4096 => LogicalBlockSize::Lb4096, _ => return None, @@ -116,7 +116,7 @@ impl DiskWrapper { // TODO: Perhaps this impl should be used in the rest of the scheme. impl<'a> Read for Device<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result { - let blksize = self.disk.block_length(); + let blksize = self.disk.block_size(); let size_in_blocks = self.disk.size() / u64::from(blksize); let disk = &mut self.disk; diff --git a/storage/ided/src/ide.rs b/storage/ided/src/ide.rs index 94584a9dfb..9748b46b93 100644 --- a/storage/ided/src/ide.rs +++ b/storage/ided/src/ide.rs @@ -169,7 +169,11 @@ pub struct AtaDisk { } impl Disk for AtaDisk { - fn size(&mut self) -> u64 { + fn block_size(&self) -> u32 { + 512 + } + + fn size(&self) -> u64 { self.size } @@ -460,8 +464,4 @@ impl Disk for AtaDisk { Ok(Some(count)) } - - fn block_length(&mut self) -> u32 { - 512 - } } diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs index fb0fa26169..167eb78a80 100644 --- a/storage/ided/src/scheme.rs +++ b/storage/ided/src/scheme.rs @@ -178,7 +178,7 @@ impl SchemeBlock for DiskScheme { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; stat.st_size = disk.size(); - stat.st_blksize = disk.block_length(); + stat.st_blksize = disk.block_size(); Ok(Some(0)) } Handle::Partition(disk_id, part_num) => { @@ -193,8 +193,8 @@ impl SchemeBlock for DiskScheme { }; stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_length()); - stat.st_blksize = disk.block_length(); + stat.st_size = size * u64::from(disk.block_size()); + stat.st_blksize = disk.block_size(); stat.st_blocks = size; Ok(Some(0)) } @@ -265,12 +265,12 @@ impl SchemeBlock for DiskScheme { } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length(); + let blk_len = disk.block_size(); disk.read(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length(); + let blksize = disk.block_size(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize); @@ -299,12 +299,12 @@ impl SchemeBlock for DiskScheme { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_length(); + let blk_len = disk.block_size(); disk.write(offset / u64::from(blk_len), buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_length(); + let blksize = disk.block_size(); // validate that we're actually reading within the bounds of the partition let rel_block = offset / u64::from(blksize as u64); @@ -345,7 +345,7 @@ impl SchemeBlock for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))? .size; - Ok(Some(u64::from(disk.block_length()) * block_count)) + Ok(Some(u64::from(disk.block_size()) * block_count)) } } } diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 04cf4bb27c..8a6d1c6663 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -13,7 +13,6 @@ redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" -partitionlib = { path = "../partitionlib" } smallvec = "1" common = { path = "../../common" } diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 1a730920c9..48018b33e5 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -4,8 +4,7 @@ use std::fmt::Write; use std::str; use std::sync::Arc; -use driver_block::Disk; -use partitionlib::PartitionTable; +use driver_block::{Disk, DiskWrapper}; use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; use syscall::schemev2::NewFdFlags; use syscall::{ @@ -21,14 +20,14 @@ enum Handle { Partition(u32, u32), // disk num, part num } -struct NamespaceAndNvme<'a>(&'a Nvme, NvmeNamespace); +struct NvmeDisk(Arc, NvmeNamespace); -impl Disk for NamespaceAndNvme<'_> { - fn block_length(&mut self) -> u32 { +impl Disk for NvmeDisk { + fn block_size(&self) -> u32 { self.1.block_size.try_into().unwrap() } - fn size(&mut self) -> u64 { + fn size(&self) -> u64 { self.1.blocks * self.1.block_size } @@ -41,33 +40,9 @@ impl Disk for NamespaceAndNvme<'_> { } } -pub struct DiskWrapper { - inner: NvmeNamespace, - pt: Option, -} - -impl AsRef for DiskWrapper { - fn as_ref(&self) -> &NvmeNamespace { - &self.inner - } -} - -impl DiskWrapper { - fn pt(disk: NvmeNamespace, nvme: &Nvme) -> Option { - driver_block::DiskWrapper::pt(&mut NamespaceAndNvme(nvme, disk)) - } - fn new(inner: NvmeNamespace, nvme: &Nvme) -> Self { - Self { - pt: Self::pt(inner, nvme), - inner, - } - } -} - pub struct DiskScheme { scheme_name: String, - nvme: Arc, - disks: BTreeMap, + disks: BTreeMap>, handles: BTreeMap, next_id: usize, } @@ -82,9 +57,8 @@ impl DiskScheme { scheme_name, disks: disks .into_iter() - .map(|(k, v)| (k, DiskWrapper::new(v, &nvme))) + .map(|(k, ns)| (k, DiskWrapper::new(NvmeDisk(nvme.clone(), ns)))) .collect(), - nvme, handles: BTreeMap::new(), next_id: 0, } @@ -209,13 +183,9 @@ impl SchemeBlock for DiskScheme { Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; - stat.st_blocks = disk.as_ref().blocks; - stat.st_blksize = disk - .as_ref() - .block_size - .try_into() - .expect("Unreasonable block size of over 2^32 bytes"); - stat.st_size = disk.as_ref().blocks * disk.as_ref().block_size; + stat.st_blocks = disk.1.blocks; + stat.st_blksize = disk.block_size(); + stat.st_size = disk.size(); Ok(Some(0)) } Handle::Partition(disk_num, part_num) => { @@ -228,13 +198,9 @@ impl SchemeBlock for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; - stat.st_size = part.size * disk.as_ref().block_size; + stat.st_size = part.size * u64::from(disk.block_size()); stat.st_blocks = part.size; - stat.st_blksize = disk - .as_ref() - .block_size - .try_into() - .expect("Unreasonable block size of over 2^32 bytes"); + stat.st_blksize = disk.block_size(); Ok(Some(0)) } } @@ -304,9 +270,8 @@ impl SchemeBlock for DiskScheme { } Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block_size = disk.as_ref().block_size; - self.nvme - .namespace_read(*disk.as_ref(), offset / block_size, buf) + let block_size = u64::from(disk.block_size()); + disk.read(offset / block_size, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; @@ -318,7 +283,7 @@ impl SchemeBlock for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))?; - let block_size = disk.as_ref().block_size; + let block_size = u64::from(disk.block_size()); let rel_block = offset / block_size; if rel_block >= part.size { return Err(Error::new(EOVERFLOW)); @@ -326,7 +291,7 @@ impl SchemeBlock for DiskScheme { let abs_block = part.start_lba + rel_block; - self.nvme.namespace_read(*disk.as_ref(), abs_block, buf) + disk.read(abs_block, buf) } } } @@ -342,9 +307,8 @@ impl SchemeBlock for DiskScheme { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block_size = disk.as_ref().block_size; - self.nvme - .namespace_write(*disk.as_ref(), offset / block_size, buf) + let block_size = u64::from(disk.block_size()); + disk.write(offset / block_size, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; @@ -356,7 +320,7 @@ impl SchemeBlock for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))?; - let block_size = disk.as_ref().block_size; + let block_size = u64::from(disk.block_size()); let rel_block = offset / block_size; if rel_block >= part.size { return Err(Error::new(EOVERFLOW)); @@ -364,7 +328,7 @@ impl SchemeBlock for DiskScheme { let abs_block = part.start_lba + rel_block; - self.nvme.namespace_write(*disk.as_ref(), abs_block, buf) + disk.write(abs_block, buf) } } } @@ -375,7 +339,7 @@ impl SchemeBlock for DiskScheme { Handle::List(ref handle) => handle.len() as u64, Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - disk.as_ref().blocks * disk.as_ref().block_size + disk.size() } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; @@ -387,7 +351,7 @@ impl SchemeBlock for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))?; - part.size * disk.as_ref().block_size + part.size * u64::from(disk.block_size()) } }, )) diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index e498798556..f47abc33c6 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -98,11 +98,11 @@ impl<'a> VirtioDisk<'a> { } impl driver_block::Disk for VirtioDisk<'_> { - fn block_length(&mut self) -> u32 { + fn block_size(&self) -> u32 { self.cfg.block_size() } - fn size(&mut self) -> u64 { + fn size(&self) -> u64 { self.cfg.capacity() * u64::from(self.cfg.block_size()) } @@ -259,7 +259,7 @@ impl<'a> SchemeBlock for DiskScheme<'a> { } Handle::Disk => { - let block = offset / u64::from(self.disk.block_length()); + let block = offset / u64::from(self.disk.block_size()); self.disk.read(block, buf) } } @@ -274,7 +274,7 @@ impl<'a> SchemeBlock for DiskScheme<'a> { ) -> syscall::Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::Disk => { - let block = offset / u64::from(self.disk.block_length()); + let block = offset / u64::from(self.disk.block_size()); self.disk.write(block, buf) } From 60a141b51c27219984f2d4e1712e8e544d9f2d52 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 7 Mar 2025 22:49:22 +0100 Subject: [PATCH 1124/1301] storage: Move most partition handling into DiskWrapper --- storage/ahcid/src/scheme.rs | 57 ++++----------------- storage/bcm2835-sdhcid/src/scheme.rs | 56 ++++---------------- storage/driver-block/src/lib.rs | 76 +++++++++++++++++++++++++--- storage/ided/src/scheme.rs | 56 ++++---------------- storage/nvmed/src/scheme.rs | 52 ++++--------------- storage/virtio-blkd/src/scheme.rs | 36 +++++-------- 6 files changed, 121 insertions(+), 212 deletions(-) diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index 63d432e9a8..74dc53067e 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -7,8 +7,8 @@ use driver_block::{Disk, DiskWrapper}; use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, - O_DIRECTORY, O_STAT, + Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, + O_STAT, }; use crate::ahci::hba::HbaMem; @@ -263,32 +263,13 @@ impl SchemeBlock for DiskScheme { } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_size(); - disk.read(offset / u64::from(blk_len), buf) + let block = offset / u64::from(disk.block_size()); + disk.read(None, block, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_size(); - - // validate that we're actually reading within the bounds of the partition - let rel_block = offset / u64::from(blksize); - - let abs_block = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - - let abs_block = partition.start_lba + rel_block; - // TODO: This shouldn't return EOVERFLOW? - if rel_block >= partition.size { - return Err(Error::new(EOVERFLOW)); - } - abs_block - }; - - disk.read(abs_block, buf) + let block = offset / u64::from(disk.block_size()); + disk.read(Some(part_num as usize), block, buf) } } } @@ -304,31 +285,13 @@ impl SchemeBlock for DiskScheme { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_size(); - disk.write(offset / u64::from(blk_len), buf) + let block = offset / u64::from(disk.block_size()); + disk.write(None, block, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_size(); - - // validate that we're actually reading within the bounds of the partition - let rel_block = offset / u64::from(blksize); - - let abs_block = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - - let abs_block = partition.start_lba + rel_block; - if rel_block >= partition.size { - return Err(Error::new(EOVERFLOW)); - } - abs_block - }; - - disk.write(abs_block, buf) + let block = offset / u64::from(disk.block_size()); + disk.write(Some(part_num as usize), block, buf) } } } diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs index ebe0612346..dfd7264786 100644 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ b/storage/bcm2835-sdhcid/src/scheme.rs @@ -5,8 +5,8 @@ use std::str; use driver_block::{Disk, DiskWrapper}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, - O_DIRECTORY, O_STAT, + Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, + O_STAT, }; use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; @@ -251,31 +251,13 @@ impl SchemeBlock for DiskScheme { } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_size(); - disk.read(offset / u64::from(blk_len), buf) + let block = offset / u64::from(disk.block_size()); + disk.read(None, block, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_size(); - - // validate that we're actually reading within the bounds of the partition - let rel_block = offset / u64::from(blksize); - - let abs_block = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - - let abs_block = partition.start_lba + rel_block; - if rel_block >= partition.size { - return Err(Error::new(EOVERFLOW)); - } - abs_block - }; - - disk.read(abs_block, buf) + let block = offset / u64::from(disk.block_size()); + disk.read(Some(part_num as usize), block, buf) } } } @@ -285,31 +267,13 @@ impl SchemeBlock for DiskScheme { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_size(); - disk.write(offset / u64::from(blk_len), buf) + let block = offset / u64::from(disk.block_size()); + disk.write(None, block, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_size(); - - // validate that we're actually reading within the bounds of the partition - let rel_block = offset / u64::from(blksize as u64); - - let abs_block = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - - let abs_block = partition.start_lba + rel_block; - if rel_block >= partition.size { - return Err(Error::new(EOVERFLOW)); - } - abs_block - }; - - disk.write(abs_block, buf) + let block = offset / u64::from(disk.block_size()); + disk.write(Some(part_num as usize), block, buf) } } } diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 1eb165d185..a2910c7b11 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -3,6 +3,7 @@ use std::io::Error; use std::io::{self, Read, Seek, SeekFrom}; use partitionlib::{LogicalBlockSize, PartitionTable}; +use syscall::{EBADF, EOVERFLOW}; /// Split the read operation into a series of block reads. /// `read_fn` will be called with a block number to be read, and a buffer to be filled. @@ -157,17 +158,76 @@ impl DiskWrapper { disk, } } -} -impl std::ops::Deref for DiskWrapper { - type Target = T; - - fn deref(&self) -> &Self::Target { + pub fn disk(&self) -> &T { &self.disk } -} -impl std::ops::DerefMut for DiskWrapper { - fn deref_mut(&mut self) -> &mut T { + + pub fn disk_mut(&mut self) -> &mut T { &mut self.disk } + + pub fn block_size(&self) -> u32 { + self.disk.block_size() + } + + pub fn size(&self) -> u64 { + self.disk.size() + } + + pub fn read( + &mut self, + part_num: Option, + block: u64, + buf: &mut [u8], + ) -> syscall::Result> { + if let Some(part_num) = part_num { + let part = self + .pt + .as_ref() + .ok_or(syscall::Error::new(EBADF))? + .partitions + .get(part_num) + .ok_or(syscall::Error::new(EBADF))?; + + let block_size = u64::from(self.block_size()); + if block >= part.size / block_size { + return Err(syscall::Error::new(EOVERFLOW)); + } + + let abs_block = part.start_lba + block; + + self.disk.read(abs_block, buf) + } else { + self.disk.read(block, buf) + } + } + + pub fn write( + &mut self, + part_num: Option, + block: u64, + buf: &[u8], + ) -> syscall::Result> { + if let Some(part_num) = part_num { + let part = self + .pt + .as_ref() + .ok_or(syscall::Error::new(EBADF))? + .partitions + .get(part_num) + .ok_or(syscall::Error::new(EBADF))?; + + let block_size = u64::from(self.block_size()); + if block >= part.size / block_size { + return Err(syscall::Error::new(EOVERFLOW)); + } + + let abs_block = part.start_lba + block; + + self.disk.write(abs_block, buf) + } else { + self.disk.write(block, buf) + } + } } diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs index 167eb78a80..f41a227579 100644 --- a/storage/ided/src/scheme.rs +++ b/storage/ided/src/scheme.rs @@ -6,8 +6,8 @@ use std::sync::{Arc, Mutex}; use driver_block::{Disk, DiskWrapper}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, - O_DIRECTORY, O_STAT, + Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, + O_STAT, }; use crate::ide::Channel; @@ -265,31 +265,13 @@ impl SchemeBlock for DiskScheme { } Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_size(); - disk.read(offset / u64::from(blk_len), buf) + let block = offset / u64::from(disk.block_size()); + disk.read(None, block, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_size(); - - // validate that we're actually reading within the bounds of the partition - let rel_block = offset / u64::from(blksize); - - let abs_block = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - - let abs_block = partition.start_lba + rel_block; - if rel_block >= partition.size { - return Err(Error::new(EOVERFLOW)); - } - abs_block - }; - - disk.read(abs_block, buf) + let block = offset / u64::from(disk.block_size()); + disk.read(Some(part_num as usize), block, buf) } } } @@ -299,31 +281,13 @@ impl SchemeBlock for DiskScheme { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let blk_len = disk.block_size(); - disk.write(offset / u64::from(blk_len), buf) + let block = offset / u64::from(disk.block_size()); + disk.write(None, block, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let blksize = disk.block_size(); - - // validate that we're actually reading within the bounds of the partition - let rel_block = offset / u64::from(blksize as u64); - - let abs_block = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - - let abs_block = partition.start_lba + rel_block; - if rel_block >= partition.size { - return Err(Error::new(EOVERFLOW)); - } - abs_block - }; - - disk.write(abs_block, buf) + let block = offset / u64::from(disk.block_size()); + disk.write(Some(part_num as usize), block, buf) } } } diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs index 48018b33e5..bd864441dd 100644 --- a/storage/nvmed/src/scheme.rs +++ b/storage/nvmed/src/scheme.rs @@ -8,8 +8,8 @@ use driver_block::{Disk, DiskWrapper}; use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, EOVERFLOW, MODE_DIR, MODE_FILE, - O_DIRECTORY, O_STAT, + Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, + O_STAT, }; use crate::nvme::{Nvme, NvmeNamespace}; @@ -183,7 +183,7 @@ impl SchemeBlock for DiskScheme { Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; stat.st_mode = MODE_FILE; - stat.st_blocks = disk.1.blocks; + stat.st_blocks = disk.disk().1.blocks; stat.st_blksize = disk.block_size(); stat.st_size = disk.size(); Ok(Some(0)) @@ -270,28 +270,13 @@ impl SchemeBlock for DiskScheme { } Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block_size = u64::from(disk.block_size()); - disk.read(offset / block_size, buf) + let block = offset / u64::from(disk.block_size()); + disk.read(None, block, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - - let block_size = u64::from(disk.block_size()); - let rel_block = offset / block_size; - if rel_block >= part.size { - return Err(Error::new(EOVERFLOW)); - } - - let abs_block = part.start_lba + rel_block; - - disk.read(abs_block, buf) + let block = offset / u64::from(disk.block_size()); + disk.read(Some(part_num as usize), block, buf) } } } @@ -307,28 +292,13 @@ impl SchemeBlock for DiskScheme { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block_size = u64::from(disk.block_size()); - disk.write(offset / block_size, buf) + let block = offset / u64::from(disk.block_size()); + disk.write(None, block, buf) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - - let block_size = u64::from(disk.block_size()); - let rel_block = offset / block_size; - if rel_block >= part.size { - return Err(Error::new(EOVERFLOW)); - } - - let abs_block = part.start_lba + rel_block; - - disk.write(abs_block, buf) + let block = offset / u64::from(disk.block_size()); + disk.write(Some(part_num as usize), block, buf) } } } diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index f47abc33c6..974573da51 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -4,7 +4,7 @@ use std::fmt::Write; use std::sync::Arc; use common::dma::Dma; -use driver_block::{Disk, DiskWrapper}; +use driver_block::DiskWrapper; use redox_scheme::CallerCtx; use redox_scheme::OpenResult; @@ -239,28 +239,13 @@ impl<'a> SchemeBlock for DiskScheme<'a> { buf[..count].copy_from_slice(&src[..count]); Ok(Some(count)) } - - Handle::Partition { number } => { - let part_table = self.disk.pt.as_ref().unwrap(); - let part = part_table - .partitions - .get(number as usize) - .ok_or(Error::new(EBADF))?; - - // Get the offset in sectors. - let rel_block = offset / BLK_SIZE; - // if rel_block >= part.size { - // return Err(Error::new(EOVERFLOW)); - // } - - let abs_block = part.start_lba + rel_block; - - self.disk.read(abs_block, buf) - } - Handle::Disk => { let block = offset / u64::from(self.disk.block_size()); - self.disk.read(block, buf) + self.disk.read(None, block, buf) + } + Handle::Partition { number } => { + let block = offset / u64::from(self.disk.block_size()); + self.disk.read(Some(number as usize), block, buf) } } } @@ -273,12 +258,15 @@ impl<'a> SchemeBlock for DiskScheme<'a> { _fcntl_flags: u32, ) -> syscall::Result> { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List { .. } => Err(Error::new(EBADF)), Handle::Disk => { let block = offset / u64::from(self.disk.block_size()); - self.disk.write(block, buf) + self.disk.write(None, block, buf) + } + Handle::Partition { number } => { + let block = offset / u64::from(self.disk.block_size()); + self.disk.write(Some(number as usize), block, buf) } - - _ => todo!(), } } From c68a50faf22fed7a762440a921c7a68498e13fb8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 8 Mar 2025 12:38:14 +0100 Subject: [PATCH 1125/1301] storage: Move irq methods out of the scheme structs --- net/driver-network/src/lib.rs | 4 +-- storage/ahcid/src/main.rs | 17 ++++++++-- storage/ahcid/src/scheme.rs | 30 +----------------- storage/ided/src/main.rs | 60 ++++++++++++++++++----------------- storage/ided/src/scheme.rs | 14 +------- 5 files changed, 50 insertions(+), 75 deletions(-) diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index 0f5a8663a9..d811464b70 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -72,13 +72,13 @@ impl NetworkScheme { &mut self.adapter } - /// Process pending and new packets. + /// Process pending and new requests. /// /// This needs to be called each time there is a new event on the scheme /// file and each time a new network packet has been received by the /// driver. // FIXME maybe split into one method for events on the scheme fd and one - // to call when an irq is received to indicate that blocked packets can + // to call when an irq is received to indicate that blocked requests can // be processed. pub fn tick(&mut self) -> io::Result<()> { // Handle any blocked requests diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 1c5239c1b5..51dd830585 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -7,6 +7,7 @@ use std::io::{Read, Write}; use std::os::fd::AsRawFd; use std::usize; +use common::io::Io; use event::{EventFlags, RawEventQueue}; use pcid_interface::PciFunctionHandle; use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; @@ -68,7 +69,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("ahcid: failed to notify parent"); let (hba_mem, disks) = ahci::disks(address as usize, &name); - let mut scheme = DiskScheme::new(scheme_name, hba_mem, disks); + let mut scheme = DiskScheme::new(scheme_name, disks); let mut mounted = true; let mut todo = Vec::new(); @@ -120,7 +121,19 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("ahcid: failed to read irq file") >= irq.len() { - if scheme.irq() { + let is = hba_mem.is.read(); + if is > 0 { + let pi = hba_mem.pi.read(); + let pi_is = pi & is; + for i in 0..hba_mem.ports.len() { + if pi_is & 1 << i > 0 { + let port = &mut hba_mem.ports[i]; + let is = port.is.read(); + port.is.write(is); + } + } + hba_mem.is.write(is); + irq_file .write(&irq) .expect("ahcid: failed to write irq file"); diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs index 74dc53067e..bf4f20ddde 100644 --- a/storage/ahcid/src/scheme.rs +++ b/storage/ahcid/src/scheme.rs @@ -2,7 +2,6 @@ use std::collections::BTreeMap; use std::fmt::Write; use std::str; -use common::io::Io as _; use driver_block::{Disk, DiskWrapper}; use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; use syscall::schemev2::NewFdFlags; @@ -11,8 +10,6 @@ use syscall::{ O_STAT, }; -use crate::ahci::hba::HbaMem; - enum Handle { List(Vec), // Dir contents buffer Disk(usize), // Disk index @@ -21,21 +18,15 @@ enum Handle { pub struct DiskScheme { scheme_name: String, - hba_mem: &'static mut HbaMem, disks: Box<[DiskWrapper>]>, handles: BTreeMap, next_id: usize, } impl DiskScheme { - pub fn new( - scheme_name: String, - hba_mem: &'static mut HbaMem, - disks: Vec>, - ) -> DiskScheme { + pub fn new(scheme_name: String, disks: Vec>) -> DiskScheme { DiskScheme { scheme_name, - hba_mem, disks: disks .into_iter() .map(DiskWrapper::new) @@ -46,25 +37,6 @@ impl DiskScheme { } } - pub fn irq(&mut self) -> bool { - let is = self.hba_mem.is.read(); - if is > 0 { - let pi = self.hba_mem.pi.read(); - let pi_is = pi & is; - for i in 0..self.hba_mem.ports.len() { - if pi_is & 1 << i > 0 { - let port = &mut self.hba_mem.ports[i]; - let is = port.is.read(); - port.is.write(is); - } - } - self.hba_mem.is.write(is); - true - } else { - false - } - } - // Checks if any conflicting handles already exist fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { for (_, handle) in self.handles.iter() { diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 2bf9c7c3e9..3f1bc352dd 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -229,7 +229,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .subscribe(secondary_irq_fd, 0, EventFlags::READ) .expect("ided: failed to event irq scheme"); - let mut scheme = DiskScheme::new(scheme_name, chans, disks); + let mut scheme = DiskScheme::new(scheme_name, disks); let mut todo = Vec::new(); 'outer: loop { @@ -274,21 +274,22 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("ided: failed to read irq file") >= irq.len() { - if scheme.irq(0) { - primary_irq_file - .write(&irq) - .expect("ided: failed to write irq file"); + let _chan = chans[0].lock().unwrap(); + //TODO: check chan for irq - // Handle todos in order to finish previous packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("ided: failed to write disk scheme"); - } else { - i += 1; - } + primary_irq_file + .write(&irq) + .expect("ided: failed to write irq file"); + + // Handle todos in order to finish previous packets if possible + let mut i = 0; + while i < todo.len() { + if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { + socket_fd + .write_response(resp, SignalBehavior::Restart) + .expect("ided: failed to write disk scheme"); + } else { + i += 1; } } } @@ -299,21 +300,22 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("ided: failed to read irq file") >= irq.len() { - if scheme.irq(1) { - secondary_irq_file - .write(&irq) - .expect("ided: failed to write irq file"); + let _chan = chans[1].lock().unwrap(); + //TODO: check chan for irq - // Handle todos in order to finish previous packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("ided: failed to write disk scheme"); - } else { - i += 1; - } + secondary_irq_file + .write(&irq) + .expect("ided: failed to write irq file"); + + // Handle todos in order to finish previous packets if possible + let mut i = 0; + while i < todo.len() { + if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { + socket_fd + .write_response(resp, SignalBehavior::Restart) + .expect("ided: failed to write disk scheme"); + } else { + i += 1; } } } diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs index f41a227579..48d8bd6df6 100644 --- a/storage/ided/src/scheme.rs +++ b/storage/ided/src/scheme.rs @@ -21,21 +21,15 @@ enum Handle { pub struct DiskScheme { scheme_name: String, - chans: Box<[Arc>]>, disks: Box<[DiskWrapper>]>, handles: BTreeMap, next_id: usize, } impl DiskScheme { - pub fn new( - scheme_name: String, - chans: Vec>>, - disks: Vec>, - ) -> DiskScheme { + pub fn new(scheme_name: String, disks: Vec>) -> DiskScheme { DiskScheme { scheme_name, - chans: chans.into_boxed_slice(), disks: disks .into_iter() .map(DiskWrapper::new) @@ -46,12 +40,6 @@ impl DiskScheme { } } - pub fn irq(&mut self, chan_i: usize) -> bool { - let _chan = self.chans[chan_i].lock().unwrap(); - //TODO: check chan for irq - true - } - // Checks if any conflicting handles already exist fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { for (_, handle) in self.handles.iter() { From 865ca866662fed6182f8c47d8f2bc17460b16579 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 8 Mar 2025 13:06:31 +0100 Subject: [PATCH 1126/1301] storage: Mostly unify disk scheme implementations lived and usbscsid still keep their old scheme implementations. --- Cargo.lock | 8 +- storage/ahcid/Cargo.toml | 1 - storage/ahcid/src/main.rs | 109 ++------ storage/ahcid/src/scheme.rs | 301 --------------------- storage/bcm2835-sdhcid/Cargo.toml | 1 - storage/bcm2835-sdhcid/src/main.rs | 104 ++----- storage/bcm2835-sdhcid/src/scheme.rs | 309 --------------------- storage/driver-block/Cargo.toml | 2 + storage/driver-block/src/lib.rs | 387 ++++++++++++++++++++++++++- storage/ided/Cargo.toml | 1 - storage/ided/src/main.rs | 110 ++------ storage/ided/src/scheme.rs | 311 --------------------- storage/nvmed/Cargo.toml | 3 +- storage/nvmed/src/main.rs | 83 +++--- storage/nvmed/src/scheme.rs | 336 ----------------------- storage/virtio-blkd/Cargo.toml | 2 +- storage/virtio-blkd/src/main.rs | 51 ++-- storage/virtio-blkd/src/scheme.rs | 217 +-------------- 18 files changed, 525 insertions(+), 1811 deletions(-) delete mode 100644 storage/ahcid/src/scheme.rs delete mode 100644 storage/bcm2835-sdhcid/src/scheme.rs delete mode 100644 storage/ided/src/scheme.rs delete mode 100644 storage/nvmed/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index 7f304690ff..9506ce08e1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,7 +52,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -180,7 +179,6 @@ dependencies = [ "fdt 0.2.0-alpha1", "libredox", "redox-daemon", - "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -392,7 +390,9 @@ checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" name = "driver-block" version = "0.1.0" dependencies = [ + "libredox", "partitionlib", + "redox-scheme 0.3.0", "redox_syscall", ] @@ -680,7 +680,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] @@ -856,7 +855,6 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme 0.3.0", "redox_event", "redox_syscall", "smallvec 1.13.2", @@ -1673,7 +1671,7 @@ dependencies = [ "log", "pcid", "redox-daemon", - "redox-scheme 0.3.0", + "redox_event", "redox_syscall", "spin", "static_assertions", diff --git a/storage/ahcid/Cargo.toml b/storage/ahcid/Cargo.toml index 5186da6460..7b1a06accf 100644 --- a/storage/ahcid/Cargo.toml +++ b/storage/ahcid/Cargo.toml @@ -14,5 +14,4 @@ common = { path = "../../common" } driver-block = { path = "../driver-block" } pcid = { path = "../../pcid" } libredox = "0.1.3" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 51dd830585..9ea8964dd1 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -8,18 +8,13 @@ use std::os::fd::AsRawFd; use std::usize; use common::io::Io; +use driver_block::DiskScheme; use event::{EventFlags, RawEventQueue}; use pcid_interface::PciFunctionHandle; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; -use syscall::error::{Error, ENODEV}; use log::{error, info}; -use syscall::{EAGAIN, EWOULDBLOCK}; - -use crate::scheme::DiskScheme; pub mod ahci; -pub mod scheme; fn main() { redox_daemon::Daemon::new(daemon).expect("ahcid: failed to daemonize"); @@ -49,18 +44,27 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { pcid_handle.map_bar(5) }.ptr.as_ptr() as usize; { + let (hba_mem, disks) = ahci::disks(address as usize, &name); + let scheme_name = format!("disk.{}", name); - let socket = Socket::nonblock(&scheme_name).expect("ahcid: failed to create disk scheme"); + let mut scheme = DiskScheme::new( + scheme_name, + disks + .into_iter() + .enumerate() + .map(|(i, disk)| (i as u32, disk)) + .collect(), + ); let mut irq_file = irq.irq_handle("ahcid"); let irq_fd = irq_file.as_raw_fd() as usize; - let mut event_queue = RawEventQueue::new().expect("ahcid: failed to create event queue"); + let event_queue = RawEventQueue::new().expect("ahcid: failed to create event queue"); libredox::call::setrens(0, 0).expect("ahcid: failed to enter null namespace"); event_queue - .subscribe(socket.inner().raw(), 1, EventFlags::READ) + .subscribe(scheme.event_handle().raw(), 1, EventFlags::READ) .expect("ahcid: failed to event scheme socket"); event_queue .subscribe(irq_fd, 1, EventFlags::READ) @@ -68,52 +72,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("ahcid: failed to notify parent"); - let (hba_mem, disks) = ahci::disks(address as usize, &name); - let mut scheme = DiskScheme::new(scheme_name, disks); - - let mut mounted = true; - let mut todo = Vec::new(); - while mounted { - let Some(event) = event_queue - .next() - .transpose() - .expect("ahcid: failed to read event file") - else { - break; - }; - if event.fd == socket.inner().raw() { - loop { - let sqe = match socket.next_request(SignalBehavior::Interrupt) { - Ok(None) => { - mounted = false; - break; - } - Ok(Some(s)) => { - if let RequestKind::Call(call) = s.kind() { - call - } else { - // TODO: Support e.g. cancellation - continue; - } - } - Err(err) => { - if err.errno == EWOULDBLOCK || err.errno == EAGAIN { - break; - } else { - panic!("ahcid: failed to read disk scheme: {}", err); - } - } - }; - - if let Some(response) = sqe.handle_scheme_block(&mut scheme) { - // TODO: handle full CQE? - socket - .write_response(response, SignalBehavior::Restart) - .expect("ahcid: failed to write disk scheme"); - } else { - todo.push(sqe); - } - } + for event in event_queue { + let event = event.unwrap(); + if event.fd == scheme.event_handle().raw() { + scheme.tick().unwrap(); } else if event.fd == irq_fd { let mut irq = [0; 8]; if irq_file @@ -138,47 +100,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .write(&irq) .expect("ahcid: failed to write irq file"); - // Handle todos in order to finish previous packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - let _sqe = todo.remove(i); - socket - .write_response(resp, SignalBehavior::Restart) - .expect("ahcid: failed to write disk scheme"); - } else { - i += 1; - } - } + scheme.tick().unwrap(); } } } else { error!("Unknown event {}", event.fd); } - - // Handle todos to start new packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(response) = todo[i].handle_scheme_block(&mut scheme) { - let _sqe = todo.remove(i); - socket - .write_response(response, SignalBehavior::Restart) - .expect("ahcid: failed to write disk scheme"); - } else { - i += 1; - } - } - - if !mounted { - for sqe in todo.drain(..) { - socket - .write_response( - Response::new(&sqe, Err(Error::new(ENODEV))), - SignalBehavior::Restart, - ) - .expect("ahcid: failed to write disk scheme"); - } - } } } diff --git a/storage/ahcid/src/scheme.rs b/storage/ahcid/src/scheme.rs deleted file mode 100644 index bf4f20ddde..0000000000 --- a/storage/ahcid/src/scheme.rs +++ /dev/null @@ -1,301 +0,0 @@ -use std::collections::BTreeMap; -use std::fmt::Write; -use std::str; - -use driver_block::{Disk, DiskWrapper}; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; -use syscall::schemev2::NewFdFlags; -use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, -}; - -enum Handle { - List(Vec), // Dir contents buffer - Disk(usize), // Disk index - Partition(usize, u32), // Disk index, partition index -} - -pub struct DiskScheme { - scheme_name: String, - disks: Box<[DiskWrapper>]>, - handles: BTreeMap, - next_id: usize, -} - -impl DiskScheme { - pub fn new(scheme_name: String, disks: Vec>) -> DiskScheme { - DiskScheme { - scheme_name, - disks: disks - .into_iter() - .map(DiskWrapper::new) - .collect::>() - .into_boxed_slice(), - handles: BTreeMap::new(), - next_id: 0, - } - } - - // Checks if any conflicting handles already exist - fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { - for (_, handle) in self.handles.iter() { - match handle { - Handle::Disk(i) => { - if disk_i == *i { - return Err(Error::new(ENOLCK)); - } - } - Handle::Partition(i, p) => { - if disk_i == *i { - match part_i_opt { - Some(part_i) => { - if part_i == *p { - return Err(Error::new(ENOLCK)); - } - } - None => { - return Err(Error::new(ENOLCK)); - } - } - } - } - _ => (), - } - } - Ok(()) - } -} - -impl SchemeBlock for DiskScheme { - fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - let path_str = path.trim_matches('/'); - - let handle = if path_str.is_empty() { - if flags & O_DIRECTORY != O_DIRECTORY && flags & O_STAT != O_STAT { - return Err(Error::new(EISDIR)); - } - let mut list = String::new(); - - for (disk_index, disk) in self.disks.iter().enumerate() { - write!(list, "{}\n", disk_index).unwrap(); - - if disk.pt.is_none() { - continue; - } - for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { - write!(list, "{}p{}\n", disk_index, part_index).unwrap(); - } - } - - Handle::List(list.into_bytes()) - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let disk_id_str = &path_str[..p_pos]; - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_id_str = &path_str[p_pos + 1..]; - let i = disk_id_str.parse::().or(Err(Error::new(ENOENT)))?; - let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; - - let disk = self.disks.get(i).ok_or(Error::new(ENOENT))?; - if disk.pt.is_none() - || disk - .pt - .as_ref() - .unwrap() - .partitions - .get(p as usize) - .is_none() - { - return Err(Error::new(ENOENT)); - } - - self.check_locks(i, Some(p))?; - - Handle::Partition(i, p) - } else { - let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if self.disks.get(i).is_none() { - return Err(Error::new(ENOENT)); - } - self.check_locks(i, None)?; - - Handle::Disk(i) - }; - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, handle); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } - - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { - match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data) => { - stat.st_mode = MODE_DIR; - stat.st_size = data.len() as u64; - Ok(Some(0)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_size = disk.size(); - stat.st_blksize = disk.block_size(); - Ok(Some(0)) - } - Handle::Partition(disk_id, part_num) => { - let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; - let size = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - partition.size - }; - - stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_size()); - stat.st_blksize = disk.block_size(); - stat.st_blocks = size; - Ok(Some(0)) - } - } - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - - let scheme_name = self.scheme_name.as_bytes(); - let mut j = 0; - while i < buf.len() && j < scheme_name.len() { - buf[i] = scheme_name[j]; - i += 1; - j += 1; - } - - if i < buf.len() { - buf[i] = b':'; - i += 1; - } - - match *handle { - Handle::List(_) => (), - Handle::Disk(number) => { - let number_str = format!("{}", number); - let number_bytes = number_str.as_bytes(); - j = 0; - while i < buf.len() && j < number_bytes.len() { - buf[i] = number_bytes[j]; - i += 1; - j += 1; - } - } - Handle::Partition(disk_num, part_num) => { - let path = format!("{}p{}", disk_num, part_num); - let path_bytes = path.as_bytes(); - j = 0; - while i < buf.len() && j < path_bytes.len() { - buf[i] = path_bytes[j]; - i += 1; - j += 1; - } - } - } - - Ok(Some(i)) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _fcntl_flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| handle.get(o..)) - .unwrap_or(&[]); - - let byte_count = core::cmp::min(src.len(), buf.len()); - buf[..byte_count].copy_from_slice(&src[..byte_count]); - Ok(Some(byte_count)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(Some(part_num as usize), block, buf) - } - } - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - offset: u64, - _fcntl_flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => Err(Error::new(EBADF)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(Some(part_num as usize), block, buf) - } - } - } - - fn fsize(&mut self, id: usize) -> Result> { - Ok(Some( - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle) => handle.len() as u64, - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - disk.size() - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block_count = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))? - .size; - u64::from(disk.block_size()) * block_count - } - }, - )) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) - } -} diff --git a/storage/bcm2835-sdhcid/Cargo.toml b/storage/bcm2835-sdhcid/Cargo.toml index ac42319149..ceabb4a0b6 100644 --- a/storage/bcm2835-sdhcid/Cargo.toml +++ b/storage/bcm2835-sdhcid/Cargo.toml @@ -13,5 +13,4 @@ driver-block = { path = "../driver-block" } redox-daemon = "0.1" libredox = "0.1.3" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index fded57eb4b..34668a55f9 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -1,27 +1,11 @@ #![feature(let_chains)] -use std::{ - fs::File, - io::{Read, Write}, - process, -}; +use std::process; -use driver_block::Disk; +use driver_block::{Disk, DiskScheme}; use event::{EventFlags, RawEventQueue}; -use fdt::{node::FdtNode, Fdt}; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; -use syscall::{ - data::{Event, Packet}, - error::{Error, ENODEV}, - flag::EVENT_READ, - io::Io, - scheme::SchemeBlockMut, - EAGAIN, EINTR, EWOULDBLOCK, -}; +use fdt::Fdt; -use crate::scheme::DiskScheme; - -mod scheme; mod sd; #[cfg(target_os = "redox")] @@ -114,82 +98,32 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { */ } - let scheme_name = "disk.mmc"; - let socket_fd = Socket::create(&scheme_name).expect("mmcd: failed to create disk scheme"); + let mut disks = Vec::new(); + disks.push(Box::new(sdhci) as Box); + let mut scheme = DiskScheme::new( + "disk.mmc".to_string(), + disks + .into_iter() + .enumerate() + .map(|(i, disk)| (i as u32, disk)) + .collect(), + ); - let mut event_queue = RawEventQueue::new().expect("mmcd: failed to open event file"); + let event_queue = RawEventQueue::new().expect("mmcd: failed to open event file"); event_queue - .subscribe(socket_fd.inner().raw(), 0, EventFlags::READ) + .subscribe(scheme.event_handle().raw(), 0, EventFlags::READ) .expect("mmcd: failed to event disk scheme"); libredox::call::setrens(0, 0).expect("mmcd: failed to enter null namespace"); daemon.ready().expect("mmcd: failed to notify parent"); - let mut todo = Vec::new(); - let mut disks = Vec::new(); - - disks.push(Box::new(sdhci) as Box); - let mut scheme = DiskScheme::new(scheme_name.to_string(), disks); - - 'outer: loop { - let Some(event) = event_queue - .next() - .transpose() - .expect("mmcd: failed to read event file") - else { - break; - }; - if event.fd == socket_fd.inner().raw() { - loop { - let req = match socket_fd.next_request(SignalBehavior::Interrupt) { - Ok(None) => break 'outer, - Ok(Some(r)) => { - if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - } - } - Err(err) => { - if matches!(err.errno, EAGAIN | EWOULDBLOCK | EINTR) { - break; - } else { - panic!("mmcd: failed to read disk scheme: {}", err); - } - } - }; - if let Some(resp) = req.handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("mmcd: failed to write disk scheme"); - } else { - todo.push(req); - } - } + for event in event_queue { + let event = event.unwrap(); + if event.fd == scheme.event_handle().raw() { + scheme.tick().unwrap(); } else { println!("Unknown event {}", event.fd); } - - // Handle todos to start new packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("mmcd: failed to write disk scheme"); - } else { - i += 1; - } - } - - for req in todo.drain(..) { - socket_fd - .write_response( - Response::new(&req, Err(Error::new(ENODEV))), - SignalBehavior::Restart, - ) - .expect("mmcd: failed to write disk scheme"); - } } process::exit(0); } diff --git a/storage/bcm2835-sdhcid/src/scheme.rs b/storage/bcm2835-sdhcid/src/scheme.rs deleted file mode 100644 index dfd7264786..0000000000 --- a/storage/bcm2835-sdhcid/src/scheme.rs +++ /dev/null @@ -1,309 +0,0 @@ -use std::collections::BTreeMap; -use std::fmt::Write; -use std::str; - -use driver_block::{Disk, DiskWrapper}; -use syscall::schemev2::NewFdFlags; -use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, -}; - -use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; - -enum Handle { - List(Vec), // Dir contents buffer - Disk(usize), // Disk index - Partition(usize, u32), // Disk index, partition index -} - -pub struct DiskScheme { - scheme_name: String, - disks: Box<[DiskWrapper>]>, - handles: BTreeMap, - next_id: usize, -} - -impl DiskScheme { - pub fn new(scheme_name: String, disks: Vec>) -> DiskScheme { - DiskScheme { - scheme_name, - disks: disks - .into_iter() - .map(DiskWrapper::new) - .collect::>() - .into_boxed_slice(), - handles: BTreeMap::new(), - next_id: 0, - } - } - - // Checks if any conflicting handles already exist - fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { - for (_, handle) in self.handles.iter() { - match handle { - Handle::Disk(i) => { - if disk_i == *i { - return Err(Error::new(ENOLCK)); - } - } - Handle::Partition(i, p) => { - if disk_i == *i { - match part_i_opt { - Some(part_i) => { - if part_i == *p { - return Err(Error::new(ENOLCK)); - } - } - None => { - return Err(Error::new(ENOLCK)); - } - } - } - } - _ => (), - } - } - Ok(()) - } -} - -impl SchemeBlock for DiskScheme { - fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { - if ctx.uid == 0 { - let path_str = path.trim_matches('/'); - if path_str.is_empty() { - if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { - let mut list = String::new(); - - for (disk_index, disk) in self.disks.iter().enumerate() { - write!(list, "{}\n", disk_index).unwrap(); - - if disk.pt.is_none() { - continue; - } - for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { - write!(list, "{}p{}\n", disk_index, part_index).unwrap(); - } - } - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::List(list.into_bytes())); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(EISDIR)) - } - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let disk_id_str = &path_str[..p_pos]; - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_id_str = &path_str[p_pos + 1..]; - let i = disk_id_str.parse::().or(Err(Error::new(ENOENT)))?; - let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; - - if let Some(disk) = self.disks.get(i) { - if disk.pt.is_none() - || disk - .pt - .as_ref() - .unwrap() - .partitions - .get(p as usize) - .is_none() - { - return Err(Error::new(ENOENT)); - } - - self.check_locks(i, Some(p))?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Partition(i, p)); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(ENOENT)) - } - } else { - let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if self.disks.get(i).is_some() { - self.check_locks(i, None)?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Disk(i)); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(ENOENT)) - } - } - } else { - Err(Error::new(EACCES)) - } - } - - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { - match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data) => { - stat.st_mode = MODE_DIR; - stat.st_size = data.len() as u64; - Ok(Some(0)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_size = disk.size(); - stat.st_blksize = disk.block_size(); - Ok(Some(0)) - } - Handle::Partition(disk_id, part_num) => { - let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; - let size = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - partition.size - }; - - stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_size()); - stat.st_blksize = disk.block_size(); - stat.st_blocks = size; - Ok(Some(0)) - } - } - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - - let scheme_name = self.scheme_name.as_bytes(); - let mut j = 0; - while i < buf.len() && j < scheme_name.len() { - buf[i] = scheme_name[j]; - i += 1; - j += 1; - } - - if i < buf.len() { - buf[i] = b':'; - i += 1; - } - - match *handle { - Handle::List(_) => (), - Handle::Disk(number) => { - let number_str = format!("{}", number); - let number_bytes = number_str.as_bytes(); - j = 0; - while i < buf.len() && j < number_bytes.len() { - buf[i] = number_bytes[j]; - i += 1; - j += 1; - } - } - Handle::Partition(disk_num, part_num) => { - let path = format!("{}p{}", disk_num, part_num); - let path_bytes = path.as_bytes(); - j = 0; - while i < buf.len() && j < path_bytes.len() { - buf[i] = path_bytes[j]; - i += 1; - j += 1; - } - } - } - - Ok(Some(i)) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| handle.get(o..)) - .unwrap_or(&[]); - let bytes = src.len().min(buf.len()); - buf[..bytes].copy_from_slice(&src[..bytes]); - Ok(Some(bytes)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(Some(part_num as usize), block, buf) - } - } - } - - fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => Err(Error::new(EBADF)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(Some(part_num as usize), block, buf) - } - } - } - - fn fsize(&mut self, id: usize) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle) => Ok(Some(handle.len() as u64)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - Ok(Some(disk.size())) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block_count = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))? - .size; - Ok(Some(u64::from(disk.block_size()) * block_count)) - } - } - } - - fn close(&mut self, id: usize) -> Result> { - self.handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) - } -} diff --git a/storage/driver-block/Cargo.toml b/storage/driver-block/Cargo.toml index 278520adca..1645bf0314 100644 --- a/storage/driver-block/Cargo.toml +++ b/storage/driver-block/Cargo.toml @@ -6,4 +6,6 @@ edition = "2021" [dependencies] partitionlib = { path = "../partitionlib" } +libredox = "0.1.3" redox_syscall = "0.5" +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index a2910c7b11..a60a208847 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -1,9 +1,21 @@ use std::cmp; -use std::io::Error; use std::io::{self, Read, Seek, SeekFrom}; +use std::collections::BTreeMap; +use std::convert::TryFrom; +use std::fmt::Write; +use std::str; + +use libredox::Fd; use partitionlib::{LogicalBlockSize, PartitionTable}; -use syscall::{EBADF, EOVERFLOW}; +use redox_scheme::{ + CallRequest, CallerCtx, OpenResult, RequestKind, Response, SchemeBlock, SignalBehavior, Socket, +}; +use syscall::schemev2::NewFdFlags; +use syscall::{ + Error, Result, Stat, EACCES, EAGAIN, EBADF, EISDIR, ENOENT, ENOLCK, EOPNOTSUPP, EOVERFLOW, + MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, +}; /// Split the read operation into a series of block reads. /// `read_fn` will be called with a block number to be read, and a buffer to be filled. @@ -13,8 +25,8 @@ fn block_read( offset: u64, blksize: u32, buf: &mut [u8], - mut read_fn: impl FnMut(u64, &mut [u8]) -> Result<(), Error>, -) -> Result { + mut read_fn: impl FnMut(u64, &mut [u8]) -> io::Result<()>, +) -> io::Result { // TODO: Yield sometimes, perhaps after a few blocks or something. if buf.len() == 0 { @@ -231,3 +243,370 @@ impl DiskWrapper { } } } + +enum Handle { + List(Vec), // entries + Disk(u32), // disk num + Partition(u32, u32), // disk num, part num +} + +pub struct DiskScheme { + scheme_name: String, + socket: Socket, + disks: BTreeMap>, + handles: BTreeMap, + next_id: usize, + blocked: Vec, +} + +impl DiskScheme { + pub fn new(scheme_name: String, disks: BTreeMap) -> Self { + assert!(scheme_name.starts_with("disk")); + let socket = Socket::nonblock(&scheme_name).expect("failed to create disk scheme"); + + Self { + scheme_name, + socket, + disks: disks + .into_iter() + .map(|(k, disk)| (k, DiskWrapper::new(disk))) + .collect(), + next_id: 0, + handles: BTreeMap::new(), + blocked: vec![], + } + } + + pub fn event_handle(&self) -> &Fd { + self.socket.inner() + } + + /// Process pending and new requests. + /// + /// This needs to be called each time there is a new event on the scheme + /// file and each time a read or write operation has completed. + // FIXME maybe split into one method for events on the scheme fd and one + // to call when an irq is received to indicate that blocked packets can + // be processed. + pub fn tick(&mut self) -> io::Result<()> { + // Handle any blocked requests + let mut i = 0; + while i < self.blocked.len() { + if let Some(resp) = self.blocked[i].handle_scheme_block(self) { + self.socket + .write_response(resp, SignalBehavior::Restart) + .expect("driver-block: failed to write scheme"); + self.blocked.remove(i); + } else { + i += 1; + } + } + + // Handle new scheme requests + loop { + let request = match self.socket.next_request(SignalBehavior::Restart) { + Ok(Some(request)) => request, + Ok(None) => { + // Scheme likely got unmounted + std::process::exit(0); + } + Err(err) if err.errno == EAGAIN => break, + Err(err) => return Err(err.into()), + }; + + match request.kind() { + RequestKind::Call(call_request) => { + if let Some(resp) = call_request.handle_scheme_block(self) { + self.socket.write_response(resp, SignalBehavior::Restart)?; + } else { + self.blocked.push(call_request); + } + } + RequestKind::SendFd(sendfd_request) => { + self.socket.write_response( + Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), + SignalBehavior::Restart, + )?; + } + RequestKind::Cancellation(_cancellation_request) => { + // FIXME implement cancellation + } + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() + } + } + } + + Ok(()) + } + + // Checks if any conflicting handles already exist + fn check_locks(&self, disk_i: u32, part_i_opt: Option) -> Result<()> { + for (_, handle) in self.handles.iter() { + match handle { + Handle::Disk(i) => { + if disk_i == *i { + return Err(Error::new(ENOLCK)); + } + } + Handle::Partition(i, p) => { + if disk_i == *i { + match part_i_opt { + Some(part_i) => { + if part_i == *p { + return Err(Error::new(ENOLCK)); + } + } + None => { + return Err(Error::new(ENOLCK)); + } + } + } + } + _ => (), + } + } + Ok(()) + } +} + +impl SchemeBlock for DiskScheme { + fn xopen( + &mut self, + path_str: &str, + flags: usize, + ctx: &CallerCtx, + ) -> Result> { + if ctx.uid != 0 { + return Err(Error::new(EACCES)); + } + let path_str = path_str.trim_matches('/'); + + let handle = if path_str.is_empty() { + if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { + let mut list = String::new(); + + for (nsid, disk) in self.disks.iter() { + write!(list, "{}\n", nsid).unwrap(); + + if disk.pt.is_none() { + continue; + } + for part_num in 0..disk.pt.as_ref().unwrap().partitions.len() { + write!(list, "{}p{}\n", nsid, part_num).unwrap(); + } + } + + Handle::List(list.into_bytes()) + } else { + return Err(Error::new(EISDIR)); + } + } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { + let nsid_str = &path_str[..p_pos]; + + if p_pos + 1 >= path_str.len() { + return Err(Error::new(ENOENT)); + } + let part_num_str = &path_str[p_pos + 1..]; + + let nsid = nsid_str.parse::().or(Err(Error::new(ENOENT)))?; + let part_num = part_num_str.parse::().or(Err(Error::new(ENOENT)))?; + + if let Some(disk) = self.disks.get(&nsid) { + if disk + .pt + .as_ref() + .ok_or(Error::new(ENOENT))? + .partitions + .get(part_num as usize) + .is_some() + { + self.check_locks(nsid, Some(part_num))?; + + Handle::Partition(nsid, part_num) + } else { + return Err(Error::new(ENOENT)); + } + } else { + return Err(Error::new(ENOENT)); + } + } else { + let nsid = path_str.parse::().or(Err(Error::new(ENOENT)))?; + + if self.disks.contains_key(&nsid) { + self.check_locks(nsid, None)?; + Handle::Disk(nsid) + } else { + return Err(Error::new(ENOENT)); + } + }; + let id = self.next_id; + self.next_id += 1; + self.handles.insert(id, handle); + Ok(Some(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + })) + } + + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + match *self.handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref data) => { + stat.st_mode = MODE_DIR; + stat.st_size = data.len() as u64; + Ok(Some(0)) + } + Handle::Disk(number) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + stat.st_mode = MODE_FILE; + stat.st_blocks = disk.disk().size() / u64::from(disk.block_size()); + stat.st_blksize = disk.block_size(); + stat.st_size = disk.size(); + Ok(Some(0)) + } + Handle::Partition(disk_num, part_num) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let part = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; + stat.st_mode = MODE_FILE; + stat.st_size = part.size * u64::from(disk.block_size()); + stat.st_blocks = part.size; + stat.st_blksize = disk.block_size(); + Ok(Some(0)) + } + } + } + + fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + + let mut i = 0; + + let scheme_name = self.scheme_name.as_bytes(); + let mut j = 0; + while i < buf.len() && j < scheme_name.len() { + buf[i] = scheme_name[j]; + i += 1; + j += 1; + } + + if i < buf.len() { + buf[i] = b':'; + i += 1; + } + + match *handle { + Handle::List(_) => (), + Handle::Disk(number) => { + let number_str = format!("{}", number); + let number_bytes = number_str.as_bytes(); + j = 0; + while i < buf.len() && j < number_bytes.len() { + buf[i] = number_bytes[j]; + i += 1; + j += 1; + } + } + Handle::Partition(disk_num, part_num) => { + let number_str = format!("{}p{}", disk_num, part_num); + let number_bytes = number_str.as_bytes(); + j = 0; + while i < buf.len() && j < number_bytes.len() { + buf[i] = number_bytes[j]; + i += 1; + j += 1; + } + } + } + + Ok(Some(i)) + } + + fn read( + &mut self, + id: usize, + buf: &mut [u8], + offset: u64, + _fcntl_flags: u32, + ) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref handle) => { + let src = usize::try_from(offset) + .ok() + .and_then(|o| handle.get(o..)) + .unwrap_or(&[]); + let count = core::cmp::min(src.len(), buf.len()); + buf[..count].copy_from_slice(&src[..count]); + Ok(Some(count)) + } + Handle::Disk(number) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + let block = offset / u64::from(disk.block_size()); + disk.read(None, block, buf) + } + Handle::Partition(disk_num, part_num) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let block = offset / u64::from(disk.block_size()); + disk.read(Some(part_num as usize), block, buf) + } + } + } + + fn write( + &mut self, + id: usize, + buf: &[u8], + offset: u64, + _fcntl_flags: u32, + ) -> Result> { + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(_) => Err(Error::new(EBADF)), + Handle::Disk(number) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + let block = offset / u64::from(disk.block_size()); + disk.write(None, block, buf) + } + Handle::Partition(disk_num, part_num) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let block = offset / u64::from(disk.block_size()); + disk.write(Some(part_num as usize), block, buf) + } + } + } + + fn fsize(&mut self, id: usize) -> Result> { + Ok(Some( + match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref handle) => handle.len() as u64, + Handle::Disk(number) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + disk.size() + } + Handle::Partition(disk_num, part_num) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let part = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; + + part.size * u64::from(disk.block_size()) + } + }, + )) + } + + fn close(&mut self, id: usize) -> Result> { + self.handles + .remove(&id) + .ok_or(Error::new(EBADF)) + .and(Ok(Some(0))) + } +} diff --git a/storage/ided/Cargo.toml b/storage/ided/Cargo.toml index 3a0f34d5f7..9f6ee66745 100644 --- a/storage/ided/Cargo.toml +++ b/storage/ided/Cargo.toml @@ -11,5 +11,4 @@ log = "0.4" pcid = { path = "../../pcid" } redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 3f1bc352dd..c7dd8f8746 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -1,10 +1,9 @@ use common::io::Io as _; -use driver_block::Disk; +use driver_block::{Disk, DiskScheme}; use event::{EventFlags, RawEventQueue}; use libredox::flag; use log::{error, info}; use pcid_interface::PciFunctionHandle; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; use std::{ fs::File, io::{Read, Write}, @@ -13,15 +12,10 @@ use std::{ thread::{self, sleep}, time::Duration, }; -use syscall::error::{Error, EAGAIN, EINTR, ENODEV, EWOULDBLOCK}; -use crate::{ - ide::{AtaCommand, AtaDisk, Channel}, - scheme::DiskScheme, -}; +use crate::ide::{AtaCommand, AtaDisk, Channel}; pub mod ide; -pub mod scheme; fn main() { redox_daemon::Daemon::new(daemon).expect("ided: failed to daemonize"); @@ -193,7 +187,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } let scheme_name = format!("disk.{}", name); - let socket_fd = Socket::nonblock(&scheme_name).expect("ided: failed to create disk scheme"); + let mut scheme = DiskScheme::new( + scheme_name, + disks + .into_iter() + .enumerate() + .map(|(i, disk)| (i as u32, disk)) + .collect(), + ); let primary_irq_fd = libredox::call::open( &format!("/scheme/irq/{}", primary_irq), @@ -211,14 +212,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("ided: failed to open irq file"); let mut secondary_irq_file = unsafe { File::from_raw_fd(secondary_irq_fd as RawFd) }; - let mut event_queue = RawEventQueue::new().expect("ided: failed to open event file"); + let event_queue = RawEventQueue::new().expect("ided: failed to open event file"); libredox::call::setrens(0, 0).expect("ided: failed to enter null namespace"); daemon.ready().expect("ided: failed to notify parent"); event_queue - .subscribe(socket_fd.inner().raw(), 0, EventFlags::READ) + .subscribe(scheme.event_handle().raw(), 0, EventFlags::READ) .expect("ided: failed to event disk scheme"); event_queue @@ -229,44 +230,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .subscribe(secondary_irq_fd, 0, EventFlags::READ) .expect("ided: failed to event irq scheme"); - let mut scheme = DiskScheme::new(scheme_name, disks); - - let mut todo = Vec::new(); - 'outer: loop { - let Some(event) = event_queue - .next() - .transpose() - .expect("ided: failed to read event file") - else { - break; - }; - if event.fd == socket_fd.inner().raw() { - loop { - let req = match socket_fd.next_request(SignalBehavior::Interrupt) { - Ok(None) => break 'outer, - Ok(Some(r)) => { - if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - } - } - Err(err) => { - if matches!(err.errno, EAGAIN | EWOULDBLOCK | EINTR) { - break; - } else { - panic!("ided: failed to read disk scheme: {}", err); - } - } - }; - if let Some(resp) = req.handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("ided: failed to write disk scheme"); - } else { - todo.push(req); - } - } + for event in event_queue { + let event = event.unwrap(); + if event.fd == scheme.event_handle().raw() { + scheme.tick().unwrap(); } else if event.fd == primary_irq_fd { let mut irq = [0; 8]; if primary_irq_file @@ -281,17 +248,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .write(&irq) .expect("ided: failed to write irq file"); - // Handle todos in order to finish previous packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("ided: failed to write disk scheme"); - } else { - i += 1; - } - } + scheme.tick().unwrap(); } } else if event.fd == secondary_irq_fd { let mut irq = [0; 8]; @@ -307,42 +264,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .write(&irq) .expect("ided: failed to write irq file"); - // Handle todos in order to finish previous packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("ided: failed to write disk scheme"); - } else { - i += 1; - } - } + scheme.tick().unwrap(); } } else { error!("Unknown event {}", event.fd); } - - // Handle todos to start new packets if possible - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("ided: failed to write disk scheme"); - } else { - i += 1; - } - } - - for req in todo.drain(..) { - socket_fd - .write_response( - Response::new(&req, Err(Error::new(ENODEV))), - SignalBehavior::Restart, - ) - .expect("ided: failed to write disk scheme"); - } } std::process::exit(0); diff --git a/storage/ided/src/scheme.rs b/storage/ided/src/scheme.rs deleted file mode 100644 index 48d8bd6df6..0000000000 --- a/storage/ided/src/scheme.rs +++ /dev/null @@ -1,311 +0,0 @@ -use std::collections::BTreeMap; -use std::fmt::Write; -use std::str; -use std::sync::{Arc, Mutex}; - -use driver_block::{Disk, DiskWrapper}; -use syscall::schemev2::NewFdFlags; -use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, -}; - -use crate::ide::Channel; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; - -enum Handle { - List(Vec), // Dir contents buffer - Disk(usize), // Disk index - Partition(usize, u32), // Disk index, partition index -} - -pub struct DiskScheme { - scheme_name: String, - disks: Box<[DiskWrapper>]>, - handles: BTreeMap, - next_id: usize, -} - -impl DiskScheme { - pub fn new(scheme_name: String, disks: Vec>) -> DiskScheme { - DiskScheme { - scheme_name, - disks: disks - .into_iter() - .map(DiskWrapper::new) - .collect::>() - .into_boxed_slice(), - handles: BTreeMap::new(), - next_id: 0, - } - } - - // Checks if any conflicting handles already exist - fn check_locks(&self, disk_i: usize, part_i_opt: Option) -> Result<()> { - for (_, handle) in self.handles.iter() { - match handle { - Handle::Disk(i) => { - if disk_i == *i { - return Err(Error::new(ENOLCK)); - } - } - Handle::Partition(i, p) => { - if disk_i == *i { - match part_i_opt { - Some(part_i) => { - if part_i == *p { - return Err(Error::new(ENOLCK)); - } - } - None => { - return Err(Error::new(ENOLCK)); - } - } - } - } - _ => (), - } - } - Ok(()) - } -} - -impl SchemeBlock for DiskScheme { - fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result> { - if ctx.uid == 0 { - let path_str = path.trim_matches('/'); - if path_str.is_empty() { - if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { - let mut list = String::new(); - - for (disk_index, disk) in self.disks.iter().enumerate() { - write!(list, "{}\n", disk_index).unwrap(); - - if disk.pt.is_none() { - continue; - } - for part_index in 0..disk.pt.as_ref().unwrap().partitions.len() { - write!(list, "{}p{}\n", disk_index, part_index).unwrap(); - } - } - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::List(list.into_bytes())); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(EISDIR)) - } - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let disk_id_str = &path_str[..p_pos]; - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_id_str = &path_str[p_pos + 1..]; - let i = disk_id_str.parse::().or(Err(Error::new(ENOENT)))?; - let p = part_id_str.parse::().or(Err(Error::new(ENOENT)))?; - - if let Some(disk) = self.disks.get(i) { - if disk.pt.is_none() - || disk - .pt - .as_ref() - .unwrap() - .partitions - .get(p as usize) - .is_none() - { - return Err(Error::new(ENOENT)); - } - - self.check_locks(i, Some(p))?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Partition(i, p)); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(ENOENT)) - } - } else { - let i = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if self.disks.get(i).is_some() { - self.check_locks(i, None)?; - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Disk(i)); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - Err(Error::new(ENOENT)) - } - } - } else { - Err(Error::new(EACCES)) - } - } - - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { - match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data) => { - stat.st_mode = MODE_DIR; - stat.st_size = data.len() as u64; - Ok(Some(0)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_size = disk.size(); - stat.st_blksize = disk.block_size(); - Ok(Some(0)) - } - Handle::Partition(disk_id, part_num) => { - let disk = self.disks.get_mut(disk_id).ok_or(Error::new(EBADF))?; - let size = { - let pt = disk.pt.as_ref().ok_or(Error::new(EBADF))?; - let partition = pt - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - partition.size - }; - - stat.st_mode = MODE_FILE; // TODO: Block device? - stat.st_size = size * u64::from(disk.block_size()); - stat.st_blksize = disk.block_size(); - stat.st_blocks = size; - Ok(Some(0)) - } - } - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - - let scheme_name = self.scheme_name.as_bytes(); - let mut j = 0; - while i < buf.len() && j < scheme_name.len() { - buf[i] = scheme_name[j]; - i += 1; - j += 1; - } - - if i < buf.len() { - buf[i] = b':'; - i += 1; - } - - match *handle { - Handle::List(_) => (), - Handle::Disk(number) => { - let number_str = format!("{}", number); - let number_bytes = number_str.as_bytes(); - j = 0; - while i < buf.len() && j < number_bytes.len() { - buf[i] = number_bytes[j]; - i += 1; - j += 1; - } - } - Handle::Partition(disk_num, part_num) => { - let path = format!("{}p{}", disk_num, part_num); - let path_bytes = path.as_bytes(); - j = 0; - while i < buf.len() && j < path_bytes.len() { - buf[i] = path_bytes[j]; - i += 1; - j += 1; - } - } - } - - Ok(Some(i)) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| handle.get(o..)) - .unwrap_or(&[]); - let bytes = src.len().min(buf.len()); - buf[..bytes].copy_from_slice(&src[..bytes]); - Ok(Some(bytes)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(Some(part_num as usize), block, buf) - } - } - } - - fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => Err(Error::new(EBADF)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(Some(part_num as usize), block, buf) - } - } - } - - fn fsize(&mut self, id: usize) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref mut handle) => Ok(Some(handle.len() as u64)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(number).ok_or(Error::new(EBADF))?; - Ok(Some(disk.size())) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(disk_num).ok_or(Error::new(EBADF))?; - let block_count = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))? - .size; - Ok(Some(u64::from(disk.block_size()) * block_count)) - } - } - } - - fn close(&mut self, id: usize) -> Result> { - self.handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) - } -} diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 8a6d1c6663..3650871a87 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "nvmed" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] arrayvec = "0.5" @@ -11,7 +11,6 @@ futures = "0.3" log = "0.4" redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" smallvec = "1" diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 93bd7e47c9..d53189d1f2 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -5,15 +5,15 @@ use std::ptr::NonNull; use std::sync::Arc; use std::{slice, usize}; +use driver_block::{Disk, DiskScheme}; use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PciFunctionHandle}; -use redox_scheme::{RequestKind, SignalBehavior, Socket}; use syscall::Result; +use crate::nvme::NvmeNamespace; + use self::nvme::{InterruptMethod, InterruptSources, Nvme}; -use self::scheme::DiskScheme; mod nvme; -mod scheme; /// Get the most optimal yet functional interrupt mechanism: either (in the order of preference): /// MSI-X, MSI, and INTx# pin. Returns both runtime interrupt structures (MSI/MSI-X capability @@ -140,6 +140,26 @@ fn get_int_method( } } +struct NvmeDisk(Arc, NvmeNamespace); + +impl Disk for NvmeDisk { + fn block_size(&self) -> u32 { + self.1.block_size.try_into().unwrap() + } + + fn size(&self) -> u64 { + self.1.blocks * self.1.block_size + } + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + self.0.namespace_read(self.1, block, buffer) + } + + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + self.0.namespace_write(self.1, block, buffer) + } +} + fn main() { redox_daemon::Daemon::new(daemon).expect("nvmed: failed to daemonize"); } @@ -161,8 +181,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { pcid_handle.map_bar(0).ptr }; - let socket = Socket::create(&scheme_name).expect("nvmed: failed to create disk scheme"); - daemon.ready().expect("nvmed: failed to signal readiness"); let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); @@ -185,40 +203,35 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { reactor_receiver, ); let namespaces = nvme.init_with_queues(); + let event_queue = event::EventQueue::new().unwrap(); + + event::user_data! { + enum Event { + Scheme, + } + }; + + let mut scheme = DiskScheme::new( + scheme_name, + namespaces + .into_iter() + .map(|(k, ns)| (k, NvmeDisk(nvme.clone(), ns))) + .collect(), + ); libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - let mut scheme = DiskScheme::new(scheme_name, nvme, namespaces); - let mut todo = Vec::new(); - loop { - // TODO: Use a proper event queue once interrupt support is back. - match socket - .next_request(SignalBehavior::Restart) - .expect("nvmed: failed to read disk scheme") - { - None => { - break; - } - Some(req) => { - if let RequestKind::Call(c) = req.kind() { - todo.push(c); - } else { - // TODO: cancellation - continue; - } - } - } + event_queue + .subscribe( + scheme.event_handle().raw(), + Event::Scheme, + event::EventFlags::READ, + ) + .unwrap(); - let mut i = 0; - while i < todo.len() { - if let Some(resp) = todo[i].handle_scheme_block(&mut scheme) { - let _req = todo.remove(i); - socket - .write_response(resp, SignalBehavior::Restart) - .expect("nvmed: failed to write disk scheme"); - } else { - i += 1; - } + for event in event_queue { + match event.unwrap().user_data { + Event::Scheme => scheme.tick().unwrap(), } } diff --git a/storage/nvmed/src/scheme.rs b/storage/nvmed/src/scheme.rs deleted file mode 100644 index bd864441dd..0000000000 --- a/storage/nvmed/src/scheme.rs +++ /dev/null @@ -1,336 +0,0 @@ -use std::collections::BTreeMap; -use std::convert::{TryFrom, TryInto}; -use std::fmt::Write; -use std::str; -use std::sync::Arc; - -use driver_block::{Disk, DiskWrapper}; -use redox_scheme::{CallerCtx, OpenResult, SchemeBlock}; -use syscall::schemev2::NewFdFlags; -use syscall::{ - Error, Result, Stat, EACCES, EBADF, EISDIR, ENOENT, ENOLCK, MODE_DIR, MODE_FILE, O_DIRECTORY, - O_STAT, -}; - -use crate::nvme::{Nvme, NvmeNamespace}; - -enum Handle { - List(Vec), // entries - Disk(u32), // disk num - Partition(u32, u32), // disk num, part num -} - -struct NvmeDisk(Arc, NvmeNamespace); - -impl Disk for NvmeDisk { - fn block_size(&self) -> u32 { - self.1.block_size.try_into().unwrap() - } - - fn size(&self) -> u64 { - self.1.blocks * self.1.block_size - } - - fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { - self.0.namespace_read(self.1, block, buffer) - } - - fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { - self.0.namespace_write(self.1, block, buffer) - } -} - -pub struct DiskScheme { - scheme_name: String, - disks: BTreeMap>, - handles: BTreeMap, - next_id: usize, -} - -impl DiskScheme { - pub fn new( - scheme_name: String, - nvme: Arc, - disks: BTreeMap, - ) -> DiskScheme { - DiskScheme { - scheme_name, - disks: disks - .into_iter() - .map(|(k, ns)| (k, DiskWrapper::new(NvmeDisk(nvme.clone(), ns)))) - .collect(), - handles: BTreeMap::new(), - next_id: 0, - } - } - - // Checks if any conflicting handles already exist - fn check_locks(&self, disk_i: u32, part_i_opt: Option) -> Result<()> { - for (_, handle) in self.handles.iter() { - match handle { - Handle::Disk(i) => { - if disk_i == *i { - return Err(Error::new(ENOLCK)); - } - } - Handle::Partition(i, p) => { - if disk_i == *i { - match part_i_opt { - Some(part_i) => { - if part_i == *p { - return Err(Error::new(ENOLCK)); - } - } - None => { - return Err(Error::new(ENOLCK)); - } - } - } - } - _ => (), - } - } - Ok(()) - } -} - -impl SchemeBlock for DiskScheme { - fn xopen( - &mut self, - path_str: &str, - flags: usize, - ctx: &CallerCtx, - ) -> Result> { - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - let path_str = path_str.trim_matches('/'); - - let handle = if path_str.is_empty() { - if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { - let mut list = String::new(); - - for (nsid, disk) in self.disks.iter() { - write!(list, "{}\n", nsid).unwrap(); - - if disk.pt.is_none() { - continue; - } - for part_num in 0..disk.pt.as_ref().unwrap().partitions.len() { - write!(list, "{}p{}\n", nsid, part_num).unwrap(); - } - } - - Handle::List(list.into_bytes()) - } else { - return Err(Error::new(EISDIR)); - } - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let nsid_str = &path_str[..p_pos]; - - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_num_str = &path_str[p_pos + 1..]; - - let nsid = nsid_str.parse::().or(Err(Error::new(ENOENT)))?; - let part_num = part_num_str.parse::().or(Err(Error::new(ENOENT)))?; - - if let Some(disk) = self.disks.get(&nsid) { - if disk - .pt - .as_ref() - .ok_or(Error::new(ENOENT))? - .partitions - .get(part_num as usize) - .is_some() - { - self.check_locks(nsid, Some(part_num))?; - - Handle::Partition(nsid, part_num) - } else { - return Err(Error::new(ENOENT)); - } - } else { - return Err(Error::new(ENOENT)); - } - } else { - let nsid = path_str.parse::().or(Err(Error::new(ENOENT)))?; - - if self.disks.contains_key(&nsid) { - self.check_locks(nsid, None)?; - Handle::Disk(nsid) - } else { - return Err(Error::new(ENOENT)); - } - }; - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, handle); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } - - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { - match *self.handles.get(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref data) => { - stat.st_mode = MODE_DIR; - stat.st_size = data.len() as u64; - Ok(Some(0)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_blocks = disk.disk().1.blocks; - stat.st_blksize = disk.block_size(); - stat.st_size = disk.size(); - Ok(Some(0)) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - stat.st_mode = MODE_FILE; - stat.st_size = part.size * u64::from(disk.block_size()); - stat.st_blocks = part.size; - stat.st_blksize = disk.block_size(); - Ok(Some(0)) - } - } - } - - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - let mut i = 0; - - let scheme_name = self.scheme_name.as_bytes(); - let mut j = 0; - while i < buf.len() && j < scheme_name.len() { - buf[i] = scheme_name[j]; - i += 1; - j += 1; - } - - if i < buf.len() { - buf[i] = b':'; - i += 1; - } - - match *handle { - Handle::List(_) => (), - Handle::Disk(number) => { - let number_str = format!("{}", number); - let number_bytes = number_str.as_bytes(); - j = 0; - while i < buf.len() && j < number_bytes.len() { - buf[i] = number_bytes[j]; - i += 1; - j += 1; - } - } - Handle::Partition(disk_num, part_num) => { - let number_str = format!("{}p{}", disk_num, part_num); - let number_bytes = number_str.as_bytes(); - j = 0; - while i < buf.len() && j < number_bytes.len() { - buf[i] = number_bytes[j]; - i += 1; - j += 1; - } - } - } - - Ok(Some(i)) - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _fcntl_flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| handle.get(o..)) - .unwrap_or(&[]); - let count = core::cmp::min(src.len(), buf.len()); - buf[..count].copy_from_slice(&src[..count]); - Ok(Some(count)) - } - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.read(Some(part_num as usize), block, buf) - } - } - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - offset: u64, - _fcntl_flags: u32, - ) -> Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(_) => Err(Error::new(EBADF)), - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(None, block, buf) - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let block = offset / u64::from(disk.block_size()); - disk.write(Some(part_num as usize), block, buf) - } - } - } - - fn fsize(&mut self, id: usize) -> Result> { - Ok(Some( - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => handle.len() as u64, - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - disk.size() - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; - - part.size * u64::from(disk.block_size()) - } - }, - )) - } - - fn close(&mut self, id: usize) -> Result> { - self.handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) - } -} diff --git a/storage/virtio-blkd/Cargo.toml b/storage/virtio-blkd/Cargo.toml index 2b2a663565..34cc370cae 100644 --- a/storage/virtio-blkd/Cargo.toml +++ b/storage/virtio-blkd/Cargo.toml @@ -13,8 +13,8 @@ futures = { version = "0.3.28", features = ["executor"] } spin = "*" redox-daemon = "0.1" +redox_event = "0.4" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } common = { path = "../../common" } driver-block = { path = "../driver-block" } diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index ac94312eef..7503b477d7 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -1,8 +1,9 @@ #![deny(trivial_numeric_casts, unused_allocation)] +use std::collections::BTreeMap; use std::sync::{Arc, Weak}; -use redox_scheme::{RequestKind, SignalBehavior, Socket}; +use driver_block::DiskScheme; use static_assertions::const_assert_eq; use pcid_interface::*; @@ -15,6 +16,8 @@ mod scheme; use thiserror::Error; +use crate::scheme::VirtioDisk; + #[derive(Debug, Error)] pub enum Error { #[error("capability {0:?} not found")] @@ -140,31 +143,37 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let scheme_name = format!("disk.{}", name); - let socket_fd = Socket::create(&scheme_name).map_err(Error::SyscallError)?; + let event_queue = event::EventQueue::new().unwrap(); - let mut scheme = scheme::DiskScheme::new(queue, device_space); + event::user_data! { + enum Event { + Scheme, + } + }; + + let mut scheme = DiskScheme::new( + scheme_name, + BTreeMap::from([(0, VirtioDisk::new(queue, device_space))]), + ); + + libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + + event_queue + .subscribe( + scheme.event_handle().raw(), + Event::Scheme, + event::EventFlags::READ, + ) + .unwrap(); deamon.ready().expect("virtio-blkd: failed to deamonize"); - loop { - let req = match socket_fd - .next_request(SignalBehavior::Restart) - .expect("virtio-blkd: failed to read disk scheme") - { - Some(r) => { - if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - } - } - None => break, - }; - let resp = req.handle_scheme_block(&mut scheme).expect("TODO: block?"); - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("virtio-blkd: failed to write to disk scheme"); + for event in event_queue { + match event.unwrap().user_data { + Event::Scheme => scheme.tick().unwrap(), + } } + Ok(()) } diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 974573da51..074f2ff61c 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -1,17 +1,6 @@ -use std::collections::BTreeMap; - -use std::fmt::Write; use std::sync::Arc; use common::dma::Dma; -use driver_block::DiskWrapper; - -use redox_scheme::CallerCtx; -use redox_scheme::OpenResult; -use redox_scheme::SchemeBlock; -use syscall::error::*; -use syscall::flag::*; -use syscall::schemev2::NewFdFlags; use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags}; use virtio_core::transport::Queue; @@ -19,8 +8,6 @@ use crate::BlockDeviceConfig; use crate::BlockRequestTy; use crate::BlockVirtRequest; -const BLK_SIZE: u64 = 512; - trait BlkExtension { async fn read(&self, block: u64, target: &mut [u8]) -> usize; async fn write(&self, block: u64, target: &[u8]) -> usize; @@ -86,13 +73,13 @@ impl BlkExtension for Queue<'_> { } } -struct VirtioDisk<'a> { +pub(crate) struct VirtioDisk<'a> { queue: Arc>, cfg: BlockDeviceConfig, } impl<'a> VirtioDisk<'a> { - pub fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { + pub(crate) fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { Self { queue, cfg } } } @@ -118,203 +105,3 @@ impl driver_block::Disk for VirtioDisk<'_> { ))) } } - -pub enum Handle { - Partition { - /// Partition Number - number: u32, - }, - - List { - entries: Vec, - }, - - Disk, -} - -pub struct DiskScheme<'a> { - disk: DiskWrapper>, - next_id: usize, - handles: BTreeMap, -} - -impl<'a> DiskScheme<'a> { - pub fn new(queue: Arc>, cfg: BlockDeviceConfig) -> Self { - Self { - disk: DiskWrapper::new(VirtioDisk::new(queue, cfg)), - next_id: 0, - handles: BTreeMap::new(), - } - } -} - -impl<'a> SchemeBlock for DiskScheme<'a> { - fn xopen( - &mut self, - path: &str, - flags: usize, - _ctx: &CallerCtx, - ) -> syscall::Result> { - log::info!("virtiod: open: {}", path); - - let path_str = path.trim_matches('/'); - if path_str.is_empty() { - if flags & O_DIRECTORY == O_DIRECTORY || flags & O_STAT == O_STAT { - let mut list = String::new(); - // FIXME: The zero is the disk identifier (look in the nvmed scheme, it set's this - // to the namespace id). - write!(list, "{}\n", 0).unwrap(); - - if let Some(part_table) = &self.disk.pt { - for part_num in 0..part_table.partitions.len() { - write!(list, "{}p{}\n", 0, part_num).unwrap(); - } - } - - let id = self.next_id; - self.next_id += 1; - self.handles.insert( - id, - Handle::List { - entries: list.into_bytes(), - }, - ); - - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - return Err(syscall::Error::new(EISDIR)); - } - } else if let Some(p_pos) = path_str.chars().position(|c| c == 'p') { - let _nsid_str = &path_str[..p_pos]; - - if p_pos + 1 >= path_str.len() { - return Err(Error::new(ENOENT)); - } - let part_num_str = &path_str[p_pos + 1..]; - let part_num = part_num_str.parse::().unwrap(); - - let part_table = self.disk.pt.as_ref().unwrap(); - let _part = part_table.partitions.get(part_num as usize).unwrap(); - - let id = self.next_id; - self.next_id += 1; - self.handles - .insert(id, Handle::Partition { number: part_num }); - - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } else { - let nsid = path_str.parse::().unwrap(); - assert_eq!(nsid, 0); - - let id = self.next_id; - self.next_id += 1; - self.handles.insert(id, Handle::Disk); - Ok(Some(OpenResult::ThisScheme { - number: id, - flags: NewFdFlags::POSITIONED, - })) - } - } - - fn read( - &mut self, - id: usize, - buf: &mut [u8], - offset: u64, - _fcntl_flags: u32, - ) -> syscall::Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List { ref mut entries } => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| entries.get(o..)) - .unwrap_or(&[]); - let count = core::cmp::min(src.len(), buf.len()); - buf[..count].copy_from_slice(&src[..count]); - Ok(Some(count)) - } - Handle::Disk => { - let block = offset / u64::from(self.disk.block_size()); - self.disk.read(None, block, buf) - } - Handle::Partition { number } => { - let block = offset / u64::from(self.disk.block_size()); - self.disk.read(Some(number as usize), block, buf) - } - } - } - - fn write( - &mut self, - id: usize, - buf: &[u8], - offset: u64, - _fcntl_flags: u32, - ) -> syscall::Result> { - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List { .. } => Err(Error::new(EBADF)), - Handle::Disk => { - let block = offset / u64::from(self.disk.block_size()); - self.disk.write(None, block, buf) - } - Handle::Partition { number } => { - let block = offset / u64::from(self.disk.block_size()); - self.disk.write(Some(number as usize), block, buf) - } - } - } - - fn fsize(&mut self, id: usize) -> syscall::Result> { - Ok(Some( - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List { ref entries } => { - let len = entries.len() as u64; - log::debug!("list: part_len={len:?}"); - - len - } - - Handle::Partition { number } => { - let part_table = self.disk.pt.as_ref().unwrap(); - let part = part_table - .partitions - .get(number as usize) - .ok_or(Error::new(EBADF))?; - - // Partition size in bytes. - let len = part.size * BLK_SIZE; - - log::debug!("part: part_len={len:?}"); - - len - } - - Handle::Disk => self.disk.size(), - }, - )) - } - - fn fpath(&mut self, _id: usize, _buf: &mut [u8]) -> syscall::Result> { - todo!() - } - - fn fstat(&mut self, id: usize, _stat: &mut syscall::Stat) -> syscall::Result> { - match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List { .. } => Ok(Some(0)), - Handle::Disk { .. } | Handle::Partition { .. } => todo!(), - } - } - - fn close(&mut self, id: usize) -> syscall::Result> { - self.handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) - } -} From 269fd9abc042a861a1ffd2e6a339676952f3ec0b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 8 Mar 2025 21:41:33 +0100 Subject: [PATCH 1127/1301] storage/lived: Use the unified disk scheme implementation --- Cargo.lock | 2 +- storage/driver-block/src/lib.rs | 2 + storage/lived/Cargo.toml | 2 +- storage/lived/src/main.rs | 198 ++++++++++---------------------- 4 files changed, 66 insertions(+), 138 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9506ce08e1..d024866c9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -780,9 +780,9 @@ name = "lived" version = "0.1.0" dependencies = [ "anyhow", + "driver-block", "libredox", "redox-daemon", - "redox-scheme 0.3.0", "redox_event", "redox_syscall", ] diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index a60a208847..fa5b4fb22a 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -69,6 +69,8 @@ pub trait Disk { fn block_size(&self) -> u32; fn size(&self) -> u64; + // These operate on a whole multiple of the block size + // FIXME maybe only operate on a single block worth of data? fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result>; fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result>; } diff --git a/storage/lived/Cargo.toml b/storage/lived/Cargo.toml index 57ec2be9fe..034ba80d0a 100644 --- a/storage/lived/Cargo.toml +++ b/storage/lived/Cargo.toml @@ -12,5 +12,5 @@ anyhow = "1" libredox = "0.1.3" redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_event = "0.4" +driver-block = { path = "../driver-block" } diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index b2f9096600..f4c2ac15ff 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -2,46 +2,26 @@ #![feature(int_roundings)] +use std::collections::BTreeMap; use std::fs::File; use std::os::fd::AsRawFd; -use std::str; +use driver_block::{Disk, DiskScheme}; use libredox::call::MmapArgs; use libredox::flag; -use redox_scheme::{CallerCtx, OpenResult, RequestKind, Scheme, SignalBehavior, Socket}; -use syscall::data::Stat; use syscall::error::*; -use syscall::flag::{MODE_DIR, MODE_FILE}; -use syscall::schemev2::NewFdFlags; use syscall::PAGE_SIZE; use anyhow::{anyhow, bail, Context}; -const LIST: [u8; 2] = *b"0\n"; - -#[repr(usize)] -enum HandleType { - TopLevel = 0, - TheData = 1, -} -impl HandleType { - fn try_from_raw(raw: usize) -> Option { - Some(match raw { - 0 => Self::TopLevel, - 1 => Self::TheData, - _ => return None, - }) - } -} - -pub struct DiskScheme { +struct LiveDisk { the_data: &'static mut [u8], } -impl DiskScheme { - pub fn new() -> anyhow::Result { +impl LiveDisk { + fn new() -> anyhow::Result { let mut phys = 0; let mut size = 0; @@ -93,133 +73,79 @@ impl DiskScheme { std::slice::from_raw_parts_mut(base as *mut u8, size) }; - Ok(DiskScheme { the_data }) + Ok(LiveDisk { the_data }) } } -impl Scheme for DiskScheme { - fn fsize(&mut self, id: usize) -> Result { - Ok( - match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { - HandleType::TopLevel => LIST.len() as u64, - HandleType::TheData => self.the_data.len() as u64, - }, - ) +impl Disk for LiveDisk { + fn block_size(&self) -> u32 { + 512 } - fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize) -> Result { - Ok(0) + fn size(&self) -> u64 { + self.the_data.len() as u64 } - fn fsync(&mut self, _id: usize) -> Result { - Ok(0) - } - - fn close(&mut self, _id: usize) -> Result { - Ok(0) - } - fn xopen(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> Result { - if ctx.uid != 0 { - return Err(Error::new(EACCES)); + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + let block = block as usize; + let block_size = self.block_size() as usize; + if block * block_size + buffer.len() > self.size() as usize { + return Err(syscall::Error::new(EOVERFLOW)); } - - let path_trimmed = path.trim_matches('/'); - - Ok(OpenResult::ThisScheme { - number: match path_trimmed { - "" => HandleType::TopLevel as usize, - "0" => HandleType::TheData as usize, - _ => return Err(Error::new(ENOENT)), - }, - flags: NewFdFlags::POSITIONED, - }) - } - fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _flags: u32) -> Result { - let data = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { - HandleType::TheData => &*self.the_data, - HandleType::TopLevel => &LIST, - }; - - let src = usize::try_from(offset) - .ok() - .and_then(|o| data.get(o..)) - .unwrap_or(&[]); - let byte_count = std::cmp::min(src.len(), buf.len()); - buf[..byte_count].copy_from_slice(&src[..byte_count]); - Ok(byte_count) - } - fn write(&mut self, id: usize, buf: &[u8], offset: u64, _flags: u32) -> Result { - let data = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { - HandleType::TheData => &mut *self.the_data, - HandleType::TopLevel => return Err(Error::new(EBADF)), - }; - - let dst = usize::try_from(offset) - .ok() - .and_then(|o| data.get_mut(o..)) - .unwrap_or(&mut []); - let byte_count = std::cmp::min(dst.len(), buf.len()); - dst[..byte_count].copy_from_slice(&buf[..byte_count]); - Ok(byte_count) + buffer + .copy_from_slice(&self.the_data[block * block_size..block * block_size + buffer.len()]); + Ok(Some(block_size)) } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result { - let path = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { - HandleType::TopLevel => "", - HandleType::TheData => "0", - }; - - let src = format!("disk.live:{}", path).into_bytes(); - - let byte_count = std::cmp::min(buf.len(), src.len()); - buf[..byte_count].copy_from_slice(&src[..byte_count]); - - Ok(byte_count) - } - fn fstat(&mut self, id: usize, stat_buf: &mut Stat) -> Result { - let (len, mode) = match HandleType::try_from_raw(id).ok_or(Error::new(EBADF))? { - HandleType::TheData => (self.the_data.len(), MODE_FILE | 0o644), - HandleType::TopLevel => (LIST.len(), MODE_DIR | 0o755), - }; - - *stat_buf = Stat { - st_mode: mode, - st_uid: 0, - st_gid: 0, - st_size: len.try_into().map_err(|_| Error::new(EOVERFLOW))?, - ..Stat::default() - }; - - Ok(0) + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + let block = block as usize; + let block_size = self.block_size() as usize; + if block * block_size + buffer.len() > self.size() as usize { + return Err(syscall::Error::new(EOVERFLOW)); + } + self.the_data[block * block_size..block * block_size + buffer.len()] + .copy_from_slice(buffer); + Ok(Some(block_size)) } } + fn main() -> anyhow::Result<()> { redox_daemon::Daemon::new(move |daemon| { - let socket_fd = Socket::create("disk.live").expect("failed to open scheme"); - let mut scheme = DiskScheme::new().unwrap_or_else(|err| { - eprintln!("failed to initialize livedisk scheme: {}", err); - std::process::exit(1) - }); + let event_queue = event::EventQueue::new().unwrap(); + + event::user_data! { + enum Event { + Scheme, + } + }; + + let mut scheme = DiskScheme::new( + "disk.live".to_owned(), + BTreeMap::from([( + 0, + LiveDisk::new().unwrap_or_else(|err| { + eprintln!("failed to initialize livedisk scheme: {}", err); + std::process::exit(1) + }), + )]), + ); + + libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + + event_queue + .subscribe( + scheme.event_handle().raw(), + Event::Scheme, + event::EventFlags::READ, + ) + .unwrap(); + daemon.ready().expect("failed to signal readiness"); - loop { - let req = match socket_fd - .next_request(SignalBehavior::Restart) - .expect("failed to get next request") - { - Some(r) => { - if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - } - } - None => break, - }; - let resp = req.handle_scheme(&mut scheme); - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("failed to write packet"); + for event in event_queue { + match event.unwrap().user_data { + Event::Scheme => scheme.tick().unwrap(), + } } std::process::exit(0); From 9800c571339cffde6f6deef33fe408f0d8882b52 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Mar 2025 17:02:03 +0100 Subject: [PATCH 1128/1301] storage/driver-block: Fix couple of error condition checks --- storage/driver-block/src/lib.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index fa5b4fb22a..d3569febcb 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -13,8 +13,8 @@ use redox_scheme::{ }; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EAGAIN, EBADF, EISDIR, ENOENT, ENOLCK, EOPNOTSUPP, EOVERFLOW, - MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, + Error, Result, Stat, EACCES, EAGAIN, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOPNOTSUPP, + EOVERFLOW, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, }; /// Split the read operation into a series of block reads. @@ -195,6 +195,10 @@ impl DiskWrapper { block: u64, buf: &mut [u8], ) -> syscall::Result> { + if buf.len() as u64 % u64::from(self.disk.block_size()) != 0 { + return Err(Error::new(EINVAL)); + } + if let Some(part_num) = part_num { let part = self .pt @@ -204,8 +208,7 @@ impl DiskWrapper { .get(part_num) .ok_or(syscall::Error::new(EBADF))?; - let block_size = u64::from(self.block_size()); - if block >= part.size / block_size { + if block >= part.size { return Err(syscall::Error::new(EOVERFLOW)); } @@ -223,6 +226,10 @@ impl DiskWrapper { block: u64, buf: &[u8], ) -> syscall::Result> { + if buf.len() as u64 % u64::from(self.disk.block_size()) != 0 { + return Err(Error::new(EINVAL)); + } + if let Some(part_num) = part_num { let part = self .pt @@ -232,8 +239,7 @@ impl DiskWrapper { .get(part_num) .ok_or(syscall::Error::new(EBADF))?; - let block_size = u64::from(self.block_size()); - if block >= part.size / block_size { + if block >= part.size { return Err(syscall::Error::new(EOVERFLOW)); } From 258ea4e6a58a6137d19869d432c428d5a8d1bd79 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Mar 2025 17:02:25 +0100 Subject: [PATCH 1129/1301] storage/usbscsid: Use the unified disk scheme implementation --- Cargo.lock | 3 +- storage/usbscsid/Cargo.toml | 3 +- storage/usbscsid/src/main.rs | 103 +++++++++++++++------- storage/usbscsid/src/scheme.rs | 146 ------------------------------- storage/usbscsid/src/scsi/mod.rs | 2 +- 5 files changed, 78 insertions(+), 179 deletions(-) delete mode 100644 storage/usbscsid/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index d024866c9b..f9dd06081e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1594,10 +1594,11 @@ name = "usbscsid" version = "0.1.0" dependencies = [ "base64 0.11.0", + "driver-block", "libredox", "plain", "redox-daemon", - "redox-scheme 0.3.0", + "redox_event", "redox_syscall", "thiserror", "xhcid", diff --git a/storage/usbscsid/Cargo.toml b/storage/usbscsid/Cargo.toml index 7a7f1e3752..5e862aa06c 100644 --- a/storage/usbscsid/Cargo.toml +++ b/storage/usbscsid/Cargo.toml @@ -11,8 +11,9 @@ license = "MIT" base64 = "0.11" # Only for debugging libredox = "0.1.3" plain = "0.2" +driver-block = { path = "../driver-block" } redox-daemon = "0.1" +redox_event = "0.4" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } thiserror = "1" xhcid = { path = "../../xhcid" } diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index a4cb53992a..9950814e7c 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -1,15 +1,15 @@ +use std::collections::BTreeMap; use std::env; -use redox_scheme::{RequestKind, SignalBehavior, Socket}; +use driver_block::{Disk, DiskScheme}; +use syscall::{Error, EIO}; use xhcid_interface::{ConfigureEndpointsReq, XhciClientHandle}; pub mod protocol; pub mod scsi; -mod scheme; - -use scheme::ScsiScheme; -use scsi::Scsi; +use crate::protocol::Protocol; +use crate::scsi::Scsi; fn main() { let mut args = env::args().skip(1); @@ -37,7 +37,7 @@ fn main() { .expect("usbscsid: failed to daemonize"); } fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u8) -> ! { - let disk_scheme_name = format!(":disk.usb-{scheme}+{port}-scsi"); + let disk_scheme_name = format!("disk.usb-{scheme}+{port}-scsi"); // TODO: Use eventfds. let handle = XhciClientHandle::new(scheme.to_owned(), port); @@ -82,38 +82,81 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u // TODO: Let all of the USB drivers fork or be managed externally, and xhcid won't have to keep // track of all the drivers. - let socket_fd = - Socket::create(&disk_scheme_name).expect("usbscsid: failed to create disk scheme"); - - //libredox::call::setrens(0, 0).expect("scsid: failed to enter null namespace"); let mut scsi = Scsi::new(&mut *protocol).expect("usbscsid: failed to setup SCSI"); println!("SCSI initialized"); let mut buffer = [0u8; 512]; scsi.read(&mut *protocol, 0, &mut buffer).unwrap(); println!("DISK CONTENT: {}", base64::encode(&buffer[..])); - let mut scsi_scheme = ScsiScheme::new(&mut scsi, &mut *protocol); + let event_queue = event::EventQueue::new().unwrap(); - // TODO: Use nonblocking and put all pending calls in a todo VecDeque. Use an eventfd as well. - loop { - let req = match socket_fd - .next_request(SignalBehavior::Restart) - .expect("scsid: failed to read disk scheme") - { - Some(r) => { - if let RequestKind::Call(c) = r.kind() { - c - } else { - continue; - } - } - None => break, - }; - let resp = req.handle_scheme(&mut scsi_scheme); - socket_fd - .write_response(resp, SignalBehavior::Restart) - .expect("scsid: failed to write cqe"); + event::user_data! { + enum Event { + Scheme, + } + }; + + let mut scheme = DiskScheme::new( + disk_scheme_name, + BTreeMap::from([( + 0, + UsbDisk { + scsi: &mut scsi, + protocol: &mut *protocol, + }, + )]), + ); + + //libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); + + event_queue + .subscribe( + scheme.event_handle().raw(), + Event::Scheme, + event::EventFlags::READ, + ) + .unwrap(); + + for event in event_queue { + match event.unwrap().user_data { + Event::Scheme => scheme.tick().unwrap(), + } } std::process::exit(0); } + +struct UsbDisk<'a> { + scsi: &'a mut Scsi, + protocol: &'a mut dyn Protocol, +} + +impl Disk for UsbDisk<'_> { + fn block_size(&self) -> u32 { + self.scsi.block_size + } + + fn size(&self) -> u64 { + self.scsi.get_disk_size() + } + + fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + match self.scsi.read(self.protocol, block, buffer) { + Ok(bytes_read) => Ok(Some(bytes_read as usize)), + Err(err) => { + eprintln!("usbscsid: READ IO ERROR: {err}"); + Err(Error::new(EIO)) + } + } + } + + fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + match self.scsi.write(self.protocol, block, buffer) { + Ok(bytes_written) => Ok(Some(bytes_written as usize)), + Err(err) => { + eprintln!("usbscsid: WRITE IO ERROR: {err}"); + Err(Error::new(EIO)) + } + } + } +} diff --git a/storage/usbscsid/src/scheme.rs b/storage/usbscsid/src/scheme.rs deleted file mode 100644 index 4680fb937e..0000000000 --- a/storage/usbscsid/src/scheme.rs +++ /dev/null @@ -1,146 +0,0 @@ -use std::collections::BTreeMap; -use std::str; - -use crate::protocol::Protocol; -use crate::scsi::Scsi; - -use redox_scheme::{CallerCtx, OpenResult, Scheme}; -use syscall::error::{Error, Result}; -use syscall::error::{EACCES, EBADF, EINVAL, EIO, ENOSYS}; -use syscall::flag::{MODE_CHR, MODE_DIR}; -use syscall::flag::{O_DIRECTORY, O_STAT}; -use syscall::schemev2::NewFdFlags; - -// TODO: Only one disk, right? -const LIST_CONTENTS: &'static [u8] = b"0\n"; - -enum Handle { - List, - Disk, - //Partition(usize, u32), -} - -pub struct ScsiScheme<'a> { - scsi: &'a mut Scsi, - protocol: &'a mut dyn Protocol, - handles: BTreeMap, - next_fd: usize, -} - -impl<'a> ScsiScheme<'a> { - pub fn new(scsi: &'a mut Scsi, protocol: &'a mut dyn Protocol) -> Self { - Self { - scsi, - protocol, - handles: BTreeMap::new(), - next_fd: 0, - } - } -} - -impl Scheme for ScsiScheme<'_> { - fn xopen(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result { - if ctx.uid != 0 { - return Err(Error::new(EACCES)); - } - if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { - return Err(Error::new(EACCES)); - } - let path_str = path_str.trim_start_matches('/'); - let handle = if path_str.is_empty() { - // List - Handle::List - } else if let Some(_p_pos) = path_str.chars().position(|c| c == 'p') { - // TODO: Partitions. - return Err(Error::new(ENOSYS)); - } else { - Handle::Disk - }; - self.next_fd += 1; - self.handles.insert(self.next_fd, handle); - Ok(OpenResult::ThisScheme { - number: self.next_fd, - flags: NewFdFlags::POSITIONED, - }) - } - fn fstat(&mut self, fd: usize, stat: &mut syscall::Stat) -> Result { - match self.handles.get(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk => { - stat.st_mode = MODE_CHR; - stat.st_size = self.scsi.get_disk_size(); - stat.st_blksize = self.scsi.block_size; - stat.st_blocks = self.scsi.block_count; - } - Handle::List => { - stat.st_mode = MODE_DIR; - stat.st_size = LIST_CONTENTS.len() as u64; - } - } - Ok(0) - } - fn fpath(&mut self, fd: usize, buf: &mut [u8]) -> Result { - let path = match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk => "0", - Handle::List => "", - } - .as_bytes(); - let min = std::cmp::min(path.len(), buf.len()); - buf[..min].copy_from_slice(&path[..min]); - Ok(min) - } - fn fsize(&mut self, fd: usize) -> Result { - Ok(match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk => self.scsi.get_disk_size(), - Handle::List => LIST_CONTENTS.len() as u64, - }) - } - fn read(&mut self, fd: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk => { - if offset % u64::from(self.scsi.block_size) != 0 - || buf.len() as u64 % u64::from(self.scsi.block_size) != 0 - { - return Err(Error::new(EINVAL)); - } - let lba = offset / u64::from(self.scsi.block_size); - match self.scsi.read(self.protocol, lba, buf) { - Ok(bytes_read) => Ok(bytes_read as usize), - Err(err) => { - eprintln!("usbscsid: READ IO ERROR: {err}"); - Err(Error::new(EIO)) - } - } - } - Handle::List => { - let src = usize::try_from(offset) - .ok() - .and_then(|o| LIST_CONTENTS.get(o..)) - .unwrap_or(&[]); - let min = core::cmp::min(src.len(), buf.len()); - buf[..min].copy_from_slice(&src[..min]); - - Ok(min) - } - } - } - fn write(&mut self, fd: usize, buf: &[u8], offset: u64, _fcntl_flags: u32) -> Result { - match self.handles.get_mut(&fd).ok_or(Error::new(EBADF))? { - Handle::Disk => { - if offset % u64::from(self.scsi.block_size) != 0 - || buf.len() as u64 % u64::from(self.scsi.block_size) != 0 - { - return Err(Error::new(EINVAL)); - } - let lba = offset / u64::from(self.scsi.block_size); - match self.scsi.write(self.protocol, lba, buf) { - Ok(bytes_written) => Ok(bytes_written as usize), - Err(err) => { - eprintln!("usbscsid: WRITE IO ERROR: {err}"); - Err(Error::new(EIO)) - } - } - } - Handle::List => Err(Error::new(EBADF)), - } - } -} diff --git a/storage/usbscsid/src/scsi/mod.rs b/storage/usbscsid/src/scsi/mod.rs index e6364e9c2f..a5350ea67f 100644 --- a/storage/usbscsid/src/scsi/mod.rs +++ b/storage/usbscsid/src/scsi/mod.rs @@ -249,7 +249,7 @@ impl Scsi { pub fn res_read_capacity10(&self) -> &cmds::ReadCapacity10ParamData { plain::from_bytes(&self.data_buffer).unwrap() } - pub fn get_disk_size(&mut self) -> u64 { + pub fn get_disk_size(&self) -> u64 { self.block_count * u64::from(self.block_size) } pub fn read( From 674b8c6724412d227d7de05ac8ab1a0e23345bbf Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 9 Mar 2025 17:03:50 +0100 Subject: [PATCH 1130/1301] xhcid: Fix a bunch of things to make usb storage work configuration_value is not an index into config_descs, so scan for a config_desc with the right configuration_value instead. And fix get_desc getting confused by companion descriptors. --- xhcid/src/lib.rs | 1 - xhcid/src/main.rs | 1 - xhcid/src/xhci/mod.rs | 7 ++++++- xhcid/src/xhci/scheme.rs | 33 +++++++++++++++++---------------- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/xhcid/src/lib.rs b/xhcid/src/lib.rs index e1bfb5e222..771958a18d 100644 --- a/xhcid/src/lib.rs +++ b/xhcid/src/lib.rs @@ -22,7 +22,6 @@ //! - USB2 - [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification) //! - USB32 - [Universal Serial Bus 3.2 Specification Revision 1.1](https://usb.org/document-library/usb-32-revision-11-june-2022) //! -#![warn(missing_docs)] pub extern crate plain; mod driver_interface; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 67bec0174c..69479844be 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -22,7 +22,6 @@ //! - USB2 - [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification) //! - USB32 - [Universal Serial Bus 3.2 Specification Revision 1.1](https://usb.org/document-library/usb-32-revision-11-june-2022) //! -#![warn(missing_docs)] #[macro_use] extern crate bitflags; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index d64a03a0da..a625b77216 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -300,7 +300,12 @@ impl PortState { //TODO: fetch using endpoint number instead fn get_endp_desc(&self, endp_idx: u8) -> Option<&EndpDesc> { let cfg_idx = self.cfg_idx?; - let config_desc = self.dev_desc.as_ref()?.config_descs.get(cfg_idx as usize)?; + let config_desc = self + .dev_desc + .as_ref()? + .config_descs + .iter() + .find(|desc| desc.configuration_value == cfg_idx)?; let mut endp_count = 0; for if_desc in config_desc.interface_descs.iter() { for endp_desc in if_desc.endpoints.iter() { diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index bf4d948ef1..d365c34560 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -918,8 +918,10 @@ impl Xhci { .as_ref() .unwrap() .config_descs - .get(usize::from(req.config_desc)) - .ok_or(Error::new(EBADFD))?; + .iter() + .find(|desc| desc.configuration_value == req.config_desc) + .ok_or(Error::new(EBADFD)) + .unwrap(); //TODO: USE ENDPOINTS FROM ALL INTERFACES let mut endp_desc_count = 0; @@ -1459,7 +1461,7 @@ impl Xhci { } let mut interface_descs = SmallVec::new(); - let mut iter = descriptors.into_iter(); + let mut iter = descriptors.into_iter().peekable(); while let Some(item) = iter.next() { if let AnyDescriptor::Interface(idesc) = item { @@ -1481,21 +1483,20 @@ impl Xhci { }; let mut endp = EndpDesc::from(next); - if supports_superspeed { - let next = match iter.next() { - Some(AnyDescriptor::SuperSpeedCompanion(n)) => n, + loop { + match iter.peek() { + Some(AnyDescriptor::SuperSpeedCompanion(n)) => { + endp.ssc = Some(SuperSpeedCmp::from(n.clone())); + iter.next().unwrap(); + } + Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => { + endp.sspc = Some(SuperSpeedPlusIsochCmp::from(n.clone())); + iter.next().unwrap(); + } _ => break, - }; - endp.ssc = Some(SuperSpeedCmp::from(next)); - - if endp.has_ssp_companion() && supports_superspeedplus { - let next = match iter.next() { - Some(AnyDescriptor::SuperSpeedPlusCompanion(n)) => n, - _ => break, - }; - endp.sspc = Some(SuperSpeedPlusIsochCmp::from(next)); } } + endpoints.push(endp); } @@ -1506,7 +1507,7 @@ impl Xhci { } else { log::warn!("expected interface, got {:?}", item); // TODO - break; + //break; } } From 451480a3e065fd8ff99fe34b291e7c9c28276db0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 13 Mar 2025 08:41:23 -0600 Subject: [PATCH 1131/1301] xhcid: do not panic if unable to find configuration descriptor --- xhcid/src/xhci/scheme.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index d365c34560..82dcc7010b 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -920,8 +920,7 @@ impl Xhci { .config_descs .iter() .find(|desc| desc.configuration_value == req.config_desc) - .ok_or(Error::new(EBADFD)) - .unwrap(); + .ok_or(Error::new(EBADFD))?; //TODO: USE ENDPOINTS FROM ALL INTERFACES let mut endp_desc_count = 0; From 09ef96ae800c9d44e4172c1e430365fd4c9c8354 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 13 Mar 2025 16:40:34 +0100 Subject: [PATCH 1132/1301] graphics/drivers-graphics: Fix some comments and remove no longer necessary feature --- graphics/driver-graphics/Cargo.toml | 2 +- graphics/driver-graphics/src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/graphics/driver-graphics/Cargo.toml b/graphics/driver-graphics/Cargo.toml index a592861035..6ad15add9d 100644 --- a/graphics/driver-graphics/Cargo.toml +++ b/graphics/driver-graphics/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] log = "0.4" redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } -redox_syscall = { version = "0.5", features = ["std"] } +redox_syscall = "0.5" libredox = "0.1.3" common = { path = "../../common" } diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index d3b8fe3777..ac31cdcf12 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -114,7 +114,7 @@ impl GraphicsScheme { std::process::exit(0); } Err(err) if err.errno == EAGAIN => break, - Err(err) => panic!("vesad: failed to read display scheme: {err}"), + Err(err) => panic!("driver-graphics: failed to read display scheme: {err}"), }; match request.kind() { @@ -122,7 +122,7 @@ impl GraphicsScheme { let resp = call_request.handle_scheme(self); self.socket .write_response(resp, SignalBehavior::Restart) - .expect("vesad: failed to write display scheme"); + .expect("driver-graphics: failed to write display scheme"); } RequestKind::SendFd(sendfd_request) => { self.socket.write_response( From f2d3d16455a0de76918324e0c8f78323f18b98c5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 13 Mar 2025 16:42:05 +0100 Subject: [PATCH 1133/1301] graphics/bgad: Use redox-scheme --- Cargo.lock | 1 + graphics/bgad/Cargo.toml | 3 ++- graphics/bgad/src/main.rs | 54 ++++++++++++++++++++++--------------- graphics/bgad/src/scheme.rs | 15 ++++++++--- 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9dd06081e..a324841450 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -193,6 +193,7 @@ dependencies = [ "orbclient", "pcid", "redox-daemon", + "redox-scheme 0.3.0", "redox_syscall", ] diff --git a/graphics/bgad/Cargo.toml b/graphics/bgad/Cargo.toml index eadf2c22f9..19e7d08bb7 100644 --- a/graphics/bgad/Cargo.toml +++ b/graphics/bgad/Cargo.toml @@ -1,11 +1,12 @@ [package] name = "bgad" version = "0.1.0" -edition = "2018" +edition = "2021" [dependencies] orbclient = "0.3.47" redox-daemon = "0.1" +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_syscall = "0.5" common = { path = "../../common" } diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index 72824703ed..b814bc772b 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -1,14 +1,8 @@ -extern crate orbclient; -extern crate syscall; - -use std::fs::File; -use std::io::{Read, Write}; - use inputd::ProducerHandle; use pcid_interface::PciFunctionHandle; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; use syscall::call::iopl; -use syscall::data::Packet; -use syscall::scheme::SchemeMut; +use syscall::EOPNOTSUPP; use crate::bga::Bga; use crate::scheme::BgaScheme; @@ -28,7 +22,7 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { unsafe { iopl(3).unwrap() }; - let mut socket = File::create(":bga").expect("bgad: failed to create bga scheme"); + let socket = Socket::create("bga").expect("bgad: failed to create bga scheme"); let mut bga = Bga::new(); println!(" - BGA {}x{}", bga.width(), bga.height()); @@ -45,20 +39,38 @@ fn main() { daemon.ready().expect("bgad: failed to notify parent"); loop { - let mut packet = Packet::default(); - if socket - .read(&mut packet) - .expect("bgad: failed to read events from bga scheme") - == 0 - { - break; + let Some(request) = socket + .next_request(SignalBehavior::Restart) + .expect("bgad: failed to read scheme") + else { + // Scheme likely got unmounted + std::process::exit(0); + }; + + match request.kind() { + RequestKind::Call(call_request) => { + let resp = call_request.handle_scheme(&mut scheme); + socket + .write_response(resp, SignalBehavior::Restart) + .expect("bgad: failed to write display scheme"); + } + RequestKind::SendFd(sendfd_request) => { + socket + .write_response( + Response::for_sendfd( + &sendfd_request, + Err(syscall::Error::new(EOPNOTSUPP)), + ), + SignalBehavior::Restart, + ) + .expect("bgad: failed to write response"); + } + RequestKind::Cancellation(_cancellation_request) => {} + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() + } } - scheme.handle(&mut packet); - socket - .write(&packet) - .expect("bgad: failed to write responses to bga scheme"); } - std::process::exit(0); }) .expect("bgad: failed to daemonize"); } diff --git a/graphics/bgad/src/scheme.rs b/graphics/bgad/src/scheme.rs index 3d2c89996e..02b197d060 100644 --- a/graphics/bgad/src/scheme.rs +++ b/graphics/bgad/src/scheme.rs @@ -1,7 +1,8 @@ use inputd::ProducerHandle; +use redox_scheme::Scheme; use std::str; use syscall::data::Stat; -use syscall::{Error, Result, SchemeMut, EACCES, EINVAL, MODE_CHR}; +use syscall::{Error, Result, EACCES, EINVAL, MODE_CHR}; use crate::bga::Bga; @@ -24,7 +25,7 @@ impl BgaScheme { } } -impl SchemeMut for BgaScheme { +impl Scheme for BgaScheme { fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result { if uid == 0 { Ok(0) @@ -33,7 +34,13 @@ impl SchemeMut for BgaScheme { } } - fn read(&mut self, _file: usize, buf: &mut [u8]) -> Result { + fn read( + &mut self, + _id: usize, + buf: &mut [u8], + _offset: u64, + _fcntl_flags: u32, + ) -> Result { let mut i = 0; let data = format!("{},{}\n", self.bga.width(), self.bga.height()).into_bytes(); while i < buf.len() && i < data.len() { @@ -43,7 +50,7 @@ impl SchemeMut for BgaScheme { Ok(i) } - fn write(&mut self, _file: usize, buf: &[u8]) -> Result { + fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { let string = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?; let string = string.trim(); From 374e5fbfab486bb422e7124dd99e124a864162dc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 13 Mar 2025 17:00:48 +0100 Subject: [PATCH 1134/1301] xhcid: Use redox-scheme --- Cargo.lock | 1 + xhcid/Cargo.toml | 1 + xhcid/src/main.rs | 59 +++++++------- xhcid/src/xhci/scheme.rs | 162 +++++++++++++++------------------------ 4 files changed, 92 insertions(+), 131 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a324841450..147a51493d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1934,6 +1934,7 @@ dependencies = [ "pcid", "plain", "redox-daemon", + "redox-scheme 0.3.0", "redox_event", "redox_syscall", "regex", diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 865f4d9600..f36753e9e7 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -21,6 +21,7 @@ lazy_static = "1.4" log = "0.4" redox-daemon = "0.1" redox_event = "0.4.1" +redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } redox_syscall = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 69479844be..74e1ef3454 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -26,12 +26,9 @@ extern crate bitflags; use std::fs::File; -use std::io::{Read, Write}; -use std::os::unix::io::{FromRawFd, RawFd}; use std::ptr::NonNull; use std::sync::{Arc, Mutex}; -use libredox::flag; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; @@ -40,9 +37,8 @@ use pcid_interface::{ MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, }; -use syscall::data::Packet; -use syscall::error::EWOULDBLOCK; -use syscall::scheme::Scheme; +use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; +use syscall::EOPNOTSUPP; use crate::xhci::{InterruptMethod, Xhci}; @@ -190,14 +186,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { println!(" + XHCI {}", pci_config.func.display()); let scheme_name = format!("usb.{}", name); - let socket_fd = - libredox::call::open(format!(":{}", scheme_name), flag::O_RDWR | flag::O_CREAT, 0) - .expect("xhcid: failed to create usb scheme"); - let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + let socket = Socket::create(scheme_name.clone()).expect("xhcid: failed to create usb scheme"); daemon.ready().expect("xhcid: failed to notify parent"); - let mut hci = Arc::new( + let hci = Arc::new( Xhci::new(scheme_name, address, interrupt_method, pcid_handle) .expect("xhcid: failed to allocate device"), ); @@ -207,26 +200,34 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { hci.poll(); - let mut todo = Vec::::new(); loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => break, - Ok(_) => (), - Err(err) => panic!("xhcid failed to read from socket: {err}"), - } + let Some(request) = socket + .next_request(SignalBehavior::Restart) + .expect("xhcid: failed to read scheme") + else { + // Scheme likely got unmounted + std::process::exit(0); + }; - let a = packet.a; - hci.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.push(packet); - } else { - socket - .write(&packet) - .expect("xhcid failed to write to socket"); + match request.kind() { + RequestKind::Call(call_request) => { + let resp = call_request.handle_scheme(&mut &*hci); + socket + .write_response(resp, SignalBehavior::Restart) + .expect("xhcid: failed to write scheme"); + } + RequestKind::SendFd(sendfd_request) => { + socket + .write_response( + Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), + SignalBehavior::Restart, + ) + .expect("xhcid: failed to write response"); + } + RequestKind::Cancellation(_cancellation_request) => {} + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() + } } } - - std::process::exit(0); } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 82dcc7010b..1b3944ea15 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -28,7 +28,8 @@ use log::{debug, error, info, trace, warn}; use smallvec::SmallVec; use common::io::Io; -use syscall::scheme::Scheme; +use redox_scheme::{CallerCtx, OpenResult, Scheme}; +use syscall::schemev2::NewFdFlags; use syscall::{ Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, ENOTDIR, EPROTO, ESPIPE, MODE_CHR, MODE_DIR, MODE_FILE, O_DIRECTORY, O_RDWR, O_STAT, O_WRONLY, @@ -97,7 +98,7 @@ pub enum EndpointHandleTy { Ctl, /// portX/endpoints/Y/ - Root(usize, Vec), // offset, content + Root(Vec), // content } #[derive(Clone, Copy, Debug)] @@ -122,13 +123,13 @@ pub enum PortReqState { /// Contains some information about the data requested via the handle. #[derive(Debug)] pub enum Handle { - TopLevel(usize, Vec), // offset, contents (ports) - Port(usize, usize, Vec), // port, offset, contents - PortDesc(usize, usize, Vec), // port, offset, contents - PortState(usize, usize), // port, offset + TopLevel(Vec), // contents (ports) + Port(usize, Vec), // port, contents + PortDesc(usize, Vec), // port, contents + PortState(usize), // port PortReq(usize, PortReqState), // port, state - Endpoints(usize, usize, Vec), // port, offset, contents - Endpoint(usize, u8, EndpointHandleTy), // port, endpoint, offset, state + Endpoints(usize, Vec), // port, contents + Endpoint(usize, u8, EndpointHandleTy), // port, endpoint, state ConfigureEndpoints(usize), // port } @@ -181,20 +182,20 @@ impl Handle { /// - A [String] containing the scheme path that the handle is associated with. pub(crate) fn to_scheme(&self) -> String { match self { - Handle::TopLevel(_, _) => String::from(""), - Handle::Port(port_num, _, _) => { + Handle::TopLevel(_) => String::from(""), + Handle::Port(port_num, _) => { format!("port{}", port_num) } - Handle::PortDesc(port_num, _, _) => { + Handle::PortDesc(port_num, _) => { format!("port{}/descriptors", port_num) } - Handle::PortState(port_num, _) => { + Handle::PortState(port_num) => { format!("port{}/state", port_num) } Handle::PortReq(port_num, _) => { format!("port{}/request", port_num) } - Handle::Endpoints(port_num, _, _) => { + Handle::Endpoints(port_num, _) => { format!("port{}/endpoints", port_num) } Handle::Endpoint(port_num, endpoint_num, handle_type) => match handle_type { @@ -204,7 +205,7 @@ impl Handle { EndpointHandleTy::Ctl => { format!("port{}/endpoints/{}/ctl", port_num, endpoint_num) } - EndpointHandleTy::Root(_, _) => { + EndpointHandleTy::Root(_) => { format!("port{}/endpoints/{}", port_num, endpoint_num) } }, @@ -224,21 +225,21 @@ impl Handle { /// - [HandleType] - The access mode associated with the handle. pub(crate) fn get_handle_type(&self) -> HandleType { match self { - &Handle::TopLevel(_, _) => HandleType::Directory, - &Handle::Port(_, _, _) => HandleType::Directory, - &Handle::Endpoints(_, _, _) => HandleType::Directory, - &Handle::PortDesc(_, _, _) => HandleType::File, + &Handle::TopLevel(_) => HandleType::Directory, + &Handle::Port(_, _) => HandleType::Directory, + &Handle::Endpoints(_, _) => HandleType::Directory, + &Handle::PortDesc(_, _) => HandleType::File, &Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(_, _)) => HandleType::Character, &Handle::PortReq(_, PortReqState::WaitingForHostBytes(_, _)) => HandleType::Character, &Handle::PortReq(_, PortReqState::Tmp) => unreachable!(), &Handle::PortReq(_, PortReqState::TmpSetup(_)) => unreachable!(), - &Handle::PortState(_, _) => HandleType::Character, + &Handle::PortState(_) => HandleType::Character, &Handle::PortReq(_, _) => HandleType::Character, &Handle::ConfigureEndpoints(_) => HandleType::Character, &Handle::Endpoint(_, _, ref st) => match st { EndpointHandleTy::Data => HandleType::Character, EndpointHandleTy::Ctl => HandleType::Character, - EndpointHandleTy::Root(_, _) => HandleType::Directory, + EndpointHandleTy::Root(_) => HandleType::Directory, }, } } @@ -252,21 +253,21 @@ impl Handle { /// Either the size of the buffer, or [Option::None] if the buffer does not exist. pub(crate) fn get_buf_len(&self) -> Option { match self { - &Handle::TopLevel(_, ref buf) => Some(buf.len()), - &Handle::Port(_, _, ref buf) => Some(buf.len()), - &Handle::Endpoints(_, _, ref buf) => Some(buf.len()), - &Handle::PortDesc(_, _, ref buf) => Some(buf.len()), + &Handle::TopLevel(ref buf) => Some(buf.len()), + &Handle::Port(_, ref buf) => Some(buf.len()), + &Handle::Endpoints(_, ref buf) => Some(buf.len()), + &Handle::PortDesc(_, ref buf) => Some(buf.len()), &Handle::PortReq(_, PortReqState::WaitingForDeviceBytes(ref buf, _)) => Some(buf.len()), &Handle::PortReq(_, PortReqState::WaitingForHostBytes(ref buf, _)) => Some(buf.len()), &Handle::PortReq(_, PortReqState::Tmp) => None, &Handle::PortReq(_, PortReqState::TmpSetup(_)) => None, - &Handle::PortState(_, _) => None, + &Handle::PortState(_) => None, &Handle::PortReq(_, _) => None, &Handle::ConfigureEndpoints(_) => None, &Handle::Endpoint(_, _, ref st) => match st { EndpointHandleTy::Data => None, EndpointHandleTy::Ctl => None, - EndpointHandleTy::Root(_, ref buf) => Some(buf.len()), + EndpointHandleTy::Root(ref buf) => Some(buf.len()), }, } } @@ -1551,13 +1552,11 @@ impl Xhci { .dev_desc; serde_json::to_vec(dev_desc).or(Err(Error::new(EIO))) } - fn write_dyn_string(string: &[u8], buf: &mut [u8], offset: &mut usize) -> usize { + fn write_dyn_string(string: &[u8], buf: &mut [u8], offset: usize) -> usize { let max_bytes_to_read = cmp::min(string.len(), buf.len()); - let bytes_to_read = cmp::max(*offset, max_bytes_to_read) - *offset; + let bytes_to_read = cmp::max(offset, max_bytes_to_read) - offset; buf[..bytes_to_read].copy_from_slice(&string[..bytes_to_read]); - *offset += bytes_to_read; - bytes_to_read } async fn port_req_transfer( @@ -1735,7 +1734,7 @@ impl Xhci { write!(contents, "port{}\n", index).unwrap(); } - Ok(Handle::TopLevel(0, contents)) + Ok(Handle::TopLevel(contents)) } else { Err(Error::new(EISDIR)) } @@ -1758,7 +1757,7 @@ impl Xhci { } let contents = self.port_desc_json(port_num)?; - Ok(Handle::PortDesc(port_num, 0, contents)) + Ok(Handle::PortDesc(port_num, contents)) } /// implements open() for /port @@ -1792,7 +1791,7 @@ impl Xhci { write!(contents, "configure\n").unwrap(); } - Ok(Handle::Port(port_num, 0, contents)) + Ok(Handle::Port(port_num, contents)) } else { Err(Error::new(EISDIR)) } @@ -1814,7 +1813,7 @@ impl Xhci { return Err(Error::new(ENOTDIR)); } - Ok(Handle::PortState(port_num, 0)) + Ok(Handle::PortState(port_num)) } /// implements open() for /port/endpoints @@ -1843,7 +1842,7 @@ impl Xhci { write!(contents, "{}\n", ep_num).unwrap(); } - Ok(Handle::Endpoints(port_num, 0, contents)) + Ok(Handle::Endpoints(port_num, contents)) } /// implements open() for /port/endpoints/ @@ -1886,7 +1885,7 @@ impl Xhci { Ok(Handle::Endpoint( port_num, endpoint_num, - EndpointHandleTy::Root(0, contents), + EndpointHandleTy::Root(contents), )) } @@ -1983,9 +1982,9 @@ impl Xhci { } } -impl Scheme for Xhci { - fn open(&self, path_str: &str, flags: usize, uid: u32, _gid: u32) -> Result { - if uid != 0 { +impl Scheme for &Xhci { + fn xopen(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result { + if ctx.uid != 0 { return Err(Error::new(EACCES)); } @@ -2025,11 +2024,14 @@ impl Scheme for Xhci { self.handles.insert(fd, handle); - Ok(fd) + Ok(OpenResult::ThisScheme { + number: fd, + flags: NewFdFlags::POSITIONED, + }) } - fn fstat(&self, id: usize, stat: &mut Stat) -> Result { - let mut guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; + fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { + let guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; stat.st_mode = match (&*guard).get_handle_type() { HandleType::Directory => MODE_DIR, @@ -2043,14 +2045,14 @@ impl Scheme for Xhci { }; //If we have a handle to the configure scheme, we need to mark it as write only. - if let &Handle::ConfigureEndpoints(_) = (&*guard) { + if let &Handle::ConfigureEndpoints(_) = &*guard { stat.st_mode = stat.st_mode | 0o200; } Ok(0) } - fn fpath(&self, fd: usize, buffer: &mut [u8]) -> Result { + fn fpath(&mut self, fd: usize, buffer: &mut [u8]) -> Result { let mut cursor = io::Cursor::new(buffer); let guard = self.handles.get(&fd).ok_or(Error::new(EBADF))?; @@ -2068,51 +2070,8 @@ impl Scheme for Xhci { Ok(src_len) } - fn seek(&self, fd: usize, pos: isize, whence: usize) -> Result { - let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; - - trace!( - "SEEK fd={}, handle={:?}, pos {}, whence {}", - fd, - guard, - pos, - whence - ); - - match &mut *guard { - // Directories, or fixed files - Handle::TopLevel(ref mut offset, ref buf) - | Handle::Port(_, ref mut offset, ref buf) - | Handle::PortDesc(_, ref mut offset, ref buf) - | Handle::Endpoints(_, ref mut offset, ref buf) - | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref buf)) => { - let max = buf.len() as isize; - *offset = match whence { - SEEK_SET => cmp::max(0, cmp::min(pos, max)), - SEEK_CUR => cmp::max(0, cmp::min(*offset as isize + pos, max)), - SEEK_END => cmp::max(0, cmp::min(max + pos, max)), - _ => return Err(Error::new(EINVAL)), - } as usize; - Ok(*offset as isize) - } - Handle::PortState(_, ref mut offset) => { - match whence { - //TODO: checks for invalid pos - SEEK_SET => *offset = pos as usize, - SEEK_CUR => *offset = pos as usize, - SEEK_END => *offset = pos as usize, - _ => return Err(Error::new(EINVAL)), - }; - Ok(*offset as isize) - } - // Write-once configure or transfer - Handle::Endpoint(_, _, _) | Handle::ConfigureEndpoints(_) | Handle::PortReq(_, _) => { - Err(Error::new(ESPIPE)) - } - } - } - - fn read(&self, fd: usize, buf: &mut [u8]) -> Result { + fn read(&mut self, fd: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result { + let offset = offset as usize; let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; trace!( "READ fd={}, handle={:?}, buf=(addr {:p}, length {})", @@ -2122,16 +2081,15 @@ impl Scheme for Xhci { buf.len() ); match &mut *guard { - Handle::TopLevel(ref mut offset, ref src_buf) - | Handle::Port(_, ref mut offset, ref src_buf) - | Handle::PortDesc(_, ref mut offset, ref src_buf) - | Handle::Endpoints(_, ref mut offset, ref src_buf) - | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref mut offset, ref src_buf)) => { + Handle::TopLevel(ref src_buf) + | Handle::Port(_, ref src_buf) + | Handle::PortDesc(_, ref src_buf) + | Handle::Endpoints(_, ref src_buf) + | Handle::Endpoint(_, _, EndpointHandleTy::Root(ref src_buf)) => { let max_bytes_to_read = cmp::min(src_buf.len(), buf.len()); - let bytes_to_read = cmp::max(max_bytes_to_read, *offset) - *offset; + let bytes_to_read = cmp::max(max_bytes_to_read, offset) - offset; buf[..bytes_to_read].copy_from_slice(&src_buf[..bytes_to_read]); - *offset += bytes_to_read; Ok(bytes_to_read) } @@ -2140,9 +2098,9 @@ impl Scheme for Xhci { &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { EndpointHandleTy::Ctl => self.on_read_endp_ctl(port_num, endp_num, buf), EndpointHandleTy::Data => block_on(self.on_read_endp_data(port_num, endp_num, buf)), - EndpointHandleTy::Root(_, _) => Err(Error::new(EBADF)), + EndpointHandleTy::Root(_) => Err(Error::new(EBADF)), }, - &mut Handle::PortState(port_num, ref mut offset) => { + &mut Handle::PortState(port_num) => { let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?; let state = self .dev_ctx @@ -2164,7 +2122,7 @@ impl Scheme for Xhci { .unwrap_or("unknown") .as_bytes(); - Ok(Self::write_dyn_string(string, buf, offset)) + Ok(Xhci::write_dyn_string(string, buf, offset)) } &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); @@ -2173,7 +2131,7 @@ impl Scheme for Xhci { } } } - fn write(&self, fd: usize, buf: &[u8]) -> Result { + fn write(&mut self, fd: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; trace!( "WRITE fd={}, handle={:?}, buf=(addr {:p}, length {})", @@ -2193,7 +2151,7 @@ impl Scheme for Xhci { EndpointHandleTy::Data => { block_on(self.on_write_endp_data(port_num, endp_num, buf)) } - EndpointHandleTy::Root(_, _) => return Err(Error::new(EBADF)), + EndpointHandleTy::Root(_) => return Err(Error::new(EBADF)), }, &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); @@ -2205,7 +2163,7 @@ impl Scheme for Xhci { _ => Err(Error::new(EBADF)), } } - fn close(&self, fd: usize) -> Result { + fn close(&mut self, fd: usize) -> Result { if self.handles.remove(&fd).is_none() { return Err(Error::new(EBADF)); } From c627024cd6099a9749ddcdaa39ce0b944dc404d8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 13 Mar 2025 17:22:20 +0100 Subject: [PATCH 1135/1301] inputd: Avoid usage of legacy scheme path format --- inputd/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inputd/src/main.rs b/inputd/src/main.rs index d98fe35dd5..e8cb36a138 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -219,7 +219,7 @@ impl Scheme for InputScheme { if let Handle::Consumer { vt, .. } = handle { let display = self.display.as_ref().ok_or(SysError::new(EINVAL))?; - let vt = format!("{}:{vt}", display); + let vt = format!("/scheme/{}/{vt}", display); let size = core::cmp::min(vt.len(), buf.len()); buf[..size].copy_from_slice(&vt.as_bytes()[..size]); From 7bb1693e86233e4f87ce28a952c2ceebb5341418 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 13 Mar 2025 19:04:28 +0100 Subject: [PATCH 1136/1301] graphics/graphics-ipc: Fix Damage::clip --- graphics/graphics-ipc/src/v1.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/graphics/graphics-ipc/src/v1.rs b/graphics/graphics-ipc/src/v1.rs index 39226f2b31..ddebae9c1a 100644 --- a/graphics/graphics-ipc/src/v1.rs +++ b/graphics/graphics-ipc/src/v1.rs @@ -126,13 +126,16 @@ impl Damage { #[must_use] pub fn clip(mut self, width: u32, height: u32) -> Self { // Clip damage + let x2 = self.x + self.width; self.x = cmp::min(self.x, width); - if self.x + self.width > width { - self.width -= cmp::min(self.width, width - self.x); + if x2 > width { + self.width = width - self.x; } + + let y2 = self.y + self.height; self.y = cmp::min(self.y, height); - if self.y + self.height > height { - self.height = cmp::min(self.height, height - self.y); + if y2 > height { + self.height = height - self.y; } self } From d5692c28559a118c9fc0436bfd4d7617bd885ee6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 13 Mar 2025 19:19:41 +0100 Subject: [PATCH 1137/1301] Remove pcspkrd The PC speaker device is not a general purpose audio device, but only capable of playing beeps. While pcspkrd does currently get built, it never actually gets started at startup. There is also no program anywhere inside Redox OS capable of playing any sound through pcspkrd. And finally basically the thing it is used for on modern systems is to emit a beep when pressing backspace in a VT while there is no input buffered. I personally find that beep rather annoying and have disabled the Linux counterpart to pcspkrd on my system because of this. --- Cargo.lock | 10 ----- Cargo.toml | 1 - README.md | 1 - audio/pcspkrd/Cargo.toml | 11 ----- audio/pcspkrd/src/main.rs | 46 -------------------- audio/pcspkrd/src/pcspkr.rs | 35 --------------- audio/pcspkrd/src/scheme.rs | 87 ------------------------------------- 7 files changed, 191 deletions(-) delete mode 100644 audio/pcspkrd/Cargo.toml delete mode 100644 audio/pcspkrd/src/main.rs delete mode 100644 audio/pcspkrd/src/pcspkr.rs delete mode 100644 audio/pcspkrd/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index 147a51493d..d7cd2c0362 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -984,16 +984,6 @@ dependencies = [ "toml 0.5.11", ] -[[package]] -name = "pcspkrd" -version = "0.1.0" -dependencies = [ - "common", - "libredox", - "redox-daemon", - "redox_syscall", -] - [[package]] name = "pico-args" version = "0.5.0" diff --git a/Cargo.toml b/Cargo.toml index 62d4865e02..14dd17de9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,6 @@ members = [ "audio/ac97d", "audio/ihdad", - "audio/pcspkrd", "audio/sb16d", "graphics/bgad", diff --git a/README.md b/README.md index 41a8b5fff7..682cd06b74 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ This document covers the driver details. - ixgbed - Intel 10 Gigabit ethernet - nvmed - NVMe interface - pcid - PCI interface with extensions for PCI Express -- pcspkrd - PC speaker - ps2d - PS/2 interface - rtl8139d - Realtek ethernet - rtl8168d - Realtek ethernet diff --git a/audio/pcspkrd/Cargo.toml b/audio/pcspkrd/Cargo.toml deleted file mode 100644 index 555c25f566..0000000000 --- a/audio/pcspkrd/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "pcspkrd" -version = "0.1.0" -authors = ["Tibor Nagy "] -edition = "2018" - -[dependencies] -common = { path = "../../common" } -redox_syscall = "0.5" -redox-daemon = "0.1" -libredox = "0.1.3" diff --git a/audio/pcspkrd/src/main.rs b/audio/pcspkrd/src/main.rs deleted file mode 100644 index d021257710..0000000000 --- a/audio/pcspkrd/src/main.rs +++ /dev/null @@ -1,46 +0,0 @@ -mod pcspkr; -mod scheme; - -use std::fs::File; -use std::io::{Read, Write}; - -use syscall::call::iopl; -use syscall::data::Packet; -use syscall::scheme::SchemeMut; - -use redox_daemon::Daemon; - -use self::pcspkr::Pcspkr; -use self::scheme::PcspkrScheme; - -fn main() { - Daemon::new(move |daemon| { - unsafe { iopl(3).unwrap() }; - - let mut socket = File::create(":pcspkr").expect("pcspkrd: failed to create pcspkr scheme"); - daemon.ready().expect("failed to notify parent"); - - let pcspkr = Pcspkr::new(); - println!(" + pcspkr"); - - let mut scheme = PcspkrScheme { - pcspkr, - handle: None, - next_id: 0, - }; - - libredox::call::setrens(0, 0).expect("pcspkrd: failed to enter null namespace"); - - loop { - let mut packet = Packet::default(); - socket - .read(&mut packet) - .expect("pcspkrd: failed to read events from pcspkr scheme"); - scheme.handle(&mut packet); - socket - .write(&packet) - .expect("pcspkrd: failed to write responses to pcspkr scheme"); - } - }) - .expect("pcspkrd: failed to daemonize"); -} diff --git a/audio/pcspkrd/src/pcspkr.rs b/audio/pcspkrd/src/pcspkr.rs deleted file mode 100644 index 945421c2eb..0000000000 --- a/audio/pcspkrd/src/pcspkr.rs +++ /dev/null @@ -1,35 +0,0 @@ -use common::io::{Io, Pio}; - -pub struct Pcspkr { - command: Pio, - channel: Pio, - gate: Pio, -} - -const PIT_FREQUENCY: usize = 0x1234DC; - -impl Pcspkr { - pub fn new() -> Pcspkr { - Pcspkr { - command: Pio::new(0x43), - channel: Pio::new(0x42), - gate: Pio::new(0x61), - } - } - - pub fn set_frequency(&mut self, frequency: usize) { - let div = PIT_FREQUENCY.checked_div(frequency).unwrap_or(0); - self.command.write(0xB6); - self.channel.write((div & 0xFF) as u8); - self.channel.write(((div >> 8) & 0xFF) as u8); - } - - pub fn set_gate(&mut self, state: bool) { - let gate_value = self.gate.read(); - if state { - self.gate.write(gate_value | 0x03); - } else { - self.gate.write(gate_value & 0xFC); - } - } -} diff --git a/audio/pcspkrd/src/scheme.rs b/audio/pcspkrd/src/scheme.rs deleted file mode 100644 index 2cb21fc51a..0000000000 --- a/audio/pcspkrd/src/scheme.rs +++ /dev/null @@ -1,87 +0,0 @@ -use syscall::data::Stat; -use syscall::{ - Error, Result, SchemeMut, EBUSY, EINVAL, EPERM, MODE_CHR, O_ACCMODE, O_STAT, O_WRONLY, -}; - -use crate::pcspkr::Pcspkr; - -pub struct PcspkrScheme { - pub pcspkr: Pcspkr, - pub handle: Option, - pub next_id: usize, -} - -impl SchemeMut for PcspkrScheme { - fn open(&mut self, _path: &str, flags: usize, _uid: u32, _gid: u32) -> Result { - if (flags & O_ACCMODE == 0) && (flags & O_STAT == O_STAT) { - Ok(0) - } else if flags & O_ACCMODE == O_WRONLY { - if self.handle.is_none() { - self.next_id += 1; - self.handle = Some(self.next_id); - Ok(self.next_id) - } else { - Err(Error::new(EBUSY)) - } - } else { - Err(Error::new(EINVAL)) - } - } - - fn read(&mut self, _id: usize, _buf: &mut [u8]) -> Result { - Err(Error::new(EPERM)) - } - - fn write(&mut self, id: usize, buf: &[u8]) -> Result { - if self.handle != Some(id) { - return Err(Error::new(EINVAL)); - } - - if buf.len() != 2 { - return Err(Error::new(EINVAL)); - } - - let frequency = buf[0] as usize + ((buf[1] as usize) << 8); - - if frequency == 0 { - self.pcspkr.set_gate(false); - } else { - self.pcspkr.set_frequency(frequency); - self.pcspkr.set_gate(true); - } - - Ok(buf.len()) - } - - fn fpath(&mut self, _id: usize, buf: &mut [u8]) -> Result { - let mut i = 0; - let scheme_path = b"pcspkr"; - while i < buf.len() && i < scheme_path.len() { - buf[i] = scheme_path[i]; - i += 1; - } - Ok(i) - } - - fn fstat(&mut self, _id: usize, stat: &mut Stat) -> Result { - *stat = Stat { - st_mode: MODE_CHR | 0o222, - ..Default::default() - }; - - Ok(0) - } - - fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize) -> Result { - Ok(0) - } - - fn close(&mut self, id: usize) -> Result { - if self.handle == Some(id) { - self.pcspkr.set_gate(false); - self.handle = None; - } - - Ok(0) - } -} From 5d76acfd745aaae8279cbe780822ac44da5bad71 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 14 Mar 2025 21:32:39 +0100 Subject: [PATCH 1138/1301] Update to redox-scheme 0.4 --- Cargo.lock | 29 +++++++++---------------- acpid/Cargo.toml | 2 +- acpid/src/main.rs | 26 ++++++++++++----------- acpid/src/scheme.rs | 10 ++++----- graphics/bgad/Cargo.toml | 2 +- graphics/bgad/src/main.rs | 32 +++++++++------------------- graphics/bgad/src/scheme.rs | 8 +++---- graphics/driver-graphics/Cargo.toml | 2 +- graphics/driver-graphics/src/lib.rs | 33 ++++++++++++----------------- graphics/fbbootlogd/Cargo.toml | 2 +- graphics/fbbootlogd/src/main.rs | 28 ++++++++---------------- graphics/fbbootlogd/src/scheme.rs | 8 +++---- graphics/fbcond/Cargo.toml | 2 +- graphics/fbcond/src/main.rs | 18 ++++------------ graphics/fbcond/src/scheme.rs | 7 +++--- inputd/Cargo.toml | 2 +- inputd/src/main.rs | 23 +++++++++----------- net/driver-network/Cargo.toml | 2 +- net/driver-network/src/lib.rs | 19 ++++++----------- storage/driver-block/Cargo.toml | 2 +- storage/driver-block/src/lib.rs | 26 +++++++++-------------- xhcid/Cargo.toml | 2 +- xhcid/src/main.rs | 17 ++++----------- xhcid/src/xhci/scheme.rs | 10 ++++----- 24 files changed, 121 insertions(+), 191 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d7cd2c0362..476cf221e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,7 +32,7 @@ dependencies = [ "parking_lot 0.12.3", "plain", "redox-daemon", - "redox-scheme 0.3.0", + "redox-scheme", "redox_event", "redox_syscall", "ron", @@ -193,7 +193,7 @@ dependencies = [ "orbclient", "pcid", "redox-daemon", - "redox-scheme 0.3.0", + "redox-scheme", "redox_syscall", ] @@ -393,7 +393,7 @@ version = "0.1.0" dependencies = [ "libredox", "partitionlib", - "redox-scheme 0.3.0", + "redox-scheme", "redox_syscall", ] @@ -406,7 +406,7 @@ dependencies = [ "inputd", "libredox", "log", - "redox-scheme 0.3.0", + "redox-scheme", "redox_syscall", ] @@ -415,7 +415,7 @@ name = "driver-network" version = "0.1.0" dependencies = [ "libredox", - "redox-scheme 0.3.0", + "redox-scheme", "redox_syscall", ] @@ -450,7 +450,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox-scheme 0.3.0", + "redox-scheme", "redox_event", "redox_syscall", ] @@ -466,7 +466,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox-scheme 0.3.0", + "redox-scheme", "redox_event", "redox_syscall", ] @@ -720,7 +720,7 @@ dependencies = [ "log", "orbclient", "redox-daemon", - "redox-scheme 0.3.0", + "redox-scheme", "redox_syscall", ] @@ -965,7 +965,7 @@ dependencies = [ "pico-args", "plain", "redox-daemon", - "redox-scheme 0.4.0", + "redox-scheme", "redox_syscall", "serde", ] @@ -1115,15 +1115,6 @@ dependencies = [ "termion", ] -[[package]] -name = "redox-scheme" -version = "0.3.0" -source = "git+https://gitlab.redox-os.org/redox-os/redox-scheme.git#d2bfa80a1072facb2662d0bc73656247f0b254b4" -dependencies = [ - "libredox", - "redox_syscall", -] - [[package]] name = "redox-scheme" version = "0.4.0" @@ -1924,7 +1915,7 @@ dependencies = [ "pcid", "plain", "redox-daemon", - "redox-scheme 0.3.0", + "redox-scheme", "redox_event", "redox_syscall", "regex", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index cf55061667..a7ee63043c 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -23,5 +23,5 @@ ron = "0.8.1" amlserde = { path = "../amlserde" } common = { path = "../common" } libredox = "0.1.3" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox-scheme = "0.4" arrayvec = "0.7.6" diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 0b846b54b7..acae764017 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -91,18 +91,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { if event.fd == socket.inner().raw() { loop { - let sqe = match socket.next_request(SignalBehavior::Interrupt) { + let req = match socket.next_request(SignalBehavior::Interrupt) { Ok(None) => { mounted = false; break; } - Ok(Some(s)) => { - if let RequestKind::Call(call) = s.kind() { - call - } else { - continue; - } - } + Ok(Some(req)) => req, Err(err) => { if err.errno == EWOULDBLOCK || err.errno == EAGAIN { break; @@ -112,10 +106,18 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } }; - let response = sqe.handle_scheme(&mut scheme); - socket - .write_response(response, SignalBehavior::Restart) - .expect("acpid: failed to write response"); + match req.kind() { + RequestKind::Call(call) => { + let response = call.handle_scheme(&mut scheme); + socket + .write_response(response, SignalBehavior::Restart) + .expect("acpid: failed to write response"); + } + RequestKind::OnClose { id } => { + scheme.on_close(id); + } + _ => (), + } } } else if event.fd == shutdown_pipe.as_raw_fd() as usize { log::info!("Received shutdown request from kernel."); diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index 19ab3d7454..a380a33dca 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -343,12 +343,10 @@ impl Scheme for AcpiScheme<'_> { fn write(&mut self, _id: usize, _buf: &[u8], _offset: u64, _fcntl: u32) -> Result { Err(Error::new(EBADF)) } +} - fn close(&mut self, id: usize) -> Result { - if self.handles.remove(&id).is_none() { - return Err(Error::new(EBADF)); - } - - Ok(0) +impl AcpiScheme<'_> { + pub fn on_close(&mut self, id: usize) { + self.handles.remove(&id); } } diff --git a/graphics/bgad/Cargo.toml b/graphics/bgad/Cargo.toml index 19e7d08bb7..894f414377 100644 --- a/graphics/bgad/Cargo.toml +++ b/graphics/bgad/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] orbclient = "0.3.47" redox-daemon = "0.1" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox-scheme = "0.4" redox_syscall = "0.5" common = { path = "../../common" } diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index b814bc772b..9fde996ac2 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -1,8 +1,7 @@ use inputd::ProducerHandle; use pcid_interface::PciFunctionHandle; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; +use redox_scheme::{RequestKind, SignalBehavior, Socket}; use syscall::call::iopl; -use syscall::EOPNOTSUPP; use crate::bga::Bga; use crate::scheme::BgaScheme; @@ -41,34 +40,23 @@ fn main() { loop { let Some(request) = socket .next_request(SignalBehavior::Restart) - .expect("bgad: failed to read scheme") + .expect("bgad: failed to get next scheme request") else { // Scheme likely got unmounted std::process::exit(0); }; - match request.kind() { - RequestKind::Call(call_request) => { - let resp = call_request.handle_scheme(&mut scheme); + RequestKind::Call(call) => { + let response = call.handle_scheme(&mut scheme); + socket - .write_response(resp, SignalBehavior::Restart) - .expect("bgad: failed to write display scheme"); + .write_responses(&[response], SignalBehavior::Restart) + .expect("bgad: failed to write next scheme response"); } - RequestKind::SendFd(sendfd_request) => { - socket - .write_response( - Response::for_sendfd( - &sendfd_request, - Err(syscall::Error::new(EOPNOTSUPP)), - ), - SignalBehavior::Restart, - ) - .expect("bgad: failed to write response"); - } - RequestKind::Cancellation(_cancellation_request) => {} - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { - unreachable!() + RequestKind::OnClose { id } => { + scheme.on_close(id); } + _ => (), } } }) diff --git a/graphics/bgad/src/scheme.rs b/graphics/bgad/src/scheme.rs index 02b197d060..14ad5a6cb9 100644 --- a/graphics/bgad/src/scheme.rs +++ b/graphics/bgad/src/scheme.rs @@ -97,8 +97,8 @@ impl Scheme for BgaScheme { fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize) -> Result { Ok(0) } - - fn close(&mut self, _file: usize) -> Result { - Ok(0) - } +} + +impl BgaScheme { + pub fn on_close(&mut self, _id: usize) {} } diff --git a/graphics/driver-graphics/Cargo.toml b/graphics/driver-graphics/Cargo.toml index 6ad15add9d..a1525e23f2 100644 --- a/graphics/driver-graphics/Cargo.toml +++ b/graphics/driver-graphics/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] log = "0.4" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox-scheme = "0.4" redox_syscall = "0.5" libredox = "0.1.3" diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index ac31cdcf12..cfe0089928 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -3,9 +3,8 @@ use std::io; use graphics_ipc::v1::Damage; use inputd::{VtEvent, VtEventKind}; -use libredox::errno::EOPNOTSUPP; use libredox::Fd; -use redox_scheme::{RequestKind, Response, Scheme, SignalBehavior, Socket}; +use redox_scheme::{RequestKind, Scheme, SignalBehavior, Socket}; use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL}; pub trait GraphicsAdapter { @@ -118,22 +117,16 @@ impl GraphicsScheme { }; match request.kind() { - RequestKind::Call(call_request) => { - let resp = call_request.handle_scheme(self); + RequestKind::Call(call) => { + let response = call.handle_scheme(self); self.socket - .write_response(resp, SignalBehavior::Restart) - .expect("driver-graphics: failed to write display scheme"); + .write_response(response, SignalBehavior::Restart) + .expect("driver-graphics: failed to write response"); } - RequestKind::SendFd(sendfd_request) => { - self.socket.write_response( - Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), - SignalBehavior::Restart, - )?; - } - RequestKind::Cancellation(_cancellation_request) => {} - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { - unreachable!() + RequestKind::OnClose { id } => { + self.on_close(id); } + _ => (), } } @@ -246,10 +239,6 @@ impl Scheme for GraphicsScheme { Ok(buf.len()) } - fn close(&mut self, id: usize) -> syscall::Result { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(0) - } fn mmap_prep( &mut self, id: usize, @@ -265,3 +254,9 @@ impl Scheme for GraphicsScheme { Ok(ptr as usize) } } + +impl GraphicsScheme { + fn on_close(&mut self, id: usize) { + self.handles.remove(&id); + } +} diff --git a/graphics/fbbootlogd/Cargo.toml b/graphics/fbbootlogd/Cargo.toml index b05978513e..a4707c8640 100644 --- a/graphics/fbbootlogd/Cargo.toml +++ b/graphics/fbbootlogd/Cargo.toml @@ -9,7 +9,7 @@ ransid = "0.4" redox_event = "0.4" redox_syscall = "0.5" redox-daemon = "0.1" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox-scheme = "0.4" console-draw = { path = "../console-draw" } graphics-ipc = { path = "../graphics-ipc" } diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index 8584718c5d..1b0d941362 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -9,8 +9,7 @@ //! to get new input. Fbbootlogd does all blocking operations in background threads such that the //! main thread will always keep accepting new input and writing it to the framebuffer. -use libredox::errno::EOPNOTSUPP; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; +use redox_scheme::{RequestKind, SignalBehavior, Socket}; use crate::scheme::FbbootlogScheme; @@ -45,26 +44,17 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { }; match request.kind() { - RequestKind::Call(call_request) => { + RequestKind::Call(call) => { + let response = call.handle_scheme(&mut scheme); + socket - .write_response( - call_request.handle_scheme(&mut scheme), - SignalBehavior::Restart, - ) - .expect("fbbootlogd: failed to write display scheme"); + .write_responses(&[response], SignalBehavior::Restart) + .expect("pcid: failed to write next scheme response"); } - RequestKind::SendFd(sendfd_request) => { - socket - .write_response( - Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), - SignalBehavior::Restart, - ) - .expect("fbbootlogd: failed to write scheme"); - } - RequestKind::Cancellation(_cancellation_request) => {} - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { - unreachable!() + RequestKind::OnClose { id } => { + scheme.on_close(id); } + _ => (), } } } diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 1cf0adb5c3..9fa087f0fa 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -73,8 +73,8 @@ impl Scheme for FbbootlogScheme { Ok(buf.len()) } - - fn close(&mut self, _id: usize) -> Result { - Ok(0) - } +} + +impl FbbootlogScheme { + pub fn on_close(&mut self, _id: usize) {} } diff --git a/graphics/fbcond/Cargo.toml b/graphics/fbcond/Cargo.toml index 10fc0ebf37..6e8816cfaa 100644 --- a/graphics/fbcond/Cargo.toml +++ b/graphics/fbcond/Cargo.toml @@ -9,7 +9,7 @@ ransid = "0.4" redox_event = "0.4" redox_syscall = "0.5" redox-daemon = "0.1" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox-scheme = "0.4" console-draw = { path = "../console-draw" } graphics-ipc = { path = "../graphics-ipc" } diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 2b70ddc0ce..6c4c5c2214 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -1,5 +1,5 @@ use event::EventQueue; -use libredox::errno::{EAGAIN, EINTR, EOPNOTSUPP, ESTALE}; +use libredox::errno::{EAGAIN, EINTR, ESTALE}; use orbclient::Event; use redox_scheme::{CallRequest, RequestKind, Response, SignalBehavior, Socket}; use std::os::fd::{AsRawFd, BorrowedFd}; @@ -105,16 +105,8 @@ fn handle_event( blocked.push(call_request); } } - RequestKind::SendFd(sendfd_request) => { - socket - .write_response( - Response::for_sendfd( - &sendfd_request, - Err(syscall::Error::new(EOPNOTSUPP)), - ), - SignalBehavior::Restart, - ) - .expect("fbcond: failed to write scheme"); + RequestKind::OnClose { id } => { + scheme.on_close(id); } RequestKind::Cancellation(cancellation_request) => { if let Some(i) = blocked @@ -128,9 +120,7 @@ fn handle_event( .expect("vesad: failed to write display scheme"); } } - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { - unreachable!() - } + _ => {} } } } diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index 0643b11223..dd4c957e01 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -161,9 +161,10 @@ impl SchemeBlock for FbconScheme { Err(Error::new(EBADF)) } } +} - fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) +impl FbconScheme { + pub fn on_close(&mut self, id: usize) { + self.handles.remove(&id); } } diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index c3cb227a08..cf1de6546e 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -13,4 +13,4 @@ orbclient = "0.3.27" libredox = "0.1.3" common = { path = "../common" } -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox-scheme = "0.4" diff --git a/inputd/src/main.rs b/inputd/src/main.rs index e8cb36a138..d69aa81ef5 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -18,8 +18,8 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use inputd::{VtActivate, VtEvent, VtEventKind}; -use libredox::errno::{EOPNOTSUPP, ESTALE}; -use redox_scheme::{RequestKind, Response, Scheme, SignalBehavior, Socket}; +use libredox::errno::ESTALE; +use redox_scheme::{RequestKind, Scheme, SignalBehavior, Socket}; use orbclient::{Event, EventOption}; use syscall::{Error as SysError, EventFlags, EINVAL}; @@ -457,11 +457,13 @@ impl Scheme for InputScheme { } } } +} - fn close(&mut self, id: usize) -> syscall::Result { - let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; +impl InputScheme { + fn on_close(&mut self, id: usize) { + let handle = self.handles.remove(&id).unwrap(); - match *handle { + match handle { Handle::Consumer { vt, .. } => { self.vts.remove(&vt); if self.active_vt == Some(vt) { @@ -474,7 +476,6 @@ impl Scheme for InputScheme { } _ => {} } - Ok(0) } } @@ -499,14 +500,10 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { SignalBehavior::Restart, )?; } - RequestKind::SendFd(sendfd_request) => { - socket_file.write_response( - Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), - SignalBehavior::Restart, - )?; + RequestKind::OnClose { id } => { + scheme.on_close(id); } - RequestKind::Cancellation(_cancellation_request) => {} - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => unreachable!(), + _ => {} } if !scheme.has_new_events { diff --git a/net/driver-network/Cargo.toml b/net/driver-network/Cargo.toml index 524abbffe3..665df4f60e 100644 --- a/net/driver-network/Cargo.toml +++ b/net/driver-network/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" [dependencies] libredox = "0.1.3" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox-scheme = "0.4" redox_syscall = { version = "0.5", features = ["std"] } diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index d811464b70..339a195cc9 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -1,7 +1,6 @@ use std::collections::BTreeMap; use std::{cmp, io}; -use libredox::errno::EOPNOTSUPP; use libredox::flag::O_NONBLOCK; use libredox::Fd; use redox_scheme::{ @@ -114,11 +113,8 @@ impl NetworkScheme { self.blocked.push(call_request); } } - RequestKind::SendFd(sendfd_request) => { - self.socket.write_response( - Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), - SignalBehavior::Restart, - )?; + RequestKind::OnClose { id } => { + self.on_close(id); } RequestKind::Cancellation(cancellation_request) => { if let Some(i) = self @@ -131,9 +127,7 @@ impl NetworkScheme { self.socket.write_response(resp, SignalBehavior::Restart)?; } } - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { - unreachable!() - } + _ => {} } } @@ -282,9 +276,10 @@ impl SchemeBlock for NetworkScheme { let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; Ok(Some(0)) } +} - fn close(&mut self, id: usize) -> Result> { - self.handles.remove(&id).ok_or(Error::new(EBADF))?; - Ok(Some(0)) +impl NetworkScheme { + fn on_close(&mut self, id: usize) { + self.handles.remove(&id); } } diff --git a/storage/driver-block/Cargo.toml b/storage/driver-block/Cargo.toml index 1645bf0314..00e10150bb 100644 --- a/storage/driver-block/Cargo.toml +++ b/storage/driver-block/Cargo.toml @@ -8,4 +8,4 @@ partitionlib = { path = "../partitionlib" } libredox = "0.1.3" redox_syscall = "0.5" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox-scheme = "0.4" diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index d3569febcb..6efe0f5c2c 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -9,12 +9,12 @@ use std::str; use libredox::Fd; use partitionlib::{LogicalBlockSize, PartitionTable}; use redox_scheme::{ - CallRequest, CallerCtx, OpenResult, RequestKind, Response, SchemeBlock, SignalBehavior, Socket, + CallRequest, CallerCtx, OpenResult, RequestKind, SchemeBlock, SignalBehavior, Socket, }; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EAGAIN, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOPNOTSUPP, - EOVERFLOW, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, + Error, Result, Stat, EACCES, EAGAIN, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, + MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, }; /// Split the read operation into a series of block reads. @@ -330,18 +330,13 @@ impl DiskScheme { self.blocked.push(call_request); } } - RequestKind::SendFd(sendfd_request) => { - self.socket.write_response( - Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), - SignalBehavior::Restart, - )?; + RequestKind::OnClose { id } => { + self.on_close(id); } RequestKind::Cancellation(_cancellation_request) => { // FIXME implement cancellation } - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { - unreachable!() - } + _ => {} } } @@ -610,11 +605,10 @@ impl SchemeBlock for DiskScheme { }, )) } +} - fn close(&mut self, id: usize) -> Result> { - self.handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) +impl DiskScheme { + fn on_close(&mut self, id: usize) { + self.handles.remove(&id); } } diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index f36753e9e7..95eb88ddee 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -21,7 +21,7 @@ lazy_static = "1.4" log = "0.4" redox-daemon = "0.1" redox_event = "0.4.1" -redox-scheme = { git = "https://gitlab.redox-os.org/redox-os/redox-scheme.git" } +redox-scheme = "0.4" redox_syscall = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 74e1ef3454..a7a2d86e9a 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -37,8 +37,7 @@ use pcid_interface::{ MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, }; -use redox_scheme::{RequestKind, Response, SignalBehavior, Socket}; -use syscall::EOPNOTSUPP; +use redox_scheme::{RequestKind, SignalBehavior, Socket}; use crate::xhci::{InterruptMethod, Xhci}; @@ -216,18 +215,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .write_response(resp, SignalBehavior::Restart) .expect("xhcid: failed to write scheme"); } - RequestKind::SendFd(sendfd_request) => { - socket - .write_response( - Response::for_sendfd(&sendfd_request, Err(syscall::Error::new(EOPNOTSUPP))), - SignalBehavior::Restart, - ) - .expect("xhcid: failed to write response"); - } - RequestKind::Cancellation(_cancellation_request) => {} - RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { - unreachable!() + RequestKind::OnClose { id } => { + hci.on_close(id); } + _ => {} } } } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 1b3944ea15..36190e834c 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -2163,14 +2163,12 @@ impl Scheme for &Xhci { _ => Err(Error::new(EBADF)), } } - fn close(&mut self, fd: usize) -> Result { - if self.handles.remove(&fd).is_none() { - return Err(Error::new(EBADF)); - } - Ok(0) - } } impl Xhci { + pub fn on_close(&self, fd: usize) { + self.handles.remove(&fd); + } + pub fn get_endp_status(&self, port_num: usize, endp_num: u8) -> Result { let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; From 943cbe37079d3e102cc5a0e7fecfe868d505d262 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 16:27:04 +0100 Subject: [PATCH 1139/1301] graphics/fbbootlogd: Remove workaround that prevents blocking on the graphics driver Instead logd will no longer block on fbbootlogd to prevent the deadlock that this worked around. --- graphics/fbbootlogd/src/display.rs | 37 ++++-------------------------- graphics/fbbootlogd/src/main.rs | 10 ++++---- 2 files changed, 8 insertions(+), 39 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index d276a24038..a26f0fc578 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -5,7 +5,6 @@ use libredox::errno::ESTALE; use orbclient::Event; use std::mem; use std::os::fd::BorrowedFd; -use std::sync::mpsc::{self, Receiver, Sender}; use std::sync::{Arc, Mutex}; use std::{io, os::unix::io::AsRawFd, slice}; @@ -35,12 +34,7 @@ pub struct DisplayMap { pub inner: graphics_ipc::v1::DisplayMap, } -enum DisplayCommand { - SyncRects(Vec), -} - pub struct Display { - cmd_tx: Sender, pub map: Arc>>, } @@ -67,13 +61,7 @@ impl Display { Self::handle_input_events(map_clone, input_handle); }); - let (cmd_tx, cmd_rx) = mpsc::channel(); - let map_clone = map.clone(); - std::thread::spawn(move || { - Self::handle_sync_rect(map_clone, cmd_rx); - }); - - Ok(Self { cmd_tx, map }) + Ok(Self { map }) } fn handle_input_events(map: Arc>>, input_handle: ConsumerHandle) { @@ -129,26 +117,9 @@ impl Display { } } - fn handle_sync_rect(map: Arc>>, cmd_rx: Receiver) { - while let Ok(cmd) = cmd_rx.recv() { - match cmd { - DisplayCommand::SyncRects(sync_rects) => { - // We may not hold this lock across the write call to avoid deadlocking if the - // graphics driver tries to write to the bootlog. - let display_handle = if let Some(map) = &*map.lock().unwrap() { - map.display_handle.clone() - } else { - continue; - }; - display_handle.sync_rects(&sync_rects).unwrap(); - } - } + pub fn sync_rects(&mut self, sync_rects: Vec) { + if let Some(map) = &*self.map.lock().unwrap() { + map.display_handle.sync_rects(&sync_rects).unwrap(); } } - - pub fn sync_rects(&mut self, sync_rects: Vec) { - self.cmd_tx - .send(DisplayCommand::SyncRects(sync_rects)) - .unwrap(); - } } diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index 1b0d941362..b566a76df4 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -1,13 +1,11 @@ //! Fbbootlogd renders the boot log and presents it on VT1. //! -//! While fbbootlogd is superficially similar to fbcond, there are two major differences: +//! While fbbootlogd is superficially similar to fbcond, the major difference is: //! //! * Fbbootlogd doesn't accept input coming from the keyboard. It only allows getting written to. -//! * Writing to fbbootlogd will never block. Not even on the graphics driver or inputd. This makes -//! it safe for graphics drivers and inputd to write to the boot log without risking deadlocks. -//! Fbcond will block on the graphics driver during handoff and will continously block on inputd -//! to get new input. Fbbootlogd does all blocking operations in background threads such that the -//! main thread will always keep accepting new input and writing it to the framebuffer. +//! +//! In the future fbbootlogd may also pull from logd as opposed to have logd push logs to it. And it +//! it could display a boot splash like plymouth instead of a boot log when booting in quiet mode. use redox_scheme::{RequestKind, SignalBehavior, Socket}; From 56808dbfb14babd9a98ba912e8ce99f34571a551 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 16:50:29 +0100 Subject: [PATCH 1140/1301] graphics/fbbootlogd: Remove input events background thread --- graphics/fbbootlogd/src/display.rs | 56 +++++++-------------- graphics/fbbootlogd/src/main.rs | 81 ++++++++++++++++++++++-------- graphics/fbbootlogd/src/scheme.rs | 6 +-- 3 files changed, 79 insertions(+), 64 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index a26f0fc578..430bff7c12 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -1,12 +1,11 @@ -use event::{user_data, EventQueue}; use graphics_ipc::v1::{Damage, V1GraphicsHandle}; use inputd::ConsumerHandle; use libredox::errno::ESTALE; use orbclient::Event; use std::mem; use std::os::fd::BorrowedFd; -use std::sync::{Arc, Mutex}; -use std::{io, os::unix::io::AsRawFd, slice}; +use std::os::unix::io::AsRawFd; +use std::{io, slice}; fn read_to_slice( file: BorrowedFd, @@ -24,18 +23,19 @@ fn read_to_slice( fn display_fd_map(display_handle: V1GraphicsHandle) -> io::Result { let display_map = display_handle.map_display()?; Ok(DisplayMap { - display_handle: Arc::new(display_handle), + display_handle, inner: display_map, }) } pub struct DisplayMap { - display_handle: Arc, + display_handle: V1GraphicsHandle, pub inner: graphics_ipc::v1::DisplayMap, } pub struct Display { - pub map: Arc>>, + pub input_handle: ConsumerHandle, + pub map: Option, } impl Display { @@ -45,51 +45,28 @@ impl Display { let map = match input_handle.open_display() { Ok(display) => { let display_handle = V1GraphicsHandle::from_file(display)?; - Arc::new(Mutex::new(Some( + Some( display_fd_map(display_handle) .unwrap_or_else(|e| panic!("failed to map display: {e}")), - ))) + ) } Err(err) => { println!("fbbootlogd: No display present yet: {err}"); - Arc::new(Mutex::new(None)) + None } }; - let map_clone = map.clone(); - std::thread::spawn(move || { - Self::handle_input_events(map_clone, input_handle); - }); - - Ok(Self { map }) + Ok(Self { input_handle, map }) } - fn handle_input_events(map: Arc>>, input_handle: ConsumerHandle) { - let event_queue = EventQueue::new().expect("fbbootlogd: failed to create event queue"); - - user_data! { - enum Source { - Input, - } - } - - // FIXME listen for resize events from inputd and handle them - - event_queue - .subscribe( - input_handle.inner().as_raw_fd() as usize, - Source::Input, - event::EventFlags::READ, - ) - .expect("fbbootlogd: failed to subscribe to scheme events"); - + pub fn handle_input_events(&mut self) { let mut events = [Event::new(); 16]; - for Source::Input in event_queue.map(|event| event.unwrap().user_data) { - match read_to_slice(input_handle.inner(), &mut events) { + loop { + match read_to_slice(self.input_handle.inner(), &mut events) { Err(err) if err.errno() == ESTALE => { eprintln!("fbbootlogd: handoff requested"); - let new_display_handle = match input_handle.open_display() { + let new_display_handle = match self.input_handle.open_display() { Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), Err(err) => { println!("fbbootlogd: No display present yet: {err}"); @@ -99,7 +76,7 @@ impl Display { match display_fd_map(new_display_handle) { Ok(ok) => { - *map.lock().unwrap() = Some(ok); + self.map = Some(ok); eprintln!("fbbootlogd: handoff finished"); } @@ -109,6 +86,7 @@ impl Display { } } + Ok(0) => break, Ok(_count) => {} Err(err) => { panic!("fbbootlogd: error while reading events: {err}"); @@ -118,7 +96,7 @@ impl Display { } pub fn sync_rects(&mut self, sync_rects: Vec) { - if let Some(map) = &*self.map.lock().unwrap() { + if let Some(map) = &self.map { map.display_handle.sync_rects(&sync_rects).unwrap(); } } diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index b566a76df4..30e99c9ea0 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -7,6 +7,10 @@ //! In the future fbbootlogd may also pull from logd as opposed to have logd push logs to it. And it //! it could display a boot splash like plymouth instead of a boot log when booting in quiet mode. +use std::os::fd::AsRawFd; + +use event::EventQueue; +use libredox::errno::EAGAIN; use redox_scheme::{RequestKind, SignalBehavior, Socket}; use crate::scheme::FbbootlogScheme; @@ -18,41 +22,76 @@ fn main() { redox_daemon::Daemon::new(|daemon| inner(daemon)).expect("failed to create daemon"); } fn inner(daemon: redox_daemon::Daemon) -> ! { + let event_queue = EventQueue::new().expect("fbbootlogd: failed to create event queue"); + + event::user_data! { + enum Source { + Scheme, + Input, + } + } + let socket = - Socket::create("fbbootlog").expect("fbbootlogd: failed to create fbbootlog scheme"); + Socket::nonblock("fbbootlog").expect("fbbootlogd: failed to create fbbootlog scheme"); + + event_queue + .subscribe( + socket.inner().raw(), + Source::Scheme, + event::EventFlags::READ, + ) + .expect("fbcond: failed to subscribe to scheme events"); let mut scheme = FbbootlogScheme::new(); + event_queue + .subscribe( + scheme.display.input_handle.inner().as_raw_fd() as usize, + Source::Input, + event::EventFlags::READ, + ) + .expect("fbbootlogd: failed to subscribe to scheme events"); + // This is not possible for now as fbbootlogd needs to open new displays at runtime for graphics // driver handoff. In the future inputd may directly pass a handle to the display instead. //libredox::call::setrens(0, 0).expect("fbbootlogd: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); - loop { - let request = match socket - .next_request(SignalBehavior::Restart) - .expect("fbbootlogd: failed to read display scheme") - { - Some(request) => request, - None => { - // Scheme likely got unmounted - std::process::exit(0); - } - }; + for event in event_queue { + match event.expect("fbbootlogd: failed to get event").user_data { + Source::Scheme => { + loop { + let request = match socket.next_request(SignalBehavior::Restart) { + Ok(Some(request)) => request, + Ok(None) => { + // Scheme likely got unmounted + std::process::exit(0); + } + Err(err) if err.errno == EAGAIN => break, + Err(err) => panic!("fbbootlogd: failed to read display scheme: {err:?}"), + }; - match request.kind() { - RequestKind::Call(call) => { - let response = call.handle_scheme(&mut scheme); + match request.kind() { + RequestKind::Call(call) => { + let response = call.handle_scheme(&mut scheme); - socket - .write_responses(&[response], SignalBehavior::Restart) - .expect("pcid: failed to write next scheme response"); + socket + .write_responses(&[response], SignalBehavior::Restart) + .expect("pcid: failed to write next scheme response"); + } + RequestKind::OnClose { id } => { + scheme.on_close(id); + } + _ => (), + } + } } - RequestKind::OnClose { id } => { - scheme.on_close(id); + Source::Input => { + scheme.display.handle_input_events(); } - _ => (), } } + + std::process::exit(0); } diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 9fa087f0fa..d4b21ef06c 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -6,7 +6,7 @@ use syscall::{Error, Result, EINVAL, ENOENT}; use crate::display::Display; pub struct FbbootlogScheme { - display: Display, + pub display: Display, text_screen: console_draw::TextScreen, } @@ -55,8 +55,7 @@ impl Scheme for FbbootlogScheme { } fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { - let mut map_guard = self.display.map.lock().unwrap(); - if let Some(map) = &mut *map_guard { + if let Some(map) = &mut self.display.map { let damage = self.text_screen.write( &mut console_draw::DisplayMap { offscreen: map.inner.ptr_mut(), @@ -66,7 +65,6 @@ impl Scheme for FbbootlogScheme { buf, &mut VecDeque::new(), ); - drop(map_guard); self.display.sync_rects(damage); } From b9d043f6e22903a2cdbe58ed96ed7cf946b3d13b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:07:22 +0100 Subject: [PATCH 1141/1301] inputd: Add ConsumerHandle::read_events --- graphics/fbbootlogd/src/display.rs | 40 +++++++--------------- graphics/fbbootlogd/src/main.rs | 2 +- graphics/fbcond/src/main.rs | 41 +++++++--------------- graphics/fbcond/src/scheme.rs | 2 +- inputd/src/lib.rs | 55 +++++++++++++++++++++++------- 5 files changed, 69 insertions(+), 71 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index 430bff7c12..8ef8c1a558 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -1,24 +1,8 @@ -use graphics_ipc::v1::{Damage, V1GraphicsHandle}; -use inputd::ConsumerHandle; -use libredox::errno::ESTALE; -use orbclient::Event; -use std::mem; -use std::os::fd::BorrowedFd; -use std::os::unix::io::AsRawFd; -use std::{io, slice}; +use std::io; -fn read_to_slice( - file: BorrowedFd, - buf: &mut [T], -) -> Result { - unsafe { - libredox::call::read( - file.as_raw_fd() as usize, - slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * mem::size_of::()), - ) - .map(|count| count / mem::size_of::()) - } -} +use graphics_ipc::v1::{Damage, V1GraphicsHandle}; +use inputd::{ConsumerHandle, ConsumerHandleEvent}; +use orbclient::Event; fn display_fd_map(display_handle: V1GraphicsHandle) -> io::Result { let display_map = display_handle.map_display()?; @@ -62,8 +46,14 @@ impl Display { pub fn handle_input_events(&mut self) { let mut events = [Event::new(); 16]; loop { - match read_to_slice(self.input_handle.inner(), &mut events) { - Err(err) if err.errno() == ESTALE => { + match self + .input_handle + .read_events(&mut events) + .expect("fbbootlogd: error while reading events") + { + ConsumerHandleEvent::Events(&[]) => break, + ConsumerHandleEvent::Events(_) => {} + ConsumerHandleEvent::Handoff => { eprintln!("fbbootlogd: handoff requested"); let new_display_handle = match self.input_handle.open_display() { @@ -85,12 +75,6 @@ impl Display { } } } - - Ok(0) => break, - Ok(_count) => {} - Err(err) => { - panic!("fbbootlogd: error while reading events: {err}"); - } } } } diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index 30e99c9ea0..6be03245cf 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -46,7 +46,7 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { event_queue .subscribe( - scheme.display.input_handle.inner().as_raw_fd() as usize, + scheme.display.input_handle.event_handle().as_raw_fd() as usize, Source::Input, event::EventFlags::READ, ) diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 6c4c5c2214..27f81244f4 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -1,9 +1,9 @@ use event::EventQueue; -use libredox::errno::{EAGAIN, EINTR, ESTALE}; +use inputd::ConsumerHandleEvent; +use libredox::errno::{EAGAIN, EINTR}; use orbclient::Event; use redox_scheme::{CallRequest, RequestKind, Response, SignalBehavior, Socket}; -use std::os::fd::{AsRawFd, BorrowedFd}; -use std::{env, mem, slice}; +use std::env; use syscall::EVENT_READ; use crate::scheme::{FbconScheme, VtIndex}; @@ -12,19 +12,6 @@ mod display; mod scheme; mod text; -fn read_to_slice( - file: BorrowedFd, - buf: &mut [T], -) -> Result { - unsafe { - libredox::call::read( - file.as_raw_fd() as usize, - slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * mem::size_of::()), - ) - .map(|count| count / mem::size_of::()) - } -} - fn main() { let vt_ids = env::args() .skip(1) @@ -129,21 +116,19 @@ fn handle_event( let mut events = [Event::new(); 16]; loop { - match read_to_slice(vt.display.input_handle.inner(), &mut events) { - Ok(0) => break, - Err(err) if err.errno() == ESTALE => { - vt.handle_handoff(); - } - - Ok(count) => { - let events = &mut events[..count]; - for event in events.iter_mut() { + match vt + .display + .input_handle + .read_events(&mut events) + .expect("fbcond: Error while reading events") + { + ConsumerHandleEvent::Events(&[]) => break, + ConsumerHandleEvent::Events(events) => { + for event in events { vt.input(event) } } - Err(err) => { - panic!("fbcond: Error while reading events: {err}"); - } + ConsumerHandleEvent::Handoff => vt.handle_handoff(), } } } diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index dd4c957e01..b8393c7b23 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -46,7 +46,7 @@ impl FbconScheme { let display = Display::open_vt(vt_i).expect("Failed to open display for vt"); event_queue .subscribe( - display.input_handle.inner().as_raw_fd() as usize, + display.input_handle.event_handle().as_raw_fd() as usize, VtIndex(vt_i), event::EventFlags::READ, ) diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index b7ca196db6..0a2559beb9 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -1,23 +1,44 @@ use std::fs::{File, OpenOptions}; -use std::io::{Error, Read, Write}; +use std::io::{self, Read, Write}; use std::mem::size_of; use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd}; use std::os::unix::fs::OpenOptionsExt; +use std::slice; use libredox::flag::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; +use orbclient::Event; +use syscall::ESTALE; + +fn read_to_slice( + file: BorrowedFd, + buf: &mut [T], +) -> Result { + unsafe { + libredox::call::read( + file.as_raw_fd() as usize, + slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * size_of::()), + ) + .map(|count| count / size_of::()) + } +} unsafe fn any_as_u8_slice(p: &T) -> &[u8] { - std::slice::from_raw_parts((p as *const T) as *const u8, size_of::()) + slice::from_raw_parts((p as *const T) as *const u8, size_of::()) } unsafe fn any_as_u8_slice_mut(p: &mut T) -> &mut [u8] { - std::slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::()) + slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::()) } pub struct ConsumerHandle(File); +pub enum ConsumerHandleEvent<'a> { + Events(&'a [Event]), + Handoff, +} + impl ConsumerHandle { - pub fn new_vt() -> Result { + pub fn new_vt() -> io::Result { let file = OpenOptions::new() .read(true) .custom_flags(O_NONBLOCK as i32) @@ -25,11 +46,11 @@ impl ConsumerHandle { Ok(Self(file)) } - pub fn inner(&self) -> BorrowedFd<'_> { + pub fn event_handle(&self) -> BorrowedFd<'_> { self.0.as_fd() } - pub fn open_display(&self) -> Result { + pub fn open_display(&self) -> io::Result { let mut buffer = [0; 1024]; let fd = self.0.as_raw_fd(); let written = libredox::call::fpath(fd as usize, &mut buffer)?; @@ -49,6 +70,14 @@ impl ConsumerHandle { Ok(display_file) } + + pub fn read_events<'a>(&self, events: &'a mut [Event]) -> io::Result> { + match read_to_slice(self.0.as_fd(), events) { + Ok(count) => Ok(ConsumerHandleEvent::Events(&events[..count])), + Err(err) if err.errno() == ESTALE => Ok(ConsumerHandleEvent::Handoff), + Err(err) => Err(err.into()), + } + } } #[derive(Debug, Clone)] @@ -60,17 +89,17 @@ pub struct VtActivate { pub struct DisplayHandle(File); impl DisplayHandle { - pub fn new>(device_name: S) -> Result { + pub fn new>(device_name: S) -> io::Result { let path = format!("/scheme/input/handle/display/{}", device_name.into()); Ok(Self(File::open(path)?)) } - pub fn new_early>(device_name: S) -> Result { + pub fn new_early>(device_name: S) -> io::Result { let path = format!("/scheme/input/handle_early/display/{}", device_name.into()); Ok(Self(File::open(path)?)) } - pub fn read_vt_event(&mut self) -> Result, Error> { + pub fn read_vt_event(&mut self) -> io::Result> { let mut event = VtEvent { kind: VtEventKind::Resize, vt: usize::MAX, @@ -97,12 +126,12 @@ impl DisplayHandle { pub struct ControlHandle(File); impl ControlHandle { - pub fn new() -> Result { + pub fn new() -> io::Result { let path = format!("/scheme/input/control"); Ok(Self(File::open(path)?)) } - pub fn activate_vt(&mut self, vt: usize) -> Result { + pub fn activate_vt(&mut self, vt: usize) -> io::Result { let cmd = VtActivate { vt }; self.0.write(unsafe { any_as_u8_slice(&cmd) }) } @@ -129,11 +158,11 @@ pub struct VtEvent { pub struct ProducerHandle(File); impl ProducerHandle { - pub fn new() -> Result { + pub fn new() -> io::Result { File::open("/scheme/input/producer").map(ProducerHandle) } - pub fn write_event(&mut self, event: orbclient::Event) -> Result<(), Error> { + pub fn write_event(&mut self, event: orbclient::Event) -> io::Result<()> { self.0.write(&event)?; Ok(()) } From 9290cffa70305e60960b85e8c49aa0dc1795f1e1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:18:28 +0100 Subject: [PATCH 1142/1301] graphics/fbbootlogd: Extract handle_handoff method --- graphics/fbbootlogd/src/display.rs | 49 +++++++++++------------------- graphics/fbbootlogd/src/main.rs | 18 ++++++++++- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index 8ef8c1a558..4de0db6859 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -1,8 +1,7 @@ use std::io; use graphics_ipc::v1::{Damage, V1GraphicsHandle}; -use inputd::{ConsumerHandle, ConsumerHandleEvent}; -use orbclient::Event; +use inputd::ConsumerHandle; fn display_fd_map(display_handle: V1GraphicsHandle) -> io::Result { let display_map = display_handle.map_display()?; @@ -43,38 +42,24 @@ impl Display { Ok(Self { input_handle, map }) } - pub fn handle_input_events(&mut self) { - let mut events = [Event::new(); 16]; - loop { - match self - .input_handle - .read_events(&mut events) - .expect("fbbootlogd: error while reading events") - { - ConsumerHandleEvent::Events(&[]) => break, - ConsumerHandleEvent::Events(_) => {} - ConsumerHandleEvent::Handoff => { - eprintln!("fbbootlogd: handoff requested"); + pub fn handle_handoff(&mut self) { + eprintln!("fbbootlogd: handoff requested"); + let new_display_handle = match self.input_handle.open_display() { + Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), + Err(err) => { + println!("fbbootlogd: No display present yet: {err}"); + return; + } + }; - let new_display_handle = match self.input_handle.open_display() { - Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), - Err(err) => { - println!("fbbootlogd: No display present yet: {err}"); - continue; - } - }; + match display_fd_map(new_display_handle) { + Ok(ok) => { + self.map = Some(ok); - match display_fd_map(new_display_handle) { - Ok(ok) => { - self.map = Some(ok); - - eprintln!("fbbootlogd: handoff finished"); - } - Err(err) => { - eprintln!("fbbootlogd: failed to open display: {}", err); - } - } - } + eprintln!("fbbootlogd: handoff finished"); + } + Err(err) => { + eprintln!("fbbootlogd: failed to open display: {}", err); } } } diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index 6be03245cf..d06faf9170 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -10,7 +10,9 @@ use std::os::fd::AsRawFd; use event::EventQueue; +use inputd::ConsumerHandleEvent; use libredox::errno::EAGAIN; +use orbclient::Event; use redox_scheme::{RequestKind, SignalBehavior, Socket}; use crate::scheme::FbbootlogScheme; @@ -88,7 +90,21 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { } } Source::Input => { - scheme.display.handle_input_events(); + let mut events = [Event::new(); 16]; + loop { + match scheme + .display + .input_handle + .read_events(&mut events) + .expect("fbbootlogd: error while reading events") + { + ConsumerHandleEvent::Events(&[]) => break, + ConsumerHandleEvent::Events(_) => {} + ConsumerHandleEvent::Handoff => { + scheme.display.handle_handoff(); + } + } + } } } } From 54113f8fde8daf482d791a1e3a3266e251a8642b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:21:23 +0100 Subject: [PATCH 1143/1301] graphics/fbbootlogd: Make it robust against initial graphics driver being broken --- graphics/fbbootlogd/src/display.rs | 26 ++++++++------------------ graphics/fbbootlogd/src/main.rs | 1 + 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs index 4de0db6859..f08dba2d5c 100644 --- a/graphics/fbbootlogd/src/display.rs +++ b/graphics/fbbootlogd/src/display.rs @@ -23,31 +23,21 @@ pub struct Display { impl Display { pub fn open_first_vt() -> io::Result { - let input_handle = ConsumerHandle::new_vt()?; - - let map = match input_handle.open_display() { - Ok(display) => { - let display_handle = V1GraphicsHandle::from_file(display)?; - Some( - display_fd_map(display_handle) - .unwrap_or_else(|e| panic!("failed to map display: {e}")), - ) - } - Err(err) => { - println!("fbbootlogd: No display present yet: {err}"); - None - } + let mut display = Self { + input_handle: ConsumerHandle::new_vt()?, + map: None, }; - Ok(Self { input_handle, map }) + display.handle_handoff(); + + Ok(display) } pub fn handle_handoff(&mut self) { - eprintln!("fbbootlogd: handoff requested"); let new_display_handle = match self.input_handle.open_display() { Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), Err(err) => { - println!("fbbootlogd: No display present yet: {err}"); + eprintln!("fbbootlogd: No display present yet: {err}"); return; } }; @@ -56,7 +46,7 @@ impl Display { Ok(ok) => { self.map = Some(ok); - eprintln!("fbbootlogd: handoff finished"); + eprintln!("fbbootlogd: mapped display"); } Err(err) => { eprintln!("fbbootlogd: failed to open display: {}", err); diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index d06faf9170..05bf921685 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -101,6 +101,7 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { ConsumerHandleEvent::Events(&[]) => break, ConsumerHandleEvent::Events(_) => {} ConsumerHandleEvent::Handoff => { + eprintln!("fbbootlogd: handoff requested"); scheme.display.handle_handoff(); } } From 87d71bc70802375e9d88547b096d4558e89561ea Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:27:08 +0100 Subject: [PATCH 1144/1301] graphics/fbbootlogd: Merge Display into FbbbootlogScheme --- graphics/fbbootlogd/src/display.rs | 62 ------------------------------ graphics/fbbootlogd/src/main.rs | 6 +-- graphics/fbbootlogd/src/scheme.rs | 49 ++++++++++++++++++++--- 3 files changed, 45 insertions(+), 72 deletions(-) delete mode 100644 graphics/fbbootlogd/src/display.rs diff --git a/graphics/fbbootlogd/src/display.rs b/graphics/fbbootlogd/src/display.rs deleted file mode 100644 index f08dba2d5c..0000000000 --- a/graphics/fbbootlogd/src/display.rs +++ /dev/null @@ -1,62 +0,0 @@ -use std::io; - -use graphics_ipc::v1::{Damage, V1GraphicsHandle}; -use inputd::ConsumerHandle; - -fn display_fd_map(display_handle: V1GraphicsHandle) -> io::Result { - let display_map = display_handle.map_display()?; - Ok(DisplayMap { - display_handle, - inner: display_map, - }) -} - -pub struct DisplayMap { - display_handle: V1GraphicsHandle, - pub inner: graphics_ipc::v1::DisplayMap, -} - -pub struct Display { - pub input_handle: ConsumerHandle, - pub map: Option, -} - -impl Display { - pub fn open_first_vt() -> io::Result { - let mut display = Self { - input_handle: ConsumerHandle::new_vt()?, - map: None, - }; - - display.handle_handoff(); - - Ok(display) - } - - pub fn handle_handoff(&mut self) { - let new_display_handle = match self.input_handle.open_display() { - Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), - Err(err) => { - eprintln!("fbbootlogd: No display present yet: {err}"); - return; - } - }; - - match display_fd_map(new_display_handle) { - Ok(ok) => { - self.map = Some(ok); - - eprintln!("fbbootlogd: mapped display"); - } - Err(err) => { - eprintln!("fbbootlogd: failed to open display: {}", err); - } - } - } - - pub fn sync_rects(&mut self, sync_rects: Vec) { - if let Some(map) = &self.map { - map.display_handle.sync_rects(&sync_rects).unwrap(); - } - } -} diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index 05bf921685..3de5509c2f 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -17,7 +17,6 @@ use redox_scheme::{RequestKind, SignalBehavior, Socket}; use crate::scheme::FbbootlogScheme; -mod display; mod scheme; fn main() { @@ -48,7 +47,7 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { event_queue .subscribe( - scheme.display.input_handle.event_handle().as_raw_fd() as usize, + scheme.input_handle.event_handle().as_raw_fd() as usize, Source::Input, event::EventFlags::READ, ) @@ -93,7 +92,6 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { let mut events = [Event::new(); 16]; loop { match scheme - .display .input_handle .read_events(&mut events) .expect("fbbootlogd: error while reading events") @@ -102,7 +100,7 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { ConsumerHandleEvent::Events(_) => {} ConsumerHandleEvent::Handoff => { eprintln!("fbbootlogd: handoff requested"); - scheme.display.handle_handoff(); + scheme.handle_handoff(); } } } diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index d4b21ef06c..3b66ae5dca 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -1,20 +1,55 @@ use std::collections::VecDeque; +use graphics_ipc::v1::V1GraphicsHandle; +use inputd::ConsumerHandle; use redox_scheme::Scheme; use syscall::{Error, Result, EINVAL, ENOENT}; -use crate::display::Display; +pub struct DisplayMap { + display_handle: V1GraphicsHandle, + inner: graphics_ipc::v1::DisplayMap, +} pub struct FbbootlogScheme { - pub display: Display, + pub input_handle: ConsumerHandle, + display_map: Option, text_screen: console_draw::TextScreen, } impl FbbootlogScheme { pub fn new() -> FbbootlogScheme { - FbbootlogScheme { - display: Display::open_first_vt().expect("Failed to open display for vt"), + let mut scheme = FbbootlogScheme { + input_handle: ConsumerHandle::new_vt().expect("fbbootlogd: Failed to open vt"), + display_map: None, text_screen: console_draw::TextScreen::new(), + }; + + scheme.handle_handoff(); + + scheme + } + + pub fn handle_handoff(&mut self) { + let new_display_handle = match self.input_handle.open_display() { + Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), + Err(err) => { + eprintln!("fbbootlogd: No display present yet: {err}"); + return; + } + }; + + match new_display_handle.map_display() { + Ok(display_map) => { + self.display_map = Some(DisplayMap { + display_handle: new_display_handle, + inner: display_map, + }); + + eprintln!("fbbootlogd: mapped display"); + } + Err(err) => { + eprintln!("fbbootlogd: failed to open display: {}", err); + } } } } @@ -55,7 +90,7 @@ impl Scheme for FbbootlogScheme { } fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { - if let Some(map) = &mut self.display.map { + if let Some(map) = &mut self.display_map { let damage = self.text_screen.write( &mut console_draw::DisplayMap { offscreen: map.inner.ptr_mut(), @@ -66,7 +101,9 @@ impl Scheme for FbbootlogScheme { &mut VecDeque::new(), ); - self.display.sync_rects(damage); + if let Some(map) = &self.display_map { + map.display_handle.sync_rects(&damage).unwrap(); + } } Ok(buf.len()) From ffbfecbdb0843dc3a88a7f081e1dc84ac48eeb7b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:30:39 +0100 Subject: [PATCH 1145/1301] graphics/fbcond: Make it robust against initial graphics driver being broken --- graphics/fbcond/src/display.rs | 28 +++++++--------------------- graphics/fbcond/src/scheme.rs | 2 +- graphics/fbcond/src/text.rs | 1 + 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 45ee86d2ca..60d7a18218 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -13,33 +13,19 @@ pub struct DisplayMap { } impl Display { - pub fn open_vt(vt: usize) -> io::Result { - let input_handle = ConsumerHandle::new_vt()?; + pub fn open_new_vt() -> io::Result { + let mut display = Self { + input_handle: ConsumerHandle::new_vt()?, + map: None, + }; - if let Ok(display_handle) = Self::open_display(&input_handle) { - let map = display_handle - .map_display() - .unwrap_or_else(|e| panic!("failed to map display for VT #{vt}: {e}")); + display.reopen_for_handoff(); - Ok(Self { - input_handle, - map: Some(DisplayMap { - display_handle, - inner: map, - }), - }) - } else { - Ok(Self { - input_handle, - map: None, - }) - } + Ok(display) } /// Re-open the display after a handoff. pub fn reopen_for_handoff(&mut self) { - eprintln!("fbcond: Performing handoff"); - let new_display_handle = Self::open_display(&self.input_handle).unwrap(); eprintln!("fbcond: Opened new display"); diff --git a/graphics/fbcond/src/scheme.rs b/graphics/fbcond/src/scheme.rs index b8393c7b23..76c17ff210 100644 --- a/graphics/fbcond/src/scheme.rs +++ b/graphics/fbcond/src/scheme.rs @@ -43,7 +43,7 @@ impl FbconScheme { let mut vts = BTreeMap::new(); for &vt_i in vt_ids { - let display = Display::open_vt(vt_i).expect("Failed to open display for vt"); + let display = Display::open_new_vt().expect("Failed to open display for vt"); event_queue .subscribe( display.input_handle.event_handle().as_raw_fd() as usize, diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index 3499316da2..11d4c7ca19 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -23,6 +23,7 @@ impl TextScreen { } pub fn handle_handoff(&mut self) { + eprintln!("fbcond: Performing handoff"); self.display.reopen_for_handoff(); } From f48ae933fffef5dc63ff335a152212e29b9f73e3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 6 Mar 2025 20:36:54 +0100 Subject: [PATCH 1146/1301] graphics: Only allow passing a single damage area at a time Currently only fbbootlogd and fbcond make use of support for multiple damage areas and they are not all that performance critical anyway. Orbital always passes a single damage area per write call. Out of all graphics drivers we have and are likely to get only vesad could potentially benefit from fine-grained damage areas. This commit doesn't significantly impact performance of fbcond. --- graphics/console-draw/src/lib.rs | 63 +++++++++++++---------------- graphics/driver-graphics/src/lib.rs | 19 +++------ graphics/fbbootlogd/src/scheme.rs | 2 +- graphics/fbcond/src/display.rs | 4 +- graphics/fbcond/src/text.rs | 2 +- graphics/graphics-ipc/src/v1.rs | 6 +-- graphics/vesad/src/scheme.rs | 45 +++++++++------------ graphics/virtio-gpud/src/scheme.rs | 21 ++++------ 8 files changed, 66 insertions(+), 96 deletions(-) diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index 59aea00469..82d180501f 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -1,6 +1,6 @@ extern crate ransid; -use std::collections::{BTreeSet, VecDeque}; +use std::collections::VecDeque; use std::convert::{TryFrom, TryInto}; use std::{cmp, ptr}; @@ -15,7 +15,6 @@ pub struct DisplayMap { pub struct TextScreen { console: ransid::Console, - changed: BTreeSet, } impl TextScreen { @@ -23,7 +22,6 @@ impl TextScreen { TextScreen { // Width and height will be filled in on the next write to the console console: ransid::Console::new(0, 0), - changed: BTreeSet::new(), } } @@ -118,18 +116,24 @@ impl TextScreen { } impl TextScreen { - pub fn write( - &mut self, - map: &mut DisplayMap, - buf: &[u8], - input: &mut VecDeque, - ) -> Vec { + pub fn write(&mut self, map: &mut DisplayMap, buf: &[u8], input: &mut VecDeque) -> Damage { + let mut min_changed = usize::MAX; + let mut max_changed = 0; + let mut line_changed = |line| { + if line < min_changed { + min_changed = line; + } + if line > max_changed { + max_changed = line; + } + }; + self.console.resize(map.width / 8, map.height / 16); - if self.console.state.x > self.console.state.w { - self.console.state.x = self.console.state.w; + if self.console.state.x >= self.console.state.w { + self.console.state.x = self.console.state.w - 1; } - if self.console.state.y > self.console.state.h { - self.console.state.y = self.console.state.h; + if self.console.state.y >= self.console.state.h { + self.console.state.y = self.console.state.h - 1; } if self.console.state.cursor @@ -139,7 +143,7 @@ impl TextScreen { let x = self.console.state.x; let y = self.console.state.y; Self::invert(map, x * 8, y * 16, 8, 16); - self.changed.insert(y); + line_changed(y); } self.console.write(buf, |event| match event { @@ -152,13 +156,13 @@ impl TextScreen { .. } => { Self::char(map, x * 8, y * 16, c, color.as_rgb(), bold, false); - self.changed.insert(y); + line_changed(y); } ransid::Event::Input { data } => input.extend(data), ransid::Event::Rect { x, y, w, h, color } => { Self::rect(map, x * 8, y * 16, w * 8, h * 16, color.as_rgb()); for y2 in y..y + h { - self.changed.insert(y2); + line_changed(y2); } } ransid::Event::ScreenBuffer { .. } => (), @@ -195,7 +199,7 @@ impl TextScreen { } } - self.changed.insert(to_y + y); + line_changed(to_y + y); } } ransid::Event::Resize { .. } => (), @@ -209,27 +213,16 @@ impl TextScreen { let x = self.console.state.x; let y = self.console.state.y; Self::invert(map, x * 8, y * 16, 8, 16); - self.changed.insert(y); + line_changed(y); } let width = map.width.try_into().unwrap(); - let mut damage: Vec = vec![]; - let mut last_change = usize::MAX - 1; - for &change in &self.changed { - if change == last_change + 1 { - damage.last_mut().unwrap().height += 16; - } else { - damage.push(Damage { - x: 0, - y: u32::try_from(change).unwrap() * 16, - width, - height: 16, - }); - } - last_change = change; - } - - self.changed.clear(); + let damage = Damage { + x: 0, + y: u32::try_from(min_changed).unwrap() * 16, + width, + height: u32::try_from(max_changed.saturating_sub(min_changed)).unwrap() * 16, + }; damage } diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index cfe0089928..03cab9c6e7 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -16,12 +16,7 @@ pub trait GraphicsAdapter { fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer; fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8; - fn update_plane( - &mut self, - display_id: usize, - framebuffer: &Self::Framebuffer, - damage: &[Damage], - ); + fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage); } pub trait Framebuffer { @@ -137,12 +132,12 @@ impl GraphicsScheme { adapter.update_plane( screen, framebuffer, - &[Damage { + Damage { x: 0, y: 0, width: framebuffer.width(), height: framebuffer.height(), - }], + }, ); } } @@ -227,12 +222,8 @@ impl Scheme for GraphicsScheme { let framebuffer = &self.vts_fb[vt][screen]; - let damage = unsafe { - core::slice::from_raw_parts( - buf.as_ptr() as *const Damage, - buf.len() / core::mem::size_of::(), - ) - }; + assert_eq!(buf.len(), std::mem::size_of::()); + let damage = unsafe { *buf.as_ptr().cast::() }; self.adapter.update_plane(*screen, framebuffer, damage); diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 3b66ae5dca..17166c43af 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -102,7 +102,7 @@ impl Scheme for FbbootlogScheme { ); if let Some(map) = &self.display_map { - map.display_handle.sync_rects(&damage).unwrap(); + map.display_handle.sync_rect(damage).unwrap(); } } diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 60d7a18218..d95d0c7789 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -55,9 +55,9 @@ impl Display { V1GraphicsHandle::from_file(display_file) } - pub fn sync_rects(&mut self, sync_rects: Vec) { + pub fn sync_rect(&mut self, sync_rect: Damage) { if let Some(map) = &self.map { - map.display_handle.sync_rects(&sync_rects).unwrap(); + map.display_handle.sync_rect(sync_rect).unwrap(); } } } diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index 11d4c7ca19..e503488bfc 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -132,7 +132,7 @@ impl TextScreen { &mut self.input, ); - self.display.sync_rects(damage); + self.display.sync_rect(damage); } Ok(buf.len()) diff --git a/graphics/graphics-ipc/src/v1.rs b/graphics/graphics-ipc/src/v1.rs index ddebae9c1a..2ff0ddf900 100644 --- a/graphics/graphics-ipc/src/v1.rs +++ b/graphics/graphics-ipc/src/v1.rs @@ -64,11 +64,11 @@ impl V1GraphicsHandle { Ok(()) } - pub fn sync_rects(&self, sync_rects: &[Damage]) -> io::Result<()> { + pub fn sync_rect(&self, sync_rect: Damage) -> io::Result<()> { libredox::call::write(self.file.as_raw_fd() as usize, unsafe { slice::from_raw_parts( - sync_rects.as_ptr() as *const u8, - sync_rects.len() * mem::size_of::(), + ptr::addr_of!(sync_rect).cast::(), + mem::size_of::(), ) })?; Ok(()) diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 32e3a22436..d89b5e600a 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -34,12 +34,7 @@ impl GraphicsAdapter for FbAdapter { framebuffer.ptr.as_ptr().cast::() } - fn update_plane( - &mut self, - display_id: usize, - framebuffer: &Self::Framebuffer, - damage: &[Damage], - ) { + fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage) { framebuffer.sync(&mut self.framebuffers[display_id], damage) } } @@ -89,29 +84,27 @@ impl Framebuffer for GraphicScreen { } impl GraphicScreen { - fn sync(&self, framebuffer: &mut FrameBuffer, sync_rects: &[Damage]) { - for sync_rect in sync_rects { - let sync_rect = sync_rect.clip( - self.width.try_into().unwrap(), - self.height.try_into().unwrap(), - ); + fn sync(&self, framebuffer: &mut FrameBuffer, sync_rect: Damage) { + let sync_rect = sync_rect.clip( + self.width.try_into().unwrap(), + self.height.try_into().unwrap(), + ); - let start_x: usize = sync_rect.x.try_into().unwrap(); - let start_y: usize = sync_rect.y.try_into().unwrap(); - let w: usize = sync_rect.width.try_into().unwrap(); - let h: usize = sync_rect.height.try_into().unwrap(); + let start_x: usize = sync_rect.x.try_into().unwrap(); + let start_y: usize = sync_rect.y.try_into().unwrap(); + let w: usize = sync_rect.width.try_into().unwrap(); + let h: usize = sync_rect.height.try_into().unwrap(); - let offscreen_ptr = self.ptr.as_ptr() as *mut u32; - let onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable + let offscreen_ptr = self.ptr.as_ptr() as *mut u32; + let onscreen_ptr = framebuffer.onscreen as *mut u32; // FIXME use as_mut_ptr once stable - for row in start_y..start_y + h { - unsafe { - ptr::copy( - offscreen_ptr.add(row * self.width + start_x), - onscreen_ptr.add(row * framebuffer.stride + start_x), - w, - ); - } + for row in start_y..start_y + h { + unsafe { + ptr::copy( + offscreen_ptr.add(row * self.width + start_x), + onscreen_ptr.add(row * framebuffer.stride + start_x), + w, + ); } } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index b6eda2e2b0..41ee3c31ca 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -170,12 +170,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { framebuffer.sgl.as_ptr() } - fn update_plane( - &mut self, - display_id: usize, - framebuffer: &Self::Framebuffer, - damage: &[Damage], - ) { + fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage) { futures::executor::block_on(async { let req = Dma::new(XferToHost2d::new( framebuffer.id, @@ -204,14 +199,12 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { self.displays[display_id].active_resource = Some(framebuffer.id); } - for damage in damage { - let flush = ResourceFlush::new( - framebuffer.id, - damage.clip(framebuffer.width, framebuffer.height).into(), - ); - let header = self.send_request(Dma::new(flush).unwrap()).await.unwrap(); - assert_eq!(header.ty, CommandTy::RespOkNodata); - } + let flush = ResourceFlush::new( + framebuffer.id, + damage.clip(framebuffer.width, framebuffer.height).into(), + ); + let header = self.send_request(Dma::new(flush).unwrap()).await.unwrap(); + assert_eq!(header.ty, CommandTy::RespOkNodata); }); } } From fb24979c516e51d98f016771e4e821ba3a5dab20 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 21:09:12 +0100 Subject: [PATCH 1147/1301] Reduce verbosity of debug logs during booting These logs are only useful when actively working on the respective driver. --- graphics/driver-graphics/src/lib.rs | 10 ++++------ pcid/src/cfg_access/mod.rs | 4 ++-- pcid/src/driver_interface/cap.rs | 10 +++++----- virtio-core/src/probe.rs | 2 -- 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 03cab9c6e7..f06dbf59b4 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -154,8 +154,6 @@ impl Scheme for GraphicsScheme { let vt = screen.next().unwrap_or("").parse::().unwrap(); let id = screen.next().unwrap_or("").parse::().unwrap_or(0); - dbg!(vt, id); - if id >= self.adapter.displays().len() { return Err(Error::new(EINVAL)); } @@ -233,11 +231,11 @@ impl Scheme for GraphicsScheme { fn mmap_prep( &mut self, id: usize, - offset: u64, - size: usize, - flags: MapFlags, + _offset: u64, + _size: usize, + _flags: MapFlags, ) -> syscall::Result { - log::info!("KSMSG MMAP {} {:?} {} {}", id, flags, offset, size); + // log::trace!("KSMSG MMAP {} {:?} {} {}", id, _flags, _offset, _size); let handle = self.handles.get(&id).ok_or(Error::new(EINVAL))?; let Handle::Screen { vt, screen } = handle; let framebuffer = &self.vts_fb[vt][screen]; diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index 476592dd66..58de2a5556 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -151,8 +151,8 @@ impl Mcfg { if table_filename.get(0..4) == Some(&MCFG_NAME) { let bytes = fs::read(table_path)?.into_boxed_slice(); match Mcfg::parse(&*bytes) { - Some((mcfg, allocs)) => { - log::info!("MCFG {mcfg:?} ALLOCS {allocs:?}"); + Some((_mcfg, allocs)) => { + log::info!("MCFG ALLOCS {:?}", allocs.0); return f(allocs, Vec::new(), [u32::MAX, u32::MAX, u32::MAX, u32::MAX]); } None => { diff --git a/pcid/src/driver_interface/cap.rs b/pcid/src/driver_interface/cap.rs index 4e1b746a6d..19521608f8 100644 --- a/pcid/src/driver_interface/cap.rs +++ b/pcid/src/driver_interface/cap.rs @@ -10,12 +10,12 @@ pub struct VendorSpecificCapability { impl VendorSpecificCapability { pub unsafe fn parse(addr: PciCapabilityAddress, access: &dyn ConfigRegionAccess) -> Self { let dword = access.read(addr.address, addr.offset); - let next = (dword >> 8) & 0xFF; let length = ((dword >> 16) & 0xFF) as u16; - log::info!( - "Vendor specific offset: {:#02x} next: {next:#02x} cap len: {length:#02x}", - addr.offset - ); + // let next = (dword >> 8) & 0xFF; + // log::trace!( + // "Vendor specific offset: {:#02x} next: {next:#02x} cap len: {length:#02x}", + // addr.offset + // ); let data = if length > 0 { assert!( length > 3 && length % 4 == 0, diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index 25cf1efb92..be3977d96b 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -122,8 +122,6 @@ pub fn probe_device(pcid_handle: &mut PciFunctionHandle) -> Result unreachable!(), } - - log::trace!("virtio-core::device-probe: {capability:?}"); } let common_addr = common_addr.expect("virtio common capability missing"); From 7e6534ff35359870aa1cf6ad78005c71dfbcd21d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 22:09:14 +0100 Subject: [PATCH 1148/1301] graphics/console-draw: Fix damage calculation --- graphics/console-draw/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index 82d180501f..2cf93db76c 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -221,7 +221,7 @@ impl TextScreen { x: 0, y: u32::try_from(min_changed).unwrap() * 16, width, - height: u32::try_from(max_changed.saturating_sub(min_changed)).unwrap() * 16, + height: u32::try_from(max_changed.saturating_sub(min_changed) + 1).unwrap() * 16, }; damage From 980414e7e74b2d18e1ab520bba851abfcbb256d9 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Mar 2025 11:51:58 -0600 Subject: [PATCH 1149/1301] usbhidd: fix configuration request --- input/usbhidd/src/main.rs | 9 ++++----- usbhubd/src/main.rs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/input/usbhidd/src/main.rs b/input/usbhidd/src/main.rs index dfda4cd472..da4e798cdd 100644 --- a/input/usbhidd/src/main.rs +++ b/input/usbhidd/src/main.rs @@ -204,11 +204,10 @@ fn main() { log::info!("{:X?}", desc); let mut endp_count = 0; - let (conf_desc, conf_num, (if_desc, endp_desc_opt, hid_desc)) = desc + let (conf_desc, (if_desc, endp_desc_opt, hid_desc)) = desc .config_descs .iter() - .enumerate() - .find_map(|(conf_num, conf_desc)| { + .find_map(|conf_desc| { let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { if if_desc.number == interface_num { let endp_desc_opt = if_desc.endpoints.iter().find_map(|endp_desc| { @@ -231,13 +230,13 @@ fn main() { None } })?; - Some((conf_desc.clone(), conf_num, if_desc)) + Some((conf_desc.clone(), if_desc)) }) .expect("Failed to find suitable configuration"); handle .configure_endpoints(&ConfigureEndpointsReq { - config_desc: conf_num as u8, + config_desc: conf_desc.configuration_value, interface_desc: Some(interface_num), alternate_setting: Some(if_desc.alternate_setting), }) diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index f95b8a7a92..d3ed91f182 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -61,7 +61,7 @@ fn main() { /*TODO handle .configure_endpoints(&ConfigureEndpointsReq { - config_desc: conf_num as u8, + config_desc: conf_desc.configuration_value, interface_desc: Some(interface_num), alternate_setting: Some(if_desc.alternate_setting), }) From 2299bb0b27751d674d72d793923e211d92e560a5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Mar 2025 13:24:16 -0600 Subject: [PATCH 1150/1301] xhcid: fix panic when no ssc is available --- xhcid/src/xhci/scheme.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 36190e834c..f7a5a803c7 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -874,10 +874,10 @@ impl Xhci { if dev_desc.major_version() == 2 && endp_desc.is_periodic() { u32::from(max_packet_size) * (u32::from(max_burst_size) + 1) - } else if !endp_desc.has_ssp_companion() { - u32::from(endp_desc.ssc.as_ref().unwrap().bytes_per_interval) } else if endp_desc.has_ssp_companion() { endp_desc.sspc.as_ref().unwrap().bytes_per_interval + } else if endp_desc.ssc.is_some() { + u32::from(endp_desc.ssc.as_ref().unwrap().bytes_per_interval) } else if speed_id.is_fullspeed() && endp_desc.is_interrupt() { 64 } else if speed_id.is_fullspeed() && endp_desc.is_isoch() { From 68760cf5af55cf24798d53dec4d3a8ea299b8015 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Mar 2025 13:24:45 -0600 Subject: [PATCH 1151/1301] Improve USB hub driver --- usbhubd/src/main.rs | 114 +++++++++++++++++++++++++++----------------- 1 file changed, 70 insertions(+), 44 deletions(-) diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index d3ed91f182..c029c278c7 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -1,7 +1,7 @@ -use std::env; +use std::{env, thread, time}; use xhcid_interface::{ - plain, usb, DevDesc, DeviceReqData, PortReqRecipient, PortReqTy, XhciClientHandle, + plain, usb, ConfigureEndpointsReq, DevDesc, DeviceReqData, PortReqRecipient, PortReqTy, XhciClientHandle, }; fn main() { @@ -42,11 +42,10 @@ fn main() { .expect("Failed to get standard descriptors"); log::info!("{:X?}", desc); - let (conf_desc, conf_num, if_desc) = desc + let (conf_desc, if_desc) = desc .config_descs .iter() - .enumerate() - .find_map(|(conf_num, conf_desc)| { + .find_map(|conf_desc| { let if_desc = conf_desc.interface_descs.iter().find_map(|if_desc| { if if_desc.number == interface_num { Some(if_desc.clone()) @@ -54,11 +53,10 @@ fn main() { None } })?; - Some((conf_desc.clone(), conf_num, if_desc)) + Some((conf_desc.clone(), if_desc)) }) .expect("Failed to find suitable configuration"); - /*TODO handle .configure_endpoints(&ConfigureEndpointsReq { config_desc: conf_desc.configuration_value, @@ -66,7 +64,6 @@ fn main() { alternate_setting: Some(if_desc.alternate_setting), }) .expect("Failed to configure endpoints"); - */ let mut hub_desc = usb::HubDescriptor::default(); handle @@ -82,50 +79,79 @@ fn main() { .expect("Failed to retrieve hub descriptor"); log::info!("{:X?}", hub_desc); - for port in 1..=hub_desc.ports { - log::info!("power on port {port}"); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Other, - usb::SetupReq::SetFeature as u8, - usb::HubFeature::PortPower as u16, - port as u16, - DeviceReqData::NoData, - ) - .expect("Failed to set port power"); - } - - for port in 1..=hub_desc.ports { - let mut port_sts = usb::HubPortStatus::default(); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Other, - usb::SetupReq::GetStatus as u8, - 0, - port as u16, - DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut port_sts) }), - ) - .expect("Failed to retrieve port status"); - log::info!("port {} status {:X?}", port, port_sts); - - if port_sts.contains(usb::HubPortStatus::CONNECTION) { - /*TODO - log::info!("reset port {port}"); + //TODO: use change flags? + let mut last_port_statuses = vec![usb::HubPortStatus::default(); hub_desc.ports.into()]; + loop { + for port in 1..=hub_desc.ports { + let mut port_sts = usb::HubPortStatus::default(); handle .device_request( PortReqTy::Class, PortReqRecipient::Other, - usb::SetupReq::SetFeature as u8, - usb::HubFeature::PortReset as u16, + usb::SetupReq::GetStatus as u8, + 0, port as u16, - DeviceReqData::NoData, + DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut port_sts) }), ) - .expect("Failed to set port enable"); - */ + .expect("Failed to retrieve port status"); + + { + let port_idx: usize = port.checked_sub(1).unwrap().into(); + let last_port_sts = last_port_statuses.get_mut(port_idx).unwrap(); + if *last_port_sts != port_sts { + *last_port_sts = port_sts; + log::info!("port {} status {:X?}", port, port_sts); + } + } + + // Ensure port is powered on + if !port_sts.contains(usb::HubPortStatus::POWER) { + log::info!("power on port {port}"); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Other, + usb::SetupReq::SetFeature as u8, + usb::HubFeature::PortPower as u16, + port as u16, + DeviceReqData::NoData, + ) + .expect("Failed to set port power"); + continue; + } + + // Ignore disconnected port + //TODO: turn off disconnected ports? + if !port_sts.contains(usb::HubPortStatus::CONNECTION) { + continue; + } + + // Ignore port in reset + if port_sts.contains(usb::HubPortStatus::RESET) { + continue; + } + + // Ensure port is enabled + if !port_sts.contains(usb::HubPortStatus::ENABLE) { + log::info!("reset port {port}"); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Other, + usb::SetupReq::SetFeature as u8, + usb::HubFeature::PortReset as u16, + port as u16, + DeviceReqData::NoData, + ) + .expect("Failed to set port enable"); + continue; + } + //TODO: address device } + + //TODO: use interrupts or poll faster? + thread::sleep(time::Duration::new(1, 0)); } //TODO: read interrupt port for changes From e3a13a0ce7d080d59c0fbc746e417af5a533b189 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Mar 2025 21:27:17 -0600 Subject: [PATCH 1152/1301] xhcid and friends: use newtype PortId to ensure route string can be passed where needed --- input/usbhidd/src/main.rs | 7 +- storage/usbscsid/src/main.rs | 8 +- usbctl/src/main.rs | 6 +- usbhubd/src/main.rs | 11 +- xhcid/src/driver_interface.rs | 74 ++++++++++- xhcid/src/xhci/device_enumerator.rs | 47 +++---- xhcid/src/xhci/irq_reactor.rs | 10 +- xhcid/src/xhci/mod.rs | 141 ++++++++++----------- xhcid/src/xhci/scheme.rs | 189 +++++++++++++++------------- 9 files changed, 283 insertions(+), 210 deletions(-) diff --git a/input/usbhidd/src/main.rs b/input/usbhidd/src/main.rs index da4e798cdd..da6af6a82e 100644 --- a/input/usbhidd/src/main.rs +++ b/input/usbhidd/src/main.rs @@ -8,7 +8,8 @@ use rehid::{ usage_tables::{GenericDesktopUsage, UsagePage}, }; use xhcid_interface::{ - ConfigureEndpointsReq, DevDesc, EndpDirection, EndpointTy, PortReqRecipient, XhciClientHandle, + ConfigureEndpointsReq, DevDesc, EndpDirection, EndpointTy, PortId, PortReqRecipient, + XhciClientHandle, }; mod keymap; @@ -182,8 +183,8 @@ fn main() { let port = args .next() .expect(USAGE) - .parse::() - .expect("Expected integer as input of port"); + .parse::() + .expect("Expected port ID"); let interface_num = args .next() .expect(USAGE) diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index 9950814e7c..ff87d2109e 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -3,7 +3,7 @@ use std::env; use driver_block::{Disk, DiskScheme}; use syscall::{Error, EIO}; -use xhcid_interface::{ConfigureEndpointsReq, XhciClientHandle}; +use xhcid_interface::{ConfigureEndpointsReq, PortId, XhciClientHandle}; pub mod protocol; pub mod scsi; @@ -20,8 +20,8 @@ fn main() { let port = args .next() .expect(USAGE) - .parse::() - .expect("port has to be a number"); + .parse::() + .expect("Expected port ID"); let protocol = args .next() .expect(USAGE) @@ -36,7 +36,7 @@ fn main() { redox_daemon::Daemon::new(move |d| daemon(d, scheme, port, protocol)) .expect("usbscsid: failed to daemonize"); } -fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: usize, protocol: u8) -> ! { +fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: PortId, protocol: u8) -> ! { let disk_scheme_name = format!("disk.usb-{scheme}+{port}-scsi"); // TODO: Use eventfds. diff --git a/usbctl/src/main.rs b/usbctl/src/main.rs index fb2f20d1c1..517cde041a 100644 --- a/usbctl/src/main.rs +++ b/usbctl/src/main.rs @@ -1,5 +1,5 @@ use clap::{App, Arg}; -use xhcid_interface::XhciClientHandle; +use xhcid_interface::{PortId, XhciClientHandle}; fn main() { let matches = App::new("usbctl") @@ -32,8 +32,8 @@ fn main() { let port = port_scmd_matches .value_of("PORT") .expect("invalid utf-8 for PORT argument") - .parse::() - .expect("expected PORT to be an integer"); + .parse::() + .expect("expected PORT ID"); let handle = XhciClientHandle::new(scheme.to_owned(), port); diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index c029c278c7..198641cc1a 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -1,7 +1,8 @@ use std::{env, thread, time}; use xhcid_interface::{ - plain, usb, ConfigureEndpointsReq, DevDesc, DeviceReqData, PortReqRecipient, PortReqTy, XhciClientHandle, + plain, usb, ConfigureEndpointsReq, DevDesc, DeviceReqData, PortId, PortReqRecipient, PortReqTy, + XhciClientHandle, }; fn main() { @@ -21,8 +22,8 @@ fn main() { let port = args .next() .expect(USAGE) - .parse::() - .expect("Expected integer as input of port"); + .parse::() + .expect("Expected port ID"); let interface_num = args .next() .expect(USAGE) @@ -40,7 +41,6 @@ fn main() { let desc: DevDesc = handle .get_standard_descs() .expect("Failed to get standard descriptors"); - log::info!("{:X?}", desc); let (conf_desc, if_desc) = desc .config_descs @@ -77,10 +77,9 @@ fn main() { DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), ) .expect("Failed to retrieve hub descriptor"); - log::info!("{:X?}", hub_desc); //TODO: use change flags? - let mut last_port_statuses = vec![usb::HubPortStatus::default(); hub_desc.ports.into()]; + let mut last_port_statuses = vec![usb::HubPortStatus::default(); hub_desc.ports.into()]; loop { for port in 1..=hub_desc.ports { let mut port_sts = usb::HubPortStatus::default(); diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 37bc50d68d..d974a0468f 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -5,7 +5,7 @@ use std::convert::TryFrom; use std::fs::{File, OpenOptions}; use std::io::prelude::*; use std::num::NonZeroU8; -use std::{io, result, str}; +use std::{fmt, io, result, str}; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; @@ -280,10 +280,78 @@ pub enum PortReqRecipient { VendorSpecific, } +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct PortId { + pub root_hub_port_num: u8, + pub route_string: u32, +} + +impl PortId { + pub fn root_hub_port_index(&self) -> usize { + self.root_hub_port_num.checked_sub(1).unwrap().into() + } +} + +impl fmt::Display for PortId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.root_hub_port_num)?; + // USB 3.1 Revision 1.1 Specification Section 8.9 Route String Field + // The Route String is a 20-bit field in downstream directed packets that the hub uses to route + // each packet to the designated downstream port. It is composed of a concatenation of the + // downstream port numbers (4 bits per hub) for each hub traversed to reach a device. + // The lowest 4 bits are ignored. + let mut route_string = self.route_string >> 4; + while route_string > 0 { + write!(f, ".{}", route_string & 0xF)?; + route_string >>= 4; + } + Ok(()) + } +} + +impl str::FromStr for PortId { + type Err = String; + + fn from_str(s: &str) -> Result { + let mut root_hub_port_num = 0; + let mut route_string = 0; + for (i, part) in s.split('.').enumerate() { + let value: u8 = part + .parse() + .map_err(|e| format!("failed to parse {:?}: {}", part, e))?; + + // Parse root hub port number + if i == 0 { + root_hub_port_num = value; + continue; + } + + // Parse route string component + if value & 0xF0 != 0 { + return Err(format!( + "value {:?} is too large for route string component", + value + )); + } + route_string |= (value as u32) << (i * 4); + } + if root_hub_port_num == 0 { + return Err(format!( + "invalid root hub port number {:?}", + root_hub_port_num + )); + } + Ok(Self { + root_hub_port_num, + route_string, + }) + } +} + #[derive(Debug)] pub struct XhciClientHandle { scheme: String, - port: usize, + port: PortId, } #[repr(u8)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -410,7 +478,7 @@ impl DeviceReqData<'_> { } impl XhciClientHandle { - pub fn new(scheme: String, port: usize) -> Self { + pub fn new(scheme: String, port: PortId) -> Self { Self { scheme, port } } diff --git a/xhcid/src/xhci/device_enumerator.rs b/xhcid/src/xhci/device_enumerator.rs index 207211133b..c418ef8b07 100644 --- a/xhcid/src/xhci/device_enumerator.rs +++ b/xhcid/src/xhci/device_enumerator.rs @@ -1,5 +1,5 @@ use crate::xhci::port::PortFlags; -use crate::xhci::Xhci; +use crate::xhci::{PortId, Xhci}; use common::io::Io; use crossbeam_channel; use log::{debug, info, warn}; @@ -108,24 +108,29 @@ impl DeviceEnumerator { panic!("Failed to received an enumeration request! error: {}", err) } }; - info!("Device Enumerator request for port {}", request.port_number); - let port_array_index = request.port_number - 1; + let port_id = PortId { + root_hub_port_num: request.port_number, + route_string: 0, + }; + let port_array_index = port_id.root_hub_port_index(); + + info!("Device Enumerator request for port {}", port_id); let (len, flags) = { let ports = self.hci.ports.lock().unwrap(); let len = ports.len(); - if port_array_index as usize >= len { + if port_array_index >= len { warn!( "Received out of bounds Device Enumeration request for port {}", - request.port_number + port_id ); continue; } - (len, ports[port_array_index as usize].flags()) + (len, ports[port_array_index].flags()) }; if flags.contains(PortFlags::PORT_CCS) { @@ -145,21 +150,18 @@ impl DeviceEnumerator { if !disabled_state { panic!( "Port {} isn't in the disabled state! Current flags: {:?}", - request.port_number, flags + port_id, flags ); } else { - debug!( - "Port {} has entered the disabled state.", - request.port_number - ); + debug!("Port {} has entered the disabled state.", port_id); } //THIS LOCKS THE PORTS. DO NOT LOCK PORTS BEFORE THIS POINT - info!("Received a device connect on port {}, but it's not enabled. Resetting the port.", request.port_number); - self.hci.reset_port((port_array_index as usize)); + info!("Received a device connect on port {}, but it's not enabled. Resetting the port.", port_id); + self.hci.reset_port(port_array_index); let mut ports = self.hci.ports.lock().unwrap(); - let port = &mut ports[port_array_index as usize]; + let port = &mut ports[port_array_index]; port.portsc.writef(PortFlags::PORT_PRC.bits(), true); @@ -175,20 +177,20 @@ impl DeviceEnumerator { if !enabled_state { warn!( "Port {} isn't in the enabled state! Current flags: {:?}", - request.port_number, flags + port_id, flags ); } else { debug!( "Port {} is in the enabled state. Proceeding with enumeration", - request.port_number + port_id ); } } - let result = futures::executor::block_on(self.hci.attach_device(port_array_index)); + let result = futures::executor::block_on(self.hci.attach_device(port_id)); match result { Ok(_) => { - info!("Device on port {} was attached", port_array_index); + info!("Device on port {} was attached", port_id); } Err(err) => { if err.errno == EAGAIN { @@ -201,14 +203,13 @@ impl DeviceEnumerator { } else { info!( "Device Enumerator received Detach request on port {} which is in state {}", - request.port_number, - self.hci.get_pls((port_array_index) as usize) + port_id, + self.hci.get_pls(port_id) ); - let result = - futures::executor::block_on(self.hci.detach_device(port_array_index as usize)); + let result = futures::executor::block_on(self.hci.detach_device(port_id)); match result { Ok(_) => { - info!("Device on port {} was detached", port_array_index); + info!("Device on port {} was detached", port_id); } Err(err) => { warn!("processing of device attach request failed! Error: {}", err); diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 298e52ddcc..ee271e228e 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -14,7 +14,7 @@ use super::doorbell::Doorbell; use super::event::EventRing; use super::ring::Ring; use super::trb::{Trb, TrbCompletionCode, TrbType}; -use super::Xhci; +use super::{PortId, Xhci}; use crate::xhci::device_enumerator::DeviceEnumerationRequest; use crate::xhci::port::PortFlags; use common::io::Io as _; @@ -48,12 +48,12 @@ pub struct NextEventTrb { // indexed using this struct instead. #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub struct RingId { - pub port: u8, + pub port: PortId, pub endpoint_num: u8, pub stream_id: u16, } impl RingId { - pub const fn default_control_pipe(port: u8) -> Self { + pub const fn default_control_pipe(port: PortId) -> Self { Self { port, endpoint_num: 0, @@ -623,7 +623,7 @@ impl Xhci { pub fn with_ring T>(&self, id: RingId, function: F) -> Option { use super::RingOrStreams; - let slot_state = self.port_states.get(&(id.port as usize))?; + let slot_state = self.port_states.get(&id.port)?; let endpoint_state = slot_state.endpoint_states.get(&id.endpoint_num)?; let ring_ref = match endpoint_state.transfer { @@ -640,7 +640,7 @@ impl Xhci { ) -> Option { use super::RingOrStreams; - let mut slot_state = self.port_states.get_mut(&(id.port as usize))?; + let mut slot_state = self.port_states.get_mut(&id.port)?; let mut endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?; let ring_ref = match endpoint_state.transfer { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index a625b77216..a7cde500f5 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -59,6 +59,7 @@ use self::trb::{TransferKind, Trb, TrbCompletionCode}; use self::scheme::EndpIfState; +pub use crate::driver_interface::PortId; use crate::driver_interface::*; /// Specifies the configurable interrupt mechanism used by the xhci subsystem for registering @@ -95,7 +96,7 @@ impl Xhci { /// Gets descriptors, before the port state is initiated. async fn get_desc_raw( &self, - port: usize, + port: PortId, slot: u8, kind: usb::DescriptorKind, index: u8, @@ -147,7 +148,7 @@ impl Xhci { cmd.status(interrupter, input, ioc, ch, ent, cycle); self.next_transfer_event_trb( - RingId::default_control_pipe(port as u8), + RingId::default_control_pipe(port), &ring, &ring.trbs[first_index], &ring.trbs[last_index], @@ -168,7 +169,7 @@ impl Xhci { async fn fetch_dev_desc_8_byte( &self, - port: usize, + port: PortId, slot: u8, ) -> Result { let mut desc = unsafe { self.alloc_dma_zeroed::()? }; @@ -177,7 +178,7 @@ impl Xhci { Ok(*desc) } - async fn fetch_dev_desc(&self, port: usize, slot: u8) -> Result { + async fn fetch_dev_desc(&self, port: PortId, slot: u8) -> Result { let mut desc = unsafe { self.alloc_dma_zeroed::()? }; self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc) .await?; @@ -186,7 +187,7 @@ impl Xhci { async fn fetch_config_desc( &self, - port: usize, + port: PortId, slot: u8, config: u8, ) -> Result<(usb::ConfigDescriptor, [u8; 4087])> { @@ -204,7 +205,7 @@ impl Xhci { async fn fetch_bos_desc( &self, - port: usize, + port: PortId, slot: u8, ) -> Result<(usb::BosDescriptor, [u8; 4087])> { let mut desc = unsafe { self.alloc_dma_zeroed::<(usb::BosDescriptor, [u8; 4087])>()? }; @@ -219,7 +220,7 @@ impl Xhci { Ok(*desc) } - async fn fetch_string_desc(&self, port: usize, slot: u8, index: u8) -> Result { + async fn fetch_string_desc(&self, port: PortId, slot: u8, index: u8) -> Result { let mut sdesc = unsafe { self.alloc_dma_zeroed::<(u8, u8, [u16; 127])>()? }; self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, &mut sdesc) .await?; @@ -266,8 +267,8 @@ pub struct Xhci { handles: CHashMap, next_handle: AtomicUsize, - port_states: CHashMap, - drivers: CHashMap>, + port_states: CHashMap, + drivers: CHashMap>, scheme_name: String, interrupt_method: InterruptMethod, @@ -546,9 +547,9 @@ impl Xhci { Ok(()) } - pub fn get_pls(&self, port_num: usize) -> u32 { + pub fn get_pls(&self, port_id: PortId) -> u32 { let mut ports = self.ports.lock().unwrap(); - let port = ports.get_mut(port_num).unwrap(); + let port = ports.get_mut(port_id.root_hub_port_index()).unwrap(); let state = port.portsc.read(); (state >> 5) & 4 } @@ -594,23 +595,28 @@ impl Xhci { len = ports.len(); } - for port in 0..len { - let state = self.get_pls(port); + for root_hub_port_num in 1..=(len as u8) { + let port_id = PortId { + root_hub_port_num, + route_string: 0, + }; + + let state = self.get_pls(port_id); let mut flags; { let mut ports = self.ports.lock().unwrap(); - flags = ports[port].flags(); + flags = ports[port_id.root_hub_port_index()].flags(); } - match self.supported_protocol(port as u8) { + match self.supported_protocol(port_id) { None => { - warn!("No detected supported protocol for port {}", port); + warn!("No detected supported protocol for port {}", port_id); } Some(protocol) => { info!( "Port {} is a USB {}.{} port with slot type {} and in current state {}: {:?}", - port + 1, + port_id, protocol.rev_major(), protocol.rev_minor(), protocol.proto_slot_ty(), @@ -728,25 +734,23 @@ impl Xhci { Self::alloc_dma_zeroed_unsized_raw(self.cap.ac64(), count) } - pub async fn attach_device(&self, port_number: u8) -> syscall::Result<()> { - let i = port_number as usize; - - if self.port_states.contains_key(&i) { + pub async fn attach_device(&self, port_id: PortId) -> syscall::Result<()> { + if self.port_states.contains_key(&port_id) { return Err(syscall::Error::new(EAGAIN)); } let (data, state, speed, flags) = { - let port = &self.ports.lock().unwrap()[i]; + let port = &self.ports.lock().unwrap()[port_id.root_hub_port_index()]; (port.read(), port.state(), port.speed(), port.flags()) }; info!( "XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", - i, data, state, speed, flags + port_id, data, state, speed, flags ); if flags.contains(port::PortFlags::PORT_CCS) { - let slot_ty = match self.supported_protocol(i as u8) { + let slot_ty = match self.supported_protocol(port_id) { Some(protocol) => protocol.proto_slot_ty(), None => { warn!("Failed to find supported protocol information for port"); @@ -759,23 +763,23 @@ impl Xhci { let slot = match self.enable_port_slot(slot_ty).await { Ok(ok) => ok, Err(err) => { - error!("Failed to enable slot for port {}: {}", i, err); + error!("Failed to enable slot for port {}: {}", port_id, err); return Err(err); } }; - info!("Enabled port {}, which the xHC mapped to {}", i, slot); + info!("Enabled port {}, which the xHC mapped to {}", port_id, slot); let mut input = unsafe { self.alloc_dma_zeroed::()? }; info!("Attempting to address the device"); let mut ring = match self - .address_device(&mut input, i, slot_ty, slot, speed) + .address_device(&mut input, port_id, slot_ty, slot, speed) .await { Ok(device_ring) => device_ring, Err(err) => { - error!("Failed to spawn driver for port {}: `{}`", i, err); + error!("Failed to spawn driver for port {}: `{}`", port_id, err); return Err(err); } }; @@ -798,13 +802,13 @@ impl Xhci { )) .collect::>(), }; - self.port_states.insert(i, port_state); + self.port_states.insert(port_id, port_state); debug!("Got port states!"); // Ensure correct packet size is used - let dev_desc_8_byte = self.fetch_dev_desc_8_byte(i, slot).await?; + let dev_desc_8_byte = self.fetch_dev_desc_8_byte(port_id, slot).await?; { - let mut port_state = self.port_states.get_mut(&i).unwrap(); + let mut port_state = self.port_states.get_mut(&port_id).unwrap(); let mut input = port_state.input_context.lock().unwrap(); @@ -814,13 +818,13 @@ impl Xhci { debug!("Got the 8 byte dev descriptor"); - let dev_desc = self.get_desc(i, slot).await?; + let dev_desc = self.get_desc(port_id, slot).await?; debug!("Got the full device descriptor!"); - self.port_states.get_mut(&i).unwrap().dev_desc = Some(dev_desc); + self.port_states.get_mut(&port_id).unwrap().dev_desc = Some(dev_desc); debug!("Got the port states again!"); { - let mut port_state = self.port_states.get_mut(&i).unwrap(); + let mut port_state = self.port_states.get_mut(&port_id).unwrap(); let mut input = port_state.input_context.lock().unwrap(); debug!("Got the input context!"); @@ -832,10 +836,10 @@ impl Xhci { debug!("Updated the default control pipe"); - match self.spawn_drivers(i) { + match self.spawn_drivers(port_id) { Ok(()) => (), Err(err) => { - error!("Failed to spawn driver for port {}: `{}`", i, err) + error!("Failed to spawn driver for port {}: `{}`", port_id, err) } } } else { @@ -845,28 +849,20 @@ impl Xhci { Ok(()) } - pub async fn detach_device(&self, port_number: usize) -> Result<()> { - if let Some(children) = self.drivers.remove(&port_number) { + pub async fn detach_device(&self, port_id: PortId) -> Result<()> { + if let Some(children) = self.drivers.remove(&port_id) { for mut child in children { - info!( - "killing driver process {} for port {}", - child.id(), - port_number - ); + info!("killing driver process {} for port {}", child.id(), port_id); match child.kill() { Ok(()) => { - info!( - "killed driver process {} for port {}", - child.id(), - port_number - ); + info!("killed driver process {} for port {}", child.id(), port_id); match child.try_wait() { Ok(status_opt) => match status_opt { Some(status) => { info!( "driver process {} for port {} exited with status {}", child.id(), - port_number, + port_id, status ); } @@ -875,7 +871,7 @@ impl Xhci { info!( "driver process {} for port {} still running", child.id(), - port_number + port_id ); } }, @@ -883,7 +879,7 @@ impl Xhci { info!( "failed to wait for the driver process {} for port {}: {}", child.id(), - port_number, + port_id, err ); } @@ -893,7 +889,7 @@ impl Xhci { warn!( "failed to kill the driver process {} for port {}: {}", child.id(), - port_number, + port_id, err ); } @@ -901,22 +897,19 @@ impl Xhci { } } - if let Some(state) = self.port_states.remove(&port_number) { - info!( - "disabling port slot {} for port {}", - state.slot, port_number - ); + if let Some(state) = self.port_states.remove(&port_id) { + info!("disabling port slot {} for port {}", state.slot, port_id); let result = self.disable_port_slot(state.slot).await; info!( "disabled port slot {} for port {} with result: {:?}", - state.slot, port_number, result + state.slot, port_id, result ); result } else { warn!( "Attempted to detach from port {}, which wasn't previously attached.", - port_number + port_id ); Ok(()) } @@ -989,7 +982,7 @@ impl Xhci { pub async fn address_device( &self, input_context: &mut Dma, - i: usize, + port: PortId, slot_ty: u8, slot: u8, speed: u8, @@ -1001,7 +994,7 @@ impl Xhci { let slot_ctx = &mut input_context.device.slot; - let route_string = 0u32; // TODO + let route_string = port.route_string; let context_entries = 1u8; let mtt = false; let hub = false; @@ -1015,7 +1008,7 @@ impl Xhci { ); let max_exit_latency = 0u16; - let root_hub_port_num = (i + 1) as u8; + let root_hub_port_num = port.root_hub_port_num; let number_of_ports = 0u8; slot_ctx.b.write( u32::from(max_exit_latency) @@ -1040,7 +1033,7 @@ impl Xhci { let endp_ctx = &mut input_context.device.endpoints[0]; let speed_id = self - .lookup_psiv(root_hub_port_num, speed) + .lookup_psiv(port, speed) .expect("Failed to retrieve speed ID"); let max_error_count = 3u8; // recommended value according to the XHCI spec @@ -1085,7 +1078,7 @@ impl Xhci { error!( "Failed to address device at slot {} (port {}), completion code 0x{:X}", slot, - i, + port, event_trb.completion_code() ); //self.event_handler_finished(); @@ -1155,14 +1148,14 @@ impl Xhci { false } } - fn spawn_drivers(&self, port: usize) -> Result<()> { + fn spawn_drivers(&self, port: PortId) -> Result<()> { // TODO: There should probably be a way to select alternate interfaces, and not just the // first one. // TODO: Now that there are some good error crates, I don't think errno.h error codes are // suitable here. let ps = self.port_states.get(&port).unwrap(); - trace!("Spawning driver on port: {}", port + 1); + trace!("Spawning driver on port: {}", port); //TODO: support choosing config? let config_desc = &ps @@ -1179,7 +1172,7 @@ impl Xhci { Error::new(EBADF) })?; - trace!("Got config and device descriptors on port {}", port + 1); + trace!("Got config and device descriptors on port {}", port); let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; for ifdesc in config_desc.interface_descs.iter() { @@ -1244,14 +1237,16 @@ impl Xhci { } }) } - pub fn supported_protocol(&self, port: u8) -> Option<&'static SupportedProtoCap> { - self.supported_protocols_iter() - .find(|supp_proto| supp_proto.compat_port_range().contains(&(port + 1))) - //Increment by 1, because USB ports index themselves by 1. + pub fn supported_protocol(&self, port: PortId) -> Option<&'static SupportedProtoCap> { + self.supported_protocols_iter().find(|supp_proto| { + supp_proto + .compat_port_range() + .contains(&port.root_hub_port_num) + }) } pub fn supported_protocol_speeds( &self, - port: u8, + port: PortId, ) -> impl Iterator { use extended::*; const DEFAULT_SUPP_PROTO_SPEEDS: [ProtocolSpeed; 7] = [ @@ -1334,7 +1329,7 @@ impl Xhci { } } } - pub fn lookup_psiv(&self, port: u8, psiv: u8) -> Option<&'static ProtocolSpeed> { + pub fn lookup_psiv(&self, port: PortId, psiv: u8) -> Option<&'static ProtocolSpeed> { self.supported_protocol_speeds(port) .find(|speed| speed.psiv() == psiv) } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index f7a5a803c7..924ed612e6 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -37,7 +37,7 @@ use syscall::{ }; use super::{port, usb}; -use super::{EndpointState, Xhci}; +use super::{EndpointState, PortId, Xhci}; use super::context::{SlotState, StreamContextArray, StreamContextType}; use super::extended::ProtocolSpeed; @@ -50,21 +50,21 @@ use crate::driver_interface::*; use regex::Regex; lazy_static! { - static ref REGEX_PORT_CONFIGURE: Regex = Regex::new(r"^port(\d{1,3})/configure$") + static ref REGEX_PORT_CONFIGURE: Regex = Regex::new(r"^port([\d\.]+)/configure$") .expect("Failed to create the regex for the port/configure scheme."); - static ref REGEX_PORT_DESCRIPTORS: Regex = Regex::new(r"^port(\d{1,3})/descriptors$") + static ref REGEX_PORT_DESCRIPTORS: Regex = Regex::new(r"^port([\d\.]+)/descriptors$") .expect("Failed to create the regex for the port/descriptors"); - static ref REGEX_PORT_STATE: Regex = Regex::new(r"^port(\d{1,3})/state$") + static ref REGEX_PORT_STATE: Regex = Regex::new(r"^port([\d\.]+)/state$") .expect("Failed to create the regex for the port/state scheme"); - static ref REGEX_PORT_REQUEST: Regex = Regex::new(r"^port(\d{1,3})/request$") + static ref REGEX_PORT_REQUEST: Regex = Regex::new(r"^port([\d\.]+)/request$") .expect("Failed to create the regex for the port/request scheme"); - static ref REGEX_PORT_ENDPOINTS: Regex = Regex::new(r"^port(\d{1,3})/endpoints$") + static ref REGEX_PORT_ENDPOINTS: Regex = Regex::new(r"^port([\d\.]+)/endpoints$") .expect("Failed to create the regex for the port/endpoints scheme"); static ref REGEX_PORT_SPECIFIC_ENDPOINT: Regex = - Regex::new(r"^port(\d{1,3})/endpoints/(\d{1,3})$") + Regex::new(r"^port([\d\.]+)/endpoints/(\d{1,3})$") .expect("Failed to create the regex for the port/endpoints/ scheme"); static ref REGEX_PORT_SUB_ENDPOINT: Regex = Regex::new( - r"port(\d{1,3})/endpoints/(\d{1,3})/(ctl|data)$" + r"port([\d\.]+)/endpoints/(\d{1,3})/(ctl|data)$" ) .expect("Failed to create the regex for the port/endpoints// scheme"); static ref REGEX_TOP_LEVEL: Regex = @@ -123,14 +123,14 @@ pub enum PortReqState { /// Contains some information about the data requested via the handle. #[derive(Debug)] pub enum Handle { - TopLevel(Vec), // contents (ports) - Port(usize, Vec), // port, contents - PortDesc(usize, Vec), // port, contents - PortState(usize), // port - PortReq(usize, PortReqState), // port, state - Endpoints(usize, Vec), // port, contents - Endpoint(usize, u8, EndpointHandleTy), // port, endpoint, state - ConfigureEndpoints(usize), // port + TopLevel(Vec), // contents (ports) + Port(PortId, Vec), // port, contents + PortDesc(PortId, Vec), // port, contents + PortState(PortId), // port + PortReq(PortId, PortReqState), // port, state + Endpoints(PortId, Vec), // port, contents + Endpoint(PortId, u8, EndpointHandleTy), // port, endpoint, state + ConfigureEndpoints(PortId), // port } /// The type of handle. @@ -154,22 +154,22 @@ enum SchemeParameters { /// The scheme references the top-level XHCI driver endpoint TopLevel, /// /port - Port(usize), // port number + Port(PortId), // port number /// /port/descriptors - PortDesc(usize), // port number + PortDesc(PortId), // port number /// /port/state - PortState(usize), // port number + PortState(PortId), // port number /// /port/request - PortReq(usize), // port number + PortReq(PortId), // port number /// /port/endpoints - Endpoints(usize), // port number + Endpoints(PortId), // port number /// /port/endpoints//(data|ctl) /// /// This can also represent /// /port/endpoints/ - Endpoint(usize, u8, String), // port number, endpoint number, handle type + Endpoint(PortId, u8, String), // port number, endpoint number, handle type /// /port/configure - ConfigureEndpoints(usize), // port number + ConfigureEndpoints(PortId), // port number } impl Handle { @@ -305,15 +305,15 @@ impl SchemeParameters { Err(Error::new(ENOENT)) }; - fn get_usize_from_regex( + fn get_port_id_from_regex( rgx: &Regex, scheme: &str, capture_idx: usize, - ) -> syscall::Result { + ) -> syscall::Result { if let Some(capture_list) = rgx.captures(scheme) { if let Some(value) = capture_list.get(capture_idx + 1) { - if let Ok(integer) = value.as_str().parse::() { - return Ok(integer); + if let Ok(port_id) = value.as_str().parse::() { + return Ok(port_id); } } } @@ -342,32 +342,32 @@ impl SchemeParameters { //Check if we have a match and either return a partially initialized scheme, OR ENOENT if REGEX_PORT_CONFIGURE.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_CONFIGURE, scheme, 0)?; + let port_num = get_port_id_from_regex(®EX_PORT_CONFIGURE, scheme, 0)?; Ok(Self::ConfigureEndpoints(port_num)) } else if REGEX_PORT_DESCRIPTORS.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_DESCRIPTORS, scheme, 0)?; + let port_num = get_port_id_from_regex(®EX_PORT_DESCRIPTORS, scheme, 0)?; Ok(Self::PortDesc(port_num)) } else if REGEX_PORT_STATE.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_STATE, scheme, 0)?; + let port_num = get_port_id_from_regex(®EX_PORT_STATE, scheme, 0)?; Ok(Self::PortState(port_num)) } else if REGEX_PORT_REQUEST.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_REQUEST, scheme, 0)?; + let port_num = get_port_id_from_regex(®EX_PORT_REQUEST, scheme, 0)?; Ok(Self::PortReq(port_num)) } else if REGEX_PORT_ENDPOINTS.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_ENDPOINTS, scheme, 0)?; + let port_num = get_port_id_from_regex(®EX_PORT_ENDPOINTS, scheme, 0)?; Ok(Self::Endpoints(port_num)) } else if REGEX_PORT_SPECIFIC_ENDPOINT.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_SPECIFIC_ENDPOINT, scheme, 0)?; + let port_num = get_port_id_from_regex(®EX_PORT_SPECIFIC_ENDPOINT, scheme, 0)?; let endpoint_num = get_u8_from_regex(®EX_PORT_SPECIFIC_ENDPOINT, scheme, 1)?; Ok(Self::Endpoint(port_num, endpoint_num, String::from("root"))) } else if REGEX_PORT_SUB_ENDPOINT.is_match(scheme) { - let port_num = get_usize_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 0)?; + let port_num = get_port_id_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 0)?; let endpoint_num = get_u8_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 1)?; let handle_type = get_string_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 2)?; @@ -517,7 +517,7 @@ impl AnyDescriptor { impl Xhci { async fn new_if_desc( &self, - port_id: usize, + port_id: PortId, slot: u8, desc: usb::InterfaceDescriptor, endps: impl IntoIterator, @@ -588,7 +588,7 @@ impl Xhci { } pub async fn execute_control_transfer( &self, - port_num: usize, + port_num: PortId, setup: usb::Setup, tk: TransferKind, name: &str, @@ -634,7 +634,7 @@ impl Xhci { cmd.status(interrupter, input, ioc, ch, ent, cycle); self.next_transfer_event_trb( - RingId::default_control_pipe(port_num as u8), + RingId::default_control_pipe(port_num), ring, &ring.trbs[first_index], &ring.trbs[last_index], @@ -658,7 +658,7 @@ impl Xhci { /// will never complete. pub async fn execute_transfer( &self, - port_num: usize, + port_num: PortId, endp_num: u8, stream_id: u16, name: &str, @@ -714,7 +714,7 @@ impl Xhci { ControlFlow::Break => { break self.next_transfer_event_trb( super::irq_reactor::RingId { - port: port_num as u8, + port: port_num, endpoint_num: endp_num, stream_id, }, @@ -758,7 +758,7 @@ impl Xhci { Ok(event_trb) } - async fn device_req_no_data(&self, port: usize, req: usb::Setup) -> Result<()> { + async fn device_req_no_data(&self, port: PortId, req: usb::Setup) -> Result<()> { trace!("DEVICE_REQ_NO_DATA port {}, req: {:?}", port, req); self.execute_control_transfer( @@ -772,7 +772,7 @@ impl Xhci { Ok(()) } - async fn set_configuration(&self, port: usize, config: u8) -> Result<()> { + async fn set_configuration(&self, port: PortId, config: u8) -> Result<()> { debug!("Setting configuration value {} to port {}", config, port); self.device_req_no_data(port, usb::Setup::set_configuration(config)) .await @@ -780,7 +780,7 @@ impl Xhci { async fn set_interface( &self, - port: usize, + port: PortId, interface_num: u8, alternate_setting: u8, ) -> Result<()> { @@ -795,7 +795,7 @@ impl Xhci { .await } - async fn reset_endpoint(&self, port_num: usize, endp_num: u8, tsp: bool) -> Result<()> { + async fn reset_endpoint(&self, port_num: PortId, endp_num: u8, tsp: bool) -> Result<()> { let endp_idx = endp_num.checked_sub(1).ok_or(Error::new(EIO))?; let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; @@ -894,19 +894,22 @@ impl Xhci { } } - fn port_state(&self, port: usize) -> Result> { + fn port_state( + &self, + port: PortId, + ) -> Result> { self.port_states.get(&port).ok_or(Error::new(EBADF)) } fn port_state_mut( &self, - port: usize, - ) -> Result> { + port: PortId, + ) -> Result> { self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) } async fn configure_endpoints_once( &self, - port: usize, + port: PortId, req: &ConfigureEndpointsReq, ) -> Result<()> { let (endp_desc_count, new_context_entries, configuration_value) = { @@ -951,12 +954,11 @@ impl Xhci { let lec = self.cap.lec(); let log_max_psa_size = self.cap.max_psa_size(); - let port_speed_id = self.ports.lock().unwrap()[port].speed(); - let speed_id: &ProtocolSpeed = - self.lookup_psiv(port as u8, port_speed_id).ok_or_else(|| { - warn!("no speed_id"); - Error::new(EIO) - })?; + let port_speed_id = self.ports.lock().unwrap()[port.root_hub_port_index()].speed(); + let speed_id: &ProtocolSpeed = self.lookup_psiv(port, port_speed_id).ok_or_else(|| { + warn!("no speed_id"); + Error::new(EIO) + })?; { let port_state = self.port_states.get(&port).ok_or(Error::new(EBADFD))?; @@ -1155,7 +1157,7 @@ impl Xhci { Ok(()) } - async fn configure_endpoints(&self, port: usize, json_buf: &[u8]) -> Result<()> { + async fn configure_endpoints(&self, port: PortId, json_buf: &[u8]) -> Result<()> { let mut req: ConfigureEndpointsReq = serde_json::from_slice(json_buf).or(Err(Error::new(EBADMSG)))?; @@ -1188,7 +1190,7 @@ impl Xhci { } async fn transfer_read( &self, - port_num: usize, + port_num: PortId, endp_idx: u8, buf: &mut [u8], ) -> Result<(u8, u32)> { @@ -1211,7 +1213,7 @@ impl Xhci { } async fn transfer_write( &self, - port_num: usize, + port_num: PortId, endp_idx: u8, sbuf: &[u8], ) -> Result<(u8, u32)> { @@ -1267,7 +1269,7 @@ impl Xhci { // TODO: Rename DeviceReqData to something more general. async fn transfer( &self, - port_num: usize, + port_num: PortId, endp_idx: u8, dma_buf: Option>, direction: PortReqDirection, @@ -1386,9 +1388,11 @@ impl Xhci { Ok((event.completion_code(), bytes_transferred, dma_buf)) } - pub async fn get_desc(&self, port_id: usize, slot: u8) -> Result { + pub async fn get_desc(&self, port_id: PortId, slot: u8) -> Result { let ports = self.ports.lock().unwrap(); - let port = ports.get(port_id).ok_or(Error::new(ENOENT))?; + let port = ports + .get(port_id.root_hub_port_index()) + .ok_or(Error::new(ENOENT))?; if !port.flags().contains(port::PortFlags::PORT_CCS) { return Err(Error::new(ENOENT)); } @@ -1544,7 +1548,7 @@ impl Xhci { config_descs, }) } - fn port_desc_json(&self, port_id: usize) -> Result> { + fn port_desc_json(&self, port_id: PortId) -> Result> { let dev_desc = &self .port_states .get(&port_id) @@ -1561,7 +1565,7 @@ impl Xhci { } async fn port_req_transfer( &self, - port_num: usize, + port_num: PortId, data_buffer: Option<&mut Dma<[u8]>>, setup: usb::Setup, transfer_kind: TransferKind, @@ -1584,7 +1588,7 @@ impl Xhci { .await?; Ok(()) } - fn port_req_init_st(&self, port_num: usize, req: &PortReq) -> Result { + fn port_req_init_st(&self, port_num: PortId, req: &PortReq) -> Result { use usb::setup::*; let direction = ReqDirection::from(req.direction); @@ -1634,7 +1638,7 @@ impl Xhci { async fn handle_port_req_write( &self, fd: usize, - port_num: usize, + port_num: PortId, mut st: PortReqState, buf: &[u8], ) -> Result { @@ -1678,7 +1682,7 @@ impl Xhci { async fn handle_port_req_read( &self, fd: usize, - port_num: usize, + port_num: PortId, mut st: PortReqState, buf: &mut [u8], ) -> Result { @@ -1743,7 +1747,7 @@ impl Xhci { /// implements open() for /port/descriptors /// /// # Arguments - /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'port_num: [PortId]' - The port number specified in the scheme path /// - 'flags: [usize]' - The flags parameter passed to open() /// /// # Returns @@ -1751,7 +1755,7 @@ impl Xhci { /// /// - [Handle::PortDesc] - The handle was opened successfully /// - [ENOTDIR] - Directory-specific flags were passed to open(), but this endpoint is not a directory. - fn open_handle_port_descriptors(&self, port_num: usize, flags: usize) -> Result { + fn open_handle_port_descriptors(&self, port_num: PortId, flags: usize) -> Result { if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { return Err(Error::new(ENOTDIR)); } @@ -1763,7 +1767,7 @@ impl Xhci { /// implements open() for /port /// /// # Arguments - /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'port_num: [PortId]' - The port number specified in the scheme path /// - 'flags: [usize]' - The flags parameter passed to open() /// /// # Returns @@ -1772,7 +1776,7 @@ impl Xhci { /// - [Handle::Port] - The handle was opened successfully /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open - fn open_handle_port(&self, port_num: usize, flags: usize) -> Result { + fn open_handle_port(&self, port_num: PortId, flags: usize) -> Result { // The != here is unintuitive. You would assume that you could do // flags & O_DIRECTORY || flags & O_STAT, but rust doesn't allow // you to cast integers to booleans. @@ -1800,7 +1804,7 @@ impl Xhci { /// implements open() for /port/state /// /// # Arguments - /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'port_num: [PortId]' - The port number specified in the scheme path /// - 'flags: [usize]' - The flags parameter passed to open() /// /// # Returns @@ -1808,7 +1812,7 @@ impl Xhci { /// /// - [Handle::Port] - The handle was opened successfully /// - [ENOTDIR] - open() was called on this scheme endpoint, but directory-specific flags were passed to open - fn open_handle_port_state(&self, port_num: usize, flags: usize) -> Result { + fn open_handle_port_state(&self, port_num: PortId, flags: usize) -> Result { if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { return Err(Error::new(ENOTDIR)); } @@ -1819,7 +1823,7 @@ impl Xhci { /// implements open() for /port/endpoints /// /// # Arguments - /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'port_num: [PortId]' - The port number specified in the scheme path /// - 'flags: [usize]' - The flags parameter passed to open() /// /// # Returns @@ -1827,7 +1831,7 @@ impl Xhci { /// /// - [Handle::Port] - The handle was opened successfully /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open - fn open_handle_port_endpoints(&self, port_num: usize, flags: usize) -> Result { + fn open_handle_port_endpoints(&self, port_num: PortId, flags: usize) -> Result { if flags & O_DIRECTORY == 0 && flags & O_STAT == 0 { return Err(Error::new(EISDIR)); }; @@ -1848,7 +1852,7 @@ impl Xhci { /// implements open() for /port/endpoints/ /// /// # Arguments - /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'port_num: [PortId]' - The port number specified in the scheme path /// - 'endpoint_num: [u8]' - The endpoint number to access /// - 'flags: [usize]' - The flags parameter passed to open() /// @@ -1860,7 +1864,7 @@ impl Xhci { /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num fn open_handle_endpoint_root( &self, - port_num: usize, + port_num: PortId, endpoint_num: u8, flags: usize, ) -> Result { @@ -1892,7 +1896,7 @@ impl Xhci { /// implements open() for /port/endpoints//data and /port/endpoints//ctl /// /// # Arguments - /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'port_num: [PortId]' - The port number specified in the scheme path /// - 'endpoint_num: [u8]' - The endpoint number to access /// - 'handle_type: [String]' - The type of the handle /// - 'flags: [usize]' - The flags parameter passed to open() @@ -1905,7 +1909,7 @@ impl Xhci { /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num, or no endpoint with the given endpoint_num fn open_handle_single_endpoint( &self, - port_num: usize, + port_num: PortId, endpoint_num: u8, handle_type: String, flags: usize, @@ -1940,7 +1944,7 @@ impl Xhci { /// implements open() for /port/configure /// /// # Arguments - /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'port_num: [PortId]' - The port number specified in the scheme path /// - 'endpoint_num: [u8]' - The endpoint number to access /// - 'flags: [usize]' - The flags parameter passed to open() /// @@ -1950,7 +1954,7 @@ impl Xhci { /// - [Handle::Port] - The handle was opened successfully /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num, or no endpoint with the given endpoint_num - fn open_handle_configure_endpoints(&self, port_num: usize, flags: usize) -> Result { + fn open_handle_configure_endpoints(&self, port_num: PortId, flags: usize) -> Result { if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { return Err(Error::new(ENOTDIR)); } @@ -1965,7 +1969,7 @@ impl Xhci { /// implements open() for /port/request /// /// # Arguments - /// - 'port_num: [usize]' - The port number specified in the scheme path + /// - 'port_num: [PortId]' - The port number specified in the scheme path /// - 'flags: [usize]' - The flags parameter passed to open() /// /// # Returns @@ -1973,7 +1977,7 @@ impl Xhci { /// /// - [Handle::Port] - The handle was opened successfully /// - [ENOTDIR] - open() was called on this scheme endpoint, but directory-specific flags were passed to open - fn open_handle_port_request(&self, port_num: usize, flags: usize) -> Result { + fn open_handle_port_request(&self, port_num: PortId, flags: usize) -> Result { if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { return Err(Error::new(ENOTDIR)); } @@ -2169,7 +2173,7 @@ impl Xhci { self.handles.remove(&fd); } - pub fn get_endp_status(&self, port_num: usize, endp_num: u8) -> Result { + pub fn get_endp_status(&self, port_num: PortId, endp_num: u8) -> Result { let port_state = self.port_states.get(&port_num).ok_or(Error::new(EBADFD))?; let slot = port_state.slot; @@ -2217,7 +2221,7 @@ impl Xhci { } pub async fn on_req_reset_device( &self, - port_num: usize, + port_num: PortId, endp_num: u8, clear_feature: bool, ) -> Result<()> { @@ -2244,7 +2248,7 @@ impl Xhci { } Ok(()) } - pub async fn restart_endpoint(&self, port_num: usize, endp_num: u8) -> Result<()> { + pub async fn restart_endpoint(&self, port_num: PortId, endp_num: u8) -> Result<()> { let mut port_state = self .port_states .get_mut(&port_num) @@ -2297,7 +2301,7 @@ impl Xhci { Ok(()) } - pub fn endp_direction(&self, port_num: usize, endp_num: u8) -> Result { + pub fn endp_direction(&self, port_num: PortId, endp_num: u8) -> Result { Ok(self .port_states .get(&port_num) @@ -2316,12 +2320,12 @@ impl Xhci { .ok_or(Error::new(EIO))? .direction()) } - pub fn slot(&self, port_num: usize) -> Result { + pub fn slot(&self, port_num: PortId) -> Result { Ok(self.port_states.get(&port_num).ok_or(Error::new(EIO))?.slot) } pub async fn set_tr_deque_ptr( &self, - port_num: usize, + port_num: PortId, endp_num: u8, deque_ptr_and_cycle: u64, ) -> Result<()> { @@ -2352,7 +2356,7 @@ impl Xhci { } pub async fn on_write_endp_ctl( &self, - port_num: usize, + port_num: PortId, endp_num: u8, buf: &[u8], ) -> Result { @@ -2442,7 +2446,7 @@ impl Xhci { } pub async fn on_write_endp_data( &self, - port_num: usize, + port_num: PortId, endp_num: u8, buf: &[u8], ) -> Result { @@ -2506,7 +2510,12 @@ impl Xhci { _ => return Err(Error::new(EBADF)), } } - pub fn on_read_endp_ctl(&self, port_num: usize, endp_num: u8, buf: &mut [u8]) -> Result { + pub fn on_read_endp_ctl( + &self, + port_num: PortId, + endp_num: u8, + buf: &mut [u8], + ) -> Result { let port_state = &mut self .port_states .get_mut(&port_num) @@ -2538,7 +2547,7 @@ impl Xhci { } pub async fn on_read_endp_data( &self, - port_num: usize, + port_num: PortId, endp_num: u8, buf: &mut [u8], ) -> Result { From 2c349f7eb08309a835049455021a902a301654c1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 20 Mar 2025 21:32:50 -0600 Subject: [PATCH 1153/1301] Cleanup to allow enumeration requests on any port id --- xhcid/src/driver_interface.rs | 3 +++ xhcid/src/xhci/device_enumerator.rs | 7 ++----- xhcid/src/xhci/irq_reactor.rs | 16 +++++++++------- xhcid/src/xhci/mod.rs | 15 +++++++++------ 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index d974a0468f..2d4604d0a3 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -327,6 +327,9 @@ impl str::FromStr for PortId { } // Parse route string component + if i > 5 { + return Err(format!("too many route string components")); + } if value & 0xF0 != 0 { return Err(format!( "value {:?} is too large for route string component", diff --git a/xhcid/src/xhci/device_enumerator.rs b/xhcid/src/xhci/device_enumerator.rs index c418ef8b07..cd75a96500 100644 --- a/xhcid/src/xhci/device_enumerator.rs +++ b/xhcid/src/xhci/device_enumerator.rs @@ -85,7 +85,7 @@ use syscall::EAGAIN; //} pub struct DeviceEnumerationRequest { - pub port_number: u8, + pub port_id: PortId, } pub struct DeviceEnumerator { @@ -109,10 +109,7 @@ impl DeviceEnumerator { } }; - let port_id = PortId { - root_hub_port_num: request.port_number, - route_string: 0, - }; + let port_id = request.port_id; let port_array_index = port_id.root_hub_port_index(); info!("Device Enumerator request for port {}", port_id); diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index ee271e228e..70d90b9013 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -316,22 +316,24 @@ impl IrqReactor { /// Handles device attach/detach events as indicated by a PortStatusChange fn handle_port_status_change(&mut self, trb: Trb) { - if let Some(port_num) = trb.port_status_change_port_id() { - trace!("Received Port Status Change Request on port {}", port_num); + if let Some(root_hub_port_num) = trb.port_status_change_port_id() { + let port_id = PortId { + root_hub_port_num, + route_string: 0, + }; + trace!("Received Port Status Change Request on port {}", port_id); self.device_enumerator_sender - .send(DeviceEnumerationRequest { - port_number: port_num, - }) + .send(DeviceEnumerationRequest { port_id }) .expect( format!( "Failed to transmit device numeration request on port {}", - port_num + port_id ) .as_str(), ); { let mut ports = self.hci.ports.lock().unwrap(); - let port = &mut ports[(port_num - 1) as usize]; + let port = &mut ports[port_id.root_hub_port_index()]; port.portsc.writef(PortFlags::PORT_CSC.bits(), true); } } else { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index a7cde500f5..34b910e4af 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -559,18 +559,23 @@ impl Xhci { let len = self.ports.lock().unwrap().len(); - for index in 0..len { + for root_hub_port_num in 1..=(len as u8) { + let port_id = PortId { + root_hub_port_num, + route_string: 0, + }; + //Get the CCS and CSC flags let (ccs, csc, flags) = { let mut ports = self.ports.lock().unwrap(); - let port = &mut ports[index]; + let port = &mut ports[port_id.root_hub_port_index()]; let ccs = port.portsc.readf(PortFlags::PORT_CCS.bits()); let csc = port.portsc.readf(PortFlags::PORT_CSC.bits()); (ccs, csc, port.flags()) }; - debug!("Port {} has flags {:?}", index + 1, flags); + debug!("Port {} has flags {:?}", port_id, flags); match (ccs, csc) { (false, false) => { // Nothing is connected, and there was no port status change @@ -579,9 +584,7 @@ impl Xhci { _ => { //Either something is connected, or nothing is connected and a port status change was asserted. self.device_enumerator_sender - .send(DeviceEnumerationRequest { - port_number: (index + 1) as u8, - }) + .send(DeviceEnumerationRequest { port_id }) .expect("Failed to generate the port enumeration request!"); } } From 58bd24da8c6c187dd685da6d877d775d2213409d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 21 Mar 2025 10:15:36 -0600 Subject: [PATCH 1154/1301] Support addressing of hub devices --- input/usbhidd/src/main.rs | 1 + storage/usbscsid/src/main.rs | 1 + usbhubd/src/main.rs | 93 ++++++++++++++++++------ xhcid/src/driver_interface.rs | 60 +++++++++++++--- xhcid/src/xhci/mod.rs | 1 + xhcid/src/xhci/scheme.rs | 128 +++++++++++++++++++++++++++++++--- 6 files changed, 244 insertions(+), 40 deletions(-) diff --git a/input/usbhidd/src/main.rs b/input/usbhidd/src/main.rs index da6af6a82e..eae573bae4 100644 --- a/input/usbhidd/src/main.rs +++ b/input/usbhidd/src/main.rs @@ -240,6 +240,7 @@ fn main() { config_desc: conf_desc.configuration_value, interface_desc: Some(interface_num), alternate_setting: Some(if_desc.alternate_setting), + hub_ports: None, }) .expect("Failed to configure endpoints"); diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index ff87d2109e..807ab11c38 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -74,6 +74,7 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: PortId, protocol: config_desc: configuration_value, interface_desc: Some(interface_num), alternate_setting: Some(alternate_setting), + hub_ports: None, }) .expect("Failed to configure endpoints"); diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index 198641cc1a..16da57caf5 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -19,7 +19,7 @@ fn main() { const USAGE: &'static str = "usbhubd "; let scheme = args.next().expect(USAGE); - let port = args + let port_id = args .next() .expect(USAGE) .parse::() @@ -33,11 +33,11 @@ fn main() { log::info!( "USB HUB driver spawned with scheme `{}`, port {}, interface {}", scheme, - port, + port_id, interface_num ); - let handle = XhciClientHandle::new(scheme, port); + let handle = XhciClientHandle::new(scheme.clone(), port_id); let desc: DevDesc = handle .get_standard_descs() .expect("Failed to get standard descriptors"); @@ -57,14 +57,6 @@ fn main() { }) .expect("Failed to find suitable configuration"); - handle - .configure_endpoints(&ConfigureEndpointsReq { - config_desc: conf_desc.configuration_value, - interface_desc: Some(interface_num), - alternate_setting: Some(if_desc.alternate_setting), - }) - .expect("Failed to configure endpoints"); - let mut hub_desc = usb::HubDescriptor::default(); handle .device_request( @@ -78,10 +70,69 @@ fn main() { ) .expect("Failed to retrieve hub descriptor"); + handle + .configure_endpoints(&ConfigureEndpointsReq { + config_desc: conf_desc.configuration_value, + interface_desc: Some(interface_num), + alternate_setting: Some(if_desc.alternate_setting), + hub_ports: Some(hub_desc.ports), + }) + .expect("Failed to configure endpoints"); + + /*TODO: only set hub depth on USB 3+ hubs + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Device, + 0x0c, // SET_HUB_DEPTH + port_id.hub_depth().into(), + 0, + DeviceReqData::NoData, + ) + .expect("Failed to set hub depth"); + */ + + // Initialize states + struct PortState { + port_id: PortId, + port_sts: usb::HubPortStatus, + handle: XhciClientHandle, + attached: bool, + } + + impl PortState { + pub fn ensure_attached(&mut self, attached: bool) { + if attached == self.attached { + return; + } + + if attached { + self.handle.attach().expect("Failed to attach"); + } else { + self.handle.detach().expect("Failed to detach"); + } + + self.attached = attached; + } + } + + let mut states = Vec::new(); + for port in 1..=hub_desc.ports { + let child_port_id = port_id.child(port).expect("Cannot get child port ID"); + states.push(PortState { + port_id: child_port_id, + port_sts: usb::HubPortStatus::default(), + handle: XhciClientHandle::new(scheme.clone(), child_port_id), + attached: false, + }); + } + //TODO: use change flags? - let mut last_port_statuses = vec![usb::HubPortStatus::default(); hub_desc.ports.into()]; loop { for port in 1..=hub_desc.ports { + let port_idx: usize = port.checked_sub(1).unwrap().into(); + let mut state = states.get_mut(port_idx).unwrap(); + let mut port_sts = usb::HubPortStatus::default(); handle .device_request( @@ -93,14 +144,9 @@ fn main() { DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut port_sts) }), ) .expect("Failed to retrieve port status"); - - { - let port_idx: usize = port.checked_sub(1).unwrap().into(); - let last_port_sts = last_port_statuses.get_mut(port_idx).unwrap(); - if *last_port_sts != port_sts { - *last_port_sts = port_sts; - log::info!("port {} status {:X?}", port, port_sts); - } + if state.port_sts != port_sts { + state.port_sts = port_sts; + log::info!("port {} status {:X?}", port, port_sts); } // Ensure port is powered on @@ -116,17 +162,19 @@ fn main() { DeviceReqData::NoData, ) .expect("Failed to set port power"); + state.ensure_attached(false); continue; } // Ignore disconnected port - //TODO: turn off disconnected ports? if !port_sts.contains(usb::HubPortStatus::CONNECTION) { + state.ensure_attached(false); continue; } // Ignore port in reset if port_sts.contains(usb::HubPortStatus::RESET) { + state.ensure_attached(false); continue; } @@ -143,10 +191,11 @@ fn main() { DeviceReqData::NoData, ) .expect("Failed to set port enable"); + state.ensure_attached(false); continue; } - //TODO: address device + state.ensure_attached(true); } //TODO: use interrupts or poll faster? diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index 2d4604d0a3..bcb9dddad3 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -20,6 +20,7 @@ pub struct ConfigureEndpointsReq { pub config_desc: u8, pub interface_desc: Option, pub alternate_setting: Option, + pub hub_ports: Option, } #[derive(Clone, Debug, Serialize, Deserialize)] @@ -290,6 +291,33 @@ impl PortId { pub fn root_hub_port_index(&self) -> usize { self.root_hub_port_num.checked_sub(1).unwrap().into() } + + pub fn hub_depth(&self) -> u8 { + let mut hub_depth = 0; + let mut route_string = self.route_string; + while route_string > 0 { + route_string >>= 4; + hub_depth += 1; + } + hub_depth + } + + pub fn child(&self, value: u8) -> Result { + let depth = self.hub_depth(); + if depth >= 5 { + return Err(format!("too many route string components")); + } + if value & 0xF0 != 0 { + return Err(format!( + "value {:?} is too large for route string component", + value + )); + } + Ok(Self { + root_hub_port_num: self.root_hub_port_num, + route_string: self.route_string | u32::from(value) << (depth * 4), + }) + } } impl fmt::Display for PortId { @@ -299,8 +327,7 @@ impl fmt::Display for PortId { // The Route String is a 20-bit field in downstream directed packets that the hub uses to route // each packet to the designated downstream port. It is composed of a concatenation of the // downstream port numbers (4 bits per hub) for each hub traversed to reach a device. - // The lowest 4 bits are ignored. - let mut route_string = self.route_string >> 4; + let mut route_string = self.route_string; while route_string > 0 { write!(f, ".{}", route_string & 0xF)?; route_string >>= 4; @@ -320,6 +347,12 @@ impl str::FromStr for PortId { .parse() .map_err(|e| format!("failed to parse {:?}: {}", part, e))?; + // Neither root hub port number nor route string support 0 components + // to identify downstream ports + if value == 0 { + return Err(format!("zero is not a valid port ID component")); + } + // Parse root hub port number if i == 0 { root_hub_port_num = value; @@ -327,7 +360,8 @@ impl str::FromStr for PortId { } // Parse route string component - if i > 5 { + let depth = i - 1; + if depth >= 5 { return Err(format!("too many route string components")); } if value & 0xF0 != 0 { @@ -336,13 +370,7 @@ impl str::FromStr for PortId { value )); } - route_string |= (value as u32) << (i * 4); - } - if root_hub_port_num == 0 { - return Err(format!( - "invalid root hub port number {:?}", - root_hub_port_num - )); + route_string |= u32::from(value) << (depth * 4); } Ok(Self { root_hub_port_num, @@ -485,6 +513,18 @@ impl XhciClientHandle { Self { scheme, port } } + pub fn attach(&self) -> result::Result<(), XhciClientHandleError> { + let path = format!("/scheme/{}/port{}/attach", self.scheme, self.port); + let mut file = OpenOptions::new().read(false).write(true).open(path)?; + let _bytes_written = file.write(&[])?; + Ok(()) + } + pub fn detach(&self) -> result::Result<(), XhciClientHandleError> { + let path = format!("/scheme/{}/port{}/detach", self.scheme, self.port); + let mut file = OpenOptions::new().read(false).write(true).open(path)?; + let _bytes_written = file.write(&[])?; + Ok(()) + } pub fn get_standard_descs(&self) -> result::Result { let path = format!("/scheme/{}/port{}/descriptors", self.scheme, self.port); let json = std::fs::read(path)?; diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 34b910e4af..cad83c23fa 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -739,6 +739,7 @@ impl Xhci { pub async fn attach_device(&self, port_id: PortId) -> syscall::Result<()> { if self.port_states.contains_key(&port_id) { + println!("Already contains port {}", port_id); return Err(syscall::Error::new(EAGAIN)); } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 924ed612e6..9c53a323dc 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -52,6 +52,10 @@ use regex::Regex; lazy_static! { static ref REGEX_PORT_CONFIGURE: Regex = Regex::new(r"^port([\d\.]+)/configure$") .expect("Failed to create the regex for the port/configure scheme."); + static ref REGEX_PORT_ATTACH: Regex = Regex::new(r"^port([\d\.]+)/attach$") + .expect("Failed to create the regex for the port/attach scheme."); + static ref REGEX_PORT_DETACH: Regex = Regex::new(r"^port([\d\.]+)/detach$") + .expect("Failed to create the regex for the port/detach scheme."); static ref REGEX_PORT_DESCRIPTORS: Regex = Regex::new(r"^port([\d\.]+)/descriptors$") .expect("Failed to create the regex for the port/descriptors"); static ref REGEX_PORT_STATE: Regex = Regex::new(r"^port([\d\.]+)/state$") @@ -131,6 +135,8 @@ pub enum Handle { Endpoints(PortId, Vec), // port, contents Endpoint(PortId, u8, EndpointHandleTy), // port, endpoint, state ConfigureEndpoints(PortId), // port + AttachDevice(PortId), // port + DetachDevice(PortId), // port } /// The type of handle. @@ -170,6 +176,10 @@ enum SchemeParameters { Endpoint(PortId, u8, String), // port number, endpoint number, handle type /// /port/configure ConfigureEndpoints(PortId), // port number + /// /port/attach + AttachDevice(PortId), // port number + /// /port/detach + DetachDevice(PortId), // port number } impl Handle { @@ -212,6 +222,12 @@ impl Handle { Handle::ConfigureEndpoints(port_num) => { format!("port{}/configure", port_num) } + Handle::AttachDevice(port_num) => { + format!("port{}/attach", port_num) + } + Handle::DetachDevice(port_num) => { + format!("port{}/detach", port_num) + } } } @@ -236,6 +252,8 @@ impl Handle { &Handle::PortState(_) => HandleType::Character, &Handle::PortReq(_, _) => HandleType::Character, &Handle::ConfigureEndpoints(_) => HandleType::Character, + &Handle::AttachDevice(_) => HandleType::Character, + &Handle::DetachDevice(_) => HandleType::Character, &Handle::Endpoint(_, _, ref st) => match st { EndpointHandleTy::Data => HandleType::Character, EndpointHandleTy::Ctl => HandleType::Character, @@ -264,6 +282,8 @@ impl Handle { &Handle::PortState(_) => None, &Handle::PortReq(_, _) => None, &Handle::ConfigureEndpoints(_) => None, + &Handle::AttachDevice(_) => None, + &Handle::DetachDevice(_) => None, &Handle::Endpoint(_, _, ref st) => match st { EndpointHandleTy::Data => None, EndpointHandleTy::Ctl => None, @@ -345,6 +365,14 @@ impl SchemeParameters { let port_num = get_port_id_from_regex(®EX_PORT_CONFIGURE, scheme, 0)?; Ok(Self::ConfigureEndpoints(port_num)) + } else if REGEX_PORT_ATTACH.is_match(scheme) { + let port_num = get_port_id_from_regex(®EX_PORT_ATTACH, scheme, 0)?; + + Ok(Self::AttachDevice(port_num)) + } else if REGEX_PORT_DETACH.is_match(scheme) { + let port_num = get_port_id_from_regex(®EX_PORT_DETACH, scheme, 0)?; + + Ok(Self::DetachDevice(port_num)) } else if REGEX_PORT_DESCRIPTORS.is_match(scheme) { let port_num = get_port_id_from_regex(®EX_PORT_DESCRIPTORS, scheme, 0)?; @@ -971,13 +999,28 @@ impl Xhci { const CONTEXT_ENTRIES_MASK: u32 = 0xF800_0000; const CONTEXT_ENTRIES_SHIFT: u8 = 27; - let current_slot_a = input_context.device.slot.a.read(); + const HUB_PORTS_MASK: u32 = 0xFF00_0000; + const HUB_PORTS_SHIFT: u8 = 24; + + let mut current_slot_a = input_context.device.slot.a.read(); + let mut current_slot_b = input_context.device.slot.b.read(); + + // Set context entries + current_slot_a &= !CONTEXT_ENTRIES_MASK; + current_slot_a |= + (u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT) & CONTEXT_ENTRIES_MASK; + + // Set hub data + current_slot_a &= !(1 << 26); + current_slot_b &= !HUB_PORTS_MASK; + if let Some(hub_ports) = req.hub_ports { + current_slot_a |= 1 << 26; + current_slot_b |= (u32::from(hub_ports) << HUB_PORTS_SHIFT) & HUB_PORTS_MASK; + } + + input_context.device.slot.a.write(current_slot_a); + input_context.device.slot.b.write(current_slot_b); - input_context.device.slot.a.write( - (current_slot_a & !CONTEXT_ENTRIES_MASK) - | ((u32::from(new_context_entries) << CONTEXT_ENTRIES_SHIFT) - & CONTEXT_ENTRIES_MASK), - ); let control = if self.op.lock().unwrap().cie() { (u32::from(req.alternate_setting.unwrap_or(0)) << 16) | (u32::from(req.interface_desc.unwrap_or(0)) << 8) @@ -1966,6 +2009,54 @@ impl Xhci { Ok(Handle::ConfigureEndpoints(port_num)) } + /// implements open() for /port/attach + /// + /// # Arguments + /// - 'port_num: [PortId]' - The port number specified in the scheme path + /// - 'flags: [usize]' - The flags parameter passed to open() + /// + /// # Returns + /// This function returns a [Result] containing either: + /// + /// - [Handle::Port] - The handle was opened successfully + /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open + /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num, or no endpoint with the given endpoint_num + fn open_handle_attach_device(&self, port_num: PortId, flags: usize) -> Result { + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(ENOTDIR)); + } + + if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { + return Err(Error::new(EACCES)); + } + + Ok(Handle::AttachDevice(port_num)) + } + + /// implements open() for /port/detach + /// + /// # Arguments + /// - 'port_num: [PortId]' - The port number specified in the scheme path + /// - 'flags: [usize]' - The flags parameter passed to open() + /// + /// # Returns + /// This function returns a [Result] containing either: + /// + /// - [Handle::Port] - The handle was opened successfully + /// - [EISDIR] - open() was called on this scheme endpoint, but no directory-specific flags were passed to open + /// - [ENOENT] - The scheme is valid, but there is no port associated with the given port_num, or no endpoint with the given endpoint_num + fn open_handle_detach_device(&self, port_num: PortId, flags: usize) -> Result { + if flags & O_DIRECTORY != 0 && flags & O_STAT == 0 { + return Err(Error::new(ENOTDIR)); + } + + if flags & O_RDWR != O_WRONLY && flags & O_STAT == 0 { + return Err(Error::new(EACCES)); + } + + Ok(Handle::DetachDevice(port_num)) + } + /// implements open() for /port/request /// /// # Arguments @@ -2020,6 +2111,12 @@ impl Scheme for &Xhci { SchemeParameters::ConfigureEndpoints(port_number) => { self.open_handle_configure_endpoints(port_number, flags)? } + SchemeParameters::AttachDevice(port_number) => { + self.open_handle_attach_device(port_number, flags)? + } + SchemeParameters::DetachDevice(port_number) => { + self.open_handle_detach_device(port_number, flags)? + } }; let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed); @@ -2049,8 +2146,11 @@ impl Scheme for &Xhci { }; //If we have a handle to the configure scheme, we need to mark it as write only. - if let &Handle::ConfigureEndpoints(_) = &*guard { - stat.st_mode = stat.st_mode | 0o200; + match &*guard { + Handle::ConfigureEndpoints(_) | Handle::AttachDevice(_) | Handle::DetachDevice(_) => { + stat.st_mode = stat.st_mode | 0o200; + } + _ => {} } Ok(0) @@ -2098,6 +2198,8 @@ impl Scheme for &Xhci { Ok(bytes_to_read) } Handle::ConfigureEndpoints(_) => Err(Error::new(EBADF)), + Handle::AttachDevice(_) => Err(Error::new(EBADF)), + Handle::DetachDevice(_) => Err(Error::new(EBADF)), &mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st { EndpointHandleTy::Ctl => self.on_read_endp_ctl(port_num, endp_num, buf), @@ -2150,6 +2252,16 @@ impl Scheme for &Xhci { block_on(self.configure_endpoints(port_num, buf))?; Ok(buf.len()) } + &mut Handle::AttachDevice(port_num) => { + //TODO: accept some arguments in buffer? + block_on(self.attach_device(port_num))?; + Ok(buf.len()) + } + &mut Handle::DetachDevice(port_num) => { + //TODO: accept some arguments in buffer? + block_on(self.detach_device(port_num))?; + Ok(buf.len()) + } &mut Handle::Endpoint(port_num, endp_num, ref ep_file_ty) => match ep_file_ty { EndpointHandleTy::Ctl => block_on(self.on_write_endp_ctl(port_num, endp_num, buf)), EndpointHandleTy::Data => { From f0d39b872db5a7c9ab79a0b204709038004a8723 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 21 Mar 2025 13:58:56 -0600 Subject: [PATCH 1155/1301] xhcid: fix usage of portsc rwc bits --- xhcid/src/xhci/device_enumerator.rs | 101 ++++---------------------- xhcid/src/xhci/irq_reactor.rs | 2 +- xhcid/src/xhci/mod.rs | 39 ++++++----- xhcid/src/xhci/port.rs | 105 ++++++++++++++++++++++------ xhcid/src/xhci/scheme.rs | 4 +- 5 files changed, 117 insertions(+), 134 deletions(-) diff --git a/xhcid/src/xhci/device_enumerator.rs b/xhcid/src/xhci/device_enumerator.rs index cd75a96500..b1573ec7b8 100644 --- a/xhcid/src/xhci/device_enumerator.rs +++ b/xhcid/src/xhci/device_enumerator.rs @@ -7,83 +7,6 @@ use std::sync::Arc; use std::time::Duration; use syscall::EAGAIN; -//enum HubPortState{ -// PoweredOff, -// Disabled, -// Disconnected, -// Reset, -// Enabled, -// Error, -// Polling, -// Compliance, -// Loopback -//} -// -//impl HubPortState{ -// pub fn from_port_flags(flags: PortFlags, protocol_version: (u8, u8)) -> Self{ -// let pp = flags.contains(PortFlags::PORT_PP); -// let ccs = flags.contains(PortFlags::PORT_CCS); -// let ped = flags.contains(PortFlags::PORT_PED); -// let pr = flags.contains(PortFlags::PORT_PR); -// -// match protocol_version { -// (2, _) | (1, _) => { -// match (pp, ccs, ped, pr) { -// (false, false, false, false) => { HubPortState::PoweredOff }, -// (true, false, false, false) => { HubPortState::Disconnected }, -// (true, true, false, true) => { HubPortState::Reset }, -// (true, true, false, false) => { HubPortState::Disabled }, -// (true, true, true, false) => { HubPortState::Enabled }, -// (true, true, true, true) => unreachable!(), //PED shouldnt be set when PR is set -// (false, _, _, _) => unreachable!(), //None of the other bits should be set when the port is off -// _ => unreachable!() //This state shouldn't be valid. -// } -// } -// (3, _) => { -// //TO-DO: USB3 state machine. -// HubPortState::PoweredOff -// }, -// (_, _) => unreachable!() //We don't support protocols > 3 yet. -// } -// } -//} -// -//struct RootHubPortStateMachine{ -// hci: Arc, -// port_num: u8, -// port_index: usize, -// protocol_major_version: u8, -// protocol_minor_version: u8, -// state: HubPortState -//} -// -//impl RootHubPortStateMachine{ -// fn new(port_num: u8, hci: Arc) -> Self{ -// -// let hci = hci.clone(); -// let port_index = (port_num - 1) as usize; -// -// //TODO: Get actual protocol version -// let (maj, min) = (2u8, 0u8); -// -// //TODO: Get actual flags -// let flags = PortFlags::all(); -// -// RootHubPortStateMachine{ -// hci, -// port_num, -// port_index, -// protocol_major_version: maj, -// protocol_minor_version: min, -// state: HubPortState::from_port_flags(flags, (maj, min)) -// } -// } -// -// fn execute(&mut self, port_num: u8){ -// //TO-DO: Implement the state machine. -// } -//} - pub struct DeviceEnumerationRequest { pub port_id: PortId, } @@ -130,7 +53,7 @@ impl DeviceEnumerator { (len, ports[port_array_index].flags()) }; - if flags.contains(PortFlags::PORT_CCS) { + if flags.contains(PortFlags::CCS) { info!( "Received Device Connect Port Status Change Event with port flags {:?}", flags @@ -138,11 +61,11 @@ impl DeviceEnumerator { //If the port isn't enabled (i.e. it's a USB2 port), we need to reset it if it isn't resetting already //A USB3 port won't generate a Connect Status Change until it's already enabled, so this check //will always be skipped for USB3 ports - if !flags.contains(PortFlags::PORT_PED) { - let disabled_state = flags.contains(PortFlags::PORT_PP) - && flags.contains(PortFlags::PORT_CCS) - && !flags.contains(PortFlags::PORT_PED) - && !flags.contains(PortFlags::PORT_PR); + if !flags.contains(PortFlags::PED) { + let disabled_state = flags.contains(PortFlags::PP) + && flags.contains(PortFlags::CCS) + && !flags.contains(PortFlags::PED) + && !flags.contains(PortFlags::PR); if !disabled_state { panic!( @@ -155,21 +78,21 @@ impl DeviceEnumerator { //THIS LOCKS THE PORTS. DO NOT LOCK PORTS BEFORE THIS POINT info!("Received a device connect on port {}, but it's not enabled. Resetting the port.", port_id); - self.hci.reset_port(port_array_index); + self.hci.reset_port(port_id); let mut ports = self.hci.ports.lock().unwrap(); let port = &mut ports[port_array_index]; - port.portsc.writef(PortFlags::PORT_PRC.bits(), true); + port.clear_prc(); std::thread::sleep(Duration::from_millis(16)); //Some controllers need some extra time to make the transition. let flags = port.flags(); - let enabled_state = flags.contains(PortFlags::PORT_PP) - && flags.contains(PortFlags::PORT_CCS) - && flags.contains(PortFlags::PORT_PED) - && !flags.contains(PortFlags::PORT_PR); + let enabled_state = flags.contains(PortFlags::PP) + && flags.contains(PortFlags::CCS) + && flags.contains(PortFlags::PED) + && !flags.contains(PortFlags::PR); if !enabled_state { warn!( diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 70d90b9013..c551040450 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -334,7 +334,7 @@ impl IrqReactor { { let mut ports = self.hci.ports.lock().unwrap(); let port = &mut ports[port_id.root_hub_port_index()]; - port.portsc.writef(PortFlags::PORT_CSC.bits(), true); + port.clear_csc(); } } else { warn!( diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index cad83c23fa..cc02df6172 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -547,11 +547,10 @@ impl Xhci { Ok(()) } - pub fn get_pls(&self, port_id: PortId) -> u32 { + pub fn get_pls(&self, port_id: PortId) -> u8 { let mut ports = self.ports.lock().unwrap(); let port = ports.get_mut(port_id.root_hub_port_index()).unwrap(); - let state = port.portsc.read(); - (state >> 5) & 4 + port.state() } pub fn poll(&self) { @@ -569,10 +568,11 @@ impl Xhci { let (ccs, csc, flags) = { let mut ports = self.ports.lock().unwrap(); let port = &mut ports[port_id.root_hub_port_index()]; - let ccs = port.portsc.readf(PortFlags::PORT_CCS.bits()); - let csc = port.portsc.readf(PortFlags::PORT_CSC.bits()); + let flags = port.flags(); + let ccs = flags.contains(PortFlags::CCS); + let csc = flags.contains(PortFlags::CSC); - (ccs, csc, port.flags()) + (ccs, csc, flags) }; debug!("Port {} has flags {:?}", port_id, flags); @@ -630,28 +630,29 @@ impl Xhci { }; } } - pub fn reset_port(&self, port_num: usize) { - debug!("XHCI Port {} reset", port_num); + pub fn reset_port(&self, port_id: PortId) { + debug!("XHCI Port {} reset", port_id); //TODO handle the second unwrap let mut ports = self.ports.lock().unwrap(); - let port = ports.get_mut(port_num).unwrap(); + let port = ports.get_mut(port_id.root_hub_port_index()).unwrap(); let instant = std::time::Instant::now(); - let state = port.portsc.read(); - let pls = (state >> 5) & 4; + debug!("Port {} Link State: {}", port_id, port.state()); - debug!("Port Link State: {}", pls); - - port.portsc.writef(port::PortFlags::PORT_PR.bits(), true); - debug!("Flags after setting port reset: {:?}", port.flags()); - while !port.portsc.readf(port::PortFlags::PORT_PRC.bits()) { - debug!("Ran at least once!"); + port.set_pr(); + debug!( + "Flags after setting port {} reset: {:?}", + port_id, + port.flags() + ); + while !port.flags().contains(port::PortFlags::PRC) { + debug!("port {} reset loop ran at least once!", port_id); if instant.elapsed().as_secs() >= 1 { warn!("timeout"); break; } - //std::thread::yield_now(); + std::thread::yield_now(); } } @@ -753,7 +754,7 @@ impl Xhci { port_id, data, state, speed, flags ); - if flags.contains(port::PortFlags::PORT_CCS) { + if flags.contains(port::PortFlags::CCS) { let slot_ty = match self.supported_protocol(port_id) { Some(protocol) => protocol.proto_slot_ty(), None => { diff --git a/xhcid/src/xhci/port.rs b/xhcid/src/xhci/port.rs index cf1066f955..7c0f570d37 100644 --- a/xhcid/src/xhci/port.rs +++ b/xhcid/src/xhci/port.rs @@ -1,35 +1,54 @@ use common::io::{Io, Mmio}; +// RO - read-only +// ROS - read-only sticky +// RW - read/write +// RWS - read/write sticky +// RW1CS - read/write-1-to-clear sticky +// RW1S - read/write-1-to-set +// Sticky register values may preserve values through chip hardware reset + bitflags! { pub struct PortFlags: u32 { - const PORT_CCS = 1 << 0; - const PORT_PED = 1 << 1; - const PORT_OCA = 1 << 3; - const PORT_PR = 1 << 4; - const PORT_PLS = 1 << 5; - const PORT_PP = 1 << 9; - const PORT_PIC_AMB = 1 << 14; - const PORT_PIC_GRN = 1 << 15; - const PORT_LWS = 1 << 16; - const PORT_CSC = 1 << 17; - const PORT_PEC = 1 << 18; - const PORT_WRC = 1 << 19; - const PORT_OCC = 1 << 20; - const PORT_PRC = 1 << 21; - const PORT_PLC = 1 << 22; - const PORT_CEC = 1 << 23; - const PORT_CAS = 1 << 24; - const PORT_WCE = 1 << 25; - const PORT_WDE = 1 << 26; - const PORT_WOE = 1 << 27; - const PORT_DR = 1 << 30; - const PORT_WPR = 1 << 31; + const CCS = 1 << 0; // ROS + const PED = 1 << 1; // RW1CS + const RSVD_2 = 1 << 2; // RsvdZ + const OCA = 1 << 3; // RO + const PR = 1 << 4; // RW1S + const PLS_0 = 1 << 5; // RWS + const PLS_1 = 1 << 6; // RWS + const PLS_2 = 1 << 7; // RWS + const PLS_3 = 1 << 8; // RWS + const PP = 1 << 9; // RWS + const SPEED_0 = 1 << 10; // ROS + const SPEED_1 = 1 << 11; // ROS + const SPEED_2 = 1 << 12; // ROS + const SPEED_3 = 1 << 13; // ROS + const PIC_AMB = 1 << 14; // RWS + const PIC_GRN = 1 << 15; // RWS + const LWS = 1 << 16; // RW + const CSC = 1 << 17; // RW1CS + const PEC = 1 << 18; // RW1CS + const WRC = 1 << 19; // RW1CS + const OCC = 1 << 20; // RW1CS + const PRC = 1 << 21; // RW1CS + const PLC = 1 << 22; // RW1CS + const CEC = 1 << 23; // RW1CS + const CAS = 1 << 24; // RO + const WCE = 1 << 25; // RWS + const WDE = 1 << 26; // RWS + const WOE = 1 << 27; // RWS + const RSVD_28 = 1 << 28; // RsvdZ + const RSVD_29 = 1 << 29; // RsvdZ + const DR = 1 << 30; // RO + const WPR = 1 << 31; // RW1S } } #[repr(C, packed)] pub struct Port { - pub portsc: Mmio, + // This has write one to clear fields, do not expose it, handle writes carefully! + portsc: Mmio, pub portpmsc: Mmio, pub portli: Mmio, pub porthlpmc: Mmio, @@ -40,6 +59,21 @@ impl Port { self.portsc.read() } + pub fn clear_csc(&mut self) { + self.portsc + .write((self.flags_preserved() | PortFlags::CSC).bits()); + } + + pub fn clear_prc(&mut self) { + self.portsc + .write((self.flags_preserved() | PortFlags::PRC).bits()); + } + + pub fn set_pr(&mut self) { + self.portsc + .write((self.flags_preserved() | PortFlags::PR).bits()); + } + pub fn state(&self) -> u8 { ((self.read() & (0b1111 << 5)) >> 5) as u8 } @@ -51,4 +85,29 @@ impl Port { pub fn flags(&self) -> PortFlags { PortFlags::from_bits_truncate(self.read()) } + + // Read only preserved flags + pub fn flags_preserved(&self) -> PortFlags { + // RO(S) and RW(S) bits should be preserved + // RW1S and RW1CS bits should not + let preserved = PortFlags::CCS + | PortFlags::OCA + | PortFlags::PLS_0 + | PortFlags::PLS_1 + | PortFlags::PLS_2 + | PortFlags::PLS_3 + | PortFlags::PP + | PortFlags::SPEED_0 + | PortFlags::SPEED_1 + | PortFlags::SPEED_2 + | PortFlags::SPEED_3 + | PortFlags::PIC_AMB + | PortFlags::PIC_GRN + | PortFlags::WCE + | PortFlags::WDE + | PortFlags::WOE + | PortFlags::DR; + + self.flags() & preserved + } } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 9c53a323dc..c475bb2b18 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1436,7 +1436,7 @@ impl Xhci { let port = ports .get(port_id.root_hub_port_index()) .ok_or(Error::new(ENOENT))?; - if !port.flags().contains(port::PortFlags::PORT_CCS) { + if !port.flags().contains(port::PortFlags::CCS) { return Err(Error::new(ENOENT)); } @@ -1776,7 +1776,7 @@ impl Xhci { for (index, _) in ports_guard .iter() .enumerate() - .filter(|(_, port)| port.flags().contains(port::PortFlags::PORT_CCS)) + .filter(|(_, port)| port.flags().contains(port::PortFlags::CCS)) { write!(contents, "port{}\n", index).unwrap(); } From 5afc5c9de49a0914103cd929fa0c1583977e64e8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 21 Mar 2025 14:45:06 -0600 Subject: [PATCH 1156/1301] xhcid: adjust logging --- xhcid/src/xhci/mod.rs | 14 +++++++++++--- xhcid/src/xhci/scheme.rs | 4 ++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index cc02df6172..3ceec1e196 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1188,7 +1188,15 @@ impl Xhci { .map(|subclass| subclass == ifdesc.sub_class) .unwrap_or(true) }) { - info!("Loading subdriver \"{}\"", driver.name); + info!( + "Loading subdriver \"{}\" for port {} iface {} proto {} class {}.{}", + driver.name, + port, + ifdesc.number, + ifdesc.protocol, + ifdesc.class, + ifdesc.sub_class + ); let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; let command = if command.starts_with('/') { @@ -1217,8 +1225,8 @@ impl Xhci { }); } else { warn!( - "No driver for USB class {}.{}", - ifdesc.class, ifdesc.sub_class + "No driver for port {} iface {} proto {} class {}.{}", + port, ifdesc.number, ifdesc.protocol, ifdesc.class, ifdesc.sub_class ); } } diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index c475bb2b18..4120365096 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -578,7 +578,7 @@ impl Xhci { pub async fn execute_command(&self, f: F) -> (Trb, Trb) { //TODO: find out why this bit is set earlier! if self.interrupt_is_pending(0) { - warn!("The EHB bit is already set!"); + debug!("The EHB bit is already set!"); //self.force_clear_interrupt(0); } @@ -586,7 +586,7 @@ impl Xhci { let mut command_ring = self.cmd.lock().unwrap(); let (cmd_index, cycle) = (command_ring.next_index(), command_ring.cycle); - info!("Sending command with cycle bit {}", cycle as u8); + debug!("Sending command with cycle bit {}", cycle as u8); { let command_trb = &mut command_ring.trbs[cmd_index]; From 7c9801379d9a836eb87c2e6110ed750fcf6aa844 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 21 Mar 2025 15:41:53 -0600 Subject: [PATCH 1157/1301] xhcid: use lang id when reading string descriptors --- usbhubd/src/main.rs | 11 ++++++---- xhcid/src/usb/hub.rs | 5 +++++ xhcid/src/xhci/mod.rs | 44 +++++++++++++++++++++++++++++++++------- xhcid/src/xhci/scheme.rs | 26 ++++++++++++++++++------ 4 files changed, 69 insertions(+), 17 deletions(-) diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index 16da57caf5..08013df206 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -56,7 +56,10 @@ fn main() { Some((conf_desc.clone(), if_desc)) }) .expect("Failed to find suitable configuration"); + + //TODO: is it required to configure before reading hub descriptor? + // Read hub descriptor let mut hub_desc = usb::HubDescriptor::default(); handle .device_request( @@ -64,12 +67,12 @@ fn main() { PortReqRecipient::Device, usb::SetupReq::GetDescriptor as u8, 0, - //TODO: should this be an index into interface_descs? - interface_num as u16, + 0, DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), ) - .expect("Failed to retrieve hub descriptor"); + .expect("Failed to read hub descriptor"); + // Configure as hub device handle .configure_endpoints(&ConfigureEndpointsReq { config_desc: conf_desc.configuration_value, @@ -77,7 +80,7 @@ fn main() { alternate_setting: Some(if_desc.alternate_setting), hub_ports: Some(hub_desc.ports), }) - .expect("Failed to configure endpoints"); + .expect("Failed to configure endpoints after reading hub descriptor"); /*TODO: only set hub depth on USB 3+ hubs handle diff --git a/xhcid/src/usb/hub.rs b/xhcid/src/usb/hub.rs index f83d734fe6..2eeff3ab3d 100644 --- a/xhcid/src/usb/hub.rs +++ b/xhcid/src/usb/hub.rs @@ -2,14 +2,17 @@ #[derive(Clone, Copy, Debug)] pub struct HubDescriptor { pub length: u8, + // 0x29 for USB 2, 0x2A for USB 3 pub kind: u8, pub ports: u8, pub characteristics: u16, pub power_on_good: u8, pub current: u8, + /*TODO: USB 2 and 3 disagree on the descriptor, so some fields are disabled // device_removable: bitmap of ports, maximum of 256 bits (32 bytes) // power_control_mask: bitmap of ports, maximum of 256 bits (32 bytes) bitmaps: [u8; 64], + */ } unsafe impl plain::Plain for HubDescriptor {} @@ -23,7 +26,9 @@ impl Default for HubDescriptor { characteristics: 0, power_on_good: 0, current: 0, + /* bitmaps: [0; 64], + */ } } } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 3ceec1e196..61daf60307 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -99,7 +99,8 @@ impl Xhci { port: PortId, slot: u8, kind: usb::DescriptorKind, - index: u8, + value: u8, + index: u16, desc: &mut Dma, ) -> Result<()> { if self.interrupt_is_pending(0) { @@ -108,10 +109,11 @@ impl Xhci { } let len = mem::size_of::(); log::debug!( - "get_desc_raw port {} slot {} kind {:?} index {} len {}", + "get_desc_raw port {} slot {} kind {:?} value {} index {} len {}", port, slot, kind, + value, index, len ); @@ -128,7 +130,7 @@ impl Xhci { let first_index = ring.next_index(); let (cmd, cycle) = (&mut ring.trbs[first_index], ring.cycle); cmd.setup( - usb::Setup::get_descriptor(kind, index, 0, len as u16), + usb::Setup::get_descriptor(kind, value, index, len as u16), TransferKind::In, cycle, ); @@ -173,14 +175,14 @@ impl Xhci { slot: u8, ) -> Result { let mut desc = unsafe { self.alloc_dma_zeroed::()? }; - self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc) + self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, 0, &mut desc) .await?; Ok(*desc) } async fn fetch_dev_desc(&self, port: PortId, slot: u8) -> Result { let mut desc = unsafe { self.alloc_dma_zeroed::()? }; - self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, &mut desc) + self.get_desc_raw(port, slot, usb::DescriptorKind::Device, 0, 0, &mut desc) .await?; Ok(*desc) } @@ -197,6 +199,7 @@ impl Xhci { slot, usb::DescriptorKind::Configuration, config, + 0, &mut desc, ) .await?; @@ -214,17 +217,44 @@ impl Xhci { slot, usb::DescriptorKind::BinaryObjectStorage, 0, + 0, &mut desc, ) .await?; Ok(*desc) } - async fn fetch_string_desc(&self, port: PortId, slot: u8, index: u8) -> Result { + async fn fetch_lang_ids_desc(&self, port: PortId, slot: u8) -> Result> { let mut sdesc = unsafe { self.alloc_dma_zeroed::<(u8, u8, [u16; 127])>()? }; - self.get_desc_raw(port, slot, usb::DescriptorKind::String, index, &mut sdesc) + self.get_desc_raw(port, slot, usb::DescriptorKind::String, 0, 0, &mut sdesc) .await?; + let len = sdesc.0 as usize; + if len > 2 { + Ok(sdesc.2[..(len - 2) / 2].to_vec()) + } else { + Ok(Vec::new()) + } + } + + async fn fetch_string_desc( + &self, + port: PortId, + slot: u8, + value: u8, + lang_id: u16, + ) -> Result { + let mut sdesc = unsafe { self.alloc_dma_zeroed::<(u8, u8, [u16; 127])>()? }; + self.get_desc_raw( + port, + slot, + usb::DescriptorKind::String, + value, + lang_id, + &mut sdesc, + ) + .await?; + let len = sdesc.0 as usize; if len > 2 { Ok(String::from_utf16(&sdesc.2[..(len - 2) / 2]).unwrap_or(String::new())) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 4120365096..8c97271610 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -550,13 +550,14 @@ impl Xhci { desc: usb::InterfaceDescriptor, endps: impl IntoIterator, hid_descs: impl IntoIterator, + lang_id: u16, ) -> Result { Ok(IfDesc { alternate_setting: desc.alternate_setting, class: desc.class, interface_str: if desc.interface_str > 0 { Some( - self.fetch_string_desc(port_id, slot, desc.interface_str) + self.fetch_string_desc(port_id, slot, desc.interface_str, lang_id) .await?, ) } else { @@ -1443,10 +1444,23 @@ impl Xhci { let raw_dd = self.fetch_dev_desc(port_id, slot).await?; log::debug!("port {} slot {} desc {:X?}", port_id, slot, raw_dd); + let lang_ids = self.fetch_lang_ids_desc(port_id, slot).await?; + // Prefer US English, but fall back to first language ID, or zero + let en_us_id = 0x409; + let lang_id = if lang_ids.contains(&en_us_id) { + en_us_id + } else { + match lang_ids.first() { + Some(some) => *some, + None => 0, + } + }; + log::debug!("port {} using language ID 0x{:04x}", port_id, lang_id); + let (manufacturer_str, product_str, serial_str) = ( if raw_dd.manufacturer_str > 0 { Some( - self.fetch_string_desc(port_id, slot, raw_dd.manufacturer_str) + self.fetch_string_desc(port_id, slot, raw_dd.manufacturer_str, lang_id) .await?, ) } else { @@ -1454,7 +1468,7 @@ impl Xhci { }, if raw_dd.product_str > 0 { Some( - self.fetch_string_desc(port_id, slot, raw_dd.product_str) + self.fetch_string_desc(port_id, slot, raw_dd.product_str, lang_id) .await?, ) } else { @@ -1462,7 +1476,7 @@ impl Xhci { }, if raw_dd.serial_str > 0 { Some( - self.fetch_string_desc(port_id, slot, raw_dd.serial_str) + self.fetch_string_desc(port_id, slot, raw_dd.serial_str, lang_id) .await?, ) } else { @@ -1548,7 +1562,7 @@ impl Xhci { } interface_descs.push( - self.new_if_desc(port_id, slot, idesc, endpoints, hid_descs) + self.new_if_desc(port_id, slot, idesc, endpoints, hid_descs, lang_id) .await?, ); } else { @@ -1562,7 +1576,7 @@ impl Xhci { kind: desc.kind, configuration: if desc.configuration_str > 0 { Some( - self.fetch_string_desc(port_id, slot, desc.configuration_str) + self.fetch_string_desc(port_id, slot, desc.configuration_str, lang_id) .await?, ) } else { From a5f87735d242060ad5b4af6f8ac3c175357c50be Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 21 Mar 2025 16:31:44 -0600 Subject: [PATCH 1158/1301] xhcid: ignore alternate settings --- xhcid/src/xhci/mod.rs | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 61daf60307..39284a28e5 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1211,6 +1211,24 @@ impl Xhci { let drivers_usercfg: &DriversConfig = &DRIVERS_CONFIG; for ifdesc in config_desc.interface_descs.iter() { + //TODO: support alternate settings + // This is difficult because the device driver must know which alternate + // to use, but if alternates can have different classes, then a different + // device driver may be required for each alternate. For now, we will use + // only the default alternate setting (0) + if ifdesc.alternate_setting != 0 { + warn!( + "ignoring port {} iface {} alternate {} class {}.{} proto {}", + port, + ifdesc.number, + ifdesc.alternate_setting, + ifdesc.class, + ifdesc.sub_class, + ifdesc.protocol + ); + continue; + } + if let Some(driver) = drivers_usercfg.drivers.iter().find(|driver| { driver.class == ifdesc.class && driver @@ -1219,13 +1237,14 @@ impl Xhci { .unwrap_or(true) }) { info!( - "Loading subdriver \"{}\" for port {} iface {} proto {} class {}.{}", + "Loading subdriver \"{}\" for port {} iface {} alternate {} class {}.{} proto {}", driver.name, port, ifdesc.number, - ifdesc.protocol, + ifdesc.alternate_setting, ifdesc.class, - ifdesc.sub_class + ifdesc.sub_class, + ifdesc.protocol, ); let (command, args) = driver.command.split_first().ok_or(Error::new(EBADMSG))?; @@ -1255,8 +1274,13 @@ impl Xhci { }); } else { warn!( - "No driver for port {} iface {} proto {} class {}.{}", - port, ifdesc.number, ifdesc.protocol, ifdesc.class, ifdesc.sub_class + "No driver for port {} iface {} alternate {} class {}.{} proto {}", + port, + ifdesc.number, + ifdesc.alternate_setting, + ifdesc.class, + ifdesc.sub_class, + ifdesc.protocol ); } } From 145d6b355a322e68193608c512070bb33cbc1115 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 21 Mar 2025 16:32:06 -0600 Subject: [PATCH 1159/1301] Fix reading hub descriptor on real hardware --- usbhubd/src/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index 08013df206..2dcb6f14e5 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -56,8 +56,6 @@ fn main() { Some((conf_desc.clone(), if_desc)) }) .expect("Failed to find suitable configuration"); - - //TODO: is it required to configure before reading hub descriptor? // Read hub descriptor let mut hub_desc = usb::HubDescriptor::default(); @@ -66,7 +64,9 @@ fn main() { PortReqTy::Class, PortReqRecipient::Device, usb::SetupReq::GetDescriptor as u8, - 0, + // 0x29 is USB 2.0 hub descriptor + // TODO: suppot reading USB 3.0 descriptor? + 0x29_00, 0, DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), ) From 59edc11beed93af4c0e55da6d69e777aa5879a06 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Mar 2025 20:00:07 -0600 Subject: [PATCH 1160/1301] xhcid: prepare for getting protocol speed from hubs --- xhcid/src/driver_interface.rs | 18 +++++++++-- xhcid/src/xhci/mod.rs | 60 ++++++++++++++++++++++++++--------- 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/xhcid/src/driver_interface.rs b/xhcid/src/driver_interface.rs index bcb9dddad3..035e93da1b 100644 --- a/xhcid/src/driver_interface.rs +++ b/xhcid/src/driver_interface.rs @@ -295,7 +295,7 @@ impl PortId { pub fn hub_depth(&self) -> u8 { let mut hub_depth = 0; let mut route_string = self.route_string; - while route_string > 0 { + while route_string != 0 { route_string >>= 4; hub_depth += 1; } @@ -318,6 +318,20 @@ impl PortId { route_string: self.route_string | u32::from(value) << (depth * 4), }) } + + pub fn parent(&self) -> Option<(Self, u8)> { + let depth = self.hub_depth(); + let parent_depth = depth.checked_sub(1)?; + let parent_shift = parent_depth * 4; + let parent_mask = 0xF << parent_shift; + Some(( + Self { + root_hub_port_num: self.root_hub_port_num, + route_string: self.route_string & !parent_mask, + }, + u8::try_from((self.route_string & parent_mask) >> parent_shift).unwrap(), + )) + } } impl fmt::Display for PortId { @@ -328,7 +342,7 @@ impl fmt::Display for PortId { // each packet to the designated downstream port. It is composed of a concatenation of the // downstream port numbers (4 bits per hub) for each hub traversed to reach a device. let mut route_string = self.route_string; - while route_string > 0 { + while route_string != 0 { write!(f, ".{}", route_string & 0xF)?; route_string >>= 4; } diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 39284a28e5..4d31618ba5 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -321,6 +321,7 @@ unsafe impl Sync for Xhci {} struct PortState { slot: u8, + protocol_speed: &'static ProtocolSpeed, cfg_idx: Option, input_context: Mutex>, dev_desc: Option, @@ -805,16 +806,21 @@ impl Xhci { info!("Enabled port {}, which the xHC mapped to {}", port_id, slot); + //TODO: get correct speed for child devices + let protocol_speed = self + .lookup_psiv(port_id, speed) + .expect("Failed to retrieve speed ID"); + let mut input = unsafe { self.alloc_dma_zeroed::()? }; info!("Attempting to address the device"); let mut ring = match self - .address_device(&mut input, port_id, slot_ty, slot, speed) + .address_device(&mut input, port_id, slot_ty, slot, protocol_speed) .await { Ok(device_ring) => device_ring, Err(err) => { - error!("Failed to spawn driver for port {}: `{}`", port_id, err); + error!("Failed to address device for port {}: `{}`", port_id, err); return Err(err); } }; @@ -825,6 +831,7 @@ impl Xhci { let mut port_state = PortState { slot, + protocol_speed, input_context: Mutex::new(input), dev_desc: None, cfg_idx: None, @@ -1020,8 +1027,38 @@ impl Xhci { port: PortId, slot_ty: u8, slot: u8, - speed: u8, + protocol_speed: &ProtocolSpeed, ) -> Result { + // Collect MTT, parent port number, parent slot ID + let mut mtt = false; + let mut parent_hub_slot_id = 0u8; + let mut parent_port_num = 0u8; + if let Some((parent_port, port_num)) = port.parent() { + match self.port_states.get(&parent_port) { + Some(parent_state) => { + // parent info must be supplied if: + let mut needs_parent_info = false; + // 1. the device is low or full speed and connected through a high speed hub + //TODO: determine device speed (speed is not accurate as it comes from the port) + // 2. the device is superspeed and connected through a higher rank hub + //TODO: determine device speed (speed is not accurate as it comes from the port) + // For now, this is just set to true to force things to work + needs_parent_info = true; + if needs_parent_info { + parent_hub_slot_id = parent_state.slot; + parent_port_num = port_num; + } + info!( + "port {} parent_hub_slot_id {} parent_port_num {}", + port, parent_hub_slot_id, parent_port_num + ); + } + None => { + warn!("port {} missing parent port {} state", port, parent_port); + } + } + } + let mut ring = Ring::new(self.cap.ac64(), 16, true)?; { @@ -1031,7 +1068,6 @@ impl Xhci { let route_string = port.route_string; let context_entries = 1u8; - let mtt = false; let hub = false; assert_eq!(route_string & 0x000F_FFFF, route_string); @@ -1052,14 +1088,12 @@ impl Xhci { ); // TODO - let parent_hud_slot_id = 0u8; - let parent_port_num = 0u8; let ttt = 0u8; let interrupter = 0u8; assert_eq!(ttt & 0b11, ttt); slot_ctx.c.write( - u32::from(parent_hud_slot_id) + u32::from(parent_hub_slot_id) | (u32::from(parent_port_num) << 8) | (u32::from(ttt) << 16) | (u32::from(interrupter) << 22), @@ -1067,19 +1101,15 @@ impl Xhci { let endp_ctx = &mut input_context.device.endpoints[0]; - let speed_id = self - .lookup_psiv(port, speed) - .expect("Failed to retrieve speed ID"); - let max_error_count = 3u8; // recommended value according to the XHCI spec let ep_ty = 4u8; // control endpoint, bidirectional - let max_packet_size: u32 = if speed_id.is_lowspeed() { + let max_packet_size: u32 = if protocol_speed.is_lowspeed() { 8 // only valid value - } else if speed_id.is_fullspeed() { + } else if protocol_speed.is_fullspeed() { 64 // valid values are 8, 16, 32, 64 - } else if speed_id.is_highspeed() { + } else if protocol_speed.is_highspeed() { 64 // only valid value - } else if speed_id.is_superspeed_gen_x() { + } else if protocol_speed.is_superspeed_gen_x() { 512 // only valid value } else { unreachable!() From 8dcd85b546924dbd6951680bbb5e8493050a52f1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 28 Mar 2025 17:48:47 -0600 Subject: [PATCH 1161/1301] Fix packet size for USB 3.0 --- xhcid/src/xhci/mod.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 4d31618ba5..5ac85adf8a 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -858,7 +858,7 @@ impl Xhci { .await?; } - debug!("Got the 8 byte dev descriptor"); + debug!("Got the 8 byte dev descriptor: {:X?}", dev_desc_8_byte); let dev_desc = self.get_desc(port_id, slot).await?; debug!("Got the full device descriptor!"); @@ -963,12 +963,13 @@ impl Xhci { slot_id: u8, dev_desc: usb::DeviceDescriptor8Byte, ) -> Result<()> { - let new_max_packet_size = u32::from(dev_desc.packet_size); //if dev_desc.major_usb_vers() == 2 { - //u32::from(dev_desc.packet_size) - //} else { - // info!("USB 2 device detected. Packet size is: {}", dev_desc.packet_size); - // 1u32 << dev_desc.packet_size - //}; + let new_max_packet_size = if dev_desc.major_usb_vers() == 2 { + // For USB 2.0, packet_size is in bytes + u32::from(dev_desc.packet_size) + } else { + // For other USB versions, packet_size is the shift + 1u32 << dev_desc.packet_size + }; let endp_ctx = &mut input_context.device.endpoints[0]; let mut b = endp_ctx.b.read(); b &= 0x0000_FFFF; @@ -997,11 +998,13 @@ impl Xhci { input_context.add_context.write(1 << 1); input_context.drop_context.write(0); - let new_max_packet_size = u32::from(dev_desc.packet_size); //if dev_desc.major_version() == 2 { - // u32::from(dev_desc.packet_size) - //} else { - // 1u32 << dev_desc.packet_size - //}; + let new_max_packet_size = if dev_desc.major_version() == 2 { + // For USB 2.0, packet_size is in bytes + u32::from(dev_desc.packet_size) + } else { + // For other USB versions, packet_size is the shift + 1u32 << dev_desc.packet_size + }; let endp_ctx = &mut input_context.device.endpoints[0]; let mut b = endp_ctx.b.read(); b &= 0x0000_FFFF; From ba0ca4ce056a4919cdda67a5c1c244a4f867e541 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 28 Mar 2025 18:02:18 -0600 Subject: [PATCH 1162/1301] Also fix packet size on USB 1 --- xhcid/src/xhci/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 5ac85adf8a..2f91f72497 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -963,11 +963,11 @@ impl Xhci { slot_id: u8, dev_desc: usb::DeviceDescriptor8Byte, ) -> Result<()> { - let new_max_packet_size = if dev_desc.major_usb_vers() == 2 { - // For USB 2.0, packet_size is in bytes + let new_max_packet_size = if dev_desc.major_usb_vers() <= 2 { + // For USB 2.0 and below, packet_size is in bytes u32::from(dev_desc.packet_size) } else { - // For other USB versions, packet_size is the shift + // For later USB versions, packet_size is the shift 1u32 << dev_desc.packet_size }; let endp_ctx = &mut input_context.device.endpoints[0]; @@ -998,11 +998,11 @@ impl Xhci { input_context.add_context.write(1 << 1); input_context.drop_context.write(0); - let new_max_packet_size = if dev_desc.major_version() == 2 { - // For USB 2.0, packet_size is in bytes + let new_max_packet_size = if dev_desc.major_version() <= 2 { + // For USB 2.0 and below, packet_size is in bytes u32::from(dev_desc.packet_size) } else { - // For other USB versions, packet_size is the shift + // For later USB versions, packet_size is the shift 1u32 << dev_desc.packet_size }; let endp_ctx = &mut input_context.device.endpoints[0]; From cbbcbc9ec3fb1a7ac074252498aa49a8171fd38d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 28 Mar 2025 18:27:29 -0600 Subject: [PATCH 1163/1301] usbhubd/xhcid: fix reading descriptor on USB 3 hubs --- usbhubd/src/main.rs | 48 +++++++++++++++++++++++++++++--------------- xhcid/src/usb/hub.rs | 47 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index 2dcb6f14e5..98d7798b3e 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -58,19 +58,35 @@ fn main() { .expect("Failed to find suitable configuration"); // Read hub descriptor - let mut hub_desc = usb::HubDescriptor::default(); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Device, - usb::SetupReq::GetDescriptor as u8, - // 0x29 is USB 2.0 hub descriptor - // TODO: suppot reading USB 3.0 descriptor? - 0x29_00, - 0, - DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), - ) - .expect("Failed to read hub descriptor"); + let ports = if desc.major_version() >= 3 { + // USB 3.0 hubs + let mut hub_desc = usb::HubDescriptor3::default(); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Device, + usb::SetupReq::GetDescriptor as u8, + u16::from(usb::HubDescriptor3::DESCRIPTOR_KIND) << 8, + 0, + DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), + ) + .expect("Failed to read hub descriptor"); + hub_desc.ports + } else { + // USB 2.0 and earlier hubs + let mut hub_desc = usb::HubDescriptor::default(); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Device, + usb::SetupReq::GetDescriptor as u8, + u16::from(usb::HubDescriptor::DESCRIPTOR_KIND) << 8, + 0, + DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), + ) + .expect("Failed to read hub descriptor"); + hub_desc.ports + }; // Configure as hub device handle @@ -78,7 +94,7 @@ fn main() { config_desc: conf_desc.configuration_value, interface_desc: Some(interface_num), alternate_setting: Some(if_desc.alternate_setting), - hub_ports: Some(hub_desc.ports), + hub_ports: Some(ports), }) .expect("Failed to configure endpoints after reading hub descriptor"); @@ -120,7 +136,7 @@ fn main() { } let mut states = Vec::new(); - for port in 1..=hub_desc.ports { + for port in 1..=ports { let child_port_id = port_id.child(port).expect("Cannot get child port ID"); states.push(PortState { port_id: child_port_id, @@ -132,7 +148,7 @@ fn main() { //TODO: use change flags? loop { - for port in 1..=hub_desc.ports { + for port in 1..=ports { let port_idx: usize = port.checked_sub(1).unwrap().into(); let mut state = states.get_mut(port_idx).unwrap(); diff --git a/xhcid/src/usb/hub.rs b/xhcid/src/usb/hub.rs index 2eeff3ab3d..acc9d0c75e 100644 --- a/xhcid/src/usb/hub.rs +++ b/xhcid/src/usb/hub.rs @@ -2,7 +2,6 @@ #[derive(Clone, Copy, Debug)] pub struct HubDescriptor { pub length: u8, - // 0x29 for USB 2, 0x2A for USB 3 pub kind: u8, pub ports: u8, pub characteristics: u16, @@ -17,6 +16,10 @@ pub struct HubDescriptor { unsafe impl plain::Plain for HubDescriptor {} +impl HubDescriptor { + pub const DESCRIPTOR_KIND: u8 = 0x29; +} + impl Default for HubDescriptor { fn default() -> Self { Self { @@ -33,6 +36,48 @@ impl Default for HubDescriptor { } } +#[repr(C, packed)] +#[derive(Clone, Copy, Debug)] +pub struct HubDescriptor3 { + pub length: u8, + pub kind: u8, + pub ports: u8, + pub characteristics: u16, + pub power_on_good: u8, + pub current: u8, + pub decode_latency: u8, + pub delay: u16, + /*TODO: USB 2 and 3 disagree on the descriptor, so some fields are disabled + // device_removable: bitmap of ports, maximum of 256 bits (32 bytes) + // power_control_mask: bitmap of ports, maximum of 256 bits (32 bytes) + bitmaps: [u8; 64], + */ +} + +unsafe impl plain::Plain for HubDescriptor3 {} + +impl HubDescriptor3 { + pub const DESCRIPTOR_KIND: u8 = 0x2A; +} + +impl Default for HubDescriptor3 { + fn default() -> Self { + Self { + length: 0, + kind: 0, + ports: 0, + characteristics: 0, + power_on_good: 0, + current: 0, + decode_latency: 0, + delay: 0, + /* + bitmaps: [0; 64], + */ + } + } +} + #[derive(Clone, Copy, Debug)] #[repr(u8)] pub enum HubFeature { From f58625b0352cd725e93c1197ed812ada60c546f1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 28 Mar 2025 20:45:01 -0600 Subject: [PATCH 1164/1301] usbhubd/xhcid: fix port status for USB 3 hubs --- usbhubd/src/main.rs | 98 +++++++++++++++++++++++++----------------- xhcid/src/usb/hub.rs | 100 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 139 insertions(+), 59 deletions(-) diff --git a/usbhubd/src/main.rs b/usbhubd/src/main.rs index 98d7798b3e..5d063d45b1 100644 --- a/usbhubd/src/main.rs +++ b/usbhubd/src/main.rs @@ -58,58 +58,58 @@ fn main() { .expect("Failed to find suitable configuration"); // Read hub descriptor - let ports = if desc.major_version() >= 3 { + let (ports, usb_3) = if desc.major_version() >= 3 { // USB 3.0 hubs - let mut hub_desc = usb::HubDescriptor3::default(); + let mut hub_desc = usb::HubDescriptorV3::default(); handle .device_request( PortReqTy::Class, PortReqRecipient::Device, usb::SetupReq::GetDescriptor as u8, - u16::from(usb::HubDescriptor3::DESCRIPTOR_KIND) << 8, + u16::from(usb::HubDescriptorV3::DESCRIPTOR_KIND) << 8, 0, DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), ) .expect("Failed to read hub descriptor"); - hub_desc.ports + (hub_desc.ports, true) } else { // USB 2.0 and earlier hubs - let mut hub_desc = usb::HubDescriptor::default(); + let mut hub_desc = usb::HubDescriptorV2::default(); handle .device_request( PortReqTy::Class, PortReqRecipient::Device, usb::SetupReq::GetDescriptor as u8, - u16::from(usb::HubDescriptor::DESCRIPTOR_KIND) << 8, + u16::from(usb::HubDescriptorV2::DESCRIPTOR_KIND) << 8, 0, DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut hub_desc) }), ) .expect("Failed to read hub descriptor"); - hub_desc.ports + (hub_desc.ports, false) }; // Configure as hub device handle .configure_endpoints(&ConfigureEndpointsReq { config_desc: conf_desc.configuration_value, - interface_desc: Some(interface_num), - alternate_setting: Some(if_desc.alternate_setting), + interface_desc: None, //TODO: stalls on USB 3 hub: Some(interface_num), + alternate_setting: None, //TODO: stalls on USB 3 hub: Some(if_desc.alternate_setting), hub_ports: Some(ports), }) .expect("Failed to configure endpoints after reading hub descriptor"); - /*TODO: only set hub depth on USB 3+ hubs - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Device, - 0x0c, // SET_HUB_DEPTH - port_id.hub_depth().into(), - 0, - DeviceReqData::NoData, - ) - .expect("Failed to set hub depth"); - */ + if usb_3 { + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Device, + 0x0c, // SET_HUB_DEPTH + port_id.hub_depth().into(), + 0, + DeviceReqData::NoData, + ) + .expect("Failed to set hub depth"); + } // Initialize states struct PortState { @@ -140,7 +140,11 @@ fn main() { let child_port_id = port_id.child(port).expect("Cannot get child port ID"); states.push(PortState { port_id: child_port_id, - port_sts: usb::HubPortStatus::default(), + port_sts: if usb_3 { + usb::HubPortStatus::V3(usb::HubPortStatusV3::default()) + } else { + usb::HubPortStatus::V2(usb::HubPortStatusV2::default()) + }, handle: XhciClientHandle::new(scheme.clone(), child_port_id), attached: false, }); @@ -152,31 +156,47 @@ fn main() { let port_idx: usize = port.checked_sub(1).unwrap().into(); let mut state = states.get_mut(port_idx).unwrap(); - let mut port_sts = usb::HubPortStatus::default(); - handle - .device_request( - PortReqTy::Class, - PortReqRecipient::Other, - usb::SetupReq::GetStatus as u8, - 0, - port as u16, - DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut port_sts) }), - ) - .expect("Failed to retrieve port status"); + let port_sts = if usb_3 { + let mut port_sts = usb::HubPortStatusV3::default(); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Other, + usb::SetupReq::GetStatus as u8, + 0, + port as u16, + DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut port_sts) }), + ) + .expect("Failed to retrieve port status"); + usb::HubPortStatus::V3(port_sts) + } else { + let mut port_sts = usb::HubPortStatusV2::default(); + handle + .device_request( + PortReqTy::Class, + PortReqRecipient::Other, + usb::SetupReq::GetStatus as u8, + 0, + port as u16, + DeviceReqData::In(unsafe { plain::as_mut_bytes(&mut port_sts) }), + ) + .expect("Failed to retrieve port status"); + usb::HubPortStatus::V2(port_sts) + }; if state.port_sts != port_sts { state.port_sts = port_sts; log::info!("port {} status {:X?}", port, port_sts); } // Ensure port is powered on - if !port_sts.contains(usb::HubPortStatus::POWER) { + if !port_sts.is_powered() { log::info!("power on port {port}"); handle .device_request( PortReqTy::Class, PortReqRecipient::Other, usb::SetupReq::SetFeature as u8, - usb::HubFeature::PortPower as u16, + usb::HubPortFeature::PortPower as u16, port as u16, DeviceReqData::NoData, ) @@ -186,26 +206,26 @@ fn main() { } // Ignore disconnected port - if !port_sts.contains(usb::HubPortStatus::CONNECTION) { + if !port_sts.is_connected() { state.ensure_attached(false); continue; } // Ignore port in reset - if port_sts.contains(usb::HubPortStatus::RESET) { + if port_sts.is_resetting() { state.ensure_attached(false); continue; } // Ensure port is enabled - if !port_sts.contains(usb::HubPortStatus::ENABLE) { + if !port_sts.is_enabled() { log::info!("reset port {port}"); handle .device_request( PortReqTy::Class, PortReqRecipient::Other, usb::SetupReq::SetFeature as u8, - usb::HubFeature::PortReset as u16, + usb::HubPortFeature::PortReset as u16, port as u16, DeviceReqData::NoData, ) diff --git a/xhcid/src/usb/hub.rs b/xhcid/src/usb/hub.rs index acc9d0c75e..4962cb7a56 100644 --- a/xhcid/src/usb/hub.rs +++ b/xhcid/src/usb/hub.rs @@ -1,6 +1,6 @@ #[repr(C, packed)] #[derive(Clone, Copy, Debug)] -pub struct HubDescriptor { +pub struct HubDescriptorV2 { pub length: u8, pub kind: u8, pub ports: u8, @@ -14,13 +14,13 @@ pub struct HubDescriptor { */ } -unsafe impl plain::Plain for HubDescriptor {} +unsafe impl plain::Plain for HubDescriptorV2 {} -impl HubDescriptor { +impl HubDescriptorV2 { pub const DESCRIPTOR_KIND: u8 = 0x29; } -impl Default for HubDescriptor { +impl Default for HubDescriptorV2 { fn default() -> Self { Self { length: 0, @@ -38,7 +38,7 @@ impl Default for HubDescriptor { #[repr(C, packed)] #[derive(Clone, Copy, Debug)] -pub struct HubDescriptor3 { +pub struct HubDescriptorV3 { pub length: u8, pub kind: u8, pub ports: u8, @@ -54,13 +54,13 @@ pub struct HubDescriptor3 { */ } -unsafe impl plain::Plain for HubDescriptor3 {} +unsafe impl plain::Plain for HubDescriptorV3 {} -impl HubDescriptor3 { +impl HubDescriptorV3 { pub const DESCRIPTOR_KIND: u8 = 0x2A; } -impl Default for HubDescriptor3 { +impl Default for HubDescriptorV3 { fn default() -> Self { Self { length: 0, @@ -78,31 +78,24 @@ impl Default for HubDescriptor3 { } } +// This only includes matching features from both USB 2.0 and 3.0 specs #[derive(Clone, Copy, Debug)] #[repr(u8)] -pub enum HubFeature { - //TODO: CHubLocalPower = 0, - //TODO: CHubOverCurrent = 1, +pub enum HubPortFeature { PortConnection = 0, - PortEnable = 1, - PortSuspend = 2, PortOverCurrent = 3, PortReset = 4, + PortLinkState = 5, PortPower = 8, - PortLowSpeed = 9, CPortConnection = 16, - CPortEnable = 17, - CPortSuspend = 18, CPortOverCurrent = 19, CPortReset = 20, - PortTest = 21, - PortIndicator = 22, } bitflags::bitflags! { #[derive(Default)] #[repr(transparent)] - pub struct HubPortStatus: u32 { + pub struct HubPortStatusV2: u32 { const CONNECTION = 1 << 0; const ENABLE = 1 << 1; const SUSPEND = 1 << 2; @@ -124,4 +117,71 @@ bitflags::bitflags! { } } -unsafe impl plain::Plain for HubPortStatus {} +unsafe impl plain::Plain for HubPortStatusV2 {} + +bitflags::bitflags! { + #[derive(Default)] + #[repr(transparent)] + pub struct HubPortStatusV3: u32 { + const CONNECTION = 1 << 0; + const ENABLE = 1 << 1; + // bit 2 reserved + const OVER_CURRENT = 1 << 3; + const RESET = 1 << 4; + const LINK_STATE_0 = 1 << 5; + const LINK_STATE_1 = 1 << 6; + const LINK_STATE_2 = 1 << 7; + const LINK_STATE_3 = 1 << 8; + const POWER = 1 << 9; + const SPEED_0 = 1 << 10; + const SPEED_1 = 1 << 11; + const SPEED_2 = 1 << 12; + // bits 13 - 15 reserved + const CONNECTION_CHANGED = 1 << 16; + // bits 17-18 + const OVER_CURRENT_CHANGED = 1 << 19; + const RESET_CHANGED = 1 << 20; + const BH_RESET_CHANGED = 1 << 21; + const LINK_STATE_CHANGED = 1 << 22; + const CONFIG_ERROR = 1 << 23; + // bits 24 - 31 reserved + } +} + +unsafe impl plain::Plain for HubPortStatusV3 {} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum HubPortStatus { + V2(HubPortStatusV2), + V3(HubPortStatusV3), +} + +impl HubPortStatus { + pub fn is_powered(&self) -> bool { + match self { + Self::V2(x) => x.contains(HubPortStatusV2::POWER), + Self::V3(x) => x.contains(HubPortStatusV3::POWER), + } + } + + pub fn is_connected(&self) -> bool { + match self { + Self::V2(x) => x.contains(HubPortStatusV2::CONNECTION), + Self::V3(x) => x.contains(HubPortStatusV3::CONNECTION), + } + } + + pub fn is_resetting(&self) -> bool { + match self { + Self::V2(x) => x.contains(HubPortStatusV2::RESET), + Self::V3(x) => x.contains(HubPortStatusV3::RESET), + } + } + + pub fn is_enabled(&self) -> bool { + match self { + Self::V2(x) => x.contains(HubPortStatusV2::ENABLE), + Self::V3(x) => x.contains(HubPortStatusV3::ENABLE), + } + } +} \ No newline at end of file From cd4cc3e51999d96e7d244ac0c94d62d68721ab9b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 28 Mar 2025 21:18:38 -0600 Subject: [PATCH 1165/1301] Only fetch language IDs if required --- xhcid/src/xhci/scheme.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 8c97271610..7349ee101b 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1444,16 +1444,22 @@ impl Xhci { let raw_dd = self.fetch_dev_desc(port_id, slot).await?; log::debug!("port {} slot {} desc {:X?}", port_id, slot, raw_dd); - let lang_ids = self.fetch_lang_ids_desc(port_id, slot).await?; - // Prefer US English, but fall back to first language ID, or zero - let en_us_id = 0x409; - let lang_id = if lang_ids.contains(&en_us_id) { - en_us_id - } else { - match lang_ids.first() { - Some(some) => *some, - None => 0, + // Only fetch language IDs if we need to. Some devices will fail to return this descriptor + //TODO: also check configurations and interfaces for defined strings? + let lang_id = if raw_dd.manufacturer_str > 0 || raw_dd.product_str > 0 || raw_dd.serial_str > 0 { + let lang_ids = self.fetch_lang_ids_desc(port_id, slot).await?; + // Prefer US English, but fall back to first language ID, or zero + let en_us_id = 0x409; + if lang_ids.contains(&en_us_id) { + en_us_id + } else { + match lang_ids.first() { + Some(some) => *some, + None => 0, + } } + } else { + 0 }; log::debug!("port {} using language ID 0x{:04x}", port_id, lang_id); From fd28f5123c58a213f5e652bf32a79986e93f2d05 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 9 Mar 2025 12:12:49 +0100 Subject: [PATCH 1166/1301] Add a hw-based async framework for block drivers. --- Cargo.lock | 45 +++- Cargo.toml | 4 +- executor/Cargo.toml | 12 + executor/src/lib.rs | 396 ++++++++++++++++++++++++++++++++ storage/driver-block/Cargo.toml | 6 +- storage/driver-block/src/lib.rs | 255 ++++++++++---------- 6 files changed, 580 insertions(+), 138 deletions(-) create mode 100644 executor/Cargo.toml create mode 100644 executor/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 476cf221e7..7f911a6daa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,7 +32,7 @@ dependencies = [ "parking_lot 0.12.3", "plain", "redox-daemon", - "redox-scheme", + "redox-scheme 0.4.0", "redox_event", "redox_syscall", "ron", @@ -193,7 +193,7 @@ dependencies = [ "orbclient", "pcid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.4.0", "redox_syscall", ] @@ -391,9 +391,11 @@ checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" name = "driver-block" version = "0.1.0" dependencies = [ + "executor", "libredox", + "log", "partitionlib", - "redox-scheme", + "redox-scheme 0.5.0", "redox_syscall", ] @@ -406,7 +408,7 @@ dependencies = [ "inputd", "libredox", "log", - "redox-scheme", + "redox-scheme 0.4.0", "redox_syscall", ] @@ -415,7 +417,7 @@ name = "driver-network" version = "0.1.0" dependencies = [ "libredox", - "redox-scheme", + "redox-scheme 0.4.0", "redox_syscall", ] @@ -439,6 +441,15 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "executor" +version = "0.1.0" +dependencies = [ + "log", + "redox_event", + "slab", +] + [[package]] name = "fbbootlogd" version = "0.1.0" @@ -450,7 +461,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.4.0", "redox_event", "redox_syscall", ] @@ -466,7 +477,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox-scheme", + "redox-scheme 0.4.0", "redox_event", "redox_syscall", ] @@ -720,7 +731,7 @@ dependencies = [ "log", "orbclient", "redox-daemon", - "redox-scheme", + "redox-scheme 0.4.0", "redox_syscall", ] @@ -965,7 +976,7 @@ dependencies = [ "pico-args", "plain", "redox-daemon", - "redox-scheme", + "redox-scheme 0.4.0", "redox_syscall", "serde", ] @@ -1125,6 +1136,16 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "redox-scheme" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96b9cfb034251dfb0aaa66a67059a7f0ea344039904d1d70cd36266af9c8a2f" +dependencies = [ + "libredox", + "redox_syscall", +] + [[package]] name = "redox_event" version = "0.4.1" @@ -1137,9 +1158,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b568323e98e49e2a0899dcee453dd679fae22d69adf9b11dd508d1549b7e2f" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ "bitflags 2.6.0", ] @@ -1915,7 +1936,7 @@ dependencies = [ "pcid", "plain", "redox-daemon", - "redox-scheme", + "redox-scheme 0.4.0", "redox_event", "redox_syscall", "regex", diff --git a/Cargo.toml b/Cargo.toml index 14dd17de9d..d27f9e6e46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,9 @@ [workspace] members = [ - "acpid", "common", + "executor", + + "acpid", "hwd", "pcid", "pcid-spawner", diff --git a/executor/Cargo.toml b/executor/Cargo.toml new file mode 100644 index 0000000000..0d5b12f070 --- /dev/null +++ b/executor/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "executor" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +version = "0.1.0" +edition = "2021" +license = "MIT" +description = "Async framework for queue-based HW interfaces" + +[dependencies] +log = "0.4" +redox_event = "0.4.1" +slab = "0.4.9" diff --git a/executor/src/lib.rs b/executor/src/lib.rs new file mode 100644 index 0000000000..6b54e07bc1 --- /dev/null +++ b/executor/src/lib.rs @@ -0,0 +1,396 @@ +use std::cell::{Cell, RefCell}; +use std::collections::{HashMap, VecDeque}; +use std::fmt::Debug; +use std::fs::File; +use std::future::{Future, IntoFuture}; +use std::hash::Hash; +use std::io::{Read, Write}; +use std::marker::PhantomData; +use std::os::fd::AsRawFd; +use std::panic::AssertUnwindSafe; +use std::pin::Pin; +use std::ptr::NonNull; +use std::rc::Rc; +use std::task; + +use event::{EventFlags, RawEventQueue}; +use slab::Slab; + +type EventUserData = usize; + +type FutIdx = usize; + +pub trait Hardware: Sized { + type CmdId: Clone + Copy + Debug + Hash + Eq + PartialEq; + type CqId: Clone + Copy + Debug + Hash + Eq + PartialEq; + type SqId: Clone + Copy + Debug + Hash + Eq + PartialEq; + type Sqe: Debug + Clone + Copy; + type Cqe; + type Iv: Clone + Copy + Debug; + + type GlobalCtxt; + + // TODO: the kernel should also do this automatically before sending EOI messages to the IC + fn mask_vector(ctxt: &Self::GlobalCtxt, iv: Self::Iv); + fn unmask_vector(ctxt: &Self::GlobalCtxt, iv: Self::Iv); + + fn set_sqe_cmdid(sqe: &mut Self::Sqe, id: Self::CmdId); + fn get_cqe_cmdid(cqe: &Self::Cqe) -> Self::CmdId; + + // TODO: support multiple SQs per CQ or vice versa? + fn sq_cq(ctxt: &Self::GlobalCtxt, id: Self::CqId) -> Self::SqId; + + fn current() -> Rc>; + fn vtable() -> &'static task::RawWakerVTable; + + fn try_submit( + ctxt: &Self::GlobalCtxt, + sq_id: Self::SqId, + success: impl FnOnce(Self::CmdId) -> Self::Sqe, + fail: impl FnOnce(), + ) -> Option<(Self::CqId, Self::CmdId)>; + fn poll_cqes(ctxt: &Self::GlobalCtxt, handle: impl FnMut(Self::CqId, Self::Cqe)); +} + +/// Async executor, single IV, thread-per-core architecture +pub struct LocalExecutor { + global_ctxt: Hw::GlobalCtxt, + + queue: RawEventQueue, + vector: Hw::Iv, + irq_handle: File, + intx: bool, + + // TODO: One IV and SQ/CQ per core (where the admin queue can be managed by the main thread). + awaiting_submission: RefCell>>, + awaiting_completion: + RefCell>)>>>, + + external_event: RefCell)>>, + next_user_data: Cell, + + ready_futures: RefCell>, + futures: RefCell + 'static>>>>, + is_polling: Cell, +} + +impl LocalExecutor { + pub fn register_external_event( + &self, + fd: usize, + flags: event::EventFlags, + ) -> ExternalEventSource { + let user_data = self.next_user_data.get(); + self.next_user_data.set(user_data.checked_add(1).unwrap()); + + self.queue + .subscribe(fd, user_data, flags) + .expect("failed to subscribe to event"); + + ExternalEventSource { + flags: event::EventFlags::empty(), + user_data, + _not_send_or_unpin: PhantomData, + } + } + pub fn current() -> Rc { + Hw::current() + } + pub fn poll(&self) -> usize { + assert!(!self.is_polling.replace(true)); + + let mut finished = 0; + + for future_idx in self.ready_futures.borrow_mut().drain(..) { + let waker = waker::(future_idx); + + let mut futures = self.futures.borrow_mut(); + let res = match std::panic::catch_unwind(AssertUnwindSafe(|| { + futures[future_idx] + .as_mut() + .poll(&mut task::Context::from_waker(&waker)) + })) { + Ok(r) => r, + Err(_) => { + log::error!("Task panicked!"); + core::mem::forget(futures.remove(future_idx)); + continue; + } + }; + if res.is_ready() { + drop(futures.remove(future_idx)); + finished += 1; + } + } + self.is_polling.set(false); + + finished + } + pub fn spawn(&self, fut: impl IntoFuture + 'static) { + let idx = self + .futures + .borrow_mut() + .insert(Box::pin(fut.into_future())); + self.ready_futures.borrow_mut().push_back(idx); + } + pub fn block_on<'a, O: 'a>(&self, fut: impl IntoFuture + 'a) -> O { + let retval = Rc::new(RefCell::new(None)); + + let retval2 = Rc::clone(&retval); + let idx = self.futures.borrow_mut().insert({ + let t1: Pin + 'a>> = Box::pin(async move { + *retval2.borrow_mut() = Some(fut.await); + }); + // SAFETY: Apart from the lifetimes, the types are exactly the same. We also know + // block_on simply cannot return without having fully awaited and dropped the future, + // even if that future panics (cf. the catch_unwind invocation). + let t2: Pin + 'static>> = + unsafe { std::mem::transmute(t1) }; + + t2 + }); + + self.ready_futures.borrow_mut().push_front(idx); + + loop { + let finished = self.poll(); + if retval.borrow().is_some() { + break; + } + if finished == 0 { + self.react(); + } + } + + let o = retval.borrow_mut().take().unwrap(); + o + } + fn react(&self) { + let event = self.queue.next_event().expect("failed to get next event"); + + if event.user_data != 0 { + let Some((fut_idx, flags_ptr)) = + self.external_event.borrow_mut().remove(&event.user_data) + else { + // Spurious event + return; + }; + unsafe { + flags_ptr + .as_ptr() + .write(event::EventFlags::from_bits_retain(event.flags)); + } + self.ready_futures.borrow_mut().push_back(fut_idx); + return; + } + + if self.intx { + let mut buf = [0_u8; core::mem::size_of::()]; + if (&self.irq_handle).read(&mut buf).unwrap() != 0 { + (&self.irq_handle).write(&buf).unwrap(); + } + } + + // TODO: The kernel should probably do the masking (when using MSI/MSI-X at least), which + // should happen before EOI messages to the interrupt controller. + Hw::mask_vector(&self.global_ctxt, self.vector); + Hw::poll_cqes(&self.global_ctxt, |cq_id, cqe| { + if let Some((fut_idx, comp_ptr)) = self + .awaiting_completion + .borrow_mut() + .get_mut(&cq_id) + .and_then(|per_cmd| per_cmd.remove(&Hw::get_cqe_cmdid(&cqe))) + { + unsafe { + comp_ptr.as_ptr().write(Some(cqe)); + } + self.ready_futures.borrow_mut().push_back(fut_idx); + + if let Some(submitting) = self + .awaiting_submission + .borrow_mut() + .get_mut(&Hw::sq_cq(&self.global_ctxt, cq_id)) + .and_then(|q| q.pop_front()) + { + self.ready_futures.borrow_mut().push_back(submitting); + } + } + }); + Hw::unmask_vector(&self.global_ctxt, self.vector); + } + pub async fn submit(&self, sq_id: Hw::SqId, cmd: Hw::Sqe) -> Hw::Cqe { + CqeFuture:: { + state: State::::Submitting { sq_id, cmd }, + comp: None, + _not_send: PhantomData, + } + .await + } +} + +struct CqeFuture { + pub state: State, + pub comp: Option, + pub _not_send: PhantomData<*const ()>, +} +enum State { + Submitting { sq_id: Hw::SqId, cmd: Hw::Sqe }, + Completing { cq_id: Hw::CqId, cmd_id: Hw::CmdId }, +} + +fn current_executor_and_idx( + cx: &mut task::Context<'_>, +) -> (Rc>, FutIdx) { + let executor = LocalExecutor::current(); + + let idx = cx.waker().data() as FutIdx; + assert_eq!( + cx.waker().vtable() as *const _, + Hw::vtable(), + "incompatible executor for CqeFuture" + ); + + (executor, idx) +} + +impl Future for CqeFuture { + type Output = Hw::Cqe; + + fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll { + let this = unsafe { self.get_unchecked_mut() }; + + let (executor, idx) = current_executor_and_idx::(cx); + + match this.state { + State::Submitting { sq_id, mut cmd } => { + let mut awaiting = executor.awaiting_submission.borrow_mut(); + + if let Some((cq_id, cmd_id)) = Hw::try_submit( + &executor.global_ctxt, + sq_id, + |cmd_id| { + Hw::set_sqe_cmdid(&mut cmd, cmd_id); + log::trace!("About to submit {cmd:?}"); + cmd + }, + || { + awaiting.entry(sq_id).or_default().push_back(idx); + }, + ) { + executor + .awaiting_completion + .borrow_mut() + .entry(cq_id) + .or_default() + .insert(cmd_id, (idx, (&mut this.comp).into())); + this.state = State::Completing { cq_id, cmd_id }; + } + task::Poll::Pending + } + State::Completing { cq_id, cmd_id } => match this.comp.take() { + Some(comp) => { + log::trace!("ready!"); + task::Poll::Ready(comp) + } + + // Shouldn't technically be possible + None => { + log::trace!("spurious poll"); + executor + .awaiting_completion + .borrow_mut() + .entry(cq_id) + .or_default() + .insert(cmd_id, (idx, (&mut this.comp).into())); + task::Poll::Pending + } + }, + } + } +} + +unsafe fn vt_clone(idx: *const ()) -> task::RawWaker { + task::RawWaker::new(idx, Hw::vtable()) +} +unsafe fn vt_drop(_idx: *const ()) {} +unsafe fn vt_wake(idx: *const ()) { + Hw::current() + .ready_futures + .borrow_mut() + .push_back(idx as FutIdx); +} + +fn waker(idx: FutIdx) -> task::Waker { + unsafe { task::Waker::from_raw(task::RawWaker::new(idx as *const (), Hw::vtable())) } +} +pub const fn vtable() -> task::RawWakerVTable { + task::RawWakerVTable::new(vt_clone::, vt_wake::, vt_wake::, vt_drop) +} + +pub struct ExternalEventSource { + flags: event::EventFlags, + user_data: EventUserData, + _not_send_or_unpin: PhantomData<(*const (), fn() -> Hw)>, +} +pub struct Event { + flags: event::EventFlags, + _not_send: PhantomData<*const ()>, +} +impl Event { + pub fn flags(&self) -> event::EventFlags { + self.flags + } +} +impl ExternalEventSource { + fn poll_next(self: Pin<&mut Self>, cx: &mut task::Context) -> task::Poll> { + let this = unsafe { self.get_unchecked_mut() }; + + let flags = std::mem::take(&mut this.flags); + + if flags.is_empty() { + let (executor, idx) = current_executor_and_idx::(cx); + executor + .external_event + .borrow_mut() + .insert(this.user_data, (idx, (&mut this.flags).into())); + return task::Poll::Pending; + } + task::Poll::Ready(Some(Event { + flags, + _not_send: PhantomData, + })) + } + pub async fn next(mut self: Pin<&mut Self>) -> Option { + core::future::poll_fn(|cx| self.as_mut().poll_next(cx)).await + } +} +pub fn init_raw( + global_ctxt: Hw::GlobalCtxt, + vector: Hw::Iv, + intx: bool, + irq_handle: File, +) -> LocalExecutor { + let queue = RawEventQueue::new().expect("failed to allocate event queue for local executor"); + + // TODO: Multiple CPUs + queue + .subscribe(irq_handle.as_raw_fd() as usize, 0, EventFlags::READ) + .expect("failed to subscribe to IRQ event"); + + LocalExecutor { + global_ctxt, + + queue, + vector, + intx, + irq_handle, + + awaiting_submission: RefCell::new(HashMap::new()), + awaiting_completion: RefCell::new(HashMap::new()), + external_event: RefCell::new(HashMap::new()), + next_user_data: Cell::new(1), + ready_futures: RefCell::new(VecDeque::new()), + futures: RefCell::new(Slab::with_capacity(16)), + is_polling: Cell::new(false), + } +} diff --git a/storage/driver-block/Cargo.toml b/storage/driver-block/Cargo.toml index 00e10150bb..1ae22f56e0 100644 --- a/storage/driver-block/Cargo.toml +++ b/storage/driver-block/Cargo.toml @@ -4,8 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] +executor = { path = "../../executor" } partitionlib = { path = "../partitionlib" } libredox = "0.1.3" -redox_syscall = "0.5" -redox-scheme = "0.4" +log = "0.4" +redox_syscall = { version = "0.5", features = ["std"] } +redox-scheme = "0.5" diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 6efe0f5c2c..bd36c9a23b 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -1,4 +1,5 @@ use std::cmp; +use std::future::IntoFuture; use std::io::{self, Read, Seek, SeekFrom}; use std::collections::BTreeMap; @@ -6,15 +7,15 @@ use std::convert::TryFrom; use std::fmt::Write; use std::str; +use executor::LocalExecutor; use libredox::Fd; use partitionlib::{LogicalBlockSize, PartitionTable}; -use redox_scheme::{ - CallRequest, CallerCtx, OpenResult, RequestKind, SchemeBlock, SignalBehavior, Socket, -}; +use redox_scheme::scheme::SchemeAsync; +use redox_scheme::{CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket}; +use syscall::dirent::DirentBuf; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EAGAIN, EBADF, EINVAL, EISDIR, ENOENT, ENOLCK, EOVERFLOW, - MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, + Error, Result, Stat, EACCES, EAGAIN, EBADF, EINTR, EINVAL, EISDIR, ENOENT, ENOLCK, EOPNOTSUPP, EOVERFLOW, EWOULDBLOCK, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT }; /// Split the read operation into a series of block reads. @@ -71,8 +72,8 @@ pub trait Disk { // These operate on a whole multiple of the block size // FIXME maybe only operate on a single block worth of data? - fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result>; - fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result>; + async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result; + async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result; } impl Disk for Box { @@ -84,12 +85,12 @@ impl Disk for Box { (**self).size() } - fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { - (**self).read(block, buffer) + async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { + (**self).read(block, buffer).await } - fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { - (**self).write(block, buffer) + async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { + (**self).write(block, buffer).await } } @@ -99,18 +100,19 @@ pub struct DiskWrapper { } impl DiskWrapper { - pub fn pt(disk: &mut T) -> Option { + pub fn pt(disk: &mut T, executor: &impl ExecutorTrait) -> Option { let bs = match disk.block_size() { 512 => LogicalBlockSize::Lb512, 4096 => LogicalBlockSize::Lb4096, _ => return None, }; - struct Device<'a> { - disk: &'a mut dyn Disk, + struct Device<'a, D: Disk, E: ExecutorTrait> { + disk: &'a mut D, + executor: &'a E, offset: u64, } - impl<'a> Seek for Device<'a> { + impl<'a, D: Disk, E: ExecutorTrait> Seek for Device<'a, D, E> { fn seek(&mut self, from: SeekFrom) -> io::Result { let size = i64::try_from(self.disk.size()).or(Err(io::Error::new( io::ErrorKind::Other, @@ -129,7 +131,7 @@ impl DiskWrapper { } } // TODO: Perhaps this impl should be used in the rest of the scheme. - impl<'a> Read for Device<'a> { + impl<'a, D: Disk, E: ExecutorTrait> Read for Device<'a, D, E> { fn read(&mut self, buf: &mut [u8]) -> io::Result { let blksize = self.disk.block_size(); let size_in_blocks = self.disk.size() / u64::from(blksize); @@ -141,17 +143,9 @@ impl DiskWrapper { return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); } loop { - match disk.read(block, block_bytes) { - Ok(Some(bytes)) => { - assert_eq!(bytes, block_bytes.len()); - return Ok(()); - } - Ok(None) => { - std::thread::yield_now(); - continue; - } - Err(err) => return Err(io::Error::from_raw_os_error(err.errno)), - } + let bytes = self.executor.block_on(disk.read(block, block_bytes))?; + assert_eq!(bytes, block_bytes.len()); + return Ok(()); } }; let bytes_read = block_read(self.offset, blksize, buf, read_block)?; @@ -161,14 +155,21 @@ impl DiskWrapper { } } - partitionlib::get_partitions(&mut Device { disk, offset: 0 }, bs) - .ok() - .flatten() + partitionlib::get_partitions( + &mut Device { + disk, + offset: 0, + executor, + }, + bs, + ) + .ok() + .flatten() } - pub fn new(mut disk: T) -> Self { + pub fn new(mut disk: T, executor: &impl ExecutorTrait) -> Self { Self { - pt: Self::pt(&mut disk), + pt: Self::pt(&mut disk, executor), disk, } } @@ -189,12 +190,12 @@ impl DiskWrapper { self.disk.size() } - pub fn read( + pub async fn read( &mut self, part_num: Option, block: u64, buf: &mut [u8], - ) -> syscall::Result> { + ) -> syscall::Result { if buf.len() as u64 % u64::from(self.disk.block_size()) != 0 { return Err(Error::new(EINVAL)); } @@ -214,18 +215,18 @@ impl DiskWrapper { let abs_block = part.start_lba + block; - self.disk.read(abs_block, buf) + self.disk.read(abs_block, buf).await } else { - self.disk.read(block, buf) + self.disk.read(block, buf).await } } - pub fn write( + pub async fn write( &mut self, part_num: Option, block: u64, buf: &[u8], - ) -> syscall::Result> { + ) -> syscall::Result { if buf.len() as u64 % u64::from(self.disk.block_size()) != 0 { return Err(Error::new(EINVAL)); } @@ -245,9 +246,9 @@ impl DiskWrapper { let abs_block = part.start_lba + block; - self.disk.write(abs_block, buf) + self.disk.write(abs_block, buf).await } else { - self.disk.write(block, buf) + self.disk.write(block, buf).await } } } @@ -264,11 +265,23 @@ pub struct DiskScheme { disks: BTreeMap>, handles: BTreeMap, next_id: usize, - blocked: Vec, +} + +pub trait ExecutorTrait { + fn block_on<'a, O: 'a>(&self, fut: impl IntoFuture + 'a) -> O; +} +impl ExecutorTrait for LocalExecutor { + fn block_on<'a, O: 'a>(&self, fut: impl IntoFuture + 'a) -> O { + LocalExecutor::block_on(self, fut) + } } impl DiskScheme { - pub fn new(scheme_name: String, disks: BTreeMap) -> Self { + pub fn new( + scheme_name: String, + disks: BTreeMap, + executor: &impl ExecutorTrait, + ) -> Self { assert!(scheme_name.starts_with("disk")); let socket = Socket::nonblock(&scheme_name).expect("failed to create disk scheme"); @@ -277,11 +290,10 @@ impl DiskScheme { socket, disks: disks .into_iter() - .map(|(k, disk)| (k, DiskWrapper::new(disk))) + .map(|(k, disk)| (k, DiskWrapper::new(disk, executor))) .collect(), next_id: 0, handles: BTreeMap::new(), - blocked: vec![], } } @@ -291,53 +303,45 @@ impl DiskScheme { /// Process pending and new requests. /// - /// This needs to be called each time there is a new event on the scheme - /// file and each time a read or write operation has completed. - // FIXME maybe split into one method for events on the scheme fd and one - // to call when an irq is received to indicate that blocked packets can - // be processed. - pub fn tick(&mut self) -> io::Result<()> { - // Handle any blocked requests - let mut i = 0; - while i < self.blocked.len() { - if let Some(resp) = self.blocked[i].handle_scheme_block(self) { - self.socket - .write_response(resp, SignalBehavior::Restart) - .expect("driver-block: failed to write scheme"); - self.blocked.remove(i); - } else { - i += 1; - } - } - + /// This needs to be called each time there is a new event on the scheme. + pub async fn tick(&mut self) -> io::Result<()> { // Handle new scheme requests loop { - let request = match self.socket.next_request(SignalBehavior::Restart) { + let request = match self.socket.next_request(SignalBehavior::Interrupt) { Ok(Some(request)) => request, Ok(None) => { // Scheme likely got unmounted + // TODO: return this to caller instead std::process::exit(0); } - Err(err) if err.errno == EAGAIN => break, + Err(error) if error.errno == EWOULDBLOCK || error.errno == EAGAIN => break, + Err(err) if err.errno == EINTR => continue, Err(err) => return Err(err.into()), }; - match request.kind() { + let response = match request.kind() { RequestKind::Call(call_request) => { - if let Some(resp) = call_request.handle_scheme_block(self) { - self.socket.write_response(resp, SignalBehavior::Restart)?; - } else { - self.blocked.push(call_request); - } + // TODO: Spawn a separate task for each scheme call. This would however require the + // use of a smarter buffer pool (or direct IO, or a buffer per fd) in order to do + // parallel IO. It might also require async-aware locks so that a close() is + // correctly ordered wrt IO on the same fd. + call_request.handle_async(self).await + } + RequestKind::SendFd(sendfd_request) => Response::err(EOPNOTSUPP, sendfd_request), + RequestKind::Cancellation(_cancellation_request) => { + // FIXME implement cancellation + continue; + } + RequestKind::MsyncMsg | RequestKind::MunmapMsg | RequestKind::MmapMsg => { + unreachable!() } RequestKind::OnClose { id } => { self.on_close(id); + continue; } - RequestKind::Cancellation(_cancellation_request) => { - // FIXME implement cancellation - } - _ => {} - } + }; + self.socket + .write_response(response, SignalBehavior::Restart)?; } Ok(()) @@ -373,13 +377,8 @@ impl DiskScheme { } } -impl SchemeBlock for DiskScheme { - fn xopen( - &mut self, - path_str: &str, - flags: usize, - ctx: &CallerCtx, - ) -> Result> { +impl SchemeAsync for DiskScheme { + async fn open(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result { if ctx.uid != 0 { return Err(Error::new(EACCES)); } @@ -446,18 +445,27 @@ impl SchemeBlock for DiskScheme { let id = self.next_id; self.next_id += 1; self.handles.insert(id, handle); - Ok(Some(OpenResult::ThisScheme { + Ok(OpenResult::ThisScheme { number: id, flags: NewFdFlags::POSITIONED, - })) + }) + } + async fn getdents<'buf>( + &mut self, + _id: usize, + _buf: DirentBuf<&'buf mut [u8]>, + _opaque_offset: u64, + ) -> Result> { + // TODO + Err(Error::new(EOPNOTSUPP)) } - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result> { + async fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { match *self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::List(ref data) => { stat.st_mode = MODE_DIR; stat.st_size = data.len() as u64; - Ok(Some(0)) + Ok(()) } Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; @@ -465,7 +473,7 @@ impl SchemeBlock for DiskScheme { stat.st_blocks = disk.disk().size() / u64::from(disk.block_size()); stat.st_blksize = disk.block_size(); stat.st_size = disk.size(); - Ok(Some(0)) + Ok(()) } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; @@ -480,18 +488,19 @@ impl SchemeBlock for DiskScheme { stat.st_size = part.size * u64::from(disk.block_size()); stat.st_blocks = part.size; stat.st_blksize = disk.block_size(); - Ok(Some(0)) + Ok(()) } } } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + async fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; let mut i = 0; let scheme_name = self.scheme_name.as_bytes(); let mut j = 0; + // TODO: copy_from_slice while i < buf.len() && j < scheme_name.len() { buf[i] = scheme_name[j]; i += 1; @@ -527,16 +536,17 @@ impl SchemeBlock for DiskScheme { } } - Ok(Some(i)) + Ok(i) } - fn read( + async fn read( &mut self, id: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32, - ) -> Result> { + _ctx: &CallerCtx, + ) -> Result { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(ref handle) => { let src = usize::try_from(offset) @@ -545,70 +555,69 @@ impl SchemeBlock for DiskScheme { .unwrap_or(&[]); let count = core::cmp::min(src.len(), buf.len()); buf[..count].copy_from_slice(&src[..count]); - Ok(Some(count)) + Ok(count) } Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block = offset / u64::from(disk.block_size()); - disk.read(None, block, buf) + disk.read(None, block, buf).await } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; let block = offset / u64::from(disk.block_size()); - disk.read(Some(part_num as usize), block, buf) + disk.read(Some(part_num as usize), block, buf).await } } } - fn write( + async fn write( &mut self, id: usize, buf: &[u8], offset: u64, _fcntl_flags: u32, - ) -> Result> { + _ctx: &CallerCtx, + ) -> Result { match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { Handle::List(_) => Err(Error::new(EBADF)), Handle::Disk(number) => { let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; let block = offset / u64::from(disk.block_size()); - disk.write(None, block, buf) + disk.write(None, block, buf).await } Handle::Partition(disk_num, part_num) => { let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; let block = offset / u64::from(disk.block_size()); - disk.write(Some(part_num as usize), block, buf) + disk.write(Some(part_num as usize), block, buf).await } } } - fn fsize(&mut self, id: usize) -> Result> { - Ok(Some( - match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::List(ref handle) => handle.len() as u64, - Handle::Disk(number) => { - let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; - disk.size() - } - Handle::Partition(disk_num, part_num) => { - let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; - let part = disk - .pt - .as_ref() - .ok_or(Error::new(EBADF))? - .partitions - .get(part_num as usize) - .ok_or(Error::new(EBADF))?; + async fn fsize(&mut self, id: usize, _ctx: &CallerCtx) -> Result { + Ok(match *self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::List(ref handle) => handle.len() as u64, + Handle::Disk(number) => { + let disk = self.disks.get_mut(&number).ok_or(Error::new(EBADF))?; + disk.size() + } + Handle::Partition(disk_num, part_num) => { + let disk = self.disks.get_mut(&disk_num).ok_or(Error::new(EBADF))?; + let part = disk + .pt + .as_ref() + .ok_or(Error::new(EBADF))? + .partitions + .get(part_num as usize) + .ok_or(Error::new(EBADF))?; part.size * u64::from(disk.block_size()) - } - }, - )) + } + }) } } -impl DiskScheme { - fn on_close(&mut self, id: usize) { - self.handles.remove(&id); +impl DiskScheme { + pub fn on_close(&mut self, id: usize) { + let _ = self.handles.remove(&id); } } From ab549721e996c34440bb139414d89865b8d28844 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 9 Mar 2025 12:14:21 +0100 Subject: [PATCH 1167/1301] Use async executor for nvmed. --- storage/nvmed/Cargo.toml | 13 +- storage/nvmed/src/main.rs | 101 +++--- storage/nvmed/src/nvme/executor.rs | 82 +++++ storage/nvmed/src/nvme/identify.rs | 34 +- storage/nvmed/src/nvme/mod.rs | 482 +++++++++++++---------------- storage/nvmed/src/nvme/queues.rs | 46 ++- 6 files changed, 414 insertions(+), 344 deletions(-) create mode 100644 storage/nvmed/src/nvme/executor.rs diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 3650871a87..e3f36e9832 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -4,20 +4,21 @@ version = "0.1.0" edition = "2021" [dependencies] -arrayvec = "0.5" -bitflags = "1" -crossbeam-channel = "0.4" -futures = "0.3" +arrayvec = "0.7" +bitflags = "2" +libredox = "0.1.3" log = "0.4" +parking_lot = "0.12.1" redox-daemon = "0.1" +redox_event = "0.4.1" redox_syscall = { version = "0.5", features = ["std"] } -redox_event = "0.4" smallvec = "1" +executor = { path = "../../executor" } common = { path = "../../common" } driver-block = { path = "../driver-block" } +partitionlib = { path = "../partitionlib" } pcid = { path = "../../pcid" } -libredox = "0.1.3" [features] default = ["async"] diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index d53189d1f2..efe390f967 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -1,7 +1,9 @@ #![cfg_attr(target_arch = "aarch64", feature(stdarch_arm_hints))] // Required for yield instruction #![cfg_attr(target_arch = "riscv64", feature(riscv_ext_intrinsics))] // Required for pause instruction +use std::cell::RefCell; use std::ptr::NonNull; +use std::rc::Rc; use std::sync::Arc; use std::{slice, usize}; @@ -140,23 +142,26 @@ fn get_int_method( } } -struct NvmeDisk(Arc, NvmeNamespace); +struct NvmeDisk { + nvme: Arc, + ns: NvmeNamespace, +} impl Disk for NvmeDisk { fn block_size(&self) -> u32 { - self.1.block_size.try_into().unwrap() + self.ns.block_size.try_into().unwrap() } fn size(&self) -> u64 { - self.1.blocks * self.1.block_size + self.ns.blocks * self.ns.block_size } - fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { - self.0.namespace_read(self.1, block, buffer) + async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { + self.nvme.namespace_read(&self.ns, block, buffer).await } - fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { - self.0.namespace_write(self.1, block, buffer) + async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { + self.nvme.namespace_write(&self.ns, block, buffer).await } } @@ -181,65 +186,67 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { pcid_handle.map_bar(0).ptr }; - daemon.ready().expect("nvmed: failed to signal readiness"); - - let (reactor_sender, reactor_receiver) = crossbeam_channel::unbounded(); let (interrupt_method, interrupt_sources) = get_int_method(&mut pcid_handle, &pci_config.func) .expect("nvmed: failed to find a suitable interrupt method"); - let mut nvme = Nvme::new( - address.as_ptr() as usize, - interrupt_method, - pcid_handle, - reactor_sender, - ) - .expect("nvmed: failed to allocate driver data"); + let mut nvme = Nvme::new(address.as_ptr() as usize, interrupt_method, pcid_handle) + .expect("nvmed: failed to allocate driver data"); + unsafe { nvme.init() } log::debug!("Finished base initialization"); let nvme = Arc::new(nvme); - #[cfg(feature = "async")] - let reactor_thread = nvme::cq_reactor::start_cq_reactor_thread( - Arc::clone(&nvme), - interrupt_sources, - reactor_receiver, - ); - let namespaces = nvme.init_with_queues(); - let event_queue = event::EventQueue::new().unwrap(); - event::user_data! { - enum Event { - Scheme, - } + let executor = { + let (intx, (iv, irq_handle)) = match interrupt_sources { + InterruptSources::Msi(mut vectors) => ( + false, + vectors.pop_first().map(|(a, b)| (u16::from(a), b)).unwrap(), + ), + InterruptSources::MsiX(mut vectors) => (false, vectors.pop_first().unwrap()), + InterruptSources::Intx(file) => (true, (0, file)), + }; + nvme::executor::init(Arc::clone(&nvme), iv, intx, irq_handle) }; + let namespaces = executor.block_on(nvme.init_with_queues()); + log::debug!("Initialized!"); - let mut scheme = DiskScheme::new( + let scheme = Rc::new(RefCell::new(DiskScheme::new( scheme_name, namespaces .into_iter() - .map(|(k, ns)| (k, NvmeDisk(nvme.clone(), ns))) + .map(|(k, ns)| { + ( + k, + NvmeDisk { + nvme: nvme.clone(), + ns, + }, + ) + }) .collect(), - ); + &*executor, + ))); + daemon.ready().expect("nvmed: failed to signal readiness"); + + let mut scheme_events = Box::pin(executor.register_external_event( + scheme.borrow().event_handle().raw(), + event::EventFlags::READ, + )); libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - event_queue - .subscribe( - scheme.event_handle().raw(), - Event::Scheme, - event::EventFlags::READ, - ) - .unwrap(); + log::info!("Starting to listen for scheme events"); - for event in event_queue { - match event.unwrap().user_data { - Event::Scheme => scheme.tick().unwrap(), + executor.block_on(async { + loop { + log::trace!("new event iteration"); + if let Err(err) = scheme.borrow_mut().tick().await { + log::error!("scheme error: {err}"); + } + let _ = scheme_events.as_mut().next().await; } - } + }); //TODO: destroy NVMe stuff - #[cfg(feature = "async")] - reactor_thread - .join() - .expect("nvmed: failed to join reactor thread"); std::process::exit(0); } diff --git a/storage/nvmed/src/nvme/executor.rs b/storage/nvmed/src/nvme/executor.rs new file mode 100644 index 0000000000..6242fa98cb --- /dev/null +++ b/storage/nvmed/src/nvme/executor.rs @@ -0,0 +1,82 @@ +use std::cell::RefCell; +use std::fs::File; +use std::rc::Rc; +use std::sync::Arc; + +use executor::{Hardware, LocalExecutor}; + +use super::{CmdId, CqId, Nvme, NvmeCmd, NvmeComp, SqId}; + +pub struct NvmeHw; + +impl Hardware for NvmeHw { + type Iv = u16; + type Sqe = NvmeCmd; + type Cqe = NvmeComp; + type CmdId = CmdId; + type CqId = CqId; + type SqId = SqId; + type GlobalCtxt = Arc; + + fn mask_vector(ctxt: &Arc, iv: Self::Iv) { + ctxt.set_vector_masked(iv, true) + } + fn unmask_vector(ctxt: &Arc, iv: Self::Iv) { + ctxt.set_vector_masked(iv, false) + } + fn set_sqe_cmdid(sqe: &mut NvmeCmd, id: CmdId) { + sqe.cid = id; + } + fn get_cqe_cmdid(cqe: &Self::Cqe) -> Self::CmdId { + cqe.cid + } + fn vtable() -> &'static std::task::RawWakerVTable { + &VTABLE + } + fn current() -> std::rc::Rc> { + THE_EXECUTOR.with(|exec| Rc::clone(exec.borrow().as_ref().unwrap())) + } + fn try_submit( + nvme: &Arc, + sq_id: Self::SqId, + success: impl FnOnce(Self::CmdId) -> Self::Sqe, + fail: impl FnOnce(), + ) -> Option<(Self::CqId, Self::CmdId)> { + let ctxt = nvme.cur_thread_ctxt(); + let ctxt = ctxt.lock(); + + nvme.try_submit_raw(&*ctxt, sq_id, success, fail) + } + fn poll_cqes(nvme: &Arc, mut handle: impl FnMut(Self::CqId, Self::Cqe)) { + let ctxt = nvme.cur_thread_ctxt(); + let ctxt = ctxt.lock(); + + for (sq_cq_id, (sq, cq)) in ctxt.queues.borrow_mut().iter_mut() { + while let Some((new_head, cqe)) = cq.complete() { + unsafe { + nvme.completion_queue_head(*sq_cq_id, new_head); + } + sq.head = cqe.sq_head; + log::trace!("new head {new_head} cqe {cqe:?}"); + handle(*sq_cq_id, cqe); + } + } + } + fn sq_cq(_ctxt: &Arc, id: Self::CqId) -> Self::SqId { + id + } +} + +static VTABLE: std::task::RawWakerVTable = executor::vtable::(); + +thread_local! { + static THE_EXECUTOR: RefCell>>> = RefCell::new(None); +} + +pub type NvmeExecutor = LocalExecutor; + +pub fn init(nvme: Arc, iv: u16, intx: bool, irq_handle: File) -> Rc> { + let this = Rc::new(executor::init_raw(nvme, iv, intx, irq_handle)); + THE_EXECUTOR.with(|exec| *exec.borrow_mut() = Some(Rc::clone(&this))); + this +} diff --git a/storage/nvmed/src/nvme/identify.rs b/storage/nvmed/src/nvme/identify.rs index 93f221039d..05e5b9b2b6 100644 --- a/storage/nvmed/src/nvme/identify.rs +++ b/storage/nvmed/src/nvme/identify.rs @@ -151,14 +151,16 @@ impl LbaFormat { impl Nvme { /// Returns the serial number, model, and firmware, in that order. - pub fn identify_controller(&self) { + pub async fn identify_controller(&self) { // TODO: Use same buffer let data: Dma = unsafe { Dma::zeroed().unwrap().assume_init() }; // println!(" - Attempting to identify controller"); - let comp = self.submit_and_complete_admin_command(|cid| { - NvmeCmd::identify_controller(cid, data.physical()) - }); + let comp = self + .submit_and_complete_admin_command(|cid| { + NvmeCmd::identify_controller(cid, data.physical()) + }) + .await; log::trace!("Completion: {:?}", comp); // println!(" - Dumping identify controller"); @@ -178,30 +180,34 @@ impl Nvme { firmware, ); } - pub fn identify_namespace_list(&self, base: u32) -> Vec { + pub async fn identify_namespace_list(&self, base: u32) -> Vec { // TODO: Use buffer let data: Dma<[u32; 1024]> = unsafe { Dma::zeroed().unwrap().assume_init() }; // println!(" - Attempting to retrieve namespace ID list"); - let comp = self.submit_and_complete_admin_command(|cid| { - NvmeCmd::identify_namespace_list(cid, data.physical(), base) - }); + let comp = self + .submit_and_complete_admin_command(|cid| { + NvmeCmd::identify_namespace_list(cid, data.physical(), base) + }) + .await; log::trace!("Completion2: {:?}", comp); // println!(" - Dumping namespace ID list"); data.iter().copied().take_while(|&nsid| nsid != 0).collect() } - pub fn identify_namespace(&self, nsid: u32) -> NvmeNamespace { + pub async fn identify_namespace(&self, nsid: u32) -> NvmeNamespace { //TODO: Use buffer let data: Dma = unsafe { Dma::zeroed().unwrap().assume_init() }; - // println!(" - Attempting to identify namespace {}", nsid); - let comp = self.submit_and_complete_admin_command(|cid| { - NvmeCmd::identify_namespace(cid, data.physical(), nsid) - }); + log::debug!("Attempting to identify namespace {nsid}"); + let comp = self + .submit_and_complete_admin_command(|cid| { + NvmeCmd::identify_namespace(cid, data.physical(), nsid) + }) + .await; - // println!(" - Dumping identify namespace"); + log::debug!("Dumping identify namespace"); let size = data.size_in_blocks(); let capacity = data.capacity_in_blocks(); diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 93a1c03b9b..513814c9d0 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -1,11 +1,12 @@ -use std::collections::BTreeMap; +use std::cell::RefCell; +use std::collections::{BTreeMap, HashMap}; use std::convert::TryFrom; use std::fs::File; -use std::sync::atomic::{AtomicU16, AtomicU64}; -use std::sync::{Mutex, RwLock}; +use std::iter; +use std::sync::atomic::AtomicU16; +use std::sync::Arc; -use crossbeam_channel::Sender; -use smallvec::{smallvec, SmallVec}; +use parking_lot::{Mutex, ReentrantMutex, RwLock}; use common::io::{Io, Mmio}; use syscall::error::{Error, Result, EIO}; @@ -13,11 +14,11 @@ use syscall::error::{Error, Result, EIO}; use common::dma::Dma; pub mod cmd; -pub mod cq_reactor; +pub mod executor; pub mod identify; pub mod queues; -use self::cq_reactor::NotifReq; +use self::executor::NvmeExecutor; pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue}; use pcid_interface::msi::{MsiInfo, MsixInfo, MsixTableEntry}; @@ -47,7 +48,7 @@ pub(crate) unsafe fn pause() { std::arch::riscv64::pause(); } -/// Used in conjunction with `InterruptMethod`, primarily by the CQ reactor. +/// Used in conjunction with `InterruptMethod`, primarily by the CQ executor. #[derive(Debug)] pub enum InterruptSources { MsiX(BTreeMap), @@ -183,28 +184,32 @@ pub type CmdId = u16; pub type AtomicCqId = AtomicU16; pub type AtomicSqId = AtomicU16; pub type AtomicCmdId = AtomicU16; +pub type Iv = u16; pub struct Nvme { interrupt_method: Mutex, pcid_interface: Mutex, regs: RwLock<&'static mut NvmeRegs>, - pub(crate) submission_queues: RwLock, CqId)>>, - pub(crate) completion_queues: - RwLock)>>>, + sq_ivs: RwLock>, + cq_ivs: RwLock>, // maps interrupt vectors with the completion queues they have - cqs_for_ivs: RwLock>>, - - buffer: Mutex>, // 2MB of buffer - buffer_prp: Mutex>, // 4KB of PRP for the buffer - reactor_sender: Sender, + thread_ctxts: RwLock>>>, next_sqid: AtomicSqId, next_cqid: AtomicCqId, - - next_avail_submission_epoch: AtomicU64, } + +pub struct ThreadCtxt { + buffer: RefCell>, // 2MB of buffer + buffer_prp: RefCell>, // 4KB of PRP for the buffer + + // Yes, technically NVME allows multiple submission queues to be mapped to the same completion + // queue, but we don't use that feature. + queues: RefCell>, +} + unsafe impl Send for Nvme {} unsafe impl Sync for Nvme {} @@ -213,8 +218,8 @@ pub enum FullSqHandling { /// Return an error immediately prior to posting the command. ErrorDirectly, - /// Tell the IRQ reactor that we want to be notified when a command on the same submission - /// queue has been completed. + /// Tell the executor that we want to be notified when a command on the same submission queue + /// has been completed. Wait, } @@ -223,29 +228,34 @@ impl Nvme { address: usize, interrupt_method: InterruptMethod, pcid_interface: PciFunctionHandle, - reactor_sender: Sender, ) -> Result { Ok(Nvme { regs: RwLock::new(unsafe { &mut *(address as *mut NvmeRegs) }), - submission_queues: RwLock::new( - std::iter::once((0u16, (Mutex::new(NvmeCmdQueue::new()?), 0u16))).collect(), + thread_ctxts: RwLock::new( + iter::once(( + 0_u16, + Arc::new(ReentrantMutex::new(ThreadCtxt { + buffer: RefCell::new(unsafe { Dma::zeroed()?.assume_init() }), + buffer_prp: RefCell::new(unsafe { Dma::zeroed()?.assume_init() }), + + queues: RefCell::new( + iter::once((0, (NvmeCmdQueue::new()?, NvmeCompQueue::new()?))) + .collect(), + ), + })), + )) + .collect(), ), - completion_queues: RwLock::new( - std::iter::once((0u16, Mutex::new((NvmeCompQueue::new()?, smallvec!(0))))) - .collect(), - ), - // map the zero interrupt vector (which according to the spec shall always point to the - // admin completion queue) to CQID 0 (admin completion queue) - cqs_for_ivs: RwLock::new(std::iter::once((0, smallvec!(0))).collect()), - buffer: Mutex::new(unsafe { Dma::zeroed()?.assume_init() }), - buffer_prp: Mutex::new(unsafe { Dma::zeroed()?.assume_init() }), + + cq_ivs: RwLock::new(iter::once((0, 0)).collect()), + sq_ivs: RwLock::new(iter::once((0, 0)).collect()), + interrupt_method: Mutex::new(interrupt_method), pcid_interface: Mutex::new(pcid_interface), - reactor_sender, - next_sqid: AtomicSqId::new(0), - next_cqid: AtomicCqId::new(0), - next_avail_submission_epoch: AtomicU64::new(0), + // TODO + next_sqid: AtomicSqId::new(2), + next_cqid: AtomicCqId::new(2), }) } /// Write to a doorbell register. @@ -255,13 +265,17 @@ impl Nvme { unsafe fn doorbell_write(&self, index: usize, value: u32) { use std::ops::DerefMut; - let mut regs_guard = self.regs.write().unwrap(); - let mut regs: &mut NvmeRegs = regs_guard.deref_mut(); + let mut regs_guard = self.regs.write(); + let regs: &mut NvmeRegs = regs_guard.deref_mut(); let dstrd = (regs.cap_high.read() & 0b1111) as usize; let addr = (regs as *mut NvmeRegs as usize) + 0x1000 + index * (4 << dstrd); (&mut *(addr as *mut Mmio)).write(value); } + fn cur_thread_ctxt(&self) -> Arc> { + // TODO: multi-threading + Arc::clone(self.thread_ctxts.read().get(&0).unwrap()) + } pub unsafe fn submission_queue_tail(&self, qid: u16, tail: u16) { self.doorbell_write(2 * (qid as usize), u32::from(tail)); @@ -272,15 +286,9 @@ impl Nvme { } pub unsafe fn init(&mut self) { - let mut buffer = self.buffer.get_mut().unwrap(); - let mut buffer_prp = self.buffer_prp.get_mut().unwrap(); - - for i in 0..buffer_prp.len() { - buffer_prp[i] = (buffer.physical() + i * 4096) as u64; - } - + let thread_ctxts = self.thread_ctxts.get_mut(); { - let regs = self.regs.read().unwrap(); + let regs = self.regs.read(); log::debug!("CAP_LOW: {:X}", regs.cap_low.read()); log::debug!("CAP_HIGH: {:X}", regs.cap_high.read()); log::debug!("VS: {:X}", regs.vs.read()); @@ -289,11 +297,11 @@ impl Nvme { } log::debug!("Disabling controller."); - self.regs.get_mut().unwrap().cc.writef(1, false); + self.regs.get_mut().cc.writef(1, false); log::trace!("Waiting for not ready."); loop { - let csts = self.regs.get_mut().unwrap().csts.read(); + let csts = self.regs.get_mut().csts.read(); log::trace!("CSTS: {:X}", csts); if csts & 1 == 1 { pause(); @@ -302,46 +310,41 @@ impl Nvme { } } - match self.interrupt_method.get_mut().unwrap() { + match self.interrupt_method.get_mut() { &mut InterruptMethod::Intx | InterruptMethod::Msi { .. } => { - self.regs.get_mut().unwrap().intms.write(0xFFFF_FFFF); - self.regs.get_mut().unwrap().intmc.write(0x0000_0001); + self.regs.get_mut().intms.write(0xFFFF_FFFF); + self.regs.get_mut().intmc.write(0x0000_0001); } &mut InterruptMethod::MsiX(ref mut cfg) => { cfg.table[0].unmask(); } } - for (qid, queue) in self.completion_queues.get_mut().unwrap().iter_mut() { - let &(ref cq, ref sq_ids) = &*queue.get_mut().unwrap(); - let data = &cq.data; - log::debug!( - "completion queue {}: {:X}, {}, (submission queue ids: {:?}", - qid, - data.physical(), - data.len(), - sq_ids - ); - } + for (qid, iv) in self.cq_ivs.get_mut().iter_mut() { + let ctxt = thread_ctxts.get(&0).unwrap().lock(); + let queues = ctxt.queues.borrow(); - for (qid, (queue, cq_id)) in self.submission_queues.get_mut().unwrap().iter_mut() { - let data = &queue.get_mut().unwrap().data; + let &(ref cq, ref sq) = queues.get(qid).unwrap(); log::debug!( - "submission queue {}: {:X}, {}, attached to CQID: {}", - qid, - data.physical(), - data.len(), - cq_id + "iv {iv} [cq {qid}: {:X}, {}] [sq {qid}: {:X}, {}]", + cq.data.physical(), + cq.data.len(), + sq.data.physical(), + sq.data.len() ); } { - let regs = self.regs.get_mut().unwrap(); - let submission_queues = self.submission_queues.get_mut().unwrap(); - let completion_queues = self.completion_queues.get_mut().unwrap(); + let main_ctxt = thread_ctxts.get(&0).unwrap().lock(); - let asq = submission_queues.get_mut(&0).unwrap().0.get_mut().unwrap(); - let (acq, _) = completion_queues.get_mut(&0).unwrap().get_mut().unwrap(); + for (i, prp) in main_ctxt.buffer_prp.borrow_mut().iter_mut().enumerate() { + *prp = (main_ctxt.buffer.borrow_mut().physical() + i * 4096) as u64; + } + + let regs = self.regs.get_mut(); + + let mut queues = main_ctxt.queues.borrow_mut(); + let (asq, acq) = queues.get_mut(&0).unwrap(); regs.aqa .write(((acq.data.len() as u32 - 1) << 16) | (asq.data.len() as u32 - 1)); regs.asq_low.write(asq.data.physical() as u32); @@ -359,11 +362,11 @@ impl Nvme { } log::debug!("Enabling controller."); - self.regs.get_mut().unwrap().cc.writef(1, true); + self.regs.get_mut().cc.writef(1, true); log::debug!("Waiting for ready"); loop { - let csts = self.regs.get_mut().unwrap().csts.read(); + let csts = self.regs.get_mut().csts.read(); log::debug!("CSTS: {:X}", csts); if csts & 1 == 0 { pause(); @@ -378,7 +381,7 @@ impl Nvme { /// # Panics /// Will panic if the same vector is called twice with different mask flags. pub fn set_vectors_masked(&self, vectors: impl IntoIterator) { - let mut interrupt_method_guard = self.interrupt_method.lock().unwrap(); + let mut interrupt_method_guard = self.interrupt_method.lock(); match &mut *interrupt_method_guard { &mut InterruptMethod::Intx => { @@ -394,9 +397,9 @@ impl Nvme { ); assert_eq!(vector, 0, "nvmed: internal error: nonzero vector on INTx#"); if mask { - self.regs.write().unwrap().intms.write(0x0000_0001); + self.regs.write().intms.write(0x0000_0001); } else { - self.regs.write().unwrap().intmc.write(0x0000_0001); + self.regs.write().intmc.write(0x0000_0001); } } &mut InterruptMethod::Msi { @@ -431,10 +434,10 @@ impl Nvme { } if to_mask != 0 { - self.regs.write().unwrap().intms.write(to_mask); + self.regs.write().intms.write(to_mask); } if to_clear != 0 { - self.regs.write().unwrap().intmc.write(to_clear); + self.regs.write().intmc.write(to_clear); } } &mut InterruptMethod::MsiX(ref mut cfg) => { @@ -451,226 +454,175 @@ impl Nvme { self.set_vectors_masked(std::iter::once((vector, masked))) } - #[cfg(not(feature = "async"))] - pub fn submit_and_complete_command NvmeCmd>( + pub async fn submit_and_complete_command( &self, sq_id: SqId, - cmd_init: F, + cmd_init: impl FnOnce(CmdId) -> NvmeCmd, ) -> NvmeComp { - // Submit command - let cmd = { - let sqs_read_guard = self.submission_queues.read().unwrap(); - let &(ref sq_lock, cq_id) = sqs_read_guard - .get(&sq_id) - .expect("nvmed: internal error: given SQ for SQ ID not there"); - let mut sq_guard = sq_lock.lock().unwrap(); - let sq = &mut *sq_guard; + NvmeExecutor::current().submit(sq_id, cmd_init(0)).await + } - assert!(!sq.is_full()); - - let cmd_id = u16::try_from(sq.tail) - .expect("nvmed: internal error: CQ has more than 2^16 entries"); - let cmd = cmd_init(cmd_id); - log::trace!( - "Sent submission queue entry (SQID {}): {:?} at {}", - sq_id, - cmd, - cmd_id - ); - let tail = sq.submit_unchecked(cmd); - let tail = u16::try_from(tail).unwrap(); - - // make sure that we register interest before the reactor can get notified - unsafe { self.submission_queue_tail(sq_id, tail) }; - - cmd - }; - - // Read completion - loop { - for (cq_id, completion_queue_lock) in self.completion_queues.read().unwrap().iter() { - if *cq_id != sq_id { - // Currently, CQ and SQ IDs have to match - continue; + pub async fn submit_and_complete_admin_command( + &self, + cmd_init: impl FnOnce(CmdId) -> NvmeCmd, + ) -> NvmeComp { + self.submit_and_complete_command(0, cmd_init).await + } + pub fn try_submit_raw( + &self, + ctxt: &ThreadCtxt, + sq_id: SqId, + cmd_init: impl FnOnce(CmdId) -> NvmeCmd, + fail: impl FnOnce(), + ) -> Option<(CqId, CmdId)> { + match ctxt.queues.borrow_mut().get_mut(&sq_id).unwrap() { + (sq, _cq) => { + if sq.is_full() { + fail(); + return None; } + let cmd_id = sq.tail; + let tail = sq.submit_unchecked(cmd_init(cmd_id)); - let mut completion_queue_guard = completion_queue_lock.lock().unwrap(); - let &mut (ref mut completion_queue, _) = &mut *completion_queue_guard; - - while let Some((head, entry)) = completion_queue.complete(Some((sq_id, cmd))) { - unsafe { self.completion_queue_head(*cq_id, head) }; - - log::trace!( - "Got completion queue entry (CQID {}): {:?} at {}", - cq_id, - entry, - head - ); - - assert_eq!(sq_id, { entry.sq_id }); - assert_eq!({ cmd.cid }, { entry.cid }); - - { - let submission_queues_read_lock = self.submission_queues.read().unwrap(); - // this lock is actually important, since it will block during submission from other - // threads. the lock won't be held for long by the submitters, but it still prevents - // the entry being lost before this reactor is actually able to respond: - let &(ref sq_lock, corresponding_cq_id) = submission_queues_read_lock.get(&{entry.sq_id}).expect("nvmed: internal error: queue returned from controller doesn't exist"); - assert_eq!(*cq_id, corresponding_cq_id); - let mut sq_guard = sq_lock.lock().unwrap(); - sq_guard.head = entry.sq_head; - } - - return entry; + // TODO: Submit in bulk + unsafe { + self.submission_queue_tail(sq_id, tail); } + Some((sq_id, cmd_id)) } - std::thread::yield_now(); } } - #[cfg(feature = "async")] - pub fn submit_and_complete_command NvmeCmd>( + pub async fn create_io_completion_queue( &self, - sq_id: SqId, - cmd_init: F, - ) -> NvmeComp { - use crate::nvme::cq_reactor::{CompletionFuture, CompletionFutureState}; - futures::executor::block_on(CompletionFuture { - state: CompletionFutureState::PendingSubmission { - cmd_init, - nvme: &self, - sq_id, - }, - }) - } + io_cq_id: CqId, + vector: Option, + ) -> NvmeCompQueue { + let queue = NvmeCompQueue::new().expect("nvmed: failed to allocate I/O completion queue"); - pub fn submit_and_complete_admin_command NvmeCmd>( - &self, - cmd_init: F, - ) -> NvmeComp { - self.submit_and_complete_command(0, cmd_init) - } - - pub fn create_io_completion_queue(&self, io_cq_id: CqId, vector: Option) { - let (ptr, len) = { - let mut completion_queues_guard = self.completion_queues.write().unwrap(); - - let queue_guard = completion_queues_guard - .entry(io_cq_id) - .or_insert_with(|| { - let queue = NvmeCompQueue::new() - .expect("nvmed: failed to allocate I/O completion queue"); - let sqs = SmallVec::new(); - Mutex::new((queue, sqs)) - }) - .get_mut() - .unwrap(); - - let &(ref queue, _) = &*queue_guard; - (queue.data.physical(), queue.data.len()) - }; - - let len = - u16::try_from(len).expect("nvmed: internal error: I/O CQ longer than 2^16 entries"); + let len = u16::try_from(queue.data.len()) + .expect("nvmed: internal error: I/O CQ longer than 2^16 entries"); let raw_len = len .checked_sub(1) .expect("nvmed: internal error: CQID 0 for I/O CQ"); - let comp = self.submit_and_complete_admin_command(|cid| { - NvmeCmd::create_io_completion_queue(cid, io_cq_id, ptr, raw_len, vector) - }); - - if let Some(vector) = vector { - self.cqs_for_ivs - .write() - .unwrap() - .entry(vector) - .or_insert_with(SmallVec::new) - .push(io_cq_id); - } - } - pub fn create_io_submission_queue(&self, io_sq_id: SqId, io_cq_id: CqId) { - let (ptr, len) = { - let mut submission_queues_guard = self.submission_queues.write().unwrap(); - - let (queue_lock, _) = submission_queues_guard.entry(io_sq_id).or_insert_with(|| { - ( - Mutex::new( - NvmeCmdQueue::new() - .expect("nvmed: failed to allocate I/O completion queue"), - ), + let comp = self + .submit_and_complete_admin_command(|cid| { + NvmeCmd::create_io_completion_queue( + cid, io_cq_id, + queue.data.physical(), + raw_len, + vector, ) - }); - let queue = queue_lock.get_mut().unwrap(); + }) + .await; - (queue.data.physical(), queue.data.len()) - }; + /*match comp.status.specific { + 1 => panic!("invalid queue identifier"), + 2 => panic!("invalid queue size"), + 8 => panic!("invalid interrupt vector"), + _ => (), + }*/ - let len = - u16::try_from(len).expect("nvmed: internal error: I/O SQ longer than 2^16 entries"); + queue + } + pub async fn create_io_submission_queue(&self, io_sq_id: SqId, io_cq_id: CqId) -> NvmeCmdQueue { + let q = NvmeCmdQueue::new().expect("failed to create submission queue"); + + let len = u16::try_from(q.data.len()) + .expect("nvmed: internal error: I/O SQ longer than 2^16 entries"); let raw_len = len .checked_sub(1) .expect("nvmed: internal error: SQID 0 for I/O SQ"); - let comp = self.submit_and_complete_admin_command(|cid| { - NvmeCmd::create_io_submission_queue(cid, io_sq_id, ptr, raw_len, io_cq_id) - }); + let comp = self + .submit_and_complete_admin_command(|cid| { + NvmeCmd::create_io_submission_queue( + cid, + io_sq_id, + q.data.physical(), + raw_len, + io_cq_id, + ) + }) + .await; + /*match comp.status.specific { + 0 => panic!("completion queue invalid"), + 1 => panic!("invalid queue identifier"), + 2 => panic!("invalid queue size"), + _ => (), + }*/ + + q } - pub fn init_with_queues(&self) -> BTreeMap { + pub async fn init_with_queues(&self) -> BTreeMap { log::trace!("preinit"); - self.identify_controller(); - let nsids = self.identify_namespace_list(0); + self.identify_controller().await; + + let nsids = self.identify_namespace_list(0).await; log::debug!("first commands"); let mut namespaces = BTreeMap::new(); for nsid in nsids.iter().copied() { - namespaces.insert(nsid, self.identify_namespace(nsid)); + namespaces.insert(nsid, self.identify_namespace(nsid).await); } // TODO: Multiple queues - self.create_io_completion_queue(1, Some(0)); - self.create_io_submission_queue(1, 1); + let cq = self.create_io_completion_queue(1, Some(0)).await; + log::trace!("created compq"); + let sq = self.create_io_submission_queue(1, 1).await; + log::trace!("created subq"); + self.thread_ctxts + .read() + .get(&0) + .unwrap() + .lock() + .queues + .borrow_mut() + .insert(1, (sq, cq)); + self.sq_ivs.write().insert(1, 0); + self.cq_ivs.write().insert(1, 0); namespaces } - fn namespace_rw( + async fn namespace_rw( &self, - namespace: NvmeNamespace, + ctxt: &ThreadCtxt, + namespace: &NvmeNamespace, lba: u64, blocks_1: u16, write: bool, ) -> Result<()> { let block_size = namespace.block_size; - let buffer_prp_guard = self.buffer_prp.lock().unwrap(); - + let prp = ctxt.buffer_prp.borrow_mut(); let bytes = ((blocks_1 as u64) + 1) * block_size; let (ptr0, ptr1) = if bytes <= 4096 { - (buffer_prp_guard[0], 0) + (prp[0], 0) } else if bytes <= 8192 { - (buffer_prp_guard[0], buffer_prp_guard[1]) + (prp[0], prp[1]) } else { - ( - buffer_prp_guard[0], - (buffer_prp_guard.physical() + 8) as u64, - ) + (prp[0], (prp.physical() + 8) as u64) }; let mut cmd = NvmeCmd::default(); - let comp = self.submit_and_complete_command(1, |cid| { - cmd = if write { - NvmeCmd::io_write(cid, namespace.id, lba, blocks_1, ptr0, ptr1) - } else { - NvmeCmd::io_read(cid, namespace.id, lba, blocks_1, ptr0, ptr1) - }; - cmd.clone() - }); + let comp = self + .submit_and_complete_command(1, |cid| { + cmd = if write { + NvmeCmd::io_write(cid, namespace.id, lba, blocks_1, ptr0, ptr1) + } else { + NvmeCmd::io_read(cid, namespace.id, lba, blocks_1, ptr0, ptr1) + }; + cmd.clone() + }) + .await; + let status = comp.status >> 1; if status == 0 { Ok(()) @@ -680,55 +632,59 @@ impl Nvme { } } - pub fn namespace_read( + pub async fn namespace_read( &self, - namespace: NvmeNamespace, + namespace: &NvmeNamespace, mut lba: u64, buf: &mut [u8], - ) -> Result> { + ) -> Result { + let ctxt = self.cur_thread_ctxt(); + let ctxt = ctxt.lock(); + let block_size = namespace.block_size as usize; - let buffer_guard = self.buffer.lock().unwrap(); - - for chunk in buf.chunks_mut(/*TODO: buffer_guard.len()*/ 8192) { + for chunk in buf.chunks_mut(/* TODO: buf len */ 8192) { let blocks = (chunk.len() + block_size - 1) / block_size; assert!(blocks > 0); assert!(blocks <= 0x1_0000); - self.namespace_rw(namespace, lba, (blocks - 1) as u16, false)?; + self.namespace_rw(&*ctxt, namespace, lba, (blocks - 1) as u16, false) + .await?; - chunk.copy_from_slice(&buffer_guard[..chunk.len()]); + chunk.copy_from_slice(&ctxt.buffer.borrow()[..chunk.len()]); lba += blocks as u64; } - Ok(Some(buf.len())) + Ok(buf.len()) } - pub fn namespace_write( + pub async fn namespace_write( &self, - namespace: NvmeNamespace, + namespace: &NvmeNamespace, mut lba: u64, buf: &[u8], - ) -> Result> { + ) -> Result { + let ctxt = self.cur_thread_ctxt(); + let ctxt = ctxt.lock(); + let block_size = namespace.block_size as usize; - let mut buffer_guard = self.buffer.lock().unwrap(); - - for chunk in buf.chunks(/*TODO: buffer_guard.len()*/ 8192) { + for chunk in buf.chunks(/* TODO: buf len */ 8192) { let blocks = (chunk.len() + block_size - 1) / block_size; assert!(blocks > 0); assert!(blocks <= 0x1_0000); - buffer_guard[..chunk.len()].copy_from_slice(chunk); + ctxt.buffer.borrow_mut()[..chunk.len()].copy_from_slice(chunk); - self.namespace_rw(namespace, lba, (blocks - 1) as u16, true)?; + self.namespace_rw(&*ctxt, namespace, lba, (blocks - 1) as u16, true) + .await?; lba += blocks as u64; } - Ok(Some(buf.len())) + Ok(buf.len()) } } diff --git a/storage/nvmed/src/nvme/queues.rs b/storage/nvmed/src/nvme/queues.rs index 133c42effe..9d9cf2e2cb 100644 --- a/storage/nvmed/src/nvme/queues.rs +++ b/storage/nvmed/src/nvme/queues.rs @@ -1,3 +1,4 @@ +use std::cell::UnsafeCell; use std::ptr; use syscall::Result; @@ -49,7 +50,7 @@ pub struct NvmeComp { /// Completion queue pub struct NvmeCompQueue { - pub data: Dma<[NvmeComp]>, + pub data: Dma<[UnsafeCell]>, pub head: u16, pub phase: bool, } @@ -64,15 +65,8 @@ impl NvmeCompQueue { } /// Get a new completion queue entry, or return None if no entry is available yet. - pub(crate) fn complete(&mut self, cmd_opt: Option<(u16, NvmeCmd)>) -> Option<(u16, NvmeComp)> { - let entry = unsafe { ptr::read_volatile(self.data.as_ptr().add(self.head as usize)) }; - - //HACK FOR SOMETIMES RETURNING INVALID DATA ON QEMU! - if let Some((sq_id, cmd)) = cmd_opt { - if entry.sq_id != sq_id || entry.cid != cmd.cid { - return None; - } - } + pub(crate) fn complete(&mut self) -> Option<(u16, NvmeComp)> { + let entry = unsafe { ptr::read_volatile(self.data[usize::from(self.head)].get()) }; if ((entry.status & 1) == 1) == self.phase { self.head = (self.head + 1) % (self.data.len() as u16); @@ -86,10 +80,10 @@ impl NvmeCompQueue { } /// Get a new CQ entry, busy waiting until an entry appears. - fn complete_spin(&mut self, cmd_opt: Option<(u16, NvmeCmd)>) -> (u16, NvmeComp) { + pub fn complete_spin(&mut self) -> (u16, NvmeComp) { log::debug!("Waiting for new CQ entry"); loop { - if let Some(some) = self.complete(cmd_opt) { + if let Some(some) = self.complete() { return some; } else { unsafe { @@ -102,7 +96,7 @@ impl NvmeCompQueue { /// Submission queue pub struct NvmeCmdQueue { - pub data: Dma<[NvmeCmd]>, + pub data: Dma<[UnsafeCell]>, pub tail: u16, pub head: u16, } @@ -126,8 +120,32 @@ impl NvmeCmdQueue { /// Add a new submission command entry to the queue. The caller must ensure that the queue have free /// entries; this can be checked using `is_full`. pub fn submit_unchecked(&mut self, entry: NvmeCmd) -> u16 { - unsafe { ptr::write_volatile(&mut self.data[self.tail as usize] as *mut _, entry) } + unsafe { ptr::write_volatile(self.data[usize::from(self.tail)].get(), entry) } self.tail = (self.tail + 1) % (self.data.len() as u16); self.tail } } + +#[derive(Debug)] +pub enum Status { + GenericCmdStatus(u8), + CommandSpecificStatus(u8), + IntegrityError(u8), + PathRelatedStatus(u8), + Rsvd(u8), + Vendor(u8), +} +impl Status { + pub fn parse(raw: u16) -> Self { + let code = (raw >> 1) as u8; + match (raw >> 9) & 0b111 { + 0 => Self::GenericCmdStatus(code), + 1 => Self::CommandSpecificStatus(code), + 2 => Self::IntegrityError(code), + 3 => Self::PathRelatedStatus(code), + 4..=6 => Self::Rsvd(code), + 7 => Self::Vendor(code), + _ => unreachable!(), + } + } +} From 6b0d4da2a205e8ab3f25a32c8866dcbce1f8473d Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 7 Mar 2025 11:18:11 +0100 Subject: [PATCH 1168/1301] Remove 'async' Cargo feature from nvmed. --- storage/nvmed/Cargo.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index e3f36e9832..948f30a970 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -21,5 +21,4 @@ partitionlib = { path = "../partitionlib" } pcid = { path = "../../pcid" } [features] -default = ["async"] -async = [] +default = [] From 4beb4209532f6b8a2c2aa973518c4b6322858780 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Mar 2025 09:09:27 +0100 Subject: [PATCH 1169/1301] Update dependencies. --- Cargo.lock | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f911a6daa..606960fcff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,7 +23,7 @@ version = "0.1.0" dependencies = [ "aml", "amlserde", - "arrayvec 0.7.6", + "arrayvec", "common", "libredox", "log", @@ -129,12 +129,6 @@ version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "arrayvec" version = "0.7.6" @@ -857,14 +851,15 @@ checksum = "6aa2c4e539b869820a2b82e1aef6ff40aa85e65decdd5185e83fb4b1249cd00f" name = "nvmed" version = "0.1.0" dependencies = [ - "arrayvec 0.5.2", - "bitflags 1.3.2", + "arrayvec", + "bitflags 2.6.0", "common", - "crossbeam-channel", "driver-block", - "futures", + "executor", "libredox", "log", + "parking_lot 0.12.3", + "partitionlib", "pcid", "redox-daemon", "redox_event", From 49333114e4e4ebc3f74c83c20d8387cc9b2ed00f Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Mar 2025 09:34:12 +0100 Subject: [PATCH 1170/1301] rustfmt. --- Cargo.lock | 247 +++++++++++++++++------------- storage/driver-block/Cargo.toml | 4 + storage/driver-block/src/lib.rs | 14 +- storage/usbscsid/src/main.rs | 15 +- storage/virtio-blkd/src/main.rs | 3 +- storage/virtio-blkd/src/scheme.rs | 12 +- 6 files changed, 173 insertions(+), 122 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 606960fcff..132f30d794 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,7 +69,7 @@ dependencies = [ name = "alxd" version = "0.1.0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "common", "libredox", "redox-daemon", @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.92" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "arrayvec" @@ -214,9 +214,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" dependencies = [ "serde", ] @@ -235,9 +235,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byteorder" @@ -247,9 +247,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.1.34" +version = "1.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9" +checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" dependencies = [ "shlex", ] @@ -278,16 +278,16 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", - "windows-targets", + "windows-link", ] [[package]] @@ -357,11 +357,11 @@ dependencies = [ [[package]] name = "crossbeam-queue" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" dependencies = [ - "crossbeam-utils 0.8.20", + "crossbeam-utils 0.8.21", ] [[package]] @@ -377,15 +377,16 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "driver-block" version = "0.1.0" dependencies = [ "executor", + "futures", "libredox", "log", "partitionlib", @@ -419,7 +420,7 @@ dependencies = [ name = "e1000d" version = "0.1.0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "common", "driver-network", "libredox", @@ -431,9 +432,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "executor" @@ -555,7 +556,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.100", ] [[package]] @@ -590,12 +591,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" dependencies = [ "cfg-if 1.0.0", "libc", + "r-efi", "wasi", ] @@ -605,7 +607,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8283e7331b8c93b9756e0cfdbcfb90312852f953c6faf9bf741e684cc3b6ad69" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "crc", "log", "uuid", @@ -622,9 +624,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "hermit-abi" @@ -655,14 +657,15 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.61" +version = "0.1.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -694,7 +697,7 @@ dependencies = [ name = "ihdad" version = "0.1.0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "common", "libredox", "log", @@ -707,9 +710,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.6.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", "hashbrown", @@ -731,15 +734,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "ixgbed" version = "1.0.0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "common", "driver-network", "libredox", @@ -751,10 +754,11 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -766,9 +770,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.161" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libredox" @@ -776,7 +780,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "libc", "redox_syscall", ] @@ -805,9 +809,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "maybe-uninit" @@ -852,7 +856,7 @@ name = "nvmed" version = "0.1.0" dependencies = [ "arrayvec", - "bitflags 2.6.0", + "bitflags 2.9.0", "common", "driver-block", "executor", @@ -864,14 +868,14 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "smallvec 1.13.2", + "smallvec 1.14.0", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" [[package]] name = "orbclient" @@ -934,7 +938,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", - "smallvec 1.13.2", + "smallvec 1.14.0", "windows-targets", ] @@ -954,7 +958,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4325c6aa3cca3373503b1527e75756f9fbfe5fd76be4b4c8a143ee47430b8e0" dependencies = [ "bit_field", - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[package]] @@ -998,9 +1002,9 @@ checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -1016,9 +1020,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] @@ -1040,13 +1044,19 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" + [[package]] name = "radium" version = "0.7.0" @@ -1117,7 +1127,7 @@ checksum = "81460b1526438123d16f0c968dbe42ba7f61e99645109b70e57864a8b66710fb" dependencies = [ "chrono", "log", - "smallvec 1.13.2", + "smallvec 1.14.0", "termion", ] @@ -1147,7 +1157,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69609faa5d5992247a4ef379917bb3e39be281405d6a0ccd4f942429400b956f" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "libredox", ] @@ -1157,7 +1167,7 @@ version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[package]] @@ -1180,9 +1190,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -1211,7 +1221,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64 0.21.7", - "bitflags 2.6.0", + "bitflags 2.9.0", "serde", "serde_derive", ] @@ -1220,7 +1230,7 @@ dependencies = [ name = "rtl8139d" version = "0.1.0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "common", "driver-network", "libredox", @@ -1235,7 +1245,7 @@ dependencies = [ name = "rtl8168d" version = "0.1.0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "common", "driver-network", "libredox", @@ -1253,16 +1263,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] -name = "ryu" -version = "1.0.18" +name = "rustversion" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "sb16d" version = "0.1.0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "common", "libredox", "log", @@ -1323,29 +1339,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.214" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.219" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.100", ] [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "itoa", "memchr", @@ -1388,9 +1404,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" dependencies = [ "serde", ] @@ -1444,9 +1460,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -1461,9 +1477,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "termion" -version = "4.0.3" +version = "4.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eaa98560e51a2cf4f0bb884d8b2098a9ea11ecf3b7078e9c68242c74cc923a7" +checksum = "6f359c854fbecc1ea65bc3683f1dcb2dce78b174a1ca7fda37acd1fff81df6ff" dependencies = [ "libc", "libredox", @@ -1482,22 +1498,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.100", ] [[package]] @@ -1545,9 +1561,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-width" @@ -1567,7 +1583,7 @@ dependencies = [ name = "usbhidd" version = "0.1.0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "common", "inputd", "log", @@ -1610,9 +1626,9 @@ checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" [[package]] name = "uuid" -version = "1.11.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" dependencies = [ "getrandom", ] @@ -1682,7 +1698,7 @@ dependencies = [ name = "virtio-core" version = "0.1.0" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "common", "crossbeam-queue", "futures", @@ -1744,41 +1760,44 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.14.2+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +dependencies = [ + "wit-bindgen-rt", +] [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if 1.0.0", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.100", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1786,22 +1805,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.100", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "winapi" @@ -1834,6 +1856,12 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + [[package]] name = "windows-targets" version = "0.52.6" @@ -1907,6 +1935,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" +dependencies = [ + "bitflags 2.9.0", +] + [[package]] name = "wyz" version = "0.5.1" @@ -1937,7 +1974,7 @@ dependencies = [ "regex", "serde", "serde_json", - "smallvec 1.13.2", + "smallvec 1.14.0", "thiserror", "toml 0.5.11", ] diff --git a/storage/driver-block/Cargo.toml b/storage/driver-block/Cargo.toml index 1ae22f56e0..da969a41c8 100644 --- a/storage/driver-block/Cargo.toml +++ b/storage/driver-block/Cargo.toml @@ -9,5 +9,9 @@ partitionlib = { path = "../partitionlib" } libredox = "0.1.3" log = "0.4" + +# TODO: migrate virtio to our executor +futures = { version = "0.3.28", features = ["executor"] } + redox_syscall = { version = "0.5", features = ["std"] } redox-scheme = "0.5" diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index bd36c9a23b..5397523a37 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -15,7 +15,8 @@ use redox_scheme::{CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, use syscall::dirent::DirentBuf; use syscall::schemev2::NewFdFlags; use syscall::{ - Error, Result, Stat, EACCES, EAGAIN, EBADF, EINTR, EINVAL, EISDIR, ENOENT, ENOLCK, EOPNOTSUPP, EOVERFLOW, EWOULDBLOCK, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT + Error, Result, Stat, EACCES, EAGAIN, EBADF, EINTR, EINVAL, EISDIR, ENOENT, ENOLCK, EOPNOTSUPP, + EOVERFLOW, EWOULDBLOCK, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT, }; /// Split the read operation into a series of block reads. @@ -275,6 +276,15 @@ impl ExecutorTrait for LocalExecutor { LocalExecutor::block_on(self, fut) } } +#[deprecated = "use custom executor"] +pub struct FuturesExecutor; + +#[allow(deprecated)] +impl ExecutorTrait for FuturesExecutor { + fn block_on<'a, O: 'a>(&self, fut: impl IntoFuture + 'a) -> O { + futures::executor::block_on(fut.into_future()) + } +} impl DiskScheme { pub fn new( @@ -610,7 +620,7 @@ impl SchemeAsync for DiskScheme { .get(part_num as usize) .ok_or(Error::new(EBADF))?; - part.size * u64::from(disk.block_size()) + part.size * u64::from(disk.block_size()) } }) } diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index 807ab11c38..6da8c36fe6 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::env; -use driver_block::{Disk, DiskScheme}; +use driver_block::{Disk, DiskScheme, ExecutorTrait}; use syscall::{Error, EIO}; use xhcid_interface::{ConfigureEndpointsReq, PortId, XhciClientHandle}; @@ -106,6 +106,7 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: PortId, protocol: protocol: &mut *protocol, }, )]), + &driver_block::FuturesExecutor, ); //libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); @@ -120,7 +121,9 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: PortId, protocol: for event in event_queue { match event.unwrap().user_data { - Event::Scheme => scheme.tick().unwrap(), + Event::Scheme => driver_block::FuturesExecutor + .block_on(scheme.tick()) + .unwrap(), } } @@ -141,9 +144,9 @@ impl Disk for UsbDisk<'_> { self.scsi.get_disk_size() } - fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { match self.scsi.read(self.protocol, block, buffer) { - Ok(bytes_read) => Ok(Some(bytes_read as usize)), + Ok(bytes_read) => Ok(bytes_read as usize), Err(err) => { eprintln!("usbscsid: READ IO ERROR: {err}"); Err(Error::new(EIO)) @@ -151,9 +154,9 @@ impl Disk for UsbDisk<'_> { } } - fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { match self.scsi.write(self.protocol, block, buffer) { - Ok(bytes_written) => Ok(Some(bytes_written as usize)), + Ok(bytes_written) => Ok(bytes_written as usize), Err(err) => { eprintln!("usbscsid: WRITE IO ERROR: {err}"); Err(Error::new(EIO)) diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 7503b477d7..88fbb52bdf 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -154,6 +154,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut scheme = DiskScheme::new( scheme_name, BTreeMap::from([(0, VirtioDisk::new(queue, device_space))]), + &driver_block::FuturesExecutor, ); libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); @@ -170,7 +171,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { for event in event_queue { match event.unwrap().user_data { - Event::Scheme => scheme.tick().unwrap(), + Event::Scheme => futures::executor::block_on(scheme.tick()).unwrap(), } } diff --git a/storage/virtio-blkd/src/scheme.rs b/storage/virtio-blkd/src/scheme.rs index 074f2ff61c..ec4ecf732d 100644 --- a/storage/virtio-blkd/src/scheme.rs +++ b/storage/virtio-blkd/src/scheme.rs @@ -93,15 +93,11 @@ impl driver_block::Disk for VirtioDisk<'_> { self.cfg.capacity() * u64::from(self.cfg.block_size()) } - fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { - Ok(Some(futures::executor::block_on( - self.queue.read(block, buffer), - ))) + async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { + Ok(self.queue.read(block, buffer).await) } - fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { - Ok(Some(futures::executor::block_on( - self.queue.write(block, buffer), - ))) + async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { + Ok(self.queue.write(block, buffer).await) } } From 6353fc73b4b997e8e8134fe9286796c3ea22eacf Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Mar 2025 09:54:29 +0100 Subject: [PATCH 1171/1301] Make ided and lived compile. --- storage/driver-block/src/lib.rs | 19 ++++++++++++++++- storage/ided/src/ide.rs | 10 +++++---- storage/ided/src/main.rs | 36 +++++++++++++++++++++++++++------ storage/lived/src/main.rs | 12 ++++++----- 4 files changed, 61 insertions(+), 16 deletions(-) diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 5397523a37..0363228587 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -1,11 +1,12 @@ use std::cmp; -use std::future::IntoFuture; +use std::future::{Future, IntoFuture}; use std::io::{self, Read, Seek, SeekFrom}; use std::collections::BTreeMap; use std::convert::TryFrom; use std::fmt::Write; use std::str; +use std::task::Poll; use executor::LocalExecutor; use libredox::Fd; @@ -285,6 +286,22 @@ impl ExecutorTrait for FuturesExecutor { futures::executor::block_on(fut.into_future()) } } +pub struct TrivialExecutor; +impl ExecutorTrait for TrivialExecutor { + fn block_on<'a, O: 'a>(&self, fut: impl IntoFuture + 'a) -> O { + let mut fut = std::pin::pin!(fut.into_future()); + let mut cx = std::task::Context::from_waker(std::task::Waker::noop()); + loop { + match fut.as_mut().poll(&mut cx) { + Poll::Ready(v) => return v, + Poll::Pending => { + log::warn!("TrivialExecutor: future wasn't trivial"); + continue; + } + } + } + } +} impl DiskScheme { pub fn new( diff --git a/storage/ided/src/ide.rs b/storage/ided/src/ide.rs index 9748b46b93..0a14bcc99a 100644 --- a/storage/ided/src/ide.rs +++ b/storage/ided/src/ide.rs @@ -177,7 +177,8 @@ impl Disk for AtaDisk { self.size } - fn read(&mut self, start_block: u64, buffer: &mut [u8]) -> Result> { + // NOTE: not async + async fn read(&mut self, start_block: u64, buffer: &mut [u8]) -> Result { let mut count = 0; for chunk in buffer.chunks_mut(65536) { let block = start_block + (count as u64) / 512; @@ -314,10 +315,11 @@ impl Disk for AtaDisk { count += chunk.len(); } - Ok(Some(count)) + Ok(count) } - fn write(&mut self, start_block: u64, buffer: &[u8]) -> Result> { + // NOTE: not async + async fn write(&mut self, start_block: u64, buffer: &[u8]) -> Result { let mut count = 0; for chunk in buffer.chunks(65536) { let block = start_block + (count as u64) / 512; @@ -462,6 +464,6 @@ impl Disk for AtaDisk { count += chunk.len(); } - Ok(Some(count)) + Ok(count) } } diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index c7dd8f8746..d3509a1ba8 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -1,5 +1,5 @@ use common::io::Io as _; -use driver_block::{Disk, DiskScheme}; +use driver_block::{Disk, DiskScheme, ExecutorTrait, FuturesExecutor}; use event::{EventFlags, RawEventQueue}; use libredox::flag; use log::{error, info}; @@ -61,7 +61,28 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { Arc::new(Mutex::new(primary)), Arc::new(Mutex::new(secondary)), ]; - let mut disks: Vec> = Vec::new(); + enum AnyDisk { + Ata(AtaDisk), + } + impl Disk for AnyDisk { + fn block_size(&self) -> u32 { + let AnyDisk::Ata(a) = self; + a.block_size() + } + fn size(&self) -> u64 { + let AnyDisk::Ata(a) = self; + a.size() + } + async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { + let AnyDisk::Ata(a) = self; + a.write(block, buffer).await + } + async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { + let AnyDisk::Ata(a) = self; + a.read(block, buffer).await + } + } + let mut disks: Vec = Vec::new(); for (chan_i, chan_lock) in chans.iter().enumerate() { let mut chan = chan_lock.lock().unwrap(); @@ -174,7 +195,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { println!(" DMA: {}", dma); println!(" {}-bit LBA", lba_bits); - disks.push(Box::new(AtaDisk { + disks.push(AnyDisk::Ata(AtaDisk { chan: chan_lock.clone(), chan_i, dev, @@ -194,6 +215,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .enumerate() .map(|(i, disk)| (i as u32, disk)) .collect(), + // TODO: Should ided just use TrivialExecutor or would it be valuable to actually use a + // real executor? + &FuturesExecutor, ); let primary_irq_fd = libredox::call::open( @@ -233,7 +257,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { for event in event_queue { let event = event.unwrap(); if event.fd == scheme.event_handle().raw() { - scheme.tick().unwrap(); + FuturesExecutor.block_on(scheme.tick()).unwrap(); } else if event.fd == primary_irq_fd { let mut irq = [0; 8]; if primary_irq_file @@ -248,7 +272,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .write(&irq) .expect("ided: failed to write irq file"); - scheme.tick().unwrap(); + FuturesExecutor.block_on(scheme.tick()).unwrap(); } } else if event.fd == secondary_irq_fd { let mut irq = [0; 8]; @@ -264,7 +288,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .write(&irq) .expect("ided: failed to write irq file"); - scheme.tick().unwrap(); + FuturesExecutor.block_on(scheme.tick()).unwrap(); } } else { error!("Unknown event {}", event.fd); diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index f4c2ac15ff..b53452e779 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -8,6 +8,7 @@ use std::fs::File; use std::os::fd::AsRawFd; use driver_block::{Disk, DiskScheme}; +use driver_block::{ExecutorTrait, TrivialExecutor}; use libredox::call::MmapArgs; use libredox::flag; @@ -86,7 +87,7 @@ impl Disk for LiveDisk { self.the_data.len() as u64 } - fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result> { + async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { let block = block as usize; let block_size = self.block_size() as usize; if block * block_size + buffer.len() > self.size() as usize { @@ -94,10 +95,10 @@ impl Disk for LiveDisk { } buffer .copy_from_slice(&self.the_data[block * block_size..block * block_size + buffer.len()]); - Ok(Some(block_size)) + Ok(block_size) } - fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result> { + async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { let block = block as usize; let block_size = self.block_size() as usize; if block * block_size + buffer.len() > self.size() as usize { @@ -105,7 +106,7 @@ impl Disk for LiveDisk { } self.the_data[block * block_size..block * block_size + buffer.len()] .copy_from_slice(buffer); - Ok(Some(block_size)) + Ok(block_size) } } @@ -128,6 +129,7 @@ fn main() -> anyhow::Result<()> { std::process::exit(1) }), )]), + &TrivialExecutor, ); libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); @@ -144,7 +146,7 @@ fn main() -> anyhow::Result<()> { for event in event_queue { match event.unwrap().user_data { - Event::Scheme => scheme.tick().unwrap(), + Event::Scheme => TrivialExecutor.block_on(scheme.tick()).unwrap(), } } From a180c5893f693a95f4d612c527e4e4a3ba37413b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 24 Mar 2025 10:15:50 +0100 Subject: [PATCH 1172/1301] Make ahcid compile. --- storage/ahcid/src/ahci/disk_ata.rs | 9 +++--- storage/ahcid/src/ahci/disk_atapi.rs | 6 ++-- storage/ahcid/src/ahci/mod.rs | 41 ++++++++++++++++++++++++---- storage/ahcid/src/main.rs | 10 +++---- 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/storage/ahcid/src/ahci/disk_ata.rs b/storage/ahcid/src/ahci/disk_ata.rs index bb52a4571d..3494d8624d 100644 --- a/storage/ahcid/src/ahci/disk_ata.rs +++ b/storage/ahcid/src/ahci/disk_ata.rs @@ -144,6 +144,7 @@ impl DiskATA { self.request_opt = Some(request); + // TODO: support async internally return Ok(None); } else { // Done @@ -162,21 +163,21 @@ impl Disk for DiskATA { self.size } - fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result> { + async fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { //TODO: FIGURE OUT WHY INTERRUPTS CAUSE HANGS loop { match self.request(block, BufferKind::Read(buffer))? { - Some(count) => return Ok(Some(count)), + Some(count) => return Ok(count), None => std::thread::yield_now(), } } } - fn write(&mut self, block: u64, buffer: &[u8]) -> Result> { + async fn write(&mut self, block: u64, buffer: &[u8]) -> Result { //TODO: FIGURE OUT WHY INTERRUPTS CAUSE HANGS loop { match self.request(block, BufferKind::Write(buffer))? { - Some(count) => return Ok(Some(count)), + Some(count) => return Ok(count), None => std::thread::yield_now(), } } diff --git a/storage/ahcid/src/ahci/disk_atapi.rs b/storage/ahcid/src/ahci/disk_atapi.rs index b92112c36e..9571ed9e0e 100644 --- a/storage/ahcid/src/ahci/disk_atapi.rs +++ b/storage/ahcid/src/ahci/disk_atapi.rs @@ -77,7 +77,7 @@ impl Disk for DiskATAPI { u64::from(self.blk_count) * u64::from(self.blk_size) } - fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result> { + async fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { // TODO: Handle audio CDs, which use special READ CD command let blk_len = self.blk_size; @@ -139,10 +139,10 @@ impl Disk for DiskATAPI { sector += sectors - sector; } - Ok(Some((sector * blk_len) as usize)) + Ok((sector * blk_len) as usize) } - fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result> { + async fn write(&mut self, _block: u64, _buffer: &[u8]) -> Result { Err(Error::new(EBADF)) // TODO: Implement writing } } diff --git a/storage/ahcid/src/ahci/mod.rs b/storage/ahcid/src/ahci/mod.rs index 73e66c5ec5..4d8cc8c040 100644 --- a/storage/ahcid/src/ahci/mod.rs +++ b/storage/ahcid/src/ahci/mod.rs @@ -11,27 +11,58 @@ pub mod disk_atapi; pub mod fis; pub mod hba; -pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec>) { +pub enum AnyDisk { + Ata(DiskATA), + Atapi(DiskATAPI), +} +impl Disk for AnyDisk { + fn block_size(&self) -> u32 { + match self { + Self::Ata(a) => a.block_size(), + Self::Atapi(a) => a.block_size(), + } + } + fn size(&self) -> u64 { + match self { + Self::Ata(a) => a.size(), + Self::Atapi(a) => a.size(), + } + } + async fn read(&mut self, base: u64, buffer: &mut [u8]) -> syscall::Result { + match self { + Self::Ata(a) => a.read(base, buffer).await, + Self::Atapi(a) => a.read(base, buffer).await, + } + } + async fn write(&mut self, base: u64, buffer: &[u8]) -> syscall::Result { + match self { + Self::Ata(a) => a.write(base, buffer).await, + Self::Atapi(a) => a.write(base, buffer).await, + } + } +} + +pub fn disks(base: usize, name: &str) -> (&'static mut HbaMem, Vec) { let hba_mem = unsafe { &mut *(base as *mut HbaMem) }; hba_mem.init(); let pi = hba_mem.pi.read(); - let disks: Vec> = (0..hba_mem.ports.len()) + let disks: Vec = (0..hba_mem.ports.len()) .filter(|&i| pi & 1 << i as i32 == 1 << i as i32) .filter_map(|i| { let port = unsafe { &mut *hba_mem.ports.as_mut_ptr().add(i) }; let port_type = port.probe(); info!("{}-{}: {:?}", name, i, port_type); - let disk: Option> = match port_type { + let disk: Option = match port_type { HbaPortType::SATA => match DiskATA::new(i, port) { - Ok(disk) => Some(Box::new(disk)), + Ok(disk) => Some(AnyDisk::Ata(disk)), Err(err) => { error!("{}: {}", i, err); None } }, HbaPortType::SATAPI => match DiskATAPI::new(i, port) { - Ok(disk) => Some(Box::new(disk)), + Ok(disk) => Some(AnyDisk::Atapi(disk)), Err(err) => { error!("{}: {}", i, err); None diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 9ea8964dd1..d6b9f83d1c 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -1,14 +1,11 @@ #![cfg_attr(target_arch = "aarch64", feature(stdsimd))] // Required for yield instruction -extern crate byteorder; -extern crate syscall; - use std::io::{Read, Write}; use std::os::fd::AsRawFd; use std::usize; use common::io::Io; -use driver_block::DiskScheme; +use driver_block::{DiskScheme, ExecutorTrait, FuturesExecutor}; use event::{EventFlags, RawEventQueue}; use pcid_interface::PciFunctionHandle; @@ -54,6 +51,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .enumerate() .map(|(i, disk)| (i as u32, disk)) .collect(), + &FuturesExecutor, ); let mut irq_file = irq.irq_handle("ahcid"); @@ -75,7 +73,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { for event in event_queue { let event = event.unwrap(); if event.fd == scheme.event_handle().raw() { - scheme.tick().unwrap(); + FuturesExecutor.block_on(scheme.tick()).unwrap(); } else if event.fd == irq_fd { let mut irq = [0; 8]; if irq_file @@ -100,7 +98,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .write(&irq) .expect("ahcid: failed to write irq file"); - scheme.tick().unwrap(); + FuturesExecutor.block_on(scheme.tick()).unwrap(); } } } else { From af1dd1e78e47e5056909e11738cfb3d20188929c Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 16 May 2021 16:20:14 +0200 Subject: [PATCH 1173/1301] Add a userspace RTC driver for x86 PCs. The reason behind this is that an RTC driver should ideally consult ACPI tables before assuming any I/O ports exist, which userspace can do much better. --- Cargo.lock | 35 ++++++++--- Cargo.toml | 1 + rtcd/Cargo.toml | 12 ++++ rtcd/src/main.rs | 26 +++++++++ rtcd/src/x86.rs | 147 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 212 insertions(+), 9 deletions(-) create mode 100644 rtcd/Cargo.toml create mode 100644 rtcd/src/main.rs create mode 100644 rtcd/src/x86.rs diff --git a/Cargo.lock b/Cargo.lock index 132f30d794..d49167ab10 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,7 +14,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "spin", + "spin 0.9.8", ] [[package]] @@ -705,7 +705,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "spin", + "spin 0.9.8", ] [[package]] @@ -809,9 +809,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.26" +version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" +checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" [[package]] name = "maybe-uninit" @@ -873,9 +873,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "orbclient" @@ -1226,6 +1226,14 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "rtcd" +version = "0.1.0" +dependencies = [ + "anyhow", + "common", +] + [[package]] name = "rtl8139d" version = "0.1.0" @@ -1285,7 +1293,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "spin", + "spin 0.9.8", ] [[package]] @@ -1420,6 +1428,15 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spin" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" +dependencies = [ + "lock_api", +] + [[package]] name = "spinning_top" version = "0.2.5" @@ -1688,7 +1705,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "spin", + "spin 0.10.0", "static_assertions", "thiserror", "virtio-core", @@ -1728,7 +1745,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "spin", + "spin 0.9.8", "static_assertions", "virtio-core", ] diff --git a/Cargo.toml b/Cargo.toml index d27f9e6e46..4fb623614e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ members = [ "hwd", "pcid", "pcid-spawner", + "rtcd", "vboxd", "xhcid", "usbctl", diff --git a/rtcd/Cargo.toml b/rtcd/Cargo.toml new file mode 100644 index 0000000000..a6b9587872 --- /dev/null +++ b/rtcd/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rtcd" +version = "0.1.0" +authors = ["4lDO2 <4lDO2@protonmail.com>"] +edition = "2018" +license = "MIT" + + +[dependencies] +anyhow = "1" + +common = { path = "../common" } diff --git a/rtcd/src/main.rs b/rtcd/src/main.rs new file mode 100644 index 0000000000..3e913780ab --- /dev/null +++ b/rtcd/src/main.rs @@ -0,0 +1,26 @@ +use anyhow::{Context, Result}; + +// TODO: Do not use target architecture to distinguish these. +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +mod x86; + +/// The rtc driver runs only once, being perhaps the first of all processes that init starts (since +/// early logging benefits from knowing the time, even though this can be adjusted later once the +/// time is known). The sole job of `rtcd` is to read from the hardware real-time clock, and then +/// write the offset to the kernel. + +fn main() -> Result<()> { + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + { + common::acquire_port_io_rights().context("failed to set iopl")?; + + let time_s = self::x86::get_time(); + let time_ns = u128::from(time_s) * 1_000_000_000; + + std::fs::write("/scheme/sys/update_time_offset", &time_ns.to_ne_bytes()) + .context("failed to write to time offset")?; + } + // TODO: aarch64 is currently handled in the kernel + + Ok(()) +} diff --git a/rtcd/src/x86.rs b/rtcd/src/x86.rs new file mode 100644 index 0000000000..ea2aebcbbf --- /dev/null +++ b/rtcd/src/x86.rs @@ -0,0 +1,147 @@ +// TODO: Get RTC information from acpid. +use common::io::{Io, Pio}; + +pub fn get_time() -> u64 { + Rtc::new().time() +} + +fn cvt_bcd(value: usize) -> usize { + (value & 0xF) + ((value / 16) * 10) +} + +/// RTC +pub struct Rtc { + addr: Pio, + data: Pio, + nmi: bool, +} + +impl Rtc { + /// Create new empty RTC + pub fn new() -> Self { + Rtc { + addr: Pio::::new(0x70), + data: Pio::::new(0x71), + nmi: false, + } + } + + /// Read + unsafe fn read(&mut self, reg: u8) -> u8 { + if self.nmi { + self.addr.write(reg & 0x7F); + } else { + self.addr.write(reg | 0x80); + } + self.data.read() + } + + /// Write + #[allow(dead_code)] + unsafe fn write(&mut self, reg: u8, value: u8) { + if self.nmi { + self.addr.write(reg & 0x7F); + } else { + self.addr.write(reg | 0x80); + } + self.data.write(value); + } + + /// Wait for an update, can take one second if full is specified! + unsafe fn wait(&mut self, full: bool) { + if full { + while self.read(0xA) & 0x80 != 0x80 {} + } + while self.read(0xA) & 0x80 == 0x80 {} + } + + /// Get time without waiting + pub unsafe fn time_no_wait(&mut self) -> u64 { + /*let century_register = if let Some(ref fadt) = acpi::ACPI_TABLE.lock().fadt { + Some(fadt.century) + } else { + None + };*/ + + let mut second = self.read(0) as usize; + let mut minute = self.read(2) as usize; + let mut hour = self.read(4) as usize; + let mut day = self.read(7) as usize; + let mut month = self.read(8) as usize; + let mut year = self.read(9) as usize; + let mut century = /* TODO: Fix invalid value from VirtualBox + if let Some(century_reg) = century_register { + self.read(century_reg) as usize + } else */ { + 20 + }; + let register_b = self.read(0xB); + + if register_b & 4 != 4 { + second = cvt_bcd(second); + minute = cvt_bcd(minute); + hour = cvt_bcd(hour & 0x7F) | (hour & 0x80); + day = cvt_bcd(day); + month = cvt_bcd(month); + year = cvt_bcd(year); + century = /* TODO: Fix invalid value from VirtualBox + if century_register.is_some() { + cvt_bcd(century) + } else */ { + century + }; + } + + if register_b & 2 != 2 || hour & 0x80 == 0x80 { + hour = ((hour & 0x7F) + 12) % 24; + } + + year += century * 100; + + // Unix time from clock + let mut secs: u64 = (year as u64 - 1970) * 31_536_000; + + let mut leap_days = (year as u64 - 1972) / 4 + 1; + if year % 4 == 0 && month <= 2 { + leap_days -= 1; + } + secs += leap_days * 86_400; + + match month { + 2 => secs += 2_678_400, + 3 => secs += 5_097_600, + 4 => secs += 7_776_000, + 5 => secs += 10_368_000, + 6 => secs += 13_046_400, + 7 => secs += 15_638_400, + 8 => secs += 18_316_800, + 9 => secs += 20_995_200, + 10 => secs += 23_587_200, + 11 => secs += 26_265_600, + 12 => secs += 28_857_600, + _ => (), + } + + secs += (day as u64 - 1) * 86_400; + secs += hour as u64 * 3600; + secs += minute as u64 * 60; + secs += second as u64; + + secs + } + + /// Get time + pub fn time(&mut self) -> u64 { + loop { + unsafe { + self.wait(false); + let time = self.time_no_wait(); + self.wait(false); + let next_time = self.time_no_wait(); + if time == next_time { + return time; + } + } + } + } +} From 3ba8c99915a4a96b0e1ebc593f7388eec278a758 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 30 Mar 2025 16:08:13 +0200 Subject: [PATCH 1174/1301] Fix rustfmt CI and make bcm2835-sdhcid compile. --- storage/bcm2835-sdhcid/src/main.rs | 7 ++++--- storage/bcm2835-sdhcid/src/sd/mod.rs | 10 ++++++---- xhcid/src/usb/hub.rs | 2 +- xhcid/src/xhci/scheme.rs | 29 ++++++++++++++-------------- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index 34668a55f9..fda44f8860 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -2,7 +2,7 @@ use std::process; -use driver_block::{Disk, DiskScheme}; +use driver_block::{Disk, DiskScheme, ExecutorTrait, TrivialExecutor}; use event::{EventFlags, RawEventQueue}; use fdt::Fdt; @@ -99,7 +99,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } let mut disks = Vec::new(); - disks.push(Box::new(sdhci) as Box); + disks.push(sdhci); let mut scheme = DiskScheme::new( "disk.mmc".to_string(), disks @@ -107,6 +107,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .enumerate() .map(|(i, disk)| (i as u32, disk)) .collect(), + &TrivialExecutor, // TODO: real executor ); let event_queue = RawEventQueue::new().expect("mmcd: failed to open event file"); @@ -120,7 +121,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { for event in event_queue { let event = event.unwrap(); if event.fd == scheme.event_handle().raw() { - scheme.tick().unwrap(); + TrivialExecutor.block_on(scheme.tick()).unwrap(); } else { println!("Unknown event {}", event.fd); } diff --git a/storage/bcm2835-sdhcid/src/sd/mod.rs b/storage/bcm2835-sdhcid/src/sd/mod.rs index f8e9ab351b..5dda89acb6 100644 --- a/storage/bcm2835-sdhcid/src/sd/mod.rs +++ b/storage/bcm2835-sdhcid/src/sd/mod.rs @@ -742,7 +742,8 @@ impl Disk for SdHostCtrl { self.size } - fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result> { + // TODO: real async? + async fn read(&mut self, block: u64, buffer: &mut [u8]) -> Result { if (buffer.len() % 512) != 0 { println!("buffer.len {} should be aligned to {}", buffer.len(), 512); return Err(Error::new(EINVAL)); @@ -755,12 +756,13 @@ impl Disk for SdHostCtrl { self.sd_readblock(block as u32, u32_buffer, num as u32) }; match ret { - Ok(cnt) => Ok(Some(cnt)), + Ok(cnt) => Ok(cnt), Err(err) => Err(err), } } - fn write(&mut self, block: u64, buffer: &[u8]) -> Result> { + // TODO: real async? + async fn write(&mut self, block: u64, buffer: &[u8]) -> Result { if (buffer.len() % 512) != 0 { println!("buffer.len {} should be aligned to {}", buffer.len(), 512); return Err(Error::new(EINVAL)); @@ -773,7 +775,7 @@ impl Disk for SdHostCtrl { self.sd_writeblock(block as u32, u32_buffer, num as u32) }; match ret { - Ok(cnt) => Ok(Some(cnt)), + Ok(cnt) => Ok(cnt), Err(err) => Err(err), } } diff --git a/xhcid/src/usb/hub.rs b/xhcid/src/usb/hub.rs index 4962cb7a56..fbdb860624 100644 --- a/xhcid/src/usb/hub.rs +++ b/xhcid/src/usb/hub.rs @@ -184,4 +184,4 @@ impl HubPortStatus { Self::V3(x) => x.contains(HubPortStatusV3::ENABLE), } } -} \ No newline at end of file +} diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 7349ee101b..29c5b58e08 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -1446,21 +1446,22 @@ impl Xhci { // Only fetch language IDs if we need to. Some devices will fail to return this descriptor //TODO: also check configurations and interfaces for defined strings? - let lang_id = if raw_dd.manufacturer_str > 0 || raw_dd.product_str > 0 || raw_dd.serial_str > 0 { - let lang_ids = self.fetch_lang_ids_desc(port_id, slot).await?; - // Prefer US English, but fall back to first language ID, or zero - let en_us_id = 0x409; - if lang_ids.contains(&en_us_id) { - en_us_id - } else { - match lang_ids.first() { - Some(some) => *some, - None => 0, + let lang_id = + if raw_dd.manufacturer_str > 0 || raw_dd.product_str > 0 || raw_dd.serial_str > 0 { + let lang_ids = self.fetch_lang_ids_desc(port_id, slot).await?; + // Prefer US English, but fall back to first language ID, or zero + let en_us_id = 0x409; + if lang_ids.contains(&en_us_id) { + en_us_id + } else { + match lang_ids.first() { + Some(some) => *some, + None => 0, + } } - } - } else { - 0 - }; + } else { + 0 + }; log::debug!("port {} using language ID 0x{:04x}", port_id, lang_id); let (manufacturer_str, product_str, serial_str) = ( From a813d93001f31db0fedfa2de7d5971e6deb566fe Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 31 Mar 2025 08:11:44 -0600 Subject: [PATCH 1175/1301] Reduce some logging --- input/usbhidd/src/main.rs | 2 +- xhcid/src/xhci/device_enumerator.rs | 2 +- xhcid/src/xhci/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/input/usbhidd/src/main.rs b/input/usbhidd/src/main.rs index eae573bae4..6bc79da3aa 100644 --- a/input/usbhidd/src/main.rs +++ b/input/usbhidd/src/main.rs @@ -202,7 +202,7 @@ fn main() { let desc: DevDesc = handle .get_standard_descs() .expect("Failed to get standard descriptors"); - log::info!("{:X?}", desc); + log::debug!("{:X?}", desc); let mut endp_count = 0; let (conf_desc, (if_desc, endp_desc_opt, hid_desc)) = desc diff --git a/xhcid/src/xhci/device_enumerator.rs b/xhcid/src/xhci/device_enumerator.rs index b1573ec7b8..f33f420c90 100644 --- a/xhcid/src/xhci/device_enumerator.rs +++ b/xhcid/src/xhci/device_enumerator.rs @@ -24,7 +24,7 @@ impl DeviceEnumerator { pub fn run(&mut self) { loop { - info!("Start Device Enumerator Loop"); + debug!("Start Device Enumerator Loop"); let request = match self.request_queue.recv() { Ok(req) => req, Err(err) => { diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 2f91f72497..3d3798a312 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -104,7 +104,7 @@ impl Xhci { desc: &mut Dma, ) -> Result<()> { if self.interrupt_is_pending(0) { - warn!("EHB is already set!"); + debug!("EHB is already set!"); self.force_clear_interrupt(0); } let len = mem::size_of::(); From de4cc6ed4acd1f993ddc4a6be833592192d89c1f Mon Sep 17 00:00:00 2001 From: Dimitar Gjorgievski Date: Thu, 3 Apr 2025 21:21:32 +0000 Subject: [PATCH 1176/1301] adding support for gpu cursor --- graphics/driver-graphics/src/lib.rs | 42 ++++++- graphics/graphics-ipc/src/v1.rs | 13 ++ graphics/vesad/src/scheme.rs | 21 +++- graphics/virtio-gpud/src/main.rs | 67 +++++++++++ graphics/virtio-gpud/src/scheme.rs | 176 +++++++++++++++++++++++++++- 5 files changed, 312 insertions(+), 7 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index f06dbf59b4..f79d2c2d35 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use std::io; -use graphics_ipc::v1::Damage; +use graphics_ipc::v1::{CursorDamage, Damage}; use inputd::{VtEvent, VtEventKind}; use libredox::Fd; use redox_scheme::{RequestKind, Scheme, SignalBehavior, Socket}; @@ -9,6 +9,7 @@ use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL}; pub trait GraphicsAdapter { type Framebuffer: Framebuffer; + type Cursor: Cursor; fn displays(&self) -> Vec; fn display_size(&self, display_id: usize) -> (u32, u32); @@ -17,6 +18,10 @@ pub trait GraphicsAdapter { fn map_dumb_framebuffer(&mut self, framebuffer: &Self::Framebuffer) -> *mut u8; fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage); + + fn supports_hw_cursor(&self) -> bool; + fn create_cursor_framebuffer(&mut self) -> Self::Cursor; + fn handle_cursor(&mut self, cursor_damage: CursorDamage, cursor_resource: &mut Self::Cursor); } pub trait Framebuffer { @@ -24,6 +29,8 @@ pub trait Framebuffer { fn height(&self) -> u32; } +pub trait Cursor {} + pub struct GraphicsScheme { adapter: T, @@ -34,6 +41,7 @@ pub struct GraphicsScheme { active_vt: usize, vts_fb: HashMap>, + cursor_resources: HashMap, } enum Handle { @@ -53,6 +61,7 @@ impl GraphicsScheme { handles: BTreeMap::new(), active_vt: 0, vts_fb: HashMap::new(), + cursor_resources: HashMap::new(), } } @@ -167,6 +176,11 @@ impl Scheme for GraphicsScheme { self.adapter.create_dumb_framebuffer(width, height) }); + if self.adapter.supports_hw_cursor() { + self.cursor_resources + .insert(vt, self.adapter.create_cursor_framebuffer()); + } + self.next_id += 1; self.handles .insert(self.next_id, Handle::Screen { vt, screen: id }); @@ -201,12 +215,21 @@ impl Scheme for GraphicsScheme { fn read( &mut self, id: usize, - _buf: &mut [u8], + buf: &mut [u8], _offset: u64, _fcntl_flags: u32, ) -> Result { let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; - Err(Error::new(EINVAL)) + + //Currently read is only used for Orbital to check GPU cursor support + //and only expects a buf to pass a 0 or 1 flag + if self.adapter.supports_hw_cursor() { + buf[0] = 1; + } else { + buf[0] = 0; + } + + Ok(1) } fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { @@ -218,6 +241,19 @@ impl Scheme for GraphicsScheme { return Ok(buf.len()); } + if size_of_val(buf) == std::mem::size_of::() + && self.adapter.supports_hw_cursor() + { + let cursor_damage = unsafe { *buf.as_ptr().cast::() }; + + //There is always expected to be cursor_resource if supports_hw_cursor returns true + if let Some(cursor_resource) = self.cursor_resources.get_mut(vt) { + self.adapter.handle_cursor(cursor_damage, cursor_resource); + } + + return Ok(buf.len()); + } + let framebuffer = &self.vts_fb[vt][screen]; assert_eq!(buf.len(), std::mem::size_of::()); diff --git a/graphics/graphics-ipc/src/v1.rs b/graphics/graphics-ipc/src/v1.rs index 2ff0ddf900..14fb1e10b4 100644 --- a/graphics/graphics-ipc/src/v1.rs +++ b/graphics/graphics-ipc/src/v1.rs @@ -110,6 +110,19 @@ impl Drop for DisplayMap { } } +#[derive(Debug, Copy, Clone)] +#[repr(C, packed)] +pub struct CursorDamage { + pub header: u32, + pub x: i32, + pub y: i32, + pub hot_x: i32, + pub hot_y: i32, + pub width: i32, + pub height: i32, + pub cursor_img_bytes: [u32; 4096], +} + // Keep synced with orbital's SyncRect // Technically orbital uses i32 rather than u32, but values larger than i32::MAX // would be a bug anyway. diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index d89b5e600a..4b23b27893 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -2,8 +2,8 @@ use std::alloc::{self, Layout}; use std::convert::TryInto; use std::ptr::{self, NonNull}; -use driver_graphics::{Framebuffer, GraphicsAdapter}; -use graphics_ipc::v1::Damage; +use driver_graphics::{Cursor, Framebuffer, GraphicsAdapter}; +use graphics_ipc::v1::{CursorDamage, Damage}; use syscall::PAGE_SIZE; use crate::framebuffer::FrameBuffer; @@ -12,8 +12,13 @@ pub struct FbAdapter { pub framebuffers: Vec, } +pub enum VesadCursor {} + +impl Cursor for VesadCursor {} + impl GraphicsAdapter for FbAdapter { type Framebuffer = GraphicScreen; + type Cursor = VesadCursor; fn displays(&self) -> Vec { (0..self.framebuffers.len()).collect() @@ -37,6 +42,18 @@ impl GraphicsAdapter for FbAdapter { fn update_plane(&mut self, display_id: usize, framebuffer: &Self::Framebuffer, damage: Damage) { framebuffer.sync(&mut self.framebuffers[display_id], damage) } + + fn supports_hw_cursor(&self) -> bool { + false + } + + fn create_cursor_framebuffer(&mut self) -> VesadCursor { + unimplemented!("Vesad does not support this function"); + } + + fn handle_cursor(&mut self, _cursor_damage: CursorDamage, _cursor_resource: &mut VesadCursor) { + unimplemented!("Vesad does not support this function"); + } } pub struct GraphicScreen { diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index fa2a5da6f5..ea2b67eafe 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -361,6 +361,73 @@ impl XferToHost2d { } } +#[derive(Debug)] +#[repr(C)] +pub struct CursorPos { + pub scanout_id: u32, + pub x: i32, + pub y: i32, + _padding: u32, +} + +impl CursorPos { + pub fn new(scanout_id: u32, x: i32, y: i32) -> Self { + Self { + scanout_id, + x, + y, + _padding: 0, + } + } +} + +/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */ +#[derive(Debug)] +#[repr(C)] +pub struct UpdateCursor { + pub header: ControlHeader, + pub pos: CursorPos, + pub resource_id: ResourceId, + pub hot_x: i32, + pub hot_y: i32, + _padding: u32, +} + +impl UpdateCursor { + pub fn update_cursor(x: i32, y: i32, hot_x: i32, hot_y: i32, resource_id: ResourceId) -> Self { + Self { + header: ControlHeader::with_ty(CommandTy::UpdateCursor), + pos: CursorPos::new(0, x, y), + resource_id, + hot_x, + hot_y, + _padding: 0, + } + } +} + +pub struct MoveCursor { + pub header: ControlHeader, + pub pos: CursorPos, + pub resource_id: ResourceId, + pub hot_x: i32, + pub hot_y: i32, + _padding: u32, +} + +impl MoveCursor { + pub fn move_cursor(x: i32, y: i32, hot_x: i32, hot_y: i32, resource_id: ResourceId) -> Self { + Self { + header: ControlHeader::with_ty(CommandTy::MoveCursor), + pos: CursorPos::new(0, x, y), + resource_id, + hot_x, + hot_y, + _padding: 0, + } + } +} + static DEVICE: spin::Once = spin::Once::new(); fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 41ee3c31ca..459e29c367 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -1,8 +1,8 @@ use std::sync::Arc; use common::{dma::Dma, sgl}; -use driver_graphics::{Framebuffer, GraphicsAdapter, GraphicsScheme}; -use graphics_ipc::v1::Damage; +use driver_graphics::{Cursor, Framebuffer, GraphicsAdapter, GraphicsScheme}; +use graphics_ipc::v1::{CursorDamage, Damage}; use inputd::DisplayHandle; use syscall::PAGE_SIZE; @@ -40,6 +40,14 @@ impl Framebuffer for VirtGpuFramebuffer { } } +pub struct VirtGpuCursor { + resource_id: ResourceId, + sgl: sgl::Sgl, + set: bool, +} + +impl Cursor for VirtGpuCursor {} + #[derive(Debug, Copy, Clone)] pub struct Display { width: u32, @@ -92,10 +100,93 @@ impl VirtGpuAdapter<'_> { Ok(response) } + + fn update_cursor(&mut self, cursor_damage: CursorDamage, cursor: &mut VirtGpuCursor) { + let x = cursor_damage.x; + let y = cursor_damage.y; + let hot_x = cursor_damage.hot_x; + let hot_y = cursor_damage.hot_y; + + let w: i32 = cursor_damage.width; + let h: i32 = cursor_damage.height; + let cursor_image = cursor_damage.cursor_img_bytes; + + //Clear previous image from backing storage + unsafe { + core::ptr::write_bytes(cursor.sgl.as_ptr() as *mut u8, 0, 64 * 64 * 4); + } + + //Write image to backing storage + for row in 0..h { + let start: usize = (w * row) as usize; + let end: usize = (w * row + w) as usize; + + unsafe { + core::ptr::copy_nonoverlapping( + cursor_image[start..end].as_ptr(), + (cursor.sgl.as_ptr() as *mut u32).offset(64 * row as isize), + w as usize, + ); + } + } + + //Transfering cursor resource to host + futures::executor::block_on(async { + let transfer_request = Dma::new(XferToHost2d::new( + cursor.resource_id, + GpuRect { + x: 0, + y: 0, + width: 64, + height: 64, + }, + 0, + )) + .unwrap(); + let header = self.send_request_fenced(transfer_request).await.unwrap(); + assert_eq!(header.ty, CommandTy::RespOkNodata); + }); + + //Update the cursor position + let request = Dma::new(UpdateCursor::update_cursor( + x, + y, + hot_x, + hot_y, + cursor.resource_id, + )) + .unwrap(); + futures::executor::block_on(async { + let command = ChainBuilder::new().chain(Buffer::new(&request)).build(); + self.cursor_queue.send(command).await; + }); + } + + fn move_cursor(&self, cursor_damage: CursorDamage, cursor: &mut VirtGpuCursor) { + let x = cursor_damage.x; + let y = cursor_damage.y; + let hot_x = cursor_damage.hot_x; + let hot_y = cursor_damage.hot_y; + + let request = Dma::new(MoveCursor::move_cursor( + x, + y, + hot_x, + hot_y, + cursor.resource_id, + )) + .unwrap(); + + futures::executor::block_on(async { + let command = ChainBuilder::new().chain(Buffer::new(&request)).build(); + self.cursor_queue.send(command).await; + }); + } } impl GraphicsAdapter for VirtGpuAdapter<'_> { type Framebuffer = VirtGpuFramebuffer; + type Cursor = VirtGpuCursor; fn displays(&self) -> Vec { self.displays.iter().enumerate().map(|(i, _)| i).collect() @@ -207,6 +298,87 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { assert_eq!(header.ty, CommandTy::RespOkNodata); }); } + + fn supports_hw_cursor(&self) -> bool { + true + } + + fn create_cursor_framebuffer(&mut self) -> VirtGpuCursor { + //Creating a new resource for the cursor + let fb_size = 64 * 64 * 4; + let sgl = sgl::Sgl::new(fb_size).unwrap(); + let res_id = ResourceId::alloc(); + + futures::executor::block_on(async { + unsafe { + core::ptr::write_bytes(sgl.as_ptr() as *mut u8, 0, fb_size); + } + + let resource_request = + Dma::new(ResourceCreate2d::new(res_id, ResourceFormat::Bgrx, 64, 64)).unwrap(); + + let header = self.send_request_fenced(resource_request).await.unwrap(); + assert_eq!(header.ty, CommandTy::RespOkNodata); + + //Attaching cursor resource as backing storage + let mut mem_entries = + unsafe { Dma::zeroed_slice(sgl.chunks().len()).unwrap().assume_init() }; + for (entry, chunk) in mem_entries.iter_mut().zip(sgl.chunks().iter()) { + *entry = MemEntry { + address: chunk.phys as u64, + length: chunk.length.next_multiple_of(PAGE_SIZE) as u32, + padding: 0, + }; + } + + let attach_request = + Dma::new(AttachBacking::new(res_id, mem_entries.len() as u32)).unwrap(); + let mut header = Dma::new(ControlHeader::default()).unwrap(); + header.flags |= VIRTIO_GPU_FLAG_FENCE; + let command = ChainBuilder::new() + .chain(Buffer::new(&attach_request)) + .chain(Buffer::new_unsized(&mem_entries)) + .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.control_queue.send(command).await; + assert_eq!(header.ty, CommandTy::RespOkNodata); + + //Transfering cursor resource to host + let transfer_request = Dma::new(XferToHost2d::new( + res_id, + GpuRect { + x: 0, + y: 0, + width: 64, + height: 64, + }, + 0, + )) + .unwrap(); + let header = self.send_request_fenced(transfer_request).await.unwrap(); + assert_eq!(header.ty, CommandTy::RespOkNodata); + }); + + VirtGpuCursor { + resource_id: res_id, + sgl: sgl, + set: false, + } + } + + fn handle_cursor(&mut self, cursor_damage: CursorDamage, cursor: &mut VirtGpuCursor) { + if !cursor.set { + cursor.set = true; + self.update_cursor(cursor_damage, cursor); + } + + if cursor_damage.header == 0 { + self.move_cursor(cursor_damage, cursor); + } else { + self.update_cursor(cursor_damage, cursor); + } + } } pub struct GpuScheme {} From 03cf0955d240ecdebc6c03f263207238a18b5a69 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 4 Apr 2025 20:04:14 +0200 Subject: [PATCH 1177/1301] Move cursor resource writing to driver-graphics --- graphics/driver-graphics/src/lib.rs | 31 +++++++++++++++++++++++++++-- graphics/vesad/src/scheme.rs | 4 ++++ graphics/virtio-gpud/src/scheme.rs | 29 +++++---------------------- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index f79d2c2d35..9f0b9c7a60 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -21,6 +21,7 @@ pub trait GraphicsAdapter { fn supports_hw_cursor(&self) -> bool; fn create_cursor_framebuffer(&mut self) -> Self::Cursor; + fn map_cursor_framebuffer(&mut self, cursor: &Self::Cursor) -> *mut u8; fn handle_cursor(&mut self, cursor_damage: CursorDamage, cursor_resource: &mut Self::Cursor); } @@ -247,10 +248,36 @@ impl Scheme for GraphicsScheme { let cursor_damage = unsafe { *buf.as_ptr().cast::() }; //There is always expected to be cursor_resource if supports_hw_cursor returns true - if let Some(cursor_resource) = self.cursor_resources.get_mut(vt) { - self.adapter.handle_cursor(cursor_damage, cursor_resource); + let cursor_resource = self.cursor_resources.get_mut(vt).unwrap(); + + if cursor_damage.header != 0 { + let w: i32 = cursor_damage.width; + let h: i32 = cursor_damage.height; + let cursor_image = cursor_damage.cursor_img_bytes; + let cursor_ptr = self.adapter.map_cursor_framebuffer(cursor_resource); + + //Clear previous image from backing storage + unsafe { + core::ptr::write_bytes(cursor_ptr as *mut u8, 0, 64 * 64 * 4); + } + + //Write image to backing storage + for row in 0..h { + let start: usize = (w * row) as usize; + let end: usize = (w * row + w) as usize; + + unsafe { + core::ptr::copy_nonoverlapping( + cursor_image[start..end].as_ptr(), + cursor_ptr.cast::().offset(64 * row as isize), + w as usize, + ); + } + } } + self.adapter.handle_cursor(cursor_damage, cursor_resource); + return Ok(buf.len()); } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 4b23b27893..2336272cb0 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -51,6 +51,10 @@ impl GraphicsAdapter for FbAdapter { unimplemented!("Vesad does not support this function"); } + fn map_cursor_framebuffer(&mut self, _cursor: &Self::Cursor) -> *mut u8 { + unimplemented!("Vesad does not support this function"); + } + fn handle_cursor(&mut self, _cursor_damage: CursorDamage, _cursor_resource: &mut VesadCursor) { unimplemented!("Vesad does not support this function"); } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 459e29c367..2657df38e4 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -101,35 +101,12 @@ impl VirtGpuAdapter<'_> { Ok(response) } - fn update_cursor(&mut self, cursor_damage: CursorDamage, cursor: &mut VirtGpuCursor) { + fn update_cursor(&mut self, cursor_damage: CursorDamage, cursor: &VirtGpuCursor) { let x = cursor_damage.x; let y = cursor_damage.y; let hot_x = cursor_damage.hot_x; let hot_y = cursor_damage.hot_y; - let w: i32 = cursor_damage.width; - let h: i32 = cursor_damage.height; - let cursor_image = cursor_damage.cursor_img_bytes; - - //Clear previous image from backing storage - unsafe { - core::ptr::write_bytes(cursor.sgl.as_ptr() as *mut u8, 0, 64 * 64 * 4); - } - - //Write image to backing storage - for row in 0..h { - let start: usize = (w * row) as usize; - let end: usize = (w * row + w) as usize; - - unsafe { - core::ptr::copy_nonoverlapping( - cursor_image[start..end].as_ptr(), - (cursor.sgl.as_ptr() as *mut u32).offset(64 * row as isize), - w as usize, - ); - } - } - //Transfering cursor resource to host futures::executor::block_on(async { let transfer_request = Dma::new(XferToHost2d::new( @@ -367,6 +344,10 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { } } + fn map_cursor_framebuffer(&mut self, cursor: &Self::Cursor) -> *mut u8 { + cursor.sgl.as_ptr() + } + fn handle_cursor(&mut self, cursor_damage: CursorDamage, cursor: &mut VirtGpuCursor) { if !cursor.set { cursor.set = true; From abab5c9a3c66d58969b0c5fde6b05d3db8c87061 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 4 Apr 2025 20:25:57 +0200 Subject: [PATCH 1178/1301] Avoid passing unused fields to VIRTIO_GPU_CMD_MOVE_CURSOR --- graphics/virtio-gpud/src/main.rs | 8 ++++---- graphics/virtio-gpud/src/scheme.rs | 18 +++--------------- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index ea2b67eafe..7f95d9d572 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -416,13 +416,13 @@ pub struct MoveCursor { } impl MoveCursor { - pub fn move_cursor(x: i32, y: i32, hot_x: i32, hot_y: i32, resource_id: ResourceId) -> Self { + pub fn move_cursor(x: i32, y: i32) -> Self { Self { header: ControlHeader::with_ty(CommandTy::MoveCursor), pos: CursorPos::new(0, x, y), - resource_id, - hot_x, - hot_y, + resource_id: ResourceId(0), + hot_x: 0, + hot_y: 0, _padding: 0, } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 2657df38e4..606a768c3c 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -139,20 +139,8 @@ impl VirtGpuAdapter<'_> { }); } - fn move_cursor(&self, cursor_damage: CursorDamage, cursor: &mut VirtGpuCursor) { - let x = cursor_damage.x; - let y = cursor_damage.y; - let hot_x = cursor_damage.hot_x; - let hot_y = cursor_damage.hot_y; - - let request = Dma::new(MoveCursor::move_cursor( - x, - y, - hot_x, - hot_y, - cursor.resource_id, - )) - .unwrap(); + fn move_cursor(&self, cursor_damage: CursorDamage) { + let request = Dma::new(MoveCursor::move_cursor(cursor_damage.x, cursor_damage.y)).unwrap(); futures::executor::block_on(async { let command = ChainBuilder::new().chain(Buffer::new(&request)).build(); @@ -355,7 +343,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { } if cursor_damage.header == 0 { - self.move_cursor(cursor_damage, cursor); + self.move_cursor(cursor_damage); } else { self.update_cursor(cursor_damage, cursor); } From 215b8185c243d8de60b22062aeb36480aeaceb3a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 4 Apr 2025 20:34:42 +0200 Subject: [PATCH 1179/1301] Handle vt switching for cursors without requiring a cursor update This requires storing the cursor state on the driver-graphics side to be be able to restore the correct state for the target vt. --- graphics/driver-graphics/src/lib.rs | 70 ++++++++++++++++++++++------- graphics/vesad/src/scheme.rs | 8 ++-- graphics/virtio-gpud/src/scheme.rs | 42 ++++++++--------- 3 files changed, 77 insertions(+), 43 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 9f0b9c7a60..b52dfb5039 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -9,7 +9,7 @@ use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL}; pub trait GraphicsAdapter { type Framebuffer: Framebuffer; - type Cursor: Cursor; + type Cursor: CursorFramebuffer; fn displays(&self) -> Vec; fn display_size(&self, display_id: usize) -> (u32, u32); @@ -22,7 +22,7 @@ pub trait GraphicsAdapter { fn supports_hw_cursor(&self) -> bool; fn create_cursor_framebuffer(&mut self) -> Self::Cursor; fn map_cursor_framebuffer(&mut self, cursor: &Self::Cursor) -> *mut u8; - fn handle_cursor(&mut self, cursor_damage: CursorDamage, cursor_resource: &mut Self::Cursor); + fn handle_cursor(&mut self, cursor: &mut CursorPlane, dirty_fb: bool); } pub trait Framebuffer { @@ -30,7 +30,15 @@ pub trait Framebuffer { fn height(&self) -> u32; } -pub trait Cursor {} +pub struct CursorPlane { + pub x: i32, + pub y: i32, + pub hot_x: i32, + pub hot_y: i32, + pub framebuffer: C, +} + +pub trait CursorFramebuffer {} pub struct GraphicsScheme { adapter: T, @@ -42,7 +50,7 @@ pub struct GraphicsScheme { active_vt: usize, vts_fb: HashMap>, - cursor_resources: HashMap, + cursor_planes: HashMap>, } enum Handle { @@ -62,7 +70,7 @@ impl GraphicsScheme { handles: BTreeMap::new(), active_vt: 0, vts_fb: HashMap::new(), - cursor_resources: HashMap::new(), + cursor_planes: HashMap::new(), } } @@ -96,6 +104,15 @@ impl GraphicsScheme { Self::update_whole_screen(&mut self.adapter, display_id, framebuffer); self.active_vt = vt_event.vt; + + if self.adapter.supports_hw_cursor() { + let cursor_plane = Self::cursor_plane_for_vt( + &mut self.adapter, + &mut self.cursor_planes, + self.active_vt, + ); + self.adapter.handle_cursor(cursor_plane, true); + } } } @@ -150,6 +167,20 @@ impl GraphicsScheme { }, ); } + + fn cursor_plane_for_vt<'a>( + adapter: &mut T, + cursor_planes: &'a mut HashMap>, + vt: usize, + ) -> &'a mut CursorPlane { + cursor_planes.entry(vt).or_insert_with(|| CursorPlane { + x: 0, + y: 0, + hot_x: 0, + hot_y: 0, + framebuffer: adapter.create_cursor_framebuffer(), + }) + } } impl Scheme for GraphicsScheme { @@ -177,11 +208,6 @@ impl Scheme for GraphicsScheme { self.adapter.create_dumb_framebuffer(width, height) }); - if self.adapter.supports_hw_cursor() { - self.cursor_resources - .insert(vt, self.adapter.create_cursor_framebuffer()); - } - self.next_id += 1; self.handles .insert(self.next_id, Handle::Screen { vt, screen: id }); @@ -247,14 +273,25 @@ impl Scheme for GraphicsScheme { { let cursor_damage = unsafe { *buf.as_ptr().cast::() }; - //There is always expected to be cursor_resource if supports_hw_cursor returns true - let cursor_resource = self.cursor_resources.get_mut(vt).unwrap(); + let cursor_plane = Self::cursor_plane_for_vt( + &mut self.adapter, + &mut self.cursor_planes, + self.active_vt, + ); + + cursor_plane.x = cursor_damage.x; + cursor_plane.y = cursor_damage.y; + + if cursor_damage.header == 0 { + self.adapter.handle_cursor(cursor_plane, false); + } else { + cursor_plane.hot_x = cursor_damage.hot_x; + cursor_plane.hot_y = cursor_damage.hot_y; - if cursor_damage.header != 0 { let w: i32 = cursor_damage.width; let h: i32 = cursor_damage.height; let cursor_image = cursor_damage.cursor_img_bytes; - let cursor_ptr = self.adapter.map_cursor_framebuffer(cursor_resource); + let cursor_ptr = self.adapter.map_cursor_framebuffer(&cursor_plane.framebuffer); //Clear previous image from backing storage unsafe { @@ -274,9 +311,10 @@ impl Scheme for GraphicsScheme { ); } } - } - self.adapter.handle_cursor(cursor_damage, cursor_resource); + self.adapter + .handle_cursor(cursor_plane, true); + } return Ok(buf.len()); } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 2336272cb0..f8c4249ee5 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -2,8 +2,8 @@ use std::alloc::{self, Layout}; use std::convert::TryInto; use std::ptr::{self, NonNull}; -use driver_graphics::{Cursor, Framebuffer, GraphicsAdapter}; -use graphics_ipc::v1::{CursorDamage, Damage}; +use driver_graphics::{CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter}; +use graphics_ipc::v1::Damage; use syscall::PAGE_SIZE; use crate::framebuffer::FrameBuffer; @@ -14,7 +14,7 @@ pub struct FbAdapter { pub enum VesadCursor {} -impl Cursor for VesadCursor {} +impl CursorFramebuffer for VesadCursor {} impl GraphicsAdapter for FbAdapter { type Framebuffer = GraphicScreen; @@ -55,7 +55,7 @@ impl GraphicsAdapter for FbAdapter { unimplemented!("Vesad does not support this function"); } - fn handle_cursor(&mut self, _cursor_damage: CursorDamage, _cursor_resource: &mut VesadCursor) { + fn handle_cursor(&mut self, _cursor: &mut CursorPlane, _dirty_fb: bool) { unimplemented!("Vesad does not support this function"); } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 606a768c3c..86fc9c9fc9 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -1,8 +1,10 @@ use std::sync::Arc; use common::{dma::Dma, sgl}; -use driver_graphics::{Cursor, Framebuffer, GraphicsAdapter, GraphicsScheme}; -use graphics_ipc::v1::{CursorDamage, Damage}; +use driver_graphics::{ + CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapter, GraphicsScheme, +}; +use graphics_ipc::v1::Damage; use inputd::DisplayHandle; use syscall::PAGE_SIZE; @@ -43,10 +45,9 @@ impl Framebuffer for VirtGpuFramebuffer { pub struct VirtGpuCursor { resource_id: ResourceId, sgl: sgl::Sgl, - set: bool, } -impl Cursor for VirtGpuCursor {} +impl CursorFramebuffer for VirtGpuCursor {} #[derive(Debug, Copy, Clone)] pub struct Display { @@ -101,12 +102,7 @@ impl VirtGpuAdapter<'_> { Ok(response) } - fn update_cursor(&mut self, cursor_damage: CursorDamage, cursor: &VirtGpuCursor) { - let x = cursor_damage.x; - let y = cursor_damage.y; - let hot_x = cursor_damage.hot_x; - let hot_y = cursor_damage.hot_y; - + fn update_cursor(&mut self, cursor: &VirtGpuCursor, x: i32, y: i32, hot_x: i32, hot_y: i32) { //Transfering cursor resource to host futures::executor::block_on(async { let transfer_request = Dma::new(XferToHost2d::new( @@ -139,8 +135,8 @@ impl VirtGpuAdapter<'_> { }); } - fn move_cursor(&self, cursor_damage: CursorDamage) { - let request = Dma::new(MoveCursor::move_cursor(cursor_damage.x, cursor_damage.y)).unwrap(); + fn move_cursor(&mut self, x: i32, y: i32) { + let request = Dma::new(MoveCursor::move_cursor(x, y)).unwrap(); futures::executor::block_on(async { let command = ChainBuilder::new().chain(Buffer::new(&request)).build(); @@ -327,8 +323,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { VirtGpuCursor { resource_id: res_id, - sgl: sgl, - set: false, + sgl, } } @@ -336,16 +331,17 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { cursor.sgl.as_ptr() } - fn handle_cursor(&mut self, cursor_damage: CursorDamage, cursor: &mut VirtGpuCursor) { - if !cursor.set { - cursor.set = true; - self.update_cursor(cursor_damage, cursor); - } - - if cursor_damage.header == 0 { - self.move_cursor(cursor_damage); + fn handle_cursor(&mut self, cursor: &mut CursorPlane, dirty_fb: bool) { + if dirty_fb { + self.update_cursor( + &cursor.framebuffer, + cursor.x, + cursor.y, + cursor.hot_x, + cursor.hot_y, + ); } else { - self.update_cursor(cursor_damage, cursor); + self.move_cursor(cursor.x, cursor.y); } } } From f1b5ba52eda2ac308b53f88f940218c78ca718c5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 4 Apr 2025 20:41:31 +0200 Subject: [PATCH 1180/1301] Rustfmt --- graphics/driver-graphics/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index b52dfb5039..3ef5c0874e 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -291,7 +291,9 @@ impl Scheme for GraphicsScheme { let w: i32 = cursor_damage.width; let h: i32 = cursor_damage.height; let cursor_image = cursor_damage.cursor_img_bytes; - let cursor_ptr = self.adapter.map_cursor_framebuffer(&cursor_plane.framebuffer); + let cursor_ptr = self + .adapter + .map_cursor_framebuffer(&cursor_plane.framebuffer); //Clear previous image from backing storage unsafe { @@ -312,8 +314,7 @@ impl Scheme for GraphicsScheme { } } - self.adapter - .handle_cursor(cursor_plane, true); + self.adapter.handle_cursor(cursor_plane, true); } return Ok(buf.len()); From 65c23ed77d65f5a63a6f61217d0742e2311fba31 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 6 Apr 2025 17:12:10 +0200 Subject: [PATCH 1181/1301] graphics/vesad: Disable kernel graphical debug as late as possible --- graphics/vesad/src/main.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index dee3318404..e107129af0 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -3,9 +3,10 @@ extern crate syscall; use driver_graphics::GraphicsScheme; use event::{user_data, EventQueue}; -use inputd::DisplayHandle; +use inputd::{DisplayHandle, VtEventKind}; use std::env; use std::fs::File; +use std::io::Write; use std::os::fd::AsRawFd; use crate::framebuffer::FrameBuffer; @@ -104,7 +105,10 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec) -> ! { ) .unwrap(); - let _ = File::open("/scheme/debug/disable-graphical-debug"); + let mut disable_graphical_debug = Some( + File::open("/scheme/debug/disable-graphical-debug") + .expect("vesad: Failed to open /scheme/debug/disable-graphical-debug"), + ); libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); @@ -121,6 +125,16 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec) -> ! { .read_vt_event() .expect("vesad: failed to read display handle") { + if let VtEventKind::Activate = vt_event.kind { + // Disable the kernel graphical debug writing once switching vt's for the + // first time. This way the kernel graphical debug remains enabled if the + // userspace logging infrastructure doesn't start up because for example a + // kernel panic happened prior to it starting up or logd crashed. + if let Some(mut disable_graphical_debug) = disable_graphical_debug.take() { + let _ = disable_graphical_debug.write(&[1]); + } + } + scheme.handle_vt_event(vt_event); } } From d31867911276a2165ecffabb60500ceb0785a815 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 6 Apr 2025 20:10:44 +0200 Subject: [PATCH 1182/1301] graphics/fbbootlogd: Tell logd to use us as log sink --- graphics/fbbootlogd/src/main.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index 3de5509c2f..cfd0ce59b1 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -7,6 +7,7 @@ //! In the future fbbootlogd may also pull from logd as opposed to have logd push logs to it. And it //! it could display a boot splash like plymouth instead of a boot log when booting in quiet mode. +use std::io::Write; use std::os::fd::AsRawFd; use event::EventQueue; @@ -35,6 +36,15 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { let socket = Socket::nonblock("fbbootlog").expect("fbbootlogd: failed to create fbbootlog scheme"); + { + // Add ourself as log sink + let mut log_file = std::fs::OpenOptions::new() + .write(true) + .open("/scheme/log/add_sink") + .unwrap(); + log_file.write(b"/scheme/fbbootlog").unwrap(); + } + event_queue .subscribe( socket.inner().raw(), From 328f96bd8fabb3d56157ba98d5c15b8831bea972 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 12 Apr 2025 14:13:57 +0200 Subject: [PATCH 1183/1301] acpid: Gracefully exit on non-ACPI systems --- acpid/src/main.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/acpid/src/main.rs b/acpid/src/main.rs index acae764017..d53ef51e76 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -25,6 +25,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("acpid: failed to read `/scheme/kernel.acpi/rxsdt`") .into(); + if rxsdt_raw_data.is_empty() { + log::info!("System doesn't use ACPI"); + daemon.ready().expect("acpid: failed to notify parent"); + std::process::exit(0); + } + let sdt = self::acpi::Sdt::new(rxsdt_raw_data).expect("acpid: failed to parse [RX]SDT"); let mut thirty_two_bit; From 7625dcd0ce91257879c0f5a2bd3e25dbf39d0389 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 12 Apr 2025 14:54:50 +0200 Subject: [PATCH 1184/1301] pcid: Avoid legacy scheme path format --- pcid/src/cfg_access/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index 58de2a5556..b62be0a3ba 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -21,7 +21,7 @@ pub struct InterruptMap { fn locate_ecam_dtb( f: impl FnOnce(PcieAllocs<'_>, Vec, [u32; 4]) -> io::Result, ) -> io::Result { - let dtb = fs::read("kernel.dtb:")?; + let dtb = fs::read("/scheme/kernel.dtb")?; let dt = Fdt::new(&dtb).map_err(|err| { io::Error::new( io::ErrorKind::InvalidData, From 1d43e39b0e28593e4396c05466d720e48a6ee16a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 12 Apr 2025 14:55:17 +0200 Subject: [PATCH 1185/1301] pcid: Handle #address-cells on interrupt parent --- pcid/src/cfg_access/mod.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index b62be0a3ba..8e7f58b7be 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -55,6 +55,24 @@ fn locate_ecam_dtb( let mut interrupt_map = Vec::::new(); while let Ok([addr1, addr2, addr3, int1, phandle]) = interrupt_map_data.next_chunk::<5>() { let parent = dt.find_phandle(phandle).unwrap(); + let parent_address_cells = u32::from_be_bytes( + parent.property("#address-cells").unwrap().value[..4] + .try_into() + .unwrap(), + ); + match parent_address_cells { + 0 => {} + 1 => { + assert_eq!(interrupt_map_data.next().unwrap(), 0); + } + 2 => { + assert_eq!(interrupt_map_data.next_chunk::<2>().unwrap(), [0, 0]); + } + 3 => { + assert_eq!(interrupt_map_data.next_chunk::<3>().unwrap(), [0, 0, 0]); + } + _ => break, + }; let parent_interrupt_cells = parent.interrupt_cells().unwrap(); let parent_interrupt = match parent_interrupt_cells { 1 if let Some(a) = interrupt_map_data.next() => [a, 0, 0], From 657bf13d7c1045be71389263b0efaacfc5e1c807 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Fri, 7 Mar 2025 23:49:32 +0100 Subject: [PATCH 1186/1301] Use library call for iopl. --- Cargo.lock | 2 -- Cargo.toml | 1 + common/Cargo.toml | 2 +- common/src/lib.rs | 18 +++++++++++++++--- graphics/bgad/src/main.rs | 4 ++-- input/ps2d/Cargo.toml | 2 +- input/ps2d/src/main.rs | 6 ++---- 7 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d49167ab10..b16900eff7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1164,8 +1164,6 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ "bitflags 2.9.0", ] diff --git a/Cargo.toml b/Cargo.toml index 4fb623614e..fc3c6b4481 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,3 +56,4 @@ lto = "fat" mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } redox-daemon = { git = "https://gitlab.redox-os.org/redox-os/redox-daemon.git" } +redox_syscall = { path = "/home/dev/Projects/syscall3" } diff --git a/common/Cargo.toml b/common/Cargo.toml index 278e00c9c3..8cea98c907 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -10,5 +10,5 @@ license = "MIT" [dependencies] libredox = "0.1.3" log = "0.4" -redox_syscall = { version = "0.5", features = ["std"] } +redox_syscall = { version = "0.5.10", features = ["std"] } redox-log = "0.1.2" diff --git a/common/src/lib.rs b/common/src/lib.rs index 73ab361c37..47a35a2847 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -7,7 +7,7 @@ use libredox::call::MmapArgs; use libredox::flag::{self, O_CLOEXEC, O_RDONLY, O_RDWR, O_WRONLY}; use libredox::{errno::EINVAL, error::*, Fd}; -use syscall::PAGE_SIZE; +use syscall::{ProcSchemeVerb, PAGE_SIZE}; /// The Direct Memory Access (DMA) API for drivers pub mod dma; @@ -250,8 +250,20 @@ impl Drop for PhysBorrowed { /// prevent system instability caused by a faulty driver. Processes with ring 3 IOPL have access to /// I/O ports. pub fn acquire_port_io_rights() -> Result<()> { - unsafe { - syscall::iopl(3)?; + extern "C" { + fn redox_cur_thrfd_v0() -> usize; } + let fd = unsafe { redox_cur_thrfd_v0() }; + let metadata = [ProcSchemeVerb::Iopl as u64]; + let _ = unsafe { + syscall::syscall5( + syscall::SYS_CALL, + fd, + 0, + 0, + metadata.len(), + metadata.as_ptr() as usize, + )? + }; Ok(()) } diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index 9fde996ac2..c8d4e55c56 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -1,7 +1,7 @@ +use common::acquire_port_io_rights; use inputd::ProducerHandle; use pcid_interface::PciFunctionHandle; use redox_scheme::{RequestKind, SignalBehavior, Socket}; -use syscall::call::iopl; use crate::bga::Bga; use crate::scheme::BgaScheme; @@ -19,7 +19,7 @@ fn main() { println!(" + BGA {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { - unsafe { iopl(3).unwrap() }; + acquire_port_io_rights().expect("bgad: failed to get port IO permission"); let socket = Socket::create("bga").expect("bgad: failed to create bga scheme"); diff --git a/input/ps2d/Cargo.toml b/input/ps2d/Cargo.toml index 9e3298eb17..e289ab0cae 100644 --- a/input/ps2d/Cargo.toml +++ b/input/ps2d/Cargo.toml @@ -8,7 +8,7 @@ bitflags = "1" log = "0.4" orbclient = "0.3.27" redox_event = "0.4.1" -redox_syscall = "0.5" +redox_syscall = "0.5.10" redox-daemon = "0.1" libredox = "0.1.3" diff --git a/input/ps2d/src/main.rs b/input/ps2d/src/main.rs index 20f6b2d5f9..466943ee01 100644 --- a/input/ps2d/src/main.rs +++ b/input/ps2d/src/main.rs @@ -9,10 +9,10 @@ use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::AsRawFd; use std::{env, process}; +use common::acquire_port_io_rights; use event::{user_data, EventQueue}; use inputd::ProducerHandle; use log::info; -use syscall::call::iopl; use crate::state::Ps2d; @@ -30,9 +30,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { log::LevelFilter::Info, ); - unsafe { - iopl(3).expect("ps2d: failed to get I/O permission"); - } + acquire_port_io_rights().expect("ps2d: failed to get I/O permission"); let (keymap, keymap_name): (fn(u8, bool) -> char, &str) = match env::args().skip(1).next() { Some(k) => match k.to_lowercase().as_ref() { From 96ca98c9b6258fcd547f4c32130084723b0a19ad Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 22 Mar 2025 11:30:30 +0100 Subject: [PATCH 1187/1301] Replace virttophys by fd-based interface. --- common/src/dma.rs | 20 +++++++++------- common/src/lib.rs | 61 ++++++++++++++++++++++++++++++++++++----------- common/src/sgl.rs | 5 +++- 3 files changed, 63 insertions(+), 23 deletions(-) diff --git a/common/src/dma.rs b/common/src/dma.rs index 9b413b5bcd..98f7abc23d 100644 --- a/common/src/dma.rs +++ b/common/src/dma.rs @@ -1,12 +1,13 @@ use std::mem::{self, size_of, MaybeUninit}; use std::ops::{Deref, DerefMut}; use std::ptr; +use std::sync::LazyLock; use libredox::call::MmapArgs; use libredox::{error::Result, flag, Fd}; use syscall::PAGE_SIZE; -use crate::MemoryType; +use crate::{MemoryType, VirtaddrTranslationHandle}; /// Defines the platform-specific memory type for DMA operations /// @@ -68,7 +69,7 @@ pub(crate) fn phys_contiguous_fd() -> Result { /// - A file descriptor to physically contiguous memory of type [DMA_MEMTY] could not be acquired /// - A virtual mapping for the physically contiguous memory could not be created /// - The virtual address returned by the memory manager was invalid. -fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> { +fn alloc_and_map(length: usize, handle: &VirtaddrTranslationHandle) -> Result<(usize, *mut ())> { assert_eq!(length % PAGE_SIZE, 0); unsafe { let fd = phys_contiguous_fd()?; @@ -80,10 +81,10 @@ fn alloc_and_map(length: usize) -> Result<(usize, *mut ())> { flags: flag::MAP_PRIVATE, prot: flag::PROT_READ | flag::PROT_WRITE, })?; - let phys = syscall::virttophys(virt as usize)?; + let phys = handle.translate(virt as usize)?; for i in 1..length.div_ceil(PAGE_SIZE) { debug_assert_eq!( - syscall::virttophys(virt as usize + i * PAGE_SIZE), + handle.translate(virt as usize + i * PAGE_SIZE), Ok(phys + i * PAGE_SIZE), "NOT CONTIGUOUS" ); @@ -133,7 +134,7 @@ impl Dma { /// - An '[Err]' containing an error. pub fn zeroed() -> Result>> { let aligned_len = size_of::().next_multiple_of(PAGE_SIZE); - let (phys, virt) = alloc_and_map(aligned_len)?; + let (phys, virt) = alloc_and_map(aligned_len, &*VIRTTOPHYS_HANDLE)?; Ok(Dma { phys, virt: virt.cast(), @@ -177,6 +178,11 @@ impl Dma { self.phys } } +// TODO: there should exist a "context" struct that drivers create at start, which would be passed +// to the respective functions +static VIRTTOPHYS_HANDLE: LazyLock = LazyLock::new(|| { + VirtaddrTranslationHandle::new().expect("failed to acquire virttophys translation handle") +}); impl Dma<[T]> { /// Returns a [Dma] object containing a zeroized slice of T with a given count. @@ -184,14 +190,12 @@ impl Dma<[T]> { /// # Arguments /// /// - 'count: [usize]' - The number of elements of type T in the allocated slice. - /// - /// pub fn zeroed_slice(count: usize) -> Result]>> { let aligned_len = count .checked_mul(size_of::()) .unwrap() .next_multiple_of(PAGE_SIZE); - let (phys, virt) = alloc_and_map(aligned_len)?; + let (phys, virt) = alloc_and_map(aligned_len, &*VIRTTOPHYS_HANDLE)?; Ok(Dma { phys, diff --git a/common/src/lib.rs b/common/src/lib.rs index 47a35a2847..818c12e24d 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -243,27 +243,60 @@ impl Drop for PhysBorrowed { } } -/// Uses the [syscall::iopl] system call to set the I/O privilege level of the current process -/// to 3. +// TODO: temporary wrapper in redox_syscall? +unsafe fn sys_call(fd: usize, buf: &mut [u8], metadata: &[u64]) -> Result { + Ok(syscall::syscall5( + syscall::SYS_CALL, + fd, + buf.as_mut_ptr() as usize, + buf.len(), + metadata.len(), + metadata.as_ptr() as usize, + )?) +} + +/// Instructs the kernel to enable I/O ports for this (usermode) process (x86-specific). /// -/// In Redox, x86 privilege ring 3 represents userspace. Most Redox drivers run in userspace to -/// prevent system instability caused by a faulty driver. Processes with ring 3 IOPL have access to -/// I/O ports. +/// On Redox, x86 privilege ring 3 represents userspace. Most Redox drivers run in userspace to +/// prevent system instability caused by a faulty driver. Processes with (bitmap-enabled) IO port +/// rights can use the IN/OUT instructions. This is not the same as IOPL 3; the CLI instruction is +/// still not allowed. pub fn acquire_port_io_rights() -> Result<()> { extern "C" { fn redox_cur_thrfd_v0() -> usize; } - let fd = unsafe { redox_cur_thrfd_v0() }; - let metadata = [ProcSchemeVerb::Iopl as u64]; let _ = unsafe { - syscall::syscall5( - syscall::SYS_CALL, - fd, - 0, - 0, - metadata.len(), - metadata.as_ptr() as usize, + sys_call( + redox_cur_thrfd_v0(), + &mut [], + &[ProcSchemeVerb::Iopl as u64], )? }; Ok(()) } + +/// Kernel handle for translating virtual addresses in the current address space, to their +/// underlying physical addresses. +/// +/// It is currently unspecified whether this handle is specific to the address space at the time it +/// was created, or whether all calls reference the currently active address space. +pub struct VirtaddrTranslationHandle { + fd: Fd, +} + +impl VirtaddrTranslationHandle { + /// Create a new handle, requires uid=0 but this may change. + pub fn new() -> Result { + Ok(Self { + fd: Fd::open("/scheme/memory/translation", O_CLOEXEC, 0)?, + }) + } + /// Translate physical => virtual. + pub fn translate(&self, physical: usize) -> Result { + let mut buf = physical.to_ne_bytes(); + unsafe { + sys_call(self.fd.raw(), &mut buf, &[])?; + } + Ok(usize::from_ne_bytes(buf)) + } +} diff --git a/common/src/sgl.rs b/common/src/sgl.rs index 9bab7ad7c4..5a55f40b02 100644 --- a/common/src/sgl.rs +++ b/common/src/sgl.rs @@ -7,6 +7,7 @@ use libredox::flag::{MAP_PRIVATE, PROT_READ, PROT_WRITE}; use syscall::{MAP_FIXED, PAGE_SIZE}; use crate::dma::phys_contiguous_fd; +use crate::VirtaddrTranslationHandle; /// A Scatter-Gather List data structure /// @@ -69,7 +70,9 @@ impl Sgl { chunks: Vec::new(), }; + // TODO: SglContext to avoid reopening these fds? let phys_contiguous_fd = phys_contiguous_fd()?; + let virttophys_handle = VirtaddrTranslationHandle::new()?; let mut offset = 0; while offset < aligned_length { @@ -90,7 +93,7 @@ impl Sgl { offset: 0, })?; - let phys = syscall::virttophys(virt as usize + offset)?; + let phys = virttophys_handle.translate(virt as usize + offset)?; this.chunks.push(Chunk { offset, phys, From 6ff8c9fd9a0b72b55416086e3b3999cbf1962081 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Mon, 31 Mar 2025 16:20:15 +0200 Subject: [PATCH 1188/1301] Handle level of indirection with procmgr thread fds. --- common/src/lib.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/common/src/lib.rs b/common/src/lib.rs index 818c12e24d..61a2c428c6 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -265,13 +265,10 @@ pub fn acquire_port_io_rights() -> Result<()> { extern "C" { fn redox_cur_thrfd_v0() -> usize; } - let _ = unsafe { - sys_call( - redox_cur_thrfd_v0(), - &mut [], - &[ProcSchemeVerb::Iopl as u64], - )? - }; + let kernel_fd = syscall::dup(unsafe { redox_cur_thrfd_v0() }, b"open_via_dup")?; + let res = unsafe { sys_call(kernel_fd, &mut [], &[ProcSchemeVerb::Iopl as u64]) }; + let _ = syscall::close(kernel_fd); + res?; Ok(()) } From cd4b7ef2281eb4b43c0dd44fb4622d6697aab94b Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Thu, 17 Apr 2025 16:13:17 +0200 Subject: [PATCH 1189/1301] Update deps. --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index b16900eff7..af2b80bf6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1163,7 +1163,7 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.11" dependencies = [ "bitflags 2.9.0", ] From 5c43f396414f8e3ead29aca190dea425914f3d0e Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 19 Apr 2025 19:30:57 +0200 Subject: [PATCH 1190/1301] Update syscall --- Cargo.lock | 91 ++++++++++++++++++++++++++++++++++++++++-------------- Cargo.toml | 2 +- 2 files changed, 69 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af2b80bf6d..4a8ad0b076 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" [[package]] name = "arrayvec" @@ -247,9 +247,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.2.17" +version = "1.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" dependencies = [ "shlex", ] @@ -657,9 +657,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.62" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -710,9 +710,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", @@ -770,9 +770,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "libredox" @@ -868,7 +868,7 @@ dependencies = [ "redox-daemon", "redox_event", "redox_syscall", - "smallvec 1.14.0", + "smallvec 1.15.0", ] [[package]] @@ -938,7 +938,7 @@ dependencies = [ "cfg-if 1.0.0", "libc", "redox_syscall", - "smallvec 1.14.0", + "smallvec 1.15.0", "windows-targets", ] @@ -1020,9 +1020,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -1127,7 +1127,7 @@ checksum = "81460b1526438123d16f0c968dbe42ba7f61e99645109b70e57864a8b66710fb" dependencies = [ "chrono", "log", - "smallvec 1.14.0", + "smallvec 1.15.0", "termion", ] @@ -1164,6 +1164,7 @@ dependencies = [ [[package]] name = "redox_syscall" version = "0.5.11" +source = "git+https://gitlab.redox-os.org/redox-os/syscall.git?branch=master#8f646a63ac9c3aa532a37ddfdc136ec19878f0d6" dependencies = [ "bitflags 2.9.0", ] @@ -1410,9 +1411,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" dependencies = [ "serde", ] @@ -1492,9 +1493,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "termion" -version = "4.0.4" +version = "4.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f359c854fbecc1ea65bc3683f1dcb2dce78b174a1ca7fda37acd1fff81df6ff" +checksum = "3669a69de26799d6321a5aa713f55f7e2cd37bd47be044b50f2acafc42c122bb" dependencies = [ "libc", "libredox", @@ -1864,11 +1865,37 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" dependencies = [ - "windows-targets", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.100", ] [[package]] @@ -1877,6 +1904,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +[[package]] +name = "windows-result" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" version = "0.52.6" @@ -1989,7 +2034,7 @@ dependencies = [ "regex", "serde", "serde_json", - "smallvec 1.14.0", + "smallvec 1.15.0", "thiserror", "toml 0.5.11", ] diff --git a/Cargo.toml b/Cargo.toml index fc3c6b4481..de99b5ded3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,4 +56,4 @@ lto = "fat" mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } redox-daemon = { git = "https://gitlab.redox-os.org/redox-os/redox-daemon.git" } -redox_syscall = { path = "/home/dev/Projects/syscall3" } +redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git", branch = "master" } From 5b1e4724317ec43a3dc7d2c15bc882d030911c7a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 25 Apr 2025 10:16:08 -0600 Subject: [PATCH 1191/1301] Clean up aml::Handler --- acpid/src/aml_physmem.rs | 272 +++++++++++---------------------------- 1 file changed, 74 insertions(+), 198 deletions(-) diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 8f38ef6dcd..6cee399c9c 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -147,7 +147,6 @@ impl AmlPhysMemHandler { } } -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] impl aml::Handler for AmlPhysMemHandler { fn read_u8(&self, address: usize) -> u8 { log::trace!("read u8 {:X}", address); @@ -156,6 +155,7 @@ impl aml::Handler for AmlPhysMemHandler { return value; } } + log::error!("failed to read u8 {:#x}", address); 0 } fn read_u16(&self, address: usize) -> u16 { @@ -165,6 +165,7 @@ impl aml::Handler for AmlPhysMemHandler { return value; } } + log::error!("failed to read u16 {:#x}", address); 0 } fn read_u32(&self, address: usize) -> u32 { @@ -174,6 +175,7 @@ impl aml::Handler for AmlPhysMemHandler { return value; } } + log::error!("failed to read u32 {:#x}", address); 0 } fn read_u64(&self, address: usize) -> u64 { @@ -183,40 +185,45 @@ impl aml::Handler for AmlPhysMemHandler { return value; } } + log::error!("failed to read u64 {:#x}", address); 0 } fn write_u8(&mut self, address: usize, value: u8) { - log::error!("write u8 {:X} = {:X}", address, value); + log::trace!("write u8 {:X} = {:X}", address, value); if let Ok(mut page_cache) = self.page_cache.lock() { - if page_cache.write_to_phys::(address, value).is_err() { - log::error!("failed to get page {:#x}", address); + if page_cache.write_to_phys::(address, value).is_ok() { + return; } } + log::error!("failed to write u8 {:#x}", address); } fn write_u16(&mut self, address: usize, value: u16) { - log::error!("write u16 {:X} = {:X}", address, value); + log::trace!("write u16 {:X} = {:X}", address, value); if let Ok(mut page_cache) = self.page_cache.lock() { - if page_cache.write_to_phys::(address, value).is_err() { - log::error!("failed to get page {:#x}", address); + if page_cache.write_to_phys::(address, value).is_ok() { + return; } } + log::error!("failed to write u16 {:#x}", address); } fn write_u32(&mut self, address: usize, value: u32) { - log::error!("write u32 {:X} = {:X}", address, value); + log::trace!("write u32 {:X} = {:X}", address, value); if let Ok(mut page_cache) = self.page_cache.lock() { - if page_cache.write_to_phys::(address, value).is_err() { - log::error!("failed to get page {:#x}", address); + if page_cache.write_to_phys::(address, value).is_ok() { + return; } } + log::error!("failed to write u32 {:#x}", address); } fn write_u64(&mut self, address: usize, value: u64) { - log::error!("write u64 {:X} = {:X}", address, value); + log::trace!("write u64 {:X} = {:X}", address, value); if let Ok(mut page_cache) = self.page_cache.lock() { - if page_cache.write_to_phys::(address, value).is_err() { - log::error!("failed to get page {:#x}", address); + if page_cache.write_to_phys::(address, value).is_ok() { + return; } } + log::error!("failed to write u64 {:#x}", address); } // Pio must be enabled via syscall::iopl @@ -246,230 +253,99 @@ impl aml::Handler for AmlPhysMemHandler { Pio::::new(port).write(value) } - fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { - log::error!( - "read pci u8 {:X}, {:X}, {:X}, {:X}, {:X}", - _segment, - _bus, - _device, - _function, - _offset - ); - - 0 - } - fn read_pci_u16( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - ) -> u16 { - log::error!( - "read pci u16 {:X}, {:X}, {:X}, {:X}, {:X}", - _segment, - _bus, - _device, - _function, - _offset - ); - - 0 - } - fn read_pci_u32( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - ) -> u32 { - log::error!( - "read pci u32 {:X}, {:X}, {:X}, {:X}, {:X}", - _segment, - _bus, - _device, - _function, - _offset - ); - - 0 - } - fn write_pci_u8( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u8, - ) { - log::error!( - "write pci u8 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", - _segment, - _bus, - _device, - _function, - _offset, - _value - ); - } - fn write_pci_u16( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u16, - ) { - log::error!( - "write pci u16 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", - _segment, - _bus, - _device, - _function, - _offset, - _value - ); - } - fn write_pci_u32( - &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u32, - ) { - log::error!( - "write pci u32 {:X}, {:X}, {:X}, {:X}, {:X} = {:X}", - _segment, - _bus, - _device, - _function, - _offset, - _value - ); - } -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -impl aml::Handler for AmlPhysMemHandler { - fn read_u8(&self, _address: usize) -> u8 { - log::error!("read u8 {:X}", _address); - 0 - } - fn read_u16(&self, _address: usize) -> u16 { - log::error!("read u16 {:X}", _address); - 0 - } - fn read_u32(&self, _address: usize) -> u32 { - log::error!("read u32 {:X}", _address); - 0 - } - fn read_u64(&self, _address: usize) -> u64 { - log::error!("read u64 {:X}", _address); - 0 - } - - fn write_u8(&mut self, _address: usize, _value: u8) { - log::error!("write u8 {:X} = {:X}", _address, _value); - } - fn write_u16(&mut self, _address: usize, _value: u16) { - log::error!("write u16 {:X} = {:X}", _address, _value); - } - fn write_u32(&mut self, _address: usize, _value: u32) { - log::error!("write u32 {:X} = {:X}", _address, _value); - } - fn write_u64(&mut self, _address: usize, _value: u64) { - log::error!("write u64 {:X} = {:X}", _address, _value); - } - + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn read_io_u8(&self, port: u16) -> u8 { - log::error!("read io u8 {:X}", port); + log::error!("cannot read u8 from port 0x{port:04X}"); 0 } + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn read_io_u16(&self, port: u16) -> u16 { - log::error!("read io u16 {:X}", port); + log::error!("cannot read u16 from port 0x{port:04X}"); 0 } + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn read_io_u32(&self, port: u16) -> u32 { - log::error!("read io u32 {:X}", port); + log::error!("cannot read u32 from port 0x{port:04X}"); 0 } + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn write_io_u8(&self, port: u16, value: u8) { - log::error!("write io u8 {:X} = {:X}", port, value); + log::error!("cannot write 0x{value:02X} to port 0x{port:04X}"); } + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn write_io_u16(&self, port: u16, value: u16) { - log::error!("write io u16 {:X} = {:X}", port, value); + log::error!("cannot write 0x{value:04X} to port 0x{port:04X}"); } + #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn write_io_u32(&self, port: u16, value: u32) { - log::error!("write io u32 {:X} = {:X}", port, value); + log::error!("cannot write 0x{value:08X} to port 0x{port:04X}"); } - fn read_pci_u8(&self, _segment: u16, _bus: u8, _device: u8, _function: u8, _offset: u16) -> u8 { - log::error!("read pci u8 {:X}", _device); - + fn read_pci_u8( + &self, + seg: u16, + bus: u8, + dev: u8, + func: u8, + off: u16, + ) -> u8 { + log::error!("read pci u8 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}"); 0 } fn read_pci_u16( &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, + seg: u16, + bus: u8, + dev: u8, + func: u8, + off: u16, ) -> u16 { - log::error!("read pci u8 {:X}", _device); - + log::error!("read pci u16 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}"); 0 } fn read_pci_u32( &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, + seg: u16, + bus: u8, + dev: u8, + func: u8, + off: u16, ) -> u32 { - log::error!("read pci u8 {:X}", _device); - + log::error!("read pci u32 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}"); 0 } fn write_pci_u8( &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u8, + seg: u16, + bus: u8, + dev: u8, + func: u8, + off: u16, + value: u8 ) { - log::error!("write pci u8 {:X}", _device); + log::error!("write pci u8 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}={value:02X}"); } fn write_pci_u16( &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u16, + seg: u16, + bus: u8, + dev: u8, + func: u8, + off: u16, + value: u16 ) { - log::error!("write pci u8 {:X}", _device); + log::error!("write pci u16 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}={value:04X}"); } fn write_pci_u32( &self, - _segment: u16, - _bus: u8, - _device: u8, - _function: u8, - _offset: u16, - _value: u32, + seg: u16, + bus: u8, + dev: u8, + func: u8, + off: u16, + value: u32 ) { - log::error!("write pci u8 {:X}", _device); + log::error!("write pci u32 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}={value:08X}"); } } From 5e4d4427db6efad8ffa29dc00359dcf42cd473eb Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 25 Apr 2025 12:14:09 -0600 Subject: [PATCH 1192/1301] Timeout of five seconds for nvmed init --- Cargo.lock | 1 + storage/nvmed/Cargo.toml | 1 + storage/nvmed/src/main.rs | 46 ++- storage/nvmed/src/nvme/cq_reactor.rs | 455 --------------------------- 4 files changed, 47 insertions(+), 456 deletions(-) delete mode 100644 storage/nvmed/src/nvme/cq_reactor.rs diff --git a/Cargo.lock b/Cargo.lock index 4a8ad0b076..851563d12f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -860,6 +860,7 @@ dependencies = [ "common", "driver-block", "executor", + "futures", "libredox", "log", "parking_lot 0.12.3", diff --git a/storage/nvmed/Cargo.toml b/storage/nvmed/Cargo.toml index 948f30a970..1d00992081 100644 --- a/storage/nvmed/Cargo.toml +++ b/storage/nvmed/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] arrayvec = "0.7" bitflags = "2" +futures = "0.3" libredox = "0.1.3" log = "0.4" parking_lot = "0.12.1" diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index efe390f967..e35df00629 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -2,6 +2,9 @@ #![cfg_attr(target_arch = "riscv64", feature(riscv_ext_intrinsics))] // Required for pause instruction use std::cell::RefCell; +use std::fs::File; +use std::io::{self, Read, Write}; +use std::os::fd::AsRawFd; use std::ptr::NonNull; use std::rc::Rc; use std::sync::Arc; @@ -83,6 +86,7 @@ fn get_int_method( let interrupt_sources = InterruptSources::MsiX(std::iter::once((msix_vector_number, irq_handle)).collect()); + log::trace!("Using MSI-X"); Ok((interrupt_method, interrupt_sources)) } else if has_msi { // Message signaled interrupts. @@ -117,10 +121,12 @@ fn get_int_method( pcid_handle.enable_feature(PciFeature::Msi); + log::trace!("Using MSI"); Ok((interrupt_method, interrupt_sources)) } else if let Some(irq) = function.legacy_interrupt_line { // INTx# pin based interrupts. let irq_handle = irq.irq_handle("nvmed"); + log::trace!("Using legacy interrupts"); Ok((InterruptMethod::Intx, InterruptSources::Intx(irq_handle))) } else { panic!("nvmed: no interrupts supported at all") @@ -165,6 +171,21 @@ impl Disk for NvmeDisk { } } +fn time_arm(time_handle: &mut File, secs: i64) -> io::Result<()> { + let mut time_buf = [0_u8; core::mem::size_of::()]; + if time_handle.read(&mut time_buf)? < time_buf.len() { + return Err(io::Error::new(io::ErrorKind::InvalidData, "time read too small")); + } + + match libredox::data::timespec_from_mut_bytes(&mut time_buf) { + time => { + time.tv_sec += secs; + } + } + time_handle.write(&time_buf)?; + Ok(()) +} + fn main() { redox_daemon::Daemon::new(daemon).expect("nvmed: failed to daemonize"); } @@ -206,7 +227,30 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { }; nvme::executor::init(Arc::clone(&nvme), iv, intx, irq_handle) }; - let namespaces = executor.block_on(nvme.init_with_queues()); + + let mut time_handle = File::open(&format!("/scheme/time/{}", libredox::flag::CLOCK_MONOTONIC)) + .expect("failed to open time handle"); + + let mut time_events = Box::pin(executor.register_external_event( + time_handle.as_raw_fd() as usize, + event::EventFlags::READ, + )); + + // Try to init namespaces for 5 seconds + time_arm(&mut time_handle, 5).expect("failed to arm timer"); + let namespaces = executor.block_on(async { + let namespaces_future = nvme.init_with_queues(); + let time_future = time_events.as_mut().next(); + futures::pin_mut!(namespaces_future); + futures::pin_mut!(time_future); + match futures::future::select( + namespaces_future, + time_future, + ).await { + futures::future::Either::Left((namespaces, _)) => namespaces, + futures::future::Either::Right(_) => panic!("timeout on init") + } + }); log::debug!("Initialized!"); let scheme = Rc::new(RefCell::new(DiskScheme::new( diff --git a/storage/nvmed/src/nvme/cq_reactor.rs b/storage/nvmed/src/nvme/cq_reactor.rs deleted file mode 100644 index 3a10c136ef..0000000000 --- a/storage/nvmed/src/nvme/cq_reactor.rs +++ /dev/null @@ -1,455 +0,0 @@ -//! The Completion Queue Reactor. Functions like any other async/await reactor, but is driven by -//! IRQs triggering wakeups in order to poll NVME completion queues (see `CompletionFuture`). -//! -//! While the reactor is primarily intended to wait for IRQs and then poll completion queues, it -//! can also be used for notifying when a full submission queue can submit a new command (see -//! `AvailableSqEntryFuture`). - -use std::convert::TryFrom; -use std::fs::File; -use std::future::Future; -use std::io::prelude::*; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::pin::Pin; -use std::sync::{Arc, Mutex}; -use std::{mem, task, thread}; - -use syscall::data::Event; -use syscall::Result; - -use crossbeam_channel::Receiver; - -use super::{CmdId, CqId, InterruptSources, Nvme, NvmeCmd, NvmeComp, SqId}; - -/// A notification request, sent by the future in order to tell the completion thread that the -/// current task wants a notification when a matching completion queue entry has been seen. -#[derive(Debug)] -pub enum NotifReq { - RequestCompletion { - cq_id: CqId, - sq_id: SqId, - cmd_id: CmdId, - - waker: task::Waker, - - // TODO: Get rid of this allocation, or maybe a thread-local vec for reusing. - // TODO: Maybe the `remem` crate. - message: Arc>>, - }, - RequestAvailSubmission { - sq_id: SqId, - waker: task::Waker, - }, -} - -enum PendingReq { - PendingCompletion { - waker: task::Waker, - message: Arc>>, - cq_id: CqId, - sq_id: SqId, - cmd_id: CmdId, - }, - PendingAvailSubmission { - waker: task::Waker, - sq_id: SqId, - }, -} -struct CqReactor { - int_sources: InterruptSources, - nvme: Arc, - pending_reqs: Vec, - // used to store commands that may be completed before a completion is requested - receiver: Receiver, - event_queue: File, -} -impl CqReactor { - fn create_event_queue(int_sources: &mut InterruptSources) -> Result { - use libredox::flag::*; - let fd = libredox::call::open("/scheme/event", O_CLOEXEC | O_RDWR, 0)?; - let mut file = unsafe { File::from_raw_fd(fd as RawFd) }; - - for (num, irq_handle) in int_sources.iter_mut() { - if file - .write(&Event { - id: irq_handle.as_raw_fd() as usize, - flags: syscall::EVENT_READ, - data: num as usize, - }) - .unwrap() - == 0 - { - panic!("Failed to setup event queue for {} {:?}", num, irq_handle); - } - } - Ok(file) - } - fn new( - nvme: Arc, - mut int_sources: InterruptSources, - receiver: Receiver, - ) -> Result { - Ok(Self { - event_queue: Self::create_event_queue(&mut int_sources)?, - int_sources, - nvme, - pending_reqs: Vec::new(), - receiver, - }) - } - fn handle_notif_reqs_raw( - pending_reqs: &mut Vec, - receiver: &Receiver, - block_until_first: bool, - ) { - let mut blocking_iter; - let mut nonblocking_iter; - - let iter: &mut dyn Iterator = if block_until_first { - blocking_iter = std::iter::once(receiver.recv().unwrap()).chain(receiver.try_iter()); - &mut blocking_iter - } else { - nonblocking_iter = receiver.try_iter(); - &mut nonblocking_iter - }; - - for req in iter { - log::trace!("Got notif req: {:?}", req); - match req { - NotifReq::RequestCompletion { - sq_id, - cq_id, - cmd_id, - waker, - message, - } => pending_reqs.push(PendingReq::PendingCompletion { - sq_id, - cq_id, - cmd_id, - message, - waker, - }), - NotifReq::RequestAvailSubmission { sq_id, waker } => { - pending_reqs.push(PendingReq::PendingAvailSubmission { sq_id, waker }) - } - } - } - } - fn poll_completion_queues(&mut self, iv: u16) -> Option<()> { - let ivs_read_guard = self.nvme.cqs_for_ivs.read().unwrap(); - let cqs_read_guard = self.nvme.completion_queues.read().unwrap(); - - let mut entry_count = 0; - - let cq_ids = ivs_read_guard.get(&iv)?; - - for cq_id in cq_ids.iter().copied() { - let mut completion_queue_guard = cqs_read_guard.get(&cq_id)?.lock().unwrap(); - let &mut (ref mut completion_queue, _) = &mut *completion_queue_guard; - - while let Some((head, entry)) = completion_queue.complete(None) { - unsafe { self.nvme.completion_queue_head(cq_id, head) }; - - log::trace!( - "Got completion queue entry (CQID {}): {:?} at {}", - cq_id, - entry, - head - ); - - { - let submission_queues_read_lock = self.nvme.submission_queues.read().unwrap(); - // this lock is actually important, since it will block during submission from other - // threads. the lock won't be held for long by the submitters, but it still prevents - // the entry being lost before this reactor is actually able to respond: - let &(ref sq_lock, corresponding_cq_id) = - submission_queues_read_lock.get(&{ entry.sq_id }).expect( - "nvmed: internal error: queue returned from controller doesn't exist", - ); - assert_eq!(cq_id, corresponding_cq_id); - let mut sq_guard = sq_lock.lock().unwrap(); - sq_guard.head = entry.sq_head; - // the channel still has to be polled twice though: - Self::handle_notif_reqs_raw(&mut self.pending_reqs, &self.receiver, false); - } - - Self::try_notify_futures(&mut self.pending_reqs, cq_id, &entry); - - entry_count += 1; - } - } - if entry_count == 0 {} - - Some(()) - } - fn finish_pending_completion( - pending_reqs: &mut Vec, - req_cq_id: CqId, - cq_id: CqId, - sq_id: SqId, - cmd_id: CmdId, - entry: &NvmeComp, - i: usize, - ) -> bool { - if req_cq_id == cq_id && sq_id == entry.sq_id && cmd_id == entry.cid { - let (waker, message) = match pending_reqs.remove(i) { - PendingReq::PendingCompletion { waker, message, .. } => (waker, message), - _ => unreachable!(), - }; - - *message.lock().unwrap() = Some(CompletionMessage { cq_entry: *entry }); - waker.wake(); - - true - } else { - false - } - } - fn finish_pending_avail_submission( - pending_reqs: &mut Vec, - sq_id: SqId, - entry: &NvmeComp, - i: usize, - ) -> bool { - if sq_id == entry.sq_id { - let waker = match pending_reqs.remove(i) { - PendingReq::PendingAvailSubmission { waker, .. } => waker, - _ => unreachable!(), - }; - waker.wake(); - - true - } else { - false - } - } - fn try_notify_futures( - pending_reqs: &mut Vec, - cq_id: CqId, - entry: &NvmeComp, - ) -> Option<()> { - let mut i = 0usize; - - let mut futures_notified = 0; - - while i < pending_reqs.len() { - match &pending_reqs[i] { - &PendingReq::PendingCompletion { - cq_id: req_cq_id, - sq_id, - cmd_id, - .. - } => { - if Self::finish_pending_completion( - pending_reqs, - req_cq_id, - cq_id, - sq_id, - cmd_id, - entry, - i, - ) { - futures_notified += 1; - } else { - i += 1; - } - } - &PendingReq::PendingAvailSubmission { sq_id, .. } => { - if Self::finish_pending_avail_submission(pending_reqs, sq_id, entry, i) { - futures_notified += 1; - } else { - i += 1; - } - } - } - } - if futures_notified == 0 {} - Some(()) - } - - fn run(mut self) { - log::debug!("Running CQ reactor"); - let mut event = Event::default(); - let mut irq_word = [0u8; 8]; // stores the IRQ count - - const WORD_SIZE: usize = mem::size_of::(); - - loop { - let block_until_first = self.pending_reqs.is_empty(); - Self::handle_notif_reqs_raw(&mut self.pending_reqs, &self.receiver, block_until_first); - log::trace!("Handled notif reqs"); - - // block on getting the next event - if self.event_queue.read(&mut event).unwrap() == 0 { - // event queue has been destroyed - break; - } - - let (vector, irq_handle) = match self.int_sources.iter_mut().nth(event.data) { - Some(s) => s, - None => continue, - }; - if irq_handle.read(&mut irq_word[..WORD_SIZE]).unwrap() == 0 { - continue; - } - // acknowledge the interrupt (only necessary for level-triggered INTx# interrups) - if irq_handle.write(&irq_word[..WORD_SIZE]).unwrap() == 0 { - continue; - } - log::trace!("NVME IRQ: vector {}", vector); - self.nvme.set_vector_masked(vector, true); - self.poll_completion_queues(vector); - self.nvme.set_vector_masked(vector, false); - } - } -} - -pub fn start_cq_reactor_thread( - nvme: Arc, - interrupt_sources: InterruptSources, - receiver: Receiver, -) -> thread::JoinHandle<()> { - // Actually, nothing prevents us from spawning additional threads. the channel is MPMC and - // everything is properly synchronized. I'm not saying this is strictly required, but with - // multiple completion queues it might actually be worth considering. The (in-kernel) IRQ - // subsystem can have some room for improvement regarding lowering the latency, but MSI-X allows - // multiple vectors to point to different CPUs, so that the load can be balanced across the - // logical processors. - let reactor = CqReactor::new(nvme, interrupt_sources, receiver) - .expect("nvmed: failed to setup CQ reactor"); - thread::spawn(move || reactor.run()) -} - -#[derive(Debug)] -pub struct CompletionMessage { - cq_entry: NvmeComp, -} - -pub enum CompletionFutureState<'a, F> { - // the future is in its initial state: the command has not been submitted yet, and no interest - // has been registered. this state will repeat until a free submission queue entry appears to - // it, which it probably will since queues aren't supposed to be nearly always be full. - PendingSubmission { - cmd_init: F, - nvme: &'a Nvme, - sq_id: SqId, - }, - PendingCompletion { - nvme: &'a Nvme, - cq_id: CqId, - cmd_id: CmdId, - sq_id: SqId, - message: Arc>>, - }, - Finished, - Placeholder, -} -pub struct CompletionFuture<'a, F> { - pub state: CompletionFutureState<'a, F>, -} - -// enum not self-referential -impl Unpin for CompletionFuture<'_, F> {} - -impl Future for CompletionFuture<'_, F> -where - F: FnOnce(CmdId) -> NvmeCmd, -{ - type Output = NvmeComp; - - fn poll(self: Pin<&mut Self>, context: &mut task::Context) -> task::Poll { - let this = &mut self.get_mut().state; - - match mem::replace(this, CompletionFutureState::Placeholder) { - CompletionFutureState::PendingSubmission { - cmd_init, - nvme, - sq_id, - } => { - let sqs_read_guard = nvme.submission_queues.read().unwrap(); - let &(ref sq_lock, cq_id) = sqs_read_guard - .get(&sq_id) - .expect("nvmed: internal error: given SQ for SQ ID not there"); - let mut sq_guard = sq_lock.lock().unwrap(); - let sq = &mut *sq_guard; - - if sq.is_full() { - // when the CQ reactor gets a new completion queue entry, it'll lock the - // submisson queue it came from. since we're holding the same lock, this - // message will always be sent before the reactor is done with the entry. - nvme.reactor_sender - .send(NotifReq::RequestAvailSubmission { - sq_id, - waker: context.waker().clone(), - }) - .unwrap(); - *this = CompletionFutureState::PendingSubmission { - cmd_init, - nvme, - sq_id, - }; - return task::Poll::Pending; - } - - let cmd_id = u16::try_from(sq.tail) - .expect("nvmed: internal error: CQ has more than 2^16 entries"); - let tail = sq.submit_unchecked(cmd_init(cmd_id)); - let tail = u16::try_from(tail).unwrap(); - - // make sure that we register interest before the reactor can get notified - let message = Arc::new(Mutex::new(None)); - *this = CompletionFutureState::PendingCompletion { - nvme, - cq_id, - cmd_id, - sq_id, - message: Arc::clone(&message), - }; - nvme.reactor_sender - .send(NotifReq::RequestCompletion { - cq_id, - sq_id, - cmd_id, - message, - waker: context.waker().clone(), - }) - .expect("reactor dead"); - unsafe { nvme.submission_queue_tail(sq_id, tail) }; - task::Poll::Pending - } - CompletionFutureState::PendingCompletion { - message, - cq_id, - cmd_id, - sq_id, - nvme, - } => { - if let Some(value) = message.lock().unwrap().take() { - *this = CompletionFutureState::Finished; - return task::Poll::Ready(value.cq_entry); - } - nvme.reactor_sender - .send(NotifReq::RequestCompletion { - cq_id, - sq_id, - cmd_id, - waker: context.waker().clone(), - message: Arc::clone(&message), - }) - .expect("reactor dead"); - *this = CompletionFutureState::PendingCompletion { - message, - cq_id, - cmd_id, - sq_id, - nvme, - }; - task::Poll::Pending - } - CompletionFutureState::Finished => { - panic!("calling poll() on an already finished CompletionFuture") - } - CompletionFutureState::Placeholder => unreachable!(), - } - } -} From 5827a0e3092d08dc0b6e3c1718b7ef972f4f57f9 Mon Sep 17 00:00:00 2001 From: Arne de Bruijn Date: Fri, 2 May 2025 18:47:14 +0200 Subject: [PATCH 1193/1301] Accept right ctrl key from ps2 keyboard Map both ctrl keys to K_CTRL for now, same as usbhidd. --- input/ps2d/src/state.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/input/ps2d/src/state.rs b/input/ps2d/src/state.rs index 711c7bfbbf..b9abe4ed42 100644 --- a/input/ps2d/src/state.rs +++ b/input/ps2d/src/state.rs @@ -89,10 +89,10 @@ impl char> Ps2d { match ps2_scancode { //TODO: media keys //TODO: 0x1C => orbclient::K_NUM_ENTER, - //TODO: 0x1D => orbclient::K_RIGHT_CTRL, - 0x20 => 0x80 + 0x20, //TODO: orbclient::K_VOLUME_MUTE, - 0x2E => 0x80 + 0x2E, //TODO: orbclient::K_VOLUME_DOWN, - 0x30 => 0x80 + 0x30, //TODO: orbclient::K_VOLUME_UP, + 0x1D => orbclient::K_CTRL, //TODO: 0x1D => orbclient::K_RIGHT_CTRL, + 0x20 => 0x80 + 0x20, //TODO: orbclient::K_VOLUME_MUTE, + 0x2E => 0x80 + 0x2E, //TODO: orbclient::K_VOLUME_DOWN, + 0x30 => 0x80 + 0x30, //TODO: orbclient::K_VOLUME_UP, //TODO: 0x35 => orbclient::K_NUM_SLASH, 0x38 => orbclient::K_ALT_GR, 0x47 => orbclient::K_HOME, From a1b0feaadbd3e7101b0e93dfcaccf79c1a69aaaa Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 20 May 2025 22:03:01 +0200 Subject: [PATCH 1194/1301] storage: Notify readiness as soon as the disk scheme has been created This prevents boot hangs when the disk driver hangs between creating the disk scheme and being fully initialized, while still preventing race conditions. --- Cargo.lock | 1 + storage/ahcid/src/main.rs | 3 +-- storage/bcm2835-sdhcid/src/main.rs | 2 +- storage/driver-block/Cargo.toml | 1 + storage/driver-block/src/lib.rs | 5 +++++ storage/ided/src/main.rs | 3 +-- storage/lived/src/main.rs | 3 +-- storage/nvmed/src/main.rs | 21 ++++++++++----------- storage/usbscsid/src/main.rs | 2 ++ storage/virtio-blkd/src/main.rs | 7 +++---- 10 files changed, 26 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 851563d12f..a3fd0ece1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -390,6 +390,7 @@ dependencies = [ "libredox", "log", "partitionlib", + "redox-daemon", "redox-scheme 0.5.0", "redox_syscall", ] diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index d6b9f83d1c..7108647bf7 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -45,6 +45,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let scheme_name = format!("disk.{}", name); let mut scheme = DiskScheme::new( + Some(daemon), scheme_name, disks .into_iter() @@ -68,8 +69,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .subscribe(irq_fd, 1, EventFlags::READ) .expect("ahcid: failed to event irq scheme"); - daemon.ready().expect("ahcid: failed to notify parent"); - for event in event_queue { let event = event.unwrap(); if event.fd == scheme.event_handle().raw() { diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index fda44f8860..0bfcea69da 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -101,6 +101,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut disks = Vec::new(); disks.push(sdhci); let mut scheme = DiskScheme::new( + Some(daemon), "disk.mmc".to_string(), disks .into_iter() @@ -116,7 +117,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("mmcd: failed to event disk scheme"); libredox::call::setrens(0, 0).expect("mmcd: failed to enter null namespace"); - daemon.ready().expect("mmcd: failed to notify parent"); for event in event_queue { let event = event.unwrap(); diff --git a/storage/driver-block/Cargo.toml b/storage/driver-block/Cargo.toml index da969a41c8..8f465cd535 100644 --- a/storage/driver-block/Cargo.toml +++ b/storage/driver-block/Cargo.toml @@ -13,5 +13,6 @@ log = "0.4" # TODO: migrate virtio to our executor futures = { version = "0.3.28", features = ["executor"] } +redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } redox-scheme = "0.5" diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 0363228587..29cf01eda0 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -305,6 +305,7 @@ impl ExecutorTrait for TrivialExecutor { impl DiskScheme { pub fn new( + daemon: Option, scheme_name: String, disks: BTreeMap, executor: &impl ExecutorTrait, @@ -312,6 +313,10 @@ impl DiskScheme { assert!(scheme_name.starts_with("disk")); let socket = Socket::nonblock(&scheme_name).expect("failed to create disk scheme"); + if let Some(daemon) = daemon { + daemon.ready().expect("failed to signal readiness"); + } + Self { scheme_name, socket, diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index d3509a1ba8..db96961807 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -209,6 +209,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let scheme_name = format!("disk.{}", name); let mut scheme = DiskScheme::new( + Some(daemon), scheme_name, disks .into_iter() @@ -240,8 +241,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { libredox::call::setrens(0, 0).expect("ided: failed to enter null namespace"); - daemon.ready().expect("ided: failed to notify parent"); - event_queue .subscribe(scheme.event_handle().raw(), 0, EventFlags::READ) .expect("ided: failed to event disk scheme"); diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index b53452e779..f05950222e 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -121,6 +121,7 @@ fn main() -> anyhow::Result<()> { }; let mut scheme = DiskScheme::new( + Some(daemon), "disk.live".to_owned(), BTreeMap::from([( 0, @@ -142,8 +143,6 @@ fn main() -> anyhow::Result<()> { ) .unwrap(); - daemon.ready().expect("failed to signal readiness"); - for event in event_queue { match event.unwrap().user_data { Event::Scheme => TrivialExecutor.block_on(scheme.tick()).unwrap(), diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index e35df00629..6966570a52 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -174,7 +174,10 @@ impl Disk for NvmeDisk { fn time_arm(time_handle: &mut File, secs: i64) -> io::Result<()> { let mut time_buf = [0_u8; core::mem::size_of::()]; if time_handle.read(&mut time_buf)? < time_buf.len() { - return Err(io::Error::new(io::ErrorKind::InvalidData, "time read too small")); + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "time read too small", + )); } match libredox::data::timespec_from_mut_bytes(&mut time_buf) { @@ -231,10 +234,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut time_handle = File::open(&format!("/scheme/time/{}", libredox::flag::CLOCK_MONOTONIC)) .expect("failed to open time handle"); - let mut time_events = Box::pin(executor.register_external_event( - time_handle.as_raw_fd() as usize, - event::EventFlags::READ, - )); + let mut time_events = Box::pin( + executor.register_external_event(time_handle.as_raw_fd() as usize, event::EventFlags::READ), + ); // Try to init namespaces for 5 seconds time_arm(&mut time_handle, 5).expect("failed to arm timer"); @@ -243,17 +245,15 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let time_future = time_events.as_mut().next(); futures::pin_mut!(namespaces_future); futures::pin_mut!(time_future); - match futures::future::select( - namespaces_future, - time_future, - ).await { + match futures::future::select(namespaces_future, time_future).await { futures::future::Either::Left((namespaces, _)) => namespaces, - futures::future::Either::Right(_) => panic!("timeout on init") + futures::future::Either::Right(_) => panic!("timeout on init"), } }); log::debug!("Initialized!"); let scheme = Rc::new(RefCell::new(DiskScheme::new( + Some(daemon), scheme_name, namespaces .into_iter() @@ -269,7 +269,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .collect(), &*executor, ))); - daemon.ready().expect("nvmed: failed to signal readiness"); let mut scheme_events = Box::pin(executor.register_external_event( scheme.borrow().event_handle().raw(), diff --git a/storage/usbscsid/src/main.rs b/storage/usbscsid/src/main.rs index 6da8c36fe6..bc6d993a5e 100644 --- a/storage/usbscsid/src/main.rs +++ b/storage/usbscsid/src/main.rs @@ -42,6 +42,7 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: PortId, protocol: // TODO: Use eventfds. let handle = XhciClientHandle::new(scheme.to_owned(), port); + // FIXME should this wait notifying readiness until the disk scheme is created? daemon.ready().expect("usbscsid: failed to signal rediness"); let desc = handle @@ -98,6 +99,7 @@ fn daemon(daemon: redox_daemon::Daemon, scheme: String, port: PortId, protocol: }; let mut scheme = DiskScheme::new( + None, disk_scheme_name, BTreeMap::from([( 0, diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 88fbb52bdf..253eb9c572 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -109,7 +109,7 @@ pub struct BlockVirtRequest { const_assert_eq!(core::mem::size_of::(), 16); -fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { +fn daemon(daemon: redox_daemon::Daemon) -> anyhow::Result<()> { let mut pcid_handle = PciFunctionHandle::connect_default(); // Double check that we have the right device. @@ -152,6 +152,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { }; let mut scheme = DiskScheme::new( + Some(daemon), scheme_name, BTreeMap::from([(0, VirtioDisk::new(queue, device_space))]), &driver_block::FuturesExecutor, @@ -167,8 +168,6 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { ) .unwrap(); - deamon.ready().expect("virtio-blkd: failed to deamonize"); - for event in event_queue { match event.unwrap().user_data { Event::Scheme => futures::executor::block_on(scheme.tick()).unwrap(), @@ -179,6 +178,6 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { - deamon(redox_daemon).unwrap(); + daemon(redox_daemon).unwrap(); unreachable!(); } From 71f1838eea33cc45530901eb350d46a3679e0825 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 20 May 2025 22:03:10 +0200 Subject: [PATCH 1195/1301] acpid: Rustfmt --- acpid/src/aml_physmem.rs | 57 +++++----------------------------------- 1 file changed, 6 insertions(+), 51 deletions(-) diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 6cee399c9c..ce07ba4cfe 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -282,70 +282,25 @@ impl aml::Handler for AmlPhysMemHandler { log::error!("cannot write 0x{value:08X} to port 0x{port:04X}"); } - fn read_pci_u8( - &self, - seg: u16, - bus: u8, - dev: u8, - func: u8, - off: u16, - ) -> u8 { + fn read_pci_u8(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16) -> u8 { log::error!("read pci u8 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}"); 0 } - fn read_pci_u16( - &self, - seg: u16, - bus: u8, - dev: u8, - func: u8, - off: u16, - ) -> u16 { + fn read_pci_u16(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16) -> u16 { log::error!("read pci u16 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}"); 0 } - fn read_pci_u32( - &self, - seg: u16, - bus: u8, - dev: u8, - func: u8, - off: u16, - ) -> u32 { + fn read_pci_u32(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16) -> u32 { log::error!("read pci u32 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}"); 0 } - fn write_pci_u8( - &self, - seg: u16, - bus: u8, - dev: u8, - func: u8, - off: u16, - value: u8 - ) { + fn write_pci_u8(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16, value: u8) { log::error!("write pci u8 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}={value:02X}"); } - fn write_pci_u16( - &self, - seg: u16, - bus: u8, - dev: u8, - func: u8, - off: u16, - value: u16 - ) { + fn write_pci_u16(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16, value: u16) { log::error!("write pci u16 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}={value:04X}"); } - fn write_pci_u32( - &self, - seg: u16, - bus: u8, - dev: u8, - func: u8, - off: u16, - value: u32 - ) { + fn write_pci_u32(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16, value: u32) { log::error!("write pci u32 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}={value:08X}"); } } From ff7325df14af17377c2bef16ea195b407bcd9a4a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 22 May 2025 20:44:07 +0200 Subject: [PATCH 1196/1301] input/ps2d: More helpful panic locations when initializing fails --- input/ps2d/src/controller.rs | 27 ++++++++++++++++----------- input/ps2d/src/state.rs | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/input/ps2d/src/controller.rs b/input/ps2d/src/controller.rs index f1560faaef..3a8c597b7f 100644 --- a/input/ps2d/src/controller.rs +++ b/input/ps2d/src/controller.rs @@ -499,14 +499,16 @@ impl Ps2 { Ok(mouse_extra) } - pub fn init(&mut self) -> Result { + pub fn init(&mut self) -> bool { // Clear remaining data self.flush_read("init start"); { // Disable devices - self.command(Command::DisableFirst)?; - self.command(Command::DisableSecond)?; + self.command(Command::DisableFirst) + .expect("ps2d: failed to initialize"); + self.command(Command::DisableSecond) + .expect("ps2d: failed to initialize"); // Clear remaining data self.flush_read("disable"); @@ -521,7 +523,7 @@ impl Ps2 { | ConfigFlags::FIRST_DISABLED | ConfigFlags::SECOND_DISABLED; trace!("ps2d: config set {:?}", config); - self.set_config(config)?; + self.set_config(config).expect("ps2d: failed to initialize"); // Clear remaining data self.flush_read("disable interrupts"); @@ -529,15 +531,16 @@ impl Ps2 { { // Perform the self test - self.command(Command::TestController)?; - assert_eq!(self.read()?, 0x55); + self.command(Command::TestController) + .expect("ps2d: failed to initialize"); + assert_eq!(self.read().expect("ps2d: failed to initialize"), 0x55); // Clear remaining data self.flush_read("test controller"); } // Initialize keyboard - self.init_keyboard()?; + self.init_keyboard().expect("ps2d: failed to initialize"); // Initialize mouse let (mouse_found, mouse_extra) = match self.init_mouse() { @@ -551,7 +554,8 @@ impl Ps2 { { // Enable keyboard data reporting // Use inner function to prevent retries - self.keyboard_command_inner(KeyboardCommand::EnableReporting as u8)?; + self.keyboard_command_inner(KeyboardCommand::EnableReporting as u8) + .expect("ps2d: failed to initialize"); // Response is ignored since scanning is now on //TODO: fix by using interrupts? } @@ -559,7 +563,8 @@ impl Ps2 { if mouse_found { // Enable mouse data reporting // Use inner function to prevent retries - self.mouse_command_inner(MouseCommand::EnableReporting as u8)?; + self.mouse_command_inner(MouseCommand::EnableReporting as u8) + .expect("ps2d: failed to initialize"); // Response is ignored since scanning is now on //TODO: fix by using interrupts? } @@ -577,12 +582,12 @@ impl Ps2 { config.remove(ConfigFlags::SECOND_INTERRUPT); } trace!("ps2d: config set {:?}", config); - self.set_config(config)?; + self.set_config(config).expect("ps2d: failed to initialize"); } // Clear remaining data self.flush_read("init finish"); - Ok(mouse_extra) + mouse_extra } } diff --git a/input/ps2d/src/state.rs b/input/ps2d/src/state.rs index b9abe4ed42..6e35b33fe9 100644 --- a/input/ps2d/src/state.rs +++ b/input/ps2d/src/state.rs @@ -41,7 +41,7 @@ pub struct Ps2d char> { impl char> Ps2d { pub fn new(input: ProducerHandle, keymap: F) -> Self { let mut ps2 = Ps2::new(); - let extra_packet = ps2.init().expect("ps2d: failed to initialize"); + let extra_packet = ps2.init(); // FIXME add an option for orbital to disable this when an app captures the mouse. let vmmouse_relative = false; From 5ddddd91dfc949c96bca06d700d0b7eb980baec8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:01:40 +0200 Subject: [PATCH 1197/1301] graphics: Pass CursorPlane by shared ref to handle_cursor --- graphics/driver-graphics/src/lib.rs | 2 +- graphics/vesad/src/scheme.rs | 2 +- graphics/virtio-gpud/src/scheme.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 3ef5c0874e..09464cc083 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -22,7 +22,7 @@ pub trait GraphicsAdapter { fn supports_hw_cursor(&self) -> bool; fn create_cursor_framebuffer(&mut self) -> Self::Cursor; fn map_cursor_framebuffer(&mut self, cursor: &Self::Cursor) -> *mut u8; - fn handle_cursor(&mut self, cursor: &mut CursorPlane, dirty_fb: bool); + fn handle_cursor(&mut self, cursor: &CursorPlane, dirty_fb: bool); } pub trait Framebuffer { diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index f8c4249ee5..0c140e4767 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -55,7 +55,7 @@ impl GraphicsAdapter for FbAdapter { unimplemented!("Vesad does not support this function"); } - fn handle_cursor(&mut self, _cursor: &mut CursorPlane, _dirty_fb: bool) { + fn handle_cursor(&mut self, _cursor: &CursorPlane, _dirty_fb: bool) { unimplemented!("Vesad does not support this function"); } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 86fc9c9fc9..1a908fbb68 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -331,7 +331,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { cursor.sgl.as_ptr() } - fn handle_cursor(&mut self, cursor: &mut CursorPlane, dirty_fb: bool) { + fn handle_cursor(&mut self, cursor: &CursorPlane, dirty_fb: bool) { if dirty_fb { self.update_cursor( &cursor.framebuffer, From 56d4fdd025ab72c33b110ba2aedd29d08c4f65af Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 29 Jun 2025 19:48:30 +0200 Subject: [PATCH 1198/1301] graphics: Replace adapter.displays() with .display_count() --- graphics/driver-graphics/src/lib.rs | 6 +++--- graphics/vesad/src/scheme.rs | 4 ++-- graphics/virtio-gpud/src/scheme.rs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 09464cc083..9d6bc87097 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -11,7 +11,7 @@ pub trait GraphicsAdapter { type Framebuffer: Framebuffer; type Cursor: CursorFramebuffer; - fn displays(&self) -> Vec; + fn display_count(&self) -> usize; fn display_size(&self, display_id: usize) -> (u32, u32); fn create_dumb_framebuffer(&mut self, width: u32, height: u32) -> Self::Framebuffer; @@ -91,7 +91,7 @@ impl GraphicsScheme { VtEventKind::Activate => { log::info!("activate {}", vt_event.vt); - for display_id in self.adapter.displays() { + for display_id in 0..self.adapter.display_count() { let framebuffer = self .vts_fb .entry(vt_event.vt) @@ -195,7 +195,7 @@ impl Scheme for GraphicsScheme { let vt = screen.next().unwrap_or("").parse::().unwrap(); let id = screen.next().unwrap_or("").parse::().unwrap_or(0); - if id >= self.adapter.displays().len() { + if id >= self.adapter.display_count() { return Err(Error::new(EINVAL)); } diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 0c140e4767..63a83896c8 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -20,8 +20,8 @@ impl GraphicsAdapter for FbAdapter { type Framebuffer = GraphicScreen; type Cursor = VesadCursor; - fn displays(&self) -> Vec { - (0..self.framebuffers.len()).collect() + fn display_count(&self) -> usize { + self.framebuffers.len() } fn display_size(&self, display_id: usize) -> (u32, u32) { diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 1a908fbb68..0bb3ee52e9 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -149,8 +149,8 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { type Framebuffer = VirtGpuFramebuffer; type Cursor = VirtGpuCursor; - fn displays(&self) -> Vec { - self.displays.iter().enumerate().map(|(i, _)| i).collect() + fn display_count(&self) -> usize { + self.displays.len() } fn display_size(&self, display_id: usize) -> (u32, u32) { From 74bb9f40e51963d0d44545a3ac1000f22731c24b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 29 Jun 2025 19:49:57 +0200 Subject: [PATCH 1199/1301] graphics/graphics-ipc: Introduce a common module for code shared between versions --- graphics/graphics-ipc/src/common.rs | 75 ++++++++++++++++++++++++++ graphics/graphics-ipc/src/lib.rs | 1 + graphics/graphics-ipc/src/v1.rs | 81 +++-------------------------- 3 files changed, 83 insertions(+), 74 deletions(-) create mode 100644 graphics/graphics-ipc/src/common.rs diff --git a/graphics/graphics-ipc/src/common.rs b/graphics/graphics-ipc/src/common.rs new file mode 100644 index 0000000000..81e02640d5 --- /dev/null +++ b/graphics/graphics-ipc/src/common.rs @@ -0,0 +1,75 @@ +use std::cmp; + +// Keep synced with orbital's SyncRect +// Technically orbital uses i32 rather than u32, but values larger than i32::MAX +// would be a bug anyway. +#[derive(Debug, Copy, Clone)] +#[repr(C, packed)] +pub struct Damage { + pub x: u32, + pub y: u32, + pub width: u32, + pub height: u32, +} + +impl Damage { + #[must_use] + pub fn clip(mut self, width: u32, height: u32) -> Self { + // Clip damage + let x2 = self.x + self.width; + self.x = cmp::min(self.x, width); + if x2 > width { + self.width = width - self.x; + } + + let y2 = self.y + self.height; + self.y = cmp::min(self.y, height); + if y2 > height { + self.height = height - self.y; + } + self + } +} + +pub struct DisplayMap { + offscreen: *mut [u32], + width: usize, + height: usize, +} + +impl DisplayMap { + pub(crate) unsafe fn new(offscreen: *mut [u32], width: usize, height: usize) -> Self { + DisplayMap { + offscreen, + width, + height, + } + } + + pub fn ptr(&self) -> *const [u32] { + self.offscreen + } + + pub fn ptr_mut(&mut self) -> *mut [u32] { + self.offscreen + } + + pub fn width(&self) -> usize { + self.width + } + + pub fn height(&self) -> usize { + self.height + } +} + +unsafe impl Send for DisplayMap {} +unsafe impl Sync for DisplayMap {} + +impl Drop for DisplayMap { + fn drop(&mut self) { + unsafe { + let _ = libredox::call::munmap(self.offscreen as *mut (), self.offscreen.len()); + } + } +} diff --git a/graphics/graphics-ipc/src/lib.rs b/graphics/graphics-ipc/src/lib.rs index a3a6d96c3f..99b52a835b 100644 --- a/graphics/graphics-ipc/src/lib.rs +++ b/graphics/graphics-ipc/src/lib.rs @@ -1 +1,2 @@ +mod common; pub mod v1; diff --git a/graphics/graphics-ipc/src/v1.rs b/graphics/graphics-ipc/src/v1.rs index 14fb1e10b4..a29258db9c 100644 --- a/graphics/graphics-ipc/src/v1.rs +++ b/graphics/graphics-ipc/src/v1.rs @@ -1,13 +1,16 @@ use std::fs::File; use std::os::unix::io::AsRawFd; -use std::{cmp, io, mem, ptr, slice}; +use std::{io, mem, ptr, slice}; use libredox::flag; +pub use crate::common::Damage; +pub use crate::common::DisplayMap; + /// A graphics handle using the v1 graphics API. /// -/// The v1 graphics API only allows a single framebuffer for each VT and supports neither page -/// flipping nor cursor planes. +/// The v1 graphics API only allows a single framebuffer for each VT, requires each display to be +/// handled separately and doesn't support page flipping. pub struct V1GraphicsHandle { file: File, } @@ -52,11 +55,7 @@ impl V1GraphicsHandle { }; let offscreen = ptr::slice_from_raw_parts_mut(display_ptr as *mut u32, width * height); - Ok(DisplayMap { - offscreen, - width, - height, - }) + Ok(unsafe { DisplayMap::new(offscreen, width, height) }) } pub fn sync_full_screen(&self) -> io::Result<()> { @@ -75,41 +74,6 @@ impl V1GraphicsHandle { } } -pub struct DisplayMap { - offscreen: *mut [u32], - width: usize, - height: usize, -} - -impl DisplayMap { - pub fn ptr(&self) -> *const [u32] { - self.offscreen - } - - pub fn ptr_mut(&mut self) -> *mut [u32] { - self.offscreen - } - - pub fn width(&self) -> usize { - self.width - } - - pub fn height(&self) -> usize { - self.height - } -} - -unsafe impl Send for DisplayMap {} -unsafe impl Sync for DisplayMap {} - -impl Drop for DisplayMap { - fn drop(&mut self) { - unsafe { - let _ = libredox::call::munmap(self.offscreen as *mut (), self.offscreen.len()); - } - } -} - #[derive(Debug, Copy, Clone)] #[repr(C, packed)] pub struct CursorDamage { @@ -122,34 +86,3 @@ pub struct CursorDamage { pub height: i32, pub cursor_img_bytes: [u32; 4096], } - -// Keep synced with orbital's SyncRect -// Technically orbital uses i32 rather than u32, but values larger than i32::MAX -// would be a bug anyway. -#[derive(Debug, Copy, Clone)] -#[repr(packed)] -pub struct Damage { - pub x: u32, - pub y: u32, - pub width: u32, - pub height: u32, -} - -impl Damage { - #[must_use] - pub fn clip(mut self, width: u32, height: u32) -> Self { - // Clip damage - let x2 = self.x + self.width; - self.x = cmp::min(self.x, width); - if x2 > width { - self.width = width - self.x; - } - - let y2 = self.y + self.height; - self.y = cmp::min(self.y, height); - if y2 > height { - self.height = height - self.y; - } - self - } -} From 993b23e63c3f1d3d96aa9a7c20ee0c24b95f1064 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 30 Jun 2025 20:04:40 +0200 Subject: [PATCH 1200/1301] graphics/driver-graphics: Prepare for future abi versions --- graphics/driver-graphics/src/lib.rs | 190 +++++++++++++++------------- 1 file changed, 100 insertions(+), 90 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 9d6bc87097..b4f78525d1 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -54,7 +54,7 @@ pub struct GraphicsScheme { } enum Handle { - Screen { vt: usize, screen: usize }, + V1Screen { vt: usize, screen: usize }, } impl GraphicsScheme { @@ -210,33 +210,39 @@ impl Scheme for GraphicsScheme { self.next_id += 1; self.handles - .insert(self.next_id, Handle::Screen { vt, screen: id }); + .insert(self.next_id, Handle::V1Screen { vt, screen: id }); Ok(self.next_id) } fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { - let Handle::Screen { vt, screen } = self.handles.get(&id).ok_or(Error::new(EBADF))?; - let framebuffer = &self.vts_fb[vt][screen]; - let path = format!( - "{}:{vt}.{screen}/{}/{}", - self.scheme_name, - framebuffer.width(), - framebuffer.height() - ); + let path = match self.handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::V1Screen { vt, screen } => { + let framebuffer = &self.vts_fb[vt][screen]; + format!( + "{}:{vt}.{screen}/{}/{}", + self.scheme_name, + framebuffer.width(), + framebuffer.height() + ) + } + }; buf[..path.len()].copy_from_slice(path.as_bytes()); Ok(path.len()) } fn fsync(&mut self, id: usize) -> syscall::Result { - let Handle::Screen { vt, screen } = self.handles.get(&id).ok_or(Error::new(EBADF))?; - if *vt != self.active_vt { - // This is a protection against background VT's spamming us with flush requests. We will - // flush the framebuffer on the next VT switch anyway - return Ok(0); + match self.handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::V1Screen { vt, screen } => { + if *vt != self.active_vt { + // This is a protection against background VT's spamming us with flush requests. We will + // flush the framebuffer on the next VT switch anyway + return Ok(0); + } + let framebuffer = &self.vts_fb[vt][screen]; + Self::update_whole_screen(&mut self.adapter, *screen, framebuffer); + Ok(0) + } } - let framebuffer = &self.vts_fb[vt][screen]; - Self::update_whole_screen(&mut self.adapter, *screen, framebuffer); - Ok(0) } fn read( @@ -246,88 +252,92 @@ impl Scheme for GraphicsScheme { _offset: u64, _fcntl_flags: u32, ) -> Result { - let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; + match self.handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::V1Screen { .. } => { + //Currently read is only used for Orbital to check GPU cursor support + //and only expects a buf to pass a 0 or 1 flag + if self.adapter.supports_hw_cursor() { + buf[0] = 1; + } else { + buf[0] = 0; + } - //Currently read is only used for Orbital to check GPU cursor support - //and only expects a buf to pass a 0 or 1 flag - if self.adapter.supports_hw_cursor() { - buf[0] = 1; - } else { - buf[0] = 0; + Ok(1) + } } - - Ok(1) } fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { - let Handle::Screen { vt, screen } = self.handles.get(&id).ok_or(Error::new(EBADF))?; - - if *vt != self.active_vt { - // This is a protection against background VT's spamming us with flush requests. We will - // flush the framebuffer on the next VT switch anyway - return Ok(buf.len()); - } - - if size_of_val(buf) == std::mem::size_of::() - && self.adapter.supports_hw_cursor() - { - let cursor_damage = unsafe { *buf.as_ptr().cast::() }; - - let cursor_plane = Self::cursor_plane_for_vt( - &mut self.adapter, - &mut self.cursor_planes, - self.active_vt, - ); - - cursor_plane.x = cursor_damage.x; - cursor_plane.y = cursor_damage.y; - - if cursor_damage.header == 0 { - self.adapter.handle_cursor(cursor_plane, false); - } else { - cursor_plane.hot_x = cursor_damage.hot_x; - cursor_plane.hot_y = cursor_damage.hot_y; - - let w: i32 = cursor_damage.width; - let h: i32 = cursor_damage.height; - let cursor_image = cursor_damage.cursor_img_bytes; - let cursor_ptr = self - .adapter - .map_cursor_framebuffer(&cursor_plane.framebuffer); - - //Clear previous image from backing storage - unsafe { - core::ptr::write_bytes(cursor_ptr as *mut u8, 0, 64 * 64 * 4); + match self.handles.get(&id).ok_or(Error::new(EBADF))? { + Handle::V1Screen { vt, screen } => { + if *vt != self.active_vt { + // This is a protection against background VT's spamming us with flush requests. We will + // flush the framebuffer on the next VT switch anyway + return Ok(buf.len()); } - //Write image to backing storage - for row in 0..h { - let start: usize = (w * row) as usize; - let end: usize = (w * row + w) as usize; + if size_of_val(buf) == std::mem::size_of::() + && self.adapter.supports_hw_cursor() + { + let cursor_damage = unsafe { *buf.as_ptr().cast::() }; - unsafe { - core::ptr::copy_nonoverlapping( - cursor_image[start..end].as_ptr(), - cursor_ptr.cast::().offset(64 * row as isize), - w as usize, - ); + let cursor_plane = Self::cursor_plane_for_vt( + &mut self.adapter, + &mut self.cursor_planes, + self.active_vt, + ); + + cursor_plane.x = cursor_damage.x; + cursor_plane.y = cursor_damage.y; + + if cursor_damage.header == 0 { + self.adapter.handle_cursor(cursor_plane, false); + } else { + cursor_plane.hot_x = cursor_damage.hot_x; + cursor_plane.hot_y = cursor_damage.hot_y; + + let w: i32 = cursor_damage.width; + let h: i32 = cursor_damage.height; + let cursor_image = cursor_damage.cursor_img_bytes; + let cursor_ptr = self + .adapter + .map_cursor_framebuffer(&cursor_plane.framebuffer); + + //Clear previous image from backing storage + unsafe { + core::ptr::write_bytes(cursor_ptr as *mut u8, 0, 64 * 64 * 4); + } + + //Write image to backing storage + for row in 0..h { + let start: usize = (w * row) as usize; + let end: usize = (w * row + w) as usize; + + unsafe { + core::ptr::copy_nonoverlapping( + cursor_image[start..end].as_ptr(), + cursor_ptr.cast::().offset(64 * row as isize), + w as usize, + ); + } + } + + self.adapter.handle_cursor(cursor_plane, true); } + + return Ok(buf.len()); } - self.adapter.handle_cursor(cursor_plane, true); + let framebuffer = &self.vts_fb[vt][screen]; + + assert_eq!(buf.len(), std::mem::size_of::()); + let damage = unsafe { *buf.as_ptr().cast::() }; + + self.adapter.update_plane(*screen, framebuffer, damage); + + Ok(buf.len()) } - - return Ok(buf.len()); } - - let framebuffer = &self.vts_fb[vt][screen]; - - assert_eq!(buf.len(), std::mem::size_of::()); - let damage = unsafe { *buf.as_ptr().cast::() }; - - self.adapter.update_plane(*screen, framebuffer, damage); - - Ok(buf.len()) } fn mmap_prep( @@ -338,9 +348,9 @@ impl Scheme for GraphicsScheme { _flags: MapFlags, ) -> syscall::Result { // log::trace!("KSMSG MMAP {} {:?} {} {}", id, _flags, _offset, _size); - let handle = self.handles.get(&id).ok_or(Error::new(EINVAL))?; - let Handle::Screen { vt, screen } = handle; - let framebuffer = &self.vts_fb[vt][screen]; + let framebuffer = match self.handles.get(&id).ok_or(Error::new(EINVAL))? { + Handle::V1Screen { vt, screen } => &self.vts_fb[vt][screen], + }; let ptr = T::map_dumb_framebuffer(&mut self.adapter, framebuffer); Ok(ptr as usize) } From c2249f2fa061fe15aa08e3f3adda215c36a3091e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 30 Jun 2025 21:40:02 +0200 Subject: [PATCH 1201/1301] graphics/driver-graphics: Couple of minor changes --- graphics/driver-graphics/src/lib.rs | 43 +++++++++++++++++------------ 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index b4f78525d1..3f79f6dbbd 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -1,5 +1,6 @@ use std::collections::{BTreeMap, HashMap}; use std::io; +use std::sync::Arc; use graphics_ipc::v1::{CursorDamage, Damage}; use inputd::{VtEvent, VtEventKind}; @@ -49,7 +50,7 @@ pub struct GraphicsScheme { handles: BTreeMap, active_vt: usize, - vts_fb: HashMap>, + vts_fb: HashMap>>, cursor_planes: HashMap>, } @@ -92,15 +93,12 @@ impl GraphicsScheme { log::info!("activate {}", vt_event.vt); for display_id in 0..self.adapter.display_count() { - let framebuffer = self - .vts_fb - .entry(vt_event.vt) - .or_default() - .entry(display_id) - .or_insert_with(|| { - let (width, height) = self.adapter.display_size(display_id); - self.adapter.create_dumb_framebuffer(width, height) - }); + let framebuffer = Self::framebuffer_for_vt_and_display( + &mut self.adapter, + &mut self.vts_fb, + vt_event.vt, + display_id, + ); Self::update_whole_screen(&mut self.adapter, display_id, framebuffer); self.active_vt = vt_event.vt; @@ -168,6 +166,22 @@ impl GraphicsScheme { ); } + fn framebuffer_for_vt_and_display<'a>( + adapter: &mut T, + vts_fb: &'a mut HashMap>>, + vt: usize, + display_id: usize, + ) -> &'a T::Framebuffer { + vts_fb + .entry(vt) + .or_default() + .entry(display_id) + .or_insert_with(|| { + let (width, height) = adapter.display_size(display_id); + Arc::new(adapter.create_dumb_framebuffer(width, height)) + }) + } + fn cursor_plane_for_vt<'a>( adapter: &mut T, cursor_planes: &'a mut HashMap>, @@ -199,14 +213,7 @@ impl Scheme for GraphicsScheme { return Err(Error::new(EINVAL)); } - self.vts_fb - .entry(vt) - .or_default() - .entry(id) - .or_insert_with(|| { - let (width, height) = self.adapter.display_size(id); - self.adapter.create_dumb_framebuffer(width, height) - }); + Self::framebuffer_for_vt_and_display(&mut self.adapter, &mut self.vts_fb, vt, id); self.next_id += 1; self.handles From 7882372dab47f16ae888dc92d18a1d6bd5111504 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 30 Jun 2025 22:10:02 +0200 Subject: [PATCH 1202/1301] graphics/driver-graphics: Introduce VtState This contains the current state for a single VT. --- graphics/driver-graphics/src/lib.rs | 66 +++++++++++++++++------------ 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 3f79f6dbbd..dd1c873fbc 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -50,8 +50,21 @@ pub struct GraphicsScheme { handles: BTreeMap, active_vt: usize, - vts_fb: HashMap>>, - cursor_planes: HashMap>, + vts: HashMap>, +} + +struct VtState { + display_fbs: HashMap>, + cursor_plane: Option>, +} + +impl Default for VtState { + fn default() -> Self { + VtState { + display_fbs: HashMap::default(), + cursor_plane: None, + } + } } enum Handle { @@ -70,8 +83,7 @@ impl GraphicsScheme { next_id: 0, handles: BTreeMap::new(), active_vt: 0, - vts_fb: HashMap::new(), - cursor_planes: HashMap::new(), + vts: HashMap::new(), } } @@ -95,7 +107,7 @@ impl GraphicsScheme { for display_id in 0..self.adapter.display_count() { let framebuffer = Self::framebuffer_for_vt_and_display( &mut self.adapter, - &mut self.vts_fb, + &mut self.vts, vt_event.vt, display_id, ); @@ -106,7 +118,7 @@ impl GraphicsScheme { if self.adapter.supports_hw_cursor() { let cursor_plane = Self::cursor_plane_for_vt( &mut self.adapter, - &mut self.cursor_planes, + &mut self.vts, self.active_vt, ); self.adapter.handle_cursor(cursor_plane, true); @@ -168,13 +180,13 @@ impl GraphicsScheme { fn framebuffer_for_vt_and_display<'a>( adapter: &mut T, - vts_fb: &'a mut HashMap>>, + vts: &'a mut HashMap>, vt: usize, display_id: usize, ) -> &'a T::Framebuffer { - vts_fb - .entry(vt) + vts.entry(vt) .or_default() + .display_fbs .entry(display_id) .or_insert_with(|| { let (width, height) = adapter.display_size(display_id); @@ -184,16 +196,19 @@ impl GraphicsScheme { fn cursor_plane_for_vt<'a>( adapter: &mut T, - cursor_planes: &'a mut HashMap>, + vts: &'a mut HashMap>, vt: usize, ) -> &'a mut CursorPlane { - cursor_planes.entry(vt).or_insert_with(|| CursorPlane { - x: 0, - y: 0, - hot_x: 0, - hot_y: 0, - framebuffer: adapter.create_cursor_framebuffer(), - }) + vts.entry(vt) + .or_default() + .cursor_plane + .get_or_insert_with(|| CursorPlane { + x: 0, + y: 0, + hot_x: 0, + hot_y: 0, + framebuffer: adapter.create_cursor_framebuffer(), + }) } } @@ -213,7 +228,7 @@ impl Scheme for GraphicsScheme { return Err(Error::new(EINVAL)); } - Self::framebuffer_for_vt_and_display(&mut self.adapter, &mut self.vts_fb, vt, id); + Self::framebuffer_for_vt_and_display(&mut self.adapter, &mut self.vts, vt, id); self.next_id += 1; self.handles @@ -224,7 +239,7 @@ impl Scheme for GraphicsScheme { fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { let path = match self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::V1Screen { vt, screen } => { - let framebuffer = &self.vts_fb[vt][screen]; + let framebuffer = &self.vts[vt].display_fbs[screen]; format!( "{}:{vt}.{screen}/{}/{}", self.scheme_name, @@ -245,7 +260,7 @@ impl Scheme for GraphicsScheme { // flush the framebuffer on the next VT switch anyway return Ok(0); } - let framebuffer = &self.vts_fb[vt][screen]; + let framebuffer = &self.vts[vt].display_fbs[screen]; Self::update_whole_screen(&mut self.adapter, *screen, framebuffer); Ok(0) } @@ -288,11 +303,8 @@ impl Scheme for GraphicsScheme { { let cursor_damage = unsafe { *buf.as_ptr().cast::() }; - let cursor_plane = Self::cursor_plane_for_vt( - &mut self.adapter, - &mut self.cursor_planes, - self.active_vt, - ); + let cursor_plane = + Self::cursor_plane_for_vt(&mut self.adapter, &mut self.vts, self.active_vt); cursor_plane.x = cursor_damage.x; cursor_plane.y = cursor_damage.y; @@ -335,7 +347,7 @@ impl Scheme for GraphicsScheme { return Ok(buf.len()); } - let framebuffer = &self.vts_fb[vt][screen]; + let framebuffer = &self.vts[vt].display_fbs[screen]; assert_eq!(buf.len(), std::mem::size_of::()); let damage = unsafe { *buf.as_ptr().cast::() }; @@ -356,7 +368,7 @@ impl Scheme for GraphicsScheme { ) -> syscall::Result { // log::trace!("KSMSG MMAP {} {:?} {} {}", id, _flags, _offset, _size); let framebuffer = match self.handles.get(&id).ok_or(Error::new(EINVAL))? { - Handle::V1Screen { vt, screen } => &self.vts_fb[vt][screen], + Handle::V1Screen { vt, screen } => &self.vts[vt].display_fbs[screen], }; let ptr = T::map_dumb_framebuffer(&mut self.adapter, framebuffer); Ok(ptr as usize) From 7f5c58892cd3b3f694c9e1575c865a3bc78c512b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 30 Jun 2025 23:01:52 +0200 Subject: [PATCH 1203/1301] graphics/driver-graphics: Eagerly create contents of VtState --- graphics/driver-graphics/src/lib.rs | 111 ++++++++++++---------------- 1 file changed, 48 insertions(+), 63 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index dd1c873fbc..a466c19139 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -12,6 +12,9 @@ pub trait GraphicsAdapter { type Framebuffer: Framebuffer; type Cursor: CursorFramebuffer; + /// The maximum amount of displays that could be attached. + /// + /// This must be constant for the lifetime of the graphics adapter. fn display_count(&self) -> usize; fn display_size(&self, display_id: usize) -> (u32, u32); @@ -54,19 +57,10 @@ pub struct GraphicsScheme { } struct VtState { - display_fbs: HashMap>, + display_fbs: Vec>, cursor_plane: Option>, } -impl Default for VtState { - fn default() -> Self { - VtState { - display_fbs: HashMap::default(), - cursor_plane: None, - } - } -} - enum Handle { V1Screen { vt: usize, screen: usize }, } @@ -104,26 +98,18 @@ impl GraphicsScheme { VtEventKind::Activate => { log::info!("activate {}", vt_event.vt); - for display_id in 0..self.adapter.display_count() { - let framebuffer = Self::framebuffer_for_vt_and_display( - &mut self.adapter, - &mut self.vts, - vt_event.vt, - display_id, - ); - Self::update_whole_screen(&mut self.adapter, display_id, framebuffer); + let vt_state = + Self::get_or_create_vt(&mut self.adapter, &mut self.vts, vt_event.vt); - self.active_vt = vt_event.vt; - - if self.adapter.supports_hw_cursor() { - let cursor_plane = Self::cursor_plane_for_vt( - &mut self.adapter, - &mut self.vts, - self.active_vt, - ); - self.adapter.handle_cursor(cursor_plane, true); - } + for (display_id, fb) in vt_state.display_fbs.iter().enumerate() { + Self::update_whole_screen(&mut self.adapter, display_id, fb); } + + if let Some(cursor_plane) = &vt_state.cursor_plane { + self.adapter.handle_cursor(cursor_plane, true); + } + + self.active_vt = vt_event.vt; } VtEventKind::Resize => { @@ -178,37 +164,31 @@ impl GraphicsScheme { ); } - fn framebuffer_for_vt_and_display<'a>( + fn get_or_create_vt<'a>( adapter: &mut T, vts: &'a mut HashMap>, vt: usize, - display_id: usize, - ) -> &'a T::Framebuffer { - vts.entry(vt) - .or_default() - .display_fbs - .entry(display_id) - .or_insert_with(|| { + ) -> &'a mut VtState { + vts.entry(vt).or_insert_with(|| { + let mut display_fbs = vec![]; + for display_id in 0..adapter.display_count() { let (width, height) = adapter.display_size(display_id); - Arc::new(adapter.create_dumb_framebuffer(width, height)) - }) - } + display_fbs.push(Arc::new(adapter.create_dumb_framebuffer(width, height))); + } - fn cursor_plane_for_vt<'a>( - adapter: &mut T, - vts: &'a mut HashMap>, - vt: usize, - ) -> &'a mut CursorPlane { - vts.entry(vt) - .or_default() - .cursor_plane - .get_or_insert_with(|| CursorPlane { + let cursor_plane = adapter.supports_hw_cursor().then(|| CursorPlane { x: 0, y: 0, hot_x: 0, hot_y: 0, framebuffer: adapter.create_cursor_framebuffer(), - }) + }); + + VtState { + display_fbs, + cursor_plane, + } + }) } } @@ -228,7 +208,8 @@ impl Scheme for GraphicsScheme { return Err(Error::new(EINVAL)); } - Self::framebuffer_for_vt_and_display(&mut self.adapter, &mut self.vts, vt, id); + // Ensure the VT exists such that the rest of the methods can freely access it. + Self::get_or_create_vt(&mut self.adapter, &mut self.vts, vt); self.next_id += 1; self.handles @@ -239,7 +220,7 @@ impl Scheme for GraphicsScheme { fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { let path = match self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::V1Screen { vt, screen } => { - let framebuffer = &self.vts[vt].display_fbs[screen]; + let framebuffer = &self.vts[vt].display_fbs[*screen]; format!( "{}:{vt}.{screen}/{}/{}", self.scheme_name, @@ -260,8 +241,11 @@ impl Scheme for GraphicsScheme { // flush the framebuffer on the next VT switch anyway return Ok(0); } - let framebuffer = &self.vts[vt].display_fbs[screen]; - Self::update_whole_screen(&mut self.adapter, *screen, framebuffer); + Self::update_whole_screen( + &mut self.adapter, + *screen, + &self.vts[vt].display_fbs[*screen], + ); Ok(0) } } @@ -298,13 +282,15 @@ impl Scheme for GraphicsScheme { return Ok(buf.len()); } - if size_of_val(buf) == std::mem::size_of::() - && self.adapter.supports_hw_cursor() - { - let cursor_damage = unsafe { *buf.as_ptr().cast::() }; + let vt_state = self.vts.get_mut(vt).unwrap(); - let cursor_plane = - Self::cursor_plane_for_vt(&mut self.adapter, &mut self.vts, self.active_vt); + if size_of_val(buf) == std::mem::size_of::() { + let Some(cursor_plane) = &mut vt_state.cursor_plane else { + // Hardware cursor not supported + return Err(Error::new(EINVAL)); + }; + + let cursor_damage = unsafe { *buf.as_ptr().cast::() }; cursor_plane.x = cursor_damage.x; cursor_plane.y = cursor_damage.y; @@ -347,12 +333,11 @@ impl Scheme for GraphicsScheme { return Ok(buf.len()); } - let framebuffer = &self.vts[vt].display_fbs[screen]; - assert_eq!(buf.len(), std::mem::size_of::()); let damage = unsafe { *buf.as_ptr().cast::() }; - self.adapter.update_plane(*screen, framebuffer, damage); + self.adapter + .update_plane(*screen, &vt_state.display_fbs[*screen], damage); Ok(buf.len()) } @@ -368,7 +353,7 @@ impl Scheme for GraphicsScheme { ) -> syscall::Result { // log::trace!("KSMSG MMAP {} {:?} {} {}", id, _flags, _offset, _size); let framebuffer = match self.handles.get(&id).ok_or(Error::new(EINVAL))? { - Handle::V1Screen { vt, screen } => &self.vts[vt].display_fbs[screen], + Handle::V1Screen { vt, screen } => &self.vts[vt].display_fbs[*screen], }; let ptr = T::map_dumb_framebuffer(&mut self.adapter, framebuffer); Ok(ptr as usize) From 7f3f1817751303677271e402dae77636b99a321c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:06:22 +0200 Subject: [PATCH 1204/1301] graphics/virtio-gpud: Create DisplayHandle after registering the scheme This fixes a race-condition. It is unlikely to cause issues in practice though. --- graphics/virtio-gpud/src/scheme.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index 0bb3ee52e9..b7707ab5f1 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -390,11 +390,8 @@ impl<'a> GpuScheme { } } - let inputd_handle = DisplayHandle::new("virtio-gpu").unwrap(); - - Ok(( - GraphicsScheme::new(adapter, "display.virtio-gpu".to_owned()), - inputd_handle, - )) + let scheme = GraphicsScheme::new(adapter, "display.virtio-gpu".to_owned()); + let handle = DisplayHandle::new("virtio-gpu").unwrap(); + Ok((scheme, handle)) } } From 565add84b152dae1be6f6194a24e3190570483d5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 1 Jul 2025 18:31:52 +0200 Subject: [PATCH 1205/1301] graphics/driver-graphics: Update to redox-scheme 0.6 --- Cargo.lock | 17 ++++++++++++--- Cargo.toml | 1 - graphics/driver-graphics/Cargo.toml | 2 +- graphics/driver-graphics/src/lib.rs | 34 ++++++++++++++++++++--------- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3fd0ece1a..ce7c05e14d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -404,7 +404,7 @@ dependencies = [ "inputd", "libredox", "log", - "redox-scheme 0.4.0", + "redox-scheme 0.6.2", "redox_syscall", ] @@ -1153,6 +1153,16 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "redox-scheme" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c00025a04f76fdcf72c15f10c7a12d9f2fdde93e539be9a57d5d632c4158a9e" +dependencies = [ + "libredox", + "redox_syscall", +] + [[package]] name = "redox_event" version = "0.4.1" @@ -1165,8 +1175,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.11" -source = "git+https://gitlab.redox-os.org/redox-os/syscall.git?branch=master#8f646a63ac9c3aa532a37ddfdc136ec19878f0d6" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" dependencies = [ "bitflags 2.9.0", ] diff --git a/Cargo.toml b/Cargo.toml index de99b5ded3..4fb623614e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,4 +56,3 @@ lto = "fat" mio = { git = "https://gitlab.redox-os.org/redox-os/mio.git", branch = "redox-unix" } orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient.git", version = "0.3.44" } redox-daemon = { git = "https://gitlab.redox-os.org/redox-os/redox-daemon.git" } -redox_syscall = { git = "https://gitlab.redox-os.org/redox-os/syscall.git", branch = "master" } diff --git a/graphics/driver-graphics/Cargo.toml b/graphics/driver-graphics/Cargo.toml index a1525e23f2..ef5078e59e 100644 --- a/graphics/driver-graphics/Cargo.toml +++ b/graphics/driver-graphics/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] log = "0.4" -redox-scheme = "0.4" +redox-scheme = "0.6.2" redox_syscall = "0.5" libredox = "0.1.3" diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index a466c19139..6fb09e91b8 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -5,7 +5,9 @@ use std::sync::Arc; use graphics_ipc::v1::{CursorDamage, Damage}; use inputd::{VtEvent, VtEventKind}; use libredox::Fd; -use redox_scheme::{RequestKind, Scheme, SignalBehavior, Socket}; +use redox_scheme::scheme::SchemeSync; +use redox_scheme::{CallerCtx, OpenResult, RequestKind, SignalBehavior, Socket}; +use syscall::schemev2::NewFdFlags; use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL}; pub trait GraphicsAdapter { @@ -136,7 +138,7 @@ impl GraphicsScheme { match request.kind() { RequestKind::Call(call) => { - let response = call.handle_scheme(self); + let response = call.handle_sync(self); self.socket .write_response(response, SignalBehavior::Restart) .expect("driver-graphics: failed to write response"); @@ -192,8 +194,8 @@ impl GraphicsScheme { } } -impl Scheme for GraphicsScheme { - fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> Result { +impl SchemeSync for GraphicsScheme { + fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result { if path.is_empty() { return Err(Error::new(EINVAL)); } @@ -214,10 +216,13 @@ impl Scheme for GraphicsScheme { self.next_id += 1; self.handles .insert(self.next_id, Handle::V1Screen { vt, screen: id }); - Ok(self.next_id) + Ok(OpenResult::ThisScheme { + number: self.next_id, + flags: NewFdFlags::empty(), + }) } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { + fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> syscall::Result { let path = match self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::V1Screen { vt, screen } => { let framebuffer = &self.vts[vt].display_fbs[*screen]; @@ -233,20 +238,20 @@ impl Scheme for GraphicsScheme { Ok(path.len()) } - fn fsync(&mut self, id: usize) -> syscall::Result { + fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> syscall::Result<()> { match self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::V1Screen { vt, screen } => { if *vt != self.active_vt { // This is a protection against background VT's spamming us with flush requests. We will // flush the framebuffer on the next VT switch anyway - return Ok(0); + return Ok(()); } Self::update_whole_screen( &mut self.adapter, *screen, &self.vts[vt].display_fbs[*screen], ); - Ok(0) + Ok(()) } } } @@ -257,6 +262,7 @@ impl Scheme for GraphicsScheme { buf: &mut [u8], _offset: u64, _fcntl_flags: u32, + _ctx: &CallerCtx, ) -> Result { match self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::V1Screen { .. } => { @@ -273,7 +279,14 @@ impl Scheme for GraphicsScheme { } } - fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { + fn write( + &mut self, + id: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> Result { match self.handles.get(&id).ok_or(Error::new(EBADF))? { Handle::V1Screen { vt, screen } => { if *vt != self.active_vt { @@ -350,6 +363,7 @@ impl Scheme for GraphicsScheme { _offset: u64, _size: usize, _flags: MapFlags, + _ctx: &CallerCtx, ) -> syscall::Result { // log::trace!("KSMSG MMAP {} {:?} {} {}", id, _flags, _offset, _size); let framebuffer = match self.handles.get(&id).ok_or(Error::new(EINVAL))? { From 2f756fd29dceb899a2f7092a8d905974936e8df2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 1 Jul 2025 21:44:06 +0200 Subject: [PATCH 1206/1301] virtio-core: Fix a warning --- virtio-core/src/transport.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index b34f1b50e4..b2782bdc5c 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -59,7 +59,7 @@ pub fn spawn_irq_thread(irq_handle: &File, queue: &Arc>) { let queue_copy = queue.clone(); std::thread::spawn(move || { - let mut event_queue = RawEventQueue::new().unwrap(); + let event_queue = RawEventQueue::new().unwrap(); event_queue .subscribe(irq_fd as usize, 0, event::EventFlags::READ) From 8ac07539b076dddb2f9c8d8c37ec96ad8bbe0431 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 1 Jul 2025 21:46:20 +0200 Subject: [PATCH 1207/1301] graphics/driver-graphics: Handle mmap offset --- graphics/driver-graphics/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 6fb09e91b8..94860f3103 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -360,17 +360,17 @@ impl SchemeSync for GraphicsScheme { fn mmap_prep( &mut self, id: usize, - _offset: u64, + offset: u64, _size: usize, _flags: MapFlags, _ctx: &CallerCtx, ) -> syscall::Result { // log::trace!("KSMSG MMAP {} {:?} {} {}", id, _flags, _offset, _size); - let framebuffer = match self.handles.get(&id).ok_or(Error::new(EINVAL))? { - Handle::V1Screen { vt, screen } => &self.vts[vt].display_fbs[*screen], + let (framebuffer, offset) = match self.handles.get(&id).ok_or(Error::new(EINVAL))? { + Handle::V1Screen { vt, screen } => (&self.vts[vt].display_fbs[*screen], offset), }; let ptr = T::map_dumb_framebuffer(&mut self.adapter, framebuffer); - Ok(ptr as usize) + Ok(unsafe { ptr.add(offset as usize) } as usize) } } From 27ca1c329638dc22a003c6f157a7de9dd9b3b47f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 29 Jun 2025 18:04:42 +0200 Subject: [PATCH 1208/1301] graphics/virtio-gpud: Handle VIRTIO_GPU_EVENT_DISPLAY This doesn't yet provide a way for individual consumers to resize their own framebuffer in response to the display changing size. --- graphics/virtio-gpud/src/main.rs | 30 +++++++++++++- graphics/virtio-gpud/src/scheme.rs | 64 +++++++++++++++++------------- virtio-core/src/transport.rs | 14 +++++++ 3 files changed, 78 insertions(+), 30 deletions(-) diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 7f95d9d572..ff04932dff 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -31,7 +31,7 @@ use virtio_core::MSIX_PRIMARY_VECTOR; mod scheme; -// const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0; +const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0; const VIRTIO_GPU_MAX_SCANOUTS: usize = 16; #[repr(C)] @@ -457,6 +457,8 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { .transport .setup_queue(MSIX_PRIMARY_VECTOR, &device.irq_handle)?; + device.transport.setup_config_notify(MSIX_PRIMARY_VECTOR); + device.transport.run_device(); deamon.ready().unwrap(); @@ -471,6 +473,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { enum Source { Input, Scheme, + Interrupt, } } @@ -490,8 +493,15 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { event::EventFlags::READ, ) .unwrap(); + event_queue + .subscribe( + device.irq_handle.as_raw_fd() as usize, + Source::Interrupt, + event::EventFlags::READ, + ) + .unwrap(); - let all = [Source::Input, Source::Scheme]; + let all = [Source::Input, Source::Scheme, Source::Interrupt]; for event in all .into_iter() .chain(event_queue.map(|e| e.expect("virtio-gpud: failed to get next event").user_data)) @@ -510,6 +520,22 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { .tick() .expect("virtio-gpud: failed to process scheme events"); } + Source::Interrupt => loop { + let before_gen = device.transport.config_generation(); + + let events = config.events_read.get(); + + if events & VIRTIO_GPU_EVENT_DISPLAY != 0 { + futures::executor::block_on(scheme.adapter_mut().update_displays(config)) + .unwrap(); + config.events_clear.set(VIRTIO_GPU_EVENT_DISPLAY); + } + + let after_gen = device.transport.config_generation(); + if before_gen == after_gen { + break; + } + }, } } diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index b7707ab5f1..c6656c5398 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -64,6 +64,40 @@ pub struct VirtGpuAdapter<'a> { } impl VirtGpuAdapter<'_> { + pub async fn update_displays(&mut self, config: &mut GpuConfig) -> Result<(), Error> { + let mut display_info = self.get_display_info().await?; + let raw_displays = &mut display_info.display_info[..config.num_scanouts() as usize]; + + self.displays.resize( + raw_displays.len(), + Display { + width: 0, + height: 0, + active_resource: None, + }, + ); + for (i, info) in raw_displays.iter().enumerate() { + log::info!( + "virtio-gpu: display {i} ({}x{}px)", + info.rect.width, + info.rect.height + ); + + if info.rect.width == 0 || info.rect.height == 0 { + // QEMU gives all displays other than the first a zero width and height, but trying + // to attach a zero sized framebuffer to the display will result an error, so + // default to 640x480px. + self.displays[i].width = 640; + self.displays[i].height = 480; + } else { + self.displays[i].width = info.rect.width; + self.displays[i].height = info.rect.height; + } + } + + Ok(()) + } + async fn send_request(&self, request: Dma) -> Result, Error> { let header = Dma::new(ControlHeader::default())?; let command = ChainBuilder::new() @@ -350,7 +384,7 @@ pub struct GpuScheme {} impl<'a> GpuScheme { pub async fn new( - config: &'a mut GpuConfig, + config: &mut GpuConfig, control_queue: Arc>, cursor_queue: Arc>, transport: Arc, @@ -362,33 +396,7 @@ impl<'a> GpuScheme { displays: vec![], }; - let mut display_info = adapter.get_display_info().await?; - let raw_displays = &mut display_info.display_info[..config.num_scanouts() as usize]; - - for info in raw_displays.iter() { - log::info!( - "virtio-gpu: opening display ({}x{}px)", - info.rect.width, - info.rect.height - ); - - if info.rect.width == 0 || info.rect.height == 0 { - // QEMU gives all displays other than the first a zero width and height, but trying - // to attach a zero sized framebuffer to the display will result an error, so - // default to 640x480px. - adapter.displays.push(Display { - width: 640, - height: 480, - active_resource: None, - }); - } else { - adapter.displays.push(Display { - width: info.rect.width, - height: info.rect.height, - active_resource: None, - }); - } - } + adapter.update_displays(config).await?; let scheme = GraphicsScheme::new(adapter, "display.virtio-gpu".to_owned()); let handle = DisplayHandle::new("virtio-gpu").unwrap(); diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index b2782bdc5c..5f3ecaa91f 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -492,6 +492,12 @@ pub trait Transport: Sync + Send { self.insert_status(DeviceStatusFlags::DRIVER_OK); } + /// Request to be notified on configuration changes on the given MSI-X vector. + fn setup_config_notify(&self, vector: u16); + + /// Each time the device configuration changes this number will be updated. + fn config_generation(&self) -> u32; + /// Creates a new queue. /// /// ## Panics @@ -601,6 +607,14 @@ impl Transport for StandardTransport<'_> { assert!((confirm & DeviceStatusFlags::FEATURES_OK) == DeviceStatusFlags::FEATURES_OK); } + fn setup_config_notify(&self, vector: u16) { + self.common.lock().unwrap().config_msix_vector.set(vector); + } + + fn config_generation(&self) -> u32 { + u32::from(self.common.lock().unwrap().config_generation.get()) + } + fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result, Error> { let mut common = self.common.lock().unwrap(); From 4f7b0eb6b61f40855b0a93742c8fd59c81743ef4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 2 Jul 2025 15:30:11 +0200 Subject: [PATCH 1209/1301] graphics: Introduce a new graphics api This allows page flipping and handling display resizing. Hardware cursors and getting notifications about display resizing are not yet supported. --- graphics/driver-graphics/src/lib.rs | 200 +++++++++++++++++++++++++--- graphics/graphics-ipc/src/lib.rs | 1 + graphics/graphics-ipc/src/v2.rs | 179 +++++++++++++++++++++++++ graphics/virtio-gpud/src/main.rs | 1 + inputd/src/lib.rs | 29 ++++ 5 files changed, 393 insertions(+), 17 deletions(-) create mode 100644 graphics/graphics-ipc/src/v2.rs diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 94860f3103..e9971323fb 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -1,5 +1,8 @@ +#![feature(slice_as_array)] + use std::collections::{BTreeMap, HashMap}; use std::io; +use std::mem::transmute; use std::sync::Arc; use graphics_ipc::v1::{CursorDamage, Damage}; @@ -8,7 +11,7 @@ use libredox::Fd; use redox_scheme::scheme::SchemeSync; use redox_scheme::{CallerCtx, OpenResult, RequestKind, SignalBehavior, Socket}; use syscall::schemev2::NewFdFlags; -use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL}; +use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL, ENOENT, EOPNOTSUPP}; pub trait GraphicsAdapter { type Framebuffer: Framebuffer; @@ -52,7 +55,7 @@ pub struct GraphicsScheme { scheme_name: String, socket: Socket, next_id: usize, - handles: BTreeMap, + handles: BTreeMap>, active_vt: usize, vts: HashMap>, @@ -63,8 +66,16 @@ struct VtState { cursor_plane: Option>, } -enum Handle { - V1Screen { vt: usize, screen: usize }, +enum Handle { + V1Screen { + vt: usize, + screen: usize, + }, + V2 { + vt: usize, + next_id: usize, + fbs: HashMap>, + }, } impl GraphicsScheme { @@ -100,6 +111,8 @@ impl GraphicsScheme { VtEventKind::Activate => { log::info!("activate {}", vt_event.vt); + self.active_vt = vt_event.vt; + let vt_state = Self::get_or_create_vt(&mut self.adapter, &mut self.vts, vt_event.vt); @@ -110,8 +123,6 @@ impl GraphicsScheme { if let Some(cursor_plane) = &vt_state.cursor_plane { self.adapter.handle_cursor(cursor_plane, true); } - - self.active_vt = vt_event.vt; } VtEventKind::Resize => { @@ -120,6 +131,10 @@ impl GraphicsScheme { } } + pub fn notify_displays_changed(&mut self) { + // FIXME notify clients + } + /// Process new scheme requests. /// /// This needs to be called each time there is a new event on the scheme @@ -200,22 +215,40 @@ impl SchemeSync for GraphicsScheme { return Err(Error::new(EINVAL)); } - let mut parts = path.split('/'); - let mut screen = parts.next().unwrap_or("").split('.'); + let handle = if path.starts_with("v") { + if !path.starts_with("v2/") { + return Err(Error::new(ENOENT)); + } + let vt = path["v2/".len()..] + .parse::() + .map_err(|_| Error::new(EINVAL))?; - let vt = screen.next().unwrap_or("").parse::().unwrap(); - let id = screen.next().unwrap_or("").parse::().unwrap_or(0); + // Ensure the VT exists such that the rest of the methods can freely access it. + Self::get_or_create_vt(&mut self.adapter, &mut self.vts, vt); - if id >= self.adapter.display_count() { - return Err(Error::new(EINVAL)); - } + Handle::V2 { + vt, + next_id: 0, + fbs: HashMap::new(), + } + } else { + let mut parts = path.split('/'); + let mut screen = parts.next().unwrap_or("").split('.'); - // Ensure the VT exists such that the rest of the methods can freely access it. - Self::get_or_create_vt(&mut self.adapter, &mut self.vts, vt); + let vt = screen.next().unwrap_or("").parse::().unwrap(); + let id = screen.next().unwrap_or("").parse::().unwrap_or(0); + if id >= self.adapter.display_count() { + return Err(Error::new(EINVAL)); + } + + // Ensure the VT exists such that the rest of the methods can freely access it. + Self::get_or_create_vt(&mut self.adapter, &mut self.vts, vt); + + Handle::V1Screen { vt, screen: id } + }; self.next_id += 1; - self.handles - .insert(self.next_id, Handle::V1Screen { vt, screen: id }); + self.handles.insert(self.next_id, handle); Ok(OpenResult::ThisScheme { number: self.next_id, flags: NewFdFlags::empty(), @@ -233,6 +266,11 @@ impl SchemeSync for GraphicsScheme { framebuffer.height() ) } + Handle::V2 { + vt, + next_id: _, + fbs: _, + } => format!("/scheme/{}/v2/{vt}", self.scheme_name), }; buf[..path.len()].copy_from_slice(path.as_bytes()); Ok(path.len()) @@ -253,6 +291,7 @@ impl SchemeSync for GraphicsScheme { ); Ok(()) } + Handle::V2 { .. } => Err(Error::new(EOPNOTSUPP)), } } @@ -276,6 +315,7 @@ impl SchemeSync for GraphicsScheme { Ok(1) } + Handle::V2 { .. } => Err(Error::new(EOPNOTSUPP)), } } @@ -354,6 +394,122 @@ impl SchemeSync for GraphicsScheme { Ok(buf.len()) } + Handle::V2 { .. } => Err(Error::new(EOPNOTSUPP)), + } + } + + fn call(&mut self, id: usize, payload: &mut [u8], metadata: &[u64]) -> Result { + use graphics_ipc::v2::ipc; + + match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? { + Handle::V1Screen { .. } => { + return Err(Error::new(EOPNOTSUPP)); + } + Handle::V2 { vt, next_id, fbs } => match metadata[0] { + ipc::DISPLAY_COUNT => { + if payload.len() < size_of::() { + return Err(Error::new(EINVAL)); + } + let payload = unsafe { + transmute::<&mut [u8; size_of::()], &mut ipc::DisplayCount>( + payload.as_mut_array().unwrap(), + ) + }; + payload.count = self.adapter.display_count(); + Ok(size_of::()) + } + ipc::DISPLAY_SIZE => { + if payload.len() < size_of::() { + return Err(Error::new(EINVAL)); + } + let payload = unsafe { + transmute::<&mut [u8; size_of::()], &mut ipc::DisplaySize>( + payload.as_mut_array().unwrap(), + ) + }; + let display_id = payload.display_id; + if display_id >= self.adapter.display_count() { + return Err(Error::new(EINVAL)); + } + let (width, height) = self.adapter.display_size(display_id); + payload.width = width; + payload.height = height; + Ok(size_of::()) + } + ipc::CREATE_DUMB_FRAMEBUFFER => { + if payload.len() < size_of::() { + return Err(Error::new(EINVAL)); + } + let payload = unsafe { + transmute::< + &mut [u8; size_of::()], + &mut ipc::CreateDumbFramebuffer, + >(payload.as_mut_array().unwrap()) + }; + + let fb = self + .adapter + .create_dumb_framebuffer(payload.width, payload.height); + + *next_id += 1; + fbs.insert(*next_id, Arc::new(fb)); + payload.fb_id = *next_id; + Ok(size_of::()) + } + ipc::DUMB_FRAMEBUFFER_MAP_OFFSET => { + if payload.len() < size_of::() { + return Err(Error::new(EINVAL)); + } + let payload = unsafe { + transmute::< + &mut [u8; size_of::()], + &mut ipc::DumbFramebufferMapOffset, + >(payload.as_mut_array().unwrap()) + }; + + let fb_id = payload.fb_id; + + if !fbs.contains_key(&fb_id) { + return Err(Error::new(EINVAL)); + } + + // FIXME use a better scheme for creating map offsets + assert!(fbs[&fb_id].width() * fbs[&fb_id].height() * 4 < 0x1_000_000); + + payload.offset = fb_id * 0x10_000_000; + + Ok(size_of::()) + } + ipc::UPDATE_PLANE => { + if payload.len() < size_of::() { + return Err(Error::new(EINVAL)); + } + let payload = unsafe { + transmute::<&mut [u8; size_of::()], &mut ipc::UpdatePlane>( + payload.as_mut_array().unwrap(), + ) + }; + + let display_id = payload.display_id; + if display_id >= self.adapter.display_count() { + return Err(Error::new(EINVAL)); + } + + let Some(framebuffer) = fbs.get(&{ payload.fb_id }) else { + return Err(Error::new(EINVAL)); + }; + + self.vts.get_mut(vt).unwrap().display_fbs[display_id] = framebuffer.clone(); + + if *vt == self.active_vt { + self.adapter + .update_plane(display_id, framebuffer, payload.damage); + } + + Ok(size_of::()) + } + _ => return Err(Error::new(EINVAL)), + }, } } @@ -368,6 +524,16 @@ impl SchemeSync for GraphicsScheme { // log::trace!("KSMSG MMAP {} {:?} {} {}", id, _flags, _offset, _size); let (framebuffer, offset) = match self.handles.get(&id).ok_or(Error::new(EINVAL))? { Handle::V1Screen { vt, screen } => (&self.vts[vt].display_fbs[*screen], offset), + Handle::V2 { + vt: _, + next_id: _, + fbs, + } => ( + fbs.get(&(offset as usize / 0x10_000_000)) + .ok_or(Error::new(EINVAL)) + .unwrap(), + offset & (0x10_000_000 - 1), + ), }; let ptr = T::map_dumb_framebuffer(&mut self.adapter, framebuffer); Ok(unsafe { ptr.add(offset as usize) } as usize) diff --git a/graphics/graphics-ipc/src/lib.rs b/graphics/graphics-ipc/src/lib.rs index 99b52a835b..ed4b73a675 100644 --- a/graphics/graphics-ipc/src/lib.rs +++ b/graphics/graphics-ipc/src/lib.rs @@ -1,2 +1,3 @@ mod common; pub mod v1; +pub mod v2; diff --git a/graphics/graphics-ipc/src/v2.rs b/graphics/graphics-ipc/src/v2.rs new file mode 100644 index 0000000000..fa316d96b0 --- /dev/null +++ b/graphics/graphics-ipc/src/v2.rs @@ -0,0 +1,179 @@ +use std::fs::File; +use std::os::unix::io::AsRawFd; +use std::{io, mem, ptr}; + +use libredox::flag; + +pub use crate::common::{Damage, DisplayMap}; + +extern "C" { + fn redox_sys_call_v0( + fd: usize, + payload: *mut u8, + payload_len: usize, + flags: usize, + metadata: *const u64, + metadata_len: usize, + ) -> usize; +} + +unsafe fn sys_call( + fd: &impl AsRawFd, + payload: &mut T, + flags: usize, + metadata: &[u64], +) -> libredox::error::Result { + libredox::error::Error::demux(redox_sys_call_v0( + fd.as_raw_fd() as usize, + payload as *mut T as *mut u8, + mem::size_of::(), + flags, + metadata.as_ptr(), + metadata.len(), + )) +} + +/// A graphics handle using the (currently unstable) v2 graphics API. +/// +/// The v2 graphics API allows creating framebuffers on the fly, using them for page flipping and +/// handles all displays using a single fd. +pub struct V2GraphicsHandle { + file: File, +} + +impl V2GraphicsHandle { + pub fn from_file(file: File) -> io::Result { + Ok(V2GraphicsHandle { file }) + } + + pub fn display_count(&self) -> io::Result { + let mut cmd = ipc::DisplayCount { count: 0 }; + unsafe { + sys_call(&self.file, &mut cmd, 0, &[ipc::DISPLAY_COUNT, 0, 0])?; + } + Ok(cmd.count) + } + + pub fn display_size(&self, id: usize) -> io::Result<(u32, u32)> { + let mut cmd = ipc::DisplaySize { + display_id: id, + width: 0, + height: 0, + }; + unsafe { + sys_call(&self.file, &mut cmd, 0, &[ipc::DISPLAY_SIZE, 0, 0])?; + } + Ok((cmd.width, cmd.height)) + } + + pub fn create_dumb_framebuffer(&self, width: u32, height: u32) -> io::Result { + let mut cmd = ipc::CreateDumbFramebuffer { + width, + height, + + fb_id: 0, + }; + unsafe { + sys_call( + &self.file, + &mut cmd, + 0, + &[ipc::CREATE_DUMB_FRAMEBUFFER, 0, 0], + )?; + } + Ok(cmd.fb_id) + } + + pub fn map_dumb_framebuffer( + &self, + id: usize, + width: u32, + height: u32, + ) -> io::Result { + let mut cmd = ipc::DumbFramebufferMapOffset { + fb_id: id, + offset: 0, + }; + unsafe { + sys_call( + &self.file, + &mut cmd, + 0, + &[ipc::DUMB_FRAMEBUFFER_MAP_OFFSET, 0, 0], + )?; + } + + let display_ptr = unsafe { + libredox::call::mmap(libredox::call::MmapArgs { + fd: self.file.as_raw_fd() as usize, + offset: cmd.offset as u64, + length: (width * height * 4) as usize, + prot: flag::PROT_READ | flag::PROT_WRITE, + flags: flag::MAP_SHARED, + addr: core::ptr::null_mut(), + })? + }; + let offscreen = ptr::slice_from_raw_parts_mut( + display_ptr as *mut u32, + width as usize * height as usize, + ); + + Ok(unsafe { DisplayMap::new(offscreen, width as usize, height as usize) }) + } + + pub fn update_plane(&self, display_id: usize, fb_id: usize, damage: Damage) -> io::Result<()> { + let mut cmd = ipc::UpdatePlane { + display_id, + fb_id, + damage, + }; + unsafe { + sys_call(&self.file, &mut cmd, 0, &[ipc::UPDATE_PLANE, 0, 0])?; + } + Ok(()) + } +} + +pub mod ipc { + use crate::common::Damage; + + pub const DISPLAY_COUNT: u64 = 1; + #[repr(C, packed)] + pub struct DisplayCount { + pub count: usize, + } + + pub const DISPLAY_SIZE: u64 = 2; + #[repr(C, packed)] + pub struct DisplaySize { + pub display_id: usize, + + pub width: u32, + pub height: u32, + } + + pub const CREATE_DUMB_FRAMEBUFFER: u64 = 3; + #[repr(C, packed)] + pub struct CreateDumbFramebuffer { + pub width: u32, + pub height: u32, + + pub fb_id: usize, + } + + pub const DUMB_FRAMEBUFFER_MAP_OFFSET: u64 = 4; + #[repr(C, packed)] + pub struct DumbFramebufferMapOffset { + pub fb_id: usize, + + pub offset: usize, + } + + pub const UPDATE_PLANE: u64 = 5; + #[repr(C, packed)] + pub struct UpdatePlane { + pub display_id: usize, + pub fb_id: usize, + pub damage: Damage, + } +} diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index ff04932dff..4b9654fe17 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -528,6 +528,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { if events & VIRTIO_GPU_EVENT_DISPLAY != 0 { futures::executor::block_on(scheme.adapter_mut().update_displays(config)) .unwrap(); + scheme.notify_displays_changed(); config.events_clear.set(VIRTIO_GPU_EVENT_DISPLAY); } diff --git a/inputd/src/lib.rs b/inputd/src/lib.rs index 0a2559beb9..e7e7e47fa7 100644 --- a/inputd/src/lib.rs +++ b/inputd/src/lib.rs @@ -3,6 +3,7 @@ use std::io::{self, Read, Write}; use std::mem::size_of; use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd}; use std::os::unix::fs::OpenOptionsExt; +use std::path::PathBuf; use std::slice; use libredox::flag::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; @@ -71,6 +72,34 @@ impl ConsumerHandle { Ok(display_file) } + pub fn open_display_v2(&self) -> io::Result { + let mut buffer = [0; 1024]; + let fd = self.0.as_raw_fd(); + let written = libredox::call::fpath(fd as usize, &mut buffer)?; + + assert!(written <= buffer.len()); + + let mut display_path = PathBuf::from( + std::str::from_utf8(&buffer[..written]) + .expect("init: display path UTF-8 check failed") + .to_owned(), + ); + display_path.set_file_name(format!( + "v2/{}", + display_path.file_name().unwrap().to_str().unwrap() + )); + let display_path = display_path.to_str().unwrap(); + + let display_file = + libredox::call::open(&display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) + .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) + .unwrap_or_else(|err| { + panic!("failed to open display {}: {}", display_path, err); + }); + + Ok(display_file) + } + pub fn read_events<'a>(&self, events: &'a mut [Event]) -> io::Result> { match read_to_slice(self.0.as_fd(), events) { Ok(count) => Ok(ConsumerHandleEvent::Events(&events[..count])), From cc0db37209528493973d4dc5d2f281ad7a3d436d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 2 Jul 2025 15:37:35 +0200 Subject: [PATCH 1210/1301] graphics/fbbootlogd: Use the new graphics api --- graphics/console-draw/src/lib.rs | 33 +++++++++++++++ graphics/fbbootlogd/src/scheme.rs | 70 ++++++++++++++++++++++++++++--- 2 files changed, 97 insertions(+), 6 deletions(-) diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index 2cf93db76c..b1551d9c79 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -226,4 +226,37 @@ impl TextScreen { damage } + + pub fn resize(&mut self, old_map: &mut DisplayMap, new_map: &mut DisplayMap) { + // FIXME fold row when target is narrower and maybe unfold when it is wider + fn copy_row( + old_map: &mut DisplayMap, + new_map: &mut DisplayMap, + from_row: usize, + to_row: usize, + ) { + for x in 0..cmp::min(old_map.width, new_map.width) { + let old_idx = from_row * old_map.width + x; + let new_idx = to_row * new_map.width + x; + unsafe { + (*new_map.offscreen)[new_idx] = (*old_map.offscreen)[old_idx]; + } + } + } + + if new_map.height >= old_map.height { + for row in 0..old_map.height { + copy_row(old_map, new_map, row, row); + } + } else { + let deleted_rows = (old_map.height - new_map.height).div_ceil(16); + for row in 0..new_map.height { + if row + (deleted_rows + 1) * 16 >= old_map.height { + break; + } + copy_row(old_map, new_map, row + deleted_rows * 16, row); + } + self.console.state.y = self.console.state.y.saturating_sub(deleted_rows); + } + } } diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 17166c43af..647999fb3b 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -1,12 +1,15 @@ use std::collections::VecDeque; +use std::ptr; -use graphics_ipc::v1::V1GraphicsHandle; +use console_draw::TextScreen; +use graphics_ipc::v2::V2GraphicsHandle; use inputd::ConsumerHandle; use redox_scheme::Scheme; use syscall::{Error, Result, EINVAL, ENOENT}; pub struct DisplayMap { - display_handle: V1GraphicsHandle, + display_handle: V2GraphicsHandle, + fb: usize, inner: graphics_ipc::v1::DisplayMap, } @@ -30,18 +33,24 @@ impl FbbootlogScheme { } pub fn handle_handoff(&mut self) { - let new_display_handle = match self.input_handle.open_display() { - Ok(display) => V1GraphicsHandle::from_file(display).unwrap(), + let new_display_handle = match self.input_handle.open_display_v2() { + Ok(display) => V2GraphicsHandle::from_file(display).unwrap(), Err(err) => { eprintln!("fbbootlogd: No display present yet: {err}"); return; } }; - match new_display_handle.map_display() { + let (width, height) = new_display_handle.display_size(0).unwrap(); + let fb = new_display_handle + .create_dumb_framebuffer(width, height) + .unwrap(); + + match new_display_handle.map_dumb_framebuffer(fb, width, height) { Ok(display_map) => { self.display_map = Some(DisplayMap { display_handle: new_display_handle, + fb, inner: display_map, }); @@ -52,6 +61,53 @@ impl FbbootlogScheme { } } } + + fn handle_resize(map: &mut DisplayMap, text_screen: &mut TextScreen) { + let (width, height) = match map.display_handle.display_size(0) { + Ok((width, height)) => (width, height), + Err(err) => { + eprintln!("fbbootlogd: failed to get display size: {}", err); + (map.inner.width() as u32, map.inner.height() as u32) + } + }; + + if width as usize != map.inner.width() || height as usize != map.inner.height() { + match map.display_handle.create_dumb_framebuffer(width, height) { + Ok(fb) => match map.display_handle.map_dumb_framebuffer(fb, width, height) { + Ok(mut new_map) => { + let count = new_map.ptr().len(); + unsafe { + ptr::write_bytes(new_map.ptr_mut() as *mut u32, 0, count); + } + + text_screen.resize( + &mut console_draw::DisplayMap { + offscreen: map.inner.ptr_mut(), + width: map.inner.width(), + height: map.inner.height(), + }, + &mut console_draw::DisplayMap { + offscreen: new_map.ptr_mut(), + width: new_map.width(), + height: new_map.height(), + }, + ); + + map.fb = fb; + map.inner = new_map; + + eprintln!("fbbootlogd: mapped display"); + } + Err(err) => { + eprintln!("fbbootlogd: failed to open display: {}", err); + } + }, + Err(err) => { + eprintln!("fbbootlogd: failed to create framebuffer: {}", err); + } + } + } + } } impl Scheme for FbbootlogScheme { @@ -91,6 +147,8 @@ impl Scheme for FbbootlogScheme { fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { if let Some(map) = &mut self.display_map { + Self::handle_resize(map, &mut self.text_screen); + let damage = self.text_screen.write( &mut console_draw::DisplayMap { offscreen: map.inner.ptr_mut(), @@ -102,7 +160,7 @@ impl Scheme for FbbootlogScheme { ); if let Some(map) = &self.display_map { - map.display_handle.sync_rect(damage).unwrap(); + map.display_handle.update_plane(0, map.fb, damage).unwrap(); } } From a261f1257dbe7b6b54cae758b56497256eb314f5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 3 Jul 2025 20:56:10 +0200 Subject: [PATCH 1211/1301] graphics/virtio-gpud: Destroy virtio-gpu resource before freeing fb memory This fixes a gpu side use-after-free. --- graphics/virtio-gpud/src/scheme.rs | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/graphics/virtio-gpud/src/scheme.rs b/graphics/virtio-gpud/src/scheme.rs index c6656c5398..34159dac3f 100644 --- a/graphics/virtio-gpud/src/scheme.rs +++ b/graphics/virtio-gpud/src/scheme.rs @@ -25,14 +25,15 @@ impl Into for Damage { } } -pub struct VirtGpuFramebuffer { +pub struct VirtGpuFramebuffer<'a> { + queue: Arc>, id: ResourceId, sgl: sgl::Sgl, width: u32, height: u32, } -impl Framebuffer for VirtGpuFramebuffer { +impl Framebuffer for VirtGpuFramebuffer<'_> { fn width(&self) -> u32 { self.width } @@ -42,6 +43,22 @@ impl Framebuffer for VirtGpuFramebuffer { } } +impl Drop for VirtGpuFramebuffer<'_> { + fn drop(&mut self) { + futures::executor::block_on(async { + let request = Dma::new(ResourceUnref::new(self.id)).unwrap(); + + let header = Dma::new(ControlHeader::default()).unwrap(); + let command = ChainBuilder::new() + .chain(Buffer::new(&request)) + .chain(Buffer::new(&header).flags(DescriptorFlags::WRITE_ONLY)) + .build(); + + self.queue.send(command).await; + }); + } +} + pub struct VirtGpuCursor { resource_id: ResourceId, sgl: sgl::Sgl, @@ -179,8 +196,8 @@ impl VirtGpuAdapter<'_> { } } -impl GraphicsAdapter for VirtGpuAdapter<'_> { - type Framebuffer = VirtGpuFramebuffer; +impl<'a> GraphicsAdapter for VirtGpuAdapter<'a> { + type Framebuffer = VirtGpuFramebuffer<'a>; type Cursor = VirtGpuCursor; fn display_count(&self) -> usize { @@ -244,6 +261,7 @@ impl GraphicsAdapter for VirtGpuAdapter<'_> { assert_eq!(header.ty, CommandTy::RespOkNodata); VirtGpuFramebuffer { + queue: self.control_queue.clone(), id: res_id, sgl, width, From 04ae0158c9b008f3e32b88aaf8ab0f80a0d7904d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 14 Mar 2025 21:50:45 +0100 Subject: [PATCH 1212/1301] Update most crates to redox-scheme 0.6 A couple of crates need to stay on redox-scheme 0.4 as they need cancellation for async schemes. --- Cargo.lock | 24 +++++++--------------- acpid/Cargo.toml | 2 +- acpid/src/main.rs | 2 +- acpid/src/scheme.rs | 29 ++++++++++++++++++++------- graphics/bgad/Cargo.toml | 2 +- graphics/bgad/src/main.rs | 4 ++-- graphics/bgad/src/scheme.rs | 33 +++++++++++++++++++++---------- graphics/fbbootlogd/Cargo.toml | 2 +- graphics/fbbootlogd/src/main.rs | 4 ++-- graphics/fbbootlogd/src/scheme.rs | 29 +++++++++++++++++++-------- inputd/Cargo.toml | 2 +- inputd/src/main.rs | 30 ++++++++++++++++++++-------- pcid/Cargo.toml | 2 +- pcid/src/main.rs | 4 ++-- pcid/src/scheme.rs | 21 ++++++++++++++------ storage/driver-block/Cargo.toml | 2 +- xhcid/Cargo.toml | 2 +- xhcid/src/main.rs | 2 +- xhcid/src/xhci/scheme.rs | 31 +++++++++++++++++++++-------- 19 files changed, 148 insertions(+), 79 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce7c05e14d..0d927e43bf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,7 +32,7 @@ dependencies = [ "parking_lot 0.12.3", "plain", "redox-daemon", - "redox-scheme 0.4.0", + "redox-scheme 0.6.2", "redox_event", "redox_syscall", "ron", @@ -187,7 +187,7 @@ dependencies = [ "orbclient", "pcid", "redox-daemon", - "redox-scheme 0.4.0", + "redox-scheme 0.6.2", "redox_syscall", ] @@ -391,7 +391,7 @@ dependencies = [ "log", "partitionlib", "redox-daemon", - "redox-scheme 0.5.0", + "redox-scheme 0.6.2", "redox_syscall", ] @@ -457,7 +457,7 @@ dependencies = [ "orbclient", "ransid", "redox-daemon", - "redox-scheme 0.4.0", + "redox-scheme 0.6.2", "redox_event", "redox_syscall", ] @@ -729,7 +729,7 @@ dependencies = [ "log", "orbclient", "redox-daemon", - "redox-scheme 0.4.0", + "redox-scheme 0.6.2", "redox_syscall", ] @@ -977,7 +977,7 @@ dependencies = [ "pico-args", "plain", "redox-daemon", - "redox-scheme 0.4.0", + "redox-scheme 0.6.2", "redox_syscall", "serde", ] @@ -1143,16 +1143,6 @@ dependencies = [ "redox_syscall", ] -[[package]] -name = "redox-scheme" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96b9cfb034251dfb0aaa66a67059a7f0ea344039904d1d70cd36266af9c8a2f" -dependencies = [ - "libredox", - "redox_syscall", -] - [[package]] name = "redox-scheme" version = "0.6.2" @@ -2041,7 +2031,7 @@ dependencies = [ "pcid", "plain", "redox-daemon", - "redox-scheme 0.4.0", + "redox-scheme 0.6.2", "redox_event", "redox_syscall", "regex", diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index a7ee63043c..b704be076c 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -23,5 +23,5 @@ ron = "0.8.1" amlserde = { path = "../amlserde" } common = { path = "../common" } libredox = "0.1.3" -redox-scheme = "0.4" +redox-scheme = "0.6.2" arrayvec = "0.7.6" diff --git a/acpid/src/main.rs b/acpid/src/main.rs index d53ef51e76..aef18c2cb6 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -114,7 +114,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { match req.kind() { RequestKind::Call(call) => { - let response = call.handle_scheme(&mut scheme); + let response = call.handle_sync(&mut scheme); socket .write_response(response, SignalBehavior::Restart) .expect("acpid: failed to write response"); diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index a380a33dca..e744b5b257 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -1,6 +1,7 @@ use core::str; use parking_lot::RwLockReadGuard; -use redox_scheme::{CallerCtx, OpenResult, Scheme}; +use redox_scheme::scheme::SchemeSync; +use redox_scheme::{CallerCtx, OpenResult}; use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; @@ -141,8 +142,8 @@ fn parse_table(table: &[u8]) -> Option { }) } -impl Scheme for AcpiScheme<'_> { - fn xopen(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result { +impl SchemeSync for AcpiScheme<'_> { + fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result { let path = path.trim_start_matches('/'); let flag_stat = flags & O_STAT == O_STAT; @@ -218,7 +219,7 @@ impl Scheme for AcpiScheme<'_> { }) } - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { + fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?; stat.st_size = handle @@ -233,10 +234,17 @@ impl Scheme for AcpiScheme<'_> { stat.st_mode = MODE_FILE; } - Ok(0) + Ok(()) } - fn read(&mut self, id: usize, buf: &mut [u8], offset: u64, _fcntl: u32) -> Result { + fn read( + &mut self, + id: usize, + buf: &mut [u8], + offset: u64, + _fcntl: u32, + _ctx: &CallerCtx, + ) -> Result { let offset: usize = offset.try_into().map_err(|_| Error::new(EINVAL))?; let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; @@ -340,7 +348,14 @@ impl Scheme for AcpiScheme<'_> { Ok(buf) } - fn write(&mut self, _id: usize, _buf: &[u8], _offset: u64, _fcntl: u32) -> Result { + fn write( + &mut self, + _id: usize, + _buf: &[u8], + _offset: u64, + _fcntl: u32, + _ctx: &CallerCtx, + ) -> Result { Err(Error::new(EBADF)) } } diff --git a/graphics/bgad/Cargo.toml b/graphics/bgad/Cargo.toml index 894f414377..eb62538387 100644 --- a/graphics/bgad/Cargo.toml +++ b/graphics/bgad/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" [dependencies] orbclient = "0.3.47" redox-daemon = "0.1" -redox-scheme = "0.4" +redox-scheme = "0.6.2" redox_syscall = "0.5" common = { path = "../../common" } diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index c8d4e55c56..2d30ac4e1b 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -47,10 +47,10 @@ fn main() { }; match request.kind() { RequestKind::Call(call) => { - let response = call.handle_scheme(&mut scheme); + let response = call.handle_sync(&mut scheme); socket - .write_responses(&[response], SignalBehavior::Restart) + .write_response(response, SignalBehavior::Restart) .expect("bgad: failed to write next scheme response"); } RequestKind::OnClose { id } => { diff --git a/graphics/bgad/src/scheme.rs b/graphics/bgad/src/scheme.rs index 14ad5a6cb9..5cd214e91e 100644 --- a/graphics/bgad/src/scheme.rs +++ b/graphics/bgad/src/scheme.rs @@ -1,7 +1,9 @@ use inputd::ProducerHandle; -use redox_scheme::Scheme; +use redox_scheme::scheme::SchemeSync; +use redox_scheme::{CallerCtx, OpenResult}; use std::str; use syscall::data::Stat; +use syscall::schemev2::NewFdFlags; use syscall::{Error, Result, EACCES, EINVAL, MODE_CHR}; use crate::bga::Bga; @@ -25,10 +27,13 @@ impl BgaScheme { } } -impl Scheme for BgaScheme { - fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result { - if uid == 0 { - Ok(0) +impl SchemeSync for BgaScheme { + fn open(&mut self, _path: &str, _flags: usize, ctx: &CallerCtx) -> Result { + if ctx.uid == 0 { + Ok(OpenResult::ThisScheme { + number: 0, + flags: NewFdFlags::empty(), + }) } else { Err(Error::new(EACCES)) } @@ -40,6 +45,7 @@ impl Scheme for BgaScheme { buf: &mut [u8], _offset: u64, _fcntl_flags: u32, + _ctx: &CallerCtx, ) -> Result { let mut i = 0; let data = format!("{},{}\n", self.bga.width(), self.bga.height()).into_bytes(); @@ -50,7 +56,14 @@ impl Scheme for BgaScheme { Ok(i) } - fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { + fn write( + &mut self, + _id: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> Result { let string = str::from_utf8(buf).or(Err(Error::new(EINVAL)))?; let string = string.trim(); @@ -75,7 +88,7 @@ impl Scheme for BgaScheme { Ok(buf.len()) } - fn fpath(&mut self, _file: usize, buf: &mut [u8]) -> Result { + fn fpath(&mut self, _file: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { let mut i = 0; let scheme_path = b"bga"; while i < buf.len() && i < scheme_path.len() { @@ -85,16 +98,16 @@ impl Scheme for BgaScheme { Ok(i) } - fn fstat(&mut self, _id: usize, stat: &mut Stat) -> Result { + fn fstat(&mut self, _id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { *stat = Stat { st_mode: MODE_CHR | 0o666, ..Default::default() }; - Ok(0) + Ok(()) } - fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize) -> Result { + fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result { Ok(0) } } diff --git a/graphics/fbbootlogd/Cargo.toml b/graphics/fbbootlogd/Cargo.toml index a4707c8640..4652dce682 100644 --- a/graphics/fbbootlogd/Cargo.toml +++ b/graphics/fbbootlogd/Cargo.toml @@ -9,7 +9,7 @@ ransid = "0.4" redox_event = "0.4" redox_syscall = "0.5" redox-daemon = "0.1" -redox-scheme = "0.4" +redox-scheme = "0.6.2" console-draw = { path = "../console-draw" } graphics-ipc = { path = "../graphics-ipc" } diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index cfd0ce59b1..b2f723ba3f 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -85,10 +85,10 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { match request.kind() { RequestKind::Call(call) => { - let response = call.handle_scheme(&mut scheme); + let response = call.handle_sync(&mut scheme); socket - .write_responses(&[response], SignalBehavior::Restart) + .write_response(response, SignalBehavior::Restart) .expect("pcid: failed to write next scheme response"); } RequestKind::OnClose { id } => { diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 647999fb3b..1cf2f21cf2 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -4,7 +4,9 @@ use std::ptr; use console_draw::TextScreen; use graphics_ipc::v2::V2GraphicsHandle; use inputd::ConsumerHandle; -use redox_scheme::Scheme; +use redox_scheme::scheme::SchemeSync; +use redox_scheme::{CallerCtx, OpenResult}; +use syscall::schemev2::NewFdFlags; use syscall::{Error, Result, EINVAL, ENOENT}; pub struct DisplayMap { @@ -110,16 +112,19 @@ impl FbbootlogScheme { } } -impl Scheme for FbbootlogScheme { - fn open(&mut self, path_str: &str, _flags: usize, _uid: u32, _gid: u32) -> Result { +impl SchemeSync for FbbootlogScheme { + fn open(&mut self, path_str: &str, _flags: usize, _ctx: &CallerCtx) -> Result { if !path_str.is_empty() { return Err(Error::new(ENOENT)); } - Ok(0) + Ok(OpenResult::ThisScheme { + number: 0, + flags: NewFdFlags::empty(), + }) } - fn fpath(&mut self, _id: usize, buf: &mut [u8]) -> Result { + fn fpath(&mut self, _id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { let path = b"fbbootlog:"; let mut i = 0; @@ -131,8 +136,8 @@ impl Scheme for FbbootlogScheme { Ok(i) } - fn fsync(&mut self, _id: usize) -> Result { - Ok(0) + fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> { + Ok(()) } fn read( @@ -141,11 +146,19 @@ impl Scheme for FbbootlogScheme { _buf: &mut [u8], _offset: u64, _fcntl_flags: u32, + _ctx: &CallerCtx, ) -> Result { Err(Error::new(EINVAL)) } - fn write(&mut self, _id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { + fn write( + &mut self, + _id: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> Result { if let Some(map) = &mut self.display_map { Self::handle_resize(map, &mut self.text_screen); diff --git a/inputd/Cargo.toml b/inputd/Cargo.toml index cf1de6546e..20ccff318a 100644 --- a/inputd/Cargo.toml +++ b/inputd/Cargo.toml @@ -13,4 +13,4 @@ orbclient = "0.3.27" libredox = "0.1.3" common = { path = "../common" } -redox-scheme = "0.4" +redox-scheme = "0.6.2" diff --git a/inputd/src/main.rs b/inputd/src/main.rs index d69aa81ef5..4b8646f4c5 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -19,9 +19,11 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use inputd::{VtActivate, VtEvent, VtEventKind}; use libredox::errno::ESTALE; -use redox_scheme::{RequestKind, Scheme, SignalBehavior, Socket}; +use redox_scheme::scheme::SchemeSync; +use redox_scheme::{CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket}; use orbclient::{Event, EventOption}; +use syscall::schemev2::NewFdFlags; use syscall::{Error as SysError, EventFlags, EINVAL}; enum Handle { @@ -121,8 +123,8 @@ impl InputScheme { } } -impl Scheme for InputScheme { - fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result { +impl SchemeSync for InputScheme { + fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> syscall::Result { let mut path_parts = path.split('/'); let command = path_parts.next().ok_or(SysError::new(EINVAL))?; @@ -211,10 +213,13 @@ impl Scheme for InputScheme { log::info!("inputd: {path} channel has been opened"); self.handles.insert(fd, handle_ty); - Ok(fd) + Ok(OpenResult::ThisScheme { + number: fd, + flags: NewFdFlags::empty(), + }) } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result { + fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> syscall::Result { let handle = self.handles.get(&id).ok_or(SysError::new(EINVAL))?; if let Handle::Consumer { vt, .. } = handle { @@ -236,6 +241,7 @@ impl Scheme for InputScheme { buf: &mut [u8], _offset: u64, _fcntl_flags: u32, + _ctx: &CallerCtx, ) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; @@ -294,6 +300,7 @@ impl Scheme for InputScheme { buf: &[u8], _offset: u64, _fcntl_flags: u32, + _ctx: &CallerCtx, ) -> syscall::Result { self.has_new_events = true; @@ -429,6 +436,7 @@ impl Scheme for InputScheme { &mut self, id: usize, flags: syscall::EventFlags, + _ctx: &CallerCtx, ) -> syscall::Result { let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?; @@ -496,7 +504,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { match request.kind() { RequestKind::Call(call_request) => { socket_file.write_response( - call_request.handle_scheme(&mut scheme), + call_request.handle_sync(&mut scheme), SignalBehavior::Restart, )?; } @@ -527,7 +535,10 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } // Notify the consumer that we have some events to read. Yum yum. - socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?; + socket_file.write_response( + Response::post_fevent(*id, EventFlags::EVENT_READ.bits()), + SignalBehavior::Restart, + )?; *notified = true; } @@ -542,7 +553,10 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> { } // Notify the consumer that we have some events to read. Yum yum. - socket_file.post_fevent(*id, EventFlags::EVENT_READ.bits())?; + socket_file.write_response( + Response::post_fevent(*id, EventFlags::EVENT_READ.bits()), + SignalBehavior::Restart, + )?; *notified = true; } diff --git a/pcid/Cargo.toml b/pcid/Cargo.toml index 78f0192346..45261f838b 100644 --- a/pcid/Cargo.toml +++ b/pcid/Cargo.toml @@ -20,7 +20,7 @@ pci_types = "0.10" pico-args = { version = "0.5", features = ["combined-flags"] } plain = "0.2" redox-daemon = "0.1" -redox-scheme = "0.4" +redox-scheme = "0.6.2" redox_syscall = "0.5.9" serde = { version = "1", features = ["derive"] } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 3545c800f9..2035ac497b 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -223,10 +223,10 @@ fn main_inner(daemon: redox_daemon::Daemon) -> ! { }; match request.kind() { RequestKind::Call(call) => { - let response = call.handle_scheme(&mut scheme); + let response = call.handle_sync(&mut scheme); socket - .write_responses(&[response], SignalBehavior::Restart) + .write_response(response, SignalBehavior::Restart) .expect("pcid: failed to write next scheme response"); } RequestKind::OnClose { id } => { diff --git a/pcid/src/scheme.rs b/pcid/src/scheme.rs index cee1fc7a11..135a067b73 100644 --- a/pcid/src/scheme.rs +++ b/pcid/src/scheme.rs @@ -1,7 +1,8 @@ use std::collections::{BTreeMap, VecDeque}; use pci_types::PciAddress; -use redox_scheme::{CallerCtx, OpenResult, Scheme}; +use redox_scheme::scheme::SchemeSync; +use redox_scheme::{CallerCtx, OpenResult}; use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR}; use syscall::flag::{MODE_CHR, MODE_DIR, O_DIRECTORY, O_STAT}; @@ -45,8 +46,8 @@ enum ChannelState { const DEVICE_CONTENTS: &[&str] = &["channel"]; -impl Scheme for PciScheme { - fn xopen(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result { +impl SchemeSync for PciScheme { + fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result { log::trace!("OPEN `{}` flags {}", path, flags); // TODO: Check flags are correct @@ -97,7 +98,7 @@ impl Scheme for PciScheme { flags: NewFdFlags::POSITIONED, }) } - fn fstat(&mut self, id: usize, stat: &mut syscall::Stat) -> Result { + fn fstat(&mut self, id: usize, stat: &mut syscall::Stat, _ctx: &CallerCtx) -> Result<()> { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; let (len, mode) = match handle.inner { @@ -107,7 +108,7 @@ impl Scheme for PciScheme { }; stat.st_size = len as u64; stat.st_mode = mode; - Ok(0) + Ok(()) } fn read( &mut self, @@ -115,6 +116,7 @@ impl Scheme for PciScheme { buf: &mut [u8], _offset: u64, _fcntl_flags: u32, + _ctx: &CallerCtx, ) -> Result { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; @@ -174,7 +176,14 @@ impl Scheme for PciScheme { Ok(buf) } - fn write(&mut self, id: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { + fn write( + &mut self, + id: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> Result { let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; if handle.stat { diff --git a/storage/driver-block/Cargo.toml b/storage/driver-block/Cargo.toml index 8f465cd535..7a0b2a4029 100644 --- a/storage/driver-block/Cargo.toml +++ b/storage/driver-block/Cargo.toml @@ -15,4 +15,4 @@ futures = { version = "0.3.28", features = ["executor"] } redox-daemon = "0.1" redox_syscall = { version = "0.5", features = ["std"] } -redox-scheme = "0.5" +redox-scheme = "0.6.2" diff --git a/xhcid/Cargo.toml b/xhcid/Cargo.toml index 95eb88ddee..7f566ce208 100644 --- a/xhcid/Cargo.toml +++ b/xhcid/Cargo.toml @@ -21,7 +21,7 @@ lazy_static = "1.4" log = "0.4" redox-daemon = "0.1" redox_event = "0.4.1" -redox-scheme = "0.4" +redox-scheme = "0.6.2" redox_syscall = "0.5" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index a7a2d86e9a..800614e2e0 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -210,7 +210,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { match request.kind() { RequestKind::Call(call_request) => { - let resp = call_request.handle_scheme(&mut &*hci); + let resp = call_request.handle_sync(&mut &*hci); socket .write_response(resp, SignalBehavior::Restart) .expect("xhcid: failed to write scheme"); diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 29c5b58e08..12d77d39e3 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -25,10 +25,11 @@ use std::{cmp, fmt, io, mem, str}; use common::dma::Dma; use futures::executor::block_on; use log::{debug, error, info, trace, warn}; +use redox_scheme::scheme::SchemeSync; use smallvec::SmallVec; use common::io::Io; -use redox_scheme::{CallerCtx, OpenResult, Scheme}; +use redox_scheme::{CallerCtx, OpenResult}; use syscall::schemev2::NewFdFlags; use syscall::{ Error, Result, Stat, EACCES, EBADF, EBADFD, EBADMSG, EINVAL, EIO, EISDIR, ENOENT, ENOSYS, @@ -2098,8 +2099,8 @@ impl Xhci { } } -impl Scheme for &Xhci { - fn xopen(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result { +impl SchemeSync for &Xhci { + fn open(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result { if ctx.uid != 0 { return Err(Error::new(EACCES)); } @@ -2152,7 +2153,7 @@ impl Scheme for &Xhci { }) } - fn fstat(&mut self, id: usize, stat: &mut Stat) -> Result { + fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> { let guard = self.handles.get(&id).ok_or(Error::new(EBADF))?; stat.st_mode = match (&*guard).get_handle_type() { @@ -2174,10 +2175,10 @@ impl Scheme for &Xhci { _ => {} } - Ok(0) + Ok(()) } - fn fpath(&mut self, fd: usize, buffer: &mut [u8]) -> Result { + fn fpath(&mut self, fd: usize, buffer: &mut [u8], _ctx: &CallerCtx) -> Result { let mut cursor = io::Cursor::new(buffer); let guard = self.handles.get(&fd).ok_or(Error::new(EBADF))?; @@ -2195,7 +2196,14 @@ impl Scheme for &Xhci { Ok(src_len) } - fn read(&mut self, fd: usize, buf: &mut [u8], offset: u64, _fcntl_flags: u32) -> Result { + fn read( + &mut self, + fd: usize, + buf: &mut [u8], + offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> Result { let offset = offset as usize; let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; trace!( @@ -2258,7 +2266,14 @@ impl Scheme for &Xhci { } } } - fn write(&mut self, fd: usize, buf: &[u8], _offset: u64, _fcntl_flags: u32) -> Result { + fn write( + &mut self, + fd: usize, + buf: &[u8], + _offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> Result { let mut guard = self.handles.get_mut(&fd).ok_or(Error::new(EBADF))?; trace!( "WRITE fd={}, handle={:?}, buf=(addr {:p}, length {})", From e59d4ac7e1398ec4ada984bda7561714c2ed384f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 5 Jul 2025 15:21:40 +0200 Subject: [PATCH 1213/1301] graphics/vesad: Move FrameBuffer to scheme.rs --- graphics/vesad/src/framebuffer.rs | 59 ------------------------------ graphics/vesad/src/main.rs | 4 +-- graphics/vesad/src/scheme.rs | 60 +++++++++++++++++++++++++++++-- 3 files changed, 59 insertions(+), 64 deletions(-) delete mode 100644 graphics/vesad/src/framebuffer.rs diff --git a/graphics/vesad/src/framebuffer.rs b/graphics/vesad/src/framebuffer.rs deleted file mode 100644 index 7eeab2fe4d..0000000000 --- a/graphics/vesad/src/framebuffer.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::ptr; - -pub struct FrameBuffer { - pub onscreen: *mut [u32], - pub phys: usize, - pub width: usize, - pub height: usize, - pub stride: usize, -} - -impl FrameBuffer { - pub unsafe fn new(phys: usize, width: usize, height: usize, stride: usize) -> Self { - let size = stride * height; - let virt = common::physmap( - phys, - size * 4, - common::Prot { - read: true, - write: true, - }, - common::MemoryType::WriteCombining, - ) - .expect("vesad: failed to map framebuffer") as *mut u32; - - let onscreen = ptr::slice_from_raw_parts_mut(virt, size); - - Self { - onscreen, - phys, - width, - height, - stride, - } - } - - pub unsafe fn parse(var: &str) -> Option { - fn parse_number(part: &str) -> Option { - let (start, radix) = if part.starts_with("0x") { - (2, 16) - } else { - (0, 10) - }; - match usize::from_str_radix(&part[start..], radix) { - Ok(ok) => Some(ok), - Err(err) => { - eprintln!("vesad: failed to parse '{}': {}", part, err); - None - } - } - } - - let mut parts = var.split(','); - let phys = parse_number(parts.next()?)?; - let width = parse_number(parts.next()?)?; - let height = parse_number(parts.next()?)?; - let stride = parse_number(parts.next()?)?; - Some(Self::new(phys, width, height, stride)) - } -} diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index e107129af0..7549e86a93 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -9,10 +9,8 @@ use std::fs::File; use std::io::Write; use std::os::fd::AsRawFd; -use crate::framebuffer::FrameBuffer; -use crate::scheme::FbAdapter; +use crate::scheme::{FbAdapter, FrameBuffer}; -mod framebuffer; mod scheme; fn main() { diff --git a/graphics/vesad/src/scheme.rs b/graphics/vesad/src/scheme.rs index 63a83896c8..42e4054e41 100644 --- a/graphics/vesad/src/scheme.rs +++ b/graphics/vesad/src/scheme.rs @@ -6,8 +6,6 @@ use driver_graphics::{CursorFramebuffer, CursorPlane, Framebuffer, GraphicsAdapt use graphics_ipc::v1::Damage; use syscall::PAGE_SIZE; -use crate::framebuffer::FrameBuffer; - pub struct FbAdapter { pub framebuffers: Vec, } @@ -60,6 +58,64 @@ impl GraphicsAdapter for FbAdapter { } } +pub struct FrameBuffer { + pub onscreen: *mut [u32], + pub phys: usize, + pub width: usize, + pub height: usize, + pub stride: usize, +} + +impl FrameBuffer { + pub unsafe fn new(phys: usize, width: usize, height: usize, stride: usize) -> Self { + let size = stride * height; + let virt = common::physmap( + phys, + size * 4, + common::Prot { + read: true, + write: true, + }, + common::MemoryType::WriteCombining, + ) + .expect("vesad: failed to map framebuffer") as *mut u32; + + let onscreen = ptr::slice_from_raw_parts_mut(virt, size); + + Self { + onscreen, + phys, + width, + height, + stride, + } + } + + pub unsafe fn parse(var: &str) -> Option { + fn parse_number(part: &str) -> Option { + let (start, radix) = if part.starts_with("0x") { + (2, 16) + } else { + (0, 10) + }; + match usize::from_str_radix(&part[start..], radix) { + Ok(ok) => Some(ok), + Err(err) => { + eprintln!("vesad: failed to parse '{}': {}", part, err); + None + } + } + } + + let mut parts = var.split(','); + let phys = parse_number(parts.next()?)?; + let width = parse_number(parts.next()?)?; + let height = parse_number(parts.next()?)?; + let stride = parse_number(parts.next()?)?; + Some(Self::new(phys, width, height, stride)) + } +} + pub struct GraphicScreen { width: usize, height: usize, From 9abeafde8d4296e559a02b2a66a8b4b55dc2e8e7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 5 Jul 2025 15:43:21 +0200 Subject: [PATCH 1214/1301] graphics: Move disable-graphical-debug to driver-graphics This ensures it graphical debug gets disabled even when vesad never runs. --- graphics/driver-graphics/src/lib.rs | 18 +++++++++++++++++- graphics/vesad/src/main.rs | 19 +------------------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index e9971323fb..cb3ddf741d 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -1,7 +1,8 @@ #![feature(slice_as_array)] use std::collections::{BTreeMap, HashMap}; -use std::io; +use std::fs::File; +use std::io::{self, Write}; use std::mem::transmute; use std::sync::Arc; @@ -53,6 +54,7 @@ pub struct GraphicsScheme { adapter: T, scheme_name: String, + disable_graphical_debug: Option, socket: Socket, next_id: usize, handles: BTreeMap>, @@ -83,9 +85,15 @@ impl GraphicsScheme { assert!(scheme_name.starts_with("display")); let socket = Socket::nonblock(&scheme_name).expect("failed to create graphics scheme"); + let disable_graphical_debug = Some( + File::open("/scheme/debug/disable-graphical-debug") + .expect("vesad: Failed to open /scheme/debug/disable-graphical-debug"), + ); + GraphicsScheme { adapter, scheme_name, + disable_graphical_debug, socket, next_id: 0, handles: BTreeMap::new(), @@ -111,6 +119,14 @@ impl GraphicsScheme { VtEventKind::Activate => { log::info!("activate {}", vt_event.vt); + // Disable the kernel graphical debug writing once switching vt's for the + // first time. This way the kernel graphical debug remains enabled if the + // userspace logging infrastructure doesn't start up because for example a + // kernel panic happened prior to it starting up or logd crashed. + if let Some(mut disable_graphical_debug) = self.disable_graphical_debug.take() { + let _ = disable_graphical_debug.write(&[1]); + } + self.active_vt = vt_event.vt; let vt_state = diff --git a/graphics/vesad/src/main.rs b/graphics/vesad/src/main.rs index 7549e86a93..be52174509 100644 --- a/graphics/vesad/src/main.rs +++ b/graphics/vesad/src/main.rs @@ -3,10 +3,8 @@ extern crate syscall; use driver_graphics::GraphicsScheme; use event::{user_data, EventQueue}; -use inputd::{DisplayHandle, VtEventKind}; +use inputd::DisplayHandle; use std::env; -use std::fs::File; -use std::io::Write; use std::os::fd::AsRawFd; use crate::scheme::{FbAdapter, FrameBuffer}; @@ -103,11 +101,6 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec) -> ! { ) .unwrap(); - let mut disable_graphical_debug = Some( - File::open("/scheme/debug/disable-graphical-debug") - .expect("vesad: Failed to open /scheme/debug/disable-graphical-debug"), - ); - libredox::call::setrens(0, 0).expect("vesad: failed to enter null namespace"); daemon.ready().expect("failed to notify parent"); @@ -123,16 +116,6 @@ fn inner(daemon: redox_daemon::Daemon, framebuffers: Vec) -> ! { .read_vt_event() .expect("vesad: failed to read display handle") { - if let VtEventKind::Activate = vt_event.kind { - // Disable the kernel graphical debug writing once switching vt's for the - // first time. This way the kernel graphical debug remains enabled if the - // userspace logging infrastructure doesn't start up because for example a - // kernel panic happened prior to it starting up or logd crashed. - if let Some(mut disable_graphical_debug) = disable_graphical_debug.take() { - let _ = disable_graphical_debug.write(&[1]); - } - } - scheme.handle_vt_event(vt_event); } } From 918efd01cdc18b274a139b5a75742040d5f05141 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Mar 2025 17:30:39 +0100 Subject: [PATCH 1215/1301] graphics/fbcond: Inline open_display --- graphics/fbcond/src/display.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index d95d0c7789..218f8f2284 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -26,7 +26,8 @@ impl Display { /// Re-open the display after a handoff. pub fn reopen_for_handoff(&mut self) { - let new_display_handle = Self::open_display(&self.input_handle).unwrap(); + let display_file = self.input_handle.open_display().unwrap(); + let new_display_handle = V1GraphicsHandle::from_file(display_file).unwrap(); eprintln!("fbcond: Opened new display"); @@ -49,12 +50,6 @@ impl Display { } } - fn open_display(input_handle: &ConsumerHandle) -> io::Result { - let display_file = input_handle.open_display()?; - - V1GraphicsHandle::from_file(display_file) - } - pub fn sync_rect(&mut self, sync_rect: Damage) { if let Some(map) = &self.map { map.display_handle.sync_rect(sync_rect).unwrap(); From ded7a6ed863180a1a11becfed21161b9ab22bf99 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 6 Jul 2025 15:30:05 +0200 Subject: [PATCH 1216/1301] graphics/graphics-ipc: Update handle doc comments --- graphics/graphics-ipc/src/v1.rs | 2 ++ graphics/graphics-ipc/src/v2.rs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/graphics/graphics-ipc/src/v1.rs b/graphics/graphics-ipc/src/v1.rs index a29258db9c..640d117bab 100644 --- a/graphics/graphics-ipc/src/v1.rs +++ b/graphics/graphics-ipc/src/v1.rs @@ -11,6 +11,8 @@ pub use crate::common::DisplayMap; /// /// The v1 graphics API only allows a single framebuffer for each VT, requires each display to be /// handled separately and doesn't support page flipping. +/// +/// This API is stable. No breaking changes are allowed to be made without a version bump. pub struct V1GraphicsHandle { file: File, } diff --git a/graphics/graphics-ipc/src/v2.rs b/graphics/graphics-ipc/src/v2.rs index fa316d96b0..689e865bc2 100644 --- a/graphics/graphics-ipc/src/v2.rs +++ b/graphics/graphics-ipc/src/v2.rs @@ -33,10 +33,13 @@ unsafe fn sys_call( )) } -/// A graphics handle using the (currently unstable) v2 graphics API. +/// A graphics handle using the v2 graphics API. /// /// The v2 graphics API allows creating framebuffers on the fly, using them for page flipping and /// handles all displays using a single fd. +/// +/// This API is not yet stable. Do not depend on it outside of the drivers repo until it has been +/// stabilized. pub struct V2GraphicsHandle { file: File, } From 93e95f6fe8a5e8be25ae33bdefb015485ea91a2f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 6 Jul 2025 16:22:41 +0200 Subject: [PATCH 1217/1301] graphics: Fix memory leak when resizing the display --- graphics/driver-graphics/src/lib.rs | 17 +++++++++++++++++ graphics/fbbootlogd/src/scheme.rs | 2 ++ graphics/graphics-ipc/src/v2.rs | 21 ++++++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index cb3ddf741d..383e34cb7f 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -496,6 +496,23 @@ impl SchemeSync for GraphicsScheme { Ok(size_of::()) } + ipc::DESTROY_DUMB_FRAMEBUFFER => { + if payload.len() < size_of::() { + return Err(Error::new(EINVAL)); + } + let payload = unsafe { + transmute::< + &mut [u8; size_of::()], + &mut ipc::DestroyDumbFramebuffer, + >(payload.as_mut_array().unwrap()) + }; + + if fbs.remove(&{ payload.fb_id }).is_none() { + return Err(Error::new(ENOENT)); + } + + Ok(size_of::()) + } ipc::UPDATE_PLANE => { if payload.len() < size_of::() { return Err(Error::new(EINVAL)); diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 1cf2f21cf2..f6180e280b 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -95,6 +95,8 @@ impl FbbootlogScheme { }, ); + let _ = map.display_handle.destroy_dumb_framebuffer(map.fb); + map.fb = fb; map.inner = new_map; diff --git a/graphics/graphics-ipc/src/v2.rs b/graphics/graphics-ipc/src/v2.rs index 689e865bc2..ca23f82e25 100644 --- a/graphics/graphics-ipc/src/v2.rs +++ b/graphics/graphics-ipc/src/v2.rs @@ -124,6 +124,19 @@ impl V2GraphicsHandle { Ok(unsafe { DisplayMap::new(offscreen, width as usize, height as usize) }) } + pub fn destroy_dumb_framebuffer(&self, id: usize) -> io::Result { + let mut cmd = ipc::DestroyDumbFramebuffer { fb_id: id }; + unsafe { + sys_call( + &self.file, + &mut cmd, + 0, + &[ipc::DESTROY_DUMB_FRAMEBUFFER, 0, 0], + )?; + } + Ok(cmd.fb_id) + } + pub fn update_plane(&self, display_id: usize, fb_id: usize, damage: Damage) -> io::Result<()> { let mut cmd = ipc::UpdatePlane { display_id, @@ -172,7 +185,13 @@ pub mod ipc { pub offset: usize, } - pub const UPDATE_PLANE: u64 = 5; + pub const DESTROY_DUMB_FRAMEBUFFER: u64 = 5; + #[repr(C, packed)] + pub struct DestroyDumbFramebuffer { + pub fb_id: usize, + } + + pub const UPDATE_PLANE: u64 = 6; #[repr(C, packed)] pub struct UpdatePlane { pub display_id: usize, From b5caa8690663569f211c459ce3c71c4d218c9bc5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 7 Jul 2025 21:39:50 +0200 Subject: [PATCH 1218/1301] graphics/fbcond: Use the v2 graphics api --- graphics/fbcond/src/display.rs | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index 218f8f2284..e17ecbd204 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,4 +1,4 @@ -use graphics_ipc::v1::{Damage, V1GraphicsHandle}; +use graphics_ipc::v2::{Damage, V2GraphicsHandle}; use inputd::ConsumerHandle; use std::io; @@ -8,8 +8,9 @@ pub struct Display { } pub struct DisplayMap { - display_handle: V1GraphicsHandle, - pub inner: graphics_ipc::v1::DisplayMap, + display_handle: V2GraphicsHandle, + fb: usize, + pub inner: graphics_ipc::v2::DisplayMap, } impl Display { @@ -26,12 +27,17 @@ impl Display { /// Re-open the display after a handoff. pub fn reopen_for_handoff(&mut self) { - let display_file = self.input_handle.open_display().unwrap(); - let new_display_handle = V1GraphicsHandle::from_file(display_file).unwrap(); + let display_file = self.input_handle.open_display_v2().unwrap(); + let new_display_handle = V2GraphicsHandle::from_file(display_file).unwrap(); eprintln!("fbcond: Opened new display"); - match new_display_handle.map_display() { + let (width, height) = new_display_handle.display_size(0).unwrap(); + let fb = new_display_handle + .create_dumb_framebuffer(width, height) + .unwrap(); + + match new_display_handle.map_dumb_framebuffer(fb, width, height) { Ok(map) => { eprintln!( "fbcond: Mapped new display with size {}x{}", @@ -41,6 +47,7 @@ impl Display { self.map = Some(DisplayMap { display_handle: new_display_handle, + fb, inner: map, }); } @@ -50,9 +57,9 @@ impl Display { } } - pub fn sync_rect(&mut self, sync_rect: Damage) { + pub fn sync_rect(&mut self, damage: Damage) { if let Some(map) = &self.map { - map.display_handle.sync_rect(sync_rect).unwrap(); + map.display_handle.update_plane(0, map.fb, damage).unwrap(); } } } From a6a6dce185a014759bd0c2f3fec5ede67e5314a8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 7 Jul 2025 21:58:12 +0200 Subject: [PATCH 1219/1301] graphics/fbcond: Handle display resizing Currently resizing only happens when writing to the terminal. --- graphics/fbcond/src/display.rs | 52 +++++++++++++++++++++++++++++++++- graphics/fbcond/src/text.rs | 2 ++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index e17ecbd204..d47f130e78 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -1,6 +1,7 @@ +use console_draw::TextScreen; use graphics_ipc::v2::{Damage, V2GraphicsHandle}; use inputd::ConsumerHandle; -use std::io; +use std::{io, ptr}; pub struct Display { pub input_handle: ConsumerHandle, @@ -57,6 +58,55 @@ impl Display { } } + pub fn handle_resize(map: &mut DisplayMap, text_screen: &mut TextScreen) { + let (width, height) = match map.display_handle.display_size(0) { + Ok((width, height)) => (width, height), + Err(err) => { + eprintln!("fbcond: failed to get display size: {}", err); + (map.inner.width() as u32, map.inner.height() as u32) + } + }; + + if width as usize != map.inner.width() || height as usize != map.inner.height() { + match map.display_handle.create_dumb_framebuffer(width, height) { + Ok(fb) => match map.display_handle.map_dumb_framebuffer(fb, width, height) { + Ok(mut new_map) => { + let count = new_map.ptr().len(); + unsafe { + ptr::write_bytes(new_map.ptr_mut() as *mut u32, 0, count); + } + + text_screen.resize( + &mut console_draw::DisplayMap { + offscreen: map.inner.ptr_mut(), + width: map.inner.width(), + height: map.inner.height(), + }, + &mut console_draw::DisplayMap { + offscreen: new_map.ptr_mut(), + width: new_map.width(), + height: new_map.height(), + }, + ); + + let _ = map.display_handle.destroy_dumb_framebuffer(map.fb); + + map.fb = fb; + map.inner = new_map; + + eprintln!("fbcond: mapped display"); + } + Err(err) => { + eprintln!("fbcond: failed to open display: {}", err); + } + }, + Err(err) => { + eprintln!("fbcond: failed to create framebuffer: {}", err); + } + } + } + } + pub fn sync_rect(&mut self, damage: Damage) { if let Some(map) = &self.map { map.display_handle.update_plane(0, map.fb, damage).unwrap(); diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index e503488bfc..f8ec4d31e1 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -122,6 +122,8 @@ impl TextScreen { pub fn write(&mut self, buf: &[u8]) -> Result { if let Some(map) = &mut self.display.map { + Display::handle_resize(map, &mut self.inner); + let damage = self.inner.write( &mut console_draw::DisplayMap { offscreen: map.inner.ptr_mut(), From 36e37958c988ec1da1669c8cc3acca7a2a24a4f0 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 11 Jul 2025 09:06:10 -0600 Subject: [PATCH 1220/1301] e1000d: do not print in busy loop --- net/e1000d/src/device.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/e1000d/src/device.rs b/net/e1000d/src/device.rs index 30213fd829..3bec4122b9 100644 --- a/net/e1000d/src/device.rs +++ b/net/e1000d/src/device.rs @@ -1,5 +1,5 @@ use std::convert::TryInto; -use std::{cmp, mem, ptr, slice}; +use std::{cmp, mem, ptr, slice, thread, time}; use driver_network::NetworkAdapter; @@ -350,8 +350,9 @@ impl Intel8254x { // TIPG Packet Gap // TODO ... + print!(" - Waiting for link up: {:X}\n", self.read_reg(STATUS)); while self.read_reg(STATUS) & 2 != 2 { - print!(" - Waiting for link up: {:X}\n", self.read_reg(STATUS)); + thread::sleep(time::Duration::from_millis(100)); } print!( " - Link is up with speed {}\n", From e8bfe4448c86aa504545a0e1933b9e68b184bc87 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Sun, 24 Aug 2025 20:06:14 +0700 Subject: [PATCH 1221/1301] Fix possible panic in device enumeration --- xhcid/src/xhci/irq_reactor.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index c551040450..d3c82f699f 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -333,7 +333,16 @@ impl IrqReactor { ); { let mut ports = self.hci.ports.lock().unwrap(); - let port = &mut ports[port_id.root_hub_port_index()]; + let root_port_index = port_id.root_hub_port_index(); + if root_port_index >= ports.len() { + warn!( + "Received out of bounds transmit device numeration request on root index {} at port {} [port len was: {}]", + root_port_index, port_id, ports.len() + ); + return; + } + + let port = &mut ports[root_port_index]; port.clear_csc(); } } else { From 259999c9c3bb817f3135747dad2f453bb9e9d93f Mon Sep 17 00:00:00 2001 From: Wildan Mubarok Date: Sat, 30 Aug 2025 12:27:35 +0000 Subject: [PATCH 1222/1301] Fix fbcond panicking when vim quit --- graphics/console-draw/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index b1551d9c79..390c5cc73a 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -117,7 +117,7 @@ impl TextScreen { impl TextScreen { pub fn write(&mut self, map: &mut DisplayMap, buf: &[u8], input: &mut VecDeque) -> Damage { - let mut min_changed = usize::MAX; + let mut min_changed = map.height; let mut max_changed = 0; let mut line_changed = |line| { if line < min_changed { From 191e6ac4ebb55480bfed027f29823089f590c6d7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 25 Jan 2024 14:55:04 +0100 Subject: [PATCH 1223/1301] pcid: Disable MSI and MSI-X before launching a driver --- pcid/src/driver_handler.rs | 11 +++++++---- pcid/src/main.rs | 14 ++++++++++++++ pcid/src/scheme.rs | 9 ++++++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/pcid/src/driver_handler.rs b/pcid/src/driver_handler.rs index 435c225937..f70a7f6da3 100644 --- a/pcid/src/driver_handler.rs +++ b/pcid/src/driver_handler.rs @@ -7,7 +7,7 @@ use crate::cfg_access::Pcie; pub struct DriverHandler<'a> { func: PciFunction, endpoint_header: &'a mut EndpointHeader, - capabilities: Vec, + capabilities: &'a mut [PciCapability], pcie: &'a Pcie, } @@ -16,7 +16,7 @@ impl<'a> DriverHandler<'a> { pub fn new( func: PciFunction, endpoint_header: &'a mut EndpointHeader, - capabilities: Vec, + capabilities: &'a mut [PciCapability], pcie: &'a Pcie, ) -> Self { DriverHandler { @@ -36,8 +36,11 @@ impl<'a> DriverHandler<'a> { #[forbid(non_exhaustive_omitted_patterns)] match request { PcidClientRequest::EnableDevice => { - self.func.legacy_interrupt_line = - crate::enable_function(&self.pcie, &mut self.endpoint_header); + self.func.legacy_interrupt_line = crate::enable_function( + &self.pcie, + &mut self.endpoint_header, + &mut self.capabilities, + ); PcidClientResponse::EnabledDevice } diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 2035ac497b..bbfb8ba301 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -109,6 +109,7 @@ fn handle_parsed_header( fn enable_function( pcie: &Pcie, endpoint_header: &mut EndpointHeader, + capabilities: &mut [PciCapability], ) -> Option { // Enable bus mastering, memory space, and I/O space endpoint_header.update_command(pcie, |cmd| { @@ -117,6 +118,19 @@ fn enable_function( | CommandRegister::IO_ENABLE }); + // Disable MSI and MSI-X in case a previous driver instance enabled them. + for capability in capabilities { + match capability { + PciCapability::Msi(capability) => { + capability.set_enabled(false, pcie); + } + PciCapability::MsiX(capability) => { + capability.set_enabled(false, pcie); + } + _ => {} + } + } + // Set IRQ line to 9 if not set let mut irq = 0xFF; let mut interrupt_pin = 0xFF; diff --git a/pcid/src/scheme.rs b/pcid/src/scheme.rs index 135a067b73..dcf3a26a3f 100644 --- a/pcid/src/scheme.rs +++ b/pcid/src/scheme.rs @@ -242,8 +242,11 @@ impl PciScheme { if func.enabled { return Err(Error::new(ENOLCK)); } - func.inner.legacy_interrupt_line = - crate::enable_function(&self.pcie, &mut func.endpoint_header); + func.inner.legacy_interrupt_line = crate::enable_function( + &self.pcie, + &mut func.endpoint_header, + &mut func.capabilities, + ); func.enabled = true; Handle::Channel { addr, @@ -287,7 +290,7 @@ impl PciScheme { let response = crate::driver_handler::DriverHandler::new( func.inner.clone(), &mut func.endpoint_header, - func.capabilities.clone(), + &mut func.capabilities, &*pci_state, ) .respond(request); From 0b6b5e0d04422b8601c13926ed571920e5a4814f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Aug 2025 18:25:29 +0200 Subject: [PATCH 1224/1301] pcid: Move MappedMsixRegs to pcid_interface --- net/rtl8139d/src/main.rs | 35 ++--------------------- net/rtl8168d/src/main.rs | 35 ++--------------------- pcid/src/driver_interface/msi.rs | 48 +++++++++++++++++++++++++++++++- storage/nvmed/src/main.rs | 30 +++----------------- storage/nvmed/src/nvme/mod.rs | 14 ++-------- virtio-core/src/arch/x86.rs | 19 ++----------- virtio-core/src/probe.rs | 19 ------------- xhcid/src/main.rs | 26 +++-------------- xhcid/src/xhci/mod.rs | 17 +---------- 9 files changed, 66 insertions(+), 177 deletions(-) diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index c0272136c7..80b1091808 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -1,17 +1,14 @@ use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; -use std::ptr::NonNull; -use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; -use pcid_interface::msi::{MsixInfo, MsixTableEntry}; use pcid_interface::{ - MappedBar, MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, + MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, }; pub mod device; @@ -28,21 +25,6 @@ where } } -pub struct MappedMsixRegs { - pub virt_table_base: NonNull, - pub info: MsixInfo, -} - -impl MappedMsixRegs { - pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { - &mut *self.virt_table_base.as_ptr().offset(k as isize) - } - pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { - assert!(k < self.info.table_size as usize); - unsafe { self.table_entry_pointer_unchecked(k) } - } -} - #[cfg(target_arch = "x86_64")] fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.config(); @@ -83,19 +65,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; - msix_info.validate(pci_config.func.bars); - - let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar) } - .ptr - .as_ptr() as usize; - - let virt_table_base = - (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; - - let mut info = MappedMsixRegs { - virt_table_base: NonNull::new(virt_table_base).unwrap(), - info: msix_info, - }; + let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; // Allocate one msi vector. @@ -103,7 +73,6 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { // primary interrupter let k = 0; - assert_eq!(std::mem::size_of::(), 16); let table_entry_pointer = info.table_entry_pointer(k); let destination_id = read_bsp_apic_id().expect("rtl8139d: failed to read BSP apic id"); diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 44150572f7..44c8f41859 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -1,17 +1,14 @@ use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; -use std::ptr::NonNull; -use std::rc::Rc; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; -use pcid_interface::msi::{MsixInfo, MsixTableEntry}; use pcid_interface::{ - MappedBar, MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, + MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, }; pub mod device; @@ -28,21 +25,6 @@ where } } -pub struct MappedMsixRegs { - pub virt_table_base: NonNull, - pub info: MsixInfo, -} - -impl MappedMsixRegs { - pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { - &mut *self.virt_table_base.as_ptr().offset(k as isize) - } - pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { - assert!(k < self.info.table_size as usize); - unsafe { self.table_entry_pointer_unchecked(k) } - } -} - #[cfg(target_arch = "x86_64")] fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let pci_config = pcid_handle.config(); @@ -83,19 +65,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; - msix_info.validate(pci_config.func.bars); - - let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar) } - .ptr - .as_ptr() as usize; - - let virt_table_base = - (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; - - let mut info = MappedMsixRegs { - virt_table_base: NonNull::new(virt_table_base).unwrap(), - info: msix_info, - }; + let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; // Allocate one msi vector. @@ -103,7 +73,6 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { // primary interrupter let k = 0; - assert_eq!(std::mem::size_of::(), 16); let table_entry_pointer = info.table_entry_pointer(k); let destination_id = read_bsp_apic_id().expect("rtl8168d: failed to read BSP apic id"); diff --git a/pcid/src/driver_interface/msi.rs b/pcid/src/driver_interface/msi.rs index 822ac0976c..0ca68ec556 100644 --- a/pcid/src/driver_interface/msi.rs +++ b/pcid/src/driver_interface/msi.rs @@ -1,6 +1,8 @@ use std::fmt; +use std::ptr::NonNull; use crate::driver_interface::PciBar; +use crate::PciFunctionHandle; use common::io::{Io, Mmio}; use serde::{Deserialize, Serialize}; @@ -32,7 +34,32 @@ pub struct MsixInfo { } impl MsixInfo { - pub fn validate(&self, bars: [PciBar; 6]) { + pub unsafe fn map_and_mask_all(self, pcid_handle: &mut PciFunctionHandle) -> MappedMsixRegs { + self.validate(pcid_handle.config().func.bars); + + let virt_table_base = unsafe { + pcid_handle + .map_bar(self.table_bar) + .ptr + .as_ptr() + .byte_add(self.table_offset as usize) + }; + + let mut info = MappedMsixRegs { + virt_table_base: NonNull::new(virt_table_base.cast::()).unwrap(), + info: self, + }; + + // Mask all interrupts in case some earlier driver/os already unmasked them (according to + // the PCI Local Bus spec 3.0, they are masked after system reset). + for i in 0..info.info.table_size { + info.table_entry_pointer(i.into()).mask(); + } + + info + } + + fn validate(&self, bars: [PciBar; 6]) { if self.table_bar > 5 { panic!( "MSI-X Table BIR contained a reserved enum value: {}", @@ -78,6 +105,21 @@ impl MsixInfo { } } +pub struct MappedMsixRegs { + pub virt_table_base: NonNull, + pub info: MsixInfo, +} +impl MappedMsixRegs { + pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { + &mut *self.virt_table_base.as_ptr().add(k) + } + + pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { + assert!(k < self.info.table_size as usize); + unsafe { self.table_entry_pointer_unchecked(k) } + } +} + #[repr(C, packed)] pub struct MsixTableEntry { pub addr_lo: Mmio, @@ -86,6 +128,10 @@ pub struct MsixTableEntry { pub vec_ctl: Mmio, } +const _: () = { + assert!(size_of::() == 16); +}; + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub mod x86 { #[repr(u8)] diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 6966570a52..342caf055e 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -5,10 +5,9 @@ use std::cell::RefCell; use std::fs::File; use std::io::{self, Read, Write}; use std::os::fd::AsRawFd; -use std::ptr::NonNull; use std::rc::Rc; use std::sync::Arc; -use std::{slice, usize}; +use std::usize; use driver_block::{Disk, DiskScheme}; use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PciFunctionHandle}; @@ -39,35 +38,17 @@ fn get_int_method( // TODO: Allocate more than one vector when possible and useful. if has_msix { // Extended message signaled interrupts. - use self::nvme::MappedMsixRegs; - use pcid_interface::msi::MsixTableEntry; let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { PciFeatureInfo::MsiX(msix) => msix, _ => unreachable!(), }; - msix_info.validate(function.bars); - fn bar_base(pcid_handle: &mut PciFunctionHandle, bir: u8) -> Result> { - Ok(unsafe { pcid_handle.map_bar(bir) }.ptr) - } - let table_bar_base: *mut u8 = bar_base(pcid_handle, msix_info.table_bar)?.as_ptr(); - let table_base = unsafe { table_bar_base.offset(msix_info.table_offset as isize) }; - - let vector_count = msix_info.table_size; - let table_entries: &'static mut [MsixTableEntry] = unsafe { - slice::from_raw_parts_mut(table_base as *mut MsixTableEntry, vector_count as usize) - }; - - // Mask all interrupts in case some earlier driver/os already unmasked them (according to - // the PCI Local Bus spec 3.0, they are masked after system reset). - for table_entry in table_entries.iter_mut() { - table_entry.mask(); - } + let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; pcid_handle.enable_feature(PciFeature::MsiX); let (msix_vector_number, irq_handle) = { - let entry: &mut MsixTableEntry = &mut table_entries[0]; + let entry = info.table_entry_pointer(0); let bsp_cpu_id = irq_helpers::read_bsp_apic_id().expect("nvmed: failed to read APIC ID"); @@ -79,10 +60,7 @@ fn get_int_method( (0, irq_handle) }; - let interrupt_method = InterruptMethod::MsiX(MappedMsixRegs { - info: msix_info, - table: table_entries, - }); + let interrupt_method = InterruptMethod::MsiX(info); let interrupt_sources = InterruptSources::MsiX(std::iter::once((msix_vector_number, irq_handle)).collect()); diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 513814c9d0..93dfab4ed2 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -21,7 +21,7 @@ pub mod queues; use self::executor::NvmeExecutor; pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue}; -use pcid_interface::msi::{MsiInfo, MsixInfo, MsixTableEntry}; +use pcid_interface::msi::{MappedMsixRegs, MsiInfo}; use pcid_interface::PciFunctionHandle; #[cfg(target_arch = "aarch64")] @@ -133,11 +133,6 @@ impl InterruptMethod { } } -pub struct MappedMsixRegs { - pub info: MsixInfo, - pub table: &'static mut [MsixTableEntry], -} - #[repr(C, packed)] pub struct NvmeRegs { /// Controller Capabilities @@ -316,7 +311,7 @@ impl Nvme { self.regs.get_mut().intmc.write(0x0000_0001); } &mut InterruptMethod::MsiX(ref mut cfg) => { - cfg.table[0].unmask(); + cfg.table_entry_pointer(0).unmask(); } } @@ -442,10 +437,7 @@ impl Nvme { } &mut InterruptMethod::MsiX(ref mut cfg) => { for (vector, mask) in vectors { - cfg.table - .get_mut(vector as usize) - .expect("nvmed: internal error: MSI-X vector out of range") - .set_masked(mask); + cfg.table_entry_pointer(vector.into()).set_masked(mask); } } } diff --git a/virtio-core/src/arch/x86.rs b/virtio-core/src/arch/x86.rs index 7275c63e41..751f268e07 100644 --- a/virtio-core/src/arch/x86.rs +++ b/virtio-core/src/arch/x86.rs @@ -1,32 +1,19 @@ use crate::transport::Error; use pcid_interface::irq_helpers::{allocate_single_interrupt_vector_for_msi, read_bsp_apic_id}; -use pcid_interface::msi::MsixTableEntry; -use std::{fs::File, ptr::NonNull}; +use std::fs::File; -use crate::{probe::MappedMsixRegs, MSIX_PRIMARY_VECTOR}; +use crate::MSIX_PRIMARY_VECTOR; use pcid_interface::*; pub fn enable_msix(pcid_handle: &mut PciFunctionHandle) -> Result { - let pci_config = pcid_handle.config(); - // Extended message signaled interrupts. let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { PciFeatureInfo::MsiX(capability) => capability, _ => unreachable!(), }; - msix_info.validate(pci_config.func.bars); - - let bar_address = unsafe { pcid_handle.map_bar(msix_info.table_bar) } - .ptr - .as_ptr() as usize; - let virt_table_base = (bar_address + msix_info.table_offset as usize) as *mut MsixTableEntry; - - let mut info = MappedMsixRegs { - virt_table_base: NonNull::new(virt_table_base).unwrap(), - info: msix_info, - }; + let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; // Allocate the primary MSI vector. // FIXME allow the driver to register multiple MSI-X vectors diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index be3977d96b..da95234636 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -1,8 +1,6 @@ use std::fs::File; -use std::ptr::NonNull; use std::sync::Arc; -use pcid_interface::msi::{MsixInfo, MsixTableEntry}; use pcid_interface::*; use crate::spec::*; @@ -20,23 +18,6 @@ pub struct Device { unsafe impl Send for Device {} unsafe impl Sync for Device {} -pub struct MappedMsixRegs { - pub virt_table_base: NonNull, - pub info: MsixInfo, -} - -impl MappedMsixRegs { - pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { - &mut *self.virt_table_base.as_ptr().add(k) - } - - pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { - assert!(k < self.info.table_size as usize); - unsafe { self.table_entry_pointer_unchecked(k) } - } -} - -static_assertions::const_assert_eq!(std::mem::size_of::(), 16); pub const MSIX_PRIMARY_VECTOR: u16 = 0; diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 800614e2e0..a7c6034105 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -26,13 +26,11 @@ extern crate bitflags; use std::fs::File; -use std::ptr::NonNull; use std::sync::{Arc, Mutex}; #[cfg(target_arch = "x86_64")] use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; -use pcid_interface::msi::MsixTableEntry; use pcid_interface::{ MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, }; @@ -50,10 +48,7 @@ mod usb; mod xhci; #[cfg(target_arch = "x86_64")] -fn get_int_method( - pcid_handle: &mut PciFunctionHandle, - bar0_address: usize, -) -> (Option, InterruptMethod) { +fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> (Option, InterruptMethod) { let pci_config = pcid_handle.config(); let all_pci_features = pcid_handle.fetch_all_features(); @@ -92,16 +87,7 @@ fn get_int_method( PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, }; - msix_info.validate(pci_config.func.bars); - - assert_eq!(msix_info.table_bar, 0); - let virt_table_base = - (bar0_address + msix_info.table_offset as usize) as *mut MsixTableEntry; - - let mut info = xhci::MappedMsixRegs { - virt_table_base: NonNull::new(virt_table_base).unwrap(), - info: msix_info, - }; + let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; // Allocate one msi vector. @@ -109,7 +95,6 @@ fn get_int_method( // primary interrupter let k = 0; - assert_eq!(std::mem::size_of::(), 16); let table_entry_pointer = info.table_entry_pointer(k); let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); @@ -141,10 +126,7 @@ fn get_int_method( //TODO: MSI on non-x86_64? #[cfg(not(target_arch = "x86_64"))] -fn get_int_method( - pcid_handle: &mut PciFunctionHandle, - address: usize, -) -> (Option, InterruptMethod) { +fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> (Option, InterruptMethod) { let pci_config = pcid_handle.config(); if let Some(irq) = pci_config.func.legacy_interrupt_line { @@ -179,7 +161,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; - let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle, address); + let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle); //TODO: Fix interrupts. println!(" + XHCI {}", pci_config.func.display()); diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 3d3798a312..bbbfb9ffbd 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -12,11 +12,11 @@ use std::collections::BTreeMap; use std::convert::TryFrom; use std::fs::File; -use std::ptr::NonNull; use std::sync::atomic::AtomicUsize; use std::sync::{Arc, Mutex, MutexGuard}; use std::{mem, process, slice, thread}; +use pcid_interface::msi::MappedMsixRegs; use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT}; use syscall::{EAGAIN, PAGE_SIZE}; @@ -28,7 +28,6 @@ use serde::Deserialize; use crate::usb; -use pcid_interface::msi::{MsixInfo, MsixTableEntry}; use pcid_interface::PciFunctionHandle; mod capability; @@ -78,20 +77,6 @@ pub enum InterruptMethod { MsiX(Mutex), } -pub struct MappedMsixRegs { - pub virt_table_base: NonNull, - pub info: MsixInfo, -} -impl MappedMsixRegs { - pub unsafe fn table_entry_pointer_unchecked(&mut self, k: usize) -> &mut MsixTableEntry { - &mut *self.virt_table_base.as_ptr().offset(k as isize) - } - pub fn table_entry_pointer(&mut self, k: usize) -> &mut MsixTableEntry { - assert!(k < self.info.table_size as usize); - unsafe { self.table_entry_pointer_unchecked(k) } - } -} - impl Xhci { /// Gets descriptors, before the port state is initiated. async fn get_desc_raw( From 0a314b0bad98b800c0f8ccaf2b028f315fb38d97 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Aug 2025 18:34:25 +0200 Subject: [PATCH 1225/1301] nvmed: Use std::hint::spin_loop --- storage/nvmed/src/main.rs | 3 --- storage/nvmed/src/nvme/mod.rs | 28 ++-------------------------- storage/nvmed/src/nvme/queues.rs | 2 +- 3 files changed, 3 insertions(+), 30 deletions(-) diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 342caf055e..9f328a78c4 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -1,6 +1,3 @@ -#![cfg_attr(target_arch = "aarch64", feature(stdarch_arm_hints))] // Required for yield instruction -#![cfg_attr(target_arch = "riscv64", feature(riscv_ext_intrinsics))] // Required for pause instruction - use std::cell::RefCell; use std::fs::File; use std::io::{self, Read, Write}; diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 93dfab4ed2..312a0eb3e8 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -24,30 +24,6 @@ pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue}; use pcid_interface::msi::{MappedMsixRegs, MsiInfo}; use pcid_interface::PciFunctionHandle; -#[cfg(target_arch = "aarch64")] -#[inline(always)] -pub(crate) unsafe fn pause() { - std::arch::aarch64::__yield(); -} - -#[cfg(target_arch = "x86")] -#[inline(always)] -pub(crate) unsafe fn pause() { - std::arch::x86::_mm_pause(); -} - -#[cfg(target_arch = "x86_64")] -#[inline(always)] -pub(crate) unsafe fn pause() { - std::arch::x86_64::_mm_pause(); -} - -#[cfg(target_arch = "riscv64")] -#[inline(always)] -pub(crate) unsafe fn pause() { - std::arch::riscv64::pause(); -} - /// Used in conjunction with `InterruptMethod`, primarily by the CQ executor. #[derive(Debug)] pub enum InterruptSources { @@ -299,7 +275,7 @@ impl Nvme { let csts = self.regs.get_mut().csts.read(); log::trace!("CSTS: {:X}", csts); if csts & 1 == 1 { - pause(); + std::hint::spin_loop(); } else { break; } @@ -364,7 +340,7 @@ impl Nvme { let csts = self.regs.get_mut().csts.read(); log::debug!("CSTS: {:X}", csts); if csts & 1 == 0 { - pause(); + std::hint::spin_loop(); } else { break; } diff --git a/storage/nvmed/src/nvme/queues.rs b/storage/nvmed/src/nvme/queues.rs index 9d9cf2e2cb..a3712aeb74 100644 --- a/storage/nvmed/src/nvme/queues.rs +++ b/storage/nvmed/src/nvme/queues.rs @@ -87,7 +87,7 @@ impl NvmeCompQueue { return some; } else { unsafe { - super::pause(); + std::hint::spin_loop(); } } } From ea47c97bf8e67dc5827900ca19234296a33412f7 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Aug 2025 19:03:54 +0200 Subject: [PATCH 1226/1301] Check for MSI-X before checking for MSI --- audio/ihdad/src/main.rs | 3 +-- net/rtl8139d/src/main.rs | 52 ++++++++++++++++++++-------------------- net/rtl8168d/src/main.rs | 52 ++++++++++++++++++++-------------------- xhcid/src/main.rs | 52 ++++++++++++++++++++-------------------- 4 files changed, 79 insertions(+), 80 deletions(-) diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index e9a91590ec..2effe88ddd 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -35,9 +35,8 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { log::debug!("PCI FEATURES: {:?}", all_pci_features); let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); - let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - if has_msi && !has_msix { + if has_msi { let capability = match pcid_handle.feature_info(PciFeature::Msi) { PciFeatureInfo::Msi(s) => s, PciFeatureInfo::MsiX(_) => panic!(), diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 80b1091808..a8b8c2c19a 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -35,32 +35,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - if has_msi && !has_msix { - let capability = match pcid_handle.feature_info(PciFeature::Msi) { - PciFeatureInfo::Msi(s) => s, - PciFeatureInfo::MsiX(_) => panic!(), - }; - // TODO: Allow allocation of up to 32 vectors. - - // TODO: Find a way to abstract this away, potantially as a helper module for - // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. - - let destination_id = read_bsp_apic_id().expect("rtl8139d: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - - let set_feature_info = MsiSetFeatureInfo { - multi_message_enable: Some(0), - message_address_and_data: Some(msg_addr_and_data), - mask_bits: None, - }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - - pcid_handle.enable_feature(PciFeature::Msi); - log::info!("Enabled MSI"); - - interrupt_handle - } else if has_msix { + if has_msix { let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, @@ -88,6 +63,31 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { log::info!("Enabled MSI-X"); method + } else if has_msi { + let capability = match pcid_handle.feature_info(PciFeature::Msi) { + PciFeatureInfo::Msi(s) => s, + PciFeatureInfo::MsiX(_) => panic!(), + }; + // TODO: Allow allocation of up to 32 vectors. + + // TODO: Find a way to abstract this away, potantially as a helper module for + // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. + + let destination_id = read_bsp_apic_id().expect("rtl8139d: failed to read BSP apic id"); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); + + let set_feature_info = MsiSetFeatureInfo { + multi_message_enable: Some(0), + message_address_and_data: Some(msg_addr_and_data), + mask_bits: None, + }; + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); + + pcid_handle.enable_feature(PciFeature::Msi); + log::info!("Enabled MSI"); + + interrupt_handle } else if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. irq.irq_handle("rtl8139d") diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 44c8f41859..6e9d4c1acc 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -35,32 +35,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - if has_msi && !has_msix { - let capability = match pcid_handle.feature_info(PciFeature::Msi) { - PciFeatureInfo::Msi(s) => s, - PciFeatureInfo::MsiX(_) => panic!(), - }; - // TODO: Allow allocation of up to 32 vectors. - - // TODO: Find a way to abstract this away, potantially as a helper module for - // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. - - let destination_id = read_bsp_apic_id().expect("rtl8168d: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - - let set_feature_info = MsiSetFeatureInfo { - multi_message_enable: Some(0), - message_address_and_data: Some(msg_addr_and_data), - mask_bits: None, - }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - - pcid_handle.enable_feature(PciFeature::Msi); - log::info!("Enabled MSI"); - - interrupt_handle - } else if has_msix { + if has_msix { let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, @@ -88,6 +63,31 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { log::info!("Enabled MSI-X"); method + } else if has_msi { + let capability = match pcid_handle.feature_info(PciFeature::Msi) { + PciFeatureInfo::Msi(s) => s, + PciFeatureInfo::MsiX(_) => panic!(), + }; + // TODO: Allow allocation of up to 32 vectors. + + // TODO: Find a way to abstract this away, potantially as a helper module for + // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. + + let destination_id = read_bsp_apic_id().expect("rtl8168d: failed to read BSP apic id"); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); + + let set_feature_info = MsiSetFeatureInfo { + multi_message_enable: Some(0), + message_address_and_data: Some(msg_addr_and_data), + mask_bits: None, + }; + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); + + pcid_handle.enable_feature(PciFeature::Msi); + log::info!("Enabled MSI"); + + interrupt_handle } else if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. irq.irq_handle("rtl8168d") diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index a7c6034105..0cc877cd1d 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -57,32 +57,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> (Option, Interru let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - if has_msi && !has_msix { - let mut capability = match pcid_handle.feature_info(PciFeature::Msi) { - PciFeatureInfo::Msi(s) => s, - PciFeatureInfo::MsiX(_) => panic!(), - }; - // TODO: Allow allocation of up to 32 vectors. - - // TODO: Find a way to abstract this away, potantially as a helper module for - // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. - - let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - - let set_feature_info = MsiSetFeatureInfo { - multi_message_enable: Some(0), - message_address_and_data: Some(msg_addr_and_data), - mask_bits: None, - }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - - pcid_handle.enable_feature(PciFeature::Msi); - log::debug!("Enabled MSI"); - - (Some(interrupt_handle), InterruptMethod::Msi) - } else if has_msix { + if has_msix { let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { PciFeatureInfo::Msi(_) => panic!(), PciFeatureInfo::MsiX(s) => s, @@ -113,6 +88,31 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> (Option, Interru log::debug!("Enabled MSI-X"); method + } else if has_msi { + let mut capability = match pcid_handle.feature_info(PciFeature::Msi) { + PciFeatureInfo::Msi(s) => s, + PciFeatureInfo::MsiX(_) => panic!(), + }; + // TODO: Allow allocation of up to 32 vectors. + + // TODO: Find a way to abstract this away, potantially as a helper module for + // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. + + let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); + + let set_feature_info = MsiSetFeatureInfo { + multi_message_enable: Some(0), + message_address_and_data: Some(msg_addr_and_data), + mask_bits: None, + }; + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); + + pcid_handle.enable_feature(PciFeature::Msi); + log::debug!("Enabled MSI"); + + (Some(interrupt_handle), InterruptMethod::Msi) } else if let Some(irq) = pci_config.func.legacy_interrupt_line { log::debug!("Legacy IRQ {}", irq); From 2945b86b824fec63098e3be70c658118c1a22d1b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Aug 2025 19:13:00 +0200 Subject: [PATCH 1227/1301] pcid: Helper to allocate first MSI interrupt --- audio/ihdad/src/main.rs | 32 +++-------------------- net/rtl8139d/src/main.rs | 33 ++++-------------------- net/rtl8168d/src/main.rs | 33 ++++-------------------- pcid/src/driver_interface/irq_helpers.rs | 25 ++++++++++++++++++ storage/nvmed/src/main.rs | 18 ++----------- xhcid/src/main.rs | 32 ++++------------------- 6 files changed, 45 insertions(+), 128 deletions(-) diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 2effe88ddd..078b12265d 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -12,11 +12,8 @@ use syscall::{Packet, SchemeBlockMut}; use event::{user_data, EventQueue}; #[cfg(target_arch = "x86_64")] -use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; -use pcid_interface::irq_helpers::read_bsp_apic_id; -use pcid_interface::{ - MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, -}; +use pcid_interface::irq_helpers::allocate_first_msi_interrupt_on_bsp; +use pcid_interface::PciFunctionHandle; pub mod hda; @@ -37,30 +34,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); if has_msi { - let capability = match pcid_handle.feature_info(PciFeature::Msi) { - PciFeatureInfo::Msi(s) => s, - PciFeatureInfo::MsiX(_) => panic!(), - }; - // TODO: Allow allocation of up to 32 vectors. - - // TODO: Find a way to abstract this away, potantially as a helper module for - // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. - - let destination_id = read_bsp_apic_id().expect("ihdad: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - - let set_feature_info = MsiSetFeatureInfo { - multi_message_enable: Some(0), - message_address_and_data: Some(msg_addr_and_data), - mask_bits: None, - }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - - pcid_handle.enable_feature(PciFeature::Msi); - log::debug!("Enabled MSI"); - - interrupt_handle + allocate_first_msi_interrupt_on_bsp(pcid_handle) } else if let Some(irq) = pci_config.func.legacy_interrupt_line { log::debug!("Legacy IRQ {}", irq); diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index a8b8c2c19a..aaf4a9bd70 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -4,12 +4,12 @@ use std::os::unix::io::AsRawFd; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; -#[cfg(target_arch = "x86_64")] -use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; -use pcid_interface::{ - MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, +#[cfg(target_arch = "x86_64")] +use pcid_interface::irq_helpers::{ + allocate_first_msi_interrupt_on_bsp, allocate_single_interrupt_vector_for_msi, }; +use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle}; pub mod device; @@ -64,30 +64,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { method } else if has_msi { - let capability = match pcid_handle.feature_info(PciFeature::Msi) { - PciFeatureInfo::Msi(s) => s, - PciFeatureInfo::MsiX(_) => panic!(), - }; - // TODO: Allow allocation of up to 32 vectors. - - // TODO: Find a way to abstract this away, potantially as a helper module for - // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. - - let destination_id = read_bsp_apic_id().expect("rtl8139d: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - - let set_feature_info = MsiSetFeatureInfo { - multi_message_enable: Some(0), - message_address_and_data: Some(msg_addr_and_data), - mask_bits: None, - }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - - pcid_handle.enable_feature(PciFeature::Msi); - log::info!("Enabled MSI"); - - interrupt_handle + allocate_first_msi_interrupt_on_bsp(pcid_handle) } else if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. irq.irq_handle("rtl8139d") diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 6e9d4c1acc..27094eb481 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -4,12 +4,12 @@ use std::os::unix::io::AsRawFd; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; -#[cfg(target_arch = "x86_64")] -use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; -use pcid_interface::{ - MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, +#[cfg(target_arch = "x86_64")] +use pcid_interface::irq_helpers::{ + allocate_first_msi_interrupt_on_bsp, allocate_single_interrupt_vector_for_msi, }; +use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle}; pub mod device; @@ -64,30 +64,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { method } else if has_msi { - let capability = match pcid_handle.feature_info(PciFeature::Msi) { - PciFeatureInfo::Msi(s) => s, - PciFeatureInfo::MsiX(_) => panic!(), - }; - // TODO: Allow allocation of up to 32 vectors. - - // TODO: Find a way to abstract this away, potantially as a helper module for - // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. - - let destination_id = read_bsp_apic_id().expect("rtl8168d: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - - let set_feature_info = MsiSetFeatureInfo { - multi_message_enable: Some(0), - message_address_and_data: Some(msg_addr_and_data), - mask_bits: None, - }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - - pcid_handle.enable_feature(PciFeature::Msi); - log::info!("Enabled MSI"); - - interrupt_handle + allocate_first_msi_interrupt_on_bsp(pcid_handle) } else if let Some(irq) = pci_config.func.legacy_interrupt_line { // legacy INTx# interrupt pins. irq.irq_handle("rtl8168d") diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index 6c7b010485..6a91bd1000 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -202,3 +202,28 @@ pub fn allocate_single_interrupt_vector_for_msi(cpu_id: usize) -> (MsiAddrAndDat interrupt_handle, ) } + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub fn allocate_first_msi_interrupt_on_bsp( + pcid_handle: &mut crate::driver_interface::PciFunctionHandle, +) -> File { + use crate::driver_interface::{MsiSetFeatureInfo, PciFeature, SetFeatureInfo}; + + // TODO: Allow allocation of up to 32 vectors. + + let destination_id = read_bsp_apic_id().expect("failed to read BSP apic id"); + let (msg_addr_and_data, interrupt_handle) = + allocate_single_interrupt_vector_for_msi(destination_id); + + let set_feature_info = MsiSetFeatureInfo { + multi_message_enable: Some(0), + message_address_and_data: Some(msg_addr_and_data), + mask_bits: None, + }; + pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); + + pcid_handle.enable_feature(PciFeature::Msi); + log::info!("Enabled MSI"); + + interrupt_handle +} diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 9f328a78c4..56e307769d 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -70,22 +70,8 @@ fn get_int_method( _ => unreachable!(), }; - let (msi_vector_number, irq_handle) = { - use pcid_interface::{MsiSetFeatureInfo, SetFeatureInfo}; - - let bsp_cpu_id = - irq_helpers::read_bsp_apic_id().expect("nvmed: failed to read BSP APIC ID"); - let (msg_addr_and_data, irq_handle) = - irq_helpers::allocate_single_interrupt_vector_for_msi(bsp_cpu_id); - - pcid_handle.set_feature_info(SetFeatureInfo::Msi(MsiSetFeatureInfo { - message_address_and_data: Some(msg_addr_and_data), - multi_message_enable: Some(0), // enable 2^0=1 vectors - mask_bits: None, - })); - - (0, irq_handle) - }; + let msi_vector_number = 0; + let irq_handle = irq_helpers::allocate_first_msi_interrupt_on_bsp(pcid_handle); let interrupt_method = InterruptMethod::Msi { msi_info, diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 0cc877cd1d..74b83a3ff0 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -28,12 +28,12 @@ extern crate bitflags; use std::fs::File; use std::sync::{Arc, Mutex}; -#[cfg(target_arch = "x86_64")] -use pcid_interface::irq_helpers::allocate_single_interrupt_vector_for_msi; use pcid_interface::irq_helpers::read_bsp_apic_id; -use pcid_interface::{ - MsiSetFeatureInfo, PciFeature, PciFeatureInfo, PciFunctionHandle, SetFeatureInfo, +#[cfg(target_arch = "x86_64")] +use pcid_interface::irq_helpers::{ + allocate_first_msi_interrupt_on_bsp, allocate_single_interrupt_vector_for_msi, }; +use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle}; use redox_scheme::{RequestKind, SignalBehavior, Socket}; @@ -89,29 +89,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> (Option, Interru method } else if has_msi { - let mut capability = match pcid_handle.feature_info(PciFeature::Msi) { - PciFeatureInfo::Msi(s) => s, - PciFeatureInfo::MsiX(_) => panic!(), - }; - // TODO: Allow allocation of up to 32 vectors. - - // TODO: Find a way to abstract this away, potantially as a helper module for - // pcid_interface, so that this can be shared between nvmed, xhcid, ixgebd, etc.. - - let destination_id = read_bsp_apic_id().expect("xhcid: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - - let set_feature_info = MsiSetFeatureInfo { - multi_message_enable: Some(0), - message_address_and_data: Some(msg_addr_and_data), - mask_bits: None, - }; - pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); - - pcid_handle.enable_feature(PciFeature::Msi); - log::debug!("Enabled MSI"); - + let interrupt_handle = allocate_first_msi_interrupt_on_bsp(pcid_handle); (Some(interrupt_handle), InterruptMethod::Msi) } else if let Some(irq) = pci_config.func.legacy_interrupt_line { log::debug!("Legacy IRQ {}", irq); From b9ce02ea90b926a7b5cfdd925338aac9717d47ad Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Aug 2025 20:11:05 +0200 Subject: [PATCH 1228/1301] storage/nvmed: Remove unused InterruptSources methods and fields --- storage/nvmed/src/main.rs | 9 +--- storage/nvmed/src/nvme/mod.rs | 79 ++--------------------------------- 2 files changed, 4 insertions(+), 84 deletions(-) diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 56e307769d..013cc70589 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -65,18 +65,11 @@ fn get_int_method( Ok((interrupt_method, interrupt_sources)) } else if has_msi { // Message signaled interrupts. - let msi_info = match pcid_handle.feature_info(PciFeature::Msi) { - PciFeatureInfo::Msi(msi) => msi, - _ => unreachable!(), - }; let msi_vector_number = 0; let irq_handle = irq_helpers::allocate_first_msi_interrupt_on_bsp(pcid_handle); - let interrupt_method = InterruptMethod::Msi { - msi_info, - log2_multiple_message_enabled: 0, - }; + let interrupt_method = InterruptMethod::Msi; let interrupt_sources = InterruptSources::Msi(std::iter::once((msi_vector_number, irq_handle)).collect()); diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index 312a0eb3e8..b10369e2cd 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -21,7 +21,7 @@ pub mod queues; use self::executor::NvmeExecutor; pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue}; -use pcid_interface::msi::{MappedMsixRegs, MsiInfo}; +use pcid_interface::msi::MappedMsixRegs; use pcid_interface::PciFunctionHandle; /// Used in conjunction with `InterruptMethod`, primarily by the CQ executor. @@ -31,46 +31,6 @@ pub enum InterruptSources { Msi(BTreeMap), Intx(File), } -impl InterruptSources { - pub fn iter_mut(&mut self) -> impl Iterator { - use std::collections::btree_map::IterMut as BTreeIterMut; - use std::iter::Once; - - enum IterMut<'a> { - Msi(BTreeIterMut<'a, u8, File>), - MsiX(BTreeIterMut<'a, u16, File>), - Intx(Once<&'a mut File>), - } - impl<'a> Iterator for IterMut<'a> { - type Item = (u16, &'a mut File); - - fn next(&mut self) -> Option { - match self { - &mut Self::Msi(ref mut iter) => iter - .next() - .map(|(&vector, handle)| (u16::from(vector), handle)), - &mut Self::MsiX(ref mut iter) => { - iter.next().map(|(&vector, handle)| (vector, handle)) - } - &mut Self::Intx(ref mut iter) => iter.next().map(|handle| (0u16, handle)), - } - } - fn size_hint(&self) -> (usize, Option) { - match self { - &Self::Msi(ref iter) => iter.size_hint(), - &Self::MsiX(ref iter) => iter.size_hint(), - &Self::Intx(ref iter) => iter.size_hint(), - } - } - } - - match self { - &mut Self::MsiX(ref mut map) => IterMut::MsiX(map.iter_mut()), - &mut Self::Msi(ref mut map) => IterMut::Msi(map.iter_mut()), - &mut Self::Intx(ref mut single) => IterMut::Intx(std::iter::once(single)), - } - } -} /// The way interrupts are sent. Unlike other PCI-based interfaces, like XHCI, it doesn't seem like /// NVME supports operating with interrupts completely disabled. @@ -78,36 +38,10 @@ pub enum InterruptMethod { /// Traditional level-triggered, INTx# interrupt pins. Intx, /// Message signaled interrupts - Msi { - msi_info: MsiInfo, - log2_multiple_message_enabled: u8, - }, + Msi, /// Extended message signaled interrupts MsiX(MappedMsixRegs), } -impl InterruptMethod { - fn is_intx(&self) -> bool { - if let Self::Intx = self { - true - } else { - false - } - } - fn is_msi(&self) -> bool { - if let Self::Msi { .. } = self { - true - } else { - false - } - } - fn is_msix(&self) -> bool { - if let Self::MsiX(_) = self { - true - } else { - false - } - } -} #[repr(C, packed)] pub struct NvmeRegs { @@ -373,18 +307,11 @@ impl Nvme { self.regs.write().intmc.write(0x0000_0001); } } - &mut InterruptMethod::Msi { - msi_info: _, - log2_multiple_message_enabled: log2_enabled_messages, - } => { + &mut InterruptMethod::Msi => { let mut to_mask = 0x0000_0000; let mut to_clear = 0x0000_0000; for (vector, mask) in vectors { - assert!( - vector < (1 << log2_enabled_messages), - "nvmed: internal error: MSI vector out of range" - ); let vector = vector as u8; if mask { From 2c9be2e9b80131eeebdb19830441b38bbeeefe6d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Aug 2025 20:12:20 +0200 Subject: [PATCH 1229/1301] xhcid: Remove unused InterruptSources methods and fields --- xhcid/src/main.rs | 7 ++----- xhcid/src/xhci/mod.rs | 38 +++++--------------------------------- 2 files changed, 7 insertions(+), 38 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 74b83a3ff0..7cd01894d7 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -26,7 +26,7 @@ extern crate bitflags; use std::fs::File; -use std::sync::{Arc, Mutex}; +use std::sync::Arc; use pcid_interface::irq_helpers::read_bsp_apic_id; #[cfg(target_arch = "x86_64")] @@ -78,10 +78,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> (Option, Interru table_entry_pointer.write_addr_and_data(msg_addr_and_data); table_entry_pointer.unmask(); - ( - Some(interrupt_handle), - InterruptMethod::MsiX(Mutex::new(info)), - ) + (Some(interrupt_handle), InterruptMethod::Msi) }; pcid_handle.enable_feature(PciFeature::MsiX); diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index bbbfb9ffbd..24e611cc34 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -13,10 +13,9 @@ use std::collections::BTreeMap; use std::convert::TryFrom; use std::fs::File; use std::sync::atomic::AtomicUsize; -use std::sync::{Arc, Mutex, MutexGuard}; +use std::sync::{Arc, Mutex}; use std::{mem, process, slice, thread}; -use pcid_interface::msi::MappedMsixRegs; use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT}; use syscall::{EAGAIN, PAGE_SIZE}; @@ -70,11 +69,8 @@ pub enum InterruptMethod { /// Legacy PCI INTx# interrupt pin. Intx, - /// Message signaled interrupts. + /// (Extended) Message signaled interrupts. Msi, - - /// Extended message signaled interrupts. - MsiX(Mutex), } impl Xhci { @@ -1142,32 +1138,8 @@ impl Xhci { Ok(ring) } - pub fn uses_msi(&self) -> bool { - if let InterruptMethod::Msi = self.interrupt_method { - true - } else { - false - } - } - pub fn uses_msix(&self) -> bool { - if let InterruptMethod::MsiX(_) = self.interrupt_method { - true - } else { - false - } - } - // TODO: Perhaps use an rwlock? - pub fn msix_info(&self) -> Option> { - match self.interrupt_method { - InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), - _ => None, - } - } - pub fn msix_info_mut(&self) -> Option> { - match self.interrupt_method { - InterruptMethod::MsiX(ref info) => Some(info.lock().unwrap()), - _ => None, - } + fn uses_msi_interrupts(&self) -> bool { + matches!(self.interrupt_method, InterruptMethod::Msi) } /// Checks whether an IRQ has been received from *this* device, in case of an interrupt. Always @@ -1175,7 +1147,7 @@ impl Xhci { pub fn received_irq(&self) -> bool { let mut runtime_regs = self.run.lock().unwrap(); - if self.uses_msi() || self.uses_msix() { + if self.uses_msi_interrupts() { // Since using MSI and MSI-X implies having no IRQ sharing whatsoever, the IP bit // doesn't have to be touched. trace!( From e4aab16782651073e6e923d9c89ab61635bc95f6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Aug 2025 22:08:15 +0200 Subject: [PATCH 1230/1301] xhcid: Don't exit the event loop when using irqs --- xhcid/src/xhci/irq_reactor.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index d3c82f699f..8215f06034 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -121,7 +121,7 @@ impl IrqReactor { fn pause(&self) { std::thread::sleep(std::time::Duration::from_millis(2)); } - fn run_polling(mut self) { + fn run_polling(mut self) -> ! { debug!("Running IRQ reactor in polling mode."); let hci_clone = Arc::clone(&self.hci); @@ -204,11 +204,11 @@ impl IrqReactor { run.ints[0].iman.writef(1 << 1, true); } - fn run_with_irq_file(mut self) { + fn run_with_irq_file(mut self) -> ! { debug!("Running IRQ reactor with IRQ file and event queue"); let hci_clone = Arc::clone(&self.hci); - let mut event_queue = + let event_queue = RawEventQueue::new().expect("xhcid irq_reactor: failed to create IRQ event queue"); let irq_fd = self.irq_file.as_ref().unwrap().as_raw_fd(); event_queue @@ -226,7 +226,8 @@ impl IrqReactor { }; trace!("IRQ reactor has grabbed the next index in the event ring."); - for _event in event_queue { + 'trb_loop: loop { + let _event = event_queue.next_event().unwrap(); trace!("IRQ event queue notified"); let mut buffer = [0u8; 8]; @@ -240,7 +241,7 @@ impl IrqReactor { if !self.hci.received_irq() { // continue only when an IRQ to this device was received trace!("no interrupt pending"); - break; + continue 'trb_loop; } self.mask_interrupts(); @@ -265,7 +266,7 @@ impl IrqReactor { } //hci_clone.event_handler_finished(); self.unmask_interrupts(); - return; + continue 'trb_loop; } else { count += 1 } @@ -287,7 +288,7 @@ impl IrqReactor { debug!("The interrupt bit is no longer pending."); } self.unmask_interrupts(); - return; + continue 'trb_loop; } self.handle_requests(); @@ -309,9 +310,7 @@ impl IrqReactor { event_trb_index = event_ring.ring.next_index(); } - trace!("Exited event loop!"); } - trace!("IRQ Reactor has finished handling the interrupt"); } /// Handles device attach/detach events as indicated by a PortStatusChange @@ -538,7 +537,7 @@ impl IrqReactor { error!("TODO: grow event ring"); } - pub fn run(mut self) { + pub fn run(self) -> ! { if self.irq_file.is_some() { self.run_with_irq_file(); } else { From 7e3e841f694374c0047586b853b0867d1919f76f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Aug 2025 22:09:06 +0200 Subject: [PATCH 1231/1301] xhcid: Fix reading EHB flag in received_irq --- xhcid/src/xhci/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 24e611cc34..38a447bd1e 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -1153,14 +1153,14 @@ impl Xhci { trace!( "Successfully received MSI/MSI-X interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), - runtime_regs.ints[0].erdp_low.readf(3) + runtime_regs.ints[0].erdp_low.readf(1 << 3) ); true } else if runtime_regs.ints[0].iman.readf(1) { trace!( "Successfully received INTx# interrupt, IP={}, EHB={}", runtime_regs.ints[0].iman.readf(1), - runtime_regs.ints[0].erdp_low.readf(3) + runtime_regs.ints[0].erdp_low.readf(1 << 3) ); // If MSI and/or MSI-X are not used, the interrupt might have to be shared, and thus there is // a special register to specify whether the IRQ actually came from the xHC. From 131063eb0eeb597befdb005eb9287f08204a1b61 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 31 Aug 2025 16:07:57 +0200 Subject: [PATCH 1232/1301] Rustfmt --- virtio-core/src/probe.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/virtio-core/src/probe.rs b/virtio-core/src/probe.rs index da95234636..5762912f8e 100644 --- a/virtio-core/src/probe.rs +++ b/virtio-core/src/probe.rs @@ -18,7 +18,6 @@ pub struct Device { unsafe impl Send for Device {} unsafe impl Sync for Device {} - pub const MSIX_PRIMARY_VECTOR: u16 = 0; /// VirtIO Device Probe From 69a80a6a13b2e6d592d7e4c34b02f87422efd802 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 11 Sep 2025 15:31:15 -0600 Subject: [PATCH 1233/1301] xhcid: fix reset procedure on real hardware --- xhcid/src/xhci/mod.rs | 12 ++++++------ xhcid/src/xhci/operational.rs | 10 ++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index 38a447bd1e..fbf75bff59 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -49,7 +49,7 @@ use self::doorbell::Doorbell; use self::event::EventRing; use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap}; use self::irq_reactor::{EventDoorbell, IrqReactor, NewPendingTrb, RingId}; -use self::operational::OperationalRegs; +use self::operational::*; use self::port::Port; use self::ring::Ring; use self::runtime::RuntimeRegs; @@ -372,23 +372,23 @@ impl Xhci { let (max_slots, max_ports) = { debug!("Waiting for xHC becoming ready."); // Wait until controller is ready - while op.usb_sts.readf(1 << 11) { + while op.usb_sts.readf(USB_STS_CNR) { trace!("Waiting for the xHC to be ready."); } debug!("Stopping the xHC"); // Set run/stop to 0 - op.usb_cmd.writef(1, false); + op.usb_cmd.writef(USB_CMD_RS, false); debug!("Waiting for the xHC to stop."); // Wait until controller not running - while !op.usb_sts.readf(1) { + while !op.usb_sts.readf(USB_STS_HCH) { trace!("Waiting for the xHC to stop."); } debug!("Resetting the xHC."); - op.usb_cmd.writef(1 << 1, true); - while op.usb_sts.readf(1 << 1) { + op.usb_cmd.writef(USB_CMD_HCRST, true); + while op.usb_cmd.readf(USB_CMD_HCRST) { trace!("Waiting for the xHC to reset."); } diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index 6562a48760..4ac6549179 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -76,6 +76,16 @@ pub struct OperationalRegs { // The standard has 400-13FFh has a Port Register Set here (likely defined in port.rs). } +// Run/stop +pub const USB_CMD_RS: u32 = 1 << 0; +/// Host controller reset +pub const USB_CMD_HCRST: u32 = 1 << 1; + +/// Host controller halted +pub const USB_STS_HCH: u32 = 1 << 0; +/// Host controller not ready +pub const USB_STS_CNR: u32 = 1 << 11; + /// The mask to get the CIE bit from the Config register. See [OperationalRegs] pub const OP_CONFIG_CIE_BIT: u32 = 1 << 9; From 12e601b336ec9925f91359838292658e6b214fc4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 11 Sep 2025 21:06:21 -0600 Subject: [PATCH 1234/1301] xhcid: improvements based on real hardware testing --- xhcid/src/xhci/mod.rs | 35 +++++++++++++++++++---------------- xhcid/src/xhci/operational.rs | 2 ++ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index fbf75bff59..fe633432db 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -465,12 +465,12 @@ impl Xhci { pub fn init(&mut self, max_slots: u8) -> Result<()> { // Set run/stop to 0 debug!("Stopping xHC."); - self.op.get_mut().unwrap().usb_cmd.writef(1, false); + self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, false); // Warm reset debug!("Reset xHC"); - self.op.get_mut().unwrap().usb_cmd.writef(1 << 1, true); - while self.op.get_mut().unwrap().usb_cmd.readf(1 << 1) { + self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_HCRST, true); + while self.op.get_mut().unwrap().usb_cmd.readf(USB_CMD_HCRST) { thread::yield_now(); } @@ -531,18 +531,18 @@ impl Xhci { debug!("Enabling Primary Interrupter."); int.iman.writef(1 << 1 | 1, true); } - self.op.get_mut().unwrap().usb_cmd.writef(1 << 2, true); + self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_INTE, true); // Setup the scratchpad buffers that are required for the xHC to function. self.setup_scratchpads()?; // Set run/stop to 1 debug!("Starting xHC."); - self.op.get_mut().unwrap().usb_cmd.writef(1, true); + self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, true); // Wait until controller is running debug!("Waiting for start request to complete."); - while self.op.get_mut().unwrap().usb_sts.readf(1) { + while self.op.get_mut().unwrap().usb_sts.readf(USB_STS_HCH) { trace!("Waiting for XHCI to report running status."); } @@ -796,7 +796,7 @@ impl Xhci { info!("Attempting to address the device"); let mut ring = match self - .address_device(&mut input, port_id, slot_ty, slot, protocol_speed) + .address_device(&mut input, port_id, slot_ty, slot, protocol_speed, speed) .await { Ok(device_ring) => device_ring, @@ -1012,6 +1012,7 @@ impl Xhci { slot_ty: u8, slot: u8, protocol_speed: &ProtocolSpeed, + speed: u8, ) -> Result { // Collect MTT, parent port number, parent slot ID let mut mtt = false; @@ -1057,6 +1058,7 @@ impl Xhci { assert_eq!(route_string & 0x000F_FFFF, route_string); slot_ctx.a.write( route_string + | (u32::from(speed) << 20) | (u32::from(mtt) << 25) | (u32::from(hub) << 26) | (u32::from(context_entries) << 27), @@ -1087,16 +1089,12 @@ impl Xhci { let max_error_count = 3u8; // recommended value according to the XHCI spec let ep_ty = 4u8; // control endpoint, bidirectional - let max_packet_size: u32 = if protocol_speed.is_lowspeed() { - 8 // only valid value - } else if protocol_speed.is_fullspeed() { - 64 // valid values are 8, 16, 32, 64 + let max_packet_size: u32 = if protocol_speed.is_lowspeed() || protocol_speed.is_fullspeed() { + 8 } else if protocol_speed.is_highspeed() { - 64 // only valid value - } else if protocol_speed.is_superspeed_gen_x() { - 512 // only valid value + 64 } else { - unreachable!() + 512 }; let host_initiate_disable = false; // only applies to streams let max_burst_size = 0u8; // TODO @@ -1110,9 +1108,14 @@ impl Xhci { | (u32::from(max_packet_size) << 16), ); + let dequeue_cycle_state = true; let tr = ring.register(); endp_ctx.trh.write((tr >> 32) as u32); - endp_ctx.trl.write(tr as u32); + endp_ctx.trl.write((tr as u32) | u32::from(dequeue_cycle_state)); + + // The default control pipe can always use 8 bytes + let avg_trb_len = 8u8; + endp_ctx.c.write(u32::from(avg_trb_len)); } let input_context_physical = input_context.physical(); diff --git a/xhcid/src/xhci/operational.rs b/xhcid/src/xhci/operational.rs index 4ac6549179..12be477296 100644 --- a/xhcid/src/xhci/operational.rs +++ b/xhcid/src/xhci/operational.rs @@ -80,6 +80,8 @@ pub struct OperationalRegs { pub const USB_CMD_RS: u32 = 1 << 0; /// Host controller reset pub const USB_CMD_HCRST: u32 = 1 << 1; +// Interrupter enable +pub const USB_CMD_INTE: u32 = 1 << 2; /// Host controller halted pub const USB_STS_HCH: u32 = 1 << 0; From 00b06cb91526d43eeac1c7a04e50567b0fd01430 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 12 Sep 2025 09:42:58 -0600 Subject: [PATCH 1235/1301] xhci: support 64-bit contexts (CSZ) --- xhcid/src/main.rs | 23 +++++- xhcid/src/xhci/capability.rs | 9 +++ xhcid/src/xhci/context.rs | 75 +++++++++++------- xhcid/src/xhci/device_enumerator.rs | 8 +- xhcid/src/xhci/event.rs | 6 +- xhcid/src/xhci/irq_reactor.rs | 12 +-- xhcid/src/xhci/mod.rs | 114 ++++++++++++++++------------ xhcid/src/xhci/ring.rs | 4 +- xhcid/src/xhci/scheme.rs | 59 +++++++------- 9 files changed, 185 insertions(+), 125 deletions(-) diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index 7cd01894d7..d85df737d9 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -22,6 +22,9 @@ //! - USB2 - [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification) //! - USB32 - [Universal Serial Bus 3.2 Specification Revision 1.1](https://usb.org/document-library/usb-32-revision-11-june-2022) //! +#![allow(warnings)] +#![feature(generic_const_exprs)] + #[macro_use] extern crate bitflags; @@ -117,8 +120,11 @@ fn main() { redox_daemon::Daemon::new(daemon).expect("xhcid: failed to daemonize"); } -fn daemon(daemon: redox_daemon::Daemon) -> ! { - let mut pcid_handle = PciFunctionHandle::connect_default(); +//TODO: cleanup CSZ support +fn daemon_with_context_size( + daemon: redox_daemon::Daemon, + mut pcid_handle: PciFunctionHandle, +) -> ! { let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); @@ -147,7 +153,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("xhcid: failed to notify parent"); let hci = Arc::new( - Xhci::new(scheme_name, address, interrupt_method, pcid_handle) + Xhci::::new(scheme_name, address, interrupt_method, pcid_handle) .expect("xhcid: failed to allocate device"), ); @@ -179,3 +185,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } } + +fn daemon(daemon: redox_daemon::Daemon) -> ! { + let mut pcid_handle = PciFunctionHandle::connect_default(); + let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; + let cap = unsafe { &mut *(address as *mut xhci::CapabilityRegs) }; + if cap.csz() { + daemon_with_context_size::<{ xhci::CONTEXT_64 }>(daemon, pcid_handle) + } else { + daemon_with_context_size::<{ xhci::CONTEXT_32 }>(daemon, pcid_handle) + } +} diff --git a/xhcid/src/xhci/capability.rs b/xhcid/src/xhci/capability.rs index cc45611c7d..2ad4ad1aa0 100644 --- a/xhcid/src/xhci/capability.rs +++ b/xhcid/src/xhci/capability.rs @@ -120,6 +120,10 @@ pub struct CapabilityRegs { pub const HCC_PARAMS1_AC64_BIT: u32 = 1 << HCC_PARAMS1_AC64_SHIFT; /// The shift to use to get the AC64 bit from HCCParams1. See [CapabilityRegs] pub const HCC_PARAMS1_AC64_SHIFT: u8 = 0; +/// The mask to use to get the CSZ bit from HCCPARAMS1. See [CapabilityRegs] +pub const HCC_PARAMS1_CSZ_BIT: u32 = 1 << HCC_PARAMS1_CSZ_SHIFT; +/// The shift to use to get the CSZ bit from HCCParams1. See [CapabilityRegs] +pub const HCC_PARAMS1_CSZ_SHIFT: u8 = 2; /// The Mask to use to get the MAXPSASIZE value from HCCParams1. See [CapabilityRegs] pub const HCC_PARAMS1_MAXPSASIZE_MASK: u32 = 0xF000; // 15:12 /// The shift to use to get the MAXPSASIZE value from HCCParams1. See [CapabilityRegs] @@ -161,6 +165,11 @@ impl CapabilityRegs { self.hcc_params1.readf(HCC_PARAMS1_AC64_BIT) } + /// Gets the context size (CSZ) bit from HCCParams1. + pub fn csz(&self) -> bool { + self.hcc_params1.readf(HCC_PARAMS1_CSZ_BIT) + } + /// Gets the LEC bit from HCCParams2. pub fn lec(&self) -> bool { self.hcc_params2.readf(HCC_PARAMS2_LEC_BIT) diff --git a/xhcid/src/xhci/context.rs b/xhcid/src/xhci/context.rs index 497a39dafe..b8f2f45a95 100644 --- a/xhcid/src/xhci/context.rs +++ b/xhcid/src/xhci/context.rs @@ -10,24 +10,25 @@ use common::dma::Dma; use super::ring::Ring; use super::Xhci; +pub const CONTEXT_32: usize = 0; +pub const CONTEXT_64: usize = 1; + #[repr(C, packed)] -pub struct SlotContext { +struct Rsvd64([[Mmio; 8]; N]); + +#[repr(C, packed)] +pub struct SlotContext { pub a: Mmio, pub b: Mmio, pub c: Mmio, pub d: Mmio, _rsvd: [Mmio; 4], + _rsvd64: Rsvd64, } pub const SLOT_CONTEXT_STATE_MASK: u32 = 0xF800_0000; pub const SLOT_CONTEXT_STATE_SHIFT: u8 = 27; -impl SlotContext { - pub fn state(&self) -> u8 { - ((self.d.read() & SLOT_CONTEXT_STATE_MASK) >> SLOT_CONTEXT_STATE_SHIFT) as u8 - } -} - #[repr(u8)] pub enum SlotState { EnabledOrDisabled = 0, @@ -37,32 +38,34 @@ pub enum SlotState { } #[repr(C, packed)] -pub struct EndpointContext { +pub struct EndpointContext { pub a: Mmio, pub b: Mmio, pub trl: Mmio, pub trh: Mmio, pub c: Mmio, _rsvd: [Mmio; 3], + _rsvd64: Rsvd64, } pub const ENDPOINT_CONTEXT_STATUS_MASK: u32 = 0x7; #[repr(C, packed)] -pub struct DeviceContext { - pub slot: SlotContext, - pub endpoints: [EndpointContext; 31], +pub struct DeviceContext { + pub slot: SlotContext, + pub endpoints: [EndpointContext; 31], } #[repr(C, packed)] -pub struct InputContext { +pub struct InputContext { pub drop_context: Mmio, pub add_context: Mmio, _rsvd: [Mmio; 5], pub control: Mmio, - pub device: DeviceContext, + _rsvd64: Rsvd64, + pub device: DeviceContext, } -impl InputContext { +impl InputContext { pub fn dump_control(&self) { debug!( "INPUT CONTEXT: {} {} [{} {} {} {} {}] {}", @@ -78,19 +81,19 @@ impl InputContext { } } -pub struct DeviceContextList { +pub struct DeviceContextList { pub dcbaa: Dma<[u64; 256]>, - pub contexts: Box<[Dma]>, + pub contexts: Box<[Dma>]>, } -impl DeviceContextList { - pub fn new(ac64: bool, max_slots: u8) -> Result { - let mut dcbaa = unsafe { Xhci::alloc_dma_zeroed_raw::<[u64; 256]>(ac64)? }; +impl DeviceContextList { + pub fn new(ac64: bool, max_slots: u8) -> Result { + let mut dcbaa = unsafe { Xhci::::alloc_dma_zeroed_raw::<[u64; 256]>(ac64)? }; let mut contexts = vec![]; // Create device context buffers for each slot for i in 0..max_slots as usize { - let context: Dma = unsafe { Xhci::alloc_dma_zeroed_raw(ac64) }?; + let context: Dma> = unsafe { Xhci::::alloc_dma_zeroed_raw(ac64) }?; dcbaa[i] = context.physical() as u64; contexts.push(context); } @@ -134,19 +137,24 @@ pub struct StreamContextArray { } impl StreamContextArray { - pub fn new(ac64: bool, count: usize) -> Result { + pub fn new(ac64: bool, count: usize) -> Result { unsafe { Ok(Self { - contexts: Xhci::alloc_dma_zeroed_unsized_raw(ac64, count)?, + contexts: Xhci::::alloc_dma_zeroed_unsized_raw(ac64, count)?, rings: BTreeMap::new(), }) } } - pub fn add_ring(&mut self, ac64: bool, stream_id: u16, link: bool) -> Result<()> { + pub fn add_ring( + &mut self, + ac64: bool, + stream_id: u16, + link: bool, + ) -> Result<()> { // NOTE: stream_id 0 is reserved assert_ne!(stream_id, 0); - let ring = Ring::new(ac64, 16, link)?; + let ring = Ring::new::(ac64, 16, link)?; let pointer = ring.register(); let sct = StreamContextType::PrimaryRing; @@ -182,8 +190,9 @@ pub struct ScratchpadBufferArray { pub pages: Vec>, } impl ScratchpadBufferArray { - pub fn new(ac64: bool, entries: u16) -> Result { - let mut entries = unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? }; + pub fn new(ac64: bool, entries: u16) -> Result { + let mut entries = + unsafe { Xhci::::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? }; let pages = entries .iter_mut() @@ -203,3 +212,17 @@ impl ScratchpadBufferArray { self.entries.physical() } } + +#[cfg(test)] +mod test { + use super::*; + use core::mem; + + #[test] + fn context_size() { + assert_eq!(mem::size_of::>(), 32); + assert_eq!(mem::size_of::>(), 64); + assert_eq!(mem::size_of::>(), 32); + assert_eq!(mem::size_of::>(), 64); + } +} diff --git a/xhcid/src/xhci/device_enumerator.rs b/xhcid/src/xhci/device_enumerator.rs index f33f420c90..a48900c226 100644 --- a/xhcid/src/xhci/device_enumerator.rs +++ b/xhcid/src/xhci/device_enumerator.rs @@ -11,13 +11,13 @@ pub struct DeviceEnumerationRequest { pub port_id: PortId, } -pub struct DeviceEnumerator { - hci: Arc, +pub struct DeviceEnumerator { + hci: Arc>, request_queue: crossbeam_channel::Receiver, } -impl DeviceEnumerator { - pub fn new(hci: Arc) -> Self { +impl DeviceEnumerator { + pub fn new(hci: Arc>) -> Self { let request_queue = hci.device_enumerator_receiver.clone(); DeviceEnumerator { hci, request_queue } } diff --git a/xhcid/src/xhci/event.rs b/xhcid/src/xhci/event.rs index 47c370ccff..83af1209af 100644 --- a/xhcid/src/xhci/event.rs +++ b/xhcid/src/xhci/event.rs @@ -23,10 +23,10 @@ pub struct EventRing { } impl EventRing { - pub fn new(ac64: bool) -> Result { + pub fn new(ac64: bool) -> Result { let mut ring = EventRing { - ste: unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, 1)? }, - ring: Ring::new(ac64, 256, false)?, + ste: unsafe { Xhci::::alloc_dma_zeroed_unsized_raw(ac64, 1)? }, + ring: Ring::new::(ac64, 256, false)?, }; ring.ste[0] diff --git a/xhcid/src/xhci/irq_reactor.rs b/xhcid/src/xhci/irq_reactor.rs index 8215f06034..ac492d5bc1 100644 --- a/xhcid/src/xhci/irq_reactor.rs +++ b/xhcid/src/xhci/irq_reactor.rs @@ -92,8 +92,8 @@ impl StateKind { } } -pub struct IrqReactor { - hci: Arc, +pub struct IrqReactor { + hci: Arc>, irq_file: Option, irq_receiver: Receiver, device_enumerator_sender: Sender, @@ -104,8 +104,8 @@ pub struct IrqReactor { pub type NewPendingTrb = State; -impl IrqReactor { - pub fn new(hci: Arc, irq_file: Option) -> Self { +impl IrqReactor { + pub fn new(hci: Arc>, irq_file: Option) -> Self { let device_enumerator_sender = hci.device_enumerator_sender.clone(); let irq_receiver = hci.irq_reactor_receiver.clone(); @@ -559,7 +559,7 @@ pub struct EventDoorbell { } impl EventDoorbell { - pub fn new(hci: &Xhci, index: usize, data: u32) -> Self { + pub fn new(hci: &Xhci, index: usize, data: u32) -> Self { Self { //TODO: simplify this logic, maybe just use a raw pointer? dbs: hci.dbs.clone(), @@ -625,7 +625,7 @@ impl Future for EventTrbFuture { } } -impl Xhci { +impl Xhci { pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option { self.with_ring(id, |ring| ring.phys_addr_to_entry(self.cap.ac64(), paddr)) .flatten() diff --git a/xhcid/src/xhci/mod.rs b/xhcid/src/xhci/mod.rs index fe633432db..aea7439397 100644 --- a/xhcid/src/xhci/mod.rs +++ b/xhcid/src/xhci/mod.rs @@ -43,8 +43,12 @@ mod runtime; pub mod scheme; mod trb; -use self::capability::CapabilityRegs; -use self::context::{DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray}; +pub use self::capability::CapabilityRegs; +use self::context::{ + DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray, + SLOT_CONTEXT_STATE_MASK, SLOT_CONTEXT_STATE_SHIFT, +}; +pub use self::context::{CONTEXT_32, CONTEXT_64}; use self::doorbell::Doorbell; use self::event::EventRing; use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap}; @@ -73,7 +77,7 @@ pub enum InterruptMethod { Msi, } -impl Xhci { +impl Xhci { /// Gets descriptors, before the port state is initiated. async fn get_desc_raw( &self, @@ -246,7 +250,7 @@ impl Xhci { } /// The eXtensible Host Controller Interface (XHCI) data structure -pub struct Xhci { +pub struct Xhci { // immutable /// The Host Controller Interface Capability Registers. These read-only registers specify the /// limits and capabilities of the host controller implementation (See XHCI section 5.3) @@ -270,7 +274,7 @@ pub struct Xhci { primary_event_ring: Mutex, // immutable - dev_ctx: DeviceContextList, + dev_ctx: DeviceContextList, scratchpad_buf_arr: Option, // used for the extended capabilities, and so far none of them are mutated, and thus no lock. @@ -278,7 +282,7 @@ pub struct Xhci { handles: CHashMap, next_handle: AtomicUsize, - port_states: CHashMap, + port_states: CHashMap>, drivers: CHashMap>, scheme_name: String, @@ -297,19 +301,19 @@ pub struct Xhci { device_enumerator_receiver: Receiver, } -unsafe impl Send for Xhci {} -unsafe impl Sync for Xhci {} +unsafe impl Send for Xhci {} +unsafe impl Sync for Xhci {} -struct PortState { +struct PortState { slot: u8, protocol_speed: &'static ProtocolSpeed, cfg_idx: Option, - input_context: Mutex>, + input_context: Mutex>>, dev_desc: Option, endpoint_states: BTreeMap, } -impl PortState { +impl PortState { //TODO: fetch using endpoint number instead fn get_endp_desc(&self, endp_idx: u8) -> Option<&EndpDesc> { let cfg_idx = self.cfg_idx?; @@ -350,13 +354,13 @@ impl EndpointState { } } -impl Xhci { +impl Xhci { pub fn new( scheme_name: String, address: usize, interrupt_method: InterruptMethod, pcid_handle: PciFunctionHandle, - ) -> Result { + ) -> Result { //Locate the capability registers from the mapped PCI Bar let cap = unsafe { &mut *(address as *mut CapabilityRegs) }; debug!("CAP REGS BASE {:X}", address); @@ -419,7 +423,7 @@ impl Xhci { // Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the // DMA allocation (which is at least a 4k page). let entries_per_page = PAGE_SIZE / mem::size_of::(); - let cmd = Ring::new(cap.ac64(), entries_per_page, true)?; + let cmd = Ring::new::(cap.ac64(), entries_per_page, true)?; let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded(); @@ -439,7 +443,7 @@ impl Xhci { scratchpad_buf_arr: None, // initialized in init() cmd: Mutex::new(cmd), - primary_event_ring: Mutex::new(EventRing::new(cap.ac64())?), + primary_event_ring: Mutex::new(EventRing::new::(cap.ac64())?), handles: CHashMap::new(), next_handle: AtomicUsize::new(0), port_states: CHashMap::new(), @@ -469,7 +473,11 @@ impl Xhci { // Warm reset debug!("Reset xHC"); - self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_HCRST, true); + self.op + .get_mut() + .unwrap() + .usb_cmd + .writef(USB_CMD_HCRST, true); while self.op.get_mut().unwrap().usb_cmd.readf(USB_CMD_HCRST) { thread::yield_now(); } @@ -531,7 +539,11 @@ impl Xhci { debug!("Enabling Primary Interrupter."); int.iman.writef(1 << 1 | 1, true); } - self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_INTE, true); + self.op + .get_mut() + .unwrap() + .usb_cmd + .writef(USB_CMD_INTE, true); // Setup the scratchpad buffers that are required for the xHC to function. self.setup_scratchpads()?; @@ -674,7 +686,7 @@ impl Xhci { if buf_count == 0 { return Ok(()); } - let scratchpad_buf_arr = ScratchpadBufferArray::new(self.cap.ac64(), buf_count)?; + let scratchpad_buf_arr = ScratchpadBufferArray::new::(self.cap.ac64(), buf_count)?; self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64; debug!( "Setting up {} scratchpads, at {:#0x}", @@ -733,7 +745,8 @@ impl Xhci { } pub fn slot_state(&self, slot: usize) -> u8 { - self.dev_ctx.contexts[slot].slot.state() + ((self.dev_ctx.contexts[slot].slot.d.read() & SLOT_CONTEXT_STATE_MASK) + >> SLOT_CONTEXT_STATE_SHIFT) as u8 } pub unsafe fn alloc_dma_zeroed_raw(_ac64: bool) -> Result> { // TODO: ac64 @@ -792,7 +805,7 @@ impl Xhci { .lookup_psiv(port_id, speed) .expect("Failed to retrieve speed ID"); - let mut input = unsafe { self.alloc_dma_zeroed::()? }; + let mut input = unsafe { self.alloc_dma_zeroed::>()? }; info!("Attempting to address the device"); let mut ring = match self @@ -940,7 +953,7 @@ impl Xhci { pub async fn update_max_packet_size( &self, - input_context: &mut Dma, + input_context: &mut Dma>, slot_id: u8, dev_desc: usb::DeviceDescriptor8Byte, ) -> Result<()> { @@ -951,11 +964,10 @@ impl Xhci { // For later USB versions, packet_size is the shift 1u32 << dev_desc.packet_size }; - let endp_ctx = &mut input_context.device.endpoints[0]; - let mut b = endp_ctx.b.read(); + let mut b = input_context.device.endpoints[0].b.read(); b &= 0x0000_FFFF; b |= (new_max_packet_size) << 16; - endp_ctx.b.write(b); + input_context.device.endpoints[0].b.write(b); let (event_trb, command_trb) = self .execute_command(|trb, cycle| { @@ -971,7 +983,7 @@ impl Xhci { pub async fn update_default_control_pipe( &self, - input_context: &mut Dma, + input_context: &mut Dma>, slot_id: u8, dev_desc: &DevDesc, ) -> Result<()> { @@ -986,11 +998,10 @@ impl Xhci { // For later USB versions, packet_size is the shift 1u32 << dev_desc.packet_size }; - let endp_ctx = &mut input_context.device.endpoints[0]; - let mut b = endp_ctx.b.read(); + let mut b = input_context.device.endpoints[0].b.read(); b &= 0x0000_FFFF; b |= (new_max_packet_size) << 16; - endp_ctx.b.write(b); + input_context.device.endpoints[0].b.write(b); let (event_trb, command_trb) = self .execute_command(|trb, cycle| { @@ -1007,7 +1018,7 @@ impl Xhci { pub async fn address_device( &self, - input_context: &mut Dma, + input_context: &mut Dma>, port: PortId, slot_ty: u8, slot: u8, @@ -1044,19 +1055,17 @@ impl Xhci { } } - let mut ring = Ring::new(self.cap.ac64(), 16, true)?; + let mut ring = Ring::new::(self.cap.ac64(), 16, true)?; { input_context.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit). - let slot_ctx = &mut input_context.device.slot; - let route_string = port.route_string; let context_entries = 1u8; let hub = false; assert_eq!(route_string & 0x000F_FFFF, route_string); - slot_ctx.a.write( + input_context.device.slot.a.write( route_string | (u32::from(speed) << 20) | (u32::from(mtt) << 25) @@ -1067,7 +1076,7 @@ impl Xhci { let max_exit_latency = 0u16; let root_hub_port_num = port.root_hub_port_num; let number_of_ports = 0u8; - slot_ctx.b.write( + input_context.device.slot.b.write( u32::from(max_exit_latency) | (u32::from(root_hub_port_num) << 16) | (u32::from(number_of_ports) << 24), @@ -1078,29 +1087,28 @@ impl Xhci { let interrupter = 0u8; assert_eq!(ttt & 0b11, ttt); - slot_ctx.c.write( + input_context.device.slot.c.write( u32::from(parent_hub_slot_id) | (u32::from(parent_port_num) << 8) | (u32::from(ttt) << 16) | (u32::from(interrupter) << 22), ); - let endp_ctx = &mut input_context.device.endpoints[0]; - let max_error_count = 3u8; // recommended value according to the XHCI spec let ep_ty = 4u8; // control endpoint, bidirectional - let max_packet_size: u32 = if protocol_speed.is_lowspeed() || protocol_speed.is_fullspeed() { - 8 - } else if protocol_speed.is_highspeed() { - 64 - } else { - 512 - }; + let max_packet_size: u32 = + if protocol_speed.is_lowspeed() || protocol_speed.is_fullspeed() { + 8 + } else if protocol_speed.is_highspeed() { + 64 + } else { + 512 + }; let host_initiate_disable = false; // only applies to streams let max_burst_size = 0u8; // TODO assert_eq!(max_error_count & 0b11, max_error_count); - endp_ctx.b.write( + input_context.device.endpoints[0].b.write( (u32::from(max_error_count) << 1) | (u32::from(ep_ty) << 3) | (u32::from(host_initiate_disable) << 7) @@ -1110,12 +1118,18 @@ impl Xhci { let dequeue_cycle_state = true; let tr = ring.register(); - endp_ctx.trh.write((tr >> 32) as u32); - endp_ctx.trl.write((tr as u32) | u32::from(dequeue_cycle_state)); + input_context.device.endpoints[0] + .trh + .write((tr >> 32) as u32); + input_context.device.endpoints[0] + .trl + .write((tr as u32) | u32::from(dequeue_cycle_state)); // The default control pipe can always use 8 bytes let avg_trb_len = 8u8; - endp_ctx.c.write(u32::from(avg_trb_len)); + input_context.device.endpoints[0] + .c + .write(u32::from(avg_trb_len)); } let input_context_physical = input_context.physical(); @@ -1394,7 +1408,7 @@ impl Xhci { .find(|speed| speed.psiv() == psiv) } } -pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { +pub fn start_irq_reactor(hci: &Arc>, irq_file: Option) { let hci_clone = Arc::clone(&hci); debug!("About to start IRQ reactor"); @@ -1405,7 +1419,7 @@ pub fn start_irq_reactor(hci: &Arc, irq_file: Option) { })); } -pub fn start_device_enumerator(hci: &Arc) { +pub fn start_device_enumerator(hci: &Arc>) { let hci_clone = Arc::clone(&hci); debug!("About to start Device Enumerator"); diff --git a/xhcid/src/xhci/ring.rs b/xhcid/src/xhci/ring.rs index e0e76d5228..8e187ebea4 100644 --- a/xhcid/src/xhci/ring.rs +++ b/xhcid/src/xhci/ring.rs @@ -15,10 +15,10 @@ pub struct Ring { } impl Ring { - pub fn new(ac64: bool, length: usize, link: bool) -> Result { + pub fn new(ac64: bool, length: usize, link: bool) -> Result { Ok(Ring { link, - trbs: unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, length)? }, + trbs: unsafe { Xhci::::alloc_dma_zeroed_unsized_raw(ac64, length)? }, i: 0, cycle: link, }) diff --git a/xhcid/src/xhci/scheme.rs b/xhcid/src/xhci/scheme.rs index 12d77d39e3..1b92fa51aa 100644 --- a/xhcid/src/xhci/scheme.rs +++ b/xhcid/src/xhci/scheme.rs @@ -40,7 +40,10 @@ use syscall::{ use super::{port, usb}; use super::{EndpointState, PortId, Xhci}; -use super::context::{SlotState, StreamContextArray, StreamContextType}; +use super::context::{ + SlotState, StreamContextArray, StreamContextType, CONTEXT_32, CONTEXT_64, + SLOT_CONTEXT_STATE_MASK, SLOT_CONTEXT_STATE_SHIFT, +}; use super::extended::ProtocolSpeed; use super::irq_reactor::{EventDoorbell, RingId}; use super::ring::Ring; @@ -543,7 +546,7 @@ impl AnyDescriptor { } } -impl Xhci { +impl Xhci { async fn new_if_desc( &self, port_id: PortId, @@ -927,13 +930,13 @@ impl Xhci { fn port_state( &self, port: PortId, - ) -> Result> { + ) -> Result>> { self.port_states.get(&port).ok_or(Error::new(EBADF)) } fn port_state_mut( &self, port: PortId, - ) -> Result> { + ) -> Result>> { self.port_states.get_mut(&port).ok_or(Error::new(EBADF)) } @@ -1103,10 +1106,10 @@ impl Xhci { let ring_ptr = if usb_log_max_streams.is_some() { let mut array = - StreamContextArray::new(self.cap.ac64(), 1 << (primary_streams + 1))?; + StreamContextArray::new::(self.cap.ac64(), 1 << (primary_streams + 1))?; // TODO: Use as many stream rings as needed. - array.add_ring(self.cap.ac64(), 1, true)?; + array.add_ring::(self.cap.ac64(), 1, true)?; let array_ptr = array.register(); assert_eq!( @@ -1124,7 +1127,7 @@ impl Xhci { array_ptr } else { - let ring = Ring::new(self.cap.ac64(), 16, true)?; + let ring = Ring::new::(self.cap.ac64(), 16, true)?; let ring_ptr = ring.register(); assert_eq!( @@ -1146,23 +1149,15 @@ impl Xhci { let mut input_context = port_state.input_context.lock().unwrap(); input_context.add_context.writef(1 << endp_num_xhc, true); - let endp_ctx = input_context - .device - .endpoints - .get_mut(endp_num_xhc as usize - 1) - .ok_or_else(|| { - warn!("failed to find endpoint {}", endp_num_xhc - 1); - Error::new(EIO) - })?; - - endp_ctx.a.write( + let endp_i = endp_num_xhc as usize - 1; + input_context.device.endpoints[endp_i].a.write( u32::from(mult) << 8 | u32::from(primary_streams) << 10 | u32::from(linear_stream_array) << 15 | u32::from(interval) << 16 | u32::from(max_esit_payload_hi) << 24, ); - endp_ctx.b.write( + input_context.device.endpoints[endp_i].b.write( max_error_count << 1 | u32::from(ep_ty) << 3 | u32::from(host_initiate_disable) << 7 @@ -1170,10 +1165,14 @@ impl Xhci { | u32::from(max_packet_size) << 16, ); - endp_ctx.trl.write(ring_ptr as u32); - endp_ctx.trh.write((ring_ptr >> 32) as u32); + input_context.device.endpoints[endp_i] + .trl + .write(ring_ptr as u32); + input_context.device.endpoints[endp_i] + .trh + .write((ring_ptr >> 32) as u32); - endp_ctx + input_context.device.endpoints[endp_i] .c .write(u32::from(avg_trb_len) | (u32::from(max_esit_payload_lo) << 16)); @@ -2099,7 +2098,7 @@ impl Xhci { } } -impl SchemeSync for &Xhci { +impl SchemeSync for &Xhci { fn open(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result { if ctx.uid != 0 { return Err(Error::new(EACCES)); @@ -2237,13 +2236,13 @@ impl SchemeSync for &Xhci { }, &mut Handle::PortState(port_num) => { let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?; - let state = self + let ctx = self .dev_ctx .contexts .get(ps.slot as usize) - .ok_or(Error::new(EBADF))? - .slot - .state(); + .ok_or(Error::new(EBADF))?; + let state = ((ctx.slot.d.read() & SLOT_CONTEXT_STATE_MASK) + >> SLOT_CONTEXT_STATE_SHIFT) as u8; let string = match state { 0 => Some(PortState::EnabledOrDisabled), @@ -2257,7 +2256,7 @@ impl SchemeSync for &Xhci { .unwrap_or("unknown") .as_bytes(); - Ok(Xhci::write_dyn_string(string, buf, offset)) + Ok(Xhci::::write_dyn_string(string, buf, offset)) } &mut Handle::PortReq(port_num, ref mut st) => { let state = std::mem::replace(st, PortReqState::Tmp); @@ -2316,7 +2315,7 @@ impl SchemeSync for &Xhci { } } } -impl Xhci { +impl Xhci { pub fn on_close(&self, fd: usize) { self.handles.remove(&fd); } @@ -2351,9 +2350,7 @@ impl Xhci { .contexts .get(slot as usize) .ok_or(Error::new(EBADFD))? - .endpoints - .get(endp_num_xhc as usize - 1) - .ok_or(Error::new(EBADFD))? + .endpoints[endp_num_xhc as usize - 1] .a .read() & super::context::ENDPOINT_CONTEXT_STATUS_MASK; From 1756244e109e49c9663198e0f863520e6e8a7078 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 23 Sep 2025 22:28:15 +0200 Subject: [PATCH 1236/1301] graphics/driver-graphics: Allow larger framebuffers Previously only frame buffers up to 0x1_000_000 bytes were allowed, while we use 0x10_000_000 as multiplier for the fake offsets and thus can safely accept framebuffers this large. This should be enough for 4k displays. --- graphics/driver-graphics/src/lib.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/graphics/driver-graphics/src/lib.rs b/graphics/driver-graphics/src/lib.rs index 383e34cb7f..0fc6995aa0 100644 --- a/graphics/driver-graphics/src/lib.rs +++ b/graphics/driver-graphics/src/lib.rs @@ -225,6 +225,8 @@ impl GraphicsScheme { } } +const MAP_FAKE_OFFSET_MULTIPLIER: usize = 0x10_000_000; + impl SchemeSync for GraphicsScheme { fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result { if path.is_empty() { @@ -490,9 +492,12 @@ impl SchemeSync for GraphicsScheme { } // FIXME use a better scheme for creating map offsets - assert!(fbs[&fb_id].width() * fbs[&fb_id].height() * 4 < 0x1_000_000); + assert!( + ((fbs[&fb_id].width() * fbs[&fb_id].height() * 4) as usize) + < MAP_FAKE_OFFSET_MULTIPLIER + ); - payload.offset = fb_id * 0x10_000_000; + payload.offset = fb_id * MAP_FAKE_OFFSET_MULTIPLIER; Ok(size_of::()) } @@ -562,10 +567,10 @@ impl SchemeSync for GraphicsScheme { next_id: _, fbs, } => ( - fbs.get(&(offset as usize / 0x10_000_000)) + fbs.get(&(offset as usize / MAP_FAKE_OFFSET_MULTIPLIER)) .ok_or(Error::new(EINVAL)) .unwrap(), - offset & (0x10_000_000 - 1), + offset & (MAP_FAKE_OFFSET_MULTIPLIER as u64 - 1), ), }; let ptr = T::map_dumb_framebuffer(&mut self.adapter, framebuffer); From 407533201f1d3c081c54a729da43dec377331bdf Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 24 Sep 2025 17:26:07 -0600 Subject: [PATCH 1237/1301] Add tested Thinkpad T60 ethernet to e1000d driver --- net/e1000d/config.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/e1000d/config.toml b/net/e1000d/config.toml index 44ce84dd09..4862da27dc 100644 --- a/net/e1000d/config.toml +++ b/net/e1000d/config.toml @@ -1,5 +1,5 @@ [[drivers]] name = "E1000 NIC" class = 0x02 -ids = { 0x8086 = [0x1004, 0x100e, 0x100f, 0x1503] } +ids = { 0x8086 = [0x1004, 0x100e, 0x100f, 0x109a, 0x1503] } command = ["e1000d"] From 0b3d81e06b12bc80db49739594684dcb60673553 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 25 Sep 2025 09:50:06 -0600 Subject: [PATCH 1238/1301] lived: preserve original disk data for performant installer --- storage/lived/src/main.rs | 68 ++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index f05950222e..eadc62965e 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -2,7 +2,7 @@ #![feature(int_roundings)] -use std::collections::BTreeMap; +use std::collections::{BTreeMap, HashMap}; use std::fs::File; use std::os::fd::AsRawFd; @@ -18,7 +18,9 @@ use syscall::PAGE_SIZE; use anyhow::{anyhow, bail, Context}; struct LiveDisk { - the_data: &'static mut [u8], + original: &'static [u8], + //TODO: drop overlay blocks if they match the original + overlay: HashMap>, } impl LiveDisk { @@ -59,14 +61,14 @@ impl LiveDisk { .next_multiple_of(PAGE_SIZE); let size = end - start; - let the_data = unsafe { + let original = unsafe { let file = File::open("/scheme/memory/physical")?; let base = libredox::call::mmap(MmapArgs { fd: file.as_raw_fd() as usize, addr: core::ptr::null_mut(), offset: start as u64, length: size, - prot: flag::PROT_READ | flag::PROT_WRITE, + prot: flag::PROT_READ, flags: flag::MAP_SHARED, }) .map_err(|err| anyhow!("failed to mmap livedisk: {}", err))?; @@ -74,39 +76,59 @@ impl LiveDisk { std::slice::from_raw_parts_mut(base as *mut u8, size) }; - Ok(LiveDisk { the_data }) + Ok(LiveDisk { + original, + overlay: HashMap::new(), + }) } } impl Disk for LiveDisk { fn block_size(&self) -> u32 { - 512 + PAGE_SIZE as u32 } fn size(&self) -> u64 { - self.the_data.len() as u64 + self.original.len() as u64 } - async fn read(&mut self, block: u64, buffer: &mut [u8]) -> syscall::Result { - let block = block as usize; - let block_size = self.block_size() as usize; - if block * block_size + buffer.len() > self.size() as usize { - return Err(syscall::Error::new(EOVERFLOW)); + async fn read(&mut self, mut block: u64, buffer: &mut [u8]) -> syscall::Result { + let mut offset = (block as usize) * PAGE_SIZE; + if offset + buffer.len() > self.original.len() { + return Err(syscall::Error::new(EINVAL)); } - buffer - .copy_from_slice(&self.the_data[block * block_size..block * block_size + buffer.len()]); - Ok(block_size) + for chunk in buffer.chunks_mut(PAGE_SIZE) { + match self.overlay.get(&block) { + Some(overlay) => { + chunk.copy_from_slice(&overlay[..chunk.len()]); + } + None => { + chunk.copy_from_slice(&self.original[offset..offset + chunk.len()]); + } + } + block += 1; + offset += PAGE_SIZE; + } + Ok(buffer.len()) } - async fn write(&mut self, block: u64, buffer: &[u8]) -> syscall::Result { - let block = block as usize; - let block_size = self.block_size() as usize; - if block * block_size + buffer.len() > self.size() as usize { - return Err(syscall::Error::new(EOVERFLOW)); + async fn write(&mut self, mut block: u64, buffer: &[u8]) -> syscall::Result { + let mut offset = (block as usize) * PAGE_SIZE; + if offset + buffer.len() > self.original.len() { + return Err(syscall::Error::new(EINVAL)); } - self.the_data[block * block_size..block * block_size + buffer.len()] - .copy_from_slice(buffer); - Ok(block_size) + for chunk in buffer.chunks(PAGE_SIZE) { + self.overlay.entry(block).or_insert_with(|| { + let offset = (block as usize) * PAGE_SIZE; + self.original[offset..offset + PAGE_SIZE] + .to_vec() + .into_boxed_slice() + })[..chunk.len()] + .copy_from_slice(chunk); + block += 1; + offset += PAGE_SIZE; + } + Ok(buffer.len()) } } From 6b335d4f90c1651d6f47d2cb9ea0bc60c1858613 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 27 Sep 2025 18:22:05 -0600 Subject: [PATCH 1239/1301] hwd: decode some ACPI IDs --- hwd/src/main.rs | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/hwd/src/main.rs b/hwd/src/main.rs index 45710fb8cc..264bbc8c8e 100644 --- a/hwd/src/main.rs +++ b/hwd/src/main.rs @@ -16,7 +16,15 @@ fn acpi() -> Result<(), Box> { let vendor_1 = (((vendor_rev >> 10) & 0x1f) as u8 + 64) as char; let vendor_2 = (((vendor_rev >> 5) & 0x1f) as u8 + 64) as char; let vendor_3 = (((vendor_rev >> 0) & 0x1f) as u8 + 64) as char; - format!("{}{}{}{:04X}", vendor_1, vendor_2, vendor_3, device) + //TODO: simplify this nibble swap + let device_1 = (device >> 4) & 0xF; + let device_2 = (device >> 0) & 0xF; + let device_3 = (device >> 12) & 0xF; + let device_4 = (device >> 8) & 0xF; + format!( + "{}{}{}{:01X}{:01X}{:01X}{:01X}", + vendor_1, vendor_2, vendor_3, device_1, device_2, device_3, device_4 + ) } AmlSerdeValue::String(string) => string, _ => { @@ -24,7 +32,24 @@ fn acpi() -> Result<(), Box> { continue; } }; - log::debug!("{}: {}", name, id); + let what = match id.as_str() { + // https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html + "ACPI0006" => "GPE block device", + "ACPI0010" => "Processor control device", + // https://uefi.org/sites/default/files/resources/devids%20%285%29.txt + "PNP0103" => "HPET", + "PNP0303" => "IBM Enhanced (101/102-key, PS/2 mouse support)", + "PNP0400" => "Standard LPT printer port", + "PNP0501" => "16550A-compatible COM port", + "PNP0A03" => "PCI bus", + "PNP0A05" => "Generic ACPI bus", + "PNP0A06" => "Generic ACPI Extended-IO bus (EIO bus)", + "PNP0B00" => "AT real-time clock", + "PNP0C0F" => "PCI interrupt link device", + "PNP0F13" => "PS/2 port for PS/2-style mouse", + _ => "?", + }; + log::debug!("{}: {} ({})", name, id, what); } } } @@ -36,8 +61,8 @@ fn main() { "misc", "hwd", "hwd", - log::LevelFilter::Info, - log::LevelFilter::Info, + log::LevelFilter::Debug, + log::LevelFilter::Debug, ); //TODO: HWD is meant to locate PCI/XHCI/etc devices in ACPI and DeviceTree definitions and start their drivers From 62fab168e507a8a71755ee02700a318be26115d2 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 28 Sep 2025 08:53:18 -0600 Subject: [PATCH 1240/1301] Update to latest acpi crate --- Cargo.lock | 73 +++--------- acpid/Cargo.toml | 2 +- acpid/src/acpi.rs | 62 +++++----- acpid/src/aml_physmem.rs | 98 +++++++++++++--- amlserde/Cargo.toml | 3 +- amlserde/src/lib.rs | 239 +++++++++++++++++++++------------------ 6 files changed, 255 insertions(+), 222 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0d927e43bf..607c1ad322 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,11 +17,24 @@ dependencies = [ "spin 0.9.8", ] +[[package]] +name = "acpi" +version = "6.0.1" +source = "git+https://github.com/jackpot51/acpi.git#1c404f42bae2c1c5e8e65f6f86a956c212e97311" +dependencies = [ + "bit_field", + "bitflags 2.9.0", + "byteorder", + "log", + "pci_types", + "spinning_top", +] + [[package]] name = "acpid" version = "0.1.0" dependencies = [ - "aml", + "acpi", "amlserde", "arrayvec", "common", @@ -77,24 +90,11 @@ dependencies = [ "redox_syscall", ] -[[package]] -name = "aml" -version = "0.16.3" -source = "git+https://github.com/rw-vanc/acpi.git?branch=cumulative#e4eb93891367e73d3633804002aa050edfbacb6e" -dependencies = [ - "bit_field", - "bitvec", - "byteorder", - "log", - "spinning_top", -] - [[package]] name = "amlserde" version = "0.0.1" dependencies = [ - "aml", - "rustc-hash", + "acpi", "serde", "toml 0.7.8", ] @@ -221,18 +221,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "bumpalo" version = "3.17.0" @@ -495,12 +483,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - [[package]] name = "futures" version = "0.3.31" @@ -1059,12 +1041,6 @@ version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - [[package]] name = "rand" version = "0.4.6" @@ -1441,9 +1417,9 @@ dependencies = [ [[package]] name = "spinning_top" -version = "0.2.5" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" dependencies = [ "lock_api", ] @@ -1488,12 +1464,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "termion" version = "4.0.5" @@ -2007,15 +1977,6 @@ dependencies = [ "bitflags 2.9.0", ] -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - [[package]] name = "xhcid" version = "0.1.0" diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index b704be076c..516aa9a78d 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -7,7 +7,7 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -aml = { git = "https://github.com/rw-vanc/acpi.git", branch = "cumulative" } +acpi = { git = "https://github.com/jackpot51/acpi.git" } log = "0.4" num-derive = "0.3" num-traits = "0.2" diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 48a1f559b8..464a8a1a2c 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,6 +1,7 @@ use rustc_hash::FxHashMap; use std::convert::{TryFrom, TryInto}; use std::ops::Deref; +use std::str::FromStr; use std::sync::{Arc, Mutex}; use std::{fmt, mem}; use syscall::PAGE_SIZE; @@ -11,9 +12,13 @@ use common::io::{Io, Pio}; use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use thiserror::Error; -use aml::{AmlContext, AmlError, AmlHandle, AmlName}; +use acpi::{ + aml::{namespace::AmlName, AmlError, Interpreter}, + platform::AcpiPlatform, + AcpiTables, +}; use amlserde::aml_serde_name::aml_to_symbol; -use amlserde::{AmlHandleLookup, AmlSerde}; +use amlserde::AmlSerde; #[cfg(target_arch = "x86_64")] pub mod dmar; @@ -232,7 +237,7 @@ pub struct Ssdt(Sdt); // must empty the cache so it is rebuilt. // If you modify an SDT, you must discard the aml_context and rebuild it. pub struct AmlSymbols { - aml_context: AmlContext, + aml_context: Interpreter, // k = name, v = description symbol_cache: FxHashMap, page_cache: Arc>, @@ -241,17 +246,19 @@ pub struct AmlSymbols { impl AmlSymbols { pub fn new() -> Self { let page_cache = Arc::new(Mutex::new(AmlPageCache::default())); + let handler = AmlPhysMemHandler::new(Arc::clone(&page_cache)); + //TODO: use these parsed tables for the rest of acpid and return errors instead of unwrap + let rsdp_address = usize::from_str_radix(&std::env::var("RSDP_ADDR").unwrap(), 16).unwrap(); + let tables = unsafe { AcpiTables::from_rsdp(handler.clone(), rsdp_address).unwrap() }; + let platform = AcpiPlatform::new(tables, handler).unwrap(); Self { - aml_context: AmlContext::new( - Box::new(AmlPhysMemHandler::new(Arc::clone(&page_cache))), - aml::DebugVerbosity::None, - ), + aml_context: Interpreter::new_from_platform(&platform).unwrap(), symbol_cache: FxHashMap::default(), page_cache, } } - pub fn mut_aml_context(&mut self) -> &mut AmlContext { + pub fn mut_aml_context(&mut self) -> &mut Interpreter { &mut self.aml_context } @@ -260,7 +267,7 @@ impl AmlSymbols { } pub fn parse_table(&mut self, aml: &[u8]) -> Result<(), AmlError> { - self.aml_context.parse_table(aml) + self.aml_context.load_table(aml) } pub fn lookup(&self, symbol: &str) -> Option { @@ -272,18 +279,19 @@ impl AmlSymbols { } pub fn build_cache(&mut self) { - let mut symbol_list: Vec<(AmlName, String, AmlHandle)> = Vec::with_capacity(5000); + let mut symbol_list: Vec<(AmlName, String)> = Vec::with_capacity(5000); if self .aml_context .namespace + .lock() .traverse(|level_aml_name, level| { for (child_seg, handle) in level.values.iter() { if let Ok(aml_name) = AmlName::from_name_seg(child_seg.to_owned()).resolve(level_aml_name) { let name = aml_to_symbol(&aml_name); - symbol_list.push((aml_name, name, handle.to_owned())); + symbol_list.push((aml_name, name)); } else { log::error!( "AmlName resolve failed, {:?}:{:?}", @@ -300,24 +308,12 @@ impl AmlSymbols { return; } - let mut handle_lookup = AmlHandleLookup::new(); - - for (aml_name, name, handle) in &symbol_list { - handle_lookup.insert(handle.to_owned(), aml_name.to_owned()); - } - let mut symbol_cache: FxHashMap = FxHashMap::default(); - for (aml_name, name, handle) in &symbol_list { + for (aml_name, name) in &symbol_list { // create an empty entry, in case something goes wrong with serialization symbol_cache.insert(name.to_owned(), "".to_owned()); - if let Some(ser_value) = AmlSerde::from_aml( - &mut self.aml_context, - &handle_lookup, - &aml_to_symbol(aml_name), - aml_name, - handle, - ) { + if let Some(ser_value) = AmlSerde::from_aml(&mut self.aml_context, aml_name) { if let Ok(ser_string) = ron::ser::to_string_pretty(&ser_value, Default::default()) { // replace the empty entry symbol_cache.insert(name.to_owned(), ser_string); @@ -536,7 +532,7 @@ impl AcpiContext { let aml_symbols = self.aml_symbols.read(); - let s5_aml_name = match aml::AmlName::from_str("\\_S5") { + let s5_aml_name = match acpi::aml::namespace::AmlName::from_str("\\_S5") { Ok(aml_name) => aml_name, Err(error) => { log::error!("Could not build AmlName for \\_S5, {:?}", error); @@ -544,7 +540,7 @@ impl AcpiContext { } }; - let s5 = match aml_symbols.aml_context.namespace.get_by_path(&s5_aml_name) { + let s5 = match aml_symbols.aml_context.namespace.lock().get(s5_aml_name) { Ok(s5) => s5, Err(error) => { log::error!("Cannot set S-state, missing \\_S5, {:?}", error); @@ -552,23 +548,23 @@ impl AcpiContext { } }; - let package = match s5 { - aml::AmlValue::Package(package) => package, + let package = match s5.deref() { + acpi::aml::object::Object::Package(package) => package, _ => { log::error!("Cannot set S-state, \\_S5 is not a package"); return; } }; - let slp_typa = match package[0] { - aml::AmlValue::Integer(i) => i, + let slp_typa = match package[0].deref() { + acpi::aml::object::Object::Integer(i) => i.to_owned(), _ => { log::error!("typa is not an Integer"); return; } }; - let slp_typb = match package[1] { - aml::AmlValue::Integer(i) => i, + let slp_typb = match package[1].deref() { + acpi::aml::object::Object::Integer(i) => i.to_owned(), _ => { log::error!("typb is not an Integer"); return; diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index ce07ba4cfe..4145a5fe00 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -1,9 +1,11 @@ +use acpi::{aml::AmlError, Handle, PciAddress, PhysicalMapping}; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use common::io::{Io, Pio}; use num_traits::PrimInt; use rustc_hash::FxHashMap; use std::fmt::LowerHex; use std::mem::size_of; +use std::ptr::NonNull; use std::sync::{Arc, Mutex}; use syscall::PAGE_SIZE; @@ -21,7 +23,7 @@ impl MappedPage { common::physmap( phys_page, PAGE_SIZE, - common::Prot::RO, + common::Prot::RW, common::MemoryType::default(), ) .map_err(|error| std::io::Error::from_raw_os_error(error.errno()))? @@ -135,6 +137,7 @@ impl AmlPageCache { } } +#[derive(Clone)] pub struct AmlPhysMemHandler { page_cache: Arc>, } @@ -147,7 +150,35 @@ impl AmlPhysMemHandler { } } -impl aml::Handler for AmlPhysMemHandler { +impl acpi::Handler for AmlPhysMemHandler { + unsafe fn map_physical_region(&self, phys: usize, size: usize) -> PhysicalMapping { + let phys_page = phys & PAGE_MASK; + let offset = phys & OFFSET_MASK; + let pages = (offset + size + PAGE_SIZE - 1) / PAGE_SIZE; + let map_size = pages * PAGE_SIZE; + let virt_page = common::physmap( + phys_page, + map_size, + common::Prot::RW, + common::MemoryType::default(), + ) + .expect("failed to map physical region") as usize; + PhysicalMapping { + physical_start: phys, + virtual_start: NonNull::new((virt_page + offset) as *mut T).unwrap(), + region_length: size, + mapped_length: map_size, + handler: self.clone(), + } + } + fn unmap_physical_region(region: &PhysicalMapping) { + let virt_page = region.virtual_start.addr().get() & PAGE_MASK; + unsafe { + libredox::call::munmap(virt_page as *mut (), region.mapped_length) + .expect("failed to unmap physical region") + } + } + fn read_u8(&self, address: usize) -> u8 { log::trace!("read u8 {:X}", address); if let Ok(mut page_cache) = self.page_cache.lock() { @@ -189,7 +220,7 @@ impl aml::Handler for AmlPhysMemHandler { 0 } - fn write_u8(&mut self, address: usize, value: u8) { + fn write_u8(&self, address: usize, value: u8) { log::trace!("write u8 {:X} = {:X}", address, value); if let Ok(mut page_cache) = self.page_cache.lock() { if page_cache.write_to_phys::(address, value).is_ok() { @@ -198,7 +229,7 @@ impl aml::Handler for AmlPhysMemHandler { } log::error!("failed to write u8 {:#x}", address); } - fn write_u16(&mut self, address: usize, value: u16) { + fn write_u16(&self, address: usize, value: u16) { log::trace!("write u16 {:X} = {:X}", address, value); if let Ok(mut page_cache) = self.page_cache.lock() { if page_cache.write_to_phys::(address, value).is_ok() { @@ -207,7 +238,7 @@ impl aml::Handler for AmlPhysMemHandler { } log::error!("failed to write u16 {:#x}", address); } - fn write_u32(&mut self, address: usize, value: u32) { + fn write_u32(&self, address: usize, value: u32) { log::trace!("write u32 {:X} = {:X}", address, value); if let Ok(mut page_cache) = self.page_cache.lock() { if page_cache.write_to_phys::(address, value).is_ok() { @@ -216,7 +247,7 @@ impl aml::Handler for AmlPhysMemHandler { } log::error!("failed to write u32 {:#x}", address); } - fn write_u64(&mut self, address: usize, value: u64) { + fn write_u64(&self, address: usize, value: u64) { log::trace!("write u64 {:X} = {:X}", address, value); if let Ok(mut page_cache) = self.page_cache.lock() { if page_cache.write_to_phys::(address, value).is_ok() { @@ -282,25 +313,56 @@ impl aml::Handler for AmlPhysMemHandler { log::error!("cannot write 0x{value:08X} to port 0x{port:04X}"); } - fn read_pci_u8(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16) -> u8 { - log::error!("read pci u8 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}"); + fn read_pci_u8(&self, addr: PciAddress, off: u16) -> u8 { + log::error!("read pci u8 {addr}@{off:04X}"); 0 } - fn read_pci_u16(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16) -> u16 { - log::error!("read pci u16 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}"); + fn read_pci_u16(&self, addr: PciAddress, off: u16) -> u16 { + log::error!("read pci u16 {addr}@{off:04X}"); 0 } - fn read_pci_u32(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16) -> u32 { - log::error!("read pci u32 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}"); + fn read_pci_u32(&self, addr: PciAddress, off: u16) -> u32 { + log::error!("read pci u32 {addr}@{off:04X}"); 0 } - fn write_pci_u8(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16, value: u8) { - log::error!("write pci u8 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}={value:02X}"); + fn write_pci_u8(&self, addr: PciAddress, off: u16, value: u8) { + log::error!("write pci u8 {addr}@{off:04X}={value:02X}"); } - fn write_pci_u16(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16, value: u16) { - log::error!("write pci u16 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}={value:04X}"); + fn write_pci_u16(&self, addr: PciAddress, off: u16, value: u16) { + log::error!("write pci u16 {addr}@{off:04X}={value:04X}"); } - fn write_pci_u32(&self, seg: u16, bus: u8, dev: u8, func: u8, off: u16, value: u32) { - log::error!("write pci u32 {seg:04X}:{bus:02X}:{dev:02X}.{func:01X}@{off:04X}={value:08X}"); + fn write_pci_u32(&self, addr: PciAddress, off: u16, value: u32) { + log::error!("write pci u32 {addr}@{off:04X}={value:08X}"); + } + + fn nanos_since_boot(&self) -> u64 { + let ts = libredox::call::clock_gettime(libredox::flag::CLOCK_MONOTONIC) + .expect("failed to get time"); + (ts.tv_sec as u64) * 1_000_000_000 + (ts.tv_nsec as u64) + } + + fn stall(&self, microseconds: u64) { + let start = std::time::Instant::now(); + while start.elapsed().as_micros() < microseconds.into() { + std::hint::spin_loop(); + } + } + + fn sleep(&self, milliseconds: u64) { + std::thread::sleep(std::time::Duration::from_millis(milliseconds)); + } + + fn create_mutex(&self) -> Handle { + log::warn!("TODO: Handler::create_mutex"); + Handle(0) + } + + fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), AmlError> { + log::warn!("TODO: Handler::aquire"); + Ok(()) + } + + fn release(&self, mutex: Handle) { + log::warn!("TODO: Handler::release"); } } diff --git a/amlserde/Cargo.toml b/amlserde/Cargo.toml index 49adbe294e..28d1b56834 100644 --- a/amlserde/Cargo.toml +++ b/amlserde/Cargo.toml @@ -9,7 +9,6 @@ license = "MIT/Apache-2.0" edition = "2021" [dependencies] -aml = { git = "https://github.com/rw-vanc/acpi.git", branch = "cumulative" } -rustc-hash = "1.1.0" +acpi = { git = "https://github.com/jackpot51/acpi.git" } serde = { version = "1.0", features = ["derive"] } toml = "0.7.3" diff --git a/amlserde/src/lib.rs b/amlserde/src/lib.rs index a7ea76b9de..7fa2f7c50e 100644 --- a/amlserde/src/lib.rs +++ b/amlserde/src/lib.rs @@ -1,7 +1,14 @@ -use aml::value::{FieldAccessType, FieldUpdateRule, RegionSpace}; -use aml::{AmlContext, AmlHandle, AmlName, AmlValue}; -use rustc_hash::FxHashMap; +use acpi::{ + aml::{ + namespace::AmlName, + object::{FieldAccessType, FieldUnitKind, FieldUpdateRule, Object, ReferenceKind}, + op_region::RegionSpace, + Interpreter, + }, + Handler, +}; use serde::{Deserialize, Serialize}; +use std::{ops::Deref, sync::atomic::Ordering}; #[derive(Debug, Serialize, Deserialize)] pub struct AmlSerde { @@ -11,7 +18,7 @@ pub struct AmlSerde { #[derive(Debug, Serialize, Deserialize)] pub enum AmlSerdeValue { - Boolean(bool), + Uninitialized, Integer(u64), String(String), OpRegion { @@ -21,14 +28,15 @@ pub enum AmlSerdeValue { parent_device: Option, }, Field { - region: String, + kind: AmlSerdeFieldKind, flags: AmlSerdeFieldFlags, offset: u64, length: u64, }, Device, + Event(u64), Method { - arg_count: u8, + arg_count: usize, serialize: bool, sync_level: u8, }, @@ -36,7 +44,7 @@ pub enum AmlSerdeValue { BufferField { offset: u64, length: u64, - data: Vec, + data: Option>, }, Processor { id: u8, @@ -44,8 +52,13 @@ pub enum AmlSerdeValue { pblk_len: u8, }, Mutex { + mutex: u32, sync_level: u8, }, + Reference { + kind: AmlSerdeReferenceKind, + inner: Option>, + }, Package { contents: Vec, }, @@ -53,8 +66,9 @@ pub enum AmlSerdeValue { system_level: u8, resource_order: u16, }, + RawDataBuffer, ThermalZone, - External, + Debug, } #[derive(Debug, Serialize, Deserialize)] @@ -69,9 +83,26 @@ pub enum AmlSerdeRegionSpace { IPMI, GeneralPurposeIo, GenericSerialBus, + Pcc, OemDefined(u8), } +#[derive(Debug, Serialize, Deserialize)] +pub enum AmlSerdeFieldKind { + Normal { + region: Option>, + }, + Bank { + region: Option>, + bank: Option>, + bank_value: u64, + }, + Index { + index: Option>, + data: Option>, + }, +} + #[derive(Debug, Serialize, Deserialize)] pub struct AmlSerdeFieldFlags { pub access_type: AmlSerdeFieldAccessType, @@ -96,6 +127,13 @@ pub enum AmlSerdeFieldUpdateRule { WriteAsZeros, } +#[derive(Debug, Serialize, Deserialize)] +pub enum AmlSerdeReferenceKind { + RefOf, + LocalOrArg, + Unresolved, +} + impl AmlSerde { pub fn default() -> Self { Self { @@ -104,20 +142,15 @@ impl AmlSerde { } } - pub fn from_aml( - aml_context: &mut AmlContext, - aml_lookup: &AmlHandleLookup, - name: &String, - aml_name: &AmlName, - handle: &AmlHandle, - ) -> Option { - let aml_value = if let Ok(aml_value) = aml_context.namespace.get(handle.clone()) { + pub fn from_aml(aml_context: &Interpreter, aml_name: &AmlName) -> Option { + //TODO: why does namespace.get not take a reference to aml_name + let aml_value = if let Ok(aml_value) = aml_context.namespace.lock().get(aml_name.clone()) { aml_value } else { return None; }; - let value = if let Some(value) = AmlSerdeValue::from_aml_value(aml_value, aml_lookup) { + let value = if let Some(value) = AmlSerdeValue::from_aml_value(aml_value.deref()) { value } else { return None; @@ -135,55 +168,51 @@ impl AmlSerdeValue { AmlSerdeValue::String("".to_owned()) } - fn from_aml_value(aml_value: &AmlValue, aml_lookup: &AmlHandleLookup) -> Option { + fn from_aml_value(aml_value: &Object) -> Option { Some(match aml_value { - AmlValue::Boolean(b) => AmlSerdeValue::Boolean(b.to_owned()), - - AmlValue::Integer(n) => AmlSerdeValue::Integer(n.to_owned()), - - AmlValue::String(s) => AmlSerdeValue::String(s.to_owned()), - - AmlValue::OpRegion { - region, - offset, - length, - parent_device, - } => AmlSerdeValue::OpRegion { - region: match region { + Object::Uninitialized => AmlSerdeValue::Uninitialized, + Object::Integer(n) => AmlSerdeValue::Integer(n.to_owned()), + Object::String(s) => AmlSerdeValue::String(s.to_owned()), + Object::OpRegion(region) => AmlSerdeValue::OpRegion { + region: match region.space { RegionSpace::SystemMemory => AmlSerdeRegionSpace::SystemMemory, - RegionSpace::SystemIo => AmlSerdeRegionSpace::SystemIo, + RegionSpace::SystemIO => AmlSerdeRegionSpace::SystemIo, RegionSpace::PciConfig => AmlSerdeRegionSpace::PciConfig, RegionSpace::EmbeddedControl => AmlSerdeRegionSpace::EmbeddedControl, - RegionSpace::SMBus => AmlSerdeRegionSpace::SMBus, + RegionSpace::SmBus => AmlSerdeRegionSpace::SMBus, RegionSpace::SystemCmos => AmlSerdeRegionSpace::SystemCmos, RegionSpace::PciBarTarget => AmlSerdeRegionSpace::PciBarTarget, - RegionSpace::IPMI => AmlSerdeRegionSpace::IPMI, + RegionSpace::Ipmi => AmlSerdeRegionSpace::IPMI, RegionSpace::GeneralPurposeIo => AmlSerdeRegionSpace::GeneralPurposeIo, RegionSpace::GenericSerialBus => AmlSerdeRegionSpace::GenericSerialBus, - RegionSpace::OemDefined(n) => AmlSerdeRegionSpace::OemDefined(n.to_owned()), - }, - offset: offset.to_owned(), - length: length.to_owned(), - parent_device: if let Some(parent) = parent_device { - Some(parent.to_string()) - } else { - None + RegionSpace::Pcc => AmlSerdeRegionSpace::Pcc, + RegionSpace::Oem(n) => AmlSerdeRegionSpace::OemDefined(n.to_owned()), }, + offset: region.base, + length: region.length, + parent_device: Some(region.parent_device_path.to_string()), }, - - AmlValue::Field { - region, - flags, - offset, - length, - } => AmlSerdeValue::Field { - region: if let Some((region, _handle)) = aml_lookup.get(region) { - region.to_string() - } else { - return None; + Object::FieldUnit(field) => AmlSerdeValue::Field { + kind: match &field.kind { + FieldUnitKind::Normal { region } => AmlSerdeFieldKind::Normal { + region: AmlSerdeValue::from_aml_value(region.deref()).map(Box::new), + }, + FieldUnitKind::Bank { + region, + bank, + bank_value, + } => AmlSerdeFieldKind::Bank { + region: AmlSerdeValue::from_aml_value(region.deref()).map(Box::new), + bank: AmlSerdeValue::from_aml_value(bank.deref()).map(Box::new), + bank_value: bank_value.to_owned(), + }, + FieldUnitKind::Index { index, data } => AmlSerdeFieldKind::Index { + index: AmlSerdeValue::from_aml_value(index.deref()).map(Box::new), + data: AmlSerdeValue::from_aml_value(data.deref()).map(Box::new), + }, }, flags: AmlSerdeFieldFlags { - access_type: match flags.access_type() { + access_type: match field.flags.access_type() { Ok(FieldAccessType::Any) => AmlSerdeFieldAccessType::Any, Ok(FieldAccessType::Byte) => AmlSerdeFieldAccessType::Byte, Ok(FieldAccessType::Word) => AmlSerdeFieldAccessType::Word, @@ -192,71 +221,82 @@ impl AmlSerdeValue { Ok(FieldAccessType::Buffer) => AmlSerdeFieldAccessType::Buffer, _ => return None, }, - lock_rule: flags.lock_rule(), - update_rule: match flags.field_update_rule() { - Ok(FieldUpdateRule::Preserve) => AmlSerdeFieldUpdateRule::Preserve, - Ok(FieldUpdateRule::WriteAsOnes) => AmlSerdeFieldUpdateRule::WriteAsOnes, - Ok(FieldUpdateRule::WriteAsZeros) => AmlSerdeFieldUpdateRule::WriteAsZeros, - _ => return None, + lock_rule: field.flags.lock_rule(), + update_rule: match field.flags.update_rule() { + FieldUpdateRule::Preserve => AmlSerdeFieldUpdateRule::Preserve, + FieldUpdateRule::WriteAsOnes => AmlSerdeFieldUpdateRule::WriteAsOnes, + FieldUpdateRule::WriteAsZeros => AmlSerdeFieldUpdateRule::WriteAsZeros, }, }, - offset: offset.to_owned(), - length: length.to_owned(), + offset: field.bit_index as u64, + length: field.bit_length as u64, }, - - AmlValue::Device => AmlSerdeValue::Device, - - AmlValue::Method { flags, code: _ } => AmlSerdeValue::Method { + Object::Device => AmlSerdeValue::Device, + Object::Event(event) => AmlSerdeValue::Event(event.load(Ordering::Relaxed)), + Object::Method { flags, code: _ } => AmlSerdeValue::Method { arg_count: flags.arg_count(), serialize: flags.serialize(), sync_level: flags.sync_level(), }, - AmlValue::Buffer(buffer_data) => { - AmlSerdeValue::Buffer({ buffer_data.lock().to_owned() }) - } - AmlValue::BufferField { - buffer_data, + //TODO: distinguish from Method? + Object::NativeMethod { f: _, flags } => AmlSerdeValue::Method { + arg_count: flags.arg_count(), + serialize: flags.serialize(), + sync_level: flags.sync_level(), + }, + Object::Buffer(buffer_data) => AmlSerdeValue::Buffer(buffer_data.to_owned()), + Object::BufferField { + buffer, offset, length, } => AmlSerdeValue::BufferField { - offset: offset.to_owned(), - length: length.to_owned(), - data: { buffer_data.lock().to_owned() }, + offset: offset.to_owned() as u64, + length: length.to_owned() as u64, + data: AmlSerdeValue::from_aml_value(buffer.deref()).map(Box::new), }, - AmlValue::Processor { - id, + Object::Processor { + proc_id, pblk_address, - pblk_len, + pblk_length, } => AmlSerdeValue::Processor { - id: id.to_owned(), + id: proc_id.to_owned(), pblk_address: pblk_address.to_owned(), - pblk_len: pblk_len.to_owned(), + pblk_len: pblk_length.to_owned(), }, - AmlValue::Mutex { sync_level } => AmlSerdeValue::Mutex { + Object::Mutex { mutex, sync_level } => AmlSerdeValue::Mutex { + mutex: mutex.0, sync_level: sync_level.to_owned(), }, - AmlValue::Package(aml_contents) => AmlSerdeValue::Package { + Object::Reference { kind, inner } => AmlSerdeValue::Reference { + kind: match kind { + ReferenceKind::RefOf => AmlSerdeReferenceKind::RefOf, + ReferenceKind::LocalOrArg => AmlSerdeReferenceKind::LocalOrArg, + ReferenceKind::Unresolved => AmlSerdeReferenceKind::Unresolved, + }, + inner: AmlSerdeValue::from_aml_value(inner.deref()).map(Box::new), + }, + Object::Package(aml_contents) => AmlSerdeValue::Package { contents: aml_contents .iter() - .filter_map(|item| AmlSerdeValue::from_aml_value(item, aml_lookup)) + .filter_map(|item| AmlSerdeValue::from_aml_value(item)) .collect(), }, - - AmlValue::PowerResource { + Object::PowerResource { system_level, resource_order, } => AmlSerdeValue::PowerResource { system_level: system_level.to_owned(), resource_order: resource_order.to_owned(), }, - AmlValue::ThermalZone => AmlSerdeValue::ThermalZone, - AmlValue::External => AmlSerdeValue::External, + Object::RawDataBuffer => AmlSerdeValue::RawDataBuffer, + Object::ThermalZone => AmlSerdeValue::ThermalZone, + Object::Debug => AmlSerdeValue::Debug, }) } } pub mod aml_serde_name { - use aml::AmlName; + use acpi::aml::namespace::AmlName; /// Add a leading backslash to make the name a valid /// namespace reference @@ -288,28 +328,3 @@ pub mod aml_serde_name { to_symbol(&aml_name.as_string()) } } - -pub struct AmlHandleLookup { - map: FxHashMap, -} - -impl AmlHandleLookup { - pub fn new() -> Self { - Self { - map: FxHashMap::default(), - } - } - - fn handle_to_key(&self, handle: &AmlHandle) -> String { - format!("{:?}", handle) - } - - pub fn insert(&mut self, handle: AmlHandle, aml_name: AmlName) { - self.map - .insert(self.handle_to_key(&handle), (aml_name, handle)); - } - - pub fn get(&self, handle: &AmlHandle) -> Option<&(AmlName, AmlHandle)> { - self.map.get(&self.handle_to_key(handle)) - } -} From 68f0fc6f80337b69c02b787d121a1f43ee472876 Mon Sep 17 00:00:00 2001 From: Filippo Mutta Date: Tue, 30 Sep 2025 22:48:28 +0200 Subject: [PATCH 1241/1301] USB: reorganised directory structure. --- {usbctl => usb/usbctl}/.gitignore | 0 {usbctl => usb/usbctl}/Cargo.toml | 0 {usbctl => usb/usbctl}/src/main.rs | 0 {usbhubd => usb/usbhubd}/.gitignore | 0 {usbhubd => usb/usbhubd}/Cargo.toml | 0 {usbhubd => usb/usbhubd}/src/main.rs | 0 {xhcid => usb/xhcid}/.gitignore | 0 {xhcid => usb/xhcid}/Cargo.toml | 0 {xhcid => usb/xhcid}/config.toml | 0 {xhcid => usb/xhcid}/drivers.toml | 0 {xhcid => usb/xhcid}/src/driver_interface.rs | 0 {xhcid => usb/xhcid}/src/lib.rs | 0 {xhcid => usb/xhcid}/src/main.rs | 0 {xhcid => usb/xhcid}/src/usb/bos.rs | 0 {xhcid => usb/xhcid}/src/usb/config.rs | 0 {xhcid => usb/xhcid}/src/usb/device.rs | 0 {xhcid => usb/xhcid}/src/usb/endpoint.rs | 0 {xhcid => usb/xhcid}/src/usb/hub.rs | 0 {xhcid => usb/xhcid}/src/usb/interface.rs | 0 {xhcid => usb/xhcid}/src/usb/mod.rs | 0 {xhcid => usb/xhcid}/src/usb/setup.rs | 0 {xhcid => usb/xhcid}/src/xhci/capability.rs | 0 {xhcid => usb/xhcid}/src/xhci/context.rs | 0 {xhcid => usb/xhcid}/src/xhci/device_enumerator.rs | 0 {xhcid => usb/xhcid}/src/xhci/doorbell.rs | 0 {xhcid => usb/xhcid}/src/xhci/event.rs | 0 {xhcid => usb/xhcid}/src/xhci/extended.rs | 0 {xhcid => usb/xhcid}/src/xhci/irq_reactor.rs | 0 {xhcid => usb/xhcid}/src/xhci/mod.rs | 0 {xhcid => usb/xhcid}/src/xhci/operational.rs | 0 {xhcid => usb/xhcid}/src/xhci/port.rs | 0 {xhcid => usb/xhcid}/src/xhci/ring.rs | 0 {xhcid => usb/xhcid}/src/xhci/runtime.rs | 0 {xhcid => usb/xhcid}/src/xhci/scheme.rs | 0 {xhcid => usb/xhcid}/src/xhci/trb.rs | 0 35 files changed, 0 insertions(+), 0 deletions(-) rename {usbctl => usb/usbctl}/.gitignore (100%) rename {usbctl => usb/usbctl}/Cargo.toml (100%) rename {usbctl => usb/usbctl}/src/main.rs (100%) rename {usbhubd => usb/usbhubd}/.gitignore (100%) rename {usbhubd => usb/usbhubd}/Cargo.toml (100%) rename {usbhubd => usb/usbhubd}/src/main.rs (100%) rename {xhcid => usb/xhcid}/.gitignore (100%) rename {xhcid => usb/xhcid}/Cargo.toml (100%) rename {xhcid => usb/xhcid}/config.toml (100%) rename {xhcid => usb/xhcid}/drivers.toml (100%) rename {xhcid => usb/xhcid}/src/driver_interface.rs (100%) rename {xhcid => usb/xhcid}/src/lib.rs (100%) rename {xhcid => usb/xhcid}/src/main.rs (100%) rename {xhcid => usb/xhcid}/src/usb/bos.rs (100%) rename {xhcid => usb/xhcid}/src/usb/config.rs (100%) rename {xhcid => usb/xhcid}/src/usb/device.rs (100%) rename {xhcid => usb/xhcid}/src/usb/endpoint.rs (100%) rename {xhcid => usb/xhcid}/src/usb/hub.rs (100%) rename {xhcid => usb/xhcid}/src/usb/interface.rs (100%) rename {xhcid => usb/xhcid}/src/usb/mod.rs (100%) rename {xhcid => usb/xhcid}/src/usb/setup.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/capability.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/context.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/device_enumerator.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/doorbell.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/event.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/extended.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/irq_reactor.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/mod.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/operational.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/port.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/ring.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/runtime.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/scheme.rs (100%) rename {xhcid => usb/xhcid}/src/xhci/trb.rs (100%) diff --git a/usbctl/.gitignore b/usb/usbctl/.gitignore similarity index 100% rename from usbctl/.gitignore rename to usb/usbctl/.gitignore diff --git a/usbctl/Cargo.toml b/usb/usbctl/Cargo.toml similarity index 100% rename from usbctl/Cargo.toml rename to usb/usbctl/Cargo.toml diff --git a/usbctl/src/main.rs b/usb/usbctl/src/main.rs similarity index 100% rename from usbctl/src/main.rs rename to usb/usbctl/src/main.rs diff --git a/usbhubd/.gitignore b/usb/usbhubd/.gitignore similarity index 100% rename from usbhubd/.gitignore rename to usb/usbhubd/.gitignore diff --git a/usbhubd/Cargo.toml b/usb/usbhubd/Cargo.toml similarity index 100% rename from usbhubd/Cargo.toml rename to usb/usbhubd/Cargo.toml diff --git a/usbhubd/src/main.rs b/usb/usbhubd/src/main.rs similarity index 100% rename from usbhubd/src/main.rs rename to usb/usbhubd/src/main.rs diff --git a/xhcid/.gitignore b/usb/xhcid/.gitignore similarity index 100% rename from xhcid/.gitignore rename to usb/xhcid/.gitignore diff --git a/xhcid/Cargo.toml b/usb/xhcid/Cargo.toml similarity index 100% rename from xhcid/Cargo.toml rename to usb/xhcid/Cargo.toml diff --git a/xhcid/config.toml b/usb/xhcid/config.toml similarity index 100% rename from xhcid/config.toml rename to usb/xhcid/config.toml diff --git a/xhcid/drivers.toml b/usb/xhcid/drivers.toml similarity index 100% rename from xhcid/drivers.toml rename to usb/xhcid/drivers.toml diff --git a/xhcid/src/driver_interface.rs b/usb/xhcid/src/driver_interface.rs similarity index 100% rename from xhcid/src/driver_interface.rs rename to usb/xhcid/src/driver_interface.rs diff --git a/xhcid/src/lib.rs b/usb/xhcid/src/lib.rs similarity index 100% rename from xhcid/src/lib.rs rename to usb/xhcid/src/lib.rs diff --git a/xhcid/src/main.rs b/usb/xhcid/src/main.rs similarity index 100% rename from xhcid/src/main.rs rename to usb/xhcid/src/main.rs diff --git a/xhcid/src/usb/bos.rs b/usb/xhcid/src/usb/bos.rs similarity index 100% rename from xhcid/src/usb/bos.rs rename to usb/xhcid/src/usb/bos.rs diff --git a/xhcid/src/usb/config.rs b/usb/xhcid/src/usb/config.rs similarity index 100% rename from xhcid/src/usb/config.rs rename to usb/xhcid/src/usb/config.rs diff --git a/xhcid/src/usb/device.rs b/usb/xhcid/src/usb/device.rs similarity index 100% rename from xhcid/src/usb/device.rs rename to usb/xhcid/src/usb/device.rs diff --git a/xhcid/src/usb/endpoint.rs b/usb/xhcid/src/usb/endpoint.rs similarity index 100% rename from xhcid/src/usb/endpoint.rs rename to usb/xhcid/src/usb/endpoint.rs diff --git a/xhcid/src/usb/hub.rs b/usb/xhcid/src/usb/hub.rs similarity index 100% rename from xhcid/src/usb/hub.rs rename to usb/xhcid/src/usb/hub.rs diff --git a/xhcid/src/usb/interface.rs b/usb/xhcid/src/usb/interface.rs similarity index 100% rename from xhcid/src/usb/interface.rs rename to usb/xhcid/src/usb/interface.rs diff --git a/xhcid/src/usb/mod.rs b/usb/xhcid/src/usb/mod.rs similarity index 100% rename from xhcid/src/usb/mod.rs rename to usb/xhcid/src/usb/mod.rs diff --git a/xhcid/src/usb/setup.rs b/usb/xhcid/src/usb/setup.rs similarity index 100% rename from xhcid/src/usb/setup.rs rename to usb/xhcid/src/usb/setup.rs diff --git a/xhcid/src/xhci/capability.rs b/usb/xhcid/src/xhci/capability.rs similarity index 100% rename from xhcid/src/xhci/capability.rs rename to usb/xhcid/src/xhci/capability.rs diff --git a/xhcid/src/xhci/context.rs b/usb/xhcid/src/xhci/context.rs similarity index 100% rename from xhcid/src/xhci/context.rs rename to usb/xhcid/src/xhci/context.rs diff --git a/xhcid/src/xhci/device_enumerator.rs b/usb/xhcid/src/xhci/device_enumerator.rs similarity index 100% rename from xhcid/src/xhci/device_enumerator.rs rename to usb/xhcid/src/xhci/device_enumerator.rs diff --git a/xhcid/src/xhci/doorbell.rs b/usb/xhcid/src/xhci/doorbell.rs similarity index 100% rename from xhcid/src/xhci/doorbell.rs rename to usb/xhcid/src/xhci/doorbell.rs diff --git a/xhcid/src/xhci/event.rs b/usb/xhcid/src/xhci/event.rs similarity index 100% rename from xhcid/src/xhci/event.rs rename to usb/xhcid/src/xhci/event.rs diff --git a/xhcid/src/xhci/extended.rs b/usb/xhcid/src/xhci/extended.rs similarity index 100% rename from xhcid/src/xhci/extended.rs rename to usb/xhcid/src/xhci/extended.rs diff --git a/xhcid/src/xhci/irq_reactor.rs b/usb/xhcid/src/xhci/irq_reactor.rs similarity index 100% rename from xhcid/src/xhci/irq_reactor.rs rename to usb/xhcid/src/xhci/irq_reactor.rs diff --git a/xhcid/src/xhci/mod.rs b/usb/xhcid/src/xhci/mod.rs similarity index 100% rename from xhcid/src/xhci/mod.rs rename to usb/xhcid/src/xhci/mod.rs diff --git a/xhcid/src/xhci/operational.rs b/usb/xhcid/src/xhci/operational.rs similarity index 100% rename from xhcid/src/xhci/operational.rs rename to usb/xhcid/src/xhci/operational.rs diff --git a/xhcid/src/xhci/port.rs b/usb/xhcid/src/xhci/port.rs similarity index 100% rename from xhcid/src/xhci/port.rs rename to usb/xhcid/src/xhci/port.rs diff --git a/xhcid/src/xhci/ring.rs b/usb/xhcid/src/xhci/ring.rs similarity index 100% rename from xhcid/src/xhci/ring.rs rename to usb/xhcid/src/xhci/ring.rs diff --git a/xhcid/src/xhci/runtime.rs b/usb/xhcid/src/xhci/runtime.rs similarity index 100% rename from xhcid/src/xhci/runtime.rs rename to usb/xhcid/src/xhci/runtime.rs diff --git a/xhcid/src/xhci/scheme.rs b/usb/xhcid/src/xhci/scheme.rs similarity index 100% rename from xhcid/src/xhci/scheme.rs rename to usb/xhcid/src/xhci/scheme.rs diff --git a/xhcid/src/xhci/trb.rs b/usb/xhcid/src/xhci/trb.rs similarity index 100% rename from xhcid/src/xhci/trb.rs rename to usb/xhcid/src/xhci/trb.rs From e157117890a8c07a5bce061b06b0189553e59dff Mon Sep 17 00:00:00 2001 From: Filippo Mutta Date: Tue, 30 Sep 2025 23:10:46 +0200 Subject: [PATCH 1242/1301] USB: Added new paths in cargo.toml --- Cargo.toml | 8 +++++--- input/usbhidd/Cargo.toml | 2 +- storage/usbscsid/Cargo.toml | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4fb623614e..067278f84d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,12 +9,14 @@ members = [ "pcid-spawner", "rtcd", "vboxd", - "xhcid", - "usbctl", - "usbhubd", "inputd", "virtio-core", + "usb/xhcid", + "usb/usbctl", + "usb/usbhubd", + + "audio/ac97d", "audio/ihdad", "audio/sb16d", diff --git a/input/usbhidd/Cargo.toml b/input/usbhidd/Cargo.toml index 0a3df4d43c..0a98084810 100644 --- a/input/usbhidd/Cargo.toml +++ b/input/usbhidd/Cargo.toml @@ -13,7 +13,7 @@ log = "0.4" orbclient = "0.3.47" redox_syscall = "0.5" rehid = { git = "https://gitlab.redox-os.org/redox-os/rehid.git" } -xhcid = { path = "../../xhcid" } +xhcid = { path = "../../usb/xhcid" } common = { path = "../../common" } inputd = { path = "../../inputd" } diff --git a/storage/usbscsid/Cargo.toml b/storage/usbscsid/Cargo.toml index 5e862aa06c..d7b148ee47 100644 --- a/storage/usbscsid/Cargo.toml +++ b/storage/usbscsid/Cargo.toml @@ -16,4 +16,4 @@ redox-daemon = "0.1" redox_event = "0.4" redox_syscall = { version = "0.5", features = ["std"] } thiserror = "1" -xhcid = { path = "../../xhcid" } +xhcid = { path = "../../usb/xhcid" } From dd17e81cc9dd31e320241addc2068026ae79c458 Mon Sep 17 00:00:00 2001 From: Filippo Mutta Date: Wed, 1 Oct 2025 08:12:41 +0200 Subject: [PATCH 1243/1301] USB: Fixed relative paths for deps in usb/ dir --- usb/usbhubd/Cargo.toml | 2 +- usb/xhcid/Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/usb/usbhubd/Cargo.toml b/usb/usbhubd/Cargo.toml index 708234e823..8534ebb2a1 100644 --- a/usb/usbhubd/Cargo.toml +++ b/usb/usbhubd/Cargo.toml @@ -11,4 +11,4 @@ log = "0.4" redox_syscall = "0.5" xhcid = { path = "../xhcid" } -common = { path = "../common" } +common = { path = "../../common" } diff --git a/usb/xhcid/Cargo.toml b/usb/xhcid/Cargo.toml index 7f566ce208..e59d63cd61 100644 --- a/usb/xhcid/Cargo.toml +++ b/usb/xhcid/Cargo.toml @@ -29,7 +29,7 @@ smallvec = { version = "1", features = ["serde"] } thiserror = "1" toml = "0.5" -common = { path = "../common" } -pcid = { path = "../pcid" } +common = { path = "../../common" } +pcid = { path = "../../pcid" } libredox = "0.1.3" regex = "1.10.6" From c00056e79155fbad8bbf8757ee130ad7cb90db51 Mon Sep 17 00:00:00 2001 From: Filippo Mutta Date: Wed, 1 Oct 2025 18:56:27 +0200 Subject: [PATCH 1244/1301] USB: reorganised order. --- Cargo.toml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 067278f84d..4a569bd1f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,11 +12,6 @@ members = [ "inputd", "virtio-core", - "usb/xhcid", - "usb/usbctl", - "usb/usbhubd", - - "audio/ac97d", "audio/ihdad", "audio/sb16d", @@ -49,6 +44,10 @@ members = [ "storage/nvmed", "storage/usbscsid", "storage/virtio-blkd", + + "usb/xhcid", + "usb/usbctl", + "usb/usbhubd", ] [profile.release] From 05f80e68415b38088a83586f2534b19794cac3f5 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sat, 4 Oct 2025 16:08:14 +0200 Subject: [PATCH 1245/1301] Replace removed nightly features. --- net/alxd/src/device/mod.rs | 12 ++++++------ net/alxd/src/main.rs | 3 ++- pcid/src/main.rs | 1 - 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/net/alxd/src/device/mod.rs b/net/alxd/src/device/mod.rs index 8dcfc3192d..28719dd7d1 100644 --- a/net/alxd/src/device/mod.rs +++ b/net/alxd/src/device/mod.rs @@ -127,27 +127,27 @@ const ADVERTISE_1000FULL: u32 = 0x0200; macro_rules! FIELD_GETX { ($x:expr, $name:ident) => { - ((($x) >> concat_idents!($name, _SHIFT)) & concat_idents!($name, _MASK)) + ((($x) >> ${concat($name, _SHIFT)} & ${concat($name, _MASK)})) }; } macro_rules! FIELDX { ($name:ident, $v:expr) => { - (((($v) as u32) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT)) + (((($v) as u32) & ${concat($name, _MASK)}) << ${concat($name, _SHIFT)}) }; } macro_rules! FIELD_SETS { ($x:expr, $name:ident, $v:expr) => {{ - ($x) = (($x) & !(concat_idents!($name, _MASK) << concat_idents!($name, _SHIFT))) - | (((($v) as u16) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT)) + ($x) = (($x) & !(${concat($name, _MASK)} << ${concat($name, _SHIFT)})) + | (((($v) as u16) & ${concat($name, _MASK)}) << ${concat($name, _SHIFT)}) }}; } macro_rules! FIELD_SET32 { ($x:expr, $name:ident, $v:expr) => {{ - ($x) = (($x) & !(concat_idents!($name, _MASK) << concat_idents!($name, _SHIFT))) - | (((($v) as u32) & concat_idents!($name, _MASK)) << concat_idents!($name, _SHIFT)) + ($x) = (($x) & !(${concat($name, _MASK)} << ${concat($name, _SHIFT)})) + | (((($v) as u32) & ${concat($name, _MASK)}) << ${concat($name, _SHIFT)}) }}; } diff --git a/net/alxd/src/main.rs b/net/alxd/src/main.rs index f87d256dba..5a9223ee04 100644 --- a/net/alxd/src/main.rs +++ b/net/alxd/src/main.rs @@ -1,7 +1,8 @@ +#![feature(macro_metavar_expr_concat)] + #![allow(dead_code)] #![allow(non_upper_case_globals)] #![allow(unused_parens)] -#![feature(concat_idents)] extern crate event; extern crate syscall; diff --git a/pcid/src/main.rs b/pcid/src/main.rs index bbfb8ba301..c06e583c63 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,4 +1,3 @@ -#![feature(array_chunks)] #![feature(non_exhaustive_omitted_patterns_lint)] #![feature(iter_next_chunk)] #![feature(if_let_guard)] From b7e260747f53d65314bd08656c3f76750c1181a6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 4 Oct 2025 08:10:15 -0600 Subject: [PATCH 1246/1301] array_chunks feature is stable in new nightly --- pcid/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index bbfb8ba301..c06e583c63 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,4 +1,3 @@ -#![feature(array_chunks)] #![feature(non_exhaustive_omitted_patterns_lint)] #![feature(iter_next_chunk)] #![feature(if_let_guard)] From 86aea82139e7376a0f59db4316ee0dd7d4d04dd6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 4 Oct 2025 09:18:58 -0600 Subject: [PATCH 1247/1301] Update rust-toolchain.toml --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index e34f9fb808..42f22f6190 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2025-01-12" +channel = "nightly-2025-10-03" components = ["rust-src"] From 1ca468f66dda931c913a032700d2af852f1bfcb4 Mon Sep 17 00:00:00 2001 From: Ribbon Date: Mon, 6 Oct 2025 07:19:29 -0300 Subject: [PATCH 1248/1301] Improve README --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 682cd06b74..352100bbce 100644 --- a/README.md +++ b/README.md @@ -64,15 +64,17 @@ If you want to port a driver from a monolithic OS to Redox you will need to rewr ### Write a Driver -Datasheets are preferable, when they are freely available. Be aware that datasheets are often provided under a [Non-Disclosure Agreement](https://en.wikipedia.org/wiki/Non-disclosure_agreement) from hardware vendors, which can affect the ability to create an MIT-licensed driver. +Datasheets are preferable (much more easy depending on device complexity), when they are freely available. Be aware that datasheets are often provided under a [Non-Disclosure Agreement](https://en.wikipedia.org/wiki/Non-disclosure_agreement) from hardware vendors, which can affect the ability to create an MIT-licensed driver. If you don't have datasheets, we recommend you to do reverse-engineering of available C code on BSD drivers. -You can use the [example](https://gitlab.redox-os.org/redox-os/exampled) driver or read the code of other drivers with the same type of your device. +### Libraries + +You should use the [redox-scheme](https://crates.io/crates/redox-scheme) and [redox_event](https://crates.io/crates/redox_event) crates to create your drivers, you can also read the [example driver](https://gitlab.redox-os.org/redox-os/exampled) or read the code of other drivers with the same type of your device. Before testing your changes, be aware of [this](https://doc.redox-os.org/book/coding-and-building.html#a-note-about-drivers). -### Driver References +### References If you want to reverse enginner the existing drivers, you can access the BSD code using these links: From 322b7440bf2ac5182d16e18d44ed246f78b846b1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 14 Oct 2025 20:15:35 +0200 Subject: [PATCH 1249/1301] Remove a useless loop in driver-block This is a leftover from switching from a readiness based api to async functions. --- storage/driver-block/src/lib.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/storage/driver-block/src/lib.rs b/storage/driver-block/src/lib.rs index 29cf01eda0..1c28cae0aa 100644 --- a/storage/driver-block/src/lib.rs +++ b/storage/driver-block/src/lib.rs @@ -144,11 +144,10 @@ impl DiskWrapper { if block >= size_in_blocks { return Err(io::Error::from_raw_os_error(syscall::EOVERFLOW)); } - loop { - let bytes = self.executor.block_on(disk.read(block, block_bytes))?; - assert_eq!(bytes, block_bytes.len()); - return Ok(()); - } + + let bytes = self.executor.block_on(disk.read(block, block_bytes))?; + assert_eq!(bytes, block_bytes.len()); + Ok(()) }; let bytes_read = block_read(self.offset, blksize, buf, read_block)?; From ae846274793be9bb99198929897dc04f08bb56bb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 14 Oct 2025 20:22:49 +0200 Subject: [PATCH 1250/1301] Rustfmt --- net/alxd/src/main.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/net/alxd/src/main.rs b/net/alxd/src/main.rs index 5a9223ee04..7f4c11d6a9 100644 --- a/net/alxd/src/main.rs +++ b/net/alxd/src/main.rs @@ -1,5 +1,4 @@ #![feature(macro_metavar_expr_concat)] - #![allow(dead_code)] #![allow(non_upper_case_globals)] #![allow(unused_parens)] From a463b5dcb5532960594a2aa365037e8799ca1292 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Oct 2025 11:55:17 -0600 Subject: [PATCH 1251/1301] Update acpi crate --- Cargo.lock | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 607c1ad322..18db58060d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,7 +20,7 @@ dependencies = [ [[package]] name = "acpi" version = "6.0.1" -source = "git+https://github.com/jackpot51/acpi.git#1c404f42bae2c1c5e8e65f6f86a956c212e97311" +source = "git+https://github.com/jackpot51/acpi.git#33b23373c8affe75c60f2872a525394331aa859e" dependencies = [ "bit_field", "bitflags 2.9.0", @@ -634,6 +634,7 @@ version = "0.1.0" dependencies = [ "amlserde", "common", + "fdt 0.1.5", "log", "ron", ] From ce10c962c93d2621a9ce4de677fe4d26b5562d17 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Oct 2025 12:09:59 -0600 Subject: [PATCH 1252/1301] hwd: spawn acpid and provide abstraction for acpi/dtb/legacy --- hwd/Cargo.toml | 1 + hwd/src/backend/acpi.rs | 82 ++++++++++++++++++++++++++++++++ hwd/src/backend/devicetree.rs | 20 ++++++++ hwd/src/backend/legacy.rs | 16 +++++++ hwd/src/backend/mod.rs | 14 ++++++ hwd/src/main.rs | 89 ++++++++++++----------------------- 6 files changed, 164 insertions(+), 58 deletions(-) create mode 100644 hwd/src/backend/acpi.rs create mode 100644 hwd/src/backend/devicetree.rs create mode 100644 hwd/src/backend/legacy.rs create mode 100644 hwd/src/backend/mod.rs diff --git a/hwd/Cargo.toml b/hwd/Cargo.toml index 6f6dd6a9d7..b592f2da71 100644 --- a/hwd/Cargo.toml +++ b/hwd/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2018" [dependencies] +fdt = "0.1.5" log = "0.4" ron = "0.8.1" diff --git a/hwd/src/backend/acpi.rs b/hwd/src/backend/acpi.rs new file mode 100644 index 0000000000..9827f5aae3 --- /dev/null +++ b/hwd/src/backend/acpi.rs @@ -0,0 +1,82 @@ +use amlserde::{AmlSerde, AmlSerdeValue}; +use std::{error::Error, fs, process::Command}; + +use super::Backend; + +pub struct AcpiBackend { + rxsdt: Vec, +} + +impl Backend for AcpiBackend { + fn new() -> Result> { + let rxsdt = fs::read("/scheme/kernel.acpi/rxsdt")?; + + // Spawn acpid + //TODO: pass rxsdt data to acpid? + Command::new("acpid").spawn()?.wait()?; + + Ok(Self { rxsdt }) + } + + fn probe(&mut self) -> Result<(), Box> { + // Read symbols from acpi scheme + for entry_res in fs::read_dir("/scheme/acpi/symbols")? { + let entry = entry_res?; + if let Some(file_name) = entry.file_name().to_str() { + if file_name.ends_with("_CID") || file_name.ends_with("_HID") { + let ron = fs::read_to_string(entry.path())?; + let AmlSerde { name, value } = ron::from_str(&ron)?; + let id = match value { + AmlSerdeValue::Integer(integer) => { + let vendor = integer & 0xFFFF; + let device = (integer >> 16) & 0xFFFF; + let vendor_rev = ((vendor & 0xFF) << 8) | vendor >> 8; + let vendor_1 = (((vendor_rev >> 10) & 0x1f) as u8 + 64) as char; + let vendor_2 = (((vendor_rev >> 5) & 0x1f) as u8 + 64) as char; + let vendor_3 = (((vendor_rev >> 0) & 0x1f) as u8 + 64) as char; + //TODO: simplify this nibble swap + let device_1 = (device >> 4) & 0xF; + let device_2 = (device >> 0) & 0xF; + let device_3 = (device >> 12) & 0xF; + let device_4 = (device >> 8) & 0xF; + format!( + "{}{}{}{:01X}{:01X}{:01X}{:01X}", + vendor_1, + vendor_2, + vendor_3, + device_1, + device_2, + device_3, + device_4 + ) + } + AmlSerdeValue::String(string) => string, + _ => { + log::warn!("{}: unsupported value {:x?}", name, value); + continue; + } + }; + let what = match id.as_str() { + // https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html + "ACPI0006" => "GPE block device", + "ACPI0010" => "Processor control device", + // https://uefi.org/sites/default/files/resources/devids%20%285%29.txt + "PNP0103" => "HPET", + "PNP0303" => "IBM Enhanced (101/102-key, PS/2 mouse support)", + "PNP0400" => "Standard LPT printer port", + "PNP0501" => "16550A-compatible COM port", + "PNP0A03" => "PCI bus", + "PNP0A05" => "Generic ACPI bus", + "PNP0A06" => "Generic ACPI Extended-IO bus (EIO bus)", + "PNP0B00" => "AT real-time clock", + "PNP0C0F" => "PCI interrupt link device", + "PNP0F13" => "PS/2 port for PS/2-style mouse", + _ => "?", + }; + log::debug!("{}: {} ({})", name, id, what); + } + } + } + Ok(()) + } +} diff --git a/hwd/src/backend/devicetree.rs b/hwd/src/backend/devicetree.rs new file mode 100644 index 0000000000..10b9a6e997 --- /dev/null +++ b/hwd/src/backend/devicetree.rs @@ -0,0 +1,20 @@ +use std::{error::Error, fs}; + +use super::Backend; + +pub struct DeviceTreeBackend { + dtb: Vec, +} + +impl Backend for DeviceTreeBackend { + fn new() -> Result> { + let dtb = fs::read("/scheme/kernel.dtb")?; + Ok(Self { dtb }) + } + + fn probe(&mut self) -> Result<(), Box> { + let dt = fdt::Fdt::new(&self.dtb).map_err(|err| format!("failed to parse dtb: {}", err))?; + log::info!("TODO: handle driver spawning from devicetree backend"); + Ok(()) + } +} diff --git a/hwd/src/backend/legacy.rs b/hwd/src/backend/legacy.rs new file mode 100644 index 0000000000..23e9c1f24f --- /dev/null +++ b/hwd/src/backend/legacy.rs @@ -0,0 +1,16 @@ +use std::error::Error; + +use super::Backend; + +pub struct LegacyBackend; + +impl Backend for LegacyBackend { + fn new() -> Result> { + Ok(Self) + } + + fn probe(&mut self) -> Result<(), Box> { + log::info!("TODO: handle driver spawning from legacy backend"); + Ok(()) + } +} diff --git a/hwd/src/backend/mod.rs b/hwd/src/backend/mod.rs new file mode 100644 index 0000000000..815b48aa75 --- /dev/null +++ b/hwd/src/backend/mod.rs @@ -0,0 +1,14 @@ +use std::error::Error; + +mod acpi; +mod devicetree; +mod legacy; + +pub use self::{acpi::AcpiBackend, devicetree::DeviceTreeBackend, legacy::LegacyBackend}; + +pub trait Backend { + fn new() -> Result> + where + Self: Sized; + fn probe(&mut self) -> Result<(), Box>; +} diff --git a/hwd/src/main.rs b/hwd/src/main.rs index 264bbc8c8e..e71cbbf198 100644 --- a/hwd/src/main.rs +++ b/hwd/src/main.rs @@ -1,60 +1,5 @@ -use amlserde::{AmlSerde, AmlSerdeValue}; -use std::{error::Error, fs}; - -fn acpi() -> Result<(), Box> { - for entry_res in fs::read_dir("/scheme/acpi/symbols")? { - let entry = entry_res?; - if let Some(file_name) = entry.file_name().to_str() { - if file_name.ends_with("_CID") || file_name.ends_with("_HID") { - let ron = fs::read_to_string(entry.path())?; - let AmlSerde { name, value } = ron::from_str(&ron)?; - let id = match value { - AmlSerdeValue::Integer(integer) => { - let vendor = integer & 0xFFFF; - let device = (integer >> 16) & 0xFFFF; - let vendor_rev = ((vendor & 0xFF) << 8) | vendor >> 8; - let vendor_1 = (((vendor_rev >> 10) & 0x1f) as u8 + 64) as char; - let vendor_2 = (((vendor_rev >> 5) & 0x1f) as u8 + 64) as char; - let vendor_3 = (((vendor_rev >> 0) & 0x1f) as u8 + 64) as char; - //TODO: simplify this nibble swap - let device_1 = (device >> 4) & 0xF; - let device_2 = (device >> 0) & 0xF; - let device_3 = (device >> 12) & 0xF; - let device_4 = (device >> 8) & 0xF; - format!( - "{}{}{}{:01X}{:01X}{:01X}{:01X}", - vendor_1, vendor_2, vendor_3, device_1, device_2, device_3, device_4 - ) - } - AmlSerdeValue::String(string) => string, - _ => { - log::warn!("{}: unsupported value {:x?}", name, value); - continue; - } - }; - let what = match id.as_str() { - // https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html - "ACPI0006" => "GPE block device", - "ACPI0010" => "Processor control device", - // https://uefi.org/sites/default/files/resources/devids%20%285%29.txt - "PNP0103" => "HPET", - "PNP0303" => "IBM Enhanced (101/102-key, PS/2 mouse support)", - "PNP0400" => "Standard LPT printer port", - "PNP0501" => "16550A-compatible COM port", - "PNP0A03" => "PCI bus", - "PNP0A05" => "Generic ACPI bus", - "PNP0A06" => "Generic ACPI Extended-IO bus (EIO bus)", - "PNP0B00" => "AT real-time clock", - "PNP0C0F" => "PCI interrupt link device", - "PNP0F13" => "PS/2 port for PS/2-style mouse", - _ => "?", - }; - log::debug!("{}: {} ({})", name, id, what); - } - } - } - Ok(()) -} +mod backend; +use self::backend::{AcpiBackend, Backend, DeviceTreeBackend, LegacyBackend}; fn main() { common::setup_logging( @@ -65,6 +10,34 @@ fn main() { log::LevelFilter::Debug, ); + // Prefer DTB if available (matches kernel preference) + let mut backend: Box = match DeviceTreeBackend::new() { + Ok(ok) => { + log::info!("using devicetree backend"); + Box::new(ok) + } + Err(err) => { + log::debug!("cannot use devicetree backend: {}", err); + match AcpiBackend::new() { + Ok(ok) => { + log::info!("using ACPI backend"); + Box::new(ok) + } + Err(err) => { + log::debug!("cannot use ACPI backend: {}", err); + + log::info!("using legacy backend"); + Box::new(LegacyBackend) + } + } + } + }; + //TODO: HWD is meant to locate PCI/XHCI/etc devices in ACPI and DeviceTree definitions and start their drivers - acpi().unwrap(); + match backend.probe() { + Ok(()) => {} + Err(err) => { + log::error!("failed to probe with error {}", err); + } + } } From 16f24757ea09b7fa5a57dfc1d7eef089a16f9fe4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Oct 2025 13:56:23 -0600 Subject: [PATCH 1253/1301] Update dependencies --- Cargo.lock | 393 ++++++++++++++++++++--------------------------- acpid/Cargo.toml | 2 +- 2 files changed, 169 insertions(+), 226 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 18db58060d..455a3d4100 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,10 +20,10 @@ dependencies = [ [[package]] name = "acpi" version = "6.0.1" -source = "git+https://github.com/jackpot51/acpi.git#33b23373c8affe75c60f2872a525394331aa859e" +source = "git+https://github.com/jackpot51/acpi.git#444e039346b8dfc0b25ed868cf03e2033eee86c1" dependencies = [ "bit_field", - "bitflags 2.9.0", + "bitflags 2.9.4", "byteorder", "log", "pci_types", @@ -42,7 +42,7 @@ dependencies = [ "log", "num-derive", "num-traits", - "parking_lot 0.12.3", + "parking_lot 0.12.5", "plain", "redox-daemon", "redox-scheme 0.6.2", @@ -82,7 +82,7 @@ dependencies = [ name = "alxd" version = "0.1.0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "common", "libredox", "redox-daemon", @@ -99,12 +99,6 @@ dependencies = [ "toml 0.7.8", ] -[[package]] -name = "android-tzdata" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -125,9 +119,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "arrayvec" @@ -148,9 +142,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "base64" @@ -202,9 +196,9 @@ dependencies = [ [[package]] name = "bit_field" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" +checksum = "1e4b40c7323adcfc0a41c4b88143ed58346ff65a288fc144329c5c45e05d70c6" [[package]] name = "bitflags" @@ -214,18 +208,18 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" dependencies = [ "serde", ] [[package]] name = "bumpalo" -version = "3.17.0" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byteorder" @@ -235,10 +229,11 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.2.19" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a13707ac958681c13b39b458c073d0d9bc8a22cb1b2f4c8e55eb72c13f362" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ + "find-msvc-tools", "shlex", ] @@ -250,9 +245,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "chashmap" @@ -266,11 +261,10 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", @@ -320,9 +314,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -409,7 +403,7 @@ dependencies = [ name = "e1000d" version = "0.1.0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "common", "driver-network", "libredox", @@ -477,6 +471,12 @@ name = "fdt" version = "0.2.0-alpha1" source = "git+https://github.com/repnop/fdt.git#059bb2383873f8001959456e36ec123228f67642" +[[package]] +name = "find-msvc-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" + [[package]] name = "fuchsia-cprng" version = "0.1.1" @@ -539,7 +539,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.107", ] [[package]] @@ -574,14 +574,14 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 1.0.4", "libc", "r-efi", - "wasi", + "wasip2", ] [[package]] @@ -590,7 +590,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8283e7331b8c93b9756e0cfdbcfb90312852f953c6faf9bf741e684cc3b6ad69" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "crc", "log", "uuid", @@ -607,9 +607,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" [[package]] name = "hermit-abi" @@ -641,9 +641,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -681,7 +681,7 @@ dependencies = [ name = "ihdad" version = "0.1.0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "common", "libredox", "log", @@ -694,9 +694,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.9.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "6717a8d2a5a929a1a2eb43a12812498ed141a0bcfb7e8f7844fbdbe4303bba9f" dependencies = [ "equivalent", "hashbrown", @@ -726,7 +726,7 @@ checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" name = "ixgbed" version = "1.0.0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "common", "driver-network", "libredox", @@ -738,9 +738,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ "once_cell", "wasm-bindgen", @@ -754,17 +754,17 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "libc", "redox_syscall", ] @@ -783,19 +783,18 @@ dependencies = [ [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "maybe-uninit" @@ -805,9 +804,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "num-derive" @@ -840,20 +839,20 @@ name = "nvmed" version = "0.1.0" dependencies = [ "arrayvec", - "bitflags 2.9.0", + "bitflags 2.9.4", "common", "driver-block", "executor", "futures", "libredox", "log", - "parking_lot 0.12.3", + "parking_lot 0.12.5", "partitionlib", "pcid", "redox-daemon", "redox_event", "redox_syscall", - "smallvec 1.15.0", + "smallvec 1.15.1", ] [[package]] @@ -894,12 +893,12 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", - "parking_lot_core 0.9.10", + "parking_lot_core 0.9.12", ] [[package]] @@ -916,15 +915,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 1.0.4", "libc", "redox_syscall", - "smallvec 1.15.0", - "windows-targets", + "smallvec 1.15.1", + "windows-link", ] [[package]] @@ -943,7 +942,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4325c6aa3cca3373503b1527e75756f9fbfe5fd76be4b4c8a143ee47430b8e0" dependencies = [ "bit_field", - "bitflags 2.9.0", + "bitflags 2.9.4", ] [[package]] @@ -1005,9 +1004,9 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -1029,18 +1028,18 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] [[package]] name = "r-efi" -version = "5.2.0" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" [[package]] name = "rand" @@ -1106,7 +1105,7 @@ checksum = "81460b1526438123d16f0c968dbe42ba7f61e99645109b70e57864a8b66710fb" dependencies = [ "chrono", "log", - "smallvec 1.15.0", + "smallvec 1.15.1", "termion", ] @@ -1136,17 +1135,17 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69609faa5d5992247a4ef379917bb3e39be281405d6a0ccd4f942429400b956f" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "libredox", ] [[package]] name = "redox_syscall" -version = "0.5.13" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d04b7d0ee6b4a0207a0a7adb104d23ecb0b47d6beae7152d0fa34b692b29fd6" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", ] [[package]] @@ -1157,9 +1156,9 @@ checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb" [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -1169,9 +1168,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -1180,9 +1179,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rehid" @@ -1200,7 +1199,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ "base64 0.21.7", - "bitflags 2.9.0", + "bitflags 2.9.4", "serde", "serde_derive", ] @@ -1217,7 +1216,7 @@ dependencies = [ name = "rtl8139d" version = "0.1.0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "common", "driver-network", "libredox", @@ -1232,7 +1231,7 @@ dependencies = [ name = "rtl8168d" version = "0.1.0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "common", "driver-network", "libredox", @@ -1251,9 +1250,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" @@ -1265,7 +1264,7 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" name = "sb16d" version = "0.1.0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "common", "libredox", "log", @@ -1319,48 +1318,59 @@ version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3586be2cf6c0a8099a79a12b4084357aa9b3e0b0d7980e3b67aaf7a9d55f9f0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 1.0.4", "libc", "version-compare", ] [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.107", ] [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] name = "serde_spanned" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" dependencies = [ "serde", ] @@ -1373,12 +1383,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" @@ -1391,9 +1398,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" dependencies = [ "serde", ] @@ -1427,9 +1434,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -1456,9 +1463,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.100" +version = "2.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "2a26dbd934e5451d21ef060c018dae56fc073894c5a7896f882928a76e6d081b" dependencies = [ "proc-macro2", "quote", @@ -1503,7 +1510,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.107", ] [[package]] @@ -1529,9 +1536,9 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] @@ -1551,9 +1558,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] name = "unicode-width" @@ -1573,7 +1580,7 @@ dependencies = [ name = "usbhidd" version = "0.1.0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "common", "inputd", "log", @@ -1616,11 +1623,13 @@ checksum = "8772a4ccbb4e89959023bc5b7cb8623a795caa7092d99f3aa9501b9484d4557d" [[package]] name = "uuid" -version = "1.16.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" +checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" dependencies = [ "getrandom", + "js-sys", + "wasm-bindgen", ] [[package]] @@ -1688,7 +1697,7 @@ dependencies = [ name = "virtio-core" version = "0.1.0" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "common", "crossbeam-queue", "futures", @@ -1749,45 +1758,46 @@ dependencies = [ ] [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if 1.0.4", "once_cell", "rustversion", "wasm-bindgen-macro", + "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.107", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1795,22 +1805,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.107", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ "unicode-ident", ] @@ -1839,9 +1849,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", @@ -1852,114 +1862,50 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.107", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn 2.0.107", ] [[package]] name = "windows-link" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.3.2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - [[package]] name = "winnow" version = "0.5.40" @@ -1970,13 +1916,10 @@ dependencies = [ ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.0", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "xhcid" @@ -1999,7 +1942,7 @@ dependencies = [ "regex", "serde", "serde_json", - "smallvec 1.15.0", + "smallvec 1.15.1", "thiserror", "toml 0.5.11", ] diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 516aa9a78d..2e71a1e811 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -24,4 +24,4 @@ amlserde = { path = "../amlserde" } common = { path = "../common" } libredox = "0.1.3" redox-scheme = "0.6.2" -arrayvec = "0.7.6" +arrayvec = "0.7.6" \ No newline at end of file From 7109334d2b94cce94949488a6b9bb48c57979a0e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Oct 2025 16:51:04 -0600 Subject: [PATCH 1254/1301] hwd: require dtb to parse in order to use devicetree backend --- hwd/src/backend/devicetree.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/hwd/src/backend/devicetree.rs b/hwd/src/backend/devicetree.rs index 10b9a6e997..9159b9e631 100644 --- a/hwd/src/backend/devicetree.rs +++ b/hwd/src/backend/devicetree.rs @@ -9,6 +9,7 @@ pub struct DeviceTreeBackend { impl Backend for DeviceTreeBackend { fn new() -> Result> { let dtb = fs::read("/scheme/kernel.dtb")?; + let dt = fdt::Fdt::new(&dtb).map_err(|err| format!("failed to parse dtb: {}", err))?; Ok(Self { dtb }) } From 7359af31dedde8a088d779e9b78d01d42346ff57 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Oct 2025 16:58:09 -0600 Subject: [PATCH 1255/1301] Add two more ACPI IDs to hwd --- hwd/src/backend/acpi.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hwd/src/backend/acpi.rs b/hwd/src/backend/acpi.rs index 9827f5aae3..924a4e14db 100644 --- a/hwd/src/backend/acpi.rs +++ b/hwd/src/backend/acpi.rs @@ -65,10 +65,11 @@ impl Backend for AcpiBackend { "PNP0303" => "IBM Enhanced (101/102-key, PS/2 mouse support)", "PNP0400" => "Standard LPT printer port", "PNP0501" => "16550A-compatible COM port", - "PNP0A03" => "PCI bus", + "PNP0A03" | "PNP0A08" => "PCI bus", "PNP0A05" => "Generic ACPI bus", "PNP0A06" => "Generic ACPI Extended-IO bus (EIO bus)", "PNP0B00" => "AT real-time clock", + "PNP0C01" => "System board", "PNP0C0F" => "PCI interrupt link device", "PNP0F13" => "PS/2 port for PS/2-style mouse", _ => "?", From f7540f24f63754dde41b190b21ec4622bacb1be5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Oct 2025 17:53:51 -0600 Subject: [PATCH 1256/1301] hwd: describe more ACPI devices --- hwd/src/backend/acpi.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/hwd/src/backend/acpi.rs b/hwd/src/backend/acpi.rs index 924a4e14db..42170b2221 100644 --- a/hwd/src/backend/acpi.rs +++ b/hwd/src/backend/acpi.rs @@ -58,11 +58,17 @@ impl Backend for AcpiBackend { }; let what = match id.as_str() { // https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html - "ACPI0006" => "GPE block device", - "ACPI0010" => "Processor control device", + "ACPI0003" => "Power source", + "ACPI0006" => "GPE block", + "ACPI0007" => "Processor", + "ACPI0010" => "Processor control", // https://uefi.org/sites/default/files/resources/devids%20%285%29.txt + "PNP0000" => "AT interrupt controller", + "PNP0100" => "AT timer", "PNP0103" => "HPET", + "PNP0200" => "AT DMA controller", "PNP0303" => "IBM Enhanced (101/102-key, PS/2 mouse support)", + "PNP030B" => "PS/2 keyboard", "PNP0400" => "Standard LPT printer port", "PNP0501" => "16550A-compatible COM port", "PNP0A03" | "PNP0A08" => "PCI bus", @@ -70,7 +76,16 @@ impl Backend for AcpiBackend { "PNP0A06" => "Generic ACPI Extended-IO bus (EIO bus)", "PNP0B00" => "AT real-time clock", "PNP0C01" => "System board", - "PNP0C0F" => "PCI interrupt link device", + "PNP0C02" => "Reserved resources", + "PNP0C04" => "Math coprocessor", + "PNP0C09" => "Embedded controller", + "PNP0C0A" => "Battery", + "PNP0C0B" => "Fan", + "PNP0C0C" => "Power button", + "PNP0C0D" => "Lid sensor", + "PNP0C0E" => "Sleep button", + "PNP0C0F" => "PCI interrupt link", + "PNP0C50" => "I2C HID", "PNP0F13" => "PS/2 port for PS/2-style mouse", _ => "?", }; From 99160faeb1066c796f91e7c4c5eea71447e070fe Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 18 Oct 2025 19:49:18 -0600 Subject: [PATCH 1257/1301] hwd: debug devicetree devices --- hwd/src/backend/devicetree.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/hwd/src/backend/devicetree.rs b/hwd/src/backend/devicetree.rs index 9159b9e631..d9ff5e2ca6 100644 --- a/hwd/src/backend/devicetree.rs +++ b/hwd/src/backend/devicetree.rs @@ -6,6 +6,27 @@ pub struct DeviceTreeBackend { dtb: Vec, } +impl DeviceTreeBackend { + fn dump(node: &fdt::node::FdtNode<'_, '_>, level: usize) { + let mut line = String::new(); + for _ in 0..level { + line.push_str(" "); + } + line.push_str(node.name); + if let Some(compatible) = node.compatible() { + line.push_str(":"); + for id in compatible.all() { + line.push_str(" "); + line.push_str(id); + } + } + log::debug!("{}", line); + for child in node.children() { + Self::dump(&child, level + 1); + } + } +} + impl Backend for DeviceTreeBackend { fn new() -> Result> { let dtb = fs::read("/scheme/kernel.dtb")?; @@ -15,7 +36,8 @@ impl Backend for DeviceTreeBackend { fn probe(&mut self) -> Result<(), Box> { let dt = fdt::Fdt::new(&self.dtb).map_err(|err| format!("failed to parse dtb: {}", err))?; - log::info!("TODO: handle driver spawning from devicetree backend"); + let root = dt.find_node("/").ok_or_else(|| format!("failed to find root node"))?; + Self::dump(&root, 0); Ok(()) } } From d23eaf616a83958b4bad2ede10b978ae0345e4c6 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Mon, 20 Oct 2025 23:36:19 +0700 Subject: [PATCH 1258/1301] Add keymap config via ps2 scheme --- Cargo.lock | 1 + input/ps2d/Cargo.toml | 1 + input/ps2d/src/main.rs | 86 +++++++++++++++++++---- input/ps2d/src/scheme.rs | 145 +++++++++++++++++++++++++++++++++++++++ input/ps2d/src/state.rs | 4 ++ inputd/src/main.rs | 2 +- 6 files changed, 224 insertions(+), 15 deletions(-) create mode 100644 input/ps2d/src/scheme.rs diff --git a/Cargo.lock b/Cargo.lock index 455a3d4100..6581dacbea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1022,6 +1022,7 @@ dependencies = [ "log", "orbclient", "redox-daemon", + "redox-scheme 0.6.2", "redox_event", "redox_syscall", ] diff --git a/input/ps2d/Cargo.toml b/input/ps2d/Cargo.toml index e289ab0cae..e03d148ff1 100644 --- a/input/ps2d/Cargo.toml +++ b/input/ps2d/Cargo.toml @@ -10,6 +10,7 @@ orbclient = "0.3.27" redox_event = "0.4.1" redox_syscall = "0.5.10" redox-daemon = "0.1" +redox-scheme = "0.6.2" libredox = "0.1.3" common = { path = "../../common" } diff --git a/input/ps2d/src/main.rs b/input/ps2d/src/main.rs index 466943ee01..3a8922bbe4 100644 --- a/input/ps2d/src/main.rs +++ b/input/ps2d/src/main.rs @@ -13,11 +13,15 @@ use common::acquire_port_io_rights; use event::{user_data, EventQueue}; use inputd::ProducerHandle; use log::info; +use redox_scheme::{RequestKind, SignalBehavior, Socket}; +use syscall::{EAGAIN, EWOULDBLOCK}; +use crate::scheme::Ps2Scheme; use crate::state::Ps2d; mod controller; mod keymap; +mod scheme; mod state; mod vm; @@ -32,18 +36,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { acquire_port_io_rights().expect("ps2d: failed to get I/O permission"); - let (keymap, keymap_name): (fn(u8, bool) -> char, &str) = match env::args().skip(1).next() { - Some(k) => match k.to_lowercase().as_ref() { - "dvorak" => (keymap::dvorak::get_char, "dvorak"), - "us" => (keymap::us::get_char, "us"), - "gb" => (keymap::gb::get_char, "gb"), - "azerty" => (keymap::azerty::get_char, "azerty"), - "bepo" => (keymap::bepo::get_char, "bepo"), - "it" => (keymap::it::get_char, "it"), - &_ => (keymap::us::get_char, "us"), - }, - None => (keymap::us::get_char, "us"), - }; + let (mut keymap, mut keymap_name): (fn(u8, bool) -> char, &str) = + match env::args().skip(1).next() { + Some(k) => get_keymap_from_str(&k), + None => (keymap::us::get_char, "us"), + }; info!("ps2d: using keymap '{}'", keymap_name); @@ -53,6 +50,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { enum Source { Keyboard, Mouse, + Scheme, } } @@ -89,14 +87,29 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { ) .unwrap(); + let mut ps2d = Ps2d::new(input, keymap); + + let scheme_file = Socket::nonblock("ps2").expect("ps2d: failed to create ps2 scheme"); + + let mut scheme_handle = Ps2Scheme::new( + keymap_name.to_owned(), + vec!["dvorak", "us", "gb", "azerty", "bepo", "it"], + ); + + event_queue + .subscribe( + scheme_file.inner().raw(), + Source::Scheme, + event::EventFlags::READ, + ) + .unwrap(); + libredox::call::setrens(0, 0).expect("ps2d: failed to enter null namespace"); daemon .ready() .expect("ps2d: failed to mark daemon as ready"); - let mut ps2d = Ps2d::new(input, keymap); - let mut data = [0; 256]; for event in event_queue.map(|e| e.expect("ps2d: failed to get next event").user_data) { // There are some gotchas with ps/2 controllers that require this weird @@ -111,6 +124,39 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let (file, keyboard) = match event { Source::Keyboard => (&mut key_file, true), Source::Mouse => (&mut mouse_file, false), + Source::Scheme => { + loop { + let request = match scheme_file.next_request(SignalBehavior::Interrupt) { + Ok(Some(request)) => request, + Ok(None) => { + // Scheme likely got unmounted + std::process::exit(0); + } + Err(err) if err.errno == EWOULDBLOCK || err.errno == EAGAIN => break, + Err(err) => panic!("ps2: failed to read scheme: {:?}", err), + }; + + match request.kind() { + RequestKind::Call(call) => { + let response = call.handle_sync(&mut scheme_handle); + + scheme_file + .write_response(response, SignalBehavior::Restart) + .expect("ps2: failed to write next scheme response"); + } + RequestKind::OnClose { id: _ } => {} + _ => (), + } + } + + if keymap_name != &scheme_handle.keymap { + (keymap, keymap_name) = get_keymap_from_str(&scheme_handle.keymap); + info!("ps2d: updating to new keymap '{:?}'", keymap_name); + ps2d.update_keymap(keymap); + } + + continue; + } }; loop { @@ -128,6 +174,18 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { process::exit(0); } +fn get_keymap_from_str(k: &str) -> (fn(u8, bool) -> char, &'static str) { + match k.to_lowercase().as_ref() { + "dvorak" => (keymap::dvorak::get_char, "dvorak"), + "us" => (keymap::us::get_char, "us"), + "gb" => (keymap::gb::get_char, "gb"), + "azerty" => (keymap::azerty::get_char, "azerty"), + "bepo" => (keymap::bepo::get_char, "bepo"), + "it" => (keymap::it::get_char, "it"), + &_ => (keymap::us::get_char, "us"), + } +} + fn main() { redox_daemon::Daemon::new(daemon).expect("ps2d: failed to create daemon"); } diff --git a/input/ps2d/src/scheme.rs b/input/ps2d/src/scheme.rs new file mode 100644 index 0000000000..058ec776c3 --- /dev/null +++ b/input/ps2d/src/scheme.rs @@ -0,0 +1,145 @@ +use redox_scheme::scheme::SchemeSync; +use redox_scheme::{CallerCtx, OpenResult}; +use std::convert::TryFrom; +use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; +use syscall::schemev2::NewFdFlags; +use syscall::{ + Error, Result, EACCES, EINVAL, EMFILE, ENOENT, ENOTDIR, MODE_DIR, MODE_FILE, O_WRONLY, +}; + +pub struct Ps2Scheme { + pub keymap: String, + pub keymap_list: String, +} + +impl Ps2Scheme { + pub fn new(keymap: String, keymap_list: Vec<&str>) -> Ps2Scheme { + let scheme = Ps2Scheme { + keymap, + keymap_list: keymap_list.join("\n"), + }; + scheme + } +} + +impl SchemeSync for Ps2Scheme { + fn open(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result { + let path = path_str.trim_start_matches('/'); + if flags & O_WRONLY != 0 { + if ctx.uid != 0 || ctx.gid != 0 { + return Err(Error::new(EACCES)); + } else if path != "keymap" { + return Err(Error::new(EINVAL)); + } + } + + match path { + "" => Ok(OpenResult::ThisScheme { + number: 0, + flags: NewFdFlags::empty(), + }), + "keymap" => Ok(OpenResult::ThisScheme { + number: 1, + flags: NewFdFlags::POSITIONED, + }), + "keymap_list" => Ok(OpenResult::ThisScheme { + number: 2, + flags: NewFdFlags::POSITIONED, + }), + _ => Err(Error::new(ENOENT)), + } + } + fn getdents<'buf>( + &mut self, + id: usize, + mut buf: DirentBuf<&'buf mut [u8]>, + opaque_offset: u64, + ) -> Result> { + if id != 0 { + return Err(Error::new(ENOTDIR)); + } + let Ok(offset) = usize::try_from(opaque_offset) else { + return Ok(buf); + }; + for (this_idx, name) in ["keymap", "keymap_list"].iter().enumerate().skip(offset) { + buf.entry(DirEntry { + inode: this_idx as u64, + next_opaque_id: this_idx as u64 + 1, + kind: DirentKind::Regular, + name, + })?; + } + Ok(buf) + } + + fn fstat(&mut self, id: usize, stat: &mut syscall::Stat, _ctx: &CallerCtx) -> Result<()> { + stat.st_size = 0; + stat.st_mode = match id { + 0 => 0o555 | MODE_DIR, + 1 => 0o644 | MODE_FILE, + 2 => 0o444 | MODE_FILE, + _ => return Err(Error::new(ENOENT)), + }; + Ok(()) + } + + fn fpath(&mut self, _id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { + let path = b"/scheme/ps2"; + + let mut i = 0; + while i < buf.len() && i < path.len() { + buf[i] = path[i]; + i += 1; + } + + Ok(i) + } + + fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> { + Ok(()) + } + + fn read( + &mut self, + id: usize, + buf: &mut [u8], + offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> Result { + if offset != 0 { + return Ok(0); + } + let value = match id { + 1 => self.keymap.as_bytes(), + 2 => self.keymap_list.as_bytes(), + _ => { + return Err(Error::new(ENOENT)); + } + }; + + if buf.len() + 2 < value.len() { + return Err(Error::new(EMFILE)); + } + buf[..value.len()].copy_from_slice(value); + buf[value.len()] = b'\n'; + buf[value.len() + 1] = b'\0'; + Ok(value.len() + 2) + } + + fn write( + &mut self, + id: usize, + buf: &[u8], + offset: u64, + _fcntl_flags: u32, + _ctx: &CallerCtx, + ) -> Result { + if offset != 0 || id != 1 { + return Ok(0); + } + let new_keymap = String::from_utf8(buf.to_vec()).map_err(|_| Error::new(EINVAL))?; + self.keymap = new_keymap.trim().to_string(); + Ok(buf.len()) + } +} diff --git a/input/ps2d/src/state.rs b/input/ps2d/src/state.rs index 6e35b33fe9..b8126bcb1c 100644 --- a/input/ps2d/src/state.rs +++ b/input/ps2d/src/state.rs @@ -67,6 +67,10 @@ impl char> Ps2d { } } + pub fn update_keymap(&mut self, keymap: F) { + self.get_char = keymap; + } + pub fn irq(&mut self) { while let Some((keyboard, data)) = self.ps2.next() { self.handle(keyboard, data); diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 4b8646f4c5..6853a5769a 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -205,7 +205,7 @@ impl SchemeSync for InputScheme { "control" => Handle::Control, _ => { - log::error!("inputd: invalid path {path}"); + log::error!("inputd: invalid path '{path}'"); return Err(SysError::new(EINVAL)); } }; From f18cd7608135a6b61f799ef73036b6d29c72c4b6 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Mon, 20 Oct 2025 23:36:38 +0700 Subject: [PATCH 1259/1301] Fix fmt --- hwd/src/backend/devicetree.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hwd/src/backend/devicetree.rs b/hwd/src/backend/devicetree.rs index d9ff5e2ca6..8a91d04e42 100644 --- a/hwd/src/backend/devicetree.rs +++ b/hwd/src/backend/devicetree.rs @@ -36,7 +36,9 @@ impl Backend for DeviceTreeBackend { fn probe(&mut self) -> Result<(), Box> { let dt = fdt::Fdt::new(&self.dtb).map_err(|err| format!("failed to parse dtb: {}", err))?; - let root = dt.find_node("/").ok_or_else(|| format!("failed to find root node"))?; + let root = dt + .find_node("/") + .ok_or_else(|| format!("failed to find root node"))?; Self::dump(&root, 0); Ok(()) } From dfb977875fd0ea38e175e407e9dc7445bd806b8c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 21 Oct 2025 15:13:26 -0600 Subject: [PATCH 1260/1301] ahcid: add timeouts to all spin loops --- storage/ahcid/src/ahci/disk_ata.rs | 4 +- storage/ahcid/src/ahci/disk_atapi.rs | 2 +- storage/ahcid/src/ahci/hba.rs | 235 +++++++++++++++------------ 3 files changed, 133 insertions(+), 108 deletions(-) diff --git a/storage/ahcid/src/ahci/disk_ata.rs b/storage/ahcid/src/ahci/disk_ata.rs index 3494d8624d..4f83c51dcf 100644 --- a/storage/ahcid/src/ahci/disk_ata.rs +++ b/storage/ahcid/src/ahci/disk_ata.rs @@ -44,7 +44,7 @@ impl DiskATA { let mut fb = unsafe { Dma::zeroed()?.assume_init() }; let buf = unsafe { Dma::zeroed()?.assume_init() }; - port.init(&mut clb, &mut ctbas, &mut fb); + port.init(&mut clb, &mut ctbas, &mut fb)?; let size = unsafe { port.identify(&mut clb, &mut ctbas).unwrap_or(0) }; @@ -138,7 +138,7 @@ impl DiskATA { &mut self.clb, &mut self.ctbas, &mut self.buf, - ) { + )? { request.running_opt = Some((slot, sectors)); } diff --git a/storage/ahcid/src/ahci/disk_atapi.rs b/storage/ahcid/src/ahci/disk_atapi.rs index 9571ed9e0e..a0e75c0964 100644 --- a/storage/ahcid/src/ahci/disk_atapi.rs +++ b/storage/ahcid/src/ahci/disk_atapi.rs @@ -42,7 +42,7 @@ impl DiskATAPI { let mut fb = unsafe { Dma::zeroed()?.assume_init() }; let mut buf = unsafe { Dma::zeroed()?.assume_init() }; - port.init(&mut clb, &mut ctbas, &mut fb); + port.init(&mut clb, &mut ctbas, &mut fb)?; let size = unsafe { port.identify_packet(&mut clb, &mut ctbas).unwrap_or(0) }; diff --git a/storage/ahcid/src/ahci/hba.rs b/storage/ahcid/src/ahci/hba.rs index 0a4c71757e..a9d51792b0 100644 --- a/storage/ahcid/src/ahci/hba.rs +++ b/storage/ahcid/src/ahci/hba.rs @@ -1,6 +1,7 @@ use log::{debug, error, info, trace}; use std::mem::size_of; use std::ops::DerefMut; +use std::time::{Duration, Instant}; use std::{ptr, u32}; use common::io::{Io, Mmio}; @@ -29,6 +30,8 @@ const HBA_SIG_ATAPI: u32 = 0xEB140101; const HBA_SIG_PM: u32 = 0x96690101; const HBA_SIG_SEMB: u32 = 0xC33C0101; +const TIMEOUT: Duration = Duration::new(5, 0); + #[derive(Debug)] pub enum HbaPortType { None, @@ -76,22 +79,34 @@ impl HbaPort { } } - pub fn start(&mut self) { + pub fn start(&mut self) -> Result<()> { + let timer = Instant::now(); while self.cmd.readf(HBA_PORT_CMD_CR) { core::hint::spin_loop(); + if timer.elapsed() >= TIMEOUT { + log::error!("HBA start timed out"); + return Err(Error::new(EIO)); + } } self.cmd.writef(HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST, true); + Ok(()) } - pub fn stop(&mut self) { + pub fn stop(&mut self) -> Result<()> { self.cmd.writef(HBA_PORT_CMD_ST, false); + let timer = Instant::now(); while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { core::hint::spin_loop(); + if timer.elapsed() >= TIMEOUT { + log::error!("HBA stop timed out"); + return Err(Error::new(EIO)); + } } self.cmd.writef(HBA_PORT_CMD_FRE, false); + Ok(()) } pub fn slot(&self) -> Option { @@ -109,8 +124,8 @@ impl HbaPort { clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], fb: &mut Dma<[u8; 256]>, - ) { - self.stop(); + ) -> Result<()> { + self.stop()?; for i in 0..32 { let cmdheader = &mut clb[i]; @@ -139,13 +154,14 @@ impl HbaPort { self.cmd.writef(1 << 2 | 1 << 1, true); debug!(" - AHCI init {:X}", self.cmd.read()); + Ok(()) } pub unsafe fn identify( &mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], - ) -> Option { + ) -> Result { self.identify_inner(ATA_CMD_IDENTIFY, clb, ctbas) } @@ -153,7 +169,7 @@ impl HbaPort { &mut self, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], - ) -> Option { + ) -> Result { self.identify_inner(ATA_CMD_IDENTIFY_PACKET, clb, ctbas) } @@ -163,7 +179,7 @@ impl HbaPort { cmd: u8, clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], - ) -> Option { + ) -> Result { let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); let slot = self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { @@ -181,73 +197,72 @@ impl HbaPort { cmdfis.device.write(0); cmdfis.countl.write(1); cmdfis.counth.write(0); - })?; + })? + .ok_or(Error::new(EIO))?; - if self.ata_stop(slot).is_ok() { - let mut serial = String::new(); - for word in 10..20 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - serial.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - serial.push(b); - } + self.ata_stop(slot)?; + + let mut serial = String::new(); + for word in 10..20 { + let d = dest[word]; + let a = ((d >> 8) as u8) as char; + if a != '\0' { + serial.push(a); } - - let mut firmware = String::new(); - for word in 23..27 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - firmware.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - firmware.push(b); - } + let b = (d as u8) as char; + if b != '\0' { + serial.push(b); } - - let mut model = String::new(); - for word in 27..47 { - let d = dest[word]; - let a = ((d >> 8) as u8) as char; - if a != '\0' { - model.push(a); - } - let b = (d as u8) as char; - if b != '\0' { - model.push(b); - } - } - - let mut sectors = (dest[100] as u64) - | ((dest[101] as u64) << 16) - | ((dest[102] as u64) << 32) - | ((dest[103] as u64) << 48); - - let lba_bits = if sectors == 0 { - sectors = (dest[60] as u64) | ((dest[61] as u64) << 16); - 28 - } else { - 48 - }; - - info!( - " + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", - serial.trim(), - firmware.trim(), - model.trim(), - lba_bits, - sectors / 2048 - ); - - Some(sectors * 512) - } else { - None } + + let mut firmware = String::new(); + for word in 23..27 { + let d = dest[word]; + let a = ((d >> 8) as u8) as char; + if a != '\0' { + firmware.push(a); + } + let b = (d as u8) as char; + if b != '\0' { + firmware.push(b); + } + } + + let mut model = String::new(); + for word in 27..47 { + let d = dest[word]; + let a = ((d >> 8) as u8) as char; + if a != '\0' { + model.push(a); + } + let b = (d as u8) as char; + if b != '\0' { + model.push(b); + } + } + + let mut sectors = (dest[100] as u64) + | ((dest[101] as u64) << 16) + | ((dest[102] as u64) << 32) + | ((dest[103] as u64) << 48); + + let lba_bits = if sectors == 0 { + sectors = (dest[60] as u64) | ((dest[61] as u64) << 16); + 28 + } else { + 48 + }; + + info!( + " + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", + serial.trim(), + firmware.trim(), + model.trim(), + lba_bits, + sectors / 2048 + ); + + Ok(sectors * 512) } pub fn ata_dma( @@ -258,7 +273,7 @@ impl HbaPort { clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], buf: &mut Dma<[u8; 256 * 512]>, - ) -> Option { + ) -> Result> { trace!( "AHCI {:X} DMA BLOCK: {:X} SECTORS: {} WRITE: {}", (self as *mut HbaPort) as usize, @@ -338,7 +353,7 @@ impl HbaPort { cmdfis.featureh.write(0); unsafe { ptr::write_volatile(acmd.as_mut_ptr() as *mut [u8; 16], *cmd) }; - }) + })? .ok_or(Error::new(EIO))?; self.ata_stop(slot) } @@ -348,7 +363,7 @@ impl HbaPort { clb: &mut Dma<[HbaCmdHeader; 32]>, ctbas: &mut [Dma; 32], callback: F, - ) -> Option + ) -> Result> where F: FnOnce( &mut HbaCmdHeader, @@ -360,44 +375,49 @@ impl HbaPort { //TODO: Should probably remove self.is.write(u32::MAX); - if let Some(slot) = self.slot() { - { - let cmdheader = &mut clb[slot as usize]; - cmdheader - .cfl - .write((size_of::() / size_of::()) as u8); + let Some(slot) = self.slot() else { + return Ok(None); + }; - let cmdtbl = &mut ctbas[slot as usize]; - unsafe { - ptr::write_bytes( - cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, - 0, - size_of::(), - ); - } + { + let cmdheader = &mut clb[slot as usize]; + cmdheader + .cfl + .write((size_of::() / size_of::()) as u8); - let cmdfis = unsafe { &mut *(cmdtbl.cfis.as_mut_ptr() as *mut FisRegH2D) }; - cmdfis.fis_type.write(FisType::RegH2D as u8); - - let prdt_entry = unsafe { &mut *(&mut cmdtbl.prdt_entry as *mut _) }; - let acmd = unsafe { &mut *(&mut cmdtbl.acmd as *mut _) }; - - callback(cmdheader, cmdfis, prdt_entry, acmd) + let cmdtbl = &mut ctbas[slot as usize]; + unsafe { + ptr::write_bytes( + cmdtbl.deref_mut() as *mut HbaCmdTable as *mut u8, + 0, + size_of::(), + ); } - while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - core::hint::spin_loop(); - } + let cmdfis = unsafe { &mut *(cmdtbl.cfis.as_mut_ptr() as *mut FisRegH2D) }; + cmdfis.fis_type.write(FisType::RegH2D as u8); - self.ci.writef(1 << slot, true); + let prdt_entry = unsafe { &mut *(&mut cmdtbl.prdt_entry as *mut _) }; + let acmd = unsafe { &mut *(&mut cmdtbl.acmd as *mut _) }; - //TODO: Should probably remove - self.start(); - - Some(slot) - } else { - None + callback(cmdheader, cmdfis, prdt_entry, acmd) } + + let timer = Instant::now(); + while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { + core::hint::spin_loop(); + if timer.elapsed() >= TIMEOUT { + log::error!("HBA ata_start timeout"); + return Err(Error::new(EIO)); + } + } + + self.ci.writef(1 << slot, true); + + //TODO: Should probably remove + self.start()?; + + Ok(Some(slot)) } pub fn ata_running(&self, slot: u32) -> bool { @@ -405,11 +425,16 @@ impl HbaPort { } pub fn ata_stop(&mut self, slot: u32) -> Result<()> { + let timer = Instant::now(); while self.ata_running(slot) { core::hint::spin_loop(); + if timer.elapsed() >= TIMEOUT { + log::error!("HBA ata_stop timeout"); + return Err(Error::new(EIO)); + } } - self.stop(); + self.stop()?; if self.is.read() & HBA_PORT_IS_ERR != 0 { let (is, ie, cmd, tfd, ssts, sctl, serr, sact, ci, sntf, fbs) = ( From b9d0599bac57a9982f5a13780e6dcd2e15f69318 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 22 Oct 2025 16:27:32 +0700 Subject: [PATCH 1261/1301] Add scrollback into fbbootlogd --- graphics/console-draw/src/lib.rs | 34 ++++++++++ graphics/fbbootlogd/src/main.rs | 6 +- graphics/fbbootlogd/src/scheme.rs | 109 ++++++++++++++++++++++++++---- 3 files changed, 136 insertions(+), 13 deletions(-) diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index 390c5cc73a..93fa641cd1 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -260,3 +260,37 @@ impl TextScreen { } } } + +pub struct TextBuffer { + pub lines: VecDeque>, + pub lines_max: u32, +} + +impl TextBuffer { + pub fn new(max: u32) -> Self { + let mut lines = VecDeque::new(); + lines.push_back(Vec::new()); + Self { + lines, + lines_max: max, + } + } + pub fn write(&mut self, buf: &[u8]) { + if buf.is_empty() { + return; + } + + for &byte in buf { + self.lines.back_mut().unwrap().push(byte); + + if byte == b'\n' { + self.lines.push_back(Vec::new()); + } + } + + let max_len = self.lines_max as usize; + while self.lines.len() > max_len { + self.lines.pop_front(); + } + } +} diff --git a/graphics/fbbootlogd/src/main.rs b/graphics/fbbootlogd/src/main.rs index b2f723ba3f..bc3759c469 100644 --- a/graphics/fbbootlogd/src/main.rs +++ b/graphics/fbbootlogd/src/main.rs @@ -107,7 +107,11 @@ fn inner(daemon: redox_daemon::Daemon) -> ! { .expect("fbbootlogd: error while reading events") { ConsumerHandleEvent::Events(&[]) => break, - ConsumerHandleEvent::Events(_) => {} + ConsumerHandleEvent::Events(events) => { + for event in events { + scheme.handle_input(&event); + } + } ConsumerHandleEvent::Handoff => { eprintln!("fbbootlogd: handoff requested"); scheme.handle_handoff(); diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index f6180e280b..0b33312959 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -1,9 +1,10 @@ use std::collections::VecDeque; -use std::ptr; +use std::{cmp, ptr}; use console_draw::TextScreen; use graphics_ipc::v2::V2GraphicsHandle; use inputd::ConsumerHandle; +use orbclient::{Event, EventOption}; use redox_scheme::scheme::SchemeSync; use redox_scheme::{CallerCtx, OpenResult}; use syscall::schemev2::NewFdFlags; @@ -19,6 +20,9 @@ pub struct FbbootlogScheme { pub input_handle: ConsumerHandle, display_map: Option, text_screen: console_draw::TextScreen, + text_buffer: console_draw::TextBuffer, + is_scrollback: bool, + scrollback_offset: usize, } impl FbbootlogScheme { @@ -27,6 +31,9 @@ impl FbbootlogScheme { input_handle: ConsumerHandle::new_vt().expect("fbbootlogd: Failed to open vt"), display_map: None, text_screen: console_draw::TextScreen::new(), + text_buffer: console_draw::TextBuffer::new(1000), + is_scrollback: false, + scrollback_offset: 1000, }; scheme.handle_handoff(); @@ -64,6 +71,81 @@ impl FbbootlogScheme { } } + pub fn handle_input(&mut self, ev: &Event) { + match ev.to_option() { + EventOption::Key(key_event) => { + match key_event.scancode { + 0x48 => { + // Up + if self.scrollback_offset >= 1 { + self.scrollback_offset -= 1; + } + } + 0x49 => { + // Page up + if self.scrollback_offset >= 10 { + self.scrollback_offset -= 10; + } else { + self.scrollback_offset = 0; + } + } + 0x50 => { + // Down + self.scrollback_offset += 1; + } + 0x51 => { + // Page down + self.scrollback_offset += 10; + } + 0x47 => { + // Home + self.scrollback_offset = 0; + } + 0x4F => { + // End + self.scrollback_offset = 1000; + } + _ => return, + } + } + _ => return, + } + self.handle_scrollback_render(); + } + + fn handle_scrollback_render(&mut self) { + let Some(map) = &mut self.display_map else { + return; + }; + self.is_scrollback = true; + let buffer_len = self.text_buffer.lines.len(); + self.scrollback_offset = cmp::min(self.scrollback_offset, buffer_len - 10); + let mut i = self.scrollback_offset; + let dmap = &mut console_draw::DisplayMap { + offscreen: map.inner.ptr_mut(), + width: map.inner.width(), + height: map.inner.height(), + }; + self.text_screen + .write(dmap, b"\x1B[1;1H\x1B[2J", &mut VecDeque::new()); + while i < buffer_len { + let mut damage = + self.text_screen + .write(dmap, &self.text_buffer.lines[i][..], &mut VecDeque::new()); + i += 1; + let yd = damage.y + damage.height; + if i == buffer_len || yd + 48 >= dmap.height as u32 { + // render until end of screen + damage.height = (dmap.height as u32) - damage.y; + map.display_handle.update_plane(0, map.fb, damage).unwrap(); + self.is_scrollback = i < buffer_len; + break; + } else { + map.display_handle.update_plane(0, map.fb, damage).unwrap(); + } + } + } + fn handle_resize(map: &mut DisplayMap, text_screen: &mut TextScreen) { let (width, height) = match map.display_handle.display_size(0) { Ok((width, height)) => (width, height), @@ -163,19 +245,22 @@ impl SchemeSync for FbbootlogScheme { ) -> Result { if let Some(map) = &mut self.display_map { Self::handle_resize(map, &mut self.text_screen); + self.text_buffer.write(buf); - let damage = self.text_screen.write( - &mut console_draw::DisplayMap { - offscreen: map.inner.ptr_mut(), - width: map.inner.width(), - height: map.inner.height(), - }, - buf, - &mut VecDeque::new(), - ); + if !self.is_scrollback { + let damage = self.text_screen.write( + &mut console_draw::DisplayMap { + offscreen: map.inner.ptr_mut(), + width: map.inner.width(), + height: map.inner.height(), + }, + buf, + &mut VecDeque::new(), + ); - if let Some(map) = &self.display_map { - map.display_handle.update_plane(0, map.fb, damage).unwrap(); + if let Some(map) = &self.display_map { + map.display_handle.update_plane(0, map.fb, damage).unwrap(); + } } } From 306079c0918d74fd1c89bfab40d215bd1adbbd2e Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 22 Oct 2025 16:27:38 +0700 Subject: [PATCH 1262/1301] Fix fmt --- storage/ahcid/src/ahci/hba.rs | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/storage/ahcid/src/ahci/hba.rs b/storage/ahcid/src/ahci/hba.rs index a9d51792b0..bf5dac6e3a 100644 --- a/storage/ahcid/src/ahci/hba.rs +++ b/storage/ahcid/src/ahci/hba.rs @@ -182,23 +182,24 @@ impl HbaPort { ) -> Result { let dest: Dma<[u16; 256]> = Dma::new([0; 256]).unwrap(); - let slot = self.ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { - cmdheader.prdtl.write(1); + let slot = self + .ata_start(clb, ctbas, |cmdheader, cmdfis, prdt_entries, _acmd| { + cmdheader.prdtl.write(1); - let prdt_entry = &mut prdt_entries[0]; - prdt_entry.dba_low.write(dest.physical() as u32); - prdt_entry - .dba_high - .write((dest.physical() as u64 >> 32) as u32); - prdt_entry.dbc.write(512 | 1); + let prdt_entry = &mut prdt_entries[0]; + prdt_entry.dba_low.write(dest.physical() as u32); + prdt_entry + .dba_high + .write((dest.physical() as u64 >> 32) as u32); + prdt_entry.dbc.write(512 | 1); - cmdfis.pm.write(1 << 7); - cmdfis.command.write(cmd); - cmdfis.device.write(0); - cmdfis.countl.write(1); - cmdfis.counth.write(0); - })? - .ok_or(Error::new(EIO))?; + cmdfis.pm.write(1 << 7); + cmdfis.command.write(cmd); + cmdfis.device.write(0); + cmdfis.countl.write(1); + cmdfis.counth.write(0); + })? + .ok_or(Error::new(EIO))?; self.ata_stop(slot)?; From 6c9822893e09a2b118caddbb7123657a46f89653 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Wed, 22 Oct 2025 17:02:03 +0700 Subject: [PATCH 1263/1301] Fix double key register on dbbootlogd --- graphics/console-draw/src/lib.rs | 6 +++--- graphics/fbbootlogd/src/scheme.rs | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/graphics/console-draw/src/lib.rs b/graphics/console-draw/src/lib.rs index 93fa641cd1..20bc77b6e6 100644 --- a/graphics/console-draw/src/lib.rs +++ b/graphics/console-draw/src/lib.rs @@ -263,11 +263,11 @@ impl TextScreen { pub struct TextBuffer { pub lines: VecDeque>, - pub lines_max: u32, + pub lines_max: usize, } impl TextBuffer { - pub fn new(max: u32) -> Self { + pub fn new(max: usize) -> Self { let mut lines = VecDeque::new(); lines.push_back(Vec::new()); Self { @@ -288,7 +288,7 @@ impl TextBuffer { } } - let max_len = self.lines_max as usize; + let max_len = self.lines_max; while self.lines.len() > max_len { self.lines.pop_front(); } diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 0b33312959..4bfc0570b0 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -74,6 +74,9 @@ impl FbbootlogScheme { pub fn handle_input(&mut self, ev: &Event) { match ev.to_option() { EventOption::Key(key_event) => { + if !key_event.pressed { + return; + } match key_event.scancode { 0x48 => { // Up @@ -103,7 +106,7 @@ impl FbbootlogScheme { } 0x4F => { // End - self.scrollback_offset = 1000; + self.scrollback_offset = self.text_buffer.lines_max; } _ => return, } From fa9127ca34da6e208ea57045938b0f9c7b82f8fa Mon Sep 17 00:00:00 2001 From: Wildan M Date: Thu, 23 Oct 2025 00:14:05 +0700 Subject: [PATCH 1264/1301] Require shift key for scrollback and have better limit --- graphics/fbbootlogd/src/scheme.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/graphics/fbbootlogd/src/scheme.rs b/graphics/fbbootlogd/src/scheme.rs index 4bfc0570b0..58166f906c 100644 --- a/graphics/fbbootlogd/src/scheme.rs +++ b/graphics/fbbootlogd/src/scheme.rs @@ -23,6 +23,7 @@ pub struct FbbootlogScheme { text_buffer: console_draw::TextBuffer, is_scrollback: bool, scrollback_offset: usize, + shift: bool, } impl FbbootlogScheme { @@ -34,6 +35,7 @@ impl FbbootlogScheme { text_buffer: console_draw::TextBuffer::new(1000), is_scrollback: false, scrollback_offset: 1000, + shift: false, }; scheme.handle_handoff(); @@ -74,7 +76,9 @@ impl FbbootlogScheme { pub fn handle_input(&mut self, ev: &Event) { match ev.to_option() { EventOption::Key(key_event) => { - if !key_event.pressed { + if key_event.scancode == 0x2A || key_event.scancode == 0x36 { + self.shift = key_event.pressed; + } else if !key_event.pressed || !self.shift { return; } match key_event.scancode { @@ -120,15 +124,20 @@ impl FbbootlogScheme { let Some(map) = &mut self.display_map else { return; }; - self.is_scrollback = true; let buffer_len = self.text_buffer.lines.len(); - self.scrollback_offset = cmp::min(self.scrollback_offset, buffer_len - 10); - let mut i = self.scrollback_offset; let dmap = &mut console_draw::DisplayMap { offscreen: map.inner.ptr_mut(), width: map.inner.width(), height: map.inner.height(), }; + // for both extra space on wrapping text and a scrollback indicator + let spare_lines = 3; + self.is_scrollback = true; + self.scrollback_offset = cmp::min( + self.scrollback_offset, + buffer_len - dmap.height / 16 + spare_lines, + ); + let mut i = self.scrollback_offset; self.text_screen .write(dmap, b"\x1B[1;1H\x1B[2J", &mut VecDeque::new()); while i < buffer_len { @@ -136,8 +145,8 @@ impl FbbootlogScheme { self.text_screen .write(dmap, &self.text_buffer.lines[i][..], &mut VecDeque::new()); i += 1; - let yd = damage.y + damage.height; - if i == buffer_len || yd + 48 >= dmap.height as u32 { + let yd = (damage.y + damage.height) as usize; + if i == buffer_len || yd + spare_lines * 16 > dmap.height { // render until end of screen damage.height = (dmap.height as u32) - damage.y; map.display_handle.update_plane(0, map.fb, damage).unwrap(); From 8bf5d60e96e6f08aa0b47c64d8d229ca01dedb08 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 24 Oct 2025 08:19:34 -0600 Subject: [PATCH 1265/1301] Adjust logging, ensure drivers get unique logfiles --- audio/ac97d/src/main.rs | 4 ++-- audio/ihdad/src/hda/cmdbuff.rs | 4 +--- audio/ihdad/src/main.rs | 16 ++++++++-------- audio/sb16d/src/main.rs | 2 +- graphics/virtio-gpud/src/main.rs | 2 +- input/usbhidd/src/main.rs | 17 +++++++++-------- net/rtl8139d/src/main.rs | 16 ++++++++-------- net/rtl8168d/src/main.rs | 16 ++++++++-------- net/virtio-netd/src/main.rs | 2 +- storage/ahcid/src/main.rs | 2 +- storage/ided/src/main.rs | 2 +- storage/nvmed/src/main.rs | 2 +- storage/virtio-blkd/src/main.rs | 2 +- usb/usbhubd/src/main.rs | 16 +++++++++------- 14 files changed, 52 insertions(+), 51 deletions(-) diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index 92bd69db41..3249fb2e1e 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -38,8 +38,8 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { common::setup_logging( "audio", - "pcie", - "ac97", + "pci", + &name, log::LevelFilter::Info, log::LevelFilter::Info, ); diff --git a/audio/ihdad/src/hda/cmdbuff.rs b/audio/ihdad/src/hda/cmdbuff.rs index 88c08b5eea..6ada5f43c8 100644 --- a/audio/ihdad/src/hda/cmdbuff.rs +++ b/audio/ihdad/src/hda/cmdbuff.rs @@ -74,7 +74,6 @@ struct Corb { impl Corb { pub fn new(regs_addr: usize, corb_buff_phys: usize, corb_buff_virt: *mut u32) -> Corb { - println!("regs addr {:x}", regs_addr); unsafe { Corb { regs: &mut *(regs_addr as *mut CorbRegs), @@ -84,11 +83,10 @@ impl Corb { } } } + //Intel 4.4.1.3 pub fn init(&mut self) { - println!("{}:{}", file!(), line!()); self.stop(); - println!("{}:{}", file!(), line!()); //Determine CORB and RIRB size and allocate buffer //3.3.24 diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 078b12265d..fefaf2f0ad 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -59,14 +59,6 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - common::setup_logging( - "audio", - "pcie", - "ihda", - log::LevelFilter::Info, - log::LevelFilter::Info, - ); - let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); @@ -74,6 +66,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_ihda"); + common::setup_logging( + "audio", + "pci", + &name, + log::LevelFilter::Info, + log::LevelFilter::Info, + ); + log::info!(" + IHDA {}", pci_config.func.display()); let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index dfa863a7e1..352313dbda 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -21,7 +21,7 @@ fn main() { redox_daemon::Daemon::new(move |daemon| { common::setup_logging( "audio", - "pcie", + "pci", "sb16", log::LevelFilter::Info, log::LevelFilter::Info, diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 4b9654fe17..0c000f53ae 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -551,7 +551,7 @@ fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { pub fn main() { common::setup_logging( "misc", - "pcie", + "pci", "virtio-gpud", log::LevelFilter::Trace, log::LevelFilter::Trace, diff --git a/input/usbhidd/src/main.rs b/input/usbhidd/src/main.rs index 6bc79da3aa..4cef9c7c6e 100644 --- a/input/usbhidd/src/main.rs +++ b/input/usbhidd/src/main.rs @@ -167,14 +167,6 @@ fn send_key_event( } fn main() { - common::setup_logging( - "usb", - "device", - "hid", - log::LevelFilter::Info, - log::LevelFilter::Info, - ); - let mut args = env::args().skip(1); const USAGE: &'static str = "usbhidd "; @@ -190,6 +182,15 @@ fn main() { .expect(USAGE) .parse::() .expect("Expected integer as input of interface"); + + let name = format!("{}_{}_{}_hid", scheme, port, interface_num); + common::setup_logging( + "usb", + "device", + &name, + log::LevelFilter::Info, + log::LevelFilter::Info, + ); log::info!( "USB HID driver spawned with scheme `{}`, port {}, interface {}", diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index aaf4a9bd70..03fd17dd52 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -102,14 +102,6 @@ fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - common::setup_logging( - "net", - "pcie", - "rtl8139", - log::LevelFilter::Info, - log::LevelFilter::Info, - ); - let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); @@ -117,6 +109,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_rtl8139"); + common::setup_logging( + "net", + "pci", + &name, + log::LevelFilter::Info, + log::LevelFilter::Info, + ); + log::info!(" + RTL8139 {}", pci_config.func.display()); let bar = map_bar(&mut pcid_handle); diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 27094eb481..59c25ba985 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -102,14 +102,6 @@ fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { } fn daemon(daemon: redox_daemon::Daemon) -> ! { - common::setup_logging( - "net", - "pcie", - "rtl8168", - log::LevelFilter::Info, - log::LevelFilter::Info, - ); - let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); @@ -117,6 +109,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut name = pci_config.func.name(); name.push_str("_rtl8168"); + common::setup_logging( + "net", + "pci", + &name, + log::LevelFilter::Info, + log::LevelFilter::Info, + ); + log::info!(" + RTL8168 {}", pci_config.func.display()); let bar = map_bar(&mut pcid_handle); diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index ac4c2fa92b..c0231618f7 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -122,7 +122,7 @@ fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { pub fn main() { common::setup_logging( "net", - "pcie", + "pci", "virtio-netd", log::LevelFilter::Trace, log::LevelFilter::Trace, diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 7108647bf7..3df8947f73 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -31,7 +31,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { common::setup_logging( "disk", - "pcie", + "pci", &name, log::LevelFilter::Info, log::LevelFilter::Info, diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index db96961807..45592aedf6 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -31,7 +31,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { common::setup_logging( "disk", - "pcie", + "pci", &name, log::LevelFilter::Info, log::LevelFilter::Info, diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 013cc70589..ca0802c406 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -154,7 +154,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { common::setup_logging( "disk", - "pcie", + "pci", &scheme_name, log::LevelFilter::Info, log::LevelFilter::Info, diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 253eb9c572..b27343dce9 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -33,7 +33,7 @@ pub enum Error { pub fn main() -> anyhow::Result<()> { common::setup_logging( "disk", - "pcie", + "pci", "virtio-blkd", log::LevelFilter::Trace, log::LevelFilter::Trace, diff --git a/usb/usbhubd/src/main.rs b/usb/usbhubd/src/main.rs index 5d063d45b1..06a1550228 100644 --- a/usb/usbhubd/src/main.rs +++ b/usb/usbhubd/src/main.rs @@ -6,13 +6,6 @@ use xhcid_interface::{ }; fn main() { - common::setup_logging( - "usb", - "device", - "hub", - log::LevelFilter::Info, - log::LevelFilter::Info, - ); let mut args = env::args().skip(1); @@ -37,6 +30,15 @@ fn main() { interface_num ); + let name = format!("{}_{}_{}_hub", scheme, port, interface_num); + common::setup_logging( + "usb", + "device", + &name, + log::LevelFilter::Info, + log::LevelFilter::Info, + ); + let handle = XhciClientHandle::new(scheme.clone(), port_id); let desc: DevDesc = handle .get_standard_descs() From 57ca3be97581d509a37875ba0cdb5be6c94fe714 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 24 Oct 2025 08:21:01 -0600 Subject: [PATCH 1266/1301] Fixup for last commit --- usb/usbhubd/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usb/usbhubd/src/main.rs b/usb/usbhubd/src/main.rs index 06a1550228..408b776a74 100644 --- a/usb/usbhubd/src/main.rs +++ b/usb/usbhubd/src/main.rs @@ -30,7 +30,7 @@ fn main() { interface_num ); - let name = format!("{}_{}_{}_hub", scheme, port, interface_num); + let name = format!("{}_{}_{}_hub", scheme, port_id, interface_num); common::setup_logging( "usb", "device", From 63bad6332173aedc5142734b0240c3b26f77c07b Mon Sep 17 00:00:00 2001 From: aarch <126242-aarch@users.noreply.gitlab.redox-os.org> Date: Fri, 24 Oct 2025 17:48:29 +0000 Subject: [PATCH 1267/1301] Expose AML evaluation through acpi scheme --- Cargo.lock | 1 + acpid/Cargo.toml | 3 +- acpid/src/acpi.rs | 50 ++++++++- acpid/src/aml_physmem.rs | 2 +- acpid/src/main.rs | 1 + acpid/src/scheme.rs | 73 ++++++++++++-- amlserde/src/lib.rs | 213 ++++++++++++++++++++++++++++++++------- 7 files changed, 297 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6581dacbea..7f385b7175 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -50,6 +50,7 @@ dependencies = [ "redox_syscall", "ron", "rustc-hash", + "serde", "thiserror", ] diff --git a/acpid/Cargo.toml b/acpid/Cargo.toml index 2e71a1e811..8b162993a5 100644 --- a/acpid/Cargo.toml +++ b/acpid/Cargo.toml @@ -24,4 +24,5 @@ amlserde = { path = "../amlserde" } common = { path = "../common" } libredox = "0.1.3" redox-scheme = "0.6.2" -arrayvec = "0.7.6" \ No newline at end of file +arrayvec = "0.7.6" +serde = { version = "1.0.228", features = ["derive"] } diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 464a8a1a2c..9ddfdb3ab1 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,3 +1,4 @@ +use acpi::aml::object::{Object, WrappedObject}; use rustc_hash::FxHashMap; use std::convert::{TryFrom, TryInto}; use std::ops::Deref; @@ -18,7 +19,7 @@ use acpi::{ AcpiTables, }; use amlserde::aml_serde_name::aml_to_symbol; -use amlserde::AmlSerde; +use amlserde::{AmlSerde, AmlSerdeValue}; #[cfg(target_arch = "x86_64")] pub mod dmar; @@ -328,6 +329,21 @@ impl AmlSymbols { } } +#[derive(Debug, Error)] +pub enum AmlEvalError { + #[error("AML error")] + AmlError(AmlError), + #[error("Failed to serialize argument")] + SerializationError, + #[error("Failed to deserialize")] + DeserializationError, +} +impl From for AmlEvalError { + fn from(value: AmlError) -> Self { + AmlEvalError::AmlError(value) + } +} + pub struct AcpiContext { tables: Vec, dsdt: Option, @@ -344,6 +360,38 @@ pub struct AcpiContext { } impl AcpiContext { + pub fn aml_eval( + &self, + symbol: AmlName, + args: Vec, + ) -> Result { + let interpreter = &mut self.aml_symbols.write().aml_context; + interpreter.acquire_global_lock(16)?; + + let args = args + .into_iter() + .map(|aml_serde_value| { + aml_serde_value + .to_aml_object() + .map(Object::wrap) + .ok_or(AmlEvalError::DeserializationError) + }) + .collect::, AmlEvalError>>()?; + + let result = interpreter.evaluate(symbol, args); + interpreter + .release_global_lock() + .expect("Failed to release GIL!"); //TODO: check if this should panic + + result + .map_err(AmlEvalError::from) + .map(|object| { + AmlSerdeValue::from_aml_value(object.deref()) + .ok_or(AmlEvalError::SerializationError) + }) + .flatten() + } + pub fn init(rxsdt_physaddrs: impl Iterator) -> Self { let tables = rxsdt_physaddrs .map(|physaddr| { diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 4145a5fe00..8e0d47d7bc 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -358,7 +358,7 @@ impl acpi::Handler for AmlPhysMemHandler { } fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), AmlError> { - log::warn!("TODO: Handler::aquire"); + log::warn!("TODO: Handler::acquire"); Ok(()) } diff --git a/acpid/src/main.rs b/acpid/src/main.rs index aef18c2cb6..65e35513fb 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -10,6 +10,7 @@ use syscall::{EAGAIN, EWOULDBLOCK}; mod acpi; mod aml_physmem; + mod scheme; fn daemon(daemon: redox_daemon::Daemon) -> ! { diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index e744b5b257..13797f2924 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -1,9 +1,14 @@ +use acpi::aml::namespace::AmlName; +use amlserde::aml_serde_name::to_aml_format; +use amlserde::AmlSerdeValue; use core::str; use parking_lot::RwLockReadGuard; use redox_scheme::scheme::SchemeSync; use redox_scheme::{CallerCtx, OpenResult}; +use ron::de::SpannedError; use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; +use std::str::FromStr; use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; use syscall::schemev2::NewFdFlags; @@ -12,7 +17,7 @@ use syscall::error::{Error, Result}; use syscall::error::{EBADF, EBADFD, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR}; use syscall::flag::{MODE_DIR, MODE_FILE}; use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDONLY, O_STAT, O_SYMLINK}; -use syscall::EOPNOTSUPP; +use syscall::{EOPNOTSUPP, EOVERFLOW, EPERM}; use crate::acpi::{AcpiContext, AmlSymbols, SdtSignature}; @@ -25,13 +30,14 @@ pub struct AcpiScheme<'acpi> { struct Handle<'a> { kind: HandleKind<'a>, stat: bool, + allowed_to_eval: bool, } enum HandleKind<'a> { TopLevel, Tables, Table(SdtSignature), Symbols(RwLockReadGuard<'a, AmlSymbols>), - Symbol(String), + Symbol { name: String, description: String }, } impl HandleKind<'_> { @@ -41,7 +47,7 @@ impl HandleKind<'_> { Self::Tables => true, Self::Table(_) => false, Self::Symbols(_) => true, - Self::Symbol(_) => false, + Self::Symbol { .. } => false, } } fn len(&self, acpi_ctx: &AcpiContext) -> Result { @@ -51,7 +57,7 @@ impl HandleKind<'_> { .sdt_from_signature(signature) .ok_or(Error::new(EBADFD))? .length(), - Self::Symbol(description) => description.len(), + Self::Symbol { description, .. } => description.len(), // Directories Self::TopLevel | Self::Symbols(_) | Self::Tables => 0, }) @@ -143,7 +149,7 @@ fn parse_table(table: &[u8]) -> Option { } impl SchemeSync for AcpiScheme<'_> { - fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result { + fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result { let path = path.trim_start_matches('/'); let flag_stat = flags & O_STAT == O_STAT; @@ -179,7 +185,10 @@ impl SchemeSync for AcpiScheme<'_> { ["symbols", symbol] => { if let Some(description) = self.ctx.aml_lookup(symbol) { - HandleKind::Symbol(description) + HandleKind::Symbol { + name: (*symbol).to_owned(), + description, + } } else { return Err(Error::new(ENOENT)); } @@ -194,9 +203,13 @@ impl SchemeSync for AcpiScheme<'_> { return Err(Error::new(ENOTDIR)); } - if flags & O_ACCMODE != O_RDONLY && !flag_stat { + let allowed_to_eval = if flags & O_ACCMODE == O_RDONLY || flag_stat { + false + } else if ctx.uid != 0 { + true + } else { return Err(Error::new(EINVAL)); - } + }; if flags & O_SYMLINK == O_SYMLINK && !flag_stat { return Err(Error::new(EINVAL)); @@ -210,6 +223,7 @@ impl SchemeSync for AcpiScheme<'_> { Handle { stat: flag_stat, kind, + allowed_to_eval, }, ); @@ -259,7 +273,7 @@ impl SchemeSync for AcpiScheme<'_> { .sdt_from_signature(signature) .ok_or(Error::new(EBADFD))? .as_slice(), - HandleKind::Symbol(description) => description.as_bytes(), + HandleKind::Symbol { description, .. } => description.as_bytes(), _ => return Err(Error::new(EINVAL)), }; @@ -358,6 +372,47 @@ impl SchemeSync for AcpiScheme<'_> { ) -> Result { Err(Error::new(EBADF)) } + + fn call(&mut self, id: usize, payload: &mut [u8], _metadata: &[u64]) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + if !handle.allowed_to_eval { + return Err(Error::new(EPERM)); + } + + let Ok(args): Result, SpannedError> = ron::de::from_bytes(payload) + else { + return Err(Error::new(EINVAL)); + }; + + let HandleKind::Symbol { name, .. } = &handle.kind else { + return Err(Error::new(EBADF)); + }; + + let Ok(aml_name) = AmlName::from_str(&to_aml_format(name)) else { + log::error!("Failed to convert symbol name: \"{name}\" to aml name!"); + return Err(Error::new(EBADF)); + }; + + let Ok(result) = self.ctx.aml_eval(aml_name, args) else { + return Err(Error::new(EINVAL)); + }; + + let Ok(serialized_result) = ron::ser::to_string(&result) else { + log::error!("Failed to serialize aml result!"); + return Err(Error::new(EINVAL)); + }; + + let byte_result = serialized_result.as_bytes(); + let result_len = byte_result.len(); + + if result_len > payload.len() { + return Err(Error::new(EOVERFLOW)); + } + + payload[..result_len].copy_from_slice(byte_result); + + Ok(result_len) + } } impl AcpiScheme<'_> { diff --git a/amlserde/src/lib.rs b/amlserde/src/lib.rs index 7fa2f7c50e..1cf8e3f2c6 100644 --- a/amlserde/src/lib.rs +++ b/amlserde/src/lib.rs @@ -1,14 +1,24 @@ use acpi::{ aml::{ namespace::AmlName, - object::{FieldAccessType, FieldUnitKind, FieldUpdateRule, Object, ReferenceKind}, - op_region::RegionSpace, + object::{ + FieldAccessType, FieldFlags, FieldUnit, FieldUnitKind, FieldUpdateRule, MethodFlags, + Object, ReferenceKind, WrappedObject, + }, + op_region::{OpRegion, RegionSpace}, Interpreter, }, - Handler, + Handle, Handler, }; use serde::{Deserialize, Serialize}; -use std::{ops::Deref, sync::atomic::Ordering}; +use std::{ + ops::{Deref, Shl}, + str::FromStr, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, +}; #[derive(Debug, Serialize, Deserialize)] pub struct AmlSerde { @@ -25,7 +35,7 @@ pub enum AmlSerdeValue { region: AmlSerdeRegionSpace, offset: u64, length: u64, - parent_device: Option, + parent_device: String, }, Field { kind: AmlSerdeFieldKind, @@ -44,7 +54,7 @@ pub enum AmlSerdeValue { BufferField { offset: u64, length: u64, - data: Option>, + data: Box, }, Processor { id: u8, @@ -57,7 +67,7 @@ pub enum AmlSerdeValue { }, Reference { kind: AmlSerdeReferenceKind, - inner: Option>, + inner: Box, }, Package { contents: Vec, @@ -90,41 +100,53 @@ pub enum AmlSerdeRegionSpace { #[derive(Debug, Serialize, Deserialize)] pub enum AmlSerdeFieldKind { Normal { - region: Option>, + region: Box, }, Bank { - region: Option>, - bank: Option>, + region: Box, + bank: Box, bank_value: u64, }, Index { - index: Option>, - data: Option>, + index: Box, + data: Box, }, } #[derive(Debug, Serialize, Deserialize)] pub struct AmlSerdeFieldFlags { pub access_type: AmlSerdeFieldAccessType, - pub lock_rule: bool, + pub lock_rule: bool, // bit 4 pub update_rule: AmlSerdeFieldUpdateRule, } - -#[derive(Debug, Serialize, Deserialize)] -pub enum AmlSerdeFieldAccessType { - Any, - Byte, - Word, - DWord, - QWord, - Buffer, +impl Into for AmlSerdeFieldFlags { + fn into(self) -> u8 { + // bits 0..4 + (self.access_type as u8) + + // bit 4 + (self.lock_rule as u8).shl(4) + + // bits 5..7 + (self.update_rule as u8).shl(5) + } } #[derive(Debug, Serialize, Deserialize)] +#[repr(u8)] +pub enum AmlSerdeFieldAccessType { + Any = 0, + Byte = 1, + Word = 2, + DWord = 3, + QWord = 4, + Buffer = 5, +} + +#[derive(Debug, Serialize, Deserialize)] +#[repr(u8)] pub enum AmlSerdeFieldUpdateRule { - Preserve, - WriteAsOnes, - WriteAsZeros, + Preserve = 0, + WriteAsOnes = 1, + WriteAsZeros = 2, } #[derive(Debug, Serialize, Deserialize)] @@ -168,7 +190,7 @@ impl AmlSerdeValue { AmlSerdeValue::String("".to_owned()) } - fn from_aml_value(aml_value: &Object) -> Option { + pub fn from_aml_value(aml_value: &Object) -> Option { Some(match aml_value { Object::Uninitialized => AmlSerdeValue::Uninitialized, Object::Integer(n) => AmlSerdeValue::Integer(n.to_owned()), @@ -190,25 +212,25 @@ impl AmlSerdeValue { }, offset: region.base, length: region.length, - parent_device: Some(region.parent_device_path.to_string()), + parent_device: region.parent_device_path.to_string(), }, Object::FieldUnit(field) => AmlSerdeValue::Field { kind: match &field.kind { FieldUnitKind::Normal { region } => AmlSerdeFieldKind::Normal { - region: AmlSerdeValue::from_aml_value(region.deref()).map(Box::new), + region: AmlSerdeValue::from_aml_value(region.deref()).map(Box::new)?, }, FieldUnitKind::Bank { region, bank, bank_value, } => AmlSerdeFieldKind::Bank { - region: AmlSerdeValue::from_aml_value(region.deref()).map(Box::new), - bank: AmlSerdeValue::from_aml_value(bank.deref()).map(Box::new), + region: AmlSerdeValue::from_aml_value(region.deref()).map(Box::new)?, + bank: AmlSerdeValue::from_aml_value(bank.deref()).map(Box::new)?, bank_value: bank_value.to_owned(), }, FieldUnitKind::Index { index, data } => AmlSerdeFieldKind::Index { - index: AmlSerdeValue::from_aml_value(index.deref()).map(Box::new), - data: AmlSerdeValue::from_aml_value(data.deref()).map(Box::new), + index: AmlSerdeValue::from_aml_value(index.deref()).map(Box::new)?, + data: AmlSerdeValue::from_aml_value(data.deref()).map(Box::new)?, }, }, flags: AmlSerdeFieldFlags { @@ -252,7 +274,7 @@ impl AmlSerdeValue { } => AmlSerdeValue::BufferField { offset: offset.to_owned() as u64, length: length.to_owned() as u64, - data: AmlSerdeValue::from_aml_value(buffer.deref()).map(Box::new), + data: AmlSerdeValue::from_aml_value(buffer.deref()).map(Box::new)?, }, Object::Processor { proc_id, @@ -273,7 +295,7 @@ impl AmlSerdeValue { ReferenceKind::LocalOrArg => AmlSerdeReferenceKind::LocalOrArg, ReferenceKind::Unresolved => AmlSerdeReferenceKind::Unresolved, }, - inner: AmlSerdeValue::from_aml_value(inner.deref()).map(Box::new), + inner: AmlSerdeValue::from_aml_value(inner.deref()).map(Box::new)?, }, Object::Package(aml_contents) => AmlSerdeValue::Package { contents: aml_contents @@ -293,6 +315,129 @@ impl AmlSerdeValue { Object::Debug => AmlSerdeValue::Debug, }) } + pub fn to_aml_object(self) -> Option { + Some(match self { + AmlSerdeValue::Uninitialized => Object::Uninitialized, + AmlSerdeValue::Integer(n) => Object::Integer(n), + AmlSerdeValue::String(s) => Object::String(s), + AmlSerdeValue::OpRegion { + region, + offset, + length, + parent_device, + } => Object::OpRegion(OpRegion { + space: match region { + AmlSerdeRegionSpace::PciConfig => RegionSpace::PciConfig, + AmlSerdeRegionSpace::EmbeddedControl => RegionSpace::EmbeddedControl, + AmlSerdeRegionSpace::SMBus => RegionSpace::SmBus, + AmlSerdeRegionSpace::SystemCmos => RegionSpace::SystemCmos, + AmlSerdeRegionSpace::PciBarTarget => RegionSpace::PciBarTarget, + AmlSerdeRegionSpace::IPMI => RegionSpace::Ipmi, + AmlSerdeRegionSpace::GeneralPurposeIo => RegionSpace::GeneralPurposeIo, + AmlSerdeRegionSpace::GenericSerialBus => RegionSpace::GenericSerialBus, + AmlSerdeRegionSpace::SystemMemory => RegionSpace::SystemMemory, + AmlSerdeRegionSpace::SystemIo => RegionSpace::SystemIO, + AmlSerdeRegionSpace::Pcc => RegionSpace::Pcc, + AmlSerdeRegionSpace::OemDefined(n) => RegionSpace::Oem(n), + }, + base: offset, + length, + // + parent_device_path: AmlName::from_str(&parent_device).ok()?, // TODO: Error value hidden + }), + AmlSerdeValue::Field { + kind, + flags, + offset, + length, + } => Object::FieldUnit(FieldUnit { + kind: match kind { + AmlSerdeFieldKind::Normal { region } => FieldUnitKind::Normal { + region: region.to_aml_object()?.wrap(), + }, + AmlSerdeFieldKind::Bank { + region, + bank, + bank_value, + } => FieldUnitKind::Bank { + region: region.to_aml_object()?.wrap(), + bank: bank.to_aml_object()?.wrap(), + bank_value: bank_value.to_owned(), + }, + AmlSerdeFieldKind::Index { index, data } => FieldUnitKind::Index { + index: index.to_aml_object()?.wrap(), + data: data.to_aml_object()?.wrap(), + }, + }, + flags: FieldFlags(flags.into()), + bit_index: offset as usize, + bit_length: length as usize, + }), + AmlSerdeValue::Device => Object::Device, + AmlSerdeValue::Event(event) => Object::Event(Arc::new(AtomicU64::new(event))), + AmlSerdeValue::Method { + arg_count, + serialize, + sync_level, + } => Object::Method { + code: (return None), //TODO figure out what to do here + //TODO check specs to see if all bit patterns are allowed + flags: MethodFlags( + (arg_count as u8).clamp(0, 7) + + (serialize as u8).shl(3) + + sync_level.clamp(0, 15).shl(4), + ), + }, + //TODO: handle native method? + AmlSerdeValue::Buffer(buffer_data) => Object::Buffer(buffer_data), + AmlSerdeValue::BufferField { + data, + offset, + length, + } => Object::BufferField { + offset: offset as usize, + length: length as usize, + buffer: data.to_aml_object()?.wrap(), + }, + AmlSerdeValue::Processor { + id, + pblk_address, + pblk_len, + } => Object::Processor { + proc_id: id, + pblk_address, + pblk_length: pblk_len, + }, + AmlSerdeValue::Mutex { mutex, sync_level } => Object::Mutex { + mutex: Handle(mutex), + sync_level: sync_level, + }, + AmlSerdeValue::Reference { kind, inner } => Object::Reference { + kind: match kind { + AmlSerdeReferenceKind::RefOf => ReferenceKind::RefOf, + AmlSerdeReferenceKind::LocalOrArg => ReferenceKind::LocalOrArg, + AmlSerdeReferenceKind::Unresolved => ReferenceKind::Unresolved, + }, + inner: inner.to_aml_object()?.wrap(), + }, + AmlSerdeValue::Package { contents } => Object::Package( + contents + .into_iter() + .map(|item| item.to_aml_object().map(Object::wrap)) // TODO: see if errors should be ignored here + .collect::>>()?, + ), + AmlSerdeValue::PowerResource { + system_level, + resource_order, + } => Object::PowerResource { + system_level: system_level.to_owned(), + resource_order: resource_order.to_owned(), + }, + AmlSerdeValue::RawDataBuffer => Object::RawDataBuffer, + AmlSerdeValue::ThermalZone => Object::ThermalZone, + AmlSerdeValue::Debug => Object::Debug, + }) + } } pub mod aml_serde_name { From 22ab2fe17d0aa3eeb3f4dbe5848889c6c19a857b Mon Sep 17 00:00:00 2001 From: aarch <60485626+aarch64angel@users.noreply.github.com> Date: Sat, 25 Oct 2025 15:42:45 +0200 Subject: [PATCH 1268/1301] Fix inverted root check --- acpid/src/scheme.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acpid/src/scheme.rs b/acpid/src/scheme.rs index 13797f2924..fd506f5a4c 100644 --- a/acpid/src/scheme.rs +++ b/acpid/src/scheme.rs @@ -205,7 +205,7 @@ impl SchemeSync for AcpiScheme<'_> { let allowed_to_eval = if flags & O_ACCMODE == O_RDONLY || flag_stat { false - } else if ctx.uid != 0 { + } else if ctx.uid == 0 { true } else { return Err(Error::new(EINVAL)); From 6d5523de2ad092a8b3a66e9fe57c366b6a9919ff Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 1 Nov 2025 19:36:38 -0600 Subject: [PATCH 1269/1301] Set all log levels, reduce unnecessary logs --- acpid/src/aml_physmem.rs | 6 +-- acpid/src/main.rs | 2 +- audio/ac97d/src/main.rs | 2 +- audio/ihdad/src/main.rs | 2 +- audio/sb16d/src/main.rs | 2 +- graphics/virtio-gpud/src/main.rs | 4 +- hwd/src/backend/acpi.rs | 2 +- hwd/src/backend/devicetree.rs | 2 +- hwd/src/main.rs | 4 +- input/ps2d/src/main.rs | 2 +- input/usbhidd/src/main.rs | 2 +- inputd/src/main.rs | 2 +- net/rtl8139d/src/main.rs | 2 +- net/rtl8168d/src/main.rs | 2 +- net/virtio-netd/src/main.rs | 4 +- pcid-spawner/src/main.rs | 2 +- pcid/src/main.rs | 7 +-- storage/ahcid/src/main.rs | 2 +- storage/ided/src/main.rs | 2 +- storage/lived/src/main.rs | 59 ++++++++++++------------- storage/nvmed/src/main.rs | 2 +- storage/virtio-blkd/src/main.rs | 4 +- usb/usbhubd/src/main.rs | 2 +- usb/xhcid/src/main.rs | 2 +- usb/xhcid/src/xhci/device_enumerator.rs | 8 ++-- usb/xhcid/src/xhci/mod.rs | 16 +++---- 26 files changed, 72 insertions(+), 74 deletions(-) diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 8e0d47d7bc..eb5dcfb24c 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -353,16 +353,16 @@ impl acpi::Handler for AmlPhysMemHandler { } fn create_mutex(&self) -> Handle { - log::warn!("TODO: Handler::create_mutex"); + log::info!("TODO: Handler::create_mutex"); Handle(0) } fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), AmlError> { - log::warn!("TODO: Handler::acquire"); + log::info!("TODO: Handler::acquire"); Ok(()) } fn release(&self, mutex: Handle) { - log::warn!("TODO: Handler::release"); + log::info!("TODO: Handler::release"); } } diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 65e35513fb..215ccb43fd 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -18,8 +18,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "misc", "acpi", "acpid", - log::LevelFilter::Info, log::LevelFilter::Warn, + log::LevelFilter::Info, ); let rxsdt_raw_data: Arc<[u8]> = std::fs::read("/scheme/kernel.acpi/rxsdt") diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index 3249fb2e1e..bbd5d954e3 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -40,7 +40,7 @@ fn main() { "audio", "pci", &name, - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index fefaf2f0ad..31aee8a65d 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -70,7 +70,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "audio", "pci", &name, - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index 352313dbda..cfe25f77e7 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -23,7 +23,7 @@ fn main() { "audio", "pci", "sb16", - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 0c000f53ae..780148f2b6 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -553,8 +553,8 @@ pub fn main() { "misc", "pci", "virtio-gpud", - log::LevelFilter::Trace, - log::LevelFilter::Trace, + log::LevelFilter::Warn, + log::LevelFilter::Info, ); redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } diff --git a/hwd/src/backend/acpi.rs b/hwd/src/backend/acpi.rs index 42170b2221..53b96a9d33 100644 --- a/hwd/src/backend/acpi.rs +++ b/hwd/src/backend/acpi.rs @@ -89,7 +89,7 @@ impl Backend for AcpiBackend { "PNP0F13" => "PS/2 port for PS/2-style mouse", _ => "?", }; - log::debug!("{}: {} ({})", name, id, what); + log::info!("{}: {} ({})", name, id, what); } } } diff --git a/hwd/src/backend/devicetree.rs b/hwd/src/backend/devicetree.rs index 8a91d04e42..a2dc7706dc 100644 --- a/hwd/src/backend/devicetree.rs +++ b/hwd/src/backend/devicetree.rs @@ -20,7 +20,7 @@ impl DeviceTreeBackend { line.push_str(id); } } - log::debug!("{}", line); + log::info!("{}", line); for child in node.children() { Self::dump(&child, level + 1); } diff --git a/hwd/src/main.rs b/hwd/src/main.rs index e71cbbf198..5b772af0a8 100644 --- a/hwd/src/main.rs +++ b/hwd/src/main.rs @@ -6,8 +6,8 @@ fn main() { "misc", "hwd", "hwd", - log::LevelFilter::Debug, - log::LevelFilter::Debug, + log::LevelFilter::Warn, + log::LevelFilter::Info, ); // Prefer DTB if available (matches kernel preference) diff --git a/input/ps2d/src/main.rs b/input/ps2d/src/main.rs index 3a8922bbe4..9aad438168 100644 --- a/input/ps2d/src/main.rs +++ b/input/ps2d/src/main.rs @@ -30,7 +30,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "misc", "ps2", "ps2", - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/input/usbhidd/src/main.rs b/input/usbhidd/src/main.rs index 4cef9c7c6e..9da7803011 100644 --- a/input/usbhidd/src/main.rs +++ b/input/usbhidd/src/main.rs @@ -188,7 +188,7 @@ fn main() { "usb", "device", &name, - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 6853a5769a..863c2a226a 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -576,8 +576,8 @@ fn main() { "misc", "inputd", "inputd", + log::LevelFilter::Warn, log::LevelFilter::Info, - log::LevelFilter::Debug, ); let mut args = std::env::args().skip(1); diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 03fd17dd52..5be7ba6452 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -113,7 +113,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "net", "pci", &name, - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 59c25ba985..243cb43b2a 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -113,7 +113,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "net", "pci", &name, - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index c0231618f7..d9d9e3d602 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -124,8 +124,8 @@ pub fn main() { "net", "pci", "virtio-netd", - log::LevelFilter::Trace, - log::LevelFilter::Trace, + log::LevelFilter::Warn, + log::LevelFilter::Info, ); redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } diff --git a/pcid-spawner/src/main.rs b/pcid-spawner/src/main.rs index e99ce2e320..ecdcda1d6d 100644 --- a/pcid-spawner/src/main.rs +++ b/pcid-spawner/src/main.rs @@ -16,8 +16,8 @@ fn main() -> Result<()> { "bus", "pci", "pci-spawner.log", + log::LevelFilter::Warn, log::LevelFilter::Info, - log::LevelFilter::Trace, ); let config_data = if fs::metadata(&config_path)?.is_file() { diff --git a/pcid/src/main.rs b/pcid/src/main.rs index c06e583c63..3102cdbbbb 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -191,12 +191,13 @@ fn main() { let mut args = pico_args::Arguments::from_env(); let verbosity = (0..).find(|_| !args.contains("-v")).unwrap_or(0); let log_level = match verbosity { - 0 => log::LevelFilter::Info, - 1 => log::LevelFilter::Debug, + 0 => log::LevelFilter::Warn, + 1 => log::LevelFilter::Info, + 2 => log::LevelFilter::Debug, _ => log::LevelFilter::Trace, }; - common::setup_logging("bus", "pci", "pcid", log_level, log::LevelFilter::Trace); + common::setup_logging("bus", "pci", "pcid", log_level, log::LevelFilter::Info); redox_daemon::Daemon::new(move |daemon| main_inner(daemon)).unwrap(); } diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index 3df8947f73..dd8a06319c 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -33,7 +33,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "disk", "pci", &name, - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 45592aedf6..0bab7a4ed8 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -33,7 +33,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "disk", "pci", &name, - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index eadc62965e..eadc3a5c89 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -24,36 +24,7 @@ struct LiveDisk { } impl LiveDisk { - fn new() -> anyhow::Result { - let mut phys = 0; - let mut size = 0; - - // TODO: handle error - for line in std::fs::read_to_string("/scheme/sys/env") - .context("failed to read env")? - .lines() - { - let mut parts = line.splitn(2, '='); - let name = parts.next().unwrap_or(""); - let value = parts.next().unwrap_or(""); - - if name == "DISK_LIVE_ADDR" { - phys = usize::from_str_radix(value, 16).unwrap_or(0); - } - - if name == "DISK_LIVE_SIZE" { - size = usize::from_str_radix(value, 16).unwrap_or(0); - } - } - - if phys == 0 || size == 0 { - bail!( - "either livedisk phys ({}) or size ({}) was zero", - phys, - size - ); - } - + fn new(phys: usize, size: usize) -> anyhow::Result { let start = phys.div_floor(PAGE_SIZE) * PAGE_SIZE; let end = phys .checked_add(size) @@ -133,6 +104,32 @@ impl Disk for LiveDisk { } fn main() -> anyhow::Result<()> { + let mut phys = 0; + let mut size = 0; + + // TODO: handle error + for line in std::fs::read_to_string("/scheme/sys/env") + .context("failed to read env")? + .lines() + { + let mut parts = line.splitn(2, '='); + let name = parts.next().unwrap_or(""); + let value = parts.next().unwrap_or(""); + + if name == "DISK_LIVE_ADDR" { + phys = usize::from_str_radix(value, 16).unwrap_or(0); + } + + if name == "DISK_LIVE_SIZE" { + size = usize::from_str_radix(value, 16).unwrap_or(0); + } + } + + if phys == 0 || size == 0 { + // No live disk data, no need to say anything or exit with error + std::process::exit(0); + } + redox_daemon::Daemon::new(move |daemon| { let event_queue = event::EventQueue::new().unwrap(); @@ -147,7 +144,7 @@ fn main() -> anyhow::Result<()> { "disk.live".to_owned(), BTreeMap::from([( 0, - LiveDisk::new().unwrap_or_else(|err| { + LiveDisk::new(phys, size).unwrap_or_else(|err| { eprintln!("failed to initialize livedisk scheme: {}", err); std::process::exit(1) }), diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index ca0802c406..7a3a44b616 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -156,7 +156,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "disk", "pci", &scheme_name, - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index b27343dce9..609d42002a 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -35,8 +35,8 @@ pub fn main() -> anyhow::Result<()> { "disk", "pci", "virtio-blkd", - log::LevelFilter::Trace, - log::LevelFilter::Trace, + log::LevelFilter::Warn, + log::LevelFilter::Info, ); redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } diff --git a/usb/usbhubd/src/main.rs b/usb/usbhubd/src/main.rs index 408b776a74..fa3c2ee784 100644 --- a/usb/usbhubd/src/main.rs +++ b/usb/usbhubd/src/main.rs @@ -35,7 +35,7 @@ fn main() { "usb", "device", &name, - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/usb/xhcid/src/main.rs b/usb/xhcid/src/main.rs index d85df737d9..b7d3e4d15d 100644 --- a/usb/xhcid/src/main.rs +++ b/usb/xhcid/src/main.rs @@ -134,7 +134,7 @@ fn daemon_with_context_size( "usb", "host", &name, - log::LevelFilter::Info, + log::LevelFilter::Warn, log::LevelFilter::Info, ); diff --git a/usb/xhcid/src/xhci/device_enumerator.rs b/usb/xhcid/src/xhci/device_enumerator.rs index a48900c226..547ba11905 100644 --- a/usb/xhcid/src/xhci/device_enumerator.rs +++ b/usb/xhcid/src/xhci/device_enumerator.rs @@ -35,7 +35,7 @@ impl DeviceEnumerator { let port_id = request.port_id; let port_array_index = port_id.root_hub_port_index(); - info!("Device Enumerator request for port {}", port_id); + debug!("Device Enumerator request for port {}", port_id); let (len, flags) = { let ports = self.hci.ports.lock().unwrap(); @@ -54,7 +54,7 @@ impl DeviceEnumerator { }; if flags.contains(PortFlags::CCS) { - info!( + debug!( "Received Device Connect Port Status Change Event with port flags {:?}", flags ); @@ -114,14 +114,14 @@ impl DeviceEnumerator { } Err(err) => { if err.errno == EAGAIN { - info!("Received a device connect notification for an already connected device. Ignoring...") + debug!("Received a device connect notification for an already connected device. Ignoring...") } else { warn!("processing of device attach request failed! Error: {}", err); } } } } else { - info!( + debug!( "Device Enumerator received Detach request on port {} which is in state {}", port_id, self.hci.get_pls(port_id) diff --git a/usb/xhcid/src/xhci/mod.rs b/usb/xhcid/src/xhci/mod.rs index aea7439397..14203a70f5 100644 --- a/usb/xhcid/src/xhci/mod.rs +++ b/usb/xhcid/src/xhci/mod.rs @@ -765,7 +765,7 @@ impl Xhci { pub async fn attach_device(&self, port_id: PortId) -> syscall::Result<()> { if self.port_states.contains_key(&port_id) { - println!("Already contains port {}", port_id); + debug!("Already contains port {}", port_id); return Err(syscall::Error::new(EAGAIN)); } @@ -798,7 +798,7 @@ impl Xhci { } }; - info!("Enabled port {}, which the xHC mapped to {}", port_id, slot); + debug!("Enabled port {}, which the xHC mapped to {}", port_id, slot); //TODO: get correct speed for child devices let protocol_speed = self @@ -895,7 +895,7 @@ impl Xhci { match child.try_wait() { Ok(status_opt) => match status_opt { Some(status) => { - info!( + debug!( "driver process {} for port {} exited with status {}", child.id(), port_id, @@ -904,7 +904,7 @@ impl Xhci { } None => { //TODO: kill harder - info!( + warn!( "driver process {} for port {} still running", child.id(), port_id @@ -912,7 +912,7 @@ impl Xhci { } }, Err(err) => { - info!( + warn!( "failed to wait for the driver process {} for port {}: {}", child.id(), port_id, @@ -934,16 +934,16 @@ impl Xhci { } if let Some(state) = self.port_states.remove(&port_id) { - info!("disabling port slot {} for port {}", state.slot, port_id); + debug!("disabling port slot {} for port {}", state.slot, port_id); let result = self.disable_port_slot(state.slot).await; - info!( + debug!( "disabled port slot {} for port {} with result: {:?}", state.slot, port_id, result ); result } else { - warn!( + debug!( "Attempted to detach from port {}, which wasn't previously attached.", port_id ); From c4d28fff233e76667a48454e3880078dc84c5f74 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 1 Nov 2025 19:55:35 -0600 Subject: [PATCH 1270/1301] xhcid: adjust another log message --- usb/xhcid/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usb/xhcid/src/main.rs b/usb/xhcid/src/main.rs index b7d3e4d15d..6e57345f28 100644 --- a/usb/xhcid/src/main.rs +++ b/usb/xhcid/src/main.rs @@ -145,7 +145,7 @@ fn daemon_with_context_size( let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle); //TODO: Fix interrupts. - println!(" + XHCI {}", pci_config.func.display()); + log::info!(" + XHCI {}", pci_config.func.display()); let scheme_name = format!("usb.{}", name); let socket = Socket::create(scheme_name.clone()).expect("xhcid: failed to create usb scheme"); From ec49a9664042abb660d2c4f2ca0b6fae2bed7d94 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 1 Nov 2025 20:44:26 -0600 Subject: [PATCH 1271/1301] More logging improvements --- Cargo.lock | 2 ++ graphics/bgad/Cargo.toml | 1 + graphics/bgad/src/main.rs | 12 ++++++++++-- graphics/virtio-gpud/src/main.rs | 2 +- input/ps2d/src/main.rs | 2 +- inputd/src/main.rs | 2 +- net/e1000d/Cargo.toml | 1 + net/e1000d/src/device.rs | 17 +++++++---------- net/e1000d/src/main.rs | 10 +++++++++- 9 files changed, 33 insertions(+), 16 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f385b7175..f24e915aa8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -179,6 +179,7 @@ dependencies = [ "common", "inputd", "libredox", + "log", "orbclient", "pcid", "redox-daemon", @@ -408,6 +409,7 @@ dependencies = [ "common", "driver-network", "libredox", + "log", "pcid", "redox-daemon", "redox_event", diff --git a/graphics/bgad/Cargo.toml b/graphics/bgad/Cargo.toml index eb62538387..fa63aa2069 100644 --- a/graphics/bgad/Cargo.toml +++ b/graphics/bgad/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [dependencies] orbclient = "0.3.47" +log = "0.4" redox-daemon = "0.1" redox-scheme = "0.6.2" redox_syscall = "0.5" diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index 2d30ac4e1b..a803cdf196 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -16,7 +16,15 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_bga"); - println!(" + BGA {}", pci_config.func.display()); + common::setup_logging( + "graphics", + "pci", + &name, + log::LevelFilter::Warn, + log::LevelFilter::Info, + ); + + log::info!(" + BGA {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { acquire_port_io_rights().expect("bgad: failed to get port IO permission"); @@ -24,7 +32,7 @@ fn main() { let socket = Socket::create("bga").expect("bgad: failed to create bga scheme"); let mut bga = Bga::new(); - println!(" - BGA {}x{}", bga.width(), bga.height()); + log::info!(" - BGA {}x{}", bga.width(), bga.height()); let mut scheme = BgaScheme { bga, diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index 780148f2b6..f2a2d354ca 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -550,7 +550,7 @@ fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { pub fn main() { common::setup_logging( - "misc", + "graphics", "pci", "virtio-gpud", log::LevelFilter::Warn, diff --git a/input/ps2d/src/main.rs b/input/ps2d/src/main.rs index 9aad438168..d775089ead 100644 --- a/input/ps2d/src/main.rs +++ b/input/ps2d/src/main.rs @@ -27,7 +27,7 @@ mod vm; fn daemon(daemon: redox_daemon::Daemon) -> ! { common::setup_logging( - "misc", + "input", "ps2", "ps2", log::LevelFilter::Warn, diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 863c2a226a..6fbdf4cd9e 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -573,7 +573,7 @@ fn daemon_runner(redox_daemon: redox_daemon::Daemon) -> ! { fn main() { common::setup_logging( - "misc", + "input", "inputd", "inputd", log::LevelFilter::Warn, diff --git a/net/e1000d/Cargo.toml b/net/e1000d/Cargo.toml index 3066ac6c16..62653d7b36 100644 --- a/net/e1000d/Cargo.toml +++ b/net/e1000d/Cargo.toml @@ -5,6 +5,7 @@ edition = "2018" [dependencies] bitflags = "2" +log = "0.4" redox-daemon = "0.1.2" libredox = "0.1.3" redox_event = "0.4.1" diff --git a/net/e1000d/src/device.rs b/net/e1000d/src/device.rs index 3bec4122b9..7d231e99a3 100644 --- a/net/e1000d/src/device.rs +++ b/net/e1000d/src/device.rs @@ -259,7 +259,7 @@ impl Intel8254x { pub unsafe fn init(&mut self) { self.flag(CTRL, CTRL_RST, true); while self.read_reg(CTRL) & CTRL_RST == CTRL_RST { - print!(" - Waiting for reset: {:X}\n", self.read_reg(CTRL)); + log::trace!("Waiting for reset: {:X}", self.read_reg(CTRL)); } // Enable auto negotiate, link, clear reset, do not Invert Loss-Of Signal @@ -287,12 +287,9 @@ impl Intel8254x { mac_high as u8, (mac_high >> 8) as u8, ]; - print!( - "{}", - format!( - " - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] - ) + log::info!( + "MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); self.mac_address = mac; @@ -350,12 +347,12 @@ impl Intel8254x { // TIPG Packet Gap // TODO ... - print!(" - Waiting for link up: {:X}\n", self.read_reg(STATUS)); + log::debug!("Waiting for link up: {:X}", self.read_reg(STATUS)); while self.read_reg(STATUS) & 2 != 2 { thread::sleep(time::Duration::from_millis(100)); } - print!( - " - Link is up with speed {}\n", + log::info!( + "Link is up with speed {}", match (self.read_reg(STATUS) >> 6) & 0b11 { 0b00 => "10 Mb/s", 0b01 => "100 Mb/s", diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index 412986739a..f508616676 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -14,12 +14,20 @@ fn main() { let mut name = pci_config.func.name(); name.push_str("_e1000"); + common::setup_logging( + "net", + "pci", + &name, + log::LevelFilter::Warn, + log::LevelFilter::Info, + ); + let irq = pci_config .func .legacy_interrupt_line .expect("e1000d: no legacy interrupts supported"); - eprintln!(" + E1000 {}", pci_config.func.display()); + log::info!(" + E1000 {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { let mut irq_file = irq.irq_handle("e1000d"); From 9ee833d5f2b4a26083fbc0df74f41aedc8e058fa Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 1 Nov 2025 20:59:39 -0600 Subject: [PATCH 1272/1301] ps2d: do not block on device init --- input/ps2d/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/input/ps2d/src/main.rs b/input/ps2d/src/main.rs index d775089ead..1d55190b63 100644 --- a/input/ps2d/src/main.rs +++ b/input/ps2d/src/main.rs @@ -87,8 +87,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { ) .unwrap(); - let mut ps2d = Ps2d::new(input, keymap); - let scheme_file = Socket::nonblock("ps2").expect("ps2d: failed to create ps2 scheme"); let mut scheme_handle = Ps2Scheme::new( @@ -110,6 +108,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .ready() .expect("ps2d: failed to mark daemon as ready"); + let mut ps2d = Ps2d::new(input, keymap); + let mut data = [0; 256]; for event in event_queue.map(|e| e.expect("ps2d: failed to get next event").user_data) { // There are some gotchas with ps/2 controllers that require this weird From 6dc44087bfe896d866b2a4cf3a10bfb15711a7ab Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 1 Nov 2025 21:02:42 -0600 Subject: [PATCH 1273/1301] Reduce logging in rtl ethernet drivers --- net/rtl8139d/src/device.rs | 18 +++++++++--------- net/rtl8168d/src/device.rs | 16 ++++++++-------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/net/rtl8139d/src/device.rs b/net/rtl8139d/src/device.rs index cf98266feb..cfab18833f 100644 --- a/net/rtl8139d/src/device.rs +++ b/net/rtl8139d/src/device.rs @@ -150,7 +150,7 @@ impl NetworkAdapter for Rtl8139 { Ok(Some(i)) } else { //TODO: better error types - eprintln!("rtl8139d: invalid receive status 0x{:X}", rxsts); + log::error!("invalid receive status 0x{:X}", rxsts); Err(Error::new(EIO)) }; @@ -264,36 +264,36 @@ impl Rtl8139 { mac_high as u8, (mac_high >> 8) as u8, ]; - println!( - " - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + log::debug!( + "MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value - println!(" - Reset"); + log::debug!("Reset"); self.regs.cr.writef(CR_RST, true); while self.regs.cr.readf(CR_RST) { core::hint::spin_loop(); } // Set up rx buffer - println!(" - Receive buffer"); + log::debug!("Receive buffer"); self.regs .rbstart .write(self.receive_buffer.physical() as u32); - println!(" - Interrupt mask"); + log::debug!("Interrupt mask"); self.regs.imr.write(IMR_TOK | IMR_ROK); - println!(" - Receive configuration"); + log::debug!("Receive configuration"); self.regs .rcr .write(RCR_RBLEN_64K | RCR_AB | RCR_AM | RCR_APM | RCR_AAP); - println!(" - Enable RX and TX"); + log::debug!("Enable RX and TX"); self.regs.cr.writef(CR_RE | CR_TE, true); - println!(" - Complete!"); + log::debug!("Complete!"); } } diff --git a/net/rtl8168d/src/device.rs b/net/rtl8168d/src/device.rs index 32288cf8d1..c6cf616607 100644 --- a/net/rtl8168d/src/device.rs +++ b/net/rtl8168d/src/device.rs @@ -231,21 +231,21 @@ impl Rtl8168 { mac_high as u8, (mac_high >> 8) as u8, ]; - println!( - " - MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", + log::debug!( + "MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value - println!(" - Reset"); + log::debug!("Reset"); self.regs.cmd.writef(1 << 4, true); while self.regs.cmd.readf(1 << 4) { core::hint::spin_loop(); } // Set up rx buffers - println!(" - Receive buffers"); + log::debug!("Receive buffers"); for i in 0..self.receive_ring.len() { let rd = &mut self.receive_ring[i]; let data = &mut self.receive_buffer[i]; @@ -258,7 +258,7 @@ impl Rtl8168 { } // Set up normal priority tx buffers - println!(" - Transmit buffers (normal priority)"); + log::debug!("Transmit buffers (normal priority)"); for i in 0..self.transmit_ring.len() { self.transmit_ring[i] .buffer_low @@ -272,7 +272,7 @@ impl Rtl8168 { } // Set up high priority tx buffers - println!(" - Transmit buffers (high priority)"); + log::debug!("Transmit buffers (high priority)"); for i in 0..self.transmit_ring_h.len() { self.transmit_ring_h[i] .buffer_low @@ -285,7 +285,7 @@ impl Rtl8168 { td.ctrl.writef(EOR, true); } - println!(" - Set config"); + log::debug!("Set config"); // Unlock config self.regs.cmd_9346.write(1 << 7 | 1 << 6); @@ -331,6 +331,6 @@ impl Rtl8168 { // Lock config self.regs.cmd_9346.write(0); - println!(" - Complete!"); + log::debug!("Complete!"); } } From 28dd3596f314c7f1988038c1e3e0fb34e6937679 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 2 Nov 2025 07:55:32 -0700 Subject: [PATCH 1274/1301] More logging adjustments and set default level to info --- Cargo.lock | 2 ++ acpid/src/aml_physmem.rs | 6 ++--- acpid/src/main.rs | 4 ++-- audio/ac97d/src/main.rs | 4 ++-- audio/ihdad/src/hda/device.rs | 8 +++---- audio/ihdad/src/main.rs | 6 ++--- audio/sb16d/src/main.rs | 4 ++-- common/src/lib.rs | 2 +- common/src/logger.rs | 9 ++++++++ graphics/bgad/src/main.rs | 8 +++---- graphics/fbcond/Cargo.toml | 2 ++ graphics/fbcond/src/display.rs | 14 ++++++------ graphics/fbcond/src/main.rs | 8 +++++++ graphics/fbcond/src/text.rs | 2 +- graphics/virtio-gpud/src/main.rs | 4 ++-- hwd/src/backend/acpi.rs | 2 +- hwd/src/backend/devicetree.rs | 2 +- hwd/src/main.rs | 4 ++-- input/ps2d/src/controller.rs | 2 +- input/ps2d/src/main.rs | 4 ++-- input/usbhidd/src/main.rs | 4 ++-- inputd/src/main.rs | 28 ++++++++++++------------ net/e1000d/src/device.rs | 4 ++-- net/e1000d/src/main.rs | 6 ++--- net/rtl8139d/src/main.rs | 6 ++--- net/rtl8168d/src/main.rs | 8 +++---- net/virtio-netd/src/main.rs | 4 ++-- pcid-spawner/src/main.rs | 4 ++-- pcid/src/driver_interface/irq_helpers.rs | 2 +- storage/ahcid/src/ahci/hba.rs | 6 ++--- storage/ahcid/src/main.rs | 6 ++--- storage/ided/src/main.rs | 4 ++-- storage/nvmed/src/main.rs | 6 ++--- storage/virtio-blkd/src/main.rs | 4 ++-- usb/usbhubd/src/main.rs | 3 +-- usb/xhcid/src/driver_interface.rs | 3 +-- usb/xhcid/src/main.rs | 4 ++-- 37 files changed, 109 insertions(+), 90 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f24e915aa8..bb4deae74f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -451,10 +451,12 @@ dependencies = [ name = "fbcond" version = "0.1.0" dependencies = [ + "common", "console-draw", "graphics-ipc", "inputd", "libredox", + "log", "orbclient", "ransid", "redox-daemon", diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index eb5dcfb24c..1b8c9c5a44 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -353,16 +353,16 @@ impl acpi::Handler for AmlPhysMemHandler { } fn create_mutex(&self) -> Handle { - log::info!("TODO: Handler::create_mutex"); + log::debug!("TODO: Handler::create_mutex"); Handle(0) } fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), AmlError> { - log::info!("TODO: Handler::acquire"); + log::debug!("TODO: Handler::acquire"); Ok(()) } fn release(&self, mutex: Handle) { - log::info!("TODO: Handler::release"); + log::debug!("TODO: Handler::release"); } } diff --git a/acpid/src/main.rs b/acpid/src/main.rs index 215ccb43fd..e344468a44 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -18,8 +18,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "misc", "acpi", "acpid", - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); let rxsdt_raw_data: Arc<[u8]> = std::fs::read("/scheme/kernel.acpi/rxsdt") diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index bbd5d954e3..f37e2b0f5a 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -40,8 +40,8 @@ fn main() { "audio", "pci", &name, - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); common::acquire_port_io_rights() diff --git a/audio/ihdad/src/hda/device.rs b/audio/ihdad/src/hda/device.rs index 5a885ce056..f3ae108e61 100755 --- a/audio/ihdad/src/hda/device.rs +++ b/audio/ihdad/src/hda/device.rs @@ -209,7 +209,7 @@ impl IntelHDA { module.enumerate(); module.configure(); - log::info!("IHDA: Initialization finished."); + log::debug!("IHDA: Initialization finished."); Ok(module) } @@ -716,7 +716,7 @@ impl IntelHDA { } pub fn info(&self) { - log::info!( + log::debug!( "Intel HD Audio Version {}.{}", self.regs.vmaj.read(), self.regs.vmin.read() @@ -961,7 +961,7 @@ impl IntelHDA { impl Drop for IntelHDA { fn drop(&mut self) { - log::info!("IHDA: Deallocating IHDA driver."); + log::debug!("IHDA: Deallocating IHDA driver."); } } @@ -1019,7 +1019,7 @@ impl SchemeBlockMut for IntelHDA { } }; - //log::info!("Int count: {}", self.int_counter); + //log::debug!("Int count: {}", self.int_counter); self.write_to_output(index, buf) } diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 31aee8a65d..e0c8d3cced 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -70,11 +70,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "audio", "pci", &name, - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); - log::info!(" + IHDA {}", pci_config.func.display()); + log::info!("IHDA {}", pci_config.func.display()); let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index cfe25f77e7..bf5c7227db 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -23,8 +23,8 @@ fn main() { "audio", "pci", "sb16", - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights"); diff --git a/common/src/lib.rs b/common/src/lib.rs index 61a2c428c6..1966d5b05a 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -17,7 +17,7 @@ mod logger; /// The Scatter Gather List (SGL) API for drivers. pub mod sgl; -pub use logger::setup_logging; +pub use logger::{output_level, file_level, setup_logging}; /// Specifies the write behavior for a specific region of memory /// diff --git a/common/src/logger.rs b/common/src/logger.rs index 6b62cf86fe..20e090d9f7 100644 --- a/common/src/logger.rs +++ b/common/src/logger.rs @@ -1,5 +1,14 @@ use redox_log::{OutputBuilder, RedoxLogger}; +pub fn output_level() -> log::LevelFilter { + //TODO: adjust with bootloader environment + log::LevelFilter::Info +} + +pub fn file_level() -> log::LevelFilter { + log::LevelFilter::Info +} + /// Configures logging for a single driver. #[cfg_attr(not(target_os = "redox"), allow(unused_variables, unused_mut))] pub fn setup_logging( diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index a803cdf196..2e2ca05564 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -20,11 +20,11 @@ fn main() { "graphics", "pci", &name, - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); - log::info!(" + BGA {}", pci_config.func.display()); + log::info!("BGA {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { acquire_port_io_rights().expect("bgad: failed to get port IO permission"); @@ -32,7 +32,7 @@ fn main() { let socket = Socket::create("bga").expect("bgad: failed to create bga scheme"); let mut bga = Bga::new(); - log::info!(" - BGA {}x{}", bga.width(), bga.height()); + log::debug!("BGA {}x{}", bga.width(), bga.height()); let mut scheme = BgaScheme { bga, diff --git a/graphics/fbcond/Cargo.toml b/graphics/fbcond/Cargo.toml index 6e8816cfaa..435c15b1a7 100644 --- a/graphics/fbcond/Cargo.toml +++ b/graphics/fbcond/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] +log = "0.4" orbclient = "0.3.27" ransid = "0.4" redox_event = "0.4" @@ -11,6 +12,7 @@ redox_syscall = "0.5" redox-daemon = "0.1" redox-scheme = "0.4" +common = { path = "../../common" } console-draw = { path = "../console-draw" } graphics-ipc = { path = "../graphics-ipc" } inputd = { path = "../../inputd" } diff --git a/graphics/fbcond/src/display.rs b/graphics/fbcond/src/display.rs index d47f130e78..9ad75e7f63 100644 --- a/graphics/fbcond/src/display.rs +++ b/graphics/fbcond/src/display.rs @@ -31,7 +31,7 @@ impl Display { let display_file = self.input_handle.open_display_v2().unwrap(); let new_display_handle = V2GraphicsHandle::from_file(display_file).unwrap(); - eprintln!("fbcond: Opened new display"); + log::debug!("fbcond: Opened new display"); let (width, height) = new_display_handle.display_size(0).unwrap(); let fb = new_display_handle @@ -40,7 +40,7 @@ impl Display { match new_display_handle.map_dumb_framebuffer(fb, width, height) { Ok(map) => { - eprintln!( + log::debug!( "fbcond: Mapped new display with size {}x{}", map.width(), map.height() @@ -53,7 +53,7 @@ impl Display { }); } Err(err) => { - eprintln!("failed to resize display: {}", err); + log::error!("failed to map display: {}", err); } } } @@ -62,7 +62,7 @@ impl Display { let (width, height) = match map.display_handle.display_size(0) { Ok((width, height)) => (width, height), Err(err) => { - eprintln!("fbcond: failed to get display size: {}", err); + log::error!("fbcond: failed to get display size: {}", err); (map.inner.width() as u32, map.inner.height() as u32) } }; @@ -94,14 +94,14 @@ impl Display { map.fb = fb; map.inner = new_map; - eprintln!("fbcond: mapped display"); + log::debug!("fbcond: mapped display"); } Err(err) => { - eprintln!("fbcond: failed to open display: {}", err); + log::error!("fbcond: failed to open display: {}", err); } }, Err(err) => { - eprintln!("fbcond: failed to create framebuffer: {}", err); + log::error!("fbcond: failed to create framebuffer: {}", err); } } } diff --git a/graphics/fbcond/src/main.rs b/graphics/fbcond/src/main.rs index 27f81244f4..5b9bfd73e8 100644 --- a/graphics/fbcond/src/main.rs +++ b/graphics/fbcond/src/main.rs @@ -18,6 +18,14 @@ fn main() { .map(|arg| arg.parse().expect("invalid vt number")) .collect::>(); + common::setup_logging( + "graphics", + "fbcond", + "fbcond", + common::output_level(), + common::file_level() + ); + redox_daemon::Daemon::new(|daemon| inner(daemon, &vt_ids)).expect("failed to create daemon"); } fn inner(daemon: redox_daemon::Daemon, vt_ids: &[usize]) -> ! { diff --git a/graphics/fbcond/src/text.rs b/graphics/fbcond/src/text.rs index f8ec4d31e1..8cbd70b348 100644 --- a/graphics/fbcond/src/text.rs +++ b/graphics/fbcond/src/text.rs @@ -23,7 +23,7 @@ impl TextScreen { } pub fn handle_handoff(&mut self) { - eprintln!("fbcond: Performing handoff"); + log::info!("fbcond: Performing handoff"); self.display.reopen_for_handoff(); } diff --git a/graphics/virtio-gpud/src/main.rs b/graphics/virtio-gpud/src/main.rs index f2a2d354ca..ad89ed78e5 100644 --- a/graphics/virtio-gpud/src/main.rs +++ b/graphics/virtio-gpud/src/main.rs @@ -553,8 +553,8 @@ pub fn main() { "graphics", "pci", "virtio-gpud", - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } diff --git a/hwd/src/backend/acpi.rs b/hwd/src/backend/acpi.rs index 53b96a9d33..42170b2221 100644 --- a/hwd/src/backend/acpi.rs +++ b/hwd/src/backend/acpi.rs @@ -89,7 +89,7 @@ impl Backend for AcpiBackend { "PNP0F13" => "PS/2 port for PS/2-style mouse", _ => "?", }; - log::info!("{}: {} ({})", name, id, what); + log::debug!("{}: {} ({})", name, id, what); } } } diff --git a/hwd/src/backend/devicetree.rs b/hwd/src/backend/devicetree.rs index a2dc7706dc..8a91d04e42 100644 --- a/hwd/src/backend/devicetree.rs +++ b/hwd/src/backend/devicetree.rs @@ -20,7 +20,7 @@ impl DeviceTreeBackend { line.push_str(id); } } - log::info!("{}", line); + log::debug!("{}", line); for child in node.children() { Self::dump(&child, level + 1); } diff --git a/hwd/src/main.rs b/hwd/src/main.rs index 5b772af0a8..ed62b87e4d 100644 --- a/hwd/src/main.rs +++ b/hwd/src/main.rs @@ -6,8 +6,8 @@ fn main() { "misc", "hwd", "hwd", - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); // Prefer DTB if available (matches kernel preference) diff --git a/input/ps2d/src/controller.rs b/input/ps2d/src/controller.rs index 3a8c597b7f..1a4eb593a2 100644 --- a/input/ps2d/src/controller.rs +++ b/input/ps2d/src/controller.rs @@ -202,7 +202,7 @@ impl Ps2 { return Ok(ok); } Err(ref err) => { - info!("ps2d: {}: retry {}/{}: {:?}", name, retry + 1, retries, err); + debug!("ps2d: {}: retry {}/{}: {:?}", name, retry + 1, retries, err); } } } diff --git a/input/ps2d/src/main.rs b/input/ps2d/src/main.rs index 1d55190b63..64415dd3d2 100644 --- a/input/ps2d/src/main.rs +++ b/input/ps2d/src/main.rs @@ -30,8 +30,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "input", "ps2", "ps2", - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); acquire_port_io_rights().expect("ps2d: failed to get I/O permission"); diff --git a/input/usbhidd/src/main.rs b/input/usbhidd/src/main.rs index 9da7803011..efc763399d 100644 --- a/input/usbhidd/src/main.rs +++ b/input/usbhidd/src/main.rs @@ -188,8 +188,8 @@ fn main() { "usb", "device", &name, - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); log::info!( diff --git a/inputd/src/main.rs b/inputd/src/main.rs index 6fbdf4cd9e..fa1f963444 100644 --- a/inputd/src/main.rs +++ b/inputd/src/main.rs @@ -87,12 +87,12 @@ impl InputScheme { } if !self.vts.contains(&new_active) { - log::warn!("inputd: switch to non-existent VT #{new_active} was requested"); + log::warn!("switch to non-existent VT #{new_active} was requested"); return; } - log::info!( - "inputd: switching from VT #{} to VT #{new_active}", + log::debug!( + "switching from VT #{} to VT #{new_active}", self.active_vt.unwrap_or(0) ); @@ -205,12 +205,12 @@ impl SchemeSync for InputScheme { "control" => Handle::Control, _ => { - log::error!("inputd: invalid path '{path}'"); + log::error!("invalid path '{path}'"); return Err(SysError::new(EINVAL)); } }; - log::info!("inputd: {path} channel has been opened"); + log::debug!("{path} channel has been opened"); self.handles.insert(fd, handle_ty); Ok(OpenResult::ThisScheme { @@ -278,17 +278,17 @@ impl SchemeSync for InputScheme { } Ok(copy * size_of::()) } else { - log::error!("inputd: display tried to read incorrectly sized event"); + log::error!("display tried to read incorrectly sized event"); return Err(SysError::new(EINVAL)); } } Handle::Producer => { - log::error!("inputd: producer tried to read"); + log::error!("producer tried to read"); return Err(SysError::new(EINVAL)); } Handle::Control => { - log::error!("inputd: control tried to read"); + log::error!("control tried to read"); return Err(SysError::new(EINVAL)); } } @@ -309,7 +309,7 @@ impl SchemeSync for InputScheme { match handle { Handle::Control => { if buf.len() != size_of::() { - log::error!("inputd: control tried to write incorrectly sized command"); + log::error!("control tried to write incorrectly sized command"); return Err(SysError::new(EINVAL)); } @@ -322,11 +322,11 @@ impl SchemeSync for InputScheme { } Handle::Consumer { .. } => { - log::error!("inputd: consumer tried to write"); + log::error!("consumer tried to write"); return Err(SysError::new(EINVAL)); } Handle::Display { .. } => { - log::error!("inputd: display tried to write"); + log::error!("display tried to write"); return Err(SysError::new(EINVAL)); } Handle::Producer => {} @@ -460,7 +460,7 @@ impl SchemeSync for InputScheme { Ok(EventFlags::empty()) } Handle::Producer | Handle::Control => { - log::error!("inputd: producer or control tried to use an event queue"); + log::error!("producer or control tried to use an event queue"); Err(SysError::new(EINVAL)) } } @@ -576,8 +576,8 @@ fn main() { "input", "inputd", "inputd", - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); let mut args = std::env::args().skip(1); diff --git a/net/e1000d/src/device.rs b/net/e1000d/src/device.rs index 7d231e99a3..b980e5b10c 100644 --- a/net/e1000d/src/device.rs +++ b/net/e1000d/src/device.rs @@ -287,7 +287,7 @@ impl Intel8254x { mac_high as u8, (mac_high >> 8) as u8, ]; - log::info!( + log::debug!( "MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] ); @@ -351,7 +351,7 @@ impl Intel8254x { while self.read_reg(STATUS) & 2 != 2 { thread::sleep(time::Duration::from_millis(100)); } - log::info!( + log::debug!( "Link is up with speed {}", match (self.read_reg(STATUS) >> 6) & 0b11 { 0b00 => "10 Mb/s", diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index f508616676..44c0282390 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -18,8 +18,8 @@ fn main() { "net", "pci", &name, - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); let irq = pci_config @@ -27,7 +27,7 @@ fn main() { .legacy_interrupt_line .expect("e1000d: no legacy interrupts supported"); - log::info!(" + E1000 {}", pci_config.func.display()); + log::info!("E1000 {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { let mut irq_file = irq.irq_handle("e1000d"); diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 5be7ba6452..891c888912 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -60,7 +60,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { }; pcid_handle.enable_feature(PciFeature::MsiX); - log::info!("Enabled MSI-X"); + log::debug!("Enabled MSI-X"); method } else if has_msi { @@ -113,8 +113,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "net", "pci", &name, - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); log::info!(" + RTL8139 {}", pci_config.func.display()); diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 243cb43b2a..8c009822ee 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -60,7 +60,7 @@ fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { }; pcid_handle.enable_feature(PciFeature::MsiX); - log::info!("Enabled MSI-X"); + log::debug!("Enabled MSI-X"); method } else if has_msi { @@ -113,11 +113,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "net", "pci", &name, - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); - log::info!(" + RTL8168 {}", pci_config.func.display()); + log::info!("RTL8168 {}", pci_config.func.display()); let bar = map_bar(&mut pcid_handle); diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index d9d9e3d602..f566a7d82e 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -124,8 +124,8 @@ pub fn main() { "net", "pci", "virtio-netd", - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } diff --git a/pcid-spawner/src/main.rs b/pcid-spawner/src/main.rs index ecdcda1d6d..97cc3cece0 100644 --- a/pcid-spawner/src/main.rs +++ b/pcid-spawner/src/main.rs @@ -16,8 +16,8 @@ fn main() -> Result<()> { "bus", "pci", "pci-spawner.log", - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); let config_data = if fs::metadata(&config_path)?.is_file() { diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index 6a91bd1000..f4221d0c68 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -223,7 +223,7 @@ pub fn allocate_first_msi_interrupt_on_bsp( pcid_handle.set_feature_info(SetFeatureInfo::Msi(set_feature_info)); pcid_handle.enable_feature(PciFeature::Msi); - log::info!("Enabled MSI"); + log::debug!("Enabled MSI"); interrupt_handle } diff --git a/storage/ahcid/src/ahci/hba.rs b/storage/ahcid/src/ahci/hba.rs index bf5dac6e3a..1e788dc912 100644 --- a/storage/ahcid/src/ahci/hba.rs +++ b/storage/ahcid/src/ahci/hba.rs @@ -153,7 +153,7 @@ impl HbaPort { // Power on and spin up device self.cmd.writef(1 << 2 | 1 << 1, true); - debug!(" - AHCI init {:X}", self.cmd.read()); + debug!("AHCI init {:X}", self.cmd.read()); Ok(()) } @@ -255,7 +255,7 @@ impl HbaPort { }; info!( - " + Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", + "Serial: {} Firmware: {} Model: {} {}-bit LBA Size: {} MB", serial.trim(), firmware.trim(), model.trim(), @@ -496,7 +496,7 @@ impl HbaMem { self.ghc.write(1 << 31 | 1 << 1); debug!( - " - AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}", + "AHCI CAP {:X} GHC {:X} IS {:X} PI {:X} VS {:X} CAP2 {:X} BOHC {:X}", self.cap.read(), self.ghc.read(), self.is.read(), diff --git a/storage/ahcid/src/main.rs b/storage/ahcid/src/main.rs index dd8a06319c..159a726cb8 100644 --- a/storage/ahcid/src/main.rs +++ b/storage/ahcid/src/main.rs @@ -33,11 +33,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "disk", "pci", &name, - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); - info!(" + AHCI {}", pci_config.func.display()); + info!("AHCI {}", pci_config.func.display()); let address = unsafe { pcid_handle.map_bar(5) }.ptr.as_ptr() as usize; { diff --git a/storage/ided/src/main.rs b/storage/ided/src/main.rs index 0bab7a4ed8..8015baae9e 100644 --- a/storage/ided/src/main.rs +++ b/storage/ided/src/main.rs @@ -33,8 +33,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "disk", "pci", &name, - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); info!("IDE PCI CONFIG: {:?}", pci_config); diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 7a3a44b616..6112756c76 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -156,8 +156,8 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { "disk", "pci", &scheme_name, - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); log::debug!("NVME PCI CONFIG: {:?}", pci_config); @@ -231,7 +231,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace"); - log::info!("Starting to listen for scheme events"); + log::debug!("Starting to listen for scheme events"); executor.block_on(async { loop { diff --git a/storage/virtio-blkd/src/main.rs b/storage/virtio-blkd/src/main.rs index 609d42002a..82818a7584 100644 --- a/storage/virtio-blkd/src/main.rs +++ b/storage/virtio-blkd/src/main.rs @@ -35,8 +35,8 @@ pub fn main() -> anyhow::Result<()> { "disk", "pci", "virtio-blkd", - log::LevelFilter::Warn, - log::LevelFilter::Info, + common::output_level(), + common::file_level(), ); redox_daemon::Daemon::new(daemon_runner).expect("virtio-core: failed to daemonize"); } diff --git a/usb/usbhubd/src/main.rs b/usb/usbhubd/src/main.rs index fa3c2ee784..c24588deda 100644 --- a/usb/usbhubd/src/main.rs +++ b/usb/usbhubd/src/main.rs @@ -6,7 +6,6 @@ use xhcid_interface::{ }; fn main() { - let mut args = env::args().skip(1); const USAGE: &'static str = "usbhubd "; @@ -36,7 +35,7 @@ fn main() { "device", &name, log::LevelFilter::Warn, - log::LevelFilter::Info, + common::file_level(), ); let handle = XhciClientHandle::new(scheme.clone(), port_id); diff --git a/usb/xhcid/src/driver_interface.rs b/usb/xhcid/src/driver_interface.rs index 035e93da1b..004e58b29b 100644 --- a/usb/xhcid/src/driver_interface.rs +++ b/usb/xhcid/src/driver_interface.rs @@ -157,8 +157,7 @@ impl EndpDesc { self.ssc.is_some() } pub fn is_superspeedplus(&self) -> bool { - log::warn!("TODO: is_superspeedplus not implemented, defaulting to false"); - false + self.sspc.is_some() } fn interrupt_usage_bits(&self) -> u8 { assert!(self.is_interrupt()); diff --git a/usb/xhcid/src/main.rs b/usb/xhcid/src/main.rs index 6e57345f28..1167727576 100644 --- a/usb/xhcid/src/main.rs +++ b/usb/xhcid/src/main.rs @@ -135,7 +135,7 @@ fn daemon_with_context_size( "host", &name, log::LevelFilter::Warn, - log::LevelFilter::Info, + common::file_level(), ); log::debug!("XHCI PCI CONFIG: {:?}", pci_config); @@ -145,7 +145,7 @@ fn daemon_with_context_size( let (irq_file, interrupt_method) = (None, InterruptMethod::Polling); //get_int_method(&mut pcid_handle); //TODO: Fix interrupts. - log::info!(" + XHCI {}", pci_config.func.display()); + log::info!("XHCI {}", pci_config.func.display()); let scheme_name = format!("usb.{}", name); let socket = Socket::create(scheme_name.clone()).expect("xhcid: failed to create usb scheme"); From 93eeb4ca0b8e896e7fb872e1193725579ea1e07f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 2 Nov 2025 08:00:19 -0700 Subject: [PATCH 1275/1301] Adjust pcid logging --- pcid/src/cfg_access/mod.rs | 2 +- pcid/src/main.rs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/pcid/src/cfg_access/mod.rs b/pcid/src/cfg_access/mod.rs index 8e7f58b7be..c25524485a 100644 --- a/pcid/src/cfg_access/mod.rs +++ b/pcid/src/cfg_access/mod.rs @@ -170,7 +170,7 @@ impl Mcfg { let bytes = fs::read(table_path)?.into_boxed_slice(); match Mcfg::parse(&*bytes) { Some((_mcfg, allocs)) => { - log::info!("MCFG ALLOCS {:?}", allocs.0); + log::debug!("MCFG ALLOCS {:?}", allocs.0); return f(allocs, Vec::new(), [u32::MAX, u32::MAX, u32::MAX, u32::MAX]); } None => { diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 3102cdbbbb..50ffd4b6ec 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -75,7 +75,7 @@ fn handle_parsed_header( } if !string.is_empty() { - info!(" BAR{}", string); + debug!(" BAR{}", string); } let capabilities = if endpoint_header.status(pcie).has_capability_list() { @@ -191,9 +191,8 @@ fn main() { let mut args = pico_args::Arguments::from_env(); let verbosity = (0..).find(|_| !args.contains("-v")).unwrap_or(0); let log_level = match verbosity { - 0 => log::LevelFilter::Warn, - 1 => log::LevelFilter::Info, - 2 => log::LevelFilter::Debug, + 0 => log::LevelFilter::Info, + 1 => log::LevelFilter::Debug, _ => log::LevelFilter::Trace, }; @@ -221,7 +220,7 @@ fn main_inner(daemon: redox_daemon::Daemon) -> ! { scan_device(&mut tree, &pcie, &mut bus_nums, bus_num, dev_num); } } - info!("Enumeration complete, now starting pci scheme"); + debug!("Enumeration complete, now starting pci scheme"); let mut scheme = scheme::PciScheme::new(pcie, tree); let socket = redox_scheme::Socket::create("pci").expect("failed to open pci scheme socket"); From ee6e94ca1e65003001c46ed9e3fdbce2db04df7b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 2 Nov 2025 08:15:38 -0700 Subject: [PATCH 1276/1301] Adjust ps2d timeouts --- input/ps2d/src/controller.rs | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/input/ps2d/src/controller.rs b/input/ps2d/src/controller.rs index 1a4eb593a2..42c0f08f3c 100644 --- a/input/ps2d/src/controller.rs +++ b/input/ps2d/src/controller.rs @@ -3,24 +3,6 @@ use log::{debug, error, info, trace}; use std::{fmt, thread, time::Duration}; -#[cfg(target_arch = "aarch64")] -#[inline(always)] -pub(crate) unsafe fn pause() { - std::arch::aarch64::__yield(); -} - -#[cfg(target_arch = "x86")] -#[inline(always)] -pub(crate) unsafe fn pause() { - std::arch::x86::_mm_pause(); -} - -#[cfg(target_arch = "x86_64")] -#[inline(always)] -pub(crate) unsafe fn pause() { - std::arch::x86_64::_mm_pause(); -} - #[derive(Debug)] pub enum Error { CommandRetry, @@ -133,7 +115,7 @@ impl Ps2 { } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 500; + let mut timeout = 100; while timeout > 0 { if self.status().contains(StatusFlags::OUTPUT_FULL) { return Ok(()); @@ -145,7 +127,7 @@ impl Ps2 { } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 500; + let mut timeout = 100; while timeout > 0 { if !self.status().contains(StatusFlags::INPUT_FULL) { return Ok(()); @@ -163,10 +145,8 @@ impl Ps2 { let val = self.data.read(); trace!("ps2d: flush {}: {:X}", message, val); } - unsafe { - pause(); - } timeout -= 1; + thread::sleep(Duration::from_millis(1)); } } From e5beee87ddc9d2bfbf088208dcf985824ea83132 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 21 Nov 2025 15:46:27 -0700 Subject: [PATCH 1277/1301] ps2d: fix timeout code --- input/ps2d/src/controller.rs | 53 ++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/input/ps2d/src/controller.rs b/input/ps2d/src/controller.rs index 42c0f08f3c..0492573667 100644 --- a/input/ps2d/src/controller.rs +++ b/input/ps2d/src/controller.rs @@ -1,7 +1,7 @@ use common::io::{Io, Pio, ReadOnly, WriteOnly}; use log::{debug, error, info, trace}; -use std::{fmt, thread, time::Duration}; +use std::{fmt, thread, time::{Duration, Instant}}; #[derive(Debug)] pub enum Error { @@ -95,6 +95,32 @@ enum MouseCommandData { SetSampleRate = 0xF3, } +struct Timeout { + instant: Instant, + duration: Duration, +} + +impl Timeout { + fn new(millis: u64) -> Self { + Self { + instant: Instant::now(), + duration: Duration::from_millis(millis), + } + } + + fn run(&self) -> Result<(), ()> { + if self.instant.elapsed() < self.duration { + // Sleeps in Redox are only evaluated on PIT ticks (a few ms), which is not + // short enough for a reasonably responsive timeout. However, the clock is + // highly accurate. So, we yield instead of sleep to reduce latency. + thread::yield_now(); + Ok(()) + } else { + Err(()) + } + } +} + pub struct Ps2 { data: Pio, status: ReadOnly>, @@ -115,38 +141,35 @@ impl Ps2 { } fn wait_read(&mut self) -> Result<(), Error> { - let mut timeout = 100; - while timeout > 0 { + let timeout = Timeout::new(10); + loop { if self.status().contains(StatusFlags::OUTPUT_FULL) { return Ok(()); } - timeout -= 1; - thread::sleep(Duration::from_millis(1)); + timeout.run().map_err(|()| Error::ReadTimeout)? } - Err(Error::ReadTimeout) } fn wait_write(&mut self) -> Result<(), Error> { - let mut timeout = 100; - while timeout > 0 { + let timeout = Timeout::new(10); + loop { if !self.status().contains(StatusFlags::INPUT_FULL) { return Ok(()); } - timeout -= 1; - thread::sleep(Duration::from_millis(1)); + timeout.run().map_err(|()| Error::WriteTimeout)? } - Err(Error::WriteTimeout) } fn flush_read(&mut self, message: &str) { - let mut timeout = 100; - while timeout > 0 { + let timeout = Timeout::new(1); + loop { if self.status().contains(StatusFlags::OUTPUT_FULL) { let val = self.data.read(); trace!("ps2d: flush {}: {:X}", message, val); } - timeout -= 1; - thread::sleep(Duration::from_millis(1)); + if timeout.run().is_err() { + return; + } } } From 732cde5bade2f36e7b114177dd2c543053bdb06f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 21 Nov 2025 21:07:05 -0700 Subject: [PATCH 1278/1301] Make PS/2 driver cleaner and more resilient --- input/ps2d/src/controller.rs | 161 ++++++++--------------------------- 1 file changed, 37 insertions(+), 124 deletions(-) diff --git a/input/ps2d/src/controller.rs b/input/ps2d/src/controller.rs index 0492573667..fbbbf75cb0 100644 --- a/input/ps2d/src/controller.rs +++ b/input/ps2d/src/controller.rs @@ -1,7 +1,10 @@ use common::io::{Io, Pio, ReadOnly, WriteOnly}; use log::{debug, error, info, trace}; -use std::{fmt, thread, time::{Duration, Instant}}; +use std::{ + fmt, thread, + time::{Duration, Instant}, +}; #[derive(Debug)] pub enum Error { @@ -95,16 +98,21 @@ enum MouseCommandData { SetSampleRate = 0xF3, } +// Default timeout in microseconds +const DEFAULT_TIMEOUT: u64 = 50_000; +// Reset timeout in microseconds +const RESET_TIMEOUT: u64 = 500_000; + struct Timeout { instant: Instant, duration: Duration, } impl Timeout { - fn new(millis: u64) -> Self { + fn new(micros: u64) -> Self { Self { instant: Instant::now(), - duration: Duration::from_millis(millis), + duration: Duration::from_micros(micros), } } @@ -140,8 +148,8 @@ impl Ps2 { StatusFlags::from_bits_truncate(self.status.read()) } - fn wait_read(&mut self) -> Result<(), Error> { - let timeout = Timeout::new(10); + fn wait_read(&mut self, micros: u64) -> Result<(), Error> { + let timeout = Timeout::new(micros); loop { if self.status().contains(StatusFlags::OUTPUT_FULL) { return Ok(()); @@ -150,8 +158,8 @@ impl Ps2 { } } - fn wait_write(&mut self) -> Result<(), Error> { - let timeout = Timeout::new(10); + fn wait_write(&mut self, micros: u64) -> Result<(), Error> { + let timeout = Timeout::new(micros); loop { if !self.status().contains(StatusFlags::INPUT_FULL) { return Ok(()); @@ -160,32 +168,24 @@ impl Ps2 { } } - fn flush_read(&mut self, message: &str) { - let timeout = Timeout::new(1); - loop { - if self.status().contains(StatusFlags::OUTPUT_FULL) { - let val = self.data.read(); - trace!("ps2d: flush {}: {:X}", message, val); - } - if timeout.run().is_err() { - return; - } - } - } - fn command(&mut self, command: Command) -> Result<(), Error> { - self.wait_write()?; + self.wait_write(DEFAULT_TIMEOUT)?; self.command.write(command as u8); Ok(()) } fn read(&mut self) -> Result { - self.wait_read()?; - Ok(self.data.read()) + self.read_timeout(DEFAULT_TIMEOUT) + } + + fn read_timeout(&mut self, micros: u64) -> Result { + self.wait_read(micros)?; + let data = self.data.read(); + Ok(data) } fn write(&mut self, data: u8) -> Result<(), Error> { - self.wait_write()?; + self.wait_write(DEFAULT_TIMEOUT)?; self.data.write(data); Ok(()) } @@ -311,9 +311,6 @@ impl Ps2 { { // Enable first device self.command(Command::EnableFirst)?; - - // Clear remaining data - self.flush_read("enable first"); } { @@ -327,14 +324,9 @@ impl Ps2 { } else { error!("ps2d: keyboard failed to reset: {:02X}", b); } - - // Clear remaining data - self.flush_read("keyboard reset"); } self.retry(format_args!("keyboard defaults"), 4, |x| { - x.flush_read("keyboard before defaults"); - // Set defaults and disable scanning let b = x.keyboard_command(KeyboardCommand::SetDefaultsDisable)?; if b != 0xFA { @@ -342,9 +334,6 @@ impl Ps2 { return Err(Error::CommandRetry); } - // Clear remaining data - x.flush_read("keyboard after defaults"); - Ok(b) })?; @@ -358,39 +347,30 @@ impl Ps2 { scancode_set, b ); } - - // Clear remaining data - self.flush_read("keyboard scancode"); } Ok(()) } pub fn init_mouse(&mut self) -> Result { - let mut b; + let mut b: u8 = 0; { // Enable second device self.command(Command::EnableSecond)?; - - // Clear remaining data - self.flush_read("enable second"); } self.retry(format_args!("mouse reset"), 4, |x| { - // Clear remaining data - x.flush_read("mouse before reset"); - // Reset mouse let mut b = x.mouse_command(MouseCommand::Reset)?; if b == 0xFA { - b = x.read()?; + b = x.read_timeout(RESET_TIMEOUT)?; if b != 0xAA { error!("ps2d: mouse failed self test 1: {:02X}", b); return Err(Error::CommandRetry); } - b = x.read()?; + b = x.read_timeout(RESET_TIMEOUT)?; if b != 0x00 { error!("ps2d: mouse failed self test 2: {:02X}", b); return Err(Error::CommandRetry); @@ -400,23 +380,9 @@ impl Ps2 { return Err(Error::CommandRetry); } - // Clear remaining data - x.flush_read("mouse after reset"); - Ok(b) })?; - { - // Set defaults - b = self.mouse_command(MouseCommand::SetDefaults)?; - if b != 0xFA { - error!("ps2d: mouse failed to set defaults: {:02X}", b); - } - - // Clear remaining data - self.flush_read("mouse defaults"); - } - { // Enable extra packet on mouse //TODO: show error return values @@ -426,9 +392,6 @@ impl Ps2 { { error!("ps2d: mouse failed to enable extra packet"); } - - // Clear remaining data - self.flush_read("enable extra mouse packet"); } b = self.mouse_command(MouseCommand::GetDeviceId)?; @@ -439,35 +402,6 @@ impl Ps2 { false }; - // Clear remaining data - self.flush_read("get device id"); - - { - // Set resolution to maximum - let resolution = 3; - b = self.mouse_command_data(MouseCommandData::SetResolution, resolution)?; - if b != 0xFA { - error!( - "ps2d: mouse failed to set resolution to {}: {:02X}", - resolution, b - ); - } - - // Clear remaining data - self.flush_read("set sample rate"); - } - - { - // Set scaling to 1:1 - b = self.mouse_command(MouseCommand::SetScaling1To1)?; - if b != 0xFA { - error!("ps2d: mouse failed to set scaling: {:02X}", b); - } - - // Clear remaining data - self.flush_read("set scaling"); - } - { // Set sample rate to maximum let sample_rate = 200; @@ -478,9 +412,6 @@ impl Ps2 { sample_rate, b ); } - - // Clear remaining data - self.flush_read("set sample rate"); } { @@ -493,7 +424,7 @@ impl Ps2 { let c = self.read()?; debug!( - "ps2d: mouse status {:#x} resolution {:#x} sample rate {:#x}", + "ps2d: mouse status {:#x} resolution {} sample rate {}", a, b, c ); } @@ -503,33 +434,23 @@ impl Ps2 { } pub fn init(&mut self) -> bool { - // Clear remaining data - self.flush_read("init start"); - { // Disable devices self.command(Command::DisableFirst) .expect("ps2d: failed to initialize"); self.command(Command::DisableSecond) .expect("ps2d: failed to initialize"); - - // Clear remaining data - self.flush_read("disable"); } // Disable clocks, disable interrupts, and disable translate - let mut config; { // Since the default config may have interrupts enabled, and the kernel may eat up // our data in that case, we will write a config without reading the current one - config = ConfigFlags::POST_PASSED + let config = ConfigFlags::POST_PASSED | ConfigFlags::FIRST_DISABLED | ConfigFlags::SECOND_DISABLED; trace!("ps2d: config set {:?}", config); self.set_config(config).expect("ps2d: failed to initialize"); - - // Clear remaining data - self.flush_read("disable interrupts"); } { @@ -537,9 +458,6 @@ impl Ps2 { self.command(Command::TestController) .expect("ps2d: failed to initialize"); assert_eq!(self.read().expect("ps2d: failed to initialize"), 0x55); - - // Clear remaining data - self.flush_read("test controller"); } // Initialize keyboard @@ -574,23 +492,18 @@ impl Ps2 { // Enable clocks and interrupts { - config.remove(ConfigFlags::FIRST_DISABLED); - config.insert(ConfigFlags::FIRST_TRANSLATE); - config.insert(ConfigFlags::FIRST_INTERRUPT); - if mouse_found { - config.remove(ConfigFlags::SECOND_DISABLED); - config.insert(ConfigFlags::SECOND_INTERRUPT); - } else { - config.insert(ConfigFlags::SECOND_DISABLED); - config.remove(ConfigFlags::SECOND_INTERRUPT); - } + let config = ConfigFlags::POST_PASSED + | ConfigFlags::FIRST_INTERRUPT + | ConfigFlags::FIRST_TRANSLATE + | if mouse_found { + ConfigFlags::SECOND_INTERRUPT + } else { + ConfigFlags::SECOND_DISABLED + }; trace!("ps2d: config set {:?}", config); self.set_config(config).expect("ps2d: failed to initialize"); } - // Clear remaining data - self.flush_read("init finish"); - mouse_extra } } From 6107671e10ad17ee91c52f494b2540881c16593f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Nov 2025 09:45:20 -0700 Subject: [PATCH 1279/1301] ihdad: signal ready after scheme creation --- audio/ihdad/src/main.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index e0c8d3cced..c94184991c 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -92,11 +92,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - let event_queue = - EventQueue::::new().expect("ihdad: Could not create event queue."); - let mut device = unsafe { - hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") - }; let socket_fd = libredox::call::open( ":audiohw", flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, @@ -105,6 +100,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .expect("ihdad: failed to create hda scheme"); let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + daemon.ready().expect("ihdad: failed to signal readiness"); + + let event_queue = + EventQueue::::new().expect("ihdad: Could not create event queue."); + let mut device = unsafe { + hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") + }; + event_queue .subscribe(socket_fd, Source::Scheme, event::EventFlags::READ) .unwrap(); @@ -116,8 +119,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { ) .unwrap(); - daemon.ready().expect("ihdad: failed to signal readiness"); - libredox::call::setrens(0, 0).expect("ihdad: failed to enter null namespace"); let mut todo = Vec::::new(); From e1298752948bf92ef87ce38eb86e64df1d02782f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Nov 2025 10:12:56 -0700 Subject: [PATCH 1280/1301] Remove unnecessary double evaluation of AML --- acpid/src/acpi.rs | 39 --------------------------------------- 1 file changed, 39 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 9ddfdb3ab1..90a106dc71 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -267,10 +267,6 @@ impl AmlSymbols { &self.symbol_cache } - pub fn parse_table(&mut self, aml: &[u8]) -> Result<(), AmlError> { - self.aml_context.load_table(aml) - } - pub fn lookup(&self, symbol: &str) -> Option { if let Some(description) = self.symbol_cache.get(symbol) { log::trace!("Found symbol in cache, {}, {}", symbol, description); @@ -425,44 +421,9 @@ impl AcpiContext { Fadt::init(&mut this); //TODO (hangs on real hardware): Dmar::init(&this); - AcpiContext::build_aml_context(&this); - this } - fn build_aml_context(acpi: &AcpiContext) { - let mut aml_symbols = acpi.aml_symbols.write(); - - if let Some(dsdt) = acpi.dsdt() { - match aml_symbols.parse_table(dsdt.aml()) { - Ok(_) => log::trace!("Parsed DSDT"), - Err(e) => { - log::error!("DSDT: {:?}", e); - } - } - } else { - log::error!("No DSDT for aml parsing"); - } - - for ssdt in acpi.ssdts() { - match aml_symbols.parse_table(ssdt.aml()) { - Ok(_) => log::trace!("Parsed SSDT"), - Err(e) => { - log::error!("SSDT: {:?}", e); - } - } - } - - if let Ok(mut page_cache) = aml_symbols.page_cache.lock() { - page_cache.clear(); - } else { - log::error!("failed to lock AmlPageCache"); - } - - // force drop of page_cache from the previous if let - {} - } - pub fn dsdt(&self) -> Option<&Dsdt> { self.dsdt.as_ref() } From 2e96800384f9f33a233b8611d09be0ec4f35620f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Nov 2025 17:29:11 -0700 Subject: [PATCH 1281/1301] pcid: add access file --- pcid/src/scheme.rs | 73 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/pcid/src/scheme.rs b/pcid/src/scheme.rs index dcf3a26a3f..bb92f6563d 100644 --- a/pcid/src/scheme.rs +++ b/pcid/src/scheme.rs @@ -1,6 +1,6 @@ use std::collections::{BTreeMap, VecDeque}; -use pci_types::PciAddress; +use pci_types::{ConfigRegionAccess, PciAddress}; use redox_scheme::scheme::SchemeSync; use redox_scheme::{CallerCtx, OpenResult}; use syscall::dirent::{DirEntry, DirentBuf, DirentKind}; @@ -19,6 +19,7 @@ pub struct PciScheme { } enum Handle { TopLevel { entries: Vec }, + Access, Device, Channel { addr: PciAddress, st: ChannelState }, } @@ -28,14 +29,14 @@ struct HandleWrapper { } impl Handle { fn is_file(&self) -> bool { - matches!(self, Self::Channel { .. }) + matches!(self, Self::Access | Self::Channel { .. }) } fn is_dir(&self) -> bool { !self.is_file() } // TODO: capability rather than root fn requires_root(&self) -> bool { - matches!(self, Self::Channel { .. }) + matches!(self, Self::Access | Self::Channel { .. }) } } @@ -64,6 +65,8 @@ impl SchemeSync for PciScheme { .map(|(addr, _)| format!("{}", addr).replace(':', "--")) .collect::>(), } + } else if path == "access" { + Handle::Access } else { let idx = path.find('/').unwrap_or(path.len()); let (addr_str, after) = path.split_at(idx); @@ -104,7 +107,7 @@ impl SchemeSync for PciScheme { let (len, mode) = match handle.inner { Handle::TopLevel { ref entries } => (entries.len(), MODE_DIR | 0o755), Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755), - Handle::Channel { .. } => (0, MODE_CHR | 0o600), + Handle::Access | Handle::Channel { .. } => (0, MODE_CHR | 0o600), }; stat.st_size = len as u64; stat.st_mode = mode; @@ -131,6 +134,7 @@ impl SchemeSync for PciScheme { addr: _, ref mut st, } => Self::read_channel(st, buf), + _ => Err(Error::new(EBADF)) } } fn getdents<'buf>( @@ -162,7 +166,7 @@ impl SchemeSync for PciScheme { return Ok(buf); } Handle::Device => DEVICE_CONTENTS, - Handle::Channel { .. } => return Err(Error::new(ENOTDIR)), + Handle::Access | Handle::Channel { .. } => return Err(Error::new(ENOTDIR)), }; for (i, dent_name) in entries.iter().enumerate().skip(offset) { @@ -198,6 +202,65 @@ impl SchemeSync for PciScheme { _ => Err(Error::new(EBADF)), } } + + fn call(&mut self, id: usize, payload: &mut [u8], metadata: &[u64]) -> Result { + let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?; + + if handle.stat { + return Err(Error::new(EBADF)); + } + + match handle.inner { + Handle::Access => { + let (addr, offset) = match metadata.get(1) { + Some(value) => { + // Segment: u16, at 28 bits + // Bus: u8, 8 bits, 256 total, at 20 bits + // Device: u8, 5 bits, 32 total, at 15 bits + // Function: u8, 3 bits, 8 total, at 12 bits + // Offset: u16, 12 bits, 4096 total, at 0 bits + ( + PciAddress::new( + ((value >> 28) & 0xFFFF) as u16, + ((value >> 20) & 0xFF) as u8, + ((value >> 15) & 0x1F) as u8, + ((value >> 12) & 0x7) as u8, + ), + (value & 0xFFF) as u16 + ) + } + None => return Err(Error::new(EINVAL)), + }; + match metadata.get(0) { + Some(1) => { + // Read + let value = unsafe { self.pcie.read(addr, offset) }; + let bytes = value.to_le_bytes(); + let len = payload.len().min(bytes.len()); + payload.copy_from_slice(&bytes[..len]); + Ok(len) + } + Some(2) => { + // Write + let len = payload.len().min(4); + let mut bytes = if len < 4 { + //TODO: any way to do less than dword writes? + unsafe { self.pcie.read(addr, offset).to_le_bytes() } + } else { + [0; 4] + }; + bytes[..len].copy_from_slice(&payload); + let value = u32::from_le_bytes(bytes); + unsafe { self.pcie.write(addr, offset, value); } + Ok(len) + } + _ => Err(Error::new(EINVAL)), + } + } + + _ => Err(Error::new(EBADF)), + } + } } impl PciScheme { From cd5adcd848548f02f7858f85ef8ca9578f0ab8d6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Nov 2025 17:29:46 -0700 Subject: [PATCH 1282/1301] acpid: initialize aml on demand --- acpid/src/acpi.rs | 65 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 46 insertions(+), 19 deletions(-) diff --git a/acpid/src/acpi.rs b/acpid/src/acpi.rs index 90a106dc71..fc156fff96 100644 --- a/acpid/src/acpi.rs +++ b/acpid/src/acpi.rs @@ -1,6 +1,7 @@ use acpi::aml::object::{Object, WrappedObject}; use rustc_hash::FxHashMap; use std::convert::{TryFrom, TryInto}; +use std::error::Error; use std::ops::Deref; use std::str::FromStr; use std::sync::{Arc, Mutex}; @@ -238,7 +239,7 @@ pub struct Ssdt(Sdt); // must empty the cache so it is rebuilt. // If you modify an SDT, you must discard the aml_context and rebuild it. pub struct AmlSymbols { - aml_context: Interpreter, + aml_context: Option>, // k = name, v = description symbol_cache: FxHashMap, page_cache: Arc>, @@ -246,21 +247,39 @@ pub struct AmlSymbols { impl AmlSymbols { pub fn new() -> Self { - let page_cache = Arc::new(Mutex::new(AmlPageCache::default())); - let handler = AmlPhysMemHandler::new(Arc::clone(&page_cache)); - //TODO: use these parsed tables for the rest of acpid and return errors instead of unwrap - let rsdp_address = usize::from_str_radix(&std::env::var("RSDP_ADDR").unwrap(), 16).unwrap(); - let tables = unsafe { AcpiTables::from_rsdp(handler.clone(), rsdp_address).unwrap() }; - let platform = AcpiPlatform::new(tables, handler).unwrap(); Self { - aml_context: Interpreter::new_from_platform(&platform).unwrap(), + aml_context: None, symbol_cache: FxHashMap::default(), - page_cache, + page_cache: Arc::new(Mutex::new(AmlPageCache::default())), } } - pub fn mut_aml_context(&mut self) -> &mut Interpreter { - &mut self.aml_context + pub fn init(&mut self) -> Result<(), Box> { + if self.aml_context.is_some() { + return Err("AML interpreter already initialized".into()); + } + let format_err = |err| format!("{:?}", err); + let handler = AmlPhysMemHandler::new(Arc::clone(&self.page_cache)); + //TODO: use these parsed tables for the rest of acpid + let rsdp_address = usize::from_str_radix(&std::env::var("RSDP_ADDR")?, 16)?; + let tables = unsafe { AcpiTables::from_rsdp(handler.clone(), rsdp_address).map_err(format_err)? }; + let platform = AcpiPlatform::new(tables, handler).map_err(format_err)?; + let interpreter = Interpreter::new_from_platform(&platform).map_err(format_err)?; + self.aml_context = Some(interpreter); + Ok(()) + } + + pub fn aml_context_mut(&mut self) -> &mut Interpreter { + // PCID must be running by this time! + if self.aml_context.is_none() { + match self.init() { + Ok(()) => (), + Err(err) => { + log::error!("failed to initialize AML context: {}", err); + } + } + } + self.aml_context.as_mut().expect("AML context not initialized") } pub fn symbols_cache(&self) -> &FxHashMap { @@ -276,10 +295,11 @@ impl AmlSymbols { } pub fn build_cache(&mut self) { + let aml_context = self.aml_context_mut(); + let mut symbol_list: Vec<(AmlName, String)> = Vec::with_capacity(5000); - if self - .aml_context + if aml_context .namespace .lock() .traverse(|level_aml_name, level| { @@ -310,7 +330,7 @@ impl AmlSymbols { for (aml_name, name) in &symbol_list { // create an empty entry, in case something goes wrong with serialization symbol_cache.insert(name.to_owned(), "".to_owned()); - if let Some(ser_value) = AmlSerde::from_aml(&mut self.aml_context, aml_name) { + if let Some(ser_value) = AmlSerde::from_aml(aml_context, aml_name) { if let Ok(ser_string) = ron::ser::to_string_pretty(&ser_value, Default::default()) { // replace the empty entry symbol_cache.insert(name.to_owned(), ser_string); @@ -361,7 +381,8 @@ impl AcpiContext { symbol: AmlName, args: Vec, ) -> Result { - let interpreter = &mut self.aml_symbols.write().aml_context; + let mut symbols = self.aml_symbols.write(); + let interpreter = symbols.aml_context_mut(); interpreter.acquire_global_lock(16)?; let args = args @@ -549,10 +570,16 @@ impl AcpiContext { } }; - let s5 = match aml_symbols.aml_context.namespace.lock().get(s5_aml_name) { - Ok(s5) => s5, - Err(error) => { - log::error!("Cannot set S-state, missing \\_S5, {:?}", error); + let s5 = match &aml_symbols.aml_context { + Some(aml_context) => match aml_context.namespace.lock().get(s5_aml_name) { + Ok(s5) => s5, + Err(error) => { + log::error!("Cannot set S-state, missing \\_S5, {:?}", error); + return; + } + }, + None => { + log::error!("Cannot set S-state, AML context not initialized"); return; } }; From e114fd9bda8fcc54be687a98076a3dbcc7a7ebbd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Nov 2025 17:30:10 -0700 Subject: [PATCH 1283/1301] acpid: use pcid access file --- acpid/src/aml_physmem.rs | 84 +++++++++++++++++++++++++++++++++++----- 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/acpid/src/aml_physmem.rs b/acpid/src/aml_physmem.rs index 1b8c9c5a44..631c6f7583 100644 --- a/acpid/src/aml_physmem.rs +++ b/acpid/src/aml_physmem.rs @@ -140,13 +140,74 @@ impl AmlPageCache { #[derive(Clone)] pub struct AmlPhysMemHandler { page_cache: Arc>, + pci_fd: Arc>, } /// Read from a physical address. /// Generic parameter must be u8, u16, u32 or u64. impl AmlPhysMemHandler { pub fn new(page_cache: Arc>) -> Self { - Self { page_cache } + //TODO: have PCID send a socket? + let pci_fd = Arc::new( + match libredox::Fd::open( + "/scheme/pci/access", + libredox::flag::O_RDWR | libredox::flag::O_CLOEXEC, + 0 + ) { + Ok(fd) => Some(fd), + Err(err) => { + log::error!("failed to open /scheme/pci/access: {}", err); + None + } + } + ); + Self { page_cache, pci_fd } + } + + fn pci_call_metadata(kind: u8, addr: PciAddress, off: u16) -> [u64; 2] { + // Segment: u16, at 28 bits + // Bus: u8, 8 bits, 256 total, at 20 bits + // Device: u8, 5 bits, 32 total, at 15 bits + // Function: u8, 3 bits, 8 total, at 12 bits + // Offset: u16, 12 bits, 4096 total, at 0 bits + [ + kind.into(), + (u64::from(addr.segment()) << 28) | + (u64::from(addr.bus()) << 20) | + (u64::from(addr.device()) << 15) | + (u64::from(addr.function()) << 12) | + u64::from(off) + ] + } + + fn read_pci(&self, addr: PciAddress, off: u16, value: &mut [u8]) { + let metadata = Self::pci_call_metadata(1, addr, off); + match &*self.pci_fd { + Some(pci_fd) => match pci_fd.call_ro(value, syscall::CallFlags::empty(), &metadata) { + Ok(_) => {}, + Err(err) => { + log::error!("read pci {addr}@{off:04X}:{:02X}: {}", value.len(), err); + } + }, + None => { + log::error!("read pci {addr}@{off:04X}:{:02X}: pci access not available", value.len()); + } + } + } + + fn write_pci(&self, addr: PciAddress, off: u16, value: &[u8]) { + let metadata = Self::pci_call_metadata(2, addr, off); + match &*self.pci_fd { + Some(pci_fd) => match pci_fd.call_wo(value, syscall::CallFlags::empty(), &metadata) { + Ok(_) => {}, + Err(err) => { + log::error!("write pci {addr}@{off:04X}={value:02X?}: {}", err); + } + } + None => { + log::error!("write pci {addr}@{off:04X}={value:02X?}: pci access not available"); + } + } } } @@ -314,25 +375,28 @@ impl acpi::Handler for AmlPhysMemHandler { } fn read_pci_u8(&self, addr: PciAddress, off: u16) -> u8 { - log::error!("read pci u8 {addr}@{off:04X}"); - 0 + let mut value = [0u8]; + self.read_pci(addr, off, &mut value); + value[0] } fn read_pci_u16(&self, addr: PciAddress, off: u16) -> u16 { - log::error!("read pci u16 {addr}@{off:04X}"); - 0 + let mut value = [0u8; 2]; + self.read_pci(addr, off, &mut value); + u16::from_le_bytes(value) } fn read_pci_u32(&self, addr: PciAddress, off: u16) -> u32 { - log::error!("read pci u32 {addr}@{off:04X}"); - 0 + let mut value = [0u8; 4]; + self.read_pci(addr, off, &mut value); + u32::from_le_bytes(value) } fn write_pci_u8(&self, addr: PciAddress, off: u16, value: u8) { - log::error!("write pci u8 {addr}@{off:04X}={value:02X}"); + self.write_pci(addr, off, &[value]); } fn write_pci_u16(&self, addr: PciAddress, off: u16, value: u16) { - log::error!("write pci u16 {addr}@{off:04X}={value:04X}"); + self.write_pci(addr, off, &value.to_le_bytes()); } fn write_pci_u32(&self, addr: PciAddress, off: u16, value: u32) { - log::error!("write pci u32 {addr}@{off:04X}={value:08X}"); + self.write_pci(addr, off, &value.to_le_bytes()); } fn nanos_since_boot(&self) -> u64 { From 2ee3a846fb6d5c322ca7c19d248b9ac81c1923cd Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Nov 2025 17:30:37 -0700 Subject: [PATCH 1284/1301] acpid: do not enter null namespace (workaround for pci) --- acpid/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/acpid/src/main.rs b/acpid/src/main.rs index e344468a44..9628e0a7d3 100644 --- a/acpid/src/main.rs +++ b/acpid/src/main.rs @@ -75,7 +75,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { daemon.ready().expect("acpid: failed to notify parent"); - libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace"); + //TODO: needs to open /scheme/pci/access later! libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace"); event_queue .subscribe(shutdown_pipe.as_raw_fd() as usize, 0, EventFlags::READ) From ccd8d8f15861bc604a69a49b13d020f094163597 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Nov 2025 17:30:52 -0700 Subject: [PATCH 1285/1301] hwd: launch pcid after acpid but before probe --- hwd/src/main.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/hwd/src/main.rs b/hwd/src/main.rs index ed62b87e4d..afe85a1f45 100644 --- a/hwd/src/main.rs +++ b/hwd/src/main.rs @@ -1,3 +1,5 @@ +use std::process::Command; + mod backend; use self::backend::{AcpiBackend, Backend, DeviceTreeBackend, LegacyBackend}; @@ -33,6 +35,22 @@ fn main() { } }; + //TODO: launch pcid based on backend information? + // Must launch after acpid but before probe calls /scheme/acpi/symbols + match Command::new("pcid").spawn() { + Ok(mut child) => match child.wait() { + Ok(status) => if !status.success() { + log::error!("pcid exited with status {}", status); + }, + Err(err) => { + log::error!("failed to wait for pcid: {}", err); + } + }, + Err(err) => { + log::error!("failed to spawn pcid: {}", err); + } + } + //TODO: HWD is meant to locate PCI/XHCI/etc devices in ACPI and DeviceTree definitions and start their drivers match backend.probe() { Ok(()) => {} From 6d8d91ec85f21aa0790b9f7ee36cfa3a63c6134d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 22 Nov 2025 20:44:15 -0700 Subject: [PATCH 1286/1301] hwd: daemonize --- Cargo.lock | 1 + hwd/Cargo.toml | 1 + hwd/src/main.rs | 17 +++++++++++++---- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bb4deae74f..b414217d61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -641,6 +641,7 @@ dependencies = [ "common", "fdt 0.1.5", "log", + "redox-daemon", "ron", ] diff --git a/hwd/Cargo.toml b/hwd/Cargo.toml index b592f2da71..9089880e81 100644 --- a/hwd/Cargo.toml +++ b/hwd/Cargo.toml @@ -6,6 +6,7 @@ edition = "2018" [dependencies] fdt = "0.1.5" log = "0.4" +redox-daemon = "0.1" ron = "0.8.1" amlserde = { path = "../amlserde" } diff --git a/hwd/src/main.rs b/hwd/src/main.rs index afe85a1f45..b5dc4db127 100644 --- a/hwd/src/main.rs +++ b/hwd/src/main.rs @@ -1,9 +1,9 @@ -use std::process::Command; +use std::process; mod backend; use self::backend::{AcpiBackend, Backend, DeviceTreeBackend, LegacyBackend}; -fn main() { +fn daemon(daemon: redox_daemon::Daemon) -> ! { common::setup_logging( "misc", "hwd", @@ -37,7 +37,7 @@ fn main() { //TODO: launch pcid based on backend information? // Must launch after acpid but before probe calls /scheme/acpi/symbols - match Command::new("pcid").spawn() { + match process::Command::new("pcid").spawn() { Ok(mut child) => match child.wait() { Ok(status) => if !status.success() { log::error!("pcid exited with status {}", status); @@ -50,12 +50,21 @@ fn main() { log::error!("failed to spawn pcid: {}", err); } } + + daemon.ready().expect("hwd: failed to notify parent"); //TODO: HWD is meant to locate PCI/XHCI/etc devices in ACPI and DeviceTree definitions and start their drivers match backend.probe() { - Ok(()) => {} + Ok(()) => { + process::exit(0); + } Err(err) => { log::error!("failed to probe with error {}", err); + process::exit(1); } } } + +fn main() { + redox_daemon::Daemon::new(daemon).expect("hwd: failed to daemonize"); +} \ No newline at end of file From 6a11465e3e6c47a2bfa64040df90c8f65f404f02 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Nov 2025 08:08:11 -0700 Subject: [PATCH 1287/1301] pcid: allow unaligned access --- pcid/src/scheme.rs | 49 ++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/pcid/src/scheme.rs b/pcid/src/scheme.rs index bb92f6563d..2c6fb65d19 100644 --- a/pcid/src/scheme.rs +++ b/pcid/src/scheme.rs @@ -212,6 +212,12 @@ impl SchemeSync for PciScheme { match handle.inner { Handle::Access => { + let payload_len = u16::try_from(payload.len()).map_err(|_| Error::new(EINVAL))?; + let write = match metadata.get(0) { + Some(1) => false, + Some(2) => true, + _ => return Err(Error::new(EINVAL)), + }; let (addr, offset) = match metadata.get(1) { Some(value) => { // Segment: u16, at 28 bits @@ -231,31 +237,32 @@ impl SchemeSync for PciScheme { } None => return Err(Error::new(EINVAL)), }; - match metadata.get(0) { - Some(1) => { - // Read - let value = unsafe { self.pcie.read(addr, offset) }; - let bytes = value.to_le_bytes(); - let len = payload.len().min(bytes.len()); - payload.copy_from_slice(&bytes[..len]); - Ok(len) + // This handle must allow less than 4 byte access, but the + // lower level only works with 4 byte reads and writes + let unaligned = offset % 4; + let start = offset - unaligned; + let end = offset + payload_len; + let mut i = 0; + while start + i < end { + let mut bytes = unsafe { self.pcie.read(addr, start + i) }.to_le_bytes(); + for j in 0..bytes.len() { + if let Some(payload_i) = i.checked_sub(unaligned) { + if let Some(payload_b) = payload.get_mut(usize::from(payload_i)) { + if write { + bytes[j] = *payload_b; + } else { + *payload_b = bytes[j] + } + } + } + i += 1; } - Some(2) => { - // Write - let len = payload.len().min(4); - let mut bytes = if len < 4 { - //TODO: any way to do less than dword writes? - unsafe { self.pcie.read(addr, offset).to_le_bytes() } - } else { - [0; 4] - }; - bytes[..len].copy_from_slice(&payload); + if write { let value = u32::from_le_bytes(bytes); - unsafe { self.pcie.write(addr, offset, value); } - Ok(len) + unsafe { self.pcie.write(addr, start + i, value); } } - _ => Err(Error::new(EINVAL)), } + Ok(payload.len()) } _ => Err(Error::new(EBADF)), From e3d5abdaa1bf3d1d5e90235acf4a62aac80a4cef Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Nov 2025 08:14:58 -0700 Subject: [PATCH 1288/1301] pcid: also scan bus 0x80 by default for Arrow Lake --- pcid/src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 50ffd4b6ec..e377b64bb3 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -210,7 +210,9 @@ fn main_inner(daemon: redox_daemon::Daemon) -> ! { // FIXME Use full ACPI for enumerating the host bridges. MCFG only describes the first // host bridge, while multi-processor systems likely have a host bridge for each CPU. // See also https://www.kernel.org/doc/html/latest/PCI/acpi-info.html - let mut bus_nums = vec![0]; + // Bus 0x80 is scanned for compatibility with newer (Arrow Lake) Intel CPUs where PCH devices + // are there. This workaround may not be required if we had ACPI bus enumeration. + let mut bus_nums = vec![0, 0x80]; let mut bus_i = 0; while bus_i < bus_nums.len() { let bus_num = bus_nums[bus_i]; From dd41c4f13e9135a9819c082e88b06dc1a15426c8 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 23 Nov 2025 09:23:09 -0700 Subject: [PATCH 1289/1301] net: scheme created and daemon ready before device init --- Cargo.lock | 1 + net/driver-network/Cargo.toml | 1 + net/driver-network/src/lib.rs | 9 +++++++-- net/e1000d/src/device.rs | 7 ++++++- net/e1000d/src/main.rs | 15 +++++++-------- net/ixgbed/src/main.rs | 16 ++++++++-------- net/rtl8139d/src/device.rs | 7 ++++++- net/rtl8139d/src/main.rs | 15 +++++++-------- net/rtl8168d/src/device.rs | 7 ++++++- net/rtl8168d/src/main.rs | 15 +++++++-------- net/virtio-netd/src/main.rs | 11 ++++++++--- 11 files changed, 64 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b414217d61..c10dbb4064 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -397,6 +397,7 @@ name = "driver-network" version = "0.1.0" dependencies = [ "libredox", + "redox-daemon", "redox-scheme 0.4.0", "redox_syscall", ] diff --git a/net/driver-network/Cargo.toml b/net/driver-network/Cargo.toml index 665df4f60e..8220537c1b 100644 --- a/net/driver-network/Cargo.toml +++ b/net/driver-network/Cargo.toml @@ -5,5 +5,6 @@ edition = "2021" [dependencies] libredox = "0.1.3" +redox-daemon = "0.1" redox-scheme = "0.4" redox_syscall = { version = "0.5", features = ["std"] } diff --git a/net/driver-network/src/lib.rs b/net/driver-network/src/lib.rs index 339a195cc9..eadaaa0289 100644 --- a/net/driver-network/src/lib.rs +++ b/net/driver-network/src/lib.rs @@ -45,10 +45,15 @@ enum Handle { } impl NetworkScheme { - pub fn new(adapter: T, scheme_name: String) -> Self { + pub fn new( + adapter_fn: impl FnOnce() -> T, + daemon: redox_daemon::Daemon, + scheme_name: String, + ) -> Self { assert!(scheme_name.starts_with("network")); let socket = Socket::nonblock(&scheme_name).expect("failed to create network scheme"); - + daemon.ready().expect("failed to mark daemon as ready"); + let adapter = adapter_fn(); NetworkScheme { adapter, scheme_name, diff --git a/net/e1000d/src/device.rs b/net/e1000d/src/device.rs index b980e5b10c..4c518f30fc 100644 --- a/net/e1000d/src/device.rs +++ b/net/e1000d/src/device.rs @@ -289,7 +289,12 @@ impl Intel8254x { ]; log::debug!( "MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + mac[0], + mac[1], + mac[2], + mac[3], + mac[4], + mac[5] ); self.mac_address = mac; diff --git a/net/e1000d/src/main.rs b/net/e1000d/src/main.rs index 44c0282390..b7601d17fd 100644 --- a/net/e1000d/src/main.rs +++ b/net/e1000d/src/main.rs @@ -34,10 +34,13 @@ fn main() { let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; - let device = - unsafe { device::Intel8254x::new(address).expect("e1000d: failed to allocate device") }; - - let mut scheme = NetworkScheme::new(device, format!("network.{name}")); + let mut scheme = NetworkScheme::new( + move || unsafe { + device::Intel8254x::new(address).expect("e1000d: failed to allocate device") + }, + daemon, + format!("network.{name}"), + ); user_data! { enum Source { @@ -66,10 +69,6 @@ fn main() { libredox::call::setrens(0, 0).expect("e1000d: failed to enter null namespace"); - daemon - .ready() - .expect("e1000d: failed to mark daemon as ready"); - scheme.tick().unwrap(); for event in event_queue.map(|e| e.expect("e1000d: failed to get event")) { diff --git a/net/ixgbed/src/main.rs b/net/ixgbed/src/main.rs index c6ea98600f..c1aa533572 100644 --- a/net/ixgbed/src/main.rs +++ b/net/ixgbed/src/main.rs @@ -30,10 +30,14 @@ fn main() { let address = mapped_bar.ptr.as_ptr(); let size = mapped_bar.bar_size; - let device = device::Intel8259x::new(address as usize, size) - .expect("ixgbed: failed to allocate device"); - - let mut scheme = NetworkScheme::new(device, format!("network.{name}")); + let mut scheme = NetworkScheme::new( + move || { + device::Intel8259x::new(address as usize, size) + .expect("ixgbed: failed to allocate device") + }, + daemon, + format!("network.{name}"), + ); user_data! { enum Source { @@ -61,10 +65,6 @@ fn main() { libredox::call::setrens(0, 0).expect("ixgbed: failed to enter null namespace"); - daemon - .ready() - .expect("ixgbed: failed to mark daemon as ready"); - scheme.tick().unwrap(); for event in event_queue.map(|e| e.expect("ixgbed: failed to get next event")) { diff --git a/net/rtl8139d/src/device.rs b/net/rtl8139d/src/device.rs index cfab18833f..1245d864f6 100644 --- a/net/rtl8139d/src/device.rs +++ b/net/rtl8139d/src/device.rs @@ -266,7 +266,12 @@ impl Rtl8139 { ]; log::debug!( "MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + mac[0], + mac[1], + mac[2], + mac[3], + mac[4], + mac[5] ); self.mac_address = mac; diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 891c888912..97dc7921e8 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -124,10 +124,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); - let device = - unsafe { device::Rtl8139::new(bar as usize).expect("rtl8139d: failed to allocate device") }; - - let mut scheme = NetworkScheme::new(device, format!("network.{name}")); + let mut scheme = NetworkScheme::new( + move || unsafe { + device::Rtl8139::new(bar as usize).expect("rtl8139d: failed to allocate device") + }, + daemon, + format!("network.{name}"), + ); user_data! { enum Source { @@ -154,10 +157,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { libredox::call::setrens(0, 0).expect("rtl8139d: failed to enter null namespace"); - daemon - .ready() - .expect("rtl8139d: failed to mark daemon as ready"); - scheme.tick().unwrap(); for event in event_queue.map(|e| e.expect("rtl8139d: failed to get next event")) { diff --git a/net/rtl8168d/src/device.rs b/net/rtl8168d/src/device.rs index c6cf616607..fe6d7f5ebd 100644 --- a/net/rtl8168d/src/device.rs +++ b/net/rtl8168d/src/device.rs @@ -233,7 +233,12 @@ impl Rtl8168 { ]; log::debug!( "MAC: {:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}:{:>02X}", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5] + mac[0], + mac[1], + mac[2], + mac[3], + mac[4], + mac[5] ); self.mac_address = mac; diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index 8c009822ee..c394f1c70e 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -124,10 +124,13 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { //TODO: MSI-X let mut irq_file = get_int_method(&mut pcid_handle); - let device = - unsafe { device::Rtl8168::new(bar as usize).expect("rtl8168d: failed to allocate device") }; - - let mut scheme = NetworkScheme::new(device, format!("network.{name}")); + let mut scheme = NetworkScheme::new( + move || unsafe { + device::Rtl8168::new(bar as usize).expect("rtl8168d: failed to allocate device") + }, + daemon, + format!("network.{name}"), + ); user_data! { enum Source { @@ -154,10 +157,6 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { libredox::call::setrens(0, 0).expect("rtl8168d: failed to enter null namespace"); - daemon - .ready() - .expect("rtl8168d: failed to mark daemon as ready"); - scheme.tick().unwrap(); for event in event_queue.map(|e| e.expect("rtl8168d: failed to get next event")) { diff --git a/net/virtio-netd/src/main.rs b/net/virtio-netd/src/main.rs index f566a7d82e..3ee723a5de 100644 --- a/net/virtio-netd/src/main.rs +++ b/net/virtio-netd/src/main.rs @@ -93,7 +93,14 @@ fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box name.push_str("_virtio_net"); let device = VirtioNet::new(mac_address, rx_queue, tx_queue); - let mut scheme = NetworkScheme::new(device, format!("network.{name}")); + let mut scheme = NetworkScheme::new( + move || { + //TODO: do device init in this function to prevent hangs + device + }, + daemon, + format!("network.{name}"), + ); let mut event_queue = File::open("/scheme/event")?; event_queue.write(&syscall::Event { @@ -104,8 +111,6 @@ fn deamon(daemon: redox_daemon::Daemon) -> Result<(), Box libredox::call::setrens(0, 0).expect("virtio-netd: failed to enter null namespace"); - daemon.ready().expect("virtio-netd: failed to daemonize"); - scheme.tick()?; loop { From d07a33ec0b4ce14e23d9aed2c5ecb015ac4b993b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 26 Nov 2025 09:30:45 -0700 Subject: [PATCH 1290/1301] Add timeouts to more driver spin loops --- common/src/lib.rs | 2 ++ common/src/timeout.rs | 45 ++++++++++++++++++++++++++++++++ input/ps2d/src/controller.rs | 32 +++-------------------- net/rtl8139d/src/device.rs | 17 +++++++----- net/rtl8168d/src/device.rs | 22 +++++++++------- storage/ahcid/src/ahci/hba.rs | 40 +++++++++++++--------------- storage/nvmed/src/main.rs | 2 +- storage/nvmed/src/nvme/mod.rs | 49 +++++++++++++++++++++++------------ 8 files changed, 125 insertions(+), 84 deletions(-) create mode 100644 common/src/timeout.rs diff --git a/common/src/lib.rs b/common/src/lib.rs index 1966d5b05a..275caec413 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -16,6 +16,8 @@ pub mod io; mod logger; /// The Scatter Gather List (SGL) API for drivers. pub mod sgl; +/// Low latency timeout for driver loops +pub mod timeout; pub use logger::{output_level, file_level, setup_logging}; diff --git a/common/src/timeout.rs b/common/src/timeout.rs new file mode 100644 index 0000000000..ec226d1629 --- /dev/null +++ b/common/src/timeout.rs @@ -0,0 +1,45 @@ +use std::{thread, time::{Duration, Instant}}; + +pub struct Timeout { + instant: Instant, + duration: Duration, +} + +impl Timeout { + #[inline] + pub fn new(duration: Duration) -> Self { + Self { + instant: Instant::now(), + duration, + } + } + + #[inline] + pub fn from_micros(micros: u64) -> Self { + Self::new(Duration::from_micros(micros)) + } + + #[inline] + pub fn from_millis(millis: u64) -> Self { + Self::new(Duration::from_millis(millis)) + } + + #[inline] + pub fn from_secs(secs: u64) -> Self { + Self::new(Duration::from_secs(secs)) + } + + #[inline] + pub fn run(&self) -> Result<(), ()> { + if self.instant.elapsed() < self.duration { + // Sleeps in Redox are only evaluated on PIT ticks (a few ms), which is not + // short enough for a reasonably responsive timeout. However, the clock is + // highly accurate. So, we yield instead of sleep to reduce latency. + //TODO: allow timeout that spins instead of yields? + std::thread::yield_now(); + Ok(()) + } else { + Err(()) + } + } +} \ No newline at end of file diff --git a/input/ps2d/src/controller.rs b/input/ps2d/src/controller.rs index fbbbf75cb0..7a58f3de3a 100644 --- a/input/ps2d/src/controller.rs +++ b/input/ps2d/src/controller.rs @@ -1,4 +1,4 @@ -use common::io::{Io, Pio, ReadOnly, WriteOnly}; +use common::{io::{Io, Pio, ReadOnly, WriteOnly}, timeout::Timeout}; use log::{debug, error, info, trace}; use std::{ @@ -103,32 +103,6 @@ const DEFAULT_TIMEOUT: u64 = 50_000; // Reset timeout in microseconds const RESET_TIMEOUT: u64 = 500_000; -struct Timeout { - instant: Instant, - duration: Duration, -} - -impl Timeout { - fn new(micros: u64) -> Self { - Self { - instant: Instant::now(), - duration: Duration::from_micros(micros), - } - } - - fn run(&self) -> Result<(), ()> { - if self.instant.elapsed() < self.duration { - // Sleeps in Redox are only evaluated on PIT ticks (a few ms), which is not - // short enough for a reasonably responsive timeout. However, the clock is - // highly accurate. So, we yield instead of sleep to reduce latency. - thread::yield_now(); - Ok(()) - } else { - Err(()) - } - } -} - pub struct Ps2 { data: Pio, status: ReadOnly>, @@ -149,7 +123,7 @@ impl Ps2 { } fn wait_read(&mut self, micros: u64) -> Result<(), Error> { - let timeout = Timeout::new(micros); + let timeout = Timeout::from_micros(micros); loop { if self.status().contains(StatusFlags::OUTPUT_FULL) { return Ok(()); @@ -159,7 +133,7 @@ impl Ps2 { } fn wait_write(&mut self, micros: u64) -> Result<(), Error> { - let timeout = Timeout::new(micros); + let timeout = Timeout::from_micros(micros); loop { if !self.status().contains(StatusFlags::INPUT_FULL) { return Ok(()); diff --git a/net/rtl8139d/src/device.rs b/net/rtl8139d/src/device.rs index 1245d864f6..37167ee2fb 100644 --- a/net/rtl8139d/src/device.rs +++ b/net/rtl8139d/src/device.rs @@ -6,6 +6,7 @@ use syscall::error::{Error, Result, EIO, EMSGSIZE}; use common::dma::Dma; use common::io::{Io, Mmio, ReadOnly}; +use common::timeout::Timeout; const RX_BUFFER_SIZE: usize = 64 * 1024; @@ -219,7 +220,7 @@ impl Rtl8139 { mac_address: [0; 6], }; - module.init(); + module.init()?; Ok(module) } @@ -253,7 +254,7 @@ impl Rtl8139 { } } - pub unsafe fn init(&mut self) { + pub unsafe fn init(&mut self) -> Result<()> { let mac_low = self.regs.mac[0].read(); let mac_high = self.regs.mac[1].read(); let mac = [ @@ -276,10 +277,13 @@ impl Rtl8139 { self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value - log::debug!("Reset"); - self.regs.cr.writef(CR_RST, true); - while self.regs.cr.readf(CR_RST) { - core::hint::spin_loop(); + { + log::debug!("Reset"); + let timeout = Timeout::from_secs(1); + self.regs.cr.writef(CR_RST, true); + while self.regs.cr.readf(CR_RST) { + timeout.run().map_err(|()| Error::new(EIO))?; + } } // Set up rx buffer @@ -300,5 +304,6 @@ impl Rtl8139 { self.regs.cr.writef(CR_RE | CR_TE, true); log::debug!("Complete!"); + Ok(()) } } diff --git a/net/rtl8168d/src/device.rs b/net/rtl8168d/src/device.rs index fe6d7f5ebd..ce0675877a 100644 --- a/net/rtl8168d/src/device.rs +++ b/net/rtl8168d/src/device.rs @@ -1,11 +1,11 @@ use std::convert::TryInto; use std::mem; -use common::io::{Io, Mmio, ReadOnly}; -use driver_network::NetworkAdapter; -use syscall::error::{Error, Result, EMSGSIZE}; - use common::dma::Dma; +use common::io::{Io, Mmio, ReadOnly}; +use common::timeout::Timeout; +use driver_network::NetworkAdapter; +use syscall::error::{Error, Result, EIO, EMSGSIZE}; #[repr(C, packed)] struct Regs { @@ -220,7 +220,7 @@ impl Rtl8168 { } } - pub unsafe fn init(&mut self) { + pub unsafe fn init(&mut self) -> Result<()> { let mac_low = self.regs.mac[0].read(); let mac_high = self.regs.mac[1].read(); let mac = [ @@ -243,10 +243,13 @@ impl Rtl8168 { self.mac_address = mac; // Reset - this will disable tx and rx, reinitialize FIFOs, and set the system buffer pointer to the initial value - log::debug!("Reset"); - self.regs.cmd.writef(1 << 4, true); - while self.regs.cmd.readf(1 << 4) { - core::hint::spin_loop(); + { + log::debug!("Reset"); + let timeout = Timeout::from_secs(1); + self.regs.cmd.writef(1 << 4, true); + while self.regs.cmd.readf(1 << 4) { + timeout.run().map_err(|()| Error::new(EIO))?; + } } // Set up rx buffers @@ -337,5 +340,6 @@ impl Rtl8168 { self.regs.cmd_9346.write(0); log::debug!("Complete!"); + Ok(()) } } diff --git a/storage/ahcid/src/ahci/hba.rs b/storage/ahcid/src/ahci/hba.rs index 1e788dc912..af7232762b 100644 --- a/storage/ahcid/src/ahci/hba.rs +++ b/storage/ahcid/src/ahci/hba.rs @@ -4,13 +4,13 @@ use std::ops::DerefMut; use std::time::{Duration, Instant}; use std::{ptr, u32}; +use common::dma::Dma; use common::io::{Io, Mmio}; +use common::timeout::Timeout; use syscall::error::{Error, Result, EIO}; use super::fis::{FisRegH2D, FisType}; -use common::dma::Dma; - const ATA_CMD_READ_DMA_EXT: u8 = 0x25; const ATA_CMD_WRITE_DMA_EXT: u8 = 0x35; const ATA_CMD_IDENTIFY: u8 = 0xEC; @@ -80,13 +80,12 @@ impl HbaPort { } pub fn start(&mut self) -> Result<()> { - let timer = Instant::now(); + let timeout = Timeout::new(TIMEOUT); while self.cmd.readf(HBA_PORT_CMD_CR) { - core::hint::spin_loop(); - if timer.elapsed() >= TIMEOUT { + timeout.run().map_err(|()| { log::error!("HBA start timed out"); - return Err(Error::new(EIO)); - } + Error::new(EIO) + })?; } self.cmd.writef(HBA_PORT_CMD_FRE | HBA_PORT_CMD_ST, true); @@ -96,13 +95,12 @@ impl HbaPort { pub fn stop(&mut self) -> Result<()> { self.cmd.writef(HBA_PORT_CMD_ST, false); - let timer = Instant::now(); + let timeout = Timeout::new(TIMEOUT); while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) { - core::hint::spin_loop(); - if timer.elapsed() >= TIMEOUT { + timeout.run().map_err(|()| { log::error!("HBA stop timed out"); - return Err(Error::new(EIO)); - } + Error::new(EIO) + })?; } self.cmd.writef(HBA_PORT_CMD_FRE, false); @@ -404,13 +402,12 @@ impl HbaPort { callback(cmdheader, cmdfis, prdt_entry, acmd) } - let timer = Instant::now(); + let timeout = Timeout::new(TIMEOUT); while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) { - core::hint::spin_loop(); - if timer.elapsed() >= TIMEOUT { + timeout.run().map_err(|()| { log::error!("HBA ata_start timeout"); - return Err(Error::new(EIO)); - } + Error::new(EIO) + })?; } self.ci.writef(1 << slot, true); @@ -426,13 +423,12 @@ impl HbaPort { } pub fn ata_stop(&mut self, slot: u32) -> Result<()> { - let timer = Instant::now(); + let timeout = Timeout::new(TIMEOUT); while self.ata_running(slot) { - core::hint::spin_loop(); - if timer.elapsed() >= TIMEOUT { + timeout.run().map_err(|()| { log::error!("HBA ata_stop timeout"); - return Err(Error::new(EIO)); - } + Error::new(EIO) + })?; } self.stop()?; diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index 6112756c76..ed83b7809c 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -169,7 +169,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut nvme = Nvme::new(address.as_ptr() as usize, interrupt_method, pcid_handle) .expect("nvmed: failed to allocate driver data"); - unsafe { nvme.init() } + unsafe { nvme.init().expect("nvmed: failed to init") } log::debug!("Finished base initialization"); let nvme = Arc::new(nvme); diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index b10369e2cd..faa6ab4ee0 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use parking_lot::{Mutex, ReentrantMutex, RwLock}; use common::io::{Io, Mmio}; +use common::timeout::Timeout; use syscall::error::{Error, Result, EIO}; use common::dma::Dma; @@ -190,7 +191,7 @@ impl Nvme { self.doorbell_write(2 * (qid as usize) + 1, u32::from(head)); } - pub unsafe fn init(&mut self) { + pub unsafe fn init(&mut self) -> Result<()> { let thread_ctxts = self.thread_ctxts.get_mut(); { let regs = self.regs.read(); @@ -204,14 +205,20 @@ impl Nvme { log::debug!("Disabling controller."); self.regs.get_mut().cc.writef(1, false); - log::trace!("Waiting for not ready."); - loop { - let csts = self.regs.get_mut().csts.read(); - log::trace!("CSTS: {:X}", csts); - if csts & 1 == 1 { - std::hint::spin_loop(); - } else { - break; + { + log::trace!("Waiting for not ready."); + let mut timeout = Timeout::from_secs(5); + loop { + let csts = self.regs.get_mut().csts.read(); + log::trace!("CSTS: {:X}", csts); + if csts & 1 == 1 { + timeout.run().map_err(|()| { + log::error!("failed to wait for not ready"); + Error::new(EIO) + })?; + } else { + break; + } } } @@ -269,16 +276,24 @@ impl Nvme { log::debug!("Enabling controller."); self.regs.get_mut().cc.writef(1, true); - log::debug!("Waiting for ready"); - loop { - let csts = self.regs.get_mut().csts.read(); - log::debug!("CSTS: {:X}", csts); - if csts & 1 == 0 { - std::hint::spin_loop(); - } else { - break; + { + log::debug!("Waiting for ready"); + let mut timeout = Timeout::from_secs(5); + loop { + let csts = self.regs.get_mut().csts.read(); + log::debug!("CSTS: {:X}", csts); + if csts & 1 == 0 { + timeout.run().map_err(|()| { + log::error!("failed to wait for ready"); + Error::new(EIO) + })?; + } else { + break; + } } } + + Ok(()) } /// Masks or unmasks multiple vectors. From 84d43ecbf318e83db0c45cb9395edbff78dff3cc Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 26 Nov 2025 09:53:25 -0700 Subject: [PATCH 1291/1301] Add timeouts to ihdad, reduce nvmed timeouts --- audio/ihdad/src/hda/device.rs | 45 +++++++++++++++++++++++------------ storage/nvmed/src/nvme/mod.rs | 4 ++-- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/audio/ihdad/src/hda/device.rs b/audio/ihdad/src/hda/device.rs index f3ae108e61..9bbd3c8226 100755 --- a/audio/ihdad/src/hda/device.rs +++ b/audio/ihdad/src/hda/device.rs @@ -11,7 +11,8 @@ use std::time::Duration; use common::dma::Dma; use common::io::{Io, Mmio}; -use syscall::error::{Error, Result, EACCES, EBADF, EINVAL}; +use common::timeout::Timeout; +use syscall::error::{Error, Result, EACCES, EBADF, EIO, EINVAL}; use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET}; use syscall::scheme::SchemeBlockMut; @@ -203,7 +204,7 @@ impl IntelHDA { next_id: AtomicUsize::new(0), }; - module.init(); + module.init()?; module.info(); module.enumerate(); @@ -213,8 +214,8 @@ impl IntelHDA { Ok(module) } - pub fn init(&mut self) -> bool { - self.reset_controller(); + pub fn init(&mut self) -> Result<()> { + self.reset_controller()?; let use_immediate_command_interface = match self.vend_prod { 0x8086_2668 => false, @@ -224,7 +225,7 @@ impl IntelHDA { self.cmd.init(use_immediate_command_interface); self.init_interrupts(); - true + Ok(()) } pub fn init_interrupts(&mut self) { @@ -652,25 +653,39 @@ impl IntelHDA { } } - pub fn reset_controller(&mut self) -> bool { + pub fn reset_controller(&mut self) -> Result<()> { self.cmd.stop(); self.regs.statests.write(0x7FFF); // 3.3.7 - self.regs.gctl.writef(CRST, false); - loop { - if !self.regs.gctl.readf(CRST) { - break; + { + let timeout = Timeout::from_secs(1); + self.regs.gctl.writef(CRST, false); + loop { + if !self.regs.gctl.readf(CRST) { + break; + } + timeout.run().map_err(|()| { + log::error!("failed to start reset"); + Error::new(EIO) + })?; } } thread::sleep(Duration::from_millis(1)); - self.regs.gctl.writef(CRST, true); - loop { - if self.regs.gctl.readf(CRST) { - break; + { + let timeout = Timeout::from_secs(1); + self.regs.gctl.writef(CRST, true); + loop { + if self.regs.gctl.readf(CRST) { + break; + } + timeout.run().map_err(|()| { + log::error!("failed to finish reset"); + Error::new(EIO) + })?; } } @@ -692,7 +707,7 @@ impl IntelHDA { self.codecs.push(i as CodecAddr); } } - true + Ok(()) } pub fn num_output_streams(&self) -> usize { diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index faa6ab4ee0..e7050392ec 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -207,7 +207,7 @@ impl Nvme { { log::trace!("Waiting for not ready."); - let mut timeout = Timeout::from_secs(5); + let timeout = Timeout::from_secs(1); loop { let csts = self.regs.get_mut().csts.read(); log::trace!("CSTS: {:X}", csts); @@ -278,7 +278,7 @@ impl Nvme { { log::debug!("Waiting for ready"); - let mut timeout = Timeout::from_secs(5); + let timeout = Timeout::from_secs(1); loop { let csts = self.regs.get_mut().csts.read(); log::debug!("CSTS: {:X}", csts); From 8ca163d57509217efdc336d46a799bde41873fd7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 26 Nov 2025 17:30:03 -0700 Subject: [PATCH 1292/1301] ihdad: add many more timeouts and error handling --- audio/ihdad/src/hda/cmdbuff.rs | 162 +++++++++++++++++++++++---------- audio/ihdad/src/hda/device.rs | 146 ++++++++++++++--------------- 2 files changed, 190 insertions(+), 118 deletions(-) diff --git a/audio/ihdad/src/hda/cmdbuff.rs b/audio/ihdad/src/hda/cmdbuff.rs index 6ada5f43c8..f968f0dcce 100644 --- a/audio/ihdad/src/hda/cmdbuff.rs +++ b/audio/ihdad/src/hda/cmdbuff.rs @@ -1,5 +1,7 @@ use common::dma::Dma; use common::io::{Io, Mmio}; +use common::timeout::Timeout; +use syscall::error::{Error, Result, EIO}; use super::common::*; @@ -85,8 +87,8 @@ impl Corb { } //Intel 4.4.1.3 - pub fn init(&mut self) { - self.stop(); + pub fn init(&mut self) -> Result<()> { + self.stop()?; //Determine CORB and RIRB size and allocate buffer //3.3.24 @@ -118,9 +120,11 @@ impl Corb { self.set_address(addr); self.regs.corbsize.write((corbsize_reg & 0xFC) | corbsize); - self.reset_read_pointer(); + self.reset_read_pointer()?; let old_wp = self.regs.corbwp.read(); self.regs.corbwp.write(old_wp & 0xFF00); + + Ok(()) } pub fn start(&mut self) { @@ -128,10 +132,16 @@ impl Corb { } #[inline(never)] - pub fn stop(&mut self) { + pub fn stop(&mut self) -> Result<()> { + let timeout = Timeout::from_secs(1); while self.regs.corbctl.readf(CORBRUN) { self.regs.corbctl.writef(CORBRUN, false); + timeout.run().map_err(|()| { + log::error!("timeout on clearing CORBRUN"); + Error::new(EIO) + })?; } + Ok(()) } pub fn set_address(&mut self, addr: usize) { @@ -139,36 +149,60 @@ impl Corb { self.regs.corbubase.write(((addr as u64) >> 32) as u32); } - pub fn reset_read_pointer(&mut self) { + pub fn reset_read_pointer(&mut self) -> Result<()> { // 3.3.21 - self.stop(); + self.stop()?; // Set CORBRPRST to 1 log::trace!("CORBRP {:X}", self.regs.corbrp.read()); self.regs.corbrp.writef(CORBRPRST, true); log::trace!("CORBRP {:X}", self.regs.corbrp.read()); - // Wait for it to become 1 - while !self.regs.corbrp.readf(CORBRPRST) { - self.regs.corbrp.writef(CORBRPRST, true); + { + // Wait for it to become 1 + let timeout = Timeout::from_secs(1); + while !self.regs.corbrp.readf(CORBRPRST) { + self.regs.corbrp.writef(CORBRPRST, true); + timeout.run().map_err(|()| { + log::error!("timeout on setting CORBRPRST"); + Error::new(EIO) + })?; + } } // Clear the bit again self.regs.corbrp.writef(CORBRPRST, false); - // Read back the bit until zero to verify that it is cleared. - loop { - if !self.regs.corbrp.readf(CORBRPRST) { - break; + { + // Read back the bit until zero to verify that it is cleared. + let timeout = Timeout::from_secs(1); + loop { + if !self.regs.corbrp.readf(CORBRPRST) { + break; + } + self.regs.corbrp.writef(CORBRPRST, false); + timeout.run().map_err(|()| { + log::error!("timeout on clearing CORBRPRST"); + Error::new(EIO) + })?; } - self.regs.corbrp.writef(CORBRPRST, false); } + + Ok(()) } - fn send_command(&mut self, cmd: u32) { - // wait for the commands to finish - while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) {} + fn send_command(&mut self, cmd: u32) -> Result<()> { + { + // wait for the commands to finish + let timeout = Timeout::from_secs(1); + while (self.regs.corbwp.read() & 0xff) != (self.regs.corbrp.read() & 0xff) { + timeout.run().map_err(|()| { + log::error!("timeout on CORB command"); + Error::new(EIO) + })?; + } + } let write_pos: usize = ((self.regs.corbwp.read() as usize & 0xFF) + 1) % self.corb_count; unsafe { *self.corb_base.offset(write_pos as isize) = cmd; @@ -177,6 +211,7 @@ impl Corb { self.regs.corbwp.write(write_pos as u16); log::trace!("Corb: {:08X}", cmd); + Ok(()) } } @@ -212,8 +247,8 @@ impl Rirb { } } //Intel 4.4.1.3 - pub fn init(&mut self) { - self.stop(); + pub fn init(&mut self) -> Result<()> { + self.stop()?; let rirbsize_reg = self.regs.rirbsize.read(); let rirbszcap = (rirbsize_reg >> 4) & 0xF; @@ -247,16 +282,24 @@ impl Rirb { self.rirb_rp = 0; self.regs.rintcnt.write(1); + + Ok(()) } pub fn start(&mut self) { self.regs.rirbctl.writef(RIRBDMAEN | RINTCTL, true); } - pub fn stop(&mut self) { + pub fn stop(&mut self) -> Result<()> { + let timeout = Timeout::from_secs(1); while self.regs.rirbctl.readf(RIRBDMAEN) { self.regs.rirbctl.writef(RIRBDMAEN, false); + timeout.run().map_err(|()| { + log::error!("timeout on clearing RIRBDMAEN"); + Error::new(EIO) + })?; } + Ok(()) } pub fn set_address(&mut self, addr: usize) { @@ -268,9 +311,17 @@ impl Rirb { self.regs.rirbwp.writef(RIRBWPRST, true); } - fn read_response(&mut self) -> u64 { - // wait for response - while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) {} + fn read_response(&mut self) -> Result { + { + // wait for response + let timeout = Timeout::from_secs(1); + while (self.regs.rirbwp.read() & 0xff) == (self.rirb_rp & 0xff) { + timeout.run().map_err(|()| { + log::error!("timeout on RIRB response"); + Error::new(EIO) + })?; + } + } let read_pos: u16 = (self.rirb_rp + 1) % self.rirb_count as u16; let res: u64; @@ -279,7 +330,7 @@ impl Rirb { } self.rirb_rp = read_pos; log::trace!("Rirb: {:08X}", res); - res + Ok(res) } } @@ -303,9 +354,17 @@ impl ImmediateCommand { } } - pub fn cmd(&mut self, cmd: u32) -> u64 { - // wait for ready - while self.regs.ics.readf(ICB) {} + pub fn cmd(&mut self, cmd: u32) -> Result { + { + // wait for ready + let timeout = Timeout::from_secs(1); + while self.regs.ics.readf(ICB) { + timeout.run().map_err(|()| { + log::error!("timeout on immediate command"); + Error::new(EIO) + })?; + } + } // write command self.regs.icoi.write(cmd); @@ -313,8 +372,16 @@ impl ImmediateCommand { // set ICB bit to send command self.regs.ics.writef(ICB, true); - // wait for IRV bit to be set to indicate a response is latched - while !self.regs.ics.readf(IRV) {} + { + // wait for IRV bit to be set to indicate a response is latched + let timeout = Timeout::from_secs(1); + while !self.regs.ics.readf(IRV) { + timeout.run().map_err(|()| { + log::error!("timeout on immediate response"); + Error::new(EIO) + })?; + } + } // read the result register twice, total of 8 bytes // highest 4 will most likely be zeros (so I've heard) @@ -324,7 +391,7 @@ impl ImmediateCommand { // clear the bit so we know when the next response comes self.regs.ics.writef(IRV, false); - res + Ok(res) } } @@ -370,18 +437,20 @@ impl CommandBuffer { cmdbuff } - pub fn init(&mut self, use_imm_cmds: bool) { - self.corb.init(); - self.rirb.init(); - self.set_use_imm_cmds(use_imm_cmds); + pub fn init(&mut self, use_imm_cmds: bool) -> Result<()> { + self.corb.init()?; + self.rirb.init()?; + self.set_use_imm_cmds(use_imm_cmds)?; + Ok(()) } - pub fn stop(&mut self) { - self.corb.stop(); - self.rirb.stop(); + pub fn stop(&mut self) -> Result<()> { + self.corb.stop()?; + self.rirb.stop()?; + Ok(()) } - pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> u64 { + pub fn cmd12(&mut self, addr: WidgetAddr, command: u32, data: u8) -> Result { let mut ncmd: u32 = 0; ncmd |= (addr.0 as u32 & 0x00F) << 28; @@ -390,7 +459,7 @@ impl CommandBuffer { ncmd |= (data as u32 & 0x0FF) << 0; self.cmd(ncmd) } - pub fn cmd4(&mut self, addr: WidgetAddr, command: u32, data: u16) -> u64 { + pub fn cmd4(&mut self, addr: WidgetAddr, command: u32, data: u16) -> Result { let mut ncmd: u32 = 0; ncmd |= (addr.0 as u32 & 0x000F) << 28; @@ -400,7 +469,7 @@ impl CommandBuffer { self.cmd(ncmd) } - pub fn cmd(&mut self, cmd: u32) -> u64 { + pub fn cmd(&mut self, cmd: u32) -> Result { if self.use_immediate_cmd { self.cmd_imm(cmd) } else { @@ -408,24 +477,25 @@ impl CommandBuffer { } } - pub fn cmd_imm(&mut self, cmd: u32) -> u64 { + pub fn cmd_imm(&mut self, cmd: u32) -> Result { self.icmd.cmd(cmd) } - pub fn cmd_buff(&mut self, cmd: u32) -> u64 { - self.corb.send_command(cmd); + pub fn cmd_buff(&mut self, cmd: u32) -> Result { + self.corb.send_command(cmd)?; self.rirb.read_response() } - pub fn set_use_imm_cmds(&mut self, use_imm: bool) { + pub fn set_use_imm_cmds(&mut self, use_imm: bool) -> Result<()> { self.use_immediate_cmd = use_imm; if self.use_immediate_cmd { - self.corb.stop(); - self.rirb.stop(); + self.corb.stop()?; + self.rirb.stop()?; } else { self.corb.start(); self.rirb.start(); } + Ok(()) } } diff --git a/audio/ihdad/src/hda/device.rs b/audio/ihdad/src/hda/device.rs index 9bbd3c8226..df50cf13bd 100755 --- a/audio/ihdad/src/hda/device.rs +++ b/audio/ihdad/src/hda/device.rs @@ -12,7 +12,7 @@ use std::time::Duration; use common::dma::Dma; use common::io::{Io, Mmio}; use common::timeout::Timeout; -use syscall::error::{Error, Result, EACCES, EBADF, EIO, EINVAL}; +use syscall::error::{Error, Result, EACCES, EBADF, EIO, EINVAL, ENODEV}; use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET}; use syscall::scheme::SchemeBlockMut; @@ -207,9 +207,9 @@ impl IntelHDA { module.init()?; module.info(); - module.enumerate(); + module.enumerate()?; - module.configure(); + module.configure()?; log::debug!("IHDA: Initialization finished."); Ok(module) } @@ -222,7 +222,7 @@ impl IntelHDA { _ => true, }; - self.cmd.init(use_immediate_command_interface); + self.cmd.init(use_immediate_command_interface)?; self.init_interrupts(); Ok(()) @@ -248,42 +248,42 @@ impl IntelHDA { self.int_counter } - pub fn read_node(&mut self, addr: WidgetAddr) -> HDANode { + pub fn read_node(&mut self, addr: WidgetAddr) -> Result { let mut node = HDANode::new(); let mut temp: u64; node.addr = addr; - temp = self.cmd.cmd12(addr, 0xF00, 0x04); + temp = self.cmd.cmd12(addr, 0xF00, 0x04)?; node.subnode_count = (temp & 0xff) as u16; node.subnode_start = ((temp >> 16) & 0xff) as u16; if addr == (0, 0) { - return node; + return Ok(node); } - temp = self.cmd.cmd12(addr, 0xF00, 0x04); + temp = self.cmd.cmd12(addr, 0xF00, 0x04)?; node.function_group_type = (temp & 0xff) as u8; - temp = self.cmd.cmd12(addr, 0xF00, 0x09); + temp = self.cmd.cmd12(addr, 0xF00, 0x09)?; node.capabilities = temp as u32; - temp = self.cmd.cmd12(addr, 0xF00, 0x0E); + temp = self.cmd.cmd12(addr, 0xF00, 0x0E)?; node.conn_list_len = (temp & 0xFF) as u8; - node.connections = self.node_get_connection_list(&node); + node.connections = self.node_get_connection_list(&node)?; - node.connection_default = self.cmd.cmd12(addr, 0xF01, 0x00) as u8; + node.connection_default = self.cmd.cmd12(addr, 0xF01, 0x00)? as u8; - node.config_default = self.cmd.cmd12(addr, 0xF1C, 0x00) as u32; + node.config_default = self.cmd.cmd12(addr, 0xF1C, 0x00)? as u32; - node + Ok(node) } - pub fn node_get_connection_list(&mut self, node: &HDANode) -> Vec { - let len_field: u8 = (self.cmd.cmd12(node.addr, 0xF00, 0x0E) & 0xFF) as u8; + pub fn node_get_connection_list(&mut self, node: &HDANode) -> Result> { + let len_field: u8 = (self.cmd.cmd12(node.addr, 0xF00, 0x0E)? & 0xFF) as u8; // Highest bit is if addresses are represented in longer notation // lower 7 is actual count @@ -296,7 +296,7 @@ impl IntelHDA { let mut list = Vec::::new(); while current < count { - let response: u32 = (self.cmd.cmd12(node.addr, 0xF02, current) & 0xFFFFFFFF) as u32; + let response: u32 = (self.cmd.cmd12(node.addr, 0xF02, current)? & 0xFFFFFFFF) as u32; if use_long_addr { for i in 0..2 { @@ -337,16 +337,16 @@ impl IntelHDA { current = list.len() as u8; } - list + Ok(list) } - pub fn enumerate(&mut self) { + pub fn enumerate(&mut self) -> Result<()> { self.output_pins.clear(); self.input_pins.clear(); let codec: u8 = 0; - let root = self.read_node((codec, 0)); + let root = self.read_node((codec, 0))?; log::debug!("{}", root); @@ -355,13 +355,13 @@ impl IntelHDA { //FIXME: So basically the way this is set up is to only support one codec and hopes the first one is an audio for i in 0..root_count { - let afg = self.read_node((codec, root_start + i)); + let afg = self.read_node((codec, root_start + i))?; log::debug!("{}", afg); let afg_count = afg.subnode_count; let afg_start = afg.subnode_start; for j in 0..afg_count { - let mut widget = self.read_node((codec, afg_start + j)); + let mut widget = self.read_node((codec, afg_start + j))?; widget.is_widget = true; match widget.widget_type() { HDAWidgetType::AudioOutput => self.outputs.push(widget.addr), @@ -382,15 +382,15 @@ impl IntelHDA { self.widget_map.insert(widget.addr(), widget); } } + + Ok(()) } - pub fn find_best_output_pin(&mut self) -> Option { + pub fn find_best_output_pin(&mut self) -> Result { let outs = &self.output_pins; - if outs.len() == 0 { - None - } else if outs.len() == 1 { - Some(outs[0]) - } else { + if outs.len() == 1 { + return Ok(outs[0]) + } else if outs.len() > 1 { //TODO: change output based on "unsolicited response" interrupts // Check for devices in this order: Headphone, Speaker, Line Out for supported_device in &[DefaultDevice::HPOut, DefaultDevice::Speaker] { @@ -399,22 +399,22 @@ impl IntelHDA { let cd = widget.configuration_default(); if cd.sequence() == 0 && &cd.default_device() == supported_device { // Check for jack detect bit - let pin_caps = self.cmd.cmd12(widget.addr, 0xF00, 0x0C); + let pin_caps = self.cmd.cmd12(widget.addr, 0xF00, 0x0C)?; if pin_caps & (1 << 2) != 0 { // Check for presence - let pin_sense = self.cmd.cmd12(widget.addr, 0xF09, 0); + let pin_sense = self.cmd.cmd12(widget.addr, 0xF09, 0)?; if pin_sense & (1 << 31) == 0 { // Skip if nothing is plugged in continue; } } - return Some(out); + return Ok(out); } } } - None } + Err(Error::new(ENODEV)) } pub fn find_path_to_dac(&self, addr: WidgetAddr) -> Option> { @@ -466,8 +466,8 @@ impl IntelHDA { } } - pub fn configure(&mut self) { - let outpin = self.find_best_output_pin().expect("IHDA: No output pins?!"); + pub fn configure(&mut self) -> Result<()> { + let outpin = self.find_best_output_pin()?; log::debug!("Best pin: {:01X}:{:02X}", outpin.0, outpin.1); @@ -480,25 +480,25 @@ impl IntelHDA { // Set power state 0 (on) for all widgets in path for &addr in &path { - self.set_power_state(addr, 0); + self.set_power_state(addr, 0)?; } // Pin enable (0x80 = headphone amp enable, 0x40 = output enable) - self.cmd.cmd12(pin, 0x707, 0xC0); + self.cmd.cmd12(pin, 0x707, 0xC0)?; // EAPD enable - self.cmd.cmd12(pin, 0x70C, 2); + self.cmd.cmd12(pin, 0x70C, 2)?; // Set DAC stream and channel - self.set_stream_channel(dac, 1, 0); + self.set_stream_channel(dac, 1, 0)?; self.update_sound_buffers(); log::debug!( "Supported Formats: {:08X}", - self.get_supported_formats((0, 0x1)) + self.get_supported_formats((0, 0x1))? ); - log::debug!("Capabilities: {:08X}", self.get_capabilities(path[0])); + log::debug!("Capabilities: {:08X}", self.get_capabilities(path[0])?); // Create output stream let output = self.get_output_stream_descriptor(0).unwrap(); @@ -510,16 +510,16 @@ impl IntelHDA { output.set_interrupt_on_completion(true); // Set DAC converter format - self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2); + self.set_converter_format(dac, &super::SR_44_1, BitsPerSample::Bits16, 2)?; // Get DAC converter format //TODO: should validate? - self.cmd.cmd12(dac, 0xA00, 0); + self.cmd.cmd12(dac, 0xA00, 0)?; // Unmute and set gain to 0db for input and output amplifiers on all widgets in path for &addr in &path { // Read widget capabilities - let caps = self.cmd.cmd12(addr, 0xF00, 0x09); + let caps = self.cmd.cmd12(addr, 0xF00, 0x09)?; //TODO: do we need to set any other indexes? let left = true; @@ -530,28 +530,28 @@ impl IntelHDA { // Check for input amp if (caps & (1 << 1)) != 0 { // Read input capabilities - let in_caps = self.cmd.cmd12(addr, 0xF00, 0x0D); + let in_caps = self.cmd.cmd12(addr, 0xF00, 0x0D)?; let in_gain = (in_caps & 0x7f) as u8; // Set input gain let output = false; let input = true; self.set_amplifier_gain_mute( addr, output, input, left, right, index, mute, in_gain, - ); + )?; log::debug!("Set {:X?} input gain to 0x{:X}", addr, in_gain); } // Check for output amp if (caps & (1 << 2)) != 0 { // Read output capabilities - let out_caps = self.cmd.cmd12(addr, 0xF00, 0x12); + let out_caps = self.cmd.cmd12(addr, 0xF00, 0x12)?; let out_gain = (out_caps & 0x7f) as u8; // Set output gain let output = true; let input = false; self.set_amplifier_gain_mute( addr, output, input, left, right, index, mute, out_gain, - ); + )?; log::debug!("Set {:X?} output gain to 0x{:X}", addr, out_gain); } } @@ -559,9 +559,15 @@ impl IntelHDA { //TODO: implement hda-verb? output.run(); - log::debug!("Waiting for output 0 to start running..."); - while output.control() & (1 << 1) == 0 { - //TODO: relax + { + log::debug!("Waiting for output 0 to start running..."); + let timeout = Timeout::from_secs(1); + while output.control() & (1 << 1) == 0 { + timeout.run().map_err(|()| { + log::error!("timeout on output running"); + Error::new(EIO) + })?; + } } log::debug!( @@ -570,6 +576,7 @@ impl IntelHDA { output.status(), output.link_position() ); + Ok(()) } /* @@ -644,17 +651,8 @@ impl IntelHDA { } } - pub fn read_beep(&mut self) -> u8 { - let addr = self.beep_addr; - if addr != (0, 0) { - self.cmd.cmd12(addr, 0x70A, 0) as u8 - } else { - 0 - } - } - pub fn reset_controller(&mut self) -> Result<()> { - self.cmd.stop(); + self.cmd.stop()?; self.regs.statests.write(0x7FFF); @@ -800,21 +798,23 @@ impl IntelHDA { self.regs.dpubase.write((addr_val >> 32) as u32); } - fn set_stream_channel(&mut self, addr: WidgetAddr, stream: u8, channel: u8) { + fn set_stream_channel(&mut self, addr: WidgetAddr, stream: u8, channel: u8) -> Result<()> { let val = ((stream & 0xF) << 4) | (channel & 0xF); - self.cmd.cmd12(addr, 0x706, val); + self.cmd.cmd12(addr, 0x706, val)?; + Ok(()) } - fn set_power_state(&mut self, addr: WidgetAddr, state: u8) { - self.cmd.cmd12(addr, 0x705, state & 0xF) as u32; + fn set_power_state(&mut self, addr: WidgetAddr, state: u8) -> Result<()> { + self.cmd.cmd12(addr, 0x705, state & 0xF)?; + Ok(()) } - fn get_supported_formats(&mut self, addr: WidgetAddr) -> u32 { - self.cmd.cmd12(addr, 0xF00, 0x0A) as u32 + fn get_supported_formats(&mut self, addr: WidgetAddr) -> Result { + Ok(self.cmd.cmd12(addr, 0xF00, 0x0A)? as u32) } - fn get_capabilities(&mut self, addr: WidgetAddr) -> u32 { - self.cmd.cmd12(addr, 0xF00, 0x09) as u32 + fn get_capabilities(&mut self, addr: WidgetAddr) -> Result { + Ok(self.cmd.cmd12(addr, 0xF00, 0x09)? as u32) } fn set_converter_format( @@ -823,9 +823,10 @@ impl IntelHDA { sr: &super::SampleRate, bps: BitsPerSample, channels: u8, - ) { + ) -> Result<()> { let fmt = super::format_to_u16(sr, bps, channels); - self.cmd.cmd4(addr, 0x2, fmt); + self.cmd.cmd4(addr, 0x2, fmt)?; + Ok(()) } fn set_amplifier_gain_mute( @@ -838,7 +839,7 @@ impl IntelHDA { index: u8, mute: bool, gain: u8, - ) { + ) -> Result<()> { let mut payload: u16 = 0; if output { @@ -859,7 +860,8 @@ impl IntelHDA { payload |= ((index as u16) & 0x0F) << 8; payload |= (gain as u16) & 0x7F; - self.cmd.cmd4(addr, 0x3, payload); + self.cmd.cmd4(addr, 0x3, payload)?; + Ok(()) } pub fn write_to_output(&mut self, index: u8, buf: &[u8]) -> Result> { From 4d6581d454b6837cb712272564e6b59598d07f99 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 26 Nov 2025 17:45:46 -0700 Subject: [PATCH 1293/1301] xhcid: add more timeouts --- usb/xhcid/src/xhci/device_enumerator.rs | 2 +- usb/xhcid/src/xhci/mod.rs | 105 +++++++++++++++--------- 2 files changed, 68 insertions(+), 39 deletions(-) diff --git a/usb/xhcid/src/xhci/device_enumerator.rs b/usb/xhcid/src/xhci/device_enumerator.rs index 547ba11905..a84c2ada59 100644 --- a/usb/xhcid/src/xhci/device_enumerator.rs +++ b/usb/xhcid/src/xhci/device_enumerator.rs @@ -78,7 +78,7 @@ impl DeviceEnumerator { //THIS LOCKS THE PORTS. DO NOT LOCK PORTS BEFORE THIS POINT info!("Received a device connect on port {}, but it's not enabled. Resetting the port.", port_id); - self.hci.reset_port(port_id); + let _ = self.hci.reset_port(port_id); let mut ports = self.hci.ports.lock().unwrap(); let port = &mut ports[port_array_index]; diff --git a/usb/xhcid/src/xhci/mod.rs b/usb/xhcid/src/xhci/mod.rs index 14203a70f5..5881b55994 100644 --- a/usb/xhcid/src/xhci/mod.rs +++ b/usb/xhcid/src/xhci/mod.rs @@ -20,7 +20,7 @@ use syscall::error::{Error, Result, EBADF, EBADMSG, EIO, ENOENT}; use syscall::{EAGAIN, PAGE_SIZE}; use chashmap::CHashMap; -use common::{dma::Dma, io::Io}; +use common::{dma::Dma, io::Io, timeout::Timeout}; use crossbeam_channel::{Receiver, Sender}; use log::{debug, error, info, trace, warn}; use serde::Deserialize; @@ -374,26 +374,42 @@ impl Xhci { //Reset the XHCI device let (max_slots, max_ports) = { - debug!("Waiting for xHC becoming ready."); - // Wait until controller is ready - while op.usb_sts.readf(USB_STS_CNR) { - trace!("Waiting for the xHC to be ready."); + { + debug!("Waiting for xHC becoming ready."); + let timeout = Timeout::from_secs(1); + while op.usb_sts.readf(USB_STS_CNR) { + timeout.run().map_err(|()| { + log::error!("timeout on USB_STS_CNR"); + Error::new(EIO) + })?; + } } debug!("Stopping the xHC"); // Set run/stop to 0 op.usb_cmd.writef(USB_CMD_RS, false); - debug!("Waiting for the xHC to stop."); - // Wait until controller not running - while !op.usb_sts.readf(USB_STS_HCH) { - trace!("Waiting for the xHC to stop."); + { + debug!("Waiting for the xHC to stop."); + let timeout = Timeout::from_secs(1); + while !op.usb_sts.readf(USB_STS_HCH) { + timeout.run().map_err(|()| { + log::error!("timeout on USB_STS_HCH"); + Error::new(EIO) + })?; + } } - debug!("Resetting the xHC."); - op.usb_cmd.writef(USB_CMD_HCRST, true); - while op.usb_cmd.readf(USB_CMD_HCRST) { - trace!("Waiting for the xHC to reset."); + { + debug!("Resetting the xHC."); + op.usb_cmd.writef(USB_CMD_HCRST, true); + let timeout = Timeout::from_secs(1); + while op.usb_cmd.readf(USB_CMD_HCRST) { + timeout.run().map_err(|()| { + log::error!("timeout on USB_CMD_HCRST"); + Error::new(EIO) + })?; + } } debug!("Reading max slots."); @@ -472,14 +488,20 @@ impl Xhci { self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, false); // Warm reset - debug!("Reset xHC"); - self.op - .get_mut() - .unwrap() - .usb_cmd - .writef(USB_CMD_HCRST, true); - while self.op.get_mut().unwrap().usb_cmd.readf(USB_CMD_HCRST) { - thread::yield_now(); + { + debug!("Reset xHC"); + let timeout = Timeout::from_secs(1); + self.op + .get_mut() + .unwrap() + .usb_cmd + .writef(USB_CMD_HCRST, true); + while self.op.get_mut().unwrap().usb_cmd.readf(USB_CMD_HCRST) { + timeout.run().map_err(|()| { + log::error!("timeout on USB_CMD_HCRST"); + Error::new(EIO) + })?; + } } // Set enabled slots @@ -552,10 +574,15 @@ impl Xhci { debug!("Starting xHC."); self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_RS, true); - // Wait until controller is running - debug!("Waiting for start request to complete."); - while self.op.get_mut().unwrap().usb_sts.readf(USB_STS_HCH) { - trace!("Waiting for XHCI to report running status."); + { + debug!("Waiting for start request to complete."); + let timeout = Timeout::from_secs(1); + while self.op.get_mut().unwrap().usb_sts.readf(USB_STS_HCH) { + timeout.run().map_err(|()| { + log::error!("timeout on USB_STS_HCH"); + Error::new(EIO) + })?; + } } // Ring command doorbell @@ -654,7 +681,7 @@ impl Xhci { }; } } - pub fn reset_port(&self, port_id: PortId) { + pub fn reset_port(&self, port_id: PortId) -> Result<()> { debug!("XHCI Port {} reset", port_id); //TODO handle the second unwrap @@ -664,20 +691,22 @@ impl Xhci { debug!("Port {} Link State: {}", port_id, port.state()); - port.set_pr(); - debug!( - "Flags after setting port {} reset: {:?}", - port_id, - port.flags() - ); - while !port.flags().contains(port::PortFlags::PRC) { - debug!("port {} reset loop ran at least once!", port_id); - if instant.elapsed().as_secs() >= 1 { - warn!("timeout"); - break; + { + port.set_pr(); + debug!( + "Flags after setting port {} reset: {:?}", + port_id, + port.flags() + ); + let timeout = Timeout::from_secs(1); + while !port.flags().contains(port::PortFlags::PRC) { + timeout.run().map_err(|()| { + log::error!("timeout on port {} PRC", port_id); + Error::new(EIO) + })?; } - std::thread::yield_now(); } + Ok(()) } pub fn setup_scratchpads(&mut self) -> Result<()> { From f5475fc9a7eaa9cdef3e8aa4540268de773332c8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 29 Nov 2025 10:40:15 +0100 Subject: [PATCH 1294/1301] Deduplicate int vector handling between ihdad and rtl network drivers Xhcid and nvmed still use their own get_int_method function as they need need to distinguish between legacy, MSI and MSI-X interrupts. --- audio/ihdad/src/main.rs | 40 +------------ net/rtl8139d/src/main.rs | 73 +----------------------- net/rtl8168d/src/main.rs | 73 +----------------------- pcid/src/driver_interface/irq_helpers.rs | 54 ++++++++++++++++++ 4 files changed, 62 insertions(+), 178 deletions(-) diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index c94184991c..3d9d32ca73 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -11,8 +11,7 @@ use std::usize; use syscall::{Packet, SchemeBlockMut}; use event::{user_data, EventQueue}; -#[cfg(target_arch = "x86_64")] -use pcid_interface::irq_helpers::allocate_first_msi_interrupt_on_bsp; +use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; use pcid_interface::PciFunctionHandle; pub mod hda; @@ -24,40 +23,6 @@ QEMU ICH9 8086:293E 82801H ICH8 8086:284B */ -#[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - let all_pci_features = pcid_handle.fetch_all_features(); - log::debug!("PCI FEATURES: {:?}", all_pci_features); - - let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); - - if has_msi { - allocate_first_msi_interrupt_on_bsp(pcid_handle) - } else if let Some(irq) = pci_config.func.legacy_interrupt_line { - log::debug!("Legacy IRQ {}", irq); - - // legacy INTx# interrupt pins. - irq.irq_handle("ihdad") - } else { - panic!("ihdad: no interrupts supported at all") - } -} - -//TODO: MSI on non-x86_64? -#[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - if let Some(irq) = pci_config.func.legacy_interrupt_line { - // legacy INTx# interrupt pins. - irq.irq_handle("ihdad") - } else { - panic!("ihdad: no interrupts supported at all") - } -} - fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut pcid_handle = PciFunctionHandle::connect_default(); @@ -78,8 +43,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize; - //TODO: MSI-X - let mut irq_file = get_int_method(&mut pcid_handle); + let mut irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "ihdad"); { let vend_prod: u32 = ((pci_config.func.full_device_id.vendor_id as u32) << 16) diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index 97dc7921e8..bdd150982e 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -1,15 +1,10 @@ -use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; -use pcid_interface::irq_helpers::read_bsp_apic_id; -#[cfg(target_arch = "x86_64")] -use pcid_interface::irq_helpers::{ - allocate_first_msi_interrupt_on_bsp, allocate_single_interrupt_vector_for_msi, -}; -use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle}; +use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; +use pcid_interface::PciFunctionHandle; pub mod device; @@ -25,67 +20,6 @@ where } } -#[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - let all_pci_features = pcid_handle.fetch_all_features(); - log::info!("PCI FEATURES: {:?}", all_pci_features); - - let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); - let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - - if has_msix { - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { - PciFeatureInfo::Msi(_) => panic!(), - PciFeatureInfo::MsiX(s) => s, - }; - let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; - - // Allocate one msi vector. - - let method = { - // primary interrupter - let k = 0; - - let table_entry_pointer = info.table_entry_pointer(k); - - let destination_id = read_bsp_apic_id().expect("rtl8139d: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - table_entry_pointer.write_addr_and_data(msg_addr_and_data); - table_entry_pointer.unmask(); - - interrupt_handle - }; - - pcid_handle.enable_feature(PciFeature::MsiX); - log::debug!("Enabled MSI-X"); - - method - } else if has_msi { - allocate_first_msi_interrupt_on_bsp(pcid_handle) - } else if let Some(irq) = pci_config.func.legacy_interrupt_line { - // legacy INTx# interrupt pins. - irq.irq_handle("rtl8139d") - } else { - panic!("rtl8139d: no interrupts supported at all") - } -} - -//TODO: MSI on non-x86_64? -#[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - if let Some(irq) = pci_config.func.legacy_interrupt_line { - // legacy INTx# interrupt pins. - irq.irq_handle("rtl8139d") - } else { - panic!("rtl8139d: no interrupts supported at all") - } -} - fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { let config = pcid_handle.config(); @@ -121,8 +55,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let bar = map_bar(&mut pcid_handle); - //TODO: MSI-X - let mut irq_file = get_int_method(&mut pcid_handle); + let mut irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "rtl8139d"); let mut scheme = NetworkScheme::new( move || unsafe { diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index c394f1c70e..c477c0aaeb 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -1,15 +1,10 @@ -use std::fs::File; use std::io::{Read, Write}; use std::os::unix::io::AsRawFd; use driver_network::NetworkScheme; use event::{user_data, EventQueue}; -use pcid_interface::irq_helpers::read_bsp_apic_id; -#[cfg(target_arch = "x86_64")] -use pcid_interface::irq_helpers::{ - allocate_first_msi_interrupt_on_bsp, allocate_single_interrupt_vector_for_msi, -}; -use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle}; +use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; +use pcid_interface::PciFunctionHandle; pub mod device; @@ -25,67 +20,6 @@ where } } -#[cfg(target_arch = "x86_64")] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - let all_pci_features = pcid_handle.fetch_all_features(); - log::info!("PCI FEATURES: {:?}", all_pci_features); - - let has_msi = all_pci_features.iter().any(|feature| feature.is_msi()); - let has_msix = all_pci_features.iter().any(|feature| feature.is_msix()); - - if has_msix { - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { - PciFeatureInfo::Msi(_) => panic!(), - PciFeatureInfo::MsiX(s) => s, - }; - let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; - - // Allocate one msi vector. - - let method = { - // primary interrupter - let k = 0; - - let table_entry_pointer = info.table_entry_pointer(k); - - let destination_id = read_bsp_apic_id().expect("rtl8168d: failed to read BSP apic id"); - let (msg_addr_and_data, interrupt_handle) = - allocate_single_interrupt_vector_for_msi(destination_id); - table_entry_pointer.write_addr_and_data(msg_addr_and_data); - table_entry_pointer.unmask(); - - interrupt_handle - }; - - pcid_handle.enable_feature(PciFeature::MsiX); - log::debug!("Enabled MSI-X"); - - method - } else if has_msi { - allocate_first_msi_interrupt_on_bsp(pcid_handle) - } else if let Some(irq) = pci_config.func.legacy_interrupt_line { - // legacy INTx# interrupt pins. - irq.irq_handle("rtl8168d") - } else { - panic!("rtl8168d: no interrupts supported at all") - } -} - -//TODO: MSI on non-x86_64? -#[cfg(not(target_arch = "x86_64"))] -fn get_int_method(pcid_handle: &mut PciFunctionHandle) -> File { - let pci_config = pcid_handle.config(); - - if let Some(irq) = pci_config.func.legacy_interrupt_line { - // legacy INTx# interrupt pins. - irq.irq_handle("rtl8168d") - } else { - panic!("rtl8168d: no interrupts supported at all") - } -} - fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 { let config = pcid_handle.config(); @@ -121,8 +55,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let bar = map_bar(&mut pcid_handle); - //TODO: MSI-X - let mut irq_file = get_int_method(&mut pcid_handle); + let mut irq_file = pci_allocate_interrupt_vector(&mut pcid_handle, "rtl8168d"); let mut scheme = NetworkScheme::new( move || unsafe { diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index f4221d0c68..0170380c69 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -227,3 +227,57 @@ pub fn allocate_first_msi_interrupt_on_bsp( interrupt_handle } + +/// Get the most optimal supported interrupt mechanism: either (in the order of preference): +/// MSI-X, MSI, and INTx# pin. Returns the handles to the interrupts. +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub fn pci_allocate_interrupt_vector( + pcid_handle: &mut crate::driver_interface::PciFunctionHandle, + driver: &str, +) -> File { + let features = pcid_handle.fetch_all_features(); + + let has_msi = features.iter().any(|feature| feature.is_msi()); + let has_msix = features.iter().any(|feature| feature.is_msix()); + + if has_msix { + let capability_struct = match pcid_handle.feature_info(super::PciFeature::MsiX) { + super::PciFeatureInfo::MsiX(msix) => msix, + _ => unreachable!(), + }; + let mut info = unsafe { capability_struct.map_and_mask_all(pcid_handle) }; + + pcid_handle.enable_feature(crate::driver_interface::PciFeature::MsiX); + + let entry = info.table_entry_pointer(0); + + let bsp_cpu_id = read_bsp_apic_id() + .unwrap_or_else(|err| panic!("{driver}: failed to read BSP APIC ID: {err}")); + let (msg_addr_and_data, irq_handle) = allocate_single_interrupt_vector_for_msi(bsp_cpu_id); + entry.write_addr_and_data(msg_addr_and_data); + entry.unmask(); + + irq_handle + } else if has_msi { + allocate_first_msi_interrupt_on_bsp(pcid_handle) + } else if let Some(irq) = pcid_handle.config().func.legacy_interrupt_line { + // INTx# pin based interrupts. + irq.irq_handle(driver) + } else { + panic!("{driver}: no interrupts supported at all") + } +} + +// FIXME support MSI on non-x86 systems +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +fn pci_allocate_interrupt_vector( + pcid_handle: &mut crate::driver_interface::PcidServerHandle, + driver: &str, +) -> Vec { + if let Some(irq) = pcid_handle.config().func.legacy_interrupt_line { + // INTx# pin based interrupts. + irq.irq_handle(driver) + } else { + panic!("{driver}: no interrupts supported at all") + } +} From 36e3834d8b7e1386875d7252ba46aca2756a150e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 29 Nov 2025 11:15:39 +0100 Subject: [PATCH 1295/1301] Fix a bunch of warnings --- input/ps2d/src/controller.rs | 21 +++++++++------------ net/alxd/src/device/mod.rs | 16 +++------------- net/ixgbed/src/ixgbe.rs | 26 +++++++++++++------------- storage/ahcid/src/ahci/hba.rs | 2 +- storage/bcm2835-sdhcid/src/main.rs | 4 +--- storage/bcm2835-sdhcid/src/sd/mod.rs | 17 +++++++---------- storage/lived/src/main.rs | 2 +- storage/usbscsid/src/scsi/cmds.rs | 2 +- storage/usbscsid/src/scsi/mod.rs | 8 ++++---- usb/usbhubd/src/main.rs | 2 +- usb/xhcid/src/driver_interface.rs | 6 +++--- virtio-core/src/transport.rs | 12 ++++++------ 12 files changed, 50 insertions(+), 68 deletions(-) diff --git a/input/ps2d/src/controller.rs b/input/ps2d/src/controller.rs index 7a58f3de3a..ae2326062e 100644 --- a/input/ps2d/src/controller.rs +++ b/input/ps2d/src/controller.rs @@ -1,10 +1,10 @@ -use common::{io::{Io, Pio, ReadOnly, WriteOnly}, timeout::Timeout}; -use log::{debug, error, info, trace}; - -use std::{ - fmt, thread, - time::{Duration, Instant}, +use common::{ + io::{Io, Pio, ReadOnly, WriteOnly}, + timeout::Timeout, }; +use log::{debug, error, trace}; + +use std::fmt; #[derive(Debug)] pub enum Error { @@ -94,7 +94,6 @@ enum MouseCommand { #[derive(Clone, Copy, Debug)] #[repr(u8)] enum MouseCommandData { - SetResolution = 0xE8, SetSampleRate = 0xF3, } @@ -327,8 +326,6 @@ impl Ps2 { } pub fn init_mouse(&mut self) -> Result { - let mut b: u8 = 0; - { // Enable second device self.command(Command::EnableSecond)?; @@ -368,7 +365,7 @@ impl Ps2 { } } - b = self.mouse_command(MouseCommand::GetDeviceId)?; + let b = self.mouse_command(MouseCommand::GetDeviceId)?; let mouse_extra = if b == 0xFA { self.read()? == 3 } else { @@ -379,7 +376,7 @@ impl Ps2 { { // Set sample rate to maximum let sample_rate = 200; - b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate)?; + let b = self.mouse_command_data(MouseCommandData::SetSampleRate, sample_rate)?; if b != 0xFA { error!( "ps2d: mouse failed to set sample rate to {}: {:02X}", @@ -389,7 +386,7 @@ impl Ps2 { } { - b = self.mouse_command(MouseCommand::StatusRequest)?; + let b = self.mouse_command(MouseCommand::StatusRequest)?; if b != 0xFA { error!("ps2d: mouse failed to request status: {:02X}", b); } else { diff --git a/net/alxd/src/device/mod.rs b/net/alxd/src/device/mod.rs index 28719dd7d1..17746e8f2e 100644 --- a/net/alxd/src/device/mod.rs +++ b/net/alxd/src/device/mod.rs @@ -663,7 +663,7 @@ impl Alx { } /* clear WoL setting/status */ - val = self.read(WOL0); + self.read(WOL0); self.write(WOL0, 0); /* deflt val of PDLL D3PLLOFF */ @@ -1124,7 +1124,7 @@ impl Alx { let mut giga: u16 = 0; let mut err: usize; - err = self.read_phy_reg(MII_BMSR, &mut bmsr); + self.read_phy_reg(MII_BMSR, &mut bmsr); err = self.read_phy_reg(MII_BMSR, &mut bmsr); if (err > 0) { return err; @@ -1280,7 +1280,7 @@ impl Alx { self.write(RXQ0, val); /* DMA */ - val = self.read(DMA); + self.read(DMA); val = FIELDX!(DMA_RORDER_MODE, DMA_RORDER_MODE_OUT) | DMA_RREQ_PRI_DATA | FIELDX!(DMA_RREQ_BLEN, max_payload) @@ -1726,16 +1726,6 @@ impl Alx { } unsafe fn open(&mut self) -> usize { - let _err: usize = 0; - - macro_rules! goto_out { - () => {{ - self.free_all_ring_resources(); - self.disable_advanced_intr(); - return err; - }}; - } - /* allocate all memory resources */ self.init_ring_ptrs(); diff --git a/net/ixgbed/src/ixgbe.rs b/net/ixgbed/src/ixgbe.rs index a4b941f8c9..8d77959444 100644 --- a/net/ixgbed/src/ixgbe.rs +++ b/net/ixgbed/src/ixgbe.rs @@ -8,7 +8,7 @@ pub const IXGBE_EIMC: u32 = 0x00888; pub const IXGBE_CTRL: u32 = 0x00000; pub const IXGBE_CTRL_LNK_RST: u32 = 0x00000008; /* Link Reset. Resets everything. */ pub const IXGBE_CTRL_RST: u32 = 0x04000000; /* Reset (SW) */ -pub const IXGBE_CTRL_RST_MASK: u32 = (IXGBE_CTRL_LNK_RST | IXGBE_CTRL_RST); +pub const IXGBE_CTRL_RST_MASK: u32 = IXGBE_CTRL_LNK_RST | IXGBE_CTRL_RST; pub const IXGBE_EEC: u32 = 0x10010; pub const IXGBE_EEC_ARD: u32 = 0x00000200; /* EEPROM Auto Read Done */ @@ -19,11 +19,11 @@ pub const IXGBE_RDRXCTL_DMAIDONE: u32 = 0x00000008; /* DMA init cycle pub const IXGBE_AUTOC: u32 = 0x042A0; pub const IXGBE_AUTOC_LMS_SHIFT: u32 = 13; -pub const IXGBE_AUTOC_LMS_MASK: u32 = (0x7 << IXGBE_AUTOC_LMS_SHIFT); -pub const IXGBE_AUTOC_LMS_10G_SERIAL: u32 = (0x3 << IXGBE_AUTOC_LMS_SHIFT); +pub const IXGBE_AUTOC_LMS_MASK: u32 = 0x7 << IXGBE_AUTOC_LMS_SHIFT; +pub const IXGBE_AUTOC_LMS_10G_SERIAL: u32 = 0x3 << IXGBE_AUTOC_LMS_SHIFT; pub const IXGBE_AUTOC_10G_PMA_PMD_MASK: u32 = 0x00000180; pub const IXGBE_AUTOC_10G_PMA_PMD_SHIFT: u32 = 7; -pub const IXGBE_AUTOC_10G_XAUI: u32 = (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT); +pub const IXGBE_AUTOC_10G_XAUI: u32 = 0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT; pub const IXGBE_AUTOC_AN_RESTART: u32 = 0x00001000; pub const IXGBE_GPRC: u32 = 0x04074; @@ -37,7 +37,7 @@ pub const IXGBE_RXCTRL: u32 = 0x03000; pub const IXGBE_RXCTRL_RXEN: u32 = 0x00000001; /* Enable Receiver */ pub fn IXGBE_RXPBSIZE(i: u32) -> u32 { - (0x03C00 + (i * 4)) + 0x03C00 + (i * 4) } pub const IXGBE_RXPBSIZE_128KB: u32 = 0x00020000; /* 128KB Packet Buffer */ @@ -115,7 +115,7 @@ pub const IXGBE_HLREG0_TXCRCEN: u32 = 0x00000001; /* bit 0 */ pub const IXGBE_HLREG0_TXPADEN: u32 = 0x00000400; /* bit 10 */ pub fn IXGBE_TXPBSIZE(i: u32) -> u32 { - (0x0CC00 + (i * 4)) + 0x0CC00 + (i * 4) } /* 8 of these */ pub const IXGBE_TXPBSIZE_40KB: u32 = 0x0000A000; /* 40KB Packet Buffer */ @@ -124,16 +124,16 @@ pub const IXGBE_RTTDCS: u32 = 0x04900; pub const IXGBE_RTTDCS_ARBDIS: u32 = 0x00000040; /* DCB arbiter disable */ pub fn IXGBE_TDBAL(i: u32) -> u32 { - (0x06000 + (i * 0x40)) + 0x06000 + (i * 0x40) } /* 32 of them (0-31)*/ pub fn IXGBE_TDBAH(i: u32) -> u32 { - (0x06004 + (i * 0x40)) + 0x06004 + (i * 0x40) } pub fn IXGBE_TDLEN(i: u32) -> u32 { - (0x06008 + (i * 0x40)) + 0x06008 + (i * 0x40) } pub fn IXGBE_TXDCTL(i: u32) -> u32 { - (0x06028 + (i * 0x40)) + 0x06028 + (i * 0x40) } pub const IXGBE_DMATXCTL: u32 = 0x04A80; @@ -150,10 +150,10 @@ pub const IXGBE_RXDCTL_ENABLE: u32 = 0x02000000; /* Ena specific Rx pub const IXGBE_TXDCTL_ENABLE: u32 = 0x02000000; /* Ena specific Tx Queue */ pub fn IXGBE_TDH(i: u32) -> u32 { - (0x06010 + (i * 0x40)) + 0x06010 + (i * 0x40) } pub fn IXGBE_TDT(i: u32) -> u32 { - (0x06018 + (i * 0x40)) + 0x06018 + (i * 0x40) } pub const IXGBE_FCTRL_MPE: u32 = 0x00000100; /* Multicast Promiscuous Ena*/ @@ -208,7 +208,7 @@ pub const IXGBE_IVAR_ALLOC_VAL: u32 = 0x80; /* Interrupt Allocation pub const IXGBE_EICR_RTX_QUEUE: u32 = 0x0000FFFF; /* RTx Queue Interrupt */ pub fn IXGBE_IVAR(i: u32) -> u32 { - (0x00900 + (i * 4)) + 0x00900 + (i * 4) } /* 24 at 0x900-0x960 */ #[derive(Debug, Copy, Clone)] diff --git a/storage/ahcid/src/ahci/hba.rs b/storage/ahcid/src/ahci/hba.rs index af7232762b..bea8792c80 100644 --- a/storage/ahcid/src/ahci/hba.rs +++ b/storage/ahcid/src/ahci/hba.rs @@ -1,7 +1,7 @@ use log::{debug, error, info, trace}; use std::mem::size_of; use std::ops::DerefMut; -use std::time::{Duration, Instant}; +use std::time::Duration; use std::{ptr, u32}; use common::dma::Dma; diff --git a/storage/bcm2835-sdhcid/src/main.rs b/storage/bcm2835-sdhcid/src/main.rs index 0bfcea69da..c6b67acf97 100644 --- a/storage/bcm2835-sdhcid/src/main.rs +++ b/storage/bcm2835-sdhcid/src/main.rs @@ -1,8 +1,6 @@ -#![feature(let_chains)] - use std::process; -use driver_block::{Disk, DiskScheme, ExecutorTrait, TrivialExecutor}; +use driver_block::{DiskScheme, ExecutorTrait, TrivialExecutor}; use event::{EventFlags, RawEventQueue}; use fdt::Fdt; diff --git a/storage/bcm2835-sdhcid/src/sd/mod.rs b/storage/bcm2835-sdhcid/src/sd/mod.rs index 5dda89acb6..dcbcb3e09f 100644 --- a/storage/bcm2835-sdhcid/src/sd/mod.rs +++ b/storage/bcm2835-sdhcid/src/sd/mod.rs @@ -38,7 +38,7 @@ pub(crate) unsafe fn wait_msec(mut n: usize) { #[cfg(target_arch = "x86_64")] #[inline(always)] -pub(crate) unsafe fn wait_msec(mut n: usize) { +pub(crate) unsafe fn wait_msec(n: usize) { thread::sleep(Duration::from_millis(n as u64)); } @@ -381,11 +381,10 @@ impl SdHostCtrl { } pub unsafe fn set_clock(&mut self, freq: u32) -> Result<()> { - let mut cnt: i32 = 0; let regs = self.regs.get_mut().unwrap(); let mut reg_val = regs.status.read() & (SR_CMD_INHIBIT | SR_DAT_INHIBIT); - cnt = 10_0000; + let mut cnt = 10_0000; while (cnt > 0) && reg_val != 0 { wait_msec(1); cnt -= 1; @@ -436,7 +435,7 @@ impl SdHostCtrl { s = 7; } } - let mut d = 0; + let mut d; if self.host_spec_ver > HOST_SPEC_V2 { d = c; } else { @@ -454,7 +453,7 @@ impl SdHostCtrl { h = (d & 0x300) >> 2; } - d = (((d & 0xff) << 8) | h); + d = ((d & 0xff) << 8) | h; reg_val = regs.control1.read() & 0xffff_003f; regs.control1.write(reg_val | d); wait_msec(10); @@ -554,9 +553,9 @@ impl SdHostCtrl { return Ok(reg_val); } else if code == CMD_SEND_REL_ADDR { let mut err = reg_val & 0x1fff; - err |= ((reg_val & 0x2000) << 6); - err |= ((reg_val & 0x4000) << 8); - err |= ((reg_val & 0x8000) << 8); + err |= (reg_val & 0x2000) << 6; + err |= (reg_val & 0x4000) << 8; + err |= (reg_val & 0x8000) << 8; err &= CMD_ERRORS_MASK; if err != 0 { @@ -616,7 +615,6 @@ impl SdHostCtrl { pub unsafe fn sd_readblock(&mut self, lba: u32, buf: &mut [u32], num: u32) -> Result { let num = if num < 1 { 1 } else { num }; - let mut reg_val: usize = 0; //println!("sd_readblock lba 0x{:x}, num 0x{:x}", lba, num); @@ -672,7 +670,6 @@ impl SdHostCtrl { pub unsafe fn sd_writeblock(&mut self, lba: u32, buf: &[u32], num: u32) -> Result { let num = if num < 1 { 1 } else { num }; - let mut reg_val: usize = 0; //println!("sd_writelock lba 0x{:x}, num 0x{:x}", lba, num); diff --git a/storage/lived/src/main.rs b/storage/lived/src/main.rs index eadc3a5c89..57003daedc 100644 --- a/storage/lived/src/main.rs +++ b/storage/lived/src/main.rs @@ -15,7 +15,7 @@ use libredox::flag; use syscall::error::*; use syscall::PAGE_SIZE; -use anyhow::{anyhow, bail, Context}; +use anyhow::{anyhow, Context}; struct LiveDisk { original: &'static [u8], diff --git a/storage/usbscsid/src/scsi/cmds.rs b/storage/usbscsid/src/scsi/cmds.rs index a9141e8c0e..ab02525e93 100644 --- a/storage/usbscsid/src/scsi/cmds.rs +++ b/storage/usbscsid/src/scsi/cmds.rs @@ -552,7 +552,7 @@ impl<'a> Iterator for ModePageIter<'a> { } } -pub fn mode_page_iter(buffer: &[u8]) -> impl Iterator { +pub fn mode_page_iter(buffer: &[u8]) -> impl Iterator> { ModePageIter { raw: ModePageIterRaw { buffer }, } diff --git a/storage/usbscsid/src/scsi/mod.rs b/storage/usbscsid/src/scsi/mod.rs index a5350ea67f..790abea68c 100644 --- a/storage/usbscsid/src/scsi/mod.rs +++ b/storage/usbscsid/src/scsi/mod.rs @@ -131,8 +131,8 @@ impl Scsi { protocol: &mut dyn Protocol, ) -> Result<( &cmds::ModeParamHeader10, - BlkDescSlice, - impl Iterator, + BlkDescSlice<'_>, + impl Iterator>, )> { let initial_alloc_len = mem::size_of::() as u16; // covers both mode_data_len and blk_desc_len. let mode_sense10 = self.cmd_mode_sense10(); @@ -207,7 +207,7 @@ impl Scsi { ) .unwrap() } - pub fn res_blkdesc_mode10(&self) -> BlkDescSlice { + pub fn res_blkdesc_mode10(&self) -> BlkDescSlice<'_> { let header = self.res_mode_param_header10(); let descs_start = mem::size_of::(); if header.longlba() { @@ -240,7 +240,7 @@ impl Scsi { } } - pub fn res_mode_pages10(&self) -> impl Iterator { + pub fn res_mode_pages10(&self) -> impl Iterator> { let header = self.res_mode_param_header10(); let descs_start = mem::size_of::(); let buffer = &self.data_buffer[descs_start + header.block_desc_len() as usize..]; diff --git a/usb/usbhubd/src/main.rs b/usb/usbhubd/src/main.rs index c24588deda..d98706f838 100644 --- a/usb/usbhubd/src/main.rs +++ b/usb/usbhubd/src/main.rs @@ -155,7 +155,7 @@ fn main() { loop { for port in 1..=ports { let port_idx: usize = port.checked_sub(1).unwrap().into(); - let mut state = states.get_mut(port_idx).unwrap(); + let state = states.get_mut(port_idx).unwrap(); let port_sts = if usb_3 { let mut port_sts = usb::HubPortStatusV3::default(); diff --git a/usb/xhcid/src/driver_interface.rs b/usb/xhcid/src/driver_interface.rs index 004e58b29b..3268aa3de9 100644 --- a/usb/xhcid/src/driver_interface.rs +++ b/usb/xhcid/src/driver_interface.rs @@ -814,7 +814,7 @@ impl XhciEndpHandle { pub fn transfer_nodata(&mut self) -> result::Result { self.generic_transfer(XhciEndpCtlDirection::NoData, |_| Ok(0), 0) } - fn transfer_stream(&mut self, total_len: u32) -> TransferStream { + fn transfer_stream(&mut self, total_len: u32) -> TransferStream<'_> { TransferStream { bytes_to_transfer: total_len, bytes_transferred: 0, @@ -822,12 +822,12 @@ impl XhciEndpHandle { endp_handle: self, } } - pub fn transfer_write_stream(&mut self, total_len: u32) -> TransferWriteStream { + pub fn transfer_write_stream(&mut self, total_len: u32) -> TransferWriteStream<'_> { TransferWriteStream { inner: self.transfer_stream(total_len), } } - pub fn transfer_read_stream(&mut self, total_len: u32) -> TransferReadStream { + pub fn transfer_read_stream(&mut self, total_len: u32) -> TransferReadStream<'_> { TransferReadStream { inner: self.transfer_stream(total_len), } diff --git a/virtio-core/src/transport.rs b/virtio-core/src/transport.rs index 5f3ecaa91f..72376fe003 100644 --- a/virtio-core/src/transport.rs +++ b/virtio-core/src/transport.rs @@ -270,9 +270,9 @@ impl<'a> Mem<'a> { match *self { Self::Owned(ref dma) => dma.as_ptr().cast(), Self::Borrowed(Borrowed { - phys, + phys: _, virt, - size, + size: _, _unused, }) => virt as *const T, } @@ -281,9 +281,9 @@ impl<'a> Mem<'a> { match *self { Self::Owned(ref mut dma) => dma.as_mut_ptr().cast(), Self::Borrowed(Borrowed { - phys, + phys: _, virt, - size, + size: _, _unused, }) => virt as *mut T, } @@ -502,7 +502,7 @@ pub trait Transport: Sync + Send { /// /// ## Panics /// This function panics if the device is running. - fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result, Error>; + fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result>, Error>; // TODO(andypython): Should this function be unsafe? fn reinit_queue(&self, queue: Arc); @@ -615,7 +615,7 @@ impl Transport for StandardTransport<'_> { u32::from(self.common.lock().unwrap().config_generation.get()) } - fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result, Error> { + fn setup_queue(&self, vector: u16, irq_handle: &File) -> Result>, Error> { let mut common = self.common.lock().unwrap(); let queue_index = self.queue_index.fetch_add(1, Ordering::SeqCst); From 420fde3c54a825be1c34322c7bb4c26aad7d96ca Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 29 Nov 2025 11:16:59 +0100 Subject: [PATCH 1296/1301] Remove a couple of unused feature gates --- pcid/src/main.rs | 1 - usb/xhcid/src/main.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/pcid/src/main.rs b/pcid/src/main.rs index e377b64bb3..238ca8c7d7 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -1,4 +1,3 @@ -#![feature(non_exhaustive_omitted_patterns_lint)] #![feature(iter_next_chunk)] #![feature(if_let_guard)] diff --git a/usb/xhcid/src/main.rs b/usb/xhcid/src/main.rs index 1167727576..debf867c6a 100644 --- a/usb/xhcid/src/main.rs +++ b/usb/xhcid/src/main.rs @@ -23,7 +23,6 @@ //! - USB32 - [Universal Serial Bus 3.2 Specification Revision 1.1](https://usb.org/document-library/usb-32-revision-11-june-2022) //! #![allow(warnings)] -#![feature(generic_const_exprs)] #[macro_use] extern crate bitflags; From 627ead6e06fa5ec93667bbab7e0dffe1e1105d61 Mon Sep 17 00:00:00 2001 From: aarch <126242-aarch@users.noreply.gitlab.redox-os.org> Date: Sat, 29 Nov 2025 14:10:09 +0000 Subject: [PATCH 1297/1301] Fix arg type typo --- pcid/src/driver_interface/irq_helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index 0170380c69..3db1c97ce2 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -271,7 +271,7 @@ pub fn pci_allocate_interrupt_vector( // FIXME support MSI on non-x86 systems #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] fn pci_allocate_interrupt_vector( - pcid_handle: &mut crate::driver_interface::PcidServerHandle, + pcid_handle: &mut crate::driver_interface::PciFunctionHandle, driver: &str, ) -> Vec { if let Some(irq) = pcid_handle.config().func.legacy_interrupt_line { From a5d502625e9d8c6a784fb04f8a3f40d791466f66 Mon Sep 17 00:00:00 2001 From: Ibuki Omatsu Date: Sat, 29 Nov 2025 14:20:44 +0000 Subject: [PATCH 1298/1301] feat: Update some drivers to latest redox-scheme from the legacy scheme. --- Cargo.lock | 14 ++ audio/ac97d/Cargo.toml | 1 + audio/ac97d/src/device.rs | 44 +++-- audio/ac97d/src/main.rs | 100 +++++------ audio/ihdad/Cargo.toml | 1 + audio/ihdad/src/hda/device.rs | 133 +++++++------- audio/ihdad/src/main.rs | 105 +++++------- audio/sb16d/Cargo.toml | 1 + audio/sb16d/src/device.rs | 39 +++-- audio/sb16d/src/main.rs | 100 +++++------ net/alxd/Cargo.toml | 1 + net/alxd/src/device/mod.rs | 315 ++++++++++++++++++---------------- net/alxd/src/main.rs | 99 +++++------ 13 files changed, 469 insertions(+), 484 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c10dbb4064..e1130c6e7f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,7 @@ dependencies = [ "log", "pcid", "redox-daemon", + "redox-scheme 0.8.2", "redox_event", "redox_syscall", "spin 0.9.8", @@ -87,6 +88,7 @@ dependencies = [ "common", "libredox", "redox-daemon", + "redox-scheme 0.8.2", "redox_event", "redox_syscall", ] @@ -694,6 +696,7 @@ dependencies = [ "log", "pcid", "redox-daemon", + "redox-scheme 0.8.2", "redox_event", "redox_syscall", "spin 0.9.8", @@ -1137,6 +1140,16 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "redox-scheme" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54adf6001069dfc77e8e9f62dc62d4c9c1471fff65ca577ca140f0e9bdf4e10" +dependencies = [ + "libredox", + "redox_syscall", +] + [[package]] name = "redox_event" version = "0.4.1" @@ -1277,6 +1290,7 @@ dependencies = [ "libredox", "log", "redox-daemon", + "redox-scheme 0.8.2", "redox_event", "redox_syscall", "spin 0.9.8", diff --git a/audio/ac97d/Cargo.toml b/audio/ac97d/Cargo.toml index 2e97f0a1aa..3eea94c5bd 100644 --- a/audio/ac97d/Cargo.toml +++ b/audio/ac97d/Cargo.toml @@ -14,3 +14,4 @@ redox_syscall = "0.5" spin = "0.9" pcid = { path = "../../pcid" } +redox-scheme = "0.8.2" diff --git a/audio/ac97d/src/device.rs b/audio/ac97d/src/device.rs index 5785f67c0f..da73fb54be 100644 --- a/audio/ac97d/src/device.rs +++ b/audio/ac97d/src/device.rs @@ -4,8 +4,12 @@ use std::collections::BTreeMap; use std::sync::atomic::{AtomicUsize, Ordering}; use common::io::Pio; +use redox_scheme::scheme::SchemeSync; +use redox_scheme::CallerCtx; +use redox_scheme::OpenResult; use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, ENOENT}; -use syscall::scheme::SchemeBlockMut; +use syscall::schemev2::NewFdFlags; +use syscall::EWOULDBLOCK; use common::{ dma::Dma, @@ -257,18 +261,28 @@ impl Ac97 { } } -impl SchemeBlockMut for Ac97 { - fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { +impl SchemeSync for Ac97 { + fn open(&mut self, _path: &str, _flags: usize, ctx: &CallerCtx) -> Result { + if ctx.uid == 0 { let id = self.next_id.fetch_add(1, Ordering::SeqCst); self.handles.lock().insert(id, Handle::Todo); - Ok(Some(id)) + Ok(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::empty(), + }) } else { Err(Error::new(EACCES)) } } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + fn write( + &mut self, + id: usize, + buf: &[u8], + _offset: u64, + _flags: u32, + _ctx: &CallerCtx, + ) -> Result { { let mut handles = self.handles.lock(); let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; @@ -282,7 +296,7 @@ impl SchemeBlockMut for Ac97 { let mut lvi = self.bus.po.lvi.read() as usize; if lvi == (civ + 3) % NUM_SUB_BUFFS { // Block if we already are 3 buffers ahead - Ok(None) + Err(Error::new(EWOULDBLOCK)) } else { // Fill next buffer lvi = (lvi + 1) % NUM_SUB_BUFFS; @@ -291,28 +305,24 @@ impl SchemeBlockMut for Ac97 { } self.bus.po.lvi.write(lvi as u8); - Ok(Some(SUB_BUFF_SIZE)) + Ok(SUB_BUFF_SIZE) } } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { let mut handles = self.handles.lock(); let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; let mut i = 0; - let scheme_path = b"audiohw:"; + let scheme_path = b"/scheme/audiohw"; while i < buf.len() && i < scheme_path.len() { buf[i] = scheme_path[i]; i += 1; } - Ok(Some(i)) + Ok(i) } - fn close(&mut self, id: usize) -> Result> { - let mut handles = self.handles.lock(); - handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) + fn on_close(&mut self, id: usize) { + let _ = self.handles.lock().remove(&id); } } diff --git a/audio/ac97d/src/main.rs b/audio/ac97d/src/main.rs index f37e2b0f5a..0e786d5d64 100644 --- a/audio/ac97d/src/main.rs +++ b/audio/ac97d/src/main.rs @@ -5,15 +5,15 @@ extern crate event; extern crate spin; extern crate syscall; -use std::fs::File; -use std::io::{ErrorKind, Read, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::io::{Read, Write}; +use std::os::unix::io::AsRawFd; use std::usize; use event::{user_data, EventQueue}; -use libredox::flag; use pcid_interface::PciFunctionHandle; -use syscall::{Packet, SchemeBlockMut}; +use redox_scheme::wrappers::ReadinessBased; +use redox_scheme::Socket; +use std::cell::RefCell; pub mod device; @@ -49,15 +49,11 @@ fn main() { let mut irq_file = irq.irq_handle("ac97d"); - let mut device = - unsafe { device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") }; - let socket_fd = libredox::call::open( - ":audiohw", - flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, - 0, - ) - .expect("ac97d: failed to create hda scheme"); - let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + let device = RefCell::new(unsafe { + device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device") + }); + let socket = Socket::nonblock("audiohw").expect("ac97d: failed to create socket"); + let mut readiness_based = ReadinessBased::new(&socket, 16); user_data! { enum Source { @@ -76,17 +72,19 @@ fn main() { ) .unwrap(); event_queue - .subscribe(socket_fd, Source::Scheme, event::EventFlags::READ) + .subscribe( + socket.inner().raw(), + Source::Scheme, + event::EventFlags::READ, + ) .unwrap(); daemon.ready().expect("ac97d: failed to signal readiness"); libredox::call::setrens(0, 0).expect("ac97d: failed to enter null namespace"); - let mut todo = Vec::::new(); - let all = [Source::Irq, Source::Scheme]; - 'events: for event in all + for event in all .into_iter() .chain(event_queue.map(|e| e.expect("ac97d: failed to get next event").user_data)) { @@ -95,49 +93,35 @@ fn main() { let mut irq = [0; 8]; irq_file.read(&mut irq).unwrap(); - if device.irq() { - irq_file.write(&mut irq).unwrap(); - - let mut i = 0; - while i < todo.len() { - if let Some(a) = device.handle(&mut todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet).unwrap(); - } else { - i += 1; - } - } - - /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ + if !device.borrow_mut().irq() { + continue; } + irq_file.write(&mut irq).unwrap(); + + readiness_based + .poll_all_requests(|| device.borrow_mut()) + .expect("ac97d: failed to poll requests"); + + /* + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ } Source::Scheme => { - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => break 'events, - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break; - } else { - panic!("ac97d: failed to read socket: {err}"); - } - } - } - - if let Some(a) = device.handle(&mut packet) { - packet.a = a; - socket.write(&packet).unwrap(); - } else { - todo.push(packet); - } + if !readiness_based + .read_requests() + .expect("ac97d: failed to read from socket") + { + break; + } + readiness_based.process_requests(|| device.borrow_mut()); + if !readiness_based + .write_responses() + .expect("ac97d: failed to write to socket") + { + break; } /* diff --git a/audio/ihdad/Cargo.toml b/audio/ihdad/Cargo.toml index 4bd093ad88..83fc34df63 100644 --- a/audio/ihdad/Cargo.toml +++ b/audio/ihdad/Cargo.toml @@ -14,3 +14,4 @@ spin = "0.9" common = { path = "../../common" } pcid = { path = "../../pcid" } +redox-scheme = "0.8.2" diff --git a/audio/ihdad/src/hda/device.rs b/audio/ihdad/src/hda/device.rs index df50cf13bd..d48ed0def8 100755 --- a/audio/ihdad/src/hda/device.rs +++ b/audio/ihdad/src/hda/device.rs @@ -6,17 +6,20 @@ use std::collections::HashMap; use std::fmt::Write; use std::str; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::task::Poll; use std::thread; use std::time::Duration; use common::dma::Dma; use common::io::{Io, Mmio}; use common::timeout::Timeout; -use syscall::error::{Error, Result, EACCES, EBADF, EIO, EINVAL, ENODEV}; -use syscall::flag::{SEEK_CUR, SEEK_END, SEEK_SET}; -use syscall::scheme::SchemeBlockMut; +use redox_scheme::scheme::SchemeSync; +use redox_scheme::CallerCtx; +use redox_scheme::OpenResult; +use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, EIO, ENODEV, EWOULDBLOCK}; use spin::Mutex; +use syscall::schemev2::NewFdFlags; use super::common::*; use super::BitsPerSample; @@ -65,7 +68,7 @@ enum Handle { Todo, Pcmout(usize, usize, usize), // Card, index, block_ptr Pcmin(usize, usize, usize), // Card, index, block_ptr - StrBuf(Vec, usize), + StrBuf(Vec), } #[repr(C, packed)] @@ -389,7 +392,7 @@ impl IntelHDA { pub fn find_best_output_pin(&mut self) -> Result { let outs = &self.output_pins; if outs.len() == 1 { - return Ok(outs[0]) + return Ok(outs[0]); } else if outs.len() > 1 { //TODO: change output based on "unsolicited response" interrupts // Check for devices in this order: Headphone, Speaker, Line Out @@ -412,7 +415,6 @@ impl IntelHDA { } } } - } Err(Error::new(ENODEV)) } @@ -864,7 +866,7 @@ impl IntelHDA { Ok(()) } - pub fn write_to_output(&mut self, index: u8, buf: &[u8]) -> Result> { + pub fn write_to_output(&mut self, index: u8, buf: &[u8]) -> Poll> { let output = self.get_output_stream_descriptor(index as usize).unwrap(); let os = self.output_streams.get_mut(index as usize).unwrap(); @@ -875,9 +877,9 @@ impl IntelHDA { if os.current_block() == (open_block + 3) % NUM_SUB_BUFFS { // Block if we already are 3 buffers ahead - Ok(None) + Poll::Pending } else { - os.write_block(buf).map(|count| Some(count)) + Poll::Ready(os.write_block(buf)) } } @@ -982,8 +984,8 @@ impl Drop for IntelHDA { } } -impl SchemeBlockMut for IntelHDA { - fn open(&mut self, path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { +impl SchemeSync for IntelHDA { + fn open(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> Result { //let path: Vec<&str>; /* match str::from_utf8(_path) { @@ -997,37 +999,54 @@ impl SchemeBlockMut for IntelHDA { }*/ // TODO: - if uid == 0 { - let handle = match path.trim_matches('/') { - //TODO: allow multiple codecs - "codec" => Handle::StrBuf(self.dump_codec(0).into_bytes(), 0), - _ => Handle::Todo, - }; - let id = self.next_id.fetch_add(1, Ordering::SeqCst); - self.handles.lock().insert(id, handle); - Ok(Some(id)) - } else { - Err(Error::new(EACCES)) + if ctx.uid != 0 { + return Err(Error::new(EACCES)); } + let handle = match path.trim_matches('/') { + //TODO: allow multiple codecs + "codec" => Handle::StrBuf(self.dump_codec(0).into_bytes()), + _ => Handle::Todo, + }; + let id = self.next_id.fetch_add(1, Ordering::Relaxed); + self.handles.lock().insert(id, handle); + + // TODO: always positioned? + Ok(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::POSITIONED, + }) } - fn read(&mut self, id: usize, buf: &mut [u8]) -> Result> { - let mut handles = self.handles.lock(); - match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::StrBuf(ref strbuf, ref mut size) => { - let mut i = 0; - while i < buf.len() && *size < strbuf.len() { - buf[i] = strbuf[*size]; - i += 1; - *size += 1; - } - Ok(Some(i)) - } - _ => Err(Error::new(EBADF)), - } + fn read( + &mut self, + id: usize, + buf: &mut [u8], + offset: u64, + _flags: u32, + _ctx: &CallerCtx, + ) -> Result { + let handles = self.handles.lock(); + let Some(Handle::StrBuf(strbuf)) = handles.get(&id) else { + return Err(Error::new(EBADF)); + }; + + let src = usize::try_from(offset) + .ok() + .and_then(|o| strbuf.get(o..)) + .unwrap_or(&[]); + let len = src.len().min(buf.len()); + buf[..len].copy_from_slice(&src[..len]); + Ok(len) } - fn write(&mut self, id: usize, buf: &[u8]) -> Result> { + fn write( + &mut self, + id: usize, + buf: &[u8], + _offset: u64, + _flags: u32, + _ctx: &CallerCtx, + ) -> Result { let index = { let mut handles = self.handles.lock(); match handles.get_mut(&id).ok_or(Error::new(EBADF))? { @@ -1038,50 +1057,26 @@ impl SchemeBlockMut for IntelHDA { //log::debug!("Int count: {}", self.int_counter); - self.write_to_output(index, buf) - } - - fn seek(&mut self, id: usize, pos: isize, whence: usize) -> Result> { - let pos = pos as usize; - let mut handles = self.handles.lock(); - match *handles.get_mut(&id).ok_or(Error::new(EBADF))? { - Handle::StrBuf(ref mut strbuf, ref mut size) => { - let len = strbuf.len() as usize; - *size = match whence { - SEEK_SET => cmp::min(len, pos), - SEEK_CUR => { - cmp::max(0, cmp::min(len as isize, *size as isize + pos as isize)) as usize - } - SEEK_END => { - cmp::max(0, cmp::min(len as isize, len as isize + pos as isize)) as usize - } - _ => return Err(Error::new(EINVAL)), - }; - Ok(Some(*size as isize)) - } - - _ => Err(Error::new(EINVAL)), + match self.write_to_output(index, buf) { + Poll::Ready(r) => r, + Poll::Pending => Err(Error::new(EWOULDBLOCK)), } } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { let mut handles = self.handles.lock(); let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; let mut i = 0; - let scheme_path = b"audiohw:"; + let scheme_path = b"/scheme/audiohw"; while i < buf.len() && i < scheme_path.len() { buf[i] = scheme_path[i]; i += 1; } - Ok(Some(i)) + Ok(i) } - fn close(&mut self, id: usize) -> Result> { - let mut handles = self.handles.lock(); - handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) + fn on_close(&mut self, id: usize) { + let _ = self.handles.lock().remove(&id); } } diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index 3d9d32ca73..c1f4cd681f 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -3,12 +3,13 @@ extern crate event; extern crate spin; extern crate syscall; -use libredox::flag; +use redox_scheme::wrappers::ReadinessBased; +use redox_scheme::Socket; +use std::cell::RefCell; use std::fs::File; -use std::io::{ErrorKind, Read, Write}; -use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; +use std::io::{Read, Write}; +use std::os::unix::io::AsRawFd; use std::usize; -use syscall::{Packet, SchemeBlockMut}; use event::{user_data, EventQueue}; use pcid_interface::irq_helpers::pci_allocate_interrupt_vector; @@ -56,24 +57,22 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { } } - let socket_fd = libredox::call::open( - ":audiohw", - flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, - 0, - ) - .expect("ihdad: failed to create hda scheme"); - let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + let event_queue = + EventQueue::::new().expect("ihdad: Could not create event queue."); + let device = RefCell::new(unsafe { + hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") + }); + let socket = Socket::nonblock("audiohw").expect("ihdad: failed to create socket"); + let mut readiness_based = ReadinessBased::new(&socket, 16); daemon.ready().expect("ihdad: failed to signal readiness"); - let event_queue = - EventQueue::::new().expect("ihdad: Could not create event queue."); - let mut device = unsafe { - hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device") - }; - event_queue - .subscribe(socket_fd, Source::Scheme, event::EventFlags::READ) + .subscribe( + socket.inner().raw(), + Source::Scheme, + event::EventFlags::READ, + ) .unwrap(); event_queue .subscribe( @@ -85,11 +84,9 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { libredox::call::setrens(0, 0).expect("ihdad: failed to enter null namespace"); - let mut todo = Vec::::new(); - let all = [Source::Irq, Source::Scheme]; - 'events: for event in all + for event in all .into_iter() .chain(event_queue.map(|e| e.expect("failed to get next event").user_data)) { @@ -98,49 +95,35 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let mut irq = [0; 8]; irq_file.read(&mut irq).unwrap(); - if device.irq() { - irq_file.write(&mut irq).unwrap(); - - let mut i = 0; - while i < todo.len() { - if let Some(a) = device.handle(&mut todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket.write(&packet).unwrap(); - } else { - i += 1; - } - } - - /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ + if !device.borrow_mut().irq() { + continue; } + irq_file.write(&mut irq).unwrap(); + + readiness_based + .poll_all_requests(|| device.borrow_mut()) + .expect("ihdad: failed to poll requests"); + + /* + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ } Source::Scheme => { - loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => break 'events, - Ok(_) => (), - Err(err) => { - if err.kind() == ErrorKind::WouldBlock { - break; - } else { - panic!("ihdad: failed to read from socket: {err}"); - } - } - } - - if let Some(a) = device.handle(&mut packet) { - packet.a = a; - socket.write(&packet).unwrap(); - } else { - todo.push(packet); - } + if !readiness_based + .read_requests() + .expect("ihdad: failed to read from socket") + { + break; + } + readiness_based.process_requests(|| device.borrow_mut()); + if !readiness_based + .write_responses() + .expect("ihdad: failed to write to socket") + { + break; } /* diff --git a/audio/sb16d/Cargo.toml b/audio/sb16d/Cargo.toml index 29ff243ab8..7e6112edaf 100644 --- a/audio/sb16d/Cargo.toml +++ b/audio/sb16d/Cargo.toml @@ -12,3 +12,4 @@ redox-daemon = "0.1" redox_event = "0.4.1" redox_syscall = "0.5" spin = "0.9" +redox-scheme = "0.8.2" diff --git a/audio/sb16d/src/device.rs b/audio/sb16d/src/device.rs index 36a6e94b8c..ae9f4a0f04 100644 --- a/audio/sb16d/src/device.rs +++ b/audio/sb16d/src/device.rs @@ -6,8 +6,11 @@ use std::{thread, time}; use common::io::{Io, Pio, ReadOnly, WriteOnly}; +use redox_scheme::scheme::SchemeSync; +use redox_scheme::CallerCtx; +use redox_scheme::OpenResult; use syscall::error::{Error, Result, EACCES, EBADF, ENODEV}; -use syscall::scheme::SchemeBlockMut; +use syscall::schemev2::NewFdFlags; use spin::Mutex; @@ -181,40 +184,46 @@ impl Sb16 { } } -impl SchemeBlockMut for Sb16 { - fn open(&mut self, _path: &str, _flags: usize, uid: u32, _gid: u32) -> Result> { - if uid == 0 { +impl SchemeSync for Sb16 { + fn open(&mut self, _path: &str, _flags: usize, ctx: &CallerCtx) -> Result { + if ctx.uid == 0 { let id = self.next_id.fetch_add(1, Ordering::SeqCst); self.handles.lock().insert(id, Handle::Todo); - Ok(Some(id)) + Ok(OpenResult::ThisScheme { + number: id, + flags: NewFdFlags::empty(), + }) } else { Err(Error::new(EACCES)) } } - fn write(&mut self, _id: usize, _buf: &[u8]) -> Result> { + fn write( + &mut self, + _id: usize, + _buf: &[u8], + _offset: u64, + _flags: u32, + _ctx: &CallerCtx, + ) -> Result { //TODO Err(Error::new(EBADF)) } - fn fpath(&mut self, id: usize, buf: &mut [u8]) -> Result> { + fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result { let mut handles = self.handles.lock(); let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?; let mut i = 0; - let scheme_path = b"audiohw:"; + let scheme_path = b"/scheme/audiohw"; while i < buf.len() && i < scheme_path.len() { buf[i] = scheme_path[i]; i += 1; } - Ok(Some(i)) + Ok(i) } - fn close(&mut self, id: usize) -> Result> { - let mut handles = self.handles.lock(); - handles - .remove(&id) - .ok_or(Error::new(EBADF)) - .and(Ok(Some(0))) + fn on_close(&mut self, id: usize) { + let _ = self.handles.lock().remove(&id); } } diff --git a/audio/sb16d/src/main.rs b/audio/sb16d/src/main.rs index bf5c7227db..4c47f46d1d 100644 --- a/audio/sb16d/src/main.rs +++ b/audio/sb16d/src/main.rs @@ -1,9 +1,10 @@ //#![deny(warnings)] -use libredox::errno::{EAGAIN, EWOULDBLOCK}; use libredox::{flag, Fd}; +use redox_scheme::wrappers::ReadinessBased; +use redox_scheme::Socket; +use std::cell::RefCell; use std::{env, usize}; -use syscall::{Packet, SchemeBlockMut}; use event::{user_data, EventQueue}; @@ -29,17 +30,14 @@ fn main() { common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights"); - let mut device = - unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") }; - let socket = Fd::open( - ":audiohw", - flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, - 0, - ) - .expect("sb16d: failed to create hda scheme"); + let device = RefCell::new(unsafe { + device::Sb16::new(addr).expect("sb16d: failed to allocate device") + }); + let socket = Socket::nonblock("audiohw").expect("sb16d: failed to create socket"); + let mut readiness_based = ReadinessBased::new(&socket, 16); //TODO: error on multiple IRQs? - let irq_file = match device.irqs.first() { + let irq_file = match device.borrow().irqs.first() { Some(irq) => Fd::open(&format!("/scheme/irq/{}", irq), flag::O_RDWR, 0) .expect("sb16d: failed to open IRQ file"), None => panic!("sb16d: no IRQs found"), @@ -57,18 +55,20 @@ fn main() { .subscribe(irq_file.raw(), Source::Irq, event::EventFlags::READ) .unwrap(); event_queue - .subscribe(socket.raw(), Source::Scheme, event::EventFlags::READ) + .subscribe( + socket.inner().raw(), + Source::Scheme, + event::EventFlags::READ, + ) .unwrap(); daemon.ready().expect("sb16d: failed to signal readiness"); libredox::call::setrens(0, 0).expect("sb16d: failed to enter null namespace"); - let mut todo = Vec::::new(); - let all = [Source::Irq, Source::Scheme]; - 'events: for event in all + for event in all .into_iter() .chain(event_queue.map(|e| e.expect("sb16d: failed to get next event").user_data)) { @@ -77,53 +77,37 @@ fn main() { let mut irq = [0; 8]; irq_file.read(&mut irq).unwrap(); - if device.irq() { - irq_file.write(&mut irq).unwrap(); + if !device.borrow_mut().irq() { + continue; + } + irq_file.write(&mut irq).unwrap(); - let mut i = 0; - while i < todo.len() { - if let Some(a) = device.handle(&mut todo[i]) { - let mut packet = todo.remove(i); - packet.a = a; - socket - .write(&packet) - .expect("sb16d: failed to write to socket"); - } else { - i += 1; - } - } + readiness_based + .poll_all_requests(|| device.borrow_mut()) + .expect("sb16d: failed to poll requests"); - /* - let next_read = device_irq.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ + /* + let next_read = device_irq.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + } + Source::Scheme => { + if !readiness_based + .read_requests() + .expect("sb16d: failed to read from socket") + { + break; + } + readiness_based.process_requests(|| device.borrow_mut()); + if !readiness_based + .write_responses() + .expect("sb16d: failed to write to socket") + { + break; } } - Source::Scheme => loop { - let mut packet = Packet::default(); - match socket.read(&mut packet) { - Ok(0) => break 'events, - Ok(_) => (), - Err(err) => { - if err.errno() == EWOULDBLOCK || err.errno() == EAGAIN { - break; - } else { - panic!("sb16d: failed to read from scheme socket"); - } - } - } - - if let Some(a) = device.handle(&mut packet) { - packet.a = a; - socket - .write(&packet) - .expect("sb16d: failed to write to scheme socket"); - } else { - todo.push(packet); - } - }, } } diff --git a/net/alxd/Cargo.toml b/net/alxd/Cargo.toml index af09892e0b..312da94841 100644 --- a/net/alxd/Cargo.toml +++ b/net/alxd/Cargo.toml @@ -11,3 +11,4 @@ redox-daemon = "0.1" common = { path = "../../common" } libredox = "0.1.3" +redox-scheme = "0.8.2" diff --git a/net/alxd/src/device/mod.rs b/net/alxd/src/device/mod.rs index 17746e8f2e..94a09b8a86 100644 --- a/net/alxd/src/device/mod.rs +++ b/net/alxd/src/device/mod.rs @@ -2,9 +2,12 @@ use std::convert::TryInto; use std::{ptr, thread, time}; use common::io::{Io, Mmio}; +use redox_scheme::scheme::SchemeSync; +use redox_scheme::CallerCtx; +use redox_scheme::OpenResult; use syscall::error::{Error, Result, EACCES, EINVAL, EIO, EWOULDBLOCK}; use syscall::flag::{EventFlags, O_NONBLOCK}; -use syscall::scheme; +use syscall::schemev2::NewFdFlags; use common::dma::Dma; @@ -368,7 +371,7 @@ impl Alx { */ self.imask &= !ISR_PHY; let imask = self.imask; - self.write(IMR, imask); + self.reg_write(IMR, imask); self.flag |= FLAG_TASK_CHK_LINK; self.task(); } @@ -379,7 +382,7 @@ impl Alx { unsafe fn intr_1(&mut self, mut intr: u32) -> bool { /* ACK interrupt */ println!("ACK interrupt: {:X}", intr | ISR_DIS); - self.write(ISR, intr | ISR_DIS); + self.reg_write(ISR, intr | ISR_DIS); intr &= self.imask; if (self.handle_intr_misc(intr)) { @@ -392,19 +395,19 @@ impl Alx { /* mask rx/tx interrupt, enable them when napi complete */ self.imask &= !ISR_ALL_QUEUES; let imask = self.imask; - self.write(IMR, imask); + self.reg_write(IMR, imask); } - self.write(ISR, 0); + self.reg_write(ISR, 0); return true; } pub unsafe fn intr_legacy(&mut self) -> bool { /* read interrupt status */ - let intr = self.read(ISR); + let intr = self.reg_read(ISR); if (intr & ISR_DIS > 0 || intr & self.imask == 0) { - let mask = self.read(IMR); + let mask = self.reg_read(IMR); println!( "seems a wild interrupt, intr={:X}, imask={:X}, mask={:X}", intr, self.imask, mask @@ -416,10 +419,10 @@ impl Alx { return self.intr_1(intr); } - pub fn next_read(&self) -> usize { + pub fn next_reg_read(&self) -> usize { /* - let head = unsafe { self.read(RDH) }; - let mut tail = unsafe { self.read(RDT) }; + let head = unsafe { self.reg_read(RDH) }; + let mut tail = unsafe { self.reg_read(RDT) }; tail += 1; if tail >= self.receive_ring.len() as u32 { @@ -438,11 +441,11 @@ impl Alx { 0 } - unsafe fn read(&self, register: u32) -> u32 { + unsafe fn reg_read(&self, register: u32) -> u32 { ptr::read_volatile((self.base + register as usize) as *mut u32) } - unsafe fn write(&self, register: u32, data: u32) -> u32 { + unsafe fn reg_write(&self, register: u32, data: u32) -> u32 { ptr::write_volatile((self.base + register as usize) as *mut u32, data); ptr::read_volatile((self.base + register as usize) as *mut u32) } @@ -452,7 +455,7 @@ impl Alx { let mut i: u32 = 0; while (i < MDIO_MAX_AC_TO) { - val = self.read(MDIO); + val = self.reg_read(MDIO); if (val & MDIO_BUSY == 0) { break; } @@ -467,7 +470,7 @@ impl Alx { return; } - self.write(MDIO, 0); + self.reg_write(MDIO, 0); self.wait_mdio_idle(); } @@ -483,11 +486,11 @@ impl Alx { | FIELDX!(MDIO_REG, 1) | MDIO_START | MDIO_OP_READ; - self.write(MDIO, val); + self.reg_write(MDIO, val); self.wait_mdio_idle(); val |= MDIO_AUTO_POLLING; val &= !MDIO_START; - self.write(MDIO, val); + self.reg_write(MDIO, val); udelay(30); } @@ -509,7 +512,7 @@ impl Alx { if (ext) { val = FIELDX!(MDIO_EXTN_DEVAD, dev) | FIELDX!(MDIO_EXTN_REG, reg); - self.write(MDIO_EXTN, val); + self.reg_write(MDIO_EXTN, val); val = MDIO_SPRES_PRMBL | FIELDX!(MDIO_CLK_SEL, clk_sel) @@ -523,12 +526,12 @@ impl Alx { | MDIO_START | MDIO_OP_READ; } - self.write(MDIO, val); + self.reg_write(MDIO, val); if (!self.wait_mdio_idle()) { err = ERR_MIIBUSY; } else { - val = self.read(MDIO); + val = self.reg_read(MDIO); *phy_data = FIELD_GETX!(val, MDIO_DATA) as u16; err = 0; } @@ -554,7 +557,7 @@ impl Alx { if (ext) { val = FIELDX!(MDIO_EXTN_DEVAD, dev) | FIELDX!(MDIO_EXTN_REG, reg); - self.write(MDIO_EXTN, val); + self.reg_write(MDIO_EXTN, val); val = MDIO_SPRES_PRMBL | FIELDX!(MDIO_CLK_SEL, clk_sel) @@ -568,7 +571,7 @@ impl Alx { | FIELDX!(MDIO_DATA, phy_data) | MDIO_START; } - self.write(MDIO, val); + self.reg_write(MDIO, val); if !self.wait_mdio_idle() { err = ERR_MIIBUSY; @@ -617,7 +620,7 @@ impl Alx { let mut pmctrl: u32; let rev: u8 = self.revid(); - pmctrl = self.read(PMCTRL); + pmctrl = self.reg_read(PMCTRL); FIELD_SET32!(pmctrl, PMCTRL_LCKDET_TIMER, PMCTRL_LCKDET_TIMER_DEF); pmctrl |= PMCTRL_RCVR_WT_1US | PMCTRL_L1_CLKSW_EN | PMCTRL_L1_SRDSRX_PWD; @@ -644,7 +647,7 @@ impl Alx { pmctrl |= (PMCTRL_L1_EN | PMCTRL_ASPM_FCEN); } - self.write(PMCTRL, pmctrl); + self.reg_write(PMCTRL, pmctrl); } unsafe fn reset_pcie(&mut self) { @@ -663,27 +666,27 @@ impl Alx { } /* clear WoL setting/status */ - self.read(WOL0); - self.write(WOL0, 0); + self.reg_read(WOL0); + self.reg_write(WOL0, 0); /* deflt val of PDLL D3PLLOFF */ - val = self.read(PDLL_TRNS1); - self.write(PDLL_TRNS1, val & !PDLL_TRNS1_D3PLLOFF_EN); + val = self.reg_read(PDLL_TRNS1); + self.reg_write(PDLL_TRNS1, val & !PDLL_TRNS1_D3PLLOFF_EN); /* mask some pcie error bits */ - val = self.read(UE_SVRT); + val = self.reg_read(UE_SVRT); val &= !(UE_SVRT_DLPROTERR | UE_SVRT_FCPROTERR); - self.write(UE_SVRT, val); + self.reg_write(UE_SVRT, val); /* wol 25M & pclk */ - val = self.read(MASTER); + val = self.reg_read(MASTER); if ((rev == REV_A0 || rev == REV_A1) && self.with_cr()) { if ((val & MASTER_WAKEN_25M) == 0 || (val & MASTER_PCLKSEL_SRDS) == 0) { - self.write(MASTER, val | MASTER_PCLKSEL_SRDS | MASTER_WAKEN_25M); + self.reg_write(MASTER, val | MASTER_PCLKSEL_SRDS | MASTER_WAKEN_25M); } } else { if ((val & MASTER_WAKEN_25M) == 0 || (val & MASTER_PCLKSEL_SRDS) != 0) { - self.write(MASTER, (val & !MASTER_PCLKSEL_SRDS) | MASTER_WAKEN_25M); + self.reg_write(MASTER, (val & !MASTER_PCLKSEL_SRDS) | MASTER_WAKEN_25M); } } @@ -701,7 +704,7 @@ impl Alx { let mut phy_val: u16 = 0; /* (DSP)reset PHY core */ - val = self.read(PHY_CTRL); + val = self.reg_read(PHY_CTRL); val &= !(PHY_CTRL_DSPRST_OUT | PHY_CTRL_IDDQ | PHY_CTRL_GATE_25M @@ -714,9 +717,9 @@ impl Alx { } else { val &= !(PHY_CTRL_HIB_PULSE | PHY_CTRL_HIB_EN); } - self.write(PHY_CTRL, val); + self.reg_write(PHY_CTRL, val); udelay(10); - self.write(PHY_CTRL, val | PHY_CTRL_DSPRST_OUT); + self.reg_write(PHY_CTRL, val | PHY_CTRL_DSPRST_OUT); /* delay 800us */ i = 0; @@ -748,8 +751,8 @@ impl Alx { /* half amplify */ self.write_phy_dbg(MIIDBG_AZ_ANADECT, AZ_ANADECT_DEF); } else { - val = self.read(LPI_CTRL); - self.write(LPI_CTRL, val & (!LPI_CTRL_EN)); + val = self.reg_read(LPI_CTRL); + self.reg_write(LPI_CTRL, val & (!LPI_CTRL_EN)); self.write_phy_ext(MIIEXT_ANEG, MIIEXT_LOCAL_EEEADV, 0); } @@ -795,19 +798,19 @@ impl Alx { let mut val: u32; let mut i: u32; - rxq = self.read(RXQ0); - self.write(RXQ0, rxq & (!RXQ0_EN)); - txq = self.read(TXQ0); - self.write(TXQ0, txq & (!TXQ0_EN)); + rxq = self.reg_read(RXQ0); + self.reg_write(RXQ0, rxq & (!RXQ0_EN)); + txq = self.reg_read(TXQ0); + self.reg_write(TXQ0, txq & (!TXQ0_EN)); udelay(40); self.rx_ctrl &= !(MAC_CTRL_RX_EN | MAC_CTRL_TX_EN); - self.write(MAC_CTRL, self.rx_ctrl); + self.reg_write(MAC_CTRL, self.rx_ctrl); i = 0; while i < DMA_MAC_RST_TO { - val = self.read(MAC_STS); + val = self.reg_read(MAC_STS); if (val & MAC_STS_IDLE == 0) { break; } @@ -827,10 +830,10 @@ impl Alx { let txq: u32; let rxq: u32; - rxq = self.read(RXQ0); - self.write(RXQ0, rxq | RXQ0_EN); - txq = self.read(TXQ0); - self.write(TXQ0, txq | TXQ0_EN); + rxq = self.reg_read(RXQ0); + self.reg_write(RXQ0, rxq | RXQ0_EN); + txq = self.reg_read(TXQ0); + self.reg_write(TXQ0, txq | TXQ0_EN); mac = self.rx_ctrl; if (self.link_duplex == FULL_DUPLEX) { @@ -849,7 +852,7 @@ impl Alx { ); mac |= MAC_CTRL_TX_EN | MAC_CTRL_RX_EN; self.rx_ctrl = mac; - self.write(MAC_CTRL, mac); + self.reg_write(MAC_CTRL, mac); } unsafe fn reset_osc(&mut self, rev: u8) { @@ -857,13 +860,13 @@ impl Alx { let mut val2: u32; /* clear Internal OSC settings, switching OSC by hw itself */ - val = self.read(MISC3); - self.write(MISC3, (val & !MISC3_25M_BY_SW) | MISC3_25M_NOTO_INTNL); + val = self.reg_read(MISC3); + self.reg_write(MISC3, (val & !MISC3_25M_BY_SW) | MISC3_25M_NOTO_INTNL); /* 25M clk from chipset may be unstable 1s after de-assert of * PERST, driver need re-calibrate before enter Sleep for WoL */ - val = self.read(MISC); + val = self.reg_read(MISC); if (rev >= REV_B0) { /* restore over current protection def-val, * this val could be reset by MAC-RST @@ -871,13 +874,13 @@ impl Alx { FIELD_SET32!(val, MISC_PSW_OCP, MISC_PSW_OCP_DEF); /* a 0->1 change will update the internal val of osc */ val &= !MISC_INTNLOSC_OPEN; - self.write(MISC, val); - self.write(MISC, val | MISC_INTNLOSC_OPEN); + self.reg_write(MISC, val); + self.reg_write(MISC, val | MISC_INTNLOSC_OPEN); /* hw will automatically dis OSC after cab. */ - val2 = self.read(MSIC2); + val2 = self.reg_read(MSIC2); val2 &= !MSIC2_CALB_START; - self.write(MSIC2, val2); - self.write(MSIC2, val2 | MSIC2_CALB_START); + self.reg_write(MSIC2, val2); + self.reg_write(MSIC2, val2 | MSIC2_CALB_START); } else { val &= !MISC_INTNLOSC_OPEN; /* disable isoloate for A0 */ @@ -885,8 +888,8 @@ impl Alx { val &= !MISC_ISO_EN; } - self.write(MISC, val | MISC_INTNLOSC_OPEN); - self.write(MISC, val); + self.reg_write(MISC, val | MISC_INTNLOSC_OPEN); + self.reg_write(MISC, val); } udelay(20); @@ -905,9 +908,9 @@ impl Alx { a_cr = (rev == REV_A0 || rev == REV_A1) && self.with_cr(); /* disable all interrupts, RXQ/TXQ */ - self.write(MSIX_MASK, 0xFFFFFFFF); - self.write(IMR, 0); - self.write(ISR, ISR_DIS); + self.reg_write(MSIX_MASK, 0xFFFFFFFF); + self.reg_write(IMR, 0); + self.reg_write(ISR, ISR_DIS); ret = self.stop_mac(); if (ret > 0) { @@ -915,25 +918,25 @@ impl Alx { } /* mac reset workaroud */ - self.write(RFD_PIDX, 1); + self.reg_write(RFD_PIDX, 1); /* dis l0s/l1 before mac reset */ if (a_cr) { - pmctrl = self.read(PMCTRL); + pmctrl = self.reg_read(PMCTRL); if ((pmctrl & (PMCTRL_L1_EN | PMCTRL_L0S_EN)) != 0) { - self.write(PMCTRL, pmctrl & !(PMCTRL_L1_EN | PMCTRL_L0S_EN)); + self.reg_write(PMCTRL, pmctrl & !(PMCTRL_L1_EN | PMCTRL_L0S_EN)); } } /* reset whole mac safely */ - val = self.read(MASTER); - self.write(MASTER, val | MASTER_DMA_MAC_RST | MASTER_OOB_DIS); + val = self.reg_read(MASTER); + self.reg_write(MASTER, val | MASTER_DMA_MAC_RST | MASTER_OOB_DIS); /* make sure it's real idle */ udelay(10); i = 0; while (i < DMA_MAC_RST_TO) { - val = self.read(RFD_PIDX); + val = self.reg_read(RFD_PIDX); if (val == 0) { break; } @@ -941,7 +944,7 @@ impl Alx { i += 1; } while (i < DMA_MAC_RST_TO) { - val = self.read(MASTER); + val = self.reg_read(MASTER); if ((val & MASTER_DMA_MAC_RST) == 0) { break; } @@ -955,10 +958,10 @@ impl Alx { if (a_cr) { /* set MASTER_PCLKSEL_SRDS (affect by soft-rst, PERST) */ - self.write(MASTER, val | MASTER_PCLKSEL_SRDS); + self.reg_write(MASTER, val | MASTER_PCLKSEL_SRDS); /* resoter l0s / l1 */ if (pmctrl & (PMCTRL_L1_EN | PMCTRL_L0S_EN) > 0) { - self.write(PMCTRL, pmctrl); + self.reg_write(PMCTRL, pmctrl); } } @@ -966,22 +969,22 @@ impl Alx { /* clear Internal OSC settings, switching OSC by hw itself, * disable isoloate for A version */ - val = self.read(MISC3); - self.write(MISC3, (val & !MISC3_25M_BY_SW) | MISC3_25M_NOTO_INTNL); - val = self.read(MISC); + val = self.reg_read(MISC3); + self.reg_write(MISC3, (val & !MISC3_25M_BY_SW) | MISC3_25M_NOTO_INTNL); + val = self.reg_read(MISC); val &= !MISC_INTNLOSC_OPEN; if (rev == REV_A0 || rev == REV_A1) { val &= !MISC_ISO_EN; } - self.write(MISC, val); + self.reg_write(MISC, val); udelay(20); /* driver control speed/duplex, hash-alg */ - self.write(MAC_CTRL, self.rx_ctrl); + self.reg_write(MAC_CTRL, self.rx_ctrl); /* clk sw */ - val = self.read(SERDES); - self.write(SERDES, val | SERDES_MACCLK_SLWDWN | SERDES_PHYCLK_SLWDWN); + val = self.reg_read(SERDES); + self.reg_write(SERDES, val | SERDES_MACCLK_SLWDWN | SERDES_PHYCLK_SLWDWN); /* mac reset cause MDIO ctrl restore non-polling status */ if (self.is_fpga) { @@ -1053,7 +1056,7 @@ impl Alx { /* clear flag */ self.write_phy_reg(MII_DBG_ADDR, 0); - val = self.read(DRV); + val = self.reg_read(DRV); FIELD_SET32!(val, DRV_PHY, 0); if (ethadv & ADVERTISED_Autoneg > 0) { @@ -1101,14 +1104,14 @@ impl Alx { val |= self.ethadv_to_hw_cfg(ethadv); } - self.write(DRV, val); + self.reg_write(DRV, val); return err; } unsafe fn get_perm_macaddr(&mut self) -> [u8; 6] { - let mac_low = self.read(STAD0); - let mac_high = self.read(STAD1); + let mac_low = self.reg_read(STAD0); + let mac_high = self.reg_read(STAD1); [ mac_low as u8, (mac_low >> 8) as u8, @@ -1195,30 +1198,30 @@ impl Alx { //TODO alx_set_macaddr(hw, self.mac_addr); /* clk gating */ - self.write(CLK_GATE, CLK_GATE_ALL_A0); + self.reg_write(CLK_GATE, CLK_GATE_ALL_A0); /* idle timeout to switch clk_125M */ if (chip_rev >= REV_B0) { - self.write(IDLE_DECISN_TIMER, IDLE_DECISN_TIMER_DEF); + self.reg_write(IDLE_DECISN_TIMER, IDLE_DECISN_TIMER_DEF); } /* stats refresh timeout */ - self.write(SMB_TIMER, self.smb_timer * 500); + self.reg_write(SMB_TIMER, self.smb_timer * 500); /* intr moduration */ - val = self.read(MASTER); + val = self.reg_read(MASTER); val = val | MASTER_IRQMOD2_EN | MASTER_IRQMOD1_EN | MASTER_SYSALVTIMER_EN; - self.write(MASTER, val); - self.write(IRQ_MODU_TIMER, FIELDX!(IRQ_MODU_TIMER1, self.imt >> 1)); + self.reg_write(MASTER, val); + self.reg_write(IRQ_MODU_TIMER, FIELDX!(IRQ_MODU_TIMER1, self.imt >> 1)); /* intr re-trig timeout */ - self.write(INT_RETRIG, INT_RETRIG_TO); + self.reg_write(INT_RETRIG, INT_RETRIG_TO); /* tpd threshold to trig int */ - self.write(TINT_TPD_THRSHLD, self.ith_tpd); - self.write(TINT_TIMER, self.imt as u32); + self.reg_write(TINT_TPD_THRSHLD, self.ith_tpd); + self.reg_write(TINT_TIMER, self.imt as u32); /* mtu, 8:fcs+vlan */ raw_mtu = (self.mtu + ETH_HLEN) as u32; - self.write(MTU, raw_mtu + 8); + self.reg_write(MTU, raw_mtu + 8); if (raw_mtu > MTU_JUMBO_TH) { self.rx_ctrl &= !MAC_CTRL_FAST_PAUSE; } @@ -1229,7 +1232,7 @@ impl Alx { } else { val = TXQ1_JUMBO_TSO_TH >> 3; } - self.write(TXQ1, val | TXQ1_ERRLGPKT_DROP_EN); + self.reg_write(TXQ1, val | TXQ1_ERRLGPKT_DROP_EN); /* TODO max_payload = alx_get_readrq(hw) >> 8; @@ -1247,15 +1250,15 @@ impl Alx { | TXQ0_LSO_8023_EN | TXQ0_SUPT_IPOPT | FIELDX!(TXQ0_TXF_BURST_PREF, TXQ_TXF_BURST_PREF_DEF); - self.write(TXQ0, val); + self.reg_write(TXQ0, val); val = FIELDX!(HQTPD_Q1_NUMPREF, TXQ_TPD_BURSTPREF_DEF) | FIELDX!(HQTPD_Q2_NUMPREF, TXQ_TPD_BURSTPREF_DEF) | FIELDX!(HQTPD_Q3_NUMPREF, TXQ_TPD_BURSTPREF_DEF) | HQTPD_BURST_EN; - self.write(HQTPD, val); + self.reg_write(HQTPD, val); /* rxq, flow control */ - val = self.read(SRAM5); + val = self.reg_read(SRAM5); val = FIELD_GETX!(val, SRAM_RXF_LEN) << 3; if (val > SRAM_RXF_LEN_8K) { val16 = (MTU_STD_ALGN >> 3) as u16; @@ -1264,7 +1267,7 @@ impl Alx { val16 = (MTU_STD_ALGN >> 3) as u16; val = (val - MTU_STD_ALGN) >> 3; } - self.write( + self.reg_write( RXQ2, FIELDX!(RXQ2_RXF_XOFF_THRESH, val16) | FIELDX!(RXQ2_RXF_XON_THRESH, val), ); @@ -1277,17 +1280,18 @@ impl Alx { if (self.cap & CAP_GIGA > 0) { FIELD_SET32!(val, RXQ0_ASPM_THRESH, RXQ0_ASPM_THRESH_100M); } - self.write(RXQ0, val); + self.reg_write(RXQ0, val); /* DMA */ - self.read(DMA); + self.reg_read(DMA); + val = FIELDX!(DMA_RORDER_MODE, DMA_RORDER_MODE_OUT) | DMA_RREQ_PRI_DATA | FIELDX!(DMA_RREQ_BLEN, max_payload) | FIELDX!(DMA_WDLY_CNT, DMA_WDLY_CNT_DEF) | FIELDX!(DMA_RDLY_CNT, DMA_RDLY_CNT_DEF) | FIELDX!(DMA_RCHNL_SEL, self.dma_chnl - 1); - self.write(DMA, val); + self.reg_write(DMA, val); /* multi-tx-q weight */ if (self.cap & CAP_MTQ > 0) { @@ -1296,7 +1300,7 @@ impl Alx { | FIELDX!(WRR_PRI1, self.wrr[1]) | FIELDX!(WRR_PRI2, self.wrr[2]) | FIELDX!(WRR_PRI3, self.wrr[3]); - self.write(WRR, val); + self.reg_write(WRR, val); } } @@ -1312,8 +1316,8 @@ impl Alx { alx_add_mc_addr(hw, ha->addr); */ - self.write(HASH_TBL0, self.mc_hash[0]); - self.write(HASH_TBL1, self.mc_hash[1]); + self.reg_write(HASH_TBL0, self.mc_hash[0]); + self.reg_write(HASH_TBL1, self.mc_hash[1]); /* check for Promiscuous and All Multicast modes */ self.rx_ctrl &= !(MAC_CTRL_MULTIALL_EN | MAC_CTRL_PROMISC_EN); @@ -1326,7 +1330,7 @@ impl Alx { } */ - self.write(MAC_CTRL, self.rx_ctrl); + self.reg_write(MAC_CTRL, self.rx_ctrl); } unsafe fn set_vlan_mode(&mut self, vlan_rx: bool) { @@ -1336,13 +1340,13 @@ impl Alx { self.rx_ctrl &= !MAC_CTRL_VLANSTRIP; } - self.write(MAC_CTRL, self.rx_ctrl); + self.reg_write(MAC_CTRL, self.rx_ctrl); } unsafe fn configure_rss(&mut self, en: bool) { let mut ctrl: u32; - ctrl = self.read(RXQ0); + ctrl = self.reg_read(RXQ0); if (en) { unimplemented!(); @@ -1357,7 +1361,7 @@ impl Alx { } for (i = 0; i < ARRAY_SIZE(self.rss_idt); i++) - self.write(RSS_IDT_TBL0 + i * 4, + self.reg_write(RSS_IDT_TBL0 + i * 4, self.rss_idt[i]); FIELD_SET32(ctrl, RXQ0_RSS_HSTYP, self.rss_hash_type); @@ -1369,7 +1373,7 @@ impl Alx { ctrl &= !RXQ0_RSS_HASH_EN; } - self.write(RXQ0, ctrl); + self.reg_write(RXQ0, ctrl); } unsafe fn configure(&mut self) { @@ -1380,14 +1384,14 @@ impl Alx { } unsafe fn irq_enable(&mut self) { - self.write(ISR, 0); + self.reg_write(ISR, 0); let imask = self.imask; - self.write(IMR, imask); + self.reg_write(IMR, imask); } unsafe fn irq_disable(&mut self) { - self.write(ISR, ISR_DIS); - self.write(IMR, 0); + self.reg_write(ISR, ISR_DIS); + self.reg_write(IMR, 0); } unsafe fn clear_phy_intr(&mut self) -> usize { @@ -1502,7 +1506,7 @@ impl Alx { self.flag &= !FLAG_HALT; /* clear old interrupts */ - self.write(ISR, !ISR_DIS); + self.reg_write(ISR, !ISR_DIS); self.irq_enable(); @@ -1521,8 +1525,8 @@ impl Alx { unsafe fn init_ring_ptrs(&mut self) { // Write high addresses - self.write(RX_BASE_ADDR_HI, 0); - self.write(TX_BASE_ADDR_HI, 0); + self.reg_write(RX_BASE_ADDR_HI, 0); + self.reg_write(TX_BASE_ADDR_HI, 0); // RFD ring for i in 0..self.rfd_ring.len() { @@ -1533,23 +1537,23 @@ impl Alx { .addr_high .write(((self.rfd_buffer[i].physical() as u64) >> 32) as u32); } - self.write(RFD_ADDR_LO, self.rfd_ring.physical() as u32); - self.write(RFD_RING_SZ, self.rfd_ring.len() as u32); - self.write(RFD_BUF_SZ, 16384); + self.reg_write(RFD_ADDR_LO, self.rfd_ring.physical() as u32); + self.reg_write(RFD_RING_SZ, self.rfd_ring.len() as u32); + self.reg_write(RFD_BUF_SZ, 16384); // RRD ring - self.write(RRD_ADDR_LO, self.rrd_ring.physical() as u32); - self.write(RRD_RING_SZ, self.rrd_ring.len() as u32); + self.reg_write(RRD_ADDR_LO, self.rrd_ring.physical() as u32); + self.reg_write(RRD_RING_SZ, self.rrd_ring.len() as u32); // TPD ring - self.write(TPD_PRI0_ADDR_LO, self.tpd_ring[0].physical() as u32); - self.write(TPD_PRI1_ADDR_LO, self.tpd_ring[1].physical() as u32); - self.write(TPD_PRI2_ADDR_LO, self.tpd_ring[2].physical() as u32); - self.write(TPD_PRI3_ADDR_LO, self.tpd_ring[3].physical() as u32); - self.write(TPD_RING_SZ, self.tpd_ring[0].len() as u32); + self.reg_write(TPD_PRI0_ADDR_LO, self.tpd_ring[0].physical() as u32); + self.reg_write(TPD_PRI1_ADDR_LO, self.tpd_ring[1].physical() as u32); + self.reg_write(TPD_PRI2_ADDR_LO, self.tpd_ring[2].physical() as u32); + self.reg_write(TPD_PRI3_ADDR_LO, self.tpd_ring[3].physical() as u32); + self.reg_write(TPD_RING_SZ, self.tpd_ring[0].len() as u32); // Write pointers into chip SRAM - self.write(SRAM9, SRAM_LOAD_PTR); + self.reg_write(SRAM9, SRAM_LOAD_PTR); } unsafe fn check_link(&mut self) { @@ -1587,7 +1591,7 @@ impl Alx { /* open interrutp mask */ self.imask |= ISR_PHY; let imask = self.imask; - self.write(IMR, imask); + self.reg_write(IMR, imask); if (!link_up && !self.link_up) { goto_out!(); @@ -1735,7 +1739,7 @@ impl Alx { self.flag &= !FLAG_HALT; /* clear old interrupts */ - self.write(ISR, !ISR_DIS); + self.reg_write(ISR, !ISR_DIS); self.irq_enable(); @@ -1746,19 +1750,19 @@ impl Alx { unsafe fn init(&mut self) -> Result<()> { { - let pci_id = self.read(0); + let pci_id = self.reg_read(0); self.vendor_id = pci_id as u16; self.device_id = (pci_id >> 16) as u16; } { - let pci_subid = self.read(0x2C); + let pci_subid = self.reg_read(0x2C); self.subven_id = pci_subid as u16; self.subdev_id = (pci_subid >> 16) as u16; } { - let pci_rev = self.read(8); + let pci_rev = self.reg_read(8); self.revision = pci_rev as u8; } @@ -1783,19 +1787,29 @@ impl Alx { } } -impl scheme::SchemeMut for Alx { - fn open(&mut self, _path: &str, flags: usize, uid: u32, _gid: u32) -> Result { - if uid == 0 { - Ok(flags) +impl SchemeSync for Alx { + fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result { + if ctx.uid == 0 { + Ok(OpenResult::ThisScheme { + number: flags, + flags: NewFdFlags::empty(), + }) } else { Err(Error::new(EACCES)) } } - fn read(&mut self, id: usize, _buf: &mut [u8]) -> Result { + fn read( + &mut self, + id: usize, + buf: &mut [u8], + offset: u64, + _flags: u32, + _ctx: &CallerCtx, + ) -> Result { /* - let head = unsafe { self.read(RDH) }; - let mut tail = unsafe { self.read(RDT) }; + let head = unsafe { self.reg_read(RDH) }; + let mut tail = unsafe { self.reg_read(RDT) }; tail += 1; if tail >= self.receive_ring.len() as u32 { @@ -1815,7 +1829,7 @@ impl scheme::SchemeMut for Alx { i += 1; } - unsafe { self.write(RDT, tail) }; + unsafe { self.reg_write(RDT, tail) }; return Ok(i); } @@ -1829,11 +1843,18 @@ impl scheme::SchemeMut for Alx { } } - fn write(&mut self, _id: usize, _buf: &[u8]) -> Result { + fn write( + &mut self, + id: usize, + buf: &[u8], + _offset: u64, + _flags: u32, + _ctx: &CallerCtx, + ) -> Result { /* loop { - let head = unsafe { self.read(TDH) }; - let mut tail = unsafe { self.read(TDT) }; + let head = unsafe { self.reg_read(TDH) }; + let mut tail = unsafe { self.reg_read(TDT) }; let old_tail = tail; tail += 1; @@ -1860,7 +1881,7 @@ impl scheme::SchemeMut for Alx { i += 1; } - unsafe { self.write(TDT, tail) }; + unsafe { self.reg_write(TDT, tail) }; while td.status == 0 { thread::yield_now(); @@ -1873,15 +1894,13 @@ impl scheme::SchemeMut for Alx { Ok(0) } - fn fevent(&mut self, _id: usize, _flags: EventFlags) -> Result { + fn fevent(&mut self, _id: usize, _flags: EventFlags, _ctx: &CallerCtx) -> Result { Ok(EventFlags::empty()) } - fn fsync(&mut self, _id: usize) -> Result { - Ok(0) + fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> { + Ok(()) } - fn close(&mut self, _id: usize) -> Result { - Ok(0) - } + fn on_close(&mut self, _id: usize) {} } diff --git a/net/alxd/src/main.rs b/net/alxd/src/main.rs index 7f4c11d6a9..37351c8ccd 100644 --- a/net/alxd/src/main.rs +++ b/net/alxd/src/main.rs @@ -14,8 +14,10 @@ use std::{env, iter}; use event::{user_data, EventQueue}; use libredox::flag; +use redox_scheme::wrappers::ReadinessBased; +use redox_scheme::Socket; +use std::cell::RefCell; use syscall::error::EWOULDBLOCK; -use syscall::{Packet, SchemeMut}; pub mod device; @@ -35,13 +37,8 @@ fn main() { // Daemonize redox_daemon::Daemon::new(move |daemon| { - let socket_fd = libredox::call::open( - ":network", - flag::O_RDWR | flag::O_CREAT | flag::O_NONBLOCK, - 0, - ) - .expect("alxd: failed to create network scheme"); - let mut socket = unsafe { File::from_raw_fd(socket_fd as RawFd) }; + let socket = Socket::nonblock("network").expect("alxd: failed to create socket"); + let mut readiness_based = ReadinessBased::new(&socket, 16); daemon.ready().expect("alxd: failed to signal readiness"); @@ -58,8 +55,9 @@ fn main() { .expect("alxd: failed to map address") as usize }; { - let mut device = - unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") }; + let device = RefCell::new(unsafe { + device::Alx::new(address).expect("alxd: failed to allocate device") + }); user_data! { enum Source { @@ -78,13 +76,15 @@ fn main() { ) .unwrap(); event_queue - .subscribe(socket_fd, Source::Scheme, event::EventFlags::READ) + .subscribe( + socket.inner().raw(), + Source::Scheme, + event::EventFlags::READ, + ) .unwrap(); libredox::call::setrens(0, 0).expect("alxd: failed to enter null namespace"); - let mut todo = Vec::::new(); - for event in iter::once(Source::Scheme) .chain(event_queue.map(|e| e.expect("alxd: failed to get next event").user_data)) { @@ -92,53 +92,36 @@ fn main() { Source::Irq => { let mut irq = [0; 8]; irq_file.read(&mut irq).unwrap(); - if unsafe { device.intr_legacy() } { - irq_file.write(&mut irq).unwrap(); - - let mut i = 0; - while i < todo.len() { - let a = todo[i].a; - device.handle(&mut todo[i]); - if todo[i].a == (-EWOULDBLOCK) as usize { - todo[i].a = a; - i += 1; - } else { - socket - .write(&mut todo[i]) - .expect("alxd: failed to write to socket"); - todo.remove(i); - } - } - - /* TODO: Currently a no-op - let next_read = device.next_read(); - if next_read > 0 { - return Ok(Some(next_read)); - } - */ + if !unsafe { device.borrow_mut().intr_legacy() } { + continue; } - } - Source::Scheme => { - loop { - let mut packet = Packet::default(); - if socket - .read(&mut packet) - .expect("alxd: failed read from socket") - == 0 - { - break; - } + irq_file.write(&mut irq).unwrap(); - let a = packet.a; - device.handle(&mut packet); - if packet.a == (-EWOULDBLOCK) as usize { - packet.a = a; - todo.push(packet); - } else { - socket - .write(&mut packet) - .expect("alxd: failed to write to socket"); - } + readiness_based + .poll_all_requests(|| device.borrow_mut()) + .expect("ihdad: failed to poll requests"); + + /* TODO: Currently a no-op + let next_read = device.next_read(); + if next_read > 0 { + return Ok(Some(next_read)); + } + */ + } + + Source::Scheme => { + if !readiness_based + .read_requests() + .expect("alxd: failed to read from socket") + { + break; + } + readiness_based.process_requests(|| device.borrow_mut()); + if !readiness_based + .write_responses() + .expect("alxd: failed to write to socket") + { + break; } // TODO From 5c55c4bb168ddff12d773fefaa373cb47ba8cee3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 15 Jun 2024 21:16:38 +0200 Subject: [PATCH 1299/1301] Use pci_allocate_interrupt_vector in nvmed --- audio/ihdad/src/main.rs | 6 +- net/rtl8139d/src/main.rs | 6 +- net/rtl8168d/src/main.rs | 6 +- pcid/src/driver_interface/irq_helpers.rs | 72 +++++++++++-- storage/nvmed/src/main.rs | 111 ++------------------ storage/nvmed/src/nvme/mod.rs | 123 ++++++----------------- 6 files changed, 110 insertions(+), 214 deletions(-) diff --git a/audio/ihdad/src/main.rs b/audio/ihdad/src/main.rs index c1f4cd681f..687b7745d5 100755 --- a/audio/ihdad/src/main.rs +++ b/audio/ihdad/src/main.rs @@ -76,7 +76,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { .unwrap(); event_queue .subscribe( - irq_file.as_raw_fd() as usize, + irq_file.irq_handle().as_raw_fd() as usize, Source::Irq, event::EventFlags::READ, ) @@ -93,12 +93,12 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { match event { Source::Irq => { let mut irq = [0; 8]; - irq_file.read(&mut irq).unwrap(); + irq_file.irq_handle().read(&mut irq).unwrap(); if !device.borrow_mut().irq() { continue; } - irq_file.write(&mut irq).unwrap(); + irq_file.irq_handle().write(&mut irq).unwrap(); readiness_based .poll_all_requests(|| device.borrow_mut()) diff --git a/net/rtl8139d/src/main.rs b/net/rtl8139d/src/main.rs index bdd150982e..2f3533978e 100644 --- a/net/rtl8139d/src/main.rs +++ b/net/rtl8139d/src/main.rs @@ -75,7 +75,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let event_queue = EventQueue::::new().expect("rtl8139d: Could not create event queue."); event_queue .subscribe( - irq_file.as_raw_fd() as usize, + irq_file.irq_handle().as_raw_fd() as usize, Source::Irq, event::EventFlags::READ, ) @@ -96,10 +96,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { match event.user_data { Source::Irq => { let mut irq = [0; 8]; - irq_file.read(&mut irq).unwrap(); + irq_file.irq_handle().read(&mut irq).unwrap(); //TODO: This may be causing spurious interrupts if unsafe { scheme.adapter_mut().irq() } { - irq_file.write(&mut irq).unwrap(); + irq_file.irq_handle().write(&mut irq).unwrap(); scheme.tick().unwrap(); } diff --git a/net/rtl8168d/src/main.rs b/net/rtl8168d/src/main.rs index c477c0aaeb..f89c9d9825 100644 --- a/net/rtl8168d/src/main.rs +++ b/net/rtl8168d/src/main.rs @@ -75,7 +75,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let event_queue = EventQueue::::new().expect("rtl8168d: Could not create event queue."); event_queue .subscribe( - irq_file.as_raw_fd() as usize, + irq_file.irq_handle().as_raw_fd() as usize, Source::Irq, event::EventFlags::READ, ) @@ -96,10 +96,10 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { match event.user_data { Source::Irq => { let mut irq = [0; 8]; - irq_file.read(&mut irq).unwrap(); + irq_file.irq_handle().read(&mut irq).unwrap(); //TODO: This may be causing spurious interrupts if unsafe { scheme.adapter_mut().irq() } { - irq_file.write(&mut irq).unwrap(); + irq_file.irq_handle().write(&mut irq).unwrap(); scheme.tick().unwrap(); } diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index 3db1c97ce2..7ed060bce0 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -8,7 +8,7 @@ use std::fs::{self, File}; use std::io::{self, prelude::*}; use std::num::NonZeroU8; -use crate::driver_interface::msi::MsiAddrAndData; +use crate::driver_interface::msi::{MsiAddrAndData, MsixTableEntry}; /// Read the local APIC ID of the bootstrap processor. pub fn read_bsp_apic_id() -> io::Result { @@ -228,24 +228,59 @@ pub fn allocate_first_msi_interrupt_on_bsp( interrupt_handle } +pub struct InterruptVector { + irq_handle: File, + vector: u16, + kind: InterruptVectorKind, +} + +enum InterruptVectorKind { + Legacy, + Msi, + MsiX { table_entry: *mut MsixTableEntry }, +} + +impl InterruptVector { + pub fn irq_handle(&self) -> &File { + &self.irq_handle + } + + pub fn vector(&self) -> u16 { + self.vector + } + + pub fn set_masked_if_fast(&mut self, masked: bool) -> bool { + match self.kind { + InterruptVectorKind::Legacy | InterruptVectorKind::Msi => false, + InterruptVectorKind::MsiX { table_entry } => { + unsafe { (*table_entry).set_masked(masked) }; + true + } + } + } +} + /// Get the most optimal supported interrupt mechanism: either (in the order of preference): -/// MSI-X, MSI, and INTx# pin. Returns the handles to the interrupts. +/// MSI-X, MSI, and INTx# pin. Returns both runtime interrupt structures (MSI/MSI-X capability +/// structures), and the handles to the interrupts. +// FIXME allow allocating multiple interrupt vectors +// FIXME move MSI-X IRQ allocation to pcid #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] pub fn pci_allocate_interrupt_vector( pcid_handle: &mut crate::driver_interface::PciFunctionHandle, driver: &str, -) -> File { +) -> InterruptVector { let features = pcid_handle.fetch_all_features(); let has_msi = features.iter().any(|feature| feature.is_msi()); let has_msix = features.iter().any(|feature| feature.is_msix()); if has_msix { - let capability_struct = match pcid_handle.feature_info(super::PciFeature::MsiX) { + let msix_info = match pcid_handle.feature_info(super::PciFeature::MsiX) { super::PciFeatureInfo::MsiX(msix) => msix, _ => unreachable!(), }; - let mut info = unsafe { capability_struct.map_and_mask_all(pcid_handle) }; + let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; pcid_handle.enable_feature(crate::driver_interface::PciFeature::MsiX); @@ -257,12 +292,24 @@ pub fn pci_allocate_interrupt_vector( entry.write_addr_and_data(msg_addr_and_data); entry.unmask(); - irq_handle + InterruptVector { + irq_handle, + vector: 0, + kind: InterruptVectorKind::MsiX { table_entry: entry }, + } } else if has_msi { - allocate_first_msi_interrupt_on_bsp(pcid_handle) + InterruptVector { + irq_handle: allocate_first_msi_interrupt_on_bsp(pcid_handle), + vector: 0, + kind: InterruptVectorKind::Msi, + } } else if let Some(irq) = pcid_handle.config().func.legacy_interrupt_line { // INTx# pin based interrupts. - irq.irq_handle(driver) + InterruptVector { + irq_handle: irq.irq_handle(driver), + vector: 0, + kind: InterruptVectorKind::Legacy, + } } else { panic!("{driver}: no interrupts supported at all") } @@ -270,13 +317,16 @@ pub fn pci_allocate_interrupt_vector( // FIXME support MSI on non-x86 systems #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -fn pci_allocate_interrupt_vector( +pub fn pci_allocate_interrupt_vector( pcid_handle: &mut crate::driver_interface::PciFunctionHandle, driver: &str, -) -> Vec { +) -> InterruptVector { if let Some(irq) = pcid_handle.config().func.legacy_interrupt_line { // INTx# pin based interrupts. - irq.irq_handle(driver) + InterruptVector { + irq_handle: irq.irq_handle(driver), + kind: InterruptVectorKind::Legacy, + } } else { panic!("{driver}: no interrupts supported at all") } diff --git a/storage/nvmed/src/main.rs b/storage/nvmed/src/main.rs index ed83b7809c..4437ddde3c 100644 --- a/storage/nvmed/src/main.rs +++ b/storage/nvmed/src/main.rs @@ -7,101 +7,14 @@ use std::sync::Arc; use std::usize; use driver_block::{Disk, DiskScheme}; -use pcid_interface::{PciFeature, PciFeatureInfo, PciFunction, PciFunctionHandle}; -use syscall::Result; +use pcid_interface::{irq_helpers, PciFunctionHandle}; use crate::nvme::NvmeNamespace; -use self::nvme::{InterruptMethod, InterruptSources, Nvme}; +use self::nvme::Nvme; mod nvme; -/// Get the most optimal yet functional interrupt mechanism: either (in the order of preference): -/// MSI-X, MSI, and INTx# pin. Returns both runtime interrupt structures (MSI/MSI-X capability -/// structures), and the handles to the interrupts. -#[cfg(target_arch = "x86_64")] -fn get_int_method( - pcid_handle: &mut PciFunctionHandle, - function: &PciFunction, -) -> Result<(InterruptMethod, InterruptSources)> { - log::trace!("Begin get_int_method"); - use pcid_interface::irq_helpers; - - let features = pcid_handle.fetch_all_features(); - - let has_msi = features.iter().any(|feature| feature.is_msi()); - let has_msix = features.iter().any(|feature| feature.is_msix()); - - // TODO: Allocate more than one vector when possible and useful. - if has_msix { - // Extended message signaled interrupts. - - let msix_info = match pcid_handle.feature_info(PciFeature::MsiX) { - PciFeatureInfo::MsiX(msix) => msix, - _ => unreachable!(), - }; - let mut info = unsafe { msix_info.map_and_mask_all(pcid_handle) }; - - pcid_handle.enable_feature(PciFeature::MsiX); - - let (msix_vector_number, irq_handle) = { - let entry = info.table_entry_pointer(0); - - let bsp_cpu_id = - irq_helpers::read_bsp_apic_id().expect("nvmed: failed to read APIC ID"); - let (msg_addr_and_data, irq_handle) = - irq_helpers::allocate_single_interrupt_vector_for_msi(bsp_cpu_id); - entry.write_addr_and_data(msg_addr_and_data); - entry.unmask(); - - (0, irq_handle) - }; - - let interrupt_method = InterruptMethod::MsiX(info); - let interrupt_sources = - InterruptSources::MsiX(std::iter::once((msix_vector_number, irq_handle)).collect()); - - log::trace!("Using MSI-X"); - Ok((interrupt_method, interrupt_sources)) - } else if has_msi { - // Message signaled interrupts. - - let msi_vector_number = 0; - let irq_handle = irq_helpers::allocate_first_msi_interrupt_on_bsp(pcid_handle); - - let interrupt_method = InterruptMethod::Msi; - let interrupt_sources = - InterruptSources::Msi(std::iter::once((msi_vector_number, irq_handle)).collect()); - - pcid_handle.enable_feature(PciFeature::Msi); - - log::trace!("Using MSI"); - Ok((interrupt_method, interrupt_sources)) - } else if let Some(irq) = function.legacy_interrupt_line { - // INTx# pin based interrupts. - let irq_handle = irq.irq_handle("nvmed"); - log::trace!("Using legacy interrupts"); - Ok((InterruptMethod::Intx, InterruptSources::Intx(irq_handle))) - } else { - panic!("nvmed: no interrupts supported at all") - } -} - -//TODO: MSI on non-x86_64? -#[cfg(not(target_arch = "x86_64"))] -fn get_int_method( - pcid_handle: &mut PciFunctionHandle, - function: &PciFunction, -) -> Result<(InterruptMethod, InterruptSources)> { - if let Some(irq) = function.legacy_interrupt_line { - // INTx# pin based interrupts. - let irq_handle = irq.irq_handle("nvmed"); - Ok((InterruptMethod::Intx, InterruptSources::Intx(irq_handle))) - } else { - panic!("nvmed: no interrupts supported at all") - } -} - struct NvmeDisk { nvme: Arc, ns: NvmeNamespace, @@ -164,26 +77,18 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! { let address = unsafe { pcid_handle.map_bar(0).ptr }; - let (interrupt_method, interrupt_sources) = get_int_method(&mut pcid_handle, &pci_config.func) - .expect("nvmed: failed to find a suitable interrupt method"); - let mut nvme = Nvme::new(address.as_ptr() as usize, interrupt_method, pcid_handle) + let interrupt_vector = irq_helpers::pci_allocate_interrupt_vector(&mut pcid_handle, "nvmed"); + let iv = interrupt_vector.vector(); + let irq_handle = interrupt_vector.irq_handle().try_clone().unwrap(); + + let mut nvme = Nvme::new(address.as_ptr() as usize, interrupt_vector, pcid_handle) .expect("nvmed: failed to allocate driver data"); unsafe { nvme.init().expect("nvmed: failed to init") } log::debug!("Finished base initialization"); let nvme = Arc::new(nvme); - let executor = { - let (intx, (iv, irq_handle)) = match interrupt_sources { - InterruptSources::Msi(mut vectors) => ( - false, - vectors.pop_first().map(|(a, b)| (u16::from(a), b)).unwrap(), - ), - InterruptSources::MsiX(mut vectors) => (false, vectors.pop_first().unwrap()), - InterruptSources::Intx(file) => (true, (0, file)), - }; - nvme::executor::init(Arc::clone(&nvme), iv, intx, irq_handle) - }; + let executor = nvme::executor::init(Arc::clone(&nvme), iv, false /* FIXME */, irq_handle); let mut time_handle = File::open(&format!("/scheme/time/{}", libredox::flag::CLOCK_MONOTONIC)) .expect("failed to open time handle"); diff --git a/storage/nvmed/src/nvme/mod.rs b/storage/nvmed/src/nvme/mod.rs index e7050392ec..682ee93329 100644 --- a/storage/nvmed/src/nvme/mod.rs +++ b/storage/nvmed/src/nvme/mod.rs @@ -1,12 +1,12 @@ use std::cell::RefCell; use std::collections::{BTreeMap, HashMap}; use std::convert::TryFrom; -use std::fs::File; use std::iter; use std::sync::atomic::AtomicU16; use std::sync::Arc; use parking_lot::{Mutex, ReentrantMutex, RwLock}; +use pcid_interface::irq_helpers::InterruptVector; use common::io::{Io, Mmio}; use common::timeout::Timeout; @@ -22,28 +22,8 @@ pub mod queues; use self::executor::NvmeExecutor; pub use self::queues::{NvmeCmd, NvmeCmdQueue, NvmeComp, NvmeCompQueue}; -use pcid_interface::msi::MappedMsixRegs; use pcid_interface::PciFunctionHandle; -/// Used in conjunction with `InterruptMethod`, primarily by the CQ executor. -#[derive(Debug)] -pub enum InterruptSources { - MsiX(BTreeMap), - Msi(BTreeMap), - Intx(File), -} - -/// The way interrupts are sent. Unlike other PCI-based interfaces, like XHCI, it doesn't seem like -/// NVME supports operating with interrupts completely disabled. -pub enum InterruptMethod { - /// Traditional level-triggered, INTx# interrupt pins. - Intx, - /// Message signaled interrupts - Msi, - /// Extended message signaled interrupts - MsiX(MappedMsixRegs), -} - #[repr(C, packed)] pub struct NvmeRegs { /// Controller Capabilities @@ -93,7 +73,7 @@ pub type AtomicCmdId = AtomicU16; pub type Iv = u16; pub struct Nvme { - interrupt_method: Mutex, + interrupt_vector: Mutex, pcid_interface: Mutex, regs: RwLock<&'static mut NvmeRegs>, @@ -132,7 +112,7 @@ pub enum FullSqHandling { impl Nvme { pub fn new( address: usize, - interrupt_method: InterruptMethod, + interrupt_vector: InterruptVector, pcid_interface: PciFunctionHandle, ) -> Result { Ok(Nvme { @@ -156,7 +136,7 @@ impl Nvme { cq_ivs: RwLock::new(iter::once((0, 0)).collect()), sq_ivs: RwLock::new(iter::once((0, 0)).collect()), - interrupt_method: Mutex::new(interrupt_method), + interrupt_vector: Mutex::new(interrupt_vector), pcid_interface: Mutex::new(pcid_interface), // TODO @@ -222,14 +202,9 @@ impl Nvme { } } - match self.interrupt_method.get_mut() { - &mut InterruptMethod::Intx | InterruptMethod::Msi { .. } => { - self.regs.get_mut().intms.write(0xFFFF_FFFF); - self.regs.get_mut().intmc.write(0x0000_0001); - } - &mut InterruptMethod::MsiX(ref mut cfg) => { - cfg.table_entry_pointer(0).unmask(); - } + if !self.interrupt_vector.get_mut().set_masked_if_fast(false) { + self.regs.get_mut().intms.write(0xFFFF_FFFF); + self.regs.get_mut().intmc.write(0x0000_0001); } for (qid, iv) in self.cq_ivs.get_mut().iter_mut() { @@ -296,73 +271,39 @@ impl Nvme { Ok(()) } - /// Masks or unmasks multiple vectors. - /// - /// # Panics - /// Will panic if the same vector is called twice with different mask flags. - pub fn set_vectors_masked(&self, vectors: impl IntoIterator) { - let mut interrupt_method_guard = self.interrupt_method.lock(); + pub fn set_vector_masked(&self, vector: u16, masked: bool) { + let mut interrupt_vector_guard = (&self).interrupt_vector.lock(); - match &mut *interrupt_method_guard { - &mut InterruptMethod::Intx => { - let mut iter = vectors.into_iter(); - let (vector, mask) = match iter.next() { - Some(f) => f, - None => return, - }; - assert_eq!( - iter.next(), - None, - "nvmed: internal error: multiple vectors on INTx#" + if !interrupt_vector_guard.set_masked_if_fast(masked) { + let mut to_mask = 0x0000_0000; + let mut to_clear = 0x0000_0000; + + let vector = vector as u8; + + if masked { + assert_ne!( + to_clear & (1 << vector), + (1 << vector), + "nvmed: internal error: cannot both mask and set" ); - assert_eq!(vector, 0, "nvmed: internal error: nonzero vector on INTx#"); - if mask { - self.regs.write().intms.write(0x0000_0001); - } else { - self.regs.write().intmc.write(0x0000_0001); - } + to_mask |= 1 << vector; + } else { + assert_ne!( + to_mask & (1 << vector), + (1 << vector), + "nvmed: internal error: cannot both mask and set" + ); + to_clear |= 1 << vector; } - &mut InterruptMethod::Msi => { - let mut to_mask = 0x0000_0000; - let mut to_clear = 0x0000_0000; - for (vector, mask) in vectors { - let vector = vector as u8; - - if mask { - assert_ne!( - to_clear & (1 << vector), - (1 << vector), - "nvmed: internal error: cannot both mask and set" - ); - to_mask |= 1 << vector; - } else { - assert_ne!( - to_mask & (1 << vector), - (1 << vector), - "nvmed: internal error: cannot both mask and set" - ); - to_clear |= 1 << vector; - } - } - - if to_mask != 0 { - self.regs.write().intms.write(to_mask); - } - if to_clear != 0 { - self.regs.write().intmc.write(to_clear); - } + if to_mask != 0 { + (&self).regs.write().intms.write(to_mask); } - &mut InterruptMethod::MsiX(ref mut cfg) => { - for (vector, mask) in vectors { - cfg.table_entry_pointer(vector.into()).set_masked(mask); - } + if to_clear != 0 { + (&self).regs.write().intmc.write(to_clear); } } } - pub fn set_vector_masked(&self, vector: u16, masked: bool) { - self.set_vectors_masked(std::iter::once((vector, masked))) - } pub async fn submit_and_complete_command( &self, From ce9564dd3cdf5f50f917f9c2b9fbcecc82cca6d2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 3 Mar 2025 19:51:55 +0100 Subject: [PATCH 1300/1301] graphics/bgad: Use the MMIO based interface rather than port based one This only works in QEMU, so disable bgad in VirtualBox. It currently doesn't do much useful anyway. It supports reporting the display size (which vesad already supports) and changing the display size (which doesn't really work anyway as the framebuffer mapping used by vesad doesn't get resized.) And in any case vboxd already has code to use the BGA interface for resizing that is broken to the same extend the resizing in bgad is. --- graphics/bgad/config.toml | 7 ------ graphics/bgad/src/bga.rs | 48 +++++++++++++++++++++------------------ graphics/bgad/src/main.rs | 13 +++++++---- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/graphics/bgad/config.toml b/graphics/bgad/config.toml index a07ff05bbc..c76de694b1 100644 --- a/graphics/bgad/config.toml +++ b/graphics/bgad/config.toml @@ -4,10 +4,3 @@ class = 0x03 vendor = 0x1234 device = 0x1111 command = ["bgad"] - -[[drivers]] -name = "VirtualBox Graphics Array" -class = 0x03 -vendor = 0x80EE -device = 0xBEEF -command = ["bgad"] diff --git a/graphics/bgad/src/bga.rs b/graphics/bgad/src/bga.rs index a498125c9a..5014100c2f 100644 --- a/graphics/bgad/src/bga.rs +++ b/graphics/bgad/src/bga.rs @@ -1,47 +1,51 @@ -use common::io::{Io, Pio}; - const BGA_INDEX_XRES: u16 = 1; const BGA_INDEX_YRES: u16 = 2; const BGA_INDEX_BPP: u16 = 3; const BGA_INDEX_ENABLE: u16 = 4; pub struct Bga { - index: Pio, - data: Pio, + bar: *mut u8, } impl Bga { - pub fn new() -> Bga { - Bga { - index: Pio::new(0x1CE), - data: Pio::new(0x1CF), + pub unsafe fn new(bar: *mut u8) -> Bga { + Bga { bar } + } + + fn bochs_dispi_addr(&mut self, index: u16) -> *mut u16 { + assert!(index <= 0x10); + unsafe { + self.bar + .byte_add(0x500) + .cast::() + .add(usize::from(index)) } } - fn read(&mut self, index: u16) -> u16 { - self.index.write(index); - self.data.read() + fn bochs_dispi_read(&mut self, index: u16) -> u16 { + unsafe { self.bochs_dispi_addr(index).read_volatile() } } - fn write(&mut self, index: u16, data: u16) { - self.index.write(index); - self.data.write(data); + fn bochs_dispi_write(&mut self, index: u16, data: u16) { + assert!(index <= 0x10); + unsafe { + self.bochs_dispi_addr(index).write_volatile(data); + } } pub fn width(&mut self) -> u16 { - self.read(BGA_INDEX_XRES) + self.bochs_dispi_read(BGA_INDEX_XRES) } pub fn height(&mut self) -> u16 { - self.read(BGA_INDEX_YRES) + self.bochs_dispi_read(BGA_INDEX_YRES) } - #[allow(dead_code)] pub fn set_size(&mut self, width: u16, height: u16) { - self.write(BGA_INDEX_ENABLE, 0); - self.write(BGA_INDEX_XRES, width); - self.write(BGA_INDEX_YRES, height); - self.write(BGA_INDEX_BPP, 32); - self.write(BGA_INDEX_ENABLE, 0x41); + self.bochs_dispi_write(BGA_INDEX_ENABLE, 0); + self.bochs_dispi_write(BGA_INDEX_XRES, width); + self.bochs_dispi_write(BGA_INDEX_YRES, height); + self.bochs_dispi_write(BGA_INDEX_BPP, 32); + self.bochs_dispi_write(BGA_INDEX_ENABLE, 0x41); } } diff --git a/graphics/bgad/src/main.rs b/graphics/bgad/src/main.rs index 2e2ca05564..461b1b8b84 100644 --- a/graphics/bgad/src/main.rs +++ b/graphics/bgad/src/main.rs @@ -1,4 +1,5 @@ -use common::acquire_port_io_rights; +//! + use inputd::ProducerHandle; use pcid_interface::PciFunctionHandle; use redox_scheme::{RequestKind, SignalBehavior, Socket}; @@ -9,8 +10,10 @@ use crate::scheme::BgaScheme; mod bga; mod scheme; +// FIXME add a driver-graphics implementation + fn main() { - let pcid_handle = PciFunctionHandle::connect_default(); + let mut pcid_handle = PciFunctionHandle::connect_default(); let pci_config = pcid_handle.config(); let mut name = pci_config.func.name(); @@ -27,11 +30,11 @@ fn main() { log::info!("BGA {}", pci_config.func.display()); redox_daemon::Daemon::new(move |daemon| { - acquire_port_io_rights().expect("bgad: failed to get port IO permission"); - let socket = Socket::create("bga").expect("bgad: failed to create bga scheme"); - let mut bga = Bga::new(); + let bar = unsafe { pcid_handle.map_bar(2) }.ptr.as_ptr(); + + let mut bga = unsafe { Bga::new(bar) }; log::debug!("BGA {}x{}", bga.width(), bga.height()); let mut scheme = BgaScheme { From 891a9af6234e14be2e29b6e7c277391a613e3844 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 29 Nov 2025 16:18:10 +0100 Subject: [PATCH 1301/1301] pcid: Fix compilation on x86 --- pcid/src/driver_interface/irq_helpers.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pcid/src/driver_interface/irq_helpers.rs b/pcid/src/driver_interface/irq_helpers.rs index 7ed060bce0..28ca077a92 100644 --- a/pcid/src/driver_interface/irq_helpers.rs +++ b/pcid/src/driver_interface/irq_helpers.rs @@ -325,6 +325,7 @@ pub fn pci_allocate_interrupt_vector( // INTx# pin based interrupts. InterruptVector { irq_handle: irq.irq_handle(driver), + vector: 0, kind: InterruptVectorKind::Legacy, } } else {

JK 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 I__E9X8bGZLO8@`> diff --git a/vesad/res/DejaVuSansMono.ttf b/vesad/res/DejaVuSansMono.ttf deleted file mode 100644 index 8b7bb2a4e1b2c27786398c320e9020bcc24c3af3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 335068 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�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

JK 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 I__E9X8bGZLO8@`> literal 0 HcmV?d00001 diff --git a/vesad/res/DejaVuSansMono.ttf b/vesad/res/DejaVuSansMono.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8b7bb2a4e1b2c27786398c320e9020bcc24c3af3 GIT binary patch literal 335068 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�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